feat: bun support (#1800)
* feat: bun support * feat: bun support * add bun support * add bun support * add bun support * add bun
This commit is contained in:
@@ -130,6 +130,8 @@ COPY --from=builder /windmill/target/release/windmill ${APP}/windmill
|
||||
COPY --from=nsjail /nsjail/nsjail /bin/nsjail
|
||||
|
||||
COPY --from=denoland/deno:1.35.0 /usr/bin/deno /usr/bin/deno
|
||||
COPY --from=oven/bun:0.6.13 /usr/bin/bun /usr/bin/bun
|
||||
|
||||
|
||||
# docker does not support conditional COPY and we want to use the same Dockerfile for both amd64 and arm64 and privilege the official image
|
||||
COPY --from=lukechannings/deno:v1.35.0 /usr/bin/deno /usr/bin/deno-arm
|
||||
|
||||
@@ -22,8 +22,9 @@ use tokio::{
|
||||
use windmill_api::{LICENSE_KEY, OAUTH_CLIENTS, SMTP_CLIENT};
|
||||
use windmill_common::{utils::rd_string, METRICS_ADDR};
|
||||
use windmill_worker::{
|
||||
DENO_CACHE_DIR, DENO_TMP_CACHE_DIR, GO_CACHE_DIR, GO_TMP_CACHE_DIR, HUB_CACHE_DIR,
|
||||
HUB_TMP_CACHE_DIR, PIP_CACHE_DIR, ROOT_TMP_CACHE_DIR, TAR_PIP_TMP_CACHE_DIR,
|
||||
BUN_CACHE_DIR, BUN_TMP_CACHE_DIR, DENO_CACHE_DIR, DENO_TMP_CACHE_DIR, GO_CACHE_DIR,
|
||||
GO_TMP_CACHE_DIR, HUB_CACHE_DIR, HUB_TMP_CACHE_DIR, PIP_CACHE_DIR, ROOT_TMP_CACHE_DIR,
|
||||
TAR_PIP_TMP_CACHE_DIR,
|
||||
};
|
||||
|
||||
const GIT_VERSION: &str = git_version!(args = ["--tag", "--always"], fallback = "unknown-version");
|
||||
@@ -334,10 +335,12 @@ pub async fn run_workers<R: rsmq_async::RsmqConnection + Send + Sync + Clone + '
|
||||
for x in [
|
||||
PIP_CACHE_DIR,
|
||||
DENO_CACHE_DIR,
|
||||
BUN_CACHE_DIR,
|
||||
GO_CACHE_DIR,
|
||||
HUB_CACHE_DIR,
|
||||
TAR_PIP_TMP_CACHE_DIR,
|
||||
DENO_TMP_CACHE_DIR,
|
||||
BUN_TMP_CACHE_DIR,
|
||||
GO_TMP_CACHE_DIR,
|
||||
HUB_TMP_CACHE_DIR,
|
||||
] {
|
||||
|
||||
@@ -5109,7 +5109,7 @@ paths:
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- $ref: "#/components/parameters/RunnableId"
|
||||
- $ref: "#/components/parameters/RunnableType"
|
||||
- $ref: "#/components/parameters/RunnableTypeQuery"
|
||||
- $ref: "#/components/parameters/Page"
|
||||
- $ref: "#/components/parameters/PerPage"
|
||||
responses:
|
||||
@@ -5131,7 +5131,7 @@ paths:
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- $ref: "#/components/parameters/RunnableId"
|
||||
- $ref: "#/components/parameters/RunnableType"
|
||||
- $ref: "#/components/parameters/RunnableTypeQuery"
|
||||
- $ref: "#/components/parameters/Page"
|
||||
- $ref: "#/components/parameters/PerPage"
|
||||
responses:
|
||||
@@ -5153,7 +5153,7 @@ paths:
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- $ref: "#/components/parameters/RunnableId"
|
||||
- $ref: "#/components/parameters/RunnableType"
|
||||
- $ref: "#/components/parameters/RunnableTypeQuery"
|
||||
requestBody:
|
||||
description: Input
|
||||
required: true
|
||||
@@ -5491,7 +5491,7 @@ components:
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
RunnableType:
|
||||
RunnableTypeQuery:
|
||||
name: runnable_type
|
||||
in: query
|
||||
schema:
|
||||
|
||||
@@ -4,10 +4,7 @@ mode: ONCE
|
||||
hostname: "bash"
|
||||
log_level: ERROR
|
||||
|
||||
rlimit_as: 4096
|
||||
rlimit_cpu: 1000
|
||||
rlimit_fsize: 1000
|
||||
rlimit_nofile: 10000
|
||||
disable_rl: true
|
||||
|
||||
cwd: "/tmp"
|
||||
|
||||
|
||||
121
backend/windmill-worker/nsjail/run.bun.config.proto
Normal file
121
backend/windmill-worker/nsjail/run.bun.config.proto
Normal file
@@ -0,0 +1,121 @@
|
||||
name: "bun run script"
|
||||
|
||||
mode: ONCE
|
||||
hostname: "bun"
|
||||
log_level: ERROR
|
||||
|
||||
disable_rl: true
|
||||
|
||||
mount_proc: true
|
||||
|
||||
cwd: "/tmp/bun"
|
||||
|
||||
clone_newnet: false
|
||||
clone_newuser: {CLONE_NEWUSER}
|
||||
|
||||
keep_caps: false
|
||||
keep_env: true
|
||||
|
||||
mount {
|
||||
src: "/bin"
|
||||
dst: "/bin"
|
||||
is_bind: true
|
||||
}
|
||||
|
||||
mount {
|
||||
src: "/lib"
|
||||
dst: "/lib"
|
||||
is_bind: true
|
||||
}
|
||||
|
||||
|
||||
mount {
|
||||
src: "/lib64"
|
||||
dst: "/lib64"
|
||||
is_bind: true
|
||||
}
|
||||
|
||||
|
||||
mount {
|
||||
src: "/usr"
|
||||
dst: "/usr"
|
||||
is_bind: true
|
||||
}
|
||||
|
||||
mount {
|
||||
src: "/dev/null"
|
||||
dst: "/dev/null"
|
||||
is_bind: true
|
||||
rw: true
|
||||
}
|
||||
|
||||
mount {
|
||||
dst: "/tmp"
|
||||
fstype: "tmpfs"
|
||||
rw: true
|
||||
options: "size=500000000"
|
||||
}
|
||||
|
||||
|
||||
mount {
|
||||
src: "{JOB_DIR}/wrapper.ts"
|
||||
dst: "/tmp/bun/wrapper.ts"
|
||||
is_bind: true
|
||||
mandatory: false
|
||||
}
|
||||
|
||||
|
||||
mount {
|
||||
src: "{JOB_DIR}/main.ts"
|
||||
dst: "/tmp/bun/main.ts"
|
||||
is_bind: true
|
||||
mandatory: false
|
||||
}
|
||||
|
||||
|
||||
mount {
|
||||
src: "{JOB_DIR}/args.json"
|
||||
dst: "/tmp/bun/args.json"
|
||||
is_bind: true
|
||||
}
|
||||
|
||||
mount {
|
||||
src: "{JOB_DIR}/result.json"
|
||||
dst: "/tmp/bun/result.json"
|
||||
rw: true
|
||||
is_bind: true
|
||||
}
|
||||
|
||||
mount {
|
||||
src: "/etc"
|
||||
dst: "/etc"
|
||||
is_bind: true
|
||||
}
|
||||
|
||||
mount {
|
||||
src: "/dev/random"
|
||||
dst: "/dev/random"
|
||||
is_bind: true
|
||||
}
|
||||
|
||||
mount {
|
||||
src: "/dev/urandom"
|
||||
dst: "/dev/urandom"
|
||||
is_bind: true
|
||||
}
|
||||
|
||||
iface_no_lo: true
|
||||
|
||||
mount {
|
||||
src: "{CACHE_DIR}"
|
||||
dst: "/tmp/windmill/cache/bun"
|
||||
is_bind: true
|
||||
rw: true
|
||||
mandatory: false
|
||||
}
|
||||
|
||||
{SHARED_MOUNT}
|
||||
|
||||
envar: "HOME=/tmp/bun"
|
||||
|
||||
|
||||
@@ -4,10 +4,7 @@ mode: ONCE
|
||||
hostname: "go"
|
||||
log_level: ERROR
|
||||
|
||||
rlimit_as: 4096
|
||||
rlimit_cpu: 1000
|
||||
rlimit_fsize: 1000
|
||||
rlimit_nofile: 10000
|
||||
disable_rl: true
|
||||
|
||||
cwd: "/tmp/go"
|
||||
|
||||
|
||||
@@ -153,6 +153,8 @@ pub async fn copy_cache_from_bucket(bucket: &str, tx: Sender<()>) -> error::Resu
|
||||
"--filter",
|
||||
"+ deno/**",
|
||||
"--filter",
|
||||
"+ bun/**",
|
||||
"--filter",
|
||||
"+ go/**",
|
||||
"--filter",
|
||||
"+ tar/**",
|
||||
@@ -195,6 +197,8 @@ pub async fn copy_cache_to_bucket(bucket: &str) -> error::Result<()> {
|
||||
"--filter",
|
||||
"+ deno/**",
|
||||
"--filter",
|
||||
"+ bun/**",
|
||||
"--filter",
|
||||
"+ go/**",
|
||||
"--filter",
|
||||
"- *",
|
||||
@@ -226,6 +230,7 @@ pub async fn copy_cache_to_bucket_as_tar(bucket: &str) {
|
||||
&format!("{ROOT_TMP_CACHE_DIR}{TAR_CACHE_FILENAME}"),
|
||||
"go",
|
||||
"deno",
|
||||
"bun",
|
||||
],
|
||||
)
|
||||
.await
|
||||
@@ -277,7 +282,7 @@ pub async fn copy_cache_to_bucket_as_tar(bucket: &str) {
|
||||
pub async fn copy_denogo_cache_from_bucket_as_tar(bucket: &str) {
|
||||
use tokio::fs::metadata;
|
||||
|
||||
tracing::info!("Copying denogo cache from bucket {bucket} as tar");
|
||||
tracing::info!("Copying deno,go,bun cache from bucket {bucket} as tar");
|
||||
|
||||
let start: Instant = Instant::now();
|
||||
|
||||
@@ -295,7 +300,7 @@ pub async fn copy_denogo_cache_from_bucket_as_tar(bucket: &str) {
|
||||
)
|
||||
.await
|
||||
{
|
||||
tracing::info!("Failed copying denogo tar from cache. Error: {:?}", e);
|
||||
tracing::info!("Failed copying deno,go,bun tar from cache. Error: {:?}", e);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -309,7 +314,7 @@ pub async fn copy_denogo_cache_from_bucket_as_tar(bucket: &str) {
|
||||
)
|
||||
.await
|
||||
{
|
||||
tracing::info!("Failed to untar denogo. Error: {:?}", e);
|
||||
tracing::info!("Failed to untar denogobun tar. Error: {:?}", e);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -321,12 +326,12 @@ pub async fn copy_denogo_cache_from_bucket_as_tar(bucket: &str) {
|
||||
if let Err(e) =
|
||||
tokio::fs::remove_file(format!("{ROOT_TMP_CACHE_DIR}{TAR_CACHE_FILENAME}")).await
|
||||
{
|
||||
tracing::info!("Failed to remove denotar cache. Error: {:?}", e);
|
||||
tracing::info!("Failed to remove denogobuntar cache. Error: {:?}", e);
|
||||
return;
|
||||
};
|
||||
|
||||
tracing::info!(
|
||||
"Finished copying denogotar from bucket {bucket} as tar, took: {:?}s",
|
||||
"Finished copying denogobuntar from bucket {bucket} as tar, took: {:?}s",
|
||||
start.elapsed().as_secs()
|
||||
);
|
||||
}
|
||||
@@ -390,6 +395,8 @@ pub async fn copy_tmp_cache_to_cache() -> error::Result<()> {
|
||||
"--filter",
|
||||
"+ deno/**",
|
||||
"--filter",
|
||||
"+ bun/**",
|
||||
"--filter",
|
||||
"+ go/**",
|
||||
"--filter",
|
||||
"- *",
|
||||
@@ -480,6 +487,8 @@ pub async fn copy_cache_to_tmp_cache() -> error::Result<()> {
|
||||
"--filter",
|
||||
"+ deno/**",
|
||||
"--filter",
|
||||
"+ bun/**",
|
||||
"--filter",
|
||||
"+ go/**",
|
||||
"--filter",
|
||||
"- *",
|
||||
|
||||
@@ -197,6 +197,7 @@ func Run(req Req) (interface{{}}, error){{
|
||||
Command::new(NSJAIL_PATH.as_str())
|
||||
.current_dir(job_dir)
|
||||
.env_clear()
|
||||
.envs(envs)
|
||||
.envs(reserved_variables)
|
||||
.env("PATH", PATH_ENV.as_str())
|
||||
.env("BASE_INTERNAL_URL", base_internal_url)
|
||||
|
||||
@@ -136,10 +136,12 @@ pub const ROOT_TMP_CACHE_DIR: &str = "/tmp/windmill/tmpcache/";
|
||||
pub const PIP_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "pip");
|
||||
pub const DENO_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "deno");
|
||||
pub const GO_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "go");
|
||||
pub const BUN_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "bun");
|
||||
pub const HUB_CACHE_DIR: &str = concatcp!(ROOT_CACHE_DIR, "hub");
|
||||
|
||||
pub const TAR_PIP_TMP_CACHE_DIR: &str = concatcp!(ROOT_TMP_CACHE_DIR, "tar/pip");
|
||||
pub const DENO_TMP_CACHE_DIR: &str = concatcp!(ROOT_TMP_CACHE_DIR, "deno");
|
||||
pub const BUN_TMP_CACHE_DIR: &str = concatcp!(ROOT_TMP_CACHE_DIR, "bun");
|
||||
pub const GO_TMP_CACHE_DIR: &str = concatcp!(ROOT_TMP_CACHE_DIR, "go");
|
||||
pub const HUB_TMP_CACHE_DIR: &str = concatcp!(ROOT_TMP_CACHE_DIR, "hub");
|
||||
|
||||
@@ -148,6 +150,7 @@ const NUM_SECS_PING: u64 = 5;
|
||||
|
||||
const INCLUDE_DEPS_PY_SH_CONTENT: &str = include_str!("../nsjail/download_deps.py.sh");
|
||||
const NSJAIL_CONFIG_RUN_BASH_CONTENT: &str = include_str!("../nsjail/run.bash.config.proto");
|
||||
const NSJAIL_CONFIG_RUN_BUN_CONTENT: &str = include_str!("../nsjail/run.bun.config.proto");
|
||||
|
||||
|
||||
pub const DEFAULT_TIMEOUT: u64 = 900;
|
||||
@@ -187,6 +190,7 @@ lazy_static::lazy_static! {
|
||||
pub static ref HTTP_PROXY: Option<String> = std::env::var("http_proxy").ok().or(std::env::var("HTTP_PROXY").ok());
|
||||
pub static ref HTTPS_PROXY: Option<String> = std::env::var("https_proxy").ok().or(std::env::var("HTTPS_PROXY").ok());
|
||||
pub static ref DENO_PATH: String = std::env::var("DENO_PATH").unwrap_or_else(|_| "/usr/bin/deno".to_string());
|
||||
pub static ref BUN_PATH: String = std::env::var("BUN_PATH").unwrap_or_else(|_| "/usr/bin/bun".to_string());
|
||||
pub static ref NSJAIL_PATH: String = std::env::var("NSJAIL_PATH").unwrap_or_else(|_| "nsjail".to_string());
|
||||
pub static ref PATH_ENV: String = std::env::var("PATH").unwrap_or_else(|_| String::new());
|
||||
pub static ref HOME_ENV: String = std::env::var("HOME").unwrap_or_else(|_| String::new());
|
||||
@@ -1532,7 +1536,8 @@ mount {{
|
||||
&inner_content,
|
||||
base_internal_url,
|
||||
worker_name,
|
||||
envs
|
||||
envs,
|
||||
&shared_mount
|
||||
)
|
||||
.await
|
||||
}
|
||||
@@ -1688,6 +1693,21 @@ fn get_common_deno_proc_envs(token: &str, base_internal_url: &str) -> HashMap<St
|
||||
return deno_envs;
|
||||
}
|
||||
|
||||
fn get_common_bun_proc_envs(base_internal_url: &str) -> HashMap<String, String> {
|
||||
let mut deno_envs: HashMap<String, String> = HashMap::from([
|
||||
(String::from("PATH"), PATH_ENV.clone()),
|
||||
(String::from("DO_NOT_TRACK"), "1".to_string()),
|
||||
(String::from("BASE_INTERNAL_URL"), base_internal_url.to_string()),
|
||||
(String::from("BUN_INSTALL_CACHE_DIR"), BUN_CACHE_DIR.to_string()),
|
||||
|
||||
]);
|
||||
|
||||
if let Some(ref s) = *NPM_CONFIG_REGISTRY {
|
||||
deno_envs.insert(String::from("NPM_CONFIG_REGISTRY"), s.clone());
|
||||
}
|
||||
return deno_envs;
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip_all)]
|
||||
async fn handle_deno_job(
|
||||
logs: &mut String,
|
||||
@@ -1811,7 +1831,7 @@ run().catch(async (e) => {{
|
||||
|
||||
//do not cache local dependencies
|
||||
let reload = format!("--reload={base_internal_url}");
|
||||
let child = async {
|
||||
let child = {
|
||||
let script_path = format!("{job_dir}/wrapper.ts");
|
||||
let import_map_path = format!("{job_dir}/import_map.json");
|
||||
let mut args = Vec::with_capacity(12);
|
||||
@@ -1844,9 +1864,8 @@ run().catch(async (e) => {{
|
||||
.args(args)
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
}
|
||||
.await?;
|
||||
.spawn()?
|
||||
};
|
||||
// logs.push_str(format!("prepare: {:?}\n", start.elapsed().as_micros()).as_str());
|
||||
// start = Instant::now();
|
||||
handle_child(&job.id, db, logs, child, false, worker_name, &job.workspace_id, "deno run").await?;
|
||||
@@ -1868,10 +1887,11 @@ async fn handle_bun_job(
|
||||
base_internal_url: &str,
|
||||
worker_name: &str,
|
||||
envs: HashMap<String, String>,
|
||||
shared_mount: &str,
|
||||
) -> error::Result<serde_json::Value> {
|
||||
|
||||
// let mut start = Instant::now();
|
||||
logs.push_str("\n\n--- DENO CODE EXECUTION ---\n");
|
||||
logs.push_str("\n\n--- BUN CODE EXECUTION ---\n");
|
||||
|
||||
let logs_to_set = logs.clone();
|
||||
let id = job.id.clone();
|
||||
@@ -1901,8 +1921,8 @@ async fn handle_bun_job(
|
||||
r#"
|
||||
import {{ main }} from "./main.ts";
|
||||
|
||||
const args = await Deno.readTextFile("args.json")
|
||||
.then(JSON.parse)
|
||||
|
||||
const args = await Bun.file("args.json").json()
|
||||
.then(({{ {spread} }}) => [ {spread} ])
|
||||
|
||||
BigInt.prototype.toJSON = function () {{
|
||||
@@ -1913,12 +1933,12 @@ BigInt.prototype.toJSON = function () {{
|
||||
async function run() {{
|
||||
let res: any = await main(...args);
|
||||
const res_json = JSON.stringify(res ?? null, (key, value) => typeof value === 'undefined' ? null : value);
|
||||
await Deno.writeTextFile("result.json", res_json);
|
||||
Deno.exit(0);
|
||||
await Bun.write("result.json", res_json);
|
||||
process.exit(0);
|
||||
}}
|
||||
run().catch(async (e) => {{
|
||||
await Deno.writeTextFile("result.json", JSON.stringify({{ message: e.message, name: e.name, stack: e.stack }}));
|
||||
Deno.exit(1);
|
||||
await Bun.write("result.json", JSON.stringify({{ message: e.message, name: e.name, stack: e.stack }}));
|
||||
process.exit(1);
|
||||
}});
|
||||
"#,
|
||||
);
|
||||
@@ -1926,33 +1946,6 @@ run().catch(async (e) => {{
|
||||
Ok(()) as error::Result<()>
|
||||
};
|
||||
|
||||
let write_import_map_f = async {
|
||||
let w_id = job.workspace_id.clone();
|
||||
let script_path_split = job.script_path().split("/");
|
||||
let script_path_parts_len = script_path_split.clone().count();
|
||||
let mut relative_mounts = "".to_string();
|
||||
for c in 0..script_path_parts_len {
|
||||
relative_mounts += ",\n ";
|
||||
relative_mounts += &format!("\"./{}\": \"{base_internal_url}/api/w/{w_id}/scripts/raw/p/{}{}\"",
|
||||
(0..c).map(|_| "../").join(""),
|
||||
&script_path_split.clone().take(script_path_parts_len - c - 1).join("/"),
|
||||
if c == script_path_parts_len - 1 { "" } else { "/" },
|
||||
);
|
||||
}
|
||||
let import_map = format!(
|
||||
r#"{{
|
||||
"imports": {{
|
||||
"{base_internal_url}/api/w/{w_id}/scripts/raw/p/": "{base_internal_url}/api/w/{w_id}/scripts/raw/p/",
|
||||
"{base_internal_url}": "{base_internal_url}/api/w/{w_id}/scripts/raw/p/",
|
||||
"/": "{base_internal_url}/api/w/{w_id}/scripts/raw/p/",
|
||||
"./wrapper.ts": "./wrapper.ts",
|
||||
"./main.ts": "./main.ts"{relative_mounts}
|
||||
}}
|
||||
}}"#,
|
||||
);
|
||||
write_file(job_dir, "import_map.json", &import_map).await?;
|
||||
Ok(()) as error::Result<()>
|
||||
};
|
||||
|
||||
let reserved_variables_args_out_f = async {
|
||||
let client = client.get_authed().await;
|
||||
@@ -1961,68 +1954,68 @@ run().catch(async (e) => {{
|
||||
Ok(()) as Result<()>
|
||||
};
|
||||
let reserved_variables_f = async {
|
||||
let mut vars = get_reserved_variables(job, &client.token, db).await?;
|
||||
vars.insert("RUST_LOG".to_string(), "info".to_string());
|
||||
let vars = get_reserved_variables(job, &client.token, db).await?;
|
||||
Ok(vars) as Result<HashMap<String, String>>
|
||||
};
|
||||
let (_, reserved_variables) = tokio::try_join!(args_and_out_f, reserved_variables_f)?;
|
||||
Ok((reserved_variables, client.token)) as error::Result<(HashMap<String, String>, String)>
|
||||
Ok(reserved_variables) as error::Result<HashMap<String, String>>
|
||||
};
|
||||
|
||||
let (_, (reserved_variables, token), _, _, _) = tokio::try_join!(
|
||||
|
||||
let (_, reserved_variables, _, _) = tokio::try_join!(
|
||||
set_logs_f,
|
||||
reserved_variables_args_out_f,
|
||||
write_main_f,
|
||||
write_wrapper_f,
|
||||
write_import_map_f)?;
|
||||
write_wrapper_f)?;
|
||||
|
||||
let common_bun_proc_envs = get_common_bun_proc_envs(&base_internal_url);
|
||||
|
||||
let common_deno_proc_envs = get_common_deno_proc_envs(&token, base_internal_url);
|
||||
|
||||
//do not cache local dependencies
|
||||
let reload = format!("--reload={base_internal_url}");
|
||||
let child = async {
|
||||
let child = if !*DISABLE_NSJAIL {
|
||||
let _ = write_file(
|
||||
job_dir,
|
||||
"run.config.proto",
|
||||
&NSJAIL_CONFIG_RUN_BUN_CONTENT
|
||||
.replace("{JOB_DIR}", job_dir)
|
||||
.replace("{CACHE_DIR}", BUN_CACHE_DIR)
|
||||
.replace("{CLONE_NEWUSER}", &(!*DISABLE_NUSER).to_string())
|
||||
.replace("{SHARED_MOUNT}", shared_mount),
|
||||
)
|
||||
.await?;
|
||||
|
||||
Command::new(NSJAIL_PATH.as_str())
|
||||
.current_dir(job_dir)
|
||||
.env_clear()
|
||||
.envs(envs)
|
||||
.envs(reserved_variables)
|
||||
.envs(common_bun_proc_envs)
|
||||
.env("PATH", PATH_ENV.as_str())
|
||||
.env("BASE_INTERNAL_URL", base_internal_url)
|
||||
.args(vec!["--config", "run.config.proto", "--", &BUN_PATH, "run", "/tmp/bun/wrapper.ts", "--prefer-offline"])
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()?
|
||||
} else {
|
||||
let script_path = format!("{job_dir}/wrapper.ts");
|
||||
let import_map_path = format!("{job_dir}/import_map.json");
|
||||
let mut args = Vec::with_capacity(12);
|
||||
args.push("run");
|
||||
args.push("--no-check");
|
||||
args.push("--import-map");
|
||||
args.push(&import_map_path);
|
||||
args.push(&reload);
|
||||
args.push("--unstable");
|
||||
if let Some(deno_flags) = DENO_FLAGS.as_ref() {
|
||||
for flag in deno_flags {
|
||||
args.push(flag);
|
||||
}
|
||||
} else if !*DISABLE_NSJAIL {
|
||||
args.push("--allow-net");
|
||||
args.push("--allow-read=./");
|
||||
args.push("--allow-write=./");
|
||||
args.push("--allow-env");
|
||||
} else {
|
||||
args.push("-A");
|
||||
}
|
||||
let mut args = vec!["run", &script_path, "--prefer-offline"];
|
||||
args.push(&script_path);
|
||||
Command::new(DENO_PATH.as_str())
|
||||
Command::new(&*BUN_PATH)
|
||||
.current_dir(job_dir)
|
||||
.env_clear()
|
||||
.envs(envs)
|
||||
.envs(reserved_variables)
|
||||
.envs(common_deno_proc_envs)
|
||||
.env("DENO_DIR", DENO_CACHE_DIR)
|
||||
.envs(common_bun_proc_envs)
|
||||
.args(args)
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
}
|
||||
.await?;
|
||||
.spawn()?
|
||||
};
|
||||
|
||||
// logs.push_str(format!("prepare: {:?}\n", start.elapsed().as_micros()).as_str());
|
||||
// start = Instant::now();
|
||||
handle_child(&job.id, db, logs, child, false, worker_name, &job.workspace_id, "deno run").await?;
|
||||
handle_child(&job.id, db, logs, child, false, worker_name, &job.workspace_id, "bun run").await?;
|
||||
// logs.push_str(format!("execute: {:?}\n", start.elapsed().as_millis()).as_str());
|
||||
if let Err(e) = tokio::fs::remove_dir_all(format!("{DENO_CACHE_DIR}/gen/file/{job_dir}")).await {
|
||||
tracing::error!("failed to remove deno gen tmp cache dir: {}", e);
|
||||
}
|
||||
read_result(job_dir).await
|
||||
}
|
||||
|
||||
|
||||
@@ -21,13 +21,6 @@ export {
|
||||
WorkspaceService,
|
||||
} from "./windmill-api/index.ts";
|
||||
|
||||
// @ts-ignore: Otherwise BigInt is not supported for export
|
||||
BigInt.prototype.toJSON = function () {
|
||||
return this.toString();
|
||||
};
|
||||
|
||||
export { pgSql, pgClient } from "./pg.ts";
|
||||
|
||||
export type Sql = string;
|
||||
export type Email = string;
|
||||
export type Base64 = string;
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
import { createConnection } from "https://deno.land/x/mysql2@v1.0.6/mod.ts";
|
||||
import { type Resource } from "./mod.ts";
|
||||
|
||||
/**
|
||||
* Establish MySQL connection using MySQL client for Deno:
|
||||
* https://deno.land/x/mysql2@v1.0.6/mod.ts
|
||||
*
|
||||
* IMPORTANT: make sure to close the connection with `.end()`
|
||||
*
|
||||
* @param db the MySQL resource to establish the connection for
|
||||
*
|
||||
* @returns MySQL database connection
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const conn = await mysqlClient(db);
|
||||
* await conn.execute('CREATE TABLE IF NOT EXISTS pets (name varchar(255), kind varchar(255))');
|
||||
* await conn.execute('INSERT INTO pets VALUES (?, ?)', ['behemot','cat']);
|
||||
* const [rows] = await conn.execute('SELECT * from pets');
|
||||
* conn.end();
|
||||
* console.log(rows);
|
||||
* ```
|
||||
*/
|
||||
export async function mysqlClient(
|
||||
db: Resource<"mysql">
|
||||
) {
|
||||
const conn = await createConnection(db);
|
||||
return conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute SQL query. For more info check:
|
||||
* https://deno.land/x/mysql2@v1.0.6/mod.ts
|
||||
*
|
||||
* @param db the MySQL resource to run sql query for
|
||||
*
|
||||
* @returns array with two items: rows and fields
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const kind = 'cat';
|
||||
* const { rows } = await mySql(db)`SELECT * from pets WHERE kind = ${kind}`;
|
||||
* console.log(rows);
|
||||
* ```
|
||||
*/
|
||||
export function mySql(
|
||||
db: Resource<"mysql">,
|
||||
asObjects = false
|
||||
) {
|
||||
return async function execute(
|
||||
query: TemplateStringsArray,
|
||||
...args: unknown[],
|
||||
) {
|
||||
const conn = await mysqlClient(db);
|
||||
const adapter = getQueryAdapter(query, args);
|
||||
const [rows, fields] = await conn.execute(...adapter);
|
||||
conn.end();
|
||||
return { rows: asObjects ? rows : getRowsAdapter(rows), fields };
|
||||
}
|
||||
}
|
||||
|
||||
function getQueryAdapter(template: TemplateStringsArray, args: unknown[]) {
|
||||
const text = template.reduce((curr, next) => {
|
||||
return `${curr}?${next}`;
|
||||
});
|
||||
return [text, args];
|
||||
}
|
||||
|
||||
function getRowsAdapter(rows: object[] | object) {
|
||||
if (!Array.isArray(rows)) {
|
||||
return rows;
|
||||
}
|
||||
return rows.map((r) => Object.values(r))
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
import { Client } from "https://deno.land/x/postgres@v0.17.0/mod.ts"
|
||||
import { type Resource } from "./mod.ts"
|
||||
|
||||
/**
|
||||
* deno-postgres client API is very flexible:
|
||||
* https://deno.land/x/postgres@v0.17.0/mod.ts?s=QueryClient
|
||||
*
|
||||
* @param db the PostgreSQL resource to generate the client for
|
||||
*
|
||||
* @returns the client for the resource
|
||||
*
|
||||
* @example
|
||||
* // Static query
|
||||
* ```ts
|
||||
* const { rows } = await pgClient(db).queryObject(
|
||||
* "SELECT ID, NAME FROM CLIENTS"
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* // Prepared Statements
|
||||
* ```ts
|
||||
* const { rows } = await pgClient(db).queryObject`SELECT ID, NAME FROM CLIENTS WHERE ID = ${id}`;
|
||||
* ```
|
||||
*/
|
||||
export function pgClient(
|
||||
db: Resource<"postgresql">
|
||||
) {
|
||||
const databaseUrl = 'postgresql://' + db.user + ':' + db.password + '@' + db.host + ':' + db.port + '/' + db.dbname + '?sslmode=' + db.sslmode
|
||||
return new Client(databaseUrl)
|
||||
}
|
||||
|
||||
/**
|
||||
* deno-postgres client API is very flexible:
|
||||
* https://deno.land/x/postgres@v0.17.0/mod.ts?s=QueryClient
|
||||
*
|
||||
* @param db the PostgreSQL resource to run sql query for
|
||||
*
|
||||
* @returns the rows corresponding to the returned objetcs
|
||||
*
|
||||
* @example
|
||||
* // Prepared Statements
|
||||
* ```ts
|
||||
* const { rows } = await pgSql(db)`SELECT ID, NAME FROM CLIENTS WHERE ID = ${id}`;
|
||||
* ```
|
||||
*/
|
||||
export function pgSql(
|
||||
db: Resource<"postgresql">,
|
||||
asObjects = false
|
||||
) {
|
||||
return async function queryObject(
|
||||
query: TemplateStringsArray,
|
||||
...args: unknown[]
|
||||
) {
|
||||
const client = pgClient(db)
|
||||
return asObjects ? await client.queryObject(query, ...args) : await client.queryArray(query, ...args)
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,6 @@
|
||||
if (SCRIPT_SHOW_BASH) {
|
||||
langs.push(['Bash', Script.language.BASH])
|
||||
}
|
||||
// langs.push(['Typescript (Bun experimental)', Script.language.BUN])
|
||||
langs.push(['PostgreSQL', Script.language.POSTGRESQL])
|
||||
langs.push(['REST', Script.language.NATIVETS])
|
||||
const scriptKindOptions: {
|
||||
@@ -331,6 +330,19 @@
|
||||
>
|
||||
<LanguageIcon lang="docker" /><span class="ml-2 py-2">Docker</span>
|
||||
</Button>
|
||||
<Button
|
||||
size="xs"
|
||||
variant="border"
|
||||
color={script.language == 'bun' ? 'blue' : 'dark'}
|
||||
btnClasses={script.language == 'bun' ? '!border-2 !bg-blue-50/75' : 'm-[1px]'}
|
||||
disabled={lockedLanguage}
|
||||
on:click={() => {
|
||||
initContent(Script.language.BUN, script.kind, template)
|
||||
script.language = Script.language.BUN
|
||||
}}
|
||||
>
|
||||
<LanguageIcon lang="bun" /><span class="ml-2 py-2">Typescript (Bun, experimental)</span>
|
||||
</Button>
|
||||
|
||||
<!-- <Button
|
||||
size="sm"
|
||||
|
||||
@@ -45,7 +45,7 @@ export async function main(
|
||||
`
|
||||
|
||||
export const BUN_INIT_CODE = `// import { toWords } from "number-to-words@1"
|
||||
// import { VariableService } from "windmill-client"
|
||||
import { setClient, getVariable } from "windmill-client@0.3.14"
|
||||
|
||||
// fill the type, or use the +Resource type to get a type-safe reference to a resource
|
||||
// type Postgresql = object
|
||||
@@ -57,7 +57,8 @@ export async function main(
|
||||
d = "inferred type string from default arg",
|
||||
e = { nested: "object" },
|
||||
) {
|
||||
// let x = await wmill.getVariable('u/user/foo')
|
||||
// setClient()
|
||||
// let x = await getVariable('u/user/foo')
|
||||
return { foo: a };
|
||||
}
|
||||
`
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
src/
|
||||
*.sh
|
||||
@@ -4,3 +4,6 @@ set -e
|
||||
npx --yes openapi-typescript-codegen --input ../backend/windmill-api/openapi.yaml \
|
||||
--output ./src --useOptions \
|
||||
&& sed -i '213 i \\ request.referrerPolicy = \"no-referrer\"\n' src/core/request.ts
|
||||
|
||||
cp client.ts src/
|
||||
echo 'export { setClient, getVariable, setVariable, getResource, setResource } from "./client";' >> src/index.ts
|
||||
364
typescript-client/client.ts
Normal file
364
typescript-client/client.ts
Normal file
@@ -0,0 +1,364 @@
|
||||
import { JobService, ResourceService, VariableService } from "./index";
|
||||
import { OpenAPI } from "./index";
|
||||
|
||||
export {
|
||||
AdminService,
|
||||
AuditService,
|
||||
FlowService,
|
||||
GranularAclService,
|
||||
GroupService,
|
||||
JobService,
|
||||
ResourceService,
|
||||
VariableService,
|
||||
ScriptService,
|
||||
ScheduleService,
|
||||
SettingsService,
|
||||
UserService,
|
||||
WorkspaceService,
|
||||
} from "./index";
|
||||
|
||||
export type Sql = string;
|
||||
export type Email = string;
|
||||
export type Base64 = string;
|
||||
export type Resource<S extends string> = any;
|
||||
|
||||
export const SHARED_FOLDER = "/shared";
|
||||
|
||||
export function setClient(token?: string, baseUrl?: string) {
|
||||
if (baseUrl === undefined) {
|
||||
baseUrl =
|
||||
getEnv("BASE_INTERNAL_URL") ??
|
||||
getEnv("BASE_URL") ??
|
||||
"http://localhost:8000";
|
||||
}
|
||||
if (token === undefined) {
|
||||
token = getEnv("WM_TOKEN") ?? "no_token";
|
||||
}
|
||||
OpenAPI.WITH_CREDENTIALS = true;
|
||||
OpenAPI.TOKEN = token;
|
||||
OpenAPI.BASE = baseUrl + "/api";
|
||||
}
|
||||
|
||||
const getEnv = (key: string) => {
|
||||
if (typeof window === "undefined") {
|
||||
// node
|
||||
return process.env[key];
|
||||
}
|
||||
// browser
|
||||
return window.process.env[key];
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a client configuration from env variables
|
||||
* @returns client configuration
|
||||
*/
|
||||
export function getWorkspace(): string {
|
||||
return getEnv("WM_WORKSPACE") ?? "no_workspace";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a resource value by path
|
||||
* @param path path of the resource, default to internal state path
|
||||
* @param undefinedIfEmpty if the resource does not exist, return undefined instead of throwing an error
|
||||
* @returns resource value
|
||||
*/
|
||||
export async function getResource(
|
||||
path?: string,
|
||||
undefinedIfEmpty?: boolean
|
||||
): Promise<any> {
|
||||
const workspace = getWorkspace();
|
||||
path = path ?? getStatePath();
|
||||
try {
|
||||
const resource = await ResourceService.getResource({ workspace, path });
|
||||
return await _transformLeaf(resource.value);
|
||||
} catch (e: any) {
|
||||
if (undefinedIfEmpty && e.status === 404) {
|
||||
return undefined;
|
||||
} else {
|
||||
throw Error(`Resource not found at ${path} or not visible to you`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a resource value in case the default value was picked because the input payload was undefined
|
||||
* @param obj resource value or path of the resource under the format `$res:path`
|
||||
* @returns resource value
|
||||
*/
|
||||
export async function resolveDefaultResource(obj: any): Promise<any> {
|
||||
if (typeof obj === "string" && obj.startsWith("$res:")) {
|
||||
return await getResource(obj.substring(5), true);
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full resource value by path
|
||||
* @param path path of the resource, default to internal state path
|
||||
* @param undefinedIfEmpty if the resource does not exist, return undefined instead of throwing an error
|
||||
* @returns full resource
|
||||
*/
|
||||
export async function getFullResource(
|
||||
path?: string,
|
||||
undefinedIfEmpty?: boolean
|
||||
): Promise<any> {
|
||||
const workspace = getWorkspace();
|
||||
path = path ?? getStatePath();
|
||||
try {
|
||||
const resource = await ResourceService.getResource({ workspace, path });
|
||||
const value = await _transformLeaf(resource.value);
|
||||
return { ...resource, value };
|
||||
} catch (e: any) {
|
||||
if (undefinedIfEmpty && e.status === 404) {
|
||||
return undefined;
|
||||
} else {
|
||||
throw Error(`Resource not found at ${path} or not visible to you`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getStatePath(): string {
|
||||
const state_path = getEnv("WM_STATE_PATH");
|
||||
if (state_path === undefined) {
|
||||
throw Error("State path not set");
|
||||
}
|
||||
return state_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a resource value by path
|
||||
* @param path path of the resource to set, default to state path
|
||||
* @param value new value of the resource to set
|
||||
* @param initializeToTypeIfNotExist if the resource does not exist, initialize it with this type
|
||||
*/
|
||||
export async function setResource(
|
||||
value: any,
|
||||
path?: string,
|
||||
initializeToTypeIfNotExist?: string
|
||||
): Promise<void> {
|
||||
path = path ?? getStatePath();
|
||||
const workspace = getWorkspace();
|
||||
if (await ResourceService.existsResource({ workspace, path })) {
|
||||
await ResourceService.updateResourceValue({
|
||||
workspace,
|
||||
path,
|
||||
requestBody: { value },
|
||||
});
|
||||
} else if (initializeToTypeIfNotExist) {
|
||||
await ResourceService.createResource({
|
||||
workspace,
|
||||
requestBody: { path, value, resource_type: initializeToTypeIfNotExist },
|
||||
});
|
||||
} else {
|
||||
throw Error(
|
||||
`Resource at path ${path} does not exist and no type was provided to initialize it`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the state
|
||||
* @param state state to set
|
||||
* @deprecated use setState instead
|
||||
*/
|
||||
export async function setInternalState(state: any): Promise<void> {
|
||||
await setResource(state, undefined, "state");
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the state
|
||||
* @param state state to set
|
||||
*/
|
||||
export async function setState(state: any): Promise<void> {
|
||||
await setResource(state, undefined, "state");
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Set the shared state
|
||||
// * @param state state to set
|
||||
// */
|
||||
// export async function setSharedState(
|
||||
// state: any,
|
||||
// path = "state.json"
|
||||
// ): Promise<void> {
|
||||
// await Deno.writeTextFile(SHARED_FOLDER + "/" + path, JSON.stringify(state));
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Get the shared state
|
||||
// * @param state state to set
|
||||
// */
|
||||
// export async function getSharedState(path = "state.json"): Promise<any> {
|
||||
// return JSON.parse(await Deno.readTextFile(SHARED_FOLDER + "/" + path));
|
||||
// }
|
||||
|
||||
/**
|
||||
* Get the internal state
|
||||
* @deprecated use getState instead
|
||||
*/
|
||||
export async function getInternalState(): Promise<any> {
|
||||
return await getResource(getStatePath(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state shared across executions
|
||||
*/
|
||||
export async function getState(): Promise<any> {
|
||||
return await getResource(getStatePath(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a variable by path
|
||||
* @param path path of the variable
|
||||
* @returns variable value
|
||||
*/
|
||||
export async function getVariable(path: string): Promise<string | undefined> {
|
||||
const workspace = getWorkspace();
|
||||
try {
|
||||
const variable = await VariableService.getVariable({ workspace, path });
|
||||
return variable.value;
|
||||
} catch (e: any) {
|
||||
throw Error(`Variable not found at ${path} or not visible to you`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a variable by path, create if not exist
|
||||
* @param path path of the variable
|
||||
* @param value value of the variable
|
||||
* @param isSecretIfNotExist if the variable does not exist, create it as secret or not (default: false)
|
||||
* @param descriptionIfNotExist if the variable does not exist, create it with this description (default: "")
|
||||
*/
|
||||
export async function setVariable(
|
||||
path: string,
|
||||
value: string,
|
||||
isSecretIfNotExist?: boolean,
|
||||
descriptionIfNotExist?: string
|
||||
): Promise<void> {
|
||||
const workspace = getWorkspace();
|
||||
if (await VariableService.existsVariable({ workspace, path })) {
|
||||
await VariableService.updateVariable({
|
||||
workspace,
|
||||
path,
|
||||
requestBody: { value },
|
||||
});
|
||||
} else {
|
||||
await VariableService.createVariable({
|
||||
workspace,
|
||||
requestBody: {
|
||||
path,
|
||||
value,
|
||||
is_secret: isSecretIfNotExist ?? false,
|
||||
description: descriptionIfNotExist ?? "",
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function transformLeaves(d: {
|
||||
[key: string]: any;
|
||||
}): Promise<{ [key: string]: any }> {
|
||||
for (const k in d) {
|
||||
d[k] = await _transformLeaf(d[k]);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
const VAR_RESOURCE_PREFIX = "$var:";
|
||||
const RES_RESOURCE_PREFIX = "$res:";
|
||||
async function _transformLeaf(v: any): Promise<any> {
|
||||
if (typeof v === "object") {
|
||||
return transformLeaves(v);
|
||||
} else if (typeof v === "string" && v.startsWith(VAR_RESOURCE_PREFIX)) {
|
||||
const varName = v.substring(VAR_RESOURCE_PREFIX.length);
|
||||
return await getVariable(varName);
|
||||
} else if (typeof v === "string" && v.startsWith(RES_RESOURCE_PREFIX)) {
|
||||
const resName = v.substring(RES_RESOURCE_PREFIX.length);
|
||||
return await getResource(resName);
|
||||
} else {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
export async function databaseUrlFromResource(path: string): Promise<string> {
|
||||
const resource = await getResource(path);
|
||||
return `postgresql://${resource.user}:${resource.password}@${resource.host}:${resource.port}/${resource.dbname}?sslmode=${resource.sslmode}`;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Get URLs needed for resuming a flow after this step
|
||||
// * @param approver approver name
|
||||
// * @returns approval page UI URL, resume and cancel API URLs for resumeing the flow
|
||||
// */
|
||||
// export async function getResumeUrls(approver?: string): Promise<{
|
||||
// approvalPage: string;
|
||||
// resume: string;
|
||||
// cancel: string;
|
||||
// }> {
|
||||
// const nonce = Math.floor(Math.random() * 4294967295);
|
||||
// const workspace = getWorkspace();
|
||||
// return await JobService.getResumeUrls({
|
||||
// workspace,
|
||||
// resumeId: nonce,
|
||||
// approver,
|
||||
// id: process.env.get("WM_JOB_ID") ?? "NO_JOB_ID",
|
||||
// });
|
||||
// }
|
||||
|
||||
export function base64ToUint8Array(data: string): Uint8Array {
|
||||
return Uint8Array.from(atob(data), (c) => c.charCodeAt(0));
|
||||
}
|
||||
|
||||
export function uint8ArrayToBase64(arrayBuffer: Uint8Array): string {
|
||||
let base64 = "";
|
||||
const encodings =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
const bytes = new Uint8Array(arrayBuffer);
|
||||
const byteLength = bytes.byteLength;
|
||||
const byteRemainder = byteLength % 3;
|
||||
const mainLength = byteLength - byteRemainder;
|
||||
|
||||
let a, b, c, d;
|
||||
let chunk;
|
||||
|
||||
// Main loop deals with bytes in chunks of 3
|
||||
for (let i = 0; i < mainLength; i = i + 3) {
|
||||
// Combine the three bytes into a single integer
|
||||
chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
|
||||
|
||||
// Use bitmasks to extract 6-bit segments from the triplet
|
||||
a = (chunk & 16515072) >> 18; // 16515072 = (2^6 - 1) << 18
|
||||
b = (chunk & 258048) >> 12; // 258048 = (2^6 - 1) << 12
|
||||
c = (chunk & 4032) >> 6; // 4032 = (2^6 - 1) << 6
|
||||
d = chunk & 63; // 63 = 2^6 - 1
|
||||
|
||||
// Convert the raw binary segments to the appropriate ASCII encoding
|
||||
base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d];
|
||||
}
|
||||
|
||||
// Deal with the remaining bytes and padding
|
||||
if (byteRemainder == 1) {
|
||||
chunk = bytes[mainLength];
|
||||
|
||||
a = (chunk & 252) >> 2; // 252 = (2^6 - 1) << 2
|
||||
|
||||
// Set the 4 least significant bits to zero
|
||||
b = (chunk & 3) << 4; // 3 = 2^2 - 1
|
||||
|
||||
base64 += encodings[a] + encodings[b] + "==";
|
||||
} else if (byteRemainder == 2) {
|
||||
chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1];
|
||||
|
||||
a = (chunk & 64512) >> 10; // 64512 = (2^6 - 1) << 10
|
||||
b = (chunk & 1008) >> 4; // 1008 = (2^6 - 1) << 4
|
||||
|
||||
// Set the 2 least significant bits to zero
|
||||
c = (chunk & 15) << 2; // 15 = 2^4 - 1
|
||||
|
||||
base64 += encodings[a] + encodings[b] + encodings[c] + "=";
|
||||
}
|
||||
|
||||
return base64;
|
||||
}
|
||||
385
typescript-client/package-lock.json
generated
Normal file
385
typescript-client/package-lock.json
generated
Normal file
@@ -0,0 +1,385 @@
|
||||
{
|
||||
"name": "windmill-client",
|
||||
"version": "0.3.11",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "windmill-client",
|
||||
"version": "0.3.11",
|
||||
"license": "Apache 2.0",
|
||||
"devDependencies": {
|
||||
"@digitak/tsc-esm": "^3.1.4",
|
||||
"@types/node": "^20.4.0",
|
||||
"tsc": "^2.0.4",
|
||||
"typescript": "^5.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@digitak/grubber": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@digitak/grubber/-/grubber-3.1.4.tgz",
|
||||
"integrity": "sha512-pqsnp2BUYlDoTXWG34HWgEJse/Eo1okRgNex8IG84wHrJp8h3SakeR5WhB4VxSA2+/D+frNYJ0ch3yXzsfNDoA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@digitak/tsc-esm": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@digitak/tsc-esm/-/tsc-esm-3.1.4.tgz",
|
||||
"integrity": "sha512-D3AbtMYfh/BarDe0HS3nPh93zavleQH+UfeoWosz6p14YYG+zXPYqbPt9zwXJXrE9C3/g6DRLvBTK/l/qW2WlA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@digitak/grubber": "^3.1.3",
|
||||
"fast-glob": "^3.2.5",
|
||||
"relaxed-json": "^1.0.3"
|
||||
},
|
||||
"bin": {
|
||||
"tsc-esm": "binary/tsc-esm.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@nodelib/fs.stat": "2.0.5",
|
||||
"run-parallel": "^1.1.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.stat": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
|
||||
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.walk": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
|
||||
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@nodelib/fs.scandir": "2.1.5",
|
||||
"fastq": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.0.tgz",
|
||||
"integrity": "sha512-jfT7iTf/4kOQ9S7CHV9BIyRaQqHu67mOjsIQBC3BKZvzvUB6zLxEwJ6sBE3ozcvP8kF6Uk5PXN0Q+c0dfhGX0g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-convert": "^1.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/braces": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fill-range": "^7.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/commander": {
|
||||
"version": "2.20.3",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-glob": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz",
|
||||
"integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@nodelib/fs.stat": "^2.0.2",
|
||||
"@nodelib/fs.walk": "^1.2.3",
|
||||
"glob-parent": "^5.1.2",
|
||||
"merge2": "^1.3.0",
|
||||
"micromatch": "^4.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fastq": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
|
||||
"integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"reusify": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/fill-range": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/glob-parent": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-glob": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-extglob": "^2.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/micromatch": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
|
||||
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"braces": "^3.0.2",
|
||||
"picomatch": "^2.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
}
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/queue-microtask": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/relaxed-json": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/relaxed-json/-/relaxed-json-1.0.3.tgz",
|
||||
"integrity": "sha512-b7wGPo7o2KE/g7SqkJDDbav6zmrEeP4TK2VpITU72J/M949TLe/23y/ZHJo+pskcGM52xIfFoT9hydwmgr1AEg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chalk": "^2.4.2",
|
||||
"commander": "^2.6.0"
|
||||
},
|
||||
"bin": {
|
||||
"rjson": "bin/rjson.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/reusify": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
||||
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"iojs": ">=1.0.0",
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/run-parallel": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"queue-microtask": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has-flag": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-number": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tsc": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/tsc/-/tsc-2.0.4.tgz",
|
||||
"integrity": "sha512-fzoSieZI5KKJVBYGvwbVZs/J5za84f2lSTLPYf6AGiIf43tZ3GNrI1QzTLcjtyDDP4aLxd46RTZq1nQxe7+k5Q==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.1.6",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz",
|
||||
"integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,19 @@
|
||||
{
|
||||
"name": "windmill-client",
|
||||
"description": "Windmill SDK client for browsers and Node.js",
|
||||
"version": "0.3.1",
|
||||
"version": "0.3.15",
|
||||
"author": "Ruben Fiszel",
|
||||
"license": "Apache 2.0",
|
||||
"dependencies": {},
|
||||
"devDependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.4.0"
|
||||
},
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"prepublish": "tsc"
|
||||
"prepublish": "tsc",
|
||||
"files": [
|
||||
"dist",
|
||||
"LICENSE",
|
||||
"README.md",
|
||||
"package.json"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
./build.sh
|
||||
rm client.ts
|
||||
tsc
|
||||
cp src/client.ts .
|
||||
npm publish
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig to read more about this file */
|
||||
|
||||
"declaration": true,
|
||||
"outDir": "dist",
|
||||
/* Projects */
|
||||
@@ -13,7 +12,7 @@
|
||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||
|
||||
/* Language and Environment */
|
||||
"target": "es2018" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
||||
"target": "ES6" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
||||
@@ -27,7 +26,7 @@
|
||||
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||
|
||||
/* Modules */
|
||||
"module": "commonjs" /* Specify what module code is generated. */,
|
||||
"module": "CommonJS" /* Specify what module code is generated. */,
|
||||
// "rootDir": "./", /* Specify the root folder within your source files. */
|
||||
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||
|
||||
Reference in New Issue
Block a user