mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-18 16:02:10 +00:00
feat: remove nativets in favor of bun with native pragma
This commit is contained in:
@@ -0,0 +1 @@
|
||||
-- Add down migration script here
|
||||
@@ -0,0 +1,2 @@
|
||||
-- Add up migration script here
|
||||
ALTER TYPE SCRIPT_LANG ADD VALUE IF NOT EXISTS 'bunnative';
|
||||
@@ -52,7 +52,7 @@ use windmill_common::{
|
||||
utils::{
|
||||
not_found_if_none, paginate, query_elems_from_hub, require_admin, Pagination, StripPath,
|
||||
},
|
||||
worker::to_raw_value,
|
||||
worker::{get_annotation, to_raw_value},
|
||||
HUB_BASE_URL,
|
||||
};
|
||||
use windmill_git_sync::{handle_deployment_metadata, DeployedObject};
|
||||
@@ -585,6 +585,17 @@ async fn create_script_internal<'c>(
|
||||
} else {
|
||||
envs
|
||||
};
|
||||
|
||||
let lang = if &ns.language == &ScriptLang::Bun || &ns.language == &ScriptLang::Bunnative {
|
||||
let anns = get_annotation(&ns.content);
|
||||
if anns.native_mode {
|
||||
ScriptLang::Bunnative
|
||||
} else {
|
||||
ScriptLang::Bun
|
||||
}
|
||||
} else {
|
||||
ns.language.clone()
|
||||
};
|
||||
sqlx::query!(
|
||||
"INSERT INTO script (workspace_id, hash, path, parent_hashes, summary, description, \
|
||||
content, created_by, schema, is_template, extra_perms, lock, language, kind, tag, \
|
||||
@@ -604,7 +615,7 @@ async fn create_script_internal<'c>(
|
||||
ns.is_template.unwrap_or(false),
|
||||
extra_perms,
|
||||
lock,
|
||||
ns.language.clone() as ScriptLang,
|
||||
lang as ScriptLang,
|
||||
ns.kind.unwrap_or(ScriptKind::Script) as ScriptKind,
|
||||
ns.tag,
|
||||
ns.draft_only,
|
||||
|
||||
@@ -2498,7 +2498,7 @@ async fn tarball_workspace(
|
||||
ScriptLang::Mssql => "ms.sql",
|
||||
ScriptLang::Graphql => "gql",
|
||||
ScriptLang::Nativets => "fetch.ts",
|
||||
ScriptLang::Bun => {
|
||||
ScriptLang::Bun | ScriptLang::Bunnative => {
|
||||
if default_ts.as_ref().is_some_and(|x| x == "bun") {
|
||||
"ts"
|
||||
} else {
|
||||
|
||||
@@ -34,6 +34,7 @@ pub enum ScriptLang {
|
||||
Powershell,
|
||||
Postgresql,
|
||||
Bun,
|
||||
Bunnative,
|
||||
Mysql,
|
||||
Bigquery,
|
||||
Snowflake,
|
||||
@@ -46,6 +47,7 @@ impl ScriptLang {
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
ScriptLang::Bun => "bun",
|
||||
ScriptLang::Bunnative => "bunnative",
|
||||
ScriptLang::Nativets => "nativets",
|
||||
ScriptLang::Deno => "deno",
|
||||
ScriptLang::Python3 => "python3",
|
||||
|
||||
@@ -3702,10 +3702,15 @@ pub async fn push<'c, 'd, R: rsmq_async::RsmqConnection + Send + 'c>(
|
||||
language
|
||||
.as_ref()
|
||||
.map(|x| {
|
||||
if per_workspace {
|
||||
format!("{}-{}", x.as_str(), workspace_id)
|
||||
let tag_lang = if x == &ScriptLang::Bunnative {
|
||||
ScriptLang::Nativets.as_str()
|
||||
} else {
|
||||
x.as_str().to_string()
|
||||
x.as_str()
|
||||
};
|
||||
if per_workspace {
|
||||
format!("{}-{}", tag_lang, workspace_id)
|
||||
} else {
|
||||
tag_lang.to_string()
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(default)
|
||||
|
||||
@@ -34,7 +34,9 @@ use windmill_common::variables;
|
||||
|
||||
use windmill_common::{
|
||||
error::{self, Result},
|
||||
get_latest_hash_for_path,
|
||||
jobs::QueuedJob,
|
||||
scripts::ScriptLang,
|
||||
worker::{exists_in_cache, get_annotation, save_cache},
|
||||
DB,
|
||||
};
|
||||
@@ -577,7 +579,8 @@ pub async fn prebundle_script(
|
||||
worker_name: &str,
|
||||
token: &str,
|
||||
) -> Result<()> {
|
||||
let (local_path, remote_path) = compute_bundle_local_and_remote_path(inner_content, &lockfile);
|
||||
let (local_path, remote_path) =
|
||||
compute_bundle_local_and_remote_path(inner_content, &lockfile, script_path, db, w_id).await;
|
||||
if exists_in_cache(&local_path, &remote_path).await {
|
||||
return Ok(());
|
||||
}
|
||||
@@ -622,18 +625,48 @@ pub async fn prebundle_script(
|
||||
|
||||
pub const BUN_BUNDLE_OBJECT_STORE_PREFIX: &str = "bun_bundle/";
|
||||
|
||||
fn compute_bundle_local_and_remote_path(
|
||||
async fn get_script_import_updated_at(db: &DB, w_id: &str, script_path: &str) -> Result<String> {
|
||||
let script_hash = get_latest_hash_for_path(&mut db.begin().await?, w_id, script_path).await?;
|
||||
let last_updated_at = sqlx::query_scalar!(
|
||||
"SELECT created_at FROM script WHERE workspace_id = $1 AND hash = $2",
|
||||
w_id,
|
||||
script_hash.0 .0
|
||||
)
|
||||
.fetch_one(db)
|
||||
.await?;
|
||||
Ok(last_updated_at.to_string())
|
||||
}
|
||||
|
||||
async fn compute_bundle_local_and_remote_path(
|
||||
inner_content: &str,
|
||||
requirements_o: &Option<String>,
|
||||
script_path: &str,
|
||||
db: &DB,
|
||||
w_id: &str,
|
||||
) -> (String, String) {
|
||||
let hash = windmill_common::utils::calculate_hash(&format!(
|
||||
let mut input_src = format!(
|
||||
"{}{}",
|
||||
inner_content,
|
||||
requirements_o
|
||||
.as_ref()
|
||||
.map(|x| x.to_string())
|
||||
.unwrap_or_default()
|
||||
));
|
||||
);
|
||||
|
||||
let relative_imports = crate::worker_lockfiles::extract_relative_imports(
|
||||
&inner_content,
|
||||
script_path,
|
||||
&Some(ScriptLang::Bun),
|
||||
);
|
||||
|
||||
for path in relative_imports.unwrap_or_default() {
|
||||
if let Ok(updated_at) = get_script_import_updated_at(db, w_id, &path).await {
|
||||
input_src.push_str(&path);
|
||||
input_src.push_str(&updated_at.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
let hash = windmill_common::utils::calculate_hash(&input_src);
|
||||
let local_path = format!("{BUN_BUNDLE_CACHE_DIR}/{hash}");
|
||||
let remote_path = format!("{BUN_BUNDLE_OBJECT_STORE_PREFIX}{hash}");
|
||||
(local_path, remote_path)
|
||||
@@ -657,10 +690,17 @@ pub async fn handle_bun_job(
|
||||
) -> error::Result<Box<RawValue>> {
|
||||
let mut annotation = windmill_common::worker::get_annotation(inner_content);
|
||||
|
||||
let (mut bundle_cache, cache_logs, local_path, remote_path) =
|
||||
let (mut has_bundle_cache, cache_logs, local_path, remote_path) =
|
||||
if requirements_o.is_some() && !annotation.nobundling && codebase.is_none() {
|
||||
let (local_path, remote_path) =
|
||||
compute_bundle_local_and_remote_path(inner_content, &requirements_o);
|
||||
let (local_path, remote_path) = compute_bundle_local_and_remote_path(
|
||||
inner_content,
|
||||
&requirements_o,
|
||||
job.script_path(),
|
||||
db,
|
||||
&job.workspace_id,
|
||||
)
|
||||
.await;
|
||||
|
||||
let (cache, logs) =
|
||||
windmill_common::worker::load_cache(&local_path, &remote_path).await;
|
||||
(cache, logs, local_path, remote_path)
|
||||
@@ -668,9 +708,9 @@ pub async fn handle_bun_job(
|
||||
(false, "".to_string(), "".to_string(), "".to_string())
|
||||
};
|
||||
|
||||
if !codebase.is_some() && !bundle_cache {
|
||||
if !codebase.is_some() && !has_bundle_cache {
|
||||
let _ = write_file(job_dir, "main.ts", inner_content).await?;
|
||||
} else {
|
||||
} else if !annotation.native_mode {
|
||||
let _ = write_file(job_dir, "package.json", r#"{ "type": "module" }"#).await?;
|
||||
};
|
||||
|
||||
@@ -690,7 +730,7 @@ pub async fn handle_bun_job(
|
||||
}
|
||||
|
||||
let mut gbuntar_name = None;
|
||||
if bundle_cache {
|
||||
if has_bundle_cache {
|
||||
let target = format!("{job_dir}/main.js");
|
||||
std::os::unix::fs::symlink(&local_path, &target).map_err(|e| {
|
||||
error::Error::ExecutionErr(format!(
|
||||
@@ -807,7 +847,7 @@ pub async fn handle_bun_job(
|
||||
|
||||
let mut init_logs = if annotation.native_mode {
|
||||
"\n\n--- NATIVE CODE EXECUTION ---\n".to_string()
|
||||
} else if bundle_cache {
|
||||
} else if has_bundle_cache {
|
||||
if annotation.nodejs_mode {
|
||||
"\n\n--- NODE BUNDLE SNAPSHOT EXECUTION ---\n".to_string()
|
||||
} else {
|
||||
@@ -832,11 +872,14 @@ pub async fn handle_bun_job(
|
||||
);
|
||||
}
|
||||
|
||||
if bundle_cache {
|
||||
if has_bundle_cache {
|
||||
init_logs = format!("\n{}{}", cache_logs, init_logs);
|
||||
}
|
||||
|
||||
let write_wrapper_f = async {
|
||||
if !has_bundle_cache && annotation.native_mode {
|
||||
return Ok(()) as error::Result<()>;
|
||||
}
|
||||
// let mut start = Instant::now();
|
||||
let args =
|
||||
windmill_parser_ts::parse_deno_signature(inner_content, true, main_override.clone())?
|
||||
@@ -859,7 +902,7 @@ pub async fn handle_bun_job(
|
||||
// we cannot use Bun.read and Bun.write because it results in an EBADF error on cloud
|
||||
let main_name = main_override.unwrap_or("main".to_string());
|
||||
|
||||
let main_import = if codebase.is_some() || bundle_cache {
|
||||
let main_import = if codebase.is_some() || has_bundle_cache {
|
||||
"./main.js"
|
||||
} else {
|
||||
"./main.ts"
|
||||
@@ -904,6 +947,9 @@ try {{
|
||||
};
|
||||
|
||||
let reserved_variables_args_out_f = async {
|
||||
if annotation.native_mode {
|
||||
return Ok(HashMap::new()) as error::Result<HashMap<String, String>>;
|
||||
}
|
||||
let args_and_out_f = async {
|
||||
create_args_and_out_file(&client, job, job_dir, db).await?;
|
||||
Ok(()) as Result<()>
|
||||
@@ -917,7 +963,7 @@ try {{
|
||||
Ok(reserved_variables) as error::Result<HashMap<String, String>>
|
||||
};
|
||||
|
||||
let build_cache = !bundle_cache
|
||||
let build_cache = !has_bundle_cache
|
||||
&& !annotation.nobundling
|
||||
&& !codebase.is_some()
|
||||
&& (requirements_o.is_some() || annotation.native_mode);
|
||||
@@ -939,7 +985,7 @@ try {{
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
} else if !codebase.is_some() && !bundle_cache {
|
||||
} else if !codebase.is_some() && !has_bundle_cache {
|
||||
build_loader(
|
||||
job_dir,
|
||||
base_internal_url,
|
||||
@@ -963,7 +1009,7 @@ try {{
|
||||
write_wrapper_f,
|
||||
write_loader_f
|
||||
)?;
|
||||
if !codebase.is_some() && !bundle_cache {
|
||||
if !codebase.is_some() && !has_bundle_cache {
|
||||
if build_cache {
|
||||
generate_bun_bundle(
|
||||
job_dir,
|
||||
@@ -977,7 +1023,6 @@ try {{
|
||||
&common_bun_proc_envs,
|
||||
)
|
||||
.await?;
|
||||
|
||||
if !local_path.is_empty() {
|
||||
match save_cache(&local_path, &remote_path, &format!("{job_dir}/main.js")).await {
|
||||
Err(e) => {
|
||||
@@ -992,19 +1037,21 @@ try {{
|
||||
}
|
||||
}
|
||||
}
|
||||
let ex_wrapper = read_file_content(&format!("{job_dir}/wrapper.mjs")).await?;
|
||||
write_file(
|
||||
job_dir,
|
||||
"wrapper.mjs",
|
||||
&ex_wrapper.replace(
|
||||
"import * as Main from \"./main.ts\"",
|
||||
"import * as Main from \"./main.js\"",
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
write_file(job_dir, "package.json", r#"{ "type": "module" }"#).await?;
|
||||
if !annotation.native_mode {
|
||||
let ex_wrapper = read_file_content(&format!("{job_dir}/wrapper.mjs")).await?;
|
||||
write_file(
|
||||
job_dir,
|
||||
"wrapper.mjs",
|
||||
&ex_wrapper.replace(
|
||||
"import * as Main from \"./main.ts\"",
|
||||
"import * as Main from \"./main.js\"",
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
write_file(job_dir, "package.json", r#"{ "type": "module" }"#).await?;
|
||||
}
|
||||
fs::remove_file(format!("{job_dir}/main.ts"))?;
|
||||
bundle_cache = true;
|
||||
has_bundle_cache = true;
|
||||
} else if annotation.nodejs_mode {
|
||||
generate_wrapper_mjs(
|
||||
job_dir,
|
||||
@@ -1100,7 +1147,7 @@ try {{
|
||||
&NODE_PATH,
|
||||
"/tmp/nodejs/wrapper.mjs",
|
||||
]
|
||||
} else if codebase.is_some() || bundle_cache {
|
||||
} else if codebase.is_some() || has_bundle_cache {
|
||||
vec![
|
||||
"--config",
|
||||
"run.config.proto",
|
||||
@@ -1154,7 +1201,7 @@ try {{
|
||||
let script_path = format!("{job_dir}/wrapper.mjs");
|
||||
|
||||
let mut bun_cmd = Command::new(&*BUN_PATH);
|
||||
let args = if codebase.is_some() || bundle_cache {
|
||||
let args = if codebase.is_some() || has_bundle_cache {
|
||||
vec!["run", &script_path]
|
||||
} else {
|
||||
vec![
|
||||
|
||||
@@ -3023,7 +3023,7 @@ mount {{
|
||||
)
|
||||
.await
|
||||
}
|
||||
Some(ScriptLang::Bun) => {
|
||||
Some(ScriptLang::Bun) | Some(ScriptLang::Bunnative) => {
|
||||
handle_bun_job(
|
||||
requirements_o,
|
||||
codebase,
|
||||
|
||||
@@ -12,7 +12,7 @@ use windmill_common::flows::{FlowModule, FlowModuleValue};
|
||||
use windmill_common::get_latest_deployed_hash_for_path;
|
||||
use windmill_common::jobs::JobPayload;
|
||||
use windmill_common::scripts::ScriptHash;
|
||||
use windmill_common::worker::{to_raw_value, to_raw_value_owned};
|
||||
use windmill_common::worker::{get_annotation, to_raw_value, to_raw_value_owned};
|
||||
use windmill_common::{
|
||||
error::{self, to_anyhow},
|
||||
flows::FlowValue,
|
||||
@@ -187,14 +187,16 @@ fn parse_bun_relative_imports(raw_code: &str, script_path: &str) -> error::Resul
|
||||
Ok(relative_imports)
|
||||
}
|
||||
|
||||
fn extract_relative_imports(
|
||||
pub fn extract_relative_imports(
|
||||
raw_code: &str,
|
||||
script_path: &str,
|
||||
language: &Option<ScriptLang>,
|
||||
) -> Option<Vec<String>> {
|
||||
match language {
|
||||
Some(ScriptLang::Python3) => parse_relative_imports(&raw_code, script_path).ok(),
|
||||
Some(ScriptLang::Bun) => parse_bun_relative_imports(&raw_code, script_path).ok(),
|
||||
Some(ScriptLang::Bun) | Some(ScriptLang::Bunnative) => {
|
||||
parse_bun_relative_imports(&raw_code, script_path).ok()
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -286,7 +288,7 @@ pub async fn handle_dependency_job<R: rsmq_async::RsmqConnection + Send + Sync +
|
||||
let hash = job.script_hash.unwrap_or(ScriptHash(0));
|
||||
let w_id = &job.workspace_id;
|
||||
sqlx::query!(
|
||||
"UPDATE script SET lock = $1 WHERE hash = $2 AND workspace_id = $3",
|
||||
"UPDATE script SET lock = $1, created_at = now() WHERE hash = $2 AND workspace_id = $3",
|
||||
&content,
|
||||
&hash.0,
|
||||
w_id
|
||||
@@ -700,7 +702,7 @@ async fn lock_modules<'c>(
|
||||
lock,
|
||||
path,
|
||||
content,
|
||||
language,
|
||||
mut language,
|
||||
input_transforms,
|
||||
tag,
|
||||
custom_concurrency_key,
|
||||
@@ -852,8 +854,11 @@ async fn lock_modules<'c>(
|
||||
}
|
||||
} else {
|
||||
if lock.as_ref().is_some_and(|x| !x.trim().is_empty()) {
|
||||
new_flow_modules.push(e);
|
||||
continue;
|
||||
let skip_creating_new_lock = skip_creating_new_lock(&language, &content);
|
||||
if skip_creating_new_lock {
|
||||
new_flow_modules.push(e);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -911,6 +916,14 @@ async fn lock_modules<'c>(
|
||||
append_logs(&job.id, &job.workspace_id, logs, db).await;
|
||||
}
|
||||
|
||||
if language == ScriptLang::Bun || language == ScriptLang::Bunnative {
|
||||
let anns = get_annotation(&content);
|
||||
if anns.native_mode && language == ScriptLang::Bun {
|
||||
language = ScriptLang::Bunnative;
|
||||
} else if !anns.native_mode && language == ScriptLang::Bunnative {
|
||||
language = ScriptLang::Bun;
|
||||
};
|
||||
}
|
||||
e.value = windmill_common::worker::to_raw_value(&FlowModuleValue::RawScript {
|
||||
lock: Some(new_lock),
|
||||
path,
|
||||
@@ -952,6 +965,18 @@ async fn lock_modules<'c>(
|
||||
Ok((new_flow_modules, tx, modified_ids))
|
||||
}
|
||||
|
||||
fn skip_creating_new_lock(language: &ScriptLang, content: &str) -> bool {
|
||||
if language == &ScriptLang::Bun || language == &ScriptLang::Bunnative {
|
||||
let anns = get_annotation(&content);
|
||||
if anns.native_mode && language == &ScriptLang::Bun {
|
||||
return false;
|
||||
} else if !anns.native_mode && language == &ScriptLang::Bunnative {
|
||||
return false;
|
||||
};
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
#[async_recursion]
|
||||
async fn lock_modules_app(
|
||||
value: Value,
|
||||
@@ -985,10 +1010,12 @@ async fn lock_modules_app(
|
||||
if v.get("lock")
|
||||
.is_some_and(|x| !x.as_str().unwrap().trim().is_empty())
|
||||
{
|
||||
logs.push_str(
|
||||
"Found already locked inline script. Skipping lock...\n",
|
||||
);
|
||||
return Ok(Value::Object(m.clone()));
|
||||
if skip_creating_new_lock(&language, &content) {
|
||||
logs.push_str(
|
||||
"Found already locked inline script. Skipping lock...\n",
|
||||
);
|
||||
return Ok(Value::Object(m.clone()));
|
||||
}
|
||||
}
|
||||
logs.push_str("Found lockable inline script. Generating lock...\n");
|
||||
let new_lock = capture_dependency_job(
|
||||
@@ -1012,6 +1039,21 @@ async fn lock_modules_app(
|
||||
match new_lock {
|
||||
Ok(new_lock) => {
|
||||
append_logs(&job.id, &job.workspace_id, logs, db).await;
|
||||
let anns = get_annotation(&content);
|
||||
let nlang = if anns.native_mode && language == ScriptLang::Bun {
|
||||
Some(ScriptLang::Bunnative)
|
||||
} else if !anns.native_mode && language == ScriptLang::Bunnative
|
||||
{
|
||||
Some(ScriptLang::Bun)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if let Some(nlang) = nlang {
|
||||
v.insert(
|
||||
"language".to_string(),
|
||||
serde_json::Value::String(nlang.as_str().to_string()),
|
||||
);
|
||||
}
|
||||
v.insert(
|
||||
"lock".to_string(),
|
||||
serde_json::Value::String(new_lock),
|
||||
@@ -1293,7 +1335,7 @@ async fn capture_dependency_job(
|
||||
)
|
||||
.await
|
||||
}
|
||||
ScriptLang::Bun => {
|
||||
ScriptLang::Bun | ScriptLang::Bunnative => {
|
||||
let npm_mode = npm_mode
|
||||
.unwrap_or_else(|| windmill_common::worker::get_annotation(job_raw_code).npm_mode);
|
||||
if !raw_deps {
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
function computeLangs(defaultScripts: WorkspaceDefaultScripts | undefined) {
|
||||
const allLangs = Object.keys(defaultScriptLanguages)
|
||||
if (!defaultScripts || defaultScripts.order == undefined) return allLangs
|
||||
return defaultScripts.order?.concat(allLangs.filter((l) => !defaultScripts.order?.includes(l)))
|
||||
return defaultScripts.order
|
||||
?.concat(allLangs.filter((l) => !defaultScripts.order?.includes(l)))
|
||||
.filter((x) => x != 'nativets')
|
||||
}
|
||||
|
||||
async function changePosition(i: number, up: boolean) {
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
export let useWebsockets: boolean = true
|
||||
export let listenEmptyChanges = false
|
||||
export let small = false
|
||||
export let scriptLang: Preview['language']
|
||||
export let scriptLang: Preview['language'] | 'bunnative'
|
||||
export let disabled: boolean = false
|
||||
|
||||
const rHash = randomHash()
|
||||
@@ -127,7 +127,9 @@
|
||||
|
||||
let initialPath: string | undefined = path
|
||||
|
||||
$: path != initialPath && (scriptLang == 'deno' || scriptLang == 'bun') && handlePathChange()
|
||||
$: path != initialPath &&
|
||||
(scriptLang == 'deno' || scriptLang == 'bun' || scriptLang == 'bunnative') &&
|
||||
handlePathChange()
|
||||
|
||||
let websockets: WebSocket[] = []
|
||||
let languageClients: MonacoLanguageClient[] = []
|
||||
@@ -1147,7 +1149,7 @@
|
||||
const hostname = getHostname()
|
||||
|
||||
// const stdLib = { content: libStdContent, filePath: 'es6.d.ts' }
|
||||
if (scriptLang == 'bun') {
|
||||
if (scriptLang == 'bun' || scriptLang == 'bunnative') {
|
||||
// const processLib = { content: processStdContent, filePath: 'process.d.ts' }
|
||||
// const domLib = { content: domContent, filePath: 'dom.d.ts' }
|
||||
// languages.typescript.typescriptDefaults.setExtraLibs([stdLib, domLib, processLib])
|
||||
|
||||
@@ -58,7 +58,8 @@
|
||||
export let iconOnly: boolean = false
|
||||
export let validCode: boolean = true
|
||||
export let kind: 'script' | 'trigger' | 'approval' = 'script'
|
||||
export let template: 'pgsql' | 'mysql' | 'script' | 'docker' | 'powershell' = 'script'
|
||||
export let template: 'pgsql' | 'mysql' | 'script' | 'docker' | 'powershell' | 'bunnative' =
|
||||
'script'
|
||||
export let collabMode = false
|
||||
export let collabLive = false
|
||||
export let collabUsers: { name: string }[] = []
|
||||
|
||||
@@ -57,7 +57,12 @@
|
||||
import MetadataGen from './copilot/MetadataGen.svelte'
|
||||
import ScriptSchedules from './ScriptSchedules.svelte'
|
||||
import { writable } from 'svelte/store'
|
||||
import { type ScriptSchedule, loadScriptSchedule, defaultScriptLanguages } from '$lib/scripts'
|
||||
import {
|
||||
type ScriptSchedule,
|
||||
loadScriptSchedule,
|
||||
defaultScriptLanguages,
|
||||
processLangs
|
||||
} from '$lib/scripts'
|
||||
import DefaultScripts from './DefaultScripts.svelte'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import CustomPopover from './CustomPopover.svelte'
|
||||
@@ -65,7 +70,7 @@
|
||||
|
||||
export let script: NewScript
|
||||
export let initialPath: string = ''
|
||||
export let template: 'docker' | 'script' = 'script'
|
||||
export let template: 'docker' | 'bunnative' | 'script' = 'script'
|
||||
export let initialArgs: Record<string, any> = {}
|
||||
export let lockedLanguage = false
|
||||
export let showMeta: boolean = false
|
||||
@@ -114,11 +119,14 @@
|
||||
editor?.setCode(code)
|
||||
}
|
||||
|
||||
$: langs = ($defaultScripts?.order ?? Object.keys(defaultScriptLanguages))
|
||||
$: langs = processLangs(
|
||||
script.language,
|
||||
$defaultScripts?.order ?? Object.keys(defaultScriptLanguages)
|
||||
)
|
||||
.map((l) => [defaultScriptLanguages[l], l])
|
||||
.filter(
|
||||
(x) => $defaultScripts?.hidden == undefined || !$defaultScripts.hidden.includes(x[1])
|
||||
) as [string, SupportedLanguage | 'docker'][]
|
||||
) as [string, SupportedLanguage | 'docker' | 'bunnative'][]
|
||||
|
||||
const scriptKindOptions: {
|
||||
value: Script['kind']
|
||||
@@ -176,7 +184,7 @@
|
||||
function initContent(
|
||||
language: SupportedLanguage,
|
||||
kind: Script['kind'] | undefined,
|
||||
template: 'pgsql' | 'mysql' | 'script' | 'docker' | 'powershell'
|
||||
template: 'pgsql' | 'mysql' | 'script' | 'docker' | 'powershell' | 'bunnative'
|
||||
) {
|
||||
scriptEditor?.disableCollaboration()
|
||||
script.content = initialCode(language, kind, template)
|
||||
@@ -462,6 +470,16 @@
|
||||
|
||||
let deploymentMsg = ''
|
||||
let msgInput: HTMLInputElement | undefined = undefined
|
||||
|
||||
function langToLanguage(lang: SupportedLanguage | 'docker' | 'bunnative'): SupportedLanguage {
|
||||
if (lang == 'docker') {
|
||||
return 'bash'
|
||||
}
|
||||
if (lang == 'bunnative') {
|
||||
return 'bun'
|
||||
}
|
||||
return lang
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={onKeyDown} />
|
||||
@@ -567,9 +585,12 @@
|
||||
</div>
|
||||
{/if}
|
||||
<div class=" grid grid-cols-3 gap-2">
|
||||
{script.language}
|
||||
{template}
|
||||
{#each langs as [label, lang] (lang)}
|
||||
{@const isPicked =
|
||||
(lang == script.language && template == 'script') ||
|
||||
(template == 'bunnative' && lang == 'bunnative') ||
|
||||
(template == 'docker' && lang == 'docker')}
|
||||
<Popover
|
||||
disablePopup={!enterpriseLangs.includes(lang) || !!$enterpriseLicense}
|
||||
@@ -602,10 +623,12 @@
|
||||
return
|
||||
}
|
||||
template = 'docker'
|
||||
} else if (lang == 'bunnative') {
|
||||
template = 'bunnative'
|
||||
} else {
|
||||
template = 'script'
|
||||
}
|
||||
let language = lang == 'docker' ? 'bash' : lang
|
||||
let language = langToLanguage(lang)
|
||||
//
|
||||
initContent(language, script.kind, template)
|
||||
script.language = language
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
export let path: string | undefined
|
||||
export let lang: Preview['language']
|
||||
export let kind: string | undefined = undefined
|
||||
export let template: 'pgsql' | 'mysql' | 'script' | 'docker' | 'powershell' = 'script'
|
||||
export let template: 'pgsql' | 'mysql' | 'script' | 'docker' | 'powershell' | 'bunnative' =
|
||||
'script'
|
||||
export let tag: string | undefined
|
||||
export let initialArgs: Record<string, any> = {}
|
||||
export let fixedOverflowWidgets = true
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import { inferArgs } from '$lib/infer'
|
||||
import { initialCode } from '$lib/script_helpers'
|
||||
import { emptySchema } from '$lib/utils'
|
||||
import { defaultScriptLanguages, getScriptByPath } from '$lib/scripts'
|
||||
import { defaultScriptLanguages, getScriptByPath, processLangs } from '$lib/scripts'
|
||||
|
||||
import { Building, GitFork, Globe2 } from 'lucide-svelte'
|
||||
import { createEventDispatcher, getContext } from 'svelte'
|
||||
@@ -94,7 +94,7 @@
|
||||
dispatch('new', unusedInlineScript.inlineScript)
|
||||
}
|
||||
|
||||
$: langs = ($defaultScripts?.order ?? Object.keys(defaultScriptLanguages))
|
||||
$: langs = processLangs(undefined, $defaultScripts?.order ?? Object.keys(defaultScriptLanguages))
|
||||
.map((l) => [defaultScriptLanguages[l], l])
|
||||
.filter(
|
||||
(x) =>
|
||||
|
||||
+6
-4
@@ -314,10 +314,12 @@
|
||||
if (inlineScript) {
|
||||
inlineScript.content = editor?.getCode() ?? ''
|
||||
}
|
||||
runLoading = true
|
||||
await Promise.all(
|
||||
$runnableComponents[id]?.cb?.map((f) => f?.(inlineScript, true)) ?? []
|
||||
)
|
||||
try {
|
||||
runLoading = true
|
||||
await Promise.all(
|
||||
$runnableComponents[id]?.cb?.map((f) => f?.(inlineScript, true)) ?? []
|
||||
)
|
||||
} catch {}
|
||||
runLoading = false
|
||||
}}
|
||||
on:change={async (e) => {
|
||||
|
||||
@@ -26,17 +26,19 @@
|
||||
| 'fetch'
|
||||
| 'docker'
|
||||
| 'powershell'
|
||||
| 'bunnative'
|
||||
export let width = 30
|
||||
export let height = 30
|
||||
export let scale = 1
|
||||
|
||||
const languageLabel: Record<Script['language'], String> = {
|
||||
const languageLabel: Record<Script['language'] | 'bunnative', String> = {
|
||||
python3: 'Python',
|
||||
deno: 'TypeScript',
|
||||
go: 'Go',
|
||||
bash: 'Bash',
|
||||
powershell: 'PowerShell',
|
||||
nativets: 'HTTP',
|
||||
bunnative: 'HTTP',
|
||||
graphql: 'GraphQL',
|
||||
postgresql: 'Postgresql',
|
||||
bigquery: 'BigQuery',
|
||||
@@ -48,7 +50,7 @@
|
||||
}
|
||||
|
||||
const langToComponent: Record<
|
||||
SupportedLanguage | 'pgsql' | 'javascript' | 'fetch' | 'docker' | 'powershell',
|
||||
SupportedLanguage | 'pgsql' | 'javascript' | 'fetch' | 'docker' | 'powershell' | 'bunnative',
|
||||
any
|
||||
> = {
|
||||
go: GoIcon,
|
||||
@@ -56,6 +58,7 @@
|
||||
deno: TypeScriptIcon,
|
||||
// graphql: TypeScriptIcon,
|
||||
bun: TypeScriptIcon,
|
||||
bunnative: RestIcon,
|
||||
bash: BashIcon,
|
||||
pgsql: PostgresIcon,
|
||||
mysql: MySQLIcon,
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
import { Check, Code, Zap } from 'lucide-svelte'
|
||||
import SuspendDrawer from './SuspendDrawer.svelte'
|
||||
import { defaultScripts } from '$lib/stores'
|
||||
import { defaultScriptLanguages } from '$lib/scripts'
|
||||
import { defaultScriptLanguages, processLangs } from '$lib/scripts'
|
||||
import type { SupportedLanguage } from '$lib/common'
|
||||
import DefaultScripts from '$lib/components/DefaultScripts.svelte'
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
let pick_existing: 'workspace' | 'hub' = 'hub'
|
||||
let filter = ''
|
||||
|
||||
$: langs = ($defaultScripts?.order ?? Object.keys(defaultScriptLanguages))
|
||||
$: langs = processLangs(undefined, $defaultScripts?.order ?? Object.keys(defaultScriptLanguages))
|
||||
.map((l) => [defaultScriptLanguages[l], l])
|
||||
.filter(
|
||||
(x) => $defaultScripts?.hidden == undefined || !$defaultScripts.hidden.includes(x[1])
|
||||
@@ -161,7 +161,10 @@
|
||||
{/if}
|
||||
<h3 class="pb-2 pt-4 flex gap-x-8 flex-wrap">
|
||||
<div>
|
||||
Inline new <span class="text-blue-500 dark:text-blue-400">{kind == 'script' ? 'action' : kind}</span> script
|
||||
Inline new <span class="text-blue-500 dark:text-blue-400"
|
||||
>{kind == 'script' ? 'action' : kind}</span
|
||||
>
|
||||
script
|
||||
<Tooltip
|
||||
documentationLink={kind === 'script'
|
||||
? 'https://www.windmill.dev/docs/flows/editor_components#flow-actions'
|
||||
@@ -229,7 +232,9 @@
|
||||
</div>
|
||||
|
||||
<h3 class="mb-2 mt-6"
|
||||
>Use pre-made <span class="text-blue-500 dark:text-blue-400">{kind == 'script' ? 'action' : kind}</span> script</h3
|
||||
>Use pre-made <span class="text-blue-500 dark:text-blue-400"
|
||||
>{kind == 'script' ? 'action' : kind}</span
|
||||
> script</h3
|
||||
>
|
||||
{#if pick_existing == 'hub'}
|
||||
<PickHubScript bind:filter {kind} on:pick>
|
||||
|
||||
@@ -42,6 +42,8 @@ export function langToExt(lang: string): string {
|
||||
switch (lang) {
|
||||
case 'javascript':
|
||||
return 'ts'
|
||||
case 'bunnative':
|
||||
return 'ts'
|
||||
case 'json':
|
||||
return 'json'
|
||||
case 'sql':
|
||||
|
||||
@@ -43,7 +43,7 @@ export function parseDeps(code: string): string[] {
|
||||
}
|
||||
|
||||
export async function inferArgs(
|
||||
language: SupportedLanguage | undefined,
|
||||
language: SupportedLanguage | 'bunnative' | undefined,
|
||||
code: string,
|
||||
schema: Schema
|
||||
): Promise<boolean | null> {
|
||||
@@ -67,7 +67,7 @@ export async function inferArgs(
|
||||
inferedSchema = JSON.parse(parse_deno(code))
|
||||
} else if (language == 'nativets') {
|
||||
inferedSchema = JSON.parse(parse_deno(code))
|
||||
} else if (language == 'bun') {
|
||||
} else if (language == 'bun' || language == 'bunnative') {
|
||||
inferedSchema = JSON.parse(parse_deno(code))
|
||||
} else if (language == 'postgresql') {
|
||||
inferedSchema = JSON.parse(parse_sql(code))
|
||||
|
||||
@@ -25,6 +25,22 @@ export async function main(example_input: number = 3) {
|
||||
}
|
||||
`
|
||||
|
||||
export const BUNNATIVE_INIT_CODE = `//native
|
||||
|
||||
// native scripts are bun scripts that are executed on native workers and can be parallelized
|
||||
// only fetch is allowed, but imports will work as long as they also use only fetch and the standard lib
|
||||
|
||||
//import * as wmill from "windmill-client"
|
||||
|
||||
export async function main(example_input: number = 3) {
|
||||
// "3" is the default value of example_input, it can be overriden with code or using the UI
|
||||
const res = await fetch(\`https://jsonplaceholder.typicode.com/todos/\${example_input}\`, {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
return res.json();
|
||||
}
|
||||
`
|
||||
|
||||
export const NATIVETS_INIT_CODE_CLEAR = `// Fetch-only script, no imports allowed (except windmill) but benefits from a dedicated highly efficient runtime
|
||||
//import * as wmill from './windmill.ts'
|
||||
|
||||
@@ -459,9 +475,18 @@ export function isInitialCode(content: string): boolean {
|
||||
}
|
||||
|
||||
export function initialCode(
|
||||
language: SupportedLanguage | undefined,
|
||||
language: SupportedLanguage | 'bunnative' | undefined,
|
||||
kind: Script['kind'] | undefined,
|
||||
subkind: 'pgsql' | 'mysql' | 'flow' | 'script' | 'fetch' | 'docker' | 'powershell' | undefined
|
||||
subkind:
|
||||
| 'pgsql'
|
||||
| 'mysql'
|
||||
| 'flow'
|
||||
| 'script'
|
||||
| 'fetch'
|
||||
| 'docker'
|
||||
| 'powershell'
|
||||
| 'bunnative'
|
||||
| undefined
|
||||
): string {
|
||||
if (!kind) {
|
||||
kind = 'script'
|
||||
@@ -524,8 +549,10 @@ export function initialCode(
|
||||
return GRAPHQL_INIT_CODE
|
||||
} else if (language == 'php') {
|
||||
return PHP_INIT_CODE
|
||||
} else if (language == 'bun') {
|
||||
if (kind === 'approval') {
|
||||
} else if (language == 'bun' || language == 'bunnative') {
|
||||
if (language == 'bunnative' || subkind === 'bunnative') {
|
||||
return BUNNATIVE_INIT_CODE
|
||||
} else if (kind === 'approval') {
|
||||
return BUN_INIT_CODE_APPROVAL
|
||||
} else if (kind === 'failure') {
|
||||
return BUN_FAILURE_MODULE_CODE
|
||||
@@ -549,7 +576,16 @@ export function initialCode(
|
||||
export function getResetCode(
|
||||
language: SupportedLanguage | undefined,
|
||||
kind: Script['kind'] | undefined,
|
||||
subkind: 'pgsql' | 'mysql' | 'flow' | 'script' | 'fetch' | 'docker' | 'powershell' | undefined
|
||||
subkind:
|
||||
| 'pgsql'
|
||||
| 'mysql'
|
||||
| 'flow'
|
||||
| 'script'
|
||||
| 'fetch'
|
||||
| 'docker'
|
||||
| 'powershell'
|
||||
| 'bunnative'
|
||||
| undefined
|
||||
) {
|
||||
if (language === 'deno') {
|
||||
return DENO_INIT_CODE_CLEAR
|
||||
|
||||
@@ -4,10 +4,10 @@ import type { Schema, SupportedLanguage } from './common'
|
||||
import { FlowService, type Script, ScriptService, ScheduleService } from './gen'
|
||||
import { workspaceStore } from './stores'
|
||||
|
||||
export function scriptLangToEditorLang(lang: Script['language'] | undefined) {
|
||||
export function scriptLangToEditorLang(lang: Script['language'] | 'bunnative' | undefined) {
|
||||
if (lang == 'deno') {
|
||||
return 'typescript'
|
||||
} else if (lang == 'bun') {
|
||||
} else if (lang == 'bun' || lang == 'bunnative') {
|
||||
return 'typescript'
|
||||
} else if (lang == 'nativets') {
|
||||
return 'typescript'
|
||||
@@ -92,13 +92,14 @@ export function scriptPathToHref(path: string, hubBaseUrl: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
const scriptLanguagesArray: [SupportedLanguage | 'docker', string][] = [
|
||||
const scriptLanguagesArray: [SupportedLanguage | 'docker' | 'bunnative', string][] = [
|
||||
['bun', 'TypeScript (Bun)'],
|
||||
['python3', 'Python'],
|
||||
['deno', 'TypeScript (Deno)'],
|
||||
['bash', 'Bash'],
|
||||
['go', 'Go'],
|
||||
['nativets', 'REST'],
|
||||
['bunnative', 'REST'],
|
||||
['postgresql', 'PostgreSQL'],
|
||||
['mysql', 'MySQL'],
|
||||
['bigquery', 'BigQuery'],
|
||||
@@ -109,6 +110,18 @@ const scriptLanguagesArray: [SupportedLanguage | 'docker', string][] = [
|
||||
['php', 'PHP'],
|
||||
['docker', 'Docker']
|
||||
]
|
||||
export function processLangs(selected: string | undefined, langs: string[]): string[] {
|
||||
if (selected === 'nativets') {
|
||||
return langs
|
||||
} else {
|
||||
let ls = langs.filter((lang) => lang !== 'nativets')
|
||||
if (!ls.includes('bunnative')) {
|
||||
ls.push('bunnative')
|
||||
}
|
||||
return ls
|
||||
}
|
||||
}
|
||||
|
||||
export const defaultScriptLanguages = Object.fromEntries(scriptLanguagesArray)
|
||||
|
||||
export async function getScriptByPath(path: string): Promise<{
|
||||
|
||||
Reference in New Issue
Block a user