Compare commits

..

5 Commits

Author SHA1 Message Date
Ruben Fiszel
c41565b6b8 perf: allow BATCH_PULL_SIZE in any mode for benchmarking
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 12:06:33 +00:00
Ruben Fiszel
d1b8d5427b perf: batch commit completed jobs in single transaction
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:41:10 +00:00
Ruben Fiszel
fc5e479424 chore: update ee-repo-ref.txt for batch_pull endpoint
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 18:04:38 +00:00
Ruben Fiszel
da18a69808 perf: add agent-batch mode with batch pull from server
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:59:10 +00:00
Ruben Fiszel
1b6e2556b7 perf: add worker-side batch job pull from DB
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 15:37:53 +00:00
59 changed files with 781 additions and 1318 deletions

View File

@@ -1,21 +1,5 @@
# Changelog
## [1.680.0](https://github.com/windmill-labs/windmill/compare/v1.679.0...v1.680.0) (2026-04-08)
### Features
* add CLI workspace merge command and enhance fork with datatable/color support ([#8756](https://github.com/windmill-labs/windmill/issues/8756)) ([4342c18](https://github.com/windmill-labs/windmill/commit/4342c1854134500d3b2bc46280f9885ee84e2c9e))
* add scheduled job deletion with configurable retention period ([#8753](https://github.com/windmill-labs/windmill/issues/8753)) ([2d18a68](https://github.com/windmill-labs/windmill/commit/2d18a680991babe317ca315bbce40e6ce733afda))
* add status indicator dots to parallel loop iteration picker ([#8761](https://github.com/windmill-labs/windmill/issues/8761)) ([470b8aa](https://github.com/windmill-labs/windmill/commit/470b8aa5f1870e26fea022c1e2a9f48471d8a205))
### Bug Fixes
* move alert config from config table to global_settings ([#8762](https://github.com/windmill-labs/windmill/issues/8762)) ([fa66870](https://github.com/windmill-labs/windmill/commit/fa668707c0ee7f261d78e145666b1073471259fd))
* resolve esbuild host/binary version mismatch in app sync push ([#8765](https://github.com/windmill-labs/windmill/issues/8765)) ([e36d440](https://github.com/windmill-labs/windmill/commit/e36d440a251a43ea888e3ce378d0bb8ed8f42e11))
* skip serializing ws_specific on resources when false ([#8764](https://github.com/windmill-labs/windmill/issues/8764)) ([c69f10d](https://github.com/windmill-labs/windmill/commit/c69f10d20dd064f0c329934096c2945424ff81f2))
## [1.679.0](https://github.com/windmill-labs/windmill/compare/v1.678.0...v1.679.0) (2026-04-07)

View File

@@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE ws_specific SET path = $1 WHERE workspace_id = $2 AND item_kind = 'resource' AND path = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "20ca0b26a0d2e9cfb9fb8e7066d6d5f3a154de0f76ce0d12ee678bcabd7b445c"
}

View File

@@ -1,15 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM ws_specific WHERE workspace_id = $1 AND item_kind = 'resource' AND path = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": []
},
"hash": "2d236ba78748c6160abec9ae1ad11e9e90063e2c583e2145f6d5b86fbf981861"
}

View File

@@ -1,15 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM ws_specific WHERE workspace_id = $1 AND item_kind = 'resource' AND path = ANY($2)",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"TextArray"
]
},
"nullable": []
},
"hash": "3ea2e1994d576e7a1b32ab276820dcff8e4e3b83f0d6a78fa0120c73fe90f345"
}

View File

@@ -50,31 +50,36 @@
},
{
"ordinal": 9,
"name": "is_expired",
"name": "ws_specific",
"type_info": "Bool"
},
{
"ordinal": 10,
"name": "is_refreshed",
"name": "is_expired",
"type_info": "Bool"
},
{
"ordinal": 11,
"name": "is_refreshed",
"type_info": "Bool"
},
{
"ordinal": 12,
"name": "refresh_error",
"type_info": "Text"
},
{
"ordinal": 12,
"ordinal": 13,
"name": "is_linked",
"type_info": "Bool"
},
{
"ordinal": 13,
"ordinal": 14,
"name": "is_oauth?",
"type_info": "Bool"
},
{
"ordinal": 14,
"ordinal": 15,
"name": "account",
"type_info": "Int4"
}
@@ -95,6 +100,7 @@
true,
true,
true,
false,
null,
null,
true,

View File

@@ -47,6 +47,11 @@
"ordinal": 8,
"name": "labels",
"type_info": "TextArray"
},
{
"ordinal": 9,
"name": "ws_specific",
"type_info": "Bool"
}
],
"parameters": {
@@ -63,7 +68,8 @@
false,
true,
true,
true
true,
false
]
},
"hash": "45e4d13f5806122faecdb1d9ab18159555b652869a036b006f4a151e999b17b7"

View File

@@ -1,23 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT EXISTS(SELECT 1 FROM ws_specific WHERE workspace_id = $1 AND item_kind = 'resource' AND path = $2)",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "exists",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "4a623e8789073abd92c52615077b89ed24398f59205c64290fa52ab19b3e44a3"
}

View File

@@ -15,7 +15,7 @@
]
},
"nullable": [
true
null
]
},
"hash": "5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55"

View File

@@ -1,35 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT value, description, resource_type\n FROM resource\n WHERE workspace_id = $1 AND path = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "value",
"type_info": "Jsonb"
},
{
"ordinal": 1,
"name": "description",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "resource_type",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
true,
true,
false
]
},
"hash": "819c233915383e89af1bcf1a56c5f67c4e1fc217f216f609e36a9944a7807b33"
}

View File

@@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE resource\n SET value = jsonb_set(value, '{dbname}', to_jsonb($3::text))\n WHERE workspace_id = $1 AND path = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "c19df45b092a246141e52770e70e02293b0a5eac859cbdc45f07c08957f00e00"
}

View File

@@ -1,20 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO resource\n (workspace_id, path, value, description, resource_type, created_by, edited_at, labels)\n VALUES ($1, $2, $3, $4, $5, $6, now(), $7) ON CONFLICT (workspace_id, path)\n DO UPDATE SET value = EXCLUDED.value, description = EXCLUDED.description, resource_type = EXCLUDED.resource_type, edited_at = now(), labels = EXCLUDED.labels",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Varchar",
"Jsonb",
"Text",
"Varchar",
"Varchar",
"TextArray"
]
},
"nullable": []
},
"hash": "deac41298e8b0d0870e314fef0813c24dd55d63bda78a0a5f35ed6f22bea6bef"
}

View File

@@ -1,15 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO ws_specific (workspace_id, item_kind, path) VALUES ($1, 'resource', $2) ON CONFLICT DO NOTHING",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Varchar"
]
},
"nullable": []
},
"hash": "edcda7e58fd1c586b5fb7aadedfde6b9dcffbc859426295c58719f6a8a544936"
}

152
backend/Cargo.lock generated
View File

