diff --git a/backend/parsers/windmill-parser-wasm/publish-pkgs.sh b/backend/parsers/windmill-parser-wasm/publish-pkgs.sh index 7e2fd8beb2c8a..c2f2c0d7ad960 100755 --- a/backend/parsers/windmill-parser-wasm/publish-pkgs.sh +++ b/backend/parsers/windmill-parser-wasm/publish-pkgs.sh @@ -21,3 +21,6 @@ popd pushd "pkg-rust" && npm publish ${args} popd + +pushd "pkg-yaml" && npm publish ${args} +popd diff --git a/backend/parsers/windmill-parser-yaml/src/lib.rs b/backend/parsers/windmill-parser-yaml/src/lib.rs index 8c7068c54a5e8..151d6eb562c01 100644 --- a/backend/parsers/windmill-parser-yaml/src/lib.rs +++ b/backend/parsers/windmill-parser-yaml/src/lib.rs @@ -25,14 +25,19 @@ pub fn parse_ansible_sig(inner_content: &str) -> anyhow::Result anyhow::Result Option { + if let Yaml::Hash(arg) = arg { + if let Some(def) = arg.get(&Yaml::String("default".to_string())) { + if let Some(Yaml::String(typ)) = arg.get(&Yaml::String("type".to_string())) { + if let Yaml::String(path) = def { + if typ.as_str() == "windmill_resource" { + return Some(serde_json::Value::String(format!("$res:{}", path))); + } + } + } + return Some(yaml_to_json(def)); + } + } + None +} + +enum ArgTyp { + Typ(Typ), + StaticVar(String), + StaticResource(String), +} + +fn parse_ansible_arg_typ(arg: &Yaml) -> ArgTyp { + if let Yaml::Hash(a) = arg { + if let Some(Yaml::String(typ)) = a.get(&Yaml::String("type".to_string())) { + if typ.as_str() == "windmill_variable" { + if let Some(Yaml::String(variable_path)) = + a.get(&Yaml::String("variable".to_string())) + { + return ArgTyp::StaticVar(variable_path.to_string()); + } + } + if typ.as_str() == "windmill_resource" { + if let Some(Yaml::String(resource_path)) = + a.get(&Yaml::String("resource".to_string())) + { + return ArgTyp::StaticResource(resource_path.to_string()); + } + } + } + } + ArgTyp::Typ(parse_ansible_typ(arg)) +} + fn parse_ansible_typ(arg: &Yaml) -> Typ { if let Yaml::Hash(arg) = arg { if let Some(Yaml::String(typ)) = arg.get(&Yaml::String("type".to_string())) { @@ -127,7 +176,19 @@ fn parse_ansible_typ(arg: &Yaml) -> Typ { } } -#[derive(Debug)] +#[derive(Debug, Clone)] +pub struct AnsiblePlaybookOptions { + // There are a lot more options + // TODO: Add the options as customers require them + // Add it here and then on the executors cmd_options + pub verbosity: Option, + pub forks: Option, + pub timeout: Option, + pub flush_cache: Option<()>, + pub force_handlers: Option<()>, +} + +#[derive(Debug, Clone)] pub struct FileResource { pub resource_path: String, pub target_path: String, @@ -140,12 +201,15 @@ pub struct AnsibleInventory { resource_type: Option, pub pinned_resource: Option, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct AnsibleRequirements { pub python_reqs: Vec, pub collections: Option, pub file_resources: Vec, pub inventories: Vec, + pub vars: Vec<(String, String)>, + pub resources: Vec<(String, String)>, + pub options: AnsiblePlaybookOptions, } fn parse_inventories(inventory_yaml: &Yaml) -> anyhow::Result> { @@ -204,11 +268,21 @@ pub fn parse_ansible_reqs( return Ok((logs, None, inner_content.to_string())); } + let opts = AnsiblePlaybookOptions { + verbosity: None, + forks: None, + timeout: None, + flush_cache: None, + force_handlers: None, + }; let mut ret = AnsibleRequirements { python_reqs: vec![], collections: None, file_resources: vec![], inventories: vec![], + vars: vec![], + resources: vec![], + options: opts, }; if let Yaml::Hash(doc) = &docs[0] { @@ -242,10 +316,33 @@ pub fn parse_ansible_reqs( ret.file_resources.append(&mut resources?); } } - Yaml::String(key) if key == "extra_vars" => {} + Yaml::String(key) if key == "extra_vars" => { + if let Yaml::Hash(v) = &value { + for (key, arg) in v { + if let Yaml::String(arg_name) = key { + match parse_ansible_arg_typ(arg) { + ArgTyp::StaticVar(p) => { + ret.vars + .push((arg_name.to_string(), format!("$var:{}", p))); + } + ArgTyp::StaticResource(p) => { + ret.resources + .push((arg_name.to_string(), format!("$res:{}", p))); + } + ArgTyp::Typ(_) => (), + } + } + } + } + } Yaml::String(key) if key == "inventory" => { ret.inventories = parse_inventories(value)?; } + Yaml::String(key) if key == "options" => { + if let Yaml::Array(opts) = &value { + ret.options = parse_ansible_options(opts); + } + } Yaml::String(key) => logs.push_str(&format!("\nUnknown field `{}`. Ignoring", key)), _ => (), } @@ -260,6 +357,82 @@ pub fn parse_ansible_reqs( Ok((logs, Some(ret), out_str)) } +fn parse_ansible_options(opts: &Vec) -> AnsiblePlaybookOptions { + let mut ret = AnsiblePlaybookOptions { + verbosity: None, + forks: None, + timeout: None, + flush_cache: None, + force_handlers: None, + }; + for opt in opts { + if let Yaml::String(o) = opt { + match o.as_str() { + "flush_cache" => { + ret.flush_cache = Some(()); + } + "force_handlers" => { + ret.force_handlers = Some(()); + } + s if count_consecutive_vs(s) > 0 => { + ret.verbosity = Some("v".repeat(count_consecutive_vs(s).min(6))); + } + _ => (), + } + } + if let Yaml::Hash(m) = opt { + if let Some((Yaml::String(name), value)) = m.iter().last() { + match name.as_str() { + "forks" => { + if let Yaml::Integer(count) = value { + ret.forks = Some(*count); + } + } + "timeout" => { + if let Yaml::Integer(timeout) = value { + ret.timeout = Some(*timeout); + } + } + "verbosity" => { + if let Yaml::String(verbosity) = value { + let c = count_consecutive_vs(verbosity); + if c > 0 && c <= 6 { + ret.verbosity = Some("v".repeat(c.min(6))); + } + + } + } + _ => () + + } + } + + + } + } + + ret +} + +fn count_consecutive_vs(s: &str) -> usize { + let mut max_count = 0; + let mut current_count = 0; + + for c in s.chars() { + if c == 'v' { + current_count += 1; + if current_count == 6 { + return 6; // Stop early if we reach 6 + } + } else { + current_count = 0; // Reset count if the character is not 'v' + } + max_count = max_count.max(current_count); + } + + max_count +} + fn parse_file_resource(yaml: &Yaml) -> anyhow::Result { if let Yaml::Hash(f) = yaml { if let Some(Yaml::String(resource_path)) = f.get(&Yaml::String("resource".to_string())) { @@ -279,3 +452,31 @@ fn parse_file_resource(yaml: &Yaml) -> anyhow::Result { } return Err(anyhow!("Invalid file resource: Should be a dictionary.")); } + +fn yaml_to_json(yaml: &Yaml) -> serde_json::Value { + match yaml { + Yaml::Array(arr) => { + let json_array: Vec = arr.into_iter().map(yaml_to_json).collect(); + serde_json::Value::Array(json_array) + } + Yaml::Hash(hash) => { + let json_object = hash + .into_iter() + .map(|(k, v)| { + let key = match k { + Yaml::String(s) => s.clone(), + _ => k.as_str().unwrap_or("").to_string(), + }; + (key, yaml_to_json(v)) + }) + .collect(); + serde_json::Value::Object(json_object) + } + Yaml::String(s) => serde_json::Value::String(s.to_string()), + Yaml::Integer(i) => serde_json::Value::Number(i.clone().into()), + Yaml::Real(r) => serde_json::Value::Number(r.parse().unwrap_or(0.into())), + Yaml::Boolean(b) => serde_json::Value::Bool(*b), + Yaml::Null => serde_json::Value::Null, + _ => serde_json::Value::Null, + } +} diff --git a/backend/windmill-api/src/workspaces.rs b/backend/windmill-api/src/workspaces.rs index 730606385629e..685286d750ea4 100644 --- a/backend/windmill-api/src/workspaces.rs +++ b/backend/windmill-api/src/workspaces.rs @@ -2577,7 +2577,7 @@ async fn tarball_workspace( } ScriptLang::Php => "php", ScriptLang::Rust => "rs", - ScriptLang::Ansible => "yaml", + ScriptLang::Ansible => "playbook.yml", }; archive .write_to_archive(&script.content, &format!("{}.{}", script.path, ext)) diff --git a/backend/windmill-worker/src/ansible_executor.rs b/backend/windmill-worker/src/ansible_executor.rs index 5130a41614fef..297458633a80f 100644 --- a/backend/windmill-worker/src/ansible_executor.rs +++ b/backend/windmill-worker/src/ansible_executor.rs @@ -1,5 +1,8 @@ use std::{ - collections::HashMap, os::unix::fs::PermissionsExt, path::{Path, PathBuf}, process::Stdio + collections::HashMap, + os::unix::fs::PermissionsExt, + path::{Path, PathBuf}, + process::Stdio, }; use anyhow::anyhow; @@ -10,16 +13,20 @@ use uuid::Uuid; use windmill_common::{ error, jobs::QueuedJob, - worker::{write_file, write_file_at_user_defined_location, WORKER_CONFIG}, + worker::{to_raw_value, write_file, write_file_at_user_defined_location, WORKER_CONFIG}, }; use windmill_parser_yaml::AnsibleRequirements; use windmill_queue::{append_logs, CanceledBy}; use crate::{ - bash_executor::BIN_BASH, common::{ + bash_executor::BIN_BASH, + common::{ get_reserved_variables, handle_child, read_and_check_result, start_child_process, transform_json, - }, python_executor::{create_dependencies_dir, handle_python_reqs, pip_compile}, AuthedClientBackgroundTask, DISABLE_NSJAIL, DISABLE_NUSER, HOME_ENV, NSJAIL_PATH, PATH_ENV, TZ_ENV + }, + python_executor::{create_dependencies_dir, handle_python_reqs, pip_compile}, + AuthedClientBackgroundTask, DISABLE_NSJAIL, DISABLE_NUSER, HOME_ENV, NSJAIL_PATH, PATH_ENV, + TZ_ENV, }; lazy_static::lazy_static! { @@ -198,7 +205,6 @@ pub async fn handle_ansible_job( append_logs(&job.id, &job.workspace_id, logs, db).await; write_file(job_dir, "main.yml", &playbook)?; - let additional_python_paths = handle_ansible_python_deps( job_dir, requirements_o, @@ -215,7 +221,13 @@ pub async fn handle_ansible_job( let interpolated_args; if let Some(args) = &job.args { - if let Some(x) = transform_json(client, &job.workspace_id, &args.0, job, db).await? { + let mut args = args.0.clone(); + if let Some(reqs) = reqs.clone() { + for (name, path) in reqs.resources.iter().chain(reqs.vars.iter()) { + args.insert(name.clone(), to_raw_value(path)); + } + } + if let Some(x) = transform_json(client, &job.workspace_id, &args, job, db).await? { write_file( job_dir, "args.json", @@ -228,7 +240,7 @@ pub async fn handle_ansible_job( "args.json", &serde_json::to_string(&args).unwrap_or_else(|_| "{}".to_string()), )?; - interpolated_args = Some(args.clone().0); + interpolated_args = Some(args); } } else { interpolated_args = None; @@ -236,6 +248,12 @@ pub async fn handle_ansible_job( }; write_file(job_dir, "result.json", "")?; + let cmd_options: Vec = reqs + .as_ref() + .map(|r| r.options.clone()) + .map(|r| get_cmd_options(r)) + .unwrap_or_default(); + let inventories: Vec = reqs .as_ref() .map(|x| { @@ -282,14 +300,16 @@ pub async fn handle_ansible_job( db, ) .await; - let ansible_cfg_content = format!(r#" + let ansible_cfg_content = format!( + r#" [defaults] collections_path = ./ roles_path = ./roles home={job_dir}/.ansible local_tmp={job_dir}/.ansible/tmp remote_tmp={job_dir}/.ansible/tmp -"#); +"# + ); write_file(job_dir, "ansible.cfg", &ansible_cfg_content)?; let mut reserved_variables = get_reserved_variables(job, &authed_client.token, db).await?; @@ -331,10 +351,11 @@ mount {{ let mut cmd_args = vec!["main.yml", "--extra-vars", "@args.json"]; cmd_args.extend(inventories.iter().map(|s| s.as_str())); + cmd_args.extend(cmd_options.iter().map(|s| s.as_str())); let child = if !*DISABLE_NSJAIL { - - let wrapper = format!(r#"set -eou pipefail + let wrapper = format!( + r#"set -eou pipefail {0} "$@" if [ -f "result" ]; then cat result > result_nsjail_mount.json @@ -342,7 +363,9 @@ fi if [ -f "result.json" ]; then cat result.json > result_nsjail_mount.json fi -"#, ANSIBLE_PLAYBOOK_PATH.as_str()); +"#, + ANSIBLE_PLAYBOOK_PATH.as_str() + ); let file = write_file(job_dir, "wrapper.sh", &wrapper)?; @@ -406,6 +429,36 @@ fi read_and_check_result(job_dir).await } +fn get_cmd_options(r: windmill_parser_yaml::AnsiblePlaybookOptions) -> Vec { + let mut ret = vec![]; + + if let Some(v) = r.verbosity { + if v.chars().all(|c| c == 'v') && v.len() <= 6 { + ret.push(format!("-{}", v)); + } + } + + if let Some(o) = r.timeout { + ret.push("--timeout".to_string()); + ret.push(o.to_string()); + } + + if let Some(o) = r.forks { + ret.push("--forks".to_string()); + ret.push(o.to_string()); + } + + if r.flush_cache.is_some() { + ret.push("--flush-cache".to_string()); + } + + if r.force_handlers.is_some() { + ret.push("--force-handlers".to_string()); + } + + ret +} + fn define_nsjail_mount(job_dir: &str, path: &PathBuf) -> anyhow::Result { Ok(format!( r#" diff --git a/cli/build.sh b/cli/build.sh index 848e20d00c0a0..bf00b99a5746e 100755 --- a/cli/build.sh +++ b/cli/build.sh @@ -1,2 +1,3 @@ +#!/bin/bash ./gen_wm_client.sh -deno run -A dnt.ts \ No newline at end of file +deno run -A dnt.ts diff --git a/cli/gen_wm_client.sh b/cli/gen_wm_client.sh index acbf95e64a5f7..21527acee9dcd 100755 --- a/cli/gen_wm_client.sh +++ b/cli/gen_wm_client.sh @@ -1,3 +1,4 @@ +#!/bin/bash set -eou pipefail script_dirpath="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" @@ -19,4 +20,4 @@ sed -i "s/BASE: '\/api'/BASE: baseUrlApi/g" gen/core/OpenAPI.ts find gen/ -name "*.ts" -exec sed -i -E "s/(import.*from[[:space:]]*['\"][^'\"]+)(['\"])/\1.ts\2/g" {} \; -find gen/ -name "*.ts" -exec sed -i -E "s/(export.*from[[:space:]]*['\"][^'\"]+)(['\"])/\1.ts\2/g" {} \; \ No newline at end of file +find gen/ -name "*.ts" -exec sed -i -E "s/(export.*from[[:space:]]*['\"][^'\"]+)(['\"])/\1.ts\2/g" {} \; diff --git a/cli/metadata.ts b/cli/metadata.ts index 07534960558d7..a3b4738cb7d1b 100644 --- a/cli/metadata.ts +++ b/cli/metadata.ts @@ -7,6 +7,7 @@ import { } from "./bootstrap/script_bootstrap.ts"; import { instantiate as instantiateWasm, + parse_ansible, parse_bash, parse_bigquery, parse_deno, @@ -14,8 +15,10 @@ import { parse_graphql, parse_mssql, parse_mysql, + parse_php, parse_powershell, parse_python, + parse_rust, parse_snowflake, parse_sql, } from "./wasm/windmill_parser_wasm.generated.js"; @@ -306,8 +309,10 @@ export async function updateScriptSchema( path ); metadataContent.schema = result.schema; - metadataContent.has_preprocessor = result.has_preprocessor; - metadataContent.no_main_func = result.no_main_func; + if (result.has_preprocessor != null) + metadataContent.has_preprocessor = result.has_preprocessor; + if (result.no_main_func != null) + metadataContent.no_main_func = result.no_main_func; } async function updateScriptLock( @@ -324,7 +329,9 @@ async function updateScriptLock( language == "python3" || language == "go" || language == "deno" || - language == "php" + language == "php" || + language == "rust" || + language == "ansible" ) ) { return; @@ -482,6 +489,12 @@ export function inferSchema( inferedSchema = JSON.parse(parse_bash(content)); } else if (language === "powershell") { inferedSchema = JSON.parse(parse_powershell(content)); + } else if (language === "php") { + inferedSchema = JSON.parse(parse_php(content)); + } else if (language === "rust") { + inferedSchema = JSON.parse(parse_rust(content)); + } else if (language === "ansible") { + inferedSchema = JSON.parse(parse_ansible(content)); } else { throw new Error("Invalid language: " + language); } diff --git a/cli/script_common.ts b/cli/script_common.ts index fcdb4808a8276..220c6c41e9023 100644 --- a/cli/script_common.ts +++ b/cli/script_common.ts @@ -48,9 +48,9 @@ export function inferContentTypeFromFilePath( return "bash"; } else if (contentPath.endsWith(".ps1")) { return "powershell"; - } else if (contentPath.endsWith("php")) { + } else if (contentPath.endsWith(".php")) { return "php"; - } else if (contentPath.endsWith("rs")) { + } else if (contentPath.endsWith(".rs")) { return "rust"; } else if (contentPath.endsWith(".playbook.yml")) { return "ansible"; diff --git a/cli/sync.ts b/cli/sync.ts index d770029c4535a..088571362dc0f 100644 --- a/cli/sync.ts +++ b/cli/sync.ts @@ -504,18 +504,20 @@ function ZipFSElement( if (formatExtension) { const fileContent: string = parsed["value"]["content"]; - r.push({ - isDirectory: false, - path: - removeSuffix(finalPath, ".resource.json") + - ".resource.file." + - formatExtension, - async *getChildren() {}, - // deno-lint-ignore require-await - async getContentText() { - return fileContent; - }, - }); + if (typeof(fileContent) === "string") { + r.push({ + isDirectory: false, + path: + removeSuffix(finalPath, ".resource.json") + + ".resource.file." + + formatExtension, + async *getChildren() {}, + // deno-lint-ignore require-await + async getContentText() { + return fileContent; + }, + }); + } } } return r; diff --git a/cli/types.ts b/cli/types.ts index a08ed44b8d6f8..84691a37e20db 100644 --- a/cli/types.ts +++ b/cli/types.ts @@ -200,7 +200,9 @@ export function getTypeStrFromPath( parsed.ext == ".gql" || parsed.ext == ".ps1" || parsed.ext == ".js" || - parsed.ext == ".php" + parsed.ext == ".php" || + parsed.ext == ".rs" || + (parsed.ext == ".yml" && parsed.name.split(".").pop() == "playbook") ) { return "script"; } diff --git a/cli/wasm/windmill_parser_wasm.generated.js b/cli/wasm/windmill_parser_wasm.generated.js index b49526ecaf05d..c8589935b2c1d 100644 --- a/cli/wasm/windmill_parser_wasm.generated.js +++ b/cli/wasm/windmill_parser_wasm.generated.js @@ -15,20 +15,6 @@ function getObject(idx) { return heap[idx]; } -let heap_next = heap.length; - -function dropObject(idx) { - if (idx < 132) return; - heap[idx] = heap_next; - heap_next = idx; -} - -function takeObject(idx) { - const ret = getObject(idx); - dropObject(idx); - return ret; -} - let WASM_VECTOR_LEN = 0; let cachedUint8Memory0 = null; @@ -103,19 +89,27 @@ function getInt32Memory0() { return cachedInt32Memory0; } -const cachedTextDecoder = typeof TextDecoder !== "undefined" - ? new TextDecoder("utf-8", { ignoreBOM: true, fatal: true }) - : { - decode: () => { - throw Error("TextDecoder not available"); - }, - }; +let heap_next = heap.length; -if (typeof TextDecoder !== "undefined") cachedTextDecoder.decode(); +function dropObject(idx) { + if (idx < 132) return; + heap[idx] = heap_next; + heap_next = idx; +} -function getStringFromWasm0(ptr, len) { - ptr = ptr >>> 0; - return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); +function takeObject(idx) { + const ret = getObject(idx); + dropObject(idx); + return ret; +} + +let cachedFloat64Memory0 = null; + +function getFloat64Memory0() { + if (cachedFloat64Memory0 === null || cachedFloat64Memory0.byteLength === 0) { + cachedFloat64Memory0 = new Float64Array(wasm.memory.buffer); + } + return cachedFloat64Memory0; } function addHeapObject(obj) { @@ -127,13 +121,19 @@ function addHeapObject(obj) { return idx; } -let cachedFloat64Memory0 = null; +const cachedTextDecoder = typeof TextDecoder !== "undefined" + ? new TextDecoder("utf-8", { ignoreBOM: true, fatal: true }) + : { + decode: () => { + throw Error("TextDecoder not available"); + }, + }; -function getFloat64Memory0() { - if (cachedFloat64Memory0 === null || cachedFloat64Memory0.byteLength === 0) { - cachedFloat64Memory0 = new Float64Array(wasm.memory.buffer); - } - return cachedFloat64Memory0; +if (typeof TextDecoder !== "undefined") cachedTextDecoder.decode(); + +function getStringFromWasm0(ptr, len) { + ptr = ptr >>> 0; + return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); } let cachedBigInt64Memory0 = null; @@ -698,9 +698,6 @@ function handleError(f, args) { const imports = { __wbindgen_placeholder__: { - __wbindgen_object_drop_ref: function (arg0) { - takeObject(arg0); - }, __wbindgen_string_get: function (arg0, arg1) { const obj = getObject(arg1); const ret = typeof obj === "string" ? obj : undefined; @@ -715,9 +712,8 @@ const imports = { getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; }, - __wbindgen_error_new: function (arg0, arg1) { - const ret = new Error(getStringFromWasm0(arg0, arg1)); - return addHeapObject(ret); + __wbindgen_object_drop_ref: function (arg0) { + takeObject(arg0); }, __wbindgen_boolean_get: function (arg0) { const v = getObject(arg0); @@ -755,7 +751,11 @@ const imports = { const ret = BigInt.asUintN(64, arg0); return addHeapObject(ret); }, - __wbg_eval_b7405fdd08ddef3d: function (arg0, arg1) { + __wbindgen_error_new: function (arg0, arg1) { + const ret = new Error(getStringFromWasm0(arg0, arg1)); + return addHeapObject(ret); + }, + __wbg_eval_8243d86342a64a9b: function (arg0, arg1) { const ret = eval(getStringFromWasm0(arg0, arg1)); return addHeapObject(ret); }, diff --git a/cli/wasm/windmill_parser_wasm_bg.wasm b/cli/wasm/windmill_parser_wasm_bg.wasm index ef578c3cf296c..692c1e4fa81d3 100644 Binary files a/cli/wasm/windmill_parser_wasm_bg.wasm and b/cli/wasm/windmill_parser_wasm_bg.wasm differ diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 8fad43cc8890a..318017cb2af7a 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -72,7 +72,7 @@ "windmill-parser-wasm-regex": "^1.397.2", "windmill-parser-wasm-rust": "^1.397.2", "windmill-parser-wasm-ts": "^1.397.2", - "windmill-parser-wasm-yaml": "^1.396.1", + "windmill-parser-wasm-yaml": "^1.398.1", "windmill-sql-datatype-parser-wasm": "^1.318.0", "y-monaco": "^0.1.4", "y-websocket": "^1.5.4", @@ -13525,9 +13525,9 @@ "integrity": "sha512-nspEC1zLfrvvh6ta8YSjKo99lDfFvsXh7rV2mmpTAmc2ZzzyuVDvW5Cm0Wmo8Ww3seO+oDi/v3jy+8QX8pIzwA==" }, "node_modules/windmill-parser-wasm-yaml": { - "version": "1.396.1", - "resolved": "https://registry.npmjs.org/windmill-parser-wasm-yaml/-/windmill-parser-wasm-yaml-1.396.1.tgz", - "integrity": "sha512-ZRo5WIAwO21+ZweFPGe0Dx+PZbzJ9gd1qtAc9m0KeB7iNH1XY6lYKrmdQNaHJN5NqdwFiWTRgxIRgP62vvizBQ==" + "version": "1.398.1", + "resolved": "https://registry.npmjs.org/windmill-parser-wasm-yaml/-/windmill-parser-wasm-yaml-1.398.1.tgz", + "integrity": "sha512-f5MCJ9PVLrJQBcVuxnTlZNw561HIJkMqX/76HLgOqKehNpO7gboZyaHx0txUJP50MIDv/IMpn0SD6S7DZnynEg==" }, "node_modules/windmill-sql-datatype-parser-wasm": { "version": "1.318.0", diff --git a/frontend/package.json b/frontend/package.json index 48e5518b0f47b..0474f627ba5ac 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -145,7 +145,7 @@ "windmill-parser-wasm-regex": "^1.397.2", "windmill-parser-wasm-rust": "^1.397.2", "windmill-parser-wasm-ts": "^1.397.2", - "windmill-parser-wasm-yaml": "^1.396.1", + "windmill-parser-wasm-yaml": "^1.398.1", "windmill-sql-datatype-parser-wasm": "^1.318.0", "y-monaco": "^0.1.4", "y-websocket": "^1.5.4", @@ -459,4 +459,4 @@ "optionalDependencies": { "fsevents": "^2.3.3" } -} \ No newline at end of file +}