From da9e416b8ed41a0cbb219ad32b7456dd6997d09d Mon Sep 17 00:00:00 2001 From: Diego Imbert <70353967+diegoimbert@users.noreply.github.com> Date: Mon, 11 May 2026 09:56:52 +0200 Subject: [PATCH 01/21] workspace specific nit fixes (#9072) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: capture linked variables in trash on bulk resource delete delete_resources_bulk grew linked-variable cascade deletion in an earlier commit on this branch but only mirrored the deletion side of delete_resource — not the trashbin capture side. Linked variables deleted via bulk were permanently lost while their single-delete counterparts could be recovered from trash. Fetch each resource's linked variable rows as JSON before bulk delete and stash them under `trash_data['linked_variables']` of that resource's trash entry, matching the shape produced by single-resource delete. * fix: ws_specific cleanup gaps in variable rename + bulk delete; tooltip Four spots: 1. update_variable rename block: when a variable is renamed and a linked resource at the same path is renamed alongside, also move any explicit ws_specific 'resource' marker from the old path to the new one. Symmetric with what update_resource already does for ws_specific 'variable'. 2. delete_variables_bulk: clean ws_specific 'resource' rows for any linked resource paths before the resource DELETE. Without this, bulk-delete leaves orphaned markers that would cause a freshly recreated resource at the same path to be falsely treated as workspace-specific. (linked_resource trash capture is already present in the bulk path — the reviewer note about that was inaccurate against the current code.) 3. list_ws_specific: ORDER BY item_kind, path so the CLI sees a stable list across pulls/pushes — cheap on a small per-workspace row set and avoids spurious diffs. 4. VariableForm tooltip: mirror the resource form so users who find a variable already toggled know it may have been auto-marked by a workspace-specific resource referencing it, and that disabling doesn't retroactively un-mark the referencing resource. * sqlx prepare --- ...1f7f387f5055c47f493271d26731336257384.json | 10 +++--- ...631af9f524389309f17ef04f70c773b1d5e75.json | 28 +++++++++++++++ ...153c43903f929ae5d62fbba12610f89c36d55.json | 2 +- .../windmill-api-workspaces/src/workspaces.rs | 1 + backend/windmill-store/src/resources.rs | 35 +++++++++++++++++-- backend/windmill-store/src/variables.rs | 25 +++++++++++++ .../src/lib/components/VariableForm.svelte | 2 +- 7 files changed, 94 insertions(+), 9 deletions(-) create mode 100644 backend/.sqlx/query-290599fc173947acb518344d6fb631af9f524389309f17ef04f70c773b1d5e75.json diff --git a/backend/.sqlx/query-07168aaf14cb6beff0ad4274b441f7f387f5055c47f493271d26731336257384.json b/backend/.sqlx/query-07168aaf14cb6beff0ad4274b441f7f387f5055c47f493271d26731336257384.json index e7ed0aee65..d29a18c691 100644 --- a/backend/.sqlx/query-07168aaf14cb6beff0ad4274b441f7f387f5055c47f493271d26731336257384.json +++ b/backend/.sqlx/query-07168aaf14cb6beff0ad4274b441f7f387f5055c47f493271d26731336257384.json @@ -46,11 +46,11 @@ ] }, "nullable": [ - false, - false, - false, - false, - false, + true, + true, + true, + true, + true, true, true ] diff --git a/backend/.sqlx/query-290599fc173947acb518344d6fb631af9f524389309f17ef04f70c773b1d5e75.json b/backend/.sqlx/query-290599fc173947acb518344d6fb631af9f524389309f17ef04f70c773b1d5e75.json new file mode 100644 index 0000000000..ad296e9eda --- /dev/null +++ b/backend/.sqlx/query-290599fc173947acb518344d6fb631af9f524389309f17ef04f70c773b1d5e75.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT s.item_kind, s.path\n FROM ws_specific s\n WHERE s.workspace_id = $1\n AND (\n (s.item_kind = 'resource' AND EXISTS (\n SELECT 1 FROM resource r\n WHERE r.workspace_id = s.workspace_id AND r.path = s.path\n ))\n OR (s.item_kind = 'variable' AND EXISTS (\n SELECT 1 FROM variable v\n WHERE v.workspace_id = s.workspace_id AND v.path = s.path\n ))\n )\n ORDER BY s.item_kind, s.path\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "item_kind", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "path", + "type_info": "Varchar" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false + ] + }, + "hash": "290599fc173947acb518344d6fb631af9f524389309f17ef04f70c773b1d5e75" +} diff --git a/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json b/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json index 36ddb8ab9f..713ccb9dd3 100644 --- a/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json +++ b/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json @@ -15,7 +15,7 @@ ] }, "nullable": [ - true + null ] }, "hash": "5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55" diff --git a/backend/windmill-api-workspaces/src/workspaces.rs b/backend/windmill-api-workspaces/src/workspaces.rs index f479b8c719..94e2026ad3 100644 --- a/backend/windmill-api-workspaces/src/workspaces.rs +++ b/backend/windmill-api-workspaces/src/workspaces.rs @@ -7351,6 +7351,7 @@ async fn list_ws_specific( WHERE v.workspace_id = s.workspace_id AND v.path = s.path )) ) + ORDER BY s.item_kind, s.path "#, &w_id ) diff --git a/backend/windmill-store/src/resources.rs b/backend/windmill-store/src/resources.rs index 6b169a0c0d..8aa88bad86 100644 --- a/backend/windmill-store/src/resources.rs +++ b/backend/windmill-store/src/resources.rs @@ -1238,10 +1238,39 @@ async fn delete_resources_bulk( .await?; if let Some(res_data) = trash_resource { + // Per-resource linked vars so each resource's trash entry carries + // exactly the variables that vanished with it (matching the + // single-delete shape: trash_data["linked_variables"]). + let mut this_linked: Vec = Vec::new(); if let Some(value) = res_data.get("value") { - collect_var_refs(value, &mut linked_var_paths); + collect_var_refs(value, &mut this_linked); + } + this_linked.sort(); + this_linked.dedup(); + + let trash_linked_vars: Vec = if this_linked.is_empty() { + Vec::new() + } else { + let placeholders: Vec = this_linked + .iter() + .enumerate() + .map(|(i, _)| format!("${}", i + 2)) + .collect(); + let query = format!( + "SELECT to_jsonb(t) FROM variable t WHERE workspace_id = $1 AND path IN ({})", + placeholders.join(", ") + ); + let mut q = sqlx::query_scalar::<_, serde_json::Value>(&query).bind(&w_id); + for var_path in &this_linked { + q = q.bind(var_path); + } + q.fetch_all(&mut *tx).await? + }; + + let mut trash_data = serde_json::json!({"row": res_data}); + if !trash_linked_vars.is_empty() { + trash_data["linked_variables"] = serde_json::Value::Array(trash_linked_vars); } - let trash_data = serde_json::json!({"row": res_data}); windmill_common::trashbin::move_to_trash( &mut *tx, &w_id, @@ -1251,6 +1280,8 @@ async fn delete_resources_bulk( &authed.username, ) .await?; + + linked_var_paths.extend(this_linked); } } linked_var_paths.sort(); diff --git a/backend/windmill-store/src/variables.rs b/backend/windmill-store/src/variables.rs index a9f8734647..c50049fcd6 100644 --- a/backend/windmill-store/src/variables.rs +++ b/backend/windmill-store/src/variables.rs @@ -755,6 +755,17 @@ async fn delete_variables_bulk( ) .fetch_all(&mut *tx) .await?; + // Mirror single delete_variable: clean the linked-resource ws_specific + // markers BEFORE deleting the resource rows so they don't survive as + // orphans. A resource later created at the same path would otherwise + // inherit a stale ws_specific flag. + sqlx::query!( + "DELETE FROM ws_specific WHERE workspace_id = $1 AND item_kind = 'resource' AND path = ANY($2)", + w_id, + &deleted_paths + ) + .execute(&mut *tx) + .await?; sqlx::query!( "DELETE FROM resource WHERE path = ANY($1) AND workspace_id = $2", &deleted_paths, @@ -1019,6 +1030,20 @@ async fn update_variable( ) .execute(&mut *tx) .await?; + + // The linked resource at the same path is renamed above; move + // its ws_specific 'resource' marker too so an explicitly-flagged + // resource doesn't lose its ws_specific status on rename and + // doesn't leave a stale marker at the old path. Symmetric with + // update_resource's rename block. + sqlx::query!( + "UPDATE ws_specific SET path = $1 WHERE workspace_id = $2 AND item_kind = 'resource' AND path = $3", + npath, + w_id, + path + ) + .execute(&mut *tx) + .await?; } } diff --git a/frontend/src/lib/components/VariableForm.svelte b/frontend/src/lib/components/VariableForm.svelte index 167172450e..0ffa4d8ba6 100644 --- a/frontend/src/lib/components/VariableForm.svelte +++ b/frontend/src/lib/components/VariableForm.svelte @@ -86,7 +86,7 @@ {#if deployTo} From 23bb1b541e78846d5978153fd8d9bb4f01cec72b Mon Sep 17 00:00:00 2001 From: hugocasa Date: Mon, 11 May 2026 12:01:13 +0200 Subject: [PATCH 02/21] fix(frontend): mark Path dirty when folder picker changes selection (#9096) * fix(frontend): enable move button when only folder changes * fix(frontend): mark Path dirty when folder picker changes selection * fix(frontend): preserve script auto-derive for new items in Path dirty effect --- frontend/src/lib/components/Path.svelte | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/frontend/src/lib/components/Path.svelte b/frontend/src/lib/components/Path.svelte index 6e1244b05f..c35b5f1e81 100644 --- a/frontend/src/lib/components/Path.svelte +++ b/frontend/src/lib/components/Path.svelte @@ -355,6 +355,19 @@ !dirty && (dirty = true) } + $effect(() => { + if ( + path !== undefined && + path !== '' && + initialPath && + !initialPath.startsWith('tmp/') && + path !== initialPath && + !dirty + ) { + dirty = true + } + }) + const openSearchWithPrefilledText: (t?: string) => void = getContext( 'openSearchWithPrefilledText' ) From 27acbbf3d595f16b3e73b81011c4ae4df989c2a7 Mon Sep 17 00:00:00 2001 From: centdix <40307056+centdix@users.noreply.github.com> Date: Mon, 11 May 2026 12:01:45 +0200 Subject: [PATCH 03/21] refactor: move ai sse plumbing to windmill-ai (#9059) * docs: refine windmill ai refactor plan * refactor: move ai sse plumbing to windmill-ai * refactor: remove ai re-export shims * fix: update ee ai memory ref * chore: update ee-repo-ref to d3bc7fa85195b46b7a38d43c2f806520bf8b5454 This commit updates the EE repository reference after PR #560 was merged in windmill-ee-private. Previous ee-repo-ref: ff35bf7cc198e13884b33654e1d6dbd8a8b314d3 New ee-repo-ref: d3bc7fa85195b46b7a38d43c2f806520bf8b5454 Automated by sync-ee-ref workflow. --------- Co-authored-by: windmill-internal-app[bot] --- backend/Cargo.lock | 2 + backend/ee-repo-ref.txt | 2 +- backend/windmill-ai/Cargo.toml | 2 + backend/windmill-ai/src/lib.rs | 2 + .../src/ai => windmill-ai/src}/sse.rs | 19 +++-- backend/windmill-ai/src/utils.rs | 56 ++++++++++++++ backend/windmill-api/src/ai.rs | 29 +------ .../windmill-worker/src/ai/image_handler.rs | 3 +- backend/windmill-worker/src/ai/mod.rs | 2 - .../src/ai/providers/anthropic.rs | 11 +-- .../src/ai/providers/bedrock.rs | 17 ++-- .../src/ai/providers/google_ai.rs | 18 ++--- .../src/ai/providers/openai.rs | 12 +-- .../src/ai/providers/openrouter.rs | 11 ++- .../windmill-worker/src/ai/providers/other.rs | 10 +-- .../windmill-worker/src/ai/query_builder.rs | 19 ++--- backend/windmill-worker/src/ai/tools.rs | 6 +- backend/windmill-worker/src/ai/types.rs | 2 - backend/windmill-worker/src/ai/utils.rs | 29 +------ backend/windmill-worker/src/ai_executor.rs | 49 +++--------- backend/windmill-worker/src/memory_common.rs | 2 +- backend/windmill-worker/src/memory_oss.rs | 4 +- docs/windmill-ai-refactor-plan.md | 77 +++++++++++++++++-- 23 files changed, 209 insertions(+), 175 deletions(-) rename backend/{windmill-worker/src/ai => windmill-ai/src}/sse.rs (99%) create mode 100644 backend/windmill-ai/src/utils.rs delete mode 100644 backend/windmill-worker/src/ai/types.rs diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 6952682391..842799d5f9 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -16114,12 +16114,14 @@ dependencies = [ "aws-sdk-bedrockruntime", "aws-smithy-types", "base64 0.22.1", + "eventsource-stream", "lazy_static", "reqwest 0.13.1", "serde", "serde_json", "sqlx", "tokio", + "tokio-stream", "tracing", "uuid", "windmill-common", diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index 401a8213f7..2e43e667c1 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -c8d100d74b8de6bd26fc973d5edbd8853d54dd8b +d3bc7fa85195b46b7a38d43c2f806520bf8b5454 diff --git a/backend/windmill-ai/Cargo.toml b/backend/windmill-ai/Cargo.toml index 69cc0f181b..3cfea846b9 100644 --- a/backend/windmill-ai/Cargo.toml +++ b/backend/windmill-ai/Cargo.toml @@ -21,6 +21,7 @@ windmill-mcp = { workspace = true, optional = true } async-trait.workspace = true base64.workspace = true +eventsource-stream.workspace = true reqwest.workspace = true serde.workspace = true serde_json.workspace = true @@ -29,6 +30,7 @@ uuid.workspace = true lazy_static.workspace = true tracing.workspace = true tokio.workspace = true +tokio-stream.workspace = true # Bedrock (optional) aws-config = { workspace = true, optional = true } diff --git a/backend/windmill-ai/src/lib.rs b/backend/windmill-ai/src/lib.rs index dfa34e7d43..8b786cb741 100644 --- a/backend/windmill-ai/src/lib.rs +++ b/backend/windmill-ai/src/lib.rs @@ -5,4 +5,6 @@ pub mod ai_google; pub mod ai_providers; pub mod ai_types; pub mod query_builder; +pub mod sse; pub mod types; +pub mod utils; diff --git a/backend/windmill-worker/src/ai/sse.rs b/backend/windmill-ai/src/sse.rs similarity index 99% rename from backend/windmill-worker/src/ai/sse.rs rename to backend/windmill-ai/src/sse.rs index 2cc03b148e..35a4e43acc 100644 --- a/backend/windmill-worker/src/ai/sse.rs +++ b/backend/windmill-ai/src/sse.rs @@ -3,17 +3,15 @@ use std::collections::HashMap; use eventsource_stream::Eventsource; use reqwest::Response; use serde::Deserialize; -use serde_json; use tokio_stream::StreamExt; -use windmill_ai::{ - ai_google::{parse_gemini_sse_event, GeminiUsageMetadata}, - ai_types::{ExtraContent, GoogleExtraContent, OpenAIFunction, OpenAIToolCall}, -}; use windmill_common::{error::Error, utils::rd_string}; -use crate::ai::{ +use crate::{ + ai_google::{parse_gemini_sse_event, GeminiUsageMetadata}, + ai_types::UrlCitation, + ai_types::{ExtraContent, GoogleExtraContent, OpenAIFunction, OpenAIToolCall}, query_builder::StreamEventSink, - types::{StreamingEvent, UrlCitation}, + types::StreamingEvent, }; #[derive(Deserialize)] @@ -64,6 +62,7 @@ lazy_static::lazy_static! { .parse::() .unwrap_or(false); } +#[allow(async_fn_in_trait)] pub trait SSEParser { async fn parse_event_data(&mut self, data: &str) -> Result<(), Error>; @@ -459,11 +458,11 @@ impl SSEParser for AnthropicSSEParser { // Gemini SSE Parser // ============================================================================ -/// Accumulates Gemini streaming events and converts them into the worker's -/// internal [`OpenAIToolCall`] / [`StreamingEvent`] representation. +/// Accumulates Gemini streaming events and converts them into the shared +/// [`OpenAIToolCall`] / [`StreamingEvent`] representation. /// /// The actual SSE parsing is delegated to [`parse_gemini_sse_event`] from -/// `windmill_common::ai_google` so the logic can be shared with the API proxy. +/// `windmill_ai::ai_google` so the logic can be shared with the API proxy. pub struct GeminiSSEParser { pub accumulated_content: String, pub accumulated_tool_calls: HashMap, diff --git a/backend/windmill-ai/src/utils.rs b/backend/windmill-ai/src/utils.rs new file mode 100644 index 0000000000..b401282df1 --- /dev/null +++ b/backend/windmill-ai/src/utils.rs @@ -0,0 +1,56 @@ +use crate::{ + ai_providers::AIProvider, + ai_types::{ContentPart, OpenAIContent}, +}; + +lazy_static::lazy_static! { + /// Parse AI_HTTP_HEADERS environment variable into a vector of (header_name, header_value) tuples + /// Format: "header1: value1, header2: value2" + pub static ref AI_HTTP_HEADERS: Vec<(String, String)> = { + std::env::var("AI_HTTP_HEADERS") + .ok() + .map(|headers_str| { + headers_str + .split(',') + .filter_map(|header| { + let parts: Vec<&str> = header.splitn(2, ':').collect(); + if parts.len() == 2 { + let name = parts[0].trim().to_string(); + let value = parts[1].trim().to_string(); + if !name.is_empty() && !value.is_empty() { + Some((name, value)) + } else { + None + } + } else { + None + } + }) + .collect() + }) + .unwrap_or_default() + }; +} + +/// AWS Bedrock do not handle structured output query param, so we use a tool for structured output. Same for every Claude models. +pub fn should_use_structured_output_tool(provider: &AIProvider, model: &str) -> bool { + model.contains("claude") || provider == &AIProvider::AWSBedrock +} + +/// Extract text content from OpenAIContent, joining parts with space if multiple +pub fn extract_text_content(content: &OpenAIContent) -> String { + match content { + OpenAIContent::Text(text) => text.clone(), + OpenAIContent::Parts(parts) => parts + .iter() + .filter_map(|p| { + if let ContentPart::Text { text } = p { + Some(text.as_str()) + } else { + None + } + }) + .collect::>() + .join(""), + } +} diff --git a/backend/windmill-api/src/ai.rs b/backend/windmill-api/src/ai.rs index a2c4ceb811..8b415997c2 100644 --- a/backend/windmill-api/src/ai.rs +++ b/backend/windmill-api/src/ai.rs @@ -15,11 +15,12 @@ use serde::{Deserialize, Serialize}; use serde_json::{json, value::RawValue}; use std::collections::HashMap; use std::time::Duration; -use windmill_audit::{audit_oss::audit_log, ActionKind}; use windmill_ai::ai_cache::current_instance_ai_config_revision; use windmill_ai::ai_providers::{ empty_string_as_none, AIPlatform, AIProvider, ProviderConfig, ProviderModel, }; +use windmill_ai::utils::AI_HTTP_HEADERS; +use windmill_audit::{audit_oss::audit_log, ActionKind}; use windmill_common::db::UserDB; use windmill_common::error::{to_anyhow, Error, Result}; use windmill_common::utils::configure_client; @@ -101,32 +102,6 @@ lazy_static::lazy_static! { pub static ref AI_REQUEST_CACHE: Cache<(String, AIProvider), ExpiringAIRequestConfig> = Cache::new(500); - /// Parse AI_HTTP_HEADERS environment variable into a vector of (header_name, header_value) tuples - /// Format: "header1: value1, header2: value2" - static ref AI_HTTP_HEADERS: Vec<(String, String)> = { - std::env::var("AI_HTTP_HEADERS") - .ok() - .map(|headers_str| { - headers_str - .split(',') - .filter_map(|header| { - let parts: Vec<&str> = header.splitn(2, ':').collect(); - if parts.len() == 2 { - let name = parts[0].trim().to_string(); - let value = parts[1].trim().to_string(); - if !name.is_empty() && !value.is_empty() { - Some((name, value)) - } else { - None - } - } else { - None - } - }) - .collect() - }) - .unwrap_or_default() - }; } pub(crate) fn invalidate_ai_request_cache_for_workspace(workspace_id: &str) { diff --git a/backend/windmill-worker/src/ai/image_handler.rs b/backend/windmill-worker/src/ai/image_handler.rs index 4fc0bcb4db..089d73dc42 100644 --- a/backend/windmill-worker/src/ai/image_handler.rs +++ b/backend/windmill-worker/src/ai/image_handler.rs @@ -1,12 +1,11 @@ use base64::Engine; use futures; use ulid; +use windmill_ai::types::*; use windmill_common::{client::AuthedClient, error::Error}; use windmill_queue::MiniPulledJob; use windmill_types::s3::S3Object; -use crate::ai::types::*; - /// Upload image to S3 and return S3Object pub async fn upload_image_to_s3( base64_image: &str, diff --git a/backend/windmill-worker/src/ai/mod.rs b/backend/windmill-worker/src/ai/mod.rs index 4ad67b9e6e..2423fca372 100644 --- a/backend/windmill-worker/src/ai/mod.rs +++ b/backend/windmill-worker/src/ai/mod.rs @@ -4,7 +4,5 @@ pub mod image_handler; pub mod providers; pub mod query_builder; -pub mod sse; pub mod tools; -pub mod types; pub mod utils; diff --git a/backend/windmill-worker/src/ai/providers/anthropic.rs b/backend/windmill-worker/src/ai/providers/anthropic.rs index 2bbfd83768..f2c310923f 100644 --- a/backend/windmill-worker/src/ai/providers/anthropic.rs +++ b/backend/windmill-worker/src/ai/providers/anthropic.rs @@ -1,16 +1,17 @@ use async_trait::async_trait; use serde::{Deserialize, Serialize}; use serde_json::value::RawValue; -use windmill_ai::{ai_google::parse_data_url, ai_providers::AIProvider}; -use windmill_common::{client::AuthedClient, error::Error}; - -use crate::ai::{ - image_handler::prepare_messages_for_api, +use windmill_ai::{ + ai_google::parse_data_url, + ai_providers::AIProvider, query_builder::{BuildRequestArgs, ParsedResponse, QueryBuilder, StreamEventSink}, sse::{AnthropicSSEParser, SSEParser}, types::*, utils::{extract_text_content, should_use_structured_output_tool}, }; +use windmill_common::{client::AuthedClient, error::Error}; + +use crate::ai::image_handler::prepare_messages_for_api; /// Anthropic API version for standard API const ANTHROPIC_VERSION_STANDARD: &str = "2023-06-01"; diff --git a/backend/windmill-worker/src/ai/providers/bedrock.rs b/backend/windmill-worker/src/ai/providers/bedrock.rs index ce87d21a44..ec499f5fcd 100644 --- a/backend/windmill-worker/src/ai/providers/bedrock.rs +++ b/backend/windmill-worker/src/ai/providers/bedrock.rs @@ -6,25 +6,22 @@ //! - Stream event parsing //! - Helper utilities -use crate::ai::{ - image_handler::prepare_messages_for_api, - query_builder::{ParsedResponse, StreamEventSink}, - types::StreamingEvent, - types::TokenUsage, - types::{OpenAIMessage, ToolDef}, -}; +use crate::ai::image_handler::prepare_messages_for_api; use std::collections::HashMap; +use windmill_ai::{ + query_builder::{ParsedResponse, StreamEventSink}, + types::{OpenAIMessage, StreamingEvent, TokenUsage, ToolDef}, +}; use windmill_common::{client::AuthedClient, error::Error}; -// Re-export from shared module for use by other parts of the worker +// Import shared Bedrock helpers for worker-specific orchestration. use windmill_ai::ai_bedrock::{ bedrock_model_supports_prompt_caching, bedrock_stream_event_is_block_stop, bedrock_stream_event_to_text, bedrock_stream_event_to_tool_delta, bedrock_stream_event_to_tool_start, build_tool_config, create_inference_config, format_bedrock_error, openai_messages_to_bedrock, streaming_tool_calls_to_openai, - StreamingToolCall, + BedrockClient, StreamingToolCall, }; -pub use windmill_ai::ai_bedrock::{check_env_credentials, BedrockClient}; // ============================================================================ // Query Builder (Worker-specific orchestration) diff --git a/backend/windmill-worker/src/ai/providers/google_ai.rs b/backend/windmill-worker/src/ai/providers/google_ai.rs index 6098cb22d8..2a00011de7 100644 --- a/backend/windmill-worker/src/ai/providers/google_ai.rs +++ b/backend/windmill-worker/src/ai/providers/google_ai.rs @@ -1,17 +1,17 @@ use async_trait::async_trait; -use windmill_ai::ai_google::{ - openai_messages_to_gemini, openai_tools_to_gemini, GeminiGenerationConfig, GeminiImageContent, - GeminiImageRequest, GeminiImageResponse, GeminiInlineData, GeminiPart, GeminiPredictContent, - GeminiTextRequest, GeminiTool, -}; -use windmill_common::{client::AuthedClient, error::Error}; - -use crate::ai::{ - image_handler::{download_and_encode_s3_image, prepare_messages_for_api}, +use windmill_ai::{ + ai_google::{ + openai_messages_to_gemini, openai_tools_to_gemini, GeminiGenerationConfig, + GeminiImageContent, GeminiImageRequest, GeminiImageResponse, GeminiInlineData, GeminiPart, + GeminiPredictContent, GeminiTextRequest, GeminiTool, + }, query_builder::{BuildRequestArgs, ParsedResponse, QueryBuilder, StreamEventSink}, sse::{GeminiSSEParser, SSEParser}, types::*, }; +use windmill_common::{client::AuthedClient, error::Error}; + +use crate::ai::image_handler::{download_and_encode_s3_image, prepare_messages_for_api}; // ============================================================================ // Query Builder Implementation diff --git a/backend/windmill-worker/src/ai/providers/openai.rs b/backend/windmill-worker/src/ai/providers/openai.rs index 52feb2eca7..691f8fd5e3 100644 --- a/backend/windmill-worker/src/ai/providers/openai.rs +++ b/backend/windmill-worker/src/ai/providers/openai.rs @@ -1,17 +1,17 @@ use async_trait::async_trait; use serde::{Deserialize, Serialize}; use serde_json::value::RawValue; -use windmill_ai::ai_providers::AIProvider; -use windmill_ai::ai_types::OpenAIToolCall; -use windmill_common::{client::AuthedClient, error::Error}; - -use crate::ai::{ - image_handler::{prepare_messages_for_api, s3_object_to_content_part}, +use windmill_ai::{ + ai_providers::AIProvider, + ai_types::OpenAIToolCall, query_builder::{BuildRequestArgs, ParsedResponse, QueryBuilder, StreamEventSink}, sse::{OpenAIResponsesSSEParser, SSEParser}, types::*, utils::extract_text_content, }; +use windmill_common::{client::AuthedClient, error::Error}; + +use crate::ai::image_handler::{prepare_messages_for_api, s3_object_to_content_part}; // Responses API structures #[derive(Deserialize)] diff --git a/backend/windmill-worker/src/ai/providers/openrouter.rs b/backend/windmill-worker/src/ai/providers/openrouter.rs index 68ad1922d3..9bfc47ed8f 100644 --- a/backend/windmill-worker/src/ai/providers/openrouter.rs +++ b/backend/windmill-worker/src/ai/providers/openrouter.rs @@ -1,15 +1,14 @@ use async_trait::async_trait; use serde::{Deserialize, Serialize}; use serde_json; -use windmill_ai::ai_providers::AIProvider; -use windmill_common::{client::AuthedClient, error::Error}; - -use crate::ai::{ - image_handler::prepare_messages_for_api, - providers::other::OtherQueryBuilder, +use windmill_ai::{ + ai_providers::AIProvider, query_builder::{BuildRequestArgs, ParsedResponse, QueryBuilder, StreamEventSink}, types::*, }; +use windmill_common::{client::AuthedClient, error::Error}; + +use crate::ai::{image_handler::prepare_messages_for_api, providers::other::OtherQueryBuilder}; // OpenRouter-specific types #[derive(Serialize)] diff --git a/backend/windmill-worker/src/ai/providers/other.rs b/backend/windmill-worker/src/ai/providers/other.rs index f8ee60f287..7982dc739d 100644 --- a/backend/windmill-worker/src/ai/providers/other.rs +++ b/backend/windmill-worker/src/ai/providers/other.rs @@ -1,16 +1,16 @@ use async_trait::async_trait; use serde::Serialize; use serde_json; -use windmill_ai::ai_providers::AIProvider; -use windmill_common::{client::AuthedClient, error::Error}; - -use crate::ai::{ - image_handler::prepare_messages_for_api, +use windmill_ai::{ + ai_providers::AIProvider, query_builder::{BuildRequestArgs, ParsedResponse, QueryBuilder, StreamEventSink}, sse::{OpenAISSEParser, SSEParser}, types::*, utils::should_use_structured_output_tool, }; +use windmill_common::{client::AuthedClient, error::Error}; + +use crate::ai::image_handler::prepare_messages_for_api; #[derive(Serialize, Debug, Clone)] #[serde(rename_all = "lowercase")] diff --git a/backend/windmill-worker/src/ai/query_builder.rs b/backend/windmill-worker/src/ai/query_builder.rs index d74c45c098..606aa8f9db 100644 --- a/backend/windmill-worker/src/ai/query_builder.rs +++ b/backend/windmill-worker/src/ai/query_builder.rs @@ -1,24 +1,19 @@ use async_trait::async_trait; +use windmill_ai::{ + query_builder::{QueryBuilder, StreamEventSink}, + types::*, +}; use windmill_common::{error::Error, worker::Connection}; use windmill_queue::MiniPulledJob; use crate::{ - ai::{ - providers::{ - anthropic::AnthropicQueryBuilder, google_ai::GoogleAIQueryBuilder, - openai::OpenAIQueryBuilder, openrouter::OpenRouterQueryBuilder, - other::OtherQueryBuilder, - }, - types::*, + ai::providers::{ + anthropic::AnthropicQueryBuilder, google_ai::GoogleAIQueryBuilder, + openai::OpenAIQueryBuilder, openrouter::OpenRouterQueryBuilder, other::OtherQueryBuilder, }, job_logger::append_result_stream, }; -// Re-export from windmill_ai -pub use windmill_ai::query_builder::{ - BuildRequestArgs, ParsedResponse, QueryBuilder, StreamEventSink, -}; - /// Factory function to create the appropriate query builder for a provider pub fn create_query_builder(provider: &ProviderWithResource) -> Box { use windmill_ai::ai_providers::AIProvider; diff --git a/backend/windmill-worker/src/ai/tools.rs b/backend/windmill-worker/src/ai/tools.rs index c92fc2a94e..fcc9cdf3c9 100644 --- a/backend/windmill-worker/src/ai/tools.rs +++ b/backend/windmill-worker/src/ai/tools.rs @@ -1,6 +1,4 @@ -use crate::ai::query_builder::{StreamEventProcessor, StreamEventSink}; -use crate::ai::types::McpToolSource; -use crate::ai::types::*; +use crate::ai::query_builder::StreamEventProcessor; use crate::ai::utils::{ add_message_to_conversation, execute_mcp_tool, get_step_name_from_flow, is_completed_input_transform, update_flow_status_module_with_actions, @@ -20,7 +18,7 @@ use mappable_rc::Marc; use serde_json::value::RawValue; use std::{collections::HashMap, sync::Arc}; use uuid::Uuid; -use windmill_ai::ai_types::OpenAIToolCall; +use windmill_ai::{ai_types::OpenAIToolCall, query_builder::StreamEventSink, types::*}; use windmill_common::jobs::JobPayload; #[cfg(feature = "mcp")] diff --git a/backend/windmill-worker/src/ai/types.rs b/backend/windmill-worker/src/ai/types.rs deleted file mode 100644 index 57619f0dd9..0000000000 --- a/backend/windmill-worker/src/ai/types.rs +++ /dev/null @@ -1,2 +0,0 @@ -// Re-export all types from windmill_ai::types -pub use windmill_ai::types::*; diff --git a/backend/windmill-worker/src/ai/utils.rs b/backend/windmill-worker/src/ai/utils.rs index f1e8fdd22f..74e75ef0a5 100644 --- a/backend/windmill-worker/src/ai/utils.rs +++ b/backend/windmill-worker/src/ai/utils.rs @@ -1,5 +1,3 @@ -pub use crate::ai::types::McpToolSource; -use crate::ai::types::ToolDef; use anyhow::Context; use serde_json::value::RawValue; use sqlx::types::Json; @@ -8,7 +6,7 @@ use std::{ sync::Arc, }; use uuid::Uuid; -use windmill_ai::ai_providers::AIProvider; +use windmill_ai::types::*; use windmill_common::flows::FlowModuleValue; use windmill_common::{ db::DB, @@ -24,7 +22,7 @@ use windmill_common::{ use windmill_mcp::{McpClient, McpResource, McpTool}; use windmill_queue::{flow_status::get_step_of_flow_status, MiniPulledJob}; -use crate::{ai::types::*, parse_sig_of_lang}; +use crate::parse_sig_of_lang; pub fn parse_raw_script_schema( content: &str, @@ -323,11 +321,6 @@ pub fn get_step_name_from_flow( ) } -/// AWS Bedrock do not handle structured output query param, so we use a tool for structured output. Same for every Claude models. -pub fn should_use_structured_output_tool(provider: &AIProvider, model: &str) -> bool { - model.contains("claude") || provider == &AIProvider::AWSBedrock -} - /// Cleanup MCP clients by gracefully shutting down connections #[cfg(feature = "mcp")] pub async fn cleanup_mcp_clients(mcp_clients: HashMap>) { @@ -713,21 +706,3 @@ pub fn any_tool_needs_previous_result(tools: &[Tool]) -> bool { false }) } - -/// Extract text content from OpenAIContent, joining parts with space if multiple -pub fn extract_text_content(content: &OpenAIContent) -> String { - match content { - OpenAIContent::Text(text) => text.clone(), - OpenAIContent::Parts(parts) => parts - .iter() - .filter_map(|p| { - if let ContentPart::Text { text } = p { - Some(text.as_str()) - } else { - None - } - }) - .collect::>() - .join(""), - } -} diff --git a/backend/windmill-worker/src/ai_executor.rs b/backend/windmill-worker/src/ai_executor.rs index 03153df0a4..4dfeee3571 100644 --- a/backend/windmill-worker/src/ai_executor.rs +++ b/backend/windmill-worker/src/ai_executor.rs @@ -1,12 +1,10 @@ -#[cfg(feature = "bedrock")] -use crate::ai::providers::bedrock::check_env_credentials; use crate::ai::tools::{execute_tool_calls, ToolAbortHandles, ToolExecutionContext}; use crate::ai::utils::{ add_message_to_conversation, any_tool_needs_previous_result, cleanup_mcp_clients, filter_schema_by_input_transforms, find_unique_tool_name, get_flow_context, get_flow_job_runnable_and_raw_flow, get_step_name_from_flow, load_mcp_tools, - parse_raw_script_schema, should_use_structured_output_tool, - update_flow_status_module_with_actions, update_flow_status_module_with_actions_success, + parse_raw_script_schema, update_flow_status_module_with_actions, + update_flow_status_module_with_actions_success, }; use crate::memory_oss::{read_from_memory, write_to_memory}; use crate::worker_flow::{get_previous_job_result, get_transform_context}; @@ -15,12 +13,19 @@ use regex::Regex; use serde_json::value::RawValue; use std::{collections::HashMap, sync::Arc}; use uuid::Uuid; +#[cfg(feature = "bedrock")] +use windmill_ai::ai_bedrock::check_env_credentials; #[cfg(feature = "mcp")] use windmill_mcp::McpClient; #[cfg(not(feature = "mcp"))] use crate::ai::tools::McpClientStub as McpClient; -use windmill_ai::ai_providers::AIProvider; +use windmill_ai::{ + ai_providers::AIProvider, + query_builder::{BuildRequestArgs, ParsedResponse}, + types::*, + utils::{should_use_structured_output_tool, AI_HTTP_HEADERS}, +}; use windmill_common::{ cache, client::AuthedClient, @@ -40,10 +45,7 @@ use windmill_queue::{cancel_single_job, CanceledBy, MiniPulledJob}; use crate::{ ai::{ image_handler::upload_image_to_s3, - query_builder::{ - create_query_builder, BuildRequestArgs, ParsedResponse, StreamEventProcessor, - }, - types::*, + query_builder::{create_query_builder, StreamEventProcessor}, }, common::{build_args_map, resolve_job_timeout, OccupancyMetrics, StreamNotifier}, handle_child::{run_future_with_polling_update_job_poller_graceful, GracefulPollOutcome}, @@ -52,33 +54,6 @@ use crate::{ lazy_static::lazy_static! { static ref TOOL_NAME_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9_]+$").unwrap(); - /// Parse AI_HTTP_HEADERS environment variable into a vector of (header_name, header_value) tuples - /// Format: "header1: value1, header2: value2" - static ref AI_HTTP_HEADERS: Vec<(String, String)> = { - std::env::var("AI_HTTP_HEADERS") - .ok() - .map(|headers_str| { - headers_str - .split(',') - .filter_map(|header| { - let parts: Vec<&str> = header.splitn(2, ':').collect(); - if parts.len() == 2 { - let name = parts[0].trim().to_string(); - let value = parts[1].trim().to_string(); - if !name.is_empty() && !value.is_empty() { - Some((name, value)) - } else { - None - } - } else { - None - } - }) - .collect() - }) - .unwrap_or_default() - }; - static ref AI_AGENT_TOOL_SCHEMA: Box = to_raw_value(&serde_json::json!({ "type": "object", "properties": { @@ -791,7 +766,7 @@ pub async fn run_agent( let mut actions = vec![]; let mut content = None; - let mut final_usage: Option = None; + let mut final_usage: Option = None; // Check if this provider supports tools with the current output type let supports_tools = query_builder.supports_tools_with_output_type(output_type); diff --git a/backend/windmill-worker/src/memory_common.rs b/backend/windmill-worker/src/memory_common.rs index 440199702f..e024acea69 100644 --- a/backend/windmill-worker/src/memory_common.rs +++ b/backend/windmill-worker/src/memory_common.rs @@ -1,5 +1,5 @@ -use crate::ai::types::OpenAIMessage; use uuid::Uuid; +use windmill_ai::types::OpenAIMessage; use windmill_common::{db::DB, error::Error}; pub const MAX_MEMORY_SIZE_BYTES: usize = 100_000; // 100KB per memory entry in database diff --git a/backend/windmill-worker/src/memory_oss.rs b/backend/windmill-worker/src/memory_oss.rs index 74771a79e8..dcdab14e2a 100644 --- a/backend/windmill-worker/src/memory_oss.rs +++ b/backend/windmill-worker/src/memory_oss.rs @@ -3,7 +3,9 @@ pub use crate::memory_ee::*; #[cfg(not(all(feature = "private", feature = "enterprise")))] -use {crate::ai::types::OpenAIMessage, crate::memory_common, uuid::Uuid, windmill_common::db::DB}; +use { + crate::memory_common, uuid::Uuid, windmill_ai::types::OpenAIMessage, windmill_common::db::DB, +}; /// Read AI agent memory from storage /// In OSS: always reads from database diff --git a/docs/windmill-ai-refactor-plan.md b/docs/windmill-ai-refactor-plan.md index 81ab5d7b86..78b82ddcc6 100644 --- a/docs/windmill-ai-refactor-plan.md +++ b/docs/windmill-ai-refactor-plan.md @@ -23,6 +23,58 @@ windmill-worker → windmill-ai windmill-common does **NOT** re-export from windmill-ai (would be circular). All consumers update imports. +## Reviewer Note: Keep the Next PR Small + +The first merged PR established the crate boundary; it did not yet remove the duplicated API-vs-worker provider paths. The remaining work should stay split by dependency risk, not by the final desired module layout. + +Do not jump directly from the current state to provider moves, proxy unification, and credential unification in one PR. The riskiest part is the API proxy because it combines request transformation, endpoint selection, auth headers, custom headers, OAuth user injection, Azure URL handling, Anthropic Vertex handling, Bedrock SDK calls, and SSE keepalive behavior. + +Pull the shared plumbing forward before moving provider implementations: +- Move tiny shared utilities first, including `AI_HTTP_HEADERS`, `extract_text_content`, and `should_use_structured_output_tool`. +- Move SSE parsers next, using the existing `StreamEventSink` abstraction, and update callers to import from `windmill_ai` directly. +- Leave provider implementations, image upload/download handling, API proxy changes, and credential unification out of that PR. + +Avoid adding modules whose only purpose is to re-export moved code. Direct imports from `windmill_ai` make ownership and dependency direction clearer at each call site. + +Also do not make `build_proxy_request(raw_body, path)` too narrow. The proxy path needs method, incoming headers, resolved credentials, base URL/platform, organization/user fields, custom headers, and Bedrock/Azure/Vertex-specific context. Introduce a structured `ProxyBuildArgs`/`ProviderCredentials` shape before deleting `AIRequestConfig::prepare_request`, `google.rs`, or `bedrock.rs`. + +## Next Phase PR: Shared Plumbing Only + +Goal: make `windmill-ai` own the provider-independent helper code that later provider moves will need, without changing API proxy behavior or agent request behavior. + +Suggested PR title: `refactor(ai): move shared SSE plumbing into windmill-ai`. + +Scope: +- Add `windmill-ai/src/utils.rs`. +- Move the duplicated `AI_HTTP_HEADERS` parsing into `windmill_ai::utils` with identical parsing behavior. +- Move `extract_text_content` and `should_use_structured_output_tool` from `windmill-worker/src/ai/utils.rs` to `windmill_ai::utils`. +- Move `windmill-worker/src/ai/sse.rs` to `windmill-ai/src/sse.rs`. +- Delete `windmill-worker/src/ai/sse.rs` and update callers to import parser types from `windmill_ai::sse`. +- Update callers of moved utility functions to import from `windmill_ai::utils` directly. +- Add the minimal new `windmill-ai` dependencies required by `sse.rs` (`eventsource-stream`, `tokio-stream`) and avoid adding worker/queue dependencies. + +Out of scope: +- Do not move provider implementations. +- Do not move `image_handler`. +- Do not change `QueryBuilder` method signatures. +- Do not add `build_proxy_request`. +- Do not change API proxy routing, request preparation, credential resolution, audit logging, cache behavior, or Bedrock/Google special cases. +- Do not remove `windmill-api/src/google.rs`, `windmill-api/src/bedrock.rs`, or `AIRequestConfig::prepare_request`. + +Implementation checklist: +1. Add `utils.rs` to `windmill-ai` and export it from `lib.rs`. +2. Move `AI_HTTP_HEADERS` exactly once, then update `windmill-api/src/ai.rs` and `windmill-worker/src/ai_executor.rs` to import it. +3. Move the two provider-independent helper functions into `windmill_ai::utils`; leave worker-specific flow/MCP/conversation utilities in `windmill-worker/src/ai/utils.rs`. +4. Move `sse.rs` into `windmill-ai`, change imports from `crate::ai::{query_builder, types}` to `crate::{query_builder, types}`, and keep behavior unchanged. +5. Remove worker `ai/sse.rs` and update provider imports to use `windmill_ai::sse` directly. +6. Run focused grep checks for duplicate `AI_HTTP_HEADERS`, old local helper definitions, and accidental `windmill_queue`/worker dependencies from `windmill-ai`. +7. Validate with `cargo check -p windmill-ai`, `cargo check -p windmill-worker`, and `cargo check -p windmill-api`. For `bedrock` builds, also check the existing bedrock feature path. + +Review expectations: +- The diff should be mostly moved code and import updates. +- The behavior should be byte-for-byte equivalent where practical. +- Tests are only needed if helper behavior changes. For a pure move, existing backend checks plus manual AI streaming verification are enough. + ## Step-by-Step Plan Each step produces a compiling, working backend. @@ -131,18 +183,27 @@ This is the key unification step. Add a new method to the `QueryBuilder` trait: /// Used by the API chat proxy. Handles format conversion for non-OpenAI providers. fn build_proxy_request( &self, - raw_body: &[u8], - path: &str, + args: &ProxyBuildArgs<'_>, ) -> Result; ``` -Where `ProxyRequest` contains the transformed body, endpoint URL, and auth headers: +Where `ProxyBuildArgs` carries the API proxy context that provider implementations need: +```rust +pub struct ProxyBuildArgs<'a> { + pub method: http::Method, + pub path: &'a str, + pub headers: &'a http::HeaderMap, + pub body: &'a [u8], + pub credentials: &'a ProviderCredentials, +} +``` + +And `ProxyRequest` contains the transformed request: ```rust pub struct ProxyRequest { pub url: String, pub body: Vec, - pub auth_headers: Vec<(String, String)>, - pub is_sse: bool, + pub headers: Vec<(String, String)>, } ``` @@ -153,9 +214,9 @@ pub struct ProxyRequest { - **Bedrock**: Convert OpenAI format → Bedrock SDK calls. Replaces `windmill-api/src/bedrock.rs`. **Refactor API proxy** (`windmill-api/src/ai.rs`): -1. Parse provider from headers, resolve credentials → `ProviderWithResource` +1. Parse provider from headers, resolve credentials → `ProviderCredentials` 2. Create `QueryBuilder` via `create_query_builder` -3. Call `query_builder.build_proxy_request(body, path)` → `ProxyRequest` +3. Call `query_builder.build_proxy_request(&proxy_args)` → `ProxyRequest` 4. Send the request, return response with SSE keepalive injection **Remove** from windmill-api: @@ -166,7 +227,7 @@ pub struct ProxyRequest { - `supports_native_fim`, `transform_fim_to_chat_completions` — moved to windmill-ai **Keep** in API: -- `AIRequestConfig::new` credential resolution (or refactor to produce `ProviderWithResource`) +- `AIRequestConfig::new` credential resolution until it is refactored to produce `ProviderCredentials` - HTTP routes, audit logging, request caching - `inject_keepalives`, `is_sse_response` helpers - `AIConfig`, `ExpiringAIRequestConfig` caching types From e43a958c5c6ae01a1fbecf3db63c6541a245be62 Mon Sep 17 00:00:00 2001 From: Diego Imbert <70353967+diegoimbert@users.noreply.github.com> Date: Mon, 11 May 2026 14:30:37 +0200 Subject: [PATCH 04/21] feat(forks): prompt to delete forked children when deleting a fork (#9097) Co-authored-by: Claude Opus 4.5 --- .../components/sidebar/SidebarContent.svelte | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/frontend/src/lib/components/sidebar/SidebarContent.svelte b/frontend/src/lib/components/sidebar/SidebarContent.svelte index 24817571c8..c2a790264a 100644 --- a/frontend/src/lib/components/sidebar/SidebarContent.svelte +++ b/frontend/src/lib/components/sidebar/SidebarContent.svelte @@ -4,6 +4,7 @@ superadmin, usedTriggerKinds, userStore, + userWorkspaces, workspaceStore, isCriticalAlertsUIOpen, enterpriseLicense, @@ -11,6 +12,7 @@ tutorialsToDo, skippedAll } from '$lib/stores' + import { findWorkspaceDescendants } from '$lib/utils/workspaceHierarchy' import { syncTutorialsTodos } from '$lib/tutorialUtils' import { SIDEBAR_SHOW_SCHEDULES } from '$lib/consts' import { @@ -123,12 +125,28 @@ } } + if (deleteForkedChildren && forkedDescendants.length > 0) { + for (const child of forkedDescendants) { + try { + await WorkspaceService.deleteWorkspace({ workspace: child.id }) + } catch (err) { + sendUserToast(`Failed to delete forked child ${child.id}: ${err}`, true) + return + } + } + } + await WorkspaceService.deleteWorkspace({ workspace }) sendUserToast('You deleted the workspace') clearStores() goto('/user/workspaces') } + let deleteForkedChildren = $state(false) + const forkedDescendants = $derived( + $workspaceStore ? findWorkspaceDescendants($workspaceStore, $userWorkspaces ?? []) : [] + ) + let hasNewChangelogs = $state(false) let recentChangelogs: Changelog[] = $state([]) let lastOpened = localStorage.getItem('changelogsLastOpened') @@ -492,6 +510,7 @@ label: 'Delete Forked Workspace', action: async () => { await loadForkedDatatables() + deleteForkedChildren = false deleteWorkspaceForkModal = true }, icon: Trash2, @@ -807,6 +826,30 @@ >
Are you sure you want to delete this workspace fork? (deleting {$workspaceStore}) + {#if forkedDescendants.length > 0} +
+
+
+ Forked children + + This fork has {forkedDescendants.length} forked + {forkedDescendants.length === 1 ? 'child' : 'children'} (transitively). + +
+ +
+
    + {#each forkedDescendants as child} +
  • {child.id}
  • + {/each} +
+
+ {/if} {#if forkedDatatables.length > 0}
Forked databases
From 05172ac3bdfc3472da5e9d8a825cdd479ba9e375 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Mon, 11 May 2026 13:54:50 +0000 Subject: [PATCH 05/21] fix: populate raw_code for flowscript and appscript runs (#9104) --- backend/windmill-api/src/jobs.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/backend/windmill-api/src/jobs.rs b/backend/windmill-api/src/jobs.rs index efe03f73dd..ff72ddce70 100644 --- a/backend/windmill-api/src/jobs.rs +++ b/backend/windmill-api/src/jobs.rs @@ -1067,10 +1067,15 @@ impl<'a> GetQuery<'a> { .ok() .inspect(|data| job.raw_flow = Some(sqlx::types::Json(data.raw_flow.clone()))); } - if self.with_code && job.job_kind() == &JobKind::Preview { + if self.with_code + && matches!( + job.job_kind(), + JobKind::Preview | JobKind::FlowScript | JobKind::AppScript + ) + { // Try to fetch the code from the cache, fallback to the preview code. - // NOTE: This could check for the job kinds instead of the `or_else` but it's not - // necessary as `fetch_script` return early if the job kind is not a preview one. + // `fetch_script` resolves FlowScript / AppScript via their runnable_id; for + // Preview jobs it returns early and we fall through to `fetch_preview_script`. let conn = Connection::from(db.clone()); cache::job::fetch_script(db.clone(), job.job_kind(), hash) .or_else(|_| cache::job::fetch_preview_script(&conn, &id, raw_lock, raw_code)) From bbef5c9dd428c3a5f192b16d45a4592516873431 Mon Sep 17 00:00:00 2001 From: hugocasa Date: Mon, 11 May 2026 16:56:52 +0200 Subject: [PATCH 06/21] ping PR author when auto-review verdict is not good to merge (#9101) * feat(ci): ping PR author when auto-review verdict is not good to merge * fix(ci): drop (unknown) author fallback and clarify verdict-line rule --- .github/workflows/codex-pr-review.yml | 14 ++++++++++++-- .github/workflows/pi-pr-review.yml | 14 ++++++++++++-- .github/workflows/pr-ready-review.yml | 12 ++++++++++-- REVIEW.md | 6 +++++- 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/.github/workflows/codex-pr-review.yml b/.github/workflows/codex-pr-review.yml index e89a58b629..b4916714f2 100644 --- a/.github/workflows/codex-pr-review.yml +++ b/.github/workflows/codex-pr-review.yml @@ -82,10 +82,11 @@ jobs: EVENT_TITLE: ${{ github.event.pull_request.title }} EVENT_BODY: ${{ github.event.pull_request.body }} EVENT_FORK: ${{ github.event.pull_request.head.repo.fork }} + EVENT_AUTHOR: ${{ github.event.pull_request.user.login }} run: | if [ -n "$INPUT_PR_NUMBER" ]; then PR_JSON=$(gh pr view "$INPUT_PR_NUMBER" --repo "${{ github.repository }}" \ - --json number,baseRefName,baseRefOid,headRefOid,title,body,isCrossRepository) + --json number,baseRefName,baseRefOid,headRefOid,title,body,isCrossRepository,author) PR_NUMBER=$(echo "$PR_JSON" | jq -r '.number') BASE_REF=$(echo "$PR_JSON" | jq -r '.baseRefName') BASE_SHA=$(echo "$PR_JSON" | jq -r '.baseRefOid') @@ -93,6 +94,7 @@ jobs: PR_TITLE=$(echo "$PR_JSON" | jq -r '.title') PR_BODY=$(echo "$PR_JSON" | jq -r '.body // ""') IS_FORK=$(echo "$PR_JSON" | jq -r '.isCrossRepository') + PR_AUTHOR=$(echo "$PR_JSON" | jq -r '.author.login // ""') else PR_NUMBER="$EVENT_PR_NUMBER" BASE_REF="$EVENT_BASE_REF" @@ -101,6 +103,7 @@ jobs: PR_TITLE="$EVENT_TITLE" PR_BODY="$EVENT_BODY" IS_FORK="$EVENT_FORK" + PR_AUTHOR="$EVENT_AUTHOR" fi if [ "$IS_FORK" = "true" ]; then echo "Skipping Codex review for fork PR." @@ -113,6 +116,7 @@ jobs: echo "base_ref=$BASE_REF" echo "base_sha=$BASE_SHA" echo "head_sha=$HEAD_SHA" + echo "pr_author=$PR_AUTHOR" echo 'title<> "$GITHUB_OUTPUT" + PR_NUMBER="$INPUT_PR_NUMBER" + PR_AUTHOR=$(gh api "repos/$REPO/pulls/$PR_NUMBER" --jq '.user.login') else - echo "pr_number=$EVENT_PR_NUMBER" >> "$GITHUB_OUTPUT" + PR_NUMBER="$EVENT_PR_NUMBER" + PR_AUTHOR="$EVENT_PR_AUTHOR" fi + echo "pr_number=$PR_NUMBER" >> "$GITHUB_OUTPUT" + echo "pr_author=$PR_AUTHOR" >> "$GITHUB_OUTPUT" - name: Fetch prior PR discussion id: prior @@ -148,6 +155,7 @@ jobs: prompt: | REPO: ${{ github.repository }} PR NUMBER: ${{ steps.resolve.outputs.pr_number }} + PR AUTHOR: ${{ steps.resolve.outputs.pr_author }} ${{ env.REVIEW_PROMPT }} claude_args: | diff --git a/REVIEW.md b/REVIEW.md index de311cccc6..21f5e50f26 100644 --- a/REVIEW.md +++ b/REVIEW.md @@ -9,7 +9,7 @@ You are reviewing a GitHub pull request for this repository. Apply this policy a ## Verdict (first line of the review) -Start every review with a single verdict line, before any other section. Pick exactly one: +Start every review with a single verdict line, before any other section (the only thing that may appear above the verdict is the optional `cc @` ping described in "Pinging the author" below). Pick exactly one: - **Good to merge** — no blocking issues and no nits worth surfacing. - **Mergeable, but should ideally address nits: ** — no blockers, but P2 findings that are worth a look. The list must name each nit briefly (e.g. "doc/code mismatch in `foo.rs`, half-finished `pub fn bar`"). @@ -17,6 +17,10 @@ Start every review with a single verdict line, before any other section. Pick ex The names in the list must match findings detailed later in the review. If you list a nit or issue here, it must appear with full context in the body. Do not invent items that aren't in the body, and do not bury blockers in the body without surfacing them in the verdict. +## Pinging the author + +If the prompt context provides a `PR AUTHOR` (GitHub login) and the verdict is NOT "Good to merge" (i.e. it is "Mergeable, but should ideally address nits: ..." or "Should address issues before merging: ..."), prepend a single line `cc @` to the top-level review comment, above the verdict line. This pings the author so they get a notification that there are items to address. Skip the ping entirely when the verdict is "Good to merge" — there is nothing for the author to act on. Do not add the ping to inline comments; the top-level summary comment is the only place it belongs. + ## Review policy - Only report issues you are confident are real and introduced by this pull request. From 6f7d31e56ba7a1357f0ffeda221b20d4e0cf2b78 Mon Sep 17 00:00:00 2001 From: centdix <40307056+centdix@users.noreply.github.com> Date: Mon, 11 May 2026 16:59:40 +0200 Subject: [PATCH 07/21] refactor: move ai image handling to windmill-ai (#9098) --- backend/Cargo.lock | 4 +++ backend/windmill-ai/Cargo.toml | 4 +++ .../ai => windmill-ai/src}/image_handler.rs | 27 ++++++++++++------- backend/windmill-ai/src/lib.rs | 1 + backend/windmill-worker/src/ai/mod.rs | 1 - .../src/ai/providers/anthropic.rs | 3 +-- .../src/ai/providers/bedrock.rs | 2 +- .../src/ai/providers/google_ai.rs | 3 +-- .../src/ai/providers/openai.rs | 3 +-- .../src/ai/providers/openrouter.rs | 3 ++- .../windmill-worker/src/ai/providers/other.rs | 3 +-- backend/windmill-worker/src/ai_executor.rs | 9 +++---- 12 files changed, 38 insertions(+), 25 deletions(-) rename backend/{windmill-worker/src/ai => windmill-ai/src}/image_handler.rs (86%) diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 842799d5f9..719890fd97 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -16114,8 +16114,11 @@ dependencies = [ "aws-sdk-bedrockruntime", "aws-smithy-types", "base64 0.22.1", + "bytes", "eventsource-stream", + "futures", "lazy_static", + "mime_guess", "reqwest 0.13.1", "serde", "serde_json", @@ -16123,6 +16126,7 @@ dependencies = [ "tokio", "tokio-stream", "tracing", + "ulid", "uuid", "windmill-common", "windmill-mcp", diff --git a/backend/windmill-ai/Cargo.toml b/backend/windmill-ai/Cargo.toml index 3cfea846b9..542c390cc0 100644 --- a/backend/windmill-ai/Cargo.toml +++ b/backend/windmill-ai/Cargo.toml @@ -21,7 +21,10 @@ windmill-mcp = { workspace = true, optional = true } async-trait.workspace = true base64.workspace = true +bytes.workspace = true eventsource-stream.workspace = true +futures.workspace = true +mime_guess.workspace = true reqwest.workspace = true serde.workspace = true serde_json.workspace = true @@ -31,6 +34,7 @@ lazy_static.workspace = true tracing.workspace = true tokio.workspace = true tokio-stream.workspace = true +ulid.workspace = true # Bedrock (optional) aws-config = { workspace = true, optional = true } diff --git a/backend/windmill-worker/src/ai/image_handler.rs b/backend/windmill-ai/src/image_handler.rs similarity index 86% rename from backend/windmill-worker/src/ai/image_handler.rs rename to backend/windmill-ai/src/image_handler.rs index 089d73dc42..5bd9794da5 100644 --- a/backend/windmill-worker/src/ai/image_handler.rs +++ b/backend/windmill-ai/src/image_handler.rs @@ -1,15 +1,18 @@ +use crate::types::*; use base64::Engine; use futures; use ulid; -use windmill_ai::types::*; +use uuid::Uuid; use windmill_common::{client::AuthedClient, error::Error}; -use windmill_queue::MiniPulledJob; use windmill_types::s3::S3Object; -/// Upload image to S3 and return S3Object +/// Upload image to S3 and return S3Object. +/// +/// The caller must provide an AuthedClient authorized for `workspace_id`. pub async fn upload_image_to_s3( base64_image: &str, - job: &MiniPulledJob, + workspace_id: &str, + job_id: &Uuid, client: &AuthedClient, ) -> Result { let image_bytes = base64::engine::general_purpose::STANDARD @@ -18,7 +21,7 @@ pub async fn upload_image_to_s3( // Generate unique S3 key let unique_id = ulid::Ulid::new().to_string(); - let s3_key = format!("ai_images/{}/{}.png", job.id, unique_id); + let s3_key = format!("ai_images/{}/{}.png", job_id, unique_id); // Create byte stream let byte_stream = futures::stream::once(async move { @@ -28,7 +31,7 @@ pub async fn upload_image_to_s3( // Upload to S3 client .upload_s3_file( - &job.workspace_id, + workspace_id, s3_key.clone(), None, // storage - use default byte_stream, @@ -44,7 +47,9 @@ pub async fn upload_image_to_s3( }) } -/// Download an S3 image and convert it to a base64 data URL +/// Download an S3 image and convert it to a base64 data URL. +/// +/// The caller must provide an AuthedClient authorized for `workspace_id`. pub async fn download_and_encode_s3_image( image: &S3Object, client: &AuthedClient, @@ -70,6 +75,8 @@ pub async fn download_and_encode_s3_image( } /// Convert an S3Object to the appropriate ContentPart based on MIME type. +/// +/// The caller must provide an AuthedClient authorized for `workspace_id`. pub async fn s3_object_to_content_part( s3_object: &S3Object, client: &AuthedClient, @@ -79,7 +86,7 @@ pub async fn s3_object_to_content_part( download_and_encode_s3_image(s3_object, client, workspace_id).await?; let data_url = format!("data:{};base64,{}", mime_type, file_bytes); - if windmill_ai::ai_types::is_document_mime(&mime_type) { + if crate::ai_types::is_document_mime(&mime_type) { let filename = s3_object .s3 .rsplit('/') @@ -92,7 +99,9 @@ pub async fn s3_object_to_content_part( } } -/// Prepare messages for API by converting S3Objects to base64 ImageUrls +/// Prepare messages for API by converting S3Objects to base64 ImageUrls. +/// +/// The caller must provide an AuthedClient authorized for `workspace_id`. pub async fn prepare_messages_for_api( messages: &[OpenAIMessage], client: &AuthedClient, diff --git a/backend/windmill-ai/src/lib.rs b/backend/windmill-ai/src/lib.rs index 8b786cb741..945091613b 100644 --- a/backend/windmill-ai/src/lib.rs +++ b/backend/windmill-ai/src/lib.rs @@ -4,6 +4,7 @@ pub mod ai_cache; pub mod ai_google; pub mod ai_providers; pub mod ai_types; +pub mod image_handler; pub mod query_builder; pub mod sse; pub mod types; diff --git a/backend/windmill-worker/src/ai/mod.rs b/backend/windmill-worker/src/ai/mod.rs index 2423fca372..b004b0ec20 100644 --- a/backend/windmill-worker/src/ai/mod.rs +++ b/backend/windmill-worker/src/ai/mod.rs @@ -1,7 +1,6 @@ // AI executor module structure // This module will contain all AI-related execution logic -pub mod image_handler; pub mod providers; pub mod query_builder; pub mod tools; diff --git a/backend/windmill-worker/src/ai/providers/anthropic.rs b/backend/windmill-worker/src/ai/providers/anthropic.rs index f2c310923f..0a3c5df6e4 100644 --- a/backend/windmill-worker/src/ai/providers/anthropic.rs +++ b/backend/windmill-worker/src/ai/providers/anthropic.rs @@ -4,6 +4,7 @@ use serde_json::value::RawValue; use windmill_ai::{ ai_google::parse_data_url, ai_providers::AIProvider, + image_handler::prepare_messages_for_api, query_builder::{BuildRequestArgs, ParsedResponse, QueryBuilder, StreamEventSink}, sse::{AnthropicSSEParser, SSEParser}, types::*, @@ -11,8 +12,6 @@ use windmill_ai::{ }; use windmill_common::{client::AuthedClient, error::Error}; -use crate::ai::image_handler::prepare_messages_for_api; - /// Anthropic API version for standard API const ANTHROPIC_VERSION_STANDARD: &str = "2023-06-01"; /// Anthropic API version for Google Vertex AI diff --git a/backend/windmill-worker/src/ai/providers/bedrock.rs b/backend/windmill-worker/src/ai/providers/bedrock.rs index ec499f5fcd..8c37433cab 100644 --- a/backend/windmill-worker/src/ai/providers/bedrock.rs +++ b/backend/windmill-worker/src/ai/providers/bedrock.rs @@ -6,9 +6,9 @@ //! - Stream event parsing //! - Helper utilities -use crate::ai::image_handler::prepare_messages_for_api; use std::collections::HashMap; use windmill_ai::{ + image_handler::prepare_messages_for_api, query_builder::{ParsedResponse, StreamEventSink}, types::{OpenAIMessage, StreamingEvent, TokenUsage, ToolDef}, }; diff --git a/backend/windmill-worker/src/ai/providers/google_ai.rs b/backend/windmill-worker/src/ai/providers/google_ai.rs index 2a00011de7..19c50d06de 100644 --- a/backend/windmill-worker/src/ai/providers/google_ai.rs +++ b/backend/windmill-worker/src/ai/providers/google_ai.rs @@ -5,14 +5,13 @@ use windmill_ai::{ GeminiImageContent, GeminiImageRequest, GeminiImageResponse, GeminiInlineData, GeminiPart, GeminiPredictContent, GeminiTextRequest, GeminiTool, }, + image_handler::{download_and_encode_s3_image, prepare_messages_for_api}, query_builder::{BuildRequestArgs, ParsedResponse, QueryBuilder, StreamEventSink}, sse::{GeminiSSEParser, SSEParser}, types::*, }; use windmill_common::{client::AuthedClient, error::Error}; -use crate::ai::image_handler::{download_and_encode_s3_image, prepare_messages_for_api}; - // ============================================================================ // Query Builder Implementation // ============================================================================ diff --git a/backend/windmill-worker/src/ai/providers/openai.rs b/backend/windmill-worker/src/ai/providers/openai.rs index 691f8fd5e3..e0767d5dda 100644 --- a/backend/windmill-worker/src/ai/providers/openai.rs +++ b/backend/windmill-worker/src/ai/providers/openai.rs @@ -4,6 +4,7 @@ use serde_json::value::RawValue; use windmill_ai::{ ai_providers::AIProvider, ai_types::OpenAIToolCall, + image_handler::{prepare_messages_for_api, s3_object_to_content_part}, query_builder::{BuildRequestArgs, ParsedResponse, QueryBuilder, StreamEventSink}, sse::{OpenAIResponsesSSEParser, SSEParser}, types::*, @@ -11,8 +12,6 @@ use windmill_ai::{ }; use windmill_common::{client::AuthedClient, error::Error}; -use crate::ai::image_handler::{prepare_messages_for_api, s3_object_to_content_part}; - // Responses API structures #[derive(Deserialize)] #[allow(dead_code)] diff --git a/backend/windmill-worker/src/ai/providers/openrouter.rs b/backend/windmill-worker/src/ai/providers/openrouter.rs index 9bfc47ed8f..ede541cd13 100644 --- a/backend/windmill-worker/src/ai/providers/openrouter.rs +++ b/backend/windmill-worker/src/ai/providers/openrouter.rs @@ -3,12 +3,13 @@ use serde::{Deserialize, Serialize}; use serde_json; use windmill_ai::{ ai_providers::AIProvider, + image_handler::prepare_messages_for_api, query_builder::{BuildRequestArgs, ParsedResponse, QueryBuilder, StreamEventSink}, types::*, }; use windmill_common::{client::AuthedClient, error::Error}; -use crate::ai::{image_handler::prepare_messages_for_api, providers::other::OtherQueryBuilder}; +use crate::ai::providers::other::OtherQueryBuilder; // OpenRouter-specific types #[derive(Serialize)] diff --git a/backend/windmill-worker/src/ai/providers/other.rs b/backend/windmill-worker/src/ai/providers/other.rs index 7982dc739d..a840517133 100644 --- a/backend/windmill-worker/src/ai/providers/other.rs +++ b/backend/windmill-worker/src/ai/providers/other.rs @@ -3,6 +3,7 @@ use serde::Serialize; use serde_json; use windmill_ai::{ ai_providers::AIProvider, + image_handler::prepare_messages_for_api, query_builder::{BuildRequestArgs, ParsedResponse, QueryBuilder, StreamEventSink}, sse::{OpenAISSEParser, SSEParser}, types::*, @@ -10,8 +11,6 @@ use windmill_ai::{ }; use windmill_common::{client::AuthedClient, error::Error}; -use crate::ai::image_handler::prepare_messages_for_api; - #[derive(Serialize, Debug, Clone)] #[serde(rename_all = "lowercase")] pub enum ToolChoice { diff --git a/backend/windmill-worker/src/ai_executor.rs b/backend/windmill-worker/src/ai_executor.rs index 4dfeee3571..cdf2995f9c 100644 --- a/backend/windmill-worker/src/ai_executor.rs +++ b/backend/windmill-worker/src/ai_executor.rs @@ -22,6 +22,7 @@ use windmill_mcp::McpClient; use crate::ai::tools::McpClientStub as McpClient; use windmill_ai::{ ai_providers::AIProvider, + image_handler::upload_image_to_s3, query_builder::{BuildRequestArgs, ParsedResponse}, types::*, utils::{should_use_structured_output_tool, AI_HTTP_HEADERS}, @@ -43,10 +44,7 @@ use windmill_common::{ use windmill_queue::{cancel_single_job, CanceledBy, MiniPulledJob}; use crate::{ - ai::{ - image_handler::upload_image_to_s3, - query_builder::{create_query_builder, StreamEventProcessor}, - }, + ai::query_builder::{create_query_builder, StreamEventProcessor}, common::{build_args_map, resolve_job_timeout, OccupancyMetrics, StreamNotifier}, handle_child::{run_future_with_polling_update_job_poller_graceful, GracefulPollOutcome}, }; @@ -1206,7 +1204,8 @@ pub async fn run_agent( } ParsedResponse::Image { base64_data } => { // For image output, upload to S3 and track in conversation - let s3_object = upload_image_to_s3(&base64_data, job, client).await?; + let s3_object = + upload_image_to_s3(&base64_data, &job.workspace_id, &job.id, client).await?; let content = to_raw_value(&s3_object); From 03e8bc8c14258355d7d695333c1588807fbf8cd6 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Mon, 11 May 2026 17:20:46 +0000 Subject: [PATCH 08/21] perf: lazy-load script editor history and hit partial index (#9107) --- .../src/lib/components/ScriptEditor.svelte | 36 ++++++++++++++++--- .../components/scriptEditor/LogPanel.svelte | 8 ++++- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/frontend/src/lib/components/ScriptEditor.svelte b/frontend/src/lib/components/ScriptEditor.svelte index 16f835fcdd..646cbc0477 100644 --- a/frontend/src/lib/components/ScriptEditor.svelte +++ b/frontend/src/lib/components/ScriptEditor.svelte @@ -561,6 +561,8 @@ let testIsLoading = $state(false) let testJob: Job | undefined = $state() let pastPreviews: CompletedJob[] = $state([]) + let historyTabActive = false + let pastPreviewsRequest: ReturnType | undefined let validCode = $state(true) // Recording @@ -691,7 +693,9 @@ lastRecording = scriptRecording.stop() setActiveRecording(undefined) } - loadPastTests() + if (historyTabActive) { + loadPastTests() + } }, doneError({ error }) { if (scriptRecording.active) { @@ -722,12 +726,29 @@ } async function loadPastTests(): Promise { - pastPreviews = await JobService.listCompletedJobs({ + pastPreviewsRequest?.cancel() + const req = JobService.listCompletedJobs({ workspace: $workspaceStore!, jobKinds: 'preview', createdBy: $userStore?.username, - scriptPathExact: path + scriptPathExact: path, + hasNullParent: true }) + pastPreviewsRequest = req + try { + const result = await req + if (pastPreviewsRequest === req) { + pastPreviews = result + } + } catch (err) { + if (!(err instanceof Error) || err.name !== 'CancelError') { + throw err + } + } finally { + if (pastPreviewsRequest === req) { + pastPreviewsRequest = undefined + } + } } export async function inferSchema( @@ -1128,7 +1149,6 @@ if (!validCode && code && lang) { await inferSchema(code, { applyInitialArgs: true }) } - loadPastTests() aiChatManager.saveAndClear() aiChatManager.changeMode(AIMode.SCRIPT) }) @@ -1209,6 +1229,8 @@ } onDestroy(() => { + pastPreviewsRequest?.cancel() + pastPreviewsRequest = undefined disableCollaboration() aiChatManager.scriptEditorApplyCode = undefined aiChatManager.scriptEditorShowDiffMode = undefined @@ -1676,6 +1698,12 @@ } as any) : testJob} {pastPreviews} + onTabChange={(tab) => { + historyTabActive = tab === 'history' + if (historyTabActive) { + loadPastTests() + } + }} previewIsLoading={debugMode ? $debugState.running && !$debugState.stopped : testIsLoading} diff --git a/frontend/src/lib/components/scriptEditor/LogPanel.svelte b/frontend/src/lib/components/scriptEditor/LogPanel.svelte index 82845c4a88..1f31d7f12d 100644 --- a/frontend/src/lib/components/scriptEditor/LogPanel.svelte +++ b/frontend/src/lib/components/scriptEditor/LogPanel.svelte @@ -49,6 +49,7 @@ capturesTab?: import('svelte').Snippet customResultPanel?: import('svelte').Snippet showCustomResultPanel?: boolean + onTabChange?: (tab: string) => void } let { @@ -65,7 +66,8 @@ children, capturesTab, customResultPanel, - showCustomResultPanel = false + showCustomResultPanel = false, + onTabChange }: Props = $props() type DContent = { @@ -78,6 +80,10 @@ let drawerOpen: boolean = $state(false) let drawerContent: DContent | undefined = $state(undefined) + $effect(() => { + onTabChange?.(selectedTab) + }) + export function setFocusToLogs() { selectedTab = 'logs' } From 20ecd904e7060c3cf90f2605740bb349b2a3e6ed Mon Sep 17 00:00:00 2001 From: Diego Imbert <70353967+diegoimbert@users.noreply.github.com> Date: Mon, 11 May 2026 20:36:34 +0200 Subject: [PATCH 09/21] feat(operators): allow operators to access assets page (#9095) * feat(operators): allow operators to access assets page Adds the "assets" key to workspace operator_settings (defaulting to true for existing and new workspaces) and toggles the frontend default so the assets page is visible to operators by default. Co-Authored-By: Claude Opus 4.7 (1M context) * nit: remove settings btn when not available --------- Co-authored-by: Claude Opus 4.7 (1M context) --- ...5_add_assets_to_operator_settings.down.sql | 19 +++++++++++++ ...225_add_assets_to_operator_settings.up.sql | 21 ++++++++++++++ .../settings/WorkspaceOperatorSettings.svelte | 2 +- .../components/sidebar/SidebarContent.svelte | 1 - .../(root)/(logged)/assets/+page.svelte | 28 ++++++++++++------- 5 files changed, 59 insertions(+), 12 deletions(-) create mode 100644 backend/migrations/20260511075225_add_assets_to_operator_settings.down.sql create mode 100644 backend/migrations/20260511075225_add_assets_to_operator_settings.up.sql diff --git a/backend/migrations/20260511075225_add_assets_to_operator_settings.down.sql b/backend/migrations/20260511075225_add_assets_to_operator_settings.down.sql new file mode 100644 index 0000000000..c38c2a1e42 --- /dev/null +++ b/backend/migrations/20260511075225_add_assets_to_operator_settings.down.sql @@ -0,0 +1,19 @@ +-- Remove "assets" key from operator_settings +UPDATE workspace_settings +SET operator_settings = operator_settings - 'assets' +WHERE operator_settings IS NOT NULL + AND operator_settings ? 'assets'; + +-- Revert the column default +ALTER TABLE workspace_settings +ALTER COLUMN operator_settings SET DEFAULT '{ + "runs": true, + "groups": true, + "folders": true, + "workers": true, + "triggers": true, + "resources": true, + "schedules": true, + "variables": true, + "audit_logs": true +}'; diff --git a/backend/migrations/20260511075225_add_assets_to_operator_settings.up.sql b/backend/migrations/20260511075225_add_assets_to_operator_settings.up.sql new file mode 100644 index 0000000000..96aba860ec --- /dev/null +++ b/backend/migrations/20260511075225_add_assets_to_operator_settings.up.sql @@ -0,0 +1,21 @@ +-- Add "assets": true to operator_settings for all workspaces that have operator_settings +-- but don't already have an "assets" key +UPDATE workspace_settings +SET operator_settings = operator_settings || '{"assets": true}'::jsonb +WHERE operator_settings IS NOT NULL + AND NOT operator_settings ? 'assets'; + +-- Update the column default to include assets +ALTER TABLE workspace_settings +ALTER COLUMN operator_settings SET DEFAULT '{ + "runs": true, + "groups": true, + "folders": true, + "workers": true, + "triggers": true, + "resources": true, + "schedules": true, + "variables": true, + "audit_logs": true, + "assets": true +}'; diff --git a/frontend/src/lib/components/settings/WorkspaceOperatorSettings.svelte b/frontend/src/lib/components/settings/WorkspaceOperatorSettings.svelte index 6aaa69cc53..ba8f42cba7 100644 --- a/frontend/src/lib/components/settings/WorkspaceOperatorSettings.svelte +++ b/frontend/src/lib/components/settings/WorkspaceOperatorSettings.svelte @@ -17,7 +17,7 @@ schedules: true, resources: true, variables: true, - assets: false, + assets: true, triggers: true, audit_logs: true, groups: true, diff --git a/frontend/src/lib/components/sidebar/SidebarContent.svelte b/frontend/src/lib/components/sidebar/SidebarContent.svelte index c2a790264a..f95d242657 100644 --- a/frontend/src/lib/components/sidebar/SidebarContent.svelte +++ b/frontend/src/lib/components/sidebar/SidebarContent.svelte @@ -303,7 +303,6 @@ label: 'Assets', href: `${base}/assets`, icon: Pyramid, - disabled: $userStore?.operator, aiId: 'sidebar-menu-link-assets', aiDescription: 'Button to navigate to assets' }, diff --git a/frontend/src/routes/(root)/(logged)/assets/+page.svelte b/frontend/src/routes/(root)/(logged)/assets/+page.svelte index 50ed6f041b..2873140fea 100644 --- a/frontend/src/routes/(root)/(logged)/assets/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/assets/+page.svelte @@ -12,7 +12,13 @@ type AssetKind, type ListAssetsResponse } from '$lib/gen' - import { userStore, workspaceStore, userWorkspaces, globalDbManagerDrawer } from '$lib/stores' + import { + userStore, + workspaceStore, + userWorkspaces, + globalDbManagerDrawer, + superadmin + } from '$lib/stores' import { parseDbInputFromAssetSyntax, pluralize, truncate } from '$lib/utils' import ExploreAssetButton, { assetCanBeExplored @@ -182,15 +188,17 @@ > See documentation -
{#if props.data.current?.length} From 1e89aff2d67cfc1375c3d48b4f33f5517f8d01b6 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Mon, 11 May 2026 18:43:54 +0000 Subject: [PATCH 10/21] test(nativets): add #[ignore]'d smoke suite for deno_core / deno_ast / swc bumps (#9108) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds ten `#[ignore]`'d integration tests in backend/windmill-runtime-nativets/src/smoke_tests.rs exercising the JS API surface that the existing nativets tests in tests/worker.rs don't reach. Run them when bumping the deno_core / deno_ast / deno_runtime / swc_* pins in backend/Cargo.toml, not on every CI: cargo test -p windmill-runtime-nativets smoke -- --ignored # skip network-dependent ones with `--skip smoke_net_` Why here and not in tests/worker.rs: windmill-runtime-nativets is the only consumer of the deno_core crate in the workspace — ScriptLang::Deno spawns the external `deno` binary via deno_executor.rs, while ScriptLang::Nativets is the only path that loads the in-process V8 runtime. So a deno_core / deno_ast bump can only break things downstream of this crate. Co-locating the smoke tests with the runtime they exercise means they hit the right surface directly, skip the entire job-queue / worker / API-server stack, and run in <1s end-to-end (vs. ~30-60s per test for the worker-level nativets tests). The tests use the existing `PrewarmedIsolate::spawn` API (already public for the dedicated-worker path), which gives a clean "compile-TS → load module → execute main(args) → return JSON" entry point with no DB or queue plumbing required. Coverage: - smoke_basic_value_passing — args binding + return marshaling - smoke_transpile_enum_and_union — TS-specific syntax (enums, discriminated unions, casts) through swc_ecma_parser / swc_ecma_ast - smoke_set_timeout_and_promise_all — deno_web timer ops + V8 microtask drain order - smoke_url_and_searchparams — deno_url surface - smoke_web_blob_btoa_atob — deno_web Blob + base64 ops - smoke_large_payload_roundtrip — 512 KB string in/out through the op-table boundary - smoke_error_propagation_with_message — thrown Error must surface in PrewarmedResult::Err with original message - smoke_concurrent_isolates — 8 isolates spawned in parallel from the same tokio runtime; catches V8 isolate-setup races - smoke_net_fetch_example_com — deno_fetch end-to-end against example.com - smoke_net_fetch_json_and_headers — deno_fetch with custom request headers + Response.json() against httpbin.org/anything `structuredClone` is not currently wired into the nativets global — documented in the smoke_web_blob_btoa_atob test in case that ever changes. All ten tests pass locally against the current pinned versions (deno_core 0.336.0 / deno_ast =0.44.0 / swc_common =0.37.5). --- backend/windmill-runtime-nativets/src/lib.rs | 3 + .../src/smoke_tests.rs | 280 ++++++++++++++++++ 2 files changed, 283 insertions(+) create mode 100644 backend/windmill-runtime-nativets/src/smoke_tests.rs diff --git a/backend/windmill-runtime-nativets/src/lib.rs b/backend/windmill-runtime-nativets/src/lib.rs index dda57ae708..83de806716 100644 --- a/backend/windmill-runtime-nativets/src/lib.rs +++ b/backend/windmill-runtime-nativets/src/lib.rs @@ -15,6 +15,9 @@ mod dedicated; pub use dedicated::{ExecutingIsolate, PrewarmedIsolate, PrewarmedResult}; +#[cfg(test)] +mod smoke_tests; + use std::{ borrow::Cow, cell::RefCell, diff --git a/backend/windmill-runtime-nativets/src/smoke_tests.rs b/backend/windmill-runtime-nativets/src/smoke_tests.rs new file mode 100644 index 0000000000..20675ee2a7 --- /dev/null +++ b/backend/windmill-runtime-nativets/src/smoke_tests.rs @@ -0,0 +1,280 @@ +//! Opt-in smoke tests for the nativets V8 runtime. +//! +//! Exercise the deno_core / deno_ast / swc surface (TypeScript transpile, +//! fetch, timers, URL, structuredClone, error propagation, concurrent +//! isolates, large payload roundtrip) that the standard worker-level +//! nativets tests in `backend/tests/worker.rs` don't reach — those tests +//! validate value passing through the job queue, but not the JS API +//! surface a deno_core bump would actually move. +//! +//! These tests are `#[ignore]`'d so the regular `cargo test` flow doesn't +//! pay their cost (each spawns a V8 isolate; some hit the network). Run +//! when changing the `deno_core` / `deno_ast` / `deno_runtime` / `swc_*` +//! pins in `backend/Cargo.toml`: +//! +//! cargo test -p windmill-runtime-nativets smoke -- --ignored +//! +//! Tests prefixed `smoke_net_` hit the public internet (httpbin.org, +//! example.com) and will fail if the runner has no egress. Skip them +//! locally with `cargo test -p windmill-runtime-nativets smoke -- --ignored --skip smoke_net_`. + +use crate::{transpile_ts, NativeAnnotation, PrewarmedIsolate, PrewarmedResult}; + +/// Compile a TS snippet, run it through a fresh isolate with the given +/// positional args, and return the isolate's result + captured logs. +async fn run_ts(ts: &str, arg_names: &[&str], args: serde_json::Value) -> PrewarmedResult { + let js = transpile_ts(ts.to_string()).expect("transpile_ts failed"); + let ann = NativeAnnotation { useragent: None, proxy: None }; + let arg_names: Vec = arg_names.iter().map(|s| s.to_string()).collect(); + let mut iso = PrewarmedIsolate::spawn(String::new(), js, ann, arg_names, None); + iso.wait_ready().await.expect("isolate failed to pre-warm"); + iso.start_execution(args.to_string()) + .wait() + .await + .expect("isolate execution panicked") +} + +fn unwrap_value(r: &PrewarmedResult) -> serde_json::Value { + let raw = r.result.as_ref().expect("script returned an error"); + serde_json::from_str(raw.get()).expect("result not valid JSON") +} + +// ----------------------------------------------------------------------------- +// Local (no network) — these still need V8 / deno_core ops to be wired. +// ----------------------------------------------------------------------------- + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +#[ignore = "deno_core upgrade smoke; run with --ignored"] +async fn smoke_basic_value_passing() { + let ts = r#" +export async function main(x: number): Promise { + return x + 1; +} +"#; + let r = run_ts(ts, &["x"], serde_json::json!({"x": 41})).await; + assert_eq!(unwrap_value(&r), serde_json::json!(42)); +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +#[ignore = "deno_core upgrade smoke; run with --ignored"] +async fn smoke_transpile_enum_and_union() { + // Enums + discriminated union + as-cast exercise the swc_ecma_ast + + // swc_ecma_parser TS-syntax paths the bare value tests don't. + let ts = r#" +enum Direction { Up = "U", Down = "D" } +type Msg = { kind: "move"; dir: Direction } | { kind: "stop" }; +export async function main(): Promise { + const msgs: Msg[] = [ + { kind: "move", dir: Direction.Up }, + { kind: "stop" }, + { kind: "move", dir: Direction.Down }, + ]; + return msgs.map(m => m.kind === "move" ? m.dir : "_").join(","); +} +"#; + let r = run_ts(ts, &[], serde_json::json!({})).await; + assert_eq!(unwrap_value(&r), serde_json::json!("U,_,D")); +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +#[ignore = "deno_core upgrade smoke; run with --ignored"] +async fn smoke_set_timeout_and_promise_all() { + // setTimeout lives in deno_web; Promise.all hits the V8 microtask + // queue. A bump that breaks timer-op registration or microtask drain + // would surface here (script would hang or return wrong order). + let ts = r#" +export async function main(): Promise { + const delays = [40, 10, 20, 30]; + return await Promise.all(delays.map(d => + new Promise(resolve => setTimeout(() => resolve(d), d)) + )); +} +"#; + let r = run_ts(ts, &[], serde_json::json!({})).await; + // Promise.all preserves input order regardless of resolution order. + assert_eq!(unwrap_value(&r), serde_json::json!([40, 10, 20, 30])); +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +#[ignore = "deno_core upgrade smoke; run with --ignored"] +async fn smoke_url_and_searchparams() { + // deno_url surface: URL ctor, URLSearchParams parsing + iteration. + let ts = r#" +export async function main(): Promise<{ host: string; pairs: [string, string][] }> { + const u = new URL("https://example.com:8443/path?b=2&a=1&a=3"); + const pairs: [string, string][] = []; + for (const [k, v] of u.searchParams) pairs.push([k, v]); + return { host: u.host, pairs }; +} +"#; + let r = run_ts(ts, &[], serde_json::json!({})).await; + assert_eq!( + unwrap_value(&r), + serde_json::json!({ + "host": "example.com:8443", + "pairs": [["b", "2"], ["a", "1"], ["a", "3"]], + }), + ); +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +#[ignore = "deno_core upgrade smoke; run with --ignored"] +async fn smoke_web_blob_btoa_atob() { + // deno_web surface: Blob, atob/btoa. `structuredClone` is *not* wired + // into the nativets global (the deno_web binding doesn't expose it + // here) — if that's ever changed, extend this test to cover it. + let ts = r#" +export async function main(): Promise<{ b64: string; round_trip: string; size: number }> { + const blob = new Blob(["hello"], { type: "text/plain" }); + const b64 = btoa("hello"); + const round_trip = atob(b64); + return { b64, round_trip, size: blob.size }; +} +"#; + let r = run_ts(ts, &[], serde_json::json!({})).await; + assert_eq!( + unwrap_value(&r), + serde_json::json!({ + "b64": "aGVsbG8=", + "round_trip": "hello", + "size": 5, + }), + ); +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +#[ignore = "deno_core upgrade smoke; run with --ignored"] +async fn smoke_large_payload_roundtrip() { + // ~512 KB string in and out — exercises arg encoding + result + // serialization through the deno_core <-> host op boundary at sizes + // an op-table change could break. + let big_in: String = "a".repeat(512 * 1024); + let ts = r#" +export async function main(s: string): Promise<{ in_len: number; out: string }> { + if (typeof s !== "string") throw new Error(`expected string, got ${typeof s}`); + return { in_len: s.length, out: "b".repeat(512 * 1024) }; +} +"#; + let r = run_ts(ts, &["s"], serde_json::json!({"s": big_in})).await; + let v = unwrap_value(&r); + assert_eq!(v.get("in_len").and_then(|x| x.as_u64()), Some(512 * 1024)); + let out_len = v + .get("out") + .and_then(|x| x.as_str()) + .map(|s| s.len()) + .unwrap_or(0); + assert_eq!(out_len, 512 * 1024); +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +#[ignore = "deno_core upgrade smoke; run with --ignored"] +async fn smoke_error_propagation_with_message() { + // Throwing a typed Error must surface as PrewarmedResult::Err with + // the original message. A deno_core bump that changes the host-side + // error wrapping would lose this contract. + let ts = r#" +export async function main(): Promise { + throw new Error("nativets_smoke_marker_xyz"); +} +"#; + let r = run_ts(ts, &[], serde_json::json!({})).await; + let err = r.result.expect_err("expected script to fail"); + assert!( + err.contains("nativets_smoke_marker_xyz"), + "thrown error message did not reach result: {err}", + ); +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[ignore = "deno_core upgrade smoke; run with --ignored"] +async fn smoke_concurrent_isolates() { + // Spawn N isolates in parallel from the same tokio runtime. Each + // PrewarmedIsolate uses spawn_blocking + a fresh V8 isolate. + // Catches isolate-setup races (V8_ISOLATE_CREATE_LOCK ordering) and + // any per-isolate state that a deno_core bump could break under + // concurrency. + let ts = r#" +export async function main(i: number): Promise { + return i * 10; +} +"#; + let js = transpile_ts(ts.to_string()).expect("transpile_ts failed"); + + const N: i64 = 8; + let mut handles = Vec::with_capacity(N as usize); + for i in 0..N { + let js = js.clone(); + let h = tokio::spawn(async move { + let ann = NativeAnnotation { useragent: None, proxy: None }; + let mut iso = + PrewarmedIsolate::spawn(String::new(), js, ann, vec!["i".to_string()], None); + iso.wait_ready().await.expect("pre-warm failed"); + let res = iso + .start_execution(serde_json::json!({"i": i}).to_string()) + .wait() + .await + .expect("isolate panicked"); + res.result.expect("script errored") + }); + handles.push(h); + } + + let mut got: Vec = Vec::with_capacity(N as usize); + for h in handles { + let raw = h.await.expect("join failed"); + let v: serde_json::Value = serde_json::from_str(raw.get()).expect("not JSON"); + got.push(v.as_i64().unwrap_or(-1)); + } + got.sort(); + let expected: Vec = (0..N).map(|i| i * 10).collect(); + assert_eq!(got, expected); +} + +// ----------------------------------------------------------------------------- +// Network — actually exercise deno_fetch end-to-end. Skip in air-gapped CI +// with `--skip smoke_net_`. +// ----------------------------------------------------------------------------- + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +#[ignore = "deno_core upgrade smoke (network); run with --ignored"] +async fn smoke_net_fetch_example_com() { + // example.com is one of the most stable hosts on the internet and + // returns a tiny known-text body, so we can both assert "fetch works" + // and "the response body parses correctly through deno_fetch". + let ts = r#" +export async function main(): Promise<{ status: number; has_marker: boolean }> { + const r = await fetch("https://example.com/"); + const body = await r.text(); + return { status: r.status, has_marker: body.includes("Example Domain") }; +} +"#; + let r = run_ts(ts, &[], serde_json::json!({})).await; + let v = unwrap_value(&r); + assert_eq!(v.get("status").and_then(|x| x.as_u64()), Some(200)); + assert_eq!(v.get("has_marker"), Some(&serde_json::json!(true))); +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +#[ignore = "deno_core upgrade smoke (network); run with --ignored"] +async fn smoke_net_fetch_json_and_headers() { + // httpbin.org/anything echoes request metadata back as JSON, so we + // can verify: deno_fetch sends custom headers, parses JSON response, + // and propagates query params end-to-end. + let ts = r#" +export async function main(): Promise<{ ua: string; arg: string }> { + const r = await fetch("https://httpbin.org/anything?nativets=ok", { + headers: { "x-windmill-smoke": "1" }, + }); + if (!r.ok) throw new Error(`status ${r.status}`); + const j: any = await r.json(); + return { + ua: j.headers["X-Windmill-Smoke"] ?? "", + arg: j.args.nativets ?? "", + }; +} +"#; + let r = run_ts(ts, &[], serde_json::json!({})).await; + let v = unwrap_value(&r); + assert_eq!(v.get("ua").and_then(|x| x.as_str()), Some("1")); + assert_eq!(v.get("arg").and_then(|x| x.as_str()), Some("ok")); +} From 9f79a86a686708f66ccc512d4f132cb9a00397a7 Mon Sep 17 00:00:00 2001 From: brone1323 <59184559+brone1323@users.noreply.github.com> Date: Mon, 11 May 2026 13:51:49 -0600 Subject: [PATCH 11/21] fix: add Input, Result, Trigger to reserved flow step IDs (#9109) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Renaming a flow step to 'Input', 'Result', or 'Trigger' would silently corrupt the UI — the flow editor panel would switch to rendering the special Input/Result/Trigger node instead of the step's config panel, making the step inaccessible without editing YAML directly. These virtual node IDs were already handled as reserved by multiSelectUtils.ts but were missing from the forbiddenIds list that drives the IdEditorInput validation, so users got no warning. Fixes #7139 --- frontend/src/lib/components/flows/idUtils.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/src/lib/components/flows/idUtils.ts b/frontend/src/lib/components/flows/idUtils.ts index bb82c278a1..db3e496c54 100644 --- a/frontend/src/lib/components/flows/idUtils.ts +++ b/frontend/src/lib/components/flows/idUtils.ts @@ -14,7 +14,10 @@ export const forbiddenIds: string[] = [ 'in', 'failure', 'preprocessor', - 'as' + 'as', + 'Input', + 'Result', + 'Trigger' ] export function numberToChars(n: number) { From 36b316d9e848166e8ea01e7686f496873bb77594 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Mon, 11 May 2026 20:21:46 +0000 Subject: [PATCH 12/21] deps(nativets): inline maybe_transpile_source, drop deno_runtime (#9110) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit windmill-runtime-nativets was the workspace's only consumer of the deno_runtime crate, and its only use of it was one call site in build.rs: deno_runtime::transpile::maybe_transpile_source(specifier, source) That function (`deno_runtime-0.198.0/transpile.rs`, ~80 lines) is a pure deno_ast + deno_core + deno_error wrapper — it doesn't touch any deno_runtime state. Inline it verbatim into our build.rs and drop the entire deno_runtime dep. Why this matters now: deno_runtime transitively pulls in deno_cache → rusqlite → libsqlite3-sys. From deno_cache 0.128.0 (Feb-Mar 2025) onwards, rusqlite was bumped to ^0.34, which means libsqlite3-sys ^0.35. sqlx 0.8 transitively requires libsqlite3-sys ^0.30. Cargo's `links = "sqlite3"` rule allows only one libsqlite3-sys in a build graph, so the two crates collide on any deno release ≥ v2.5. Inlining the transpile helper sidesteps the collision entirely — sqlx-sqlite stays the sole libsqlite3-sys consumer at 0.30.1. All other appearances of "deno_runtime" in the source tree are for a Windmill-internal function named `setup_deno_runtime`, not the crate. Build artifacts validated: - `cargo check --features quickjs` → green. - `cargo test -p windmill-runtime-nativets smoke -- --ignored --skip smoke_net_` → 8 passed (the in-process V8 runtime + deno_fetch + deno_web + swc transpilation surface still works end-to-end through the inlined function). - `cargo tree --invert deno_cache` → "did not match any packages" (gone from the graph). - Single `libsqlite3-sys` entry in Cargo.lock at 0.30.1 (sqlx's). --- backend/Cargo.lock | 2333 +----------------- backend/Cargo.toml | 1 - backend/windmill-runtime-nativets/Cargo.toml | 3 +- backend/windmill-runtime-nativets/build.rs | 73 +- 4 files changed, 127 insertions(+), 2283 deletions(-) diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 719890fd97..c5a26d1b45 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -43,20 +43,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "aead-gcm-stream" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70c8dec860340effb00f6945c49c0daaa6dac963602750db862eabb74bf7886" -dependencies = [ - "aead", - "aes 0.8.3", - "cipher 0.4.4", - "ctr", - "ghash", - "subtle", -] - [[package]] name = "aes" version = "0.7.5" @@ -94,15 +80,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "aes-kw" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69fa2b352dcefb5f7f3a5fb840e02665d311d878955380515e4fd50095dd3d8c" -dependencies = [ - "aes 0.8.3", -] - [[package]] name = "ahash" version = "0.7.8" @@ -279,9 +256,6 @@ name = "arrayvec" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" -dependencies = [ - "serde", -] [[package]] name = "arrow" @@ -493,59 +467,22 @@ dependencies = [ "regex-syntax 0.8.10", ] -[[package]] -name = "ash" -version = "0.37.3+1.3.251" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e9c3835d686b0a6084ab4234fcd1b07dbf6e4767dce60874b12356a25ecd4a" -dependencies = [ - "libloading 0.7.4", -] - -[[package]] -name = "asn1-rs" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" -dependencies = [ - "asn1-rs-derive 0.4.0", - "asn1-rs-impl 0.1.0", - "displaydoc", - "nom 7.1.3", - "num-traits", - "rusticata-macros", - "thiserror 1.0.69", - "time", -] - [[package]] name = "asn1-rs" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" dependencies = [ - "asn1-rs-derive 0.5.1", - "asn1-rs-impl 0.2.0", + "asn1-rs-derive", + "asn1-rs-impl", "displaydoc", - "nom 7.1.3", + "nom", "num-traits", "rusticata-macros", "thiserror 1.0.69", "time", ] -[[package]] -name = "asn1-rs-derive" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "synstructure 0.12.6", -] - [[package]] name = "asn1-rs-derive" version = "0.5.1" @@ -555,18 +492,7 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.117", - "synstructure 0.13.2", -] - -[[package]] -name = "asn1-rs-impl" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "synstructure", ] [[package]] @@ -1759,19 +1685,13 @@ dependencies = [ "cpufeatures 0.3.0", ] -[[package]] -name = "block" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" - [[package]] name = "block-buffer" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "block-padding 0.2.1", + "block-padding", "generic-array", ] @@ -1799,7 +1719,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2cb03d1bed155d89dce0f845b7899b18a9a163e148fd004e1c28421a783e2d8e" dependencies = [ - "block-padding 0.2.1", + "block-padding", "cipher 0.3.0", ] @@ -1809,15 +1729,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" -[[package]] -name = "block-padding" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" -dependencies = [ - "generic-array", -] - [[package]] name = "bollard" version = "0.18.1" @@ -1895,7 +1806,7 @@ checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" dependencies = [ "borsh-derive", "bytes", - "cfg_aliases 0.2.1", + "cfg_aliases", ] [[package]] @@ -1921,17 +1832,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "brotli" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor 4.0.3", -] - [[package]] name = "brotli" version = "7.0.0" @@ -2107,12 +2007,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "cache_control" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf2a5fb3207c12b5d208ebc145f967fea5cac41a021c37417ccc31ba40f39ee" - [[package]] name = "candle-core" version = "0.9.2" @@ -2124,7 +2018,7 @@ dependencies = [ "gemm", "half", "libm", - "memmap2 0.9.10", + "memmap2", "num-traits", "num_cpus", "rand 0.9.0", @@ -2132,7 +2026,7 @@ dependencies = [ "rayon", "safetensors", "thiserror 2.0.18", - "yoke 0.8.2", + "yoke", "zip", ] @@ -2187,8 +2081,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f2d24a6dcf0cd402a21b65d35340f3a49ff3475dc5fdac91d22d2733e6641c6" dependencies = [ "capacity_builder_macros", - "ecow", - "hipstr", "itoa", ] @@ -2202,15 +2094,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "cbc" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" -dependencies = [ - "cipher 0.4.4", -] - [[package]] name = "cc" version = "1.2.62" @@ -2241,7 +2124,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ - "nom 7.1.3", + "nom", ] [[package]] @@ -2250,12 +2133,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" -[[package]] -name = "cfg_aliases" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" - [[package]] name = "cfg_aliases" version = "0.2.1" @@ -2334,7 +2211,7 @@ checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", - "libloading 0.8.9", + "libloading", ] [[package]] @@ -2377,15 +2254,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" -[[package]] -name = "clipboard-win" -version = "5.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4" -dependencies = [ - "error-code", -] - [[package]] name = "cmake" version = "0.1.58" @@ -2401,43 +2269,6 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746" -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width 0.1.14", -] - -[[package]] -name = "color-print" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3aa954171903797d5623e047d9ab69d91b493657917bdfb8c2c80ecaf9cdb6f4" -dependencies = [ - "color-print-proc-macro", -] - -[[package]] -name = "color-print-proc-macro" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692186b5ebe54007e45a59aea47ece9eb4108e141326c304cdc91699a7118a22" -dependencies = [ - "nom 7.1.3", - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "color_quant" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" - [[package]] name = "colorchoice" version = "1.0.5" @@ -2624,17 +2455,6 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" -[[package]] -name = "core-graphics-types" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" -dependencies = [ - "bitflags 1.3.2", - "core-foundation 0.9.4", - "libc", -] - [[package]] name = "cpufeatures" version = "0.2.17" @@ -2861,7 +2681,7 @@ dependencies = [ "cpufeatures 0.2.17", "curve25519-dalek-derive", "digest 0.10.7", - "fiat-crypto 0.2.9", + "fiat-crypto", "rustc_version 0.4.1", "subtle", "zeroize", @@ -2878,17 +2698,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "d3d12" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b28bfe653d79bd16c77f659305b195b82bb5ce0c0eb2a4846b82ddbd77586813" -dependencies = [ - "bitflags 2.9.4", - "libloading 0.8.9", - "winapi", -] - [[package]] name = "darling" version = "0.13.4" @@ -3764,106 +3573,6 @@ dependencies = [ "url", ] -[[package]] -name = "deno_broadcast_channel" -version = "0.184.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33db5dacb54c6fda4c5ea4103c5687b76a51202343379af8b21120ba9d20f3c2" -dependencies = [ - "async-trait", - "deno_core", - "deno_error", - "thiserror 2.0.18", - "tokio", - "uuid", -] - -[[package]] -name = "deno_cache" -version = "0.122.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0daca6ec4e6142a994d38e7bc587dda7948fa00e6194b671a5d4340f5a918a3" -dependencies = [ - "async-trait", - "deno_core", - "deno_error", - "rusqlite", - "serde", - "sha2 0.10.9", - "thiserror 2.0.18", - "tokio", -] - -[[package]] -name = "deno_cache_dir" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27429da4d0e601baaa41415a43468d49a586645d13497f12e8a9346f9f6b1347" -dependencies = [ - "async-trait", - "base32", - "base64 0.21.7", - "boxed_error", - "cache_control", - "chrono", - "data-url", - "deno_error", - "deno_media_type", - "deno_path_util", - "http 1.4.0", - "indexmap 2.14.0", - "log", - "once_cell", - "parking_lot", - "serde", - "serde_json", - "sha2 0.10.9", - "sys_traits", - "thiserror 1.0.69", - "url", -] - -[[package]] -name = "deno_canvas" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ca8f93d60d96d6f6cb0da632303afb98567accf07d9b6f8d2ef88617589d9e" -dependencies = [ - "deno_core", - "deno_error", - "deno_webgpu", - "image", - "serde", - "thiserror 2.0.18", -] - -[[package]] -name = "deno_config" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08fe512a72c4300bd997c6849450a1f050da0c909a2a4fbdc44891647392bacf" -dependencies = [ - "boxed_error", - "capacity_builder 0.5.0", - "deno_error", - "deno_package_json", - "deno_path_util", - "deno_semver", - "glob", - "ignore", - "import_map", - "indexmap 2.14.0", - "jsonc-parser", - "log", - "percent-encoding", - "phf 0.11.3", - "serde", - "serde_json", - "sys_traits", - "thiserror 2.0.18", - "url", -] - [[package]] name = "deno_console" version = "0.190.0" @@ -3918,62 +3627,6 @@ version = "0.74.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe4dccb6147bb3f3ba0c7a48e993bfeb999d2c2e47a81badee80e2b370c8d695" -[[package]] -name = "deno_cron" -version = "0.70.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8ec283bef14bcf655b209619766bdeab67f2a5e093991cca73f5d502f7bf6e8" -dependencies = [ - "anyhow", - "async-trait", - "chrono", - "deno_core", - "deno_error", - "saffron", - "thiserror 2.0.18", - "tokio", -] - -[[package]] -name = "deno_crypto" -version = "0.204.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f0493142a437e49b46aa8e08d715942076ff48c3cb776f0b015b4224ed0d37a" -dependencies = [ - "aes 0.8.3", - "aes-gcm", - "aes-kw", - "base64 0.21.7", - "cbc", - "const-oid 0.9.6", - "ctr", - "curve25519-dalek", - "deno_core", - "deno_error", - "deno_web", - "ed448-goldilocks", - "elliptic-curve", - "num-traits", - "once_cell", - "p256", - "p384", - "p521", - "rand 0.8.5", - "ring 0.17.14", - "rsa", - "sec1", - "serde", - "serde_bytes", - "sha1", - "sha2 0.10.9", - "signature", - "spki", - "thiserror 2.0.18", - "tokio", - "uuid", - "x25519-dalek", -] - [[package]] name = "deno_error" version = "0.5.5" @@ -4038,29 +3691,6 @@ dependencies = [ "tower-service", ] -[[package]] -name = "deno_ffi" -version = "0.177.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfbdc4e55c79ec1bc8a3ac72313e6f70d76340222f1e50c5c91e050296f83544" -dependencies = [ - "deno_core", - "deno_error", - "deno_permissions", - "dlopen2 0.6.1", - "dynasmrt", - "libffi", - "libffi-sys", - "log", - "num-bigint", - "serde", - "serde-value", - "serde_json", - "thiserror 2.0.18", - "tokio", - "winapi", -] - [[package]] name = "deno_fs" version = "0.100.0" @@ -4087,45 +3717,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "deno_http" -version = "0.188.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0b7e7a3bcac31ebd4677a96318003a98f0fda4613f6ba6d7f5ba57928727191" -dependencies = [ - "async-compression", - "async-trait", - "base64 0.21.7", - "brotli 6.0.0", - "bytes", - "cache_control", - "deno_core", - "deno_error", - "deno_net", - "deno_websocket", - "flate2", - "http 0.2.12", - "http 1.4.0", - "httparse", - "hyper 0.14.32", - "hyper 1.9.0", - "hyper-util", - "itertools 0.10.5", - "memmem", - "mime", - "once_cell", - "percent-encoding", - "phf 0.11.3", - "pin-project", - "ring 0.17.14", - "scopeguard", - "serde", - "smallvec", - "thiserror 2.0.18", - "tokio", - "tokio-util", -] - [[package]] name = "deno_io" version = "0.100.0" @@ -4150,53 +3741,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "deno_kv" -version = "0.98.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0e3930d0195a3350c05eb9a4bc619ec598ea84ad8bdb9b6c3e4bef798e7cf34" -dependencies = [ - "anyhow", - "async-trait", - "base64 0.21.7", - "boxed_error", - "bytes", - "chrono", - "deno_core", - "deno_error", - "deno_fetch", - "deno_path_util", - "deno_permissions", - "deno_tls", - "denokv_proto", - "denokv_remote", - "denokv_sqlite", - "faster-hex", - "http 1.4.0", - "http-body-util", - "log", - "num-bigint", - "prost", - "prost-build", - "rand 0.8.5", - "rusqlite", - "serde", - "thiserror 2.0.18", - "url", -] - -[[package]] -name = "deno_lockfile" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632e835a53ed667d62fdd766c5780fe8361c831d3e3fbf1a760a0b7896657587" -dependencies = [ - "deno_semver", - "serde", - "serde_json", - "thiserror 2.0.18", -] - [[package]] name = "deno_media_type" version = "0.2.5" @@ -4208,30 +3752,13 @@ dependencies = [ "url", ] -[[package]] -name = "deno_napi" -version = "0.121.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13f30bf147cc46dba87e3088d037cf99a2845ead1138033d3b346178cb781558" -dependencies = [ - "deno_core", - "deno_error", - "deno_permissions", - "libc", - "libloading 0.7.4", - "log", - "napi_sym", - "thiserror 2.0.18", - "windows-sys 0.59.0", -] - [[package]] name = "deno_native_certs" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86bc737e098a45aa5742d51ce694ac7236a1e69fb0d9df8c862e9b4c9583c5f9" dependencies = [ - "dlopen2 0.7.0", + "dlopen2", "dlopen2_derive", "once_cell", "rustls-native-certs 0.7.3", @@ -4259,121 +3786,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "deno_node" -version = "0.128.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9638e803a668b0a5793ff94c9b2e82c54a05d9fc510901e9f3093d2d63dbdaab" -dependencies = [ - "aead-gcm-stream", - "aes 0.8.3", - "async-trait", - "base64 0.21.7", - "blake2", - "boxed_error", - "brotli 6.0.0", - "bytes", - "cbc", - "const-oid 0.9.6", - "ctr", - "data-encoding", - "deno_core", - "deno_error", - "deno_fetch", - "deno_fs", - "deno_io", - "deno_net", - "deno_package_json", - "deno_path_util", - "deno_permissions", - "deno_process", - "deno_whoami", - "der", - "digest 0.10.7", - "dsa", - "ecb", - "ecdsa", - "ed25519-dalek", - "elliptic-curve", - "errno", - "faster-hex", - "h2 0.4.14", - "hkdf", - "http 1.4.0", - "http-body-util", - "hyper 1.9.0", - "hyper-util", - "idna", - "indexmap 2.14.0", - "ipnetwork", - "k256", - "lazy-regex", - "libc", - "libz-sys", - "md-5 0.10.6", - "md4", - "memchr", - "node_resolver", - "num-bigint", - "num-bigint-dig", - "num-integer", - "num-traits", - "once_cell", - "p224", - "p256", - "p384", - "path-clean", - "pbkdf2", - "pkcs8", - "rand 0.8.5", - "regex", - "ring 0.17.14", - "ripemd", - "rsa", - "scrypt", - "sec1", - "serde", - "sha1", - "sha2 0.10.9", - "sha3", - "signature", - "simd-json", - "sm3", - "spki", - "stable_deref_trait", - "sys_traits", - "thiserror 2.0.18", - "tokio", - "tokio-eld", - "url", - "webpki-root-certs 0.26.11", - "winapi", - "windows-sys 0.59.0", - "x25519-dalek", - "x509-parser 0.15.1", - "yoke 0.7.5", -] - -[[package]] -name = "deno_npm" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4adceb4c34f10e837d0e3ae76e88dddefb13e83c05c1ef1699fa5519241c9d27" -dependencies = [ - "async-trait", - "capacity_builder 0.5.0", - "deno_error", - "deno_lockfile", - "deno_semver", - "futures", - "log", - "monch", - "serde", - "serde_json", - "thiserror 2.0.18", - "url", -] - [[package]] name = "deno_ops" version = "0.212.0" @@ -4391,47 +3803,6 @@ dependencies = [ "thiserror 2.0.18", ] -[[package]] -name = "deno_os" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8371d206f6265c4e0b74116c1a58cc8c464c45da0b43c1e8c19a911e88feb2b" -dependencies = [ - "deno_core", - "deno_error", - "deno_path_util", - "deno_permissions", - "deno_telemetry", - "libc", - "netif", - "ntapi", - "once_cell", - "serde", - "signal-hook", - "signal-hook-registry", - "thiserror 2.0.18", - "tokio", - "winapi", -] - -[[package]] -name = "deno_package_json" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07d26dbfcc01e636aef86f9baff7faf5338398e74d283d8fe01e39068f48049" -dependencies = [ - "boxed_error", - "deno_error", - "deno_path_util", - "deno_semver", - "indexmap 2.14.0", - "serde", - "serde_json", - "sys_traits", - "thiserror 2.0.18", - "url", -] - [[package]] name = "deno_path_util" version = "0.3.1" @@ -4467,154 +3838,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "deno_process" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "700f8a2c9d369e7035e693f26a671489a73724450cbbc0a1e32f3966ef2f21fb" -dependencies = [ - "deno_core", - "deno_error", - "deno_fs", - "deno_io", - "deno_os", - "deno_path_util", - "deno_permissions", - "libc", - "log", - "memchr", - "nix 0.27.1", - "pin-project-lite", - "rand 0.8.5", - "serde", - "simd-json", - "tempfile", - "thiserror 2.0.18", - "tokio", - "which 6.0.3", - "winapi", - "windows-sys 0.59.0", -] - -[[package]] -name = "deno_resolver" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93c4ceec7b6e22344047b8a5577bb8239dc0a99884c25c1fa7d8611f4c3ed28b" -dependencies = [ - "anyhow", - "async-once-cell", - "async-trait", - "base32", - "boxed_error", - "dashmap 5.5.3", - "deno_cache_dir", - "deno_config", - "deno_error", - "deno_media_type", - "deno_npm", - "deno_package_json", - "deno_path_util", - "deno_semver", - "deno_terminal", - "futures", - "log", - "node_resolver", - "once_cell", - "parking_lot", - "sys_traits", - "thiserror 2.0.18", - "url", -] - -[[package]] -name = "deno_runtime" -version = "0.198.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a54d54ca920e5256c1e910c7574787d009a34afd41b20ad250278bb1aea290" -dependencies = [ - "color-print", - "deno_ast", - "deno_broadcast_channel", - "deno_cache", - "deno_canvas", - "deno_console", - "deno_core", - "deno_cron", - "deno_crypto", - "deno_error", - "deno_fetch", - "deno_ffi", - "deno_fs", - "deno_http", - "deno_io", - "deno_kv", - "deno_napi", - "deno_net", - "deno_node", - "deno_os", - "deno_path_util", - "deno_permissions", - "deno_process", - "deno_resolver", - "deno_telemetry", - "deno_terminal", - "deno_tls", - "deno_url", - "deno_web", - "deno_webgpu", - "deno_webidl", - "deno_websocket", - "deno_webstorage", - "dlopen2 0.6.1", - "encoding_rs", - "fastwebsockets", - "http 1.4.0", - "http-body-util", - "hyper 0.14.32", - "hyper 1.9.0", - "hyper-util", - "libc", - "log", - "nix 0.27.1", - "node_resolver", - "notify", - "ntapi", - "once_cell", - "percent-encoding", - "regex", - "rustyline", - "same-file", - "serde", - "sys_traits", - "tempfile", - "thiserror 2.0.18", - "tokio", - "tokio-metrics", - "twox-hash 1.6.3", - "uuid", - "which 6.0.3", - "winapi", - "windows-sys 0.59.0", -] - -[[package]] -name = "deno_semver" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4775271f9b5602482698f76d24ea9ed8ba27af7f587a7e9a876916300c542435" -dependencies = [ - "capacity_builder 0.5.0", - "deno_error", - "ecow", - "hipstr", - "monch", - "once_cell", - "serde", - "thiserror 2.0.18", - "url", -] - [[package]] name = "deno_telemetry" version = "0.12.0" @@ -4715,22 +3938,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "deno_webgpu" -version = "0.157.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4077584c0ccfde0737e576c396bbf1645f25ed0ebf4f44543e0ad13729285cf3" -dependencies = [ - "deno_core", - "deno_error", - "raw-window-handle", - "serde", - "thiserror 2.0.18", - "tokio", - "wgpu-core", - "wgpu-types", -] - [[package]] name = "deno_webidl" version = "0.190.0" @@ -4740,121 +3947,6 @@ dependencies = [ "deno_core", ] -[[package]] -name = "deno_websocket" -version = "0.195.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ad15c3856dd1748f9a36102e90b4e345e40d7d64a9bf6672d584201e1fded28" -dependencies = [ - "bytes", - "deno_core", - "deno_error", - "deno_net", - "deno_permissions", - "deno_tls", - "fastwebsockets", - "h2 0.4.14", - "http 1.4.0", - "http-body-util", - "hyper 1.9.0", - "hyper-util", - "once_cell", - "rustls-tokio-stream", - "serde", - "thiserror 2.0.18", - "tokio", -] - -[[package]] -name = "deno_webstorage" -version = "0.185.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "079dc4f6ce91f53bb848bad8d743dc20d16ca44cbed3425531cf5d922b1a45bc" -dependencies = [ - "deno_core", - "deno_error", - "deno_web", - "rusqlite", - "thiserror 2.0.18", -] - -[[package]] -name = "deno_whoami" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e75e4caa92b98a27f09c671d1399aee0f5970aa491b9a598523aac000a2192e3" -dependencies = [ - "libc", - "whoami", -] - -[[package]] -name = "denokv_proto" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5b77de4d3b9215e14624d4f4eb16cb38c0810e3f5860ba3b3fc47d0537f9a4d" -dependencies = [ - "async-trait", - "chrono", - "deno_error", - "futures", - "num-bigint", - "prost", - "serde", - "uuid", -] - -[[package]] -name = "denokv_remote" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6497c28eec268ed99f1e8664f0842935f02d1508529c67d94c57ca5d893d743" -dependencies = [ - "async-stream", - "async-trait", - "bytes", - "chrono", - "deno_error", - "denokv_proto", - "futures", - "http 1.4.0", - "log", - "prost", - "rand 0.8.5", - "serde", - "serde_json", - "thiserror 2.0.18", - "tokio", - "tokio-util", - "url", - "uuid", -] - -[[package]] -name = "denokv_sqlite" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc0f21a450a35eb85760761401fddf9bfff9840127be07a6ca5c31863127913d" -dependencies = [ - "async-stream", - "async-trait", - "chrono", - "deno_error", - "denokv_proto", - "futures", - "hex", - "log", - "num-bigint", - "rand 0.8.5", - "rusqlite", - "serde_json", - "thiserror 2.0.18", - "tokio", - "tokio-stream", - "uuid", - "v8_valueserializer", -] - [[package]] name = "der" version = "0.7.10" @@ -4862,50 +3954,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid 0.9.6", - "der_derive", "pem-rfc7468", "zeroize", ] -[[package]] -name = "der-parser" -version = "8.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" -dependencies = [ - "asn1-rs 0.5.2", - "displaydoc", - "nom 7.1.3", - "num-bigint", - "num-traits", - "rusticata-macros", -] - [[package]] name = "der-parser" version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" dependencies = [ - "asn1-rs 0.6.2", + "asn1-rs", "displaydoc", - "nom 7.1.3", + "nom", "num-bigint", "num-traits", "rusticata-macros", ] -[[package]] -name = "der_derive" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "deranged" version = "0.5.8" @@ -5158,18 +4224,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "dlopen2" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bc2c7ed06fd72a8513ded8d0d2f6fd2655a85d6885c48cae8625d80faf28c03" -dependencies = [ - "dlopen2_derive", - "libc", - "once_cell", - "winapi", -] - [[package]] name = "dlopen2" version = "0.7.0" @@ -5193,15 +4247,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "document-features" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" -dependencies = [ - "litrs", -] - [[package]] name = "dotenv" version = "0.15.0" @@ -5235,22 +4280,6 @@ dependencies = [ "text_lines", ] -[[package]] -name = "dsa" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48bc224a9084ad760195584ce5abb3c2c34a225fa312a128ad245a6b412b7689" -dependencies = [ - "digest 0.10.7", - "num-bigint-dig", - "num-traits", - "pkcs8", - "rfc6979", - "sha2 0.10.9", - "signature", - "zeroize", -] - [[package]] name = "duct" version = "0.13.7" @@ -5291,41 +4320,6 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d926b4d407d372f141f93bb444696142c29d32962ccbd3531117cf3aa0bfa9" -[[package]] -name = "dynasm" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add9a102807b524ec050363f09e06f1504214b0e1c7797f64261c891022dce8b" -dependencies = [ - "bitflags 1.3.2", - "byteorder", - "lazy_static", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "dynasmrt" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64fba5a42bd76a17cad4bfa00de168ee1cbfa06a5e8ce992ae880218c05641a9" -dependencies = [ - "byteorder", - "dynasm", - "memmap2 0.5.10", -] - -[[package]] -name = "ecb" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a8bfa975b1aec2145850fcaa1c6fe269a16578c44705a532ae3edc92b8881c7" -dependencies = [ - "cipher 0.4.4", -] - [[package]] name = "ecdsa" version = "0.16.9" @@ -5340,15 +4334,6 @@ dependencies = [ "spki", ] -[[package]] -name = "ecow" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78e4f79b296fbaab6ce2e22d52cb4c7f010fe0ebe7a32e34fa25885fd797bd02" -dependencies = [ - "serde", -] - [[package]] name = "ed25519" version = "2.2.3" @@ -5375,18 +4360,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "ed448-goldilocks" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06924531e9e90130842b012e447f85bdaf9161bc8a0f8092be8cb70b01ebe092" -dependencies = [ - "fiat-crypto 0.1.20", - "hex", - "subtle", - "zeroize", -] - [[package]] name = "educe" version = "0.6.0" @@ -5415,7 +4388,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", - "base64ct", "crypto-bigint", "digest 0.10.7", "ff", @@ -5426,8 +4398,6 @@ dependencies = [ "pkcs8", "rand_core 0.6.4", "sec1", - "serde_json", - "serdect", "subtle", "zeroize", ] @@ -5447,12 +4417,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "endian-type" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" - [[package]] name = "enum-as-inner" version = "0.6.1" @@ -5532,12 +4496,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "error-code" -version = "3.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" - [[package]] name = "error_reporter" version = "1.0.0" @@ -5598,7 +4556,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74fef4569247a5f429d9156b9d0a2599914385dd189c539334c625d8099d90ab" dependencies = [ "futures-core", - "nom 7.1.3", + "nom", "pin-project-lite", ] @@ -5608,18 +4566,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" -[[package]] -name = "fallible-iterator" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" - -[[package]] -name = "fallible-streaming-iterator" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" - [[package]] name = "fancy-regex" version = "0.14.0" @@ -5648,61 +4594,12 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afc2bd4d5a73106dd53d10d73d3401c2f32730ba2c0b93ddb888a8983680471" -[[package]] -name = "faster-hex" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183" -dependencies = [ - "serde", -] - [[package]] name = "fastrand" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" -[[package]] -name = "fastwebsockets" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dac026e15fb7e44d768880b868a0fd5bd30ffdee272e88b3060f657a5a72947" -dependencies = [ - "base64 0.21.7", - "bytes", - "http-body-util", - "hyper 1.9.0", - "hyper-util", - "pin-project", - "rand 0.8.5", - "sha1", - "simdutf8", - "thiserror 1.0.69", - "tokio", - "utf-8", -] - -[[package]] -name = "fd-lock" -version = "4.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" -dependencies = [ - "cfg-if", - "rustix 1.1.4", - "windows-sys 0.59.0", -] - -[[package]] -name = "fdeflate" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" -dependencies = [ - "simd-adler32", -] - [[package]] name = "ff" version = "0.13.1" @@ -5713,12 +4610,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "fiat-crypto" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" - [[package]] name = "fiat-crypto" version = "0.2.9" @@ -5770,15 +4661,6 @@ dependencies = [ "zlib-rs", ] -[[package]] -name = "float-cmp" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8" -dependencies = [ - "num-traits", -] - [[package]] name = "float8" version = "0.6.1" @@ -5827,28 +4709,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ - "foreign-types-shared 0.1.1", -] - -[[package]] -name = "foreign-types" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" -dependencies = [ - "foreign-types-macros", - "foreign-types-shared 0.3.1", -] - -[[package]] -name = "foreign-types-macros" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", + "foreign-types-shared", ] [[package]] @@ -5857,12 +4718,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" -[[package]] -name = "foreign-types-shared" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" - [[package]] name = "form_urlencoded" version = "1.2.2" @@ -5916,15 +4771,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" -[[package]] -name = "fsevent-sys" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" -dependencies = [ - "libc", -] - [[package]] name = "fslock" version = "0.2.1" @@ -6330,17 +5176,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "gl_generator" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" -dependencies = [ - "khronos_api", - "log", - "xml-rs", -] - [[package]] name = "glob" version = "0.3.3" @@ -6372,27 +5207,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "glow" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1" -dependencies = [ - "js-sys", - "slotmap", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "glutin_wgl_sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8098adac955faa2d31079b65dc48841251f69efd3ac25477903fc424362ead" -dependencies = [ - "gl_generator", -] - [[package]] name = "google-cloud-auth" version = "0.17.2" @@ -6493,45 +5307,6 @@ dependencies = [ "unic-ucd-category", ] -[[package]] -name = "gpu-alloc" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" -dependencies = [ - "bitflags 2.9.4", - "gpu-alloc-types", -] - -[[package]] -name = "gpu-alloc-types" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" -dependencies = [ - "bitflags 2.9.4", -] - -[[package]] -name = "gpu-descriptor" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" -dependencies = [ - "bitflags 2.9.4", - "gpu-descriptor-types", - "hashbrown 0.15.5", -] - -[[package]] -name = "gpu-descriptor-types" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" -dependencies = [ - "bitflags 2.9.4", -] - [[package]] name = "group" version = "0.13.0" @@ -6605,16 +5380,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "halfbrown" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8588661a8607108a5ca69cab034063441a0413a0b041c13618a7dd348021ef6f" -dependencies = [ - "hashbrown 0.14.5", - "serde", -] - [[package]] name = "hashbrown" version = "0.12.3" @@ -6675,15 +5440,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "hashlink" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" -dependencies = [ - "hashbrown 0.14.5", -] - [[package]] name = "hashlink" version = "0.10.0" @@ -6693,20 +5449,6 @@ dependencies = [ "hashbrown 0.15.5", ] -[[package]] -name = "hdrhistogram" -version = "7.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "765c9198f173dd59ce26ff9f95ef0aafd0a0fe01fb9d72841bc5066a4c06511d" -dependencies = [ - "base64 0.21.7", - "byteorder", - "crossbeam-channel", - "flate2", - "nom 7.1.3", - "num-traits", -] - [[package]] name = "headers" version = "0.4.1" @@ -6755,12 +5497,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hexf-parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" - [[package]] name = "hf-hub" version = "0.4.3" @@ -6833,17 +5569,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "hipstr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97971ffc85d4c98de12e2608e992a43f5294ebb625fdb045b27c731b64c4c6d6" -dependencies = [ - "serde", - "serde_bytes", - "sptr", -] - [[package]] name = "hkdf" version = "0.12.4" @@ -7276,7 +6001,7 @@ dependencies = [ "displaydoc", "potential_utf", "utf8_iter", - "yoke 0.8.2", + "yoke", "zerofrom", "zerovec", ] @@ -7343,7 +6068,7 @@ dependencies = [ "displaydoc", "icu_locale_core", "writeable", - "yoke 0.8.2", + "yoke", "zerofrom", "zerotrie", "zerovec", @@ -7388,52 +6113,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd62e6b5e86ea8eeeb8db1de02880a6abc01a397b2ebb64b5d74ac255318f5cb" -[[package]] -name = "ignore" -version = "0.4.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a" -dependencies = [ - "crossbeam-deque", - "globset", - "log", - "memchr", - "regex-automata", - "same-file", - "walkdir", - "winapi-util", -] - -[[package]] -name = "image" -version = "0.24.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" -dependencies = [ - "bytemuck", - "byteorder", - "color_quant", - "num-traits", - "png", -] - -[[package]] -name = "import_map" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1215d4d92511fbbdaea50e750e91f2429598ef817f02b579158e92803b52c00a" -dependencies = [ - "boxed_error", - "deno_error", - "indexmap 2.14.0", - "log", - "percent-encoding", - "serde", - "serde_json", - "thiserror 2.0.18", - "url", -] - [[package]] name = "indexmap" version = "1.9.3" @@ -7470,33 +6149,12 @@ dependencies = [ "web-time", ] -[[package]] -name = "inotify" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" -dependencies = [ - "bitflags 1.3.2", - "inotify-sys", - "libc", -] - -[[package]] -name = "inotify-sys" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" -dependencies = [ - "libc", -] - [[package]] name = "inout" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ - "block-padding 0.3.3", "generic-array", ] @@ -7545,15 +6203,6 @@ version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" -[[package]] -name = "ipnetwork" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" -dependencies = [ - "serde", -] - [[package]] name = "is-macro" version = "0.3.7" @@ -7696,15 +6345,6 @@ dependencies = [ "thiserror 2.0.18", ] -[[package]] -name = "jsonc-parser" -version = "0.26.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6d80e6d70e7911a29f3cf3f44f452df85d06f73572b494ca99a2cad3fcf8f4" -dependencies = [ - "serde_json", -] - [[package]] name = "jsonpath-rust" version = "0.7.5" @@ -7767,20 +6407,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "k256" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" -dependencies = [ - "cfg-if", - "ecdsa", - "elliptic-curve", - "once_cell", - "sha2 0.10.9", - "signature", -] - [[package]] name = "k8s-openapi" version = "0.25.0" @@ -7793,15 +6419,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "keccak" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" -dependencies = [ - "cpufeatures 0.2.17", -] - [[package]] name = "keyed_priority_queue" version = "0.4.2" @@ -7811,23 +6428,6 @@ dependencies = [ "indexmap 2.14.0", ] -[[package]] -name = "khronos-egl" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" -dependencies = [ - "libc", - "libloading 0.8.9", - "pkg-config", -] - -[[package]] -name = "khronos_api" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" - [[package]] name = "konst" version = "0.2.20" @@ -7843,26 +6443,6 @@ version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37" -[[package]] -name = "kqueue" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a" -dependencies = [ - "kqueue-sys", - "libc", -] - -[[package]] -name = "kqueue-sys" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" -dependencies = [ - "bitflags 1.3.2", - "libc", -] - [[package]] name = "kube" version = "1.1.0" @@ -7979,29 +6559,6 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" -[[package]] -name = "lazy-regex" -version = "3.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bae91019476d3ec7147de9aa291cadb6d870abf2f3015d2da73a90325ac1496" -dependencies = [ - "lazy-regex-proc_macros", - "once_cell", - "regex", -] - -[[package]] -name = "lazy-regex-proc_macros" -version = "3.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4de9c1e1439d8b7b3061b2d209809f447ca33241733d9a3c01eabf2dc8d94358" -dependencies = [ - "proc-macro2", - "quote", - "regex", - "syn 2.0.117", -] - [[package]] name = "lazy_static" version = "1.5.0" @@ -8086,16 +6643,6 @@ version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" -[[package]] -name = "libffi" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce826c243048e3d5cec441799724de52e2d42f820468431fc3fceee2341871e2" -dependencies = [ - "libc", - "libffi-sys", -] - [[package]] name = "libffi-sys" version = "2.3.0" @@ -8127,16 +6674,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if", - "winapi", -] - [[package]] name = "libloading" version = "0.8.9" @@ -8182,7 +6719,6 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ - "cc", "pkg-config", "vcpkg", ] @@ -8244,12 +6780,6 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" -[[package]] -name = "litrs" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" - [[package]] name = "lock_api" version = "0.4.14" @@ -8320,7 +6850,7 @@ version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "373f5eceeeab7925e0c1098212f2fbc4d416adec9d35051a6ab251e824c1854a" dependencies = [ - "twox-hash 2.1.2", + "twox-hash", ] [[package]] @@ -8477,15 +7007,6 @@ dependencies = [ "malachite-nz", ] -[[package]] -name = "malloc_buf" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -dependencies = [ - "libc", -] - [[package]] name = "mappable-rc" version = "0.1.1" @@ -8550,15 +7071,6 @@ dependencies = [ "digest 0.11.3", ] -[[package]] -name = "md4" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da5ac363534dce5fabf69949225e174fbf111a498bf0ff794c8ea1fba9f3dda" -dependencies = [ - "digest 0.10.7", -] - [[package]] name = "md5" version = "0.6.1" @@ -8580,15 +7092,6 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" -[[package]] -name = "memmap2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" -dependencies = [ - "libc", -] - [[package]] name = "memmap2" version = "0.9.10" @@ -8599,12 +7102,6 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -name = "memmem" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64a92489e2744ce060c349162be1c5f33c6969234104dbd99ddb5feb08b8c15" - [[package]] name = "memoffset" version = "0.9.1" @@ -8614,21 +7111,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "metal" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5637e166ea14be6063a3f8ba5ccb9a4159df7d8f6d61c02fc3d480b1f90dcfcb" -dependencies = [ - "bitflags 2.9.4", - "block", - "core-graphics-types", - "foreign-types 0.5.0", - "log", - "objc", - "paste", -] - [[package]] name = "miette" version = "7.6.0" @@ -8708,18 +7190,6 @@ dependencies = [ "simd-adler32", ] -[[package]] -name = "mio" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" -dependencies = [ - "libc", - "log", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.48.0", -] - [[package]] name = "mio" version = "1.2.0" @@ -8751,12 +7221,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "monch" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b52c1b33ff98142aecea13138bd399b68aa7ab5d9546c300988c345004001eea" - [[package]] name = "monostate" version = "0.1.18" @@ -8796,12 +7260,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "multimap" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" - [[package]] name = "murmurhash32" version = "0.3.1" @@ -8852,7 +7310,7 @@ dependencies = [ "tokio", "tokio-native-tls", "tokio-util", - "twox-hash 2.1.2", + "twox-hash", "url", ] @@ -8884,28 +7342,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "naga" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e536ae46fcab0876853bd4a632ede5df4b1c2527a58f6c5a4150fe86be858231" -dependencies = [ - "arrayvec", - "bit-set 0.5.3", - "bitflags 2.9.4", - "codespan-reporting", - "hexf-parse", - "indexmap 2.14.0", - "log", - "num-traits", - "rustc-hash 1.1.0", - "serde", - "spirv", - "termcolor", - "thiserror 1.0.69", - "unicode-xid", -] - [[package]] name = "nanorand" version = "0.7.0" @@ -8915,18 +7351,6 @@ dependencies = [ "getrandom 0.2.17", ] -[[package]] -name = "napi_sym" -version = "0.120.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33a55ec137cebb7f4a594edd16157a5b9d9addf7ebd29c88198ec4e0cff2e93e" -dependencies = [ - "quote", - "serde", - "serde_json", - "syn 2.0.117", -] - [[package]] name = "native-tls" version = "0.2.16" @@ -8944,40 +7368,12 @@ dependencies = [ "tempfile", ] -[[package]] -name = "ndk-sys" -version = "0.5.0+25.2.9519653" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" -dependencies = [ - "jni-sys 0.3.1", -] - -[[package]] -name = "netif" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29a01b9f018d6b7b277fef6c79fdbd9bf17bb2d1e298238055cafab49baa5ee" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "new_debug_unreachable" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" -[[package]] -name = "nibble_vec" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" -dependencies = [ - "smallvec", -] - [[package]] name = "nix" version = "0.27.1" @@ -8997,7 +7393,7 @@ checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ "bitflags 2.9.4", "cfg-if", - "cfg_aliases 0.2.1", + "cfg_aliases", "libc", ] @@ -9009,7 +7405,7 @@ checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ "bitflags 2.9.4", "cfg-if", - "cfg_aliases 0.2.1", + "cfg_aliases", "libc", ] @@ -9028,42 +7424,6 @@ dependencies = [ "signatory", ] -[[package]] -name = "node_resolver" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808426e80ce77a311b24ac080caf18c23c632e035d797edb217ce74cdf6a0e71" -dependencies = [ - "anyhow", - "async-trait", - "boxed_error", - "dashmap 5.5.3", - "deno_error", - "deno_media_type", - "deno_package_json", - "deno_path_util", - "futures", - "lazy-regex", - "once_cell", - "path-clean", - "regex", - "serde", - "serde_json", - "sys_traits", - "thiserror 2.0.18", - "url", -] - -[[package]] -name = "nom" -version = "5.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b" -dependencies = [ - "memchr", - "version_check", -] - [[package]] name = "nom" version = "7.1.3" @@ -9074,25 +7434,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "notify" -version = "6.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" -dependencies = [ - "bitflags 2.9.4", - "crossbeam-channel", - "filetime", - "fsevent-sys", - "inotify", - "kqueue", - "libc", - "log", - "mio 0.8.11", - "walkdir", - "windows-sys 0.48.0", -] - [[package]] name = "ntapi" version = "0.4.3" @@ -9288,7 +7629,6 @@ dependencies = [ "num-iter", "num-traits", "rand 0.8.5", - "serde", "smallvec", "zeroize", ] @@ -9418,15 +7758,6 @@ dependencies = [ "url", ] -[[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" -dependencies = [ - "malloc_buf", -] - [[package]] name = "object" version = "0.37.3" @@ -9482,22 +7813,13 @@ dependencies = [ "cc", ] -[[package]] -name = "oid-registry" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" -dependencies = [ - "asn1-rs 0.5.2", -] - [[package]] name = "oid-registry" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" dependencies = [ - "asn1-rs 0.6.2", + "asn1-rs", ] [[package]] @@ -9591,7 +7913,7 @@ checksum = "bf0b434746ee2832f4f0baf10137e1cabb18cbe6912c69e2e33263c45250f542" dependencies = [ "bitflags 2.9.4", "cfg-if", - "foreign-types 0.3.2", + "foreign-types", "libc", "openssl-macros", "openssl-sys", @@ -9912,18 +8234,6 @@ version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d211803b9b6b570f68772237e415a029d5a50c65d382910b879fb19d3271f94d" -[[package]] -name = "p224" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30c06436d66652bc2f01ade021592c80a2aad401570a18aa18b82e440d2b9aa1" -dependencies = [ - "ecdsa", - "elliptic-curve", - "primeorder", - "sha2 0.10.9", -] - [[package]] name = "p256" version = "0.13.2" @@ -9948,20 +8258,6 @@ dependencies = [ "sha2 0.10.9", ] -[[package]] -name = "p521" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" -dependencies = [ - "base16ct", - "ecdsa", - "elliptic-curve", - "primeorder", - "rand_core 0.6.4", - "sha2 0.10.9", -] - [[package]] name = "parking" version = "2.2.1" @@ -10023,7 +8319,7 @@ dependencies = [ "snap", "thrift", "tokio", - "twox-hash 2.1.2", + "twox-hash", "zstd", ] @@ -10050,28 +8346,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5a797f0e07bdf071d15742978fc3128ec6c22891c31a3a931513263904c982a" -[[package]] -name = "path-clean" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecba01bf2678719532c5e3059e0b5f0811273d94b397088b82e3bd0a78c78fdd" - [[package]] name = "pathdiff" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" -[[package]] -name = "pbkdf2" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" -dependencies = [ - "digest 0.10.7", - "hmac 0.12.1", -] - [[package]] name = "pem" version = "1.1.1" @@ -10305,21 +8585,6 @@ dependencies = [ "spki", ] -[[package]] -name = "pkcs5" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e847e2c91a18bfa887dd028ec33f2fe6f25db77db3619024764914affe8b69a6" -dependencies = [ - "aes 0.8.3", - "cbc", - "der", - "pbkdf2", - "scrypt", - "sha2 0.10.9", - "spki", -] - [[package]] name = "pkcs8" version = "0.10.2" @@ -10327,8 +8592,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ "der", - "pkcs5", - "rand_core 0.6.4", "spki", ] @@ -10344,19 +8607,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" -[[package]] -name = "png" -version = "0.17.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" -dependencies = [ - "bitflags 1.3.2", - "crc32fast", - "fdeflate", - "flate2", - "miniz_oxide 0.8.9", -] - [[package]] name = "polyval" version = "0.6.2" @@ -10406,7 +8656,7 @@ dependencies = [ "base64 0.22.1", "byteorder", "bytes", - "fallible-iterator 0.2.0", + "fallible-iterator", "hmac 0.12.1", "md-5 0.10.6", "memchr", @@ -10424,7 +8674,7 @@ dependencies = [ "base64 0.22.1", "byteorder", "bytes", - "fallible-iterator 0.2.0", + "fallible-iterator", "hmac 0.13.0", "md-5 0.11.0", "memchr", @@ -10439,7 +8689,7 @@ version = "0.2.7" source = "git+https://github.com/imor/rust-postgres?rev=20265ef38e32a06f76b6f9b678e2077fc2211f6b#20265ef38e32a06f76b6f9b678e2077fc2211f6b" dependencies = [ "bytes", - "fallible-iterator 0.2.0", + "fallible-iterator", "postgres-protocol 0.6.7", ] @@ -10453,7 +8703,7 @@ dependencies = [ "bit-vec 0.6.3", "bytes", "chrono", - "fallible-iterator 0.2.0", + "fallible-iterator", "postgres-protocol 0.6.11", "serde", "serde_json", @@ -10527,7 +8777,6 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn 1.0.109", "version_check", ] @@ -10635,12 +8884,6 @@ dependencies = [ "hex", ] -[[package]] -name = "profiling" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5" - [[package]] name = "prometheus" version = "0.14.0" @@ -10665,26 +8908,6 @@ dependencies = [ "prost-derive", ] -[[package]] -name = "prost-build" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" -dependencies = [ - "heck 0.5.0", - "itertools 0.14.0", - "log", - "multimap", - "once_cell", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn 2.0.117", - "tempfile", -] - [[package]] name = "prost-derive" version = "0.13.5" @@ -10817,7 +9040,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ "bytes", - "cfg_aliases 0.2.1", + "cfg_aliases", "pin-project-lite", "quinn-proto", "quinn-udp", @@ -10858,7 +9081,7 @@ version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" dependencies = [ - "cfg_aliases 0.2.1", + "cfg_aliases", "libc", "once_cell", "socket2 0.6.3", @@ -10893,16 +9116,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" -[[package]] -name = "radix_trie" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" -dependencies = [ - "endian-type", - "nibble_vec", -] - [[package]] name = "rand" version = "0.7.3" @@ -11031,12 +9244,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "range-alloc" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca45419789ae5a7899559e9512e58ca889e41f04f1f2445e9f4b290ceccd1d08" - [[package]] name = "raw-cpuid" version = "11.6.0" @@ -11046,12 +9253,6 @@ dependencies = [ "bitflags 2.9.4", ] -[[package]] -name = "raw-window-handle" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" - [[package]] name = "rayon" version = "1.12.0" @@ -11093,7 +9294,7 @@ dependencies = [ "ring 0.17.14", "rustls-pki-types", "time", - "x509-parser 0.16.0", + "x509-parser", "yasna", ] @@ -11460,15 +9661,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "ripemd" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" -dependencies = [ - "digest 0.10.7", -] - [[package]] name = "rkyv" version = "0.7.46" @@ -11546,18 +9738,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "ron" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" -dependencies = [ - "base64 0.21.7", - "bitflags 2.9.4", - "serde", - "serde_derive", -] - [[package]] name = "rquickjs" version = "0.11.0" @@ -11646,20 +9826,6 @@ dependencies = [ "tokio-rustls 0.25.0", ] -[[package]] -name = "rusqlite" -version = "0.32.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e" -dependencies = [ - "bitflags 2.9.4", - "fallible-iterator 0.3.0", - "fallible-streaming-iterator", - "hashlink 0.9.1", - "libsqlite3-sys", - "smallvec", -] - [[package]] name = "rust-embed" version = "6.8.1" @@ -11765,7 +9931,7 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" dependencies = [ - "nom 7.1.3", + "nom", ] [[package]] @@ -11918,7 +10084,7 @@ dependencies = [ "rustls-webpki 0.103.13", "security-framework 3.6.0", "security-framework-sys", - "webpki-root-certs 1.0.7", + "webpki-root-certs", "windows-sys 0.61.2", ] @@ -12036,28 +10202,6 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" -[[package]] -name = "rustyline" -version = "13.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02a2d683a4ac90aeef5b1013933f6d977bd37d51ff3f4dad829d4931a7e6be86" -dependencies = [ - "bitflags 2.9.4", - "cfg-if", - "clipboard-win", - "fd-lock", - "home", - "libc", - "log", - "memchr", - "nix 0.27.1", - "radix_trie", - "unicode-segmentation", - "unicode-width 0.1.14", - "utf8parse", - "winapi", -] - [[package]] name = "ryu" version = "1.0.23" @@ -12081,25 +10225,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "saffron" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03fb9a628596fc7590eb7edbf7b0613287be78df107f5f97b118aad59fb2eea9" -dependencies = [ - "chrono", - "nom 5.1.3", -] - -[[package]] -name = "salsa20" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" -dependencies = [ - "cipher 0.4.4", -] - [[package]] name = "samael" version = "0.0.20" @@ -12245,18 +10370,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "scrypt" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" -dependencies = [ - "password-hash", - "pbkdf2", - "salsa20", - "sha2 0.10.9", -] - [[package]] name = "sct" version = "0.7.1" @@ -12289,7 +10402,6 @@ dependencies = [ "der", "generic-array", "pkcs8", - "serdect", "subtle", "zeroize", ] @@ -12409,16 +10521,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "serde_bytes" -version = "0.11.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" -dependencies = [ - "serde", - "serde_core", -] - [[package]] name = "serde_core" version = "1.0.220" @@ -12599,16 +10701,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "serdect" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" -dependencies = [ - "base16ct", - "serde", -] - [[package]] name = "serial_test" version = "3.4.0" @@ -12681,16 +10773,6 @@ dependencies = [ "digest 0.11.3", ] -[[package]] -name = "sha3" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874" -dependencies = [ - "digest 0.10.7", - "keccak", -] - [[package]] name = "sharded-slab" version = "0.1.7" @@ -12725,16 +10807,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "signal-hook" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" -dependencies = [ - "libc", - "signal-hook-registry", -] - [[package]] name = "signal-hook-registry" version = "1.4.8" @@ -12782,21 +10854,6 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" -[[package]] -name = "simd-json" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2bcf6c6e164e81bc7a5d49fc6988b3d515d9e8c07457d7b74ffb9324b9cd40" -dependencies = [ - "getrandom 0.2.17", - "halfbrown", - "ref-cast", - "serde", - "serde_json", - "simdutf8", - "value-trait", -] - [[package]] name = "simdutf8" version = "0.1.5" @@ -12848,24 +10905,6 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" -[[package]] -name = "slotmap" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" -dependencies = [ - "version_check", -] - -[[package]] -name = "sm3" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebb9a3b702d0a7e33bc4d85a14456633d2b165c2ad839c5fd9a8417c1ab15860" -dependencies = [ - "digest 0.10.7", -] - [[package]] name = "smallvec" version = "1.15.1" @@ -12981,15 +11020,6 @@ dependencies = [ "lock_api", ] -[[package]] -name = "spirv" -version = "0.3.0+sdk-1.3.268.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" -dependencies = [ - "bitflags 2.9.4", -] - [[package]] name = "spki" version = "0.7.3" @@ -13007,17 +11037,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5851699c4033c63636f7ea4cf7b7c1f1bf06d0cc03cfb42e711de5a5c46cf326" dependencies = [ "base64 0.13.1", - "nom 7.1.3", + "nom", "serde", "unicode-segmentation", ] -[[package]] -name = "sptr" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a" - [[package]] name = "sql-builder" version = "3.1.1" @@ -13093,7 +11117,7 @@ dependencies = [ "futures-io", "futures-util", "hashbrown 0.15.5", - "hashlink 0.10.0", + "hashlink", "indexmap 2.14.0", "log", "memchr", @@ -13825,18 +11849,6 @@ dependencies = [ "futures-core", ] -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "unicode-xid", -] - [[package]] name = "synstructure" version = "0.13.2" @@ -13862,10 +11874,6 @@ name = "sys_traits" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b46ac05dfbe9fd3a9703eff20e17f5b31e7b6a54daf27a421dcd56c7a27ecdd" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] [[package]] name = "sysctl" @@ -13925,7 +11933,7 @@ dependencies = [ "bytesize", "lazy_static", "libc", - "nom 7.1.3", + "nom", "time", "winapi", ] @@ -13962,7 +11970,7 @@ dependencies = [ "lru 0.16.4", "lz4_flex 0.13.0", "measure_time", - "memmap2 0.9.10", + "memmap2", "once_cell", "oneshot", "rayon", @@ -14040,7 +12048,7 @@ version = "0.25.0" source = "git+https://github.com/windmill-labs/tantivy?rev=6ae7c70bc603b8e69e27f3240e08bd00a93fb12c#6ae7c70bc603b8e69e27f3240e08bd00a93fb12c" dependencies = [ "fnv", - "nom 7.1.3", + "nom", "ordered-float 5.3.0", "serde", "serde_json", @@ -14399,7 +12407,7 @@ dependencies = [ "bytes", "io-uring", "libc", - "mio 1.2.0", + "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", @@ -14410,16 +12418,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "tokio-eld" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9166030f05d6bc5642bdb8f8c2be31eb3c02cd465d662bcdc2df82d4aa41a584" -dependencies = [ - "hdrhistogram", - "tokio", -] - [[package]] name = "tokio-graceful" version = "0.1.6" @@ -14444,18 +12442,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "tokio-metrics" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eace09241d62c98b7eeb1107d4c5c64ca3bd7da92e8c218c153ab3a78f9be112" -dependencies = [ - "futures-util", - "pin-project-lite", - "tokio", - "tokio-stream", -] - [[package]] name = "tokio-native-tls" version = "0.3.1" @@ -14474,7 +12460,7 @@ dependencies = [ "async-trait", "byteorder", "bytes", - "fallible-iterator 0.2.0", + "fallible-iterator", "futures-channel", "futures-util", "log", @@ -14500,7 +12486,7 @@ dependencies = [ "async-trait", "byteorder", "bytes", - "fallible-iterator 0.2.0", + "fallible-iterator", "futures-channel", "futures-util", "log", @@ -14624,7 +12610,6 @@ dependencies = [ "futures-io", "futures-sink", "futures-util", - "hashbrown 0.15.5", "pin-project-lite", "slab", "tokio", @@ -15114,17 +13099,6 @@ dependencies = [ "utf-8", ] -[[package]] -name = "twox-hash" -version = "1.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" -dependencies = [ - "cfg-if", - "rand 0.8.5", - "static_assertions", -] - [[package]] name = "twox-hash" version = "2.1.2" @@ -15516,39 +13490,12 @@ dependencies = [ "which 6.0.3", ] -[[package]] -name = "v8_valueserializer" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97599c400fc79925922b58303e98fcb8fa88f573379a08ddb652e72cbd2e70f6" -dependencies = [ - "bitflags 2.9.4", - "encoding_rs", - "indexmap 2.14.0", - "num-bigint", - "serde", - "thiserror 1.0.69", - "wtf8", -] - [[package]] name = "valuable" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" -[[package]] -name = "value-trait" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9170e001f458781e92711d2ad666110f153e4e50bfd5cbd02db6547625714187" -dependencies = [ - "float-cmp", - "halfbrown", - "itoa", - "ryu", -] - [[package]] name = "vcpkg" version = "0.2.15" @@ -15819,15 +13766,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-root-certs" -version = "0.26.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e" -dependencies = [ - "webpki-root-certs 1.0.7", -] - [[package]] name = "webpki-root-certs" version = "1.0.7" @@ -15855,89 +13793,6 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "wgpu-core" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50819ab545b867d8a454d1d756b90cd5f15da1f2943334ca314af10583c9d39" -dependencies = [ - "arrayvec", - "bit-vec 0.6.3", - "bitflags 2.9.4", - "cfg_aliases 0.1.1", - "codespan-reporting", - "document-features", - "indexmap 2.14.0", - "log", - "naga", - "once_cell", - "parking_lot", - "profiling", - "raw-window-handle", - "ron", - "rustc-hash 1.1.0", - "serde", - "smallvec", - "thiserror 1.0.69", - "web-sys", - "wgpu-hal", - "wgpu-types", -] - -[[package]] -name = "wgpu-hal" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "172e490a87295564f3fcc0f165798d87386f6231b04d4548bca458cbbfd63222" -dependencies = [ - "android_system_properties", - "arrayvec", - "ash", - "bit-set 0.5.3", - "bitflags 2.9.4", - "block", - "cfg_aliases 0.1.1", - "core-graphics-types", - "d3d12", - "glow", - "glutin_wgl_sys", - "gpu-alloc", - "gpu-descriptor", - "js-sys", - "khronos-egl", - "libc", - "libloading 0.8.9", - "log", - "metal", - "naga", - "ndk-sys", - "objc", - "once_cell", - "parking_lot", - "profiling", - "range-alloc", - "raw-window-handle", - "rustc-hash 1.1.0", - "smallvec", - "thiserror 1.0.69", - "wasm-bindgen", - "web-sys", - "wgpu-types", - "winapi", -] - -[[package]] -name = "wgpu-types" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1353d9a46bff7f955a680577f34c69122628cc2076e1d6f3a9be6ef00ae793ef" -dependencies = [ - "bitflags 2.9.4", - "js-sys", - "serde", - "web-sys", -] - [[package]] name = "which" version = "4.4.2" @@ -17425,7 +15280,6 @@ dependencies = [ "deno_io", "deno_net", "deno_permissions", - "deno_runtime", "deno_telemetry", "deno_tls", "deno_url", @@ -17885,7 +15739,7 @@ dependencies = [ "jsonwebtoken 8.3.0", "lazy_static", "libffi-sys", - "libloading 0.8.9", + "libloading", "mappable-rc", "mime_guess", "mysql_async", @@ -17955,7 +15809,7 @@ dependencies = [ "windmill-types", "windmill-worker-volumes", "windows 0.61.3", - "x509-parser 0.16.0", + "x509-parser", "yaml-rust", ] @@ -18671,12 +16525,6 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" -[[package]] -name = "wtf8" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c01ae8492c38f52376efd3a17d0994b6bcf3df1e39c0226d458b7d81670b2a06" - [[package]] name = "wyz" version = "0.5.1" @@ -18686,47 +16534,18 @@ dependencies = [ "tap", ] -[[package]] -name = "x25519-dalek" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" -dependencies = [ - "curve25519-dalek", - "rand_core 0.6.4", - "serde", - "zeroize", -] - -[[package]] -name = "x509-parser" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7069fba5b66b9193bd2c5d3d4ff12b839118f6bcbef5328efafafb5395cf63da" -dependencies = [ - "asn1-rs 0.5.2", - "data-encoding", - "der-parser 8.2.0", - "lazy_static", - "nom 7.1.3", - "oid-registry 0.6.1", - "rusticata-macros", - "thiserror 1.0.69", - "time", -] - [[package]] name = "x509-parser" version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" dependencies = [ - "asn1-rs 0.6.2", + "asn1-rs", "data-encoding", - "der-parser 9.0.0", + "der-parser", "lazy_static", - "nom 7.1.3", - "oid-registry 0.7.1", + "nom", + "oid-registry", "ring 0.17.14", "rusticata-macros", "thiserror 1.0.69", @@ -18743,12 +16562,6 @@ dependencies = [ "rustix 1.1.4", ] -[[package]] -name = "xml-rs" -version = "0.8.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" - [[package]] name = "xmlparser" version = "0.13.6" @@ -18788,18 +16601,6 @@ dependencies = [ "time", ] -[[package]] -name = "yoke" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive 0.7.5", - "zerofrom", -] - [[package]] name = "yoke" version = "0.8.2" @@ -18807,22 +16608,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" dependencies = [ "stable_deref_trait", - "yoke-derive 0.8.2", + "yoke-derive", "zerofrom", ] -[[package]] -name = "yoke-derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", - "synstructure 0.13.2", -] - [[package]] name = "yoke-derive" version = "0.8.2" @@ -18832,7 +16621,7 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.117", - "synstructure 0.13.2", + "synstructure", ] [[package]] @@ -18873,7 +16662,7 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.117", - "synstructure 0.13.2", + "synstructure", ] [[package]] @@ -18881,20 +16670,6 @@ name = "zeroize" version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] [[package]] name = "zerotrie" @@ -18903,7 +16678,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" dependencies = [ "displaydoc", - "yoke 0.8.2", + "yoke", "zerofrom", ] @@ -18913,7 +16688,7 @@ version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" dependencies = [ - "yoke 0.8.2", + "yoke", "zerofrom", "zerovec-derive", ] diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 042179683d..fbee476402 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -455,7 +455,6 @@ deno_net = "0.182.0" deno_core = "0.336.0" deno_ast = { version = "=0.44.0", features = ["transpiling"] } deno_permissions = "0.49.0" -deno_runtime = { version = "0.198.0", features = ["transpile"] } deno_telemetry = "0.12.0" deno_error = "=0.5.5" rustls-pemfile = "2.2.0" diff --git a/backend/windmill-runtime-nativets/Cargo.toml b/backend/windmill-runtime-nativets/Cargo.toml index 417ec8de9d..c4f3461815 100644 --- a/backend/windmill-runtime-nativets/Cargo.toml +++ b/backend/windmill-runtime-nativets/Cargo.toml @@ -30,7 +30,6 @@ deno_permissions.workspace = true deno_io.workspace = true deno_telemetry.workspace = true deno_error.workspace = true -deno_runtime.workspace = true winapi.workspace = true itertools.workspace = true @@ -60,6 +59,6 @@ deno_ast.workspace = true deno_tls.workspace = true deno_permissions.workspace = true deno_io.workspace = true -deno_runtime.workspace = true deno_telemetry.workspace = true +deno_error.workspace = true winapi.workspace = true diff --git a/backend/windmill-runtime-nativets/build.rs b/backend/windmill-runtime-nativets/build.rs index 2f4ec8c38d..6598c974eb 100644 --- a/backend/windmill-runtime-nativets/build.rs +++ b/backend/windmill-runtime-nativets/build.rs @@ -1,3 +1,6 @@ +use deno_ast::{MediaType, ParseParams}; +use deno_core::{ModuleCodeString, ModuleName, SourceMapData}; +use deno_error::JsErrorBox; use deno_fetch::FetchPermissions; use deno_net::NetPermissions; use deno_web::{BlobStore, TimersPermission}; @@ -77,6 +80,74 @@ deno_core::extension!( esm = ["src/runtime.js"], ); +// `extension_transpiler` callback for `deno_core::snapshot::create_snapshot`. +// +// Specialized to our snapshot's inputs. Of the seven deno_* extensions +// we register via `init_ops_and_esm()`, six ship pre-built `.js` files +// in their `esm` lists (webidl/url/console/web/fetch/net) — only +// `deno_telemetry`'s `extension!` macro lists `.ts` files +// (`telemetry.ts`, `util.ts`), so the TypeScript branch is needed +// solely for that crate. Our local `fetch` extension contributes +// `src/runtime.js` (pure JS). No `node:` imports happen at snapshot +// build time, no `.mjs`, no user-supplied modules. So: +// - `.js` → pass through. +// - `.ts` → transpile via deno_ast (deno_telemetry only). +// - anything else → build bug (deno shipping an unexpected file type +// or us mislabelling one), panic loudly rather than emit a broken +// snapshot. +// +// No source maps: the snapshot is a binary blob the runtime loads — source +// maps would never be consumed. +// +// The signature still returns `Result<_, JsErrorBox>` because that's what +// `extension_transpiler` expects, but we never construct one — parse and +// transpile failures are build-time bugs in deno's own .ts internals (or +// in our runtime.js, if we ever change its extension), so they panic. +// +// This replaces a call to `deno_runtime::transpile::maybe_transpile_source` +// from `deno_runtime 0.198.0`. The original is more general (handles +// `node:` modules, `.mjs`, emits source maps in debug builds, plumbs +// errors via `JsErrorBox`); none of that surface is reachable in our +// build. Dropping the `deno_runtime` dep eliminates a +// `deno_cache → rusqlite → libsqlite3-sys 0.35` transitive chain that +// collides with sqlx-sqlite's `libsqlite3-sys 0.30` (cargo's +// `links = "sqlite3"` rule). +fn maybe_transpile_source( + name: ModuleName, + source: ModuleCodeString, +) -> Result<(ModuleCodeString, Option), JsErrorBox> { + let media_type = MediaType::from_path(Path::new(&name)); + match media_type { + MediaType::JavaScript => return Ok((source, None)), + MediaType::TypeScript => {} + _ => panic!("unexpected media type {media_type:?} for {name} during snapshot build"), + } + + let parsed = deno_ast::parse_module(ParseParams { + specifier: deno_core::url::Url::parse(&name).unwrap(), + text: source.into(), + media_type, + capture_tokens: false, + scope_analysis: false, + maybe_syntax: None, + }) + .unwrap_or_else(|e| panic!("snapshot transpile: parse failed for {name}: {e}")); + + let transpiled = parsed + .transpile( + &deno_ast::TranspileOptions { + imports_not_used_as_values: deno_ast::ImportsNotUsedAsValues::Remove, + ..Default::default() + }, + &deno_ast::TranspileModuleOptions::default(), + &deno_ast::EmitOptions::default(), + ) + .unwrap_or_else(|e| panic!("snapshot transpile: emit failed for {name}: {e}")) + .into_source(); + + Ok((transpiled.text.into(), None)) +} + fn main() { println!("cargo:rustc-env=TARGET={}", env::var("TARGET").unwrap()); println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap()); @@ -105,7 +176,7 @@ fn main() { cargo_manifest_dir: env!("CARGO_MANIFEST_DIR"), startup_snapshot: None, extension_transpiler: Some(std::rc::Rc::new(|specifier, source| { - deno_runtime::transpile::maybe_transpile_source(specifier, source) + maybe_transpile_source(specifier, source) })), extensions: exts, with_runtime_cb: None, From 3cd0eac8c15ec22a65035925e9b52d47cb217056 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Mon, 11 May 2026 21:13:24 +0000 Subject: [PATCH 13/21] deps: bump deno_core / deno_ast / swc to the goldilocks pin set; drop serde ceiling (#9111) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * deps: bump deno_core / deno_ast / swc to the goldilocks pin set; drop serde ceiling Bumps every deno_* and swc_* workspace dep to a hand-picked "goldilocks" combination that drops the serde =1.0.220 ceiling without crashing into the rustls / aws-sdk resolver wall that the obvious deno v2.6.0 target hits. ## What's the goldilocks set | crate | old | new | source | |------------------|----------|-----------|---------------------------------------| | deno_core | 0.336.0 | 0.352.0 | deno v2.4.0 | | deno_fetch | 0.214.0 | 0.233.0 | deno v2.4.0 | | deno_tls | 0.177.0 | 0.196.0 | deno v2.4.0 (last permissive-rustls) | | deno_console | 0.190.0 | 0.209.0 | deno v2.4.0 | | deno_url | 0.190.0 | 0.209.0 | deno v2.4.0 | | deno_webidl | 0.190.0 | 0.209.0 | deno v2.4.0 | | deno_web | 0.221.0 | 0.240.0 | deno v2.4.0 | | deno_io | 0.100.0 | 0.119.0 | deno v2.4.0 | | deno_net | 0.182.0 | 0.201.0 | deno v2.4.0 | | deno_permissions | 0.49.0 | 0.68.0 | deno v2.4.0 | | deno_telemetry | 0.12.0 | 0.31.0 | deno v2.4.0 | | deno_error | =0.5.5 | =0.6.1 | deno v2.4.0 | | deno_ast | =0.44.0 | =0.51.0 | **override** — see "load-bearing" below | | deno_fs | (new) | 0.119.0 | new workspace dep — FetchPermissions exposes deno_fs::CheckedPath / GetPath as public API | | v8 | =130.0.7 | =137.1.0 | deno_core 0.352 transitive | | swc_common | =0.37.5 | =14.0.4 | **the load-bearing pin** | | swc_ecma_ast | =0.118.2 | =15.0.0 | matched set with swc_common 14.0.4 | | swc_ecma_parser | =0.149.1 | =24.0.3 | matched set | | swc_ecma_visit | =0.104.8 | =15.0.0 | matched set | | serde | =1.0.220 | ^1 | **freed** (resolves to 1.0.228+) | ## Why this combination and not v2.6.0 The obvious target was deno v2.6.0 (with deno_ast 0.52 → swc_common 17, well past the `__private` ceiling). That hits three resolver collisions: 1. libsqlite3-sys: deno_cache → rusqlite 0.37 → libsqlite3-sys 0.35 vs sqlx → libsqlite3-sys 0.30. **Already killed by PR #9110** — we dropped deno_runtime, which is what pulled in deno_cache. 2. fqdn 0.4.6/0.4.7 yanked, required by deno_permissions 0.81.0. Solvable by injecting the yanked entry into Cargo.lock manually but ugly. 3. rustls: deno_tls 0.198+ hard-pins `=0.23.28`, but aws-sdk-bedrockruntime 1.122.0 → aws-smithy-http-client 1.1.5 wants `^0.23.31`. Within-major conflict, no resolver path. The unbeatable wall. Goldilocks-set choice sidesteps (2) and (3) entirely: - `deno_tls 0.196.0` was the last version before deno tightened `rustls ^0.23.11` (range, accepts 0.23.31) to exact `=0.23.28`. With ^0.23.11, the resolver picks rustls 0.23.35 (latest 0.23 patch) which satisfies both deno_tls's `>=0.23.11` and aws-sdk's `>=0.23.31`. Verified empirically: lockfile has rustls 0.23.35 after this bump. - `deno_permissions 0.68.0` (v2.4.0's pin) doesn't depend on fqdn at all. The fqdn dep was added in a later deno_permissions release. ## Why deno_ast =0.51.0 specifically (not 0.48.0 from v2.4.0) `swc_common 14.0.4` is the first patch that **drops the `pub use serde::__private as serde;` line** in `src/private/mod.rs`. Older 14.0.x and all 0.37.5–13.x revisions still have it, and that line is what was capping `serde = "=1.0.220"` (the workspace pin's "stuck because of swc" comment). Empirically verified by inspecting the tarballs of 14.0.0 / 14.0.1 / 14.0.2 / 14.0.3 / 14.0.4: 14.0.0: has hack 14.0.1: has hack 14.0.2: has hack 14.0.3: has hack 14.0.4: NO HACK ← inflection point `deno_ast 0.51.0` pins `swc_common =14.0.4` exactly — older deno_ast versions pin earlier swc_common patches that still have the hack. Notably, deno v2.4.0 itself pins `deno_ast =0.48.0` (swc_common 9.2.0, still has hack) — we deliberately deviate from v2.4.0's deno_ast pin to escape the swc serde wall, while keeping the rest of v2.4.0's pin set for resolver compatibility with aws-sdk. deno_ast 0.51 was never shipped in any deno release (v2.4.5 used 0.49, v2.5.0 jumped to 0.50, v2.6.0 to 0.52), but it's published on crates.io and compatible with v2.4.0's deno_core 0.352. ## What this unblocks - PR #9106's `serde = "=1.0.224"` bump variant can rebase onto this and resolve cleanly (MaterializeInc/rust-postgres' `postgres-types` needs `serde_core ^1.0.221`, which is satisfied now that we're on serde 1.0.228). - Future deno_* / swc_* bumps no longer need to argue about the serde ceiling — it's gone. ## What changes in source code This commit is Cargo.toml + Cargo.lock only. Source changes that the new deno_core / deno_fetch API requires live in the follow-up commits: - `parsers/windmill-parser-{ts,ts-asset,wac}`: swc 0.37 → 14 (`code.into()` ambiguity fix at 5 sites) - `windmill-runtime-nativets/build.rs` + `src/lib.rs`: deno_core 0.336 → 0.352 API moves (`init_ops_and_esm()` → `init()`, `FetchPermissions` / `NetPermissions` trait signature updates, `deno_tls::Proxy` enum shape change) A companion change in windmill-ee-private adjusts `otel_tracing_proxy_ee.rs:521` for `deno_telemetry::init`'s second arg becoming by-value (was `&OtelConfig`). * fix(parsers): adapt to swc_common 14 BytesStr ambiguity swc 0.37.5 → 14.0.4 changed `SourceMap::new_source_file`'s `src` argument from `String` to `impl Into`. With `BytesStr` available, the existing call sites' `code.into()` on a `&str` becomes ambiguous between `Into` (from the bytes crate) and `Into` (from bytes_str). Switch to `code.to_string()` to produce an owned `String` that satisfies `From for BytesStr` unambiguously. Five call sites across three crates: - windmill-parser-ts/src/lib.rs (3 sites) - windmill-parser-ts-asset/src/lib.rs (1 site) - windmill-parser-wac/src/typescript.rs (1 site) * fix(nativets): adapt to deno_core 0.352 / deno_fetch 0.233 API changes The goldilocks deno bump (deno_core 0.336 → 0.352, deno_fetch 0.214 → 0.233, etc.) ripples through nativets' build.rs and src/lib.rs. Source-level changes required: ## 1. `extension!` macro: `init_ops_and_esm()` and `init_ops()` removed deno_core 0.352's `extension!` macro now generates a single `init()` function on the extension struct (full: ops + esm), plus `lazy_init()` (ops only, with `needs_lazy_init = true` and a contract that the caller invokes `JsRuntime::lazy_init_extensions` after construction). - `build.rs` (snapshot creation, wants both ops and esm baked in): `X::init_ops_and_esm(...)` → `X::init(...)`. - `src/lib.rs:create_nativets_runtime` (runtime, was using `init_ops()` because the snapshot already provides esm): also → `X::init(...)`. deno_core's snapshot path skips esm re-execution when the snapshot provides them, so the esm registration is a no-op at runtime. This is how deno's own v2.4.0 runtime works. Avoided `lazy_init` because it requires plumbing `JsRuntime::lazy_init_extensions(ext_args_vec)` correctly across the codebase, which is invasive for no behavioural benefit. ## 2. Local `fetch` extension now declared in both build.rs and lib.rs deno_core 0.352 validates extension order between snapshot and runtime. Our snapshot's last extension is the local `fetch` ext (which provides ext:fetch/src/runtime.js). To avoid a runtime panic: "Extensions from snapshot loaded in wrong order: expected fetch but got windmill" …the runtime extension list now ends with `fetch::init()` matching the snapshot order. The macro requires the same `esm` argument to type-check, even though the ESM is not re-executed at runtime (it's in the snapshot). ## 3. `FetchPermissions` and `NetPermissions` trait shape `deno_fetch::FetchPermissions` (deno_fetch 0.233.0) added new methods and changed signatures: - `check_read` / `check_write`: now take `path: Cow<'a, Path>` plus a new `get_path: &'a dyn deno_fs::GetPath` parameter, and return `Result, FsError>` instead of `Result, FsError>`. - New `check_write` (didn't exist) and `check_net_vsock` methods. `deno_net::NetPermissions` (deno_net 0.201.0) gained `check_vsock` and `check_write_path` now takes `Cow<'_, Path>`. For `build.rs`'s `PermissionsContainer` (used only during snapshot creation, where permissions are never actually checked): all methods `unreachable!("snapshotting")`. For `src/lib.rs`'s `PermissionsContainer` (used at runtime — the nativets policy is "allow everything"): `check_read` / `check_write` return `Ok(CheckedPath::Unresolved(path))`, `check_*_vsock` return `Ok(())`. Smoke tests confirm fetch/net/url/web/blob/timers/structuredClone behaviour is intact end-to-end. ## 4. `deno_tls::Proxy` is now an enum `deno_tls::Proxy` was a struct, is now an enum with `Http`, `Https`, `Socks5` variants. Our call site uses HTTP proxies — switched the struct literal `deno_tls::Proxy { url, basic_auth }` to `deno_tls::Proxy::Http { url, basic_auth }`. ## 5. New `deno_fs` direct workspace dep `FetchPermissions` exposes `deno_fs::CheckedPath` and `deno_fs::GetPath` as part of its public API. We can't avoid naming `deno_fs` directly any more. Pinned to 0.119.0 (v2.4.0's matched version, transitively present already through deno_fetch). Added to workspace `[dependencies]` plus nativets's `[dependencies]` and `[build-dependencies]`. ## Validation `cargo check --features enterprise,deno_core,duckdb,license,python,rust,scoped_cache,parquet,private,private_registry_test,csharp,php,ruby,mysql,quickjs,mcp,run_inline` → clean. `cargo test -p windmill-runtime-nativets smoke -- --ignored --skip smoke_net_` → 8 passed; 0 failed (the full local smoke suite covering fetch, setTimeout/Promise.all, URL/SearchParams, Blob/btoa/atob, large payload roundtrip, error propagation, concurrent isolates, TS enum/union transpile). Network smoke tests (`smoke_net_fetch_example_com`, `smoke_net_fetch_json_and_headers`) not run as part of the validation gate but expected to pass — the change preserves deno_fetch behaviour through the trait surface. * chore: update ee-repo-ref to pick up deno_telemetry::init by-value fix Points at windmill-ee-private branch deps/bump-deno-and-swc-goldilocks which contains the companion otel_tracing_proxy_ee.rs adjustment for deno_telemetry 0.12 → 0.31 (second arg of `init` is now by-value). EE-only file, doesn't affect OSS build. * chore(nix): bump rusty_v8 in flake.nix to 137.1.0 to match Cargo.toml Cargo.toml's v8 pin moved from =130.0.7 to =137.1.0 as part of the deno_core 0.336 → 0.352 bump, but I missed the comment directly above the version pin: # Exact version NOTE: Do not forget to update version and hash in flake.nix flake.nix provides the prebuilt librusty_v8 binary that the v8 crate links against. A version mismatch would either fail to fetch (if the 137.1.0 release didn't exist) or cause link-time symbol mismatches. Nix is used by rust-client-check.yml and rust_on_release.yml in CI, plus the dev shell — stale flake pin breaks all of those. Updates x86_64-linux's sha256 to match the actual hash of librusty_v8_release_x86_64-unknown-linux-gnu.a.gz at the 137.1.0 tag. Other targets (aarch64-linux, x86_64-darwin, aarch64-darwin) remain as lib.fakeHash — they were already placeholders in the previous pin, so we don't regress on them. Caught by both cubic and Pi reviewers on PR #9111. * docs(nativets): clarify snapshot-prefix rule in extension-order comment Claude reviewer caught that the doc comment claimed the runtime extension list matches the snapshot's order — implying an exact match. The truth is more permissive: deno_core 0.352 requires the snapshot's extension list to be a *prefix* of the runtime's, not an exact match. Runtime is allowed to append extra extensions (which we do — the windmill `ext` carrying our ops is the last entry at runtime but absent from the snapshot). The code is correct as-is; only the comment wording was misleading. Also fixes the same wording in PR description. --- backend/Cargo.lock | 810 ++++++++++-------- backend/Cargo.toml | 48 +- backend/ee-repo-ref.txt | 2 +- .../windmill-parser-ts-asset/src/lib.rs | 2 +- backend/parsers/windmill-parser-ts/src/lib.rs | 6 +- .../windmill-parser-wac/src/typescript.rs | 2 +- backend/windmill-runtime-nativets/Cargo.toml | 2 + backend/windmill-runtime-nativets/build.rs | 70 +- backend/windmill-runtime-nativets/src/lib.rs | 90 +- flake.nix | 4 +- 10 files changed, 593 insertions(+), 443 deletions(-) diff --git a/backend/Cargo.lock b/backend/Cargo.lock index c5a26d1b45..d4ec956b96 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -2,16 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" -dependencies = [ - "lazy_static", - "regex", -] - [[package]] name = "addr2line" version = "0.25.1" @@ -21,12 +11,6 @@ dependencies = [ "gimli", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler2" version = "2.0.1" @@ -467,6 +451,12 @@ dependencies = [ "regex-syntax 0.8.10", ] +[[package]] +name = "ascii" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" + [[package]] name = "asn1-rs" version = "0.6.2" @@ -508,11 +498,10 @@ dependencies = [ [[package]] name = "ast_node" -version = "0.9.9" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9184f2b369b3e8625712493c89b785881f27eedc6cde480a81883cef78868b2" +checksum = "0a184645bcc6f52d69d8e7639720699c6a99efb711f886e251ed1d16db8dd90e" dependencies = [ - "proc-macro2", "quote", "swc_macros_common", "syn 2.0.117", @@ -1252,7 +1241,7 @@ version = "1.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "576b0d6991c9c32bc14fc340582ef148311f924d41815f641a308b5d11e8e7cd" dependencies = [ - "base64-simd 0.8.0", + "base64-simd", "bytes", "bytes-utils", "futures-core", @@ -1444,7 +1433,7 @@ dependencies = [ "addr2line", "cfg-if", "libc", - "miniz_oxide 0.8.9", + "miniz_oxide", "object", "rustc-demangle", "windows-link 0.2.1", @@ -1480,22 +1469,13 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "base64-simd" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "781dd20c3aff0bd194fe7d2a977dd92f21c173891f3a03b677359e5fa457e5d5" -dependencies = [ - "simd-abstraction", -] - [[package]] name = "base64-simd" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" dependencies = [ - "outref 0.5.2", + "outref", "vsimd", ] @@ -1507,9 +1487,9 @@ checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "better_scoped_tls" -version = "0.1.2" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297b153aa5e573b5863108a6ddc9d5c968bd0b20e75cc614ee9821d2f45679c7" +checksum = "7cd228125315b132eed175bf47619ac79b945b26e56b848ba203ae4ea8603609" dependencies = [ "scoped-tls", ] @@ -1536,26 +1516,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bindgen" -version = "0.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" -dependencies = [ - "bitflags 2.9.4", - "cexpr", - "clang-sys", - "itertools 0.13.0", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash 1.1.0", - "shlex", - "syn 2.0.117", -] - [[package]] name = "bindgen" version = "0.71.1" @@ -1596,15 +1556,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec 0.6.3", -] - [[package]] name = "bit-set" version = "0.8.0" @@ -1972,6 +1923,16 @@ dependencies = [ "serde", ] +[[package]] +name = "bytes-str" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c60b5ce37e0b883c37eb89f79a1e26fbe9c1081945d024eee93e8d91a7e18b3" +dependencies = [ + "bytes", + "serde", +] + [[package]] name = "bytes-utils" version = "0.1.4" @@ -2065,15 +2026,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "capacity_builder" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58ec49028cb308564429cd8fac4ef21290067a0afe8f5955330a8d487d0d790c" -dependencies = [ - "itoa", -] - [[package]] name = "capacity_builder" version = "0.5.0" @@ -2094,6 +2046,15 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "castaway" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" +dependencies = [ + "rustversion", +] + [[package]] name = "cc" version = "1.2.62" @@ -2295,6 +2256,19 @@ dependencies = [ "unicode-width 0.2.2", ] +[[package]] +name = "compact_str" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "ryu", + "static_assertions", +] + [[package]] name = "concurrent-queue" version = "2.5.0" @@ -2872,19 +2846,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "dashmap" -version = "5.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" -dependencies = [ - "cfg-if", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", -] - [[package]] name = "dashmap" version = "6.1.0" @@ -2974,7 +2935,7 @@ checksum = "61fe34f401bd03724a1f96d12108144f8cd495a3cdda2bf5e091822fb80b7e66" dependencies = [ "arrow", "async-trait", - "dashmap 6.1.0", + "dashmap", "datafusion-common", "datafusion-common-runtime", "datafusion-datasource", @@ -3180,7 +3141,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06f004d100f49a3658c9da6fb0c3a9b760062d96cd4ad82ccc3b7b69a9fb2f84" dependencies = [ "arrow", - "dashmap 6.1.0", + "dashmap", "datafusion-common", "datafusion-expr", "futures", @@ -3476,7 +3437,7 @@ checksum = "ad229a134c7406c057ece00c8743c0c34b97f4e72f78b475fe17b66c5e14fa4f" dependencies = [ "arrow", "async-trait", - "dashmap 6.1.0", + "dashmap", "datafusion-common", "datafusion-common-runtime", "datafusion-execution", @@ -3533,19 +3494,18 @@ dependencies = [ [[package]] name = "deno_ast" -version = "0.44.0" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eebc7aaabfdb3ddcad32aee1b62d250149dc8b35dfbdccbb125df2bdc62da952" +checksum = "c72e0409b3dbd60a5bf296cbc273a8e36bb3a3aab6abac389f1891e187d5ce14" dependencies = [ - "base64 0.21.7", - "deno_error", + "base64 0.22.1", + "capacity_builder", + "deno_error 0.7.3", "deno_media_type", "deno_terminal", "dprint-swc-ext", - "once_cell", "percent-encoding", "serde", - "sourcemap 9.3.2", "swc_atoms", "swc_common", "swc_config", @@ -3553,6 +3513,7 @@ dependencies = [ "swc_ecma_ast", "swc_ecma_codegen", "swc_ecma_codegen_macros", + "swc_ecma_lexer", "swc_ecma_loader", "swc_ecma_parser", "swc_ecma_transforms_base", @@ -3565,46 +3526,45 @@ dependencies = [ "swc_ecma_visit", "swc_eq_ignore_macros", "swc_macros_common", + "swc_sourcemap", "swc_visit", - "swc_visit_macros", "text_lines", "thiserror 2.0.18", - "unicode-width 0.1.14", + "unicode-width 0.2.2", "url", ] [[package]] name = "deno_console" -version = "0.190.0" +version = "0.209.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94352b8d75c288a26ef748ad0ddae07e181109374a02c547850f96eef76b5389" +checksum = "66c0b8a65dcb7b38c22e5969c6454b3cb0839b7dcfb7a4f0d904de871a4c4416" dependencies = [ "deno_core", ] [[package]] name = "deno_core" -version = "0.336.0" +version = "0.352.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd50476c4325d5fa52bb906804a1e35b127d2a1dcf674e3447b53dcf25525bf" +checksum = "bf78f3f72ac8e09b18a588bc26a1b3c5ab853e7fb489889b2f5000654d34db5d" dependencies = [ "anyhow", "az", "bincode", - "bit-set 0.5.3", - "bit-vec 0.6.3", + "bit-set", + "bit-vec 0.8.0", "bytes", - "capacity_builder 0.1.3", + "capacity_builder", "cooked-waker", "deno_core_icudata", - "deno_error", + "deno_error 0.6.1", "deno_ops", "deno_path_util", "deno_unsync", "futures", "indexmap 2.14.0", "libc", - "memoffset", "parking_lot", "percent-encoding", "pin-project", @@ -3612,7 +3572,7 @@ dependencies = [ "serde_json", "serde_v8", "smallvec", - "sourcemap 8.0.1", + "sourcemap", "static_assertions", "thiserror 2.0.18", "tokio", @@ -3629,11 +3589,11 @@ checksum = "fe4dccb6147bb3f3ba0c7a48e993bfeb999d2c2e47a81badee80e2b370c8d695" [[package]] name = "deno_error" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c23dbc46d5804814b08b4675838f9884e3a52916987ec5105af36d42f9911b5" +checksum = "612ec3fc481fea759141b0c57810889b0a4fb6fee8f10748677bfe492fd30486" dependencies = [ - "deno_error_macro", + "deno_error_macro 0.6.1", "libc", "serde", "serde_json", @@ -3642,10 +3602,20 @@ dependencies = [ ] [[package]] -name = "deno_error_macro" -version = "0.5.5" +name = "deno_error" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "babccedee31ce7e57c3e6dff2cb3ab8d68c49d0df8222fe0d11d628e65192790" +checksum = "3007d3f1ea92ea503324ae15883aac0c2de2b8cf6fead62203ff6a67161007ab" +dependencies = [ + "deno_error_macro 0.7.3", + "libc", +] + +[[package]] +name = "deno_error_macro" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8380a4224d5d2c3f84da4d764c4326cac62e9a1e3d4960442d29136fc07be863" dependencies = [ "proc-macro2", "quote", @@ -3653,16 +3623,38 @@ dependencies = [ ] [[package]] -name = "deno_fetch" -version = "0.214.0" +name = "deno_error_macro" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3df032ca1f7f06a5cc459189b960793f64d415ddc9f59f262e0ad5059865002d" +checksum = "9b565e60a9685cdf312c888665b5f8647ac692a7da7e058a5e2268a466da8eaf" dependencies = [ - "base64 0.21.7", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "deno_features" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "487773bb24b92f3b88d1c9ef0d4d15888641a2e2ea4d4cdfd6fda12cae26317c" +dependencies = [ + "deno_core", + "serde", + "serde_json", +] + +[[package]] +name = "deno_fetch" +version = "0.233.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cbe158bec955790105ded69978b1245b97c65092f7bf184add344c0e78efffa" +dependencies = [ + "base64 0.22.1", "bytes", "data-url", "deno_core", - "deno_error", + "deno_error 0.6.1", "deno_fs", "deno_path_util", "deno_permissions", @@ -3686,6 +3678,7 @@ dependencies = [ "tokio-rustls 0.26.4", "tokio-socks", "tokio-util", + "tokio-vsock", "tower 0.5.3", "tower-http", "tower-service", @@ -3693,15 +3686,15 @@ dependencies = [ [[package]] name = "deno_fs" -version = "0.100.0" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c82f79b71403b93b248727a89746026104b3a5ac1d82e79a02af6fa8e8487666" +checksum = "5ca83a95cea7bcdf19dac1888ef6f04aff69d251640a4d085bc6089c06b4b181" dependencies = [ "async-trait", "base32", "boxed_error", "deno_core", - "deno_error", + "deno_error 0.6.1", "deno_io", "deno_path_util", "deno_permissions", @@ -3719,17 +3712,19 @@ dependencies = [ [[package]] name = "deno_io" -version = "0.100.0" +version = "0.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e72489fe0dcada08047611d1ab92db1baebf7b606ab7c78790f622ecb30e22b" +checksum = "597aac25be261a1bd545d6f47a80439c60e600c076f9847b3718a592883b2a73" dependencies = [ "async-trait", "deno_core", - "deno_error", + "deno_error 0.6.1", + "deno_subprocess_windows", "filetime", "fs3", "libc", "log", + "nix 0.27.1", "once_cell", "os_pipe", "parking_lot", @@ -3743,9 +3738,9 @@ dependencies = [ [[package]] name = "deno_media_type" -version = "0.2.5" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "600222d059ab31ff31182b3e12615df2134a9e01605836b78ad8df91ba39eab3" +checksum = "9fd0af4161f90b092feb363864a64d7c74e0efc13a15905d0d09df73bb72a123" dependencies = [ "data-url", "serde", @@ -3767,12 +3762,13 @@ dependencies = [ [[package]] name = "deno_net" -version = "0.182.0" +version = "0.201.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab869063cbfe428a707511835865d55247886eb175659e538af4d5096c3d4d9d" +checksum = "eb88f1ea2762065d6cc0316372acc22696ab6004943aa029f80546f9faf1b491" dependencies = [ "deno_core", - "deno_error", + "deno_error 0.6.1", + "deno_features", "deno_permissions", "deno_tls", "hickory-proto", @@ -3781,35 +3777,39 @@ dependencies = [ "quinn", "rustls-tokio-stream", "serde", + "sha2 0.10.9", "socket2 0.5.10", "thiserror 2.0.18", "tokio", + "tokio-vsock", + "url", + "web-transport-proto", ] [[package]] name = "deno_ops" -version = "0.212.0" +version = "0.228.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2d328067139909aa81522a5d90f119368b541fbddd73ab630e4d9f777865f0d" +checksum = "8bf8dbe5abf37d270bb853c5dfe45fbe3b1b6c453877cc11d7fe84e9862a6dbc" dependencies = [ "indexmap 2.14.0", "proc-macro-rules", "proc-macro2", "quote", "stringcase", - "strum 0.25.0", - "strum_macros 0.25.3", + "strum 0.27.2", + "strum_macros 0.27.2", "syn 2.0.117", "thiserror 2.0.18", ] [[package]] name = "deno_path_util" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87b8996966ae1b13ee9c20219b1d10fc53905b9570faae6adfa34614fd15224" +checksum = "516f813389095889776b81cc9108ff6f336fd9409b4b12fc0138aea23d2708e1" dependencies = [ - "deno_error", + "deno_error 0.6.1", "percent-encoding", "sys_traits", "thiserror 2.0.18", @@ -3818,35 +3818,54 @@ dependencies = [ [[package]] name = "deno_permissions" -version = "0.49.0" +version = "0.68.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf879dff0b3de4dbcb78d6dda3a55e711369d5b9f479270a82853ef106c4176" +checksum = "baa14d9c3fbba59836ffbaac7f736a2f48d4a5fc209a2103d1e1b898915232a5" dependencies = [ - "capacity_builder 0.5.0", - "deno_core", - "deno_error", + "capacity_builder", + "deno_error 0.6.1", "deno_path_util", "deno_terminal", + "deno_unsync", "fqdn", + "ipnetwork", "libc", "log", + "nix 0.27.1", "once_cell", + "parking_lot", "percent-encoding", "serde", + "serde_json", + "sys_traits", + "temp_deno_which", "thiserror 2.0.18", - "which 6.0.3", + "url", "winapi", + "windows-sys 0.59.0", +] + +[[package]] +name = "deno_subprocess_windows" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bc6b10059f0ccb14c6e0319c5275f0407fb2f9ffe405cd555700561999ea4bf" +dependencies = [ + "fastrand", + "futures-channel", + "libc", + "windows-sys 0.59.0", ] [[package]] name = "deno_telemetry" -version = "0.12.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d73802ee27361bbb6c0e3c04a799b39f458afbed1972c4aff0867420d1c36fdb" +checksum = "377581966bd34e85ce230f7f4b1dee7e16c6bf7f845b4690648507ce7ba105d9" dependencies = [ "async-trait", "deno_core", - "deno_error", + "deno_error 0.6.1", "deno_tls", "http-body-util", "hyper 1.9.0", @@ -3867,9 +3886,9 @@ dependencies = [ [[package]] name = "deno_terminal" -version = "0.2.3" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3ba8041ae7319b3ca6a64c399df4112badcbbe0868b4517637647614bede4be" +checksum = "23f71c27009e0141dedd315f1dfa3ebb0a6ca4acce7c080fac576ea415a465f6" dependencies = [ "once_cell", "termcolor", @@ -3877,12 +3896,12 @@ dependencies = [ [[package]] name = "deno_tls" -version = "0.177.0" +version = "0.196.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e3ceb2be448150d8214e8fc454c947e0ea94f6ce16556544f05a67ad5a16b8" +checksum = "a7835eb6a8d114703b0293573fbb8885bc2c81e8c35363b9e89391dd3c541fa6" dependencies = [ "deno_core", - "deno_error", + "deno_error 0.6.1", "deno_native_certs", "rustls 0.23.35", "rustls-pemfile 2.2.0", @@ -3907,27 +3926,26 @@ dependencies = [ [[package]] name = "deno_url" -version = "0.190.0" +version = "0.209.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d79e743ad841f7826d46c6944580f5ba665fe9ab4c31a68c4eed8b5a78225da3" +checksum = "8cccbb10fb59f29b04161055a65f7fe83364f9e8317d4d2ce3bd7979faf63a87" dependencies = [ "deno_core", - "deno_error", - "thiserror 2.0.18", + "deno_error 0.6.1", "urlpattern", ] [[package]] name = "deno_web" -version = "0.221.0" +version = "0.240.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8041ba73bb2f238c61b5e4ed341d2fe1f9464a71115a240ab3390480b3c10e12" +checksum = "1d6b8a97cc90b6aaea20fe200cfa7e5b6953dd33ecda0af50d6d360387c33df4" dependencies = [ "async-trait", - "base64-simd 0.8.0", + "base64-simd", "bytes", "deno_core", - "deno_error", + "deno_error 0.6.1", "deno_permissions", "encoding_rs", "flate2", @@ -3940,9 +3958,9 @@ dependencies = [ [[package]] name = "deno_webidl" -version = "0.190.0" +version = "0.209.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4ff81a990196bf3a80fe5d339b4eb8b411ef17634d60d399a63bae6e71a37c9" +checksum = "a20bbfac0cf15918f7cbd0b55c366ac20ad65c825f362fa684c3104984254d3b" dependencies = [ "deno_core", ] @@ -4267,15 +4285,16 @@ checksum = "117240f60069e65410b3ae1bb213295bd828f707b5bec6596a1afc8793ce0cbc" [[package]] name = "dprint-swc-ext" -version = "0.20.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ba28c12892aadb751c2ba7001d8460faee4748a04b4edc51c7121cc67ee03db" +checksum = "cf592ae6a864437e98ef9c6ae7936b822077e9d038a3a48ee081ab92313afad4" dependencies = [ "num-bigint", - "rustc-hash 1.1.0", + "rustc-hash 2.1.2", "swc_atoms", "swc_common", "swc_ecma_ast", + "swc_ecma_lexer", "swc_ecma_parser", "text_lines", ] @@ -4410,9 +4429,9 @@ checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "encoding_rs" -version = "0.8.33" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] @@ -4572,7 +4591,7 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e24cb5a94bcae1e5408b0effca5cd7172ea3c5755049c5f3af4cd283a165298" dependencies = [ - "bit-set 0.8.0", + "bit-set", "regex-automata", "regex-syntax 0.8.10", ] @@ -4583,7 +4602,7 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72cf461f865c862bb7dc573f643dd6a2b6842f7c30b07882b56bd148cc2761b8" dependencies = [ - "bit-set 0.8.0", + "bit-set", "regex-automata", "regex-syntax 0.8.10", ] @@ -4657,7 +4676,7 @@ checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "libz-sys", - "miniz_oxide 0.8.9", + "miniz_oxide", "zlib-rs", ] @@ -4735,11 +4754,10 @@ checksum = "eb540cf7bc4fe6df9d8f7f0c974cfd0dce8ed4e9e8884e73433b503ee78b4e7d" [[package]] name = "from_variant" -version = "0.1.9" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32016f1242eb82af5474752d00fd8ebcd9004bd69b462b1c91de833972d08ed4" +checksum = "308530a56b099da144ebc5d8e179f343ad928fa2b3558d1eb3db9af18d6eff43" dependencies = [ - "proc-macro2", "swc_macros_common", "syn 2.0.117", ] @@ -5618,15 +5636,14 @@ dependencies = [ [[package]] name = "hstr" -version = "0.2.17" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a26def229ea95a8709dad32868d975d0dd40235bd2ce82920e4a8fe692b5e0" +checksum = "31f11d91d7befd2ffd9d216e9e5ea1fae6174b20a2a1b67a688138003d2f4122" dependencies = [ "hashbrown 0.14.5", "new_debug_unreachable", "once_cell", - "phf 0.11.3", - "rustc-hash 1.1.0", + "rustc-hash 2.1.2", "triomphe", ] @@ -6203,6 +6220,15 @@ version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" +[[package]] +name = "ipnetwork" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" +dependencies = [ + "serde", +] + [[package]] name = "is-macro" version = "0.3.7" @@ -7171,15 +7197,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.8.9" @@ -7409,6 +7426,19 @@ dependencies = [ "libc", ] +[[package]] +name = "nix" +version = "0.31.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + [[package]] name = "nkeys" version = "0.4.5" @@ -8126,6 +8156,8 @@ dependencies = [ "rand 0.8.5", "serde_json", "thiserror 1.0.69", + "tokio", + "tokio-stream", "tracing", ] @@ -8200,20 +8232,14 @@ dependencies = [ [[package]] name = "os_pipe" -version = "1.1.5" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57119c3b893986491ec9aa85056780d3a0f3cf4da7cc09dd3650dbd6c6738fb9" +checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] -[[package]] -name = "outref" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f222829ae9293e33a9f5e9f440c6760a3d450a64affe1846486b140db81c1f4" - [[package]] name = "outref" version = "0.5.2" @@ -8258,6 +8284,15 @@ dependencies = [ "sha2 0.10.9", ] +[[package]] +name = "par-core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e96cbd21255b7fb29a5d51ef38a779b517a91abd59e2756c039583f43ef4c90f" +dependencies = [ + "once_cell", +] + [[package]] name = "parking" version = "2.2.1" @@ -10096,9 +10131,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-tokio-stream" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22557157d7395bc30727745b365d923f1ecc230c4c80b176545f3f4f08c46e33" +checksum = "faa7dc7c991d9164e55bbf1558029eb5b84d32cc4d61a7df5b8641b2deedc4b3" dependencies = [ "futures", "rustls 0.23.35", @@ -10480,9 +10515,9 @@ checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" [[package]] name = "serde" -version = "1.0.220" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceecad4c782e936ac90ecfd6b56532322e3262b14320abf30ce89a92ffdbfe22" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", @@ -10523,18 +10558,18 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.220" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddba47394f3b862d6ff6efdbd26ca4673e3566a307880a0ffb98f274bbe0ec32" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.220" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60e1f3b1761e96def5ec6d04a6e7421c0404fa3cf5c0155f1e2848fae3d8cc08" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -10629,11 +10664,11 @@ dependencies = [ [[package]] name = "serde_v8" -version = "0.245.0" +version = "0.261.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "945f93c91e0c7e4799b5fefff076756141aae92e262c4dc4833310dd3d2d845e" +checksum = "3495190857461e87a2716141043218aad5281f219f54a03b7ebbe605b3b931df" dependencies = [ - "deno_error", + "deno_error 0.6.1", "num-bigint", "serde", "smallvec", @@ -10839,15 +10874,6 @@ dependencies = [ "rand_core 0.6.4", ] -[[package]] -name = "simd-abstraction" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cadb29c57caadc51ff8346233b5cec1d240b68ce55cf1afc764818791876987" -dependencies = [ - "outref 0.1.0", -] - [[package]] name = "simd-adler32" version = "0.3.9" @@ -10968,32 +10994,13 @@ dependencies = [ "winapi", ] -[[package]] -name = "sourcemap" -version = "8.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "208d40b9e8cad9f93613778ea295ed8f3c2b1824217c6cfc7219d3f6f45b96d4" -dependencies = [ - "base64-simd 0.7.0", - "bitvec", - "data-encoding", - "debugid", - "if_chain", - "rustc-hash 1.1.0", - "rustc_version 0.2.3", - "serde", - "serde_json", - "unicode-id-start", - "url", -] - [[package]] name = "sourcemap" version = "9.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "314d62a489431668f719ada776ca1d49b924db951b7450f8974c9ae51ab05ad7" dependencies = [ - "base64-simd 0.8.0", + "base64-simd", "bitvec", "data-encoding", "debugid", @@ -11327,11 +11334,10 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "string_enum" -version = "0.4.4" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05e383308aebc257e7d7920224fa055c632478d92744eca77f99be8fa1545b90" +checksum = "ae36a4951ca7bd1cfd991c241584a9824a70f6aff1e7d4f693fb3f2465e4030e" dependencies = [ - "proc-macro2", "quote", "swc_macros_common", "syn 2.0.117", @@ -11339,9 +11345,9 @@ dependencies = [ [[package]] name = "stringcase" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04028eeb851ed08af6aba5caa29f2d59a13ed168cee4d6bd753aeefcf1d636b0" +checksum = "72abeda133c49d7bddece6c154728f83eec8172380c80ab7096da9487e20d27c" [[package]] name = "stringprep" @@ -11447,64 +11453,48 @@ checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" [[package]] name = "swc_allocator" -version = "0.1.10" +version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76aa0eb65c0f39f9b6d82a7e5192c30f7ac9a78f084a21f270de1d8c600ca388" +checksum = "9d7eefd2c8b228a8c73056482b2ae4b3a1071fbe07638e3b55ceca8570cc48bb" dependencies = [ + "allocator-api2", "bumpalo", "hashbrown 0.14.5", - "ptr_meta", - "rustc-hash 1.1.0", - "triomphe", + "rustc-hash 2.1.2", ] [[package]] name = "swc_atoms" -version = "0.6.7" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb6567e4e67485b3e7662b486f1565bdae54bd5b9d6b16b2ba1a9babb1e42125" +checksum = "3500dcf04c84606b38464561edc5e46f5132201cb3e23cf9613ed4033d6b1bb2" dependencies = [ "hstr", "once_cell", - "rustc-hash 1.1.0", - "serde", -] - -[[package]] -name = "swc_cached" -version = "0.3.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83406221c501860fce9c27444f44125eafe9e598b8b81be7563d7036784cd05c" -dependencies = [ - "ahash 0.8.12", - "anyhow", - "dashmap 5.5.3", - "once_cell", - "regex", "serde", ] [[package]] name = "swc_common" -version = "0.37.5" +version = "14.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12d0a8eaaf1606c9207077d75828008cb2dfb51b095a766bd2b72ef893576e31" +checksum = "c2bb772b3a26b8b71d4e8c112ced5b5867be2266364b58517407a270328a2696" dependencies = [ + "anyhow", "ast_node", "better_scoped_tls", - "cfg-if", + "bytes-str", "either", "from_variant", "new_debug_unreachable", "num-bigint", "once_cell", - "rustc-hash 1.1.0", + "rustc-hash 2.1.2", "serde", "siphasher 0.3.11", - "sourcemap 9.3.2", - "swc_allocator", "swc_atoms", "swc_eq_ignore_macros", + "swc_sourcemap", "swc_visit", "tracing", "unicode-width 0.1.14", @@ -11513,23 +11503,23 @@ dependencies = [ [[package]] name = "swc_config" -version = "0.1.15" +version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4740e53eaf68b101203c1df0937d5161a29f3c13bceed0836ddfe245b72dd000" +checksum = "72e90b52ee734ded867104612218101722ad87ff4cf74fe30383bd244a533f97" dependencies = [ "anyhow", + "bytes-str", "indexmap 2.14.0", "serde", "serde_json", - "swc_cached", "swc_config_macro", ] [[package]] name = "swc_config_macro" -version = "0.1.4" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c5f56139042c1a95b54f5ca48baa0e0172d369bcc9d3d473dad1de36bae8399" +checksum = "7b416e8ce6de17dc5ea496e10c7012b35bbc0e3fef38d2e065eed936490db0b3" dependencies = [ "proc-macro2", "quote", @@ -11539,78 +11529,72 @@ dependencies = [ [[package]] name = "swc_ecma_ast" -version = "0.118.2" +version = "15.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6f866d12e4d519052b92a0a86d1ac7ff17570da1272ca0c89b3d6f802cd79df" +checksum = "65c25af97d53cf8aab66a6c68f3418663313fc969ad267fc2a4d19402c329be1" dependencies = [ "bitflags 2.9.4", "is-macro", "num-bigint", + "once_cell", "phf 0.11.3", - "scoped-tls", + "rustc-hash 2.1.2", "serde", "string_enum", "swc_atoms", "swc_common", + "swc_visit", "unicode-id-start", ] [[package]] name = "swc_ecma_codegen" -version = "0.155.1" +version = "17.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7641608ef117cfbef9581a99d02059b522fcca75e5244fa0cbbd8606689c6f" +checksum = "bcf55c2d7555c93f4945e29f93b7529562be97ba16e60dd94c25724d746174ac" dependencies = [ + "ascii", + "compact_str", "memchr", "num-bigint", "once_cell", + "regex", + "rustc-hash 2.1.2", + "ryu-js", "serde", - "sourcemap 9.3.2", "swc_allocator", "swc_atoms", "swc_common", "swc_ecma_ast", "swc_ecma_codegen_macros", + "swc_sourcemap", "tracing", ] [[package]] name = "swc_ecma_codegen_macros" -version = "0.7.7" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859fabde36db38634f3fad548dd5e3410c1aebba1b67a3c63e67018fa57a0bca" +checksum = "e276dc62c0a2625a560397827989c82a93fd545fcf6f7faec0935a82cc4ddbb8" dependencies = [ "proc-macro2", - "quote", "swc_macros_common", "syn 2.0.117", ] [[package]] -name = "swc_ecma_loader" -version = "0.49.1" +name = "swc_ecma_lexer" +version = "23.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55fa3d55045b97894bfb04d38aff6d6302ac8a6a38e3bb3dfb0d20475c4974a9" -dependencies = [ - "anyhow", - "pathdiff", - "serde", - "swc_atoms", - "swc_common", - "tracing", -] - -[[package]] -name = "swc_ecma_parser" -version = "0.149.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683dada14722714588b56481399c699378b35b2ba4deb5c4db2fb627a97fb54b" +checksum = "017d06ea85008234aa9fb34d805c7dc563f2ea6e03869ed5ac5a2dc27d561e4d" dependencies = [ + "arrayvec", + "bitflags 2.9.4", "either", - "new_debug_unreachable", "num-bigint", - "num-traits", "phf 0.11.3", + "rustc-hash 2.1.2", + "seq-macro", "serde", "smallvec", "smartstring", @@ -11619,23 +11603,52 @@ dependencies = [ "swc_common", "swc_ecma_ast", "tracing", - "typed-arena", +] + +[[package]] +name = "swc_ecma_loader" +version = "14.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c675d14700c92f12585049b22b02356f1e142f4b0c32a4d0eb4b7a968a4c0c1e" +dependencies = [ + "anyhow", + "pathdiff", + "rustc-hash 2.1.2", + "serde", + "swc_atoms", + "swc_common", + "tracing", +] + +[[package]] +name = "swc_ecma_parser" +version = "24.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9011783c975ba592ffc09cd208ced92b1dfabb2e5e0ef453559e2e25286127" +dependencies = [ + "either", + "num-bigint", + "serde", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_lexer", + "tracing", ] [[package]] name = "swc_ecma_transforms_base" -version = "0.145.0" +version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65f21494e75d0bd8ef42010b47cabab9caaed8f2207570e809f6f4eb51a710d1" +checksum = "6c6f1b8f4232e7a7f614ff7c0f6ccb89c2d028cdf7629f79ad710cff5b28b62c" dependencies = [ "better_scoped_tls", - "bitflags 2.9.4", "indexmap 2.14.0", "once_cell", + "par-core", "phf 0.11.3", - "rustc-hash 1.1.0", + "rustc-hash 2.1.2", "serde", - "smallvec", "swc_atoms", "swc_common", "swc_ecma_ast", @@ -11647,11 +11660,10 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_classes" -version = "0.134.0" +version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3d884594385bea9405a2e1721151470d9a14d3ceec5dd773c0ca6894791601" +checksum = "108d4d52db6151f768a516fe86e6f21fc783b03fa2d20292999f29275fd0c71d" dependencies = [ - "swc_atoms", "swc_common", "swc_ecma_ast", "swc_ecma_transforms_base", @@ -11661,9 +11673,9 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_macros" -version = "0.5.5" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500a1dadad1e0e41e417d633b3d6d5de677c9e0d3159b94ba3348436cdb15aab" +checksum = "bc777288799bf6786e5200325a56e4fbabba590264a4a48a0c70b16ad0cf5cd8" dependencies = [ "proc-macro2", "quote", @@ -11673,56 +11685,54 @@ dependencies = [ [[package]] name = "swc_ecma_transforms_proposal" -version = "0.179.0" +version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79938ff510fc647febd8c6c3ef4143d099fdad87a223680e632623d056dae2dd" +checksum = "39b3b34f6a28348416174912009d09994ab71c867682ec78d641a9feb3a96b4e" dependencies = [ "either", - "rustc-hash 1.1.0", + "rustc-hash 2.1.2", "serde", - "smallvec", "swc_atoms", "swc_common", "swc_ecma_ast", "swc_ecma_transforms_base", "swc_ecma_transforms_classes", - "swc_ecma_transforms_macros", "swc_ecma_utils", "swc_ecma_visit", ] [[package]] name = "swc_ecma_transforms_react" -version = "0.191.0" +version = "30.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76c76d8b9792ce51401d38da0fa62158d61f6d80d16d68fe5b03ce4bf5fba383" +checksum = "69ea0052ac23b5b9fbc85bbdb1791b36b918f9d55f594b0ed8e25babb4c32d16" dependencies = [ - "base64 0.21.7", - "dashmap 5.5.3", + "base64 0.22.1", + "bytes-str", "indexmap 2.14.0", "once_cell", + "rustc-hash 2.1.2", "serde", "sha1", "string_enum", - "swc_allocator", "swc_atoms", "swc_common", "swc_config", "swc_ecma_ast", "swc_ecma_parser", "swc_ecma_transforms_base", - "swc_ecma_transforms_macros", "swc_ecma_utils", "swc_ecma_visit", ] [[package]] name = "swc_ecma_transforms_typescript" -version = "0.198.1" +version = "30.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15455da4768f97186c40523e83600495210c11825d3a44db43383fd81eace88d" +checksum = "3872c006ccfdcc19f1cf5c01c15915a69964ba7982c9f581cdb7e727e77b9a2c" dependencies = [ - "ryu-js", + "bytes-str", + "rustc-hash 2.1.2", "serde", "swc_atoms", "swc_common", @@ -11735,28 +11745,28 @@ dependencies = [ [[package]] name = "swc_ecma_utils" -version = "0.134.2" +version = "21.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "029eec7dd485923a75b5a45befd04510288870250270292fc2c1b3a9e7547408" +checksum = "83259addd99ed4022aa9fc4d39428c008d3d42533769e1a005529da18cde4568" dependencies = [ "indexmap 2.14.0", "num_cpus", "once_cell", - "rustc-hash 1.1.0", + "par-core", + "rustc-hash 2.1.2", "ryu-js", "swc_atoms", "swc_common", "swc_ecma_ast", "swc_ecma_visit", "tracing", - "unicode-id", ] [[package]] name = "swc_ecma_visit" -version = "0.104.8" +version = "15.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b1c6802e68e51f336e8bc9644e9ff9da75d7da9c1a6247d532f2e908aa33e81" +checksum = "75a579aa8f9e212af521588df720ccead079c09fe5c8f61007cf724324aed3a0" dependencies = [ "new_debug_unreachable", "num-bigint", @@ -11769,9 +11779,9 @@ dependencies = [ [[package]] name = "swc_eq_ignore_macros" -version = "0.1.4" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63db0adcff29d220c3d151c5b25c0eabe7e32dd936212b84cdaa1392e3130497" +checksum = "c16ce73424a6316e95e09065ba6a207eba7765496fed113702278b7711d4b632" dependencies = [ "proc-macro2", "quote", @@ -11780,38 +11790,44 @@ dependencies = [ [[package]] name = "swc_macros_common" -version = "0.3.13" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f486687bfb7b5c560868f69ed2d458b880cebc9babebcb67e49f31b55c5bf847" +checksum = "aae1efbaa74943dc5ad2a2fb16cbd78b77d7e4d63188f3c5b4df2b4dcd2faaae" dependencies = [ "proc-macro2", "quote", "syn 2.0.117", ] +[[package]] +name = "swc_sourcemap" +version = "9.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de08ef00f816acdd1a58ee8a81c0e1a59eefef2093aefe5611f256fa6b64c4d7" +dependencies = [ + "base64-simd", + "bitvec", + "bytes-str", + "data-encoding", + "debugid", + "if_chain", + "rustc-hash 2.1.2", + "serde", + "serde_json", + "unicode-id-start", + "url", +] + [[package]] name = "swc_visit" -version = "0.6.2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ceb044142ba2719ef9eb3b6b454fce61ab849eb696c34d190f04651955c613d" +checksum = "62fb71484b486c185e34d2172f0eabe7f4722742aad700f426a494bb2de232a2" dependencies = [ "either", "new_debug_unreachable", ] -[[package]] -name = "swc_visit_macros" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92807d840959f39c60ce8a774a3f83e8193c658068e6d270dbe0a05e40e90b41" -dependencies = [ - "Inflector", - "proc-macro2", - "quote", - "swc_macros_common", - "syn 2.0.117", -] - [[package]] name = "symlink" version = "0.1.0" @@ -11871,9 +11887,23 @@ dependencies = [ [[package]] name = "sys_traits" -version = "0.1.7" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b46ac05dfbe9fd3a9703eff20e17f5b31e7b6a54daf27a421dcd56c7a27ecdd" +checksum = "dc4707edf3196e8037ee45018d1bb1bfb233b0e4fc440fa3d3f25bc69bfdaf26" +dependencies = [ + "sys_traits_macros", +] + +[[package]] +name = "sys_traits_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "181f22127402abcf8ee5c83ccd5b408933fec36a6095cf82cda545634692657e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] [[package]] name = "sysctl" @@ -12101,6 +12131,15 @@ dependencies = [ "xattr", ] +[[package]] +name = "temp_deno_which" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "366c5ccd670145885feb6efd6bbf2478ed236c4c3839046fcc8e2a1a84c51091" +dependencies = [ + "either", +] + [[package]] name = "tempfile" version = "3.27.0" @@ -12615,6 +12654,19 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-vsock" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b319ef9394889dab2e1b4f0085b45ba11d0c79dc9d1a9d1afc057d009d0f1c7" +dependencies = [ + "bytes", + "futures", + "libc", + "tokio", + "vsock", +] + [[package]] name = "tokio-websockets" version = "0.10.1" @@ -13105,12 +13157,6 @@ version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" -[[package]] -name = "typed-arena" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" - [[package]] name = "typed-path" version = "0.12.3" @@ -13246,12 +13292,6 @@ version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" -[[package]] -name = "unicode-id" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ba288e709927c043cbe476718d37be306be53fb1fafecd0dbe36d072be2580" - [[package]] name = "unicode-id-start" version = "1.4.0" @@ -13475,17 +13515,16 @@ dependencies = [ [[package]] name = "v8" -version = "130.0.7" +version = "137.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a511192602f7b435b0a241c1947aa743eb7717f20a9195f4b5e8ed1952e01db1" +checksum = "33995a1fee055ff743281cde33a41f0d618ee0bdbe8bdf6859e11864499c2595" dependencies = [ - "bindgen 0.70.1", + "bindgen 0.71.1", "bitflags 2.9.4", "fslock", "gzip-header", "home", - "miniz_oxide 0.7.4", - "once_cell", + "miniz_oxide", "paste", "which 6.0.3", ] @@ -13514,6 +13553,16 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" +[[package]] +name = "vsock" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba782755fc073877e567c2253c0be48e4aa9a254c232d36d3985dfae0bd5205" +dependencies = [ + "libc", + "nix 0.31.3", +] + [[package]] name = "vte" version = "0.14.1" @@ -13712,11 +13761,11 @@ dependencies = [ [[package]] name = "wasm_dep_analyzer" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eeee3bdea6257cc36d756fa745a70f9d393571e47d69e0ed97581676a5369ca" +checksum = "e51cf5f08b357e64cd7642ab4bbeb11aecab9e15520692129624fb9908b8df2c" dependencies = [ - "deno_error", + "deno_error 0.6.1", "thiserror 2.0.18", ] @@ -13766,6 +13815,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-transport-proto" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "974fa1e325e6cc5327de8887f189a441fcff4f8eedcd31ec87f0ef0cc5283fbc" +dependencies = [ + "bytes", + "http 1.4.0", + "thiserror 2.0.18", + "url", +] + [[package]] name = "webpki-root-certs" version = "1.0.7" @@ -14029,7 +14090,7 @@ dependencies = [ "const_format", "cookie", "cron", - "dashmap 6.1.0", + "dashmap", "datafusion", "ed25519-dalek", "eventsource-stream", @@ -14545,7 +14606,7 @@ dependencies = [ "argon2", "axum 0.8.4", "chrono", - "dashmap 6.1.0", + "dashmap", "http 1.4.0", "hyper 1.9.0", "lazy_static", @@ -14671,7 +14732,7 @@ dependencies = [ "crc", "cron", "croner", - "dashmap 6.1.0", + "dashmap", "datafusion", "equivalent", "futures", @@ -15240,7 +15301,7 @@ dependencies = [ "chrono", "chrono-tz", "cron", - "dashmap 6.1.0", + "dashmap", "futures", "futures-core", "hex", @@ -15275,8 +15336,9 @@ dependencies = [ "deno_ast", "deno_console", "deno_core", - "deno_error", + "deno_error 0.6.1", "deno_fetch", + "deno_fs", "deno_io", "deno_net", "deno_permissions", diff --git a/backend/Cargo.toml b/backend/Cargo.toml index fbee476402..b48b911b99 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -387,8 +387,7 @@ tokio-stream = { version = "0.1.17" } tower = "^0" tower-http = { version = "^0.6", features = ["trace", "cors", "catch-panic"] } tower-cookies = "^0.11" -#stuck because of swc for now -serde = "=1.0.220" +serde = "^1" serde_json = { version = "^1", features = ["preserve_order", "raw_value"] } serde_yml = "0.0.12" uuid = { version = "^1", features = ["serde", "v4", "js"] } @@ -443,20 +442,29 @@ aws-sdk-rds = "^1" async-trait = "0.1.88" -v8 = "=130.0.7" # Exact version NOTE: Do not forget to update version and hash in flake.nix -deno_fetch = "0.214.0" -deno_tls = "0.177.0" -deno_console = "0.190.0" -deno_url = "0.190.0" -deno_webidl = "0.190.0" -deno_web = "0.221.0" -deno_io = "0.100.0" -deno_net = "0.182.0" -deno_core = "0.336.0" -deno_ast = { version = "=0.44.0", features = ["transpiling"] } -deno_permissions = "0.49.0" -deno_telemetry = "0.12.0" -deno_error = "=0.5.5" +v8 = "=137.1.0" # Exact version NOTE: Do not forget to update version and hash in flake.nix +# deno_* pin set: deno v2.4.0 base, with deno_ast force-overridden to =0.51.0. +# Rationale: deno_ast 0.51.0 is the first version pulling swc_common =14.0.4, +# the first swc_common patch that dropped `pub use serde::__private as serde;` +# (the line that capped our workspace serde pin at =1.0.220). v2.4.0's other +# pins keep deno_tls at 0.196.0 which uses permissive `rustls ^0.23.11`, +# compatible with aws-sdk-bedrockruntime's `^0.23.31` requirement. deno_tls +# 0.198+ tightened that to exact `=0.23.28`, which would have made any +# meaningful deno bump resolver-impossible against aws-sdk. +deno_fetch = "0.233.0" +deno_tls = "0.196.0" +deno_console = "0.209.0" +deno_url = "0.209.0" +deno_webidl = "0.209.0" +deno_web = "0.240.0" +deno_io = "0.119.0" +deno_fs = "0.119.0" +deno_net = "0.201.0" +deno_core = "0.352.0" +deno_ast = { version = "=0.51.0", features = ["transpiling"] } +deno_permissions = "0.68.0" +deno_telemetry = "0.31.0" +deno_error = "=0.6.1" rustls-pemfile = "2.2.0" # only used with special deno_core_mac feature to prevent ffi issue on macos, requires libffi to be installed @@ -469,10 +477,10 @@ google-cloud-googleapis = {version = "0.16.1", features = ["pubsub"]} winapi = { version = "0.3.9", features = ["sysinfoapi"] } sysinfo = { version = "0.32.1" } -swc_common = "=0.37.5" -swc_ecma_parser = "=0.149.1" -swc_ecma_ast = "=0.118.2" -swc_ecma_visit = "=0.104.8" +swc_common = "=14.0.4" +swc_ecma_parser = "=24.0.3" +swc_ecma_ast = "=15.0.0" +swc_ecma_visit = "=15.0.0" async-recursion = "^1" diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index 2e43e667c1..8298e1c013 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -d3bc7fa85195b46b7a38d43c2f806520bf8b5454 +4d01d171228196f28ddabc1150242bfab623d5cf diff --git a/backend/parsers/windmill-parser-ts-asset/src/lib.rs b/backend/parsers/windmill-parser-ts-asset/src/lib.rs index bc31a16c99..3c04ef7447 100644 --- a/backend/parsers/windmill-parser-ts-asset/src/lib.rs +++ b/backend/parsers/windmill-parser-ts-asset/src/lib.rs @@ -12,7 +12,7 @@ use AssetUsageAccessType::*; pub fn parse_assets(code: &str) -> anyhow::Result { let cm: Lrc = Default::default(); - let fm = cm.new_source_file(FileName::Custom("main.ts".into()).into(), code.into()); + let fm = cm.new_source_file(FileName::Custom("main.ts".into()).into(), code.to_string()); let lexer = Lexer::new( // We want to parse ecmascript Syntax::Typescript(TsSyntax::default()), diff --git a/backend/parsers/windmill-parser-ts/src/lib.rs b/backend/parsers/windmill-parser-ts/src/lib.rs index 1ae22879b6..1e78ec8665 100644 --- a/backend/parsers/windmill-parser-ts/src/lib.rs +++ b/backend/parsers/windmill-parser-ts/src/lib.rs @@ -129,7 +129,7 @@ impl Visit for ImportsFinder { /// See also: [`parse_relative_imports`] for resolved absolute paths. pub fn parse_expr_for_imports(code: &str, skip_type_only: bool) -> anyhow::Result> { let cm: Lrc = Default::default(); - let fm = cm.new_source_file(FileName::Custom("main.d.ts".into()).into(), code.into()); + let fm = cm.new_source_file(FileName::Custom("main.d.ts".into()).into(), code.to_string()); let mut tss = TsSyntax::default(); tss.disallow_ambiguous_jsx_like; tss.tsx = true; @@ -263,7 +263,7 @@ impl Visit for OutputFinder { pub fn parse_expr_for_ids(code: &str) -> anyhow::Result> { let cm: Lrc = Default::default(); - let fm = cm.new_source_file(FileName::Custom("main.ts".into()).into(), code.into()); + let fm = cm.new_source_file(FileName::Custom("main.ts".into()).into(), code.to_string()); let lexer = Lexer::new( // We want to parse ecmascript Syntax::Es(EsSyntax { jsx: false, ..Default::default() }), @@ -305,7 +305,7 @@ pub fn parse_deno_signature( entrypoint_override: Option, ) -> anyhow::Result { let cm: Lrc = Default::default(); - let fm = cm.new_source_file(FileName::Custom("main.ts".into()).into(), code.into()); + let fm = cm.new_source_file(FileName::Custom("main.ts".into()).into(), code.to_string()); let lexer = Lexer::new( // We want to parse ecmascript Syntax::Typescript(TsSyntax::default()), diff --git a/backend/parsers/windmill-parser-wac/src/typescript.rs b/backend/parsers/windmill-parser-wac/src/typescript.rs index 87fa7cef01..9ad84a2e97 100644 --- a/backend/parsers/windmill-parser-wac/src/typescript.rs +++ b/backend/parsers/windmill-parser-wac/src/typescript.rs @@ -712,7 +712,7 @@ fn extract_ts_params(params: &[swc_ecma_ast::Param], cm: &Lrc) -> Vec pub fn parse_ts_workflow(code: &str) -> Result> { let cm: Lrc = Default::default(); - let fm = cm.new_source_file(FileName::Custom("workflow.ts".into()).into(), code.into()); + let fm = cm.new_source_file(FileName::Custom("workflow.ts".into()).into(), code.to_string()); let lexer = Lexer::new( Syntax::Typescript(TsSyntax::default()), Default::default(), diff --git a/backend/windmill-runtime-nativets/Cargo.toml b/backend/windmill-runtime-nativets/Cargo.toml index c4f3461815..edad615ae5 100644 --- a/backend/windmill-runtime-nativets/Cargo.toml +++ b/backend/windmill-runtime-nativets/Cargo.toml @@ -28,6 +28,7 @@ deno_ast.workspace = true deno_tls.workspace = true deno_permissions.workspace = true deno_io.workspace = true +deno_fs.workspace = true deno_telemetry.workspace = true deno_error.workspace = true winapi.workspace = true @@ -59,6 +60,7 @@ deno_ast.workspace = true deno_tls.workspace = true deno_permissions.workspace = true deno_io.workspace = true +deno_fs.workspace = true deno_telemetry.workspace = true deno_error.workspace = true winapi.workspace = true diff --git a/backend/windmill-runtime-nativets/build.rs b/backend/windmill-runtime-nativets/build.rs index 6598c974eb..8262827815 100644 --- a/backend/windmill-runtime-nativets/build.rs +++ b/backend/windmill-runtime-nativets/build.rs @@ -25,10 +25,30 @@ impl FetchPermissions for PermissionsContainer { #[inline(always)] fn check_read<'a>( &mut self, - _resolved: bool, - _p: &'a std::path::Path, + _path: Cow<'a, Path>, _api_name: &str, - ) -> Result, deno_io::fs::FsError> { + _get_path: &'a dyn deno_fs::GetPath, + ) -> Result, deno_io::fs::FsError> { + unreachable!("snapshotting") + } + + #[inline(always)] + fn check_write<'a>( + &mut self, + _path: Cow<'a, Path>, + _api_name: &str, + _get_path: &'a dyn deno_fs::GetPath, + ) -> Result, deno_io::fs::FsError> { + unreachable!("snapshotting") + } + + #[inline(always)] + fn check_net_vsock( + &mut self, + _cid: u32, + _port: u32, + _api_name: &str, + ) -> Result<(), deno_permissions::PermissionCheckError> { unreachable!("snapshotting") } } @@ -41,17 +61,17 @@ impl TimersPermission for PermissionsContainer { } impl NetPermissions for PermissionsContainer { - fn check_read<'a>( + fn check_read( &mut self, - _p: &'a str, + _p: &str, _api_name: &str, ) -> Result { unreachable!("snapshotting") } - fn check_write<'a>( + fn check_write( &mut self, - _p: &'a str, + _p: &str, _api_name: &str, ) -> Result { unreachable!("snapshotting") @@ -67,10 +87,19 @@ impl NetPermissions for PermissionsContainer { fn check_write_path<'a>( &mut self, - _: &'a Path, - _: &str, + _p: Cow<'a, Path>, + _api_name: &str, ) -> Result, deno_permissions::PermissionCheckError> { - todo!() + unreachable!("snapshotting") + } + + fn check_vsock( + &mut self, + _cid: u32, + _port: u32, + _api_name: &str, + ) -> Result<(), deno_permissions::PermissionCheckError> { + unreachable!("snapshotting") } } @@ -83,7 +112,7 @@ deno_core::extension!( // `extension_transpiler` callback for `deno_core::snapshot::create_snapshot`. // // Specialized to our snapshot's inputs. Of the seven deno_* extensions -// we register via `init_ops_and_esm()`, six ship pre-built `.js` files +// we register via `init()`, six ship pre-built `.js` files // in their `esm` lists (webidl/url/console/web/fetch/net) — only // `deno_telemetry`'s `extension!` macro lists `.ts` files // (`telemetry.ts`, `util.ts`), so the TypeScript branch is needed @@ -153,17 +182,14 @@ fn main() { println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap()); let exts = vec![ - deno_telemetry::deno_telemetry::init_ops_and_esm(), - deno_webidl::deno_webidl::init_ops_and_esm(), - deno_url::deno_url::init_ops_and_esm(), - deno_console::deno_console::init_ops_and_esm(), - deno_web::deno_web::init_ops_and_esm::( - Arc::new(BlobStore::default()), - None, - ), - deno_fetch::deno_fetch::init_ops_and_esm::(Default::default()), - deno_net::deno_net::init_ops_and_esm::(None, None), - fetch::init_ops_and_esm(), + deno_telemetry::deno_telemetry::init(), + deno_webidl::deno_webidl::init(), + deno_url::deno_url::init(), + deno_console::deno_console::init(), + deno_web::deno_web::init::(Arc::new(BlobStore::default()), None), + deno_fetch::deno_fetch::init::(Default::default()), + deno_net::deno_net::init::(None, None), + fetch::init(), ]; // Build the file path to the snapshot. diff --git a/backend/windmill-runtime-nativets/src/lib.rs b/backend/windmill-runtime-nativets/src/lib.rs index 83de806716..52e23f11da 100644 --- a/backend/windmill-runtime-nativets/src/lib.rs +++ b/backend/windmill-runtime-nativets/src/lib.rs @@ -50,6 +50,28 @@ use windmill_common::error::Error; use windmill_common::result_stream::append_result_stream_db; use windmill_common::worker::{write_file, Connection, WINDMILL_DIR}; +// ── Snapshot-matched extensions ────────────────────────────────────── +// +// `deno_core` 0.352 validates that the snapshot's extension list is a +// *prefix* of the runtime's extension list (snapshot does not need an +// exact match — runtime is allowed to add extensions at the tail, but +// must not reorder or omit any that the snapshot baked in). +// +// Our snapshot (in build.rs) is the same eight deno_* extensions ending +// with this local `fetch` ext. The runtime adds one extra entry at the +// end — the windmill `ext` carrying our own ops — which is fine because +// it's after the snapshot prefix. +// +// This local `fetch` extension declaration must be present in both +// build.rs and lib.rs so the type passes through the `init()` macro. +// The ESM is already in the snapshot, so this `init()` call at runtime +// is a no-op for esm — the registration just records the ext. +deno_core::extension!( + fetch, + esm_entry_point = "ext:fetch/src/runtime.js", + esm = ["src/runtime.js"], +); + // ── Permission container ───────────────────────────────────────────── pub struct PermissionsContainer; @@ -67,11 +89,31 @@ impl FetchPermissions for PermissionsContainer { #[inline(always)] fn check_read<'a>( &mut self, - _resolved: bool, - p: &'a std::path::Path, + path: Cow<'a, std::path::Path>, _api_name: &str, - ) -> Result, deno_io::fs::FsError> { - Ok(Cow::Borrowed(p)) + _get_path: &'a dyn deno_fs::GetPath, + ) -> Result, deno_io::fs::FsError> { + Ok(deno_fs::CheckedPath::Unresolved(path)) + } + + #[inline(always)] + fn check_write<'a>( + &mut self, + path: Cow<'a, std::path::Path>, + _api_name: &str, + _get_path: &'a dyn deno_fs::GetPath, + ) -> Result, deno_io::fs::FsError> { + Ok(deno_fs::CheckedPath::Unresolved(path)) + } + + #[inline(always)] + fn check_net_vsock( + &mut self, + _cid: u32, + _port: u32, + _api_name: &str, + ) -> Result<(), deno_permissions::PermissionCheckError> { + Ok(()) } } @@ -83,17 +125,17 @@ impl TimersPermission for PermissionsContainer { } impl NetPermissions for PermissionsContainer { - fn check_read<'a>( + fn check_read( &mut self, - p: &'a str, + p: &str, _api_name: &str, ) -> Result { Ok(PathBuf::from(p)) } - fn check_write<'a>( + fn check_write( &mut self, - p: &'a str, + p: &str, _api_name: &str, ) -> Result { Ok(PathBuf::from(p)) @@ -109,10 +151,19 @@ impl NetPermissions for PermissionsContainer { fn check_write_path<'a>( &mut self, - p: &'a std::path::Path, + p: Cow<'a, std::path::Path>, _api_name: &str, - ) -> Result, deno_permissions::PermissionCheckError> { - Ok(Cow::Borrowed(p)) + ) -> Result, deno_permissions::PermissionCheckError> { + Ok(p) + } + + fn check_vsock( + &mut self, + _cid: u32, + _port: u32, + _api_name: &str, + ) -> Result<(), deno_permissions::PermissionCheckError> { + Ok(()) } } @@ -384,7 +435,7 @@ pub(crate) fn create_nativets_runtime( let fetch_options = deno_fetch::Options { root_cert_store_provider: None, user_agent: ann.useragent.unwrap_or_else(|| "windmill/beta".to_string()), - proxy: ann.proxy.map(|x| deno_tls::Proxy { + proxy: ann.proxy.map(|x| deno_tls::Proxy::Http { url: x.0, basic_auth: x .1 @@ -394,13 +445,14 @@ pub(crate) fn create_nativets_runtime( }; let exts: Vec = vec![ - deno_telemetry::deno_telemetry::init_ops(), - deno_webidl::deno_webidl::init_ops(), - deno_url::deno_url::init_ops(), - deno_console::deno_console::init_ops(), - deno_web::deno_web::init_ops::(Arc::new(BlobStore::default()), None), - deno_fetch::deno_fetch::init_ops::(fetch_options), - deno_net::deno_net::init_ops::(None, None), + deno_telemetry::deno_telemetry::init(), + deno_webidl::deno_webidl::init(), + deno_url::deno_url::init(), + deno_console::deno_console::init(), + deno_web::deno_web::init::(Arc::new(BlobStore::default()), None), + deno_fetch::deno_fetch::init::(fetch_options), + deno_net::deno_net::init::(None, None), + fetch::init(), ext, ]; diff --git a/flake.nix b/flake.nix index aaf06c882e..3872ee636f 100644 --- a/flake.nix +++ b/flake.nix @@ -79,11 +79,11 @@ # --------------------------------------------------------------- rustyV8Archive = let - version = "130.0.7"; + version = "137.1.0"; target = stdenv.hostPlatform.rust.rustcTarget; sha256 = { x86_64-linux = - "sha256-pkdsuU6bAkcIHEZUJOt5PXdzK424CEgTLXjLtQ80t10="; + "sha256-Tiscfy2bzYGR3s0T+SC1IB3xWvTVpVcSEdjq3MCRoRw="; aarch64-linux = lib.fakeHash; x86_64-darwin = lib.fakeHash; aarch64-darwin = lib.fakeHash; From e3a914fd480988278c57c5d62e88353fce7d3faf Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Mon, 11 May 2026 21:39:41 +0000 Subject: [PATCH 14/21] download files via openapi client when token is set (#9102) --- .../src/lib/components/DisplayResult.svelte | 62 +++++++++++++------ .../components/FlowStatusViewerInner.svelte | 32 +++++++--- frontend/src/lib/components/LogViewer.svelte | 50 ++++++++++----- .../components/ParqetCsvTableRenderer.svelte | 13 ++-- .../lib/components/S3FilePickerInner.svelte | 30 ++++++--- .../common/fileDownload/FileDownload.svelte | 30 +++++++-- .../propertyPicker/ObjectViewer.svelte | 14 +++-- frontend/src/lib/utils/downloadFile.ts | 48 ++++++++++++++ .../(logged)/workspace_settings/+page.svelte | 28 ++++++--- 9 files changed, 235 insertions(+), 72 deletions(-) create mode 100644 frontend/src/lib/utils/downloadFile.ts diff --git a/frontend/src/lib/components/DisplayResult.svelte b/frontend/src/lib/components/DisplayResult.svelte index 4e2b07b1c5..ff4196443d 100644 --- a/frontend/src/lib/components/DisplayResult.svelte +++ b/frontend/src/lib/components/DisplayResult.svelte @@ -5,6 +5,7 @@ import { json } from 'svelte-highlight/languages' import { copyToClipboard, parseS3Object, roughSizeOfObject } from '$lib/utils' import { base } from '$lib/base' + import { downloadViaClient, shouldDownloadViaClient } from '$lib/utils/downloadFile' import { Button, Drawer, DrawerContent } from './common' import { ClipboardCopy, @@ -173,6 +174,25 @@ let largeObject: boolean | undefined = $state(undefined) + let resultApiPath = $derived( + workspaceId && jobId + ? nodeId + ? `/w/${workspaceId}/jobs/result_by_id/${jobId}/${nodeId}` + : `/w/${workspaceId}/jobs_u/completed/get_result/${jobId}` + : undefined + ) + let resultDownloadHref = $derived( + resultApiPath + ? `${base}/api${resultApiPath}` + : `data:text/json;charset=utf-8,${encodeURIComponent(toJsonStr(result))}` + ) + let resultDownloadName = $derived(`${filename ?? 'result'}.json`) + async function onResultDownload(e: MouseEvent) { + if (!resultApiPath || !shouldDownloadViaClient()) return + e.preventDefault() + await downloadViaClient(resultApiPath, resultDownloadName) + } + function checkIfS3(result: any, keys: string[]) { return keys.includes('s3') && typeof result.s3 === 'string' } @@ -1001,12 +1021,9 @@ {#if largeObject}
Download {filename ? '' : 'as JSON'} @@ -1074,19 +1091,26 @@ {#snippet actions()} {#if customUi?.disableDownload !== true} - + {#if resultApiPath && shouldDownloadViaClient()} + + {:else} + + {/if} {/if} + {#if shouldDownloadViaClient()} + + {:else} + + {/if}
{/if} {#snippet actions()} {#if jobId && download} - + {#if shouldDownloadViaClient()} + + {:else} + + {/if} {/if} + {#if shouldDownloadViaClient()} + + {:else} + + {/if}
From 0a5f8dcd48b677c865ccb9958b55314b91f65acf Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Mon, 11 May 2026 21:43:18 +0000 Subject: [PATCH 15/21] deps: pin tokio-postgres to forked branch with query_typed_raw deadlock fix (#9106) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * deps: pin tokio-postgres to MaterializeInc fork to fix query_typed_raw deadlock `pg_executor`'s `Client::query_typed_raw` (and `Client::prepare` on the streaming path) deadlock when the result schema contains a column whose Oid the client doesn't know yet — citext, custom enums, custom domains, postgis types. Easy to reproduce against any partitioned table with a citext column: ~100+ rows is enough on localhost, less on slower links. `psql` works fine for the same query because the simple-query protocol doesn't trigger the typeinfo lookup path. ## Root cause (unchanged tokio-postgres bug for years) `query::query_typed` calls `get_type(client, oid).await` synchronously while still holding the original query's `Responses` stream. The original query's `DataRow`s back up in the per-request `mpsc::channel(1)`, `Connection::poll_read` stops draining the wire, and the typeinfo sub-query response (queued on the same socket behind those DataRows) never arrives. Classic head-of-line blocking. ## Fix Pin `tokio-postgres` / `postgres-types` / `postgres-protocol` (via [patch.crates-io]) and the workspace `rust-postgres` / `rust-postgres-native-tls` aliases to the [MaterializeInc rust-postgres fork at `78c1222577`](https://github.com/MaterializeInc/rust-postgres/tree/master). MI's [PR #33 "bigger-channels"](https://github.com/MaterializeInc/rust-postgres/pull/33) (merged 2025-12-11) resized the per-request response channel from `mpsc::channel(1)` → `mpsc::channel(1024)`. That gives the connection task 1024 batches of headroom while a streaming consumer is paused mid-stream — orders of magnitude more than realistic typeinfo deferral needs (≈3 batches). ## Why MaterializeInc and not a windmill-labs fork `windmill-trigger-postgres` already depended on the imor fork for the `postgres-replication` crate (logical replication: `CopyBothDuplex`, `LogicalReplicationStream`, `TupleData` decoding including binary tuples). That crate has never been on upstream rust-postgres — petrosagg's [PR #752](https://github.com/rust-postgres/rust-postgres/pull/752) was closed in 2021 in favour of a smaller split, [PR #778](https://github.com/rust-postgres/rust-postgres/pull/778) is still open today after five years. petrosagg keeps the replication work alive on the MaterializeInc fork. MaterializeInc is a strict superset of what we previously got from imor: - imor's binary-tuple commit (sha `20265ef38e`) was merged into MI master. - petrosagg has added perf + correctness fixes on top (allocation reuse, proper decoding fixes). - The deadlock mitigation (`channel(1024)`) was added three weeks before this issue surfaced. MI tracks upstream rust-postgres with a periodic catch-up merge (12-18 mo cadence; last on 2025-12-03, ~100 commits picked up). Not an abandoned fork. ## Why this works now (didn't on earlier attempt) A previous attempt at this PR (`248ccb5a97`) hit CI failure because the MI fork's `postgres-types 0.2.11` requires `serde_core ^1.0.221`, but Windmill's workspace pinned `serde = "=1.0.220"` for swc_common 0.37.5's `pub use serde::__private as serde;` hack. Bumping serde above 1.0.220 broke the swc_ecma_ast `Deserialize` derive under the `enterprise,deno_core,…` feature set. The earlier blocker is now resolved by #9111 which bumped the deno + swc pin set to a "goldilocks" combination where `swc_common 14.0.4` drops the `__private` hack, freeing the workspace serde pin to `^1`. serde now resolves to 1.0.228, which satisfies MI's `serde_core ^1.0.221` requirement transitively — no extra workspace pin needed. ## Diff shape Two files only: - `backend/Cargo.toml` (+34/-1): three new `[patch.crates-io]` entries (`tokio-postgres`, `postgres-types`, `postgres-protocol` → MI fork) plus comment block, plus the two workspace deps (`rust-postgres` / `rust-postgres-native-tls`) repointed from imor's fork to MI's. - `backend/Cargo.lock` — auto-regenerated. Replaces all `imor/rust-postgres` references with `MaterializeInc/rust-postgres`, bumps the affected crate versions to MI's set (tokio-postgres 0.7.11 → 0.7.15, postgres-types 0.2.7 → 0.2.11, postgres-protocol 0.6.7 → 0.6.9, postgres-native-tls 0.5.0 → 0.5.2). No source code changes. ## Verification - `cargo check --features quickjs` → clean. - `cargo check -p windmill-worker --features quickjs` → clean (pg_executor builds). - Repro tested earlier in the thread that produced this PR: the partitioned-citext-table query on Neon goes from "hangs indefinitely" (server idle on `wait_event=ClientRead` while client awaits typeinfo behind undrained DataRows) to "completes in ~1.0s, 100 rows" with the MI fork's `bounded(1024)` response channel. ## Caveats - **`bounded(1024)` is a mitigation, not a closure.** Theoretical failure mode remains at >~64 MB single-query results with a custom-Oid column (typeinfo defers for >1024 batches of ~64 KB each). The strict-correct fix is `mpsc::unbounded()` — proposed as a follow-up PR to MI. For realistic Windmill workloads, 1024 batches of headroom is well past the ~3-batch typeinfo deferral that's actually needed. - **`postgres-replication` is now upstream-of-fork's only home.** No realistic path to upstream rust-postgres merging it. The MI pin is intended to stay in place until either upstream changes course (unlikely) or MI publishes to crates.io (also unlikely — they don't publish releases of the fork). 🤖 Generated with [Claude Code](https://claude.com/claude-code) * chore: update ee-repo-ref to 8fe0d290fb0b71c24184eb5ad99bbdc7c813697c This commit updates the EE repository reference after PR #568 was merged in windmill-ee-private. Previous ee-repo-ref: 4d01d171228196f28ddabc1150242bfab623d5cf New ee-repo-ref: 8fe0d290fb0b71c24184eb5ad99bbdc7c813697c Automated by sync-ee-ref workflow. --------- Co-authored-by: windmill-internal-app[bot] --- backend/Cargo.lock | 338 ++++++++++------------------------------ backend/Cargo.toml | 34 +++- backend/ee-repo-ref.txt | 2 +- 3 files changed, 118 insertions(+), 256 deletions(-) diff --git a/backend/Cargo.lock b/backend/Cargo.lock index d4ec956b96..82235725ee 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -23,7 +23,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ - "crypto-common 0.1.7", + "crypto-common", "generic-array", ] @@ -164,7 +164,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -175,7 +175,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -1052,7 +1052,7 @@ dependencies = [ "bytes", "form_urlencoded", "hex", - "hmac 0.12.1", + "hmac", "http 0.2.12", "http 1.4.0", "percent-encoding", @@ -1655,15 +1655,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-buffer" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" -dependencies = [ - "hybrid-array", -] - [[package]] name = "block-modes" version = "0.8.1" @@ -2100,17 +2091,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" -[[package]] -name = "chacha20" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" -dependencies = [ - "cfg-if", - "cpufeatures 0.3.0", - "rand_core 0.10.1", -] - [[package]] name = "chrono" version = "0.4.44" @@ -2160,7 +2140,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "crypto-common 0.1.7", + "crypto-common", "inout", ] @@ -2224,12 +2204,6 @@ dependencies = [ "cc", ] -[[package]] -name = "cmov" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746" - [[package]] name = "colorchoice" version = "1.0.5" @@ -2303,12 +2277,6 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" -[[package]] -name = "const-oid" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" - [[package]] name = "const-random" version = "0.1.18" @@ -2582,15 +2550,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "crypto-common" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" -dependencies = [ - "hybrid-array", -] - [[package]] name = "csv" version = "1.3.1" @@ -2621,15 +2580,6 @@ dependencies = [ "cipher 0.4.4", ] -[[package]] -name = "ctutils" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" -dependencies = [ - "cmov", -] - [[package]] name = "curl-sys" version = "0.4.88+curl-8.20.0" @@ -2642,7 +2592,7 @@ dependencies = [ "openssl-sys", "pkg-config", "vcpkg", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -3971,7 +3921,7 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ - "const-oid 0.9.6", + "const-oid", "pem-rfc7468", "zeroize", ] @@ -4131,23 +4081,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", - "const-oid 0.9.6", - "crypto-common 0.1.7", + "const-oid", + "crypto-common", "subtle", ] -[[package]] -name = "digest" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" -dependencies = [ - "block-buffer 0.12.0", - "const-oid 0.10.2", - "crypto-common 0.2.1", - "ctutils", -] - [[package]] name = "dirs" version = "4.0.0" @@ -4217,7 +4155,7 @@ dependencies = [ "libc", "option-ext", "redox_users 0.5.2", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -4512,7 +4450,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -5072,8 +5010,8 @@ dependencies = [ "libc", "log", "rustversion", - "windows-link 0.2.1", - "windows-result 0.4.1", + "windows-link 0.1.3", + "windows-result 0.3.4", ] [[package]] @@ -5153,7 +5091,6 @@ dependencies = [ "cfg-if", "libc", "r-efi 6.0.0", - "rand_core 0.10.1", "wasip2", "wasip3", ] @@ -5593,7 +5530,7 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ - "hmac 0.12.1", + "hmac", ] [[package]] @@ -5605,15 +5542,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "hmac" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" -dependencies = [ - "digest 0.11.3", -] - [[package]] name = "home" version = "0.5.12" @@ -5755,15 +5683,6 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" -[[package]] -name = "hybrid-array" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d46837a0ed51fe95bd3b05de33cd64a1ee88fc797477ca48446872504507c5" -dependencies = [ - "typenum", -] - [[package]] name = "hyper" version = "0.14.32" @@ -5997,7 +5916,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.2", + "windows-core 0.56.0", ] [[package]] @@ -7087,16 +7006,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "md-5" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98" -dependencies = [ - "cfg-if", - "digest 0.11.3", -] - [[package]] name = "md5" version = "0.6.1" @@ -7479,7 +7388,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -7774,7 +7683,7 @@ version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51e219e79014df21a225b1860a479e2dcd7cbd9130f4defd4bd0e191ea31d67d" dependencies = [ - "base64 0.22.1", + "base64 0.21.7", "chrono", "getrandom 0.2.17", "http 1.4.0", @@ -7914,7 +7823,7 @@ dependencies = [ "chrono", "dyn-clone", "ed25519-dalek", - "hmac 0.12.1", + "hmac", "http 1.4.0", "itertools 0.10.5", "log", @@ -8514,6 +8423,16 @@ dependencies = [ "phf_shared 0.12.1", ] +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_shared 0.13.1", + "serde", +] + [[package]] name = "phf_codegen" version = "0.11.3" @@ -8565,6 +8484,15 @@ dependencies = [ "siphasher 1.0.3", ] +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher 1.0.3", +] + [[package]] name = "php-parser-rs" version = "0.1.3" @@ -8662,85 +8590,56 @@ checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "postgres-native-tls" -version = "0.5.0" -source = "git+https://github.com/imor/rust-postgres?rev=20265ef38e32a06f76b6f9b678e2077fc2211f6b#20265ef38e32a06f76b6f9b678e2077fc2211f6b" +version = "0.5.2" +source = "git+https://github.com/MaterializeInc/rust-postgres?rev=78c1222577bb091d69bc22b1bc7ad01c14675abe#78c1222577bb091d69bc22b1bc7ad01c14675abe" dependencies = [ "native-tls", "tokio", "tokio-native-tls", - "tokio-postgres 0.7.11", + "tokio-postgres", ] [[package]] name = "postgres-native-tls" -version = "0.5.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f39498473c92f7b6820ae970382c1d83178a3454c618161cb772e8598d9f6f" +checksum = "fef4de47bb81477e0c3deaf153a1b10ae176484713ff1640969f4cb96b653ebc" dependencies = [ "native-tls", "tokio", "tokio-native-tls", - "tokio-postgres 0.7.13", + "tokio-postgres", ] [[package]] name = "postgres-protocol" -version = "0.6.7" -source = "git+https://github.com/imor/rust-postgres?rev=20265ef38e32a06f76b6f9b678e2077fc2211f6b#20265ef38e32a06f76b6f9b678e2077fc2211f6b" +version = "0.6.9" +source = "git+https://github.com/MaterializeInc/rust-postgres?rev=78c1222577bb091d69bc22b1bc7ad01c14675abe#78c1222577bb091d69bc22b1bc7ad01c14675abe" dependencies = [ "base64 0.22.1", "byteorder", "bytes", "fallible-iterator", - "hmac 0.12.1", + "hmac", "md-5 0.10.6", "memchr", - "rand 0.8.5", + "rand 0.9.0", "sha2 0.10.9", "stringprep", ] -[[package]] -name = "postgres-protocol" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56201207dac53e2f38e848e31b4b91616a6bb6e0c7205b77718994a7f49e70fc" -dependencies = [ - "base64 0.22.1", - "byteorder", - "bytes", - "fallible-iterator", - "hmac 0.13.0", - "md-5 0.11.0", - "memchr", - "rand 0.10.1", - "sha2 0.11.0", - "stringprep", -] - [[package]] name = "postgres-types" -version = "0.2.7" -source = "git+https://github.com/imor/rust-postgres?rev=20265ef38e32a06f76b6f9b678e2077fc2211f6b#20265ef38e32a06f76b6f9b678e2077fc2211f6b" -dependencies = [ - "bytes", - "fallible-iterator", - "postgres-protocol 0.6.7", -] - -[[package]] -name = "postgres-types" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613283563cd90e1dfc3518d548caee47e0e725455ed619881f5cf21f36de4b48" +version = "0.2.11" +source = "git+https://github.com/MaterializeInc/rust-postgres?rev=78c1222577bb091d69bc22b1bc7ad01c14675abe#78c1222577bb091d69bc22b1bc7ad01c14675abe" dependencies = [ "array-init", "bit-vec 0.6.3", "bytes", "chrono", "fallible-iterator", - "postgres-protocol 0.6.11", - "serde", + "postgres-protocol", + "serde_core", "serde_json", "uuid", ] @@ -9186,17 +9085,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "rand" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" -dependencies = [ - "chacha20", - "getrandom 0.4.2", - "rand_core 0.10.1", -] - [[package]] name = "rand_chacha" version = "0.2.2" @@ -9254,12 +9142,6 @@ dependencies = [ "getrandom 0.3.4", ] -[[package]] -name = "rand_core" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" - [[package]] name = "rand_distr" version = "0.5.1" @@ -9663,7 +9545,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ - "hmac 0.12.1", + "hmac", "subtle", ] @@ -9827,7 +9709,7 @@ version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" dependencies = [ - "const-oid 0.9.6", + "const-oid", "digest 0.10.7", "num-bigint-dig", "num-integer", @@ -9916,7 +9798,7 @@ dependencies = [ "borsh", "bytes", "num-traits", - "postgres-types 0.2.9", + "postgres-types", "rand 0.8.5", "rkyv", "serde", @@ -9992,7 +9874,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -10120,7 +10002,7 @@ dependencies = [ "security-framework 3.6.0", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -10797,17 +10679,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "sha2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" -dependencies = [ - "cfg-if", - "cpufeatures 0.3.0", - "digest 0.11.3", -] - [[package]] name = "sharded-slab" version = "0.1.7" @@ -10980,7 +10851,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -11206,7 +11077,7 @@ dependencies = [ "generic-array", "hex", "hkdf", - "hmac 0.12.1", + "hmac", "itoa", "log", "md-5 0.10.6", @@ -11247,7 +11118,7 @@ dependencies = [ "futures-util", "hex", "hkdf", - "hmac 0.12.1", + "hmac", "home", "itoa", "log", @@ -11323,7 +11194,7 @@ dependencies = [ "cfg-if", "libc", "psm", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -12150,7 +12021,7 @@ dependencies = [ "getrandom 0.4.2", "once_cell", "rustix 1.1.4", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -12169,7 +12040,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" dependencies = [ "rustix 1.1.4", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -12493,8 +12364,8 @@ dependencies = [ [[package]] name = "tokio-postgres" -version = "0.7.11" -source = "git+https://github.com/imor/rust-postgres?rev=20265ef38e32a06f76b6f9b678e2077fc2211f6b#20265ef38e32a06f76b6f9b678e2077fc2211f6b" +version = "0.7.15" +source = "git+https://github.com/MaterializeInc/rust-postgres?rev=78c1222577bb091d69bc22b1bc7ad01c14675abe#78c1222577bb091d69bc22b1bc7ad01c14675abe" dependencies = [ "async-trait", "byteorder", @@ -12505,38 +12376,12 @@ dependencies = [ "log", "parking_lot", "percent-encoding", - "phf 0.11.3", + "phf 0.13.1", "pin-project-lite", - "postgres-protocol 0.6.7", - "postgres-types 0.2.7", - "rand 0.8.5", - "socket2 0.5.10", - "tokio", - "tokio-util", - "whoami", -] - -[[package]] -name = "tokio-postgres" -version = "0.7.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c95d533c83082bb6490e0189acaa0bbeef9084e60471b696ca6988cd0541fb0" -dependencies = [ - "async-trait", - "byteorder", - "bytes", - "fallible-iterator", - "futures-channel", - "futures-util", - "log", - "parking_lot", - "percent-encoding", - "phf 0.11.3", - "pin-project-lite", - "postgres-protocol 0.6.11", - "postgres-types 0.2.9", + "postgres-protocol", + "postgres-types", "rand 0.9.0", - "socket2 0.5.10", + "socket2 0.6.3", "tokio", "tokio-util", "whoami", @@ -13392,7 +13237,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ - "crypto-common 0.1.7", + "crypto-common", "subtle", ] @@ -13917,7 +13762,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.48.0", ] [[package]] @@ -14098,7 +13943,7 @@ dependencies = [ "futures", "git-version", "hex", - "hmac 0.12.1", + "hmac", "http 1.4.0", "hyper 1.9.0", "indexmap 2.14.0", @@ -14114,7 +13959,7 @@ dependencies = [ "openidconnect", "openssl", "pin-project", - "postgres-native-tls 0.5.1", + "postgres-native-tls 0.5.3", "prometheus", "quick_cache", "rand 0.9.0", @@ -14137,7 +13982,7 @@ dependencies = [ "time", "tokio", "tokio-native-tls", - "tokio-postgres 0.7.13", + "tokio-postgres", "tokio-stream", "tokio-util", "tower 0.5.3", @@ -14741,7 +14586,7 @@ dependencies = [ "git-version", "globset", "hex", - "hmac 0.12.1", + "hmac", "hyper 1.9.0", "indexmap 2.14.0", "itertools 0.14.0", @@ -14760,7 +14605,7 @@ dependencies = [ "pep440_rs", "phf 0.11.3", "pin-project-lite", - "postgres-native-tls 0.5.1", + "postgres-native-tls 0.5.3", "prometheus", "quick_cache", "rand 0.9.0", @@ -14786,7 +14631,7 @@ dependencies = [ "thiserror 2.0.18", "tikv-jemalloc-ctl", "tokio", - "tokio-postgres 0.7.13", + "tokio-postgres", "tokio-stream", "tokio-util", "tonic 0.13.1", @@ -14927,7 +14772,7 @@ dependencies = [ "backon", "base64 0.22.1", "chrono", - "hmac 0.12.1", + "hmac", "http 1.4.0", "itertools 0.14.0", "lazy_static", @@ -14959,7 +14804,7 @@ dependencies = [ "base64 0.22.1", "chrono", "hex", - "hmac 0.12.1", + "hmac", "itertools 0.14.0", "lazy_static", "reqwest 0.12.28", @@ -15305,7 +15150,7 @@ dependencies = [ "futures", "futures-core", "hex", - "hmac 0.12.1", + "hmac", "itertools 0.14.0", "lazy_static", "once_cell", @@ -15562,7 +15407,7 @@ dependencies = [ "constant_time_eq 0.3.1", "futures", "hex", - "hmac 0.12.1", + "hmac", "http 1.4.0", "hyper 1.9.0", "itertools 0.14.0", @@ -15672,7 +15517,7 @@ dependencies = [ "lazy_static", "native-tls", "pg_escape", - "postgres-native-tls 0.5.0", + "postgres-native-tls 0.5.2", "quick_cache", "rand 0.9.0", "rust_decimal", @@ -15681,7 +15526,7 @@ dependencies = [ "sqlx", "thiserror 2.0.18", "tokio", - "tokio-postgres 0.7.11", + "tokio-postgres", "tokio-stream", "tracing", "uuid", @@ -15792,7 +15637,7 @@ dependencies = [ "gcp_auth", "git-version", "hex", - "hmac 0.12.1", + "hmac", "hudsucker", "hyper-http-proxy", "hyper-tls", @@ -15813,7 +15658,7 @@ dependencies = [ "oracle", "pem 3.0.6", "pep440_rs", - "postgres-native-tls 0.5.1", + "postgres-native-tls 0.5.3", "process-wrap", "prometheus", "prost", @@ -15832,7 +15677,7 @@ dependencies = [ "tempfile", "tiberius", "tokio", - "tokio-postgres 0.7.13", + "tokio-postgres", "tokio-stream", "tokio-util", "tracing", @@ -15972,19 +15817,6 @@ dependencies = [ "windows-strings 0.4.2", ] -[[package]] -name = "windows-core" -version = "0.62.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" -dependencies = [ - "windows-implement 0.60.2", - "windows-interface 0.59.3", - "windows-link 0.2.1", - "windows-result 0.4.1", - "windows-strings 0.5.1", -] - [[package]] name = "windows-future" version = "0.2.1" diff --git a/backend/Cargo.toml b/backend/Cargo.toml index b48b911b99..326b777385 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -207,6 +207,36 @@ all_sqlx_features = ["all_languages", "enterprise", "enterprise_saml", "embeddin object_store = { git = "https://github.com/apache/arrow-rs-object-store", rev = "36752c975d4f29e20b57c91f81a10872dcd48ae7" } # Use tiberius main branch for libgssapi 0.8.1 fix (https://github.com/prisma/tiberius/issues/343) tiberius = { git = "https://github.com/prisma/tiberius", rev = "59db57960a14b422fb3a1309aa4aa47880896ff8" } +# Pin tokio-postgres / postgres-types / postgres-protocol to the +# MaterializeInc fork. windmill-trigger-postgres already pulled this +# fork in transitively for the postgres-replication crate +# (CopyBothDuplex, LogicalReplicationStream, TupleData with binary +# tuple support) which upstream rust-postgres has declined to merge +# since 2021 (PR #752 → #778, both still unmerged). +# +# MI also carries a mitigation for the +# Client::query_typed_raw / Client::prepare deadlock on result columns +# whose Oid the client doesn't know about yet (citext, custom enums / +# domains, postgis): MI's 2025-12-11 PR #33 resized the per-request +# response channel from mpsc::channel(1) → mpsc::channel(1024). +# bounded(1024) is sufficient for any realistic typeinfo deferral +# (need ~2-3 batches) but leaves a theoretical failure mode at +# >~64 MB results with a custom-Oid column. The strict-correct fix is +# mpsc::unbounded(); a follow-up PR to MI is open proposing that. +# +# The [patch.crates-io] entries below force windmill-worker's +# pg_executor (which imports `tokio_postgres::` directly from +# crates.io) onto the same fork as windmill-trigger-postgres, so the +# deadlock mitigation reaches both consumers. +# +# Upstream deadlock PRs (open, not on the critical path now that MI +# is mitigated): +# https://github.com/rust-postgres/rust-postgres/pull/1348 +# https://github.com/rust-postgres/rust-postgres/pull/1349 +# Reproducer: https://github.com/rubenfiszel/tokio-postgres-deadlock-repro +tokio-postgres = { git = "https://github.com/MaterializeInc/rust-postgres", rev = "78c1222577bb091d69bc22b1bc7ad01c14675abe" } +postgres-types = { git = "https://github.com/MaterializeInc/rust-postgres", rev = "78c1222577bb091d69bc22b1bc7ad01c14675abe" } +postgres-protocol = { git = "https://github.com/MaterializeInc/rust-postgres", rev = "78c1222577bb091d69bc22b1bc7ad01c14675abe" } [dependencies] anyhow.workspace = true @@ -524,8 +554,8 @@ wasm-bindgen-test = "^0" convert_case = "0.6.0" getrandom = "0.2" tokio-postgres = {version = "^0.7", features = ["array-impls", "with-serde_json-1", "with-chrono-0_4", "with-uuid-1", "with-bit-vec-0_6"]} -rust-postgres = { package = "tokio-postgres", git = "https://github.com/imor/rust-postgres", rev = "20265ef38e32a06f76b6f9b678e2077fc2211f6b"} -rust-postgres-native-tls = { package = "postgres-native-tls", git = "https://github.com/imor/rust-postgres", features = ["runtime"], rev = "20265ef38e32a06f76b6f9b678e2077fc2211f6b" } +rust-postgres = { package = "tokio-postgres", git = "https://github.com/MaterializeInc/rust-postgres", rev = "78c1222577bb091d69bc22b1bc7ad01c14675abe"} +rust-postgres-native-tls = { package = "postgres-native-tls", git = "https://github.com/MaterializeInc/rust-postgres", features = ["runtime"], rev = "78c1222577bb091d69bc22b1bc7ad01c14675abe" } bit-vec = "=0.6.3" mappable-rc = "^0" mysql_async = { version = "*", default-features = false, features = ["minimal", "default", "native-tls-tls", "rust_decimal"]} diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index 8298e1c013..063c2e202d 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -4d01d171228196f28ddabc1150242bfab623d5cf +8fe0d290fb0b71c24184eb5ad99bbdc7c813697c From f8ba0840d74572c880cf458938365b3ec808c6fb Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Mon, 11 May 2026 21:54:40 +0000 Subject: [PATCH 16/21] feat(vault): configurable JWT auth mount path and setup-doc fixes (#9100) * chore: narrow secret-file Read deny rule to dotfiles/extensions * feat(vault): configurable JWT auth mount path and fix setup docs * chore: bump ee-repo-ref for vault jwt mount path * chore: bump ee-repo-ref after rebase onto EE main * chore: update ee-repo-ref to a1cd60b54e8595b4e5ce6b654e675e4bbe2253b2 This commit updates the EE repository reference after PR #567 was merged in windmill-ee-private. Previous ee-repo-ref: c274f233a0ebb54afa296c3db15ff330e1baebcf New ee-repo-ref: a1cd60b54e8595b4e5ce6b654e675e4bbe2253b2 Automated by sync-ee-ref workflow. --------- Co-authored-by: windmill-internal-app[bot] --- .claude/settings.json | 5 +- backend/ee-repo-ref.txt | 2 +- backend/windmill-api/openapi.yaml | 3 + .../windmill-common/src/secret_backend/mod.rs | 5 + .../src/secret_backend/tests.rs | 1 + .../tests/secret_backend_integration.rs | 64 +++++++---- .../tests/secret_backend_migration.rs | 104 ++++++++++++------ .../SecretBackendConfig.svelte | 49 +++++++-- 8 files changed, 166 insertions(+), 67 deletions(-) diff --git a/.claude/settings.json b/.claude/settings.json index 0596b17e91..1ef3704831 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -55,7 +55,10 @@ "Read(**/*.pem)", "Read(**/*.key)", "Read(**/credentials.json)", - "Read(**/*secret*)", + "Read(**/.secret*)", + "Read(**/.secrets*)", + "Read(**/*.secret)", + "Read(**/*.secrets)", "Edit(.env)", "Edit(.env.*)", "Edit(**/.env)", diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index 063c2e202d..ad6df82501 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -8fe0d290fb0b71c24184eb5ad99bbdc7c813697c +a1cd60b54e8595b4e5ce6b654e675e4bbe2253b2 diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index c6a7de2601..82c8b06cf7 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -20963,6 +20963,9 @@ components: jwt_role: type: string description: Vault JWT auth role name for Windmill (optional, if not provided token auth is used) + jwt_mount_path: + type: string + description: Mount path for the JWT auth method in Vault (optional, defaults to "jwt"). Set this when the JWT auth method is mounted at a non-default path, e.g. via `vault auth enable -path= jwt`. namespace: type: string description: Vault Enterprise namespace (optional) diff --git a/backend/windmill-common/src/secret_backend/mod.rs b/backend/windmill-common/src/secret_backend/mod.rs index a75f51ea70..36f35f0cf8 100644 --- a/backend/windmill-common/src/secret_backend/mod.rs +++ b/backend/windmill-common/src/secret_backend/mod.rs @@ -122,6 +122,11 @@ pub struct VaultSettings { /// Optional - if not provided, token auth is used #[serde(skip_serializing_if = "Option::is_none")] pub jwt_role: Option, + /// Mount path for the JWT auth method in Vault (defaults to "jwt"). + /// Set this when the JWT auth method is mounted at a non-default path, + /// e.g. via `vault auth enable -path=my-mount jwt`. + #[serde(skip_serializing_if = "Option::is_none")] + pub jwt_mount_path: Option, /// Vault Enterprise namespace (optional) #[serde(skip_serializing_if = "Option::is_none")] pub namespace: Option, diff --git a/backend/windmill-common/src/secret_backend/tests.rs b/backend/windmill-common/src/secret_backend/tests.rs index 630b6cf023..3e2a12382a 100644 --- a/backend/windmill-common/src/secret_backend/tests.rs +++ b/backend/windmill-common/src/secret_backend/tests.rs @@ -26,6 +26,7 @@ mod tests { address: "http://127.0.0.1:8200".to_string(), mount_path: "windmill".to_string(), jwt_role: Some("windmill-secrets".to_string()), + jwt_mount_path: None, namespace: None, token: Some("test-root-token".to_string()), skip_ssl_verify: None, diff --git a/backend/windmill-common/tests/secret_backend_integration.rs b/backend/windmill-common/tests/secret_backend_integration.rs index 070c70defa..350fc297af 100644 --- a/backend/windmill-common/tests/secret_backend_integration.rs +++ b/backend/windmill-common/tests/secret_backend_integration.rs @@ -91,6 +91,7 @@ mod tests { .unwrap_or_else(|_| "http://127.0.0.1:8200".to_string()), mount_path: "windmill".to_string(), jwt_role: None, // Static token mode + jwt_mount_path: None, namespace: None, token: Some( std::env::var("VAULT_TOKEN").unwrap_or_else(|_| "test-root-token".to_string()), @@ -106,6 +107,7 @@ mod tests { .unwrap_or_else(|_| "http://127.0.0.1:8200".to_string()), mount_path: "windmill".to_string(), jwt_role: Some("windmill-secrets".to_string()), // JWT mode + jwt_mount_path: None, namespace: None, token: None, // No static token - use JWT skip_ssl_verify: None, @@ -203,7 +205,10 @@ mod tests { println!("Testing Vault connection with JWT auth..."); println!(" Address: {}", settings.address); println!(" JWT Role: {:?}", settings.jwt_role); - println!(" BASE_URL: {}", (**windmill_common::BASE_URL.load()).clone()); + println!( + " BASE_URL: {}", + (**windmill_common::BASE_URL.load()).clone() + ); let result = test_vault_connection(&settings, Some(&db)).await; assert!( @@ -274,13 +279,15 @@ mod tests { // Encrypt fixture placeholders with real workspace keys encrypt_fixture_secrets(&db).await; - let secret_count = sqlx::query_scalar!( - "SELECT COUNT(*) FROM variable WHERE is_secret = true" - ) - .fetch_one(&db) - .await - .expect("Failed to count secrets"); - println!("Found {} secrets in database before migration", secret_count.unwrap_or(0)); + let secret_count = + sqlx::query_scalar!("SELECT COUNT(*) FROM variable WHERE is_secret = true") + .fetch_one(&db) + .await + .expect("Failed to count secrets"); + println!( + "Found {} secrets in database before migration", + secret_count.unwrap_or(0) + ); // Run migration println!("Migrating secrets to Vault..."); @@ -288,8 +295,10 @@ mod tests { .await .expect("Migration to Vault failed"); - println!("Migration report: total={}, migrated={}, failed={}", - report.total_secrets, report.migrated_count, report.failed_count); + println!( + "Migration report: total={}, migrated={}, failed={}", + report.total_secrets, report.migrated_count, report.failed_count + ); if !report.failures.is_empty() { for f in &report.failures { @@ -307,7 +316,11 @@ mod tests { .get_secret(ws, path) .await .unwrap_or_else(|e| panic!("Failed to read {}/{} from Vault: {:?}", ws, path, e)); - assert_eq!(value, expected_plaintext, "Vault value mismatch for {}/{}", ws, path); + assert_eq!( + value, expected_plaintext, + "Vault value mismatch for {}/{}", + ws, path + ); println!(" ✓ {}/{} correct in Vault", ws, path); } @@ -346,8 +359,10 @@ mod tests { .await .expect("Migration to database failed"); - println!("Migration report: total={}, migrated={}, failed={}", - report.total_secrets, report.migrated_count, report.failed_count); + println!( + "Migration report: total={}, migrated={}, failed={}", + report.total_secrets, report.migrated_count, report.failed_count + ); assert_eq!(report.failed_count, 0, "Migration had failures"); assert!(report.migrated_count > 0, "No secrets were migrated"); @@ -364,7 +379,11 @@ mod tests { let mc = build_crypt(&db, ws).await.unwrap(); let decrypted = decrypt(&mc, row).expect("Failed to decrypt restored value"); - assert_eq!(decrypted, expected_plaintext, "Restored value mismatch for {}/{}", ws, path); + assert_eq!( + decrypted, expected_plaintext, + "Restored value mismatch for {}/{}", + ws, path + ); println!(" ✓ {}/{} correctly restored in DB", ws, path); } @@ -488,11 +507,19 @@ mod tests { .await .unwrap_or_else(|_| panic!("Secret {}/{} not found after round-trip", ws, path)); - assert_ne!(encrypted, "ROUND_TRIP_CLEARED", "Secret {}/{} was not restored", ws, path); + assert_ne!( + encrypted, "ROUND_TRIP_CLEARED", + "Secret {}/{} was not restored", + ws, path + ); let mc = build_crypt(&db, ws).await.unwrap(); let decrypted = decrypt(&mc, encrypted).expect("Failed to decrypt"); - assert_eq!(decrypted, expected_plaintext, "Round-trip value mismatch for {}/{}", ws, path); + assert_eq!( + decrypted, expected_plaintext, + "Round-trip value mismatch for {}/{}", + ws, path + ); println!(" ✓ {}/{}: round-trip OK", ws, path); } @@ -522,10 +549,7 @@ mod tests { .get_secret("test-workspace", "u/test-user/other_secret") .await; - assert!( - cross_access.is_err(), - "Cross-workspace access should fail!" - ); + assert!(cross_access.is_err(), "Cross-workspace access should fail!"); println!("✓ Cross-workspace access correctly denied"); // Verify own workspace access works diff --git a/backend/windmill-common/tests/secret_backend_migration.rs b/backend/windmill-common/tests/secret_backend_migration.rs index 1915b90630..fba27ee260 100644 --- a/backend/windmill-common/tests/secret_backend_migration.rs +++ b/backend/windmill-common/tests/secret_backend_migration.rs @@ -23,19 +23,21 @@ use sqlx::{Pool, Postgres}; use windmill_common::error::Result; use windmill_common::secret_backend::{ - vault_oss::{migrate_secrets_to_database, migrate_secrets_to_vault, test_vault_connection, VaultBackend}, + vault_oss::{ + migrate_secrets_to_database, migrate_secrets_to_vault, test_vault_connection, VaultBackend, + }, SecretBackend, VaultSettings, }; fn test_vault_settings() -> VaultSettings { VaultSettings { - address: std::env::var("VAULT_ADDR").unwrap_or_else(|_| "http://127.0.0.1:8200".to_string()), + address: std::env::var("VAULT_ADDR") + .unwrap_or_else(|_| "http://127.0.0.1:8200".to_string()), mount_path: "windmill".to_string(), jwt_role: Some("windmill-secrets".to_string()), + jwt_mount_path: None, namespace: None, - token: Some( - std::env::var("VAULT_TOKEN").unwrap_or_else(|_| "test-root-token".to_string()), - ), + token: Some(std::env::var("VAULT_TOKEN").unwrap_or_else(|_| "test-root-token".to_string())), skip_ssl_verify: None, } } @@ -47,7 +49,11 @@ async fn test_vault_connection_works(db: Pool) { let settings = test_vault_settings(); let result = test_vault_connection(&settings, Some(&db)).await; - assert!(result.is_ok(), "Failed to connect to Vault: {:?}", result.err()); + assert!( + result.is_ok(), + "Failed to connect to Vault: {:?}", + result.err() + ); println!("✓ Successfully connected to Vault at {}", settings.address); } @@ -70,7 +76,10 @@ async fn test_migrate_db_to_vault(db: Pool) { .await .expect("Failed to query secrets"); - println!("Found {} secrets in database before migration:", secrets_before.len()); + println!( + "Found {} secrets in database before migration:", + secrets_before.len() + ); for s in &secrets_before { println!(" - {}/{}: {} chars", s.workspace_id, s.path, s.value.len()); } @@ -111,7 +120,10 @@ async fn test_migrate_db_to_vault(db: Pool) { secret.path, result.err() ); - println!(" ✓ {}/{} exists in Vault", secret.workspace_id, secret.path); + println!( + " ✓ {}/{} exists in Vault", + secret.workspace_id, secret.path + ); } println!("\n✓ Migration to Vault completed successfully"); @@ -133,8 +145,14 @@ async fn test_migrate_vault_to_db(db: Pool) { let to_vault_report = migrate_secrets_to_vault(&db, &settings) .await .expect("Initial migration to Vault failed"); - assert!(to_vault_report.migrated_count > 0, "No secrets to test with"); - println!(" Migrated {} secrets to Vault", to_vault_report.migrated_count); + assert!( + to_vault_report.migrated_count > 0, + "No secrets to test with" + ); + println!( + " Migrated {} secrets to Vault", + to_vault_report.migrated_count + ); // Clear the database values to simulate fresh migration back println!("\nClearing database secret values..."); @@ -150,7 +168,10 @@ async fn test_migrate_vault_to_db(db: Pool) { .fetch_one(&db) .await .expect("Failed to count cleared"); - println!(" Cleared {} secret values in database", cleared.count.unwrap_or(0)); + println!( + " Cleared {} secret values in database", + cleared.count.unwrap_or(0) + ); // Now migrate from Vault back to database println!("\nMigrating secrets from Vault to database..."); @@ -206,15 +227,14 @@ async fn test_full_round_trip_migration(db: Pool) { .expect("Failed to connect to Vault"); // Get original secrets - let original_secrets: std::collections::HashMap<(String, String), String> = sqlx::query!( - "SELECT workspace_id, path, value FROM variable WHERE is_secret = true" - ) - .fetch_all(&db) - .await - .expect("Failed to query original secrets") - .into_iter() - .map(|r| ((r.workspace_id, r.path), r.value)) - .collect(); + let original_secrets: std::collections::HashMap<(String, String), String> = + sqlx::query!("SELECT workspace_id, path, value FROM variable WHERE is_secret = true") + .fetch_all(&db) + .await + .expect("Failed to query original secrets") + .into_iter() + .map(|r| ((r.workspace_id, r.path), r.value)) + .collect(); println!("Original secrets: {} entries", original_secrets.len()); @@ -243,21 +263,23 @@ async fn test_full_round_trip_migration(db: Pool) { // Step 4: Verify round-trip integrity println!("\n=== Step 4: Verify round-trip integrity ==="); - let restored_secrets: std::collections::HashMap<(String, String), String> = sqlx::query!( - "SELECT workspace_id, path, value FROM variable WHERE is_secret = true" - ) - .fetch_all(&db) - .await - .expect("Failed to query restored secrets") - .into_iter() - .map(|r| ((r.workspace_id, r.path), r.value)) - .collect(); + let restored_secrets: std::collections::HashMap<(String, String), String> = + sqlx::query!("SELECT workspace_id, path, value FROM variable WHERE is_secret = true") + .fetch_all(&db) + .await + .expect("Failed to query restored secrets") + .into_iter() + .map(|r| ((r.workspace_id, r.path), r.value)) + .collect(); // Compare original and restored for ((ws, path), _original_value) in &original_secrets { let restored_value = restored_secrets .get(&(ws.clone(), path.clone())) - .expect(&format!("Secret {}/{} not found after round-trip", ws, path)); + .expect(&format!( + "Secret {}/{} not found after round-trip", + ws, path + )); // Note: Values might differ slightly due to encryption/decryption // but they should not be the cleared value @@ -266,7 +288,12 @@ async fn test_full_round_trip_migration(db: Pool) { "Secret {}/{} was not restored", ws, path ); - println!(" ✓ {}/{}: restored ({} chars)", ws, path, restored_value.len()); + println!( + " ✓ {}/{}: restored ({} chars)", + ws, + path, + restored_value.len() + ); } println!("\n✓ Full round-trip migration completed successfully!"); @@ -289,7 +316,10 @@ async fn test_workspace_isolation(db: Pool) { .await .expect("Migration failed"); - println!("Migrated {} secrets across workspaces", report.migrated_count); + println!( + "Migrated {} secrets across workspaces", + report.migrated_count + ); // Verify workspace isolation in Vault let vault_backend = VaultBackend::new(settings.clone()); @@ -309,13 +339,19 @@ async fn test_workspace_isolation(db: Pool) { let ws1_result: Result = vault_backend .get_secret("test-workspace", "u/test-user/db_password") .await; - assert!(ws1_result.is_ok(), "test-workspace secret should be accessible"); + assert!( + ws1_result.is_ok(), + "test-workspace secret should be accessible" + ); println!("✓ test-workspace secrets accessible"); let ws2_result: Result = vault_backend .get_secret("test-workspace-2", "u/test-user/other_secret") .await; - assert!(ws2_result.is_ok(), "test-workspace-2 secret should be accessible"); + assert!( + ws2_result.is_ok(), + "test-workspace-2 secret should be accessible" + ); println!("✓ test-workspace-2 secrets accessible"); println!("\n✓ Workspace isolation verified!"); diff --git a/frontend/src/lib/components/instanceSettings/SecretBackendConfig.svelte b/frontend/src/lib/components/instanceSettings/SecretBackendConfig.svelte index 15db633264..a313a0fbc4 100644 --- a/frontend/src/lib/components/instanceSettings/SecretBackendConfig.svelte +++ b/frontend/src/lib/components/instanceSettings/SecretBackendConfig.svelte @@ -70,6 +70,7 @@ address: $values['secret_backend']?.address ?? '', mount_path: $values['secret_backend']?.mount_path ?? 'windmill', jwt_role: $values['secret_backend']?.jwt_role ?? 'windmill-secrets', + jwt_mount_path: $values['secret_backend']?.jwt_mount_path ?? null, namespace: $values['secret_backend']?.namespace ?? null, token: $values['secret_backend']?.token ?? null, skip_ssl_verify: $values['secret_backend']?.skip_ssl_verify ?? false @@ -122,6 +123,7 @@ address: $values['secret_backend'].address, mount_path: $values['secret_backend'].mount_path, jwt_role: $values['secret_backend'].jwt_role, + jwt_mount_path: $values['secret_backend'].jwt_mount_path || undefined, namespace: $values['secret_backend'].namespace || undefined, token: $values['secret_backend'].token || undefined, skip_ssl_verify: $values['secret_backend'].skip_ssl_verify || undefined @@ -352,6 +354,10 @@ } let baseUrl = $derived($values['base_url'] ?? 'https://your-windmill-instance.com') + let jwtMount = $derived(($values['secret_backend']?.jwt_mount_path?.trim() || 'jwt') as string) + let vaultAudience = $derived( + ($values['secret_backend']?.address?.trim() || 'https://vault.example.com:8200') as string + )
@@ -500,6 +506,24 @@ }} bind:value={$values['secret_backend'].jwt_role} /> + + Mount path of the JWT auth method in Vault. Defaults to jwt. Set this + only if you mounted the JWT auth method at a non-default path (vault auth enable -path=<mount> jwt). +
Vault JWT Setup Instructions
# Enable JWT auth method
-vault auth enable jwt
+										># Enable JWT auth method{jwtMount === 'jwt'
+											? ''
+											: ` at custom mount '${jwtMount}'`}
+vault auth enable {jwtMount === 'jwt' ? 'jwt' : `-path=${jwtMount} jwt`}
 
 # Configure JWT auth with Windmill's JWKS endpoint
-vault write auth/jwt/config \
-  jwks_url="{baseUrl}/.well-known/jwks.json" \
-  bound_issuer="{baseUrl}"
+vault write auth/{jwtMount}/config \
+  jwks_url="{baseUrl}/api/oidc/jwks" \
+  bound_issuer="{baseUrl}/api/oidc/"
 
 # Create a policy for Windmill secrets
 vault policy write windmill-secrets - <<EOF
-path "windmill/data/*" {
+path "{$values['secret_backend']?.mount_path ?? 'windmill'}/data/*" {
   capabilities = ["create", "read", "update", "delete"]
 }
-path "windmill/metadata/*" {
+path "{$values['secret_backend']?.mount_path ?? 'windmill'}/metadata/*" {
   capabilities = ["list", "delete"]
 }
 EOF
 
-# Create the JWT role
-vault write auth/jwt/role/windmill-secrets \
+# Create the JWT role. bound_audiences must match the Vault server
+# address — Windmill signs the JWT with `aud` = your Vault address.
+vault write auth/{jwtMount}/role/{$values['secret_backend']?.jwt_role || 'windmill-secrets'} \
   role_type="jwt" \
-  bound_audiences="{baseUrl}" \
-  user_claim="email" \
+  bound_audiences="{vaultAudience}" \
+  user_claim="sub" \
   policies="windmill-secrets" \
   ttl="1h"
From 1abfe9de393c532e80468556f01c9b9101ab7bca Mon Sep 17 00:00:00 2001 From: Samuel Wilk <34423885+da-wilky@users.noreply.github.com> Date: Tue, 12 May 2026 00:03:04 +0200 Subject: [PATCH 17/21] Add max-iterations to OpenAPI spec for AI Agent (#9103) --- openflow.openapi.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openflow.openapi.yaml b/openflow.openapi.yaml index 824243b2af..630ce5fddf 100644 --- a/openflow.openapi.yaml +++ b/openflow.openapi.yaml @@ -1053,6 +1053,12 @@ components: - 0.0 = deterministic, focused responses - 0.7 = balanced (common default) - 1.0+ = more creative/random + max_iterations: + allOf: + - $ref: '#/components/schemas/InputTransform' + description: | + Number. Limits how many times the agent can loop through reasoning and tool use. + Range: 1-1000. required: - provider - user_message From 9c6cd8c852ee544848bb04fc4a4f52a111f11fda Mon Sep 17 00:00:00 2001 From: hugocasa Date: Tue, 12 May 2026 00:09:21 +0200 Subject: [PATCH 18/21] offline (URL-bound) license keys (#9089) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [ee] feat(license): offline (URL-bound) license keys Offline keys are a 4-segment variant for air-gapped customers — no phone-home, embedded seat/CU caps, locked to the instance's base_url. Existing 3-segment online keys are unchanged. Companion PRs: - windmill-labs/windmill-ee-private (full design + EE impl) - windmill-labs/windmill-customer-service (issuance + portal) - windmill-labs/windmill-cf-worker-keygen (signing) Co-Authored-By: Claude Opus 4.7 (1M context) * [ee] refactor(license): bind offline keys via instance hash; simpler CU enforcement - /settings/license_status now surfaces an `instance_hash` superadmins share with support when requesting an offline key - OfflineMetadata: `hash` replaces `base_url`; OfflineCapStatus reports `current_cu` (last 2min) and drops the grace-period fields - verify_license_key now takes a db so EE can recheck the hash - InstanceSetting.svelte: hash copy-block + simpler status panel - Bump ee-repo-ref Co-Authored-By: Claude Opus 4.7 (1M context) * [ee] chore(license): bump ee-repo-ref Pulls in the current_cu clamp + prod public key restoration. Co-Authored-By: Claude Opus 4.7 (1M context) * [ee] refactor(license): split instance_hash endpoint; minimal cap UI; restore workers expiry toast - `instance_hash` is no longer part of /settings/license_status responses; it lives at GET /settings/instance_hash (super-admin only) so it isn't re-emitted on every status poll. The UI doesn't show it — admins fetch it explicitly when requesting a key from support. - InstanceSetting offline cap UI is now two compact green/red status lines (Seats X.X/Y and CUs X.X/Y) placed above the action buttons, matching the existing "Latest key renewal" badge style. The block-panel is gone. - "Latest key renewal" line and the "Renew key" button are now hidden when an offline key is loaded (renewal is server-disabled for offline keys). - Restore parseLicenseKey + checkLicenseExpiration toast on /workers (works for both 3- and 4-segment keys). Co-Authored-By: Claude Opus 4.7 (1M context) * [ee] chore(license): bump ee-repo-ref Pulls in the plain-SHA256 instance hash + stats_ee revert. Co-Authored-By: Claude Opus 4.7 (1M context) * [ee] chore(license): bump ee-repo-ref Picks up the alert wording change. Co-Authored-By: Claude Opus 4.7 (1M context) * [ee] chore(license): bump ee-repo-ref Picks up the instance_uid cache so the periodic verify_license_key cycle no longer hits global_settings. Co-Authored-By: Claude Opus 4.7 (1M context) * [ee] refactor(license): rename /settings/license_status → /offline_license_status The endpoint was only used by the offline-license UI; the other fields it returned (license_key_id, license_key_valid, kind, offline metadata) were unused. Rename to clarify scope and flatten the response — it now returns just the OfflineCapStatus (or null when no offline license is loaded). Frontend uses `offlineCapStatus != null` as the "is offline" check. Co-Authored-By: Claude Opus 4.7 (1M context) * [ee] fix(ci): regenerate sqlx cache for the inline worker_ping query After reverting unused stats_ee helpers (fetch_worker_pings*), the inline `sqlx::query_as!(WorkerPingRecord, ...)` in get_stats_payload lost its cache entry — CI's check_ee_full + cargo_test were failing under SQLX_OFFLINE=true with E0282 type-inference errors. Re-running update_sqlx.sh regenerates the cache file under its current hash and prunes a couple of stale entries. Co-Authored-By: Claude Opus 4.7 (1M context) * [ee] fix(license): address cubic-bot review - get_offline_license_status: propagate enforce_offline_caps errors as 500 instead of swallowing into a "no offline license" (Option::None) response - canonical_base_url: rewrite the doc to match the actual fallback behavior (lowercase + trailing-slash strip on URL parse failure); the original cross-service contract is gone since the customer-service no longer canonicalizes (treats the instance hash as opaque) - check_seat_cap_for_new_user: take an email and short-circuit when the email is already in `usr ∪ workspace_invite` so net-zero invite upserts and invite→user transitions aren't spuriously blocked at cap. Mirrors the dedup rule the count itself uses. - Bump ee-repo-ref to pull in the EE-side change Co-Authored-By: Claude Opus 4.7 (1M context) * [ee] chore(license): bump ee-repo-ref Picks up the exact-delta seat-cap check (replaces the simple existence short-circuit). Regenerates the new sqlx cache for the bool_and query. Co-Authored-By: Claude Opus 4.7 (1M context) * [ee] fix(license): propagate get_instance_hash errors; bump ee-repo-ref - get_instance_hash: replace `.ok().flatten()` with map_err+? so DB errors during instance_uid lookup surface as 500 instead of silently returning `{"instance_hash": null}` (same pattern get_offline_license_status already uses) - Bump ee-repo-ref to pull in the enforce_offline_caps cached-state preservation Co-Authored-By: Claude Opus 4.7 (1M context) * chore: update ee-repo-ref to c6cd1afe2d9e04809b30751cd1687b28a65e62b1 This commit updates the EE repository reference after PR #566 was merged in windmill-ee-private. Previous ee-repo-ref: a6d91016ae0d43c46604313aecae3aa9c778c8e0 New ee-repo-ref: c6cd1afe2d9e04809b30751cd1687b28a65e62b1 Automated by sync-ee-ref workflow. --------- Co-authored-by: Claude Opus 4.7 (1M context) Co-authored-by: Ruben Fiszel Co-authored-by: windmill-internal-app[bot] --- ...1f7f387f5055c47f493271d26731336257384.json | 10 +-- ...c1ed508d83695ef6d62ca06cfb612fd332b87.json | 28 --------- ...49b8082c0052d626bf67e08317e56ab9ad026.json | 58 ------------------ ...153c43903f929ae5d62fbba12610f89c36d55.json | 2 +- ...320bb3eff65255a44bd66799ae14288312ba4.json | 23 ------- ...c31e10f89481908c479b4039af5e94fa0f8ac.json | 28 --------- ...cf6b4946e1fd337f00d243f518283783833c9.json | 22 +++++++ ...69657fd73742b6ee8289b1e9736e381314cfb.json | 23 ------- ...7ad51a4cd5cbdc2fa34038530070d6a579455.json | 26 ++++++++ ...d8c74cdc672a903d566baf5ac5ef50a4da1bd.json | 32 ++++++++++ backend/ee-repo-ref.txt | 2 +- backend/src/ee_oss.rs | 2 +- backend/src/main.rs | 2 +- backend/src/monitor.rs | 20 +++++- backend/windmill-api-settings/src/ee_oss.rs | 6 +- backend/windmill-api-settings/src/lib.rs | 53 +++++++++++++++- .../windmill-api-workspaces/src/workspaces.rs | 14 +++++ backend/windmill-api/openapi.yaml | 57 +++++++++++++++++ backend/windmill-api/src/ee_oss.rs | 6 +- backend/windmill-common/src/ee_oss.rs | 54 ++++++++++++++++ backend/windmill-common/src/lib.rs | 30 +++++++++ backend/windmill-common/src/utils.rs | 4 +- .../src/lib/components/InstanceSetting.svelte | 61 +++++++++++++++++-- .../(root)/(logged)/workers/+page.svelte | 29 ++++----- 24 files changed, 396 insertions(+), 196 deletions(-) delete mode 100644 backend/.sqlx/query-0c6e8f03a4e9f543cb85582e0aec1ed508d83695ef6d62ca06cfb612fd332b87.json delete mode 100644 backend/.sqlx/query-406bcbf55758b10243c8eaff1c349b8082c0052d626bf67e08317e56ab9ad026.json delete mode 100644 backend/.sqlx/query-6be4bf59c404d2f557d1106c48c320bb3eff65255a44bd66799ae14288312ba4.json delete mode 100644 backend/.sqlx/query-8b92a7d04fcdd8e61178d7dab97c31e10f89481908c479b4039af5e94fa0f8ac.json create mode 100644 backend/.sqlx/query-9c85ba8d41bedbcb5466f44a7d4cf6b4946e1fd337f00d243f518283783833c9.json delete mode 100644 backend/.sqlx/query-b4162468afae99cf31c4668ca6769657fd73742b6ee8289b1e9736e381314cfb.json create mode 100644 backend/.sqlx/query-e1ada31c1625b453c2ff85edbcd7ad51a4cd5cbdc2fa34038530070d6a579455.json create mode 100644 backend/.sqlx/query-f8f756bc498e5f084851f98e1e8d8c74cdc672a903d566baf5ac5ef50a4da1bd.json diff --git a/backend/.sqlx/query-07168aaf14cb6beff0ad4274b441f7f387f5055c47f493271d26731336257384.json b/backend/.sqlx/query-07168aaf14cb6beff0ad4274b441f7f387f5055c47f493271d26731336257384.json index d29a18c691..e7ed0aee65 100644 --- a/backend/.sqlx/query-07168aaf14cb6beff0ad4274b441f7f387f5055c47f493271d26731336257384.json +++ b/backend/.sqlx/query-07168aaf14cb6beff0ad4274b441f7f387f5055c47f493271d26731336257384.json @@ -46,11 +46,11 @@ ] }, "nullable": [ - true, - true, - true, - true, - true, + false, + false, + false, + false, + false, true, true ] diff --git a/backend/.sqlx/query-0c6e8f03a4e9f543cb85582e0aec1ed508d83695ef6d62ca06cfb612fd332b87.json b/backend/.sqlx/query-0c6e8f03a4e9f543cb85582e0aec1ed508d83695ef6d62ca06cfb612fd332b87.json deleted file mode 100644 index 7de0416a12..0000000000 --- a/backend/.sqlx/query-0c6e8f03a4e9f543cb85582e0aec1ed508d83695ef6d62ca06cfb612fd332b87.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT item_kind, path FROM ws_specific WHERE workspace_id = $1", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "item_kind", - "type_info": "Varchar" - }, - { - "ordinal": 1, - "name": "path", - "type_info": "Varchar" - } - ], - "parameters": { - "Left": [ - "Text" - ] - }, - "nullable": [ - false, - false - ] - }, - "hash": "0c6e8f03a4e9f543cb85582e0aec1ed508d83695ef6d62ca06cfb612fd332b87" -} diff --git a/backend/.sqlx/query-406bcbf55758b10243c8eaff1c349b8082c0052d626bf67e08317e56ab9ad026.json b/backend/.sqlx/query-406bcbf55758b10243c8eaff1c349b8082c0052d626bf67e08317e56ab9ad026.json deleted file mode 100644 index 2b5b68dfae..0000000000 --- a/backend/.sqlx/query-406bcbf55758b10243c8eaff1c349b8082c0052d626bf67e08317e56ab9ad026.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT label, email, scopes, workspace_id, super_admin, owner, expiration FROM token WHERE token_hash = $1", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "label", - "type_info": "Varchar" - }, - { - "ordinal": 1, - "name": "email", - "type_info": "Varchar" - }, - { - "ordinal": 2, - "name": "scopes", - "type_info": "TextArray" - }, - { - "ordinal": 3, - "name": "workspace_id", - "type_info": "Varchar" - }, - { - "ordinal": 4, - "name": "super_admin", - "type_info": "Bool" - }, - { - "ordinal": 5, - "name": "owner", - "type_info": "Varchar" - }, - { - "ordinal": 6, - "name": "expiration", - "type_info": "Timestamptz" - } - ], - "parameters": { - "Left": [ - "Text" - ] - }, - "nullable": [ - true, - true, - true, - true, - false, - true, - true - ] - }, - "hash": "406bcbf55758b10243c8eaff1c349b8082c0052d626bf67e08317e56ab9ad026" -} diff --git a/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json b/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json index 713ccb9dd3..36ddb8ab9f 100644 --- a/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json +++ b/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json @@ -15,7 +15,7 @@ ] }, "nullable": [ - null + true ] }, "hash": "5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55" diff --git a/backend/.sqlx/query-6be4bf59c404d2f557d1106c48c320bb3eff65255a44bd66799ae14288312ba4.json b/backend/.sqlx/query-6be4bf59c404d2f557d1106c48c320bb3eff65255a44bd66799ae14288312ba4.json deleted file mode 100644 index 0a39db6822..0000000000 --- a/backend/.sqlx/query-6be4bf59c404d2f557d1106c48c320bb3eff65255a44bd66799ae14288312ba4.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT EXISTS(SELECT 1 FROM variable WHERE workspace_id = $1 AND path = $2)", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "exists", - "type_info": "Bool" - } - ], - "parameters": { - "Left": [ - "Text", - "Text" - ] - }, - "nullable": [ - null - ] - }, - "hash": "6be4bf59c404d2f557d1106c48c320bb3eff65255a44bd66799ae14288312ba4" -} diff --git a/backend/.sqlx/query-8b92a7d04fcdd8e61178d7dab97c31e10f89481908c479b4039af5e94fa0f8ac.json b/backend/.sqlx/query-8b92a7d04fcdd8e61178d7dab97c31e10f89481908c479b4039af5e94fa0f8ac.json deleted file mode 100644 index 415544ece9..0000000000 --- a/backend/.sqlx/query-8b92a7d04fcdd8e61178d7dab97c31e10f89481908c479b4039af5e94fa0f8ac.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT s.item_kind, s.path\n FROM ws_specific s\n WHERE s.workspace_id = $1\n AND (\n (s.item_kind = 'resource' AND EXISTS (\n SELECT 1 FROM resource r\n WHERE r.workspace_id = s.workspace_id AND r.path = s.path\n ))\n OR (s.item_kind = 'variable' AND EXISTS (\n SELECT 1 FROM variable v\n WHERE v.workspace_id = s.workspace_id AND v.path = s.path\n ))\n )\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "item_kind", - "type_info": "Varchar" - }, - { - "ordinal": 1, - "name": "path", - "type_info": "Varchar" - } - ], - "parameters": { - "Left": [ - "Text" - ] - }, - "nullable": [ - false, - false - ] - }, - "hash": "8b92a7d04fcdd8e61178d7dab97c31e10f89481908c479b4039af5e94fa0f8ac" -} diff --git a/backend/.sqlx/query-9c85ba8d41bedbcb5466f44a7d4cf6b4946e1fd337f00d243f518283783833c9.json b/backend/.sqlx/query-9c85ba8d41bedbcb5466f44a7d4cf6b4946e1fd337f00d243f518283783833c9.json new file mode 100644 index 0000000000..fce125c6d5 --- /dev/null +++ b/backend/.sqlx/query-9c85ba8d41bedbcb5466f44a7d4cf6b4946e1fd337f00d243f518283783833c9.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT bool_and(operator) FROM (\n SELECT operator FROM usr WHERE email = $1\n UNION ALL\n SELECT operator FROM workspace_invite WHERE email = $1\n ) t", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "bool_and", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "9c85ba8d41bedbcb5466f44a7d4cf6b4946e1fd337f00d243f518283783833c9" +} diff --git a/backend/.sqlx/query-b4162468afae99cf31c4668ca6769657fd73742b6ee8289b1e9736e381314cfb.json b/backend/.sqlx/query-b4162468afae99cf31c4668ca6769657fd73742b6ee8289b1e9736e381314cfb.json deleted file mode 100644 index 327032afb5..0000000000 --- a/backend/.sqlx/query-b4162468afae99cf31c4668ca6769657fd73742b6ee8289b1e9736e381314cfb.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT EXISTS(SELECT 1 FROM ws_specific WHERE workspace_id = $1 AND item_kind = 'variable' AND path = $2)", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "exists", - "type_info": "Bool" - } - ], - "parameters": { - "Left": [ - "Text", - "Text" - ] - }, - "nullable": [ - null - ] - }, - "hash": "b4162468afae99cf31c4668ca6769657fd73742b6ee8289b1e9736e381314cfb" -} diff --git a/backend/.sqlx/query-e1ada31c1625b453c2ff85edbcd7ad51a4cd5cbdc2fa34038530070d6a579455.json b/backend/.sqlx/query-e1ada31c1625b453c2ff85edbcd7ad51a4cd5cbdc2fa34038530070d6a579455.json new file mode 100644 index 0000000000..f38c023cb3 --- /dev/null +++ b/backend/.sqlx/query-e1ada31c1625b453c2ff85edbcd7ad51a4cd5cbdc2fa34038530070d6a579455.json @@ -0,0 +1,26 @@ +{ + "db_name": "PostgreSQL", + "query": "WITH potential AS (\n SELECT email, operator FROM usr\n UNION\n SELECT email, operator FROM workspace_invite\n ),\n per_user AS (\n SELECT email, bool_and(operator) AS only_operator FROM potential GROUP BY email\n )\n SELECT\n COUNT(*) FILTER (WHERE NOT only_operator) AS \"authors!\",\n COUNT(*) FILTER (WHERE only_operator) AS \"operators!\"\n FROM per_user", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "authors!", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "operators!", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null, + null + ] + }, + "hash": "e1ada31c1625b453c2ff85edbcd7ad51a4cd5cbdc2fa34038530070d6a579455" +} diff --git a/backend/.sqlx/query-f8f756bc498e5f084851f98e1e8d8c74cdc672a903d566baf5ac5ef50a4da1bd.json b/backend/.sqlx/query-f8f756bc498e5f084851f98e1e8d8c74cdc672a903d566baf5ac5ef50a4da1bd.json new file mode 100644 index 0000000000..e4125ddab9 --- /dev/null +++ b/backend/.sqlx/query-f8f756bc498e5f084851f98e1e8d8c74cdc672a903d566baf5ac5ef50a4da1bd.json @@ -0,0 +1,32 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT memory, worker, native_mode FROM worker_ping WHERE ping_at > now() - interval '2 minutes'", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "memory", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "worker", + "type_info": "Varchar" + }, + { + "ordinal": 2, + "name": "native_mode", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + true, + false, + false + ] + }, + "hash": "f8f756bc498e5f084851f98e1e8d8c74cdc672a903d566baf5ac5ef50a4da1bd" +} diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index ad6df82501..91d8581950 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -a1cd60b54e8595b4e5ce6b654e675e4bbe2253b2 +c6cd1afe2d9e04809b30751cd1687b28a65e62b1 diff --git a/backend/src/ee_oss.rs b/backend/src/ee_oss.rs index 2aefaf7431..4dcaf2437b 100644 --- a/backend/src/ee_oss.rs +++ b/backend/src/ee_oss.rs @@ -8,6 +8,6 @@ pub async fn set_license_key(_license_key: String, _db: Option<&windmill_common: } #[cfg(all(feature = "enterprise", not(feature = "private")))] -pub async fn verify_license_key() -> () { +pub async fn verify_license_key(_db: Option<&windmill_common::db::DB>) -> () { // Implementation is not open source } diff --git a/backend/src/main.rs b/backend/src/main.rs index 3049064624..9a2709e9a9 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -1441,7 +1441,7 @@ Windmill Community Edition {GIT_VERSION} tracing::error!("Failed to reload license key on agent: {e:#}"); } #[cfg(feature = "enterprise")] - ee_oss::verify_license_key().await; + ee_oss::verify_license_key(conn.as_sql()).await; } // update min version explicitly. diff --git a/backend/src/monitor.rs b/backend/src/monitor.rs index 59a2f47ed0..0ddc02b256 100644 --- a/backend/src/monitor.rs +++ b/backend/src/monitor.rs @@ -2373,7 +2373,19 @@ pub async fn monitor_db( let verify_license_key_f = async { #[cfg(feature = "enterprise")] if !initial_load { - verify_license_key().await; + verify_license_key(conn.as_sql()).await; + } + }; + + let enforce_offline_caps_f = async { + #[cfg(feature = "enterprise")] + if server_mode && !initial_load { + if let Some(db) = conn.as_sql() { + // Cheap: one query for workers active in the last 2 minutes. + if let Err(e) = windmill_common::ee_oss::enforce_offline_caps(db).await { + tracing::error!("Failed to enforce offline license caps: {e:#}"); + } + } } }; @@ -2522,6 +2534,7 @@ pub async fn monitor_db( vacuum_queue_f, expose_queue_metrics_f, verify_license_key_f, + enforce_offline_caps_f, worker_groups_alerts_f, jobs_waiting_alerts_f, low_disk_alerts_f, @@ -2853,6 +2866,11 @@ pub async fn reload_base_url_setting(conn: &Connection) -> error::Result<()> { IS_SECURE.store(is_secure, Ordering::Relaxed); + #[cfg(feature = "enterprise")] + { + crate::ee_oss::verify_license_key(conn.as_sql()).await; + } + Ok(()) } diff --git a/backend/windmill-api-settings/src/ee_oss.rs b/backend/windmill-api-settings/src/ee_oss.rs index d0e0f69b62..92b3d6ad53 100644 --- a/backend/windmill-api-settings/src/ee_oss.rs +++ b/backend/windmill-api-settings/src/ee_oss.rs @@ -8,7 +8,11 @@ use anyhow::anyhow; pub async fn validate_license_key( _license_key: String, _db: Option<&windmill_common::DB>, -) -> anyhow::Result<(String, bool)> { +) -> anyhow::Result<( + String, + bool, + Option, +)> { // Implementation is not open source Err(anyhow!("License can't be validated in Windmill CE")) } diff --git a/backend/windmill-api-settings/src/lib.rs b/backend/windmill-api-settings/src/lib.rs index f027046808..09b52a3d22 100644 --- a/backend/windmill-api-settings/src/lib.rs +++ b/backend/windmill-api-settings/src/lib.rs @@ -37,13 +37,13 @@ use axum::{ use serde_json::json; use serde::{Deserialize, Serialize}; +use windmill_ai::ai_cache::bump_instance_ai_config_revision; #[cfg(feature = "enterprise")] use windmill_common::ee_oss::{send_critical_alert, CriticalAlertKind, CriticalErrorChannel}; #[cfg(all(feature = "private", feature = "enterprise"))] use windmill_common::secret_backend::{ AwsSecretsManagerSettings, AzureKeyVaultSettings, SecretMigrationReport, VaultSettings, }; -use windmill_ai::ai_cache::bump_instance_ai_config_revision; use windmill_common::{ email_oss::send_email_plain_text, error::{self, JsonResult, Result}, @@ -118,6 +118,8 @@ pub fn global_service() -> Router { get(get_latest_key_renewal_attempt), ) .route("/renew_license_key", post(renew_license_key)) + .route("/offline_license_status", get(get_offline_license_status)) + .route("/instance_hash", get(get_instance_hash)) .route("/customer_portal", post(create_customer_portal_session)) .route("/test_critical_channels", post(test_critical_channels)) .route("/critical_alerts", get(get_critical_alerts)) @@ -340,7 +342,7 @@ pub async fn test_license_key( Json(TestKey { license_key }): Json, ) -> error::Result { require_super_admin(&db, &authed.email).await?; - let (_, expired) = validate_license_key(license_key, Some(&db)).await?; + let (_, expired, _offline_meta) = validate_license_key(license_key, Some(&db)).await?; if expired { Err(error::Error::BadRequest("Expired license key".to_string())) @@ -349,6 +351,53 @@ pub async fn test_license_key( } } +#[derive(serde::Serialize)] +pub struct InstanceHash { + pub instance_hash: Option, +} + +/// Returns the live cap status for an offline license, or `null` when no +/// offline license is loaded. Used by the superadmin settings panel. +pub async fn get_offline_license_status( + Extension(db): Extension, + authed: ApiAuthed, +) -> error::JsonResult> { + require_super_admin(&db, &authed.email).await?; + + let offline = (**windmill_common::ee_oss::LICENSE_OFFLINE_METADATA.load()).clone(); + let is_offline = matches!(&offline, Some(m) if m.is_offline()); + + if !is_offline { + return Ok(Json(None)); + } + + #[cfg(feature = "enterprise")] + let cap = windmill_common::ee_oss::enforce_offline_caps(&db) + .await + .map_err(|e| error::Error::internal_err(format!("enforce_offline_caps: {e:#}")))?; + #[cfg(not(feature = "enterprise"))] + let cap: Option = None; + + Ok(Json(cap)) +} + +/// Returns the per-instance binding hash that goes into offline license keys. +/// Admin invokes via `curl` with their personal token when requesting a key +/// from support. +pub async fn get_instance_hash( + Extension(db): Extension, + authed: ApiAuthed, +) -> error::JsonResult { + require_super_admin(&db, &authed.email).await?; + #[cfg(feature = "enterprise")] + let hash = windmill_common::ee_oss::compute_instance_hash(&db) + .await + .map_err(|e| error::Error::internal_err(format!("compute_instance_hash: {e:#}")))?; + #[cfg(not(feature = "enterprise"))] + let hash: Option = None; + Ok(Json(InstanceHash { instance_hash: hash })) +} + pub async fn get_local_settings( Extension(db): Extension, authed: ApiAuthed, diff --git a/backend/windmill-api-workspaces/src/workspaces.rs b/backend/windmill-api-workspaces/src/workspaces.rs index 94e2026ad3..95c7157d61 100644 --- a/backend/windmill-api-workspaces/src/workspaces.rs +++ b/backend/windmill-api-workspaces/src/workspaces.rs @@ -5233,6 +5233,13 @@ async fn invite_user( nu.email = nu.email.to_lowercase(); + #[cfg(feature = "enterprise")] + if let Some(msg) = + windmill_common::ee_oss::check_seat_cap_for_new_user(&db, &nu.email, nu.operator).await? + { + return Err(Error::BadRequest(msg)); + } + let mut tx = db.begin().await?; let already_in_workspace = sqlx::query_scalar!( @@ -5306,6 +5313,13 @@ async fn add_user( nu.email = nu.email.to_lowercase(); + #[cfg(feature = "enterprise")] + if let Some(msg) = + windmill_common::ee_oss::check_seat_cap_for_new_user(&db, &nu.email, nu.operator).await? + { + return Err(Error::BadRequest(msg)); + } + let mut tx = db.begin().await?; let already_exists_email = sqlx::query_scalar!( diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index 82c8b06cf7..16448c622b 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -1779,6 +1779,63 @@ paths: schema: type: string + /settings/offline_license_status: + get: + summary: get cap-usage status for the currently-loaded offline license + description: | + Returns the live cap status (seats used vs cap, current CU vs cap) for + the offline license key currently in use. Returns `null` if no offline + license is loaded. Super-admin only. + operationId: getOfflineLicenseStatus + tags: + - setting + responses: + "200": + description: cap status (or null when no offline license) + content: + application/json: + schema: + type: object + nullable: true + properties: + seats_used: + type: number + description: Author-equivalent seats consumed (authors + 0.5 × operators) + seats_cap: + type: integer + author_count: + type: integer + operator_count: + type: integer + current_cu: + type: number + description: Sum of CU rate across workers that pinged in the last 2 minutes. + cu_cap: + type: number + cu_over_cap: + type: boolean + + /settings/instance_hash: + get: + summary: per-instance binding hash for offline license issuance + description: | + Returns the hash a superadmin shares with Windmill support when + requesting an offline license. Super-admin only. + operationId: getInstanceHash + tags: + - setting + responses: + '200': + description: instance hash + content: + application/json: + schema: + type: object + properties: + instance_hash: + type: string + nullable: true + /settings/customer_portal: post: summary: create customer portal session diff --git a/backend/windmill-api/src/ee_oss.rs b/backend/windmill-api/src/ee_oss.rs index a1f7a54d20..e5a7f71cbc 100644 --- a/backend/windmill-api/src/ee_oss.rs +++ b/backend/windmill-api/src/ee_oss.rs @@ -10,7 +10,11 @@ use anyhow::anyhow; pub async fn validate_license_key( _license_key: String, _db: Option<&crate::db::DB>, -) -> anyhow::Result<(String, bool)> { +) -> anyhow::Result<( + String, + bool, + Option, +)> { // Implementation is not open source Err(anyhow!("License can't be validated in Windmill CE")) } diff --git a/backend/windmill-common/src/ee_oss.rs b/backend/windmill-common/src/ee_oss.rs index 15d9e7cb5e..e68bc00c6e 100644 --- a/backend/windmill-common/src/ee_oss.rs +++ b/backend/windmill-common/src/ee_oss.rs @@ -18,6 +18,60 @@ lazy_static::lazy_static! { pub static ref LICENSE_KEY_VALID: AtomicBool = AtomicBool::new(true); pub static ref LICENSE_KEY_ID: arc_swap::ArcSwap = arc_swap::ArcSwap::from_pointee("".to_string()); pub static ref LICENSE_KEY: arc_swap::ArcSwap = arc_swap::ArcSwap::from_pointee("".to_string()); + pub static ref LICENSE_OFFLINE_METADATA: arc_swap::ArcSwap> = arc_swap::ArcSwap::from_pointee(None); + pub static ref LICENSE_OFFLINE_OVER_CU_CAP: AtomicBool = AtomicBool::new(false); + pub static ref LICENSE_OFFLINE_LAST_STATUS: arc_swap::ArcSwap> = arc_swap::ArcSwap::from_pointee(None); + pub static ref LICENSE_OFFLINE_LAST_CHECKED_AT: arc_swap::ArcSwap>> = arc_swap::ArcSwap::from_pointee(None); +} + +#[cfg(not(feature = "private"))] +#[derive(Clone, Debug, Deserialize, serde::Serialize)] +pub struct OfflineMetadata { + pub v: u32, + pub kind: String, + pub hash: String, + pub seats: i64, + pub cu_limit: f64, +} + +#[cfg(not(feature = "private"))] +impl OfflineMetadata { + pub fn is_offline(&self) -> bool { + self.kind == "offline" + } +} + +#[cfg(not(feature = "private"))] +#[derive(Clone, Debug, serde::Serialize)] +pub struct OfflineCapStatus { + pub seats_used: f64, + pub seats_cap: i64, + pub author_count: i64, + pub operator_count: i64, + pub current_cu: f64, + pub cu_cap: f64, + pub cu_over_cap: bool, +} + +#[cfg(all(feature = "enterprise", not(feature = "private")))] +pub async fn check_seat_cap_for_new_user( + _db: &DB, + _email: &str, + _new_user_is_operator: bool, +) -> anyhow::Result> { + Ok(None) +} + +#[cfg(all(feature = "enterprise", not(feature = "private")))] +pub async fn compute_instance_hash(_db: &DB) -> anyhow::Result> { + // Implementation is not open source + Ok(None) +} + +#[cfg(all(feature = "enterprise", not(feature = "private")))] +pub async fn enforce_offline_caps(_db: &DB) -> anyhow::Result> { + // Implementation is not open source + Ok(None) } #[cfg(not(feature = "private"))] diff --git a/backend/windmill-common/src/lib.rs b/backend/windmill-common/src/lib.rs index 7c7e3f79ed..39884e3d35 100644 --- a/backend/windmill-common/src/lib.rs +++ b/backend/windmill-common/src/lib.rs @@ -121,6 +121,36 @@ pub const PRIVATE_HUB_MIN_VERSION: i32 = 10_000_000; pub const SERVICE_LOG_RETENTION_SECS: i64 = 60 * 60 * 24 * 14; // 2 weeks retention period for logs pub const WM_DEPLOYERS_GROUP: &str = "wm_deployers"; +/// Canonical form of a base URL, used as one of the inputs to the offline-license +/// instance hash (`compute_instance_hash`). +/// +/// Rules: lowercase scheme and host, drop default ports (80/443), strip path/query/fragment, +/// strip trailing slash. If URL parsing fails, falls back to a best-effort lowercase + +/// trailing-slash strip so two semantically-equivalent inputs still produce the same +/// canonical form. +pub fn canonical_base_url(input: &str) -> String { + let trimmed = input.trim(); + if trimmed.is_empty() { + return String::new(); + } + match url::Url::parse(trimmed) { + Ok(u) => { + let scheme = u.scheme().to_ascii_lowercase(); + let host = u + .host_str() + .map(|h| h.to_ascii_lowercase()) + .unwrap_or_default(); + let port = match (u.port(), scheme.as_str()) { + (Some(80), "http") | (Some(443), "https") => String::new(), + (Some(p), _) => format!(":{p}"), + (None, _) => String::new(), + }; + format!("{scheme}://{host}{port}") + } + Err(_) => trimmed.trim_end_matches('/').to_ascii_lowercase(), + } +} + /// Checks if the user is allowed to preserve on_behalf_of values (admin or deployer). pub fn can_preserve_on_behalf_of(authed: &impl db::Authable) -> bool { authed.is_admin() || authed.groups().iter().any(|g| g == &WM_DEPLOYERS_GROUP) diff --git a/backend/windmill-common/src/utils.rs b/backend/windmill-common/src/utils.rs index efe5481e1d..17d9cfd804 100644 --- a/backend/windmill-common/src/utils.rs +++ b/backend/windmill-common/src/utils.rs @@ -447,7 +447,9 @@ pub async fn get_license_id_or_uid<'c, E: sqlx::Executor<'c, Database = Postgres } } -async fn get_instance_uid<'c, E: sqlx::Executor<'c, Database = Postgres>>(db: E) -> Result { +pub async fn get_instance_uid<'c, E: sqlx::Executor<'c, Database = Postgres>>( + db: E, +) -> Result { let uid_value = sqlx::query_scalar!( "SELECT value FROM global_settings WHERE name = $1", UNIQUE_ID_SETTING diff --git a/frontend/src/lib/components/InstanceSetting.svelte b/frontend/src/lib/components/InstanceSetting.svelte index f0097b877a..4964fb9c1d 100644 --- a/frontend/src/lib/components/InstanceSetting.svelte +++ b/frontend/src/lib/components/InstanceSetting.svelte @@ -56,6 +56,16 @@ attempted_at: string } | null = $state(null) + let offlineCapStatus: { + seats_used: number + seats_cap: number + author_count: number + operator_count: number + current_cu: number + cu_cap: number + cu_over_cap: boolean + } | null = $state(null) + function showSetting(setting: string, values: Record) { if (setting == 'dev_instance') { if (values['license_key'] == undefined) { @@ -72,6 +82,14 @@ latestKeyRenewalAttempt = await SettingService.getLatestKeyRenewalAttempt() } + async function reloadLicenseStatus() { + try { + offlineCapStatus = (await SettingService.getOfflineLicenseStatus()) as any + } catch { + offlineCapStatus = null + } + } + async function reloadLicenseKey() { $values['license_key'] = await SettingService.getGlobal({ key: 'license_key' @@ -80,7 +98,10 @@ $effect(() => { if (setting.key == 'license_key') { - untrack(() => reloadKeyrenewalAttemptInfo()) + untrack(() => { + reloadKeyrenewalAttemptInfo() + reloadLicenseStatus() + }) } }) @@ -430,7 +451,7 @@
{/if} {/if} - {#if latestKeyRenewalAttempt} + {#if latestKeyRenewalAttempt && !offlineCapStatus} {@const attemptedAt = new Date(latestKeyRenewalAttempt.attempted_at).toLocaleString()} {@const isTrial = latestKeyRenewalAttempt.result.startsWith('error: trial:')}
@@ -500,11 +521,41 @@
{/if} + {#if offlineCapStatus} + {@const cap = offlineCapStatus} + {@const seatsOver = cap.seats_used > cap.seats_cap} + {@const cuOver = cap.cu_over_cap} +
+
+ {#if seatsOver} + + {:else} + + {/if} + + Seats: {cap.seats_used.toFixed(1)} / {cap.seats_cap} + +
+
+ {#if cuOver} + + {:else} + + {/if} + + CUs: {cap.current_cu.toFixed(2)} / {cap.cu_cap.toFixed(2)} + +
+
+ {/if} + {#if valid || expiration}
- + {#if !offlineCapStatus} + + {/if} diff --git a/frontend/src/routes/(root)/(logged)/workers/+page.svelte b/frontend/src/routes/(root)/(logged)/workers/+page.svelte index 9bc4d1d710..c2de0b81d8 100644 --- a/frontend/src/routes/(root)/(logged)/workers/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/workers/+page.svelte @@ -194,19 +194,6 @@ } } - let defaultTagPerWorkspace: boolean | undefined = $state(undefined) - let defaultTagWorkspaces: string[] = $state([]) - async function loadDefaultTagsPerWorkspace() { - try { - defaultTagPerWorkspace = await WorkerService.isDefaultTagsPerWorkspace() - defaultTagWorkspaces = (await SettingService.getGlobal({ - key: DEFAULT_TAGS_WORKSPACES_SETTING - })) as any - } catch (err) { - sendUserToast(`Could not load default tag per workspace setting: ${err}`, true) - } - } - function parseLicenseKey(key: string): { valid: boolean expiration?: Date @@ -247,13 +234,11 @@ const { valid, expiration } = parseLicenseKey(licenseKey) if (!valid && expiration) { - // License is expired sendUserToast( `Enterprise license key expired on ${expiration.toLocaleDateString()}. Please renew your license key to continue using Windmill.`, true ) } else if (expiration) { - // Check if expires within 7 days const daysUntilExpiration = Math.floor( (expiration.getTime() - Date.now()) / (1000 * 60 * 60 * 24) ) @@ -266,11 +251,23 @@ } } } catch (err) { - // Silently fail - don't show errors for license check console.error('Failed to check license expiration:', err) } } + let defaultTagPerWorkspace: boolean | undefined = $state(undefined) + let defaultTagWorkspaces: string[] = $state([]) + async function loadDefaultTagsPerWorkspace() { + try { + defaultTagPerWorkspace = await WorkerService.isDefaultTagsPerWorkspace() + defaultTagWorkspaces = (await SettingService.getGlobal({ + key: DEFAULT_TAGS_WORKSPACES_SETTING + })) as any + } catch (err) { + sendUserToast(`Could not load default tag per workspace setting: ${err}`, true) + } + } + onMount(() => { intervalId = setInterval(() => { loadWorkers() From 07d3ffbf3434738e53b54720b2006fec154b2466 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Mon, 11 May 2026 22:13:58 +0000 Subject: [PATCH 19/21] system prompts refresh --- system_prompts/auto-generated/prompts.d.ts | 26 +++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/system_prompts/auto-generated/prompts.d.ts b/system_prompts/auto-generated/prompts.d.ts index e9e6136470..fe4156afd4 100644 --- a/system_prompts/auto-generated/prompts.d.ts +++ b/system_prompts/auto-generated/prompts.d.ts @@ -1,6 +1,6 @@ export declare const SCRIPT_BASE = "# Windmill Script Writing Guide\n\n## General Principles\n\n- Scripts must export a main function (do not call it)\n- Libraries are installed automatically - do not show installation instructions\n- Credentials and configuration are stored in resources and passed as parameters\n- The windmill client (`wmill`) provides APIs for interacting with the platform\n\n## Function Naming\n\n- Main function: `main` (or `preprocessor` for preprocessor scripts)\n- Must be async for TypeScript variants\n\n## Return Values\n\n- Scripts can return any JSON-serializable value\n- Return values become available to subsequent flow steps via `results.step_id`\n\n## Preprocessor Scripts\n\nPreprocessor scripts process raw trigger data from various sources (webhook, custom HTTP route, SQS, WebSocket, Kafka, NATS, MQTT, Postgres, or email) before passing it to the flow. This separates the trigger logic from the flow logic and keeps the auto-generated UI clean.\n\nThe returned object determines the parameter values passed to the flow.\ne.g., `{ b: 1, a: 2 }` calls the flow with `a = 2` and `b = 1`, assuming the flow has two inputs called `a` and `b`.\n\nThe preprocessor receives a single parameter called `event`.\n"; -export declare const FLOW_BASE = "# Windmill Flow Building Guide\n\n## Creating a Flow\n\n**You \u2014 the AI agent \u2014 scaffold the flow yourself by running `wmill flow new ` with the right flags. Do NOT hand-create the folder + `flow.yaml`, and do NOT tell the user to \"run `wmill flow new` and follow the prompts\".**\n\n`wmill flow new` creates the folder with the correct suffix (`__flow` or `.flow` depending on the workspace's `nonDottedPaths` setting), writes a minimal `flow.yaml` shell, and prints Claude-specific next-step hints. Scaffolding by hand skips all of that and often picks the wrong suffix.\n\n### Step 1 \u2014 Gather path + summary by asking the user\n\nYou need two things:\n\n1. **path** \u2014 the windmill path, e.g. `f/folder/my_flow` or `u/username/my_flow`.\n2. **summary** \u2014 a short description of the flow.\n\nIf the user's request didn't supply both, ask for both in a single round-trip. Use whichever interactive question facility your runtime provides \u2014 a structured multi-choice tool if available, otherwise plain chat \u2014 and provide one or two example values for each (with an \"Other\" / free-form fallback). Do not guess paths or summaries.\n\n### Step 2 \u2014 Run the command yourself\n\n```bash\nwmill flow new f/folder/my_flow --summary \"Short description\"\n```\n\nAdd `--description \"...\"` when the user provided a longer explanation worth preserving separately from the summary.\n\n### Step 3 \u2014 Fill in `flow.yaml`\n\nOpen the generated `flow.yaml` (under the folder the command just created) and replace the empty `value.modules` + `schema` with the real flow definition.\n\nFor rawscript modules, use `!inline path/to/script.ts` for the content key. Inline script files should NOT include `.inline_script.` in their names (e.g. use `a.ts`, not `a.inline_script.ts`).\n\nOnce the flow has real content, **offer** to open the visual preview as a one-sentence next step (e.g. \"Want me to open the visual preview?\"). Don't auto-open \u2014 opening the dev page has side effects (browser window, possibly a `launch.json` entry) and the user should consent.\n\n### Anti-patterns to avoid\n\n- \u274C Hand-creating the `__flow` folder + `flow.yaml` instead of running `wmill flow new`. You'll miss the suffix-setting resolution, the default shape, and the Claude hints.\n- \u274C Telling the user to \"run `wmill flow new `\" \u2014 you can and should run it yourself.\n- \u274C Inventing a path/summary instead of asking the user.\n\n## CLI Commands \u2014 running, previewing, deploying\n\nAfter writing, tell the user which command fits what they want to do:\n\n- `wmill flow preview ` \u2014 **default when iterating on a local flow.** Runs the local `flow.yaml` against local inline scripts without deploying. Add `--remote` to use deployed workspace scripts for PathScript steps instead of local files.\n- `wmill flow run ` \u2014 runs the flow **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.\n- `wmill generate-metadata` \u2014 regenerate stale `.lock` and `.script.yaml` files. By default it scans **scripts, flows, and apps** across the workspace; pass `--skip-flows --skip-apps` (or run from a subdirectory) to limit the scope when you only care about the flow you edited.\n- `wmill sync push` \u2014 deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push \u2014 not when they say \"run\", \"try\", or \"test\".\n\n### Preview vs run \u2014 choose by intent, not habit\n\nIf the user says \"run the flow\", \"try it\", \"test it\", \"does it work\" while there are **local edits to a `flow.yaml`**, use `flow preview`. Do NOT push the flow to then `flow run` it \u2014 pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.\n\nOnly use `flow run` when:\n- The user explicitly says \"run the deployed version\" / \"run what's on the server\".\n- There is no local `flow.yaml` being edited (you're just invoking an existing flow).\n\nOnly use `sync push` when:\n- The user explicitly asks to deploy, publish, push, or ship.\n- The preview has already validated the change and the user wants it in the workspace.\n\n### After writing \u2014 offer to run, don't wait passively\n\nThis is about **programmatic execution** (`wmill flow preview -d ''`), which actually runs the flow and has side effects. Visual preview (the `preview` skill) is offered separately \u2014 see \"Visual preview\" below.\n\nIf the user hasn't already told you to run/test the flow, offer it as a one-sentence next step (e.g. \"Want me to run `wmill flow preview` with sample args?\"). Do not present a multi-option menu.\n\nIf the user already asked to test/run/try the flow in their original request, skip the offer and just execute `wmill flow preview -d ''` directly \u2014 pick plausible args from the flow's input schema.\n\n`wmill flow preview` is safe to run yourself (it does not deploy). `wmill sync push` and `wmill generate-metadata` modify workspace state or local files \u2014 only run these when the user explicitly asks; otherwise tell them which to run.\n\n### Visual preview\n\nTo open the flow visually in the dev page (graph + live reload), use the `preview` skill. Always **offer** it as a one-sentence next step (e.g. \"Want me to open the visual preview?\") rather than opening it automatically \u2014 opening the dev page has side effects (browser window, possibly a `launch.json` entry under MCP-preview branches) the user should consent to. If the user already asked to see/preview/visualize the flow in their original request, skip the offer and just invoke the skill.\n\n## OpenFlow Schema\n\nThe OpenFlow schema (openflow.openapi.yaml) is the source of truth for flow structure. Refer to OPENFLOW_SCHEMA for the complete type definitions.\n\n## Reserved Module IDs\n\n- `failure` - Reserved for failure handler module\n- `preprocessor` - Reserved for preprocessor module\n- `Input` - Reserved for flow input reference\n\n## Hard Structural Rules\n\nThese are strict Windmill schema rules. Follow them exactly.\n\n- `value.modules` is only for normal sequential steps\n- `value.preprocessor_module` and `value.failure_module` are special top-level fields inside `value`, not entries in `value.modules`\n- If a flow needs a preprocessor, create `value.preprocessor_module` with `id: preprocessor`\n- If a flow needs a failure handler, create `value.failure_module` with `id: failure`\n- Do NOT create regular modules inside `value.modules` named `preprocessor` or `failure`\n- `preprocessor_module` and `failure_module` only support `script` or `rawscript`\n- `preprocessor_module` runs before normal modules and cannot reference `results.*`\n- `failure_module` can use the `error` object with `error.message`, `error.step_id`, `error.name`, and `error.stack`\n\nCorrect shape:\n\n```yaml\nvalue:\n preprocessor_module:\n id: preprocessor\n value:\n type: rawscript\n ...\n failure_module:\n id: failure\n value:\n type: rawscript\n ...\n modules:\n - id: process_event\n value:\n type: rawscript\n ...\n```\n\nIncorrect shape:\n\n```yaml\nvalue:\n modules:\n - id: preprocessor\n ...\n - id: process_event\n ...\n - id: failure\n ...\n```\n\n## Module ID Rules\n\n- Must be unique across the entire flow\n- Use underscores, not spaces (e.g., `fetch_data` not `fetch data`)\n- Use descriptive names that reflect the step's purpose\n\n## Common Mistakes to Avoid\n\n- Missing `input_transforms` - Rawscript parameters won't receive values without them\n- Referencing future steps - `results.step_id` only works for steps that execute before the current one\n- Duplicate module IDs - Each module ID must be unique in the flow\n\n## Data Flow Between Steps\n\n- `flow_input.property` - Access flow input parameters\n- `results.step_id` - Access output from a previous step only when that step result is in scope\n- `results.step_id.property` - Access specific property from a previous step output only when that step result is in scope\n- `flow_input.iter.value` - Current iteration value when inside a loop (`forloopflow` or `whileloopflow`)\n- `flow_input.iter.index` - Current loop index when inside a loop (`forloopflow` or `whileloopflow`)\n\n## Loop Structure Rules\n\n- For `whileloopflow`, use module-level `stop_after_if` on the loop module itself when the loop should stop after an iteration result\n- Do NOT put `stop_after_if` inside `value` of a `whileloopflow`\n- `stop_after_all_iters_if` is for checks after the whole loop finishes, not the normal per-iteration break condition\n- When a `whileloopflow` carries state forward between iterations, use `flow_input.iter.value` as the current loop value and provide an explicit first-iteration fallback when needed\n- Use `flow_input.iter.index` only when the loop logic is truly based on the iteration index, not as a replacement for the current loop value\n- If the user asks for a final scalar/object after a loop, add a normal step after the loop that extracts the final value from the loop result instead of returning the whole loop result array\n\nCorrect `whileloopflow` shape:\n\n```yaml\n- id: loop_until_done\n stop_after_if:\n expr: result.done === true\n skip_if_stopped: false\n value:\n type: whileloopflow\n skip_failures: false\n modules:\n - id: advance_state\n value:\n type: rawscript\n input_transforms:\n state:\n type: javascript\n expr: flow_input.iter && flow_input.iter.value !== undefined ? flow_input.iter.value : flow_input.initial_state\n- id: return_final_state\n value:\n type: rawscript\n input_transforms:\n final_state:\n type: javascript\n expr: results.loop_until_done[results.loop_until_done.length - 1]\n```\n\nIncorrect `whileloopflow` patterns:\n\n```yaml\n- id: loop_until_done\n value:\n type: whileloopflow\n stop_after_if:\n expr: result.done === true\n```\n\n```yaml\ninput_transforms:\n state:\n type: javascript\n expr: flow_input.iter.index\n```\n\n```yaml\ninput_transforms:\n final_state:\n type: javascript\n expr: results.loop_until_done\n```\n\n## Approval / Suspend Structure\n\n- `suspend` belongs on the flow module object itself, as a sibling of `id` and `value`\n- Never put `suspend` inside `value`\n\nCorrect shape:\n\n```yaml\n- id: request_approval\n suspend:\n required_events: 1\n resume_form:\n schema:\n type: object\n properties:\n comment:\n type: string\n required: [comment]\n value:\n type: identity\n```\n\nIncorrect shape:\n\n```yaml\n- id: request_approval\n value:\n type: rawscript\n suspend:\n required_events: 1\n```\n\n## Branch Result Scope Rules\n\n- Inside a branch, you may reference earlier outer steps and earlier steps in the same branch\n- Outside a `branchone`, do NOT reference ids of steps that only exist inside its branches or default branch. Use `results.` instead\n- Outside a `branchall`, do NOT reference ids of steps inside its branches. Use `results.` instead\n- If downstream steps need a stable shape after a branch, make each branch return the same fields\n- When needed, add a normalization step immediately after the branch and consume `results.` there\n\nCorrect after `branchone`:\n\n```yaml\n- id: route_order\n value:\n type: branchone\n ...\n- id: send_confirmation\n value:\n input_transforms:\n routed:\n type: javascript\n expr: results.route_order\n```\n\nIncorrect after `branchone`:\n\n```yaml\nexpr: results.create_shipment\nexpr: results.create_backorder\n```\n\nCorrect after `branchall`:\n\n```yaml\n- id: enrich_parallel\n value:\n type: branchall\n parallel: true\n ...\n- id: combine_data\n value:\n input_transforms:\n enrichments:\n type: javascript\n expr: results.enrich_parallel\n```\n\n## Input Transforms\n\nEvery rawscript module needs `input_transforms` to map function parameters to values:\n\nStatic transform (fixed value):\n{\"param_name\": {\"type\": \"static\", \"value\": \"fixed_string\"}}\n\nJavaScript transform (dynamic expression):\n{\"param_name\": {\"type\": \"javascript\", \"expr\": \"results.previous_step.data\"}}\n\n## Resource References\n\n- For flow inputs: Use type `\"object\"` with format `\"resource-{type}\"` (e.g., `\"resource-postgresql\"`)\n- For step inputs: Use static value `\"$res:path/to/resource\"`\n\n## Final Structural Self-Check\n\nBefore finalizing a flow, verify:\n\n- any preprocessor is in `value.preprocessor_module`\n- any failure handler is in `value.failure_module`\n- any approval step has module-level `suspend`\n- no downstream step references inner branch step ids from outside the branch\n\n## S3 Object Operations\n\nWindmill provides built-in support for S3-compatible storage operations.\n\nTo accept an S3 object as flow input:\n\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"file\": {\n \"type\": \"object\",\n \"format\": \"resource-s3_object\",\n \"description\": \"File to process\"\n }\n }\n}\n```\n\n## Using Resources in Flows\n\nOn Windmill, credentials and configuration are stored in resources. Resource types define the format of the resource.\n\n### As Flow Input\n\nIn the flow schema, set the property type to `\"object\"` with format `\"resource-{type}\"`:\n\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"database\": {\n \"type\": \"object\",\n \"format\": \"resource-postgresql\",\n \"description\": \"Database connection\"\n }\n }\n}\n```\n\n### As Step Input (Static Reference)\n\nReference a specific resource using `$res:` prefix:\n\n```json\n{\n \"database\": {\n \"type\": \"static\",\n \"value\": \"$res:f/folder/my_database\"\n }\n}\n```\n"; -export declare const WORKFLOW_AS_CODE_BASE = "# Windmill Workflow-as-Code Writing Guide\n\n## Scope\n\nUse this guide when writing or modifying Windmill Workflow-as-Code (WAC) scripts.\nWAC is authored as a Windmill script and deployed with the normal script workflow. It is not an OpenFlow YAML flow.\n\nSupported WAC authoring targets:\n- TypeScript scripts that import from `windmill-client`\n- Python 3 scripts that import from `wmill`\n\n## File Shape\n\nTypeScript:\n\n```typescript\nimport {\n task,\n taskScript,\n taskFlow,\n step,\n sleep,\n waitForApproval,\n getResumeUrls,\n parallel,\n workflow,\n} from \"windmill-client\";\n\nconst process = task(async (x: string): Promise => {\n return `processed: ${x}`;\n});\n\nexport const main = workflow(async (x: string) => {\n const result = await process(x);\n return { result };\n});\n```\n\nPython:\n\n```python\nfrom wmill import task, task_script, task_flow, step, sleep, wait_for_approval, get_resume_urls, parallel, workflow\n\n@task()\nasync def process(x: str) -> str:\n return f\"processed: {x}\"\n\n@workflow\nasync def main(x: str):\n result = await process(x)\n return {\"result\": result}\n```\n\nRules:\n- Do not call `main`.\n- TypeScript should export the workflow entrypoint, preferably `export const main = workflow(async (...) => { ... })`.\n- Python must use `@workflow` on an async top-level function, usually `main`.\n- Define task functions and `taskScript`/`task_script` or `taskFlow`/`task_flow` assignments at module top level with stable names.\n- Use the exact SDK names. Do not alias `workflow`, `task`, `taskScript`, `taskFlow`, `step`, `sleep`, `waitForApproval`, `task_script`, `task_flow`, or `wait_for_approval`; the WAC parser recognizes these names directly.\n\n## Checkpoint And Replay Model\n\nThe parent workflow may rerun from the top after any suspension, retry, approval, or child task completion. Completed durable steps are replayed from the checkpoint.\n\nPut every side effect or non-deterministic value behind a durable WAC boundary:\n- Use `task()` / `@task()` for substantial work that should run as its own child job.\n- Use `taskScript()` / `task_script()` for an existing script or a relative module file.\n- Use `taskFlow()` / `task_flow()` for an existing Windmill flow.\n- Use `step(name, fn)` for lightweight inline work whose result must be checkpointed.\n- Use `sleep(seconds)` for server-side sleeps that do not hold a worker.\n- Use `waitForApproval()` / `wait_for_approval()` for external approval suspension.\n\nNever put API calls, database writes, notifications, random values, timestamps, or irreversible changes directly in the top-level workflow body. The workflow body can be rerun. Put those operations in a task or in `step()`.\n\nBranching on task or step results is safe because those results are checkpointed. Branching on current time, random data, environment reads, or external state is unsafe unless the value is first captured with `step()`.\n\n## Tasks\n\nUse `task()` / `@task()` for inline functions that become workflow steps:\n\n```typescript\nconst enrich = task(async (customerId: string) => {\n return await fetchCustomer(customerId);\n});\n```\n\n```python\n@task(timeout=600, tag=\"etl\")\nasync def enrich(customer_id: str):\n return await fetch_customer(customer_id)\n```\n\nIn TypeScript, prefer assigning each task to a named top-level const. In Python, prefer top-level async functions decorated with `@task()` or `@task`.\n\nFor existing scripts:\n\n```typescript\nconst helper = taskScript(\"./helper.ts\");\nconst existing = taskScript(\"f/data/extract\", { timeout: 600 });\nconst value = await helper({ input: x });\n```\n\n```python\nhelper = task_script(\"./helper.py\")\nexisting = task_script(\"f/data/extract\", timeout=600)\nvalue = await helper(input=x)\n```\n\nFor existing flows:\n\n```typescript\nconst pipeline = taskFlow(\"f/etl/pipeline\");\nconst output = await pipeline({ input: data });\n```\n\n```python\npipeline = task_flow(\"f/etl/pipeline\")\noutput = await pipeline(input=data)\n```\n\n## Inline Steps\n\nUse `step()` for lightweight inline values that must not change during replay:\n\n```typescript\nconst urls = await step(\"get_urls\", () => getResumeUrls());\nconst startedAt = await step(\"started_at\", () => new Date().toISOString());\n```\n\n```python\nurls = await step(\"get_urls\", lambda: get_resume_urls())\n```\n\nUse stable, descriptive step names. Do not generate step names dynamically.\n\n## Parallelism\n\nTo run independent work in parallel, start task promises/coroutines before awaiting them together:\n\n```typescript\nconst [a, b] = await Promise.all([process(\"a\"), process(\"b\")]);\nconst many = await parallel(items, process, { concurrency: 5 });\n```\n\n```python\nimport asyncio\n\na, b = await asyncio.gather(process(\"a\"), process(\"b\"))\nmany = await parallel(items, process, concurrency=5)\n```\n\nOnly parallelize independent steps. Do not read the result of a task before it is awaited.\n\n## Approvals\n\nGenerate resume URLs inside `step()` before sending them:\n\n```typescript\nconst urls = await step(\"get_urls\", () => getResumeUrls());\nawait step(\"notify\", () => sendApprovalEmail(urls.approvalPage));\nconst approval = await waitForApproval({ timeout: 3600 });\n```\n\n```python\nurls = await step(\"get_urls\", lambda: get_resume_urls())\nawait step(\"notify\", lambda: send_approval_email(urls[\"approvalPage\"]))\napproval = await wait_for_approval(timeout=3600)\n```\n\n`selfApproval: false` and `self_approval=False` are Enterprise-only approval behavior. Do not use them unless the user asks for that behavior.\n\n## Error Handling\n\nLet task errors fail the workflow unless the user asks for recovery logic.\n\nPython: `except Exception` is safe around WAC calls because internal suspension inherits from `BaseException`. Avoid bare `except:` in workflow code. If the user asks for recovery logic around failed child work, catch `TaskError` from `wmill` for task failures.\n\nTypeScript: avoid broad `try/catch` around WAC SDK calls. The SDK uses an internal suspension error during initial dispatch; catching it can break workflow suspension. If a broad catch is unavoidable, rethrow internal suspension errors before handling business errors.\n"; +export declare const FLOW_BASE = "# Windmill Flow Building Guide\n\n## OpenFlow Schema\n\nThe OpenFlow schema (openflow.openapi.yaml) is the source of truth for flow structure. Refer to OPENFLOW_SCHEMA for the complete type definitions.\n\n## Reserved Module IDs\n\n- `failure` - Reserved for failure handler module\n- `preprocessor` - Reserved for preprocessor module\n- `Input` - Reserved for flow input reference\n\n## Hard Structural Rules\n\nThese are strict Windmill schema rules. Follow them exactly.\n\n- `value.modules` is only for normal sequential steps\n- `value.preprocessor_module` and `value.failure_module` are special top-level fields inside `value`, not entries in `value.modules`\n- If a flow needs a preprocessor, create `value.preprocessor_module` with `id: preprocessor`\n- If a flow needs a failure handler, create `value.failure_module` with `id: failure`\n- Do NOT create regular modules inside `value.modules` named `preprocessor` or `failure`\n- `preprocessor_module` and `failure_module` only support `script` or `rawscript`\n- `preprocessor_module` runs before normal modules and cannot reference `results.*`\n- `failure_module` can use the `error` object with `error.message`, `error.step_id`, `error.name`, and `error.stack`\n\nCorrect shape:\n\n```yaml\nvalue:\n preprocessor_module:\n id: preprocessor\n value:\n type: rawscript\n ...\n failure_module:\n id: failure\n value:\n type: rawscript\n ...\n modules:\n - id: process_event\n value:\n type: rawscript\n ...\n```\n\nIncorrect shape:\n\n```yaml\nvalue:\n modules:\n - id: preprocessor\n ...\n - id: process_event\n ...\n - id: failure\n ...\n```\n\n## Module ID Rules\n\n- Must be unique across the entire flow\n- Use underscores, not spaces (e.g., `fetch_data` not `fetch data`)\n- Use descriptive names that reflect the step's purpose\n\n## Common Mistakes to Avoid\n\n- Missing `input_transforms` - Rawscript parameters won't receive values without them\n- Referencing future steps - `results.step_id` only works for steps that execute before the current one\n- Duplicate module IDs - Each module ID must be unique in the flow\n\n## Data Flow Between Steps\n\n- `flow_input.property` - Access flow input parameters\n- `results.step_id` - Access output from a previous step only when that step result is in scope\n- `results.step_id.property` - Access specific property from a previous step output only when that step result is in scope\n- `flow_input.iter.value` - Current iteration value when inside a loop (`forloopflow` or `whileloopflow`)\n- `flow_input.iter.index` - Current loop index when inside a loop (`forloopflow` or `whileloopflow`)\n\n## Loop Structure Rules\n\n- For `whileloopflow`, use module-level `stop_after_if` on the loop module itself when the loop should stop after an iteration result\n- Do NOT put `stop_after_if` inside `value` of a `whileloopflow`\n- `stop_after_all_iters_if` is for checks after the whole loop finishes, not the normal per-iteration break condition\n- When a `whileloopflow` carries state forward between iterations, use `flow_input.iter.value` as the current loop value and provide an explicit first-iteration fallback when needed\n- Use `flow_input.iter.index` only when the loop logic is truly based on the iteration index, not as a replacement for the current loop value\n- If the user asks for a final scalar/object after a loop, add a normal step after the loop that extracts the final value from the loop result instead of returning the whole loop result array\n\nCorrect `whileloopflow` shape:\n\n```yaml\n- id: loop_until_done\n stop_after_if:\n expr: result.done === true\n skip_if_stopped: false\n value:\n type: whileloopflow\n skip_failures: false\n modules:\n - id: advance_state\n value:\n type: rawscript\n input_transforms:\n state:\n type: javascript\n expr: flow_input.iter && flow_input.iter.value !== undefined ? flow_input.iter.value : flow_input.initial_state\n- id: return_final_state\n value:\n type: rawscript\n input_transforms:\n final_state:\n type: javascript\n expr: results.loop_until_done[results.loop_until_done.length - 1]\n```\n\nIncorrect `whileloopflow` patterns:\n\n```yaml\n- id: loop_until_done\n value:\n type: whileloopflow\n stop_after_if:\n expr: result.done === true\n```\n\n```yaml\ninput_transforms:\n state:\n type: javascript\n expr: flow_input.iter.index\n```\n\n```yaml\ninput_transforms:\n final_state:\n type: javascript\n expr: results.loop_until_done\n```\n\n## Approval / Suspend Structure\n\n- `suspend` belongs on the flow module object itself, as a sibling of `id` and `value`\n- Never put `suspend` inside `value`\n\nCorrect shape:\n\n```yaml\n- id: request_approval\n suspend:\n required_events: 1\n resume_form:\n schema:\n type: object\n properties:\n comment:\n type: string\n required: [comment]\n value:\n type: identity\n```\n\nIncorrect shape:\n\n```yaml\n- id: request_approval\n value:\n type: rawscript\n suspend:\n required_events: 1\n```\n\n## Branch Result Scope Rules\n\n- Inside a branch, you may reference earlier outer steps and earlier steps in the same branch\n- Outside a `branchone`, do NOT reference ids of steps that only exist inside its branches or default branch. Use `results.` instead\n- Outside a `branchall`, do NOT reference ids of steps inside its branches. Use `results.` instead\n- If downstream steps need a stable shape after a branch, make each branch return the same fields\n- When needed, add a normalization step immediately after the branch and consume `results.` there\n\nCorrect after `branchone`:\n\n```yaml\n- id: route_order\n value:\n type: branchone\n ...\n- id: send_confirmation\n value:\n input_transforms:\n routed:\n type: javascript\n expr: results.route_order\n```\n\nIncorrect after `branchone`:\n\n```yaml\nexpr: results.create_shipment\nexpr: results.create_backorder\n```\n\nCorrect after `branchall`:\n\n```yaml\n- id: enrich_parallel\n value:\n type: branchall\n parallel: true\n ...\n- id: combine_data\n value:\n input_transforms:\n enrichments:\n type: javascript\n expr: results.enrich_parallel\n```\n\n## Input Transforms\n\nEvery rawscript module needs `input_transforms` to map function parameters to values:\n\nStatic transform (fixed value):\n{\"param_name\": {\"type\": \"static\", \"value\": \"fixed_string\"}}\n\nJavaScript transform (dynamic expression):\n{\"param_name\": {\"type\": \"javascript\", \"expr\": \"results.previous_step.data\"}}\n\n## Resource References\n\n- For flow inputs: Use type `\"object\"` with format `\"resource-{type}\"` (e.g., `\"resource-postgresql\"`)\n- For step inputs: Use static value `\"$res:path/to/resource\"`\n\n## Final Structural Self-Check\n\nBefore finalizing a flow, verify:\n\n- any preprocessor is in `value.preprocessor_module`\n- any failure handler is in `value.failure_module`\n- any approval step has module-level `suspend`\n- no downstream step references inner branch step ids from outside the branch\n\n## S3 Object Operations\n\nWindmill provides built-in support for S3-compatible storage operations.\n\nTo accept an S3 object as flow input:\n\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"file\": {\n \"type\": \"object\",\n \"format\": \"resource-s3_object\",\n \"description\": \"File to process\"\n }\n }\n}\n```\n\n## Using Resources in Flows\n\nOn Windmill, credentials and configuration are stored in resources. Resource types define the format of the resource.\n\n### As Flow Input\n\nIn the flow schema, set the property type to `\"object\"` with format `\"resource-{type}\"`:\n\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"database\": {\n \"type\": \"object\",\n \"format\": \"resource-postgresql\",\n \"description\": \"Database connection\"\n }\n }\n}\n```\n\n### As Step Input (Static Reference)\n\nReference a specific resource using `$res:` prefix:\n\n```json\n{\n \"database\": {\n \"type\": \"static\",\n \"value\": \"$res:f/folder/my_database\"\n }\n}\n```\n"; +export declare const WORKFLOW_AS_CODE_BASE = "# Windmill Workflow-as-Code Writing Guide\n\n## Scope\n\nUse this guide when writing or modifying Windmill Workflow-as-Code (WAC) scripts.\nWAC is authored as a Windmill script and deployed with the normal script workflow. It is not an OpenFlow YAML flow.\n\nSupported WAC authoring targets:\n- Bun TypeScript scripts that import from `windmill-client`\n- Python 3 scripts that import from `wmill`\n\n## File Shape\n\nBun TypeScript:\n\n```typescript\nimport {\n task,\n taskScript,\n taskFlow,\n step,\n sleep,\n waitForApproval,\n getResumeUrls,\n parallel,\n workflow,\n} from \"windmill-client\";\n\nconst process = task(async (x: string): Promise => {\n return `processed: ${x}`;\n});\n\nexport const main = workflow(async (x: string) => {\n const result = await process(x);\n return { result };\n});\n```\n\nPython:\n\n```python\nfrom wmill import task, task_script, task_flow, step, sleep, wait_for_approval, get_resume_urls, parallel, workflow\n\n@task()\nasync def process(x: str) -> str:\n return f\"processed: {x}\"\n\n@workflow\nasync def main(x: str):\n result = await process(x)\n return {\"result\": result}\n```\n\nRules:\n- Do not call `main`.\n- Bun TypeScript should export the workflow entrypoint, preferably `export const main = workflow(async (...) => { ... })`.\n- Python must use `@workflow` on an async top-level function, usually `main`.\n- Define task functions and `taskScript`/`task_script` or `taskFlow`/`task_flow` assignments at module top level with stable names.\n- Use the exact SDK names. Do not alias `workflow`, `task`, `taskScript`, `taskFlow`, `step`, `sleep`, `waitForApproval`, `task_script`, `task_flow`, or `wait_for_approval`; the WAC parser recognizes these names directly.\n\n## Checkpoint And Replay Model\n\nThe parent workflow may rerun from the top after any suspension, retry, approval, or child task completion. Completed durable steps are replayed from the checkpoint.\n\nPut every side effect or non-deterministic value behind a durable WAC boundary:\n- Use `task()` / `@task()` for substantial work that should run as its own child job.\n- Use `taskScript()` / `task_script()` for an existing script or a relative module file.\n- Use `taskFlow()` / `task_flow()` for an existing Windmill flow.\n- Use `step(name, fn)` for lightweight inline work whose result must be checkpointed.\n- Use `sleep(seconds)` for server-side sleeps that do not hold a worker.\n- Use `waitForApproval()` / `wait_for_approval()` for external approval suspension.\n\nNever put API calls, database writes, notifications, random values, timestamps, or irreversible changes directly in the top-level workflow body. The workflow body can be rerun. Put those operations in a task or in `step()`.\n\nBranching on task or step results is safe because those results are checkpointed. Branching on current time, random data, environment reads, or external state is unsafe unless the value is first captured with `step()`.\n\n## Tasks\n\nUse `task()` / `@task()` for inline functions that become workflow steps:\n\n```typescript\nconst enrich = task(async (customerId: string) => {\n return await fetchCustomer(customerId);\n});\n```\n\n```python\n@task(timeout=600, tag=\"etl\")\nasync def enrich(customer_id: str):\n return await fetch_customer(customer_id)\n```\n\nIn TypeScript, prefer assigning each task to a named top-level const. In Python, prefer top-level async functions decorated with `@task()` or `@task`.\n\nFor existing scripts:\n\n```typescript\nconst helper = taskScript(\"./helper.ts\");\nconst existing = taskScript(\"f/data/extract\", { timeout: 600 });\nconst value = await helper({ input: x });\n```\n\n```python\nhelper = task_script(\"./helper.py\")\nexisting = task_script(\"f/data/extract\", timeout=600)\nvalue = await helper(input=x)\n```\n\nFor existing flows:\n\n```typescript\nconst pipeline = taskFlow(\"f/etl/pipeline\");\nconst output = await pipeline({ input: data });\n```\n\n```python\npipeline = task_flow(\"f/etl/pipeline\")\noutput = await pipeline(input=data)\n```\n\n## Inline Steps\n\nUse `step()` for lightweight inline values that must not change during replay:\n\n```typescript\nconst urls = await step(\"get_urls\", () => getResumeUrls());\nconst startedAt = await step(\"started_at\", () => new Date().toISOString());\n```\n\n```python\nurls = await step(\"get_urls\", lambda: get_resume_urls())\n```\n\nUse stable, descriptive step names. Do not generate step names dynamically.\n\n## Parallelism\n\nTo run independent work in parallel, start task promises/coroutines before awaiting them together:\n\n```typescript\nconst [a, b] = await Promise.all([process(\"a\"), process(\"b\")]);\nconst many = await parallel(items, process, { concurrency: 5 });\n```\n\n```python\nimport asyncio\n\na, b = await asyncio.gather(process(\"a\"), process(\"b\"))\nmany = await parallel(items, process, concurrency=5)\n```\n\nOnly parallelize independent steps. Do not read the result of a task before it is awaited.\n\n## Approvals\n\nGenerate resume URLs inside `step()` before sending them:\n\n```typescript\nconst urls = await step(\"get_urls\", () => getResumeUrls());\nawait step(\"notify\", () => sendApprovalEmail(urls.approvalPage));\nconst approval = await waitForApproval({ timeout: 3600 });\n```\n\n```python\nurls = await step(\"get_urls\", lambda: get_resume_urls())\nawait step(\"notify\", lambda: send_approval_email(urls[\"approvalPage\"]))\napproval = await wait_for_approval(timeout=3600)\n```\n\n`selfApproval: false` and `self_approval=False` are Enterprise-only approval behavior. Do not use them unless the user asks for that behavior.\n\n## Error Handling\n\nLet task errors fail the workflow unless the user asks for recovery logic.\n\nPython: `except Exception` is safe around WAC calls because internal suspension inherits from `BaseException`. Avoid bare `except:` in workflow code. If the user asks for recovery logic around failed child work, catch `TaskError` from `wmill` for task failures.\n\nTypeScript: avoid broad `try/catch` around WAC SDK calls. The SDK uses an internal suspension error during initial dispatch; catching it can break workflow suspension. If a broad catch is unavoidable, rethrow internal suspension errors before handling business errors.\n"; export declare const FLOW_CHAT_SPECIAL_MODULES = "## Special Modules\n\n- Use `set_preprocessor_module` to add, replace, or remove the top-level `value.preprocessor_module`\n- Use `set_failure_module` to add, replace, or remove the top-level `value.failure_module`\n- Use `set_flow_json` only when you are replacing the whole flow, including normal modules and optional special modules\n\n**Example - Update only the special modules:**\n```javascript\nset_preprocessor_module({\n module: JSON.stringify({\n id: \"preprocessor\",\n value: {\n type: \"rawscript\",\n language: \"bun\",\n content: \"export async function preprocessor(payload: string) { const trimmed = payload.trim(); if (!trimmed) { throw new Error('payload must not be empty'); } return { payload: trimmed }; }\",\n input_transforms: {\n payload: { type: \"javascript\", expr: \"flow_input.payload\" }\n }\n }\n })\n})\n\nset_failure_module({\n module: JSON.stringify({\n id: \"failure\",\n value: {\n type: \"rawscript\",\n language: \"bun\",\n content: \"export async function main(message: string, name: string, step_id: string) { return { message, name, step_id }; }\",\n input_transforms: {\n message: { type: \"javascript\", expr: \"error.message\" },\n name: { type: \"javascript\", expr: \"error.name\" },\n step_id: { type: \"javascript\", expr: \"error.step_id\" }\n }\n }\n })\n})\n```\n"; export declare const SDK_TYPESCRIPT = "# TypeScript SDK (windmill-client)\n\nImport: import * as wmill from 'windmill-client'\n\nworkerHasInternalServer(): boolean\n\n/**\n * Initialize the Windmill client with authentication token and base URL\n * @param token - Authentication token (defaults to WM_TOKEN env variable)\n * @param baseUrl - API base URL (defaults to BASE_INTERNAL_URL or BASE_URL env variable)\n */\nsetClient(token?: string, baseUrl?: string): void\n\n/**\n * Create a client configuration from env variables\n * @returns client configuration\n */\ngetWorkspace(): string\n\n/**\n * Get a resource value by path\n * @param path path of the resource, default to internal state path\n * @param undefinedIfEmpty if the resource does not exist, return undefined instead of throwing an error\n * @returns resource value\n */\nasync getResource(path?: string, undefinedIfEmpty?: boolean): Promise\n\n/**\n * Get the true root job id\n * @param jobId job id to get the root job id from (default to current job)\n * @returns root job id\n */\nasync getRootJobId(jobId?: string): Promise\n\n/**\n * @deprecated Use runScriptByPath or runScriptByHash instead\n */\nasync runScript(path: string | null = null, hash_: string | null = null, args: Record | null = null, verbose: boolean = false): Promise\n\n/**\n * Run a script synchronously by its path and wait for the result\n * @param path - Script path in Windmill\n * @param args - Arguments to pass to the script\n * @param verbose - Enable verbose logging\n * @returns Script execution result\n */\nasync runScriptByPath(path: string, args: Record | null = null, verbose: boolean = false): Promise\n\n/**\n * Run a script synchronously by its hash and wait for the result\n * @param hash_ - Script hash in Windmill\n * @param args - Arguments to pass to the script\n * @param verbose - Enable verbose logging\n * @returns Script execution result\n */\nasync runScriptByHash(hash_: string, args: Record | null = null, verbose: boolean = false): Promise\n\n/**\n * Append a text to the result stream\n * @param text text to append to the result stream\n */\nappendToResultStream(text: string): void\n\n/**\n * Stream to the result stream\n * @param stream stream to stream to the result stream\n */\nasync streamResult(stream: AsyncIterable): Promise\n\n/**\n * Run a flow synchronously by its path and wait for the result\n * @param path - Flow path in Windmill\n * @param args - Arguments to pass to the flow\n * @param verbose - Enable verbose logging\n * @returns Flow execution result\n */\nasync runFlow(path: string | null = null, args: Record | null = null, verbose: boolean = false): Promise\n\n/**\n * Wait for a job to complete and return its result\n * @param jobId - ID of the job to wait for\n * @param verbose - Enable verbose logging\n * @returns Job result when completed\n */\nasync waitJob(jobId: string, verbose: boolean = false): Promise\n\n/**\n * Get the result of a completed job\n * @param jobId - ID of the completed job\n * @returns Job result\n */\nasync getResult(jobId: string): Promise\n\n/**\n * Get the result of a job if completed, or its current status\n * @param jobId - ID of the job\n * @returns Object with started, completed, success, and result properties\n */\nasync getResultMaybe(jobId: string): Promise\n\n/**\n * @deprecated Use runScriptByPathAsync or runScriptByHashAsync instead\n */\nasync runScriptAsync(path: string | null, hash_: string | null, args: Record | null, scheduledInSeconds: number | null = null): Promise\n\n/**\n * Run a script asynchronously by its path\n * @param path - Script path in Windmill\n * @param args - Arguments to pass to the script\n * @param scheduledInSeconds - Schedule execution for a future time (in seconds)\n * @returns Job ID of the created job\n */\nasync runScriptByPathAsync(path: string, args: Record | null = null, scheduledInSeconds: number | null = null): Promise\n\n/**\n * Run a script asynchronously by its hash\n * @param hash_ - Script hash in Windmill\n * @param args - Arguments to pass to the script\n * @param scheduledInSeconds - Schedule execution for a future time (in seconds)\n * @returns Job ID of the created job\n */\nasync runScriptByHashAsync(hash_: string, args: Record | null = null, scheduledInSeconds: number | null = null): Promise\n\n/**\n * Run a flow asynchronously by its path\n * @param path - Flow path in Windmill\n * @param args - Arguments to pass to the flow\n * @param scheduledInSeconds - Schedule execution for a future time (in seconds)\n * @param doNotTrackInParent - If false, tracks state in parent job (only use when fully awaiting the job)\n * @returns Job ID of the created job\n */\nasync runFlowAsync(path: string | null, args: Record | null, scheduledInSeconds: number | null = null, // can only be set to false if this the job will be fully await and not concurrent with any other job // as otherwise the child flow and its own child will store their state in the parent job which will // lead to incorrectness and failures doNotTrackInParent: boolean = true): Promise\n\n/**\n * Resolve a resource value in case the default value was picked because the input payload was undefined\n * @param obj resource value or path of the resource under the format `$res:path`\n * @returns resource value\n */\nasync resolveDefaultResource(obj: any): Promise\n\n/**\n * Get the state file path from environment variables\n * @returns State path string\n */\ngetStatePath(): string\n\n/**\n * Set a resource value by path\n * @param path path of the resource to set, default to state path\n * @param value new value of the resource to set\n * @param initializeToTypeIfNotExist if the resource does not exist, initialize it with this type\n */\nasync setResource(value: any, path?: string, initializeToTypeIfNotExist?: string): Promise\n\n/**\n * Set the state\n * @param state state to set\n * @deprecated use setState instead\n */\nasync setInternalState(state: any): Promise\n\n/**\n * Set the state\n * @param state state to set\n * @param path Optional state resource path override. Defaults to `getStatePath()`.\n */\nasync setState(state: any, path?: string): Promise\n\n/**\n * Set the progress\n * Progress cannot go back and limited to 0% to 99% range\n * @param percent Progress to set in %\n * @param jobId? Job to set progress for\n */\nasync setProgress(percent: number, jobId?: any): Promise\n\n/**\n * Get the progress\n * @param jobId? Job to get progress from\n * @returns Optional clamped between 0 and 100 progress value\n */\nasync getProgress(jobId?: any): Promise\n\n/**\n * Set a flow user state\n * @param key key of the state\n * @param value value of the state\n */\nasync setFlowUserState(key: string, value: any, errorIfNotPossible?: boolean): Promise\n\n/**\n * Get a flow user state\n * @param path path of the variable\n */\nasync getFlowUserState(key: string, errorIfNotPossible?: boolean): Promise\n\n/**\n * Get the internal state\n * @deprecated use getState instead\n */\nasync getInternalState(): Promise\n\n/**\n * Get the state shared across executions\n * @param path Optional state resource path override. Defaults to `getStatePath()`.\n */\nasync getState(path?: string): Promise\n\n/**\n * Get a variable by path\n * @param path path of the variable\n * @returns variable value\n */\nasync getVariable(path: string): Promise\n\n/**\n * Set a variable by path, create if not exist\n * @param path path of the variable\n * @param value value of the variable\n * @param isSecretIfNotExist if the variable does not exist, create it as secret or not (default: false)\n * @param descriptionIfNotExist if the variable does not exist, create it with this description (default: \"\")\n */\nasync setVariable(path: string, value: string, isSecretIfNotExist?: boolean, descriptionIfNotExist?: string): Promise\n\n/**\n * Build a PostgreSQL connection URL from a database resource\n * @param path - Path to the database resource\n * @returns PostgreSQL connection URL string\n */\nasync databaseUrlFromResource(path: string): Promise\n\nasync polarsConnectionSettings(s3_resource_path: string | undefined): Promise\n\nasync duckdbConnectionSettings(s3_resource_path: string | undefined): Promise\n\n/**\n * Get S3 client settings from a resource or workspace default\n * @param s3_resource_path - Path to S3 resource (uses workspace default if undefined)\n * @returns S3 client configuration settings\n */\nasync denoS3LightClientSettings(s3_resource_path: string | undefined): Promise\n\n/**\n * Load the content of a file stored in S3. If the s3ResourcePath is undefined, it will default to the workspace S3 resource.\n * \n * ```typescript\n * let fileContent = await wmill.loadS3FileContent(inputFile)\n * // if the file is a raw text file, it can be decoded and printed directly:\n * const text = new TextDecoder().decode(fileContentStream)\n * console.log(text);\n * ```\n */\nasync loadS3File(s3object: S3Object, s3ResourcePath: string | undefined = undefined): Promise\n\n/**\n * Load the content of a file stored in S3 as a stream. If the s3ResourcePath is undefined, it will default to the workspace S3 resource.\n * \n * ```typescript\n * let fileContentBlob = await wmill.loadS3FileStream(inputFile)\n * // if the content is plain text, the blob can be read directly:\n * console.log(await fileContentBlob.text());\n * ```\n */\nasync loadS3FileStream(s3object: S3Object, s3ResourcePath: string | undefined = undefined): Promise\n\n/**\n * Persist a file to the S3 bucket. If the s3ResourcePath is undefined, it will default to the workspace S3 resource.\n * \n * ```typescript\n * const s3object = await writeS3File(s3Object, \"Hello Windmill!\")\n * const fileContentAsUtf8Str = (await s3object.toArray()).toString('utf-8')\n * console.log(fileContentAsUtf8Str)\n * ```\n */\nasync writeS3File(s3object: S3Object | undefined, fileContent: string | Blob, s3ResourcePath: string | undefined = undefined, contentType: string | undefined = undefined, contentDisposition: string | undefined = undefined): Promise\n\n/**\n * Sign S3 objects to be used by anonymous users in public apps\n * @param s3objects s3 objects to sign\n * @returns signed s3 objects\n */\nasync signS3Objects(s3objects: S3Object[]): Promise\n\n/**\n * Sign S3 object to be used by anonymous users in public apps\n * @param s3object s3 object to sign\n * @returns signed s3 object\n */\nasync signS3Object(s3object: S3Object): Promise\n\n/**\n * Generate a presigned public URL for an array of S3 objects.\n * If an S3 object is not signed yet, it will be signed first.\n * @param s3Objects s3 objects to sign\n * @returns list of signed public URLs\n */\nasync getPresignedS3PublicUrls(s3Objects: S3Object[], { baseUrl }: { baseUrl?: string } = {}): Promise\n\n/**\n * Generate a presigned public URL for an S3 object. If the S3 object is not signed yet, it will be signed first.\n * @param s3Object s3 object to sign\n * @returns signed public URL\n */\nasync getPresignedS3PublicUrl(s3Objects: S3Object, { baseUrl }: { baseUrl?: string } = {}): Promise\n\n/**\n * Get URLs needed for resuming a flow after this step\n * @param approver approver name\n * @param flowLevel if true, generate resume URLs for the parent flow instead of the specific step.\n * This allows pre-approvals that can be consumed by any later suspend step in the same flow.\n * @returns approval page UI URL, resume and cancel API URLs for resuming the flow\n */\nasync getResumeUrls(approver?: string, flowLevel?: boolean): Promise<{\n approvalPage: string;\n resume: string;\n cancel: string;\n}>\n\n/**\n * @deprecated use getResumeUrls instead\n */\ngetResumeEndpoints(approver?: string): Promise<{\n approvalPage: string;\n resume: string;\n cancel: string;\n}>\n\n/**\n * Get an OIDC jwt token for auth to external services (e.g: Vault, AWS) (ee only)\n * @param audience audience of the token\n * @param expiresIn Optional number of seconds until the token expires\n * @returns jwt token\n */\nasync getIdToken(audience: string, expiresIn?: number): Promise\n\n/**\n * Convert a base64-encoded string to Uint8Array\n * @param data - Base64-encoded string\n * @returns Decoded Uint8Array\n */\nbase64ToUint8Array(data: string): Uint8Array\n\n/**\n * Convert a Uint8Array to base64-encoded string\n * @param arrayBuffer - Uint8Array to encode\n * @returns Base64-encoded string\n */\nuint8ArrayToBase64(arrayBuffer: Uint8Array): string\n\n/**\n * Get email from workspace username\n * This method is particularly useful for apps that require the email address of the viewer.\n * Indeed, in the viewer context, WM_USERNAME is set to the username of the viewer but WM_EMAIL is set to the email of the creator of the app.\n * @param username\n * @returns email address\n */\nasync usernameToEmail(username: string): Promise\n\n/**\n * Sends an interactive approval request via Slack, allowing optional customization of the message, approver, and form fields.\n * \n * **[Enterprise Edition Only]** To include form fields in the Slack approval request, go to **Advanced -> Suspend -> Form**\n * and define a form. Learn more at [Windmill Documentation](https://www.windmill.dev/docs/flows/flow_approval#form).\n * \n * @param {Object} options - The configuration options for the Slack approval request.\n * @param {string} options.slackResourcePath - The path to the Slack resource in Windmill.\n * @param {string} options.channelId - The Slack channel ID where the approval request will be sent.\n * @param {string} [options.message] - Optional custom message to include in the Slack approval request.\n * @param {string} [options.approver] - Optional user ID or name of the approver for the request.\n * @param {DefaultArgs} [options.defaultArgsJson] - Optional object defining or overriding the default arguments to a form field.\n * @param {Enums} [options.dynamicEnumsJson] - Optional object overriding the enum default values of an enum form field.\n * @param {string} [options.resumeButtonText] - Optional text for the resume button.\n * @param {string} [options.cancelButtonText] - Optional text for the cancel button.\n * \n * @returns {Promise} Resolves when the Slack approval request is successfully sent.\n * \n * @throws {Error} If the function is not called within a flow or flow preview.\n * @throws {Error} If the `JobService.getSlackApprovalPayload` call fails.\n * \n * **Usage Example:**\n * ```typescript\n * await requestInteractiveSlackApproval({\n * slackResourcePath: \"/u/alex/my_slack_resource\",\n * channelId: \"admins-slack-channel\",\n * message: \"Please approve this request\",\n * approver: \"approver123\",\n * defaultArgsJson: { key1: \"value1\", key2: 42 },\n * dynamicEnumsJson: { foo: [\"choice1\", \"choice2\"], bar: [\"optionA\", \"optionB\"] },\n * resumeButtonText: \"Resume\",\n * cancelButtonText: \"Cancel\",\n * });\n * ```\n * \n * **Note:** This function requires execution within a Windmill flow or flow preview.\n */\nasync requestInteractiveSlackApproval({ slackResourcePath, channelId, message, approver, defaultArgsJson, dynamicEnumsJson, resumeButtonText, cancelButtonText, }: SlackApprovalOptions): Promise\n\n/**\n * Sends an interactive approval request via Teams, allowing optional customization of the message, approver, and form fields.\n * \n * **[Enterprise Edition Only]** To include form fields in the Teams approval request, go to **Advanced -> Suspend -> Form**\n * and define a form. Learn more at [Windmill Documentation](https://www.windmill.dev/docs/flows/flow_approval#form).\n * \n * @param {Object} options - The configuration options for the Teams approval request.\n * @param {string} options.teamName - The Teams team name where the approval request will be sent.\n * @param {string} options.channelName - The Teams channel name where the approval request will be sent.\n * @param {string} [options.message] - Optional custom message to include in the Teams approval request.\n * @param {string} [options.approver] - Optional user ID or name of the approver for the request.\n * @param {DefaultArgs} [options.defaultArgsJson] - Optional object defining or overriding the default arguments to a form field.\n * @param {Enums} [options.dynamicEnumsJson] - Optional object overriding the enum default values of an enum form field.\n * \n * @returns {Promise} Resolves when the Teams approval request is successfully sent.\n * \n * @throws {Error} If the function is not called within a flow or flow preview.\n * @throws {Error} If the `JobService.getTeamsApprovalPayload` call fails.\n * \n * **Usage Example:**\n * ```typescript\n * await requestInteractiveTeamsApproval({\n * teamName: \"admins-teams\",\n * channelName: \"admins-teams-channel\",\n * message: \"Please approve this request\",\n * approver: \"approver123\",\n * defaultArgsJson: { key1: \"value1\", key2: 42 },\n * dynamicEnumsJson: { foo: [\"choice1\", \"choice2\"], bar: [\"optionA\", \"optionB\"] },\n * });\n * ```\n * \n * **Note:** This function requires execution within a Windmill flow or flow preview.\n */\nasync requestInteractiveTeamsApproval({ teamName, channelName, message, approver, defaultArgsJson, dynamicEnumsJson, }: TeamsApprovalOptions): Promise\n\n/**\n * Parse an S3 object from URI string or record format\n * @param s3Object - S3 object as URI string (s3://storage/key) or record\n * @returns S3 object record with storage and s3 key\n */\nparseS3Object(s3Object: S3Object): S3ObjectRecord\n\nsetWorkflowCtx(ctx: WorkflowCtx | null): void\n\nasync sleep(seconds: number): Promise\n\nasync step(name: string, fn: () => T | Promise): Promise\n\n/**\n * Create a task that dispatches to a separate Windmill script.\n * \n * @example\n * const extract = taskScript(\"f/data/extract\");\n * // inside workflow: await extract({ url: \"https://...\" })\n */\ntaskScript(path: string, options?: TaskOptions): (...args: any[]) => PromiseLike\n\n/**\n * Create a task that dispatches to a separate Windmill flow.\n * \n * @example\n * const pipeline = taskFlow(\"f/etl/pipeline\");\n * // inside workflow: await pipeline({ input: data })\n */\ntaskFlow(path: string, options?: TaskOptions): (...args: any[]) => PromiseLike\n\n/**\n * Mark an async function as a workflow-as-code entry point.\n * \n * The function must be **deterministic**: given the same inputs it must call\n * tasks in the same order on every replay. Branching on task results is fine\n * (results are replayed from checkpoint), but branching on external state\n * (current time, random values, external API calls) must use `step()` to\n * checkpoint the value so replays see the same result.\n */\nworkflow(fn: (...args: any[]) => Promise): void\n\n/**\n * Suspend the workflow and wait for an external approval.\n * \n * Use `getResumeUrls()` (wrapped in `step()`) to obtain resume/cancel/approvalPage\n * URLs before calling this function.\n * \n * @example\n * const urls = await step(\"urls\", () => getResumeUrls());\n * await step(\"notify\", () => sendEmail(urls.approvalPage));\n * const { value, approver } = await waitForApproval({ timeout: 3600 });\n */\nwaitForApproval(options?: { timeout?: number; form?: object; selfApproval?: boolean; }): PromiseLike<{ value: any; approver: string; approved: boolean }>\n\n/**\n * Process items in parallel with optional concurrency control.\n * \n * Each item is processed by calling `fn(item)`, which should be a task().\n * Items are dispatched in batches of `concurrency` (default: all at once).\n * \n * @example\n * const process = task(async (item: string) => { ... });\n * const results = await parallel(items, process, { concurrency: 5 });\n */\nasync parallel(items: T[], fn: (item: T) => PromiseLike | R, options?: { concurrency?: number },): Promise\n\n/**\n * Commit Kafka offsets for a trigger with auto_commit disabled.\n * @param triggerPath - Path to the Kafka trigger (from event.wm_trigger.trigger_path)\n * @param topic - Kafka topic name (from event.topic)\n * @param partition - Partition number (from event.partition)\n * @param offset - Message offset to commit (from event.offset)\n */\nasync commitKafkaOffsets(triggerPath: string, topic: string, partition: number, offset: number,): Promise\n\n/**\n * Create a SQL template function for PostgreSQL/datatable queries\n * @param name - Database/datatable name (default: \"main\")\n * @returns SQL template function for building parameterized queries\n * @example\n * let sql = wmill.datatable()\n * let name = 'Robin'\n * let age = 21\n * await sql`\n * SELECT * FROM friends\n * WHERE name = ${name} AND age = ${age}::int\n * `.fetch()\n */\ndatatable(name: string = \"main\"): DatatableSqlTemplateFunction\n\n/**\n * Create a SQL template function for DuckDB/ducklake queries\n * @param name - DuckDB database name (default: \"main\")\n * @returns SQL template function for building parameterized queries\n * @example\n * let sql = wmill.ducklake()\n * let name = 'Robin'\n * let age = 21\n * await sql`\n * SELECT * FROM friends\n * WHERE name = ${name} AND age = ${age}\n * `.fetch()\n */\nducklake(name: string = \"main\"): SqlTemplateFunction\n"; export declare const SDK_PYTHON = "# Python SDK (wmill)\n\nImport: import wmill\n\ndef worker_has_internal_server() -> bool\n\ndef get_mocked_api() -> Optional[dict]\n\n# Get the HTTP client instance.\n# \n# Returns:\n# Configured httpx.Client for API requests\ndef get_client() -> httpx.Client\n\n# Make an HTTP GET request to the Windmill API.\n# \n# Args:\n# endpoint: API endpoint path\n# raise_for_status: Whether to raise an exception on HTTP errors\n# **kwargs: Additional arguments passed to httpx.get\n# \n# Returns:\n# HTTP response object\ndef get(endpoint, raise_for_status = True, **kwargs) -> httpx.Response\n\n# Make an HTTP POST request to the Windmill API.\n# \n# Args:\n# endpoint: API endpoint path\n# raise_for_status: Whether to raise an exception on HTTP errors\n# **kwargs: Additional arguments passed to httpx.post\n# \n# Returns:\n# HTTP response object\ndef post(endpoint, raise_for_status = True, **kwargs) -> httpx.Response\n\n# Create a new authentication token.\n# \n# Args:\n# duration: Token validity duration (default: 1 day)\n# \n# Returns:\n# New authentication token string\ndef create_token(duration = dt.timedelta(days=1)) -> str\n\n# Create a script job and return its job id.\n# \n# .. deprecated:: Use run_script_by_path_async or run_script_by_hash_async instead.\ndef run_script_async(path: str = None, hash_: str = None, args: dict = None, scheduled_in_secs: int = None) -> str\n\n# Create a script job by path and return its job id.\ndef run_script_by_path_async(path: str, args: dict = None, scheduled_in_secs: int = None) -> str\n\n# Create a script job by hash and return its job id.\ndef run_script_by_hash_async(hash_: str, args: dict = None, scheduled_in_secs: int = None) -> str\n\n# Create a flow job and return its job id.\ndef run_flow_async(path: str, args: dict = None, scheduled_in_secs: int = None, do_not_track_in_parent: bool = True) -> str\n\n# Run script synchronously and return its result.\n# \n# .. deprecated:: Use run_script_by_path or run_script_by_hash instead.\ndef run_script(path: str = None, hash_: str = None, args: dict = None, timeout: dt.timedelta | int | float | None = None, verbose: bool = False, cleanup: bool = True, assert_result_is_not_none: bool = False) -> Any\n\n# Run script by path synchronously and return its result.\ndef run_script_by_path(path: str, args: dict = None, timeout: dt.timedelta | int | float | None = None, verbose: bool = False, cleanup: bool = True, assert_result_is_not_none: bool = False) -> Any\n\n# Run script by hash synchronously and return its result.\ndef run_script_by_hash(hash_: str, args: dict = None, timeout: dt.timedelta | int | float | None = None, verbose: bool = False, cleanup: bool = True, assert_result_is_not_none: bool = False) -> Any\n\n# Run a script on the current worker without creating a job.\n# \n# On agent workers (no internal server), falls back to running a normal\n# preview job and waiting for the result.\ndef run_inline_script_preview(content: str, language: str, args: dict = None) -> Any\n\n# Wait for a job to complete and return its result.\n# \n# Args:\n# job_id: ID of the job to wait for\n# timeout: Maximum time to wait (seconds or timedelta)\n# verbose: Enable verbose logging\n# cleanup: Register cleanup handler to cancel job on exit\n# assert_result_is_not_none: Raise exception if result is None\n# \n# Returns:\n# Job result when completed\n# \n# Raises:\n# TimeoutError: If timeout is reached\n# Exception: If job fails\ndef wait_job(job_id, timeout: dt.timedelta | int | float | None = None, verbose: bool = False, cleanup: bool = True, assert_result_is_not_none: bool = False)\n\n# Cancel a specific job by ID.\n# \n# Args:\n# job_id: UUID of the job to cancel\n# reason: Optional reason for cancellation\n# \n# Returns:\n# Response message from the cancel endpoint\ndef cancel_job(job_id: str, reason: str = None) -> str\n\n# Cancel currently running executions of the same script.\ndef cancel_running() -> dict\n\n# Get job details by ID.\n# \n# Args:\n# job_id: UUID of the job\n# \n# Returns:\n# Job details dictionary\ndef get_job(job_id: str) -> dict\n\n# Get the root job ID for a flow hierarchy.\n# \n# Args:\n# job_id: Job ID (defaults to current WM_JOB_ID)\n# \n# Returns:\n# Root job ID\ndef get_root_job_id(job_id: str | None = None) -> dict\n\n# Get an OIDC JWT token for authentication to external services.\n# \n# Args:\n# audience: Token audience (e.g., \"vault\", \"aws\")\n# expires_in: Optional expiration time in seconds\n# \n# Returns:\n# JWT token string\ndef get_id_token(audience: str, expires_in: int | None = None) -> str\n\n# Get the status of a job.\n# \n# Args:\n# job_id: UUID of the job\n# \n# Returns:\n# Job status: \"RUNNING\", \"WAITING\", or \"COMPLETED\"\ndef get_job_status(job_id: str) -> JobStatus\n\n# Get the result of a completed job.\n# \n# Args:\n# job_id: UUID of the completed job\n# assert_result_is_not_none: Raise exception if result is None\n# \n# Returns:\n# Job result\ndef get_result(job_id: str, assert_result_is_not_none: bool = True) -> Any\n\n# Get a variable value by path.\n# \n# Args:\n# path: Variable path in Windmill\n# \n# Returns:\n# Variable value as string\ndef get_variable(path: str) -> str\n\n# Set a variable value by path, creating it if it doesn't exist.\n# \n# Args:\n# path: Variable path in Windmill\n# value: Variable value to set\n# is_secret: Whether the variable should be secret (default: False)\ndef set_variable(path: str, value: str, is_secret: bool = False) -> None\n\n# Get a resource value by path.\n# \n# Args:\n# path: Resource path in Windmill\n# none_if_undefined: Return None instead of raising if not found\n# interpolated: if variables and resources are fully unrolled\n# \n# Returns:\n# Resource value dictionary or None\ndef get_resource(path: str, none_if_undefined: bool = False, interpolated: bool = True) -> dict | None\n\n# Set a resource value by path, creating it if it doesn't exist.\n# \n# Args:\n# value: Resource value to set\n# path: Resource path in Windmill\n# resource_type: Resource type for creation\ndef set_resource(value: Any, path: str, resource_type: str)\n\n# List resources from Windmill workspace.\n# \n# Args:\n# resource_type: Optional resource type to filter by (e.g., \"postgresql\", \"mysql\", \"s3\")\n# page: Optional page number for pagination\n# per_page: Optional number of results per page\n# \n# Returns:\n# List of resource dictionaries\ndef list_resources(resource_type: str = None, page: int = None, per_page: int = None) -> list[dict]\n\n# Set the workflow state.\n# \n# Args:\n# value: State value to set\n# path: Optional state resource path override.\ndef set_state(value: Any, path: str | None = None) -> None\n\n# Get the workflow state.\n# \n# Args:\n# path: Optional state resource path override.\n# \n# Returns:\n# State value or None if not set\ndef get_state(path: str | None = None) -> Any\n\n# Set job progress percentage (0-99).\n# \n# Args:\n# value: Progress percentage\n# job_id: Job ID (defaults to current WM_JOB_ID)\ndef set_progress(value: int, job_id: Optional[str] = None)\n\n# Get job progress percentage.\n# \n# Args:\n# job_id: Job ID (defaults to current WM_JOB_ID)\n# \n# Returns:\n# Progress value (0-100) or None if not set\ndef get_progress(job_id: Optional[str] = None) -> Any\n\n# Set the user state of a flow at a given key\ndef set_flow_user_state(key: str, value: Any) -> None\n\n# Get the user state of a flow at a given key\ndef get_flow_user_state(key: str) -> Any\n\n# Get the Windmill server version.\n# \n# Returns:\n# Version string\ndef version()\n\n# Convenient helpers that takes an S3 resource as input and returns the settings necessary to\n# initiate an S3 connection from DuckDB\ndef get_duckdb_connection_settings(s3_resource_path: str = '') -> DuckDbConnectionSettings | None\n\n# Convenient helpers that takes an S3 resource as input and returns the settings necessary to\n# initiate an S3 connection from Polars\ndef get_polars_connection_settings(s3_resource_path: str = '') -> PolarsConnectionSettings\n\n# Convenient helpers that takes an S3 resource as input and returns the settings necessary to\n# initiate an S3 connection using boto3\ndef get_boto3_connection_settings(s3_resource_path: str = '') -> Boto3ConnectionSettings\n\n# Load a file from the workspace s3 bucket and returns its content as bytes.\n# \n# '''python\n# from wmill import S3Object\n# \n# s3_obj = S3Object(s3=\"/path/to/my_file.txt\")\n# my_obj_content = client.load_s3_file(s3_obj)\n# file_content = my_obj_content.decode(\"utf-8\")\n# '''\ndef load_s3_file(s3object: S3Object | str, s3_resource_path: str | None) -> bytes\n\n# Load a file from the workspace s3 bucket and returns the bytes stream.\n# \n# '''python\n# from wmill import S3Object\n# \n# s3_obj = S3Object(s3=\"/path/to/my_file.txt\")\n# with wmill.load_s3_file_reader(s3object, s3_resource_path) as file_reader:\n# print(file_reader.read())\n# '''\ndef load_s3_file_reader(s3object: S3Object | str, s3_resource_path: str | None) -> BufferedReader\n\n# Write a file to the workspace S3 bucket\n# \n# '''python\n# from wmill import S3Object\n# \n# s3_obj = S3Object(s3=\"/path/to/my_file.txt\")\n# \n# # for an in memory bytes array:\n# file_content = b'Hello Windmill!'\n# client.write_s3_file(s3_obj, file_content)\n# \n# # for a file:\n# with open(\"my_file.txt\", \"rb\") as my_file:\n# client.write_s3_file(s3_obj, my_file)\n# '''\ndef write_s3_file(s3object: S3Object | str | None, file_content: BufferedReader | bytes, s3_resource_path: str | None, content_type: str | None = None, content_disposition: str | None = None) -> S3Object\n\n# Permanently delete a file from the workspace S3 bucket.\n# \n# '''python\n# from wmill import S3Object\n# \n# s3_obj = S3Object(s3=\"/path/to/my_file.txt\")\n# client.delete_s3_object(s3_obj)\n# '''\ndef delete_s3_object(s3object: S3Object | str, s3_resource_path: str | None = None) -> None\n\n# Sign S3 objects for use by anonymous users in public apps.\n# \n# Args:\n# s3_objects: List of S3 objects to sign\n# \n# Returns:\n# List of signed S3 objects\ndef sign_s3_objects(s3_objects: list[S3Object | str]) -> list[S3Object]\n\n# Sign a single S3 object for use by anonymous users in public apps.\n# \n# Args:\n# s3_object: S3 object to sign\n# \n# Returns:\n# Signed S3 object\ndef sign_s3_object(s3_object: S3Object | str) -> S3Object\n\n# Generate presigned public URLs for an array of S3 objects.\n# If an S3 object is not signed yet, it will be signed first.\n# \n# Args:\n# s3_objects: List of S3 objects to sign\n# base_url: Optional base URL for the presigned URLs (defaults to WM_BASE_URL)\n# \n# Returns:\n# List of signed public URLs\n# \n# Example:\n# >>> s3_objs = [S3Object(s3=\"/path/to/file1.txt\"), S3Object(s3=\"/path/to/file2.txt\")]\n# >>> urls = client.get_presigned_s3_public_urls(s3_objs)\ndef get_presigned_s3_public_urls(s3_objects: list[S3Object | str], base_url: str | None = None) -> list[str]\n\n# Generate a presigned public URL for an S3 object.\n# If the S3 object is not signed yet, it will be signed first.\n# \n# Args:\n# s3_object: S3 object to sign\n# base_url: Optional base URL for the presigned URL (defaults to WM_BASE_URL)\n# \n# Returns:\n# Signed public URL\n# \n# Example:\n# >>> s3_obj = S3Object(s3=\"/path/to/file.txt\")\n# >>> url = client.get_presigned_s3_public_url(s3_obj)\ndef get_presigned_s3_public_url(s3_object: S3Object | str, base_url: str | None = None) -> str\n\n# Get the current user information.\n# \n# Returns:\n# User details dictionary\ndef whoami() -> dict\n\n# Get the current user information (alias for whoami).\n# \n# Returns:\n# User details dictionary\ndef user() -> dict\n\n# Get the state resource path from environment.\n# \n# Returns:\n# State path string\ndef state_path() -> str\n\n# Get the workflow state.\n# \n# Returns:\n# State value or None if not set\ndef state() -> Any\n\n# Set the state in the shared folder using pickle\ndef set_shared_state_pickle(value: Any, path: str = 'state.pickle') -> None\n\n# Get the state in the shared folder using pickle\ndef get_shared_state_pickle(path: str = 'state.pickle') -> Any\n\n# Set the state in the shared folder using pickle\ndef set_shared_state(value: Any, path: str = 'state.json') -> None\n\n# Get the state in the shared folder using pickle\ndef get_shared_state(path: str = 'state.json') -> None\n\n# Get URLs needed for resuming a flow after suspension.\n# \n# Args:\n# approver: Optional approver name\n# flow_level: If True, generate resume URLs for the parent flow instead of the\n# specific step. This allows pre-approvals that can be consumed by any later\n# suspend step in the same flow.\n# \n# Returns:\n# Dictionary with approvalPage, resume, and cancel URLs\ndef get_resume_urls(approver: str = None, flow_level: bool = None) -> dict\n\n# Sends an interactive approval request via Slack, allowing optional customization of the message, approver, and form fields.\n# \n# **[Enterprise Edition Only]** To include form fields in the Slack approval request, use the \"Advanced -> Suspend -> Form\" functionality.\n# Learn more at: https://www.windmill.dev/docs/flows/flow_approval#form\n# \n# :param slack_resource_path: The path to the Slack resource in Windmill.\n# :type slack_resource_path: str\n# :param channel_id: The Slack channel ID where the approval request will be sent.\n# :type channel_id: str\n# :param message: Optional custom message to include in the Slack approval request.\n# :type message: str, optional\n# :param approver: Optional user ID or name of the approver for the request.\n# :type approver: str, optional\n# :param default_args_json: Optional dictionary defining or overriding the default arguments for form fields.\n# :type default_args_json: dict, optional\n# :param dynamic_enums_json: Optional dictionary overriding the enum default values of enum form fields.\n# :type dynamic_enums_json: dict, optional\n# \n# :raises Exception: If the function is not called within a flow or flow preview.\n# :raises Exception: If the required flow job or flow step environment variables are not set.\n# \n# :return: None\n# \n# **Usage Example:**\n# >>> client.request_interactive_slack_approval(\n# ... slack_resource_path=\"/u/alex/my_slack_resource\",\n# ... channel_id=\"admins-slack-channel\",\n# ... message=\"Please approve this request\",\n# ... approver=\"approver123\",\n# ... default_args_json={\"key1\": \"value1\", \"key2\": 42},\n# ... dynamic_enums_json={\"foo\": [\"choice1\", \"choice2\"], \"bar\": [\"optionA\", \"optionB\"]},\n# ... )\n# \n# **Notes:**\n# - This function must be executed within a Windmill flow or flow preview.\n# - The function checks for required environment variables (`WM_FLOW_JOB_ID`, `WM_FLOW_STEP_ID`) to ensure it is run in the appropriate context.\ndef request_interactive_slack_approval(slack_resource_path: str, channel_id: str, message: str = None, approver: str = None, default_args_json: dict = None, dynamic_enums_json: dict = None) -> None\n\n# Get email from workspace username\n# This method is particularly useful for apps that require the email address of the viewer.\n# Indeed, in the viewer context WM_USERNAME is set to the username of the viewer but WM_EMAIL is set to the email of the creator of the app.\ndef username_to_email(username: str) -> str\n\n# Send a message to a Microsoft Teams conversation with conversation_id, where success is used to style the message\ndef send_teams_message(conversation_id: str, text: str, success: bool = True, card_block: dict = None)\n\n# Get a DataTable client for SQL queries.\n# \n# Args:\n# name: Database name (default: \"main\")\n# \n# Returns:\n# DataTableClient instance\ndef datatable(name: str = 'main')\n\n# Get a DuckLake client for DuckDB queries.\n# \n# Args:\n# name: Database name (default: \"main\")\n# \n# Returns:\n# DucklakeClient instance\ndef ducklake(name: str = 'main')\n\ndef init_global_client(f)\n\ndef deprecate(in_favor_of: str)\n\n# Get the current workspace ID.\n# \n# Returns:\n# Workspace ID string\ndef get_workspace() -> str\n\ndef get_version() -> str\n\n# Run a script synchronously by hash and return its result.\n# \n# Args:\n# hash: Script hash\n# args: Script arguments\n# verbose: Enable verbose logging\n# assert_result_is_not_none: Raise exception if result is None\n# cleanup: Register cleanup handler to cancel job on exit\n# timeout: Maximum time to wait\n# \n# Returns:\n# Script result\ndef run_script_sync(hash: str, args: Dict[str, Any] = None, verbose: bool = False, assert_result_is_not_none: bool = True, cleanup: bool = True, timeout: dt.timedelta = None) -> Any\n\n# Run a script synchronously by path and return its result.\n# \n# Args:\n# path: Script path\n# args: Script arguments\n# verbose: Enable verbose logging\n# assert_result_is_not_none: Raise exception if result is None\n# cleanup: Register cleanup handler to cancel job on exit\n# timeout: Maximum time to wait\n# \n# Returns:\n# Script result\ndef run_script_by_path_sync(path: str, args: Dict[str, Any] = None, verbose: bool = False, assert_result_is_not_none: bool = True, cleanup: bool = True, timeout: dt.timedelta = None) -> Any\n\n# Convenient helpers that takes an S3 resource as input and returns the settings necessary to\n# initiate an S3 connection from DuckDB\ndef duckdb_connection_settings(s3_resource_path: str = '') -> DuckDbConnectionSettings\n\n# Convenient helpers that takes an S3 resource as input and returns the settings necessary to\n# initiate an S3 connection from Polars\ndef polars_connection_settings(s3_resource_path: str = '') -> PolarsConnectionSettings\n\n# Convenient helpers that takes an S3 resource as input and returns the settings necessary to\n# initiate an S3 connection using boto3\ndef boto3_connection_settings(s3_resource_path: str = '') -> Boto3ConnectionSettings\n\n# Get the state resource path from environment.\n# \n# Returns:\n# State path string\ndef get_state_path() -> str\n\n# Parse resource syntax from string.\ndef parse_resource_syntax(s: str) -> Optional[str]\n\n# Parse S3 object from string or S3Object format.\ndef parse_s3_object(s3_object: S3Object | str) -> S3Object\n\n# Parse variable syntax from string.\ndef parse_variable_syntax(s: str) -> Optional[str]\n\n# Append a text to the result stream.\n# \n# Args:\n# text: text to append to the result stream\ndef append_to_result_stream(text: str) -> None\n\n# Stream to the result stream.\n# \n# Args:\n# stream: stream to stream to the result stream\ndef stream_result(stream) -> None\n\n# Execute a SQL query against the DataTable.\n# \n# Args:\n# sql: SQL query string with $1, $2, etc. placeholders\n# *args: Positional arguments to bind to query placeholders\n# \n# Returns:\n# SqlQuery instance for fetching results\ndef query(sql: str, *args) -> SqlQuery\n\n# Execute query and fetch results.\n# \n# Args:\n# result_collection: Optional result collection mode\n# \n# Returns:\n# Query results\ndef fetch(result_collection: str | None = None)\n\n# Execute query and fetch first row of results.\n# \n# Returns:\n# First row of query results\ndef fetch_one()\n\n# Execute query and fetch first row of results. Return result as a scalar value.\n# \n# Returns:\n# First row of query result as a scalar value\ndef fetch_one_scalar()\n\n# Execute query and don't return any results.\n# \ndef execute()\n\n# DuckDB executor requires explicit argument types at declaration\n# These types exist in both DuckDB and Postgres\n# Check that the types exist if you plan to extend this function for other SQL engines.\ndef infer_sql_type(value) -> str\n\ndef parse_sql_client_name(name: str) -> tuple[str, Optional[str]]\n\n# Decorator that marks a function as a workflow task.\n# \n# Works in both WAC v1 (sync, HTTP-based dispatch) and WAC v2\n# (async, checkpoint/replay) modes:\n# \n# - **v2 (inside @workflow)**: dispatches as a checkpoint step.\n# - **v1 (WM_JOB_ID set, no @workflow)**: dispatches via HTTP API.\n# - **Standalone**: executes the function body directly.\n# \n# Usage::\n# \n# @task\n# async def extract_data(url: str): ...\n# \n# @task(path=\"f/external_script\", timeout=600, tag=\"gpu\")\n# async def run_external(x: int): ...\ndef task(_func = None, path: Optional[str] = None, tag: Optional[str] = None, timeout: Optional[int] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)\n\n# Create a task that dispatches to a separate Windmill script.\n# \n# Usage::\n# \n# extract = task_script(\"f/data/extract\", timeout=600)\n# \n# @workflow\n# async def main():\n# data = await extract(url=\"https://...\")\ndef task_script(path: str, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)\n\n# Create a task that dispatches to a separate Windmill flow.\n# \n# Usage::\n# \n# pipeline = task_flow(\"f/etl/pipeline\", priority=10)\n# \n# @workflow\n# async def main():\n# result = await pipeline(input=data)\ndef task_flow(path: str, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)\n\n# Decorator marking an async function as a workflow-as-code entry point.\n# \n# The function must be **deterministic**: given the same inputs it must call\n# tasks in the same order on every replay. Branching on task results is fine\n# (results are replayed from checkpoint), but branching on external state\n# (current time, random values, external API calls) must use ``step()`` to\n# checkpoint the value so replays see the same result.\ndef workflow(func)\n\n# Execute ``fn`` inline and checkpoint the result.\n# \n# On replay the cached value is returned without re-executing ``fn``.\n# Use for lightweight deterministic operations (timestamps, random IDs,\n# config reads) that should not incur the overhead of a child job.\nasync def step(name: str, fn)\n\n# Server-side sleep \u2014 suspend the workflow for the given duration without holding a worker.\n# \n# Inside a @workflow, the parent job suspends and auto-resumes after ``seconds``.\n# Outside a workflow, falls back to ``asyncio.sleep``.\nasync def sleep(seconds: int)\n\n# Suspend the workflow and wait for an external approval.\n# \n# Use ``get_resume_urls()`` (wrapped in ``step()``) to obtain\n# resume/cancel/approval URLs before calling this function.\n# \n# Returns a dict with ``value`` (form data), ``approver``, and ``approved``.\n# \n# Args:\n# timeout: Approval timeout in seconds (default 1800).\n# form: Optional form schema for the approval page.\n# self_approval: Whether the user who triggered the flow can approve it (default True).\n# \n# Example::\n# \n# urls = await step(\"urls\", lambda: get_resume_urls())\n# await step(\"notify\", lambda: send_email(urls[\"approvalPage\"]))\n# result = await wait_for_approval(timeout=3600)\nasync def wait_for_approval(timeout: int = 1800, form: dict | None = None, self_approval: bool = True) -> dict\n\n# Process items in parallel with optional concurrency control.\n# \n# Each item is processed by calling ``fn(item)``, which should be a @task.\n# Items are dispatched in batches of ``concurrency`` (default: all at once).\n# \n# Example::\n# \n# @task\n# async def process(item: str):\n# ...\n# \n# results = await parallel(items, process, concurrency=5)\nasync def parallel(items, fn, concurrency: Optional[int] = None)\n\n# Commit Kafka offsets for a trigger with auto_commit disabled.\n# \n# Args:\n# trigger_path: Path to the Kafka trigger (from event['wm_trigger']['trigger_path'])\n# topic: Kafka topic name (from event['topic'])\n# partition: Partition number (from event['partition'])\n# offset: Message offset to commit (from event['offset'])\ndef commit_kafka_offsets(trigger_path: str, topic: str, partition: int, offset: int) -> None\n\n"; @@ -9,24 +9,24 @@ export declare const WAC_SDK_PYTHON = "## Python Workflow-as-Code API (wmill)\n\ export declare const DATATABLE_SDK_TYPESCRIPT = "## TypeScript Datatable API (windmill-client)\n\nImport: `import * as wmill from 'windmill-client'`\n\nSQL statement object with query content, arguments, and execution methods\n```typescript\ntype SqlStatement = {\n /** Raw SQL content with formatted arguments */\n content: string;\n\n /** Argument values keyed by parameter name */\n args: Record;\n\n /**\n * Execute the SQL query and return results\n * @param params - Optional parameters including result collection mode\n * @returns Query results based on the result collection mode\n */\n fetch(\n params?: FetchParams // The union is for auto-completion\n ): Promise>;\n\n /**\n * Execute the SQL query and return only the first row\n * @param params - Optional parameters\n * @returns First row of the query result\n */\n fetchOne(\n params?: Omit, \"resultCollection\">\n ): Promise>;\n\n /**\n * Execute the SQL query and return only the first row as a scalar value\n * @param params - Optional parameters\n * @returns First row of the query result\n */\n fetchOneScalar(\n params?: Omit<\n FetchParams<\"last_statement_first_row_scalar\">,\n \"resultCollection\"\n >\n ): Promise>;\n\n /**\n * Execute the SQL query without fetching rows\n * @param params - Optional parameters\n */\n execute(\n params?: Omit, \"resultCollection\">\n ): Promise;\n};\n```\n\n```typescript\n// Template tag function: sql`SELECT * FROM table WHERE id = ${id}`.fetch()\ninterface DatatableSqlTemplateFunction {\n // Tagged template usage:\n (strings: TemplateStringsArray, ...values: any[]): SqlStatement;\n query(sql: string, ...params: any[]): SqlStatement;\n};\n```\n\nCreate a SQL template function for PostgreSQL/datatable queries\n@param name - Database/datatable name (default: \"main\")\n@returns SQL template function for building parameterized queries\n@example\nlet sql = wmill.datatable()\nlet name = 'Robin'\nlet age = 21\nawait sql`\n SELECT * FROM friends\n WHERE name = ${name} AND age = ${age}::int\n`.fetch()\n```typescript\nfunction datatable(name: string = \"main\"): DatatableSqlTemplateFunction\n```\n"; export declare const DATATABLE_SDK_PYTHON = "## Python Datatable API (wmill)\n\nImport: `import wmill`\n\n# Get a DataTable client for SQL queries.\n# \n# Args:\n# name: Database name (default: \"main\")\n# \n# Returns:\n# DataTableClient instance\ndef datatable(name: str = 'main') -> DataTableClient\n\n# Client for executing SQL queries against Windmill DataTables.\nclass DataTableClient:\n # Initialize DataTableClient.\n # \n # Args:\n # client: Windmill client instance\n # name: DataTable name\n def __init__(client: Windmill, name: str)\n\n # Execute a SQL query against the DataTable.\n # \n # Args:\n # sql: SQL query string with $1, $2, etc. placeholders\n # *args: Positional arguments to bind to query placeholders\n # \n # Returns:\n # SqlQuery instance for fetching results\n def query(sql: str, *args) -> SqlQuery\n\n\n# Query result handler for DataTable and DuckLake queries.\nclass SqlQuery:\n # Initialize SqlQuery.\n # \n # Args:\n # sql: SQL query string\n # fetch_fn: Function to execute the query\n def __init__(sql: str, fetch_fn)\n\n # Execute query and fetch results.\n # \n # Args:\n # result_collection: Optional result collection mode\n # \n # Returns:\n # Query results\n def fetch(result_collection: str | None = None)\n\n # Execute query and fetch first row of results.\n # \n # Returns:\n # First row of query results\n def fetch_one()\n\n # Execute query and fetch first row of results. Return result as a scalar value.\n # \n # Returns:\n # First row of query result as a scalar value\n def fetch_one_scalar()\n\n # Execute query and don't return any results.\n # \n def execute()\n\n\n"; export declare const OPENFLOW_SCHEMA = "## OpenFlow Schema\n\n{\"OpenFlow\":{\"type\":\"object\",\"description\":\"Top-level flow definition containing metadata, configuration, and the flow structure\",\"properties\":{\"summary\":{\"type\":\"string\",\"description\":\"Short description of what this flow does\"},\"description\":{\"type\":\"string\",\"description\":\"Detailed documentation for this flow\"},\"value\":{\"$ref\":\"#/components/schemas/FlowValue\"},\"schema\":{\"type\":\"object\",\"description\":\"JSON Schema for flow inputs. Use this to define input parameters, their types, defaults, and validation. For resource inputs, set type to 'object' and format to 'resource-' (e.g., 'resource-stripe')\"},\"on_behalf_of_email\":{\"type\":\"string\",\"description\":\"The flow will be run with the permissions of the user with this email.\"}},\"required\":[\"summary\",\"value\"]},\"FlowValue\":{\"type\":\"object\",\"description\":\"The flow structure containing modules and optional preprocessor/failure handlers\",\"properties\":{\"modules\":{\"type\":\"array\",\"description\":\"Array of steps that execute in sequence. Each step can be a script, subflow, loop, or branch\",\"items\":{\"$ref\":\"#/components/schemas/FlowModule\"}},\"failure_module\":{\"description\":\"Special module that executes when the flow fails. Receives error object with message, name, stack, and step_id. Must have id 'failure'. Only supports script/rawscript types\",\"$ref\":\"#/components/schemas/FlowModule\"},\"preprocessor_module\":{\"description\":\"Special module that runs before the first step on external triggers. Must have id 'preprocessor'. Only supports script/rawscript types. Cannot reference other step results\",\"$ref\":\"#/components/schemas/FlowModule\"},\"same_worker\":{\"type\":\"boolean\",\"description\":\"If true, all steps run on the same worker for better performance\"},\"concurrent_limit\":{\"type\":\"number\",\"description\":\"Maximum number of concurrent executions of this flow\"},\"concurrency_key\":{\"type\":\"string\",\"description\":\"Expression to group concurrent executions (e.g., by user ID)\"},\"concurrency_time_window_s\":{\"type\":\"number\",\"description\":\"Time window in seconds for concurrent_limit\"},\"debounce_delay_s\":{\"type\":\"integer\",\"description\":\"Delay in seconds to debounce flow executions\"},\"debounce_key\":{\"type\":\"string\",\"description\":\"Expression to group debounced executions\"},\"debounce_args_to_accumulate\":{\"type\":\"array\",\"description\":\"Arguments to accumulate across debounced executions\",\"items\":{\"type\":\"string\"}},\"max_total_debouncing_time\":{\"type\":\"integer\",\"description\":\"Maximum total time in seconds that a job can be debounced\"},\"max_total_debounces_amount\":{\"type\":\"integer\",\"description\":\"Maximum number of times a job can be debounced\"},\"skip_expr\":{\"type\":\"string\",\"description\":\"JavaScript expression to conditionally skip the entire flow\"},\"cache_ttl\":{\"type\":\"number\",\"description\":\"Cache duration in seconds for flow results\"},\"cache_ignore_s3_path\":{\"type\":\"boolean\"},\"delete_after_secs\":{\"type\":\"integer\",\"description\":\"If set, delete the flow job's args, result and logs after this many seconds following job completion\"},\"flow_env\":{\"type\":\"object\",\"description\":\"Environment variables available to all steps. Values can be strings, JSON values, or special references: '$var:path' (workspace variable) or '$res:path' (resource).\",\"additionalProperties\":{}},\"priority\":{\"type\":\"number\",\"description\":\"Execution priority (higher numbers run first)\"},\"early_return\":{\"type\":\"string\",\"description\":\"JavaScript expression to return early from the flow\"},\"chat_input_enabled\":{\"type\":\"boolean\",\"description\":\"Whether this flow accepts chat-style input\"},\"notes\":{\"type\":\"array\",\"description\":\"Sticky notes attached to the flow\",\"items\":{\"$ref\":\"#/components/schemas/FlowNote\"}},\"groups\":{\"type\":\"array\",\"description\":\"Semantic groups of modules for organizational purposes\",\"items\":{\"$ref\":\"#/components/schemas/FlowGroup\"}}},\"required\":[\"modules\"]},\"Retry\":{\"type\":\"object\",\"description\":\"Retry configuration for failed module executions\",\"properties\":{\"constant\":{\"type\":\"object\",\"description\":\"Retry with constant delay between attempts\",\"properties\":{\"attempts\":{\"type\":\"integer\",\"description\":\"Number of retry attempts\"},\"seconds\":{\"type\":\"integer\",\"description\":\"Seconds to wait between retries\"}}},\"exponential\":{\"type\":\"object\",\"description\":\"Retry with exponential backoff (delay doubles each time)\",\"properties\":{\"attempts\":{\"type\":\"integer\",\"description\":\"Number of retry attempts\"},\"multiplier\":{\"type\":\"integer\",\"description\":\"Multiplier for exponential backoff\"},\"seconds\":{\"type\":\"integer\",\"minimum\":1,\"description\":\"Initial delay in seconds\"},\"random_factor\":{\"type\":\"integer\",\"minimum\":0,\"maximum\":100,\"description\":\"Random jitter percentage (0-100) to avoid thundering herd\"}}},\"retry_if\":{\"$ref\":\"#/components/schemas/RetryIf\"}}},\"FlowNote\":{\"type\":\"object\",\"description\":\"A sticky note attached to a flow for documentation and annotation\",\"properties\":{\"id\":{\"type\":\"string\",\"description\":\"Unique identifier for the note\"},\"text\":{\"type\":\"string\",\"description\":\"Content of the note\"},\"position\":{\"type\":\"object\",\"description\":\"Position of the note in the flow editor\",\"properties\":{\"x\":{\"type\":\"number\",\"description\":\"X coordinate\"},\"y\":{\"type\":\"number\",\"description\":\"Y coordinate\"}},\"required\":[\"x\",\"y\"]},\"size\":{\"type\":\"object\",\"description\":\"Size of the note in the flow editor\",\"properties\":{\"width\":{\"type\":\"number\",\"description\":\"Width in pixels\"},\"height\":{\"type\":\"number\",\"description\":\"Height in pixels\"}},\"required\":[\"width\",\"height\"]},\"color\":{\"type\":\"string\",\"description\":\"Color of the note (e.g., \\\"yellow\\\", \\\"#ffff00\\\")\"},\"type\":{\"type\":\"string\",\"enum\":[\"free\",\"group\"],\"description\":\"Type of note - 'free' for standalone notes, 'group' for notes that group other nodes\"},\"locked\":{\"type\":\"boolean\",\"default\":false,\"description\":\"Whether the note is locked and cannot be edited or moved\"},\"contained_node_ids\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"description\":\"For group notes, the IDs of nodes contained within this group\"}},\"required\":[\"id\",\"text\",\"color\",\"type\"]},\"FlowGroup\":{\"type\":\"object\",\"description\":\"A semantic group of flow modules for organizational purposes. Does not affect execution \\u2014 modules remain in their original position in the flow. Groups provide naming and collapsibility in the editor. Members are computed dynamically from all nodes on paths between start_id and end_id.\",\"properties\":{\"summary\":{\"type\":\"string\",\"description\":\"Display name for this group\"},\"note\":{\"type\":\"string\",\"description\":\"Markdown note shown below the group header\"},\"autocollapse\":{\"type\":\"boolean\",\"default\":false,\"description\":\"If true, this group is collapsed by default in the flow editor. UI hint only.\"},\"start_id\":{\"type\":\"string\",\"description\":\"ID of the first flow module in this group (topological entry point)\"},\"end_id\":{\"type\":\"string\",\"description\":\"ID of the last flow module in this group (topological exit point)\"},\"color\":{\"type\":\"string\",\"description\":\"Color for the group in the flow editor\"}},\"required\":[\"start_id\",\"end_id\"]},\"RetryIf\":{\"type\":\"object\",\"description\":\"Conditional retry based on error or result\",\"properties\":{\"expr\":{\"type\":\"string\",\"description\":\"JavaScript expression that returns true to retry. Has access to 'result' and 'error' variables\"}},\"required\":[\"expr\"]},\"StopAfterIf\":{\"type\":\"object\",\"description\":\"Early termination condition for a module\",\"properties\":{\"skip_if_stopped\":{\"type\":\"boolean\",\"description\":\"If true, following steps are skipped when this condition triggers\"},\"expr\":{\"type\":\"string\",\"description\":\"JavaScript expression evaluated after the module runs. Can use 'result' (step's result) or 'flow_input'. Return true to stop\"},\"error_message\":{\"type\":\"string\",\"nullable\":true,\"description\":\"Custom error message when stopping with an error. Mutually exclusive with skip_if_stopped. If set to a non-empty string, the flow stops with this error. If empty string, a default error message is used. If null or omitted, no error is raised.\"}},\"required\":[\"expr\"]},\"FlowModule\":{\"type\":\"object\",\"description\":\"A single step in a flow. Can be a script, subflow, loop, or branch\",\"properties\":{\"id\":{\"type\":\"string\",\"description\":\"Unique identifier for this step. Used to reference results via 'results.step_id'. Must be a valid identifier (alphanumeric, underscore, hyphen)\"},\"value\":{\"$ref\":\"#/components/schemas/FlowModuleValue\"},\"stop_after_if\":{\"description\":\"Early termination condition evaluated after this step completes\",\"$ref\":\"#/components/schemas/StopAfterIf\"},\"stop_after_all_iters_if\":{\"description\":\"For loops only - early termination condition evaluated after all iterations complete\",\"$ref\":\"#/components/schemas/StopAfterIf\"},\"skip_if\":{\"type\":\"object\",\"description\":\"Conditionally skip this step based on previous results or flow inputs\",\"properties\":{\"expr\":{\"type\":\"string\",\"description\":\"JavaScript expression that returns true to skip. Can use 'flow_input' or 'results.'\"}},\"required\":[\"expr\"]},\"sleep\":{\"description\":\"Delay before executing this step (in seconds or as expression)\",\"$ref\":\"#/components/schemas/InputTransform\"},\"cache_ttl\":{\"type\":\"number\",\"description\":\"Cache duration in seconds for this step's results\"},\"cache_ignore_s3_path\":{\"type\":\"boolean\"},\"timeout\":{\"description\":\"Maximum execution time in seconds (static value or expression)\",\"$ref\":\"#/components/schemas/InputTransform\"},\"delete_after_secs\":{\"type\":\"integer\",\"description\":\"If set, delete the step's args, result and logs after this many seconds following job completion\"},\"summary\":{\"type\":\"string\",\"description\":\"Short description of what this step does\"},\"mock\":{\"type\":\"object\",\"description\":\"Mock configuration for testing without executing the actual step\",\"properties\":{\"enabled\":{\"type\":\"boolean\",\"description\":\"If true, return mock value instead of executing\"},\"return_value\":{\"description\":\"Value to return when mocked\"}}},\"suspend\":{\"type\":\"object\",\"description\":\"Configuration for approval/resume steps that wait for user input\",\"properties\":{\"required_events\":{\"type\":\"integer\",\"description\":\"Number of approvals required before continuing\"},\"timeout\":{\"type\":\"integer\",\"description\":\"Timeout in seconds before auto-continuing or canceling\"},\"resume_form\":{\"type\":\"object\",\"description\":\"Form schema for collecting input when resuming\",\"properties\":{\"schema\":{\"type\":\"object\",\"description\":\"JSON Schema for the resume form\"}}},\"user_auth_required\":{\"type\":\"boolean\",\"description\":\"If true, only authenticated users can approve\"},\"user_groups_required\":{\"description\":\"Expression or list of groups that can approve\",\"$ref\":\"#/components/schemas/InputTransform\"},\"self_approval_disabled\":{\"type\":\"boolean\",\"description\":\"If true, the user who started the flow cannot approve\"},\"hide_cancel\":{\"type\":\"boolean\",\"description\":\"If true, hide the cancel button on the approval form\"},\"continue_on_disapprove_timeout\":{\"type\":\"boolean\",\"description\":\"If true, continue flow on timeout instead of canceling\"}}},\"priority\":{\"type\":\"number\",\"description\":\"Execution priority for this step (higher numbers run first)\"},\"continue_on_error\":{\"type\":\"boolean\",\"description\":\"If true, flow continues even if this step fails\"},\"retry\":{\"description\":\"Retry configuration if this step fails\",\"$ref\":\"#/components/schemas/Retry\"},\"debouncing\":{\"description\":\"Debounce configuration for this step (EE only)\",\"type\":\"object\",\"properties\":{\"debounce_delay_s\":{\"type\":\"integer\",\"description\":\"Delay in seconds to debounce this step's executions across flow runs\"},\"debounce_key\":{\"type\":\"string\",\"description\":\"Expression to group debounced executions. Supports $workspace and $args[name]. Default: $workspace/flow/-\"},\"debounce_args_to_accumulate\":{\"type\":\"array\",\"description\":\"Array-type arguments to accumulate across debounced executions\",\"items\":{\"type\":\"string\"}},\"max_total_debouncing_time\":{\"type\":\"integer\",\"description\":\"Maximum total time in seconds before forced execution\"},\"max_total_debounces_amount\":{\"type\":\"integer\",\"description\":\"Maximum number of debounces before forced execution\"}}}},\"required\":[\"value\",\"id\"]},\"InputTransform\":{\"description\":\"Maps input parameters for a step. Can be a static value or a JavaScript expression that references previous results or flow inputs\",\"oneOf\":[{\"$ref\":\"#/components/schemas/StaticTransform\"},{\"$ref\":\"#/components/schemas/JavascriptTransform\"},{\"$ref\":\"#/components/schemas/AiTransform\"}],\"discriminator\":{\"propertyName\":\"type\",\"mapping\":{\"static\":\"#/components/schemas/StaticTransform\",\"javascript\":\"#/components/schemas/JavascriptTransform\",\"ai\":\"#/components/schemas/AiTransform\"}}},\"StaticTransform\":{\"type\":\"object\",\"description\":\"Static value passed directly to the step. Use for hardcoded values or resource references like '$res:path/to/resource'\",\"properties\":{\"value\":{\"description\":\"The static value. For resources, use format '$res:path/to/resource'\"},\"type\":{\"type\":\"string\",\"enum\":[\"static\"]}},\"required\":[\"type\"]},\"JavascriptTransform\":{\"type\":\"object\",\"description\":\"JavaScript expression evaluated at runtime. Can reference previous step results via 'results.step_id' or flow inputs via 'flow_input.property'. Inside loops, use 'flow_input.iter.value' for the current iteration value\",\"properties\":{\"expr\":{\"type\":\"string\",\"description\":\"JavaScript expression returning the value. Available variables - results (object with all previous step results), flow_input (flow inputs), flow_input.iter (in loops)\"},\"type\":{\"type\":\"string\",\"enum\":[\"javascript\"]}},\"required\":[\"expr\",\"type\"]},\"AiTransform\":{\"type\":\"object\",\"description\":\"Value resolved by the AI runtime for this input. The AI engine decides how to satisfy the parameter.\",\"properties\":{\"type\":{\"type\":\"string\",\"enum\":[\"ai\"]}},\"required\":[\"type\"]},\"AIProviderKind\":{\"type\":\"string\",\"description\":\"Supported AI provider types\",\"enum\":[\"openai\",\"azure_openai\",\"anthropic\",\"mistral\",\"deepseek\",\"googleai\",\"groq\",\"openrouter\",\"togetherai\",\"customai\",\"aws_bedrock\"]},\"ProviderConfig\":{\"type\":\"object\",\"description\":\"Complete AI provider configuration with resource reference and model selection\",\"properties\":{\"kind\":{\"$ref\":\"#/components/schemas/AIProviderKind\"},\"resource\":{\"type\":\"string\",\"description\":\"Resource reference in format '$res:{resource_path}' pointing to provider credentials\"},\"model\":{\"type\":\"string\",\"description\":\"Model identifier (e.g., 'gpt-4', 'claude-3-opus-20240229', 'gemini-pro')\"}},\"required\":[\"kind\",\"resource\",\"model\"]},\"StaticProviderTransform\":{\"type\":\"object\",\"description\":\"Static provider configuration passed directly to the AI agent\",\"properties\":{\"value\":{\"$ref\":\"#/components/schemas/ProviderConfig\"},\"type\":{\"type\":\"string\",\"enum\":[\"static\"]}},\"required\":[\"type\",\"value\"]},\"ProviderTransform\":{\"description\":\"Provider configuration - can be static (ProviderConfig), JavaScript expression, or AI-determined\",\"oneOf\":[{\"$ref\":\"#/components/schemas/StaticProviderTransform\"},{\"$ref\":\"#/components/schemas/JavascriptTransform\"},{\"$ref\":\"#/components/schemas/AiTransform\"}],\"discriminator\":{\"propertyName\":\"type\",\"mapping\":{\"static\":\"#/components/schemas/StaticProviderTransform\",\"javascript\":\"#/components/schemas/JavascriptTransform\",\"ai\":\"#/components/schemas/AiTransform\"}}},\"MemoryOff\":{\"type\":\"object\",\"description\":\"No conversation memory/context\",\"properties\":{\"kind\":{\"type\":\"string\",\"enum\":[\"off\"]}},\"required\":[\"kind\"]},\"MemoryAuto\":{\"type\":\"object\",\"description\":\"Automatic context management\",\"properties\":{\"kind\":{\"type\":\"string\",\"enum\":[\"auto\"]},\"context_length\":{\"type\":\"integer\",\"description\":\"Maximum number of messages to retain in context\"},\"memory_id\":{\"type\":\"string\",\"description\":\"Identifier for persistent memory across agent invocations\"}},\"required\":[\"kind\"]},\"MemoryMessage\":{\"type\":\"object\",\"description\":\"A single message in conversation history\",\"properties\":{\"role\":{\"type\":\"string\",\"enum\":[\"user\",\"assistant\",\"system\"]},\"content\":{\"type\":\"string\"}},\"required\":[\"role\",\"content\"]},\"MemoryManual\":{\"type\":\"object\",\"description\":\"Explicit message history\",\"properties\":{\"kind\":{\"type\":\"string\",\"enum\":[\"manual\"]},\"messages\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/components/schemas/MemoryMessage\"}}},\"required\":[\"kind\",\"messages\"]},\"MemoryConfig\":{\"description\":\"Conversation memory configuration\",\"oneOf\":[{\"$ref\":\"#/components/schemas/MemoryOff\"},{\"$ref\":\"#/components/schemas/MemoryAuto\"},{\"$ref\":\"#/components/schemas/MemoryManual\"}],\"discriminator\":{\"propertyName\":\"kind\",\"mapping\":{\"off\":\"#/components/schemas/MemoryOff\",\"auto\":\"#/components/schemas/MemoryAuto\",\"manual\":\"#/components/schemas/MemoryManual\"}}},\"StaticMemoryTransform\":{\"type\":\"object\",\"description\":\"Static memory configuration passed directly to the AI agent\",\"properties\":{\"value\":{\"$ref\":\"#/components/schemas/MemoryConfig\"},\"type\":{\"type\":\"string\",\"enum\":[\"static\"]}},\"required\":[\"type\",\"value\"]},\"MemoryTransform\":{\"description\":\"Memory configuration - can be static (MemoryConfig), JavaScript expression, or AI-determined\",\"oneOf\":[{\"$ref\":\"#/components/schemas/StaticMemoryTransform\"},{\"$ref\":\"#/components/schemas/JavascriptTransform\"},{\"$ref\":\"#/components/schemas/AiTransform\"}],\"discriminator\":{\"propertyName\":\"type\",\"mapping\":{\"static\":\"#/components/schemas/StaticMemoryTransform\",\"javascript\":\"#/components/schemas/JavascriptTransform\",\"ai\":\"#/components/schemas/AiTransform\"}}},\"FlowModuleValue\":{\"description\":\"The actual implementation of a flow step. Can be a script (inline or referenced), subflow, loop, branch, or special module type\",\"oneOf\":[{\"$ref\":\"#/components/schemas/RawScript\"},{\"$ref\":\"#/components/schemas/PathScript\"},{\"$ref\":\"#/components/schemas/PathFlow\"},{\"$ref\":\"#/components/schemas/ForloopFlow\"},{\"$ref\":\"#/components/schemas/WhileloopFlow\"},{\"$ref\":\"#/components/schemas/BranchOne\"},{\"$ref\":\"#/components/schemas/BranchAll\"},{\"$ref\":\"#/components/schemas/Identity\"},{\"$ref\":\"#/components/schemas/AiAgent\"}],\"discriminator\":{\"propertyName\":\"type\",\"mapping\":{\"rawscript\":\"#/components/schemas/RawScript\",\"script\":\"#/components/schemas/PathScript\",\"flow\":\"#/components/schemas/PathFlow\",\"forloopflow\":\"#/components/schemas/ForloopFlow\",\"whileloopflow\":\"#/components/schemas/WhileloopFlow\",\"branchone\":\"#/components/schemas/BranchOne\",\"branchall\":\"#/components/schemas/BranchAll\",\"identity\":\"#/components/schemas/Identity\",\"aiagent\":\"#/components/schemas/AiAgent\"}}},\"RawScript\":{\"type\":\"object\",\"description\":\"Inline script with code defined directly in the flow. Use 'bun' as default language if unspecified. The script receives arguments from input_transforms\",\"properties\":{\"input_transforms\":{\"type\":\"object\",\"description\":\"Map of parameter names to their values (static or JavaScript expressions). These become the script's input arguments\",\"additionalProperties\":{\"$ref\":\"#/components/schemas/InputTransform\"}},\"content\":{\"type\":\"string\",\"description\":\"The script source code. Should export a 'main' function\"},\"language\":{\"type\":\"string\",\"description\":\"Programming language for this script\",\"enum\":[\"deno\",\"bun\",\"python3\",\"go\",\"bash\",\"powershell\",\"postgresql\",\"mysql\",\"bigquery\",\"snowflake\",\"mssql\",\"oracledb\",\"graphql\",\"nativets\",\"php\",\"rust\",\"ansible\",\"csharp\",\"nu\",\"java\",\"ruby\",\"rlang\",\"duckdb\"]},\"path\":{\"type\":\"string\",\"description\":\"Optional path for saving this script\"},\"lock\":{\"type\":\"string\",\"description\":\"Lock file content for dependencies\"},\"type\":{\"type\":\"string\",\"enum\":[\"rawscript\"]},\"tag\":{\"type\":\"string\",\"description\":\"Worker group tag for execution routing\"},\"concurrent_limit\":{\"type\":\"number\",\"description\":\"Maximum concurrent executions of this script\"},\"concurrency_time_window_s\":{\"type\":\"number\",\"description\":\"Time window for concurrent_limit\"},\"custom_concurrency_key\":{\"type\":\"string\",\"description\":\"Custom key for grouping concurrent executions\"},\"is_trigger\":{\"type\":\"boolean\",\"description\":\"If true, this script is a trigger that can start the flow\"},\"assets\":{\"type\":\"array\",\"description\":\"External resources this script accesses (S3 objects, resources, etc.)\",\"items\":{\"type\":\"object\",\"required\":[\"path\",\"kind\"],\"properties\":{\"path\":{\"type\":\"string\",\"description\":\"Path to the asset\"},\"kind\":{\"type\":\"string\",\"description\":\"Type of asset\",\"enum\":[\"s3object\",\"resource\",\"ducklake\",\"datatable\",\"volume\"]},\"access_type\":{\"type\":\"string\",\"nullable\":true,\"description\":\"Access level for this asset\",\"enum\":[\"r\",\"w\",\"rw\"]},\"alt_access_type\":{\"type\":\"string\",\"nullable\":true,\"description\":\"Alternative access level\",\"enum\":[\"r\",\"w\",\"rw\"]}}}}},\"required\":[\"type\",\"content\",\"language\",\"input_transforms\"]},\"PathScript\":{\"type\":\"object\",\"description\":\"Reference to an existing script by path. Use this when calling a previously saved script instead of writing inline code\",\"properties\":{\"input_transforms\":{\"type\":\"object\",\"description\":\"Map of parameter names to their values (static or JavaScript expressions). These become the script's input arguments\",\"additionalProperties\":{\"$ref\":\"#/components/schemas/InputTransform\"}},\"path\":{\"type\":\"string\",\"description\":\"Path to the script in the workspace (e.g., 'f/scripts/send_email')\"},\"hash\":{\"type\":\"string\",\"description\":\"Optional specific version hash of the script to use\"},\"type\":{\"type\":\"string\",\"enum\":[\"script\"]},\"tag_override\":{\"type\":\"string\",\"description\":\"Override the script's default worker group tag\"},\"is_trigger\":{\"type\":\"boolean\",\"description\":\"If true, this script is a trigger that can start the flow\"}},\"required\":[\"type\",\"path\",\"input_transforms\"]},\"PathFlow\":{\"type\":\"object\",\"description\":\"Reference to an existing flow by path. Use this to call another flow as a subflow\",\"properties\":{\"input_transforms\":{\"type\":\"object\",\"description\":\"Map of parameter names to their values (static or JavaScript expressions). These become the subflow's input arguments\",\"additionalProperties\":{\"$ref\":\"#/components/schemas/InputTransform\"}},\"path\":{\"type\":\"string\",\"description\":\"Path to the flow in the workspace (e.g., 'f/flows/process_user')\"},\"type\":{\"type\":\"string\",\"enum\":[\"flow\"]}},\"required\":[\"type\",\"path\",\"input_transforms\"]},\"ForloopFlow\":{\"type\":\"object\",\"description\":\"Executes nested modules in a loop over an iterator. Inside the loop, use 'flow_input.iter.value' to access the current iteration value, and 'flow_input.iter.index' for the index. Supports parallel execution for better performance on I/O-bound operations\",\"properties\":{\"modules\":{\"type\":\"array\",\"description\":\"Steps to execute for each iteration. These can reference the iteration value via 'flow_input.iter.value'\",\"items\":{\"$ref\":\"#/components/schemas/FlowModule\"}},\"iterator\":{\"description\":\"JavaScript expression that returns an array to iterate over. Can reference 'results.step_id' or 'flow_input'\",\"$ref\":\"#/components/schemas/InputTransform\"},\"skip_failures\":{\"type\":\"boolean\",\"description\":\"If true, iteration failures don't stop the loop. Failed iterations return null\"},\"type\":{\"type\":\"string\",\"enum\":[\"forloopflow\"]},\"parallel\":{\"type\":\"boolean\",\"description\":\"If true, iterations run concurrently (faster for I/O-bound operations). Use with parallelism to control concurrency\"},\"parallelism\":{\"description\":\"Maximum number of concurrent iterations when parallel=true. Limits resource usage. Can be static number or expression\",\"$ref\":\"#/components/schemas/InputTransform\"},\"squash\":{\"type\":\"boolean\"}},\"required\":[\"modules\",\"iterator\",\"skip_failures\",\"type\"]},\"WhileloopFlow\":{\"type\":\"object\",\"description\":\"Executes nested modules repeatedly while a condition is true. The loop checks the condition after each iteration. Use stop_after_if on modules to control loop termination\",\"properties\":{\"modules\":{\"type\":\"array\",\"description\":\"Steps to execute in each iteration. Use stop_after_if to control when the loop ends\",\"items\":{\"$ref\":\"#/components/schemas/FlowModule\"}},\"skip_failures\":{\"type\":\"boolean\",\"description\":\"If true, iteration failures don't stop the loop. Failed iterations return null\"},\"type\":{\"type\":\"string\",\"enum\":[\"whileloopflow\"]},\"parallel\":{\"type\":\"boolean\",\"description\":\"If true, iterations run concurrently (use with caution in while loops)\"},\"parallelism\":{\"description\":\"Maximum number of concurrent iterations when parallel=true\",\"$ref\":\"#/components/schemas/InputTransform\"},\"squash\":{\"type\":\"boolean\"}},\"required\":[\"modules\",\"skip_failures\",\"type\"]},\"BranchOne\":{\"type\":\"object\",\"description\":\"Conditional branching where only the first matching branch executes. Branches are evaluated in order, and the first one with a true expression runs. If no branches match, the default branch executes\",\"properties\":{\"branches\":{\"type\":\"array\",\"description\":\"Array of branches to evaluate in order. The first branch with expr evaluating to true executes\",\"items\":{\"type\":\"object\",\"properties\":{\"summary\":{\"type\":\"string\",\"description\":\"Short description of this branch condition\"},\"expr\":{\"type\":\"string\",\"description\":\"JavaScript expression that returns boolean. Can use 'results.step_id' or 'flow_input'. First true expr wins\"},\"modules\":{\"type\":\"array\",\"description\":\"Steps to execute if this branch's expr is true\",\"items\":{\"$ref\":\"#/components/schemas/FlowModule\"}}},\"required\":[\"modules\",\"expr\"]}},\"default\":{\"type\":\"array\",\"description\":\"Steps to execute if no branch expressions match\",\"items\":{\"$ref\":\"#/components/schemas/FlowModule\"}},\"type\":{\"type\":\"string\",\"enum\":[\"branchone\"]}},\"required\":[\"branches\",\"default\",\"type\"]},\"BranchAll\":{\"type\":\"object\",\"description\":\"Parallel branching where all branches execute simultaneously. Unlike BranchOne, all branches run regardless of conditions. Useful for executing independent tasks concurrently\",\"properties\":{\"branches\":{\"type\":\"array\",\"description\":\"Array of branches that all execute (either in parallel or sequentially)\",\"items\":{\"type\":\"object\",\"properties\":{\"summary\":{\"type\":\"string\",\"description\":\"Short description of this branch's purpose\"},\"skip_failure\":{\"type\":\"boolean\",\"description\":\"If true, failure in this branch doesn't fail the entire flow\"},\"modules\":{\"type\":\"array\",\"description\":\"Steps to execute in this branch\",\"items\":{\"$ref\":\"#/components/schemas/FlowModule\"}}},\"required\":[\"modules\"]}},\"type\":{\"type\":\"string\",\"enum\":[\"branchall\"]},\"parallel\":{\"type\":\"boolean\",\"description\":\"If true, all branches execute concurrently. If false, they execute sequentially\"}},\"required\":[\"branches\",\"type\"]},\"AgentTool\":{\"type\":\"object\",\"description\":\"A tool available to an AI agent. Can be a flow module or an external MCP (Model Context Protocol) tool\",\"properties\":{\"id\":{\"type\":\"string\",\"description\":\"Unique identifier for this tool. Cannot contain spaces - use underscores instead (e.g., 'get_user_data' not 'get user data')\"},\"summary\":{\"type\":\"string\",\"description\":\"Short description of what this tool does (shown to the AI)\"},\"value\":{\"$ref\":\"#/components/schemas/ToolValue\"}},\"required\":[\"id\",\"value\"]},\"ToolValue\":{\"description\":\"The implementation of a tool. Can be a flow module (script/flow) or an MCP tool reference\",\"oneOf\":[{\"$ref\":\"#/components/schemas/FlowModuleTool\"},{\"$ref\":\"#/components/schemas/McpToolValue\"},{\"$ref\":\"#/components/schemas/WebsearchToolValue\"}],\"discriminator\":{\"propertyName\":\"tool_type\",\"mapping\":{\"flowmodule\":\"#/components/schemas/FlowModuleTool\",\"mcp\":\"#/components/schemas/McpToolValue\",\"websearch\":\"#/components/schemas/WebsearchToolValue\"}}},\"FlowModuleTool\":{\"description\":\"A tool implemented as a flow module (script, flow, etc.). The AI can call this like any other flow module\",\"allOf\":[{\"type\":\"object\",\"properties\":{\"tool_type\":{\"type\":\"string\",\"enum\":[\"flowmodule\"]}},\"required\":[\"tool_type\"]},{\"$ref\":\"#/components/schemas/FlowModuleValue\"}]},\"WebsearchToolValue\":{\"type\":\"object\",\"description\":\"A tool implemented as a websearch tool. The AI can call this like any other websearch tool\",\"properties\":{\"tool_type\":{\"type\":\"string\",\"enum\":[\"websearch\"]}},\"required\":[\"tool_type\"]},\"McpToolValue\":{\"type\":\"object\",\"description\":\"Reference to an external MCP (Model Context Protocol) tool. The AI can call tools from MCP servers\",\"properties\":{\"tool_type\":{\"type\":\"string\",\"enum\":[\"mcp\"]},\"resource_path\":{\"type\":\"string\",\"description\":\"Path to the MCP resource/server configuration\"},\"include_tools\":{\"type\":\"array\",\"description\":\"Whitelist of specific tools to include from this MCP server\",\"items\":{\"type\":\"string\"}},\"exclude_tools\":{\"type\":\"array\",\"description\":\"Blacklist of tools to exclude from this MCP server\",\"items\":{\"type\":\"string\"}}},\"required\":[\"tool_type\",\"resource_path\"]},\"AiAgent\":{\"type\":\"object\",\"description\":\"AI agent step that can use tools to accomplish tasks. The agent receives inputs and can call any of its configured tools to complete the task\",\"properties\":{\"input_transforms\":{\"type\":\"object\",\"description\":\"Input parameters for the AI agent mapped to their values\",\"properties\":{\"provider\":{\"$ref\":\"#/components/schemas/ProviderTransform\"},\"output_type\":{\"allOf\":[{\"$ref\":\"#/components/schemas/InputTransform\"}],\"description\":\"Output format type.\\nValid values: 'text' (default) - plain text response, 'image' - image generation\\n\"},\"user_message\":{\"allOf\":[{\"$ref\":\"#/components/schemas/InputTransform\"}],\"description\":\"The user's prompt/message to the AI agent. Supports variable interpolation with flow.input syntax.\"},\"system_prompt\":{\"allOf\":[{\"$ref\":\"#/components/schemas/InputTransform\"}],\"description\":\"System instructions that guide the AI's behavior, persona, and response style. Optional.\"},\"streaming\":{\"allOf\":[{\"$ref\":\"#/components/schemas/InputTransform\"}],\"description\":\"Boolean. If true, stream the AI response incrementally.\\nStreaming events include: token_delta, tool_call, tool_call_arguments, tool_execution, tool_result\\n\"},\"memory\":{\"$ref\":\"#/components/schemas/MemoryTransform\"},\"output_schema\":{\"allOf\":[{\"$ref\":\"#/components/schemas/InputTransform\"}],\"description\":\"JSON Schema object defining structured output format. Used when you need the AI to return data in a specific shape.\\nSupports standard JSON Schema properties: type, properties, required, items, enum, pattern, minLength, maxLength, minimum, maximum, etc.\\nExample: { type: 'object', properties: { name: { type: 'string' }, age: { type: 'integer' } }, required: ['name'] }\\n\"},\"user_attachments\":{\"allOf\":[{\"$ref\":\"#/components/schemas/InputTransform\"}],\"description\":\"Array of file references (images or PDFs) for the AI agent.\\nFormat: Array<{ bucket: string, key: string }> - S3 object references\\nExample: [{ bucket: 'my-bucket', key: 'documents/report.pdf' }]\\n\"},\"max_completion_tokens\":{\"allOf\":[{\"$ref\":\"#/components/schemas/InputTransform\"}],\"description\":\"Integer. Maximum number of tokens the AI will generate in its response.\\nRange: 1 to 4,294,967,295. Typical values: 256-4096 for most use cases.\\n\"},\"temperature\":{\"allOf\":[{\"$ref\":\"#/components/schemas/InputTransform\"}],\"description\":\"Float. Controls randomness/creativity of responses.\\nRange: 0.0 to 2.0 (provider-dependent)\\n- 0.0 = deterministic, focused responses\\n- 0.7 = balanced (common default)\\n- 1.0+ = more creative/random\\n\"}},\"required\":[\"provider\",\"user_message\",\"output_type\"]},\"tools\":{\"type\":\"array\",\"description\":\"Array of tools the agent can use. The agent decides which tools to call based on the task\",\"items\":{\"$ref\":\"#/components/schemas/AgentTool\"}},\"type\":{\"type\":\"string\",\"enum\":[\"aiagent\"]},\"omit_output_from_conversation\":{\"type\":\"boolean\",\"default\":false,\"description\":\"If true, this AI agent step does not persist its assistant or tool messages to the flow conversation when chat mode is enabled.\"},\"parallel\":{\"type\":\"boolean\",\"description\":\"If true, the agent can execute multiple tool calls in parallel\"}},\"required\":[\"tools\",\"type\",\"input_transforms\"]},\"Identity\":{\"type\":\"object\",\"description\":\"Pass-through module that returns its input unchanged. Useful for flow structure or as a placeholder\",\"properties\":{\"type\":{\"type\":\"string\",\"enum\":[\"identity\"]},\"flow\":{\"type\":\"boolean\",\"description\":\"If true, marks this as a flow identity (special handling)\"}},\"required\":[\"type\"]},\"FlowStatus\":{\"type\":\"object\",\"properties\":{\"step\":{\"type\":\"integer\"},\"modules\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/components/schemas/FlowStatusModule\"}},\"user_states\":{\"additionalProperties\":true},\"preprocessor_module\":{\"allOf\":[{\"$ref\":\"#/components/schemas/FlowStatusModule\"}]},\"failure_module\":{\"allOf\":[{\"$ref\":\"#/components/schemas/FlowStatusModule\"},{\"type\":\"object\",\"properties\":{\"parent_module\":{\"type\":\"string\"}}}]},\"retry\":{\"type\":\"object\",\"properties\":{\"fail_count\":{\"type\":\"integer\"},\"failed_jobs\":{\"type\":\"array\",\"items\":{\"type\":\"string\",\"format\":\"uuid\"}}}}},\"required\":[\"step\",\"modules\",\"failure_module\"]},\"FlowStatusModule\":{\"type\":\"object\",\"properties\":{\"type\":{\"type\":\"string\",\"enum\":[\"WaitingForPriorSteps\",\"WaitingForEvents\",\"WaitingForExecutor\",\"InProgress\",\"Success\",\"Failure\"]},\"id\":{\"type\":\"string\"},\"job\":{\"type\":\"string\",\"format\":\"uuid\"},\"count\":{\"type\":\"integer\"},\"progress\":{\"type\":\"integer\"},\"iterator\":{\"type\":\"object\",\"properties\":{\"index\":{\"type\":\"integer\"},\"itered\":{\"type\":\"array\",\"items\":{}},\"itered_len\":{\"type\":\"integer\"},\"args\":{}}},\"flow_jobs\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"flow_jobs_success\":{\"type\":\"array\",\"items\":{\"type\":\"boolean\"}},\"flow_jobs_duration\":{\"type\":\"object\",\"properties\":{\"started_at\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"duration_ms\":{\"type\":\"array\",\"items\":{\"type\":\"integer\"}}}},\"branch_chosen\":{\"type\":\"object\",\"properties\":{\"type\":{\"type\":\"string\",\"enum\":[\"branch\",\"default\"]},\"branch\":{\"type\":\"integer\"}},\"required\":[\"type\"]},\"branchall\":{\"type\":\"object\",\"properties\":{\"branch\":{\"type\":\"integer\"},\"len\":{\"type\":\"integer\"}},\"required\":[\"branch\",\"len\"]},\"approvers\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"resume_id\":{\"type\":\"integer\"},\"approver\":{\"type\":\"string\"}},\"required\":[\"resume_id\",\"approver\"]}},\"failed_retries\":{\"type\":\"array\",\"items\":{\"type\":\"string\",\"format\":\"uuid\"}},\"skipped\":{\"type\":\"boolean\"},\"agent_actions\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"oneOf\":[{\"type\":\"object\",\"properties\":{\"job_id\":{\"type\":\"string\",\"format\":\"uuid\"},\"function_name\":{\"type\":\"string\"},\"type\":{\"type\":\"string\",\"enum\":[\"tool_call\"]},\"module_id\":{\"type\":\"string\"}},\"required\":[\"job_id\",\"function_name\",\"type\",\"module_id\"]},{\"type\":\"object\",\"properties\":{\"call_id\":{\"type\":\"string\",\"format\":\"uuid\"},\"function_name\":{\"type\":\"string\"},\"resource_path\":{\"type\":\"string\"},\"type\":{\"type\":\"string\",\"enum\":[\"mcp_tool_call\"]},\"arguments\":{\"type\":\"object\"}},\"required\":[\"call_id\",\"function_name\",\"resource_path\",\"type\"]},{\"type\":\"object\",\"properties\":{\"type\":{\"type\":\"string\",\"enum\":[\"web_search\"]}},\"required\":[\"type\"]},{\"type\":\"object\",\"properties\":{\"type\":{\"type\":\"string\",\"enum\":[\"message\"]}},\"required\":[\"content\",\"type\"]}]}},\"agent_actions_success\":{\"type\":\"array\",\"items\":{\"type\":\"boolean\"}}},\"required\":[\"type\"]}}"; -export declare const CLI_COMMANDS = "# Windmill CLI Commands\n\nThe Windmill CLI (`wmill`) provides commands for managing scripts, flows, apps, and other resources.\n\n## Global Options\n\n- `--workspace ` - Specify the target workspace. This overrides the default workspace.\n- `--debug --verbose` - Show debug/verbose logs\n- `--show-diffs` - Show diff informations when syncing (may show sensitive informations)\n- `--token ` - Specify an API token. This will override any stored token.\n- `--base-url ` - Specify the base URL of the API. If used, --token and --workspace are required and no local remote/workspace already set will be used.\n- `--config-dir ` - Specify a custom config directory. Overrides WMILL_CONFIG_DIR environment variable and default ~/.config location.\n\n## Commands\n\n### app\n\napp related commands\n\n**Options:**\n- `--json` - Output as JSON (for piping to jq)\n\n**Subcommands:**\n\n- `app list` - list all apps\n - `--json` - Output as JSON (for piping to jq)\n- `app get ` - get an app's details\n - `--json` - Output as JSON (for piping to jq)\n- `app push ` - push a local app \n- `app dev [app_folder:string]` - Start a development server for building apps with live reload and hot module replacement\n - `--port ` - Port to run the dev server on (will find next available port if occupied)\n - `--host ` - Host to bind the dev server to\n - `--entry ` - Entry point file (default: index.ts for Svelte/Vue, index.tsx otherwise)\n - `--no-open` - Don't automatically open the browser\n- `app lint [app_folder:string]` - Lint a raw app folder to validate structure and buildability\n - `--fix` - Attempt to fix common issues (not implemented yet)\n- `app new` - create a new raw app from a template\n - `--summary ` - App summary (short description). Skips the prompt when provided. Triggers non-interactive mode.\n - `--path ` - App path (e.g., f/folder/my_app or u/username/my_app). Skips the prompt when provided. Triggers non-interactive mode.\n - `--framework ` - Framework template: react19 | react18 | svelte5 | vue. Skips the prompt when provided. Triggers non-interactive mode.\n - `--datatable ` - Datatable to wire up. Without this flag in non-interactive mode, no datatable is configured.\n - `--schema ` - Schema to use with --datatable. Created (CREATE SCHEMA IF NOT EXISTS) if it doesn't already exist.\n - `--overwrite` - Overwrite the target directory if it already exists, without prompting.\n - `--no-open-in-desktop` - Do not prompt to open the new app in Claude Desktop.\n- `app generate-agents [app_folder:string]` - regenerate AGENTS.md and DATATABLES.md from remote workspace\n- `app set-permissioned-as ` - Set the on_behalf_of_email for an app (requires admin or wm_deployers group)\n\n### audit\n\nView audit logs (requires admin)\n\n**Subcommands:**\n\n- `audit list` - List audit log entries\n- `audit get ` - Get a specific audit log entry\n - `--json` - Output as JSON (for piping to jq)\n\n### config\n\nShow all available wmill.yaml configuration options\n\n**Options:**\n- `--json` - Output as JSON for programmatic consumption\n\n**Subcommands:**\n\n- `config migrate` - Migrate wmill.yaml from gitBranches/environments to workspaces format\n\n### dependencies\n\nworkspace dependencies related commands\n\n**Alias:** `deps`\n\n**Subcommands:**\n\n- `dependencies push ` - Push workspace dependencies from a local file\n\n### dev\n\nWatch local file changes and live-reload the dev page for preview. Does NOT deploy to the remote workspace \u2014 use wmill sync push for that.\n\n**Options:**\n- `--includes ` - Filter paths given a glob pattern or path\n- `--proxy-port ` - Port for a localhost reverse proxy to the remote Windmill server\n- `--path ` - Watch a specific windmill path (e.g., u/admin/my_script or f/my_flow)\n- `--no-open` - Do not open the browser automatically\n\n### docs\n\nSearch Windmill documentation.\n\n**Arguments:** ``\n\n**Options:**\n- `--json` - Output results as JSON.\n\n### flow\n\nflow related commands\n\n**Options:**\n- `--show-archived` - Enable archived flows in output\n- `--json` - Output as JSON (for piping to jq)\n\n**Subcommands:**\n\n- `flow list` - list all flows\n - `--show-archived` - Enable archived flows in output\n - `--json` - Output as JSON (for piping to jq)\n- `flow get ` - get a flow's details\n - `--json` - Output as JSON (for piping to jq)\n- `flow push ` - push a local flow spec. This overrides any remote versions.\n - `--message ` - Deployment message\n- `flow run ` - run a flow by path.\n - `-d --data ` - Inputs specified as a JSON string or a file using @ or stdin using @-.\n - `-s --silent` - Do not ouput anything other then the final output. Useful for scripting.\n- `flow preview ` - preview a local flow without deploying it. Runs the flow definition from local files and uses local PathScripts by default.\n - `-d --data ` - Inputs specified as a JSON string or a file using @ or stdin using @-.\n - `-s --silent` - Do not output anything other then the final output. Useful for scripting.\n - `--remote` - Use deployed workspace scripts for PathScript steps instead of local files.\n- `flow new ` - create a new empty flow\n - `--summary ` - flow summary\n - `--description ` - flow description\n- `flow bootstrap ` - create a new empty flow (alias for new)\n - `--summary ` - flow summary\n - `--description ` - flow description\n- `flow history ` - Show version history for a flow\n - `--json` - Output as JSON (for piping to jq)\n- `flow show-version ` - Show a specific version of a flow\n - `--json` - Output as JSON (for piping to jq)\n- `flow set-permissioned-as ` - Set the on_behalf_of_email for a flow (requires admin or wm_deployers group)\n\n### folder\n\nfolder related commands\n\n**Options:**\n- `--json` - Output as JSON (for piping to jq)\n\n**Subcommands:**\n\n- `folder list` - list all folders\n - `--json` - Output as JSON (for piping to jq)\n- `folder get ` - get a folder's details\n - `--json` - Output as JSON (for piping to jq)\n- `folder new ` - create a new folder locally\n - `--summary ` - folder summary\n- `folder push ` - push a local folder to the remote by name. This overrides any remote versions.\n- `folder add-missing` - create default folder.meta.yaml for all subdirectories of f/ that are missing one\n - `-y, --yes` - skip confirmation prompt\n- `folder show-rules ` - Show default_permissioned_as rules for a folder. Use --test-path to see which rule matches a given item path.\n - `--test-path ` - Test which rule matches this item path (e.g. f/prod/jobs/my_script)\n - `--json` - Output as JSON\n\n### generate-metadata\n\nGenerate metadata (locks, schemas) for all scripts, flows, and apps\n\n**Arguments:** `[folder:string]`\n\n**Options:**\n- `--yes` - Skip confirmation prompt\n- `--dry-run` - Show what would be updated without making changes\n- `--lock-only` - Re-generate only the lock files\n- `--schema-only` - Re-generate only script schemas (skips flows and apps)\n- `--skip-scripts` - Skip processing scripts\n- `--skip-flows` - Skip processing flows\n- `--skip-apps` - Skip processing apps\n- `--strict-folder-boundaries` - Only update items inside the specified folder (requires folder argument)\n- `-i --includes ` - Comma separated patterns to specify which files to include\n- `-e --excludes ` - Comma separated patterns to specify which files to exclude\n\n### gitsync-settings\n\nManage git-sync settings between local wmill.yaml and Windmill backend\n\n**Subcommands:**\n\n- `gitsync-settings pull` - Pull git-sync settings from Windmill backend to local wmill.yaml\n - `--repository ` - Specify repository path (e.g., u/user/repo)\n - `--default` - Write settings to top-level defaults instead of overrides\n - `--replace` - Replace existing settings (non-interactive mode)\n - `--override` - Add branch-specific override (non-interactive mode)\n - `--diff` - Show differences without applying changes\n - `--json-output` - Output in JSON format\n - `--with-backend-settings ` - Use provided JSON settings instead of querying backend (for testing)\n - `--yes` - Skip interactive prompts and use default behavior\n - `--promotion ` - Use promotionOverrides from the specified branch instead of regular overrides\n- `gitsync-settings push` - Push git-sync settings from local wmill.yaml to Windmill backend\n - `--repository ` - Specify repository path (e.g., u/user/repo)\n - `--diff` - Show what would be pushed without applying changes\n - `--json-output` - Output in JSON format\n - `--with-backend-settings ` - Use provided JSON settings instead of querying backend (for testing)\n - `--yes` - Skip interactive prompts and use default behavior\n - `--promotion ` - Use promotionOverrides from the specified branch instead of regular overrides\n\n### group\n\nManage workspace groups\n\n**Options:**\n- `--json` - Output as JSON (for piping to jq)\n\n**Subcommands:**\n\n- `group list` - List all groups in the workspace\n - `--json` - Output as JSON (for piping to jq)\n- `group get ` - Get group details and members\n - `--json` - Output as JSON (for piping to jq)\n- `group create ` - Create a new group\n - `--summary ` - Group summary/description\n- `group delete ` - Delete a group\n- `group add-user ` - Add a user to a group\n- `group remove-user ` - Remove a user from a group\n\n### hub\n\nHub related commands. EXPERIMENTAL. INTERNAL USE ONLY.\n\n**Subcommands:**\n\n- `hub pull` - pull any supported definitions. EXPERIMENTAL.\n\n### init\n\nBootstrap a windmill project with a wmill.yaml file\n\n**Options:**\n- `--use-default` - Use default settings without checking backend\n- `--use-backend` - Use backend git-sync settings if available\n- `--repository ` - Specify repository path (e.g., u/user/repo) when using backend settings\n- `--bind-profile` - Automatically bind active workspace profile to current Git branch\n- `--no-bind-profile` - Skip workspace profile binding prompt\n\n### instance\n\nsync local with a remote instance or the opposite (push or pull)\n\n**Subcommands:**\n\n- `instance add [instance_name:string] [remote:string] [token:string]` - Add a new instance\n- `instance remove ` - Remove an instance\n- `instance switch ` - Switch the current instance\n- `instance pull` - Pull instance settings, users, configs, instance groups and overwrite local\n - `--yes` - Pull without needing confirmation\n - `--dry-run` - Perform a dry run without making changes\n - `--skip-users` - Skip pulling users\n - `--skip-settings` - Skip pulling settings\n - `--skip-configs` - Skip pulling configs (worker groups)\n - `--skip-groups` - Skip pulling instance groups\n - `--include-workspaces` - Also pull workspaces\n - `--folder-per-instance` - Create a folder per instance\n - `--instance ` - Name of the instance to pull from, override the active instance\n - `--prefix ` - Prefix of the local workspaces to pull, used to create the folders when using --include-workspaces\n - `--prefix-settings` - Store instance yamls inside prefixed folders when using --prefix and --folder-per-instance\n- `instance push` - Push instance settings, users, configs, group and overwrite remote\n - `--yes` - Push without needing confirmation\n - `--dry-run` - Perform a dry run without making changes\n - `--skip-users` - Skip pushing users\n - `--skip-settings` - Skip pushing settings\n - `--skip-configs` - Skip pushing configs (worker groups)\n - `--skip-groups` - Skip pushing instance groups\n - `--include-workspaces` - Also push workspaces\n - `--folder-per-instance` - Create a folder per instance\n - `--instance ` - Name of the instance to push to, override the active instance\n - `--prefix ` - Prefix of the local workspaces folders to push\n - `--prefix-settings` - Store instance yamls inside prefixed folders when using --prefix and --folder-per-instance\n- `instance whoami` - Display information about the currently logged-in user\n- `instance get-config` - Dump the current instance config (global settings + worker configs) as YAML\n - `-o, --output-file ` - Write YAML to a file instead of stdout\n - `--show-secrets` - Include sensitive fields (license key, JWT secret) without prompting\n - `--instance ` - Name of the instance, override the active instance\n- `instance connect-slack`\n - `--bot-token ` - Slack bot token (xoxb-...)\n - `--team-id ` - Slack team id\n - `--team-name ` - Slack team name\n - `--instance ` - Instance profile to connect against (defaults to the active instance)\n\n### job\n\nManage jobs (list, inspect, cancel)\n\n**Subcommands:**\n\n- `job list` - List recent jobs\n- `job get ` - Get job details. For flows: shows step tree with sub-job IDs\n - `--json` - Output as JSON (for piping to jq)\n- `job result ` - Get the result of a completed job (machine-friendly)\n- `job logs ` - Get job logs. For flows: aggregates all step logs\n- `job cancel ` - Cancel a running or queued job\n - `--reason ` - Reason for cancellation\n\n### jobs\n\nPull completed and queued jobs from workspace\n\n**Arguments:** `[workspace:string]`\n\n**Options:**\n- `-c, --completed-output ` - Completed jobs output file (default: completed_jobs.json)\n- `-q, --queued-output ` - Queued jobs output file (default: queued_jobs.json)\n- `--skip-worker-check` - Skip checking for active workers before export\n\n**Subcommands:**\n\n- `jobs pull`\n- `jobs push`\n\n### lint\n\nValidate Windmill flow, schedule, and trigger YAML files in a directory\n\n**Arguments:** `[directory:string]`\n\n**Options:**\n- `--json` - Output results in JSON format\n- `--fail-on-warn` - Exit with code 1 when warnings are emitted\n- `--locks-required` - Fail if scripts or flow inline scripts that need locks have no locks\n- `-w, --watch` - Watch for file changes and re-lint automatically\n\n### queues\n\nList all queues with their metrics\n\n**Arguments:** `[workspace:string] the optional workspace to filter by (default to all workspaces)`\n\n**Options:**\n- `--instance [instance]` - Name of the instance to push to, override the active instance\n- `--base-url [baseUrl]` - If used with --token, will be used as the base url for the instance\n\n### resource\n\nresource related commands\n\n**Options:**\n- `--json` - Output as JSON (for piping to jq)\n\n**Subcommands:**\n\n- `resource list` - list all resources\n - `--json` - Output as JSON (for piping to jq)\n- `resource get ` - get a resource's details\n - `--json` - Output as JSON (for piping to jq)\n- `resource new ` - create a new resource locally\n- `resource push ` - push a local resource spec. This overrides any remote versions.\n\n### resource-type\n\nresource type related commands\n\n**Options:**\n- `--json` - Output as JSON (for piping to jq)\n\n**Subcommands:**\n\n- `resource-type list` - list all resource types\n - `--schema` - Show schema in the output\n - `--json` - Output as JSON (for piping to jq)\n- `resource-type get ` - get a resource type's details\n - `--json` - Output as JSON (for piping to jq)\n- `resource-type new ` - create a new resource type locally\n- `resource-type push ` - push a local resource spec. This overrides any remote versions.\n- `resource-type generate-namespace` - Create a TypeScript definition file with the RT namespace generated from the resource types\n\n### schedule\n\nschedule related commands\n\n**Options:**\n- `--json` - Output as JSON (for piping to jq)\n\n**Subcommands:**\n\n- `schedule list` - list all schedules\n - `--json` - Output as JSON (for piping to jq)\n- `schedule get ` - get a schedule's details\n - `--json` - Output as JSON (for piping to jq)\n- `schedule new ` - create a new schedule locally\n- `schedule push ` - push a local schedule spec. This overrides any remote versions.\n- `schedule enable ` - Enable a schedule\n- `schedule disable ` - Disable a schedule\n- `schedule set-permissioned-as ` - Set the email (run-as user) for a schedule (requires admin or wm_deployers group)\n\n### script\n\nscript related commands\n\n**Options:**\n- `--show-archived` - Show archived scripts instead of active ones\n- `--json` - Output as JSON (for piping to jq)\n\n**Subcommands:**\n\n- `script list` - list all scripts\n - `--show-archived` - Show archived scripts instead of active ones\n - `--json` - Output as JSON (for piping to jq)\n- `script push ` - push a local script spec. This overrides any remote versions. Use the script file (.ts, .js, .py, .sh)\n - `--message ` - Deployment message\n- `script get ` - get a script's details\n - `--json` - Output as JSON (for piping to jq)\n- `script show ` - show a script's content (alias for get)\n- `script run ` - run a script by path\n - `-d --data ` - Inputs specified as a JSON string or a file using @ or stdin using @-.\n - `-s --silent` - Do not output anything other then the final output. Useful for scripting.\n- `script preview ` - preview a local script without deploying it. Supports both regular and codebase scripts.\n - `-d --data ` - Inputs specified as a JSON string or a file using @ or stdin using @-.\n - `-s --silent` - Do not output anything other than the final output. Useful for scripting.\n- `script new ` - create a new script\n - `--summary ` - script summary\n - `--description ` - script description\n- `script bootstrap ` - create a new script (alias for new)\n - `--summary ` - script summary\n - `--description ` - script description\n- `script set-permissioned-as ` - Set the on_behalf_of_email for a script (requires admin or wm_deployers group)\n- `script history ` - show version history for a script\n - `--json` - Output as JSON (for piping to jq)\n\n### sync\n\nsync local with a remote workspaces or the opposite (push or pull)\n\n**Subcommands:**\n\n- `sync pull` - Pull any remote changes and apply them locally.\n - `--yes` - Pull without needing confirmation\n - `--dry-run` - Show changes that would be pulled without actually pushing\n - `--plain-secrets` - Pull secrets as plain text\n - `--json` - Use JSON instead of YAML\n - `--skip-variables` - Skip syncing variables (including secrets)\n - `--skip-secrets` - Skip syncing only secrets variables\n - `--include-secrets` - Include secrets in sync (overrides skipSecrets in wmill.yaml)\n - `--skip-resources` - Skip syncing resources\n - `--skip-resource-types` - Skip syncing resource types\n - `--skip-scripts` - Skip syncing scripts\n - `--skip-flows` - Skip syncing flows\n - `--skip-apps` - Skip syncing apps\n - `--skip-folders` - Skip syncing folders\n - `--skip-workspace-dependencies` - Skip syncing workspace dependencies\n - `--skip-scripts-metadata` - Skip syncing scripts metadata, focus solely on logic\n - `--include-schedules` - Include syncing schedules\n - `--include-triggers` - Include syncing triggers\n - `--include-users` - Include syncing users\n - `--include-groups` - Include syncing groups\n - `--include-settings` - Include syncing workspace settings\n - `--include-key` - Include workspace encryption key\n - `--skip-branch-validation` - Skip git branch validation and prompts\n - `--json-output` - Output results in JSON format\n - `-i --includes ` - Comma separated patterns to specify which file to take into account (among files that are compatible with windmill). Patterns can include * (any string until '/') and ** (any string). Overrides wmill.yaml includes\n - `-e --excludes ` - Comma separated patterns to specify which file to NOT take into account. Overrides wmill.yaml excludes\n - `--extra-includes ` - Comma separated patterns to specify which file to take into account (among files that are compatible with windmill). Patterns can include * (any string until '/') and ** (any string). Useful to still take wmill.yaml into account and act as a second pattern to satisfy\n - `--repository ` - Specify repository path (e.g., u/user/repo) when multiple repositories exist\n - `--promotion ` - Use promotionOverrides from the specified branch instead of regular overrides\n - `--branch, --env ` - [Deprecated: use --workspace] Override the current git branch/environment\n- `sync push` - Push any local changes and apply them remotely.\n - `--yes` - Push without needing confirmation\n - `--dry-run` - Show changes that would be pushed without actually pushing\n - `--plain-secrets` - Push secrets as plain text\n - `--json` - Use JSON instead of YAML\n - `--skip-variables` - Skip syncing variables (including secrets)\n - `--skip-secrets` - Skip syncing only secrets variables\n - `--include-secrets` - Include secrets in sync (overrides skipSecrets in wmill.yaml)\n - `--skip-resources` - Skip syncing resources\n - `--skip-resource-types` - Skip syncing resource types\n - `--skip-scripts` - Skip syncing scripts\n - `--skip-flows` - Skip syncing flows\n - `--skip-apps` - Skip syncing apps\n - `--skip-folders` - Skip syncing folders\n - `--skip-workspace-dependencies` - Skip syncing workspace dependencies\n - `--skip-scripts-metadata` - Skip syncing scripts metadata, focus solely on logic\n - `--include-schedules` - Include syncing schedules\n - `--include-triggers` - Include syncing triggers\n - `--include-users` - Include syncing users\n - `--include-groups` - Include syncing groups\n - `--include-settings` - Include syncing workspace settings\n - `--include-key` - Include workspace encryption key\n - `--skip-branch-validation` - Skip git branch validation and prompts\n - `--json-output` - Output results in JSON format\n - `-i --includes ` - Comma separated patterns to specify which file to take into account (among files that are compatible with windmill). Patterns can include * (any string until '/') and ** (any string)\n - `-e --excludes ` - Comma separated patterns to specify which file to NOT take into account.\n - `--extra-includes ` - Comma separated patterns to specify which file to take into account (among files that are compatible with windmill). Patterns can include * (any string until '/') and ** (any string). Useful to still take wmill.yaml into account and act as a second pattern to satisfy\n - `--message ` - Include a message that will be added to all scripts/flows/apps updated during this push\n - `--parallel ` - Number of changes to process in parallel\n - `--repository ` - Specify repository path (e.g., u/user/repo) when multiple repositories exist\n - `--branch, --env ` - [Deprecated: use --workspace] Override the current git branch/environment\n - `--lint` - Run lint validation before pushing\n - `--locks-required` - Fail if scripts or flow inline scripts that need locks have no locks\n - `--auto-metadata` - Automatically regenerate stale metadata (locks and schemas) before pushing\n - `--accept-overriding-permissioned-as-with-self` - Accept that items with a different permissioned_as will be updated with your own user\n\n### token\n\nManage API tokens\n\n**Options:**\n- `--json` - Output as JSON (for piping to jq)\n\n**Subcommands:**\n\n- `token list` - List API tokens\n - `--json` - Output as JSON (for piping to jq)\n- `token create` - Create a new API token\n - `--label ` - Token label\n - `--expiration ` - Token expiration (ISO 8601 timestamp)\n- `token delete ` - Delete a token by its prefix\n\n### trigger\n\ntrigger related commands\n\n**Options:**\n- `--json` - Output as JSON (for piping to jq)\n\n**Subcommands:**\n\n- `trigger list` - list all triggers\n - `--json` - Output as JSON (for piping to jq)\n- `trigger get ` - get a trigger's details\n - `--json` - Output as JSON (for piping to jq)\n - `--kind ` - Trigger kind (http, websocket, kafka, nats, postgres, mqtt, sqs, gcp, azure, email). Recommended for faster lookup\n- `trigger new ` - create a new trigger locally\n - `--kind ` - Trigger kind (required: http, websocket, kafka, nats, postgres, mqtt, sqs, gcp, azure, email)\n- `trigger push ` - push a local trigger spec. This overrides any remote versions.\n- `trigger set-permissioned-as ` - Set the email (run-as user) for a trigger (requires admin or wm_deployers group)\n - `--kind ` - Trigger kind (required: http, websocket, kafka, nats, postgres, mqtt, sqs, gcp, azure, email)\n\n### user\n\nuser related commands\n\n**Subcommands:**\n\n- `user add [password:string]` - Create a user\n - `--superadmin` - Specify to make the new user superadmin.\n - `--company ` - Specify to set the company of the new user.\n - `--name ` - Specify to set the name of the new user.\n- `user remove ` - Delete a user\n- `user create-token` - Create a new API token for the authenticated user\n - `--email ` - Specify credentials to use for authentication. This will not be stored. It will only be used to exchange for a token with the API server, which will not be stored either.\n - `--password ` - Specify credentials to use for authentication. This will not be stored. It will only be used to exchange for a token with the API server, which will not be stored either.\n\n### variable\n\nvariable related commands\n\n**Options:**\n- `--json` - Output as JSON (for piping to jq)\n\n**Subcommands:**\n\n- `variable list` - list all variables\n - `--json` - Output as JSON (for piping to jq)\n- `variable get ` - get a variable's details\n - `--json` - Output as JSON (for piping to jq)\n- `variable new ` - create a new variable locally\n- `variable push ` - Push a local variable spec. This overrides any remote versions.\n - `--plain-secrets` - Push secrets as plain text\n- `variable add ` - Create a new variable on the remote. This will update the variable if it already exists.\n - `--plain-secrets` - Push secrets as plain text\n - `--public` - Legacy option, use --plain-secrets instead\n\n### version\n\nShow version information\n\n### worker-groups\n\ndisplay worker groups, pull and push worker groups configs\n\n**Subcommands:**\n\n- `worker-groups pull` - Pull worker groups (similar to `wmill instance pull --skip-users --skip-settings --skip-groups`)\n - `--instance` - Name of the instance to push to, override the active instance\n - `--base-url` - Base url to be passed to the instance settings instead of the local one\n - `--yes` - Pull without needing confirmation\n- `worker-groups push` - Push worker groups (similar to `wmill instance push --skip-users --skip-settings --skip-groups`)\n - `--instance [instance]` - Name of the instance to push to, override the active instance\n - `--base-url [baseUrl]` - If used with --token, will be used as the base url for the instance\n - `--yes` - Push without needing confirmation\n\n### workers\n\nList all workers grouped by worker groups\n\n**Options:**\n- `--instance [instance]` - Name of the instance to push to, override the active instance\n- `--base-url [baseUrl]` - If used with --token, will be used as the base url for the instance\n\n### workspace\n\nworkspace related commands\n\n**Alias:** `profile`\n\n**Subcommands:**\n\n- `workspace switch ` - Switch to another workspace\n- `workspace add [workspace_name:string] [workspace_id:string] [remote:string]` - Add a workspace\n - `-c --create` - Create the workspace if it does not exist\n - `--create-workspace-name ` - Specify the workspace name. Ignored if --create is not specified or the workspace already exists. Will default to the workspace id.\n - `--create-username ` - Specify your own username in the newly created workspace. Ignored if --create is not specified, the workspace already exists or automatic username creation is enabled on the instance.\n- `workspace remove ` - Remove a workspace\n- `workspace whoami` - Show the currently active user\n- `workspace list` - List local workspace profiles\n- `workspace list-remote` - List workspaces on the remote server that you have access to\n- `workspace list-forks` - List forked workspaces on the remote server\n- `workspace bind` - Create or update a workspace entry in wmill.yaml from the active profile\n - `--workspace ` - Workspace name (default: current branch or workspaceId)\n - `--branch ` - Git branch to associate (default: workspace name)\n- `workspace unbind` - Remove baseUrl and workspaceId from a workspace entry\n - `--workspace ` - Workspace to unbind\n- `workspace fork [workspace_name:string] [workspace_id:string]` - Create a forked workspace\n - `--create-workspace-name ` - Specify the workspace name. Ignored if --create is not specified or the workspace already exists. Will default to the workspace id.\n - `--color ` - Workspace color (hex code, e.g. #ff0000)\n - `--datatable-behavior ` - How to handle datatables: skip, schema_only, or schema_and_data (default: interactive prompt)\n - `-y --yes` - Skip interactive prompts (defaults datatable behavior to 'skip')\n- `workspace delete-fork ` - Delete a forked workspace and git branch\n - `-y --yes` - Skip confirmation prompt\n- `workspace merge` - Compare and deploy changes between a fork and its parent workspace\n - `--direction ` - Deploy direction: to-parent or to-fork\n - `--all` - Deploy all changed items including conflicts\n - `--skip-conflicts` - Skip items modified in both workspaces\n - `--include ` - Comma-separated kind:path items to include (e.g. script:f/test/main,flow:f/my/flow)\n - `--exclude ` - Comma-separated kind:path items to exclude\n - `--preserve-on-behalf-of` - Preserve original on_behalf_of/permissioned_as values\n - `-y --yes` - Non-interactive mode (deploy without prompts)\n- `workspace connect-slack` - Non-interactively connect Slack to the active workspace using a pre-minted bot token (xoxb-...). Produces the same artifacts as the UI OAuth flow: workspace_settings fields, g/slack group, f/slack_bot folder, and the encrypted bot token variable + resource at f/slack_bot/bot_token.\n - `--bot-token ` - Slack bot token (xoxb-...)\n - `--team-id ` - Slack team id\n - `--team-name ` - Slack team name\n- `workspace disconnect-slack`\n\n"; +export declare const CLI_COMMANDS = "# Windmill CLI Commands\n\nThe Windmill CLI (`wmill`) provides commands for managing scripts, flows, apps, and other resources.\n\n## Global Options\n\n- `--workspace ` - Specify the target workspace. This overrides the default workspace.\n- `--debug --verbose` - Show debug/verbose logs\n- `--show-diffs` - Show diff informations when syncing (may show sensitive informations)\n- `--token ` - Specify an API token. This will override any stored token.\n- `--base-url ` - Specify the base URL of the API. If used, --token and --workspace are required and no local remote/workspace already set will be used.\n- `--config-dir ` - Specify a custom config directory. Overrides WMILL_CONFIG_DIR environment variable and default ~/.config location.\n\n## Commands\n\n### app\n\napp related commands\n\n**Options:**\n- `--json` - Output as JSON (for piping to jq)\n\n**Subcommands:**\n\n- `app list` - list all apps\n - `--json` - Output as JSON (for piping to jq)\n- `app get ` - get an app's details\n - `--json` - Output as JSON (for piping to jq)\n- `app push [file_path:string] [remote_path:string]` - push a local app. With no args, infers the app from the current directory and the remote path from its location relative to wmill.yaml.\n- `app dev [app_folder:string]` - Start a development server for building apps with live reload and hot module replacement\n - `--port ` - Port to run the dev server on (will find next available port if occupied)\n - `--host ` - Host to bind the dev server to\n - `--entry ` - Entry point file (default: index.ts for Svelte/Vue, index.tsx otherwise)\n - `--no-open` - Don't automatically open the browser\n- `app lint [app_folder:string]` - Lint a raw app folder to validate structure and buildability\n - `--fix` - Attempt to fix common issues (not implemented yet)\n- `app new` - create a new raw app from a template\n - `--summary ` - App summary (short description). Skips the prompt when provided. Triggers non-interactive mode.\n - `--path ` - App path (e.g., f/folder/my_app or u/username/my_app). Skips the prompt when provided. Triggers non-interactive mode.\n - `--framework ` - Framework template: react19 | react18 | svelte5 | vue. Skips the prompt when provided. Triggers non-interactive mode.\n - `--datatable ` - Datatable to wire up. Without this flag in non-interactive mode, no datatable is configured.\n - `--schema ` - Schema to use with --datatable. Created (CREATE SCHEMA IF NOT EXISTS) if it doesn't already exist.\n - `--overwrite` - Overwrite the target directory if it already exists, without prompting.\n - `--no-open-in-desktop` - Do not prompt to open the new app in Claude Desktop.\n- `app generate-agents [app_folder:string]` - regenerate AGENTS.md and DATATABLES.md from remote workspace\n- `app set-permissioned-as ` - Set the on_behalf_of_email for an app (requires admin or wm_deployers group)\n\n### audit\n\nView audit logs (requires admin)\n\n**Subcommands:**\n\n- `audit list` - List audit log entries\n- `audit get ` - Get a specific audit log entry\n - `--json` - Output as JSON (for piping to jq)\n\n### config\n\nShow all available wmill.yaml configuration options\n\n**Options:**\n- `--json` - Output as JSON for programmatic consumption\n\n**Subcommands:**\n\n- `config migrate` - Migrate wmill.yaml from gitBranches/environments to workspaces format\n\n### dependencies\n\nworkspace dependencies related commands\n\n**Alias:** `deps`\n\n**Subcommands:**\n\n- `dependencies push ` - Push workspace dependencies from a local file\n\n### dev\n\nWatch local file changes and live-reload the dev page for preview. Does NOT deploy to the remote workspace \u2014 use wmill sync push for that.\n\n**Options:**\n- `--includes ` - Filter paths given a glob pattern or path\n- `--proxy-port ` - Port for a localhost reverse proxy to the remote Windmill server\n- `--path ` - Watch a specific windmill path (e.g., u/admin/my_script or f/my_flow)\n- `--no-open` - Do not open the browser automatically\n\n### docs\n\nSearch Windmill documentation.\n\n**Arguments:** ``\n\n**Options:**\n- `--json` - Output results as JSON.\n\n### flow\n\nflow related commands\n\n**Options:**\n- `--show-archived` - Enable archived flows in output\n- `--json` - Output as JSON (for piping to jq)\n\n**Subcommands:**\n\n- `flow list` - list all flows\n - `--show-archived` - Enable archived flows in output\n - `--json` - Output as JSON (for piping to jq)\n- `flow get ` - get a flow's details\n - `--json` - Output as JSON (for piping to jq)\n- `flow push ` - push a local flow spec. This overrides any remote versions.\n - `--message ` - Deployment message\n- `flow run ` - run a flow by path.\n - `-d --data ` - Inputs specified as a JSON string or a file using @ or stdin using @-.\n - `-s --silent` - Do not ouput anything other then the final output. Useful for scripting.\n- `flow preview ` - preview a local flow without deploying it. Runs the flow definition from local files and uses local PathScripts by default.\n - `-d --data ` - Inputs specified as a JSON string or a file using @ or stdin using @-.\n - `-s --silent` - Do not output anything other then the final output. Useful for scripting.\n - `--remote` - Use deployed workspace scripts for PathScript steps instead of local files.\n- `flow new ` - create a new empty flow\n - `--summary ` - flow summary\n - `--description ` - flow description\n- `flow bootstrap ` - create a new empty flow (alias for new)\n - `--summary ` - flow summary\n - `--description ` - flow description\n- `flow history ` - Show version history for a flow\n - `--json` - Output as JSON (for piping to jq)\n- `flow show-version ` - Show a specific version of a flow\n - `--json` - Output as JSON (for piping to jq)\n- `flow set-permissioned-as ` - Set the on_behalf_of_email for a flow (requires admin or wm_deployers group)\n\n### folder\n\nfolder related commands\n\n**Options:**\n- `--json` - Output as JSON (for piping to jq)\n\n**Subcommands:**\n\n- `folder list` - list all folders\n - `--json` - Output as JSON (for piping to jq)\n- `folder get ` - get a folder's details\n - `--json` - Output as JSON (for piping to jq)\n- `folder new ` - create a new folder locally\n - `--summary ` - folder summary\n- `folder push ` - push a local folder to the remote by name. This overrides any remote versions.\n- `folder add-missing` - create default folder.meta.yaml for all subdirectories of f/ that are missing one\n - `-y, --yes` - skip confirmation prompt\n- `folder show-rules ` - Show default_permissioned_as rules for a folder. Use --test-path to see which rule matches a given item path.\n - `--test-path ` - Test which rule matches this item path (e.g. f/prod/jobs/my_script)\n - `--json` - Output as JSON\n\n### generate-metadata\n\nGenerate metadata (locks, schemas) for all scripts, flows, and apps\n\n**Arguments:** `[folder:string]`\n\n**Options:**\n- `--yes` - Skip confirmation prompt\n- `--dry-run` - Show what would be updated without making changes\n- `--lock-only` - Re-generate only the lock files\n- `--schema-only` - Re-generate only script schemas (skips flows and apps)\n- `--skip-scripts` - Skip processing scripts\n- `--skip-flows` - Skip processing flows\n- `--skip-apps` - Skip processing apps\n- `--strict-folder-boundaries` - Only update items inside the specified folder (requires folder argument)\n- `--parallel ` - Number of items to process in parallel\n- `-i --includes ` - Comma separated patterns to specify which files to include\n- `-e --excludes ` - Comma separated patterns to specify which files to exclude\n\n**Subcommands:**\n\n- `generate-metadata rehash [folder:string]`\n - `--skip-scripts` - Skip processing scripts\n - `--skip-flows` - Skip processing flows\n - `--skip-apps` - Skip processing apps\n - `--parallel ` - Number of items to process in parallel\n - `-i --includes ` - Comma separated patterns to specify which files to include\n - `-e --excludes ` - Comma separated patterns to specify which files to exclude\n\n### gitsync-settings\n\nManage git-sync settings between local wmill.yaml and Windmill backend\n\n**Subcommands:**\n\n- `gitsync-settings pull` - Pull git-sync settings from Windmill backend to local wmill.yaml\n - `--repository ` - Specify repository path (e.g., u/user/repo)\n - `--default` - Write settings to top-level defaults instead of overrides\n - `--replace` - Replace existing settings (non-interactive mode)\n - `--override` - Add branch-specific override (non-interactive mode)\n - `--diff` - Show differences without applying changes\n - `--json-output` - Output in JSON format\n - `--with-backend-settings ` - Use provided JSON settings instead of querying backend (for testing)\n - `--yes` - Skip interactive prompts and use default behavior\n - `--promotion ` - Use promotionOverrides from the specified branch instead of regular overrides\n- `gitsync-settings push` - Push git-sync settings from local wmill.yaml to Windmill backend\n - `--repository ` - Specify repository path (e.g., u/user/repo)\n - `--diff` - Show what would be pushed without applying changes\n - `--json-output` - Output in JSON format\n - `--with-backend-settings ` - Use provided JSON settings instead of querying backend (for testing)\n - `--yes` - Skip interactive prompts and use default behavior\n - `--promotion ` - Use promotionOverrides from the specified branch instead of regular overrides\n\n### group\n\nManage workspace groups\n\n**Options:**\n- `--json` - Output as JSON (for piping to jq)\n\n**Subcommands:**\n\n- `group list` - List all groups in the workspace\n - `--json` - Output as JSON (for piping to jq)\n- `group get ` - Get group details and members\n - `--json` - Output as JSON (for piping to jq)\n- `group create ` - Create a new group\n - `--summary ` - Group summary/description\n- `group delete ` - Delete a group\n- `group add-user ` - Add a user to a group\n- `group remove-user ` - Remove a user from a group\n\n### hub\n\nHub related commands. EXPERIMENTAL. INTERNAL USE ONLY.\n\n**Subcommands:**\n\n- `hub pull` - pull any supported definitions. EXPERIMENTAL.\n\n### init\n\nBootstrap a windmill project with a wmill.yaml file\n\n**Options:**\n- `--use-default` - Use default settings without checking backend\n- `--use-backend` - Use backend git-sync settings if available\n- `--repository ` - Specify repository path (e.g., u/user/repo) when using backend settings\n- `--bind-profile` - Automatically bind active workspace profile to current Git branch\n- `--no-bind-profile` - Skip workspace profile binding prompt\n\n### instance\n\nsync local with a remote instance or the opposite (push or pull)\n\n**Subcommands:**\n\n- `instance add [instance_name:string] [remote:string] [token:string]` - Add a new instance\n- `instance remove ` - Remove an instance\n- `instance switch ` - Switch the current instance\n- `instance pull` - Pull instance settings, users, configs, instance groups and overwrite local\n - `--yes` - Pull without needing confirmation\n - `--dry-run` - Perform a dry run without making changes\n - `--skip-users` - Skip pulling users\n - `--skip-settings` - Skip pulling settings\n - `--skip-configs` - Skip pulling configs (worker groups)\n - `--skip-groups` - Skip pulling instance groups\n - `--include-workspaces` - Also pull workspaces\n - `--folder-per-instance` - Create a folder per instance\n - `--instance ` - Name of the instance to pull from, override the active instance\n - `--prefix ` - Prefix of the local workspaces to pull, used to create the folders when using --include-workspaces\n - `--prefix-settings` - Store instance yamls inside prefixed folders when using --prefix and --folder-per-instance\n- `instance push` - Push instance settings, users, configs, group and overwrite remote\n - `--yes` - Push without needing confirmation\n - `--dry-run` - Perform a dry run without making changes\n - `--skip-users` - Skip pushing users\n - `--skip-settings` - Skip pushing settings\n - `--skip-configs` - Skip pushing configs (worker groups)\n - `--skip-groups` - Skip pushing instance groups\n - `--include-workspaces` - Also push workspaces\n - `--folder-per-instance` - Create a folder per instance\n - `--instance ` - Name of the instance to push to, override the active instance\n - `--prefix ` - Prefix of the local workspaces folders to push\n - `--prefix-settings` - Store instance yamls inside prefixed folders when using --prefix and --folder-per-instance\n- `instance whoami` - Display information about the currently logged-in user\n- `instance get-config` - Dump the current instance config (global settings + worker configs) as YAML\n - `-o, --output-file ` - Write YAML to a file instead of stdout\n - `--show-secrets` - Include sensitive fields (license key, JWT secret) without prompting\n - `--instance ` - Name of the instance, override the active instance\n- `instance connect-slack`\n - `--bot-token ` - Slack bot token (xoxb-...)\n - `--team-id ` - Slack team id\n - `--team-name ` - Slack team name\n - `--instance ` - Instance profile to connect against (defaults to the active instance)\n\n### job\n\nManage jobs (list, inspect, cancel)\n\n**Subcommands:**\n\n- `job list` - List recent jobs\n- `job get ` - Get job details. For flows: shows step tree with sub-job IDs\n - `--json` - Output as JSON (for piping to jq)\n- `job result ` - Get the result of a completed job (machine-friendly)\n- `job logs ` - Get job logs. For flows: aggregates all step logs\n- `job cancel ` - Cancel a running or queued job\n - `--reason ` - Reason for cancellation\n\n### jobs\n\nPull completed and queued jobs from workspace\n\n**Arguments:** `[workspace:string]`\n\n**Options:**\n- `-c, --completed-output ` - Completed jobs output file (default: completed_jobs.json)\n- `-q, --queued-output ` - Queued jobs output file (default: queued_jobs.json)\n- `--skip-worker-check` - Skip checking for active workers before export\n\n**Subcommands:**\n\n- `jobs pull`\n- `jobs push`\n\n### lint\n\nValidate Windmill flow, schedule, and trigger YAML files in a directory\n\n**Arguments:** `[directory:string]`\n\n**Options:**\n- `--json` - Output results in JSON format\n- `--fail-on-warn` - Exit with code 1 when warnings are emitted\n- `--locks-required` - Fail if scripts or flow inline scripts that need locks have no locks\n- `-w, --watch` - Watch for file changes and re-lint automatically\n\n### queues\n\nList all queues with their metrics\n\n**Arguments:** `[workspace:string] the optional workspace to filter by (default to all workspaces)`\n\n**Options:**\n- `--instance [instance]` - Name of the instance to push to, override the active instance\n- `--base-url [baseUrl]` - If used with --token, will be used as the base url for the instance\n\n### resource\n\nresource related commands\n\n**Options:**\n- `--json` - Output as JSON (for piping to jq)\n\n**Subcommands:**\n\n- `resource list` - list all resources\n - `--json` - Output as JSON (for piping to jq)\n- `resource get ` - get a resource's details\n - `--json` - Output as JSON (for piping to jq)\n- `resource new ` - create a new resource locally\n- `resource push ` - push a local resource spec. This overrides any remote versions.\n\n### resource-type\n\nresource type related commands\n\n**Options:**\n- `--json` - Output as JSON (for piping to jq)\n\n**Subcommands:**\n\n- `resource-type list` - list all resource types\n - `--schema` - Show schema in the output\n - `--json` - Output as JSON (for piping to jq)\n- `resource-type get ` - get a resource type's details\n - `--json` - Output as JSON (for piping to jq)\n- `resource-type new ` - create a new resource type locally\n- `resource-type push ` - push a local resource spec. This overrides any remote versions.\n- `resource-type generate-namespace` - Create a TypeScript definition file with the RT namespace generated from the resource types\n\n### schedule\n\nschedule related commands\n\n**Options:**\n- `--json` - Output as JSON (for piping to jq)\n\n**Subcommands:**\n\n- `schedule list` - list all schedules\n - `--json` - Output as JSON (for piping to jq)\n- `schedule get ` - get a schedule's details\n - `--json` - Output as JSON (for piping to jq)\n- `schedule new ` - create a new schedule locally\n- `schedule push ` - push a local schedule spec. This overrides any remote versions.\n- `schedule enable ` - Enable a schedule\n - `--force` - Bypass the fork-conflict warning when the parent workspace has the same schedule (acknowledges that both crons will fire)\n- `schedule disable ` - Disable a schedule\n- `schedule set-permissioned-as ` - Set the email (run-as user) for a schedule (requires admin or wm_deployers group)\n\n### script\n\nscript related commands\n\n**Options:**\n- `--show-archived` - Show archived scripts instead of active ones\n- `--json` - Output as JSON (for piping to jq)\n\n**Subcommands:**\n\n- `script list` - list all scripts\n - `--show-archived` - Show archived scripts instead of active ones\n - `--json` - Output as JSON (for piping to jq)\n- `script push ` - push a local script spec. This overrides any remote versions. Use the script file (.ts, .js, .py, .sh)\n - `--message ` - Deployment message\n- `script get ` - get a script's details\n - `--json` - Output as JSON (for piping to jq)\n- `script show ` - show a script's content (alias for get)\n- `script run ` - run a script by path\n - `-d --data ` - Inputs specified as a JSON string or a file using @ or stdin using @-.\n - `-s --silent` - Do not output anything other then the final output. Useful for scripting.\n- `script preview ` - preview a local script without deploying it. Supports both regular and codebase scripts.\n - `-d --data ` - Inputs specified as a JSON string or a file using @ or stdin using @-.\n - `-s --silent` - Do not output anything other than the final output. Useful for scripting.\n- `script new ` - create a new script\n - `--summary ` - script summary\n - `--description ` - script description\n- `script bootstrap ` - create a new script (alias for new)\n - `--summary ` - script summary\n - `--description ` - script description\n- `script set-permissioned-as ` - Set the on_behalf_of_email for a script (requires admin or wm_deployers group)\n- `script history ` - show version history for a script\n - `--json` - Output as JSON (for piping to jq)\n\n### sync\n\nsync local with a remote workspaces or the opposite (push or pull)\n\n**Subcommands:**\n\n- `sync pull` - Pull any remote changes and apply them locally.\n - `--yes` - Pull without needing confirmation\n - `--dry-run` - Show changes that would be pulled without actually pushing\n - `--plain-secrets` - Pull secrets as plain text\n - `--json` - Use JSON instead of YAML\n - `--skip-variables` - Skip syncing variables (including secrets)\n - `--skip-secrets` - Skip syncing only secrets variables\n - `--include-secrets` - Include secrets in sync (overrides skipSecrets in wmill.yaml)\n - `--skip-resources` - Skip syncing resources\n - `--skip-resource-types` - Skip syncing resource types\n - `--skip-scripts` - Skip syncing scripts\n - `--skip-flows` - Skip syncing flows\n - `--skip-apps` - Skip syncing apps\n - `--skip-folders` - Skip syncing folders\n - `--skip-workspace-dependencies` - Skip syncing workspace dependencies\n - `--skip-scripts-metadata` - Skip syncing scripts metadata, focus solely on logic\n - `--include-schedules` - Include syncing schedules\n - `--include-triggers` - Include syncing triggers\n - `--include-users` - Include syncing users\n - `--include-groups` - Include syncing groups\n - `--include-settings` - Include syncing workspace settings\n - `--include-key` - Include workspace encryption key\n - `--skip-branch-validation` - Skip git branch validation and prompts\n - `--json-output` - Output results in JSON format\n - `-i --includes ` - Comma separated patterns to specify which file to take into account (among files that are compatible with windmill). Patterns can include * (any string until '/') and ** (any string). Overrides wmill.yaml includes\n - `-e --excludes ` - Comma separated patterns to specify which file to NOT take into account. Overrides wmill.yaml excludes\n - `--extra-includes ` - Comma separated patterns to specify which file to take into account (among files that are compatible with windmill). Patterns can include * (any string until '/') and ** (any string). Useful to still take wmill.yaml into account and act as a second pattern to satisfy\n - `--repository ` - Specify repository path (e.g., u/user/repo) when multiple repositories exist\n - `--promotion ` - Use promotionOverrides from the specified branch instead of regular overrides\n - `--branch, --env ` - [Deprecated: use --workspace] Override the current git branch/environment\n- `sync push` - Push any local changes and apply them remotely.\n - `--yes` - Push without needing confirmation\n - `--dry-run` - Show changes that would be pushed without actually pushing\n - `--plain-secrets` - Push secrets as plain text\n - `--json` - Use JSON instead of YAML\n - `--skip-variables` - Skip syncing variables (including secrets)\n - `--skip-secrets` - Skip syncing only secrets variables\n - `--include-secrets` - Include secrets in sync (overrides skipSecrets in wmill.yaml)\n - `--skip-resources` - Skip syncing resources\n - `--skip-resource-types` - Skip syncing resource types\n - `--skip-scripts` - Skip syncing scripts\n - `--skip-flows` - Skip syncing flows\n - `--skip-apps` - Skip syncing apps\n - `--skip-folders` - Skip syncing folders\n - `--skip-workspace-dependencies` - Skip syncing workspace dependencies\n - `--skip-scripts-metadata` - Skip syncing scripts metadata, focus solely on logic\n - `--include-schedules` - Include syncing schedules\n - `--include-triggers` - Include syncing triggers\n - `--include-users` - Include syncing users\n - `--include-groups` - Include syncing groups\n - `--include-settings` - Include syncing workspace settings\n - `--include-key` - Include workspace encryption key\n - `--skip-branch-validation` - Skip git branch validation and prompts\n - `--json-output` - Output results in JSON format\n - `-i --includes ` - Comma separated patterns to specify which file to take into account (among files that are compatible with windmill). Patterns can include * (any string until '/') and ** (any string)\n - `-e --excludes ` - Comma separated patterns to specify which file to NOT take into account.\n - `--extra-includes ` - Comma separated patterns to specify which file to take into account (among files that are compatible with windmill). Patterns can include * (any string until '/') and ** (any string). Useful to still take wmill.yaml into account and act as a second pattern to satisfy\n - `--message ` - Include a message that will be added to all scripts/flows/apps updated during this push\n - `--parallel ` - Number of changes to process in parallel\n - `--repository ` - Specify repository path (e.g., u/user/repo) when multiple repositories exist\n - `--branch, --env ` - [Deprecated: use --workspace] Override the current git branch/environment\n - `--lint` - Run lint validation before pushing\n - `--locks-required` - Fail if scripts or flow inline scripts that need locks have no locks\n - `--auto-metadata` - Automatically regenerate stale metadata (locks and schemas) before pushing\n - `--accept-overriding-permissioned-as-with-self` - Accept that items with a different permissioned_as will be updated with your own user\n\n### token\n\nManage API tokens\n\n**Options:**\n- `--json` - Output as JSON (for piping to jq)\n\n**Subcommands:**\n\n- `token list` - List API tokens\n - `--json` - Output as JSON (for piping to jq)\n- `token create` - Create a new API token\n - `--label ` - Token label\n - `--expiration ` - Token expiration (ISO 8601 timestamp)\n- `token delete ` - Delete a token by its prefix\n\n### trigger\n\ntrigger related commands\n\n**Options:**\n- `--json` - Output as JSON (for piping to jq)\n\n**Subcommands:**\n\n- `trigger list` - list all triggers\n - `--json` - Output as JSON (for piping to jq)\n- `trigger get ` - get a trigger's details\n - `--json` - Output as JSON (for piping to jq)\n - `--kind ` - Trigger kind (http, websocket, kafka, nats, postgres, mqtt, sqs, gcp, azure, email). Recommended for faster lookup\n- `trigger new ` - create a new trigger locally\n - `--kind ` - Trigger kind (required: http, websocket, kafka, nats, postgres, mqtt, sqs, gcp, azure, email)\n- `trigger push ` - push a local trigger spec. This overrides any remote versions.\n- `trigger set-permissioned-as ` - Set the email (run-as user) for a trigger (requires admin or wm_deployers group)\n - `--kind ` - Trigger kind (required: http, websocket, kafka, nats, postgres, mqtt, sqs, gcp, azure, email)\n\n### user\n\nuser related commands\n\n**Subcommands:**\n\n- `user add [password:string]` - Create a user\n - `--superadmin` - Specify to make the new user superadmin.\n - `--company ` - Specify to set the company of the new user.\n - `--name ` - Specify to set the name of the new user.\n- `user remove ` - Delete a user\n- `user create-token` - Create a new API token for the authenticated user\n - `--email ` - Specify credentials to use for authentication. This will not be stored. It will only be used to exchange for a token with the API server, which will not be stored either.\n - `--password ` - Specify credentials to use for authentication. This will not be stored. It will only be used to exchange for a token with the API server, which will not be stored either.\n\n### variable\n\nvariable related commands\n\n**Options:**\n- `--json` - Output as JSON (for piping to jq)\n\n**Subcommands:**\n\n- `variable list` - list all variables\n - `--json` - Output as JSON (for piping to jq)\n- `variable get ` - get a variable's details\n - `--json` - Output as JSON (for piping to jq)\n- `variable new ` - create a new variable locally\n- `variable push ` - Push a local variable spec. This overrides any remote versions.\n - `--plain-secrets` - Push secrets as plain text\n- `variable add ` - Create a new variable on the remote. This will update the variable if it already exists.\n - `--plain-secrets` - Push secrets as plain text\n - `--public` - Legacy option, use --plain-secrets instead\n\n### version\n\nShow version information\n\n### worker-groups\n\ndisplay worker groups, pull and push worker groups configs\n\n**Subcommands:**\n\n- `worker-groups pull` - Pull worker groups (similar to `wmill instance pull --skip-users --skip-settings --skip-groups`)\n - `--instance` - Name of the instance to push to, override the active instance\n - `--base-url` - Base url to be passed to the instance settings instead of the local one\n - `--yes` - Pull without needing confirmation\n- `worker-groups push` - Push worker groups (similar to `wmill instance push --skip-users --skip-settings --skip-groups`)\n - `--instance [instance]` - Name of the instance to push to, override the active instance\n - `--base-url [baseUrl]` - If used with --token, will be used as the base url for the instance\n - `--yes` - Push without needing confirmation\n\n### workers\n\nList all workers grouped by worker groups\n\n**Options:**\n- `--instance [instance]` - Name of the instance to push to, override the active instance\n- `--base-url [baseUrl]` - If used with --token, will be used as the base url for the instance\n\n### workspace\n\nworkspace related commands\n\n**Alias:** `profile`\n\n**Subcommands:**\n\n- `workspace switch ` - Switch to another workspace\n- `workspace add [workspace_name:string] [workspace_id:string] [remote:string]` - Add a workspace\n - `-c --create` - Create the workspace if it does not exist\n - `--create-workspace-name ` - Specify the workspace name. Ignored if --create is not specified or the workspace already exists. Will default to the workspace id.\n - `--create-username ` - Specify your own username in the newly created workspace. Ignored if --create is not specified, the workspace already exists or automatic username creation is enabled on the instance.\n- `workspace remove ` - Remove a workspace\n- `workspace whoami` - Show the currently active user\n- `workspace list` - List local workspace profiles\n- `workspace list-remote` - List workspaces on the remote server that you have access to\n - `--as-superadmin` - List ALL workspaces on the instance (requires the token to belong to a superadmin/devops user)\n- `workspace list-forks` - List forked workspaces on the remote server\n- `workspace bind` - Create or update a workspace entry in wmill.yaml from the active profile\n - `--workspace ` - Workspace name (default: current branch or workspaceId)\n - `--branch ` - Git branch to associate (default: workspace name)\n- `workspace unbind` - Remove baseUrl and workspaceId from a workspace entry\n - `--workspace ` - Workspace to unbind\n- `workspace fork [workspace_name:string] [workspace_id:string]` - Create a forked workspace\n - `--create-workspace-name ` - Specify the workspace name. Ignored if --create is not specified or the workspace already exists. Will default to the workspace id.\n - `--color ` - Workspace color (hex code, e.g. #ff0000)\n - `--datatable-behavior ` - How to handle datatables: skip, schema_only, or schema_and_data (default: interactive prompt)\n - `-y --yes` - Skip interactive prompts (defaults datatable behavior to 'skip')\n- `workspace delete-fork ` - Delete a forked workspace and git branch\n - `-y --yes` - Skip confirmation prompt\n- `workspace merge` - Compare and deploy changes between a fork and its parent workspace\n - `--direction ` - Deploy direction: to-parent or to-fork\n - `--all` - Deploy all changed items including conflicts\n - `--skip-conflicts` - Skip items modified in both workspaces\n - `--include ` - Comma-separated kind:path items to include (e.g. script:f/test/main,flow:f/my/flow)\n - `--exclude ` - Comma-separated kind:path items to exclude\n - `--preserve-on-behalf-of` - Preserve original on_behalf_of/permissioned_as values\n - `-y --yes` - Non-interactive mode (deploy without prompts)\n- `workspace connect-slack` - Non-interactively connect Slack to the active workspace using a pre-minted bot token (xoxb-...). Produces the same artifacts as the UI OAuth flow: workspace_settings fields, g/slack group, f/slack_bot folder, and the encrypted bot token variable + resource at f/slack_bot/bot_token.\n - `--bot-token ` - Slack bot token (xoxb-...)\n - `--team-id ` - Slack team id\n - `--team-name ` - Slack team name\n- `workspace disconnect-slack`\n\n"; export declare const LANG_BASH = "# Bash\n\n## Structure\n\nDo not include `#!/bin/bash`. Arguments are obtained as positional parameters:\n\n```bash\n# Get arguments\nvar1=\"$1\"\nvar2=\"$2\"\n\necho \"Processing $var1 and $var2\"\n\n# Return JSON by echoing to stdout\necho \"{\\\"result\\\": \\\"$var1\\\", \\\"count\\\": $var2}\"\n```\n\n**Important:**\n- Do not include shebang (`#!/bin/bash`)\n- Arguments are always strings\n- Access with `$1`, `$2`, etc.\n\n## Output\n\nThe script output is captured as the result. For structured data, output valid JSON:\n\n```bash\nname=\"$1\"\ncount=\"$2\"\n\n# Output JSON result\ncat << EOF\n{\n \"name\": \"$name\",\n \"count\": $count,\n \"timestamp\": \"$(date -Iseconds)\"\n}\nEOF\n```\n\n## Environment Variables\n\nEnvironment variables set in Windmill are available:\n\n```bash\n# Access environment variable\necho \"Workspace: $WM_WORKSPACE\"\necho \"Job ID: $WM_JOB_ID\"\n```\n"; -export declare const LANG_BIGQUERY = "# BigQuery\n\nArguments use `@name` syntax.\n\nName the parameters by adding comments before the statement:\n\n```sql\n-- @name1 (string)\n-- @name2 (int64) = 0\nSELECT * FROM users WHERE name = @name1 AND age > @name2;\n```\n"; -export declare const LANG_BUN = "# TypeScript (Bun)\n\nBun runtime with full npm ecosystem and fastest execution.\n\n## Structure\n\nExport a single **async** function called `main`:\n\n```typescript\nexport async function main(param1: string, param2: number) {\n // Your code here\n return { result: param1, count: param2 };\n}\n```\n\nDo not call the main function. Libraries are installed automatically.\n\n## Resource Types\n\nOn Windmill, credentials and configuration are stored in resources and passed as parameters to main.\n\nUse the `RT` namespace for resource types:\n\n```typescript\nexport async function main(stripe: RT.Stripe) {\n // stripe contains API key and config from the resource\n}\n```\n\nOnly use resource types if you need them to satisfy the instructions. Always use the RT namespace.\n\nBefore using a resource type, check the `rt.d.ts` file in the project root to see all available resource types and their fields. This file is generated by `wmill resource-type generate-namespace`.\n\n## Imports\n\n```typescript\nimport Stripe from \"stripe\";\nimport { someFunction } from \"some-package\";\n```\n\n## Windmill Client\n\nImport the windmill client for platform interactions:\n\n```typescript\nimport * as wmill from \"windmill-client\";\n```\n\nSee the SDK documentation for available methods.\n\n## Preprocessor Scripts\n\nFor preprocessor scripts, the function should be named `preprocessor` and receives an `event` parameter:\n\n```typescript\ntype Event = {\n kind:\n | \"webhook\"\n | \"http\"\n | \"websocket\"\n | \"kafka\"\n | \"email\"\n | \"nats\"\n | \"postgres\"\n | \"sqs\"\n | \"mqtt\"\n | \"gcp\";\n body: any;\n headers: Record;\n query: Record;\n};\n\nexport async function preprocessor(event: Event) {\n return {\n param1: event.body.field1,\n param2: event.query.id,\n };\n}\n```\n\n## S3 Object Operations\n\nWindmill provides built-in support for S3-compatible storage operations.\n\n### S3Object Type\n\nThe S3Object type represents a file in S3 storage:\n\n```typescript\ntype S3Object = {\n s3: string; // Path within the bucket\n};\n```\n\n## TypeScript Operations\n\n```typescript\nimport * as wmill from \"windmill-client\";\n\n// Load file content from S3\nconst content: Uint8Array = await wmill.loadS3File(s3object);\n\n// Load file as stream\nconst blob: Blob = await wmill.loadS3FileStream(s3object);\n\n// Write file to S3\nconst result: S3Object = await wmill.writeS3File(\n s3object, // Target path (or undefined to auto-generate)\n fileContent, // string or Blob\n s3ResourcePath // Optional: specific S3 resource to use\n);\n```\n"; -export declare const LANG_BUNNATIVE = "# TypeScript (Bun Native)\n\nNative TypeScript execution with fetch only - no external imports allowed.\n\n## Structure\n\nExport a single **async** function called `main`:\n\n```typescript\nexport async function main(param1: string, param2: number) {\n // Your code here\n return { result: param1, count: param2 };\n}\n```\n\nDo not call the main function.\n\n## Resource Types\n\nOn Windmill, credentials and configuration are stored in resources and passed as parameters to main.\n\nUse the `RT` namespace for resource types:\n\n```typescript\nexport async function main(stripe: RT.Stripe) {\n // stripe contains API key and config from the resource\n}\n```\n\nOnly use resource types if you need them to satisfy the instructions. Always use the RT namespace.\n\nBefore using a resource type, check the `rt.d.ts` file in the project root to see all available resource types and their fields. This file is generated by `wmill resource-type generate-namespace`.\n\n## Imports\n\n**No imports allowed.** Use the globally available `fetch` function:\n\n```typescript\nexport async function main(url: string) {\n const response = await fetch(url);\n return await response.json();\n}\n```\n\n## Windmill Client\n\nThe windmill client is not available in native TypeScript mode. Use fetch to call APIs directly.\n\n## Preprocessor Scripts\n\nFor preprocessor scripts, the function should be named `preprocessor` and receives an `event` parameter:\n\n```typescript\ntype Event = {\n kind:\n | \"webhook\"\n | \"http\"\n | \"websocket\"\n | \"kafka\"\n | \"email\"\n | \"nats\"\n | \"postgres\"\n | \"sqs\"\n | \"mqtt\"\n | \"gcp\";\n body: any;\n headers: Record;\n query: Record;\n};\n\nexport async function preprocessor(event: Event) {\n return {\n param1: event.body.field1,\n param2: event.query.id,\n };\n}\n```\n\n## S3 Object Operations\n\nWindmill provides built-in support for S3-compatible storage operations.\n\n### S3Object Type\n\nThe S3Object type represents a file in S3 storage:\n\n```typescript\ntype S3Object = {\n s3: string; // Path within the bucket\n};\n```\n\n## TypeScript Operations\n\n```typescript\nimport * as wmill from \"windmill-client\";\n\n// Load file content from S3\nconst content: Uint8Array = await wmill.loadS3File(s3object);\n\n// Load file as stream\nconst blob: Blob = await wmill.loadS3FileStream(s3object);\n\n// Write file to S3\nconst result: S3Object = await wmill.writeS3File(\n s3object, // Target path (or undefined to auto-generate)\n fileContent, // string or Blob\n s3ResourcePath // Optional: specific S3 resource to use\n);\n```\n"; +export declare const LANG_BIGQUERY = "# BigQuery\n\nArguments use `@name` syntax.\n\nName the parameters by adding comments before the statement:\n\n```sql\n-- @name1 (string)\n-- @name2 (int64) = 0\nSELECT * FROM users WHERE name = @name1 AND age > @name2;\n```\n\n## Receiving an S3Object as a script parameter\n\nDeclare the arg with type `(s3object)`. Windmill renders an S3 file picker for\nit, downloads the file, and binds it as a `STRING` JSON parameter \u2014 Parquet/CSV\nfiles are decoded server-side into a JSON array of records, JSON/JSONL pass\nthrough. Consume with `JSON_EXTRACT_ARRAY` / `JSON_VALUE`:\n\n```sql\n-- @file (s3object)\nSELECT\n CAST(JSON_VALUE(row, '$.id') AS INT64) AS id,\n JSON_VALUE(row, '$.name') AS name\nFROM UNNEST(JSON_EXTRACT_ARRAY(@file)) AS row;\n```\n\n## Streaming query results to S3\n\nAdd a `-- s3` directive at the top of the script to stream the result set to S3\ninstead of returning rows. Windmill writes the file and returns its `S3Object`\nas the script result.\n\n```sql\n-- s3 prefix=exports/users format=parquet\nSELECT id, name FROM users;\n```\n\nAll keys are optional: `prefix` (object key prefix), `storage` (named storage \u2014\nomit to use the workspace default), `format` (`json` (default), `parquet`, or\n`csv`). Use this for large result sets \u2014 rows stream directly to S3 instead of\nbeing buffered, bypassing the 10000-row return cap.\n"; +export declare const LANG_BUN = "# TypeScript (Bun)\n\nBun runtime with full npm ecosystem and fastest execution.\n\n## Structure\n\nExport a single **async** function called `main`:\n\n```typescript\nexport async function main(param1: string, param2: number) {\n // Your code here\n return { result: param1, count: param2 };\n}\n```\n\nDo not call the main function. Libraries are installed automatically.\n\n## Resource Types\n\nOn Windmill, credentials and configuration are stored in resources and passed as parameters to main.\n\nUse the `RT` namespace for resource types:\n\n```typescript\nexport async function main(stripe: RT.Stripe) {\n // stripe contains API key and config from the resource\n}\n```\n\nOnly use resource types if you need them to satisfy the instructions. Always use the RT namespace.\n\nBefore using a resource type, check the `rt.d.ts` file in the project root to see all available resource types and their fields. This file is generated by `wmill resource-type generate-namespace`.\n\n## Imports\n\n```typescript\nimport Stripe from \"stripe\";\nimport { someFunction } from \"some-package\";\n```\n\n## Windmill Client\n\nImport the windmill client for platform interactions:\n\n```typescript\nimport * as wmill from \"windmill-client\";\n```\n\nSee the SDK documentation for available methods.\n\n## Preprocessor Scripts\n\nFor preprocessor scripts, the function should be named `preprocessor` and receives an `event` parameter:\n\n```typescript\ntype Event = {\n kind:\n | \"webhook\"\n | \"http\"\n | \"websocket\"\n | \"kafka\"\n | \"email\"\n | \"nats\"\n | \"postgres\"\n | \"sqs\"\n | \"mqtt\"\n | \"gcp\";\n body: any;\n headers: Record;\n query: Record;\n};\n\nexport async function preprocessor(event: Event) {\n return {\n param1: event.body.field1,\n param2: event.query.id,\n };\n}\n```\n\n## S3 Object Operations\n\nWindmill provides built-in support for S3-compatible storage operations. The `wmill.S3Object` type covers both the `s3://storage/key` URI form (`s3:///key` for the workspace default storage) and the `{ s3, storage? }` record form \u2014 always use it instead of redefining your own.\n\n### Receiving an S3Object as a script parameter\n\n```typescript\nimport * as wmill from \"windmill-client\";\n\nexport async function main(file: wmill.S3Object) {\n const content = await wmill.loadS3File(file);\n // ...\n}\n```\n\n### S3 operations\n\n```typescript\nimport * as wmill from \"windmill-client\";\n\n// Load file content from S3\nconst content: Uint8Array = await wmill.loadS3File(s3object);\n\n// Load file as stream\nconst blob: Blob = await wmill.loadS3FileStream(s3object);\n\n// Write file to S3\nconst result: wmill.S3Object = await wmill.writeS3File(\n s3object, // Target path (or undefined to auto-generate)\n fileContent, // string or Blob\n s3ResourcePath // Optional: specific S3 resource to use\n);\n```\n"; +export declare const LANG_BUNNATIVE = "# TypeScript (Bun Native)\n\nNative TypeScript execution with fetch only - no external imports allowed.\n\n## Structure\n\nExport a single **async** function called `main`:\n\n```typescript\nexport async function main(param1: string, param2: number) {\n // Your code here\n return { result: param1, count: param2 };\n}\n```\n\nDo not call the main function.\n\n## Resource Types\n\nOn Windmill, credentials and configuration are stored in resources and passed as parameters to main.\n\nUse the `RT` namespace for resource types:\n\n```typescript\nexport async function main(stripe: RT.Stripe) {\n // stripe contains API key and config from the resource\n}\n```\n\nOnly use resource types if you need them to satisfy the instructions. Always use the RT namespace.\n\nBefore using a resource type, check the `rt.d.ts` file in the project root to see all available resource types and their fields. This file is generated by `wmill resource-type generate-namespace`.\n\n## Imports\n\n**No imports allowed.** Use the globally available `fetch` function:\n\n```typescript\nexport async function main(url: string) {\n const response = await fetch(url);\n return await response.json();\n}\n```\n\n## Windmill Client\n\nThe windmill client is not available in native TypeScript mode. Use fetch to call APIs directly.\n\n## Preprocessor Scripts\n\nFor preprocessor scripts, the function should be named `preprocessor` and receives an `event` parameter:\n\n```typescript\ntype Event = {\n kind:\n | \"webhook\"\n | \"http\"\n | \"websocket\"\n | \"kafka\"\n | \"email\"\n | \"nats\"\n | \"postgres\"\n | \"sqs\"\n | \"mqtt\"\n | \"gcp\";\n body: any;\n headers: Record;\n query: Record;\n};\n\nexport async function preprocessor(event: Event) {\n return {\n param1: event.body.field1,\n param2: event.query.id,\n };\n}\n```\n\n## S3 Object Operations\n\nWindmill provides built-in support for S3-compatible storage operations. The `wmill.S3Object` type covers both the `s3://storage/key` URI form (`s3:///key` for the workspace default storage) and the `{ s3, storage? }` record form \u2014 always use it instead of redefining your own.\n\n### Receiving an S3Object as a script parameter\n\n```typescript\nimport * as wmill from \"windmill-client\";\n\nexport async function main(file: wmill.S3Object) {\n const content = await wmill.loadS3File(file);\n // ...\n}\n```\n\n### S3 operations\n\n```typescript\nimport * as wmill from \"windmill-client\";\n\n// Load file content from S3\nconst content: Uint8Array = await wmill.loadS3File(s3object);\n\n// Load file as stream\nconst blob: Blob = await wmill.loadS3FileStream(s3object);\n\n// Write file to S3\nconst result: wmill.S3Object = await wmill.writeS3File(\n s3object, // Target path (or undefined to auto-generate)\n fileContent, // string or Blob\n s3ResourcePath // Optional: specific S3 resource to use\n);\n```\n"; export declare const LANG_CSHARP = "# C#\n\nThe script must contain a public static `Main` method inside a class:\n\n```csharp\npublic class Script\n{\n public static object Main(string name, int count)\n {\n return new { Name = name, Count = count };\n }\n}\n```\n\n**Important:**\n- Class name is irrelevant\n- Method must be `public static`\n- Return type can be `object` or specific type\n\n## NuGet Packages\n\nAdd packages using the `#r` directive at the top:\n\n```csharp\n#r \"nuget: Newtonsoft.Json, 13.0.3\"\n#r \"nuget: RestSharp, 110.2.0\"\n\nusing Newtonsoft.Json;\nusing RestSharp;\n\npublic class Script\n{\n public static object Main(string url)\n {\n var client = new RestClient(url);\n var request = new RestRequest();\n var response = client.Get(request);\n return JsonConvert.DeserializeObject(response.Content);\n }\n}\n```\n"; -export declare const LANG_DENO = "# TypeScript (Deno)\n\nDeno runtime with npm support via `npm:` prefix and native Deno libraries.\n\n## Structure\n\nExport a single **async** function called `main`:\n\n```typescript\nexport async function main(param1: string, param2: number) {\n // Your code here\n return { result: param1, count: param2 };\n}\n```\n\nDo not call the main function. Libraries are installed automatically.\n\n## Resource Types\n\nOn Windmill, credentials and configuration are stored in resources and passed as parameters to main.\n\nUse the `RT` namespace for resource types:\n\n```typescript\nexport async function main(stripe: RT.Stripe) {\n // stripe contains API key and config from the resource\n}\n```\n\nOnly use resource types if you need them to satisfy the instructions. Always use the RT namespace.\n\nBefore using a resource type, check the `rt.d.ts` file in the project root to see all available resource types and their fields. This file is generated by `wmill resource-type generate-namespace`.\n\n## Imports\n\n```typescript\n// npm packages use npm: prefix\nimport Stripe from \"npm:stripe\";\nimport { someFunction } from \"npm:some-package\";\n\n// Deno standard library\nimport { serve } from \"https://deno.land/std/http/server.ts\";\n```\n\n## Windmill Client\n\nImport the windmill client for platform interactions:\n\n```typescript\nimport * as wmill from \"windmill-client\";\n```\n\nSee the SDK documentation for available methods.\n\n## Preprocessor Scripts\n\nFor preprocessor scripts, the function should be named `preprocessor` and receives an `event` parameter:\n\n```typescript\ntype Event = {\n kind:\n | \"webhook\"\n | \"http\"\n | \"websocket\"\n | \"kafka\"\n | \"email\"\n | \"nats\"\n | \"postgres\"\n | \"sqs\"\n | \"mqtt\"\n | \"gcp\";\n body: any;\n headers: Record;\n query: Record;\n};\n\nexport async function preprocessor(event: Event) {\n return {\n param1: event.body.field1,\n param2: event.query.id,\n };\n}\n```\n\n## S3 Object Operations\n\nWindmill provides built-in support for S3-compatible storage operations.\n\n### S3Object Type\n\nThe S3Object type represents a file in S3 storage:\n\n```typescript\ntype S3Object = {\n s3: string; // Path within the bucket\n};\n```\n\n## TypeScript Operations\n\n```typescript\nimport * as wmill from \"windmill-client\";\n\n// Load file content from S3\nconst content: Uint8Array = await wmill.loadS3File(s3object);\n\n// Load file as stream\nconst blob: Blob = await wmill.loadS3FileStream(s3object);\n\n// Write file to S3\nconst result: S3Object = await wmill.writeS3File(\n s3object, // Target path (or undefined to auto-generate)\n fileContent, // string or Blob\n s3ResourcePath // Optional: specific S3 resource to use\n);\n```\n"; -export declare const LANG_DUCKDB = "# DuckDB\n\nArguments are defined with comments and used with `$name` syntax:\n\n```sql\n-- $name (text) = default\n-- $age (integer)\nSELECT * FROM users WHERE name = $name AND age > $age;\n```\n\n## Ducklake Integration\n\nAttach Ducklake for data lake operations:\n\n```sql\n-- Main ducklake\nATTACH 'ducklake' AS dl;\n\n-- Named ducklake\nATTACH 'ducklake://my_lake' AS dl;\n\n-- Then query\nSELECT * FROM dl.schema.table;\n```\n\n## External Database Connections\n\nConnect to external databases using resources:\n\n```sql\nATTACH '$res:path/to/resource' AS db (TYPE postgres);\nSELECT * FROM db.schema.table;\n```\n\n## S3 File Operations\n\nRead files from S3 storage:\n\n```sql\n-- Default storage\nSELECT * FROM read_csv('s3:///path/to/file.csv');\n\n-- Named storage\nSELECT * FROM read_csv('s3://storage_name/path/to/file.csv');\n\n-- Parquet files\nSELECT * FROM read_parquet('s3:///path/to/file.parquet');\n\n-- JSON files\nSELECT * FROM read_json('s3:///path/to/file.json');\n```\n"; +export declare const LANG_DENO = "# TypeScript (Deno)\n\nDeno runtime with npm support via `npm:` prefix and native Deno libraries.\n\n## Structure\n\nExport a single **async** function called `main`:\n\n```typescript\nexport async function main(param1: string, param2: number) {\n // Your code here\n return { result: param1, count: param2 };\n}\n```\n\nDo not call the main function. Libraries are installed automatically.\n\n## Resource Types\n\nOn Windmill, credentials and configuration are stored in resources and passed as parameters to main.\n\nUse the `RT` namespace for resource types:\n\n```typescript\nexport async function main(stripe: RT.Stripe) {\n // stripe contains API key and config from the resource\n}\n```\n\nOnly use resource types if you need them to satisfy the instructions. Always use the RT namespace.\n\nBefore using a resource type, check the `rt.d.ts` file in the project root to see all available resource types and their fields. This file is generated by `wmill resource-type generate-namespace`.\n\n## Imports\n\n```typescript\n// npm packages use npm: prefix\nimport Stripe from \"npm:stripe\";\nimport { someFunction } from \"npm:some-package\";\n\n// Deno standard library\nimport { serve } from \"https://deno.land/std/http/server.ts\";\n```\n\n## Windmill Client\n\nImport the windmill client for platform interactions:\n\n```typescript\nimport * as wmill from \"windmill-client\";\n```\n\nSee the SDK documentation for available methods.\n\n## Preprocessor Scripts\n\nFor preprocessor scripts, the function should be named `preprocessor` and receives an `event` parameter:\n\n```typescript\ntype Event = {\n kind:\n | \"webhook\"\n | \"http\"\n | \"websocket\"\n | \"kafka\"\n | \"email\"\n | \"nats\"\n | \"postgres\"\n | \"sqs\"\n | \"mqtt\"\n | \"gcp\";\n body: any;\n headers: Record;\n query: Record;\n};\n\nexport async function preprocessor(event: Event) {\n return {\n param1: event.body.field1,\n param2: event.query.id,\n };\n}\n```\n\n## S3 Object Operations\n\nWindmill provides built-in support for S3-compatible storage operations. The `wmill.S3Object` type covers both the `s3://storage/key` URI form (`s3:///key` for the workspace default storage) and the `{ s3, storage? }` record form \u2014 always use it instead of redefining your own.\n\n### Receiving an S3Object as a script parameter\n\n```typescript\nimport * as wmill from \"windmill-client\";\n\nexport async function main(file: wmill.S3Object) {\n const content = await wmill.loadS3File(file);\n // ...\n}\n```\n\n### S3 operations\n\n```typescript\nimport * as wmill from \"windmill-client\";\n\n// Load file content from S3\nconst content: Uint8Array = await wmill.loadS3File(s3object);\n\n// Load file as stream\nconst blob: Blob = await wmill.loadS3FileStream(s3object);\n\n// Write file to S3\nconst result: wmill.S3Object = await wmill.writeS3File(\n s3object, // Target path (or undefined to auto-generate)\n fileContent, // string or Blob\n s3ResourcePath // Optional: specific S3 resource to use\n);\n```\n"; +export declare const LANG_DUCKDB = "# DuckDB\n\nArguments are defined with comments and used with `$name` syntax:\n\n```sql\n-- $name (text) = default\n-- $age (integer)\nSELECT * FROM users WHERE name = $name AND age > $age;\n```\n\n## Ducklake Integration\n\nAttach Ducklake for data lake operations:\n\n```sql\n-- Main ducklake\nATTACH 'ducklake' AS dl;\n\n-- Named ducklake\nATTACH 'ducklake://my_lake' AS dl;\n\n-- Then query\nSELECT * FROM dl.schema.table;\n```\n\n## External Database Connections\n\nConnect to external databases using resources:\n\n```sql\nATTACH '$res:path/to/resource' AS db (TYPE postgres);\nSELECT * FROM db.schema.table;\n```\n\n## S3 File Operations\n\nRead files from S3 storage:\n\n```sql\n-- Default storage\nSELECT * FROM read_csv('s3:///path/to/file.csv');\n\n-- Named storage\nSELECT * FROM read_csv('s3://storage_name/path/to/file.csv');\n\n-- Parquet files\nSELECT * FROM read_parquet('s3:///path/to/file.parquet');\n\n-- JSON files\nSELECT * FROM read_json('s3:///path/to/file.json');\n```\n\n### Receiving an S3Object as a script parameter\n\nDeclare the arg with type `(s3object)`. Windmill renders an S3 file picker for it\nand binds the arg as the bare `s3://storage/key` URI, which DuckDB's reader\nfunctions consume directly:\n\n```sql\n-- $file (s3object)\nSELECT * FROM read_parquet($file);\n```\n\nWorks with any DuckDB reader: `read_csv($file)`, `read_json($file)`, etc.\n\n### Writing query results to S3\n\nDuckDB writes to S3 natively via `COPY ... TO`:\n\n```sql\nCOPY (SELECT * FROM users) TO 's3:///exports/users.parquet' (FORMAT PARQUET);\n```\n\nUse this instead of the `-- s3` streaming directive supported by the other SQL\ndialects \u2014 that directive is not available in DuckDB.\n"; export declare const LANG_GO = "# Go\n\n## Structure\n\nThe file package must be `inner` and export a function called `main`:\n\n```go\npackage inner\n\nfunc main(param1 string, param2 int) (map[string]interface{}, error) {\n return map[string]interface{}{\n \"result\": param1,\n \"count\": param2,\n }, nil\n}\n```\n\n**Important:**\n- Package must be `inner`\n- Return type must be `({return_type}, error)`\n- Function name is `main` (lowercase)\n\n## Return Types\n\nThe return type can be any Go type that can be serialized to JSON:\n\n```go\npackage inner\n\ntype Result struct {\n Name string `json:\"name\"`\n Count int `json:\"count\"`\n}\n\nfunc main(name string, count int) (Result, error) {\n return Result{\n Name: name,\n Count: count,\n }, nil\n}\n```\n\n## Error Handling\n\nReturn errors as the second return value:\n\n```go\npackage inner\n\nimport \"errors\"\n\nfunc main(value int) (string, error) {\n if value < 0 {\n return \"\", errors.New(\"value must be positive\")\n }\n return \"success\", nil\n}\n```\n"; export declare const LANG_GRAPHQL = "# GraphQL\n\n## Structure\n\nWrite GraphQL queries or mutations. Arguments can be added as query parameters:\n\n```graphql\nquery GetUser($id: ID!) {\n user(id: $id) {\n id\n name\n email\n }\n}\n```\n\n## Variables\n\nVariables are passed as script arguments and automatically bound to the query:\n\n```graphql\nquery SearchProducts($query: String!, $limit: Int = 10) {\n products(search: $query, first: $limit) {\n edges {\n node {\n id\n name\n price\n }\n }\n }\n}\n```\n\n## Mutations\n\n```graphql\nmutation CreateUser($input: CreateUserInput!) {\n createUser(input: $input) {\n id\n name\n createdAt\n }\n}\n```\n"; export declare const LANG_JAVA = "# Java\n\nThe script must contain a Main public class with a `public static main()` method:\n\n```java\npublic class Main {\n public static Object main(String name, int count) {\n java.util.Map result = new java.util.HashMap<>();\n result.put(\"name\", name);\n result.put(\"count\", count);\n return result;\n }\n}\n```\n\n**Important:**\n- Class must be named `Main`\n- Method must be `public static Object main(...)`\n- Return type is `Object` or `void`\n\n## Maven Dependencies\n\nAdd dependencies using comments at the top:\n\n```java\n//requirements:\n//com.google.code.gson:gson:2.10.1\n//org.apache.httpcomponents:httpclient:4.5.14\n\nimport com.google.gson.Gson;\n\npublic class Main {\n public static Object main(String input) {\n Gson gson = new Gson();\n return gson.fromJson(input, Object.class);\n }\n}\n```\n"; -export declare const LANG_MSSQL = "# Microsoft SQL Server (MSSQL)\n\nArguments use `@P1`, `@P2`, etc.\n\nName the parameters by adding comments before the statement:\n\n```sql\n-- @P1 name1 (varchar)\n-- @P2 name2 (int) = 0\nSELECT * FROM users WHERE name = @P1 AND age > @P2;\n```\n"; -export declare const LANG_MYSQL = "# MySQL\n\nArguments use `?` placeholders.\n\nName the parameters by adding comments before the statement:\n\n```sql\n-- ? name1 (text)\n-- ? name2 (int) = 0\nSELECT * FROM users WHERE name = ? AND age > ?;\n```\n"; +export declare const LANG_MSSQL = "# Microsoft SQL Server (MSSQL)\n\nArguments use `@P1`, `@P2`, etc.\n\nName the parameters by adding comments before the statement:\n\n```sql\n-- @P1 name1 (varchar)\n-- @P2 name2 (int) = 0\nSELECT * FROM users WHERE name = @P1 AND age > @P2;\n```\n\n## Receiving an S3Object as a script parameter\n\nDeclare the arg with type `(s3object)`. Windmill renders an S3 file picker for\nit, downloads the file, and binds it as `nvarchar(max)` JSON text \u2014 Parquet/CSV\nfiles are decoded server-side into a JSON array of records, JSON/JSONL pass\nthrough. Consume with `OPENJSON`:\n\n```sql\n-- @P1 file (s3object)\nSELECT id, name\nFROM OPENJSON(@P1)\nWITH (id INT, name NVARCHAR(200));\n```\n\n## Streaming query results to S3\n\nAdd a `-- s3` directive at the top of the script to stream the result set to S3\ninstead of returning rows. Windmill writes the file and returns its `S3Object`\nas the script result.\n\n```sql\n-- s3 prefix=exports/users format=parquet\nSELECT id, name FROM users;\n```\n\nAll keys are optional: `prefix` (object key prefix), `storage` (named storage \u2014\nomit to use the workspace default), `format` (`json` (default), `parquet`, or\n`csv`). Use this for large result sets \u2014 rows stream directly to S3 instead of\nbeing buffered as the script return value.\n"; +export declare const LANG_MYSQL = "# MySQL\n\nArguments use `?` placeholders.\n\nName the parameters by adding comments before the statement:\n\n```sql\n-- ? name1 (text)\n-- ? name2 (int) = 0\nSELECT * FROM users WHERE name = ? AND age > ?;\n```\n\n## Receiving an S3Object as a script parameter\n\nDeclare the arg with type `(s3object)`. Windmill renders an S3 file picker for\nit, downloads the file, and binds it as JSON text \u2014 Parquet/CSV files are\ndecoded server-side into a JSON array of records, JSON/JSONL pass through.\nConsume with `JSON_TABLE`:\n\n```sql\n-- ? file (s3object)\nSELECT id, name\nFROM JSON_TABLE(?, '$[*]'\n COLUMNS (id INT PATH '$.id', name VARCHAR(200) PATH '$.name')\n) AS r;\n```\n\n## Streaming query results to S3\n\nAdd a `-- s3` directive at the top of the script to stream the result set to S3\ninstead of returning rows. Windmill writes the file and returns its `S3Object`\nas the script result.\n\n```sql\n-- s3 prefix=exports/users format=parquet\nSELECT id, name FROM users;\n```\n\nAll keys are optional: `prefix` (object key prefix), `storage` (named storage \u2014\nomit to use the workspace default), `format` (`json` (default), `parquet`, or\n`csv`). Use this for large result sets \u2014 rows stream directly to S3 instead of\nbeing buffered as the script return value.\n"; export declare const LANG_NATIVETS = "# TypeScript (Native)\n\nNative TypeScript execution with fetch only - no external imports allowed.\n\n## Structure\n\nExport a single **async** function called `main`:\n\n```typescript\nexport async function main(param1: string, param2: number) {\n // Your code here\n return { result: param1, count: param2 };\n}\n```\n\nDo not call the main function.\n\n## Resource Types\n\nOn Windmill, credentials and configuration are stored in resources and passed as parameters to main.\n\nUse the `RT` namespace for resource types:\n\n```typescript\nexport async function main(stripe: RT.Stripe) {\n // stripe contains API key and config from the resource\n}\n```\n\nOnly use resource types if you need them to satisfy the instructions. Always use the RT namespace.\n\nBefore using a resource type, check the `rt.d.ts` file in the project root to see all available resource types and their fields. This file is generated by `wmill resource-type generate-namespace`.\n\n## Imports\n\n**No imports allowed.** Use the globally available `fetch` function:\n\n```typescript\nexport async function main(url: string) {\n const response = await fetch(url);\n return await response.json();\n}\n```\n\n## Windmill Client\n\nThe windmill client is not available in native TypeScript mode. Use fetch to call APIs directly.\n\n## Preprocessor Scripts\n\nFor preprocessor scripts, the function should be named `preprocessor` and receives an `event` parameter:\n\n```typescript\ntype Event = {\n kind:\n | \"webhook\"\n | \"http\"\n | \"websocket\"\n | \"kafka\"\n | \"email\"\n | \"nats\"\n | \"postgres\"\n | \"sqs\"\n | \"mqtt\"\n | \"gcp\";\n body: any;\n headers: Record;\n query: Record;\n};\n\nexport async function preprocessor(event: Event) {\n return {\n param1: event.body.field1,\n param2: event.query.id\n };\n}\n```\n"; export declare const LANG_PHP = "# PHP\n\n## Structure\n\nThe script must start with ` $param1, \"count\" => $param2];\n}\n```\n\n## Resource Types\n\nOn Windmill, credentials and configuration are stored in resources and passed as parameters to main.\n\nYou need to **redefine** the type of the resources that are needed before the main function. Always check if the class already exists using `class_exists`:\n\n```php\n $2::INT;\n```\n"; +export declare const LANG_POSTGRESQL = "# PostgreSQL\n\nArguments are obtained directly in the statement with `$1::{type}`, `$2::{type}`, etc.\n\nName the parameters by adding comments at the beginning of the script (without specifying the type):\n\n```sql\n-- $1 name1\n-- $2 name2 = default_value\nSELECT * FROM users WHERE name = $1::TEXT AND age > $2::INT;\n```\n\n## Receiving an S3Object as a script parameter\n\nDeclare the arg with type `(s3object)`. Windmill renders an S3 file picker for\nit, downloads the file, and binds it as a `jsonb` parameter \u2014 Parquet/CSV files\nare decoded server-side into a JSON array of records, JSON/JSONL pass through.\nConsume with `jsonb_to_recordset` (or any `jsonb` API):\n\n```sql\n-- $1 file (s3object)\nSELECT *\nFROM jsonb_to_recordset($1::jsonb) AS r(id INT, name TEXT);\n```\n\n## Streaming query results to S3\n\nAdd a `-- s3` directive at the top of the script to stream the result set to S3\ninstead of returning rows. Windmill writes the file and returns its `S3Object`\nas the script result.\n\n```sql\n-- s3 prefix=exports/users format=parquet\nSELECT id, name FROM users;\n```\n\nAll keys are optional: `prefix` (object key prefix), `storage` (named storage \u2014\nomit to use the workspace default), `format` (`json` (default), `parquet`, or\n`csv`). Use this for large result sets \u2014 rows stream directly to S3 instead of\nbeing buffered as the script return value.\n"; export declare const LANG_POWERSHELL = "# PowerShell\n\n## Structure\n\nArguments are obtained by calling the `param` function on the first line:\n\n```powershell\nparam($Name, $Count = 0, [int]$Age)\n\n# Your code here\nWrite-Output \"Processing $Name, count: $Count, age: $Age\"\n\n# Return object\n@{\n name = $Name\n count = $Count\n age = $Age\n}\n```\n\n## Parameter Types\n\nYou can specify types for parameters:\n\n```powershell\nparam(\n [string]$Name,\n [int]$Count = 0,\n [bool]$Enabled = $true,\n [array]$Items\n)\n\n@{\n name = $Name\n count = $Count\n enabled = $Enabled\n items = $Items\n}\n```\n\n## Return Values\n\nReturn values by outputting them at the end of the script:\n\n```powershell\nparam($Input)\n\n$result = @{\n processed = $true\n data = $Input\n timestamp = Get-Date -Format \"o\"\n}\n\n$result\n```\n"; -export declare const LANG_PYTHON3 = "# Python\n\n## Structure\n\nThe script must contain at least one function called `main`:\n\n```python\ndef main(param1: str, param2: int):\n # Your code here\n return {\"result\": param1, \"count\": param2}\n```\n\nDo not call the main function. Libraries are installed automatically.\n\n## Resource Types\n\nOn Windmill, credentials and configuration are stored in resources and passed as parameters to main.\n\nYou need to **redefine** the type of the resources that are needed before the main function as TypedDict:\n\n```python\nfrom typing import TypedDict\n\nclass postgresql(TypedDict):\n host: str\n port: int\n user: str\n password: str\n dbname: str\n\ndef main(db: postgresql):\n # db contains the database connection details\n pass\n```\n\n**Important rules:**\n\n- The resource type name must be **IN LOWERCASE**\n- Only include resource types if they are actually needed\n- If an import conflicts with a resource type name, **rename the imported object, not the type name**\n- Make sure to import TypedDict from typing **if you're using it**\n\n## Imports\n\nLibraries are installed automatically. Do not show installation instructions.\n\n```python\nimport requests\nimport pandas as pd\nfrom datetime import datetime\n```\n\nIf an import name conflicts with a resource type:\n\n```python\n# Wrong - don't rename the type\nimport stripe as stripe_lib\nclass stripe_type(TypedDict): ...\n\n# Correct - rename the import\nimport stripe as stripe_sdk\nclass stripe(TypedDict):\n api_key: str\n```\n\n## Windmill Client\n\nImport the windmill client for platform interactions:\n\n```python\nimport wmill\n```\n\nSee the SDK documentation for available methods.\n\n## Preprocessor Scripts\n\nFor preprocessor scripts, the function should be named `preprocessor` and receives an `event` parameter:\n\n```python\nfrom typing import TypedDict, Literal, Any\n\nclass Event(TypedDict):\n kind: Literal[\"webhook\", \"http\", \"websocket\", \"kafka\", \"email\", \"nats\", \"postgres\", \"sqs\", \"mqtt\", \"gcp\"]\n body: Any\n headers: dict[str, str]\n query: dict[str, str]\n\ndef preprocessor(event: Event):\n # Transform the event into flow input parameters\n return {\n \"param1\": event[\"body\"][\"field1\"],\n \"param2\": event[\"query\"][\"id\"]\n }\n```\n\n## S3 Object Operations\n\nWindmill provides built-in support for S3-compatible storage operations.\n\n```python\nimport wmill\n\n# Load file content from S3\ncontent: bytes = wmill.load_s3_file(s3object)\n\n# Load file as stream reader\nreader: BufferedReader = wmill.load_s3_file_reader(s3object)\n\n# Write file to S3\nresult: S3Object = wmill.write_s3_file(\n s3object, # Target path (or None to auto-generate)\n file_content, # bytes or BufferedReader\n s3_resource_path, # Optional: specific S3 resource\n content_type, # Optional: MIME type\n content_disposition # Optional: Content-Disposition header\n)\n```\n"; +export declare const LANG_PYTHON3 = "# Python\n\n## Structure\n\nThe script must contain at least one function called `main`:\n\n```python\ndef main(param1: str, param2: int):\n # Your code here\n return {\"result\": param1, \"count\": param2}\n```\n\nDo not call the main function. Libraries are installed automatically.\n\n## Resource Types\n\nOn Windmill, credentials and configuration are stored in resources and passed as parameters to main.\n\nYou need to **redefine** the type of the resources that are needed before the main function as TypedDict:\n\n```python\nfrom typing import TypedDict\n\nclass postgresql(TypedDict):\n host: str\n port: int\n user: str\n password: str\n dbname: str\n\ndef main(db: postgresql):\n # db contains the database connection details\n pass\n```\n\n**Important rules:**\n\n- The resource type name must be **IN LOWERCASE**\n- Only include resource types if they are actually needed\n- If an import conflicts with a resource type name, **rename the imported object, not the type name**\n- Make sure to import TypedDict from typing **if you're using it**\n\n## Imports\n\nLibraries are installed automatically. Do not show installation instructions.\n\n```python\nimport requests\nimport pandas as pd\nfrom datetime import datetime\n```\n\nIf an import name conflicts with a resource type:\n\n```python\n# Wrong - don't rename the type\nimport stripe as stripe_lib\nclass stripe_type(TypedDict): ...\n\n# Correct - rename the import\nimport stripe as stripe_sdk\nclass stripe(TypedDict):\n api_key: str\n```\n\n## Windmill Client\n\nImport the windmill client for platform interactions:\n\n```python\nimport wmill\n```\n\nSee the SDK documentation for available methods.\n\n## Preprocessor Scripts\n\nFor preprocessor scripts, the function should be named `preprocessor` and receives an `event` parameter:\n\n```python\nfrom typing import TypedDict, Literal, Any\n\nclass Event(TypedDict):\n kind: Literal[\"webhook\", \"http\", \"websocket\", \"kafka\", \"email\", \"nats\", \"postgres\", \"sqs\", \"mqtt\", \"gcp\"]\n body: Any\n headers: dict[str, str]\n query: dict[str, str]\n\ndef preprocessor(event: Event):\n # Transform the event into flow input parameters\n return {\n \"param1\": event[\"body\"][\"field1\"],\n \"param2\": event[\"query\"][\"id\"]\n }\n```\n\n## S3 Object Operations\n\nWindmill provides built-in support for S3-compatible storage operations.\n\n### Receiving an S3Object as a script parameter\n\nTo accept a file from S3 as input to a script, type the parameter with `S3Object` (imported from `wmill`):\n\n```python\nimport wmill\nfrom wmill import S3Object\n\ndef main(file: S3Object):\n content = wmill.load_s3_file(file)\n # ...\n```\n\n### S3 operations\n\n```python\nimport wmill\n\n# Load file content from S3\ncontent: bytes = wmill.load_s3_file(s3object)\n\n# Load file as stream reader\nreader: BufferedReader = wmill.load_s3_file_reader(s3object)\n\n# Write file to S3\nresult: S3Object = wmill.write_s3_file(\n s3object, # Target path (or None to auto-generate)\n file_content, # bytes or BufferedReader\n s3_resource_path, # Optional: specific S3 resource\n content_type, # Optional: MIME type\n content_disposition # Optional: Content-Disposition header\n)\n```\n"; export declare const LANG_RLANG = "# R\n\n## Structure\n\nDefine a `main` function using `<-` or `=` assignment. Parameters become the script inputs:\n\n```r\nlibrary(dplyr)\nlibrary(jsonlite)\n\nmain <- function(x, name = \"default\", flag = TRUE) {\n df <- tibble(x = x, name = name)\n result <- df %>% mutate(greeting = paste(\"Hello\", name))\n return(toJSON(result, auto_unbox = TRUE))\n}\n```\n\n**Important:**\n- The `main` function is required\n- Use `library()` to load packages \u2014 they are resolved and installed automatically\n- `jsonlite` is always available (used internally for argument parsing)\n- Return values must be JSON-serializable\n\n## Parameters\n\nR types map to Windmill types:\n- `numeric` \u2192 float/int\n- `character` \u2192 string\n- `logical` \u2192 bool (use `TRUE`/`FALSE`)\n- `list` \u2192 object/dict\n- `NULL` \u2192 null\n\nDefault values are inferred from the function signature:\n\n```r\nmain <- function(\n name, # required string\n count = 10, # optional int, default 10\n verbose = FALSE # optional bool, default FALSE\n) {\n # ...\n}\n```\n\n## Resources and Variables\n\nUse the built-in Windmill helpers (no import needed):\n\n```r\nmain <- function() {\n # Get a variable\n api_key <- get_variable(\"f/my_folder/api_key\")\n\n # Get a resource (returns a list)\n db <- get_resource(\"f/my_folder/postgres_config\")\n host <- db$host\n port <- db$port\n\n return(list(host = host, port = port))\n}\n```\n\n## Output\n\nReturn any JSON-serializable value from `main`. The return value becomes the step result:\n\n```r\nmain <- function(x) {\n # Return a scalar\n return(x + 1)\n\n # Or a list (becomes JSON object)\n return(list(result = x + 1, status = \"ok\"))\n}\n```\n\n## Annotations\n\nControl execution behavior with comment annotations:\n\n```r\n#renv_verbose = true # Show verbose renv output during resolution\n#renv_install_verbose = true # Show verbose output during package installation\n#sandbox = true # Run in nsjail sandbox (requires nsjail)\n```\n"; export declare const LANG_RUST = "# Rust\n\n## Structure\n\nThe script must contain a function called `main` with proper return type:\n\n```rust\nuse anyhow::anyhow;\nuse serde::Serialize;\n\n#[derive(Serialize, Debug)]\nstruct ReturnType {\n result: String,\n count: i32,\n}\n\nfn main(param1: String, param2: i32) -> anyhow::Result {\n Ok(ReturnType {\n result: param1,\n count: param2,\n })\n}\n```\n\n**Important:**\n- Arguments should be owned types\n- Return type must be serializable (`#[derive(Serialize)]`)\n- Return type is `anyhow::Result`\n\n## Dependencies\n\nPackages must be specified with a partial cargo.toml at the beginning of the script:\n\n```rust\n//! ```cargo\n//! [dependencies]\n//! anyhow = \"1.0.86\"\n//! reqwest = { version = \"0.11\", features = [\"json\"] }\n//! tokio = { version = \"1\", features = [\"full\"] }\n//! ```\n\nuse anyhow::anyhow;\n// ... rest of the code\n```\n\n**Note:** Serde is already included, no need to add it again.\n\n## Async Functions\n\nIf you need to handle async functions (e.g., using tokio), keep the main function sync and create the runtime inside:\n\n```rust\n//! ```cargo\n//! [dependencies]\n//! anyhow = \"1.0.86\"\n//! tokio = { version = \"1\", features = [\"full\"] }\n//! reqwest = { version = \"0.11\", features = [\"json\"] }\n//! ```\n\nuse anyhow::anyhow;\nuse serde::Serialize;\n\n#[derive(Serialize, Debug)]\nstruct Response {\n data: String,\n}\n\nfn main(url: String) -> anyhow::Result {\n let rt = tokio::runtime::Runtime::new()?;\n rt.block_on(async {\n let resp = reqwest::get(&url).await?.text().await?;\n Ok(Response { data: resp })\n })\n}\n```\n"; -export declare const LANG_SNOWFLAKE = "# Snowflake\n\nArguments use `?` placeholders.\n\nName the parameters by adding comments before the statement:\n\n```sql\n-- ? name1 (text)\n-- ? name2 (number) = 0\nSELECT * FROM users WHERE name = ? AND age > ?;\n```\n"; +export declare const LANG_SNOWFLAKE = "# Snowflake\n\nArguments use `?` placeholders.\n\nName the parameters by adding comments before the statement:\n\n```sql\n-- ? name1 (text)\n-- ? name2 (number) = 0\nSELECT * FROM users WHERE name = ? AND age > ?;\n```\n\n## Receiving an S3Object as a script parameter\n\nDeclare the arg with type `(s3object)`. Windmill renders an S3 file picker for\nit, downloads the file, and binds it as JSON text \u2014 Parquet/CSV files are\ndecoded server-side into a JSON array of records, JSON/JSONL pass through.\nWrap the bind with `PARSE_JSON(?)` and walk it with `LATERAL FLATTEN`:\n\n```sql\n-- ? file (s3object)\nSELECT\n v.value:id::NUMBER AS id,\n v.value:name::STRING AS name\nFROM LATERAL FLATTEN(input => PARSE_JSON(?)) v;\n```\n\n## Streaming query results to S3\n\nAdd a `-- s3` directive at the top of the script to stream the result set to S3\ninstead of returning rows. Windmill writes the file and returns its `S3Object`\nas the script result.\n\n```sql\n-- s3 prefix=exports/users format=parquet\nSELECT id, name FROM users;\n```\n\nAll keys are optional: `prefix` (object key prefix), `storage` (named storage \u2014\nomit to use the workspace default), `format` (`json` (default), `parquet`, or\n`csv`). Use this for large result sets \u2014 rows stream directly to S3 instead of\nbeing buffered, bypassing the 10000-row return cap.\n"; From ac3c155541eb5ca20d65c38ad13dca6c10a572c9 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Mon, 11 May 2026 22:30:15 +0000 Subject: [PATCH 20/21] fix: mask oauth client secret in instance settings (#9112) * feat: mask oauth client secret in instance settings * fix: address ci review - migrate nextcloud + use Password small prop * fix: associate client secret labels with input via for/id --- .../src/lib/components/Auth0Setting.svelte | 12 ++++++---- .../src/lib/components/AuthSettings.svelte | 17 ++++++++----- .../src/lib/components/AutheliaSetting.svelte | 20 ++++++++-------- .../lib/components/AuthentikSetting.svelte | 24 +++++++++++-------- .../src/lib/components/KanidmSetting.svelte | 20 ++++++++-------- .../src/lib/components/KeycloakSetting.svelte | 10 ++++---- .../lib/components/NextcloudSetting.svelte | 10 ++++---- .../src/lib/components/OAuthSetting.svelte | 10 ++++---- .../src/lib/components/OktaSetting.svelte | 9 +++++-- .../src/lib/components/PocketIdSetting.svelte | 10 ++++---- .../src/lib/components/ZitadelSetting.svelte | 20 ++++++++-------- 11 files changed, 93 insertions(+), 69 deletions(-) diff --git a/frontend/src/lib/components/Auth0Setting.svelte b/frontend/src/lib/components/Auth0Setting.svelte index beb9ec03f9..a246ae196d 100644 --- a/frontend/src/lib/components/Auth0Setting.svelte +++ b/frontend/src/lib/components/Auth0Setting.svelte @@ -7,6 +7,7 @@ import ToggleButton from './common/toggleButton-v2/ToggleButton.svelte' import ToggleButtonGroup from './common/toggleButton-v2/ToggleButtonGroup.svelte' import TextInput from './text_input/TextInput.svelte' + import Password from './Password.svelte' import SettingCard from './instanceSettings/SettingCard.svelte' interface Props { @@ -103,14 +104,15 @@ class="max-w-lg" /> - - -