@@ -16007,7 +16007,7 @@ dependencies = [
[[package]]
name = "windmill"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"async-nats",
@@ -16086,7 +16086,7 @@ dependencies = [
[[package]]
name = "windmill-alerting"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16099,7 +16099,7 @@ dependencies = [
[[package]]
name = "windmill-api"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"argon2",
@@ -16240,7 +16240,7 @@ dependencies = [
[[package]]
name = "windmill-api-agent-workers"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16263,7 +16263,7 @@ dependencies = [
[[package]]
name = "windmill-api-assets"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16276,7 +16276,7 @@ dependencies = [
[[package]]
name = "windmill-api-auth"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"axum 0.8.4",
@@ -16302,7 +16302,7 @@ dependencies = [
[[package]]
name = "windmill-api-client"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"reqwest 0.12.28",
"serde",
@@ -16312,7 +16312,7 @@ dependencies = [
[[package]]
name = "windmill-api-configs"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16329,7 +16329,7 @@ dependencies = [
[[package]]
name = "windmill-api-debug"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"axum 0.8.4",
"base64 0.22.1",
@@ -16352,7 +16352,7 @@ dependencies = [
[[package]]
name = "windmill-api-embeddings"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"axum 0.8.4",
@@ -16375,7 +16375,7 @@ dependencies = [
[[package]]
name = "windmill-api-flow-conversations"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16391,7 +16391,7 @@ dependencies = [
[[package]]
name = "windmill-api-flows"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16411,7 +16411,7 @@ dependencies = [
[[package]]
name = "windmill-api-groups"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16431,7 +16431,7 @@ dependencies = [
[[package]]
name = "windmill-api-inputs"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16445,7 +16445,7 @@ dependencies = [
[[package]]
name = "windmill-api-integration-tests"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"async-nats",
@@ -16476,7 +16476,7 @@ dependencies = [
[[package]]
name = "windmill-api-jobs"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"axum 0.8.4",
@@ -16501,7 +16501,7 @@ dependencies = [
[[package]]
name = "windmill-api-npm-proxy"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"axum 0.8.4",
"flate2",
@@ -16519,7 +16519,7 @@ dependencies = [
[[package]]
name = "windmill-api-openapi"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"axum 0.8.4",
@@ -16541,7 +16541,7 @@ dependencies = [
[[package]]
name = "windmill-api-schedule"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16561,7 +16561,7 @@ dependencies = [
[[package]]
name = "windmill-api-scripts"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16591,7 +16591,7 @@ dependencies = [
[[package]]
name = "windmill-api-settings"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"axum 0.8.4",
@@ -16618,7 +16618,7 @@ dependencies = [
[[package]]
name = "windmill-api-sse"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"lazy_static",
"serde",
@@ -16630,7 +16630,7 @@ dependencies = [
[[package]]
name = "windmill-api-users"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"argon2",
"axum 0.8.4",
@@ -16655,7 +16655,7 @@ dependencies = [
[[package]]
name = "windmill-api-workers"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16669,7 +16669,7 @@ dependencies = [
[[package]]
name = "windmill-api-workspaces"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16702,7 +16702,7 @@ dependencies = [
[[package]]
name = "windmill-audit"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"chrono",
"lazy_static",
@@ -16716,7 +16716,7 @@ dependencies = [
[[package]]
name = "windmill-autoscaling"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"axum 0.8.4",
@@ -16735,7 +16735,7 @@ dependencies = [
[[package]]
name = "windmill-common"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"aes-gcm",
"aho-corasick",
@@ -16838,7 +16838,7 @@ dependencies = [
[[package]]
name = "windmill-dep-map"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"chrono",
"itertools 0.14.0",
@@ -16857,7 +16857,7 @@ dependencies = [
[[package]]
name = "windmill-git-sync"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"regex",
"serde",
@@ -16872,7 +16872,7 @@ dependencies = [
[[package]]
name = "windmill-indexer"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"astral-tokio-tar",
@@ -16896,7 +16896,7 @@ dependencies = [
[[package]]
name = "windmill-jseval"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"futures",
@@ -16913,7 +16913,7 @@ dependencies = [
[[package]]
name = "windmill-macros"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"itertools 0.14.0",
"lazy_static",
@@ -16929,7 +16929,7 @@ dependencies = [
[[package]]
name = "windmill-mcp"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"async-trait",
@@ -16950,7 +16950,7 @@ dependencies = [
[[package]]
name = "windmill-native-triggers"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"async-trait",
@@ -16981,7 +16981,7 @@ dependencies = [
[[package]]
name = "windmill-oauth"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"async-oauth2",
@@ -17005,7 +17005,7 @@ dependencies = [
[[package]]
name = "windmill-object-store"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"async-stream",
@@ -17039,7 +17039,7 @@ dependencies = [
[[package]]
name = "windmill-operator"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"futures",
@@ -17057,7 +17057,7 @@ dependencies = [
[[package]]
name = "windmill-parser"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"convert_case 0.6.0",
"serde",
@@ -17066,7 +17066,7 @@ dependencies = [
[[package]]
name = "windmill-parser-bash"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"lazy_static",
@@ -17078,7 +17078,7 @@ dependencies = [
[[package]]
name = "windmill-parser-csharp"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"serde_json",
@@ -17090,7 +17090,7 @@ dependencies = [
[[package]]
name = "windmill-parser-go"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"gosyn",
@@ -17102,7 +17102,7 @@ dependencies = [
[[package]]
name = "windmill-parser-graphql"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"lazy_static",
@@ -17114,7 +17114,7 @@ dependencies = [
[[package]]
name = "windmill-parser-java"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"serde_json",
@@ -17126,7 +17126,7 @@ dependencies = [
[[package]]
name = "windmill-parser-nu"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"nu-parser",
@@ -17137,7 +17137,7 @@ dependencies = [
[[package]]
name = "windmill-parser-php"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"itertools 0.14.0",
@@ -17148,7 +17148,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"itertools 0.14.0",
@@ -17160,7 +17160,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py-asset"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"rustpython-ast",
@@ -17171,7 +17171,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py-imports"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"async-recursion",
@@ -17193,7 +17193,7 @@ dependencies = [
[[package]]
name = "windmill-parser-r"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"serde_json",
@@ -17205,7 +17205,7 @@ dependencies = [
[[package]]
name = "windmill-parser-ruby"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"lazy_static",
@@ -17219,7 +17219,7 @@ dependencies = [
[[package]]
name = "windmill-parser-rust"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"convert_case 0.6.0",
@@ -17236,7 +17236,7 @@ dependencies = [
[[package]]
name = "windmill-parser-sql"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"lazy_static",
@@ -17249,7 +17249,7 @@ dependencies = [
[[package]]
name = "windmill-parser-sql-asset"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"serde",
@@ -17261,7 +17261,7 @@ dependencies = [
[[package]]
name = "windmill-parser-ts"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"lazy_static",
@@ -17279,7 +17279,7 @@ dependencies = [
[[package]]
name = "windmill-parser-ts-asset"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"serde-wasm-bindgen",
@@ -17295,7 +17295,7 @@ dependencies = [
[[package]]
name = "windmill-parser-wac"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"rustpython-ast",
@@ -17311,7 +17311,7 @@ dependencies = [
[[package]]
name = "windmill-parser-yaml"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"serde",
@@ -17322,7 +17322,7 @@ dependencies = [
[[package]]
name = "windmill-queue"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"async-recursion",
@@ -17359,7 +17359,7 @@ dependencies = [
[[package]]
name = "windmill-runtime-nativets"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"const_format",
@@ -17397,7 +17397,7 @@ dependencies = [
[[package]]
name = "windmill-sql-datatype-parser-wasm"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"getrandom 0.3.4",
"wasm-bindgen",
@@ -17408,7 +17408,7 @@ dependencies = [
[[package]]
name = "windmill-store"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"async-recursion",
@@ -17437,7 +17437,7 @@ dependencies = [
[[package]]
name = "windmill-test-utils"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17461,7 +17461,7 @@ dependencies = [
[[package]]
name = "windmill-trigger"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17494,7 +17494,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-email"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17514,7 +17514,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-gcp"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17548,7 +17548,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-http"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17584,7 +17584,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-kafka"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17607,7 +17607,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-mqtt"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17631,7 +17631,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-nats"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"async-nats",
@@ -17655,7 +17655,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-postgres"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17690,7 +17690,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-sqs"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17718,7 +17718,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-websocket"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17741,7 +17741,7 @@ dependencies = [
[[package]]
name = "windmill-types"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"bitflags 2.9.4",
@@ -17760,7 +17760,7 @@ dependencies = [
[[package]]
name = "windmill-worker"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"anyhow",
"async-once-cell",
@@ -17871,7 +17871,7 @@ dependencies = [
[[package]]
name = "windmill-worker-volumes"
version = "1.680.0"
version = "1.679.0"
dependencies = [
"bytes",
"futures",

View File

@@ -1,6 +1,6 @@
[package]
name = "windmill"
version = "1.680.0"
version = "1.679.0"
authors.workspace = true
edition.workspace = true
@@ -85,7 +85,7 @@ members = [
exclude = ["./windmill-duckdb-ffi-internal", "./parsers/windmill-parser-wasm"]
[workspace.package]
version = "1.680.0"
version = "1.679.0"
authors = ["Ruben Fiszel <ruben@windmill.dev>"]
edition = "2021"

View File

@@ -1 +1 @@
9ea1259fa6a95e6b24d1523b2f6ec6ae0042ecfe
a30e828a8742b8b644a25a603f0ee380a374607f

View File

@@ -1,6 +0,0 @@
-- Move alert config back from global_settings to the config table.
INSERT INTO config (name, config)
SELECT 'alert__job_queue_waiting', value FROM global_settings WHERE name = 'alert_job_queue_waiting'
ON CONFLICT (name) DO UPDATE SET config = EXCLUDED.config;
DELETE FROM global_settings WHERE name = 'alert_job_queue_waiting';

View File

@@ -1,7 +0,0 @@
-- Move alert config from the generic config table to global_settings
-- where it belongs alongside other instance-level settings.
INSERT INTO global_settings (name, value)
SELECT 'alert_job_queue_waiting', config FROM config WHERE name = 'alert__job_queue_waiting'
ON CONFLICT (name) DO UPDATE SET value = EXCLUDED.value;
DELETE FROM config WHERE name = 'alert__job_queue_waiting';

View File

@@ -1,12 +0,0 @@
-- Re-add the column to resource
ALTER TABLE resource ADD COLUMN IF NOT EXISTS ws_specific BOOLEAN NOT NULL DEFAULT false;
-- Migrate data back
UPDATE resource SET ws_specific = true
FROM ws_specific ws
WHERE ws.workspace_id = resource.workspace_id
AND ws.item_kind = 'resource'
AND ws.path = resource.path;
-- Drop the table
DROP TABLE IF EXISTS ws_specific;

View File

@@ -1,17 +0,0 @@
-- Create the ws_specific table
CREATE TABLE IF NOT EXISTS ws_specific (
workspace_id VARCHAR(50) NOT NULL REFERENCES workspace(id) ON DELETE CASCADE ON UPDATE CASCADE,
item_kind VARCHAR(50) NOT NULL,
path VARCHAR(255) NOT NULL,
PRIMARY KEY (workspace_id, item_kind, path)
);
-- Migrate existing data from resource.ws_specific
INSERT INTO ws_specific (workspace_id, item_kind, path)
SELECT workspace_id, 'resource', path
FROM resource
WHERE ws_specific = true
ON CONFLICT DO NOTHING;
-- Drop the column from resource
ALTER TABLE resource DROP COLUMN IF EXISTS ws_specific;

View File

@@ -754,7 +754,7 @@ async fn windmill_main() -> anyhow::Result<()> {
.and_then(|x| x.parse().ok())
.unwrap_or(IpAddr::from(default_bind_addr));
let (conn, first_suffix, agent_config) = if mode == Mode::Agent {
let (conn, first_suffix, agent_config) = if matches!(mode, Mode::Agent | Mode::AgentBatch) {
let agent_config = match AgentConfig::from_env() {
Ok(config) => config,
Err(e) => {
@@ -829,7 +829,7 @@ async fn windmill_main() -> anyhow::Result<()> {
let _guard = windmill_common::tracing_init::initialize_tracing(&hostname, &mode, &environment);
let is_agent = mode == Mode::Agent;
let is_agent = matches!(mode, Mode::Agent | Mode::AgentBatch);
let mut migration_handle: Option<JoinHandle<()>> = None;
#[cfg(feature = "parquet")]
@@ -953,7 +953,7 @@ async fn windmill_main() -> anyhow::Result<()> {
}
}
let conn = if mode == Mode::Agent {
let conn = if matches!(mode, Mode::Agent | Mode::AgentBatch) {
conn
} else {
// Drop the initial connection pool before creating the main one.
@@ -1289,7 +1289,7 @@ Windmill Community Edition {GIT_VERSION}
)
},
worker_name: worker_name_with_suffix(
mode == Mode::Agent,
matches!(mode, Mode::Agent | Mode::AgentBatch),
WORKER_GROUP.as_str(),
&suffix,
),

View File

@@ -1151,125 +1151,3 @@ async fn test_replace_mode_protects_jwt_secret_and_rsa_keys(db: Pool<Postgres>)
);
assert!(get_global_setting(&db, "normal_setting").await.is_none());
}
// ========================================================================
// Alert config migration tests
// ========================================================================
#[sqlx::test(fixtures("base"))]
async fn test_alert_config_in_global_settings_roundtrip(db: Pool<Postgres>) {
clear_settings_and_configs(&db).await;
let alert_value = serde_json::json!({
"alerts": [
{
"name": "Test Alert",
"tags_to_monitor": ["default", "gpu"],
"jobs_num_threshold": 5,
"alert_cooldown_seconds": 300,
"alert_time_threshold_seconds": 60
}
]
});
// Insert alert_config into global_settings
insert_global_setting(&db, "alert_job_queue_waiting", alert_value.clone()).await;
// Verify it appears in InstanceConfig global_settings (via extra)
let config = InstanceConfig::from_db(&db).await.unwrap();
assert_eq!(
config.global_settings.extra["alert_job_queue_waiting"], alert_value,
"alert_config should appear in global_settings extra"
);
// Verify it does NOT appear in worker_configs
assert!(
!config
.worker_configs
.contains_key("alert_job_queue_waiting"),
"alert_config should not appear in worker_configs"
);
// Modify the alert_config
let updated_value = serde_json::json!({
"alerts": [
{
"name": "Updated Alert",
"tags_to_monitor": ["batch"],
"jobs_num_threshold": 10,
"alert_cooldown_seconds": 600,
"alert_time_threshold_seconds": 120
}
]
});
let current = config.global_settings.to_settings_map();
let mut desired = current.clone();
desired.insert("alert_job_queue_waiting".to_string(), updated_value.clone());
let diff = diff_global_settings(&current, &desired, ApplyMode::Merge);
assert!(
diff.upserts.contains_key("alert_job_queue_waiting"),
"alert_config change should be detected in diff"
);
apply_settings_diff(&db, &diff).await.unwrap();
// Re-read and verify the update
let config2 = InstanceConfig::from_db(&db).await.unwrap();
assert_eq!(
config2.global_settings.extra["alert_job_queue_waiting"],
updated_value
);
}
#[sqlx::test(fixtures("base"))]
async fn test_alert_config_not_in_worker_configs(db: Pool<Postgres>) {
clear_settings_and_configs(&db).await;
// Insert alert_config in global_settings (the correct location)
insert_global_setting(
&db,
"alert_job_queue_waiting",
serde_json::json!({"alerts": []}),
)
.await;
// Also insert a real worker config
insert_config(
&db,
"worker__default",
serde_json::json!({"worker_tags": ["default"]}),
)
.await;
let config = InstanceConfig::from_db(&db).await.unwrap();
// alert_config should be in global_settings, not worker_configs
assert!(
config
.global_settings
.extra
.contains_key("alert_job_queue_waiting"),
"alert_config should be in global_settings.extra"
);
assert_eq!(config.worker_configs.len(), 1);
assert!(
config.worker_configs.contains_key("default"),
"only the real worker config should be in worker_configs"
);
}
#[sqlx::test(fixtures("base"))]
async fn test_no_alert_in_config_table_after_migration(db: Pool<Postgres>) {
// After the migration runs, no alert__* entries should remain in the config table
let rows: Vec<(String,)> = sqlx::query_as("SELECT name FROM config WHERE name LIKE 'alert__%'")
.fetch_all(&db)
.await
.unwrap();
assert!(
rows.is_empty(),
"No alert entries should remain in config table after migration, found: {:?}",
rows.iter().map(|(n,)| n.as_str()).collect::<Vec<_>>()
);
}

View File

@@ -1,139 +0,0 @@
use serde_json::json;
use sqlx::{Pool, Postgres};
use windmill_test_utils::*;
fn client() -> reqwest::Client {
reqwest::Client::new()
}
fn authed(builder: reqwest::RequestBuilder) -> reqwest::RequestBuilder {
builder.header("Authorization", "Bearer SECRET_TOKEN")
}
fn assert_2xx(status: u16, body: &str, endpoint: &str) {
assert!(
(200..300).contains(&status),
"{endpoint} returned {status}: {body}",
);
}
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_worker_group_crud(db: Pool<Postgres>) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
let port = server.addr.port();
let base = format!("http://localhost:{port}/api/configs");
// Create a worker group
let resp = authed(client().post(format!("{base}/update/worker__test_group")))
.json(&json!({"worker_tags": ["test_tag"]}))
.send()
.await?;
assert_2xx(
resp.status().as_u16(),
&resp.text().await?,
"POST /configs/update/worker__test_group",
);
// Verify it exists via get
let resp = authed(client().get(format!("{base}/get/worker__test_group")))
.send()
.await?;
let status = resp.status().as_u16();
let body = resp.text().await?;
assert_2xx(status, &body, "GET /configs/get/worker__test_group");
let config: serde_json::Value = serde_json::from_str(&body)?;
assert_eq!(config["worker_tags"], json!(["test_tag"]));
// Verify it appears in list_worker_groups with prefix stripped
let resp = authed(client().get(format!("{base}/list_worker_groups")))
.send()
.await?;
let body = resp.text().await?;
let groups: Vec<serde_json::Value> = serde_json::from_str(&body)?;
let test_group = groups.iter().find(|g| g["name"] == "test_group");
assert!(
test_group.is_some(),
"test_group should appear in list_worker_groups with prefix stripped"
);
// Delete the worker group
let resp = authed(client().delete(format!("{base}/update/worker__test_group")))
.send()
.await?;
assert_2xx(
resp.status().as_u16(),
&resp.text().await?,
"DELETE /configs/update/worker__test_group",
);
// Verify it's gone from list_worker_groups
let resp = authed(client().get(format!("{base}/list_worker_groups")))
.send()
.await?;
let body = resp.text().await?;
let groups: Vec<serde_json::Value> = serde_json::from_str(&body)?;
let test_group = groups.iter().find(|g| g["name"] == "test_group");
assert!(
test_group.is_none(),
"test_group should be gone after deletion"
);
Ok(())
}
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_list_worker_groups_excludes_non_worker_entries(
db: Pool<Postgres>,
) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
let port = server.addr.port();
let base = format!("http://localhost:{port}/api/configs");
// Insert a non-worker entry directly into the config table
sqlx::query("INSERT INTO config (name, config) VALUES ($1, $2) ON CONFLICT (name) DO UPDATE SET config = EXCLUDED.config")
.bind("test__other_entry")
.bind(json!({"some_key": "some_value"}))
.execute(&db)
.await?;
// list_worker_groups should NOT return it
let resp = authed(client().get(format!("{base}/list_worker_groups")))
.send()
.await?;
let body = resp.text().await?;
let groups: Vec<serde_json::Value> = serde_json::from_str(&body)?;
let other_entry = groups
.iter()
.find(|g| g["name"] == "test__other_entry" || g["name"] == "other_entry");
assert!(
other_entry.is_none(),
"non-worker entries should not appear in list_worker_groups"
);
// Clean up
sqlx::query("DELETE FROM config WHERE name = $1")
.bind("test__other_entry")
.execute(&db)
.await?;
Ok(())
}
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_no_alert_entries_in_config_table_after_migration(
db: Pool<Postgres>,
) -> anyhow::Result<()> {
// After migration, no alert__* entries should remain in the config table
let rows: Vec<(String,)> = sqlx::query_as("SELECT name FROM config WHERE name LIKE 'alert__%'")
.fetch_all(&db)
.await?;
assert!(
rows.is_empty(),
"No alert entries should remain in config table after migration, found: {:?}",
rows.iter().map(|(n,)| n.as_str()).collect::<Vec<_>>()
);
Ok(())
}

View File

@@ -114,89 +114,3 @@ async fn test_settings_2xx(db: Pool<Postgres>) -> anyhow::Result<()> {
Ok(())
}
#[sqlx::test(migrations = "../migrations", fixtures("base"))]
async fn test_alert_job_queue_waiting_in_global_settings(db: Pool<Postgres>) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
let port = server.addr.port();
let settings_base = format!("http://localhost:{port}/api/settings");
let configs_base = format!("http://localhost:{port}/api/configs");
let alert_payload = json!({
"alerts": [
{
"name": "Test Alert",
"tags_to_monitor": ["default", "gpu"],
"jobs_num_threshold": 5,
"alert_cooldown_seconds": 300,
"alert_time_threshold_seconds": 60
}
]
});
// Set alert_job_queue_waiting in global_settings
let resp = authed(client().post(format!("{settings_base}/global/alert_job_queue_waiting")))
.json(&json!({"value": alert_payload}))
.send()
.await?;
assert_2xx(
resp.status().as_u16(),
&resp.text().await?,
"POST /settings/global/alert_job_queue_waiting",
);
// Read it back
let resp = authed(client().get(format!("{settings_base}/global/alert_job_queue_waiting")))
.send()
.await?;
let status = resp.status().as_u16();
let body = resp.text().await?;
assert_2xx(
status,
&body,
"GET /settings/global/alert_job_queue_waiting",
);
let value: serde_json::Value = serde_json::from_str(&body)?;
assert_eq!(value["alerts"][0]["name"], "Test Alert");
assert_eq!(value["alerts"][0]["jobs_num_threshold"], 5);
// Verify alert_job_queue_waiting does NOT appear in list_worker_groups
let resp = authed(client().get(format!("{configs_base}/list_worker_groups")))
.send()
.await?;
let body = resp.text().await?;
let groups: Vec<serde_json::Value> = serde_json::from_str(&body)?;
let alert_in_groups = groups.iter().find(|g| {
let name = g["name"].as_str().unwrap_or("");
name.contains("alert")
});
assert!(
alert_in_groups.is_none(),
"alert_job_queue_waiting should not appear in worker groups"
);
// Delete by setting to null
let resp = authed(client().post(format!("{settings_base}/global/alert_job_queue_waiting")))
.json(&json!({"value": null}))
.send()
.await?;
assert_2xx(
resp.status().as_u16(),
&resp.text().await?,
"POST /settings/global/alert_job_queue_waiting (null)",
);
// Verify it reads back as null
let resp = authed(client().get(format!("{settings_base}/global/alert_job_queue_waiting")))
.send()
.await?;
let body = resp.text().await?;
let value: serde_json::Value = serde_json::from_str(&body)?;
assert!(
value.is_null(),
"alert_job_queue_waiting should be null after deletion"
);
Ok(())
}

View File

@@ -4160,7 +4160,7 @@ async fn create_workspace_fork_branch(
/// Update a forked workspace's datatable config to point to the new database.
/// For instance datatables: updates resource_path in the datatable config.
/// For resource datatables: updates the resource's dbname and marks it as ws_specific.
/// For resource datatables: updates the resource's dbname and sets ws_specific.
/// Snapshot the schema from the source datatable by connecting to its database.
async fn snapshot_datatable_schema(
db: &DB,
@@ -4242,11 +4242,12 @@ async fn apply_forked_datatable(
.execute(&mut **tx)
.await?;
} else {
// Resource: update the resource's dbname and mark as ws_specific
// Resource: update the resource's dbname and set ws_specific
let resource_path = &dt.database.resource_path;
sqlx::query!(
r#"UPDATE resource
SET value = jsonb_set(value, '{dbname}', to_jsonb($3::text))
SET value = jsonb_set(value, '{dbname}', to_jsonb($3::text)),
ws_specific = true
WHERE workspace_id = $1 AND path = $2"#,
forked_w_id,
resource_path,
@@ -4255,14 +4256,6 @@ async fn apply_forked_datatable(
.execute(&mut **tx)
.await?;
sqlx::query!(
"INSERT INTO ws_specific (workspace_id, item_kind, path) VALUES ($1, 'resource', $2) ON CONFLICT DO NOTHING",
forked_w_id,
resource_path,
)
.execute(&mut **tx)
.await?;
// Set forked_from on the datatable config
sqlx::query!(
r#"UPDATE workspace_settings
@@ -6088,7 +6081,7 @@ async fn compare_two_resources(
) -> Result<ItemComparison> {
// Get resource from each workspace
let source_resource = sqlx::query!(
"SELECT value, description, resource_type
"SELECT value, description, resource_type, ws_specific
FROM resource
WHERE workspace_id = $1 AND path = $2",
source_workspace_id,
@@ -6098,7 +6091,7 @@ async fn compare_two_resources(
.await?;
let target_resource = sqlx::query!(
"SELECT value, description, resource_type
"SELECT value, description, resource_type, ws_specific
FROM resource
WHERE workspace_id = $1 AND path = $2",
fork_workspace_id,
@@ -6108,24 +6101,8 @@ async fn compare_two_resources(
.await?;
// If either side is ws_specific, consider unchanged
let source_ws_specific = sqlx::query_scalar!(
"SELECT EXISTS(SELECT 1 FROM ws_specific WHERE workspace_id = $1 AND item_kind = 'resource' AND path = $2)",
source_workspace_id,
path
)
.fetch_one(db)
.await?
.unwrap_or(false);
let target_ws_specific = sqlx::query_scalar!(
"SELECT EXISTS(SELECT 1 FROM ws_specific WHERE workspace_id = $1 AND item_kind = 'resource' AND path = $2)",
fork_workspace_id,
path
)
.fetch_one(db)
.await?
.unwrap_or(false);
let source_ws_specific = source_resource.as_ref().map_or(false, |r| r.ws_specific);
let target_ws_specific = target_resource.as_ref().map_or(false, |r| r.ws_specific);
if source_ws_specific || target_ws_specific {
return Ok(ItemComparison {
has_changes: false,

View File

@@ -1,7 +1,7 @@
openapi: "3.0.3"
info:
version: 1.680.0
version: 1.679.0
title: Windmill API
contact:
@@ -21659,6 +21659,9 @@ components:
resource_type:
type: string
description: The new resource_type to be associated with the resource
ws_specific:
type: boolean
description: When true, the resource is excluded from workspace diff comparisons
labels:
type: array
items:

View File

@@ -66,7 +66,6 @@ pub const GITHUB_ENTERPRISE_APP_SETTING: &str = "github_enterprise_app";
pub const INSTANCE_EVENTS_WEBHOOK_SETTING: &str = "instance_events_webhook";
pub const WORKSPACE_REGISTRIES_SETTING: &str = "workspace_registries";
pub const RESTART_COORDINATION_SETTING: &str = "_restart_coordination";
pub const ALERT_CONFIG_SETTING: &str = "alert_job_queue_waiting";
use std::sync::Arc;
use tokio::sync::RwLock;

View File

@@ -122,6 +122,21 @@ lazy_static::lazy_static! {
}
#[cfg(feature = "enterprise")]
Mode::Agent
} else if &x == "agent-batch" {
println!("Binary is in 'agent-batch' mode with BASE_INTERNAL_URL={}", std::env::var("BASE_INTERNAL_URL").unwrap_or_default());
if std::env::var("BASE_INTERNAL_URL").is_err() {
panic!("BASE_INTERNAL_URL is required in agent-batch mode")
}
if std::env::var("AGENT_TOKEN").is_err() {
println!("AGENT_TOKEN is not passed. This is required for the agent to work and contains the JWT to authenticate with the server.")
}
#[cfg(not(feature = "enterprise"))]
{
panic!("Agent-batch mode is only available in the EE, ignoring...");
}
#[cfg(feature = "enterprise")]
Mode::AgentBatch
} else if &x == "indexer" {
tracing::info!("Binary is in 'indexer' mode");
#[cfg(not(feature = "tantivy"))]
@@ -474,6 +489,7 @@ pub fn map_string_to_number(s: &str, max_number: u64) -> u64 {
pub enum Mode {
Worker,
Agent,
AgentBatch,
Server,
Standalone,
Indexer,
@@ -485,6 +501,7 @@ impl std::fmt::Display for Mode {
match self {
Mode::Worker => write!(f, "worker"),
Mode::Agent => write!(f, "agent"),
Mode::AgentBatch => write!(f, "agent-batch"),
Mode::Server => write!(f, "server"),
Mode::Standalone => write!(f, "standalone"),
Mode::Indexer => write!(f, "indexer"),

View File

@@ -237,6 +237,12 @@ lazy_static::lazy_static! {
pub static ref WORKER_PULL_QUERIES: Arc<RwLock<Vec<String>>> = Arc::new(RwLock::new(vec![]));
pub static ref WORKER_SUSPENDED_PULL_QUERY: Arc<RwLock<String>> = Arc::new(RwLock::new("".to_string()));
pub static ref WORKER_BATCH_PULL_QUERIES: Arc<RwLock<Vec<String>>> = Arc::new(RwLock::new(vec![]));
pub static ref BATCH_PULL_SIZE: i32 = std::env::var("BATCH_PULL_SIZE")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(0);
pub static ref SMTP_CONFIG: Arc<RwLock<Option<Smtp>>> = Arc::new(RwLock::new(None));
@@ -522,16 +528,84 @@ pub fn make_pull_query(tags: &[String]) -> String {
pub async fn store_pull_query(wc: &WorkerConfig) {
let mut queries = vec![];
let mut batch_queries = vec![];
for tags in wc.priority_tags_sorted.iter() {
if tags.tags.len() == 0 {
tracing::error!("Empty tags in priority tags, skipping");
continue;
}
let query = make_pull_query(&tags.tags);
queries.push(query);
queries.push(make_pull_query(&tags.tags));
batch_queries.push(make_batch_pull_query(&tags.tags));
}
let mut l = WORKER_PULL_QUERIES.write().await;
*l = queries;
drop(l);
let mut l = WORKER_BATCH_PULL_QUERIES.write().await;
*l = batch_queries;
}
/// Build a batch pull query that claims up to $2 jobs at once.
/// Uses $1 for worker_name and $2 for batch_size (i32).
pub fn make_batch_pull_query(tags: &[String]) -> String {
format_batch_pull_query(format!(
"SELECT id
FROM v2_job_queue
WHERE running = false
AND tag IN ({}) AND scheduled_for <= now()
AND id NOT IN (SELECT id FROM v2_job WHERE same_worker = true)
ORDER BY priority DESC NULLS LAST, scheduled_for
FOR UPDATE SKIP LOCKED
LIMIT $2",
tags.iter().map(|x| format!("'{x}'")).join(", ")
))
}
fn format_batch_pull_query(peek: String) -> String {
format!(
"WITH peek AS (
{}
), q AS NOT MATERIALIZED (
UPDATE v2_job_queue SET
running = true,
started_at = coalesce(started_at, now()),
suspend_until = null,
worker = $1
WHERE id IN (SELECT id FROM peek)
RETURNING
id, started_at, scheduled_for,
canceled_by, canceled_reason, worker, cache_ignore_s3_path, runnable_settings_handle
), r AS NOT MATERIALIZED (
UPDATE v2_job_runtime SET
ping = now()
WHERE id IN (SELECT id FROM peek)
), j AS NOT MATERIALIZED (
SELECT
id, workspace_id, parent_job, created_by, created_at, runnable_id,
runnable_path, args, kind, trigger, trigger_kind,
permissioned_as, permissioned_as_email, script_lang,
flow_innermost_root_job, root_job, flow_step_id,
same_worker, pre_run_error, visible_to_owner, tag, concurrent_limit,
concurrency_time_window_s, timeout, cache_ttl, priority, raw_code, raw_lock,
raw_flow, script_entrypoint_override, preprocessed
FROM v2_job
WHERE id IN (SELECT id FROM peek)
) SELECT j.id, j.workspace_id, j.parent_job, j.created_by, q.started_at, q.scheduled_for,
j.runnable_id, j.runnable_path, j.args, q.canceled_by,
q.canceled_reason, j.kind, j.trigger, j.trigger_kind, j.permissioned_as,
f.flow_status, j.script_lang,
j.same_worker, j.pre_run_error, j.visible_to_owner,
j.tag, j.concurrent_limit, j.concurrency_time_window_s, j.flow_innermost_root_job, j.root_job,
j.timeout, j.flow_step_id, j.cache_ttl, q.cache_ignore_s3_path, q.runnable_settings_handle, j.priority, j.raw_code, j.raw_lock, j.raw_flow,
j.script_entrypoint_override, j.preprocessed, COALESCE(pj.runnable_path, j.args->>'_FLOW_PATH') as parent_runnable_path,
COALESCE(p.email, j.permissioned_as_email) as permissioned_as_email, p.username as permissioned_as_username, p.is_admin as permissioned_as_is_admin,
p.is_operator as permissioned_as_is_operator, p.groups as permissioned_as_groups, p.folders as permissioned_as_folders, p.end_user_email as permissioned_as_end_user_email
FROM q
INNER JOIN j ON q.id = j.id
LEFT JOIN v2_job_status f ON f.id = j.id
LEFT JOIN job_perms p ON p.job_id = j.id
LEFT JOIN v2_job pj ON j.parent_job = pj.id",
peek
)
}
lazy_static::lazy_static! {

View File

@@ -443,6 +443,92 @@ pub async fn append_logs(
}
}
/// Pull up to `batch_size` jobs at once using the given batch pull query.
/// The query must use $1 for worker_name and $2 for batch_size (i32).
pub async fn batch_pull(
db: &Pool<Postgres>,
worker_name: &str,
batch_query: &str,
batch_size: i32,
) -> windmill_common::error::Result<Vec<PulledJob>> {
let jobs = sqlx::query_as::<_, PulledJob>(batch_query)
.bind(worker_name)
.bind(batch_size)
.fetch_all(db)
.await
.map_err(|e| {
windmill_common::error::Error::InternalErr(format!("batch pull error: {e:#}"))
})?;
Ok(jobs)
}
/// Batch-commit multiple completed jobs in a single transaction.
/// Only for simple jobs (no flows, no schedules, no concurrency limits).
/// Returns (job_id, duration_ms) for each committed job.
pub async fn batch_commit_completed_jobs(
db: &Pool<Postgres>,
jobs: &[(Uuid, bool, &serde_json::value::RawValue, i32, Option<i64>)], // (id, success, result, mem_peak, duration)
) -> windmill_common::error::Result<Vec<(Uuid, i64)>> {
if jobs.is_empty() {
return Ok(vec![]);
}
let mut tx = db.begin().await.map_err(|e| {
windmill_common::error::Error::InternalErr(format!("batch commit begin: {e:#}"))
})?;
let mut results = Vec::with_capacity(jobs.len());
for &(job_id, success, result, mem_peak, duration) in jobs {
let status = if success { "success" } else { "failure" };
let duration_ms: Option<i64> = sqlx::query_scalar(
"INSERT INTO v2_job_completed AS cj
(workspace_id, id, started_at, duration_ms, result,
flow_status, workflow_as_code_status,
memory_peak, status, worker)
SELECT q.workspace_id, q.id, started_at,
COALESCE($3::bigint, (EXTRACT('epoch' FROM (now())) - EXTRACT('epoch' FROM (COALESCE(started_at, now()))))*1000),
$2::jsonb, flow_status, workflow_as_code_status,
$4, $5::job_status, q.worker
FROM v2_job_queue q LEFT JOIN v2_job_status USING (id)
WHERE q.id = $1
ON CONFLICT (id) DO UPDATE SET status = EXCLUDED.status, result = $2::jsonb
RETURNING duration_ms",
)
.bind(job_id)
.bind(result.get())
.bind(duration)
.bind(if mem_peak > 0 { Some(mem_peak) } else { None })
.bind(status)
.fetch_optional(&mut *tx)
.await
.map_err(|e| {
windmill_common::error::Error::InternalErr(format!(
"batch commit insert job {job_id}: {e:#}"
))
})?;
if let Some(dur) = duration_ms {
sqlx::query!("DELETE FROM v2_job_queue WHERE id = $1", job_id)
.execute(&mut *tx)
.await
.map_err(|e| {
windmill_common::error::Error::InternalErr(format!(
"batch commit delete job {job_id}: {e:#}"
))
})?;
results.push((job_id, dur));
} else {
tracing::warn!("batch commit: job {job_id} not found in queue, skipping");
}
}
tx.commit()
.await
.map_err(|e| windmill_common::error::Error::InternalErr(format!("batch commit: {e:#}")))?;
Ok(results)
}
pub const PERIODIC_SCRIPT_TAG: &str = "periodic_bash_script";
pub const INIT_SCRIPT_TAG: &str = "init_script";
pub const INIT_SCRIPT_PATH_PREFIX: &str = "init_script_";
@@ -3638,8 +3724,11 @@ pub fn resolve_debounce_key<'b>(
.join(":"),
));
tracing::debug!("Original debounce key (len={}): {}", original_debounce_key.len(), original_debounce_key);
tracing::debug!(
"Original debounce key (len={}): {}",
original_debounce_key.len(),
original_debounce_key
);
// If debounce_key is not too long (< 255 chars), keep it as is, otherwise hash it.
// On cloud, we prepend "{workspace_id}:" so we must reserve space for that prefix

View File

@@ -125,6 +125,8 @@ pub struct Resource {
pub extra_perms: serde_json::Value,
pub created_by: Option<String>,
pub edited_at: Option<chrono::DateTime<chrono::Utc>>,
#[serde(default)]
pub ws_specific: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub labels: Option<Vec<String>>,
}
@@ -145,6 +147,8 @@ pub struct ListableResource {
pub is_expired: Option<bool>,
pub refresh_error: Option<String>,
pub account: Option<i32>,
#[serde(default)]
pub ws_specific: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub labels: Option<Vec<String>>,
}
@@ -155,6 +159,8 @@ pub struct CreateResource {
pub value: Option<Box<RawValue>>,
pub description: Option<String>,
pub resource_type: String,
#[serde(default)]
pub ws_specific: Option<bool>,
pub labels: Option<Vec<String>>,
}
#[derive(Deserialize)]
@@ -162,6 +168,7 @@ struct EditResource {
path: Option<String>,
description: Option<String>,
value: Option<Box<RawValue>>,
ws_specific: Option<bool>,
labels: Option<Vec<String>>,
}
@@ -259,6 +266,7 @@ async fn list_resources(
"account.refresh_error",
"resource.created_by",
"resource.edited_at",
"resource.ws_specific",
"resource.labels",
])
.left()
@@ -835,15 +843,16 @@ async fn create_resource(
}
sqlx::query!(
"INSERT INTO resource
(workspace_id, path, value, description, resource_type, created_by, edited_at, labels)
VALUES ($1, $2, $3, $4, $5, $6, now(), $7) ON CONFLICT (workspace_id, path)
DO UPDATE SET value = EXCLUDED.value, description = EXCLUDED.description, resource_type = EXCLUDED.resource_type, edited_at = now(), labels = EXCLUDED.labels",
(workspace_id, path, value, description, resource_type, created_by, edited_at, ws_specific, labels)
VALUES ($1, $2, $3, $4, $5, $6, now(), $7, $8) ON CONFLICT (workspace_id, path)
DO UPDATE SET value = EXCLUDED.value, description = EXCLUDED.description, resource_type = EXCLUDED.resource_type, edited_at = now(), ws_specific = EXCLUDED.ws_specific, labels = EXCLUDED.labels",
w_id,
resource.path,
raw_json as sqlx::types::Json<&RawValue>,
resource.description,
resource.resource_type,
authed.username,
resource.ws_specific.unwrap_or(false),
resource.labels.as_deref() as Option<&[String]>
)
.execute(&mut *tx)
@@ -950,14 +959,6 @@ async fn delete_resource(
q.fetch_all(&mut *tx).await?
};
sqlx::query!(
"DELETE FROM ws_specific WHERE workspace_id = $1 AND item_kind = 'resource' AND path = $2",
w_id,
path
)
.execute(&mut *tx)
.await?;
let deleted_path = sqlx::query_scalar!(
"DELETE FROM resource WHERE path = $1 AND workspace_id = $2 RETURNING path",
path,
@@ -1133,14 +1134,6 @@ async fn delete_resources_bulk(
}
}
sqlx::query!(
"DELETE FROM ws_specific WHERE workspace_id = $1 AND item_kind = 'resource' AND path = ANY($2)",
w_id,
&request.paths
)
.execute(&mut *tx)
.await?;
let deleted_paths = sqlx::query_scalar!(
"DELETE FROM resource WHERE path = ANY($1) AND workspace_id = $2 RETURNING path",
&request.paths,
@@ -1227,6 +1220,10 @@ async fn update_resource(
if let Some(ndesc) = ns.description {
sqlb.set_str("description", ndesc);
}
if let Some(nd) = ns.ws_specific {
sqlb.set_str("ws_specific", if nd { "true" } else { "false" });
}
sqlb.set_str("edited_at", "now()");
sqlb.returning("path");
@@ -1285,15 +1282,6 @@ async fn update_resource(
)
.execute(&mut *tx)
.await?;
sqlx::query!(
"UPDATE ws_specific SET path = $1 WHERE workspace_id = $2 AND item_kind = 'resource' AND path = $3",
npath,
w_id,
path
)
.execute(&mut *tx)
.await?;
}
}

View File

@@ -37,6 +37,15 @@ pub async fn pull_job(
.await
}
pub async fn batch_pull_jobs(
client: &HttpClient,
batch_size: i32,
) -> anyhow::Result<Vec<JobAndPerms>> {
client
.post("/api/agent_workers/batch_pull", None, &batch_size)
.await
}
pub async fn send_result(client: &HttpClient, jc: JobCompleted) -> anyhow::Result<String> {
client
.post(

View File

@@ -218,6 +218,22 @@ enum JobCompletedRx {
WakeUp,
}
fn is_batchable(jc: &JobCompleted) -> bool {
jc.success
&& !jc.job.is_flow_step()
&& jc.job.flow_step_id.as_deref() != Some("preprocessor")
&& jc.preprocessed_args.is_none()
&& jc.job.tag.as_str() != INIT_SCRIPT_TAG
&& !matches!(
jc.job.kind,
JobKind::Dependencies | JobKind::FlowDependencies
)
&& jc.canceled_by.is_none()
&& jc.cached_res_path.is_none()
&& jc.job.concurrent_limit.is_none()
&& jc.job.schedule_path().is_none()
}
pub fn start_background_processor(
job_completed_rx: JobCompletedReceiver,
job_completed_sender: JobCompletedSender,
@@ -264,6 +280,8 @@ pub fn start_background_processor(
}
});
let mut batch_result_buffer: Vec<windmill_queue::JobCompleted> = Vec::new();
//if we have been killed, we want to drain the queue of jobs
while let Some(sr) = {
if has_been_killed {
@@ -303,61 +321,153 @@ pub fn start_background_processor(
result: SendResultPayload::JobCompleted(jc),
time,
}) => {
let is_init_script_and_failure =
!jc.success && jc.job.tag.as_str() == INIT_SCRIPT_TAG;
let is_dependency_job = matches!(
jc.job.kind,
JobKind::Dependencies | JobKind::FlowDependencies
);
#[cfg(feature = "benchmark")]
let bench_job_id = jc.job.id;
#[cfg(feature = "benchmark")]
let is_top_level_job = jc.job.parent_job.is_none();
let batch_mode = *windmill_common::worker::BATCH_PULL_SIZE > 0
|| windmill_common::utils::MODE_AND_ADDONS.mode
== windmill_common::utils::Mode::AgentBatch;
process_jc(
jc,
&worker_name,
&base_internal_url,
&db,
&worker_dir,
Some(&same_worker_tx),
&job_completed_sender,
&stats_map,
&killpill_rx,
#[cfg(feature = "benchmark")]
&mut bench,
#[cfg(feature = "benchmark")]
&mut infos,
)
.warn_after_seconds(10)
.await;
if batch_mode && is_batchable(&jc) {
// Accumulate for batch commit
batch_result_buffer.push(jc);
if is_init_script_and_failure {
tracing::error!("init script errored, exiting");
killpill_tx.send();
break;
}
if is_dependency_job && is_dedicated_worker {
tracing::error!("Dedicated worker executed a dependency job, a new script has been deployed. Exiting expecting to be restarted.");
sqlx::query!(
"UPDATE config SET config = config WHERE name = $1",
format!("worker__{}", *WORKER_GROUP)
)
.execute(&db)
.await
.expect("update config to trigger restart of all dedicated workers at that config");
killpill_tx.send();
}
add_time!(bench, "job completed processed");
#[cfg(feature = "benchmark")]
{
if infos.add_iter(bench, bench_job_id, is_top_level_job) {
infos.shared_iters.fetch_add(1, Ordering::Relaxed);
// Drain any additional ready results
while let Ok(SendResult {
result: SendResultPayload::JobCompleted(jc2),
..
}) = bounded_rx.try_recv()
{
if is_batchable(&jc2) {
batch_result_buffer.push(jc2);
} else {
process_jc(
jc2,
&worker_name,
&base_internal_url,
&db,
&worker_dir,
Some(&same_worker_tx),
&job_completed_sender,
&stats_map,
&killpill_rx,
#[cfg(feature = "benchmark")]
&mut bench,
#[cfg(feature = "benchmark")]
&mut infos,
)
.warn_after_seconds(10)
.await;
}
if batch_result_buffer.len() >= 50 {
break;
}
}
// Flush batch
if !batch_result_buffer.is_empty() {
let batch_items: Vec<_> = batch_result_buffer
.iter()
.map(|jc| {
(
jc.job.id,
jc.success,
jc.result.as_ref() as &serde_json::value::RawValue,
jc.mem_peak,
jc.duration,
)
})
.collect();
match windmill_queue::batch_commit_completed_jobs(&db, &batch_items)
.await
{
Ok(committed) => {
tracing::debug!("batch committed {} jobs", committed.len());
}
Err(e) => {
tracing::error!(
"batch commit failed, falling back to individual: {e:#}"
);
for jc in batch_result_buffer.drain(..) {
process_jc(
jc,
&worker_name,
&base_internal_url,
&db,
&worker_dir,
Some(&same_worker_tx),
&job_completed_sender,
&stats_map,
&killpill_rx,
#[cfg(feature = "benchmark")]
&mut bench,
#[cfg(feature = "benchmark")]
&mut infos,
)
.warn_after_seconds(10)
.await;
}
}
}
batch_result_buffer.clear();
}
last_processing_duration
.store(time.elapsed().as_secs() as u16, Ordering::SeqCst);
} else {
let is_init_script_and_failure =
!jc.success && jc.job.tag.as_str() == INIT_SCRIPT_TAG;
let is_dependency_job = matches!(
jc.job.kind,
JobKind::Dependencies | JobKind::FlowDependencies
);
#[cfg(feature = "benchmark")]
let bench_job_id = jc.job.id;
#[cfg(feature = "benchmark")]
let is_top_level_job = jc.job.parent_job.is_none();
process_jc(
jc,
&worker_name,
&base_internal_url,
&db,
&worker_dir,
Some(&same_worker_tx),
&job_completed_sender,
&stats_map,
&killpill_rx,
#[cfg(feature = "benchmark")]
&mut bench,
#[cfg(feature = "benchmark")]
&mut infos,
)
.warn_after_seconds(10)
.await;
if is_init_script_and_failure {
tracing::error!("init script errored, exiting");
killpill_tx.send();
break;
}
if is_dependency_job && is_dedicated_worker {
tracing::error!("Dedicated worker executed a dependency job, a new script has been deployed. Exiting expecting to be restarted.");
sqlx::query!(
"UPDATE config SET config = config WHERE name = $1",
format!("worker__{}", *WORKER_GROUP)
)
.execute(&db)
.await
.expect("update config to trigger restart of all dedicated workers at that config");
killpill_tx.send();
}
add_time!(bench, "job completed processed");
#[cfg(feature = "benchmark")]
{
if infos.add_iter(bench, bench_job_id, is_top_level_job) {
infos.shared_iters.fetch_add(1, Ordering::Relaxed);
}
}
last_processing_duration
.store(time.elapsed().as_secs() as u16, Ordering::SeqCst);
}
last_processing_duration
.store(time.elapsed().as_secs() as u16, Ordering::SeqCst);
}
JobCompletedRx::JobCompleted(SendResult {
result:

View File

@@ -2075,6 +2075,23 @@ pub async fn run_worker(
let mut last_suspend_first = Instant::now();
let mut killed_but_draining_same_worker_jobs = false;
let is_agent_batch =
windmill_common::utils::MODE_AND_ADDONS.mode == windmill_common::utils::Mode::AgentBatch;
let batch_pull_size = {
let s = *windmill_common::worker::BATCH_PULL_SIZE;
if s > 0 {
s
} else if is_agent_batch {
100
} else {
0
}
};
let mut batch_pull_buffer: std::collections::VecDeque<windmill_queue::PulledJob> =
std::collections::VecDeque::new();
let mut agent_batch_buffer: std::collections::VecDeque<windmill_queue::JobAndPerms> =
std::collections::VecDeque::new();
let mut killpill_rx2 = killpill_rx.resubscribe();
loop {
@@ -2318,6 +2335,53 @@ pub async fn run_worker(
tokio::time::sleep(Duration::from_millis(200)).await;
continue;
}
} else if batch_pull_size > 0 && !batch_pull_buffer.is_empty() {
// Serve from batch pull buffer
Ok(batch_pull_buffer
.pop_front()
.map(|job| NextJob::Sql { flow_runners: None, job }))
} else if batch_pull_size > 0 && matches!(&conn, Connection::Sql(_)) {
// Batch pull: try to refill buffer from DB
let db = conn.as_sql().unwrap();
let queries = windmill_common::worker::WORKER_BATCH_PULL_QUERIES
.read()
.await;
if queries.is_empty() {
drop(queries);
// Queries not populated yet, fall through to normal pull below
None
} else {
let mut pulled = Vec::new();
for query in queries.iter() {
match windmill_queue::batch_pull(db, &worker_name, query, batch_pull_size)
.await
{
Ok(jobs) if !jobs.is_empty() => {
pulled = jobs;
break;
}
Ok(_) => {}
Err(e) => {
tracing::error!(worker = %worker_name, "batch pull error: {e:#}");
}
}
}
drop(queries);
if pulled.is_empty() {
Some(Ok(None))
} else {
let mut iter = pulled.into_iter();
let first = iter.next();
for job in iter {
batch_pull_buffer.push_back(job);
}
Some(Ok(first.map(|job| NextJob::Sql { flow_runners: None, job })))
}
}
.unwrap_or_else(|| {
// Fall through: queries not ready yet
Ok(None)
})
} else {
match &conn {
Connection::Sql(db) => {
@@ -2453,10 +2517,36 @@ pub async fn run_worker(
}
}
Connection::Http(client) => crate::agent_workers::pull_job(&client, None, None)
.await
.map_err(|e| error::Error::InternalErr(e.to_string()))
.map(|x| x.map(|y| NextJob::Http(y))),
Connection::Http(client) => {
if batch_pull_size > 0 {
// Agent-batch mode: serve from buffer, refill via batch pull
if let Some(job) = agent_batch_buffer.pop_front() {
Ok(Some(NextJob::Http(job)))
} else {
match crate::agent_workers::batch_pull_jobs(
&client,
batch_pull_size,
)
.await
{
Ok(mut jobs) if !jobs.is_empty() => {
let first = jobs.remove(0);
for job in jobs {
agent_batch_buffer.push_back(job);
}
Ok(Some(NextJob::Http(first)))
}
Ok(_) => Ok(None),
Err(e) => Err(error::Error::InternalErr(e.to_string())),
}
}
} else {
crate::agent_workers::pull_job(&client, None, None)
.await
.map_err(|e| error::Error::InternalErr(e.to_string()))
.map(|x| x.map(|y| NextJob::Http(y)))
}
}
}
}
};

View File

@@ -2,7 +2,7 @@ import { sleep } from "https://deno.land/x/sleep@v1.2.1/mod.ts";
import * as windmill from "https://deno.land/x/windmill@v1.174.0/mod.ts";
import * as api from "https://deno.land/x/windmill@v1.174.0/windmill-api/index.ts";
export const VERSION = "v1.680.0";
export const VERSION = "v1.679.0";
export async function login(email: string, password: string): Promise<string> {
return await windmill.UserService.login({

View File

@@ -67,7 +67,7 @@ const packageJson = {
url: "https://github.com/windmill-labs/windmill/issues",
},
dependencies: {
esbuild: "0.28.0",
esbuild: "^0.24.2",
...Object.fromEntries(parserPackages.map(p => [p, "*"])),
},
optionalDependencies: {

View File

@@ -1,8 +1,9 @@
{
"lockfileVersion": 1,
"configVersion": 1,
"workspaces": {
"": {
"name": "wmill-dev",
"name": "windmill-cli-dev",
"dependencies": {
"@cliffy/ansi": "npm:@jsr/cliffy__ansi@1.0.0",
"@cliffy/command": "npm:@jsr/cliffy__command@1.0.0",
@@ -10,7 +11,7 @@
"@cliffy/table": "npm:@jsr/cliffy__table@1.0.0",
"@windmill-labs/shared-utils": "^1.0.12",
"diff": "^5.2.0",
"esbuild": "0.28.0",
"esbuild": "0.24.2",
"get-port": "7.1.0",
"jszip": "3.8.0",
"minimatch": "^10.0.0",
@@ -52,57 +53,55 @@
"@cliffy/table": ["@jsr/cliffy__table@1.0.0", "https://npm.jsr.io/~/11/@jsr/cliffy__table/1.0.0.tgz", { "dependencies": { "@jsr/std__fmt": "^1.0.9" } }, "sha512-VoLxH0DjofHWPWKUc5N+oCwXB6O6e+carnhp23yJTa7qokBb+SCrTIABEgQdIe/p0bxgmZhz17xt2efaAxXvbQ=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.0", "", { "os": "aix", "cpu": "ppc64" }, "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.24.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA=="],
"@esbuild/android-arm": ["@esbuild/android-arm@0.28.0", "", { "os": "android", "cpu": "arm" }, "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ=="],
"@esbuild/android-arm": ["@esbuild/android-arm@0.24.2", "", { "os": "android", "cpu": "arm" }, "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q=="],
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.28.0", "", { "os": "android", "cpu": "arm64" }, "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw=="],
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.24.2", "", { "os": "android", "cpu": "arm64" }, "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg=="],
"@esbuild/android-x64": ["@esbuild/android-x64@0.28.0", "", { "os": "android", "cpu": "x64" }, "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA=="],
"@esbuild/android-x64": ["@esbuild/android-x64@0.24.2", "", { "os": "android", "cpu": "x64" }, "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw=="],
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.28.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q=="],
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.24.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA=="],
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.28.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ=="],
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.24.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA=="],
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.28.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q=="],
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.24.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg=="],
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.28.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw=="],
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.24.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q=="],
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.28.0", "", { "os": "linux", "cpu": "arm" }, "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw=="],
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.24.2", "", { "os": "linux", "cpu": "arm" }, "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA=="],
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.28.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A=="],
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.24.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg=="],
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.28.0", "", { "os": "linux", "cpu": "ia32" }, "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ=="],
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.24.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.28.0", "", { "os": "linux", "cpu": "none" }, "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ=="],
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.28.0", "", { "os": "linux", "cpu": "none" }, "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w=="],
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw=="],
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.28.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg=="],
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.24.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw=="],
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.28.0", "", { "os": "linux", "cpu": "none" }, "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ=="],
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.24.2", "", { "os": "linux", "cpu": "none" }, "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q=="],
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.28.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q=="],
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.24.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw=="],
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.28.0", "", { "os": "linux", "cpu": "x64" }, "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ=="],
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.24.2", "", { "os": "linux", "cpu": "x64" }, "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q=="],
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.28.0", "", { "os": "none", "cpu": "arm64" }, "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw=="],
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.24.2", "", { "os": "none", "cpu": "arm64" }, "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw=="],
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.28.0", "", { "os": "none", "cpu": "x64" }, "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw=="],
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.24.2", "", { "os": "none", "cpu": "x64" }, "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw=="],
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.28.0", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g=="],
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.24.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A=="],
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.28.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA=="],
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.24.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA=="],
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.28.0", "", { "os": "none", "cpu": "arm64" }, "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w=="],
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.24.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig=="],
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.28.0", "", { "os": "sunos", "cpu": "x64" }, "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw=="],
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.24.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ=="],
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.28.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA=="],
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.24.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA=="],
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.28.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA=="],
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.0", "", { "os": "win32", "cpu": "x64" }, "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw=="],
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.24.2", "", { "os": "win32", "cpu": "x64" }, "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg=="],
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
@@ -170,9 +169,9 @@
"@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
"@windmill-labs/shared-utils": ["@jsr/windmill-labs__shared-utils@1.0.12", "https://npm.jsr.io/~/11/@jsr/windmill-labs__shared-utils/1.0.12.tgz", {}, "sha512-bJOacyfxxNPwNTzA4AxCB5iGFop0h3mCgs+E9j3ZaJYDo1soblY16CebnQ56EPy/M3V344X/QoOFBORyRo1Mnw=="],
"@windmill-labs/shared-utils": ["@windmill-labs/shared-utils@1.0.12", "", {}, "sha512-n68uEYv2B5q2Pp8J9syMS3qPZbppFEfeM7HIBEUfU5lGqi3hwnv4mPvgRUyb6K9im3frXC4gzdIdZdlrDpudXQ=="],
"acorn": ["acorn@8.16.0", "", { "bin": "bin/acorn" }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="],
"acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="],
"ajv": ["ajv@8.18.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A=="],
@@ -206,7 +205,7 @@
"diff": ["diff@5.2.2", "", {}, "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A=="],
"esbuild": ["esbuild@0.28.0", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.0", "@esbuild/android-arm": "0.28.0", "@esbuild/android-arm64": "0.28.0", "@esbuild/android-x64": "0.28.0", "@esbuild/darwin-arm64": "0.28.0", "@esbuild/darwin-x64": "0.28.0", "@esbuild/freebsd-arm64": "0.28.0", "@esbuild/freebsd-x64": "0.28.0", "@esbuild/linux-arm": "0.28.0", "@esbuild/linux-arm64": "0.28.0", "@esbuild/linux-ia32": "0.28.0", "@esbuild/linux-loong64": "0.28.0", "@esbuild/linux-mips64el": "0.28.0", "@esbuild/linux-ppc64": "0.28.0", "@esbuild/linux-riscv64": "0.28.0", "@esbuild/linux-s390x": "0.28.0", "@esbuild/linux-x64": "0.28.0", "@esbuild/netbsd-arm64": "0.28.0", "@esbuild/netbsd-x64": "0.28.0", "@esbuild/openbsd-arm64": "0.28.0", "@esbuild/openbsd-x64": "0.28.0", "@esbuild/openharmony-arm64": "0.28.0", "@esbuild/sunos-x64": "0.28.0", "@esbuild/win32-arm64": "0.28.0", "@esbuild/win32-ia32": "0.28.0", "@esbuild/win32-x64": "0.28.0" }, "bin": "bin/esbuild" }, "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw=="],
"esbuild": ["esbuild@0.24.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.24.2", "@esbuild/android-arm": "0.24.2", "@esbuild/android-arm64": "0.24.2", "@esbuild/android-x64": "0.24.2", "@esbuild/darwin-arm64": "0.24.2", "@esbuild/darwin-x64": "0.24.2", "@esbuild/freebsd-arm64": "0.24.2", "@esbuild/freebsd-x64": "0.24.2", "@esbuild/linux-arm": "0.24.2", "@esbuild/linux-arm64": "0.24.2", "@esbuild/linux-ia32": "0.24.2", "@esbuild/linux-loong64": "0.24.2", "@esbuild/linux-mips64el": "0.24.2", "@esbuild/linux-ppc64": "0.24.2", "@esbuild/linux-riscv64": "0.24.2", "@esbuild/linux-s390x": "0.24.2", "@esbuild/linux-x64": "0.24.2", "@esbuild/netbsd-arm64": "0.24.2", "@esbuild/netbsd-x64": "0.24.2", "@esbuild/openbsd-arm64": "0.24.2", "@esbuild/openbsd-x64": "0.24.2", "@esbuild/sunos-x64": "0.24.2", "@esbuild/win32-arm64": "0.24.2", "@esbuild/win32-ia32": "0.24.2", "@esbuild/win32-x64": "0.24.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA=="],
"esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="],
@@ -226,9 +225,9 @@
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
"is-docker": ["is-docker@3.0.0", "", { "bin": "cli.js" }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="],
"is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="],
"is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": "cli.js" }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="],
"is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="],
"is-reference": ["is-reference@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="],
@@ -268,7 +267,7 @@
"string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
"svelte": ["svelte@5.53.2", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "@types/trusted-types": "^2.0.7", "acorn": "^8.12.1", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "devalue": "^5.6.3", "esm-env": "^1.2.1", "esrap": "^2.2.2", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-yGONuIrcl/BMmqbm6/52Q/NYzfkta7uVlos5NSzGTfNJTTFtPPzra6rAQoQIwAqupeM3s9uuTf5PvioeiCdg9g=="],
"svelte": ["svelte@5.53.1", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "@types/trusted-types": "^2.0.7", "acorn": "^8.12.1", "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "devalue": "^5.6.3", "esm-env": "^1.2.1", "esrap": "^2.2.2", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-WzxFHZhhD23Qzu7JCYdvm1rxvRSzdt9HtHO8TScMBX51bLRFTcJmATVqjqXG+6Ln6hrViGCo9DzwOhAasxwC/w=="],
"tar-stream": ["tar-stream@3.1.7", "", { "dependencies": { "b4a": "^1.6.4", "fast-fifo": "^1.2.0", "streamx": "^2.15.0" } }, "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ=="],
@@ -292,7 +291,7 @@
"windmill-parser-wasm-nu": ["windmill-parser-wasm-nu@1.510.1", "", {}, "sha512-AJLFiUy6af+LpUe7CddDo4+JOmw3c0K/1iOWh8NdTwXcLDj90lL6089mdsVo1apyloLgrTbcuFDzZMXVGBgtCg=="],
"windmill-parser-wasm-php": ["windmill-parser-wasm-php@1.647.1", "", {}, "sha512-u2qaMkupSdhJibxvkLh3r/y36IARvnYNTLXWvOKxcQ0G/BPUB4+yF5o/yf47vv9zUV5WZv4mrdsKDt/pZDYeDg=="],
"windmill-parser-wasm-php": ["windmill-parser-wasm-php@1.574.1", "", {}, "sha512-COyid6B1RYs+bpzUCInsA4HY/WZkpDLfkQ90+AqU/TVTpzYSbAC2JCbIwy0cRElBvlhI4bQ+9Wg6hSQKMpEkpA=="],
"windmill-parser-wasm-py": ["windmill-parser-wasm-py@1.628.3", "", {}, "sha512-TlluqknZpg8cZ+A3m6JFLPseY2PpKtDsxdj26fAnCUzKPtse8TxQR+n0dwC80rfW5TwdWSulvNGRDgcNuf7CTw=="],
@@ -302,7 +301,7 @@
"windmill-parser-wasm-ruby": ["windmill-parser-wasm-ruby@1.526.1", "", {}, "sha512-rMBQA8s21wmL2kA5ztRs/ZgVA3ckxe9/NLjxl3iQPL0CX6DlvfaUH0O+AnhpXXDMyBs1Y1SZIhcnbnvsHZ3R8g=="],
"windmill-parser-wasm-rust": ["windmill-parser-wasm-rust@1.647.1", "", {}, "sha512-9yGLYZX2Hn9TdTqGY/5Fp50ftzgUsrfBkSK9vJkKJd5Amyg+yXLBGzd8pz6Org+4uxMenz/16wpsgijvo6uhhQ=="],
"windmill-parser-wasm-rust": ["windmill-parser-wasm-rust@1.558.1", "", {}, "sha512-21S7lm1KF8zO1187rbq14hzPHII2RdM2+D44MoAh1F6VoaScj+Puq0z5B1O/hwn/95R/a9jBlL2D8jbkXtlD1A=="],
"windmill-parser-wasm-ts": ["windmill-parser-wasm-ts@1.659.1", "", {}, "sha512-EmXMzOmazC5r29UZh+1TVF9g/N2X51pqK11qDL6xWGeWTIIonhfOZ5nWdGvKQMDUR650fGxehImZzW2v9hNy+w=="],
@@ -314,7 +313,7 @@
"wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="],
"yaml": ["yaml@2.8.2", "", { "bin": "bin.mjs" }, "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A=="],
"yaml": ["yaml@2.8.2", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A=="],
"zimmerframe": ["zimmerframe@1.1.4", "", {}, "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ=="],
}

225
cli/package-lock.json generated
View File

@@ -12,7 +12,7 @@
"@cliffy/table": "npm:@jsr/cliffy__table@1.0.0",
"@windmill-labs/shared-utils": "^1.0.12",
"diff": "^5.2.0",
"esbuild": "0.28.0",
"esbuild": "0.24.2",
"get-port": "7.1.0",
"jszip": "3.8.0",
"minimatch": "^10.0.0",
@@ -99,9 +99,9 @@
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz",
"integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz",
"integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==",
"cpu": [
"ppc64"
],
@@ -115,9 +115,9 @@
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz",
"integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz",
"integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==",
"cpu": [
"arm"
],
@@ -131,9 +131,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz",
"integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz",
"integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==",
"cpu": [
"arm64"
],
@@ -147,9 +147,9 @@
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz",
"integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz",
"integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==",
"cpu": [
"x64"
],
@@ -163,9 +163,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz",
"integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz",
"integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==",
"cpu": [
"arm64"
],
@@ -179,9 +179,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz",
"integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz",
"integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==",
"cpu": [
"x64"
],
@@ -195,9 +195,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz",
"integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz",
"integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==",
"cpu": [
"arm64"
],
@@ -211,9 +211,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz",
"integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz",
"integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==",
"cpu": [
"x64"
],
@@ -227,9 +227,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz",
"integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz",
"integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==",
"cpu": [
"arm"
],
@@ -243,9 +243,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz",
"integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz",
"integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==",
"cpu": [
"arm64"
],
@@ -259,9 +259,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz",
"integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz",
"integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==",
"cpu": [
"ia32"
],
@@ -275,9 +275,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz",
"integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz",
"integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==",
"cpu": [
"loong64"
],
@@ -291,9 +291,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz",
"integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz",
"integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==",
"cpu": [
"mips64el"
],
@@ -307,9 +307,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz",
"integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz",
"integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==",
"cpu": [
"ppc64"
],
@@ -323,9 +323,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz",
"integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz",
"integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==",
"cpu": [
"riscv64"
],
@@ -339,9 +339,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz",
"integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz",
"integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==",
"cpu": [
"s390x"
],
@@ -355,9 +355,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz",
"integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz",
"integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==",
"cpu": [
"x64"
],
@@ -371,9 +371,9 @@
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz",
"integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz",
"integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==",
"cpu": [
"arm64"
],
@@ -387,9 +387,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz",
"integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz",
"integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==",
"cpu": [
"x64"
],
@@ -403,9 +403,9 @@
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz",
"integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz",
"integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==",
"cpu": [
"arm64"
],
@@ -419,9 +419,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz",
"integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz",
"integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==",
"cpu": [
"x64"
],
@@ -434,26 +434,10 @@
"node": ">=18"
}
},
"node_modules/@esbuild/openharmony-arm64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz",
"integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"openharmony"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz",
"integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz",
"integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==",
"cpu": [
"x64"
],
@@ -467,9 +451,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz",
"integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz",
"integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==",
"cpu": [
"arm64"
],
@@ -483,9 +467,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz",
"integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz",
"integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==",
"cpu": [
"ia32"
],
@@ -499,9 +483,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz",
"integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz",
"integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==",
"cpu": [
"x64"
],
@@ -976,9 +960,9 @@
}
},
"node_modules/esbuild": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz",
"integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==",
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz",
"integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==",
"hasInstallScript": true,
"license": "MIT",
"bin": {
@@ -988,32 +972,31 @@
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.28.0",
"@esbuild/android-arm": "0.28.0",
"@esbuild/android-arm64": "0.28.0",
"@esbuild/android-x64": "0.28.0",
"@esbuild/darwin-arm64": "0.28.0",
"@esbuild/darwin-x64": "0.28.0",
"@esbuild/freebsd-arm64": "0.28.0",
"@esbuild/freebsd-x64": "0.28.0",
"@esbuild/linux-arm": "0.28.0",
"@esbuild/linux-arm64": "0.28.0",
"@esbuild/linux-ia32": "0.28.0",
"@esbuild/linux-loong64": "0.28.0",
"@esbuild/linux-mips64el": "0.28.0",
"@esbuild/linux-ppc64": "0.28.0",
"@esbuild/linux-riscv64": "0.28.0",
"@esbuild/linux-s390x": "0.28.0",
"@esbuild/linux-x64": "0.28.0",
"@esbuild/netbsd-arm64": "0.28.0",
"@esbuild/netbsd-x64": "0.28.0",
"@esbuild/openbsd-arm64": "0.28.0",
"@esbuild/openbsd-x64": "0.28.0",
"@esbuild/openharmony-arm64": "0.28.0",
"@esbuild/sunos-x64": "0.28.0",
"@esbuild/win32-arm64": "0.28.0",
"@esbuild/win32-ia32": "0.28.0",
"@esbuild/win32-x64": "0.28.0"
"@esbuild/aix-ppc64": "0.24.2",
"@esbuild/android-arm": "0.24.2",
"@esbuild/android-arm64": "0.24.2",
"@esbuild/android-x64": "0.24.2",
"@esbuild/darwin-arm64": "0.24.2",
"@esbuild/darwin-x64": "0.24.2",
"@esbuild/freebsd-arm64": "0.24.2",
"@esbuild/freebsd-x64": "0.24.2",
"@esbuild/linux-arm": "0.24.2",
"@esbuild/linux-arm64": "0.24.2",
"@esbuild/linux-ia32": "0.24.2",
"@esbuild/linux-loong64": "0.24.2",
"@esbuild/linux-mips64el": "0.24.2",
"@esbuild/linux-ppc64": "0.24.2",
"@esbuild/linux-riscv64": "0.24.2",
"@esbuild/linux-s390x": "0.24.2",
"@esbuild/linux-x64": "0.24.2",
"@esbuild/netbsd-arm64": "0.24.2",
"@esbuild/netbsd-x64": "0.24.2",
"@esbuild/openbsd-arm64": "0.24.2",
"@esbuild/openbsd-x64": "0.24.2",
"@esbuild/sunos-x64": "0.24.2",
"@esbuild/win32-arm64": "0.24.2",
"@esbuild/win32-ia32": "0.24.2",
"@esbuild/win32-x64": "0.24.2"
}
},
"node_modules/esm-env": {

View File

@@ -20,7 +20,7 @@
"@cliffy/table": "npm:@jsr/cliffy__table@1.0.0",
"@windmill-labs/shared-utils": "^1.0.12",
"diff": "^5.2.0",
"esbuild": "0.28.0",
"esbuild": "0.24.2",
"get-port": "7.1.0",
"jszip": "3.8.0",
"minimatch": "^10.0.0",

View File

@@ -772,7 +772,7 @@ const command = new Command()
.option("--dry-run", "Perform a dry run without making changes")
.option("--skip-users", "Skip pulling users")
.option("--skip-settings", "Skip pulling settings")
.option("--skip-configs", "Skip pulling configs (worker groups)")
.option("--skip-configs", "Skip pulling configs (worker groups and SMTP)")
.option("--skip-groups", "Skip pulling instance groups")
.option("--include-workspaces", "Also pull workspaces")
.option("--folder-per-instance", "Create a folder per instance")
@@ -797,7 +797,7 @@ const command = new Command()
.option("--dry-run", "Perform a dry run without making changes")
.option("--skip-users", "Skip pushing users")
.option("--skip-settings", "Skip pushing settings")
.option("--skip-configs", "Skip pushing configs (worker groups)")
.option("--skip-configs", "Skip pushing configs (worker groups and SMTP)")
.option("--skip-groups", "Skip pushing instance groups")
.option("--include-workspaces", "Also push workspaces")
.option("--folder-per-instance", "Create a folder per instance")

View File

@@ -26,6 +26,7 @@ export interface ResourceFile {
description?: string;
resource_type: string;
is_oauth?: boolean; // deprecated
ws_specific?: boolean;
}
async function readFilesetDirectory(dirPath: string): Promise<Record<string, string>> {

View File

@@ -122,7 +122,7 @@ const command = new Command()
.action(pullWorkerGroups as any)
.command("push")
.description(
"Push worker groups (similar to `wmill instance push --skip-users --skip-settings --skip-groups`)"
"Push instance settings, users, configs, group and overwrite remote"
)
.option(
"--instance [instance]",

View File

@@ -10,6 +10,7 @@ import { AIConfig, Config, GlobalSetting } from "../../gen/types.gen.ts";
import { compareInstanceObjects, InstanceSyncOptions } from "../commands/instance/instance.ts";
import { isSuperset } from "../types.ts";
import { deepEqual } from "../utils/utils.ts";
import { removeWorkerPrefix } from "../commands/worker-groups/worker-groups.ts";
import { decrypt, encrypt } from "../utils/local_encryption.ts";
// New grouped config interfaces
@@ -624,7 +625,12 @@ export async function pullInstanceConfigs(
opts: InstanceSyncOptions,
preview = false
) {
const remoteConfigs = await wmill.listWorkerGroups();
const remoteConfigs = (await wmill.listConfigs()).map((x) => {
return {
...x,
name: removeWorkerPrefix(x.name),
};
});
if (preview) {
const localConfigs: Config[] = await readLocalConfigs(opts);
@@ -652,7 +658,12 @@ export async function pushInstanceConfigs(
opts: InstanceSyncOptions,
preview: boolean = false
) {
const remoteConfigs = await wmill.listWorkerGroups();
const remoteConfigs = (await wmill.listConfigs()).map((x) => {
return {
...x,
name: removeWorkerPrefix(x.name),
};
});
const localConfigs = await readLocalConfigs(opts);
if (preview) {
@@ -671,7 +682,9 @@ export async function pushInstanceConfigs(
}
try {
await wmill.updateConfig({
name: `worker__${config.name}`,
name: config.name.startsWith("worker__")
? config.name
: `worker__${config.name}`,
requestBody: config.config,
});
} catch (err) {
@@ -685,7 +698,7 @@ export async function pushInstanceConfigs(
if (!localMatch) {
try {
await wmill.deleteConfig({
name: `worker__${removeConfig.name}`,
name: removeConfig.name,
});
} catch (err) {
log.error(`Failed to delete config ${removeConfig.name}: ${err}`);

View File

@@ -5301,7 +5301,7 @@ sync local with a remote instance or the opposite (push or pull)
- \`--dry-run\` - Perform a dry run without making changes
- \`--skip-users\` - Skip pulling users
- \`--skip-settings\` - Skip pulling settings
- \`--skip-configs\` - Skip pulling configs (worker groups)
- \`--skip-configs\` - Skip pulling configs (worker groups and SMTP)
- \`--skip-groups\` - Skip pulling instance groups
- \`--include-workspaces\` - Also pull workspaces
- \`--folder-per-instance\` - Create a folder per instance
@@ -5313,7 +5313,7 @@ sync local with a remote instance or the opposite (push or pull)
- \`--dry-run\` - Perform a dry run without making changes
- \`--skip-users\` - Skip pushing users
- \`--skip-settings\` - Skip pushing settings
- \`--skip-configs\` - Skip pushing configs (worker groups)
- \`--skip-configs\` - Skip pushing configs (worker groups and SMTP)
- \`--skip-groups\` - Skip pushing instance groups
- \`--include-workspaces\` - Also push workspaces
- \`--folder-per-instance\` - Create a folder per instance
@@ -5617,7 +5617,7 @@ display worker groups, pull and push worker groups configs
- \`--instance\` - Name of the instance to push to, override the active instance
- \`--base-url\` - Base url to be passed to the instance settings instead of the local one
- \`--yes\` - Pull without needing confirmation
- \`worker-groups push\` - Push worker groups (similar to \`wmill instance push --skip-users --skip-settings --skip-groups\`)
- \`worker-groups push\` - Push instance settings, users, configs, group and overwrite remote
- \`--instance [instance]\` - Name of the instance to push to, override the active instance
- \`--base-url [baseUrl]\` - If used with --token, will be used as the base url for the instance
- \`--yes\` - Push without needing confirmation

View File

@@ -78,7 +78,7 @@ export {
token,
};
export const VERSION = "1.680.0";
export const VERSION = "1.679.0";
// Re-exported from constants.ts to maintain backwards compatibility
export { WM_FORK_PREFIX } from "./core/constants.ts";

View File

@@ -1,297 +0,0 @@
/**
* Unit tests for pullInstanceConfigs / pushInstanceConfigs in settings.ts.
*
* Verifies that:
* - pullInstanceConfigs writes only worker group configs (no alerts)
* - pushInstanceConfigs calls updateConfig with worker__ prefix
* - pushInstanceConfigs calls deleteConfig with worker__ prefix for removed configs
* - pushInstanceConfigs skips unchanged configs
*/
import { expect, test, describe, beforeEach, afterEach, mock } from "bun:test";
import { writeFile, readFile, mkdir, rm } from "node:fs/promises";
import { mkdtempSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { stringify as yamlStringify } from "yaml";
// Track calls to mocked wmill functions
let listWorkerGroupsResult: any[] = [];
let updateConfigCalls: { name: string; requestBody: any }[] = [];
let deleteConfigCalls: { name: string }[] = [];
// Mock the wmill module before importing settings.ts
mock.module("../gen/services.gen.ts", () => ({
listWorkerGroups: async () => listWorkerGroupsResult,
updateConfig: async (args: { name: string; requestBody: any }) => {
updateConfigCalls.push(args);
},
deleteConfig: async (args: { name: string }) => {
deleteConfigCalls.push(args);
},
listConfigs: async () => {
throw new Error("listConfigs should not be called");
},
}));
import {
pullInstanceConfigs,
pushInstanceConfigs,
readLocalConfigs,
} from "../src/core/settings.ts";
describe("instance configs", () => {
let tempDir: string;
beforeEach(() => {
tempDir = mkdtempSync(join(tmpdir(), "wm-config-test-"));
listWorkerGroupsResult = [];
updateConfigCalls = [];
deleteConfigCalls = [];
});
afterEach(async () => {
await rm(tempDir, { recursive: true, force: true });
});
// =========================================================================
// readLocalConfigs
// =========================================================================
describe("readLocalConfigs", () => {
test("reads configs from instance_configs.yaml", async () => {
const configs = [
{ name: "default", config: { worker_tags: ["deno", "bun"] } },
{ name: "gpu", config: { dedicated_worker: "ws:f/gpu_script" } },
];
await writeFile(
join(tempDir, "instance_configs.yaml"),
yamlStringify(configs),
"utf-8"
);
const result = await readLocalConfigs({
prefix: tempDir,
folderPerInstance: true,
prefixSettings: true,
});
expect(result).toEqual(configs);
});
test("returns empty array when file does not exist", async () => {
const result = await readLocalConfigs({
prefix: tempDir,
folderPerInstance: true,
prefixSettings: true,
});
expect(result).toEqual([]);
});
});
// =========================================================================
// pullInstanceConfigs
// =========================================================================
describe("pullInstanceConfigs", () => {
test("writes worker group configs to instance_configs.yaml", async () => {
listWorkerGroupsResult = [
{ name: "default", config: { worker_tags: ["deno", "bun"] } },
{ name: "native", config: { worker_tags: ["nativets"] } },
];
// readLocalConfigs sets instanceConfigsPath when prefix is used
const opts = {
prefix: tempDir,
folderPerInstance: true,
prefixSettings: true,
};
await readLocalConfigs(opts);
await pullInstanceConfigs(opts);
const content = await readFile(
join(tempDir, "instance_configs.yaml"),
"utf-8"
);
expect(content).toContain("default");
expect(content).toContain("native");
expect(content).toContain("deno");
// Should not contain alert entries (listWorkerGroups filters them)
expect(content).not.toContain("alert");
});
test("preview mode returns change count without writing file", async () => {
listWorkerGroupsResult = [
{ name: "default", config: { worker_tags: ["deno"] } },
];
const changes = await pullInstanceConfigs(
{
prefix: tempDir,
folderPerInstance: true,
prefixSettings: true,
},
true
);
// One remote config not in local = 1 change
expect(changes).toBe(1);
});
test("preview mode returns 0 when remote matches local", async () => {
const configs = [
{ name: "default", config: { worker_tags: ["deno"] } },
];
listWorkerGroupsResult = configs;
await writeFile(
join(tempDir, "instance_configs.yaml"),
yamlStringify(configs),
"utf-8"
);
const changes = await pullInstanceConfigs(
{
prefix: tempDir,
folderPerInstance: true,
prefixSettings: true,
},
true
);
expect(changes).toBe(0);
});
});
// =========================================================================
// pushInstanceConfigs
// =========================================================================
describe("pushInstanceConfigs", () => {
test("calls updateConfig with worker__ prefix for new configs", async () => {
listWorkerGroupsResult = [];
const localConfigs = [
{ name: "mygroup", config: { worker_tags: ["python3"] } },
];
await writeFile(
join(tempDir, "instance_configs.yaml"),
yamlStringify(localConfigs),
"utf-8"
);
await pushInstanceConfigs({
prefix: tempDir,
folderPerInstance: true,
prefixSettings: true,
});
expect(updateConfigCalls).toHaveLength(1);
expect(updateConfigCalls[0].name).toBe("worker__mygroup");
expect(updateConfigCalls[0].requestBody).toEqual({
worker_tags: ["python3"],
});
});
test("calls deleteConfig with worker__ prefix for removed configs", async () => {
listWorkerGroupsResult = [
{ name: "old_group", config: { worker_tags: ["bash"] } },
];
// Empty local configs = old_group should be deleted
await writeFile(
join(tempDir, "instance_configs.yaml"),
yamlStringify([]),
"utf-8"
);
await pushInstanceConfigs({
prefix: tempDir,
folderPerInstance: true,
prefixSettings: true,
});
expect(deleteConfigCalls).toHaveLength(1);
expect(deleteConfigCalls[0].name).toBe("worker__old_group");
});
test("skips unchanged configs", async () => {
const configs = [
{ name: "default", config: { worker_tags: ["deno"] } },
];
listWorkerGroupsResult = configs;
await writeFile(
join(tempDir, "instance_configs.yaml"),
yamlStringify(configs),
"utf-8"
);
await pushInstanceConfigs({
prefix: tempDir,
folderPerInstance: true,
prefixSettings: true,
});
expect(updateConfigCalls).toHaveLength(0);
expect(deleteConfigCalls).toHaveLength(0);
});
test("updates changed configs and deletes removed ones", async () => {
listWorkerGroupsResult = [
{ name: "keep", config: { worker_tags: ["old_tag"] } },
{ name: "remove_me", config: { worker_tags: ["bash"] } },
];
const localConfigs = [
{ name: "keep", config: { worker_tags: ["new_tag"] } },
{ name: "add_me", config: { worker_tags: ["python3"] } },
];
await writeFile(
join(tempDir, "instance_configs.yaml"),
yamlStringify(localConfigs),
"utf-8"
);
await pushInstanceConfigs({
prefix: tempDir,
folderPerInstance: true,
prefixSettings: true,
});
// "keep" was changed, "add_me" is new
expect(updateConfigCalls).toHaveLength(2);
const updateNames = updateConfigCalls.map((c) => c.name).sort();
expect(updateNames).toEqual(["worker__add_me", "worker__keep"]);
// "remove_me" was deleted
expect(deleteConfigCalls).toHaveLength(1);
expect(deleteConfigCalls[0].name).toBe("worker__remove_me");
});
test("preview mode returns change count without calling API", async () => {
listWorkerGroupsResult = [
{ name: "default", config: { worker_tags: ["deno"] } },
];
const localConfigs = [
{ name: "default", config: { worker_tags: ["bun"] } },
{ name: "new_group", config: { worker_tags: ["go"] } },
];
await writeFile(
join(tempDir, "instance_configs.yaml"),
yamlStringify(localConfigs),
"utf-8"
);
const changes = await pushInstanceConfigs(
{
prefix: tempDir,
folderPerInstance: true,
prefixSettings: true,
},
true
);
// "default" changed + "new_group" added = 2 changes
expect(changes).toBe(2);
expect(updateConfigCalls).toHaveLength(0);
expect(deleteConfigCalls).toHaveLength(0);
});
});
});

View File

@@ -1,12 +1,12 @@
{
"name": "windmill-components",
"version": "1.680.0",
"version": "1.679.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "windmill-components",
"version": "1.680.0",
"version": "1.679.0",
"hasInstallScript": true,
"license": "AGPL-3.0",
"dependencies": {
@@ -844,7 +844,6 @@
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.0.tgz",
"integrity": "sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -856,7 +855,6 @@
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.0.tgz",
"integrity": "sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -867,7 +865,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz",
"integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -1357,7 +1354,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz",
"integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -1514,7 +1510,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1531,7 +1526,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1548,7 +1542,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1565,7 +1558,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1582,7 +1574,6 @@
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1599,7 +1590,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1616,7 +1606,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1633,7 +1622,6 @@
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1650,7 +1638,6 @@
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1667,7 +1654,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1684,7 +1670,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1701,7 +1686,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1718,7 +1702,6 @@
"cpu": [
"wasm32"
],
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -1735,7 +1718,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -1752,7 +1734,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -2058,7 +2039,6 @@
"version": "0.10.1",
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
"integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
@@ -6867,7 +6847,7 @@
"version": "1.21.7",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
"dev": true,
"devOptional": true,
"license": "MIT",
"bin": {
"jiti": "bin/jiti.js"
@@ -7366,7 +7346,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -7387,7 +7366,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -7408,7 +7386,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -7429,7 +7406,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -7450,7 +7426,6 @@
"cpu": [
"arm"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -7471,7 +7446,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -7492,7 +7466,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -7513,7 +7486,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -7534,7 +7506,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -7555,7 +7526,6 @@
"cpu": [
"arm64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -7576,7 +7546,6 @@
"cpu": [
"x64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -12152,21 +12121,6 @@
}
}
},
"node_modules/svelte-check/node_modules/picomatch": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/svelte-eslint-parser": {
"version": "0.43.0",
"resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.43.0.tgz",
@@ -12897,7 +12851,7 @@
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"devOptional": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",

View File

@@ -1,6 +1,6 @@
{
"name": "windmill-components",
"version": "1.680.0",
"version": "1.679.0",
"scripts": {
"dev": "vite dev",
"build": "vite build",

View File

@@ -8,13 +8,15 @@
import { Plus, Edit3, Save, X, Trash, ExternalLink } from 'lucide-svelte'
import { sendUserToast } from '$lib/toast'
import { twMerge } from 'tailwind-merge'
import { ConfigService, SettingService, type Alert } from '$lib/gen'
import { ConfigService, type Alert } from '$lib/gen'
import Tooltip from './Tooltip.svelte'
import Badge from './common/badge/Badge.svelte'
import { enterpriseLicense } from '$lib/stores'
let queueAlertConfig = $state<Alert[]>([])
let availableTags = $state<string[]>([])
let configName = 'alert__job_queue_waiting'
let editingRowIndex = $state<number>(-1)
let editForm = $state<{
tags_to_monitor: string[]
@@ -48,8 +50,8 @@
async function fetchConfig() {
try {
const response = await SettingService.getGlobal({ key: 'alert_job_queue_waiting' })
queueAlertConfig = (response as any)?.alerts || []
const response = await ConfigService.getConfig({ name: configName })
queueAlertConfig = response?.alerts || []
expandedTagRows = []
} catch (error) {
console.error('Failed to fetch config:', error)
@@ -58,13 +60,12 @@
async function fetchWorkerTags(): Promise<string[]> {
try {
const response = await ConfigService.listWorkerGroups()
const response = await ConfigService.listConfigs()
const workerTagsSet = new Set<string>()
response.forEach((wg) => {
const config = wg.config as any
if (Array.isArray(config?.worker_tags)) {
config.worker_tags.forEach((tag: string) => workerTagsSet.add(tag))
response.forEach((config) => {
if (config.name.startsWith('worker__') && Array.isArray(config.config?.worker_tags)) {
config?.config?.worker_tags.forEach((tag) => workerTagsSet.add(tag))
}
})
@@ -189,9 +190,9 @@
}
async function saveQueueAlertConfig() {
await SettingService.setGlobal({
key: 'alert_job_queue_waiting',
requestBody: { value: { alerts: queueAlertConfig } }
await ConfigService.updateConfig({
name: configName,
requestBody: { alerts: queueAlertConfig }
})
}

View File

@@ -4,7 +4,7 @@ verify_ssl = true
name = "pypi"
[packages]
wmill = ">=1.680.0"
wmill = ">=1.679.0"
sendgrid = "*"
mysql-connector-python = "*"
pymongo = "*"

View File

@@ -1,7 +1,7 @@
openapi: '3.0.3'
info:
version: 1.680.0
version: 1.679.0
title: OpenFlow Spec
contact:
name: Ruben Fiszel

View File

@@ -12,7 +12,7 @@
RootModule = 'WindmillClient.psm1'
# Version number of this module.
ModuleVersion = '1.680.0'
ModuleVersion = '1.679.0'
# Supported PSEditions
# CompatiblePSEditions = @()

View File

@@ -1,6 +1,6 @@
[tool.poetry]
name = "wmill"
version = "1.680.0"
version = "1.679.0"
description = "A client library for accessing Windmill server wrapping the Windmill client API"
license = "Apache-2.0"
homepage = "https://windmill.dev"

View File

@@ -418,6 +418,7 @@ impl Windmill {
description: None,
value: Some(value),
resource_type: Some(resource_type.to_owned()),
ws_specific: None,
labels: None,
},
)

View File

@@ -228,7 +228,7 @@ sync local with a remote instance or the opposite (push or pull)
- `--dry-run` - Perform a dry run without making changes
- `--skip-users` - Skip pulling users
- `--skip-settings` - Skip pulling settings
- `--skip-configs` - Skip pulling configs (worker groups)
- `--skip-configs` - Skip pulling configs (worker groups and SMTP)
- `--skip-groups` - Skip pulling instance groups
- `--include-workspaces` - Also pull workspaces
- `--folder-per-instance` - Create a folder per instance
@@ -240,7 +240,7 @@ sync local with a remote instance or the opposite (push or pull)
- `--dry-run` - Perform a dry run without making changes
- `--skip-users` - Skip pushing users
- `--skip-settings` - Skip pushing settings
- `--skip-configs` - Skip pushing configs (worker groups)
- `--skip-configs` - Skip pushing configs (worker groups and SMTP)
- `--skip-groups` - Skip pushing instance groups
- `--include-workspaces` - Also push workspaces
- `--folder-per-instance` - Create a folder per instance
@@ -544,7 +544,7 @@ display worker groups, pull and push worker groups configs
- `--instance` - Name of the instance to push to, override the active instance
- `--base-url` - Base url to be passed to the instance settings instead of the local one
- `--yes` - Pull without needing confirmation
- `worker-groups push` - Push worker groups (similar to `wmill instance push --skip-users --skip-settings --skip-groups`)
- `worker-groups push` - Push instance settings, users, configs, group and overwrite remote
- `--instance [instance]` - Name of the instance to push to, override the active instance
- `--base-url [baseUrl]` - If used with --token, will be used as the base url for the instance
- `--yes` - Push without needing confirmation

View File

@@ -1762,7 +1762,7 @@ sync local with a remote instance or the opposite (push or pull)
- \`--dry-run\` - Perform a dry run without making changes
- \`--skip-users\` - Skip pulling users
- \`--skip-settings\` - Skip pulling settings
- \`--skip-configs\` - Skip pulling configs (worker groups)
- \`--skip-configs\` - Skip pulling configs (worker groups and SMTP)
- \`--skip-groups\` - Skip pulling instance groups
- \`--include-workspaces\` - Also pull workspaces
- \`--folder-per-instance\` - Create a folder per instance
@@ -1774,7 +1774,7 @@ sync local with a remote instance or the opposite (push or pull)
- \`--dry-run\` - Perform a dry run without making changes
- \`--skip-users\` - Skip pushing users
- \`--skip-settings\` - Skip pushing settings
- \`--skip-configs\` - Skip pushing configs (worker groups)
- \`--skip-configs\` - Skip pushing configs (worker groups and SMTP)
- \`--skip-groups\` - Skip pushing instance groups
- \`--include-workspaces\` - Also push workspaces
- \`--folder-per-instance\` - Create a folder per instance
@@ -2078,7 +2078,7 @@ display worker groups, pull and push worker groups configs
- \`--instance\` - Name of the instance to push to, override the active instance
- \`--base-url\` - Base url to be passed to the instance settings instead of the local one
- \`--yes\` - Pull without needing confirmation
- \`worker-groups push\` - Push worker groups (similar to \`wmill instance push --skip-users --skip-settings --skip-groups\`)
- \`worker-groups push\` - Push instance settings, users, configs, group and overwrite remote
- \`--instance [instance]\` - Name of the instance to push to, override the active instance
- \`--base-url [baseUrl]\` - If used with --token, will be used as the base url for the instance
- \`--yes\` - Push without needing confirmation

View File

@@ -233,7 +233,7 @@ sync local with a remote instance or the opposite (push or pull)
- `--dry-run` - Perform a dry run without making changes
- `--skip-users` - Skip pulling users
- `--skip-settings` - Skip pulling settings
- `--skip-configs` - Skip pulling configs (worker groups)
- `--skip-configs` - Skip pulling configs (worker groups and SMTP)
- `--skip-groups` - Skip pulling instance groups
- `--include-workspaces` - Also pull workspaces
- `--folder-per-instance` - Create a folder per instance
@@ -245,7 +245,7 @@ sync local with a remote instance or the opposite (push or pull)
- `--dry-run` - Perform a dry run without making changes
- `--skip-users` - Skip pushing users
- `--skip-settings` - Skip pushing settings
- `--skip-configs` - Skip pushing configs (worker groups)
- `--skip-configs` - Skip pushing configs (worker groups and SMTP)
- `--skip-groups` - Skip pushing instance groups
- `--include-workspaces` - Also push workspaces
- `--folder-per-instance` - Create a folder per instance
@@ -549,7 +549,7 @@ display worker groups, pull and push worker groups configs
- `--instance` - Name of the instance to push to, override the active instance
- `--base-url` - Base url to be passed to the instance settings instead of the local one
- `--yes` - Pull without needing confirmation
- `worker-groups push` - Push worker groups (similar to `wmill instance push --skip-users --skip-settings --skip-groups`)
- `worker-groups push` - Push instance settings, users, configs, group and overwrite remote
- `--instance [instance]` - Name of the instance to push to, override the active instance
- `--base-url [baseUrl]` - If used with --token, will be used as the base url for the instance
- `--yes` - Push without needing confirmation

View File

@@ -1,6 +1,6 @@
{
"name": "@windmill/windmill",
"version": "1.680.0",
"version": "1.679.0",
"exports": "./src/index.ts",
"publish": {
"exclude": ["!src", "./s3Types.ts", "./sqlUtils.ts", "./client.ts"]

View File

@@ -1,7 +1,7 @@
{
"name": "windmill-client",
"description": "Windmill SDK client for browsers and Node.js",
"version": "1.680.0",
"version": "1.679.0",
"author": "Ruben Fiszel",
"license": "Apache 2.0",
"sideEffects": false,

View File

@@ -1 +1 @@
1.680.0
1.679.0