Compare commits
53 Commits
v1.481.0
...
rust-inc-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d39b870b2a | ||
|
|
f107936d44 | ||
|
|
9221a63edb | ||
|
|
99fcacb2e6 | ||
|
|
cb49ae5458 | ||
|
|
5e054d3385 | ||
|
|
c57490a572 | ||
|
|
6339775404 | ||
|
|
785da73abf | ||
|
|
c740eee311 | ||
|
|
9b9006c1d6 | ||
|
|
2da10e62a4 | ||
|
|
1f1164199b | ||
|
|
63fa499015 | ||
|
|
eabd3d1346 | ||
|
|
3950cfd7e3 | ||
|
|
e4d57f9549 | ||
|
|
a74d68a5e6 | ||
|
|
f497a4bfae | ||
|
|
b4f8c88c19 | ||
|
|
f5d46d5751 | ||
|
|
0e3793356a | ||
|
|
07094b6aa2 | ||
|
|
2eb1a161d1 | ||
|
|
d874d98cc1 | ||
|
|
35fc4822f0 | ||
|
|
c2180c6eb3 | ||
|
|
1007f37f4b | ||
|
|
1f3e7d9029 | ||
|
|
62f14d1cb9 | ||
|
|
3507925624 | ||
|
|
102b58a5f4 | ||
|
|
0c3cb3700a | ||
|
|
efacda7453 | ||
|
|
b47c15165f | ||
|
|
5bd66b3f1f | ||
|
|
b926076988 | ||
|
|
4c71af8a74 | ||
|
|
b3ecde3316 | ||
|
|
4f6be6ed34 | ||
|
|
5abdc3e440 | ||
|
|
1bb402bcfc | ||
|
|
26294584d6 | ||
|
|
bc69116ff1 | ||
|
|
2c5e58cf1a | ||
|
|
6fae3a566b | ||
|
|
9276c717a2 | ||
|
|
e118d2cd5f | ||
|
|
87cf1d0c28 | ||
|
|
e454b3e05b | ||
|
|
6e9ec6323c | ||
|
|
3c99b3fdc7 | ||
|
|
f3ed108e43 |
4
.github/workflows/build-publish-rh-image.yml
vendored
4
.github/workflows/build-publish-rh-image.yml
vendored
@@ -64,7 +64,7 @@ jobs:
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
build-args: |
|
||||
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages
|
||||
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,gcp_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages
|
||||
secrets: |
|
||||
rh_username=${{ secrets.RH_USERNAME }}
|
||||
rh_password=${{ secrets.RH_PASSWORD }}
|
||||
@@ -81,7 +81,7 @@ jobs:
|
||||
platforms: linux/arm64
|
||||
push: true
|
||||
build-args: |
|
||||
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages
|
||||
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,license,otel,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,gcp_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages
|
||||
secrets: |
|
||||
rh_username=${{ secrets.RH_USERNAME }}
|
||||
rh_password=${{ secrets.RH_PASSWORD }}
|
||||
|
||||
2
.github/workflows/build_windows_worker_.yml
vendored
2
.github/workflows/build_windows_worker_.yml
vendored
@@ -51,7 +51,7 @@ jobs:
|
||||
$env:OPENSSL_DIR="${Env:VCPKG_INSTALLATION_ROOT}\installed\x64-windows-static"
|
||||
mkdir frontend/build && cd backend
|
||||
New-Item -Path . -Name "windmill-api/openapi-deref.yaml" -ItemType "File" -Force
|
||||
cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,license,http_trigger,zip,oauth2,kafka,nats,sqs_trigger,postgres_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages
|
||||
cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,license,http_trigger,zip,oauth2,kafka,nats,sqs_trigger,postgres_trigger,gcp_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages
|
||||
- name: Rename binary with corresponding architecture
|
||||
run: |
|
||||
Rename-Item -Path ".\backend\target\release\windmill.exe" -NewName "windmill-ee.exe"
|
||||
|
||||
4
.github/workflows/docker-image.yml
vendored
4
.github/workflows/docker-image.yml
vendored
@@ -95,7 +95,7 @@ jobs:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
build-args: |
|
||||
features=embedding,parquet,openidconnect,jemalloc,license,http_trigger,zip,oauth2,dind,postgres_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages
|
||||
features=embedding,parquet,openidconnect,jemalloc,license,http_trigger,zip,oauth2,dind,postgres_trigger,mqtt_trigger,websocket,smtp,static_frontend,agent_worker_server,all_languages
|
||||
tags: |
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.DEV_SHA }}
|
||||
${{ steps.meta-public.outputs.tags }}
|
||||
@@ -157,7 +157,7 @@ jobs:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
build-args: |
|
||||
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,license,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,otel,dind,postgres_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages
|
||||
features=enterprise,enterprise_saml,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,agent_worker_server,tantivy,license,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,otel,dind,postgres_trigger,mqtt_trigger,gcp_trigger,websocket,smtp,static_frontend,all_languages
|
||||
tags: |
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-ee:${{ env.DEV_SHA }}
|
||||
${{ steps.meta-ee-public.outputs.tags }}
|
||||
|
||||
2
.github/workflows/publish_windows_worker.yml
vendored
2
.github/workflows/publish_windows_worker.yml
vendored
@@ -53,7 +53,7 @@ jobs:
|
||||
$env:OPENSSL_DIR="${Env:VCPKG_INSTALLATION_ROOT}\installed\x64-windows-static"
|
||||
mkdir frontend/build && cd backend
|
||||
New-Item -Path . -Name "windmill-api/openapi-deref.yaml" -ItemType "File" -Force
|
||||
cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,license,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,mqtt_trigger,websocket,smtp,static_frontend,all_languages
|
||||
cargo build --release --features=enterprise,stripe,embedding,parquet,prometheus,openidconnect,cloud,jemalloc,tantivy,license,http_trigger,zip,oauth2,kafka,sqs_trigger,nats,postgres_trigger,mqtt_trigger,gcp_trigger,websocket,smtp,static_frontend,all_languages
|
||||
- name: Rename binary with corresponding architecture
|
||||
run: |
|
||||
Rename-Item -Path ".\backend\target\release\windmill.exe" -NewName "windmill-ee.exe"
|
||||
|
||||
128
backend/.sqlx/query-0102308ffa1c0dbfba54d29246535bb81146a4cfae0ec408435570e0813a3bef.json
generated
Normal file
128
backend/.sqlx/query-0102308ffa1c0dbfba54d29246535bb81146a4cfae0ec408435570e0813a3bef.json
generated
Normal file
@@ -0,0 +1,128 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT\n gcp_resource_path,\n subscription_id,\n topic_id,\n workspace_id,\n delivery_type AS \"delivery_type: _\",\n delivery_config AS \"delivery_config: _\",\n path,\n script_path,\n is_flow,\n edited_by,\n email,\n edited_at,\n server_id,\n last_server_ping,\n extra_perms,\n error,\n enabled\n FROM \n gcp_trigger\n WHERE \n workspace_id = $1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "gcp_resource_path",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "subscription_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "topic_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "workspace_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "delivery_type: _",
|
||||
"type_info": {
|
||||
"Custom": {
|
||||
"name": "delivery_mode",
|
||||
"kind": {
|
||||
"Enum": [
|
||||
"push",
|
||||
"pull"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "delivery_config: _",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "path",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "script_path",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"name": "is_flow",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"name": "edited_by",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"name": "email",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"name": "edited_at",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"name": "server_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"name": "last_server_ping",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"name": "extra_perms",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 15,
|
||||
"name": "error",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 16,
|
||||
"name": "enabled",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "0102308ffa1c0dbfba54d29246535bb81146a4cfae0ec408435570e0813a3bef"
|
||||
}
|
||||
26
backend/.sqlx/query-070b8ad0b59f485fa5bf68082b060f5c3561c37e9c6f2834d234a862a475a6eb.json
generated
Normal file
26
backend/.sqlx/query-070b8ad0b59f485fa5bf68082b060f5c3561c37e9c6f2834d234a862a475a6eb.json
generated
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE \n gcp_trigger \n SET \n enabled = $1, \n email = $2, \n edited_by = $3, \n edited_at = now(), \n server_id = NULL, \n error = NULL\n WHERE \n path = $4 AND \n workspace_id = $5 \n RETURNING 1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "?column?",
|
||||
"type_info": "Int4"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Bool",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "070b8ad0b59f485fa5bf68082b060f5c3561c37e9c6f2834d234a862a475a6eb"
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT value\n FROM resource\n WHERE path = $1 AND workspace_id = $2",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "value",
|
||||
"type_info": "Jsonb"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "0a9dd1addaf48eeb46eed59abb6daf9819d07b08cf7ca442ea7ec78a9b2b63b2"
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE worker_ping SET \n ping_at = now(), \n jobs_executed = 1, \n current_job_id = $1, \n current_job_workspace_id = 'admins' \n WHERE worker = $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "0e52a588f3edeb8fb58d6d62247b8590e51171e2811c62737bdb81fb0ac8f182"
|
||||
}
|
||||
126
backend/.sqlx/query-15fbe481789a7817bf37415fb935f9ed537fd7d3b266d928af4d5d3dd8bb5c18.json
generated
Normal file
126
backend/.sqlx/query-15fbe481789a7817bf37415fb935f9ed537fd7d3b266d928af4d5d3dd8bb5c18.json
generated
Normal file
@@ -0,0 +1,126 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT\n gcp_resource_path,\n subscription_id,\n topic_id,\n workspace_id,\n delivery_type AS \"delivery_type: _\",\n delivery_config AS \"delivery_config: _\",\n path,\n script_path,\n is_flow,\n edited_by,\n email,\n edited_at,\n server_id,\n last_server_ping,\n extra_perms,\n error,\n enabled\n FROM\n gcp_trigger\n WHERE\n delivery_type != 'push'::DELIVERY_MODE AND\n enabled IS TRUE\n AND (last_server_ping IS NULL OR\n last_server_ping < now() - interval '15 seconds'\n )\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "gcp_resource_path",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "subscription_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "topic_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "workspace_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "delivery_type: _",
|
||||
"type_info": {
|
||||
"Custom": {
|
||||
"name": "delivery_mode",
|
||||
"kind": {
|
||||
"Enum": [
|
||||
"push",
|
||||
"pull"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "delivery_config: _",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "path",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "script_path",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"name": "is_flow",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"name": "edited_by",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"name": "email",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"name": "edited_at",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"name": "server_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"name": "last_server_ping",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"name": "extra_perms",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 15,
|
||||
"name": "error",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 16,
|
||||
"name": "enabled",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "15fbe481789a7817bf37415fb935f9ed537fd7d3b266d928af4d5d3dd8bb5c18"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT trigger_config as \"trigger_config: _\", owner, email\n FROM capture_config\n WHERE workspace_id = $1 AND path = $2 AND is_flow = $3 AND trigger_kind = $4 AND last_client_ping > NOW() - INTERVAL '10 seconds'",
|
||||
"query": "\n SELECT \n trigger_config AS \"trigger_config: _\", \n owner, \n email\n FROM \n capture_config\n WHERE \n workspace_id = $1\n AND path = $2\n AND is_flow = $3\n AND trigger_kind = $4\n AND last_client_ping > NOW() - INTERVAL '10 seconds'\n AND (\n $5::bool IS FALSE\n OR (\n trigger_config IS NOT NULL\n AND trigger_config ->> 'delivery_type' = 'push'\n )\n )\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -37,11 +37,13 @@
|
||||
"nats",
|
||||
"postgres",
|
||||
"sqs",
|
||||
"mqtt"
|
||||
"mqtt",
|
||||
"gcp"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Bool"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
@@ -50,5 +52,5 @@
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "e23e110e1f0438d21534fc4323e0e7bc1f0dbeca2e4f44ced05bae0ca5ca1039"
|
||||
"hash": "23419adcd74c326d716527293eff518b42f4cdb33e034441015494bd26c172d2"
|
||||
}
|
||||
25
backend/.sqlx/query-299e16725162888c01712f371785199960264b54c1ddf928c0c654ab15176f63.json
generated
Normal file
25
backend/.sqlx/query-299e16725162888c01712f371785199960264b54c1ddf928c0c654ab15176f63.json
generated
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE \n capture_config \n SET \n server_id = $1,\n last_server_ping = now(), \n error = 'Connecting...' \n WHERE \n last_client_ping > NOW() - INTERVAL '10 seconds' AND \n workspace_id = $2 AND \n path = $3 AND \n is_flow = $4 AND \n trigger_kind = 'gcp' AND \n (last_server_ping IS NULL OR last_server_ping < now() - interval '15 seconds') \n RETURNING true\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "?column?",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Text",
|
||||
"Text",
|
||||
"Bool"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "299e16725162888c01712f371785199960264b54c1ddf928c0c654ab15176f63"
|
||||
}
|
||||
15
backend/.sqlx/query-2ebb0463b790ddf7ba0ee22d8c9afc88eb57c4110a202775003fb48b2f4e317f.json
generated
Normal file
15
backend/.sqlx/query-2ebb0463b790ddf7ba0ee22d8c9afc88eb57c4110a202775003fb48b2f4e317f.json
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE v2_job_status SET\n workflow_as_code_status = jsonb_set(\n jsonb_set(\n COALESCE(workflow_as_code_status, '{}'::jsonb),\n array[$1],\n COALESCE(workflow_as_code_status->$1, '{}'::jsonb)\n ),\n array[$1, 'started_at'],\n to_jsonb(now()::text)\n )\n WHERE id = $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Uuid"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "2ebb0463b790ddf7ba0ee22d8c9afc88eb57c4110a202775003fb48b2f4e317f"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE v2_job_runtime r SET\n memory_peak = $1,\n ping = now()\n FROM v2_job_queue q\n WHERE r.id = $2 AND q.id = r.id\n RETURNING canceled_by, canceled_reason",
|
||||
"query": "UPDATE v2_job_runtime r SET\n memory_peak = $1,\n ping = now()\n FROM v2_job_queue q\n WHERE r.id = $2 AND q.id = r.id\n RETURNING canceled_by, canceled_reason",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -25,5 +25,5 @@
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "6ff7a025f529c077c1b6c9632a367aa29e2f0fdac3f1984550484d5a06a6ea21"
|
||||
"hash": "2faa27519624249f16cf89814ab5efe8f8daf928c1194cecacfa8223165fb9f2"
|
||||
}
|
||||
23
backend/.sqlx/query-30483ae46f6d0452126eb2cd07fc4d960961cc6ee61cf065113b7a48f97caecc.json
generated
Normal file
23
backend/.sqlx/query-30483ae46f6d0452126eb2cd07fc4d960961cc6ee61cf065113b7a48f97caecc.json
generated
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT value as \"value: sqlx::types::Json<Box<RawValue>>\" FROM resource WHERE path = $1 AND workspace_id = $2",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "value: sqlx::types::Json<Box<RawValue>>",
|
||||
"type_info": "Jsonb"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "30483ae46f6d0452126eb2cd07fc4d960961cc6ee61cf065113b7a48f97caecc"
|
||||
}
|
||||
23
backend/.sqlx/query-33ee913ce263600a3f94f90e4a42cf0e4086030f3b7994e4892392765cbe1517.json
generated
Normal file
23
backend/.sqlx/query-33ee913ce263600a3f94f90e4a42cf0e4086030f3b7994e4892392765cbe1517.json
generated
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT EXISTS(\n SELECT \n 1 \n FROM \n gcp_trigger \n WHERE \n path = $1 AND \n workspace_id = $2\n )",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "exists",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "33ee913ce263600a3f94f90e4a42cf0e4086030f3b7994e4892392765cbe1517"
|
||||
}
|
||||
17
backend/.sqlx/query-37011e7f4cdfc87294e44252cca4f4683a12b82b972842f88f5c01111580224d.json
generated
Normal file
17
backend/.sqlx/query-37011e7f4cdfc87294e44252cca4f4683a12b82b972842f88f5c01111580224d.json
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE \n capture\n SET \n path = $1\n WHERE \n path = $2 \n AND workspace_id = $3 \n AND is_flow = $4\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Text",
|
||||
"Text",
|
||||
"Bool"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "37011e7f4cdfc87294e44252cca4f4683a12b82b972842f88f5c01111580224d"
|
||||
}
|
||||
35
backend/.sqlx/query-3f5520e0ea00569bf169da9abde31617043fcc0bea3ef62c50fcd881f3d48605.json
generated
Normal file
35
backend/.sqlx/query-3f5520e0ea00569bf169da9abde31617043fcc0bea3ef62c50fcd881f3d48605.json
generated
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO gcp_trigger (\n gcp_resource_path,\n subscription_id,\n topic_id,\n delivery_type,\n delivery_config,\n workspace_id, \n path, \n script_path, \n is_flow, \n email, \n enabled, \n edited_by\n ) \n VALUES (\n $1, \n $2, \n $3, \n $4,\n $5,\n $6, \n $7, \n $8, \n $9,\n $10,\n $11,\n $12\n )",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
{
|
||||
"Custom": {
|
||||
"name": "delivery_mode",
|
||||
"kind": {
|
||||
"Enum": [
|
||||
"push",
|
||||
"pull"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Jsonb",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Bool",
|
||||
"Varchar",
|
||||
"Bool",
|
||||
"Varchar"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "3f5520e0ea00569bf169da9abde31617043fcc0bea3ef62c50fcd881f3d48605"
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "DELETE FROM capture WHERE id = $1",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "41e557e1b63b13c9fcc195901c0bd0de7e03c539ee046955543d9693551246f7"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE capture_config SET last_client_ping = now() WHERE workspace_id = $1 AND path = $2 AND is_flow = $3 AND trigger_kind = $4",
|
||||
"query": "\n UPDATE \n capture_config\n SET \n last_client_ping = NOW()\n WHERE \n workspace_id = $1 \n AND path = $2 \n AND is_flow = $3 \n AND trigger_kind = $4\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -21,7 +21,8 @@
|
||||
"nats",
|
||||
"postgres",
|
||||
"sqs",
|
||||
"mqtt"
|
||||
"mqtt",
|
||||
"gcp"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -30,5 +31,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "c5270ee815689e42b65df507b850da43239c9a5aaea41c9aed7ed33a6219a534"
|
||||
"hash": "42b4b73e9d60348e2d90fcade9dcad6d8995242dc20a4e14c1a8fae4fc6a9fd2"
|
||||
}
|
||||
17
backend/.sqlx/query-43c8cd9f8560412bb06d9966ccfa2524943ba277c5f9a37c06bd5ee14fd46bda.json
generated
Normal file
17
backend/.sqlx/query-43c8cd9f8560412bb06d9966ccfa2524943ba277c5f9a37c06bd5ee14fd46bda.json
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE \n capture_config \n SET \n error = $1, \n server_id = NULL, \n last_server_ping = NULL \n WHERE \n workspace_id = $2 AND \n path = $3 AND \n is_flow = $4 AND \n trigger_kind = 'gcp'\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text",
|
||||
"Text",
|
||||
"Bool"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "43c8cd9f8560412bb06d9966ccfa2524943ba277c5f9a37c06bd5ee14fd46bda"
|
||||
}
|
||||
36
backend/.sqlx/query-44b9bea3651edc8ee732def1241b3d956c004376102ccc1707fc016801599dbd.json
generated
Normal file
36
backend/.sqlx/query-44b9bea3651edc8ee732def1241b3d956c004376102ccc1707fc016801599dbd.json
generated
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE \n gcp_trigger \n SET \n gcp_resource_path = $1,\n subscription_id = $2,\n topic_id = $3,\n delivery_type = $4,\n delivery_config = $5,\n is_flow = $6, \n edited_by = $7, \n email = $8,\n script_path = $9,\n path = $10,\n enabled = $11,\n edited_at = now(), \n error = NULL,\n server_id = NULL\n WHERE \n workspace_id = $12 AND \n path = $13\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
{
|
||||
"Custom": {
|
||||
"name": "delivery_mode",
|
||||
"kind": {
|
||||
"Enum": [
|
||||
"push",
|
||||
"pull"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Jsonb",
|
||||
"Bool",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Bool",
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "44b9bea3651edc8ee732def1241b3d956c004376102ccc1707fc016801599dbd"
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE v2_job_status SET\n workflow_as_code_status = jsonb_set(\n jsonb_set(\n COALESCE(workflow_as_code_status, '{}'::jsonb),\n array[$1],\n COALESCE(workflow_as_code_status->$1, '{}'::jsonb)\n ),\n array[$1, 'started_at'],\n to_jsonb(now()::text)\n )\n WHERE id = $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Uuid"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "45d616c92ebcbe30a563e1fa7d2d0e53392e238144b039cfe042587d7fe1dea3"
|
||||
}
|
||||
@@ -220,7 +220,9 @@
|
||||
"schedule",
|
||||
"app",
|
||||
"ui",
|
||||
"postgres"
|
||||
"postgres",
|
||||
"sqs",
|
||||
"gcp"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
16
backend/.sqlx/query-505250098ab003ff0ca30046df283e54bf44be74305070f10a5720a04c4789f3.json
generated
Normal file
16
backend/.sqlx/query-505250098ab003ff0ca30046df283e54bf44be74305070f10a5720a04c4789f3.json
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE v2_job_queue\n SET canceled_by = $1\n , canceled_reason = $2\nWHERE id = $3",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Text",
|
||||
"Uuid"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "505250098ab003ff0ca30046df283e54bf44be74305070f10a5720a04c4789f3"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE worker_ping SET ping_at = now(), current_job_id = $1, current_job_workspace_id = $2, memory_usage = $3, wm_memory_usage = $4,\n occupancy_rate = $6, occupancy_rate_15s = $7, occupancy_rate_5m = $8, occupancy_rate_30m = $9 WHERE worker = $5",
|
||||
"query": "UPDATE worker_ping SET ping_at = now(), current_job_id = $1, current_job_workspace_id = $2, memory_usage = $3, wm_memory_usage = $4,\n occupancy_rate = $6, occupancy_rate_15s = $7, occupancy_rate_5m = $8, occupancy_rate_30m = $9 WHERE worker = $5",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -18,5 +18,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "e968e879d3c52f7dd502c3cd15fc8fbd983a4a3ab25648c562497a27c74b5c8c"
|
||||
"hash": "506066203c49424e9944eb3948dc1657d3d796e6233e9f0ec925879c705d4773"
|
||||
}
|
||||
65
backend/.sqlx/query-5303206bbed76ee3ddc56d8057d8b82359c182ee2a5da6df35a4375d5d2d1ef7.json
generated
Normal file
65
backend/.sqlx/query-5303206bbed76ee3ddc56d8057d8b82359c182ee2a5da6df35a4375d5d2d1ef7.json
generated
Normal file
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT \n gcp_resource_path, \n script_path,\n is_flow, \n workspace_id,\n path,\n edited_by,\n email,\n delivery_config AS \"delivery_config: _\"\n FROM\n gcp_trigger\n WHERE\n workspace_id = $1 AND\n path = $2 AND\n delivery_type = 'push'::DELIVERY_MODE \n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "gcp_resource_path",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "script_path",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "is_flow",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "workspace_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "path",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "edited_by",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "email",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "delivery_config: _",
|
||||
"type_info": "Jsonb"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "5303206bbed76ee3ddc56d8057d8b82359c182ee2a5da6df35a4375d5d2d1ef7"
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT value FROM resource WHERE path = $1 AND workspace_id = $2",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "value",
|
||||
"type_info": "Jsonb"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "63c16a4277983aaed0aed54972923919cee3cc444725ac6b7906922554bae800"
|
||||
}
|
||||
16
backend/.sqlx/query-673564e6c4dcf30dae3d7a75c397998ea800860ede856e5fc6cd1f57d5408333.json
generated
Normal file
16
backend/.sqlx/query-673564e6c4dcf30dae3d7a75c397998ea800860ede856e5fc6cd1f57d5408333.json
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE \n capture_config \n SET \n last_server_ping = NULL \n WHERE \n workspace_id = $1 AND \n path = $2 AND \n is_flow = $3 AND \n trigger_kind = 'gcp' AND \n server_id IS NULL\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text",
|
||||
"Bool"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "673564e6c4dcf30dae3d7a75c397998ea800860ede856e5fc6cd1f57d5408333"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT id, created_at, trigger_kind as \"trigger_kind: _\", payload as \"payload!: _\", trigger_extra as \"trigger_extra: _\" FROM capture WHERE id = $1 AND workspace_id = $2",
|
||||
"query": "\n SELECT \n id, \n created_at, \n trigger_kind AS \"trigger_kind: _\", \n payload AS \"payload!: _\", \n trigger_extra AS \"trigger_extra: _\"\n FROM \n capture\n WHERE \n id = $1 \n AND workspace_id = $2\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -29,7 +29,8 @@
|
||||
"nats",
|
||||
"postgres",
|
||||
"sqs",
|
||||
"mqtt"
|
||||
"mqtt",
|
||||
"gcp"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -60,5 +61,5 @@
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "e17ec84003e2ec414622d100f5dfdda86bee33f31835317df512a20c805b35d7"
|
||||
"hash": "6781ba76dfce321dca4634566496ea5d698ac09d8264e35dfaa4cd8edc9e8414"
|
||||
}
|
||||
15
backend/.sqlx/query-77701b16ee1f6dd827372835db59bbffc7254af47a8d48b7ba3cf969c2f8398c.json
generated
Normal file
15
backend/.sqlx/query-77701b16ee1f6dd827372835db59bbffc7254af47a8d48b7ba3cf969c2f8398c.json
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE v2_job_queue SET tag = $1, running = false WHERE id = $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Uuid"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "77701b16ee1f6dd827372835db59bbffc7254af47a8d48b7ba3cf969c2f8398c"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT id, created_at, trigger_kind as \"trigger_kind: _\", CASE WHEN pg_column_size(payload) < 40000 THEN payload ELSE '\"WINDMILL_TOO_BIG\"'::jsonb END as \"payload!: _\", trigger_extra as \"trigger_extra: _\"\n FROM capture\n WHERE workspace_id = $1\n AND path = $2 AND is_flow = $3\n AND ($4::trigger_kind IS NULL OR trigger_kind = $4)\n ORDER BY created_at DESC\n OFFSET $5\n LIMIT $6",
|
||||
"query": "\n SELECT \n id, \n created_at, \n trigger_kind AS \"trigger_kind: _\",\n CASE \n WHEN pg_column_size(payload) < 40000 THEN payload \n ELSE '\"WINDMILL_TOO_BIG\"'::jsonb \n END AS \"payload!: _\",\n trigger_extra AS \"trigger_extra: _\"\n FROM \n capture\n WHERE \n workspace_id = $1 \n AND path = $2 \n AND is_flow = $3 \n AND ($4::trigger_kind IS NULL OR trigger_kind = $4)\n ORDER BY \n created_at DESC\n OFFSET $5\n LIMIT $6\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -29,7 +29,8 @@
|
||||
"nats",
|
||||
"postgres",
|
||||
"sqs",
|
||||
"mqtt"
|
||||
"mqtt",
|
||||
"gcp"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -64,7 +65,8 @@
|
||||
"nats",
|
||||
"postgres",
|
||||
"sqs",
|
||||
"mqtt"
|
||||
"mqtt",
|
||||
"gcp"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -81,5 +83,5 @@
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "5c1de8473e0e96c1063a9a735a064c5a91e3ed8d9260c72b783fc12542b88fbd"
|
||||
"hash": "7cba31d597215a343cb0bca5b204a15fbba193262f7895c2bba90feb4215d6f3"
|
||||
}
|
||||
14
backend/.sqlx/query-7d5a161d916cb8d1485f8d72e6b4044f505f49edcd2ebeee4a77eae737f48795.json
generated
Normal file
14
backend/.sqlx/query-7d5a161d916cb8d1485f8d72e6b4044f505f49edcd2ebeee4a77eae737f48795.json
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n DELETE FROM \n capture\n WHERE \n id = $1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "7d5a161d916cb8d1485f8d72e6b4044f505f49edcd2ebeee4a77eae737f48795"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO job_perms (job_id, email, username, is_admin, is_operator, folders, groups, workspace_id) \n values ($1, $2, $3, $4, $5, $6, $7, $8) \n ON CONFLICT (job_id) DO UPDATE SET email = $2, username = $3, is_admin = $4, is_operator = $5, folders = $6, groups = $7, workspace_id = $8",
|
||||
"query": "INSERT INTO job_perms (job_id, email, username, is_admin, is_operator, folders, groups, workspace_id) \n values ($1, $2, $3, $4, $5, $6, $7, $8) \n ON CONFLICT (job_id) DO UPDATE SET email = $2, username = $3, is_admin = $4, is_operator = $5, folders = $6, groups = $7, workspace_id = $8",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -17,5 +17,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "8efd06387ded837d7849adafe5bc93acb882ef90fc58b023650c875e0fd17047"
|
||||
"hash": "7d78efab0a588f56a13a7b5251f0a72f5d341b053218e7aec83a834cf7ccc98f"
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE capture_config SET path = $1 WHERE path = $2 AND workspace_id = $3 AND is_flow = $4",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Text",
|
||||
"Text",
|
||||
"Bool"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "7e891e053b8545c800d629421f239319a854f761a300970e2fd909f8058ec566"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT trigger_config as \"trigger_config: _\", trigger_kind as \"trigger_kind: _\", error, last_server_ping\n FROM capture_config\n WHERE workspace_id = $1 AND path = $2 AND is_flow = $3",
|
||||
"query": "\n SELECT \n trigger_config AS \"trigger_config: _\", \n trigger_kind AS \"trigger_kind: _\", \n error, \n last_server_ping\n FROM \n capture_config\n WHERE \n workspace_id = $1 \n AND path = $2 \n AND is_flow = $3\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -24,7 +24,8 @@
|
||||
"nats",
|
||||
"postgres",
|
||||
"sqs",
|
||||
"mqtt"
|
||||
"mqtt",
|
||||
"gcp"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -55,5 +56,5 @@
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "c223f8b7fa4ef1aa06e1ba2a56d677774aa237508d5610714efd2e9b8b93c7b8"
|
||||
"hash": "7fbf72d9059fcd77e4c1112fa4fa22e4276c1da653475628889ce17dc904fbaa"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT owner, email\n FROM capture_config\n WHERE workspace_id = $1 AND path = $2 AND is_flow = $3 AND trigger_kind = $4 AND last_client_ping > NOW() - INTERVAL '10 seconds'",
|
||||
"query": "\n SELECT \n owner, \n email\n FROM \n capture_config\n WHERE \n workspace_id = $1 \n AND path = $2 \n AND is_flow = $3 \n AND trigger_kind = $4 \n AND last_client_ping > NOW() - INTERVAL '10 seconds'\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -32,7 +32,8 @@
|
||||
"nats",
|
||||
"postgres",
|
||||
"sqs",
|
||||
"mqtt"
|
||||
"mqtt",
|
||||
"gcp"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -44,5 +45,5 @@
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "71d51bbc35da7b9930e3ea3a634451217ccb9f1bc35b1ad6e10d16bc19c41447"
|
||||
"hash": "87564a196a1662f524407d853db506bf08c28efe82b68b3d44bafbd3d0e91c29"
|
||||
}
|
||||
24
backend/.sqlx/query-92c2b66eb6287449f5f8cc9f8d1329f748006ab131489d2fcac21d32641bb633.json
generated
Normal file
24
backend/.sqlx/query-92c2b66eb6287449f5f8cc9f8d1329f748006ab131489d2fcac21d32641bb633.json
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE \n gcp_trigger \n SET \n server_id = $1, \n last_server_ping = now(),\n error = 'Connecting...'\n WHERE \n enabled IS TRUE \n AND workspace_id = $2 \n AND path = $3 \n AND (last_server_ping IS NULL \n OR last_server_ping < now() - INTERVAL '15 seconds'\n ) \n RETURNING true\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "?column?",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "92c2b66eb6287449f5f8cc9f8d1329f748006ab131489d2fcac21d32641bb633"
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "DELETE FROM capture\n WHERE workspace_id = $1\n AND created_at <=\n (\n SELECT created_at\n FROM capture\n WHERE workspace_id = $1\n ORDER BY created_at DESC\n OFFSET $2\n LIMIT 1\n )",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "97942578df746c8c8103b403cfc4e44ef5a0f082bdde854900064325adc4dd77"
|
||||
}
|
||||
15
backend/.sqlx/query-999edc6f54a9efb6dc6237992dad59f418ed6fc2a98ddb9bbc33dce5f029d904.json
generated
Normal file
15
backend/.sqlx/query-999edc6f54a9efb6dc6237992dad59f418ed6fc2a98ddb9bbc33dce5f029d904.json
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE \n gcp_trigger \n SET\n last_server_ping = NULL \n WHERE \n workspace_id = $1 \n AND path = $2 \n AND server_id IS NULL",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "999edc6f54a9efb6dc6237992dad59f418ed6fc2a98ddb9bbc33dce5f029d904"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT value\n FROM global_settings\n WHERE name = 'openai_azure_base_path'",
|
||||
"query": "SELECT value\n FROM global_settings\n WHERE name = 'openai_azure_base_path'",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -16,5 +16,5 @@
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "0cc3618495d5d024b2a173c58a3a8bb2a9d69b7b6e7ed6b0d0064fa2ce9c2e31"
|
||||
"hash": "a21a16064b51580a8f5c2505cb0c701281dbfa94e40994fdd1cadc86a26c294e"
|
||||
}
|
||||
24
backend/.sqlx/query-a2e86f169ffbf8acee5f7c7b71db5859ac94ffbad267c9cd6c652e8ce8fc5d3c.json
generated
Normal file
24
backend/.sqlx/query-a2e86f169ffbf8acee5f7c7b71db5859ac94ffbad267c9cd6c652e8ce8fc5d3c.json
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO job_logs (logs, job_id, workspace_id) VALUES ($1, $2, $3) ON CONFLICT (job_id) DO UPDATE SET logs = concat(job_logs.logs, $1::text) RETURNING length(logs)",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "length",
|
||||
"type_info": "Int4"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Uuid",
|
||||
"Varchar"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "a2e86f169ffbf8acee5f7c7b71db5859ac94ffbad267c9cd6c652e8ce8fc5d3c"
|
||||
}
|
||||
26
backend/.sqlx/query-a7ffc5b983d365159ef379ec6a2ab0dc7217d1b3f86f362c213982984d2cf652.json
generated
Normal file
26
backend/.sqlx/query-a7ffc5b983d365159ef379ec6a2ab0dc7217d1b3f86f362c213982984d2cf652.json
generated
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE \n capture_config \n SET \n last_server_ping = now(), \n error = $1 \n WHERE \n workspace_id = $2 AND \n path = $3 AND \n is_flow = $4 AND \n trigger_kind = 'gcp' AND \n server_id = $5 AND \n last_client_ping > NOW() - INTERVAL '10 seconds' \n RETURNING 1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "?column?",
|
||||
"type_info": "Int4"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text",
|
||||
"Text",
|
||||
"Bool",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "a7ffc5b983d365159ef379ec6a2ab0dc7217d1b3f86f362c213982984d2cf652"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT content AS \"content!: String\",\n lock AS \"lock: String\", language AS \"language: Option<ScriptLang>\", envs AS \"envs: Vec<String>\", schema AS \"schema: String\", schema_validation AS \"schema_validation: bool\", codebase LIKE '%.tar' as use_tar FROM script WHERE hash = $1 LIMIT 1",
|
||||
"query": "SELECT content AS \"content!: String\",\n lock AS \"lock: String\", language AS \"language: Option<ScriptLang>\", envs AS \"envs: Vec<String>\", schema AS \"schema: String\", schema_validation AS \"schema_validation: bool\", codebase LIKE '%.tar' as use_tar FROM script WHERE hash = $1 LIMIT 1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -83,5 +83,5 @@
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "03ae5b1c912b13a8a7aadf50cb4984a2ea952e782fd52eb3088454690bd13dd1"
|
||||
"hash": "a9db7b2f435bb82acb8c5eeb7f800b28f3256491fdaa168591adc7b4b9f3327a"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT\n EXISTS(SELECT 1 FROM websocket_trigger WHERE workspace_id = $1) AS \"websocket_used!\",\n EXISTS(SELECT 1 FROM http_trigger WHERE workspace_id = $1) AS \"http_routes_used!\",\n EXISTS(SELECT 1 FROM kafka_trigger WHERE workspace_id = $1) as \"kafka_used!\",\n EXISTS(SELECT 1 FROM nats_trigger WHERE workspace_id = $1) as \"nats_used!\",\n EXISTS(SELECT 1 FROM postgres_trigger WHERE workspace_id = $1) AS \"postgres_used!\",\n EXISTS(SELECT 1 FROM mqtt_trigger WHERE workspace_id = $1) AS \"mqtt_used!\",\n EXISTS(SELECT 1 FROM sqs_trigger WHERE workspace_id = $1) AS \"sqs_used!\"\n ",
|
||||
"query": "\n SELECT\n EXISTS(SELECT 1 FROM websocket_trigger WHERE workspace_id = $1) AS \"websocket_used!\",\n EXISTS(SELECT 1 FROM http_trigger WHERE workspace_id = $1) AS \"http_routes_used!\",\n EXISTS(SELECT 1 FROM kafka_trigger WHERE workspace_id = $1) as \"kafka_used!\",\n EXISTS(SELECT 1 FROM nats_trigger WHERE workspace_id = $1) as \"nats_used!\",\n EXISTS(SELECT 1 FROM postgres_trigger WHERE workspace_id = $1) AS \"postgres_used!\",\n EXISTS(SELECT 1 FROM mqtt_trigger WHERE workspace_id = $1) AS \"mqtt_used!\",\n EXISTS(SELECT 1 FROM sqs_trigger WHERE workspace_id = $1) AS \"sqs_used!\",\n EXISTS(SELECT 1 FROM gcp_trigger WHERE workspace_id = $1) AS \"gcp_used!\"\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -37,6 +37,11 @@
|
||||
"ordinal": 6,
|
||||
"name": "sqs_used!",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "gcp_used!",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -51,8 +56,9 @@
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "9ae20f2f29406cfa5337736ad710c496f1757d950cdec63c93c77fe79d5212cc"
|
||||
"hash": "aa0215d4174c1aeda8631bcd582c895329d2daf722d360fbcbdef6f04bb1400f"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE worker_ping SET ping_at = now(), jobs_executed = $1, custom_tags = $2,\n occupancy_rate = $3, memory_usage = $4, wm_memory_usage = $5, vcpus = COALESCE($7, vcpus),\n memory = COALESCE($8, memory), occupancy_rate_15s = $9, occupancy_rate_5m = $10, occupancy_rate_30m = $11 WHERE worker = $6",
|
||||
"query": "UPDATE worker_ping SET ping_at = now(), jobs_executed = $1, custom_tags = $2,\n occupancy_rate = $3, memory_usage = $4, wm_memory_usage = $5, vcpus = COALESCE($7, vcpus),\n memory = COALESCE($8, memory), occupancy_rate_15s = $9, occupancy_rate_5m = $10, occupancy_rate_30m = $11 WHERE worker = $6",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -20,5 +20,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "a439552f74ed0ba305e3d9cb99ae9e5d24834082ebf2fe9fd3964fdd80b69ccb"
|
||||
"hash": "aa523c363186575b4bd2537b8e2430e6938e7cc35f8c9e2d1c5459a85443cbdd"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO capture_config\n (workspace_id, path, is_flow, trigger_kind, trigger_config, owner, email)\n VALUES ($1, $2, $3, $4, $5, $6, $7)\n ON CONFLICT (workspace_id, path, is_flow, trigger_kind)\n DO UPDATE SET trigger_config = $5, owner = $6, email = $7, server_id = NULL, error = NULL",
|
||||
"query": "\n INSERT INTO capture_config (\n workspace_id, path, is_flow, trigger_kind, trigger_config, owner, email\n )\n VALUES (\n $1, $2, $3, $4, $5, $6, $7\n )\n ON CONFLICT (workspace_id, path, is_flow, trigger_kind)\n DO UPDATE \n SET \n trigger_config = $5, \n owner = $6, \n email = $7, \n server_id = NULL, \n error = NULL\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -21,7 +21,8 @@
|
||||
"nats",
|
||||
"postgres",
|
||||
"sqs",
|
||||
"mqtt"
|
||||
"mqtt",
|
||||
"gcp"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -33,5 +34,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "62475252dcf54f32433b97ae011daf5d4205d160d2aedf463c7dfe944e93257a"
|
||||
"hash": "b3f0595cacba194e08b9a3e244d9e637e9e156cd85b69126c87dfff89a47711d"
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE v2_job_queue\n SET canceled_by = 'timeout'\n , canceled_reason = $1\n WHERE id = $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Uuid"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "c00bae0d8c9bee37cbad4de4cb02c80d00f52a3fc32bf32271ebc90f7837abda"
|
||||
}
|
||||
50
backend/.sqlx/query-c0e6dbce7a401b06e1bf45155c3f81572818177a6024e743b12f558b46edf74c.json
generated
Normal file
50
backend/.sqlx/query-c0e6dbce7a401b06e1bf45155c3f81572818177a6024e743b12f558b46edf74c.json
generated
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT\n path,\n is_flow,\n workspace_id,\n owner,\n email,\n trigger_config as \"trigger_config!: _\"\n FROM\n capture_config\n WHERE\n trigger_kind = 'gcp' AND\n last_client_ping > NOW() - INTERVAL '10 seconds' AND\n trigger_config IS NOT NULL AND\n trigger_config->>'delivery_type' IS DISTINCT FROM 'push' AND\n (last_server_ping IS NULL OR last_server_ping < now() - interval '15 seconds')\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "path",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "is_flow",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "workspace_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "owner",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "email",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "trigger_config!: _",
|
||||
"type_info": "Jsonb"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "c0e6dbce7a401b06e1bf45155c3f81572818177a6024e743b12f558b46edf74c"
|
||||
}
|
||||
15
backend/.sqlx/query-c19a60a9dc3f95af218baf40c62f14572ac204cfe377166aa1d91cf58f731f50.json
generated
Normal file
15
backend/.sqlx/query-c19a60a9dc3f95af218baf40c62f14572ac204cfe377166aa1d91cf58f731f50.json
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n DELETE \n FROM \n gcp_trigger \n WHERE \n workspace_id = $1 AND \n path = $2\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "c19a60a9dc3f95af218baf40c62f14572ac204cfe377166aa1d91cf58f731f50"
|
||||
}
|
||||
15
backend/.sqlx/query-c3025cdb6e421e1225d420e8b1efd18d1dd3bb2fac53c1f2df648b61fb7488aa.json
generated
Normal file
15
backend/.sqlx/query-c3025cdb6e421e1225d420e8b1efd18d1dd3bb2fac53c1f2df648b61fb7488aa.json
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE worker_ping SET \nping_at = now(), \njobs_executed = 1, \ncurrent_job_id = $1, \ncurrent_job_workspace_id = 'admins' \nWHERE worker = $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "c3025cdb6e421e1225d420e8b1efd18d1dd3bb2fac53c1f2df648b61fb7488aa"
|
||||
}
|
||||
17
backend/.sqlx/query-c353aa9abe673749f0836fd16894d91ba89aab2318d85621ad2868017adfb48a.json
generated
Normal file
17
backend/.sqlx/query-c353aa9abe673749f0836fd16894d91ba89aab2318d85621ad2868017adfb48a.json
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE \n capture_config\n SET \n path = $1\n WHERE \n path = $2 \n AND workspace_id = $3 \n AND is_flow = $4\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Text",
|
||||
"Text",
|
||||
"Bool"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "c353aa9abe673749f0836fd16894d91ba89aab2318d85621ad2868017adfb48a"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO outstanding_wait_time(job_id, self_wait_time_ms) VALUES ($1, $2)\n ON CONFLICT (job_id) DO UPDATE SET self_wait_time_ms = EXCLUDED.self_wait_time_ms",
|
||||
"query": "INSERT INTO outstanding_wait_time(job_id, self_wait_time_ms) VALUES ($1, $2)\n ON CONFLICT (job_id) DO UPDATE SET self_wait_time_ms = EXCLUDED.self_wait_time_ms",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -11,5 +11,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "f367a1c8f80dd414dcbcd949374eeb5770796f00b5b3d547163bcfdaed65d8ae"
|
||||
"hash": "c53e1c7133c8ae187656eef5999509fae17fb0ba43e084327accbb5b24c3dfbd"
|
||||
}
|
||||
25
backend/.sqlx/query-df2a426658f0a36683cc2163fe70912d0221d191b8ab091601cb53cdd932ad58.json
generated
Normal file
25
backend/.sqlx/query-df2a426658f0a36683cc2163fe70912d0221d191b8ab091601cb53cdd932ad58.json
generated
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE \n gcp_trigger\n SET \n last_server_ping = now(),\n error = $1\n WHERE\n workspace_id = $2\n AND path = $3\n AND server_id = $4 \n AND enabled IS TRUE\n RETURNING 1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "?column?",
|
||||
"type_info": "Int4"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text",
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "df2a426658f0a36683cc2163fe70912d0221d191b8ab091601cb53cdd932ad58"
|
||||
}
|
||||
15
backend/.sqlx/query-e04a8a9f1e9cc3bb5c990194585e08f4c248e1af1c6580bdf8f2735ae1388981.json
generated
Normal file
15
backend/.sqlx/query-e04a8a9f1e9cc3bb5c990194585e08f4c248e1af1c6580bdf8f2735ae1388981.json
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n DELETE FROM \n capture\n WHERE \n workspace_id = $1\n AND created_at <= (\n SELECT \n created_at\n FROM \n capture\n WHERE \n workspace_id = $1\n ORDER BY \n created_at DESC\n OFFSET $2\n LIMIT 1\n )\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "e04a8a9f1e9cc3bb5c990194585e08f4c248e1af1c6580bdf8f2735ae1388981"
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE capture SET path = $1 WHERE path = $2 AND workspace_id = $3 AND is_flow = $4",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Text",
|
||||
"Text",
|
||||
"Bool"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "e70c3da5864b7946735b7ad6c416874ee8b277a2914dff6f9c33a1f5a2351114"
|
||||
}
|
||||
129
backend/.sqlx/query-f4f6336fc671b00bed7835124892f7a4d3bbe673f7c48153819dab385a5cb357.json
generated
Normal file
129
backend/.sqlx/query-f4f6336fc671b00bed7835124892f7a4d3bbe673f7c48153819dab385a5cb357.json
generated
Normal file
@@ -0,0 +1,129 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT\n gcp_resource_path,\n subscription_id,\n topic_id,\n workspace_id,\n delivery_type AS \"delivery_type: _\",\n delivery_config AS \"delivery_config: _\",\n path,\n script_path,\n is_flow,\n edited_by,\n email,\n edited_at,\n server_id,\n last_server_ping,\n extra_perms,\n error,\n enabled\n FROM \n gcp_trigger\n WHERE \n workspace_id = $1 AND \n path = $2\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "gcp_resource_path",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "subscription_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "topic_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "workspace_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "delivery_type: _",
|
||||
"type_info": {
|
||||
"Custom": {
|
||||
"name": "delivery_mode",
|
||||
"kind": {
|
||||
"Enum": [
|
||||
"push",
|
||||
"pull"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "delivery_config: _",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "path",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "script_path",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"name": "is_flow",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"name": "edited_by",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"name": "email",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"name": "edited_at",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"name": "server_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"name": "last_server_ping",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"name": "extra_perms",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 15,
|
||||
"name": "error",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 16,
|
||||
"name": "enabled",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "f4f6336fc671b00bed7835124892f7a4d3bbe673f7c48153819dab385a5cb357"
|
||||
}
|
||||
23
backend/.sqlx/query-f955a01779f5441efc6aa9364b24c79b3cbc6413046c3b6099d19f675d8a395b.json
generated
Normal file
23
backend/.sqlx/query-f955a01779f5441efc6aa9364b24c79b3cbc6413046c3b6099d19f675d8a395b.json
generated
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT EXISTS (SELECT 1\n FROM workspace_settings\n WHERE workspace_id <> $1\n AND slack_command_script IS NOT NULL\n AND slack_team_id = $2\n AND (SELECT slack_command_script IS NOT NULL FROM workspace_settings WHERE workspace_id = $1))\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "exists",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "f955a01779f5441efc6aa9364b24c79b3cbc6413046c3b6099d19f675d8a395b"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO capture (workspace_id, path, is_flow, trigger_kind, payload, trigger_extra, created_by)\n VALUES ($1, $2, $3, $4, $5, $6, $7)",
|
||||
"query": "\n INSERT INTO \n capture (\n workspace_id, path, is_flow, trigger_kind, payload, trigger_extra, created_by\n )\n VALUES (\n $1, $2, $3, $4, $5, $6, $7\n )\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -21,7 +21,8 @@
|
||||
"nats",
|
||||
"postgres",
|
||||
"sqs",
|
||||
"mqtt"
|
||||
"mqtt",
|
||||
"gcp"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -33,5 +34,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "07da723ce5c9ee2d7c236e8eabe254c783fc34b617c8a9a95a0eb0cda535dab5"
|
||||
"hash": "f9f7f31390f8ea1f4facd8e6a888886ea136f2327169bf93f126e2ef130d0946"
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT EXISTS (SELECT 1 \n FROM workspace_settings \n WHERE workspace_id <> $1 \n AND slack_command_script IS NOT NULL\n AND slack_team_id = $2\n AND (SELECT slack_command_script IS NOT NULL FROM workspace_settings WHERE workspace_id = $1))\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "exists",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "fa59674af1d1a4ceb696fc883005ef114772f7d2ee0f60cb1358cdb7f0b5cd0c"
|
||||
}
|
||||
22
backend/.sqlx/query-faf2c77242e0ab39b33886edf3b742531bf1351d0be1c3631bde0adfe375497a.json
generated
Normal file
22
backend/.sqlx/query-faf2c77242e0ab39b33886edf3b742531bf1351d0be1c3631bde0adfe375497a.json
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT tag FROM v2_job WHERE id = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "tag",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "faf2c77242e0ab39b33886edf3b742531bf1351d0be1c3631bde0adfe375497a"
|
||||
}
|
||||
16
backend/.sqlx/query-fd0a0ca4a107dc813240ad71f372ab7e0bf26431158fbfb5f0023ed847ca7dc5.json
generated
Normal file
16
backend/.sqlx/query-fd0a0ca4a107dc813240ad71f372ab7e0bf26431158fbfb5f0023ed847ca7dc5.json
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE \n gcp_trigger \n SET \n enabled = FALSE, \n error = $1, \n server_id = NULL, \n last_server_ping = NULL \n WHERE \n workspace_id = $2 AND \n path = $3\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "fd0a0ca4a107dc813240ad71f372ab7e0bf26431158fbfb5f0023ed847ca7dc5"
|
||||
}
|
||||
2
backend/.vscode/settings.json
vendored
2
backend/.vscode/settings.json
vendored
@@ -11,5 +11,5 @@
|
||||
"remote.autoForwardPorts": true,
|
||||
"conventionalCommits.scopes": [
|
||||
"restructring triggers, decoding trigger message on work"
|
||||
]
|
||||
],
|
||||
}
|
||||
|
||||
287
backend/Cargo.lock
generated
287
backend/Cargo.lock
generated
@@ -554,6 +554,17 @@ dependencies = [
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-channel"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"event-listener 2.5.3",
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-compression"
|
||||
version = "0.4.19"
|
||||
@@ -2572,7 +2583,7 @@ dependencies = [
|
||||
"hashbrown 0.14.5",
|
||||
"lock_api",
|
||||
"once_cell",
|
||||
"parking_lot_core",
|
||||
"parking_lot_core 0.9.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2626,7 +2637,7 @@ dependencies = [
|
||||
"log",
|
||||
"num_cpus",
|
||||
"object_store",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.3",
|
||||
"parquet",
|
||||
"paste",
|
||||
"pin-project-lite",
|
||||
@@ -2687,7 +2698,7 @@ dependencies = [
|
||||
"hashbrown 0.14.5",
|
||||
"log",
|
||||
"object_store",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.3",
|
||||
"rand 0.8.5",
|
||||
"tempfile",
|
||||
"url",
|
||||
@@ -2867,7 +2878,7 @@ dependencies = [
|
||||
"itertools 0.12.1",
|
||||
"log",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.3",
|
||||
"pin-project-lite",
|
||||
"rand 0.8.5",
|
||||
"tokio",
|
||||
@@ -2998,7 +3009,7 @@ dependencies = [
|
||||
"indexmap 2.8.0",
|
||||
"log",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.3",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.8",
|
||||
@@ -3080,7 +3091,7 @@ dependencies = [
|
||||
"indexmap 2.8.0",
|
||||
"libc",
|
||||
"memoffset",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.3",
|
||||
"percent-encoding",
|
||||
"pin-project",
|
||||
"serde",
|
||||
@@ -3325,7 +3336,7 @@ dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"os_pipe",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.3",
|
||||
"pin-project",
|
||||
"rand 0.8.5",
|
||||
"tokio",
|
||||
@@ -3705,7 +3716,7 @@ dependencies = [
|
||||
"log",
|
||||
"node_resolver",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.3",
|
||||
"sys_traits",
|
||||
"thiserror 2.0.12",
|
||||
"url",
|
||||
@@ -3862,7 +3873,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d774fd83f26b24f0805a6ab8b26834a0d06ceac0db517b769b1e4633c96a2057"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.3",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
@@ -4602,6 +4613,12 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "2.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "5.4.0"
|
||||
@@ -4972,7 +4989,7 @@ checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"lock_api",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5347,6 +5364,94 @@ dependencies = [
|
||||
"gl_generator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "google-cloud-auth"
|
||||
version = "0.17.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e57a13fbacc5e9c41ded3ad8d0373175a6b7a6ad430d99e89d314ac121b7ab06"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"base64 0.21.7",
|
||||
"google-cloud-metadata",
|
||||
"google-cloud-token",
|
||||
"home",
|
||||
"jsonwebtoken 9.3.1",
|
||||
"reqwest 0.12.15",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 1.0.69",
|
||||
"time",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"urlencoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "google-cloud-gax"
|
||||
version = "0.19.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de13e62d7e0ffc3eb40a0113ddf753cf6ec741be739164442b08893db4f9bfca"
|
||||
dependencies = [
|
||||
"google-cloud-token",
|
||||
"http 1.3.1",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
"tokio-retry2",
|
||||
"tonic",
|
||||
"tower 0.4.13",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "google-cloud-googleapis"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "886aa8ec755382a1fdf4651f6e6ec01f2f3bf49f2cb0f068b9a74cafd574a715"
|
||||
dependencies = [
|
||||
"prost",
|
||||
"prost-types",
|
||||
"tonic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "google-cloud-metadata"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d901aeb453fd80e51d64df4ee005014f6cf39f2d736dd64f7239c132d9d39a6a"
|
||||
dependencies = [
|
||||
"reqwest 0.12.15",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "google-cloud-pubsub"
|
||||
version = "0.30.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bebc6e7327e49a66ffb40508c673b7643191bd6b509530193bda97f09272cdcf"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-stream",
|
||||
"google-cloud-auth",
|
||||
"google-cloud-gax",
|
||||
"google-cloud-googleapis",
|
||||
"google-cloud-token",
|
||||
"prost-types",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "google-cloud-token"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f49c12ba8b21d128a2ce8585955246977fbce4415f680ebf9199b6f9d6d725f"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gosyn"
|
||||
version = "0.2.9"
|
||||
@@ -5638,7 +5743,7 @@ dependencies = [
|
||||
"ipconfig",
|
||||
"moka",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.3",
|
||||
"rand 0.9.0",
|
||||
"resolv-conf",
|
||||
"serde",
|
||||
@@ -6427,6 +6532,21 @@ dependencies = [
|
||||
"simple_asn1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jsonwebtoken"
|
||||
version = "9.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"js-sys",
|
||||
"pem 3.0.5",
|
||||
"ring 0.17.14",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"simple_asn1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "junction"
|
||||
version = "1.2.0"
|
||||
@@ -7230,7 +7350,7 @@ dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
"loom",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.3",
|
||||
"portable-atomic",
|
||||
"rustc_version 0.4.1",
|
||||
"smallvec",
|
||||
@@ -7933,7 +8053,7 @@ dependencies = [
|
||||
"hyper 1.6.0",
|
||||
"itertools 0.13.0",
|
||||
"md-5 0.10.6",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.3",
|
||||
"percent-encoding",
|
||||
"quick-xml 0.36.2",
|
||||
"rand 0.8.5",
|
||||
@@ -8349,6 +8469,17 @@ version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core 0.8.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.3"
|
||||
@@ -8356,7 +8487,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
"parking_lot_core 0.9.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall 0.2.16",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8957,7 +9102,7 @@ dependencies = [
|
||||
"fnv",
|
||||
"lazy_static",
|
||||
"memchr",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.3",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
@@ -9111,7 +9256,7 @@ dependencies = [
|
||||
"ahash 0.8.11",
|
||||
"equivalent",
|
||||
"hashbrown 0.15.2",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -9359,6 +9504,15 @@ version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.3.5"
|
||||
@@ -9568,6 +9722,43 @@ dependencies = [
|
||||
"windows-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest-middleware"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64e8975513bd9a7a43aad01030e79b3498e05db14e9d945df6483e8cf9b8c4c4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"http 1.3.1",
|
||||
"reqwest 0.12.15",
|
||||
"serde",
|
||||
"thiserror 1.0.69",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest-retry"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29c73e4195a6bfbcb174b790d9b3407ab90646976c55de58a6515da25d851178"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"futures",
|
||||
"getrandom 0.2.15",
|
||||
"http 1.3.1",
|
||||
"hyper 1.6.0",
|
||||
"parking_lot 0.11.2",
|
||||
"reqwest 0.12.15",
|
||||
"reqwest-middleware",
|
||||
"retry-policies",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"wasm-timer",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "resolv-conf"
|
||||
version = "0.7.1"
|
||||
@@ -9577,6 +9768,15 @@ dependencies = [
|
||||
"hostname",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "retry-policies"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5875471e6cab2871bc150ecb8c727db5113c9338cc3354dc5ee3425b6aa40a1c"
|
||||
dependencies = [
|
||||
"rand 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rfc6979"
|
||||
version = "0.4.0"
|
||||
@@ -10945,7 +11145,7 @@ dependencies = [
|
||||
"crc",
|
||||
"crossbeam-queue",
|
||||
"either",
|
||||
"event-listener",
|
||||
"event-listener 5.4.0",
|
||||
"futures-core",
|
||||
"futures-intrusive",
|
||||
"futures-io",
|
||||
@@ -12264,7 +12464,7 @@ dependencies = [
|
||||
"bytes",
|
||||
"libc",
|
||||
"mio 1.0.3",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.3",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
@@ -12328,7 +12528,7 @@ dependencies = [
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.3",
|
||||
"percent-encoding",
|
||||
"phf",
|
||||
"pin-project-lite",
|
||||
@@ -12354,7 +12554,7 @@ dependencies = [
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.3",
|
||||
"percent-encoding",
|
||||
"phf",
|
||||
"pin-project-lite",
|
||||
@@ -12367,6 +12567,16 @@ dependencies = [
|
||||
"whoami",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-retry2"
|
||||
version = "0.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1264d076dd34560544a2799e40e457bd07c43d30f4a845686b031bcd8455c84f"
|
||||
dependencies = [
|
||||
"pin-project",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.24.1"
|
||||
@@ -12544,6 +12754,7 @@ dependencies = [
|
||||
"axum",
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"flate2",
|
||||
"h2 0.4.8",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
@@ -12564,6 +12775,7 @@ dependencies = [
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
"webpki-roots",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -12613,7 +12825,7 @@ dependencies = [
|
||||
"cookie 0.18.1",
|
||||
"futures-util",
|
||||
"http 1.3.1",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.3",
|
||||
"pin-project-lite",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
@@ -13460,6 +13672,21 @@ dependencies = [
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-timer"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"js-sys",
|
||||
"parking_lot 0.11.2",
|
||||
"pin-utils",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm_dep_analyzer"
|
||||
version = "0.2.0"
|
||||
@@ -13533,7 +13760,7 @@ dependencies = [
|
||||
"log",
|
||||
"naga",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.3",
|
||||
"profiling",
|
||||
"raw-window-handle",
|
||||
"ron",
|
||||
@@ -13575,7 +13802,7 @@ dependencies = [
|
||||
"ndk-sys",
|
||||
"objc",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.3",
|
||||
"profiling",
|
||||
"range-alloc",
|
||||
"raw-window-handle",
|
||||
@@ -13748,6 +13975,8 @@ dependencies = [
|
||||
"datafusion",
|
||||
"futures",
|
||||
"git-version",
|
||||
"google-cloud-googleapis",
|
||||
"google-cloud-pubsub",
|
||||
"half",
|
||||
"hex",
|
||||
"hf-hub",
|
||||
@@ -13755,7 +13984,7 @@ dependencies = [
|
||||
"http 1.3.1",
|
||||
"hyper 1.6.0",
|
||||
"itertools 0.14.0",
|
||||
"jsonwebtoken",
|
||||
"jsonwebtoken 8.3.0",
|
||||
"lazy_static",
|
||||
"magic-crypt",
|
||||
"mail-parser",
|
||||
@@ -13798,6 +14027,7 @@ dependencies = [
|
||||
"tokio-tar",
|
||||
"tokio-tungstenite",
|
||||
"tokio-util",
|
||||
"tonic",
|
||||
"tower 0.5.2",
|
||||
"tower-cookies",
|
||||
"tower-http",
|
||||
@@ -13813,8 +14043,10 @@ dependencies = [
|
||||
"windmill-indexer",
|
||||
"windmill-parser",
|
||||
"windmill-parser-py",
|
||||
"windmill-parser-py-imports",
|
||||
"windmill-parser-ts",
|
||||
"windmill-queue",
|
||||
"windmill-worker",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -13885,7 +14117,7 @@ dependencies = [
|
||||
"hyper 1.6.0",
|
||||
"indexmap 2.8.0",
|
||||
"itertools 0.14.0",
|
||||
"jsonwebtoken",
|
||||
"jsonwebtoken 8.3.0",
|
||||
"lazy_static",
|
||||
"magic-crypt",
|
||||
"mail-send",
|
||||
@@ -13901,6 +14133,8 @@ dependencies = [
|
||||
"rand 0.9.0",
|
||||
"regex",
|
||||
"reqwest 0.12.15",
|
||||
"reqwest-middleware",
|
||||
"reqwest-retry",
|
||||
"semver 1.0.26",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -14251,7 +14485,7 @@ dependencies = [
|
||||
"git-version",
|
||||
"hex",
|
||||
"itertools 0.14.0",
|
||||
"jsonwebtoken",
|
||||
"jsonwebtoken 8.3.0",
|
||||
"lazy_static",
|
||||
"mappable-rc",
|
||||
"mysql_async",
|
||||
@@ -14267,6 +14501,7 @@ dependencies = [
|
||||
"rand 0.9.0",
|
||||
"regex",
|
||||
"reqwest 0.12.15",
|
||||
"reqwest-middleware",
|
||||
"rust_decimal",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
||||
@@ -49,6 +49,7 @@ lto = "thin"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
agent_worker_server = ["windmill-api/agent_worker_server"]
|
||||
enterprise = ["windmill-worker/enterprise", "windmill-queue/enterprise", "windmill-api/enterprise", "dep:windmill-autoscaling", "windmill-autoscaling/enterprise", "windmill-git-sync/enterprise", "windmill-common/prometheus", "windmill-common/enterprise"]
|
||||
enterprise_saml = ["windmill-api/enterprise_saml", "oauth2"]
|
||||
stripe = ["windmill-api/stripe"]
|
||||
@@ -68,13 +69,14 @@ nats = ["windmill-api/nats"]
|
||||
otel = ["windmill-common/otel", "windmill-worker/otel"]
|
||||
dind = ["windmill-worker/dind"]
|
||||
websocket = ["windmill-api/websocket"]
|
||||
http_trigger = ["windmill-api/http_trigger"]
|
||||
postgres_trigger = ["windmill-api/postgres_trigger"]
|
||||
mqtt_trigger = ["windmill-api/mqtt_trigger"]
|
||||
sqs_trigger = ["windmill-api/sqs_trigger"]
|
||||
gcp_trigger = ["windmill-api/gcp_trigger"]
|
||||
smtp = ["windmill-api/smtp", "windmill-common/smtp"]
|
||||
license = ["windmill-api/license"]
|
||||
oauth2 = ["windmill-api/oauth2"]
|
||||
http_trigger = ["windmill-api/http_trigger"]
|
||||
zip = ["windmill-api/zip"]
|
||||
static_frontend = ["windmill-api/static_frontend"]
|
||||
scoped_cache = ["windmill-common/scoped_cache"]
|
||||
@@ -170,6 +172,9 @@ windmill-parser-graphql = { path = "./parsers/windmill-parser-graphql" }
|
||||
windmill-parser-php = { path = "./parsers/windmill-parser-php" }
|
||||
windmill-api-client = { path = "./windmill-api-client" }
|
||||
|
||||
reqwest-retry = "^0"
|
||||
reqwest-middleware = { version = "^0", features = ["json"] }
|
||||
|
||||
rustls = "0.23.0"
|
||||
memchr = "2.7.4"
|
||||
axum = { version = "^0.7", features = ["multipart"] }
|
||||
@@ -238,6 +243,8 @@ deno_runtime = { version = "0.198.0", features = ["transpile"] }
|
||||
deno_telemetry = "0.12.0"
|
||||
deno_error = "=0.5.5"
|
||||
|
||||
google-cloud-pubsub = "0.30.0"
|
||||
google-cloud-googleapis = {version = "0.16.1", features = ["pubsub"]}
|
||||
# TODO: remove once deno fixes the issue on their end
|
||||
# https://github.com/denoland/deno/issues/28557
|
||||
winapi = { version = "0.3.9", features = ["sysinfoapi"] }
|
||||
|
||||
@@ -1 +1 @@
|
||||
94cbac33756c1fba56da037456f44a4d294475b1
|
||||
85c37983ffb8f622458425c182613206625c6cee
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
-- Add down migration script here
|
||||
DROP TABLE gcp_trigger;
|
||||
DROP TYPE DELIVERY_MODE;
|
||||
@@ -0,0 +1,80 @@
|
||||
-- Add up migration script here
|
||||
|
||||
ALTER TYPE TRIGGER_KIND ADD VALUE IF NOT EXISTS 'gcp';
|
||||
CREATE TYPE DELIVERY_MODE AS ENUM ('push', 'pull');
|
||||
|
||||
CREATE TABLE gcp_trigger (
|
||||
gcp_resource_path VARCHAR(255) NOT NULL,
|
||||
topic_id VARCHAR(255) NOT NULL CHECK (
|
||||
CHAR_LENGTH(topic_id) BETWEEN 3 AND 255
|
||||
),
|
||||
subscription_id VARCHAR(255) NOT NULL CHECK (
|
||||
CHAR_LENGTH(subscription_id) BETWEEN 3 AND 255
|
||||
),
|
||||
delivery_type DELIVERY_MODE NOT NULL,
|
||||
delivery_config JSONB NULL CHECK (delivery_type != 'push'::DELIVERY_MODE OR (delivery_config IS NOT NULL)),
|
||||
path VARCHAR(255) NOT NULL,
|
||||
script_path VARCHAR(255) NOT NULL,
|
||||
is_flow BOOLEAN NOT NULL,
|
||||
workspace_id VARCHAR(50) NOT NULL,
|
||||
edited_by VARCHAR(50) NOT NULL,
|
||||
email VARCHAR(255) NOT NULL,
|
||||
edited_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
extra_perms JSONB NOT NULL DEFAULT '{}',
|
||||
server_id VARCHAR(50),
|
||||
last_server_ping TIMESTAMPTZ,
|
||||
error TEXT,
|
||||
enabled BOOLEAN NOT NULL,
|
||||
PRIMARY KEY (path, workspace_id)
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX unique_subscription_per_gcp_resource
|
||||
ON gcp_trigger (subscription_id, gcp_resource_path, workspace_id);
|
||||
|
||||
GRANT ALL ON gcp_trigger TO windmill_user;
|
||||
GRANT ALL ON gcp_trigger TO windmill_admin;
|
||||
|
||||
ALTER TABLE gcp_trigger ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
CREATE POLICY admin_policy ON gcp_trigger FOR ALL TO windmill_admin USING (true);
|
||||
|
||||
CREATE POLICY see_folder_extra_perms_user_select ON gcp_trigger FOR SELECT TO windmill_user
|
||||
USING (SPLIT_PART(gcp_trigger.path, '/', 1) = 'f' AND SPLIT_PART(gcp_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_read'), ',')::text[]));
|
||||
CREATE POLICY see_folder_extra_perms_user_insert ON gcp_trigger FOR INSERT TO windmill_user
|
||||
WITH CHECK (SPLIT_PART(gcp_trigger.path, '/', 1) = 'f' AND SPLIT_PART(gcp_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_write'), ',')::text[]));
|
||||
CREATE POLICY see_folder_extra_perms_user_update ON gcp_trigger FOR UPDATE TO windmill_user
|
||||
USING (SPLIT_PART(gcp_trigger.path, '/', 1) = 'f' AND SPLIT_PART(gcp_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_write'), ',')::text[]));
|
||||
CREATE POLICY see_folder_extra_perms_user_delete ON gcp_trigger FOR DELETE TO windmill_user
|
||||
USING (SPLIT_PART(gcp_trigger.path, '/', 1) = 'f' AND SPLIT_PART(gcp_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.folders_write'), ',')::text[]));
|
||||
|
||||
CREATE POLICY see_own ON gcp_trigger FOR ALL TO windmill_user
|
||||
USING (SPLIT_PART(gcp_trigger.path, '/', 1) = 'u' AND SPLIT_PART(gcp_trigger.path, '/', 2) = current_setting('session.user'));
|
||||
CREATE POLICY see_member ON gcp_trigger FOR ALL TO windmill_user
|
||||
USING (SPLIT_PART(gcp_trigger.path, '/', 1) = 'g' AND SPLIT_PART(gcp_trigger.path, '/', 2) = any(regexp_split_to_array(current_setting('session.groups'), ',')::text[]));
|
||||
|
||||
CREATE POLICY see_extra_perms_user_select ON gcp_trigger FOR SELECT TO windmill_user
|
||||
USING (extra_perms ? CONCAT('u/', current_setting('session.user')));
|
||||
CREATE POLICY see_extra_perms_user_insert ON gcp_trigger FOR INSERT TO windmill_user
|
||||
WITH CHECK ((extra_perms ->> CONCAT('u/', current_setting('session.user')))::boolean);
|
||||
CREATE POLICY see_extra_perms_user_update ON gcp_trigger FOR UPDATE TO windmill_user
|
||||
USING ((extra_perms ->> CONCAT('u/', current_setting('session.user')))::boolean);
|
||||
CREATE POLICY see_extra_perms_user_delete ON gcp_trigger FOR DELETE TO windmill_user
|
||||
USING ((extra_perms ->> CONCAT('u/', current_setting('session.user')))::boolean);
|
||||
|
||||
CREATE POLICY see_extra_perms_groups_select ON gcp_trigger FOR SELECT TO windmill_user
|
||||
USING (extra_perms ?| regexp_split_to_array(current_setting('session.pgroups'), ',')::text[]);
|
||||
CREATE POLICY see_extra_perms_groups_insert ON gcp_trigger FOR INSERT TO windmill_user
|
||||
WITH CHECK (exists(
|
||||
SELECT key, value FROM jsonb_each_text(extra_perms)
|
||||
WHERE SPLIT_PART(key, '/', 1) = 'g' AND key = ANY(regexp_split_to_array(current_setting('session.pgroups'), ',')::text[])
|
||||
AND value::boolean));
|
||||
CREATE POLICY see_extra_perms_groups_update ON gcp_trigger FOR UPDATE TO windmill_user
|
||||
USING (exists(
|
||||
SELECT key, value FROM jsonb_each_text(extra_perms)
|
||||
WHERE SPLIT_PART(key, '/', 1) = 'g' AND key = ANY(regexp_split_to_array(current_setting('session.pgroups'), ',')::text[])
|
||||
AND value::boolean));
|
||||
CREATE POLICY see_extra_perms_groups_delete ON gcp_trigger FOR DELETE TO windmill_user
|
||||
USING (exists(
|
||||
SELECT key, value FROM jsonb_each_text(extra_perms)
|
||||
WHERE SPLIT_PART(key, '/', 1) = 'g' AND key = ANY(regexp_split_to_array(current_setting('session.pgroups'), ',')::text[])
|
||||
AND value::boolean));
|
||||
@@ -0,0 +1 @@
|
||||
-- Add down migration script here
|
||||
@@ -0,0 +1,3 @@
|
||||
-- Add up migration script here
|
||||
ALTER TYPE job_trigger_kind ADD VALUE IF NOT EXISTS 'sqs';
|
||||
ALTER TYPE job_trigger_kind ADD VALUE IF NOT EXISTS 'gcp';
|
||||
@@ -0,0 +1 @@
|
||||
-- Add down migration script here
|
||||
284
backend/migrations/20250407124204_update_hub_sync_script.up.sql
Normal file
284
backend/migrations/20250407124204_update_hub_sync_script.up.sql
Normal file
@@ -0,0 +1,284 @@
|
||||
-- Add up migration script here
|
||||
-- Add up migration script here
|
||||
UPDATE script SET content = 'import * as wmill from "windmill-cli@1.481.0"
|
||||
|
||||
export async function main() {
|
||||
await wmill.hubPull({ workspace: "admins", token: process.env["WM_TOKEN"], baseUrl: globalThis.process.env["BASE_URL"] });
|
||||
}
|
||||
', language = 'bun',
|
||||
lock = '{
|
||||
"dependencies": {
|
||||
"windmill-cli": "1.481.0"
|
||||
}
|
||||
}
|
||||
//bun.lock
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"windmill-cli": "1.481.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@ayonli/jsext": ["@ayonli/jsext@1.6.0", "", { "dependencies": { "iconv-lite": "^0.6.3", "sudo-prompt": "^9.2.1", "ws": "^8.17.0", "zod": "^3.23.8" } }, "sha512-dMQuZJIVadEgQ6xp1Q5hRv2JfwANDwnElH6kZWuSjcnAjhvtCoQQ02CdOipfCd4cyrFpaI+8yBboiT9OkRaVyg=="],
|
||||
|
||||
"@deno/shim-deno": ["@deno/shim-deno@0.18.2", "", { "dependencies": { "@deno/shim-deno-test": "^0.5.0", "which": "^4.0.0" } }, "sha512-oQ0CVmOio63wlhwQF75zA4ioolPvOwAoK0yuzcS5bDC1JUvH3y1GS8xPh8EOpcoDQRU4FTG8OQfxhpR+c6DrzA=="],
|
||||
|
||||
"@deno/shim-deno-test": ["@deno/shim-deno-test@0.5.0", "", {}, "sha512-4nMhecpGlPi0cSzT67L+Tm+GOJqvuk8gqHBziqcUQOarnuIax1z96/gJHCSIz2Z0zhxE6Rzwb3IZXPtFh51j+w=="],
|
||||
|
||||
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag=="],
|
||||
|
||||
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.2", "", { "os": "android", "cpu": "arm" }, "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA=="],
|
||||
|
||||
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.2", "", { "os": "android", "cpu": "arm64" }, "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w=="],
|
||||
|
||||
"@esbuild/android-x64": ["@esbuild/android-x64@0.25.2", "", { "os": "android", "cpu": "x64" }, "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg=="],
|
||||
|
||||
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA=="],
|
||||
|
||||
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA=="],
|
||||
|
||||
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w=="],
|
||||
|
||||
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ=="],
|
||||
|
||||
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.2", "", { "os": "linux", "cpu": "arm" }, "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g=="],
|
||||
|
||||
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g=="],
|
||||
|
||||
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ=="],
|
||||
|
||||
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.2", "", { "os": "linux", "cpu": "none" }, "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w=="],
|
||||
|
||||
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.2", "", { "os": "linux", "cpu": "none" }, "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q=="],
|
||||
|
||||
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g=="],
|
||||
|
||||
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.2", "", { "os": "linux", "cpu": "none" }, "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw=="],
|
||||
|
||||
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q=="],
|
||||
|
||||
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.2", "", { "os": "linux", "cpu": "x64" }, "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg=="],
|
||||
|
||||
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.2", "", { "os": "none", "cpu": "arm64" }, "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw=="],
|
||||
|
||||
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.2", "", { "os": "none", "cpu": "x64" }, "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg=="],
|
||||
|
||||
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg=="],
|
||||
|
||||
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw=="],
|
||||
|
||||
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA=="],
|
||||
|
||||
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q=="],
|
||||
|
||||
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg=="],
|
||||
|
||||
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.2", "", { "os": "win32", "cpu": "x64" }, "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA=="],
|
||||
|
||||
"accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
|
||||
|
||||
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
||||
|
||||
"body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="],
|
||||
|
||||
"brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
|
||||
|
||||
"bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="],
|
||||
|
||||
"bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
|
||||
|
||||
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
|
||||
|
||||
"call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="],
|
||||
|
||||
"content-disposition": ["content-disposition@1.0.0", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg=="],
|
||||
|
||||
"content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="],
|
||||
|
||||
"cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
|
||||
|
||||
"cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
|
||||
|
||||
"core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="],
|
||||
|
||||
"debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
|
||||
|
||||
"default-browser": ["default-browser@5.2.1", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg=="],
|
||||
|
||||
"default-browser-id": ["default-browser-id@5.0.0", "", {}, "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA=="],
|
||||
|
||||
"define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="],
|
||||
|
||||
"depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="],
|
||||
|
||||
"diff": ["diff@7.0.0", "", {}, "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw=="],
|
||||
|
||||
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
|
||||
|
||||
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
|
||||
|
||||
"encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="],
|
||||
|
||||
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
|
||||
|
||||
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
|
||||
|
||||
"es-main": ["es-main@1.3.0", "", {}, "sha512-AzORKdz1Zt97TzbYQnIrI3ZiibWpRXUfpo/w0xOJ20GpNYd2bd3MU9m31zS/aJ1TJl6JfLTok83Y8HjNunYT0A=="],
|
||||
|
||||
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
|
||||
|
||||
"esbuild": ["esbuild@0.25.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.2", "@esbuild/android-arm": "0.25.2", "@esbuild/android-arm64": "0.25.2", "@esbuild/android-x64": "0.25.2", "@esbuild/darwin-arm64": "0.25.2", "@esbuild/darwin-x64": "0.25.2", "@esbuild/freebsd-arm64": "0.25.2", "@esbuild/freebsd-x64": "0.25.2", "@esbuild/linux-arm": "0.25.2", "@esbuild/linux-arm64": "0.25.2", "@esbuild/linux-ia32": "0.25.2", "@esbuild/linux-loong64": "0.25.2", "@esbuild/linux-mips64el": "0.25.2", "@esbuild/linux-ppc64": "0.25.2", "@esbuild/linux-riscv64": "0.25.2", "@esbuild/linux-s390x": "0.25.2", "@esbuild/linux-x64": "0.25.2", "@esbuild/netbsd-arm64": "0.25.2", "@esbuild/netbsd-x64": "0.25.2", "@esbuild/openbsd-arm64": "0.25.2", "@esbuild/openbsd-x64": "0.25.2", "@esbuild/sunos-x64": "0.25.2", "@esbuild/win32-arm64": "0.25.2", "@esbuild/win32-ia32": "0.25.2", "@esbuild/win32-x64": "0.25.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ=="],
|
||||
|
||||
"escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="],
|
||||
|
||||
"etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="],
|
||||
|
||||
"express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="],
|
||||
|
||||
"finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="],
|
||||
|
||||
"forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
|
||||
|
||||
"fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="],
|
||||
|
||||
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
|
||||
|
||||
"get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
|
||||
|
||||
"get-port": ["get-port@7.1.0", "", {}, "sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw=="],
|
||||
|
||||
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
|
||||
|
||||
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
|
||||
|
||||
"has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
|
||||
|
||||
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
|
||||
|
||||
"http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="],
|
||||
|
||||
"iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
|
||||
|
||||
"immediate": ["immediate@3.0.6", "", {}, "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="],
|
||||
|
||||
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
|
||||
|
||||
"ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
|
||||
|
||||
"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": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="],
|
||||
|
||||
"is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="],
|
||||
|
||||
"is-wsl": ["is-wsl@3.1.0", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw=="],
|
||||
|
||||
"isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="],
|
||||
|
||||
"isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="],
|
||||
|
||||
"jszip": ["jszip@3.7.1", "", { "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", "readable-stream": "~2.3.6", "set-immediate-shim": "~1.0.1" } }, "sha512-ghL0tz1XG9ZEmRMcEN2vt7xabrDdqHHeykgARpmZ0BiIctWxM47Vt63ZO2dnp4QYt/xJVLLy5Zv1l/xRdh2byg=="],
|
||||
|
||||
"lie": ["lie@3.3.0", "", { "dependencies": { "immediate": "~3.0.5" } }, "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ=="],
|
||||
|
||||
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
||||
|
||||
"media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="],
|
||||
|
||||
"merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="],
|
||||
|
||||
"mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
||||
|
||||
"mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="],
|
||||
|
||||
"minimatch": ["minimatch@10.0.1", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
|
||||
|
||||
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
|
||||
|
||||
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
|
||||
|
||||
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
|
||||
|
||||
"open": ["open@10.1.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "is-wsl": "^3.1.0" } }, "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw=="],
|
||||
|
||||
"pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="],
|
||||
|
||||
"parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="],
|
||||
|
||||
"path-to-regexp": ["path-to-regexp@8.2.0", "", {}, "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ=="],
|
||||
|
||||
"process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="],
|
||||
|
||||
"proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
|
||||
|
||||
"qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="],
|
||||
|
||||
"range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="],
|
||||
|
||||
"raw-body": ["raw-body@3.0.0", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.6.3", "unpipe": "1.0.0" } }, "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g=="],
|
||||
|
||||
"readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
|
||||
|
||||
"router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
|
||||
|
||||
"run-applescript": ["run-applescript@7.0.0", "", {}, "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A=="],
|
||||
|
||||
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
||||
|
||||
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
|
||||
|
||||
"send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="],
|
||||
|
||||
"serve-static": ["serve-static@2.2.0", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="],
|
||||
|
||||
"set-immediate-shim": ["set-immediate-shim@1.0.1", "", {}, "sha512-Li5AOqrZWCVA2n5kryzEmqai6bKSIvpz5oUJHPVj6+dsbD3X1ixtsY5tEnsaNpH3pFAHmG8eIHUrtEtohrg+UQ=="],
|
||||
|
||||
"setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
|
||||
|
||||
"side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="],
|
||||
|
||||
"side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="],
|
||||
|
||||
"side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="],
|
||||
|
||||
"side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="],
|
||||
|
||||
"statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="],
|
||||
|
||||
"string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
|
||||
|
||||
"sudo-prompt": ["sudo-prompt@9.2.1", "", {}, "sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw=="],
|
||||
|
||||
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
|
||||
|
||||
"type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
|
||||
|
||||
"unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="],
|
||||
|
||||
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
|
||||
|
||||
"vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
|
||||
|
||||
"which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="],
|
||||
|
||||
"windmill-cli": ["windmill-cli@1.481.0", "", { "dependencies": { "@ayonli/jsext": "*", "@deno/shim-deno": "~0.18.0", "diff": "*", "es-main": "*", "esbuild": "*", "express": "*", "get-port": "7.1.0", "jszip": "3.7.1", "minimatch": "*", "open": "*", "ws": "*" }, "bin": { "wmill": "esm/main.js" } }, "sha512-nIIrt+/+TqeyHlgcDnPMTBH3CZX4TMVwxy2UFD+5lOI5OY9JOtCpWk5UPn6BOs6fw1DG0MIBJG7AhCuPelfSiQ=="],
|
||||
|
||||
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
|
||||
|
||||
"ws": ["ws@8.18.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w=="],
|
||||
|
||||
"zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="],
|
||||
|
||||
"readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
|
||||
|
||||
"string_decoder/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
|
||||
}
|
||||
}'
|
||||
WHERE hash = -28028598712388162 AND workspace_id = 'admins';
|
||||
1
backend/migrations/20250409093642_add_grant.down.sql
Normal file
1
backend/migrations/20250409093642_add_grant.down.sql
Normal file
@@ -0,0 +1 @@
|
||||
-- Add down migration script here
|
||||
3
backend/migrations/20250409093642_add_grant.up.sql
Normal file
3
backend/migrations/20250409093642_add_grant.up.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
-- Add up migration script here
|
||||
GRANT ALL on workspace_runnable_dependencies TO windmill_user;
|
||||
GRANT ALL on workspace_runnable_dependencies TO windmill_admin;
|
||||
@@ -45,7 +45,7 @@ pub fn parse_powershell_sig(code: &str) -> anyhow::Result<MainArgSignature> {
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref RE_BASH: Regex = Regex::new(r#"(?m)^(\w+)="\$(?:(\d+)|\{(\d+):-(.*)\})"(?:[\t ]*)?(?:#.*)?$"#).unwrap();
|
||||
static ref RE_BASH: Regex = Regex::new(r#"(?m)^(\w+)="\$(?:(\d+)|\{(\d+)\}|\{(\d+):-(.*)\})"(?:[\t ]*)?(?:#.*)?$"#).unwrap();
|
||||
|
||||
pub static ref RE_POWERSHELL_PARAM: Regex = Regex::new(r#"(?m)param[\t ]*\(([^)]*)\)"#).unwrap();
|
||||
static ref RE_POWERSHELL_ARGS: Regex = Regex::new(r#"(?:\[(\w+)\])?\$(\w+)[\t ]*(?:=[\t ]*(?:(?:(?:"|')([^"\n\r\$]*)(?:"|'))|([\d.]+)))?"#).unwrap();
|
||||
@@ -57,11 +57,12 @@ fn parse_bash_file(code: &str) -> anyhow::Result<Option<Vec<Arg>>> {
|
||||
hm.insert(
|
||||
cap.get(2)
|
||||
.or(cap.get(3))
|
||||
.or(cap.get(4))
|
||||
.and_then(|x| x.as_str().parse::<i32>().ok())
|
||||
.ok_or_else(|| anyhow!("Impossible to parse arg digit"))?,
|
||||
(
|
||||
cap[1].to_string(),
|
||||
cap.get(4).map(|x| x.as_str().to_string()),
|
||||
cap.get(5).map(|x| x.as_str().to_string()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -162,4 +162,4 @@ pub fn parse_java(code: &str) -> String {
|
||||
wrap_sig(windmill_parser_java::parse_java_signature(code))
|
||||
}
|
||||
|
||||
// KJQXZ
|
||||
// for related places search: ADD_NEW_LANG
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@ use std::{
|
||||
|
||||
use chrono::{NaiveDateTime, Utc};
|
||||
use futures::{stream::FuturesUnordered, StreamExt};
|
||||
use serde::{de::DeserializeOwned, Deserializer};
|
||||
use serde::de::DeserializeOwned;
|
||||
use sqlx::{Pool, Postgres};
|
||||
use tokio::{
|
||||
join,
|
||||
@@ -34,7 +34,8 @@ use windmill_common::ee::{jobs_waiting_alerts, worker_groups_alerts};
|
||||
#[cfg(feature = "oauth2")]
|
||||
use windmill_common::global_settings::OAUTH_SETTING;
|
||||
use windmill_common::{
|
||||
ee::CriticalErrorChannel, error, flow_status::{FlowStatus, FlowStatusModule}, global_settings::{
|
||||
utils::empty_string_as_none,
|
||||
agent_workers::DECODED_AGENT_TOKEN, auth::create_token_for_owner, ee::CriticalErrorChannel, error, flow_status::{FlowStatus, FlowStatusModule}, global_settings::{
|
||||
BASE_URL_SETTING, BUNFIG_INSTALL_SCOPES_SETTING, CRITICAL_ALERT_MUTE_UI_SETTING,
|
||||
CRITICAL_ERROR_CHANNELS_SETTING, DEFAULT_TAGS_PER_WORKSPACE_SETTING,
|
||||
DEFAULT_TAGS_WORKSPACES_SETTING, EXPOSE_DEBUG_METRICS_SETTING, EXPOSE_METRICS_SETTING,
|
||||
@@ -45,14 +46,12 @@ use windmill_common::{
|
||||
REQUIRE_PREEXISTING_USER_FOR_OAUTH_SETTING, RETENTION_PERIOD_SECS_SETTING,
|
||||
SAML_METADATA_SETTING, SCIM_TOKEN_SETTING, TIMEOUT_WAIT_RESULT_SETTING,
|
||||
}, indexer::load_indexer_config, jobs::QueuedJob, jwt::JWT_SECRET, oauth2::REQUIRE_PREEXISTING_USER_FOR_OAUTH, server::load_smtp_config, tracing_init::JSON_FMT, users::truncate_token, utils::{now_from_db, rd_string, report_critical_error, Mode}, worker::{
|
||||
load_worker_config, make_pull_query, make_suspended_pull_query, reload_custom_tags_setting,
|
||||
update_min_version, DEFAULT_TAGS_PER_WORKSPACE, DEFAULT_TAGS_WORKSPACES, INDEXER_CONFIG,
|
||||
SMTP_CONFIG, TMP_DIR, WORKER_CONFIG, WORKER_GROUP,
|
||||
}, KillpillSender, BASE_URL, CRITICAL_ALERT_MUTE_UI_ENABLED, CRITICAL_ERROR_CHANNELS, DB, DEFAULT_HUB_BASE_URL, HUB_BASE_URL, JOB_RETENTION_SECS, METRICS_DEBUG_ENABLED, METRICS_ENABLED, MONITOR_LOGS_ON_OBJECT_STORE, OTEL_LOGS_ENABLED, OTEL_METRICS_ENABLED, OTEL_TRACING_ENABLED, SERVICE_LOG_RETENTION_SECS
|
||||
load_worker_config, reload_custom_tags_setting, store_pull_query, store_suspended_pull_query, update_min_version, Connection, DEFAULT_TAGS_PER_WORKSPACE, DEFAULT_TAGS_WORKSPACES, INDEXER_CONFIG, SCRIPT_TOKEN_EXPIRY, SMTP_CONFIG, TMP_DIR, WORKER_CONFIG, WORKER_GROUP
|
||||
}, KillpillSender, BASE_URL, CRITICAL_ALERT_MUTE_UI_ENABLED, CRITICAL_ERROR_CHANNELS, DB, DEFAULT_HUB_BASE_URL, HUB_BASE_URL, JOB_RETENTION_SECS, METRICS_DEBUG_ENABLED, METRICS_ENABLED, MONITOR_LOGS_ON_OBJECT_STORE, OTEL_LOGS_ENABLED, OTEL_METRICS_ENABLED, OTEL_TRACING_ENABLED, SERVICE_LOG_RETENTION_SECS,
|
||||
};
|
||||
use windmill_queue::{cancel_job, MiniPulledJob};
|
||||
use windmill_queue::{cancel_job, MiniPulledJob, SameWorkerPayload};
|
||||
use windmill_worker::{
|
||||
create_token_for_owner, handle_job_error, AuthedClient, SameWorkerPayload, SameWorkerSender, SendResult, BUNFIG_INSTALL_SCOPES, INSTANCE_PYTHON_VERSION, JOB_DEFAULT_TIMEOUT, KEEP_JOB_DIR, MAVEN_REPOS, NO_DEFAULT_MAVEN, NPM_CONFIG_REGISTRY, NUGET_CONFIG, PIP_EXTRA_INDEX_URL, PIP_INDEX_URL, SCRIPT_TOKEN_EXPIRY
|
||||
handle_job_error, AuthedClient, JobCompletedSender, SameWorkerSender, BUNFIG_INSTALL_SCOPES, INSTANCE_PYTHON_VERSION, JOB_DEFAULT_TIMEOUT, KEEP_JOB_DIR, MAVEN_REPOS, NO_DEFAULT_MAVEN, NPM_CONFIG_REGISTRY, NUGET_CONFIG, PIP_EXTRA_INDEX_URL, PIP_INDEX_URL
|
||||
};
|
||||
|
||||
#[cfg(feature = "parquet")]
|
||||
@@ -113,88 +112,120 @@ lazy_static::lazy_static! {
|
||||
.unwrap_or(false);
|
||||
|
||||
|
||||
|
||||
static ref QUEUE_COUNT_TAGS: Arc<RwLock<Vec<String>>> = Arc::new(RwLock::new(Vec::new()));
|
||||
static ref DISABLE_CONCURRENCY_LIMIT: bool = std::env::var("DISABLE_CONCURRENCY_LIMIT").is_ok_and(|s| s == "true");
|
||||
|
||||
}
|
||||
|
||||
pub async fn initial_load(
|
||||
db: &Pool<Postgres>,
|
||||
conn: &Connection,
|
||||
tx: KillpillSender,
|
||||
worker_mode: bool,
|
||||
server_mode: bool,
|
||||
#[cfg(feature = "parquet")] disable_s3_store: bool,
|
||||
) {
|
||||
if let Err(e) = load_metrics_enabled(db).await {
|
||||
if let Err(e) = reload_base_url_setting(&conn).await {
|
||||
tracing::error!("Error loading base url: {:?}", e)
|
||||
}
|
||||
|
||||
if let Some(db) = conn.as_sql() {
|
||||
if let Err(e) = reload_critical_error_channels_setting(&db).await {
|
||||
tracing::error!("Could loading critical error emails setting: {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if let Err(e) = load_metrics_enabled(conn).await {
|
||||
tracing::error!("Error loading expose metrics: {e:#}");
|
||||
}
|
||||
|
||||
if let Err(e) = load_metrics_debug_enabled(db).await {
|
||||
if let Err(e) = load_metrics_debug_enabled(conn).await {
|
||||
tracing::error!("Error loading expose debug metrics: {e:#}");
|
||||
}
|
||||
|
||||
if let Err(e) = reload_critical_alert_mute_ui_setting(db).await {
|
||||
if let Err(e) = reload_critical_alert_mute_ui_setting(conn).await {
|
||||
tracing::error!("Error loading critical alert mute ui setting: {e:#}");
|
||||
}
|
||||
|
||||
if let Err(e) = load_tag_per_workspace_enabled(db).await {
|
||||
tracing::error!("Error loading default tag per workpsace: {e:#}");
|
||||
}
|
||||
if let Some(db) = conn.as_sql() {
|
||||
if let Err(e) = load_tag_per_workspace_enabled(db).await {
|
||||
tracing::error!("Error loading default tag per workpsace: {e:#}");
|
||||
}
|
||||
|
||||
if let Err(e) = load_tag_per_workspace_workspaces(db).await {
|
||||
tracing::error!("Error loading default tag per workpsace workspaces: {e:#}");
|
||||
if let Err(e) = load_tag_per_workspace_workspaces(db).await {
|
||||
tracing::error!("Error loading default tag per workpsace workspaces: {e:#}");
|
||||
}
|
||||
}
|
||||
|
||||
if server_mode {
|
||||
load_require_preexisting_user(db).await;
|
||||
if let Some(db) = conn.as_sql() {
|
||||
load_require_preexisting_user(db).await;
|
||||
}
|
||||
}
|
||||
|
||||
if worker_mode {
|
||||
load_keep_job_dir(db).await;
|
||||
reload_worker_config(&db, tx, false).await;
|
||||
load_keep_job_dir(conn).await;
|
||||
match conn {
|
||||
Connection::Sql(db) => {
|
||||
reload_worker_config(&db, tx, false).await;
|
||||
}
|
||||
Connection::Http(_) => {
|
||||
// TODO: reload worker config from http
|
||||
WORKER_CONFIG.write().await.worker_tags = DECODED_AGENT_TOKEN.as_ref().map(|x| x.tags.clone()).unwrap_or_default();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if let Err(e) = reload_custom_tags_setting(db).await {
|
||||
tracing::error!("Error reloading custom tags: {:?}", e)
|
||||
}
|
||||
|
||||
if let Err(e) = reload_hub_base_url_setting(db, server_mode).await {
|
||||
if let Err(e) = reload_hub_base_url_setting(conn, server_mode).await {
|
||||
tracing::error!("Error reloading hub base url: {:?}", e)
|
||||
}
|
||||
|
||||
if let Err(e) = reload_jwt_secret_setting(&db).await {
|
||||
tracing::error!("Could not reload jwt secret setting: {:?}", e);
|
||||
if let Some(db) = conn.as_sql() {
|
||||
if let Err(e) = reload_jwt_secret_setting(db).await {
|
||||
tracing::error!("Could not reload jwt secret setting: {:?}", e);
|
||||
}
|
||||
|
||||
if let Err(e) = reload_custom_tags_setting(db).await {
|
||||
tracing::error!("Error reloading custom tags: {:?}", e)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(feature = "parquet")]
|
||||
if !disable_s3_store {
|
||||
reload_s3_cache_setting(&db).await;
|
||||
if let Some(db) = conn.as_sql() {
|
||||
reload_s3_cache_setting(db).await;
|
||||
}
|
||||
}
|
||||
|
||||
reload_smtp_config(&db).await;
|
||||
if let Some(db) = conn.as_sql() {
|
||||
reload_smtp_config(db).await;
|
||||
}
|
||||
|
||||
if server_mode {
|
||||
reload_retention_period_setting(&db).await;
|
||||
reload_request_size(&db).await;
|
||||
reload_saml_metadata_setting(&db).await;
|
||||
reload_scim_token_setting(&db).await;
|
||||
reload_retention_period_setting(&conn).await;
|
||||
reload_request_size(&conn).await;
|
||||
reload_saml_metadata_setting(&conn).await;
|
||||
reload_scim_token_setting(&conn).await;
|
||||
}
|
||||
|
||||
if worker_mode {
|
||||
reload_job_default_timeout_setting(&db).await;
|
||||
reload_extra_pip_index_url_setting(&db).await;
|
||||
reload_pip_index_url_setting(&db).await;
|
||||
reload_npm_config_registry_setting(&db).await;
|
||||
reload_bunfig_install_scopes_setting(&db).await;
|
||||
reload_instance_python_version_setting(&db).await;
|
||||
reload_nuget_config_setting(&db).await;
|
||||
reload_maven_repos_setting(&db).await;
|
||||
reload_no_default_maven_setting(&db).await;
|
||||
reload_job_default_timeout_setting(&conn).await;
|
||||
reload_extra_pip_index_url_setting(&conn).await;
|
||||
reload_pip_index_url_setting(&conn).await;
|
||||
reload_npm_config_registry_setting(&conn).await;
|
||||
reload_bunfig_install_scopes_setting(&conn).await;
|
||||
reload_instance_python_version_setting(&conn).await;
|
||||
reload_nuget_config_setting(&conn).await;
|
||||
reload_maven_repos_setting(&conn).await;
|
||||
reload_no_default_maven_setting(&conn).await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn load_metrics_enabled(db: &DB) -> error::Result<()> {
|
||||
let metrics_enabled = load_value_from_global_settings(db, EXPOSE_METRICS_SETTING).await;
|
||||
pub async fn load_metrics_enabled(conn: &Connection) -> error::Result<()> {
|
||||
let metrics_enabled = load_value_from_global_settings_with_conn(conn, EXPOSE_METRICS_SETTING, true).await;
|
||||
match metrics_enabled {
|
||||
Ok(Some(serde_json::Value::Bool(t))) => METRICS_ENABLED.store(t, Ordering::Relaxed),
|
||||
_ => (),
|
||||
@@ -202,14 +233,6 @@ pub async fn load_metrics_enabled(db: &DB) -> error::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn empty_string_as_none<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let option = <Option<String> as serde::Deserialize>::deserialize(deserializer)?;
|
||||
Ok(option.filter(|s| !s.is_empty()))
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
struct OtelSetting {
|
||||
metrics_enabled: Option<bool>,
|
||||
@@ -317,9 +340,9 @@ pub async fn load_tag_per_workspace_workspaces(db: &DB) -> error::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn reload_critical_alert_mute_ui_setting(db: &DB) -> error::Result<()> {
|
||||
pub async fn reload_critical_alert_mute_ui_setting(conn: &Connection) -> error::Result<()> {
|
||||
if let Ok(Some(serde_json::Value::Bool(t))) =
|
||||
load_value_from_global_settings(db, CRITICAL_ALERT_MUTE_UI_SETTING).await
|
||||
load_value_from_global_settings_with_conn(conn, CRITICAL_ALERT_MUTE_UI_SETTING, true).await
|
||||
{
|
||||
CRITICAL_ALERT_MUTE_UI_ENABLED.store(t, Ordering::Relaxed);
|
||||
|
||||
@@ -327,8 +350,8 @@ pub async fn reload_critical_alert_mute_ui_setting(db: &DB) -> error::Result<()>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn load_metrics_debug_enabled(db: &DB) -> error::Result<()> {
|
||||
let metrics_enabled = load_value_from_global_settings(db, EXPOSE_DEBUG_METRICS_SETTING).await;
|
||||
pub async fn load_metrics_debug_enabled(conn: &Connection) -> error::Result<()> {
|
||||
let metrics_enabled = load_value_from_global_settings_with_conn(conn, EXPOSE_DEBUG_METRICS_SETTING, true).await;
|
||||
match metrics_enabled {
|
||||
Ok(Some(serde_json::Value::Bool(t))) => {
|
||||
METRICS_DEBUG_ENABLED.store(t, Ordering::Relaxed);
|
||||
@@ -479,8 +502,8 @@ fn get_worker_group(mode: &Mode) -> Option<String> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_logs_to_object_store(db: &DB, hostname: &str, mode: &Mode) {
|
||||
let db = db.clone();
|
||||
pub fn send_logs_to_object_store(conn: &Connection, hostname: &str, mode: &Mode) {
|
||||
let conn = conn.clone();
|
||||
let hostname = hostname.to_string();
|
||||
let mode = mode.clone();
|
||||
let worker_group = get_worker_group(&mode);
|
||||
@@ -495,7 +518,7 @@ pub fn send_logs_to_object_store(db: &DB, hostname: &str, mode: &Mode) {
|
||||
&hostname,
|
||||
&mode,
|
||||
&worker_group,
|
||||
&db,
|
||||
&conn,
|
||||
snd_highest_file,
|
||||
false,
|
||||
)
|
||||
@@ -504,11 +527,11 @@ pub fn send_logs_to_object_store(db: &DB, hostname: &str, mode: &Mode) {
|
||||
});
|
||||
}
|
||||
|
||||
pub async fn send_current_log_file_to_object_store(db: &DB, hostname: &str, mode: &Mode) {
|
||||
pub async fn send_current_log_file_to_object_store(conn: &Connection, hostname: &str, mode: &Mode) {
|
||||
tracing::info!("Sending current log file to object store");
|
||||
let (highest_file, _) = find_two_highest_files(hostname).await;
|
||||
let worker_group = get_worker_group(&mode);
|
||||
send_log_file_to_object_store(hostname, mode, &worker_group, db, highest_file, true).await;
|
||||
send_log_file_to_object_store(hostname, mode, &worker_group, conn, highest_file, true).await;
|
||||
}
|
||||
|
||||
fn get_now_and_str() -> (NaiveDateTime, String) {
|
||||
@@ -528,7 +551,7 @@ async fn send_log_file_to_object_store(
|
||||
hostname: &str,
|
||||
mode: &Mode,
|
||||
worker_group: &Option<String>,
|
||||
db: &Pool<Postgres>,
|
||||
conn: &Connection,
|
||||
snd_highest_file: Option<String>,
|
||||
use_now: bool,
|
||||
) {
|
||||
@@ -588,18 +611,23 @@ async fn send_log_file_to_object_store(
|
||||
|
||||
let (ok_lines, err_lines) = read_log_counters(ts_str);
|
||||
|
||||
if let Err(e) = sqlx::query!("INSERT INTO log_file (hostname, mode, worker_group, log_ts, file_path, ok_lines, err_lines, json_fmt) VALUES ($1, $2::text::LOG_MODE, $3, $4, $5, $6, $7, $8)",
|
||||
hostname, mode.to_string(), worker_group.clone(), ts, highest_file, ok_lines as i64, err_lines as i64, *JSON_FMT)
|
||||
.execute(db)
|
||||
.await {
|
||||
tracing::error!("Error inserting log file: {:?}", e);
|
||||
} else {
|
||||
if let Err(e) = LAST_LOG_FILE_SENT.lock().map(|mut last_log_file_sent| {
|
||||
last_log_file_sent.replace(ts);
|
||||
}) {
|
||||
tracing::error!("Error updating last log file sent: {:?}", e);
|
||||
if let Some(db) = conn.as_sql() {
|
||||
if let Err(e) = sqlx::query!("INSERT INTO log_file (hostname, mode, worker_group, log_ts, file_path, ok_lines, err_lines, json_fmt) VALUES ($1, $2::text::LOG_MODE, $3, $4, $5, $6, $7, $8)",
|
||||
hostname, mode.to_string(), worker_group.clone(), ts, highest_file, ok_lines as i64, err_lines as i64, *JSON_FMT)
|
||||
.execute(db)
|
||||
.await {
|
||||
tracing::error!("Error inserting log file: {:?}", e);
|
||||
} else {
|
||||
if let Err(e) = LAST_LOG_FILE_SENT.lock().map(|mut last_log_file_sent| {
|
||||
last_log_file_sent.replace(ts);
|
||||
}) {
|
||||
tracing::error!("Error updating last log file sent: {:?}", e);
|
||||
}
|
||||
tracing::info!("Log file sent: {}", highest_file);
|
||||
}
|
||||
tracing::info!("Log file sent: {}", highest_file);
|
||||
} else {
|
||||
// tracing::warn!("Not sending log file to object store in agent mode");
|
||||
()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -622,8 +650,8 @@ fn read_log_counters(ts_str: String) -> (usize, usize) {
|
||||
(ok_lines, err_lines)
|
||||
}
|
||||
|
||||
pub async fn load_keep_job_dir(db: &DB) {
|
||||
let value = load_value_from_global_settings(db, KEEP_JOB_DIR_SETTING).await;
|
||||
pub async fn load_keep_job_dir(conn: &Connection) {
|
||||
let value = load_value_from_global_settings_with_conn(conn, KEEP_JOB_DIR_SETTING, true).await;
|
||||
match value {
|
||||
Ok(Some(serde_json::Value::Bool(t))) => KEEP_JOB_DIR.store(t, Ordering::Relaxed),
|
||||
Err(e) => {
|
||||
@@ -890,23 +918,23 @@ async fn delete_log_files_from_disk_and_store(
|
||||
let _: Vec<_> = delete_futures.collect().await;
|
||||
}
|
||||
|
||||
pub async fn reload_scim_token_setting(db: &DB) {
|
||||
reload_option_setting_with_tracing(db, SCIM_TOKEN_SETTING, "SCIM_TOKEN", SCIM_TOKEN.clone())
|
||||
pub async fn reload_scim_token_setting(conn: &Connection) {
|
||||
reload_option_setting_with_tracing(conn, SCIM_TOKEN_SETTING, "SCIM_TOKEN", SCIM_TOKEN.clone())
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn reload_timeout_wait_result_setting(db: &DB) {
|
||||
pub async fn reload_timeout_wait_result_setting(conn: &Connection) {
|
||||
reload_option_setting_with_tracing(
|
||||
db,
|
||||
conn,
|
||||
TIMEOUT_WAIT_RESULT_SETTING,
|
||||
"TIMEOUT_WAIT_RESULT",
|
||||
TIMEOUT_WAIT_RESULT.clone(),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
pub async fn reload_saml_metadata_setting(db: &DB) {
|
||||
pub async fn reload_saml_metadata_setting(conn: &Connection) {
|
||||
reload_option_setting_with_tracing(
|
||||
db,
|
||||
conn,
|
||||
SAML_METADATA_SETTING,
|
||||
"SAML_METADATA",
|
||||
SAML_METADATA.clone(),
|
||||
@@ -914,9 +942,9 @@ pub async fn reload_saml_metadata_setting(db: &DB) {
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn reload_extra_pip_index_url_setting(db: &DB) {
|
||||
pub async fn reload_extra_pip_index_url_setting(conn: &Connection) {
|
||||
reload_option_setting_with_tracing(
|
||||
db,
|
||||
conn,
|
||||
EXTRA_PIP_INDEX_URL_SETTING,
|
||||
"PIP_EXTRA_INDEX_URL",
|
||||
PIP_EXTRA_INDEX_URL.clone(),
|
||||
@@ -924,9 +952,9 @@ pub async fn reload_extra_pip_index_url_setting(db: &DB) {
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn reload_pip_index_url_setting(db: &DB) {
|
||||
pub async fn reload_pip_index_url_setting(conn: &Connection) {
|
||||
reload_option_setting_with_tracing(
|
||||
db,
|
||||
conn,
|
||||
PIP_INDEX_URL_SETTING,
|
||||
"PIP_INDEX_URL",
|
||||
PIP_INDEX_URL.clone(),
|
||||
@@ -934,9 +962,9 @@ pub async fn reload_pip_index_url_setting(db: &DB) {
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn reload_instance_python_version_setting(db: &DB) {
|
||||
pub async fn reload_instance_python_version_setting(conn: &Connection) {
|
||||
reload_option_setting_with_tracing(
|
||||
db,
|
||||
conn,
|
||||
INSTANCE_PYTHON_VERSION_SETTING,
|
||||
"INSTANCE_PYTHON_VERSION",
|
||||
INSTANCE_PYTHON_VERSION.clone(),
|
||||
@@ -944,9 +972,9 @@ pub async fn reload_instance_python_version_setting(db: &DB) {
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn reload_npm_config_registry_setting(db: &DB) {
|
||||
pub async fn reload_npm_config_registry_setting(conn: &Connection) {
|
||||
reload_option_setting_with_tracing(
|
||||
db,
|
||||
conn,
|
||||
NPM_CONFIG_REGISTRY_SETTING,
|
||||
"NPM_CONFIG_REGISTRY",
|
||||
NPM_CONFIG_REGISTRY.clone(),
|
||||
@@ -954,9 +982,9 @@ pub async fn reload_npm_config_registry_setting(db: &DB) {
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn reload_bunfig_install_scopes_setting(db: &DB) {
|
||||
pub async fn reload_bunfig_install_scopes_setting(conn: &Connection) {
|
||||
reload_option_setting_with_tracing(
|
||||
db,
|
||||
conn,
|
||||
BUNFIG_INSTALL_SCOPES_SETTING,
|
||||
"BUNFIG_INSTALL_SCOPES",
|
||||
BUNFIG_INSTALL_SCOPES.clone(),
|
||||
@@ -964,21 +992,21 @@ pub async fn reload_bunfig_install_scopes_setting(db: &DB) {
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn reload_nuget_config_setting(db: &DB) {
|
||||
pub async fn reload_nuget_config_setting(conn: &Connection) {
|
||||
reload_option_setting_with_tracing(
|
||||
db,
|
||||
conn,
|
||||
NUGET_CONFIG_SETTING,
|
||||
"NUGET_CONFIG",
|
||||
NUGET_CONFIG.clone(),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
pub async fn reload_maven_repos_setting(db: &DB) {
|
||||
reload_option_setting_with_tracing(db, windmill_common::global_settings::MAVEN_REPOS_SETTING, "MAVEN_REPOS", MAVEN_REPOS.clone())
|
||||
pub async fn reload_maven_repos_setting(conn: &Connection) {
|
||||
reload_option_setting_with_tracing(conn, windmill_common::global_settings::MAVEN_REPOS_SETTING, "MAVEN_REPOS", MAVEN_REPOS.clone())
|
||||
.await;
|
||||
}
|
||||
pub async fn reload_no_default_maven_setting(db: &DB) {
|
||||
let value = load_value_from_global_settings(db, windmill_common::global_settings::NO_DEFAULT_MAVEN_SETTING).await;
|
||||
pub async fn reload_no_default_maven_setting(conn: &Connection) {
|
||||
let value = load_value_from_global_settings_with_conn(conn, windmill_common::global_settings::NO_DEFAULT_MAVEN_SETTING, true).await;
|
||||
match value {
|
||||
Ok(Some(serde_json::Value::Bool(t))) => NO_DEFAULT_MAVEN.store(t, Ordering::Relaxed),
|
||||
Err(e) => {
|
||||
@@ -988,9 +1016,9 @@ pub async fn reload_no_default_maven_setting(db: &DB) {
|
||||
};
|
||||
}
|
||||
|
||||
pub async fn reload_retention_period_setting(db: &DB) {
|
||||
pub async fn reload_retention_period_setting(conn: &Connection) {
|
||||
if let Err(e) = reload_setting(
|
||||
db,
|
||||
conn,
|
||||
RETENTION_PERIOD_SECS_SETTING,
|
||||
"JOB_RETENTION_SECS",
|
||||
60 * 60 * 24 * 30,
|
||||
@@ -1002,9 +1030,9 @@ pub async fn reload_retention_period_setting(db: &DB) {
|
||||
tracing::error!("Error reloading retention period: {:?}", e)
|
||||
}
|
||||
}
|
||||
pub async fn reload_delete_logs_periodically_setting(db: &DB) {
|
||||
pub async fn reload_delete_logs_periodically_setting(conn: &Connection) {
|
||||
if let Err(e) = reload_setting(
|
||||
db,
|
||||
conn,
|
||||
MONITOR_LOGS_ON_OBJECT_STORE_SETTING,
|
||||
"MONITOR_LOGS_ON_OBJECT_STORE",
|
||||
false,
|
||||
@@ -1072,9 +1100,9 @@ pub async fn reload_s3_cache_setting(db: &DB) {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn reload_job_default_timeout_setting(db: &DB) {
|
||||
pub async fn reload_job_default_timeout_setting(conn: &Connection) {
|
||||
reload_option_setting_with_tracing(
|
||||
db,
|
||||
conn,
|
||||
JOB_DEFAULT_TIMEOUT_SECS_SETTING,
|
||||
"JOB_DEFAULT_TIMEOUT_SECS",
|
||||
JOB_DEFAULT_TIMEOUT.clone(),
|
||||
@@ -1082,9 +1110,9 @@ pub async fn reload_job_default_timeout_setting(db: &DB) {
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn reload_request_size(db: &DB) {
|
||||
pub async fn reload_request_size(conn: &Connection) {
|
||||
if let Err(e) = reload_setting(
|
||||
db,
|
||||
conn,
|
||||
REQUEST_SIZE_LIMIT_SETTING,
|
||||
"REQUEST_SIZE_LIMIT",
|
||||
DEFAULT_BODY_LIMIT,
|
||||
@@ -1097,8 +1125,8 @@ pub async fn reload_request_size(db: &DB) {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn reload_license_key(db: &DB) -> anyhow::Result<()> {
|
||||
let q = load_value_from_global_settings(db, LICENSE_KEY_SETTING)
|
||||
pub async fn reload_license_key(conn: &Connection) -> anyhow::Result<()> {
|
||||
let q = load_value_from_global_settings_with_conn(conn, LICENSE_KEY_SETTING, true)
|
||||
.await
|
||||
.map_err(|err| anyhow::anyhow!("Error reloading license key: {}", err.to_string()))?;
|
||||
|
||||
@@ -1123,12 +1151,12 @@ pub async fn reload_license_key(db: &DB) -> anyhow::Result<()> {
|
||||
}
|
||||
|
||||
pub async fn reload_option_setting_with_tracing<T: FromStr + DeserializeOwned>(
|
||||
db: &DB,
|
||||
conn: &Connection,
|
||||
setting_name: &str,
|
||||
std_env_var: &str,
|
||||
lock: Arc<RwLock<Option<T>>>,
|
||||
) {
|
||||
if let Err(e) = reload_option_setting(db, setting_name, std_env_var, lock.clone()).await {
|
||||
if let Err(e) = reload_option_setting(conn, setting_name, std_env_var, lock.clone()).await {
|
||||
tracing::error!("Error reloading setting {}: {:?}", setting_name, e)
|
||||
}
|
||||
}
|
||||
@@ -1147,8 +1175,28 @@ pub async fn load_value_from_global_settings(
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
|
||||
pub async fn load_value_from_global_settings_with_conn(
|
||||
conn: &Connection,
|
||||
setting_name: &str,
|
||||
load_from_http: bool,
|
||||
) -> anyhow::Result<Option<serde_json::Value>> {
|
||||
match conn {
|
||||
Connection::Sql(db) => Ok(load_value_from_global_settings(db, setting_name).await?),
|
||||
Connection::Http(client) => {
|
||||
if load_from_http {
|
||||
client.get::<Option<serde_json::Value>>(&format!("/api/agent_workers/get_global_setting/{}", setting_name)).await
|
||||
.map_err(|e| anyhow::anyhow!("Error loading setting {}: {}", setting_name, e))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub async fn reload_option_setting<T: FromStr + DeserializeOwned>(
|
||||
db: &DB,
|
||||
conn: &Connection,
|
||||
setting_name: &str,
|
||||
std_env_var: &str,
|
||||
lock: Arc<RwLock<Option<T>>>,
|
||||
@@ -1163,7 +1211,7 @@ pub async fn reload_option_setting<T: FromStr + DeserializeOwned>(
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let q = load_value_from_global_settings(db, setting_name).await?;
|
||||
let q = load_value_from_global_settings_with_conn(conn, setting_name, true).await?;
|
||||
|
||||
let mut value = std::env::var(std_env_var)
|
||||
.ok()
|
||||
@@ -1190,14 +1238,14 @@ pub async fn reload_option_setting<T: FromStr + DeserializeOwned>(
|
||||
}
|
||||
|
||||
pub async fn reload_setting<T: FromStr + DeserializeOwned + Display>(
|
||||
db: &DB,
|
||||
conn: &Connection,
|
||||
setting_name: &str,
|
||||
std_env_var: &str,
|
||||
default: T,
|
||||
lock: Arc<RwLock<T>>,
|
||||
transformer: fn(T) -> T,
|
||||
) -> error::Result<()> {
|
||||
let q = load_value_from_global_settings(db, setting_name).await?;
|
||||
let q = load_value_from_global_settings_with_conn(conn, setting_name, true).await?;
|
||||
|
||||
let mut value = std::env::var(std_env_var)
|
||||
.ok()
|
||||
@@ -1255,27 +1303,32 @@ pub async fn monitor_pool(db: &DB) {
|
||||
}
|
||||
|
||||
pub async fn monitor_db(
|
||||
db: &Pool<Postgres>,
|
||||
conn: &Connection,
|
||||
base_internal_url: &str,
|
||||
server_mode: bool,
|
||||
_worker_mode: bool,
|
||||
initial_load: bool,
|
||||
_killpill_tx: KillpillSender,
|
||||
) {
|
||||
tracing::info!("Starting periodic monitor task");
|
||||
let zombie_jobs_f = async {
|
||||
if server_mode && !initial_load && !*DISABLE_ZOMBIE_JOBS_MONITORING {
|
||||
if let Some(db) = conn.as_sql() {
|
||||
handle_zombie_jobs(db, base_internal_url, "server").await;
|
||||
match handle_zombie_flows(db).await {
|
||||
Err(err) => {
|
||||
tracing::error!("Error handling zombie flows: {:?}", err);
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
let expired_items_f = async {
|
||||
if server_mode && !initial_load {
|
||||
if let Some(db) = conn.as_sql() {
|
||||
delete_expired_items(&db).await;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1288,35 +1341,43 @@ pub async fn monitor_db(
|
||||
|
||||
let expose_queue_metrics_f = async {
|
||||
if !initial_load && server_mode {
|
||||
expose_queue_metrics(&db).await;
|
||||
if let Some(db) = conn.as_sql() {
|
||||
expose_queue_metrics(&db).await;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let worker_groups_alerts_f = async {
|
||||
#[cfg(feature = "enterprise")]
|
||||
if server_mode && !initial_load {
|
||||
worker_groups_alerts(&db).await;
|
||||
if let Some(db) = conn.as_sql() {
|
||||
worker_groups_alerts(&db).await;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let jobs_waiting_alerts_f = async {
|
||||
#[cfg(feature = "enterprise")]
|
||||
if server_mode {
|
||||
jobs_waiting_alerts(&db).await;
|
||||
if let Some(db) = conn.as_sql() {
|
||||
jobs_waiting_alerts(&db).await;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let apply_autoscaling_f = async {
|
||||
#[cfg(feature = "enterprise")]
|
||||
if server_mode && !initial_load {
|
||||
if let Err(e) = windmill_autoscaling::apply_all_autoscaling(db).await {
|
||||
tracing::error!("Error applying autoscaling: {:?}", e);
|
||||
if let Some(db) = conn.as_sql() {
|
||||
if let Err(e) = windmill_autoscaling::apply_all_autoscaling(db).await {
|
||||
tracing::error!("Error applying autoscaling: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let update_min_worker_version_f = async {
|
||||
update_min_version(db).await;
|
||||
update_min_version(conn).await;
|
||||
};
|
||||
|
||||
join!(
|
||||
@@ -1329,6 +1390,7 @@ pub async fn monitor_db(
|
||||
apply_autoscaling_f,
|
||||
update_min_worker_version_f,
|
||||
);
|
||||
tracing::info!("Periodic monitor task completed");
|
||||
}
|
||||
|
||||
pub async fn expose_queue_metrics(db: &Pool<Postgres>) {
|
||||
@@ -1439,7 +1501,7 @@ pub async fn reload_worker_config(
|
||||
tx: KillpillSender,
|
||||
kill_if_change: bool,
|
||||
) {
|
||||
let config = load_worker_config(&db, tx.clone()).await;
|
||||
let config = load_worker_config(db, tx.clone()).await;
|
||||
if let Err(e) = config {
|
||||
tracing::error!("Error reloading worker config: {:?}", e)
|
||||
} else {
|
||||
@@ -1473,15 +1535,15 @@ pub async fn reload_worker_config(
|
||||
|
||||
let mut wc = WORKER_CONFIG.write().await;
|
||||
tracing::info!("Reloading worker config...");
|
||||
make_suspended_pull_query(&config).await;
|
||||
make_pull_query(&config).await;
|
||||
store_suspended_pull_query(&config).await;
|
||||
store_pull_query(&config).await;
|
||||
*wc = config
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn load_base_url(db: &DB) -> error::Result<String> {
|
||||
let q_base_url = load_value_from_global_settings(db, BASE_URL_SETTING).await?;
|
||||
pub async fn load_base_url(conn: &Connection) -> error::Result<String> {
|
||||
let q_base_url = load_value_from_global_settings_with_conn(conn, BASE_URL_SETTING, false).await?;
|
||||
|
||||
let std_base_url = std::env::var("BASE_URL")
|
||||
.ok()
|
||||
@@ -1511,34 +1573,39 @@ pub async fn load_base_url(db: &DB) -> error::Result<String> {
|
||||
Ok(base_url)
|
||||
}
|
||||
|
||||
pub async fn reload_base_url_setting(db: &DB) -> error::Result<()> {
|
||||
#[cfg(feature = "oauth2")]
|
||||
let q_oauth = load_value_from_global_settings(db, OAUTH_SETTING).await?;
|
||||
pub async fn reload_base_url_setting(conn: &Connection) -> error::Result<()> {
|
||||
|
||||
#[cfg(feature = "oauth2")]
|
||||
let oauths = if let Some(q) = q_oauth {
|
||||
if let Ok(v) = serde_json::from_value::<
|
||||
Option<HashMap<String, windmill_api::oauth2_ee::OAuthClient>>,
|
||||
>(q.clone())
|
||||
{
|
||||
v
|
||||
let oauths = if let Some(db) = conn.as_sql() {
|
||||
let q_oauth = load_value_from_global_settings (db, OAUTH_SETTING).await?;
|
||||
|
||||
if let Some(q) = q_oauth {
|
||||
if let Ok(v) = serde_json::from_value::<
|
||||
Option<HashMap<String, windmill_api::oauth2_ee::OAuthClient>>,
|
||||
>(q.clone())
|
||||
{
|
||||
v
|
||||
} else {
|
||||
tracing::error!("Could not parse oauth setting as a json, found: {:#?}", &q);
|
||||
None
|
||||
}
|
||||
} else {
|
||||
tracing::error!("Could not parse oauth setting as a json, found: {:#?}", &q);
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let base_url = load_base_url(db).await?;
|
||||
let base_url = load_base_url(conn).await?;
|
||||
let is_secure = base_url.starts_with("https://");
|
||||
|
||||
#[cfg(feature = "oauth2")]
|
||||
{
|
||||
let mut l = windmill_api::OAUTH_CLIENTS.write().await;
|
||||
*l = windmill_api::oauth2_ee::build_oauth_clients(&base_url, oauths, db).await
|
||||
.map_err(|e| tracing::error!("Error building oauth clients (is the oauth.json mounted and in correct format? Use '{}' as minimal oauth.json): {}", "{}", e))
|
||||
.unwrap();
|
||||
if let Some(db) = conn.as_sql() {
|
||||
let mut l = windmill_api::OAUTH_CLIENTS.write().await;
|
||||
*l = windmill_api::oauth2_ee::build_oauth_clients(&base_url, oauths, db).await
|
||||
.map_err(|e| tracing::error!("Error building oauth clients (is the oauth.json mounted and in correct format? Use '{}' as minimal oauth.json): {}", "{}", e))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
@@ -1796,7 +1863,7 @@ async fn handle_zombie_jobs(db: &Pool<Postgres>, base_internal_url: &str, worker
|
||||
mpsc::channel::<SameWorkerPayload>(1);
|
||||
let same_worker_tx_never_used =
|
||||
SameWorkerSender(same_worker_tx_never_used, Arc::new(AtomicU16::new(0)));
|
||||
let (send_result_never_used, _send_result_rx_never_used) = mpsc::channel::<SendResult>(1);
|
||||
let (send_result_never_used, _send_result_rx_never_used) = JobCompletedSender::new_never_used();
|
||||
|
||||
let label = if job.permissioned_as != format!("u/{}", job.created_by)
|
||||
&& job.permissioned_as != job.created_by
|
||||
@@ -2006,8 +2073,8 @@ async fn cancel_zombie_flow_job(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn reload_hub_base_url_setting(db: &DB, server_mode: bool) -> error::Result<()> {
|
||||
let hub_base_url = load_value_from_global_settings(db, HUB_BASE_URL_SETTING).await?;
|
||||
pub async fn reload_hub_base_url_setting(conn: &Connection, server_mode: bool) -> error::Result<()> {
|
||||
let hub_base_url = load_value_from_global_settings_with_conn(conn, HUB_BASE_URL_SETTING, true).await?;
|
||||
|
||||
let base_url = if let Some(q) = hub_base_url {
|
||||
if let Ok(v) = serde_json::from_value::<String>(q.clone()) {
|
||||
@@ -2030,16 +2097,18 @@ pub async fn reload_hub_base_url_setting(db: &DB, server_mode: bool) -> error::R
|
||||
let mut l = HUB_BASE_URL.write().await;
|
||||
if server_mode {
|
||||
#[cfg(feature = "embedding")]
|
||||
if *l != base_url {
|
||||
let disable_embedding = std::env::var("DISABLE_EMBEDDING")
|
||||
.ok()
|
||||
.map(|x| x.parse::<bool>().unwrap_or(false))
|
||||
.unwrap_or(false);
|
||||
if !disable_embedding {
|
||||
let db_clone = db.clone();
|
||||
tokio::spawn(async move {
|
||||
update_embeddings_db(&db_clone).await;
|
||||
});
|
||||
if let Some(db) = conn.as_sql() {
|
||||
if *l != base_url {
|
||||
let disable_embedding = std::env::var("DISABLE_EMBEDDING")
|
||||
.ok()
|
||||
.map(|x| x.parse::<bool>().unwrap_or(false))
|
||||
.unwrap_or(false);
|
||||
if !disable_embedding {
|
||||
let db_clone = db.clone();
|
||||
tokio::spawn(async move {
|
||||
update_embeddings_db(&db_clone).await;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2048,9 +2117,9 @@ pub async fn reload_hub_base_url_setting(db: &DB, server_mode: bool) -> error::R
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn reload_critical_error_channels_setting(db: &DB) -> error::Result<()> {
|
||||
pub async fn reload_critical_error_channels_setting(conn: &DB) -> error::Result<()> {
|
||||
let critical_error_channels =
|
||||
load_value_from_global_settings(db, CRITICAL_ERROR_CHANNELS_SETTING).await?;
|
||||
load_value_from_global_settings(conn, CRITICAL_ERROR_CHANNELS_SETTING).await?;
|
||||
|
||||
let critical_error_channels = if let Some(q) = critical_error_channels {
|
||||
if let Ok(v) = serde_json::from_value::<Vec<CriticalErrorChannel>>(q.clone()) {
|
||||
|
||||
@@ -137,7 +137,6 @@ impl ApiServer {
|
||||
rx,
|
||||
port_tx,
|
||||
false,
|
||||
#[cfg(feature = "smtp")]
|
||||
format!("http://localhost:{}", addr.port()),
|
||||
));
|
||||
|
||||
@@ -315,7 +314,7 @@ mod suspend_resume {
|
||||
let second = completed.next().await.unwrap();
|
||||
// print_job(second, &db).await;
|
||||
|
||||
let token = windmill_worker::create_token_for_owner(&db, "test-workspace", "u/test-user", "", 100, "", &Uuid::nil(), None).await.unwrap();
|
||||
let token = windmill_common::auth::create_token_for_owner(&db, "test-workspace", "u/test-user", "", 100, "", &Uuid::nil(), None).await.unwrap();
|
||||
let secret = reqwest::get(format!(
|
||||
"http://localhost:{port}/api/w/test-workspace/jobs/job_signature/{second}/0?token={token}&approver=ruben"
|
||||
))
|
||||
@@ -418,7 +417,7 @@ mod suspend_resume {
|
||||
/* ... and send a request resume it. */
|
||||
let second = completed.next().await.unwrap();
|
||||
|
||||
let token = windmill_worker::create_token_for_owner(&db, "test-workspace", "u/test-user", "", 100, "", &Uuid::nil(), None).await.unwrap();
|
||||
let token = windmill_common::auth::create_token_for_owner(&db, "test-workspace", "u/test-user", "", 100, "", &Uuid::nil(), None).await.unwrap();
|
||||
let secret = reqwest::get(format!(
|
||||
"http://localhost:{port}/api/w/test-workspace/jobs/job_signature/{second}/0?token={token}"
|
||||
))
|
||||
@@ -1033,11 +1032,11 @@ fn spawn_test_worker(
|
||||
priority: 0,
|
||||
tags: (*wc).worker_tags.clone(),
|
||||
}];
|
||||
windmill_common::worker::make_suspended_pull_query(&wc).await;
|
||||
windmill_common::worker::make_pull_query(&wc).await;
|
||||
windmill_common::worker::store_suspended_pull_query(&wc).await;
|
||||
windmill_common::worker::store_pull_query(&wc).await;
|
||||
}
|
||||
windmill_worker::run_worker(
|
||||
&db,
|
||||
&db.into(),
|
||||
worker_instance,
|
||||
worker_name,
|
||||
1,
|
||||
@@ -1046,7 +1045,6 @@ fn spawn_test_worker(
|
||||
rx,
|
||||
tx2,
|
||||
&base_internal_url,
|
||||
false,
|
||||
)
|
||||
.await
|
||||
};
|
||||
@@ -3843,7 +3841,7 @@ async fn test_result_format(db: Pool<Postgres>) {
|
||||
|
||||
let port = server.addr.port();
|
||||
|
||||
let token = windmill_worker::create_token_for_owner(
|
||||
let token = windmill_common::auth::create_token_for_owner(
|
||||
&db,
|
||||
"test-workspace",
|
||||
"u/test-user",
|
||||
@@ -3884,7 +3882,7 @@ async fn test_result_format(db: Pool<Postgres>) {
|
||||
assert_eq!(job_result.get(), correct_result);
|
||||
|
||||
let response = windmill_api::jobs::run_wait_result(
|
||||
&db,
|
||||
&db.into(),
|
||||
Uuid::parse_str(ordered_result_job_id).unwrap(),
|
||||
"test-workspace".to_string(),
|
||||
None,
|
||||
|
||||
@@ -10,13 +10,14 @@ path = "src/lib.rs"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
enterprise = ["windmill-queue/enterprise", "windmill-audit/enterprise", "windmill-git-sync/enterprise", "windmill-common/enterprise"]
|
||||
enterprise = ["windmill-queue/enterprise", "windmill-audit/enterprise", "windmill-git-sync/enterprise", "windmill-common/enterprise", "windmill-worker/enterprise"]
|
||||
stripe = []
|
||||
agent_worker_server = []
|
||||
enterprise_saml = ["dep:samael"]
|
||||
benchmark = []
|
||||
embedding = ["dep:tinyvector", "dep:hf-hub", "dep:tokenizers", "dep:candle-core", "dep:candle-transformers", "dep:candle-nn", "dep:half"]
|
||||
parquet = ["dep:datafusion", "dep:object_store", "dep:url", "windmill-common/parquet"]
|
||||
prometheus = ["windmill-common/prometheus", "windmill-queue/prometheus", "dep:prometheus"]
|
||||
parquet = ["dep:datafusion", "dep:object_store", "dep:url", "windmill-common/parquet", "windmill-worker/parquet"]
|
||||
prometheus = ["windmill-common/prometheus", "windmill-queue/prometheus", "dep:prometheus", "windmill-worker/prometheus"]
|
||||
openidconnect = ["dep:openidconnect"]
|
||||
tantivy = ["dep:windmill-indexer"]
|
||||
kafka = ["dep:rdkafka"]
|
||||
@@ -31,6 +32,7 @@ static_frontend = ["dep:rust-embed"]
|
||||
postgres_trigger = ["dep:rust-postgres", "dep:pg_escape", "dep:byteorder", "dep:thiserror", "dep:rust_decimal", "dep:rust-postgres-native-tls"]
|
||||
mqtt_trigger = ["dep:thiserror", "dep:rumqttc"]
|
||||
sqs_trigger = ["dep:aws-sdk-sqs", "dep:thiserror", "dep:aws-config"]
|
||||
gcp_trigger = ["dep:thiserror", "dep:google-cloud-pubsub", "dep:google-cloud-googleapis", "dep:tonic"]
|
||||
cloud = ["windmill-common/cloud"]
|
||||
|
||||
[dependencies]
|
||||
@@ -40,8 +42,10 @@ windmill-audit.workspace = true
|
||||
windmill-parser.workspace = true
|
||||
windmill-parser-ts.workspace = true
|
||||
windmill-parser-py.workspace = true
|
||||
windmill-parser-py-imports.workspace = true
|
||||
windmill-git-sync.workspace = true
|
||||
windmill-indexer = { workspace = true, optional = true }
|
||||
windmill-worker.workspace = true
|
||||
tokio.workspace = true
|
||||
anyhow.workspace = true
|
||||
argon2.workspace = true
|
||||
@@ -126,4 +130,7 @@ rust_decimal = { workspace = true, optional = true }
|
||||
rust-postgres-native-tls = { workspace = true, optional = true}
|
||||
rumqttc = { workspace = true, optional = true }
|
||||
aws-sdk-sqs = { workspace = true, optional = true }
|
||||
aws-config = { workspace = true, optional = true}
|
||||
aws-config = { workspace = true, optional = true }
|
||||
google-cloud-pubsub = { workspace = true, optional = true }
|
||||
google-cloud-googleapis = { workspace = true , optional = true }
|
||||
tonic = { workspace = true, optional = true }
|
||||
@@ -2702,6 +2702,8 @@ paths:
|
||||
type: boolean
|
||||
mqtt_used:
|
||||
type: boolean
|
||||
gcp_used:
|
||||
type: boolean
|
||||
sqs_used:
|
||||
type: boolean
|
||||
required:
|
||||
@@ -2711,6 +2713,7 @@ paths:
|
||||
- nats_used
|
||||
- postgres_used
|
||||
- mqtt_used
|
||||
- gcp_used
|
||||
- sqs_used
|
||||
/w/{workspace}/users/list:
|
||||
get:
|
||||
@@ -6786,6 +6789,7 @@ paths:
|
||||
- $ref: "#/components/parameters/Running"
|
||||
- $ref: "#/components/parameters/ArgsFilter"
|
||||
- $ref: "#/components/parameters/ResultFilter"
|
||||
- $ref: "#/components/parameters/AllowWildcards"
|
||||
- $ref: "#/components/parameters/Tag"
|
||||
- $ref: "#/components/parameters/Page"
|
||||
- $ref: "#/components/parameters/PerPage"
|
||||
@@ -6914,6 +6918,7 @@ paths:
|
||||
- $ref: "#/components/parameters/Running"
|
||||
- $ref: "#/components/parameters/ArgsFilter"
|
||||
- $ref: "#/components/parameters/ResultFilter"
|
||||
- $ref: "#/components/parameters/AllowWildcards"
|
||||
- $ref: "#/components/parameters/Tag"
|
||||
- $ref: "#/components/parameters/Page"
|
||||
- $ref: "#/components/parameters/PerPage"
|
||||
@@ -6992,6 +6997,7 @@ paths:
|
||||
- $ref: "#/components/parameters/JobKinds"
|
||||
- $ref: "#/components/parameters/ArgsFilter"
|
||||
- $ref: "#/components/parameters/ResultFilter"
|
||||
- $ref: "#/components/parameters/AllowWildcards"
|
||||
- $ref: "#/components/parameters/Tag"
|
||||
- $ref: "#/components/parameters/Page"
|
||||
- $ref: "#/components/parameters/PerPage"
|
||||
@@ -7055,6 +7061,7 @@ paths:
|
||||
- $ref: "#/components/parameters/ArgsFilter"
|
||||
- $ref: "#/components/parameters/Tag"
|
||||
- $ref: "#/components/parameters/ResultFilter"
|
||||
- $ref: "#/components/parameters/AllowWildcards"
|
||||
- $ref: "#/components/parameters/Page"
|
||||
- $ref: "#/components/parameters/PerPage"
|
||||
- name: is_skipped
|
||||
@@ -9218,6 +9225,264 @@ paths:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
/w/{workspace}/gcp_triggers/create:
|
||||
post:
|
||||
summary: create gcp trigger
|
||||
operationId: createGcpTrigger
|
||||
tags:
|
||||
- gcp_trigger
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
requestBody:
|
||||
description: new gcp trigger
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/NewGcpTrigger"
|
||||
responses:
|
||||
"201":
|
||||
description: gcp trigger created
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
/w/{workspace}/gcp_triggers/update/{path}:
|
||||
post:
|
||||
summary: update gcp trigger
|
||||
operationId: updateGcpTrigger
|
||||
tags:
|
||||
- gcp_trigger
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- $ref: "#/components/parameters/Path"
|
||||
requestBody:
|
||||
description: updated trigger
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/EditGcpTrigger"
|
||||
responses:
|
||||
"200":
|
||||
description: gcp trigger updated
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
/w/{workspace}/gcp_triggers/delete/{path}:
|
||||
delete:
|
||||
summary: delete gcp trigger
|
||||
operationId: deleteGcpTrigger
|
||||
tags:
|
||||
- gcp_trigger
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- $ref: "#/components/parameters/Path"
|
||||
responses:
|
||||
"200":
|
||||
description: gcp trigger deleted
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
/w/{workspace}/gcp_triggers/get/{path}:
|
||||
get:
|
||||
summary: get gcp trigger
|
||||
operationId: getGcpTrigger
|
||||
tags:
|
||||
- gcp_trigger
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- $ref: "#/components/parameters/Path"
|
||||
responses:
|
||||
"200":
|
||||
description: gcp trigger deleted
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/GcpTrigger"
|
||||
|
||||
/w/{workspace}/gcp_triggers/list:
|
||||
get:
|
||||
summary: list gcp triggers
|
||||
operationId: listGcpTriggers
|
||||
tags:
|
||||
- gcp_trigger
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
required: true
|
||||
- $ref: "#/components/parameters/Page"
|
||||
- $ref: "#/components/parameters/PerPage"
|
||||
- name: path
|
||||
description: filter by path
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
- name: is_flow
|
||||
in: query
|
||||
schema:
|
||||
type: boolean
|
||||
- name: path_start
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: gcp trigger list
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/GcpTrigger"
|
||||
|
||||
/w/{workspace}/gcp_triggers/exists/{path}:
|
||||
get:
|
||||
summary: does gcp trigger exists
|
||||
operationId: existsGcpTrigger
|
||||
tags:
|
||||
- gcp_trigger
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- $ref: "#/components/parameters/Path"
|
||||
responses:
|
||||
"200":
|
||||
description: gcp trigger exists
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: boolean
|
||||
|
||||
/w/{workspace}/gcp_triggers/setenabled/{path}:
|
||||
post:
|
||||
summary: set enabled gcp trigger
|
||||
operationId: setGcpTriggerEnabled
|
||||
tags:
|
||||
- gcp_trigger
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- $ref: "#/components/parameters/Path"
|
||||
requestBody:
|
||||
description: updated gcp trigger enable
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
enabled:
|
||||
type: boolean
|
||||
required:
|
||||
- enabled
|
||||
responses:
|
||||
"200":
|
||||
description: gcp trigger enabled set
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
/w/{workspace}/gcp_triggers/test:
|
||||
post:
|
||||
summary: test gcp connection
|
||||
operationId: testGcpConnection
|
||||
tags:
|
||||
- gcp_trigger
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
requestBody:
|
||||
description: test gcp connection
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
connection:
|
||||
type: object
|
||||
required:
|
||||
- connection
|
||||
responses:
|
||||
"200":
|
||||
description: try to connect to a gcp broker
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
|
||||
/w/{workspace}/gcp_triggers/subscriptions/delete/{path}:
|
||||
delete:
|
||||
summary: delete gcp trigger
|
||||
operationId: deleteGcpSubscription
|
||||
tags:
|
||||
- gcp_trigger
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- $ref: "#/components/parameters/Path"
|
||||
requestBody:
|
||||
description: args to delete subscription from google cloud
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/DeleteGcpSubscription"
|
||||
responses:
|
||||
"200":
|
||||
description: gcp trigger deleted
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
/w/{workspace}/gcp_triggers/topics/list/{path}:
|
||||
get:
|
||||
summary: list all topics of google cloud service
|
||||
operationId: listGoogleTopics
|
||||
tags:
|
||||
- gcp_trigger
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- $ref: "#/components/parameters/Path"
|
||||
responses:
|
||||
"200":
|
||||
description: get all google topics
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
|
||||
/w/{workspace}/gcp_triggers/subscriptions/list/{path}:
|
||||
post:
|
||||
summary: list all subscription of a give topic from google cloud service
|
||||
operationId: listAllTGoogleTopicSubscriptions
|
||||
tags:
|
||||
- gcp_trigger
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- $ref: "#/components/parameters/Path"
|
||||
requestBody:
|
||||
description: args to get subscription's topic from google cloud
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/GetAllTopicSubscription"
|
||||
responses:
|
||||
"200":
|
||||
description: get all google topic subscriptions name
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
|
||||
/w/{workspace}/postgres_triggers/is_valid_postgres_configuration/{path}:
|
||||
get:
|
||||
@@ -10494,6 +10759,41 @@ paths:
|
||||
items:
|
||||
$ref: "#/components/schemas/AutoscalingEvent"
|
||||
|
||||
/agent_workers/create_agent_token:
|
||||
post:
|
||||
summary: create agent token
|
||||
operationId: createAgentToken
|
||||
tags:
|
||||
- agent_workers
|
||||
requestBody:
|
||||
description: agent token
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
worker_group:
|
||||
type: string
|
||||
tags:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
exp:
|
||||
type: integer
|
||||
required:
|
||||
- worker_group
|
||||
- tags
|
||||
- exp
|
||||
responses:
|
||||
"200":
|
||||
description: agent token created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
|
||||
/w/{workspace}/acls/get/{kind}/{path}:
|
||||
get:
|
||||
summary: get granular acls
|
||||
@@ -10524,6 +10824,7 @@ paths:
|
||||
nats_trigger,
|
||||
postgres_trigger,
|
||||
mqtt_trigger,
|
||||
gcp_trigger,
|
||||
sqs_trigger
|
||||
]
|
||||
responses:
|
||||
@@ -10567,6 +10868,7 @@ paths:
|
||||
nats_trigger,
|
||||
postgres_trigger,
|
||||
mqtt_trigger,
|
||||
gcp_trigger,
|
||||
sqs_trigger
|
||||
]
|
||||
requestBody:
|
||||
@@ -10621,6 +10923,7 @@ paths:
|
||||
nats_trigger,
|
||||
postgres_trigger,
|
||||
mqtt_trigger,
|
||||
gcp_trigger,
|
||||
sqs_trigger
|
||||
]
|
||||
requestBody:
|
||||
@@ -10673,6 +10976,10 @@ paths:
|
||||
responses:
|
||||
"200":
|
||||
description: capture config set
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
|
||||
/w/{workspace}/capture/ping_config/{trigger_kind}/{runnable_kind}/{path}:
|
||||
post:
|
||||
@@ -11888,6 +12195,7 @@ paths:
|
||||
- $ref: "#/components/parameters/ArgsFilter"
|
||||
- $ref: "#/components/parameters/Tag"
|
||||
- $ref: "#/components/parameters/ResultFilter"
|
||||
- $ref: "#/components/parameters/AllowWildcards"
|
||||
- $ref: "#/components/parameters/Page"
|
||||
- $ref: "#/components/parameters/PerPage"
|
||||
- name: is_skipped
|
||||
@@ -12393,6 +12701,12 @@ components:
|
||||
in: query
|
||||
schema:
|
||||
type: boolean
|
||||
AllowWildcards:
|
||||
name: allow_wildcards
|
||||
description: allow wildcards (*) in the filter of label, tag, worker
|
||||
in: query
|
||||
schema:
|
||||
type: boolean
|
||||
ArgsFilter:
|
||||
name: args
|
||||
description: filter on jobs containing those args as a json subset (@> in postgres)
|
||||
@@ -12497,7 +12811,7 @@ components:
|
||||
|
||||
AIProvider:
|
||||
type: string
|
||||
enum: [openai, anthropic, mistral, deepseek, googleai, groq, openrouter, togetherai, customai]
|
||||
enum: [openai, azure_openai, anthropic, mistral, deepseek, googleai, groq, openrouter, togetherai, customai]
|
||||
|
||||
AIProviderModel:
|
||||
type: object
|
||||
@@ -13531,7 +13845,7 @@ components:
|
||||
csharp,
|
||||
nu,
|
||||
java
|
||||
# KJQXZ
|
||||
# for related places search: ADD_NEW_LANG
|
||||
]
|
||||
|
||||
Preview:
|
||||
@@ -14144,6 +14458,8 @@ components:
|
||||
type: number
|
||||
mqtt_count:
|
||||
type: number
|
||||
gcp_count:
|
||||
type: number
|
||||
sqs_count:
|
||||
type: number
|
||||
|
||||
@@ -14428,6 +14744,173 @@ components:
|
||||
- subscribe_topics
|
||||
- mqtt_resource_path
|
||||
|
||||
DeliveryType:
|
||||
type: string
|
||||
enum:
|
||||
- push
|
||||
- pull
|
||||
|
||||
PushConfig:
|
||||
type: object
|
||||
properties:
|
||||
audience:
|
||||
type: string
|
||||
authenticate:
|
||||
type: boolean
|
||||
base_endpoint:
|
||||
type: string
|
||||
required:
|
||||
- authenticate
|
||||
- base_endpoint
|
||||
|
||||
GcpTrigger:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/TriggerExtraProperty"
|
||||
type: object
|
||||
properties:
|
||||
gcp_resource_path:
|
||||
type: string
|
||||
topic_id:
|
||||
type: string
|
||||
subscription_id:
|
||||
type: string
|
||||
server_id:
|
||||
type: string
|
||||
delivery_type:
|
||||
$ref: "#/components/schemas/DeliveryType"
|
||||
delivery_config:
|
||||
$ref: "#/components/schemas/PushConfig"
|
||||
last_server_ping:
|
||||
type: string
|
||||
format: date-time
|
||||
error:
|
||||
type: string
|
||||
enabled:
|
||||
type: boolean
|
||||
required:
|
||||
- gcp_resource_path
|
||||
- topic_id
|
||||
- subscription_id
|
||||
- enabled
|
||||
- delivery_type
|
||||
|
||||
SubscriptionMode:
|
||||
type: string
|
||||
enum:
|
||||
- existing
|
||||
- create_update
|
||||
description: "The mode of subscription. 'existing' means using an existing GCP subscription, while 'create_update' involves creating or updating a new subscription."
|
||||
|
||||
GcpExistingSubscription:
|
||||
type: object
|
||||
properties:
|
||||
subscription_id:
|
||||
type: string
|
||||
base_endpoint:
|
||||
type: string
|
||||
required:
|
||||
- subscription_id
|
||||
- base_endpoint
|
||||
|
||||
GcpCreateUpdateSubscription:
|
||||
type: object
|
||||
properties:
|
||||
subscription_id:
|
||||
type: string
|
||||
delivery_type:
|
||||
$ref: "#/components/schemas/DeliveryType"
|
||||
delivery_config:
|
||||
$ref: "#/components/schemas/PushConfig"
|
||||
required:
|
||||
- delivery_type
|
||||
|
||||
|
||||
GcpSubscriptionModeConfig:
|
||||
type: object
|
||||
properties:
|
||||
subscription_mode:
|
||||
$ref: "#/components/schemas/SubscriptionMode"
|
||||
required:
|
||||
- subscription_mode
|
||||
allOf:
|
||||
- oneOf:
|
||||
- $ref: "#/components/schemas/GcpExistingSubscription"
|
||||
- $ref: "#/components/schemas/GcpCreateUpdateSubscription"
|
||||
description: |
|
||||
"This is a union type representing the subscription mode.
|
||||
- 'existing': Represents an existing GCP subscription, and should be accompanied by an 'ExistingGcpSubscription' object.
|
||||
- 'create_update': Represents a new or updated GCP subscription, and should be accompanied by a 'CreateUpdateConfig' object."
|
||||
|
||||
NewGcpTrigger:
|
||||
type: object
|
||||
properties:
|
||||
gcp_resource_path:
|
||||
type: string
|
||||
topic_id:
|
||||
type: string
|
||||
subscription_mode:
|
||||
$ref: "#/components/schemas/GcpSubscriptionModeConfig"
|
||||
path:
|
||||
type: string
|
||||
script_path:
|
||||
type: string
|
||||
is_flow:
|
||||
type: boolean
|
||||
enabled:
|
||||
type: boolean
|
||||
required:
|
||||
- path
|
||||
- script_path
|
||||
- is_flow
|
||||
- gcp_resource_path
|
||||
- topic_id
|
||||
- subscription_mode
|
||||
|
||||
EditGcpTrigger:
|
||||
type: object
|
||||
properties:
|
||||
gcp_resource_path:
|
||||
type: string
|
||||
topic_id:
|
||||
type: string
|
||||
subscription_mode:
|
||||
$ref: "#/components/schemas/GcpSubscriptionModeConfig"
|
||||
path:
|
||||
type: string
|
||||
script_path:
|
||||
type: string
|
||||
is_flow:
|
||||
type: boolean
|
||||
enabled:
|
||||
type: boolean
|
||||
required:
|
||||
- path
|
||||
- script_path
|
||||
- is_flow
|
||||
- enabled
|
||||
- mqtt_resource_path
|
||||
- subscription_id
|
||||
- delivery_type
|
||||
- topic_id
|
||||
- subscription_mode
|
||||
|
||||
GetAllTopicSubscription:
|
||||
type: object
|
||||
properties:
|
||||
topic_id:
|
||||
type: string
|
||||
required:
|
||||
- topic_id
|
||||
|
||||
|
||||
DeleteGcpSubscription:
|
||||
type: object
|
||||
properties:
|
||||
subscription_id:
|
||||
type: string
|
||||
required:
|
||||
- subscription_id
|
||||
|
||||
SqsTrigger:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/TriggerExtraProperty"
|
||||
@@ -15813,7 +16296,7 @@ components:
|
||||
|
||||
CaptureTriggerKind:
|
||||
type: string
|
||||
enum: [webhook, http, websocket, kafka, email, nats, postgres, sqs, mqtt]
|
||||
enum: [webhook, http, websocket, kafka, email, nats, postgres, sqs, mqtt, gcp]
|
||||
|
||||
Capture:
|
||||
type: object
|
||||
|
||||
52
backend/windmill-api/src/agent_workers_ee.rs
Normal file
52
backend/windmill-api/src/agent_workers_ee.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Author: Ruben Fiszel
|
||||
* Copyright: Windmill Labs, Inc 2042
|
||||
* This file and its contents are licensed under the AGPLv3 License.
|
||||
* Please see the included NOTICE for copyright information and
|
||||
* LICENSE-AGPL for a copy of the license.
|
||||
*/
|
||||
|
||||
use crate::db::DB;
|
||||
|
||||
use axum::Router;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub fn global_service() -> Router {
|
||||
Router::new()
|
||||
}
|
||||
|
||||
pub fn workspaced_service(
|
||||
db: DB,
|
||||
_base_internal_url: String,
|
||||
) -> (
|
||||
Router,
|
||||
Option<tokio::task::JoinHandle<()>>,
|
||||
windmill_worker::JobCompletedSender,
|
||||
) {
|
||||
use windmill_common::worker::Connection;
|
||||
use windmill_worker::JobCompletedSender;
|
||||
|
||||
let (job_completed_tx, _job_completed_rx) =
|
||||
JobCompletedSender::new(&Connection::Sql(db.clone()), 100);
|
||||
|
||||
let router = Router::new();
|
||||
|
||||
(router, None, job_completed_tx)
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct AgentAuth {
|
||||
pub worker_group: String,
|
||||
pub suffix: Option<String>,
|
||||
pub tags: Vec<String>,
|
||||
pub exp: Option<usize>,
|
||||
}
|
||||
|
||||
pub struct AgentCache {}
|
||||
|
||||
impl AgentCache {
|
||||
pub fn new() -> Self {
|
||||
AgentCache {}
|
||||
}
|
||||
}
|
||||
@@ -3,16 +3,12 @@ use crate::{
|
||||
variables::get_variable_or_self,
|
||||
};
|
||||
|
||||
use anyhow::Context;
|
||||
use axum::{body::Bytes, extract::Path, response::IntoResponse, routing::post, Extension, Router};
|
||||
use http::HeaderMap;
|
||||
use lazy_static::lazy_static;
|
||||
use openai::OpenaiCache;
|
||||
use openai_api_compatible::OpenaiApiCompatibleCache;
|
||||
use quick_cache::sync::Cache;
|
||||
use reqwest::{Client, RequestBuilder};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::value::{RawValue, Value};
|
||||
use serde_json::value::RawValue;
|
||||
use std::collections::HashMap;
|
||||
use windmill_audit::{audit_ee::audit_log, ActionKind};
|
||||
use windmill_common::error::{to_anyhow, Error, Result};
|
||||
@@ -22,175 +18,94 @@ lazy_static::lazy_static! {
|
||||
.timeout(std::time::Duration::from_secs(60 * 5))
|
||||
.user_agent("windmill/beta")
|
||||
.build().unwrap();
|
||||
|
||||
static ref OPENAI_AZURE_BASE_PATH: Option<String> = std::env::var("OPENAI_AZURE_BASE_PATH").ok();
|
||||
|
||||
pub static ref AI_REQUEST_CACHE: Cache<(String, AIProvider), ExpiringAIRequestConfig> = Cache::new(500);
|
||||
}
|
||||
|
||||
mod openai_api_compatible {
|
||||
use super::*;
|
||||
const AZURE_API_VERSION: &str = "2024-10-21";
|
||||
const OPENAI_BASE_URL: &str = "https://api.openai.com/v1";
|
||||
|
||||
#[derive(Deserialize, Clone, Debug)]
|
||||
pub struct OpenaiApiCompatibleCache {
|
||||
pub base_url: String,
|
||||
pub api_key: Option<String>,
|
||||
}
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct AIOAuthResource {
|
||||
client_id: String,
|
||||
client_secret: String,
|
||||
token_url: String,
|
||||
user: Option<String>,
|
||||
}
|
||||
|
||||
impl OpenaiApiCompatibleCache {
|
||||
pub fn prepare_request(self, path: &str, body: Bytes) -> Result<RequestBuilder> {
|
||||
let url = format!("{}/{}", self.base_url, path);
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct AIStandardResource {
|
||||
#[serde(alias = "baseUrl")]
|
||||
base_url: Option<String>,
|
||||
#[serde(alias = "apiKey")]
|
||||
api_key: Option<String>,
|
||||
organization_id: Option<String>,
|
||||
}
|
||||
|
||||
let mut request = HTTP_CLIENT
|
||||
.post(url)
|
||||
.header("content-type", "application/json")
|
||||
.body(body);
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct OAuthTokens {
|
||||
access_token: String,
|
||||
}
|
||||
|
||||
if let Some(api_key) = self.api_key {
|
||||
request = request.header("Authorization", format!("Bearer {}", api_key));
|
||||
}
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(untagged)]
|
||||
enum AIResource {
|
||||
OAuth(AIOAuthResource),
|
||||
Standard(AIStandardResource),
|
||||
}
|
||||
|
||||
Ok(request)
|
||||
}
|
||||
}
|
||||
#[derive(Deserialize, Clone, Debug)]
|
||||
struct AIRequestConfig {
|
||||
pub base_url: String,
|
||||
pub api_key: Option<String>,
|
||||
pub access_token: Option<String>,
|
||||
pub organization_id: Option<String>,
|
||||
pub user: Option<String>,
|
||||
}
|
||||
|
||||
pub async fn get_cached_value(
|
||||
impl AIRequestConfig {
|
||||
pub async fn new(
|
||||
provider: &AIProvider,
|
||||
db: &DB,
|
||||
w_id: &str,
|
||||
resource: Value,
|
||||
base_url: Option<String>,
|
||||
) -> Result<KeyCache> {
|
||||
let mut resource: OpenaiApiCompatibleCache = if let Some(base_url) = base_url {
|
||||
let api_key = match resource {
|
||||
Value::Object(mut obj) => obj
|
||||
.remove("api_key")
|
||||
.map(|v| serde_json::from_value::<String>(v.clone()).ok())
|
||||
.flatten()
|
||||
.or_else(|| {
|
||||
obj.remove("apiKey")
|
||||
.map(|v| serde_json::from_value::<String>(v.clone()).ok())
|
||||
.flatten()
|
||||
}),
|
||||
_ => None,
|
||||
};
|
||||
OpenaiApiCompatibleCache { base_url, api_key }
|
||||
} else {
|
||||
serde_json::from_value(resource).with_context(|| "validating custom AI resource")?
|
||||
resource: AIResource,
|
||||
) -> Result<Self> {
|
||||
let (api_key, access_token, organization_id, base_url, user) = match resource {
|
||||
AIResource::Standard(resource) => {
|
||||
let base_url = provider.get_base_url(resource.base_url, db).await?;
|
||||
let api_key = if let Some(api_key) = resource.api_key {
|
||||
Some(get_variable_or_self(api_key, db, w_id).await?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let organization_id = if let Some(organization_id) = resource.organization_id {
|
||||
Some(get_variable_or_self(organization_id, db, w_id).await?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
(api_key, None, organization_id, base_url, None)
|
||||
}
|
||||
AIResource::OAuth(resource) => {
|
||||
let user = if let Some(user) = resource.user.clone() {
|
||||
Some(get_variable_or_self(user, db, w_id).await?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let token = Self::get_token_using_oauth(resource, db, w_id).await?;
|
||||
let base_url = provider.get_base_url(None, db).await?;
|
||||
|
||||
(None, Some(token), None, base_url, user)
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(api_key) = resource.api_key {
|
||||
resource.api_key = Some(get_variable_or_self(api_key, db, w_id).await?);
|
||||
}
|
||||
|
||||
Ok(KeyCache::OpenaiApiCompatible(resource))
|
||||
}
|
||||
}
|
||||
|
||||
mod openai {
|
||||
use super::*;
|
||||
|
||||
const API_VERSION: &str = "2024-10-21";
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct OpenaiResource {
|
||||
api_key: String,
|
||||
organization_id: Option<String>,
|
||||
Ok(Self { base_url, organization_id, api_key, access_token, user })
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct OpenaiClientCredentialsOauthResource {
|
||||
client_id: String,
|
||||
client_secret: String,
|
||||
token_url: String,
|
||||
user: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(untagged, rename_all = "snake_case")]
|
||||
enum OpenaiConfig {
|
||||
Resource(OpenaiResource),
|
||||
ClientCredentialsOauthResource(OpenaiClientCredentialsOauthResource),
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref OPENAI_AZURE_BASE_PATH: Option<String> = std::env::var("OPENAI_AZURE_BASE_PATH").ok();
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct OpenaiCredentials {
|
||||
access_token: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
pub struct OpenaiCache {
|
||||
api_key: String,
|
||||
organization_id: Option<String>,
|
||||
azure_base_path: Option<String>,
|
||||
user: Option<String>,
|
||||
}
|
||||
|
||||
impl OpenaiCache {
|
||||
pub fn new(
|
||||
api_key: String,
|
||||
organization_id: Option<String>,
|
||||
azure_base_path: Option<String>,
|
||||
user: Option<String>,
|
||||
) -> Self {
|
||||
Self { api_key, organization_id, azure_base_path, user }
|
||||
}
|
||||
}
|
||||
|
||||
pub const BASE_URL: &str = "https://api.openai.com/v1";
|
||||
impl OpenaiCache {
|
||||
pub fn prepare_request(self, openai_path: &str, mut body: Bytes) -> Result<RequestBuilder> {
|
||||
let OpenaiCache { api_key, azure_base_path, organization_id, user } = self;
|
||||
if user.is_some() {
|
||||
tracing::debug!("Adding user to request body");
|
||||
let mut json_body: HashMap<String, Box<RawValue>> = serde_json::from_slice(&body)
|
||||
.map_err(|e| {
|
||||
Error::internal_err(format!("Failed to parse request body: {}", e))
|
||||
})?;
|
||||
|
||||
let user_json_string = serde_json::Value::String(user.unwrap()).to_string(); // makes sure to escape characters
|
||||
|
||||
json_body.insert(
|
||||
"user".to_string(),
|
||||
RawValue::from_string(user_json_string)
|
||||
.map_err(|e| Error::internal_err(format!("Failed to parse user: {}", e)))?,
|
||||
);
|
||||
|
||||
body = serde_json::to_vec(&json_body)
|
||||
.map_err(|e| {
|
||||
Error::internal_err(format!("Failed to reserialize request body: {}", e))
|
||||
})?
|
||||
.into();
|
||||
}
|
||||
|
||||
let base_url = if let Some(base_url) = azure_base_path {
|
||||
base_url
|
||||
} else {
|
||||
BASE_URL.to_string()
|
||||
};
|
||||
let url = format!("{}/{}", base_url, openai_path);
|
||||
let mut request = HTTP_CLIENT
|
||||
.post(url)
|
||||
.header("content-type", "application/json")
|
||||
.body(body);
|
||||
|
||||
if base_url != BASE_URL {
|
||||
request = request
|
||||
.header("api-key", api_key)
|
||||
.query(&[("api-version", API_VERSION)])
|
||||
} else {
|
||||
request = request.header("authorization", format!("Bearer {}", api_key))
|
||||
}
|
||||
|
||||
if let Some(org_id) = organization_id {
|
||||
request = request.header("OpenAI-Organization", org_id);
|
||||
}
|
||||
|
||||
Ok(request)
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_openai_key_using_credentials_flow(
|
||||
mut resource: OpenaiClientCredentialsOauthResource,
|
||||
async fn get_token_using_oauth(
|
||||
mut resource: AIOAuthResource,
|
||||
db: &DB,
|
||||
w_id: &str,
|
||||
) -> Result<String> {
|
||||
@@ -199,115 +114,114 @@ mod openai {
|
||||
resource.token_url = get_variable_or_self(resource.token_url, db, w_id).await?;
|
||||
let mut params = HashMap::new();
|
||||
params.insert("grant_type", "client_credentials");
|
||||
params.insert("scope", "https://cognitiveservices.azure.com/.default");
|
||||
let response = HTTP_CLIENT
|
||||
.post(resource.token_url)
|
||||
.form(¶ms)
|
||||
.basic_auth(resource.client_id, Some(resource.client_secret))
|
||||
.send()
|
||||
.await
|
||||
.and_then(|r| r.error_for_status())
|
||||
.map_err(|err| {
|
||||
Error::internal_err(format!(
|
||||
"Failed to get OpenAI credentials using credentials flow: {}",
|
||||
"Failed to get access token using credentials flow: {}",
|
||||
err
|
||||
))
|
||||
})?;
|
||||
let response = response.json::<OpenaiCredentials>().await.map_err(|err| {
|
||||
let response = response.json::<OAuthTokens>().await.map_err(|err| {
|
||||
Error::internal_err(format!(
|
||||
"Failed to parse OpenAI credentials from credentials flow: {}",
|
||||
"Failed to parse access token from credentials flow: {}",
|
||||
err
|
||||
))
|
||||
})?;
|
||||
Ok(response.access_token)
|
||||
}
|
||||
|
||||
pub async fn get_cached_value(db: &DB, w_id: &str, resource: Value) -> Result<KeyCache> {
|
||||
let config = serde_json::from_value(resource)
|
||||
.map_err(|e| Error::internal_err(format!("validating openai resource {e:#}")))?;
|
||||
pub fn prepare_request(
|
||||
self,
|
||||
provider: &AIProvider,
|
||||
path: &str,
|
||||
body: Bytes,
|
||||
) -> Result<RequestBuilder> {
|
||||
let url = format!("{}/{}", self.base_url, path);
|
||||
|
||||
let mut user = None::<String>;
|
||||
let mut resource = match config {
|
||||
OpenaiConfig::Resource(resource) => {
|
||||
tracing::debug!("Getting OpenAI key from static resource");
|
||||
resource
|
||||
}
|
||||
OpenaiConfig::ClientCredentialsOauthResource(resource) => {
|
||||
tracing::debug!("Getting OpenAI key with client credentials flow");
|
||||
user = resource.user.clone();
|
||||
let token = get_openai_key_using_credentials_flow(resource, db, w_id).await?;
|
||||
OpenaiResource { api_key: token, organization_id: None }
|
||||
}
|
||||
};
|
||||
|
||||
resource.api_key = get_variable_or_self(resource.api_key, db, w_id).await?;
|
||||
|
||||
if let Some(organization_id) = resource.organization_id {
|
||||
resource.organization_id = Some(get_variable_or_self(organization_id, db, w_id).await?);
|
||||
}
|
||||
|
||||
if user.is_some() {
|
||||
user = Some(get_variable_or_self(user.unwrap(), db, w_id).await?);
|
||||
}
|
||||
|
||||
let azure_base_path = sqlx::query_scalar!(
|
||||
"SELECT value
|
||||
FROM global_settings
|
||||
WHERE name = 'openai_azure_base_path'",
|
||||
)
|
||||
.fetch_optional(db)
|
||||
.await?;
|
||||
|
||||
let azure_base_path = if let Some(azure_base_path) = azure_base_path {
|
||||
Some(
|
||||
serde_json::from_value::<String>(azure_base_path).map_err(|e| {
|
||||
Error::internal_err(format!("validating openai azure base path {e:#}"))
|
||||
})?,
|
||||
)
|
||||
let body = if let Some(user) = self.user {
|
||||
Self::add_user_to_body(body, user)?
|
||||
} else {
|
||||
OPENAI_AZURE_BASE_PATH.clone()
|
||||
body
|
||||
};
|
||||
|
||||
let workspace_cache = OpenaiCache::new(
|
||||
resource.api_key.clone(),
|
||||
resource.organization_id.clone(),
|
||||
azure_base_path.clone(),
|
||||
user.clone(),
|
||||
let is_azure = matches!(provider, AIProvider::OpenAI) && self.base_url != OPENAI_BASE_URL
|
||||
|| matches!(provider, AIProvider::AzureOpenAI);
|
||||
|
||||
let mut request = HTTP_CLIENT
|
||||
.post(url)
|
||||
.header("content-type", "application/json")
|
||||
.body(body);
|
||||
|
||||
if is_azure {
|
||||
request = request.query(&[("api-version", AZURE_API_VERSION)])
|
||||
}
|
||||
|
||||
if let Some(api_key) = self.api_key {
|
||||
if is_azure {
|
||||
request = request.header("api-key", api_key)
|
||||
} else {
|
||||
request = request.header("authorization", format!("Bearer {}", api_key))
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(access_token) = self.access_token {
|
||||
request = request.header("authorization", format!("Bearer {}", access_token))
|
||||
}
|
||||
|
||||
if let Some(org_id) = self.organization_id {
|
||||
request = request.header("OpenAI-Organization", org_id);
|
||||
}
|
||||
|
||||
Ok(request)
|
||||
}
|
||||
|
||||
fn add_user_to_body(body: Bytes, user: String) -> Result<Bytes> {
|
||||
tracing::debug!("Adding user to request body");
|
||||
let mut json_body: HashMap<String, Box<RawValue>> = serde_json::from_slice(&body)
|
||||
.map_err(|e| Error::internal_err(format!("Failed to parse request body: {}", e)))?;
|
||||
|
||||
let user_json_string = serde_json::Value::String(user).to_string(); // makes sure to escape characters
|
||||
|
||||
json_body.insert(
|
||||
"user".to_string(),
|
||||
RawValue::from_string(user_json_string)
|
||||
.map_err(|e| Error::internal_err(format!("Failed to parse user: {}", e)))?,
|
||||
);
|
||||
Ok(KeyCache::Openai(workspace_cache))
|
||||
|
||||
Ok(serde_json::to_vec(&json_body)
|
||||
.map_err(|e| Error::internal_err(format!("Failed to reserialize request body: {}", e)))?
|
||||
.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum KeyCache {
|
||||
Openai(OpenaiCache),
|
||||
OpenaiApiCompatible(OpenaiApiCompatibleCache),
|
||||
pub struct ExpiringAIRequestConfig {
|
||||
config: AIRequestConfig,
|
||||
expires_at: std::time::Instant,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AICache {
|
||||
pub cached_key: KeyCache,
|
||||
pub expires_at: std::time::Instant,
|
||||
}
|
||||
|
||||
impl AICache {
|
||||
pub fn new(cached_key: KeyCache) -> Self {
|
||||
Self {
|
||||
cached_key,
|
||||
expires_at: std::time::Instant::now() + std::time::Duration::from_secs(60),
|
||||
}
|
||||
impl ExpiringAIRequestConfig {
|
||||
fn new(config: AIRequestConfig) -> Self {
|
||||
Self { config, expires_at: std::time::Instant::now() + std::time::Duration::from_secs(60) }
|
||||
}
|
||||
fn is_expired(&self) -> bool {
|
||||
self.expires_at < std::time::Instant::now()
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref AI_KEY_CACHE: Cache<(String, AIProvider), AICache> = Cache::new(500);
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Hash, Clone)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum AIProvider {
|
||||
OpenAI,
|
||||
#[serde(rename = "azure_openai")]
|
||||
AzureOpenAI,
|
||||
Anthropic,
|
||||
Mistral,
|
||||
DeepSeek,
|
||||
@@ -319,19 +233,48 @@ pub enum AIProvider {
|
||||
}
|
||||
|
||||
impl AIProvider {
|
||||
pub fn get_base_url(&self) -> Result<Option<String>> {
|
||||
pub async fn get_base_url(&self, resource_base_url: Option<String>, db: &DB) -> Result<String> {
|
||||
match self {
|
||||
AIProvider::DeepSeek => Ok(Some("https://api.deepseek.com/v1".to_string())),
|
||||
AIProvider::GoogleAI => Ok(Some(
|
||||
"https://generativelanguage.googleapis.com/v1beta/openai".to_string(),
|
||||
)),
|
||||
AIProvider::Groq => Ok(Some("https://api.groq.com/openai/v1".to_string())),
|
||||
AIProvider::OpenRouter => Ok(Some("https://openrouter.ai/api/v1".to_string())),
|
||||
AIProvider::TogetherAI => Ok(Some("https://api.together.xyz/v1".to_string())),
|
||||
AIProvider::Anthropic => Ok(Some("https://api.anthropic.com/v1".to_string())),
|
||||
AIProvider::Mistral => Ok(Some("https://api.mistral.ai/v1".to_string())),
|
||||
AIProvider::CustomAI => Ok(None),
|
||||
AIProvider::OpenAI => Ok(Some(openai::BASE_URL.to_string())),
|
||||
AIProvider::OpenAI => {
|
||||
let azure_base_path = sqlx::query_scalar!(
|
||||
"SELECT value
|
||||
FROM global_settings
|
||||
WHERE name = 'openai_azure_base_path'",
|
||||
)
|
||||
.fetch_optional(db)
|
||||
.await?;
|
||||
|
||||
let azure_base_path = if let Some(azure_base_path) = azure_base_path {
|
||||
Some(
|
||||
serde_json::from_value::<String>(azure_base_path).map_err(|e| {
|
||||
Error::internal_err(format!("validating openai azure base path {e:#}"))
|
||||
})?,
|
||||
)
|
||||
} else {
|
||||
OPENAI_AZURE_BASE_PATH.clone()
|
||||
};
|
||||
|
||||
Ok(azure_base_path.unwrap_or(OPENAI_BASE_URL.to_string()))
|
||||
}
|
||||
AIProvider::DeepSeek => Ok("https://api.deepseek.com/v1".to_string()),
|
||||
AIProvider::GoogleAI => {
|
||||
Ok("https://generativelanguage.googleapis.com/v1beta/openai".to_string())
|
||||
}
|
||||
AIProvider::Groq => Ok("https://api.groq.com/openai/v1".to_string()),
|
||||
AIProvider::OpenRouter => Ok("https://openrouter.ai/api/v1".to_string()),
|
||||
AIProvider::TogetherAI => Ok("https://api.together.xyz/v1".to_string()),
|
||||
AIProvider::Anthropic => Ok("https://api.anthropic.com/v1".to_string()),
|
||||
AIProvider::Mistral => Ok("https://api.mistral.ai/v1".to_string()),
|
||||
p @ (AIProvider::CustomAI | AIProvider::AzureOpenAI) => {
|
||||
if let Some(base_url) = resource_base_url {
|
||||
Ok(base_url)
|
||||
} else {
|
||||
Err(Error::BadRequest(format!(
|
||||
"{:?} provider requires a base URL in the resource",
|
||||
p
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -339,18 +282,9 @@ impl AIProvider {
|
||||
impl TryFrom<&str> for AIProvider {
|
||||
type Error = Error;
|
||||
fn try_from(s: &str) -> Result<Self> {
|
||||
match s {
|
||||
"openai" => Ok(AIProvider::OpenAI),
|
||||
"anthropic" => Ok(AIProvider::Anthropic),
|
||||
"mistral" => Ok(AIProvider::Mistral),
|
||||
"groq" => Ok(AIProvider::Groq),
|
||||
"openrouter" => Ok(AIProvider::OpenRouter),
|
||||
"togetherai" => Ok(AIProvider::TogetherAI),
|
||||
"deepseek" => Ok(AIProvider::DeepSeek),
|
||||
"googleai" => Ok(AIProvider::GoogleAI),
|
||||
"customai" => Ok(AIProvider::CustomAI),
|
||||
_ => Err(Error::BadRequest(format!("Invalid AI provider: {}", s))),
|
||||
}
|
||||
let s = serde_json::from_value::<AIProvider>(serde_json::Value::String(s.to_string()))
|
||||
.map_err(|e| Error::BadRequest(format!("Invalid AI provider: {}", e)))?;
|
||||
Ok(s)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -407,11 +341,7 @@ async fn global_proxy(
|
||||
return Err(Error::BadRequest("API key is required".to_string()));
|
||||
};
|
||||
|
||||
let base_url = provider.get_base_url()?;
|
||||
|
||||
let Some(base_url) = base_url else {
|
||||
return Err(Error::BadRequest("Provider is not supported".to_string()));
|
||||
};
|
||||
let base_url = provider.get_base_url(None, &db).await?;
|
||||
|
||||
let url = format!("{}/{}", base_url, ai_path);
|
||||
|
||||
@@ -439,7 +369,7 @@ async fn global_proxy(
|
||||
|
||||
if response.error_for_status_ref().is_err() {
|
||||
let err_msg = response.text().await.unwrap_or("".to_string());
|
||||
return Err(Error::AiError(err_msg));
|
||||
return Err(Error::AIError(err_msg));
|
||||
}
|
||||
|
||||
let status_code = response.status();
|
||||
@@ -464,32 +394,19 @@ async fn proxy(
|
||||
None => return Err(Error::BadRequest("Provider is required".to_string())),
|
||||
};
|
||||
|
||||
let workspace_cache = AI_KEY_CACHE.get(&(w_id.clone(), provider.clone()));
|
||||
let workspace_cache = AI_REQUEST_CACHE.get(&(w_id.clone(), provider.clone()));
|
||||
|
||||
let forced_resource_path = headers
|
||||
.get("X-Resource-Path")
|
||||
.map(|v| v.to_str().unwrap_or("").to_string());
|
||||
let ai_cache = match workspace_cache {
|
||||
Some(cache) if !cache.is_expired() && forced_resource_path.is_none() => cache.cached_key,
|
||||
let request_config = match workspace_cache {
|
||||
Some(request_cache) if !request_cache.is_expired() && forced_resource_path.is_none() => {
|
||||
request_cache.config
|
||||
}
|
||||
_ => {
|
||||
let (resource, ai_provider, save_to_cache) = if let Some(resource_path) =
|
||||
forced_resource_path
|
||||
{
|
||||
// forced resource path, get the resource directly
|
||||
let resource = sqlx::query_scalar!(
|
||||
"SELECT value FROM resource WHERE path = $1 AND workspace_id = $2",
|
||||
&resource_path,
|
||||
&w_id
|
||||
)
|
||||
.fetch_optional(&db)
|
||||
.await?
|
||||
.ok_or_else(|| {
|
||||
Error::NotFound(format!(
|
||||
"Could not find the resource {}, update the resource path in the workspace settings", resource_path
|
||||
))
|
||||
})?;
|
||||
|
||||
(resource, provider, false)
|
||||
let (resource_path, save_to_cache) = if let Some(resource_path) = forced_resource_path {
|
||||
// forced resource path
|
||||
(resource_path, false)
|
||||
} else {
|
||||
let ai_config = sqlx::query_scalar!(
|
||||
"SELECT ai_config FROM workspace_settings WHERE workspace_id = $1",
|
||||
@@ -504,13 +421,13 @@ async fn proxy(
|
||||
));
|
||||
}
|
||||
|
||||
let ai_config = serde_json::from_value::<AIConfig>(ai_config.unwrap())
|
||||
let mut ai_config = serde_json::from_value::<AIConfig>(ai_config.unwrap())
|
||||
.map_err(|e| Error::BadRequest(e.to_string()))?;
|
||||
|
||||
let provider_config = ai_config
|
||||
.providers
|
||||
.as_ref()
|
||||
.map(|providers| providers.get(&provider))
|
||||
.as_mut()
|
||||
.map(|providers| providers.remove(&provider))
|
||||
.flatten()
|
||||
.ok_or_else(|| {
|
||||
Error::BadRequest(format!("Provider {:?} not configured", provider))
|
||||
@@ -519,56 +436,37 @@ async fn proxy(
|
||||
if provider_config.resource_path.is_empty() {
|
||||
return Err(Error::BadRequest("Resource path is empty".to_string()));
|
||||
}
|
||||
let resource = sqlx::query_scalar!(
|
||||
"SELECT value
|
||||
FROM resource
|
||||
WHERE path = $1 AND workspace_id = $2",
|
||||
&provider_config.resource_path,
|
||||
&w_id
|
||||
)
|
||||
.fetch_optional(&db)
|
||||
.await?
|
||||
.ok_or_else(|| {
|
||||
Error::NotFound(format!(
|
||||
"Could not find the {:?} resource at path {}, update the resource path in the workspace settings", provider, provider_config.resource_path
|
||||
))
|
||||
})?;
|
||||
|
||||
(resource, provider, true)
|
||||
(provider_config.resource_path, true)
|
||||
};
|
||||
|
||||
let Some(resource) = resource else {
|
||||
return Err(Error::internal_err(format!(
|
||||
"{:?} resource missing value",
|
||||
ai_provider
|
||||
)));
|
||||
};
|
||||
let resource= sqlx::query_scalar!(
|
||||
"SELECT value as \"value: sqlx::types::Json<Box<RawValue>>\" FROM resource WHERE path = $1 AND workspace_id = $2",
|
||||
&resource_path,
|
||||
&w_id
|
||||
)
|
||||
.fetch_optional(&db)
|
||||
.await?
|
||||
.ok_or_else(|| Error::NotFound(format!("Could not find the resource {}, update the resource path in the workspace settings", resource_path)))?
|
||||
.ok_or_else(|| Error::BadRequest(format!("Empty resource value for {}", resource_path)))?;
|
||||
|
||||
let ai_cache = match ai_provider {
|
||||
AIProvider::OpenAI => openai::get_cached_value(&db, &w_id, resource).await?,
|
||||
_ => {
|
||||
openai_api_compatible::get_cached_value(
|
||||
&db,
|
||||
&w_id,
|
||||
resource,
|
||||
ai_provider.get_base_url()?,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
};
|
||||
let resource = serde_json::from_str::<AIResource>(resource.0.get())
|
||||
.map_err(|e| Error::BadRequest(e.to_string()))?;
|
||||
|
||||
let request_config = AIRequestConfig::new(&provider, &db, &w_id, resource).await?;
|
||||
if save_to_cache {
|
||||
AI_KEY_CACHE.insert((w_id.clone(), ai_provider), AICache::new(ai_cache.clone()));
|
||||
AI_REQUEST_CACHE.insert(
|
||||
(w_id.clone(), provider.clone()),
|
||||
ExpiringAIRequestConfig::new(request_config.clone()),
|
||||
);
|
||||
}
|
||||
ai_cache
|
||||
request_config
|
||||
}
|
||||
};
|
||||
|
||||
let request = match ai_cache {
|
||||
KeyCache::Openai(cached) => cached.prepare_request(&ai_path, body),
|
||||
KeyCache::OpenaiApiCompatible(cached) => cached.prepare_request(&ai_path, body),
|
||||
};
|
||||
let request = request_config.prepare_request(&provider, &ai_path, body)?;
|
||||
|
||||
let response = request?.send().await.map_err(to_anyhow)?;
|
||||
let response = request.send().await.map_err(to_anyhow)?;
|
||||
|
||||
let mut tx = db.begin().await?;
|
||||
|
||||
@@ -586,7 +484,7 @@ async fn proxy(
|
||||
|
||||
if response.error_for_status_ref().is_err() {
|
||||
let err_msg = response.text().await.unwrap_or("".to_string());
|
||||
return Err(Error::AiError(err_msg));
|
||||
return Err(Error::AIError(err_msg));
|
||||
}
|
||||
|
||||
let status_code = response.status();
|
||||
|
||||
@@ -509,7 +509,6 @@ where
|
||||
.map(|x| x.0)
|
||||
.unwrap_or_default();
|
||||
let path_vec: Vec<&str> = original_uri.path().split("/").collect();
|
||||
|
||||
let workspace_id = if path_vec.len() >= 4 && path_vec[0] == "" && path_vec[2] == "w" {
|
||||
Some(path_vec[3].to_owned())
|
||||
} else {
|
||||
|
||||
@@ -7,34 +7,47 @@
|
||||
*/
|
||||
|
||||
#[cfg(feature = "http_trigger")]
|
||||
use crate::http_triggers::{build_http_trigger_extra, HttpMethod};
|
||||
use {
|
||||
crate::{
|
||||
args::try_from_request_body,
|
||||
http_triggers::{build_http_trigger_extra, HttpMethod},
|
||||
},
|
||||
axum::response::{IntoResponse, Response},
|
||||
std::collections::HashMap,
|
||||
};
|
||||
|
||||
#[cfg(all(feature = "enterprise", feature = "gcp_trigger"))]
|
||||
use crate::gcp_triggers_ee::{
|
||||
manage_google_subscription, process_google_push_request, validate_jwt_token, SubscriptionMode,
|
||||
};
|
||||
|
||||
#[cfg(any(
|
||||
feature = "http_trigger",
|
||||
all(feature = "enterprise", feature = "gcp_trigger")
|
||||
))]
|
||||
use {
|
||||
axum::extract::Request, http::HeaderMap, serde::de::DeserializeOwned,
|
||||
windmill_common::error::Error,
|
||||
};
|
||||
|
||||
#[cfg(all(feature = "enterprise", feature = "kafka"))]
|
||||
use crate::kafka_triggers_ee::KafkaTriggerConfigConnection;
|
||||
|
||||
#[cfg(feature = "mqtt_trigger")]
|
||||
use crate::mqtt_triggers::{MqttClientVersion, MqttV3Config, MqttV5Config, SubscribeTopic};
|
||||
|
||||
#[cfg(all(feature = "enterprise", feature = "nats"))]
|
||||
use crate::nats_triggers_ee::NatsTriggerConfigConnection;
|
||||
|
||||
#[cfg(feature = "postgres_trigger")]
|
||||
use crate::postgres_triggers::{
|
||||
create_logical_replication_slot_query, create_publication_query, drop_publication_query,
|
||||
generate_random_string, get_database_connection, PublicationData,
|
||||
use {
|
||||
crate::postgres_triggers::{
|
||||
create_logical_replication_slot_query, create_publication_query, drop_publication_query,
|
||||
generate_random_string, get_database_connection, PublicationData,
|
||||
},
|
||||
itertools::Itertools,
|
||||
pg_escape::quote_literal,
|
||||
};
|
||||
#[cfg(feature = "http_trigger")]
|
||||
use axum::extract::Request;
|
||||
#[cfg(feature = "http_trigger")]
|
||||
use axum::response::IntoResponse;
|
||||
#[cfg(feature = "http_trigger")]
|
||||
use http::HeaderMap;
|
||||
#[cfg(feature = "postgres_trigger")]
|
||||
use itertools::Itertools;
|
||||
#[cfg(feature = "postgres_trigger")]
|
||||
use pg_escape::quote_literal;
|
||||
#[cfg(feature = "http_trigger")]
|
||||
use serde::de::DeserializeOwned;
|
||||
#[cfg(feature = "http_trigger")]
|
||||
use std::collections::HashMap;
|
||||
#[cfg(feature = "http_trigger")]
|
||||
use windmill_common::error::Error;
|
||||
|
||||
use crate::{
|
||||
args::WebhookArgs,
|
||||
@@ -42,23 +55,26 @@ use crate::{
|
||||
users::fetch_api_authed,
|
||||
utils::RunnableKind,
|
||||
};
|
||||
|
||||
use axum::{
|
||||
extract::{Extension, Path, Query},
|
||||
routing::{delete, get, head, post},
|
||||
Json, Router,
|
||||
};
|
||||
|
||||
use hyper::StatusCode;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::value::RawValue;
|
||||
use sqlx::types::Json as SqlxJson;
|
||||
|
||||
use windmill_common::{
|
||||
db::UserDB,
|
||||
error::{JsonResult, Result},
|
||||
utils::{not_found_if_none, paginate, Pagination, StripPath},
|
||||
worker::{to_raw_value, CLOUD_HOSTED},
|
||||
};
|
||||
use windmill_queue::TriggerKind;
|
||||
use windmill_queue::{PushArgs, PushArgsOwned};
|
||||
|
||||
use windmill_queue::{PushArgs, PushArgsOwned, TriggerKind};
|
||||
|
||||
const KEEP_LAST: i64 = 20;
|
||||
|
||||
@@ -85,14 +101,26 @@ pub fn workspaced_unauthed_service() -> Router {
|
||||
head(|| async {}).post(webhook_payload),
|
||||
);
|
||||
|
||||
#[cfg(feature = "http_trigger")]
|
||||
#[cfg(any(
|
||||
feature = "http_trigger",
|
||||
all(feature = "enterprise", feature = "gcp_trigger")
|
||||
))]
|
||||
{
|
||||
router.route("/http/:runnable_kind/:path/*route_path", {
|
||||
#[cfg(feature = "http_trigger")]
|
||||
let router = router.route("/http/:runnable_kind/:path/*route_path", {
|
||||
head(|| async {}).fallback(http_payload)
|
||||
})
|
||||
});
|
||||
|
||||
#[cfg(all(feature = "enterprise", feature = "gcp_trigger"))]
|
||||
let router = router.route("/gcp/:runnable_kind/*path", post(gcp_payload));
|
||||
|
||||
router
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "http_trigger"))]
|
||||
#[cfg(not(any(
|
||||
feature = "http_trigger",
|
||||
all(feature = "enterprise", feature = "gcp_trigger")
|
||||
)))]
|
||||
{
|
||||
router
|
||||
}
|
||||
@@ -124,6 +152,15 @@ pub struct SqsTriggerConfig {
|
||||
pub message_attributes: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "enterprise", feature = "gcp_trigger"))]
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct GcpTriggerConfig {
|
||||
pub gcp_resource_path: String,
|
||||
#[serde(flatten)]
|
||||
pub subscription_mode: SubscriptionMode,
|
||||
pub topic_id: String,
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "enterprise", feature = "nats"))]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct NatsTriggerConfig {
|
||||
@@ -181,6 +218,8 @@ enum TriggerConfig {
|
||||
Nats(NatsTriggerConfig),
|
||||
#[cfg(feature = "mqtt_trigger")]
|
||||
Mqtt(MqttTriggerConfig),
|
||||
#[cfg(all(feature = "enterprise", feature = "gcp_trigger"))]
|
||||
Gcp(GcpTriggerConfig),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
@@ -208,15 +247,26 @@ async fn get_configs(
|
||||
|
||||
let configs = sqlx::query_as!(
|
||||
CaptureConfig,
|
||||
r#"SELECT trigger_config as "trigger_config: _", trigger_kind as "trigger_kind: _", error, last_server_ping
|
||||
FROM capture_config
|
||||
WHERE workspace_id = $1 AND path = $2 AND is_flow = $3"#,
|
||||
r#"
|
||||
SELECT
|
||||
trigger_config AS "trigger_config: _",
|
||||
trigger_kind AS "trigger_kind: _",
|
||||
error,
|
||||
last_server_ping
|
||||
FROM
|
||||
capture_config
|
||||
WHERE
|
||||
workspace_id = $1
|
||||
AND path = $2
|
||||
AND is_flow = $3
|
||||
"#,
|
||||
&w_id,
|
||||
&path.to_path(),
|
||||
matches!(runnable_kind, RunnableKind::Flow),
|
||||
)
|
||||
.fetch_all(&mut *tx)
|
||||
.await?;
|
||||
|
||||
tx.commit().await?;
|
||||
|
||||
Ok(Json(configs))
|
||||
@@ -284,33 +334,100 @@ async fn set_postgres_trigger_config(
|
||||
Ok(capture_config)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(not(feature = "postgres_trigger"))]
|
||||
async fn set_postgres_trigger_config(
|
||||
_w_id: &str,
|
||||
_authed: ApiAuthed,
|
||||
_db: &DB,
|
||||
_user_db: UserDB,
|
||||
capture_config: NewCaptureConfig,
|
||||
) -> Result<NewCaptureConfig> {
|
||||
Ok(capture_config)
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "enterprise", feature = "gcp_trigger"))]
|
||||
async fn set_gcp_trigger_config(
|
||||
w_id: &str,
|
||||
authed: ApiAuthed,
|
||||
db: &DB,
|
||||
mut capture_config: NewCaptureConfig,
|
||||
) -> Result<NewCaptureConfig> {
|
||||
let Some(TriggerConfig::Gcp(mut gcp_config)) = capture_config.trigger_config else {
|
||||
return Err(windmill_common::error::Error::BadRequest(
|
||||
"Invalid GCP Pub/Sub config".to_string(),
|
||||
));
|
||||
};
|
||||
|
||||
let config = manage_google_subscription(
|
||||
authed,
|
||||
db,
|
||||
w_id,
|
||||
&gcp_config.gcp_resource_path,
|
||||
&capture_config.path,
|
||||
&gcp_config.topic_id,
|
||||
gcp_config.subscription_mode,
|
||||
)
|
||||
.await?;
|
||||
|
||||
gcp_config.subscription_mode = SubscriptionMode::CreateUpdate(config);
|
||||
capture_config.trigger_config = Some(TriggerConfig::Gcp(gcp_config));
|
||||
|
||||
Ok(capture_config)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(not(all(feature = "enterprise", feature = "gcp_trigger")))]
|
||||
async fn set_gcp_trigger_config(
|
||||
_w_id: &str,
|
||||
_authed: ApiAuthed,
|
||||
_db: &DB,
|
||||
capture_config: NewCaptureConfig,
|
||||
) -> Result<NewCaptureConfig> {
|
||||
Ok(capture_config)
|
||||
}
|
||||
|
||||
async fn set_config(
|
||||
authed: ApiAuthed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
#[cfg(feature = "postgres_trigger")] Extension(db): Extension<DB>,
|
||||
Extension(db): Extension<DB>,
|
||||
Path(w_id): Path<String>,
|
||||
Json(nc): Json<NewCaptureConfig>,
|
||||
) -> Result<()> {
|
||||
#[cfg(feature = "postgres_trigger")]
|
||||
let nc = if let TriggerKind::Postgres = nc.trigger_kind {
|
||||
set_postgres_trigger_config(&w_id, authed.clone(), &db, user_db.clone(), nc).await?
|
||||
} else {
|
||||
nc
|
||||
) -> JsonResult<Option<TriggerConfig>> {
|
||||
let nc = match nc.trigger_kind {
|
||||
TriggerKind::Postgres => {
|
||||
set_postgres_trigger_config(&w_id, authed.clone(), &db, user_db.clone(), nc).await?
|
||||
}
|
||||
TriggerKind::Gcp => set_gcp_trigger_config(&w_id, authed.clone(), &db, nc).await?,
|
||||
_ => nc,
|
||||
};
|
||||
|
||||
let mut tx = user_db.begin(&authed).await?;
|
||||
|
||||
sqlx::query!(
|
||||
"INSERT INTO capture_config
|
||||
(workspace_id, path, is_flow, trigger_kind, trigger_config, owner, email)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
r#"
|
||||
INSERT INTO capture_config (
|
||||
workspace_id, path, is_flow, trigger_kind, trigger_config, owner, email
|
||||
)
|
||||
VALUES (
|
||||
$1, $2, $3, $4, $5, $6, $7
|
||||
)
|
||||
ON CONFLICT (workspace_id, path, is_flow, trigger_kind)
|
||||
DO UPDATE SET trigger_config = $5, owner = $6, email = $7, server_id = NULL, error = NULL",
|
||||
DO UPDATE
|
||||
SET
|
||||
trigger_config = $5,
|
||||
owner = $6,
|
||||
email = $7,
|
||||
server_id = NULL,
|
||||
error = NULL
|
||||
"#,
|
||||
&w_id,
|
||||
&nc.path,
|
||||
nc.is_flow,
|
||||
nc.trigger_kind as TriggerKind,
|
||||
nc.trigger_config.map(|x| SqlxJson(to_raw_value(&x))) as Option<SqlxJson<Box<RawValue>>>,
|
||||
nc.trigger_config
|
||||
.as_ref()
|
||||
.map(|x| SqlxJson(to_raw_value(&x))) as Option<SqlxJson<Box<RawValue>>>,
|
||||
&authed.username,
|
||||
&authed.email,
|
||||
)
|
||||
@@ -319,7 +436,7 @@ async fn set_config(
|
||||
|
||||
tx.commit().await?;
|
||||
|
||||
Ok(())
|
||||
Ok(Json(nc.trigger_config))
|
||||
}
|
||||
|
||||
async fn ping_config(
|
||||
@@ -333,8 +450,19 @@ async fn ping_config(
|
||||
)>,
|
||||
) -> Result<()> {
|
||||
let mut tx = user_db.begin(&authed).await?;
|
||||
|
||||
sqlx::query!(
|
||||
"UPDATE capture_config SET last_client_ping = now() WHERE workspace_id = $1 AND path = $2 AND is_flow = $3 AND trigger_kind = $4",
|
||||
r#"
|
||||
UPDATE
|
||||
capture_config
|
||||
SET
|
||||
last_client_ping = NOW()
|
||||
WHERE
|
||||
workspace_id = $1
|
||||
AND path = $2
|
||||
AND is_flow = $3
|
||||
AND trigger_kind = $4
|
||||
"#,
|
||||
&w_id,
|
||||
&path.to_path(),
|
||||
matches!(runnable_kind, RunnableKind::Flow),
|
||||
@@ -342,6 +470,7 @@ async fn ping_config(
|
||||
)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
|
||||
tx.commit().await?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -374,14 +503,28 @@ async fn list_captures(
|
||||
|
||||
let captures = sqlx::query_as!(
|
||||
Capture,
|
||||
r#"SELECT id, created_at, trigger_kind as "trigger_kind: _", CASE WHEN pg_column_size(payload) < 40000 THEN payload ELSE '"WINDMILL_TOO_BIG"'::jsonb END as "payload!: _", trigger_extra as "trigger_extra: _"
|
||||
FROM capture
|
||||
WHERE workspace_id = $1
|
||||
AND path = $2 AND is_flow = $3
|
||||
r#"
|
||||
SELECT
|
||||
id,
|
||||
created_at,
|
||||
trigger_kind AS "trigger_kind: _",
|
||||
CASE
|
||||
WHEN pg_column_size(payload) < 40000 THEN payload
|
||||
ELSE '"WINDMILL_TOO_BIG"'::jsonb
|
||||
END AS "payload!: _",
|
||||
trigger_extra AS "trigger_extra: _"
|
||||
FROM
|
||||
capture
|
||||
WHERE
|
||||
workspace_id = $1
|
||||
AND path = $2
|
||||
AND is_flow = $3
|
||||
AND ($4::trigger_kind IS NULL OR trigger_kind = $4)
|
||||
ORDER BY created_at DESC
|
||||
ORDER BY
|
||||
created_at DESC
|
||||
OFFSET $5
|
||||
LIMIT $6"#,
|
||||
LIMIT $6
|
||||
"#,
|
||||
&w_id,
|
||||
&path.to_path(),
|
||||
matches!(runnable_kind, RunnableKind::Flow),
|
||||
@@ -403,14 +546,28 @@ async fn get_capture(
|
||||
Path((w_id, id)): Path<(String, i64)>,
|
||||
) -> JsonResult<Capture> {
|
||||
let mut tx = user_db.begin(&authed).await?;
|
||||
|
||||
let capture = sqlx::query_as!(
|
||||
Capture,
|
||||
r#"SELECT id, created_at, trigger_kind as "trigger_kind: _", payload as "payload!: _", trigger_extra as "trigger_extra: _" FROM capture WHERE id = $1 AND workspace_id = $2"#,
|
||||
r#"
|
||||
SELECT
|
||||
id,
|
||||
created_at,
|
||||
trigger_kind AS "trigger_kind: _",
|
||||
payload AS "payload!: _",
|
||||
trigger_extra AS "trigger_extra: _"
|
||||
FROM
|
||||
capture
|
||||
WHERE
|
||||
id = $1
|
||||
AND workspace_id = $2
|
||||
"#,
|
||||
id,
|
||||
&w_id,
|
||||
)
|
||||
.fetch_one(&mut *tx)
|
||||
.await?;
|
||||
.await?;
|
||||
|
||||
tx.commit().await?;
|
||||
Ok(Json(capture))
|
||||
}
|
||||
@@ -421,9 +578,17 @@ async fn delete_capture(
|
||||
Path((_, id)): Path<(String, i64)>,
|
||||
) -> Result<()> {
|
||||
let mut tx = user_db.begin(&authed).await?;
|
||||
sqlx::query!("DELETE FROM capture WHERE id = $1", id)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
sqlx::query!(
|
||||
r#"
|
||||
DELETE FROM
|
||||
capture
|
||||
WHERE
|
||||
id = $1
|
||||
"#,
|
||||
id
|
||||
)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -441,8 +606,18 @@ async fn move_captures_and_configs(
|
||||
) -> Result<()> {
|
||||
let mut tx = user_db.begin(&authed).await?;
|
||||
let old_path = old_path.to_path();
|
||||
|
||||
sqlx::query!(
|
||||
"UPDATE capture_config SET path = $1 WHERE path = $2 AND workspace_id = $3 AND is_flow = $4",
|
||||
r#"
|
||||
UPDATE
|
||||
capture_config
|
||||
SET
|
||||
path = $1
|
||||
WHERE
|
||||
path = $2
|
||||
AND workspace_id = $3
|
||||
AND is_flow = $4
|
||||
"#,
|
||||
body.new_path,
|
||||
old_path,
|
||||
&w_id,
|
||||
@@ -450,8 +625,18 @@ async fn move_captures_and_configs(
|
||||
)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
|
||||
sqlx::query!(
|
||||
"UPDATE capture SET path = $1 WHERE path = $2 AND workspace_id = $3 AND is_flow = $4",
|
||||
r#"
|
||||
UPDATE
|
||||
capture
|
||||
SET
|
||||
path = $1
|
||||
WHERE
|
||||
path = $2
|
||||
AND workspace_id = $3
|
||||
AND is_flow = $4
|
||||
"#,
|
||||
body.new_path,
|
||||
old_path,
|
||||
&w_id,
|
||||
@@ -459,6 +644,7 @@ async fn move_captures_and_configs(
|
||||
)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
|
||||
tx.commit().await?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -478,9 +664,19 @@ pub async fn get_active_capture_owner_and_email(
|
||||
) -> Result<(String, String)> {
|
||||
let capture_config = sqlx::query_as!(
|
||||
ActiveCaptureOwner,
|
||||
"SELECT owner, email
|
||||
FROM capture_config
|
||||
WHERE workspace_id = $1 AND path = $2 AND is_flow = $3 AND trigger_kind = $4 AND last_client_ping > NOW() - INTERVAL '10 seconds'",
|
||||
r#"
|
||||
SELECT
|
||||
owner,
|
||||
email
|
||||
FROM
|
||||
capture_config
|
||||
WHERE
|
||||
workspace_id = $1
|
||||
AND path = $2
|
||||
AND is_flow = $3
|
||||
AND trigger_kind = $4
|
||||
AND last_client_ping > NOW() - INTERVAL '10 seconds'
|
||||
"#,
|
||||
&w_id,
|
||||
&path,
|
||||
is_flow,
|
||||
@@ -498,7 +694,10 @@ pub async fn get_active_capture_owner_and_email(
|
||||
Ok((capture_config.owner, capture_config.email))
|
||||
}
|
||||
|
||||
#[cfg(feature = "http_trigger")]
|
||||
#[cfg(any(
|
||||
feature = "http_trigger",
|
||||
all(feature = "enterprise", feature = "gcp_trigger")
|
||||
))]
|
||||
async fn get_capture_trigger_config_and_owner<T: DeserializeOwned>(
|
||||
db: &DB,
|
||||
w_id: &str,
|
||||
@@ -512,16 +711,34 @@ async fn get_capture_trigger_config_and_owner<T: DeserializeOwned>(
|
||||
owner: String,
|
||||
email: String,
|
||||
}
|
||||
|
||||
let capture_config = sqlx::query_as!(
|
||||
CaptureTriggerConfigAndOwner,
|
||||
r#"SELECT trigger_config as "trigger_config: _", owner, email
|
||||
FROM capture_config
|
||||
WHERE workspace_id = $1 AND path = $2 AND is_flow = $3 AND trigger_kind = $4 AND last_client_ping > NOW() - INTERVAL '10 seconds'"#,
|
||||
r#"
|
||||
SELECT
|
||||
trigger_config AS "trigger_config: _",
|
||||
owner,
|
||||
email
|
||||
FROM
|
||||
capture_config
|
||||
WHERE
|
||||
workspace_id = $1
|
||||
AND path = $2
|
||||
AND is_flow = $3
|
||||
AND trigger_kind = $4
|
||||
AND last_client_ping > NOW() - INTERVAL '10 seconds'
|
||||
AND (
|
||||
$5::bool IS FALSE
|
||||
OR (
|
||||
trigger_config IS NOT NULL
|
||||
AND trigger_config ->> 'delivery_type' = 'push'
|
||||
)
|
||||
)
|
||||
"#,
|
||||
&w_id,
|
||||
&path,
|
||||
is_flow,
|
||||
kind as &TriggerKind,
|
||||
matches!(kind, TriggerKind::Gcp)
|
||||
)
|
||||
.fetch_optional(db)
|
||||
.await?;
|
||||
@@ -554,17 +771,24 @@ async fn clear_captures_history(db: &DB, w_id: &str) -> Result<()> {
|
||||
if *CLOUD_HOSTED {
|
||||
/* Retain only KEEP_LAST most recent captures in this workspace. */
|
||||
sqlx::query!(
|
||||
"DELETE FROM capture
|
||||
WHERE workspace_id = $1
|
||||
AND created_at <=
|
||||
(
|
||||
SELECT created_at
|
||||
FROM capture
|
||||
WHERE workspace_id = $1
|
||||
ORDER BY created_at DESC
|
||||
OFFSET $2
|
||||
LIMIT 1
|
||||
)",
|
||||
r#"
|
||||
DELETE FROM
|
||||
capture
|
||||
WHERE
|
||||
workspace_id = $1
|
||||
AND created_at <= (
|
||||
SELECT
|
||||
created_at
|
||||
FROM
|
||||
capture
|
||||
WHERE
|
||||
workspace_id = $1
|
||||
ORDER BY
|
||||
created_at DESC
|
||||
OFFSET $2
|
||||
LIMIT 1
|
||||
)
|
||||
"#,
|
||||
&w_id,
|
||||
KEEP_LAST,
|
||||
)
|
||||
@@ -585,8 +809,15 @@ pub async fn insert_capture_payload(
|
||||
owner: &str,
|
||||
) -> Result<()> {
|
||||
sqlx::query!(
|
||||
"INSERT INTO capture (workspace_id, path, is_flow, trigger_kind, payload, trigger_extra, created_by)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)",
|
||||
r#"
|
||||
INSERT INTO
|
||||
capture (
|
||||
workspace_id, path, is_flow, trigger_kind, payload, trigger_extra, created_by
|
||||
)
|
||||
VALUES (
|
||||
$1, $2, $3, $4, $5, $6, $7
|
||||
)
|
||||
"#,
|
||||
&w_id,
|
||||
path,
|
||||
is_flow,
|
||||
@@ -642,36 +873,74 @@ async fn webhook_payload(
|
||||
Ok(StatusCode::NO_CONTENT)
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "enterprise", feature = "gcp_trigger"))]
|
||||
async fn gcp_payload(
|
||||
Extension(db): Extension<DB>,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
Path((w_id, runnable_kind, path)): Path<(String, RunnableKind, String)>,
|
||||
headers: HeaderMap,
|
||||
request: Request,
|
||||
) -> Result<StatusCode> {
|
||||
let is_flow = matches!(runnable_kind, RunnableKind::Flow);
|
||||
let (gcp_trigger_config, owner, email): (GcpTriggerConfig, _, _) =
|
||||
get_capture_trigger_config_and_owner(&db, &w_id, &path, is_flow, &TriggerKind::Gcp).await?;
|
||||
|
||||
let authed = fetch_api_authed(owner.clone(), email, &w_id, &db, None).await?;
|
||||
|
||||
let SubscriptionMode::CreateUpdate(config) = &gcp_trigger_config.subscription_mode else {
|
||||
return Err(Error::BadConfig("Bad config".to_string()));
|
||||
};
|
||||
|
||||
validate_jwt_token(
|
||||
&db,
|
||||
user_db.clone(),
|
||||
authed.clone(),
|
||||
&headers,
|
||||
&gcp_trigger_config.gcp_resource_path,
|
||||
&w_id,
|
||||
config.delivery_config.as_ref().unwrap(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let (args, extra) = process_google_push_request(headers, request).await?;
|
||||
|
||||
let payload = PushArgsOwned { args, extra: None };
|
||||
|
||||
let _ = insert_capture_payload(
|
||||
&db,
|
||||
&w_id,
|
||||
&path,
|
||||
is_flow,
|
||||
&TriggerKind::Gcp,
|
||||
payload,
|
||||
Some(to_raw_value(&extra)),
|
||||
&owner,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(StatusCode::NO_CONTENT)
|
||||
}
|
||||
|
||||
#[cfg(feature = "http_trigger")]
|
||||
async fn http_payload(
|
||||
Extension(db): Extension<DB>,
|
||||
Path((w_id, kind, path, route_path)): Path<(String, RunnableKind, String, StripPath)>,
|
||||
Path((w_id, runnable_kind, path, route_path)): Path<(String, RunnableKind, String, StripPath)>,
|
||||
Query(query): Query<HashMap<String, String>>,
|
||||
method: http::Method,
|
||||
headers: HeaderMap,
|
||||
request: Request,
|
||||
) -> std::result::Result<StatusCode, impl IntoResponse> {
|
||||
use axum::response::Response;
|
||||
|
||||
use crate::args::try_from_request_body;
|
||||
|
||||
let route_path = route_path.to_path();
|
||||
) -> std::result::Result<StatusCode, Response> {
|
||||
let path = path.replace(".", "/");
|
||||
|
||||
let is_flow = matches!(runnable_kind, RunnableKind::Flow);
|
||||
let route_path = route_path.to_path();
|
||||
let (http_trigger_config, owner, email): (HttpTriggerConfig, _, _) =
|
||||
get_capture_trigger_config_and_owner(
|
||||
&db,
|
||||
&w_id,
|
||||
&path,
|
||||
matches!(kind, RunnableKind::Flow),
|
||||
&TriggerKind::Http,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| e.into_response())?;
|
||||
get_capture_trigger_config_and_owner(&db, &w_id, &path, is_flow, &TriggerKind::Http)
|
||||
.await
|
||||
.map_err(|e| e.into_response())?;
|
||||
|
||||
let args = try_from_request_body(
|
||||
request,
|
||||
&db,
|
||||
&(),
|
||||
http_trigger_config.raw_string,
|
||||
http_trigger_config.wrap_body,
|
||||
)
|
||||
@@ -721,7 +990,7 @@ async fn http_payload(
|
||||
&db,
|
||||
&w_id,
|
||||
&path,
|
||||
matches!(kind, RunnableKind::Flow),
|
||||
is_flow,
|
||||
&TriggerKind::Http,
|
||||
args,
|
||||
extra,
|
||||
@@ -730,5 +999,5 @@ async fn http_payload(
|
||||
.await
|
||||
.map_err(|e| e.into_response())?;
|
||||
|
||||
Ok::<_, Response>(StatusCode::NO_CONTENT)
|
||||
Ok(StatusCode::NO_CONTENT)
|
||||
}
|
||||
|
||||
@@ -215,6 +215,7 @@ async fn get_concurrent_intervals(
|
||||
is_flow_step: _,
|
||||
all_workspaces: _,
|
||||
concurrency_key: Some(_),
|
||||
allow_wildcards: None,
|
||||
} => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Author: Ruben Fiszel
|
||||
* Copyright: Windmill Labs, Inc 2042
|
||||
* Copyright: Windmill Labs, Inc 2024
|
||||
* This file and its contents are licensed under the AGPLv3 License.
|
||||
* Please see the included NOTICE for copyright information and
|
||||
* LICENSE-AGPL for a copy of the license.
|
||||
|
||||
133
backend/windmill-api/src/gcp_triggers_ee.rs
Normal file
133
backend/windmill-api/src/gcp_triggers_ee.rs
Normal file
@@ -0,0 +1,133 @@
|
||||
use crate::db::{ApiAuthed, DB};
|
||||
use axum::{extract::Request, Router};
|
||||
use http::HeaderMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::value::RawValue;
|
||||
use sqlx::prelude::FromRow;
|
||||
use sqlx::types::Json as SqlxJson;
|
||||
use std::collections::HashMap;
|
||||
use windmill_common::db::UserDB;
|
||||
use windmill_common::{
|
||||
error::{Error as WindmillError, Result as WindmillResult},
|
||||
utils::empty_string_as_none,
|
||||
};
|
||||
|
||||
#[derive(sqlx::Type, Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all(serialize = "lowercase", deserialize = "lowercase"))]
|
||||
#[sqlx(type_name = "DELIVERY_MODE", rename_all = "lowercase")]
|
||||
#[allow(unused)]
|
||||
pub enum DeliveryType {
|
||||
Pull,
|
||||
Push,
|
||||
}
|
||||
|
||||
impl Default for DeliveryType {
|
||||
fn default() -> Self {
|
||||
Self::Pull
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(FromRow, Deserialize, Serialize, Debug)]
|
||||
#[allow(unused)]
|
||||
pub struct PushConfig {
|
||||
#[serde(deserialize_with = "empty_string_as_none")]
|
||||
route_path: Option<String>,
|
||||
#[serde(deserialize_with = "empty_string_as_none")]
|
||||
audience: Option<String>,
|
||||
authenticate: bool,
|
||||
base_endpoint: String,
|
||||
}
|
||||
#[derive(Default, Debug, Serialize, Deserialize)]
|
||||
#[allow(unused)]
|
||||
pub struct CreateUpdateConfig {
|
||||
pub delivery_type: DeliveryType,
|
||||
#[serde(default, deserialize_with = "empty_string_as_none")]
|
||||
pub subscription_id: Option<String>,
|
||||
pub delivery_config: Option<SqlxJson<PushConfig>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct ExistingGcpSubscription {
|
||||
pub subscription_id: String,
|
||||
pub base_endpoint: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[serde(tag = "subscription_mode", rename_all = "snake_case")]
|
||||
pub enum SubscriptionMode {
|
||||
Existing(ExistingGcpSubscription),
|
||||
CreateUpdate(CreateUpdateConfig),
|
||||
}
|
||||
|
||||
pub fn workspaced_service() -> Router {
|
||||
Router::new()
|
||||
}
|
||||
|
||||
pub fn start_consuming_gcp_pubsub_event(
|
||||
_db: DB,
|
||||
mut _killpill_rx: tokio::sync::broadcast::Receiver<()>,
|
||||
) -> () {
|
||||
// implementation is not open source
|
||||
}
|
||||
|
||||
pub async fn manage_google_subscription(
|
||||
_authed: ApiAuthed,
|
||||
_db: &DB,
|
||||
_workspace_id: &str,
|
||||
_gcp_resource_path: &str,
|
||||
_path: &str,
|
||||
_topic_id: &str,
|
||||
_subscription_mode: SubscriptionMode,
|
||||
) -> WindmillResult<CreateUpdateConfig> {
|
||||
Ok(CreateUpdateConfig::default())
|
||||
}
|
||||
|
||||
pub async fn process_google_push_request(
|
||||
_headers: HeaderMap,
|
||||
_request: Request,
|
||||
) -> Result<
|
||||
(
|
||||
HashMap<String, Box<RawValue>>,
|
||||
Option<HashMap<String, Box<RawValue>>>,
|
||||
),
|
||||
WindmillError,
|
||||
> {
|
||||
Ok((HashMap::new(), None))
|
||||
}
|
||||
|
||||
pub async fn validate_jwt_token(
|
||||
_db: &DB,
|
||||
_user_db: UserDB,
|
||||
_authed: ApiAuthed,
|
||||
_headers: &HeaderMap,
|
||||
_gcp_resource_path: &str,
|
||||
_workspace_id: &str,
|
||||
_delivery_config: &PushConfig,
|
||||
) -> Result<(), windmill_common::error::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn gcp_push_route_handler() -> Router {
|
||||
Router::new()
|
||||
}
|
||||
|
||||
#[derive(FromRow, Deserialize, Serialize, Debug)]
|
||||
pub struct GcpTrigger {
|
||||
pub gcp_resource_path: String,
|
||||
pub subscription_id: String,
|
||||
pub delivery_type: DeliveryType,
|
||||
pub delivery_config: Option<SqlxJson<PushConfig>>,
|
||||
pub topic_id: String,
|
||||
pub path: String,
|
||||
pub script_path: String,
|
||||
pub is_flow: bool,
|
||||
pub workspace_id: String,
|
||||
pub edited_by: String,
|
||||
pub email: String,
|
||||
pub edited_at: chrono::DateTime<chrono::Utc>,
|
||||
pub extra_perms: Option<serde_json::Value>,
|
||||
pub error: Option<String>,
|
||||
pub server_id: Option<String>,
|
||||
pub last_server_ping: Option<chrono::DateTime<chrono::Utc>>,
|
||||
pub enabled: bool,
|
||||
}
|
||||
@@ -618,7 +618,9 @@ impl AuthenticationMethod {
|
||||
api_key_header,
|
||||
api_key_secret,
|
||||
}) => {
|
||||
let api_key_to_cmp = headers.try_get_webhook_header(&api_key_header)?;
|
||||
let api_key_to_cmp = headers
|
||||
.try_get_webhook_header(&api_key_header)
|
||||
.map_err(|_| AuthenticationError::InvalidApiKey)?;
|
||||
if api_key_to_cmp != api_key_secret {
|
||||
return Err(AuthenticationError::InvalidApiKey);
|
||||
}
|
||||
@@ -734,7 +736,9 @@ impl IntoResponse for AuthenticationError {
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
AuthenticationError::InvalidApiKey => (StatusCode::FORBIDDEN, self.to_string()),
|
||||
AuthenticationError::InvalidApiKey => {
|
||||
return (StatusCode::UNAUTHORIZED, "Unauthorized").into_response()
|
||||
}
|
||||
};
|
||||
|
||||
let body = json!({ "error": error_message });
|
||||
|
||||
@@ -953,7 +953,7 @@ async fn route_job(
|
||||
|
||||
let args = try_from_request_body(
|
||||
request,
|
||||
&db,
|
||||
&(),
|
||||
Some(match trigger.authentication_method {
|
||||
AuthenticationMethod::CustomScript | AuthenticationMethod::Signature => true,
|
||||
_ => trigger.raw_string,
|
||||
|
||||
@@ -26,7 +26,7 @@ use tower::ServiceBuilder;
|
||||
use windmill_common::error::JsonResult;
|
||||
use windmill_common::flow_status::{JobResult, RestartedFrom};
|
||||
use windmill_common::jobs::{format_completed_job_result, format_result, ENTRYPOINT_OVERRIDE};
|
||||
use windmill_common::worker::{CLOUD_HOSTED, TMP_DIR};
|
||||
use windmill_common::worker::{Connection, CLOUD_HOSTED, TMP_DIR};
|
||||
|
||||
use windmill_common::scripts::PREVIEW_IS_CODEBASE_HASH;
|
||||
use windmill_common::variables::get_workspace_key;
|
||||
@@ -372,7 +372,6 @@ async fn cancel_job_api(
|
||||
email: "anonymous".to_string(),
|
||||
},
|
||||
};
|
||||
|
||||
let (mut tx, job_option) = tokio::time::timeout(
|
||||
std::time::Duration::from_secs(120),
|
||||
windmill_queue::cancel_job(
|
||||
@@ -587,7 +586,9 @@ async fn get_flow_job_debug_info(
|
||||
Extension(db): Extension<DB>,
|
||||
Path((w_id, id)): Path<(String, Uuid)>,
|
||||
) -> error::Result<Response> {
|
||||
let job = GetQuery::new().fetch_queued(&db, id, &w_id).await?;
|
||||
let job = GetQuery::new()
|
||||
.fetch_queued((&db).into(), id, &w_id)
|
||||
.await?;
|
||||
if let Some(job) = job {
|
||||
let is_flow = job.is_flow();
|
||||
if job.is_flow_step || !is_flow {
|
||||
@@ -926,8 +927,9 @@ impl<'a> GetQuery<'a> {
|
||||
// Try to fetch the code from the cache, fallback to the preview code.
|
||||
// NOTE: This could check for the job kinds instead of the `or_else` but it's not
|
||||
// necessary as `fetch_script` return early if the job kind is not a preview one.
|
||||
cache::job::fetch_script(db, kind, hash)
|
||||
.or_else(|_| cache::job::fetch_preview_script(db, &id, raw_lock, raw_code))
|
||||
let conn = Connection::from(db.clone());
|
||||
cache::job::fetch_script(db.clone(), kind, hash)
|
||||
.or_else(|_| cache::job::fetch_preview_script(&conn, &id, raw_lock, raw_code))
|
||||
.await
|
||||
.ok()
|
||||
.inspect(|data| {
|
||||
@@ -956,7 +958,7 @@ impl<'a> GetQuery<'a> {
|
||||
|
||||
self.check_auth(job.as_ref().map(|job| job.created_by.as_str()))?;
|
||||
if let Some(job) = job.as_mut() {
|
||||
self.resolve_raw_values(db, job.id, job.job_kind, job.script_hash, job)
|
||||
self.resolve_raw_values(&db, job.id, job.job_kind, job.script_hash, job)
|
||||
.await;
|
||||
}
|
||||
if self.with_flow {
|
||||
@@ -993,12 +995,14 @@ impl<'a> GetQuery<'a> {
|
||||
self.resolve_raw_values(db, job.id, job.job_kind, job.script_hash, job)
|
||||
.await;
|
||||
}
|
||||
|
||||
if self.with_flow {
|
||||
cjob = resolve_maybe_value(db, workspace_id, self.with_code, cjob, |job| {
|
||||
job.raw_flow.as_mut()
|
||||
})
|
||||
.await?;
|
||||
}
|
||||
|
||||
if let Some(mut cjob) = cjob {
|
||||
cjob.inner = format_completed_job_result(cjob.inner);
|
||||
return Ok(Some(cjob));
|
||||
@@ -1008,7 +1012,7 @@ impl<'a> GetQuery<'a> {
|
||||
|
||||
async fn fetch(self, db: &DB, job_id: Uuid, workspace_id: &str) -> error::Result<Job> {
|
||||
let cjob = self
|
||||
.fetch_completed(db, job_id, workspace_id)
|
||||
.fetch_completed(db.into(), job_id, workspace_id)
|
||||
.await?
|
||||
.map(Job::CompletedJob);
|
||||
|
||||
@@ -1016,7 +1020,7 @@ impl<'a> GetQuery<'a> {
|
||||
Some(cjob) => Ok(cjob),
|
||||
None => {
|
||||
let job_maybe = self
|
||||
.fetch_queued(db, job_id, workspace_id)
|
||||
.fetch_queued(db.into(), job_id, workspace_id)
|
||||
.await?
|
||||
.map(Job::QueuedJob);
|
||||
// potential race condition here, if the job was in queue and completed right after the fetch completed, so we need to check one last time
|
||||
@@ -1024,7 +1028,7 @@ impl<'a> GetQuery<'a> {
|
||||
return Ok(job);
|
||||
} else {
|
||||
let cjob2 = self
|
||||
.fetch_completed(db, job_id, workspace_id)
|
||||
.fetch_completed(db.into(), job_id, workspace_id)
|
||||
.await?
|
||||
.map(Job::CompletedJob);
|
||||
not_found_if_none(cjob2, "Job", job_id.to_string())
|
||||
@@ -1374,6 +1378,7 @@ pub struct ListQueueQuery {
|
||||
pub has_null_parent: Option<bool>,
|
||||
pub is_not_schedule: Option<bool>,
|
||||
pub concurrency_key: Option<String>,
|
||||
pub allow_wildcards: Option<bool>,
|
||||
}
|
||||
|
||||
impl From<ListCompletedQuery> for ListQueueQuery {
|
||||
@@ -1404,6 +1409,7 @@ impl From<ListCompletedQuery> for ListQueueQuery {
|
||||
has_null_parent: lcq.has_null_parent,
|
||||
is_not_schedule: lcq.is_not_schedule,
|
||||
concurrency_key: lcq.concurrency_key,
|
||||
allow_wildcards: lcq.allow_wildcards,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1427,7 +1433,11 @@ pub fn filter_list_queue_query(
|
||||
}
|
||||
|
||||
if let Some(w) = &lq.worker {
|
||||
sqlb.and_where_eq("v2_job_queue.worker", "?".bind(w));
|
||||
if lq.allow_wildcards.unwrap_or(false) {
|
||||
sqlb.and_where_like_left("v2_job_queue.worker", w.replace("*", "%"));
|
||||
} else {
|
||||
sqlb.and_where_eq("v2_job_queue.worker", "?".bind(w));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ps) = &lq.script_path_start {
|
||||
@@ -1447,8 +1457,13 @@ pub fn filter_list_queue_query(
|
||||
sqlb.and_where_eq("created_by", "?".bind(cb));
|
||||
}
|
||||
if let Some(t) = &lq.tag {
|
||||
sqlb.and_where_eq("tag", "?".bind(t));
|
||||
if lq.allow_wildcards.unwrap_or(false) {
|
||||
sqlb.and_where_like_left("v2_job.tag", t.replace("*", "%"));
|
||||
} else {
|
||||
sqlb.and_where_eq("v2_job.tag", "?".bind(t));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(r) = &lq.running {
|
||||
sqlb.and_where_eq("running", &r);
|
||||
}
|
||||
@@ -1539,7 +1554,10 @@ pub fn list_queue_jobs_query(
|
||||
.clone();
|
||||
|
||||
if let Some(tags) = tags {
|
||||
sqlb.and_where_in("tag", &tags.iter().map(|x| quote(x)).collect::<Vec<_>>());
|
||||
sqlb.and_where_in(
|
||||
"v2_job.tag",
|
||||
&tags.iter().map(|x| quote(x)).collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
|
||||
filter_list_queue_query(sqlb, lq, w_id, join_outstanding_wait_times)
|
||||
@@ -1746,7 +1764,10 @@ async fn list_filtered_uuids(
|
||||
.or_where_is_null("v2_job.trigger_kind");
|
||||
|
||||
if let Some(tags) = get_scope_tags(&authed) {
|
||||
sqlb.and_where_in("tag", &tags.iter().map(|x| quote(x)).collect::<Vec<_>>());
|
||||
sqlb.and_where_in(
|
||||
"v2_job.tag",
|
||||
&tags.iter().map(|x| quote(x)).collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
|
||||
sqlb = filter_list_queue_query(sqlb, &lq, w_id.as_str(), false);
|
||||
@@ -1829,7 +1850,7 @@ async fn count_completed_jobs_detail(
|
||||
|
||||
if let Some(tags) = query.tags {
|
||||
sqlb.and_where_in(
|
||||
"tag",
|
||||
"v2_job.tag",
|
||||
&tags
|
||||
.split(",")
|
||||
.map(|t| format!("'{}'", t))
|
||||
@@ -5440,14 +5461,27 @@ pub fn filter_list_completed_query(
|
||||
}
|
||||
|
||||
if let Some(label) = &lq.label {
|
||||
let mut wh = format!("result->'wm_labels' ? ");
|
||||
wh.push_str(&format!("'{}'", &label.replace("'", "''")));
|
||||
sqlb.and_where("result ? 'wm_labels'");
|
||||
sqlb.and_where(&wh);
|
||||
if lq.allow_wildcards.unwrap_or(false) {
|
||||
let wh = format!(
|
||||
"EXISTS (SELECT 1 FROM jsonb_array_elements_text(result->'wm_labels') label WHERE label LIKE '{}')",
|
||||
&label.replace("*", "%").replace("'", "''")
|
||||
);
|
||||
sqlb.and_where("result ? 'wm_labels'");
|
||||
sqlb.and_where(&wh);
|
||||
} else {
|
||||
let mut wh = format!("result->'wm_labels' ? ");
|
||||
wh.push_str(&format!("'{}'", &label.replace("'", "''")));
|
||||
sqlb.and_where("result ? 'wm_labels'");
|
||||
sqlb.and_where(&wh);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(worker) = &lq.worker {
|
||||
sqlb.and_where_eq("v2_job_completed.worker", "?".bind(worker));
|
||||
if lq.allow_wildcards.unwrap_or(false) {
|
||||
sqlb.and_where_like_left("v2_job_completed.worker", worker.replace("*", "%"));
|
||||
} else {
|
||||
sqlb.and_where_eq("v2_job_completed.worker", "?".bind(worker));
|
||||
}
|
||||
}
|
||||
|
||||
if w_id != "admins" || !lq.all_workspaces.is_some_and(|x| x) {
|
||||
@@ -5469,8 +5503,13 @@ pub fn filter_list_completed_query(
|
||||
sqlb.and_where_eq("runnable_id", "?".bind(h));
|
||||
}
|
||||
if let Some(t) = &lq.tag {
|
||||
sqlb.and_where_eq("tag", "?".bind(t));
|
||||
if lq.allow_wildcards.unwrap_or(false) {
|
||||
sqlb.and_where_like_left("v2_job.tag", t.replace("*", "%"));
|
||||
} else {
|
||||
sqlb.and_where_eq("v2_job.tag", "?".bind(t));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(cb) = &lq.created_by {
|
||||
sqlb.and_where_eq("created_by", "?".bind(cb));
|
||||
}
|
||||
@@ -5570,7 +5609,10 @@ pub fn list_completed_jobs_query(
|
||||
.clone();
|
||||
|
||||
if let Some(tags) = tags {
|
||||
sqlb.and_where_in("tag", &tags.iter().map(|x| quote(x)).collect::<Vec<_>>());
|
||||
sqlb.and_where_in(
|
||||
"v2_job.tag",
|
||||
&tags.iter().map(|x| quote(x)).collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
|
||||
filter_list_completed_query(sqlb, lq, w_id, join_outstanding_wait_times)
|
||||
@@ -5609,6 +5651,7 @@ pub struct ListCompletedQuery {
|
||||
pub is_not_schedule: Option<bool>,
|
||||
pub concurrency_key: Option<String>,
|
||||
pub worker: Option<String>,
|
||||
pub allow_wildcards: Option<bool>,
|
||||
}
|
||||
|
||||
async fn list_completed_jobs(
|
||||
|
||||
@@ -25,6 +25,8 @@ use crate::{
|
||||
webhook_util::WebhookShared,
|
||||
};
|
||||
|
||||
#[cfg(feature = "agent_worker_server")]
|
||||
use agent_workers_ee::AgentCache;
|
||||
use anyhow::Context;
|
||||
use argon2::Argon2;
|
||||
use axum::extract::DefaultBodyLimit;
|
||||
@@ -56,6 +58,8 @@ use windmill_common::{utils::GIT_VERSION, BASE_URL, INSTANCE_NAME};
|
||||
use crate::scim_ee::has_scim_token;
|
||||
use windmill_common::error::AppError;
|
||||
|
||||
#[cfg(feature = "agent_worker_server")]
|
||||
mod agent_workers_ee;
|
||||
mod ai;
|
||||
mod apps;
|
||||
pub mod args;
|
||||
@@ -74,9 +78,9 @@ mod folders;
|
||||
mod granular_acls;
|
||||
mod groups;
|
||||
#[cfg(feature = "http_trigger")]
|
||||
mod http_triggers;
|
||||
#[cfg(feature = "http_trigger")]
|
||||
mod http_trigger_auth;
|
||||
#[cfg(feature = "http_trigger")]
|
||||
mod http_triggers;
|
||||
mod indexer_ee;
|
||||
mod inputs;
|
||||
mod integration;
|
||||
@@ -85,6 +89,8 @@ mod postgres_triggers;
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
mod apps_ee;
|
||||
#[cfg(all(feature = "enterprise", feature = "gcp_trigger"))]
|
||||
mod gcp_triggers_ee;
|
||||
#[cfg(feature = "enterprise")]
|
||||
mod git_sync_ee;
|
||||
#[cfg(feature = "parquet")]
|
||||
@@ -113,6 +119,7 @@ mod slack_approvals;
|
||||
mod smtp_server_ee;
|
||||
#[cfg(all(feature = "enterprise", feature = "sqs_trigger"))]
|
||||
mod sqs_triggers_ee;
|
||||
|
||||
mod static_assets;
|
||||
#[cfg(all(feature = "stripe", feature = "enterprise"))]
|
||||
mod stripe_ee;
|
||||
@@ -209,10 +216,10 @@ pub async fn run_server(
|
||||
job_index_reader: Option<IndexReader>,
|
||||
log_index_reader: Option<ServiceLogIndexReader>,
|
||||
addr: SocketAddr,
|
||||
mut rx: tokio::sync::broadcast::Receiver<()>,
|
||||
mut killpill_rx: tokio::sync::broadcast::Receiver<()>,
|
||||
port_tx: tokio::sync::oneshot::Sender<String>,
|
||||
server_mode: bool,
|
||||
#[cfg(feature = "smtp")] base_internal_url: String,
|
||||
_base_internal_url: String,
|
||||
) -> anyhow::Result<()> {
|
||||
let user_db = UserDB::new(db.clone());
|
||||
|
||||
@@ -246,7 +253,10 @@ pub async fn run_server(
|
||||
.layer(Extension(log_index_reader))
|
||||
// .layer(Extension(index_writer))
|
||||
.layer(CookieManagerLayer::new())
|
||||
.layer(Extension(WebhookShared::new(rx.resubscribe(), db.clone())))
|
||||
.layer(Extension(WebhookShared::new(
|
||||
killpill_rx.resubscribe(),
|
||||
db.clone(),
|
||||
)))
|
||||
.layer(DefaultBodyLimit::max(
|
||||
REQUEST_SIZE_LIMIT.read().await.clone(),
|
||||
));
|
||||
@@ -279,7 +289,7 @@ pub async fn run_server(
|
||||
db: db.clone(),
|
||||
user_db: user_db,
|
||||
auth_cache: auth_cache.clone(),
|
||||
base_internal_url: base_internal_url.clone(),
|
||||
base_internal_url: _base_internal_url.clone(),
|
||||
});
|
||||
if let Err(err) = smtp_server.start_listener_thread(addr).await {
|
||||
tracing::error!("Error starting SMTP server: {err:#}");
|
||||
@@ -340,6 +350,18 @@ pub async fn run_server(
|
||||
}
|
||||
};
|
||||
|
||||
let gcp_triggers_service = {
|
||||
#[cfg(all(feature = "enterprise", feature = "gcp_trigger"))]
|
||||
{
|
||||
gcp_triggers_ee::workspaced_service()
|
||||
}
|
||||
|
||||
#[cfg(not(all(feature = "enterprise", feature = "gcp_trigger")))]
|
||||
{
|
||||
Router::new()
|
||||
}
|
||||
};
|
||||
|
||||
let sqs_triggers_service = {
|
||||
#[cfg(all(feature = "enterprise", feature = "sqs_trigger"))]
|
||||
{
|
||||
@@ -385,41 +407,54 @@ pub async fn run_server(
|
||||
if !*CLOUD_HOSTED && server_mode {
|
||||
#[cfg(feature = "websocket")]
|
||||
{
|
||||
let ws_killpill_rx = rx.resubscribe();
|
||||
let ws_killpill_rx = killpill_rx.resubscribe();
|
||||
websocket_triggers::start_websockets(db.clone(), ws_killpill_rx);
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "enterprise", feature = "kafka"))]
|
||||
{
|
||||
let kafka_killpill_rx = rx.resubscribe();
|
||||
let kafka_killpill_rx = killpill_rx.resubscribe();
|
||||
kafka_triggers_ee::start_kafka_consumers(db.clone(), kafka_killpill_rx);
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "enterprise", feature = "nats"))]
|
||||
{
|
||||
let nats_killpill_rx = rx.resubscribe();
|
||||
let nats_killpill_rx = killpill_rx.resubscribe();
|
||||
nats_triggers_ee::start_nats_consumers(db.clone(), nats_killpill_rx);
|
||||
}
|
||||
|
||||
#[cfg(feature = "postgres_trigger")]
|
||||
{
|
||||
let db_killpill_rx = rx.resubscribe();
|
||||
let db_killpill_rx = killpill_rx.resubscribe();
|
||||
postgres_triggers::start_database(db.clone(), db_killpill_rx);
|
||||
}
|
||||
|
||||
#[cfg(feature = "mqtt_trigger")]
|
||||
{
|
||||
let mqtt_killpill_rx = rx.resubscribe();
|
||||
let mqtt_killpill_rx = killpill_rx.resubscribe();
|
||||
mqtt_triggers::start_mqtt_consumer(db.clone(), mqtt_killpill_rx);
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "enterprise", feature = "sqs_trigger"))]
|
||||
{
|
||||
let sqs_killpill_rx = rx.resubscribe();
|
||||
let sqs_killpill_rx = killpill_rx.resubscribe();
|
||||
sqs_triggers_ee::start_sqs(db.clone(), sqs_killpill_rx);
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "enterprise", feature = "gcp_trigger"))]
|
||||
{
|
||||
let gcp_killpill_rx = killpill_rx.resubscribe();
|
||||
gcp_triggers_ee::start_consuming_gcp_pubsub_event(db.clone(), gcp_killpill_rx);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "agent_worker_server")]
|
||||
let (agent_workers_router, agent_workers_bg_processor, agent_workers_killpill_tx) =
|
||||
agent_workers_ee::workspaced_service(db.clone(), _base_internal_url.clone());
|
||||
|
||||
#[cfg(feature = "agent_worker_server")]
|
||||
let agent_cache = Arc::new(AgentCache::new());
|
||||
|
||||
// build our application with a route
|
||||
let app = Router::new()
|
||||
.nest(
|
||||
@@ -474,6 +509,7 @@ pub async fn run_server(
|
||||
.nest("/nats_triggers", nats_triggers_service)
|
||||
.nest("/mqtt_triggers", mqtt_triggers_service)
|
||||
.nest("/sqs_triggers", sqs_triggers_service)
|
||||
.nest("/gcp_triggers", gcp_triggers_service)
|
||||
.nest("/postgres_triggers", postgres_triggers_service),
|
||||
)
|
||||
.nest("/workspaces", workspaces::global_service())
|
||||
@@ -495,6 +531,26 @@ pub async fn run_server(
|
||||
.nest("/ai", ai::global_service())
|
||||
.route_layer(from_extractor::<ApiAuthed>())
|
||||
.route_layer(from_extractor::<users::Tokened>())
|
||||
.nest("/agent_workers", {
|
||||
#[cfg(feature = "agent_worker_server")]
|
||||
{
|
||||
agent_workers_ee::global_service().layer(Extension(agent_cache.clone()))
|
||||
}
|
||||
#[cfg(not(feature = "agent_worker_server"))]
|
||||
{
|
||||
Router::new()
|
||||
}
|
||||
})
|
||||
.nest("/w/:workspace_id/agent_workers", {
|
||||
#[cfg(feature = "agent_worker_server")]
|
||||
{
|
||||
agent_workers_router.layer(Extension(agent_cache.clone()))
|
||||
}
|
||||
#[cfg(not(feature = "agent_worker_server"))]
|
||||
{
|
||||
Router::new()
|
||||
}
|
||||
})
|
||||
.nest("/jobs", jobs::global_root_service())
|
||||
.nest(
|
||||
"/srch/w/:workspace_id/index",
|
||||
@@ -604,6 +660,20 @@ pub async fn run_server(
|
||||
}
|
||||
.layer(from_extractor::<OptAuthed>()),
|
||||
)
|
||||
.nest(
|
||||
"/gcp/w/:workspace_id",
|
||||
{
|
||||
#[cfg(all(feature = "enterprise", feature = "gcp_trigger"))]
|
||||
{
|
||||
gcp_triggers_ee::gcp_push_route_handler()
|
||||
}
|
||||
#[cfg(not(all(feature = "enterprise", feature = "gcp_trigger")))]
|
||||
{
|
||||
Router::new()
|
||||
}
|
||||
}
|
||||
.layer(from_extractor::<OptAuthed>()),
|
||||
)
|
||||
.route("/version", get(git_v))
|
||||
.route("/uptodate", get(is_up_to_date))
|
||||
.route("/ee_license", get(ee_license))
|
||||
@@ -647,11 +717,22 @@ pub async fn run_server(
|
||||
.expect("Failed to send port");
|
||||
|
||||
let server = server.with_graceful_shutdown(async move {
|
||||
rx.recv().await.ok();
|
||||
killpill_rx.recv().await.ok();
|
||||
#[cfg(feature = "agent_worker_server")]
|
||||
if let Err(e) = agent_workers_killpill_tx.kill().await {
|
||||
tracing::error!("Error killing agent workers: {e:#}");
|
||||
}
|
||||
tracing::info!("Graceful shutdown of server");
|
||||
});
|
||||
|
||||
server.await?;
|
||||
|
||||
#[cfg(feature = "agent_worker_server")]
|
||||
if let Some(bg_processor) = agent_workers_bg_processor {
|
||||
tracing::info!("server off. shutting down agent workers bg processor");
|
||||
bg_processor.await?;
|
||||
tracing::info!("agent workers bg processor shut down");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -570,7 +570,7 @@ pub async fn transform_json_value<'c>(
|
||||
};
|
||||
|
||||
let variables = variables::get_reserved_variables(
|
||||
db,
|
||||
&db.into(),
|
||||
workspace,
|
||||
token,
|
||||
&job.email,
|
||||
@@ -599,11 +599,10 @@ pub async fn transform_json_value<'c>(
|
||||
}
|
||||
Value::Object(mut m) => {
|
||||
for (a, b) in m.clone().into_iter() {
|
||||
m.insert(
|
||||
a.clone(),
|
||||
let v =
|
||||
transform_json_value(authed, user_db.clone(), db, workspace, b, job_id, token)
|
||||
.await?,
|
||||
);
|
||||
.await?;
|
||||
m.insert(a.clone(), v);
|
||||
}
|
||||
Ok(Value::Object(m))
|
||||
}
|
||||
@@ -1212,7 +1211,10 @@ async fn update_resource_type(
|
||||
feature = "http_trigger",
|
||||
feature = "postgres_trigger",
|
||||
feature = "mqtt_trigger",
|
||||
all(feature = "sqs_trigger", feature = "enterprise")
|
||||
all(
|
||||
feature = "enterprise",
|
||||
any(feature = "sqs_trigger", feature = "gcp_trigger")
|
||||
)
|
||||
))]
|
||||
pub async fn try_get_resource_from_db_as<T>(
|
||||
authed: ApiAuthed,
|
||||
|
||||
@@ -44,12 +44,21 @@ use windmill_audit::ActionKind;
|
||||
use windmill_common::error::to_anyhow;
|
||||
|
||||
use windmill_common::{
|
||||
db::UserDB, error::{Error, JsonResult, Result}, jobs::JobPayload, schedule::Schedule, schema::should_validate_schema, scripts::{
|
||||
db::UserDB,
|
||||
error::{Error, JsonResult, Result},
|
||||
jobs::JobPayload,
|
||||
schedule::Schedule,
|
||||
schema::should_validate_schema,
|
||||
scripts::{
|
||||
to_i64, HubScript, ListScriptQuery, ListableScript, NewScript, Schema, Script, ScriptHash,
|
||||
ScriptHistory, ScriptHistoryUpdate, ScriptKind, ScriptLang, ScriptWithStarred,
|
||||
}, users::username_to_permissioned_as, utils::{
|
||||
},
|
||||
users::username_to_permissioned_as,
|
||||
utils::{
|
||||
not_found_if_none, paginate, query_elems_from_hub, require_admin, Pagination, StripPath,
|
||||
}, worker::to_raw_value, HUB_BASE_URL
|
||||
},
|
||||
worker::to_raw_value,
|
||||
HUB_BASE_URL,
|
||||
};
|
||||
use windmill_git_sync::{handle_deployment_metadata, DeployedObject};
|
||||
use windmill_parser_ts::remove_pinned_imports;
|
||||
@@ -409,10 +418,10 @@ async fn create_snapshot_script(
|
||||
std::fs::create_dir_all(
|
||||
windmill_common::worker::ROOT_STANDALONE_BUNDLE_DIR.clone(),
|
||||
)?;
|
||||
windmill_common::worker::write_file(
|
||||
windmill_common::worker::write_file_bytes(
|
||||
&windmill_common::worker::ROOT_STANDALONE_BUNDLE_DIR,
|
||||
&hash,
|
||||
&String::from_utf8_lossy(&data),
|
||||
&data,
|
||||
)?;
|
||||
} else {
|
||||
#[cfg(not(all(feature = "enterprise", feature = "parquet")))]
|
||||
@@ -636,7 +645,7 @@ async fn create_script_internal<'c>(
|
||||
|| ns.language == ScriptLang::Nu
|
||||
|| ns.language == ScriptLang::Php
|
||||
|| ns.language == ScriptLang::Java
|
||||
// KJQXZ
|
||||
// for related places search: ADD_NEW_LANG
|
||||
) {
|
||||
Some(String::new())
|
||||
} else {
|
||||
|
||||
@@ -61,7 +61,7 @@ async fn list_contextual_variables(
|
||||
) -> JsonResult<Vec<ContextualVariable>> {
|
||||
Ok(Json(
|
||||
get_reserved_variables(
|
||||
&db,
|
||||
&db.into(),
|
||||
&w_id,
|
||||
"q1A0qcPuO00yxioll7iph76N9CJDqn",
|
||||
&email,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::ai::{AIConfig, AI_KEY_CACHE};
|
||||
use crate::ai::{AIConfig, AI_REQUEST_CACHE};
|
||||
use crate::db::ApiAuthed;
|
||||
use crate::users_ee::send_email_if_possible;
|
||||
use crate::utils::get_instance_username_or_create_pending;
|
||||
@@ -704,7 +704,7 @@ async fn edit_copilot_config(
|
||||
|
||||
if let Some(ref providers) = ai_config.providers {
|
||||
for provider in providers.keys() {
|
||||
AI_KEY_CACHE.remove(&(w_id.clone(), provider.clone()));
|
||||
AI_REQUEST_CACHE.remove(&(w_id.clone(), provider.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1307,6 +1307,7 @@ struct UsedTriggers {
|
||||
pub postgres_used: bool,
|
||||
pub mqtt_used: bool,
|
||||
pub sqs_used: bool,
|
||||
pub gcp_used: bool,
|
||||
}
|
||||
|
||||
async fn get_used_triggers(
|
||||
@@ -1325,7 +1326,8 @@ async fn get_used_triggers(
|
||||
EXISTS(SELECT 1 FROM nats_trigger WHERE workspace_id = $1) as "nats_used!",
|
||||
EXISTS(SELECT 1 FROM postgres_trigger WHERE workspace_id = $1) AS "postgres_used!",
|
||||
EXISTS(SELECT 1 FROM mqtt_trigger WHERE workspace_id = $1) AS "mqtt_used!",
|
||||
EXISTS(SELECT 1 FROM sqs_trigger WHERE workspace_id = $1) AS "sqs_used!"
|
||||
EXISTS(SELECT 1 FROM sqs_trigger WHERE workspace_id = $1) AS "sqs_used!",
|
||||
EXISTS(SELECT 1 FROM gcp_trigger WHERE workspace_id = $1) AS "gcp_used!"
|
||||
"#,
|
||||
w_id
|
||||
)
|
||||
|
||||
@@ -376,7 +376,7 @@ pub(crate) async fn tarball_workspace(
|
||||
ScriptLang::Nu => "nu",
|
||||
ScriptLang::OracleDB => "odb.sql",
|
||||
ScriptLang::Java => "java",
|
||||
// KJQXZ
|
||||
// for related places search: ADD_NEW_LANG
|
||||
};
|
||||
archive
|
||||
.write_to_archive(&script.content, &format!("{}.{}", script.path, ext))
|
||||
@@ -637,6 +637,47 @@ pub(crate) async fn tarball_workspace(
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "enterprise", feature = "gcp_trigger"))]
|
||||
{
|
||||
let gcp_triggers = sqlx::query_as!(
|
||||
crate::gcp_triggers_ee::GcpTrigger,
|
||||
r#"
|
||||
SELECT
|
||||
gcp_resource_path,
|
||||
subscription_id,
|
||||
topic_id,
|
||||
workspace_id,
|
||||
delivery_type AS "delivery_type: _",
|
||||
delivery_config AS "delivery_config: _",
|
||||
path,
|
||||
script_path,
|
||||
is_flow,
|
||||
edited_by,
|
||||
email,
|
||||
edited_at,
|
||||
server_id,
|
||||
last_server_ping,
|
||||
extra_perms,
|
||||
error,
|
||||
enabled
|
||||
FROM
|
||||
gcp_trigger
|
||||
WHERE
|
||||
workspace_id = $1
|
||||
"#,
|
||||
&w_id
|
||||
)
|
||||
.fetch_all(&mut *tx)
|
||||
.await?;
|
||||
|
||||
for trigger in gcp_triggers {
|
||||
let trigger_str = &to_string_without_metadata(&trigger, false, None).unwrap();
|
||||
archive
|
||||
.write_to_archive(&trigger_str, &format!("{}.gcp_trigger.json", trigger.path))
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "enterprise", feature = "nats"))]
|
||||
{
|
||||
let nats_triggers = sqlx::query_as!(
|
||||
|
||||
@@ -34,6 +34,8 @@ serde_json.workspace = true
|
||||
chrono.workspace = true
|
||||
chrono-tz.workspace = true
|
||||
hex.workspace = true
|
||||
reqwest-middleware = { workspace = true }
|
||||
reqwest-retry = { workspace = true }
|
||||
rand.workspace = true
|
||||
sqlx = { workspace = true, features = ["postgres"] }
|
||||
uuid.workspace = true
|
||||
|
||||
90
backend/windmill-common/src/agent_workers.rs
Normal file
90
backend/windmill-common/src/agent_workers.rs
Normal file
@@ -0,0 +1,90 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct QueueInitJob {
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use std::time::Duration;
|
||||
|
||||
use reqwest_middleware::ClientBuilder;
|
||||
use reqwest_retry::{policies::ExponentialBackoff, RetryTransientMiddleware};
|
||||
|
||||
use crate::{jwt::decode_without_verify, worker::HttpClient};
|
||||
|
||||
lazy_static! {
|
||||
pub static ref BASE_INTERNAL_URL: String =
|
||||
std::env::var("BASE_INTERNAL_URL").unwrap_or("http://localhost:8080".to_string());
|
||||
pub static ref AGENT_TOKEN: String = std::env::var("AGENT_TOKEN").unwrap_or_default();
|
||||
pub static ref DECODED_AGENT_TOKEN: Option<AgentAuth> = {
|
||||
if AGENT_TOKEN.is_empty() {
|
||||
None
|
||||
} else {
|
||||
decode_without_verify::<AgentAuth>(AGENT_TOKEN.trim_start_matches(AGENT_JWT_PREFIX))
|
||||
.ok()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct AgentAuth {
|
||||
pub worker_group: String,
|
||||
pub suffix: Option<String>,
|
||||
pub tags: Vec<String>,
|
||||
pub exp: Option<usize>,
|
||||
}
|
||||
|
||||
pub const AGENT_JWT_PREFIX: &str = "jwt_agent_";
|
||||
pub fn build_agent_http_client(worker_suffix: &str) -> HttpClient {
|
||||
let client = ClientBuilder::new(
|
||||
reqwest::Client::builder()
|
||||
.pool_max_idle_per_host(10)
|
||||
.pool_idle_timeout(Duration::from_secs(60))
|
||||
.connect_timeout(Duration::from_secs(10))
|
||||
.timeout(Duration::from_secs(30))
|
||||
.default_headers({
|
||||
let mut headers = reqwest::header::HeaderMap::new();
|
||||
headers.insert(
|
||||
"User-Agent", // Replace with your desired header name
|
||||
"Windmill-Agent/1.0".parse().unwrap(), // Replace with your desired header value
|
||||
);
|
||||
let token = format!(
|
||||
"{}{}_{}",
|
||||
AGENT_JWT_PREFIX,
|
||||
worker_suffix,
|
||||
AGENT_TOKEN.trim_start_matches(AGENT_JWT_PREFIX),
|
||||
);
|
||||
headers.insert(
|
||||
"Authorization",
|
||||
format!("Bearer {}", token).parse().unwrap(),
|
||||
);
|
||||
headers
|
||||
})
|
||||
.build()
|
||||
.expect("Failed to create HTTP client"),
|
||||
)
|
||||
.with(RetryTransientMiddleware::new_with_policy(
|
||||
ExponentialBackoff::builder().build_with_max_retries(5),
|
||||
))
|
||||
.build();
|
||||
HttpClient(client)
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct PingJobStatus {
|
||||
pub mem_peak: Option<i32>,
|
||||
pub current_mem: Option<i32>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
pub struct PingJobStatusResponse {
|
||||
pub canceled_by: Option<String>,
|
||||
pub canceled_reason: Option<String>,
|
||||
pub already_completed: bool,
|
||||
}
|
||||
|
||||
// #[derive(Serialize, Deserialize)]
|
||||
// pub struct PullJobRequest {
|
||||
// pub worker_name: String,
|
||||
// }
|
||||
@@ -1,8 +1,11 @@
|
||||
use anyhow::Context;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
db::Authed,
|
||||
error::{Error, Result},
|
||||
jwt,
|
||||
users::{SUPERADMIN_NOTIFICATION_EMAIL, SUPERADMIN_SECRET_EMAIL, SUPERADMIN_SYNC_EMAIL},
|
||||
DB,
|
||||
};
|
||||
@@ -22,7 +25,7 @@ pub struct JWTAuthClaims {
|
||||
pub scopes: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct JobPerms {
|
||||
pub email: String,
|
||||
pub username: String,
|
||||
@@ -205,3 +208,62 @@ pub async fn get_groups_for_user(
|
||||
.collect();
|
||||
Ok(groups)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip_all)]
|
||||
pub async fn create_token_for_owner(
|
||||
db: &DB,
|
||||
w_id: &str,
|
||||
owner: &str,
|
||||
label: &str,
|
||||
expires_in: u64,
|
||||
email: &str,
|
||||
job_id: &Uuid,
|
||||
perms: Option<JobPerms>,
|
||||
) -> crate::error::Result<String> {
|
||||
let job_perms = if perms.is_some() {
|
||||
Ok(perms)
|
||||
} else {
|
||||
sqlx::query_as!(
|
||||
JobPerms,
|
||||
"SELECT email, username, is_admin, is_operator, groups, folders FROM job_perms WHERE job_id = $1 AND workspace_id = $2",
|
||||
job_id,
|
||||
w_id
|
||||
)
|
||||
.fetch_optional(db)
|
||||
.await
|
||||
};
|
||||
let job_authed = match job_perms {
|
||||
Ok(Some(jp)) => jp.into(),
|
||||
_ => {
|
||||
tracing::warn!("Could not get permissions for job {job_id} from job_perms table, getting permissions directly...");
|
||||
fetch_authed_from_permissioned_as(owner.to_string(), email.to_string(), w_id, db)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
Error::internal_err(format!(
|
||||
"Could not get permissions directly for job {job_id}: {e:#}"
|
||||
))
|
||||
})?
|
||||
}
|
||||
};
|
||||
|
||||
let payload = JWTAuthClaims {
|
||||
email: job_authed.email,
|
||||
username: job_authed.username,
|
||||
is_admin: job_authed.is_admin,
|
||||
is_operator: job_authed.is_operator,
|
||||
groups: job_authed.groups,
|
||||
folders: job_authed.folders,
|
||||
label: Some(label.to_string()),
|
||||
workspace_id: w_id.to_string(),
|
||||
exp: (chrono::Utc::now() + chrono::Duration::seconds(expires_in as i64)).timestamp()
|
||||
as usize,
|
||||
job_id: Some(job_id.to_string()),
|
||||
scopes: None,
|
||||
};
|
||||
|
||||
let token = jwt::encode_with_internal_secret(&payload)
|
||||
.await
|
||||
.with_context(|| format!("Could not encode JWT token for job {job_id}"))?;
|
||||
|
||||
Ok(format!("jwt_{}", token))
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
//! This shall only be used for testing, e.g. [`sqlx::test`] spawn a database per test,
|
||||
//! and there is only one test per thread, so using thread-local cache avoid unexpected results.
|
||||
|
||||
use anyhow::anyhow;
|
||||
use crate::{
|
||||
apps::AppScriptId,
|
||||
error,
|
||||
@@ -15,6 +14,7 @@ use crate::{
|
||||
schema::SchemaValidator,
|
||||
scripts::{ScriptHash, ScriptLang},
|
||||
};
|
||||
use anyhow::anyhow;
|
||||
|
||||
#[cfg(feature = "scoped_cache")]
|
||||
use std::thread::ThreadId;
|
||||
@@ -322,6 +322,25 @@ pub struct RawScript {
|
||||
pub meta: Option<ScriptMetadata>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct RawScriptApi {
|
||||
pub content: String,
|
||||
pub lock: Option<String>,
|
||||
pub meta: Option<ScriptMetadata>,
|
||||
}
|
||||
|
||||
impl From<RawScript> for RawScriptApi {
|
||||
fn from(value: RawScript) -> Self {
|
||||
RawScriptApi { content: value.content, lock: value.lock, meta: value.meta }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawScriptApi> for RawScript {
|
||||
fn from(value: RawScriptApi) -> Self {
|
||||
RawScript { content: value.content, lock: value.lock, meta: value.meta }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RawFlow {
|
||||
pub raw_flow: Box<RawValue>,
|
||||
@@ -334,6 +353,25 @@ pub struct RawNode {
|
||||
pub raw_flow: Option<Box<RawValue>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct RawNodeApi {
|
||||
pub raw_code: Option<String>,
|
||||
pub raw_lock: Option<String>,
|
||||
pub raw_flow: Option<Box<RawValue>>,
|
||||
}
|
||||
|
||||
impl From<RawNode> for RawNodeApi {
|
||||
fn from(value: RawNode) -> Self {
|
||||
RawNodeApi { raw_code: value.raw_code, raw_lock: value.raw_lock, raw_flow: value.raw_flow }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RawNodeApi> for RawNode {
|
||||
fn from(value: RawNodeApi) -> Self {
|
||||
RawNode { raw_code: value.raw_code, raw_lock: value.raw_lock, raw_flow: value.raw_flow }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Entry<T>(Arc<T>);
|
||||
|
||||
@@ -343,7 +381,7 @@ struct ScriptFull {
|
||||
pub meta: Arc<ScriptMetadata>,
|
||||
}
|
||||
|
||||
fn unwrap_or_error<Key: std::fmt::Debug, Val>(
|
||||
pub fn unwrap_or_error<Key: std::fmt::Debug, Val>(
|
||||
at: &'static Location,
|
||||
entity: &'static str,
|
||||
key: Key,
|
||||
@@ -363,6 +401,11 @@ pub fn clear() {
|
||||
}
|
||||
|
||||
pub mod flow {
|
||||
use crate::{
|
||||
worker::{fetch_flow_node_query, Connection},
|
||||
DB,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
make_static! {
|
||||
@@ -388,10 +431,10 @@ pub mod flow {
|
||||
/// This should be preferred over fetching the database directly.
|
||||
#[track_caller]
|
||||
pub fn fetch_script<'c>(
|
||||
e: impl PgExecutor<'c>,
|
||||
conn: &'c Connection,
|
||||
node: FlowNodeId,
|
||||
) -> impl Future<Output = error::Result<Arc<ScriptData>>> {
|
||||
let fetch_node = fetch_node(e, node);
|
||||
) -> impl Future<Output = error::Result<Arc<ScriptData>>> + 'c {
|
||||
let fetch_node = fetch_node(conn, node);
|
||||
async move {
|
||||
fetch_node.await.and_then(|data| match data {
|
||||
RawData::Script(data) => Ok(data),
|
||||
@@ -409,11 +452,12 @@ pub mod flow {
|
||||
/// This should be preferred over fetching the database directly.
|
||||
#[track_caller]
|
||||
pub fn fetch_flow<'c>(
|
||||
e: impl PgExecutor<'c>,
|
||||
db: &'c DB,
|
||||
node: FlowNodeId,
|
||||
) -> impl Future<Output = error::Result<Arc<FlowData>>> {
|
||||
let fetch_node = fetch_node(e, node);
|
||||
) -> impl Future<Output = error::Result<Arc<FlowData>>> + 'c {
|
||||
async move {
|
||||
let conn = Connection::Sql(db.clone());
|
||||
let fetch_node = fetch_node(&conn, node);
|
||||
fetch_node.await.and_then(|data| match data {
|
||||
RawData::Flow(data) => Ok(data),
|
||||
RawData::Script(_) => Err(error::Error::internal_err(format!(
|
||||
@@ -430,31 +474,23 @@ pub mod flow {
|
||||
/// This should be preferred over fetching the database directly.
|
||||
#[track_caller]
|
||||
pub(super) fn fetch_node<'c>(
|
||||
e: impl PgExecutor<'c>,
|
||||
conn: &'c Connection,
|
||||
node: FlowNodeId,
|
||||
) -> impl Future<Output = error::Result<RawData>> {
|
||||
) -> impl Future<Output = error::Result<RawData>> + 'c {
|
||||
let loc = Location::caller();
|
||||
// If not present, `get_or_insert_async` will lock the key until the future completes,
|
||||
// so only one thread will be able to fetch the data from the database and write it to
|
||||
// the file system and cache, hence no race on the file system.
|
||||
NODES.get_or_insert_async(node, async move {
|
||||
sqlx::query!(
|
||||
"SELECT \
|
||||
code AS \"raw_code: String\", \
|
||||
lock AS \"raw_lock: String\", \
|
||||
flow AS \"raw_flow: Json<Box<RawValue>>\" \
|
||||
FROM flow_node WHERE id = $1 LIMIT 1",
|
||||
node.0,
|
||||
)
|
||||
.fetch_optional(e)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
.and_then(unwrap_or_error(&loc, "Flow node", node))
|
||||
.map(|r| RawNode {
|
||||
raw_code: r.raw_code,
|
||||
raw_lock: r.raw_lock,
|
||||
raw_flow: r.raw_flow.map(|Json(raw_flow)| raw_flow),
|
||||
})
|
||||
match conn {
|
||||
Connection::Sql(db) => fetch_flow_node_query(db, node.0, loc).await,
|
||||
Connection::Http(client) => {
|
||||
let r = client
|
||||
.get::<RawNodeApi>(&format!("/api/agent_workers/flow_script/{}", node.0))
|
||||
.await?;
|
||||
Ok(r.into())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -502,6 +538,8 @@ pub mod flow {
|
||||
}
|
||||
|
||||
pub mod script {
|
||||
use crate::{worker::Connection, DB};
|
||||
|
||||
use super::*;
|
||||
|
||||
make_static! {
|
||||
@@ -520,66 +558,80 @@ pub mod script {
|
||||
/// it to the file system and cache.
|
||||
/// This should be preferred over fetching the database directly.
|
||||
#[track_caller]
|
||||
pub fn fetch<'c>(
|
||||
e: impl PgExecutor<'c>,
|
||||
pub fn fetch(
|
||||
conn: &Connection,
|
||||
hash: ScriptHash,
|
||||
) -> impl Future<Output = error::Result<(Arc<ScriptData>, Arc<ScriptMetadata>)>> {
|
||||
// If not present, `get_or_insert_async` will lock the key until the future completes,
|
||||
// so only one thread will be able to fetch the data from the database and write it to
|
||||
// the file system and cache, hence no race on the file system.
|
||||
let loc = Location::caller();
|
||||
let conn = conn.clone();
|
||||
let fut = CACHE.get_or_insert_async(hash, async move {
|
||||
sqlx::query!(
|
||||
"SELECT \
|
||||
content AS \"content!: String\",
|
||||
lock AS \"lock: String\", \
|
||||
language AS \"language: Option<ScriptLang>\", \
|
||||
envs AS \"envs: Vec<String>\", \
|
||||
schema AS \"schema: String\", \
|
||||
schema_validation AS \"schema_validation: bool\", \
|
||||
codebase LIKE '%.tar' as use_tar \
|
||||
FROM script WHERE hash = $1 LIMIT 1",
|
||||
hash.0
|
||||
)
|
||||
.fetch_optional(e)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
.and_then(unwrap_or_error(&loc, "Script", hash))
|
||||
.and_then(|r| {
|
||||
Ok(RawScript {
|
||||
content: r.content,
|
||||
lock: r.lock,
|
||||
meta: Some(ScriptMetadata {
|
||||
language: r.language,
|
||||
envs: r.envs,
|
||||
codebase: if let Some(use_tar) = r.use_tar {
|
||||
let sh = hash.to_string();
|
||||
if use_tar {
|
||||
Some(format!("{sh}.tar"))
|
||||
} else {
|
||||
Some(sh)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
},
|
||||
schema_validator: if r.schema_validation {
|
||||
r.schema
|
||||
.as_ref()
|
||||
.map(|schema_str| {
|
||||
SchemaValidator::from_schema(schema_str).map_err(|e| anyhow!("Couldn't create schema validator for script requiring schema validation: {e}"))
|
||||
})
|
||||
.transpose()?
|
||||
} else {
|
||||
None
|
||||
},
|
||||
schema: r.schema,
|
||||
}),
|
||||
})
|
||||
})
|
||||
match conn {
|
||||
Connection::Sql(db) => fetch_script_from_db(&db, hash, loc).await,
|
||||
Connection::Http(_) => Err(error::Error::InternalErr(format!(
|
||||
"Cannot fetch script in HTTP mode"
|
||||
))),
|
||||
}
|
||||
});
|
||||
fut.map_ok(|ScriptFull { data, meta }| (data, meta))
|
||||
}
|
||||
|
||||
async fn fetch_script_from_db(
|
||||
db: &DB,
|
||||
hash: ScriptHash,
|
||||
loc: &'static Location<'_>,
|
||||
) -> error::Result<RawScript> {
|
||||
sqlx::query!(
|
||||
"SELECT \
|
||||
content AS \"content!: String\",
|
||||
lock AS \"lock: String\", \
|
||||
language AS \"language: Option<ScriptLang>\", \
|
||||
envs AS \"envs: Vec<String>\", \
|
||||
schema AS \"schema: String\", \
|
||||
schema_validation AS \"schema_validation: bool\", \
|
||||
codebase LIKE '%.tar' as use_tar \
|
||||
FROM script WHERE hash = $1 LIMIT 1",
|
||||
hash.0
|
||||
)
|
||||
.fetch_optional(db)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
.and_then(unwrap_or_error(&loc, "Script", hash))
|
||||
.and_then(|r| {
|
||||
Ok(RawScript {
|
||||
content: r.content,
|
||||
lock: r.lock,
|
||||
meta: Some(ScriptMetadata {
|
||||
language: r.language,
|
||||
envs: r.envs,
|
||||
codebase: if let Some(use_tar) = r.use_tar {
|
||||
let sh = hash.to_string();
|
||||
if use_tar {
|
||||
Some(format!("{sh}.tar"))
|
||||
} else {
|
||||
Some(sh)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
},
|
||||
schema_validator: if r.schema_validation {
|
||||
r.schema
|
||||
.as_ref()
|
||||
.map(|schema_str| {
|
||||
SchemaValidator::from_schema(schema_str).map_err(|e| anyhow!("Couldn't create schema validator for script requiring schema validation: {e}"))
|
||||
})
|
||||
.transpose()?
|
||||
} else {
|
||||
None
|
||||
},
|
||||
schema: r.schema,
|
||||
}),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Invalidate the script cache for the given `hash`.
|
||||
pub fn invalidate(hash: ScriptHash) {
|
||||
let _ = CACHE.remove(&hash);
|
||||
@@ -587,6 +639,8 @@ pub mod script {
|
||||
}
|
||||
|
||||
pub mod app {
|
||||
use crate::worker::{fetch_raw_script_from_app_query, Connection};
|
||||
|
||||
use super::*;
|
||||
|
||||
make_static! {
|
||||
@@ -605,23 +659,23 @@ pub mod app {
|
||||
/// This should be preferred over fetching the database directly.
|
||||
#[track_caller]
|
||||
pub fn fetch_script<'c>(
|
||||
e: impl PgExecutor<'c>,
|
||||
conn: &'c Connection,
|
||||
id: AppScriptId,
|
||||
) -> impl Future<Output = error::Result<Arc<ScriptData>>> {
|
||||
) -> impl Future<Output = error::Result<Arc<ScriptData>>> + 'c {
|
||||
// If not present, `get_or_insert_async` will lock the key until the future completes,
|
||||
// so only one thread will be able to fetch the data from the database and write it to
|
||||
// the file system and cache, hence no race on the file system.
|
||||
let loc = Location::caller();
|
||||
let fut = CACHE.get_or_insert_async(id, async move {
|
||||
sqlx::query!(
|
||||
"SELECT lock, code FROM app_script WHERE id = $1 LIMIT 1",
|
||||
id.0,
|
||||
)
|
||||
.fetch_optional(e)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
.and_then(unwrap_or_error(&loc, "Application script", id))
|
||||
.map(|r| RawScript { content: r.code, lock: r.lock, meta: None })
|
||||
match conn {
|
||||
Connection::Sql(db) => fetch_raw_script_from_app_query(db, id.0, loc).await,
|
||||
Connection::Http(client) => {
|
||||
let r = client
|
||||
.get::<RawScriptApi>(&format!("/api/agent_workers/app_script/{}", id.0))
|
||||
.await?;
|
||||
Ok(r.into())
|
||||
}
|
||||
}
|
||||
});
|
||||
fut.map_ok(|Entry(data)| data)
|
||||
}
|
||||
@@ -629,7 +683,7 @@ pub mod app {
|
||||
|
||||
pub mod job {
|
||||
use super::*;
|
||||
use crate::jobs::JobKind;
|
||||
use crate::{jobs::JobKind, worker::Connection, DB};
|
||||
|
||||
#[cfg(not(feature = "scoped_cache"))]
|
||||
lazy_static! {
|
||||
@@ -649,15 +703,18 @@ pub mod job {
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn fetch_preview_flow<'a, 'c>(
|
||||
e: impl PgExecutor<'c> + 'a,
|
||||
pub fn fetch_preview_flow<'a>(
|
||||
db: &'a DB,
|
||||
job: &'a Uuid,
|
||||
// original raw values from `queue` or `completed_job` tables:
|
||||
// kept for backward compatibility.
|
||||
raw_flow: Option<Json<Box<RawValue>>>,
|
||||
) -> impl Future<Output = error::Result<Arc<FlowData>>> + 'a {
|
||||
let fetch_preview = fetch_preview(e, job, None, None, raw_flow);
|
||||
// Create the Connection first so it lives for the entire scope
|
||||
|
||||
async move {
|
||||
let conn = Connection::from(db);
|
||||
|
||||
let fetch_preview = fetch_preview(&conn, job, None, None, raw_flow);
|
||||
|
||||
fetch_preview.await.and_then(|data| match data {
|
||||
RawData::Flow(data) => Ok(data),
|
||||
RawData::Script(_) => Err(error::Error::internal_err(format!(
|
||||
@@ -669,7 +726,7 @@ pub mod job {
|
||||
|
||||
#[track_caller]
|
||||
pub fn fetch_preview_script<'a, 'c>(
|
||||
e: impl PgExecutor<'c> + 'a,
|
||||
e: &'a Connection,
|
||||
job: &'a Uuid,
|
||||
// original raw values from `queue` or `completed_job` tables:
|
||||
// kept for backward compatibility.
|
||||
@@ -689,7 +746,7 @@ pub mod job {
|
||||
|
||||
#[track_caller]
|
||||
pub fn fetch_preview<'a, 'c>(
|
||||
e: impl PgExecutor<'c> + 'a,
|
||||
e: &'a Connection,
|
||||
job: &'a Uuid,
|
||||
// original raw values from `queue` or `completed_job` tables:
|
||||
// kept for backward compatibility.
|
||||
@@ -700,16 +757,21 @@ pub mod job {
|
||||
let loc = Location::caller();
|
||||
let fetch = async move {
|
||||
match (raw_lock, raw_code, raw_flow) {
|
||||
(None, None, None) => sqlx::query!(
|
||||
"SELECT raw_code, raw_lock, raw_flow AS \"raw_flow: Json<Box<RawValue>>\" \
|
||||
FROM v2_job WHERE id = $1 LIMIT 1",
|
||||
job
|
||||
)
|
||||
.fetch_optional(e)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
.and_then(unwrap_or_error(&loc, "Preview", job))
|
||||
.map(|r| (r.raw_lock, r.raw_code, r.raw_flow)),
|
||||
(None, None, None) => match e {
|
||||
Connection::Sql(pool) => sqlx::query!(
|
||||
"SELECT raw_code, raw_lock, raw_flow AS \"raw_flow: Json<Box<RawValue>>\" \
|
||||
FROM v2_job WHERE id = $1 LIMIT 1",
|
||||
job
|
||||
)
|
||||
.fetch_optional(pool)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
.and_then(unwrap_or_error(&loc, "Preview", job))
|
||||
.map(|r| (r.raw_lock, r.raw_code, r.raw_flow)),
|
||||
Connection::Http(_) => Err(error::Error::InternalErr(format!(
|
||||
"Cannot fetch preview in HTTP mode"
|
||||
))),
|
||||
},
|
||||
(lock, code, flow) => Ok((lock, code, flow)),
|
||||
}
|
||||
.and_then(|(lock, code, flow)| match flow {
|
||||
@@ -730,8 +792,8 @@ pub mod job {
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn fetch_script<'c>(
|
||||
e: impl PgExecutor<'c>,
|
||||
pub fn fetch_script(
|
||||
db: DB,
|
||||
kind: JobKind,
|
||||
hash: Option<ScriptHash>,
|
||||
) -> impl Future<Output = error::Result<Arc<ScriptData>>> {
|
||||
@@ -739,11 +801,15 @@ pub mod job {
|
||||
let loc = Location::caller();
|
||||
async move {
|
||||
match (kind, hash.map(|ScriptHash(id)| id)) {
|
||||
(FlowScript, Some(id)) => flow::fetch_script(e, FlowNodeId(id)).await,
|
||||
(Script | Dependencies, Some(hash)) => script::fetch(e, ScriptHash(hash))
|
||||
(FlowScript, Some(id)) => {
|
||||
flow::fetch_script(&Connection::Sql(db.clone()), FlowNodeId(id)).await
|
||||
}
|
||||
(Script | Dependencies, Some(hash)) => script::fetch(&db.into(), ScriptHash(hash))
|
||||
.await
|
||||
.map(|(data, _meta)| data),
|
||||
(AppScript, Some(id)) => app::fetch_script(e, AppScriptId(id)).await,
|
||||
(AppScript, Some(id)) => {
|
||||
app::fetch_script(&Connection::Sql(db.clone()), AppScriptId(id)).await
|
||||
}
|
||||
_ => Err(error::Error::internal_err(format!(
|
||||
"Isn't a script job: {:?}",
|
||||
kind
|
||||
@@ -755,19 +821,19 @@ pub mod job {
|
||||
|
||||
#[track_caller]
|
||||
pub fn fetch_flow<'c>(
|
||||
e: impl PgExecutor<'c> + Copy,
|
||||
db: &'c DB,
|
||||
kind: JobKind,
|
||||
hash: Option<ScriptHash>,
|
||||
) -> impl Future<Output = error::Result<Arc<FlowData>>> {
|
||||
) -> impl Future<Output = error::Result<Arc<FlowData>>> + 'c {
|
||||
use JobKind::*;
|
||||
let loc = Location::caller();
|
||||
async move {
|
||||
match (kind, hash.map(|ScriptHash(id)| id)) {
|
||||
(FlowDependencies, Some(id)) => flow::fetch_version(e, id).await,
|
||||
(FlowNode, Some(id)) => flow::fetch_flow(e, FlowNodeId(id)).await,
|
||||
(Flow, Some(id)) => match flow::fetch_version_lite(e, id).await {
|
||||
(FlowDependencies, Some(id)) => flow::fetch_version(db, id).await,
|
||||
(FlowNode, Some(id)) => flow::fetch_flow(db, FlowNodeId(id)).await,
|
||||
(Flow, Some(id)) => match flow::fetch_version_lite(db, id).await {
|
||||
Ok(raw_flow) => Ok(raw_flow),
|
||||
Err(_) => flow::fetch_version(e, id).await,
|
||||
Err(_) => flow::fetch_version(db, id).await,
|
||||
},
|
||||
_ => Err(error::Error::internal_err(format!(
|
||||
"Isn't a flow job {:?}",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user