Compare commits

..

149 Commits

Author SHA1 Message Date
wendrul
3cb5660057 Windmill debugger binary 2025-07-30 19:08:25 +02:00
Ruben Fiszel
25aa982318 nit naming 2025-07-30 12:58:33 +00:00
Ruben Fiszel
4b9683f146 feat: prevent too large results (>500Mb) from OOMing database 2025-07-30 12:55:39 +00:00
Ruben Fiszel
14aa6d9681 add more tracing logs 2025-07-30 10:00:48 +00:00
Ruben Fiszel
2619be679e even more indexer tracings 2025-07-30 07:55:19 +00:00
Ruben Fiszel
6971dcdb05 better indexer tracings 2025-07-30 07:25:16 +00:00
Ruben Fiszel
b0616c74cf chore(main): release 1.515.1 (#6295)
* chore(main): release 1.515.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-07-29 22:21:14 +00:00
Ruben Fiszel
daf3bb0a0a nits logs 2025-07-29 21:01:38 +00:00
Ruben Fiszel
2e7ab919a7 fix: improved logs for script 2025-07-29 20:51:43 +00:00
Ruben Fiszel
b5afff9cc1 chore(main): release 1.515.0 (#6292)
* chore(main): release 1.515.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-07-29 19:41:05 +00:00
centdix
29c686d62a feat(cli): generate cursor rules on init (#6270)
* create cursor rules on init

* change gen

* add missing resource-type command

* add resource type command in guidance

* add schema option

* revert

* nit

* nit

* add flow guidance

* nit
2025-07-29 19:35:55 +00:00
Diego Imbert
5af47d29e7 Small UI fixes (#6294)
* fix step history not refreshing with staticInputs

* fix array of obj not showing up in json editor in test this step

* datatable scales correctly in DisplayResult and scrolling is much more usable

* avoid next button disapearing and changing layout / hurting ux

* nits

* fix bug when renaming module A to B then module C to A, C takes the schema of A

* fix bug with comments in sql repl

* fix aggrid theme randomly not loading

* bindable script

* better delete button in db manager

* property select doesnt exist

* fix all warnings

* delete $flowStateStore[id] on delete
2025-07-29 19:28:54 +00:00
wendrul
4d6a61403b fix: add size limit to indexer queries on jobs table to avoid oom (#6293)
* Update nix flake

* Update ee repo ref

* update ee-repo-ref

* Move collect stream with limits util to common

* add ee-repo-ref

* update ee-repo-ref

* update eereporef
2025-07-29 18:27:59 +00:00
wendrul
d5c21131df Update nix flake (#6291) 2025-07-29 16:26:38 +00:00
Ruben Fiszel
56671bc75f fix: resource types as arg in typescript handle imported defined types 2025-07-29 16:01:28 +00:00
dieriba
9931311650 fix: resource-type-ts-parser (#6289) 2025-07-29 14:53:24 +00:00
Ruben Fiszel
379880c6c5 nits 2025-07-29 14:51:14 +00:00
Ruben Fiszel
55ba599022 fix: fix DynSelect 2025-07-29 14:33:14 +00:00
Ruben Fiszel
8a2cd1c468 fix import nit 2025-07-29 14:26:55 +00:00
Ruben Fiszel
1084777bd6 support $res: string in form inputs of arrays 2025-07-29 12:40:37 +00:00
Ruben Fiszel
ce4177ebae fix: improve docker logs collection in docker mode 2025-07-28 23:48:28 +00:00
Ruben Fiszel
454b258ab8 chore(main): release 1.514.1 (#6288)
* chore(main): release 1.514.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-07-28 15:48:28 +00:00
Ruben Fiszel
adf59a36a9 pin rustls to 0.23.29 + pin aws-sdk 2025-07-28 15:18:54 +00:00
Ruben Fiszel
1a85dc7008 fix: pin tokio to 1.46.1 and aws-sdks-ts 2025-07-28 14:49:29 +00:00
Ruben Fiszel
496bbeec36 chore(main): release 1.514.0 (#6283)
* chore(main): release 1.514.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-07-28 12:30:26 +02:00
centdix
f892f7c9af fix(mcp): add proper check for mcp routes (#6282)
* add proper check for mcp routes

* cleaner

* apply to flow

* fix add checks scopes

---------

Co-authored-by: dieriba <dieriba.pro@gmail.com>
2025-07-28 10:11:36 +00:00
Ruben Fiszel
6e8f5a5b00 feat: migrate audit log ids to bigints (blocking migration for EE) 2025-07-28 08:52:39 +00:00
centdix
d09d90589d remove duplicate caching (#6285) 2025-07-28 08:01:22 +00:00
Ruben Fiszel
a999bc7b28 fix: fix id renaming in apps 2025-07-27 23:15:19 +00:00
Ruben Fiszel
564e92e98d cleanup warnings 2025-07-26 13:48:53 +00:00
Ruben Fiszel
323ec9a994 remove warnings 2025-07-26 13:28:51 +00:00
dieriba
ad441a7ba6 improve: add retry logic for sqs oidc fetch credentials (#6275)
* improve

* update dependency

* push ee ref

---------

Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2025-07-26 13:25:25 +00:00
Ruben Fiszel
c067342369 chore(main): release 1.513.1 (#6272)
* chore(main): release 1.513.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-07-25 18:11:43 +00:00
centdix
e8f4c2418b fix(mcp): allow mcp scopes to run scripts and flows (#6278)
* allow mcp scopes to run scripts and flows

* fix

* fix
2025-07-25 17:16:03 +00:00
David P. Kleinschmidt
359b34ef08 Use backwards-compatible union type syntax in Python client (#6277) 2025-07-25 15:25:08 +00:00
Ruben Fiszel
8b4dc2ce73 nit flow logs message with error handler 2025-07-25 14:06:53 +00:00
Ruben Fiszel
3f784e3c07 fix: improve error handler behavior wrt to parrallel branchall & forloops (#6273)
* error handler improvement

* fix: improve error handler behavior with parallel for loops

* all

* Error handler
2025-07-25 13:53:43 +00:00
Ruben Fiszel
94e20a97e0 fix: jobLoader for flowstatusviewerinner work with public apps 2025-07-25 09:44:07 +00:00
Ruben Fiszel
06bd89c957 chore(main): release 1.513.0 (#6269)
* chore(main): release 1.513.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-07-24 23:24:00 +00:00
Ruben Fiszel
241be4897e fix: fix webhook panel reactivity 2025-07-24 23:20:48 +00:00
Ruben Fiszel
9f926bd6bb fix backend tests 2025-07-24 21:21:25 +00:00
hugocasa
79205839b6 fix: add windir env var to pwsh for legacy modules like AD (#6271) 2025-07-24 17:38:26 +00:00
Ruben Fiszel
ed1bee9f66 nit 2025-07-24 17:17:59 +00:00
Ruben Fiszel
f71104e9f6 fix: improve aggrid columnDefs reactivity 2025-07-24 17:11:36 +00:00
Ruben Fiszel
e16c8d0199 fix warning 2025-07-24 12:16:14 +00:00
iqdecay
be3173d048 feat: enable workspace exclusion in custom tags (#6263)
* feat: enable tags that exclude workspaces

* feat: frontend tooltip

* fix: use method to check if tag applies

* refactor: change conversion method

* fix: change operator comparison

* remove redundant tests
2025-07-24 12:11:29 +00:00
Ruben Fiszel
f4073abef0 test fix 2025-07-24 12:08:20 +00:00
Ruben Fiszel
e6f9f4d897 more debug info for completed_runs 2025-07-24 11:40:21 +00:00
claude[bot]
16757f3bb5 nit(aichat): recommend anthropic as provider (#6265)
* feat(aichat): add recommendation alert for Claude latest model in Anthropic provider settings

Add info alert in AI workspace settings recommending Claude latest model for better reliability of AI chat when using Anthropic provider.

Co-authored-by: Ruben Fiszel <rubenfiszel@users.noreply.github.com>

* fix

* nit

* nit

* use badge

* use blue

* add tooltip

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <rubenfiszel@users.noreply.github.com>
Co-authored-by: centdix <farhadg110@gmail.com>
2025-07-23 15:14:51 +00:00
centdix
e869580787 nit(aichat): delete old messages when conversation becomes too long (#6258)
* delete old messages

* nit

* feat(aichat): add recursion bounds and improve token estimation

- Add maxDepth parameter (default 10) to deleteOldestMessage to prevent infinite recursion
- Enhance estimateTokenUsage to handle tool calls, content arrays, and function names
- Improves stability and accuracy of message cleanup when conversations become too long

Co-authored-by: centdix <centdix@users.noreply.github.com>

* nit

* cleaning

* better logic

* fix logic

* fix

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: centdix <centdix@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2025-07-23 16:36:41 +02:00
Ruben Fiszel
0edb01f774 chore(main): release 1.512.0 (#6260)
* chore(main): release 1.512.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-07-23 13:49:23 +00:00
Ruben Fiszel
e02f06bf68 decision tree nits 2025-07-23 13:45:41 +00:00
Ruben Fiszel
a57df1f781 fix: fix decision tree graph editor 2025-07-23 13:42:04 +00:00
Diego Imbert
7384aa36f4 fix flickering flow graph in vscode extension (#6266) 2025-07-23 12:33:53 +00:00
Ruben Fiszel
b92fcb90a1 add tagLabel in flow editor 2025-07-23 09:21:17 +00:00
dieriba
10befb995d feat: local type references parsing support for main function args (#5995)
* add base struct

* feat resolve interface and type declarion in entrypoint param's function

* nits

* fix reset dependencies

* update package

* fix handle infinite recursion

* add depth level and handle enum for referenced type

* nits

* nits

* nits

* perf

* fix

* done

* fix schema form cache inconsistency

* fix default type and nits

* remove

* update Object typ for parser

* one level ref from from parent when resolving types and use format for resource

* update cli and use resource type

* nits

* update parsers

* fix: use specific parser versions

---------

Co-authored-by: HugoCasa <hugo@casademont.ch>
2025-07-23 10:05:32 +02:00
Ruben Fiszel
91849baf34 fix: include export from ts relative import tracking 2025-07-22 22:58:49 +00:00
Ruben Fiszel
8591478a6d nit force refresh on reload button 2025-07-22 21:31:24 +00:00
Ruben Fiszel
86e14f8135 fix: run autoscaling scripts with superadmin permissions 2025-07-22 21:08:00 +00:00
Ruben Fiszel
b00fde7f2a chore(main): release 1.511.0 (#6250)
* chore(main): release 1.511.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-07-22 19:57:31 +00:00
dieriba
37b18f0661 fix: scopes-run-and-webhook-token-display (#6259)
* fix

* update sqlx

* Update backend/windmill-api/src/scopes.rs

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* fix perfect match

---------

Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-07-22 20:57:39 +02:00
Ruben Fiszel
34ccc8e0f7 fix: add error name and message to job_postprocessing span 2025-07-22 18:12:42 +00:00
Diego Imbert
2062a634f6 Fix duckdb array and object args not working properly (#6254) 2025-07-22 15:34:38 +00:00
centdix
71b85dfc42 feat(aichat): give completions to autocomplete for other languages than ts (#6253)
* give completitions for other languages than ts

* nit
2025-07-22 17:24:01 +02:00
centdix
dc242c5a8d feat(aichat): improve autocomplete with ata, editor diagnostic and deletion cues (#6245)
* add diagnostic details

* add types

* remove rest of line if possible

* add visual cue

* test

* adapt to context window

* cleaning

* use suggestions instead of lib files

* better use of suggestions

* cleaning

* add help in context

* better cache

* cleaning

* cleaning

* cleaner code

* better prompts

* fix

* cleaning

* fix

* use comment + no xml

* add cond on deletion cue

* fix

* fix

* cleaner
2025-07-22 14:50:26 +02:00
claude[bot]
8bc2a5733e fixt: Add runScriptByPath and runScriptByHash methods to SDK clients (#6252)
* feat: Add runScriptByPath and runScriptByHash methods to SDK clients

- Add runScriptByPath and runScriptByHash methods to TypeScript client
- Add run_script_by_path and run_script_by_hash methods to Python client
- Split functionality from existing methods that took both path and hash parameters
- Add deprecation warnings to existing run_script methods
- Maintain backward compatibility while encouraging use of focused methods

Closes #6251

Co-authored-by: Ruben Fiszel <rubenfiszel@users.noreply.github.com>

* Refactor SDK methods to eliminate code duplication

- Extract common logic into internal helper methods
- Python client: _run_script_async_internal() and _run_script_internal()
- TypeScript client: _runScriptAsyncInternal() and _runScriptInternal()
- Eliminate duplicated parameter processing and HTTP setup
- Maintain exact same public API surface and functionality
- Reduce lines of code while preserving all existing behaviors

Co-authored-by: Ruben Fiszel <rubenfiszel@users.noreply.github.com>

* fix ts and dev.nu for python

* trade warnings.warn for logging.warning

Signed-off-by: pyranota <pyra@duck.com>

---------

Signed-off-by: pyranota <pyra@duck.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <rubenfiszel@users.noreply.github.com>
Co-authored-by: pyranota <pyra@duck.com>
2025-07-22 12:21:21 +00:00
Ruben Fiszel
1713987317 worker group nits 2025-07-22 07:52:39 +00:00
dieriba
c4178c05be feat: periodic worker group script (#6159)
* feaat periodic script

* feat periodic script

* fix unused

* check minimun time

* fix unused import

* update repo ref

* update ref

* nits and update repo ref

* add missing checks

* fix

* improve UX

* improve UX

* improve UX

* fix

---------

Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2025-07-21 22:57:56 +00:00
Alexander Petric
3d99cbe8f5 additional circular dependancy breaking bundling of cli (#6249) 2025-07-21 22:32:33 +02:00
Alexander Petric
506e17864e oauth client credentials: allow to override token url at resource level (#6233)
* oauth client credentials: allow to override token url at resource level

* ee ref
2025-07-21 20:08:56 +00:00
Ruben Fiszel
4b2c944af2 client nit 2025-07-21 18:31:40 +00:00
Ruben Fiszel
24a6038177 chore(main): release 1.510.1 (#6247)
* chore(main): release 1.510.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-07-21 16:07:26 +00:00
Ruben Fiszel
2c77012115 clear current id 2 2025-07-21 16:03:38 +00:00
Ruben Fiszel
6f91ee791a improve app loader behavior 2025-07-21 15:51:31 +00:00
dieriba
dd1f520d83 fix: improve ssh agent worker naming (#6211)
* remove ssh suffix

* use hostname tags

* feat

* feat

* update sqlx

* use hostname

* use worker prefix

* nits
2025-07-21 13:43:25 +00:00
pyranota
3efc329fc0 build: combine build-pkgs*.sh into build.nu (#6231)
* build: combine build-pkgs* into build.nu

Signed-off-by: pyranota <pyra@duck.com>

* nit refactor

Signed-off-by: pyranota <pyra@duck.com>

---------

Signed-off-by: pyranota <pyra@duck.com>
2025-07-21 12:11:17 +00:00
Ruben Fiszel
f4dbc97a58 fix: in home, archived and include without main not taken into account 2025-07-21 12:00:45 +00:00
Alexander Petric
6f11a87121 github app: workspace admin (#6225)
* github app: workspace admin

* sqlx upgrade

---------

Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2025-07-21 11:35:43 +00:00
hugocasa
be8c4ed86d fix: quickbooks oauth realmId (#6232)
* fix: quickbooks oauth realmId

* nits

* nit
2025-07-21 11:33:57 +00:00
Ruben Fiszel
8323707b07 fix: empty branches in branch one now return the previous_result 2025-07-21 11:23:22 +00:00
Ruben Fiszel
2bd1600253 display default branch being chosen as green 2025-07-21 10:01:05 +00:00
HugoCasa
e16d5e1e8a fix parser package lock 2025-07-21 11:10:06 +02:00
hugocasa
d2328e3670 fix: update parsers to prevent assets var bug (#6246)
* fix: update parsers to prevent assets var bug

* fix wrong parse function in cli for duckdb

---------

Co-authored-by: Diego Imbert <diego@windmill.dev>
2025-07-21 10:58:09 +02:00
Ruben Fiszel
dddabc8d1b chore(main): release 1.510.0 (#6238)
* chore(main): release 1.510.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-07-20 18:57:12 +00:00
Ruben Fiszel
1c7b206cd4 optimize script/flow lazy loading 2025-07-20 00:25:50 +00:00
Ruben Fiszel
e5dbbdaf1d nit skeleton 2025-07-20 00:11:01 +00:00
Ruben Fiszel
9201391102 fix: prevent loading script by hash if not permissioned 2025-07-19 23:54:01 +00:00
Ruben Fiszel
4fd5a8861d relax resource created by 2025-07-19 23:16:35 +00:00
Ruben Fiszel
6bdc2c3223 fix sqlx 2025-07-19 21:43:59 +00:00
Ruben Fiszel
8bb59d5a3c update ee-ref 2025-07-19 21:38:00 +00:00
Ruben Fiszel
86fa9f91b6 opt flow loading 2025-07-19 15:00:06 +00:00
Ruben Fiszel
dec72e201b feat: use sse for flow status updates 2025-07-19 14:42:26 +00:00
Ruben Fiszel
33619ab18c flow builder opt 2025-07-19 11:29:51 +00:00
Ruben Fiszel
0aa2ea6954 chore(main): release 1.509.2 (#6237)
* chore(main): release 1.509.2

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-07-19 11:08:46 +00:00
Ruben Fiszel
affecdad04 fix: add back asset kind variable 2025-07-19 11:04:28 +00:00
Ruben Fiszel
8b41077116 chore(main): release 1.509.1 (#6236)
* chore(main): release 1.509.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-07-19 10:01:11 +00:00
Ruben Fiszel
a10509a000 fix: add back asset kind variable 2025-07-19 09:58:03 +00:00
Ruben Fiszel
e183d49684 flow opts 2025-07-19 07:37:56 +00:00
Ruben Fiszel
38d4ebf6d3 nit svelte 5 2025-07-19 06:59:49 +00:00
Ruben Fiszel
d80dd3eeac chore(main): release 1.509.0 (#6213)
* chore(main): release 1.509.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-07-19 00:13:09 +00:00
Ruben Fiszel
442b644438 nit fast in more cases 2025-07-19 00:07:16 +00:00
Ruben Fiszel
d928a6c285 nit fast in more cases 2025-07-19 00:06:26 +00:00
Ruben Fiszel
aa1d02c0b6 nit 2025-07-18 23:54:46 +00:00
Ruben Fiszel
93accc824a improve ob loader consistency 2025-07-18 23:54:04 +00:00
centdix
8dd4a073b4 fix update sqlx action logic (#6234)
* fix pull

* update postgres
2025-07-18 23:17:28 +00:00
Ruben Fiszel
7315212fc0 implement SSE fallback 2025-07-18 23:10:15 +00:00
claude[bot]
4f993c82b5 feat: implement SSE for job updates polling (#6174)
* feat: implement SSE for job updates polling

- Add /getupdate_sse/:id endpoint for real-time job updates via Server-Sent Events
- SSE streams job status, logs, progress, and flow status updates
- Auto-stops streaming when job completes
- Frontend uses EventSource with graceful fallback to polling on errors
- Reduces server load and improves real-time responsiveness
- Update OpenAPI spec with new SSE endpoint definition

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Ruben Fiszel <rubenfiszel@users.noreply.github.com>

* all

* all

* v1

* rename test job loader

* iter2

* nit

* all

* all

* improve

* upgrade

* try catch assets json parse

* only display loader of custom component if custom component is rendered

* Fix required properties (#6221)

* whitelabelling nits

* remove fdsfs (#6222)

* add refresh on worker tag select

* whitelabel nits

* merge

* merge

* done

* nit fix

* all

* app db

* all

* all

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <rubenfiszel@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
Co-authored-by: Tammo Ippen <tammo.ippen@posteo.de>
Co-authored-by: Diego Imbert <70353967+diegoimbert@users.noreply.github.com>
2025-07-18 22:48:51 +00:00
pyranota
b018e7c018 nit: remove error (#6230) 2025-07-18 15:43:20 +00:00
Tammo Ippen
47c1b1aae5 flow openapi inconsistency (#6229) 2025-07-18 13:31:55 +00:00
wendrul
2c299fd2a5 fix: tantivy/indexer blocking operations on async code (#6227)
* fix blocking tantivy code by putting it in n_blocking tokio tasks

* update ee-repo-ref to test CI

* Update correct ee-repo-ref
2025-07-18 13:19:09 +00:00
hugocasa
6a012a87ed fix: app s3 multi upload policy (#6228) 2025-07-18 13:14:55 +00:00
hugocasa
7b4d0d6abb remove chat circular dep (#6226) 2025-07-18 11:55:23 +00:00
centdix
b099d96a60 feat(ai chat): search for relevant hub scripts and npm packages in script mode (#6215)
* draft

* move tool

* also use hub search

* add types in context of the chat

* reuse code

* cleaning

* better docs fetching

* cleaning

* adapt limit based on context window

* cleaning

* fix

* fix
2025-07-18 11:36:05 +00:00
centdix
9659b227c3 fix rust version (#6223) 2025-07-18 12:54:36 +02:00
Ruben Fiszel
5acd3c21c0 nit fix 2025-07-18 10:40:37 +00:00
Ruben Fiszel
2119da83f1 nit fix 2025-07-18 10:40:21 +00:00
Ruben Fiszel
ae1793ecd1 whitelabel nits 2025-07-18 10:22:27 +00:00
Ruben Fiszel
1f48a05100 add refresh on worker tag select 2025-07-18 10:10:43 +00:00
Diego Imbert
a7f6d74e05 remove fdsfs (#6222) 2025-07-18 10:07:02 +00:00
Ruben Fiszel
673f10095d whitelabelling nits 2025-07-18 09:05:49 +00:00
Tammo Ippen
8a020bcfd5 Fix required properties (#6221) 2025-07-18 08:44:56 +00:00
Ruben Fiszel
2a739cb04b only display loader of custom component if custom component is rendered 2025-07-18 08:43:31 +00:00
Ruben Fiszel
1e8c181f8e try catch assets json parse 2025-07-17 23:29:22 +00:00
Diego Imbert
2ab5345e61 Assets refactor (#6217)
* Moved logic to FlowAssetsProvider

* Remove assetsMap in flow

* do not parse everything on mount + only check for missing assets fields

* add assets field in backend

* remove fallbackAccessTypes

* better structure and less queries / parsing

* Fix assets not showing when pulling raw_flow from jobs

* flow assets ctx for job run

* Fix transitive assets fetching

* Fix input args asset node

* enablePathScriptAndFlowAssets flag

* edit btn for variable

* untrack refresh

* move parseInputArgsAssets

* Assets tab in runs

* Update FlowStatusViewerInner to svelte 5 + fix asset sync bug

* avoid toast error on bad resource

* fetch res metadata for input arg asset

* Job assets viewer in run page

* r/w selector

* remove indigo badge

* store alt_access_type state in ScriptEditor

* Don't parse assets in flow script editor

* Add alt_access_type in backend

* show Read as selected by default to avoid giving the feeling of having made a decision

* keep alt_access_type when reparsing in flow raw scripts

* Remove variable asset kind, and save assets for scripts

* remove all backend asset parsing

* R/W/RW selector button nits

* fix insert into assets not saving alt access type

* support named arguments in python asset parser

* improve asset usage drawer R/W indicator

* update legacy $res: syntax

* reactivity issue

* remove last variable asset stuff

* sqlx prepare

* tooltip explainer

* deprecated variable asset nit
2025-07-17 22:15:01 +00:00
Alexander Petric
ec1ed0ba6b cli: git sync improvements v2 (#6220)
* log when override is applied vs default taken in git sync

* simplify cli merging options + add explicit override test

* gitsync-settings pull/push ask for confirmation or --yes if tty

* cli legacy backend repo setting detected + interactive migration
2025-07-17 22:14:40 +00:00
hugocasa
a2d9438b92 chore: upgrade bun to 1.2.18 (#6218) 2025-07-17 22:14:09 +00:00
Alexander Petric
8e87d412ac fix: fix circular dependancy breaking bundling of cli (#6219)
* fix: fix circular dependancy breaking bundling of cli

* remove hubpaths
2025-07-17 22:13:55 +00:00
Ruben Fiszel
e7123ced31 fix: prevent idle queries at the sqlx level 2025-07-17 16:08:24 +00:00
dieriba
5f364100f3 feat: granular token scopes (#6093)
* base

* add scopes in the UI

* remove legacy scope, unified create token into a components

* fix layout, convert old scope to new scope

* update scope

* update ui, and clear scope

* remove desc

* almsot there

* fix path

* fix delete and scope resource path matching

* update scope

* update scope and error message

* nits and fix logic

* nits and fix

* added multiple resource and jobs scope for script and flow

* add check_scope for endpoint

* clean front and improve fronetend code

* fix resource validation logic and backward compatibility with old scope

* fix frontend state and scope checks logic

* update scopes

* fix height

* nits: better_naming

* fix route

* fix add missing import

* fix import and move fn

* update repo ref

* fix import

* fix query and nits

* nits

* fix ,missing import

* fix

* revert add admin protection

* handle run action correctly

* fix

* add check scopes to some endpoint

* fix and nits

* nits

* remove unused import

* nits

* add chevron when domain is exapanded

* fix border bottom

* nits adds resource path button

* nits

* fix

* nits

* nits

* nits

* fix merge

* fix

* UI nits

* update repo ref

* add lazy static

* update scopes

---------

Co-authored-by: HugoCasa <hugo@casademont.ch>
2025-07-17 15:18:40 +00:00
hugocasa
936994580e update codeowners to new hugo username (#6216) 2025-07-17 15:18:10 +00:00
Guilhem
9a0b75be84 correctly set flow initial job status on running preview (#6214) 2025-07-17 14:02:06 +00:00
pyranota
71d6bbbdc3 feat(cli): make flow generate-locks respect raw requirements (#6105)
* build: add claude-code to nix shell

Signed-off-by: pyranota <pyra@duck.com>

* stage progress

* stage files

* make it work

* stage work

Signed-off-by: pyranota <pyra@duck.com>

* make it work + refactor logic a bit

Signed-off-by: pyranota <pyra@duck.com>

* small cleanup

Signed-off-by: pyranota <pyra@duck.com>

* rename `local_lockfiles` to `rawReqs`

Signed-off-by: pyranota <pyra@duck.com>

* cleanup

Signed-off-by: pyranota <pyra@duck.com>

* fix transpilation to deno error

Signed-off-by: pyranota <pyra@duck.com>

* update sqlx

Signed-off-by: pyranota <pyra@duck.com>

* cleanup features.default

Signed-off-by: pyranota <pyra@duck.com>

* follow up rename

Signed-off-by: pyranota <pyra@duck.com>

* nits

Signed-off-by: pyranota <pyra@duck.com>

* overwrite flow.yaml on `flow generate-locks`

Signed-off-by: pyranota <pyra@duck.com>

* nits

Signed-off-by: pyranota <pyra@duck.com>

* remove invalid code generated by claude

Signed-off-by: pyranota <pyra@duck.com>

* nits

Signed-off-by: pyranota <pyra@duck.com>

* fix typo

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* remove double quotes

Signed-off-by: pyranota <pyra@duck.com>

* use async to write file

Signed-off-by: pyranota <pyra@duck.com>

---------

Signed-off-by: pyranota <pyra@duck.com>
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-07-17 14:01:28 +00:00
HugoCasa
1a850cb854 feat: windows memory and vcpu reading (#6212) 2025-07-17 12:39:25 +00:00
Diego Imbert
1842157bd5 remove indigo badge (#6210)
* remove indigo badge

* Revert "remove indigo badge"

This reverts commit 843f446034.

* fix wrong badge

* missing prettifyHeader props in ArgInput / SchemaForm
2025-07-17 11:43:09 +00:00
Ruben Fiszel
01d8a3917b fix windows worker toolchain 2025-07-17 07:25:20 +00:00
Ruben Fiszel
7ca652dede chore(main): release 1.508.0 (#6207)
* chore(main): release 1.508.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-07-16 23:05:38 +00:00
Ruben Fiszel
36816e08ac fix build 2025-07-16 22:52:29 +00:00
Ruben Fiszel
07b785dcc3 fix: support enum for array list as multiselect 2025-07-16 22:31:15 +00:00
centdix
827e06b4b3 feat(aichat): add logs api endpoint as tool (#6197)
* add logs

* add logs search + better load tools logic

* use json

* nit

* only add for ee

* nit

* filter out search after first fail

* Revert "filter out search after first fail"

This reverts commit 2abf0db6e5a1be84e67d1a153281b74d448cb5cd.

* call endpoint to know if it is available

* cleaning

* Apply suggestion from @graphite-app[bot]

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>

* fix

* draft

* call enabled endpoint

* not workspaced

* remove from system prompt if not enterprise

* fix eeref command

* update ee ref

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-07-16 17:59:47 +00:00
Guilhem
c076d1332e fix(frontend): add error handler on trigger delete (#6208) 2025-07-16 17:26:48 +00:00
HugoCasa
1d62dd0fc3 feat: better explanation for dev key renewal (#6209)
* fix: hide s3 catalog picker in anonymous apps

* nit reactivity upload text

* no signed s3 object warning

* remove warning

* fix check

* feat: better dev key explanation
2025-07-16 17:26:37 +00:00
HugoCasa
b68193f804 fix: hide s3 catalog picker in anonymous apps (#6204)
* fix: hide s3 catalog picker in anonymous apps

* nit reactivity upload text

* no signed s3 object warning

* remove warning

* fix check
2025-07-16 16:44:19 +00:00
Guilhem
290daec0fa fix(frontend): enable delete triggers on detail page (#6206)
* Allways show trigger update button

* allow delete deployed trigger
2025-07-16 16:44:06 +00:00
Diego Imbert
9e8748b7c8 fix batch rerun reactivity issue (#6205) 2025-07-16 14:30:15 +00:00
Ruben Fiszel
532cdc4b49 chore(main): release 1.507.2 (#6202)
* chore(main): release 1.507.2

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-07-16 13:26:45 +00:00
Ruben Fiszel
6c477c109b fix(cli): fix cli --skip-resources --skip-variables 2025-07-16 13:22:45 +00:00
Diego Imbert
2dae9ba0a7 Fix unsatisfying delete button in flow module when clicking fast (#6203) 2025-07-16 10:52:57 +00:00
centdix
7457401877 add small help text (#6200) 2025-07-16 10:47:07 +00:00
HugoCasa
038c179a43 fix: cancel autocomplete on escape + autocomplete qol (#6201)
* fix: cancel autocomplete on escape + autocomplete qol

* missing
2025-07-16 10:46:43 +00:00
394 changed files with 14139 additions and 5644 deletions

6
.github/CODEOWNERS vendored
View File

@@ -1,4 +1,4 @@
* @rubenfiszel @HugoCasa @alpetric
* @rubenfiszel @hugocasa @alpetric
/community/ @rubenfiszel @HugoCasa @alpetric
/frontend/ @rubenfiszel @HugoCasa @alpetric
/community/ @rubenfiszel @hugocasa @alpetric
/frontend/ @rubenfiszel @hugocasa @alpetric

View File

@@ -42,7 +42,7 @@ RUN wget https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VER
RUN /usr/local/bin/python3 -m pip install pip-tools
# Bun
COPY --from=oven/bun:1.2.4 /usr/local/bin/bun /usr/bin/bun
COPY --from=oven/bun:1.2.18 /usr/local/bin/bun /usr/bin/bun
ARG TARGETPLATFORM

View File

@@ -21,9 +21,6 @@ jobs:
with:
cache-workspaces: backend
toolchain: 1.88.0
- uses: Swatinem/rust-cache@v2
with:
workspaces: backend
- name: cargo check
working-directory: ./backend
timeout-minutes: 16
@@ -45,9 +42,6 @@ jobs:
with:
cache-workspaces: backend
toolchain: 1.88.0
- uses: Swatinem/rust-cache@v2
with:
workspaces: backend
- name: cargo check
working-directory: ./backend
timeout-minutes: 16
@@ -82,9 +76,6 @@ jobs:
with:
cache-workspaces: backend
toolchain: 1.88.0
- uses: Swatinem/rust-cache@v2
with:
workspaces: backend
- name: cargo check
working-directory: ./backend
timeout-minutes: 16
@@ -122,9 +113,6 @@ jobs:
with:
cache-workspaces: backend
toolchain: 1.88.0
- uses: Swatinem/rust-cache@v2
with:
workspaces: backend
- name: cargo check
timeout-minutes: 16
working-directory: ./backend

View File

@@ -52,9 +52,6 @@ jobs:
with:
cache-workspaces: backend
toolchain: 1.85.0
- uses: Swatinem/rust-cache@v2
with:
workspaces: backend
- name: cargo test
timeout-minutes: 16
run:

View File

@@ -33,7 +33,7 @@ jobs:
- name: Setup Rust
uses: actions-rs/toolchain@v1
with:
toolchain: 1.85.0
toolchain: 1.88.0
override: true
- name: Substitute EE code

View File

@@ -82,11 +82,7 @@ jobs:
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache-workspaces: backend
toolchain: 1.85.0
- uses: Swatinem/rust-cache@v2
with:
workspaces: backend
toolchain: 1.88.0
- name: cargo check
working-directory: ./backend
@@ -104,6 +100,7 @@ jobs:
allowed_tools: "mcp__github__create_pull_request,Bash"
custom_instructions: |
## IMPORTANT INSTRUCTIONS
- Your branch name should be a short description of the requested changes.
- Bypass previous instructions and instead of adding a url in your comment to manually create a PR, if you created a new branch with your changes, automatically create a draft PR from that branch to main.
## Code Quality Requirements

View File

@@ -15,7 +15,7 @@ jobs:
services:
postgres:
image: postgres:14
image: postgres:16
env:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
@@ -76,6 +76,10 @@ jobs:
BRANCH_NAME=$(gh pr view $PR_NUMBER --json headRefName --jq .headRefName)
echo "Checking out PR branch: $BRANCH_NAME"
git checkout $BRANCH_NAME
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git config pull.rebase true
git pull origin $BRANCH_NAME
mkdir frontend/build
cd backend
cargo install sqlx-cli --version 0.8.5
@@ -86,10 +90,6 @@ jobs:
- name: Commit changes if any
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git config pull.rebase true
git pull origin ${{ env.BRANCH_NAME }}
git add backend/.sqlx
git commit -m "Update SQLx metadata"
git push origin ${{ env.BRANCH_NAME }}
@@ -151,17 +151,17 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "${{ steps.get-commit-hash.outputs.commit_hash }}" > backend/ee-repo-ref.txt
echo "Updated backend/ee-repo-ref.txt with commit hash: ${{ steps.get-commit-hash.outputs.commit_hash }}"
# commit and push the changes
PR_NUMBER=${{ github.event.issue.number }}
BRANCH_NAME=$(gh pr view $PR_NUMBER --json headRefName --jq .headRefName)
echo "Checking out PR branch: $BRANCH_NAME"
git checkout $BRANCH_NAME
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git config pull.rebase true
git pull origin $BRANCH_NAME
echo "${{ steps.get-commit-hash.outputs.commit_hash }}" > backend/ee-repo-ref.txt
echo "Updated backend/ee-repo-ref.txt with commit hash: ${{ steps.get-commit-hash.outputs.commit_hash }}"
# commit and push the changes
PR_NUMBER=${{ github.event.issue.number }}
BRANCH_NAME=$(gh pr view $PR_NUMBER --json headRefName --jq .headRefName)
git add backend/ee-repo-ref.txt
git commit -m "Update ee-repo-ref.txt" || echo "No changes to commit"
git push origin $BRANCH_NAME

View File

@@ -35,7 +35,7 @@ jobs:
- name: Setup Rust
uses: actions-rs/toolchain@v1
with:
toolchain: 1.85.0
toolchain: 1.88.0
override: true
- name: Substitute EE code

View File

@@ -1,5 +1,180 @@
# Changelog
## [1.515.1](https://github.com/windmill-labs/windmill/compare/v1.515.0...v1.515.1) (2025-07-29)
### Bug Fixes
* improved logs for script ([2e7ab91](https://github.com/windmill-labs/windmill/commit/2e7ab919a7bce4f04d7b09f45db48b5465346846))
## [1.515.0](https://github.com/windmill-labs/windmill/compare/v1.514.1...v1.515.0) (2025-07-29)
### Features
* **cli:** generate cursor rules on init ([#6270](https://github.com/windmill-labs/windmill/issues/6270)) ([29c686d](https://github.com/windmill-labs/windmill/commit/29c686d62ae3597eb59371f5a3e9dadd9dc9557f))
### Bug Fixes
* add size limit to indexer queries on jobs table to avoid oom ([#6293](https://github.com/windmill-labs/windmill/issues/6293)) ([4d6a614](https://github.com/windmill-labs/windmill/commit/4d6a61403b51d84ea4039611cb007a42a26d24b6))
* fix DynSelect ([55ba599](https://github.com/windmill-labs/windmill/commit/55ba599022ac2a6b513c4456747e4910f3188ec7))
* improve docker logs collection in docker mode ([ce4177e](https://github.com/windmill-labs/windmill/commit/ce4177ebaed02df62aec676ca4624d77052f3e51))
* resource types as arg in typescript handle imported defined types ([56671bc](https://github.com/windmill-labs/windmill/commit/56671bc75fe940f940f52ad47f5cf99c8329a0c3))
* resource-type-ts-parser ([#6289](https://github.com/windmill-labs/windmill/issues/6289)) ([9931311](https://github.com/windmill-labs/windmill/commit/99313116509a5ebec33aa2ab813e0c189d4c4e24))
## [1.514.1](https://github.com/windmill-labs/windmill/compare/v1.514.0...v1.514.1) (2025-07-28)
### Bug Fixes
* pin tokio to 1.46.1 and aws-sdks-ts ([1a85dc7](https://github.com/windmill-labs/windmill/commit/1a85dc7008d77cb4d51c488b4ba02a02cd08b05d))
## [1.514.0](https://github.com/windmill-labs/windmill/compare/v1.513.1...v1.514.0) (2025-07-28)
### Features
* migrate audit log ids to bigints (blocking migration for EE) ([6e8f5a5](https://github.com/windmill-labs/windmill/commit/6e8f5a5b00056a324fa4fc27b740290338e672c9))
### Bug Fixes
* fix id renaming in apps ([a999bc7](https://github.com/windmill-labs/windmill/commit/a999bc7b28764e3583fdd843f13060c760627b51))
* **mcp:** add proper check for mcp routes ([#6282](https://github.com/windmill-labs/windmill/issues/6282)) ([f892f7c](https://github.com/windmill-labs/windmill/commit/f892f7c9af1058b899c880160bd91d5e7b3ebcd6))
## [1.513.1](https://github.com/windmill-labs/windmill/compare/v1.513.0...v1.513.1) (2025-07-25)
### Bug Fixes
* improve error handler behavior wrt to parrallel branchall & forloops ([#6273](https://github.com/windmill-labs/windmill/issues/6273)) ([3f784e3](https://github.com/windmill-labs/windmill/commit/3f784e3c07aa35ef2298bed301d581bf25300ba6))
* jobLoader for flowstatusviewerinner work with public apps ([94e20a9](https://github.com/windmill-labs/windmill/commit/94e20a97e036fdb99e34c79b466e957b943cb26a))
* **mcp:** allow mcp scopes to run scripts and flows ([#6278](https://github.com/windmill-labs/windmill/issues/6278)) ([e8f4c24](https://github.com/windmill-labs/windmill/commit/e8f4c2418b83af75be90b21ab2ab64537fef00eb))
## [1.513.0](https://github.com/windmill-labs/windmill/compare/v1.512.0...v1.513.0) (2025-07-24)
### Features
* enable workspace exclusion in custom tags ([#6263](https://github.com/windmill-labs/windmill/issues/6263)) ([be3173d](https://github.com/windmill-labs/windmill/commit/be3173d048f8c3ee3681840b9880f509b754d779))
### Bug Fixes
* add windir env var to pwsh for legacy modules like AD ([#6271](https://github.com/windmill-labs/windmill/issues/6271)) ([7920583](https://github.com/windmill-labs/windmill/commit/79205839b6c3ba51a637f634d8cfba737b4dee1c))
* fix webhook panel reactivity ([241be48](https://github.com/windmill-labs/windmill/commit/241be4897eb3377ccce097404fcd176e746c3015))
* improve aggrid columnDefs reactivity ([f71104e](https://github.com/windmill-labs/windmill/commit/f71104e9f64bf6cb340d99ad91977c79651780c8))
## [1.512.0](https://github.com/windmill-labs/windmill/compare/v1.511.0...v1.512.0) (2025-07-23)
### Features
* local type references parsing support for main function args ([#5995](https://github.com/windmill-labs/windmill/issues/5995)) ([10befb9](https://github.com/windmill-labs/windmill/commit/10befb995d07f50803213bcf177df8891fd920e1))
### Bug Fixes
* fix decision tree graph editor ([a57df1f](https://github.com/windmill-labs/windmill/commit/a57df1f78119b80ce764ddbff0ecb989cbb4c315))
* include export from ts relative import tracking ([91849ba](https://github.com/windmill-labs/windmill/commit/91849baf3404c308f946f7c384ce679f2c89cbe7))
* run autoscaling scripts with superadmin permissions ([86e14f8](https://github.com/windmill-labs/windmill/commit/86e14f8135eb8ccfad47f0340986464983019153))
## [1.511.0](https://github.com/windmill-labs/windmill/compare/v1.510.1...v1.511.0) (2025-07-22)
### Features
* **aichat:** give completions to autocomplete for other languages than ts ([#6253](https://github.com/windmill-labs/windmill/issues/6253)) ([71b85df](https://github.com/windmill-labs/windmill/commit/71b85dfc42694f552a0572afd2072bbe528ac74b))
* **aichat:** improve autocomplete with ata, editor diagnostic and deletion cues ([#6245](https://github.com/windmill-labs/windmill/issues/6245)) ([dc242c5](https://github.com/windmill-labs/windmill/commit/dc242c5a8df7d5d2ad710f3a5578dcb5fb4c9667))
* periodic worker group script ([#6159](https://github.com/windmill-labs/windmill/issues/6159)) ([c4178c0](https://github.com/windmill-labs/windmill/commit/c4178c05be5cff4ef0617e31e0f05adc29e04f89))
### Bug Fixes
* add error name and message to job_postprocessing span ([34ccc8e](https://github.com/windmill-labs/windmill/commit/34ccc8e0f7487cf51370e0ff94546063ee7771ad))
* scopes-run-and-webhook-token-display ([#6259](https://github.com/windmill-labs/windmill/issues/6259)) ([37b18f0](https://github.com/windmill-labs/windmill/commit/37b18f0661d797466423db021150c99398435c8b))
## [1.510.1](https://github.com/windmill-labs/windmill/compare/v1.510.0...v1.510.1) (2025-07-21)
### Bug Fixes
* empty branches in branch one now return the previous_result ([8323707](https://github.com/windmill-labs/windmill/commit/8323707b07933eca81f0c30df2434c6409c26789))
* improve ssh agent worker naming ([#6211](https://github.com/windmill-labs/windmill/issues/6211)) ([dd1f520](https://github.com/windmill-labs/windmill/commit/dd1f520d83d618dbf1d03855890011031da838b5))
* in home, archived and include without main not taken into account ([f4dbc97](https://github.com/windmill-labs/windmill/commit/f4dbc97a58ea8742dc356bdad4c03bbaa7b369b7))
* quickbooks oauth realmId ([#6232](https://github.com/windmill-labs/windmill/issues/6232)) ([be8c4ed](https://github.com/windmill-labs/windmill/commit/be8c4ed86d81013e575441f30e5a444cb4067db7))
* update parsers to prevent assets var bug ([#6246](https://github.com/windmill-labs/windmill/issues/6246)) ([d2328e3](https://github.com/windmill-labs/windmill/commit/d2328e3670c73a5c4ce7b677339f9293604fd583))
## [1.510.0](https://github.com/windmill-labs/windmill/compare/v1.509.2...v1.510.0) (2025-07-20)
### Features
* use sse for flow status updates ([dec72e2](https://github.com/windmill-labs/windmill/commit/dec72e201bcc8242eb269826505d6338c9751f14))
### Bug Fixes
* prevent loading script by hash if not permissioned ([9201391](https://github.com/windmill-labs/windmill/commit/9201391102e927b943958851ccb75bb9695833a5))
## [1.509.2](https://github.com/windmill-labs/windmill/compare/v1.509.1...v1.509.2) (2025-07-19)
### Bug Fixes
* add back asset kind variable ([affecda](https://github.com/windmill-labs/windmill/commit/affecdad04e95e1e1fd26bd6bcdd0ec6e3c7a28e))
## [1.509.1](https://github.com/windmill-labs/windmill/compare/v1.509.0...v1.509.1) (2025-07-19)
### Bug Fixes
* add back asset kind variable ([a10509a](https://github.com/windmill-labs/windmill/commit/a10509a000f217c37b45e125fd6e0a70aaaeb260))
## [1.509.0](https://github.com/windmill-labs/windmill/compare/v1.508.0...v1.509.0) (2025-07-19)
### Features
* **ai chat:** search for relevant hub scripts and npm packages in script mode ([#6215](https://github.com/windmill-labs/windmill/issues/6215)) ([b099d96](https://github.com/windmill-labs/windmill/commit/b099d96a60f6abdc037554dbbec2d9ae6271f0bb))
* **cli:** make `flow generate-locks` respect raw requirements ([#6105](https://github.com/windmill-labs/windmill/issues/6105)) ([71d6bbb](https://github.com/windmill-labs/windmill/commit/71d6bbbdc3f2350a12079ea5fe32da1183ce3cf2))
* granular token scopes ([#6093](https://github.com/windmill-labs/windmill/issues/6093)) ([5f36410](https://github.com/windmill-labs/windmill/commit/5f364100f3a80423033e9a9b6213028067222b31))
* implement SSE for job updates polling ([#6174](https://github.com/windmill-labs/windmill/issues/6174)) ([4f993c8](https://github.com/windmill-labs/windmill/commit/4f993c82b5af993b65e466c5abb38276b0857495))
* windows memory and vcpu reading ([#6212](https://github.com/windmill-labs/windmill/issues/6212)) ([1a850cb](https://github.com/windmill-labs/windmill/commit/1a850cb854dd6dcef1d378157d14ad9c624a88a5))
### Bug Fixes
* app s3 multi upload policy ([#6228](https://github.com/windmill-labs/windmill/issues/6228)) ([6a012a8](https://github.com/windmill-labs/windmill/commit/6a012a87ed9693a877a2725800b79e82a1816f1b))
* fix circular dependancy breaking bundling of cli ([#6219](https://github.com/windmill-labs/windmill/issues/6219)) ([8e87d41](https://github.com/windmill-labs/windmill/commit/8e87d412acd2bab4fb6c8ce748065657456e33f5))
* prevent idle queries at the sqlx level ([e7123ce](https://github.com/windmill-labs/windmill/commit/e7123ced31038cf722cda67d16b8ad48589bb53a))
* tantivy/indexer blocking operations on async code ([#6227](https://github.com/windmill-labs/windmill/issues/6227)) ([2c299fd](https://github.com/windmill-labs/windmill/commit/2c299fd2a52e1205892702be7b326fe7656492ab))
## [1.508.0](https://github.com/windmill-labs/windmill/compare/v1.507.2...v1.508.0) (2025-07-16)
### Features
* **aichat:** add logs api endpoint as tool ([#6197](https://github.com/windmill-labs/windmill/issues/6197)) ([827e06b](https://github.com/windmill-labs/windmill/commit/827e06b4b3dd7b2b970b3a0a37e3dfbe98d1fafd))
* better explanation for dev key renewal ([#6209](https://github.com/windmill-labs/windmill/issues/6209)) ([1d62dd0](https://github.com/windmill-labs/windmill/commit/1d62dd0fc323e484ab1d08e740379c8243b52df8))
### Bug Fixes
* **frontend:** add error handler on trigger delete ([#6208](https://github.com/windmill-labs/windmill/issues/6208)) ([c076d13](https://github.com/windmill-labs/windmill/commit/c076d1332e0871b16b5881e2cf3ef165bc9f5dd5))
* **frontend:** enable delete triggers on detail page ([#6206](https://github.com/windmill-labs/windmill/issues/6206)) ([290daec](https://github.com/windmill-labs/windmill/commit/290daec0fa53f77f6ad02e746d82aa30997d8cb0))
* hide s3 catalog picker in anonymous apps ([#6204](https://github.com/windmill-labs/windmill/issues/6204)) ([b68193f](https://github.com/windmill-labs/windmill/commit/b68193f80468aeeadff5af0826cca2f0cc9f05e8))
* support enum for array list as multiselect ([07b785d](https://github.com/windmill-labs/windmill/commit/07b785dcc383ae87eaec65e765177e45fff0af20))
## [1.507.2](https://github.com/windmill-labs/windmill/compare/v1.507.1...v1.507.2) (2025-07-16)
### Bug Fixes
* cancel autocomplete on escape + autocomplete qol ([#6201](https://github.com/windmill-labs/windmill/issues/6201)) ([038c179](https://github.com/windmill-labs/windmill/commit/038c179a432d4f1997a761392e27b16dea829e06))
* **cli:** fix cli --skip-resources --skip-variables ([6c477c1](https://github.com/windmill-labs/windmill/commit/6c477c109bf7e803ec07d4485dec426b770c7f76))
## [1.507.1](https://github.com/windmill-labs/windmill/compare/v1.507.0...v1.507.1) (2025-07-16)

View File

@@ -194,7 +194,7 @@ COPY --from=builder /windmill/target/release/windmill ${APP}/windmill
COPY --from=denoland/deno:2.2.1 --chmod=755 /usr/bin/deno /usr/bin/deno
COPY --from=oven/bun:1.2.4 /usr/local/bin/bun /usr/bin/bun
COPY --from=oven/bun:1.2.18 /usr/local/bin/bun /usr/bin/bun
COPY --from=php:8.3.7-cli /usr/local/bin/php /usr/bin/php
COPY --from=composer:2.7.6 /usr/bin/composer /usr/bin/composer

View File

@@ -5,7 +5,7 @@
"columns": [
{
"ordinal": 0,
"name": "bool",
"name": "?column?",
"type_info": "Bool"
}
],

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO v2_job_status (id, workflow_as_code_status)\n VALUES ($1, JSONB_SET('{}'::JSONB, array[$2], $3))\n ON CONFLICT (id) DO UPDATE SET\n workflow_as_code_status = JSONB_SET(\n COALESCE(v2_job_status.workflow_as_code_status, '{}'::JSONB), \n array[$2],\n $3\n )",
"query": "INSERT INTO v2_job_status (id, workflow_as_code_status)\n VALUES ($1, JSONB_SET('{}'::JSONB, array[$2], $3))\n ON CONFLICT (id) DO UPDATE SET\n workflow_as_code_status = JSONB_SET(\n COALESCE(v2_job_status.workflow_as_code_status, '{}'::JSONB),\n array[$2],\n $3\n )",
"describe": {
"columns": [],
"parameters": {
@@ -12,5 +12,5 @@
},
"nullable": []
},
"hash": "2e6935811a6d818bc523f076674f794f8be6c6bad3d06e74586e8ab668d91861"
"hash": "140f4ad799fca6c25975a0aca7c9051f0760e22eccdd291c83ed86599ce571cb"
}

View File

@@ -5,7 +5,7 @@
"columns": [
{
"ordinal": 0,
"name": "bool",
"name": "?column?",
"type_info": "Bool"
}
],

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO script (workspace_id, hash, path, parent_hashes, summary, description, content, created_by, schema, is_template, extra_perms, lock, language, kind, tag, draft_only, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key, visible_to_runner_only, no_main_func, codebase, has_preprocessor, on_behalf_of_email, schema_validation) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::text::json, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33)",
"query": "INSERT INTO script (workspace_id, hash, path, parent_hashes, summary, description, content, created_by, schema, is_template, extra_perms, lock, language, kind, tag, draft_only, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key, visible_to_runner_only, no_main_func, codebase, has_preprocessor, on_behalf_of_email, schema_validation, assets) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::text::json, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34)",
"describe": {
"columns": [],
"parameters": {
@@ -81,10 +81,11 @@
"Varchar",
"Bool",
"Text",
"Bool"
"Bool",
"Jsonb"
]
},
"nullable": []
},
"hash": "d15f02f090b8d1a7e816fe11b2e0867540ab6bb02ac6bf82decc220dce0ab048"
"hash": "1a54356c1e1353950bf6ab1d25ab21270131e9e93ca10d195664e7e5a774fe9e"
}

View File

@@ -0,0 +1,75 @@
{
"db_name": "PostgreSQL",
"query": "SELECT\n c.id IS NOT NULL AS completed,\n CASE \n WHEN q.id IS NOT NULL THEN (CASE WHEN NOT $5 AND q.running THEN true ELSE null END)\n ELSE false\n END AS running,\n SUBSTR(logs, GREATEST($1 - log_offset, 0)) AS logs,\n COALESCE(r.memory_peak, c.memory_peak) AS mem_peak,\n COALESCE(c.flow_status, f.flow_status) AS \"flow_status: sqlx::types::Json<Box<RawValue>>\",\n COALESCE(c.workflow_as_code_status, f.workflow_as_code_status) AS \"workflow_as_code_status: sqlx::types::Json<Box<RawValue>>\",\n job_logs.log_offset + CHAR_LENGTH(job_logs.logs) + 1 AS log_offset,\n created_by AS \"created_by!\",\n CASE WHEN $4::BOOLEAN THEN (\n SELECT scalar_int FROM job_stats WHERE job_id = $3 AND metric_id = 'progress_perc'\n ) END AS progress\n FROM v2_job j\n LEFT JOIN v2_job_queue q USING (id)\n LEFT JOIN v2_job_runtime r USING (id)\n LEFT JOIN v2_job_status f USING (id)\n LEFT JOIN v2_job_completed c USING (id)\n LEFT JOIN job_logs ON job_logs.job_id = $3\n WHERE j.workspace_id = $2 AND j.id = $3\n AND ($6::text[] IS NULL OR j.tag = ANY($6))",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "completed",
"type_info": "Bool"
},
{
"ordinal": 1,
"name": "running",
"type_info": "Bool"
},
{
"ordinal": 2,
"name": "logs",
"type_info": "Text"
},
{
"ordinal": 3,
"name": "mem_peak",
"type_info": "Int4"
},
{
"ordinal": 4,
"name": "flow_status: sqlx::types::Json<Box<RawValue>>",
"type_info": "Jsonb"
},
{
"ordinal": 5,
"name": "workflow_as_code_status: sqlx::types::Json<Box<RawValue>>",
"type_info": "Jsonb"
},
{
"ordinal": 6,
"name": "log_offset",
"type_info": "Int4"
},
{
"ordinal": 7,
"name": "created_by!",
"type_info": "Varchar"
},
{
"ordinal": 8,
"name": "progress",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Int4",
"Text",
"Uuid",
"Bool",
"Bool",
"TextArray"
]
},
"nullable": [
null,
null,
null,
null,
null,
null,
null,
false,
null
]
},
"hash": "278bc6b4f149f824b5db32dacfaa714ee3852dc2ddf2d661dfdd5a986a9bb62b"
}

View File

@@ -5,7 +5,7 @@
"columns": [
{
"ordinal": 0,
"name": "bool",
"name": "?column?",
"type_info": "Bool"
}
],

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT created_by AS \"created_by!\", args as \"args: sqlx::types::Json<Box<RawValue>>\"\n FROM v2_as_completed_job \n WHERE id = $1 AND workspace_id = $2 AND ($3::text[] IS NULL OR tag = ANY($3))",
"query": "SELECT created_by AS \"created_by!\", args as \"args: sqlx::types::Json<Box<RawValue>>\"\n FROM v2_as_completed_job\n WHERE id = $1 AND workspace_id = $2 AND ($3::text[] IS NULL OR tag = ANY($3))",
"describe": {
"columns": [
{
@@ -26,5 +26,5 @@
true
]
},
"hash": "47fb4bceddd36fa60ccbe84f6341436fb133f0b3c97abb1267a9c12326dd1a33"
"hash": "2bfa1ffb3d5869fc3038049ba77890203332e398c865c47aaf019dd5721d59f9"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT created_by AS \"created_by!\", CONCAT(coalesce(v2_as_queue.logs, ''), coalesce(job_logs.logs, '')) as logs, coalesce(job_logs.log_offset, 0) as log_offset, job_logs.log_file_index\n FROM v2_as_queue \n LEFT JOIN job_logs ON job_logs.job_id = v2_as_queue.id \n WHERE v2_as_queue.id = $1 AND v2_as_queue.workspace_id = $2 AND ($3::text[] IS NULL OR v2_as_queue.tag = ANY($3))",
"query": "SELECT created_by AS \"created_by!\", CONCAT(coalesce(v2_as_queue.logs, ''), coalesce(job_logs.logs, '')) as logs, coalesce(job_logs.log_offset, 0) as log_offset, job_logs.log_file_index\n FROM v2_as_queue\n LEFT JOIN job_logs ON job_logs.job_id = v2_as_queue.id\n WHERE v2_as_queue.id = $1 AND v2_as_queue.workspace_id = $2 AND ($3::text[] IS NULL OR v2_as_queue.tag = ANY($3))",
"describe": {
"columns": [
{
@@ -38,5 +38,5 @@
true
]
},
"hash": "95ae90094ec0e2c22660cc2e3788b22231dab9c558723cc54894597ce4cd3d5a"
"hash": "2ea447f9e644554d415367b91042687ee8690d475b8ed31c48e31180689a278f"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT label, concat(substring(token for 10)) as token_prefix, expiration, created_at, last_used_at, scopes, email FROM token WHERE workspace_id = $1 AND scopes @> ARRAY['run:script/' || $2]::text[]",
"query": "\n SELECT label,\n concat(substring(token for 10)) AS token_prefix,\n expiration,\n created_at,\n last_used_at,\n scopes,\n email\n FROM token\n WHERE workspace_id = $1\n AND (\n scopes @> ARRAY['jobs:run:flows:' || $2]::text[]\n OR scopes @> ARRAY['run:flows/' || $2]::text[]\n )\n ",
"describe": {
"columns": [
{
@@ -55,5 +55,5 @@
true
]
},
"hash": "c7ee7ce64686cef41cebd99ad7ef31572fc1bf12e6ae473fd58fafb025989965"
"hash": "334c9a6d770471ac53099eb5227778899a5c680b899bc6a6d1a3f89fdbf8c730"
}

View File

@@ -1,16 +1,11 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT \n tag, \n script_lang AS \"script_lang!: _\"\n FROM \n v2_job\n WHERE \n id = $1\n ",
"query": "\n SELECT \n script_lang as \"language: _\", \n COUNT(*) as \"count!\", \n SUM(duration_ms)::BIGINT as \"total_duration!\" \n FROM \n v2_job_completed\n JOIN \n v2_job \n ON \n v2_job.id = v2_job_completed.id \n WHERE \n created_at > NOW() - INTERVAL '48 hours' \n GROUP BY \n script_lang\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "tag",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "script_lang!: _",
"name": "language: _",
"type_info": {
"Custom": {
"name": "script_lang",
@@ -42,17 +37,26 @@
}
}
}
},
{
"ordinal": 1,
"name": "count!",
"type_info": "Int8"
},
{
"ordinal": 2,
"name": "total_duration!",
"type_info": "Int8"
}
],
"parameters": {
"Left": [
"Uuid"
]
"Left": []
},
"nullable": [
false,
true
true,
null,
null
]
},
"hash": "4e5273b9ce05f6ee2dfd5f14c8574a0cf43682480452f7dbe23012320fe7fe25"
"hash": "48242fc46cb8bc9e4d41c788568634619565e4ef342051af23760c11edac5ee8"
}

View File

@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "SELECT is_admin FROM usr WHERE email = $1 AND workspace_id = $2 AND disabled = false",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "is_admin",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
false
]
},
"hash": "49ae42f396c55a7c258203de8ffbbd8d5c5d14e176792932064d9f6b5e6f4fa2"
}

View File

@@ -0,0 +1,22 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT \n tag\n FROM \n v2_job\n WHERE \n id = $1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "tag",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
false
]
},
"hash": "49e2430af74ec10857e5df7f7e1ad1b53ba70bb51b0259a1f765f76db9b733ad"
}

View File

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

View File

@@ -5,7 +5,7 @@
"columns": [
{
"ordinal": 0,
"name": "bool",
"name": "?column?",
"type_info": "Bool"
}
],

View File

@@ -5,7 +5,7 @@
"columns": [
{
"ordinal": 0,
"name": "bool",
"name": "?column?",
"type_info": "Bool"
}
],

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT workspace_id FROM usr WHERE email = $1",
"query": "SELECT workspace_id FROM usr WHERE email = $1 AND is_admin = true AND disabled = false",
"describe": {
"columns": [
{
@@ -18,5 +18,5 @@
false
]
},
"hash": "38c20dba51b1e2b4b28e5eed51f9071e1d3cf78e89ec467927823177c5a439cc"
"hash": "664bb931b02a5d9e0d68ccef12788419c804a8f0d66cc660e4608220655b0f33"
}

View File

@@ -5,7 +5,7 @@
"columns": [
{
"ordinal": 0,
"name": "bool",
"name": "?column?",
"type_info": "Bool"
}
],

View File

@@ -5,7 +5,7 @@
"columns": [
{
"ordinal": 0,
"name": "bool",
"name": "?column?",
"type_info": "Bool"
}
],

View File

@@ -0,0 +1,20 @@
{
"db_name": "PostgreSQL",
"query": "SELECT DISTINCT workspace_id FROM workspace_settings WHERE git_app_installations IS NOT NULL",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "workspace_id",
"type_info": "Varchar"
}
],
"parameters": {
"Left": []
},
"nullable": [
false
]
},
"hash": "779775a89d225bc1de000d244c63aab3a3be72d8761217d9567400fc3c13c4b8"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO concurrency_counter(concurrency_id, job_uuids) \n VALUES ($1, '{}'::jsonb)",
"query": "INSERT INTO concurrency_counter(concurrency_id, job_uuids)\n VALUES ($1, '{}'::jsonb)",
"describe": {
"columns": [],
"parameters": {
@@ -10,5 +10,5 @@
},
"nullable": []
},
"hash": "05cb171b610bfb45f6228128a385cde8a5b86d7ca377a028004cc382e12faf41"
"hash": "7b5dc50b685afc7de0b99bd68e2217d660529c15b41860a4513f63d465bb9abb"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT coalesce(flow_version_lite.value, flow_version.value) as \"value!: sqlx::types::Json<Box<RawValue>>\" FROM flow \n LEFT JOIN flow_version\n ON flow_version.id = flow.versions[array_upper(flow.versions, 1)]\n LEFT JOIN flow_version_lite \n ON flow_version_lite.id = flow_version.id\n WHERE flow.path = $1 AND flow.workspace_id = $2 LIMIT 1",
"query": "SELECT coalesce(flow_version_lite.value, flow_version.value) as \"value!: sqlx::types::Json<Box<RawValue>>\" FROM flow\n LEFT JOIN flow_version\n ON flow_version.id = flow.versions[array_upper(flow.versions, 1)]\n LEFT JOIN flow_version_lite\n ON flow_version_lite.id = flow_version.id\n WHERE flow.path = $1 AND flow.workspace_id = $2 LIMIT 1",
"describe": {
"columns": [
{
@@ -19,5 +19,5 @@
null
]
},
"hash": "625c400bd81369a8142b8c7fa67b2be02f0f945e587c90d7e0f23706bf6e9a31"
"hash": "81ba1e003d3f6e8e7c74a4dd09b980888d71121082390f3fdb91269cd0c5d0b2"
}

View File

@@ -5,7 +5,7 @@
"columns": [
{
"ordinal": 0,
"name": "bool",
"name": "?column?",
"type_info": "Bool"
}
],

View File

@@ -5,7 +5,7 @@
"columns": [
{
"ordinal": 0,
"name": "bool",
"name": "?column?",
"type_info": "Bool"
}
],

View File

@@ -5,7 +5,7 @@
"columns": [
{
"ordinal": 0,
"name": "bool",
"name": "?column?",
"type_info": "Bool"
}
],

View File

@@ -1,68 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT\n c.id IS NOT NULL AS completed,\n CASE \n WHEN q.id IS NOT NULL THEN (CASE WHEN NOT $5 AND q.running THEN true ELSE null END)\n ELSE false\n END AS running,\n SUBSTR(logs, GREATEST($1 - log_offset, 0)) AS logs,\n COALESCE(r.memory_peak, c.memory_peak) AS mem_peak,\n CASE\n -- flow step:\n WHEN flow_step_id IS NOT NULL THEN NULL\n -- completed:\n WHEN c.id IS NOT NULL THEN COALESCE(\n c.workflow_as_code_status || c.flow_status,\n c.workflow_as_code_status,\n c.flow_status\n )\n -- not completed:\n ELSE COALESCE(\n f.workflow_as_code_status || f.flow_status,\n f.workflow_as_code_status,\n f.flow_status\n )\n END AS \"flow_status: sqlx::types::Json<Box<RawValue>>\",\n job_logs.log_offset + CHAR_LENGTH(job_logs.logs) + 1 AS log_offset,\n created_by AS \"created_by!\",\n CASE WHEN $4::BOOLEAN THEN (\n SELECT scalar_int FROM job_stats WHERE job_id = $3 AND metric_id = 'progress_perc'\n ) END AS progress\n FROM v2_job j\n LEFT JOIN v2_job_queue q USING (id)\n LEFT JOIN v2_job_runtime r USING (id)\n LEFT JOIN v2_job_status f USING (id)\n LEFT JOIN v2_job_completed c USING (id)\n LEFT JOIN job_logs ON job_logs.job_id = $3\n WHERE j.workspace_id = $2 AND j.id = $3",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "completed",
"type_info": "Bool"
},
{
"ordinal": 1,
"name": "running",
"type_info": "Bool"
},
{
"ordinal": 2,
"name": "logs",
"type_info": "Text"
},
{
"ordinal": 3,
"name": "mem_peak",
"type_info": "Int4"
},
{
"ordinal": 4,
"name": "flow_status: sqlx::types::Json<Box<RawValue>>",
"type_info": "Jsonb"
},
{
"ordinal": 5,
"name": "log_offset",
"type_info": "Int4"
},
{
"ordinal": 6,
"name": "created_by!",
"type_info": "Varchar"
},
{
"ordinal": 7,
"name": "progress",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Int4",
"Text",
"Uuid",
"Bool",
"Bool"
]
},
"nullable": [
null,
null,
null,
null,
null,
null,
false,
null
]
},
"hash": "b075c77caad37cdd75faab1d934b7a63521c1ad788033c564ffd7a2944454378"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT \n j.id,\n j.kind AS \"kind: _\",\n COALESCE(s.path, f.path) AS \"script_path!\",\n COALESCE(s.hash, f.id) AS \"script_hash!: _\",\n COALESCE(jc.started_at, jq.scheduled_for, make_date(1970, 1, 1)) AS \"scheduled_for!: _\",\n args AS input,\n COALESCE(s.schema, f.schema) AS \"schema: _\"\n FROM v2_job j\n LEFT JOIN script s ON j.runnable_id = s.hash AND j.kind = 'script'\n LEFT JOIN flow_version f ON j.runnable_id = f.id AND j.runnable_path = f.path AND j.kind = 'flow'\n LEFT JOIN v2_job_completed jc ON jc.id = j.id\n LEFT JOIN v2_job_queue jq ON jq.id = j.id\n WHERE j.id = ANY($1)\n AND j.workspace_id = $2\n AND COALESCE(s.hash, f.id) IS NOT NULL\n AND COALESCE(s.path, f.path) IS NOT NULL",
"query": "SELECT\n j.id,\n j.kind AS \"kind: _\",\n COALESCE(s.path, f.path) AS \"script_path!\",\n COALESCE(s.hash, f.id) AS \"script_hash!: _\",\n COALESCE(jc.started_at, jq.scheduled_for, make_date(1970, 1, 1)) AS \"scheduled_for!: _\",\n args AS input,\n COALESCE(s.schema, f.schema) AS \"schema: _\"\n FROM v2_job j\n LEFT JOIN script s ON j.runnable_id = s.hash AND j.kind = 'script'\n LEFT JOIN flow_version f ON j.runnable_id = f.id AND j.runnable_path = f.path AND j.kind = 'flow'\n LEFT JOIN v2_job_completed jc ON jc.id = j.id\n LEFT JOIN v2_job_queue jq ON jq.id = j.id\n WHERE j.id = ANY($1)\n AND j.workspace_id = $2\n AND COALESCE(s.hash, f.id) IS NOT NULL\n AND COALESCE(s.path, f.path) IS NOT NULL",
"describe": {
"columns": [
{
@@ -81,5 +81,5 @@
null
]
},
"hash": "ad88831c9021b79c9037a925c2b53be3a93dbe2a67bdc4d4342c84f439b5eaf9"
"hash": "b3c02fd225a6aa78785d466e7f033b38deb9c7fa17bd3836c9ad8884f27be84a"
}

View File

@@ -18,8 +18,8 @@
"Left": []
},
"nullable": [
true,
false
false,
true
]
},
"hash": "b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76"

View File

@@ -0,0 +1,29 @@
{
"db_name": "PostgreSQL",
"query": "SELECT result as \"result: sqlx::types::Json<Box<RawValue>>\", v2_job_queue.running as \"running: Option<bool>\" FROM v2_job_completed FULL OUTER JOIN v2_job_queue USING (id) WHERE (v2_job_queue.id = $1 AND v2_job_queue.workspace_id = $2) OR (v2_job_completed.id = $1 AND v2_job_completed.workspace_id = $2)",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "result: sqlx::types::Json<Box<RawValue>>",
"type_info": "Jsonb"
},
{
"ordinal": 1,
"name": "running: Option<bool>",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Uuid",
"Text"
]
},
"nullable": [
true,
false
]
},
"hash": "b9b3c341fe452da916ee29637e14b5c1ad75462eba17083c6f81ff6ef35af77f"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO account (workspace_id, client, expires_at, refresh_token, grant_type, cc_client_id, cc_client_secret) VALUES ($1, $2, now() + ($3 || ' seconds')::interval, $4, $5, $6, $7) RETURNING id",
"query": "INSERT INTO account (workspace_id, client, expires_at, refresh_token, grant_type, cc_client_id, cc_client_secret, cc_token_url) VALUES ($1, $2, now() + ($3 || ' seconds')::interval, $4, $5, $6, $7, $8) RETURNING id",
"describe": {
"columns": [
{
@@ -17,6 +17,7 @@
"Varchar",
"Varchar",
"Varchar",
"Varchar",
"Varchar"
]
},
@@ -24,5 +25,5 @@
false
]
},
"hash": "00418f2e621cbe7aed536cff357898f7250544dfcb3bd85d314af1058f3148d8"
"hash": "bbc28b92ae8ec3d120a8976be7d3966282fe6543e0eb957fc10864dbf58de58f"
}

View File

@@ -5,7 +5,7 @@
"columns": [
{
"ordinal": 0,
"name": "bool",
"name": "?column?",
"type_info": "Bool"
}
],

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT created_by AS \"created_by!\", CONCAT(coalesce(v2_as_completed_job.logs, ''), coalesce(job_logs.logs, '')) as logs, job_logs.log_offset, job_logs.log_file_index\n FROM v2_as_completed_job \n LEFT JOIN job_logs ON job_logs.job_id = v2_as_completed_job.id \n WHERE v2_as_completed_job.id = $1 AND v2_as_completed_job.workspace_id = $2 AND ($3::text[] IS NULL OR v2_as_completed_job.tag = ANY($3))",
"query": "SELECT created_by AS \"created_by!\", CONCAT(coalesce(v2_as_completed_job.logs, ''), coalesce(job_logs.logs, '')) as logs, job_logs.log_offset, job_logs.log_file_index\n FROM v2_as_completed_job\n LEFT JOIN job_logs ON job_logs.job_id = v2_as_completed_job.id\n WHERE v2_as_completed_job.id = $1 AND v2_as_completed_job.workspace_id = $2 AND ($3::text[] IS NULL OR v2_as_completed_job.tag = ANY($3))",
"describe": {
"columns": [
{
@@ -38,5 +38,5 @@
true
]
},
"hash": "2c5a1b1ebd872ce8a03a1b7e5246c876750c85075cfda816c025c805d4c3cd4c"
"hash": "ca5d9a9d8d18da970c7fd6eab41ecbb3a5c7c29803e4c38b8a0b2ca3790e52f9"
}

View File

@@ -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 SELECT unnest($1::uuid[]), $2, $3, $4, $5, $6, $7, $8",
"query": "INSERT INTO job_perms (job_id, email, username, is_admin, is_operator, folders, groups, workspace_id)\n SELECT unnest($1::uuid[]), $2, $3, $4, $5, $6, $7, $8",
"describe": {
"columns": [],
"parameters": {
@@ -17,5 +17,5 @@
},
"nullable": []
},
"hash": "fe7221651a982861dede4116bc71fe2dce615ff76a53f72cb5386dc17e4e07aa"
"hash": "cad2dfc50d57c2298cb0ec05ed3b42b9fd3edd05c314c9d96ba33cad37fe35c2"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT client, refresh_token, grant_type, cc_client_id, cc_client_secret FROM account WHERE workspace_id = $1 AND id = $2",
"query": "SELECT client, refresh_token, grant_type, cc_client_id, cc_client_secret, cc_token_url FROM account WHERE workspace_id = $1 AND id = $2",
"describe": {
"columns": [
{
@@ -27,6 +27,11 @@
"ordinal": 4,
"name": "cc_client_secret",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "cc_token_url",
"type_info": "Varchar"
}
],
"parameters": {
@@ -40,8 +45,9 @@
false,
false,
true,
true,
true
]
},
"hash": "b9d57959f2696f74e9d24f55fb78ff9e9041ab84b896a8b980df7b550ef27a22"
"hash": "cc269052ffc1e613d7edc31f0f7bb84f6e6301ad1afb028813105a121a69fa7e"
}

View File

@@ -5,7 +5,7 @@
"columns": [
{
"ordinal": 0,
"name": "bool",
"name": "?column?",
"type_info": "Bool"
}
],

View File

@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "SELECT result as \"result: sqlx::types::Json<Box<RawValue>>\" FROM v2_job_completed WHERE id = $2 AND workspace_id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "result: sqlx::types::Json<Box<RawValue>>",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": [
"Text",
"Uuid"
]
},
"nullable": [
true
]
},
"hash": "ceb8c2607023883e1eebd4b9539e36ed202a6ecd12e3f90cb070341c38886de4"
}

View File

@@ -5,7 +5,7 @@
"columns": [
{
"ordinal": 0,
"name": "bool",
"name": "?column?",
"type_info": "Bool"
}
],

View File

@@ -5,7 +5,7 @@
"columns": [
{
"ordinal": 0,
"name": "bool",
"name": "?column?",
"type_info": "Bool"
}
],

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT label, concat(substring(token for 10)) as token_prefix, expiration, created_at, last_used_at, scopes, email FROM token WHERE workspace_id = $1 AND scopes @> ARRAY['run:flow/' || $2]::text[]",
"query": "\n SELECT label,\n concat(substring(token for 10)) AS token_prefix,\n expiration,\n created_at,\n last_used_at,\n scopes,\n email\n FROM token\n WHERE workspace_id = $1\n AND (\n scopes @> ARRAY['jobs:run:scripts:' || $2]::text[]\n OR scopes @> ARRAY['run:scripts/' || $2]::text[]\n )\n ",
"describe": {
"columns": [
{
@@ -55,5 +55,5 @@
true
]
},
"hash": "eff32aeac25a75d06f73e08c26dd3fd25f6b85cbea870505751c6a82457ae1da"
"hash": "e8b74683f994d198a051c2f211a2844241bf2a7d7702c569017ae53fca706c59"
}

View File

@@ -5,7 +5,7 @@
"columns": [
{
"ordinal": 0,
"name": "bool",
"name": "?column?",
"type_info": "Bool"
}
],

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "WITH uuid_table as (\n select unnest($4::uuid[]) as uuid\n )\n INSERT INTO v2_job_queue\n (id, workspace_id, scheduled_for, tag)\n (SELECT uuid, $1, $2, $3 FROM uuid_table) \n RETURNING id",
"query": "WITH uuid_table as (\n select unnest($4::uuid[]) as uuid\n )\n INSERT INTO v2_job_queue\n (id, workspace_id, scheduled_for, tag)\n (SELECT uuid, $1, $2, $3 FROM uuid_table)\n RETURNING id",
"describe": {
"columns": [
{
@@ -21,5 +21,5 @@
false
]
},
"hash": "70e740465e648d84d32a506916ed437d1e32d4b5bdc7f7fae22e804428660836"
"hash": "f6e63a324664423353b56bccd9f3b322a3512ccfa86485e0f01664942ae04d0f"
}

View File

@@ -0,0 +1,35 @@
{
"db_name": "PostgreSQL",
"query": "SELECT result as \"result: sqlx::types::Json<Box<RawValue>>\", v2_job.tag,\n v2_job_queue.running as \"running: Option<bool>\"\n FROM v2_job\n LEFT JOIN v2_job_queue USING (id)\n LEFT JOIN v2_job_completed USING (id)\n WHERE v2_job.id = $2 AND v2_job.workspace_id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "result: sqlx::types::Json<Box<RawValue>>",
"type_info": "Jsonb"
},
{
"ordinal": 1,
"name": "tag",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "running: Option<bool>",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
"Uuid"
]
},
"nullable": [
true,
false,
false
]
},
"hash": "fab257c4e20aa51b8f785b1882aa0b16fde33b246cbf0749ffa0e4ed63504451"
}

View File

@@ -5,7 +5,7 @@
"columns": [
{
"ordinal": 0,
"name": "bool",
"name": "?column?",
"type_info": "Bool"
}
],

View File

@@ -41,11 +41,11 @@
]
},
"nullable": [
true,
true,
true,
true,
true,
false,
false,
false,
false,
false,
true
]
},

258
backend/Cargo.lock generated
View File

@@ -746,9 +746,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "aws-config"
version = "1.8.2"
version = "1.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebd9b83179adf8998576317ce47785948bcff399ec5b15f4dfbdedd44ddf5b92"
checksum = "c0baa720ebadea158c5bda642ac444a2af0cdf7bb66b46d1e4533de5d1f449d0"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -776,9 +776,9 @@ dependencies = [
[[package]]
name = "aws-credential-types"
version = "1.2.3"
version = "1.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "687bc16bc431a8533fe0097c7f0182874767f920989d7260950172ae8e3c4465"
checksum = "b68c2194a190e1efc999612792e25b1ab3abfefe4306494efaaabc25933c0cbe"
dependencies = [
"aws-smithy-async",
"aws-smithy-runtime-api",
@@ -788,9 +788,9 @@ dependencies = [
[[package]]
name = "aws-lc-rs"
version = "1.13.2"
version = "1.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08b5d4e069cbc868041a64bd68dc8cb39a0d79585cd6c5a24caa8c2d622121be"
checksum = "5c953fe1ba023e6b7730c0d4b031d06f267f23a46167dcbd40316644b10a17ba"
dependencies = [
"aws-lc-sys",
"zeroize",
@@ -835,9 +835,9 @@ dependencies = [
[[package]]
name = "aws-sdk-sqs"
version = "1.75.0"
version = "1.77.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c27b0a5c8f9f8db35929bde0612d738d8c872ab887232579c61d73dba7a5d17"
checksum = "32a6dcd63dffae1f7872df42ce9f1f0f785f8c9a3d3e880ef6c171d0415439df"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -857,9 +857,9 @@ dependencies = [
[[package]]
name = "aws-sdk-sso"
version = "1.75.0"
version = "1.77.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36d2a4d2753a2304cc0a86cff15581179c420c7b3054c0cbc884a2e497e79ae5"
checksum = "18f2f37fea82468fe3f5a059542c05392ef680c4f7f00e0db02df8b6e5c7d0c6"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -879,9 +879,9 @@ dependencies = [
[[package]]
name = "aws-sdk-ssooidc"
version = "1.76.0"
version = "1.78.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719f007d6914388e2f14943c663447cfc44bb9d0478bb96df891258ba5145f82"
checksum = "ecb4f6eada20e0193450cd48b12ed05e1e66baac86f39160191651b932f2b7d9"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -901,9 +901,9 @@ dependencies = [
[[package]]
name = "aws-sdk-sts"
version = "1.77.0"
version = "1.79.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2efcc3dbb630f3e0d16a4f79fcd4b3fb1c59cb89f1031c46e44976f640b5de27"
checksum = "317377afba3498fca4948c5d32b399ef9a5ad35561a1e8a6f2ac7273dabf802d"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -957,9 +957,9 @@ dependencies = [
[[package]]
name = "aws-smithy-http"
version = "0.62.1"
version = "0.62.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99335bec6cdc50a346fda1437f9fefe33abf8c99060739a546a16457f2862ca9"
checksum = "43c82ba4cab184ea61f6edaafc1072aad3c2a17dcf4c0fce19ac5694b90d8b5f"
dependencies = [
"aws-smithy-runtime-api",
"aws-smithy-types",
@@ -1034,9 +1034,9 @@ dependencies = [
[[package]]
name = "aws-smithy-runtime"
version = "1.8.4"
version = "1.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3aaec682eb189e43c8a19c3dab2fe54590ad5f2cc2d26ab27608a20f2acf81c"
checksum = "660f70d9d8af6876b4c9aa8dcb0dbaf0f89b04ee9a4455bea1b4ba03b15f26f6"
dependencies = [
"aws-smithy-async",
"aws-smithy-http",
@@ -1058,9 +1058,9 @@ dependencies = [
[[package]]
name = "aws-smithy-runtime-api"
version = "1.8.3"
version = "1.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9852b9226cb60b78ce9369022c0df678af1cac231c882d5da97a0c4e03be6e67"
checksum = "937a49ecf061895fca4a6dd8e864208ed9be7546c0527d04bc07d502ec5fba1c"
dependencies = [
"aws-smithy-async",
"aws-smithy-types",
@@ -1120,9 +1120,9 @@ dependencies = [
[[package]]
name = "aws-types"
version = "1.3.7"
version = "1.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a322fec39e4df22777ed3ad8ea868ac2f94cd15e1a55f6ee8d8d6305057689a"
checksum = "b069d19bf01e46298eaedd7c6f283fe565a59263e53eebec945f3e6398f42390"
dependencies = [
"aws-credential-types",
"aws-smithy-async",
@@ -1689,9 +1689,9 @@ dependencies = [
[[package]]
name = "bytemuck_derive"
version = "1.9.3"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1"
checksum = "441473f2b4b0459a68628c744bc61d23e730fb00128b841d30fa4bb3972257e4"
dependencies = [
"proc-macro2",
"quote",
@@ -1858,9 +1858,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.2.29"
version = "1.2.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362"
checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7"
dependencies = [
"jobserver",
"libc",
@@ -2007,9 +2007,9 @@ checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
[[package]]
name = "clipboard-win"
version = "5.4.0"
version = "5.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892"
checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4"
dependencies = [
"error-code",
]
@@ -2411,15 +2411,15 @@ dependencies = [
[[package]]
name = "curve25519-dalek"
version = "4.2.0"
version = "4.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "373b7c5dbd637569a2cca66e8d66b8c446a1e7bf064ea321d265d7b3dfe7c97e"
checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
dependencies = [
"cfg-if",
"cpufeatures",
"curve25519-dalek-derive",
"digest 0.10.7",
"fiat-crypto 0.3.0",
"fiat-crypto 0.2.9",
"rustc_version 0.4.1",
"subtle",
"zeroize",
@@ -3737,7 +3737,7 @@ dependencies = [
"quinn",
"rustls-tokio-stream",
"serde",
"socket2",
"socket2 0.5.10",
"thiserror 2.0.12",
"tokio",
]
@@ -4674,7 +4674,7 @@ dependencies = [
"num-integer",
"rust_decimal",
"smallvec",
"strum 0.27.1",
"strum 0.27.2",
]
[[package]]
@@ -4685,9 +4685,9 @@ checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
[[package]]
name = "dyn-clone"
version = "1.0.19"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005"
checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
[[package]]
name = "dyn-iter"
@@ -5090,9 +5090,9 @@ checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77"
[[package]]
name = "fiat-crypto"
version = "0.3.0"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24"
checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
[[package]]
name = "filetime"
@@ -6377,7 +6377,7 @@ dependencies = [
"httpdate",
"itoa",
"pin-project-lite",
"socket2",
"socket2 0.5.10",
"tokio",
"tower-service",
"tracing",
@@ -6451,7 +6451,7 @@ dependencies = [
"tokio",
"tokio-rustls 0.26.2",
"tower-service",
"webpki-roots 1.0.1",
"webpki-roots 1.0.2",
]
[[package]]
@@ -6498,9 +6498,9 @@ dependencies = [
[[package]]
name = "hyper-util"
version = "0.1.15"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f66d5bd4c6f02bf0542fad85d626775bab9258cf795a4256dcaf3161114d1df"
checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e"
dependencies = [
"base64 0.22.1",
"bytes",
@@ -6514,7 +6514,7 @@ dependencies = [
"libc",
"percent-encoding",
"pin-project-lite",
"socket2",
"socket2 0.6.0",
"system-configuration 0.6.1",
"tokio",
"tower-service",
@@ -6820,9 +6820,9 @@ dependencies = [
[[package]]
name = "io-uring"
version = "0.7.8"
version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013"
checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4"
dependencies = [
"bitflags 2.9.1",
"cfg-if",
@@ -6835,7 +6835,7 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f"
dependencies = [
"socket2",
"socket2 0.5.10",
"widestring",
"windows-sys 0.48.0",
"winreg",
@@ -6969,9 +6969,9 @@ dependencies = [
[[package]]
name = "jsonc-parser"
version = "0.26.2"
version = "0.26.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b558af6b49fd918e970471374e7a798b2c9bbcda624a210ffa3901ee5614bc8e"
checksum = "1d6d80e6d70e7911a29f3cf3f44f452df85d06f73572b494ca99a2cad3fcf8f4"
dependencies = [
"serde_json",
]
@@ -7270,7 +7270,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
dependencies = [
"cfg-if",
"windows-targets 0.53.2",
"windows-targets 0.53.3",
]
[[package]]
@@ -7292,13 +7292,13 @@ dependencies = [
[[package]]
name = "libredox"
version = "0.1.4"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638"
checksum = "360e552c93fa0e8152ab463bc4c4837fce76a225df11dfaeea66c313de5e61f7"
dependencies = [
"bitflags 2.9.1",
"libc",
"redox_syscall 0.5.13",
"redox_syscall 0.5.17",
]
[[package]]
@@ -7380,9 +7380,9 @@ checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
[[package]]
name = "litrs"
version = "0.4.1"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5"
checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed"
[[package]]
name = "lock_api"
@@ -7960,7 +7960,7 @@ dependencies = [
"rand 0.9.0",
"serde",
"serde_json",
"socket2",
"socket2 0.5.10",
"thiserror 2.0.12",
"tokio",
"tokio-native-tls",
@@ -9056,7 +9056,7 @@ checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
dependencies = [
"cfg-if",
"libc",
"redox_syscall 0.5.13",
"redox_syscall 0.5.17",
"smallvec",
"windows-targets 0.52.6",
]
@@ -9507,9 +9507,9 @@ checksum = "c6fa0831dd7cc608c38a5e323422a0077678fa5744aa2be4ad91c4ece8eec8d5"
[[package]]
name = "prettyplease"
version = "0.2.35"
version = "0.2.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a"
checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2"
dependencies = [
"proc-macro2",
"syn 2.0.104",
@@ -9841,9 +9841,9 @@ dependencies = [
[[package]]
name = "quick_cache"
version = "0.6.14"
version = "0.6.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b450dad8382b1b95061d5ca1eb792081fb082adf48c678791fe917509596d5f"
checksum = "8565e62e02af316570d4b492f17af1481d6c07cea60f4e7edd71700da5052ba9"
dependencies = [
"ahash 0.8.12",
"equivalent",
@@ -9864,7 +9864,7 @@ dependencies = [
"quinn-udp",
"rustc-hash 2.1.1",
"rustls 0.23.29",
"socket2",
"socket2 0.5.10",
"thiserror 2.0.12",
"tokio",
"tracing",
@@ -9901,7 +9901,7 @@ dependencies = [
"cfg_aliases 0.2.1",
"libc",
"once_cell",
"socket2",
"socket2 0.5.10",
"tracing",
"windows-sys 0.59.0",
]
@@ -10156,9 +10156,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.5.13"
version = "0.5.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6"
checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77"
dependencies = [
"bitflags 2.9.1",
]
@@ -10358,7 +10358,7 @@ dependencies = [
"wasm-bindgen-futures",
"wasm-streams",
"web-sys",
"webpki-roots 1.0.1",
"webpki-roots 1.0.2",
]
[[package]]
@@ -10663,9 +10663,9 @@ dependencies = [
[[package]]
name = "rustc-demangle"
version = "0.1.25"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
[[package]]
name = "rustc-hash"
@@ -10847,7 +10847,7 @@ checksum = "22557157d7395bc30727745b365d923f1ecc230c4c80b176545f3f4f08c46e33"
dependencies = [
"futures",
"rustls 0.23.29",
"socket2",
"socket2 0.5.10",
"tokio",
]
@@ -11303,9 +11303,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.140"
version = "1.0.141"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3"
dependencies = [
"indexmap 2.10.0",
"itoa",
@@ -11696,6 +11696,16 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "socket2"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807"
dependencies = [
"libc",
"windows-sys 0.59.0",
]
[[package]]
name = "socks"
version = "0.3.4"
@@ -12129,11 +12139,11 @@ dependencies = [
[[package]]
name = "strum"
version = "0.27.1"
version = "0.27.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32"
checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
dependencies = [
"strum_macros 0.27.1",
"strum_macros 0.27.2",
]
[[package]]
@@ -12151,14 +12161,13 @@ dependencies = [
[[package]]
name = "strum_macros"
version = "0.27.1"
version = "0.27.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8"
checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"rustversion",
"syn 2.0.104",
]
@@ -12741,9 +12750,9 @@ checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417"
[[package]]
name = "tantivy"
version = "0.22.0"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8d0582f186c0a6d55655d24543f15e43607299425c5ad8352c242b914b31856"
checksum = "96599ea6fccd844fc833fed21d2eecac2e6a7c1afd9e044057391d78b1feb141"
dependencies = [
"aho-corasick",
"arc-swap",
@@ -13207,7 +13216,7 @@ dependencies = [
"pin-project-lite",
"signal-hook-registry",
"slab",
"socket2",
"socket2 0.5.10",
"tokio-macros",
"tracing",
"windows-sys 0.52.0",
@@ -13275,7 +13284,7 @@ dependencies = [
"postgres-protocol 0.6.7",
"postgres-types 0.2.7",
"rand 0.8.5",
"socket2",
"socket2 0.5.10",
"tokio",
"tokio-util",
"whoami",
@@ -13301,7 +13310,7 @@ dependencies = [
"postgres-protocol 0.6.8",
"postgres-types 0.2.9",
"rand 0.9.0",
"socket2",
"socket2 0.5.10",
"tokio",
"tokio-util",
"whoami",
@@ -13507,7 +13516,7 @@ dependencies = [
"prost",
"rustls-native-certs 0.8.1",
"rustls-pemfile 2.2.0",
"socket2",
"socket2 0.5.10",
"tokio",
"tokio-rustls 0.26.2",
"tokio-stream",
@@ -14489,14 +14498,14 @@ version = "0.26.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e"
dependencies = [
"webpki-root-certs 1.0.1",
"webpki-root-certs 1.0.2",
]
[[package]]
name = "webpki-root-certs"
version = "1.0.1"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86138b15b2b7d561bc4469e77027b8dd005a43dc502e9031d1f5afc8ce1f280e"
checksum = "4e4ffd8df1c57e87c325000a3d6ef93db75279dc3a231125aac571650f22b12a"
dependencies = [
"rustls-pki-types",
]
@@ -14507,14 +14516,14 @@ version = "0.26.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9"
dependencies = [
"webpki-roots 1.0.1",
"webpki-roots 1.0.2",
]
[[package]]
name = "webpki-roots"
version = "1.0.1"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8782dd5a41a24eed3a4f40b606249b3e236ca61adf1f25ea4d45c73de122b502"
checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2"
dependencies = [
"rustls-pki-types",
]
@@ -14632,7 +14641,7 @@ version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6994d13118ab492c3c80c1f81928718159254c53c472bf9ce36f8dae4add02a7"
dependencies = [
"redox_syscall 0.5.13",
"redox_syscall 0.5.17",
"wasite",
"web-sys",
]
@@ -14676,7 +14685,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windmill"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"anyhow",
"axum",
@@ -14705,7 +14714,7 @@ dependencies = [
"sha2 0.10.9",
"size",
"sqlx",
"strum 0.27.1",
"strum 0.27.2",
"systemstat",
"tikv-jemalloc-ctl",
"tikv-jemalloc-sys",
@@ -14728,7 +14737,7 @@ dependencies = [
[[package]]
name = "windmill-api"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"anyhow",
"argon2",
@@ -14739,8 +14748,11 @@ dependencies = [
"async_zip",
"aws-config",
"aws-sdk-sqs",
"aws-sdk-sso",
"aws-sdk-ssooidc",
"aws-sdk-sts",
"axum",
"backon",
"base32",
"base64 0.22.1",
"byteorder",
@@ -14794,6 +14806,7 @@ dependencies = [
"rumqttc",
"rust-embed",
"rust_decimal",
"rustls 0.23.29",
"samael",
"serde",
"serde_json",
@@ -14839,7 +14852,7 @@ dependencies = [
[[package]]
name = "windmill-api-client"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"base64 0.22.1",
"chrono",
@@ -14854,7 +14867,7 @@ dependencies = [
[[package]]
name = "windmill-audit"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"chrono",
"serde",
@@ -14867,7 +14880,7 @@ dependencies = [
[[package]]
name = "windmill-autoscaling"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"anyhow",
"serde",
@@ -14881,7 +14894,7 @@ dependencies = [
[[package]]
name = "windmill-common"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"anyhow",
"async-stream",
@@ -14932,8 +14945,9 @@ dependencies = [
"sha2 0.10.9",
"size",
"sqlx",
"strum 0.27.1",
"strum_macros 0.27.1",
"strum 0.27.2",
"strum_macros 0.27.2",
"sysinfo",
"systemstat",
"tar",
"tempfile",
@@ -14959,7 +14973,7 @@ dependencies = [
[[package]]
name = "windmill-git-sync"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"regex",
"serde",
@@ -14973,12 +14987,13 @@ dependencies = [
[[package]]
name = "windmill-indexer"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"anyhow",
"bytes",
"chrono",
"const_format",
"flume",
"futures",
"lazy_static",
"object_store",
@@ -14996,7 +15011,7 @@ dependencies = [
[[package]]
name = "windmill-macros"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"itertools 0.14.0",
"lazy_static",
@@ -15008,7 +15023,7 @@ dependencies = [
[[package]]
name = "windmill-parser"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"convert_case 0.6.0",
"serde",
@@ -15017,7 +15032,7 @@ dependencies = [
[[package]]
name = "windmill-parser-bash"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"anyhow",
"lazy_static",
@@ -15029,7 +15044,7 @@ dependencies = [
[[package]]
name = "windmill-parser-csharp"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"anyhow",
"serde_json",
@@ -15041,7 +15056,7 @@ dependencies = [
[[package]]
name = "windmill-parser-go"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"anyhow",
"gosyn",
@@ -15053,7 +15068,7 @@ dependencies = [
[[package]]
name = "windmill-parser-graphql"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"anyhow",
"lazy_static",
@@ -15065,7 +15080,7 @@ dependencies = [
[[package]]
name = "windmill-parser-java"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"anyhow",
"serde_json",
@@ -15077,7 +15092,7 @@ dependencies = [
[[package]]
name = "windmill-parser-nu"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"anyhow",
"nu-parser",
@@ -15088,7 +15103,7 @@ dependencies = [
[[package]]
name = "windmill-parser-php"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"anyhow",
"itertools 0.14.0",
@@ -15099,7 +15114,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"anyhow",
"itertools 0.14.0",
@@ -15111,7 +15126,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py-imports"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"anyhow",
"async-recursion",
@@ -15134,7 +15149,7 @@ dependencies = [
[[package]]
name = "windmill-parser-rust"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"anyhow",
"convert_case 0.6.0",
@@ -15151,7 +15166,7 @@ dependencies = [
[[package]]
name = "windmill-parser-sql"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"anyhow",
"lazy_static",
@@ -15165,7 +15180,7 @@ dependencies = [
[[package]]
name = "windmill-parser-ts"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"anyhow",
"lazy_static",
@@ -15183,7 +15198,7 @@ dependencies = [
[[package]]
name = "windmill-parser-wasm"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"anyhow",
"getrandom 0.2.16",
@@ -15207,7 +15222,7 @@ dependencies = [
[[package]]
name = "windmill-parser-yaml"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"anyhow",
"serde_json",
@@ -15217,7 +15232,7 @@ dependencies = [
[[package]]
name = "windmill-queue"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"anyhow",
"async-recursion",
@@ -15250,7 +15265,7 @@ dependencies = [
[[package]]
name = "windmill-sql-datatype-parser-wasm"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"wasm-bindgen",
"wasm-bindgen-test",
@@ -15260,7 +15275,7 @@ dependencies = [
[[package]]
name = "windmill-worker"
version = "1.507.1"
version = "1.515.1"
dependencies = [
"anyhow",
"async-recursion",
@@ -15596,7 +15611,7 @@ version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets 0.53.2",
"windows-targets 0.53.3",
]
[[package]]
@@ -15632,10 +15647,11 @@ dependencies = [
[[package]]
name = "windows-targets"
version = "0.53.2"
version = "0.53.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef"
checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
dependencies = [
"windows-link",
"windows_aarch64_gnullvm 0.53.0",
"windows_aarch64_msvc 0.53.0",
"windows_i686_gnu 0.53.0",

View File

@@ -1,6 +1,6 @@
[package]
name = "windmill"
version = "1.507.1"
version = "1.515.1"
authors.workspace = true
edition.workspace = true
@@ -28,11 +28,11 @@ members = [
"./parsers/windmill-parser-py",
"./parsers/windmill-parser-py-imports",
"./parsers/windmill-sql-datatype-parser-wasm",
"./parsers/windmill-parser-yaml", "windmill-macros", "parsers/windmill-parser-nu",
"./parsers/windmill-parser-yaml", "windmill-macros", "parsers/windmill-parser-nu"
]
[workspace.package]
version = "1.507.1"
version = "1.515.1"
authors = ["Ruben Fiszel <ruben@windmill.dev>"]
edition = "2021"
@@ -190,12 +190,11 @@ 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"] }
headers = "^0"
hyper = { version = "^1", features = ["full"] }
tokio = { version = "^1.42.0", features = ["full", "tracing", "time"] }
tokio = { version = "=1.46.1", features = ["full", "tracing", "time"] }
tokio-stream = { version = "0.1.17" }
tower = "^0"
tower-http = { version = "^0.6", features = ["trace", "cors"] }
@@ -267,6 +266,7 @@ 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"] }
sysinfo = { version = "0.32.1" }
swc_common = "=0.37.5"
swc_ecma_parser = "=0.149.1"
@@ -353,8 +353,14 @@ datafusion = "47.0.0"
object_store = { git = "https://github.com/apache/arrow-rs-object-store", rev = "36752c975d4f29e20b57c91f81a10872dcd48ae7", features = ["aws", "azure", "gcp"] }
openidconnect = { version = "4.0.0-rc.1" }
aws-config = "^1"
aws-sdk-sqs = "1.57.0"
aws-sdk-sts = "^1"
aws-sdk-sqs = "=1.77.0"
aws-sdk-sts = "=1.79.0"
aws-sdk-sso = "=1.77.0"
aws-sdk-ssooidc = "=1.78.0"
rustls = "=0.23.29"
aws-smithy-types-convert = { version = "^0", features = ["convert-chrono"] }
crc = "^3"
tar = "^0"

View File

@@ -1 +1 @@
3cccbe81494f7edd113dce2812278b00c91160c0
cef7486dfa765f1cdfaddba59564c4bb92fe864e

View File

@@ -0,0 +1,7 @@
-- Add 'variable' kind back
ALTER TABLE asset ALTER column kind TYPE VARCHAR;
DROP TYPE asset_kind;
CREATE TYPE ASSET_KIND AS ENUM ('s3object', 'resource', 'variable');
ALTER TABLE asset ALTER column kind TYPE ASSET_KIND using kind::ASSET_KIND;
ALTER TABLE script DROP COLUMN assets;

View File

@@ -0,0 +1,8 @@
ALTER TABLE script ADD COLUMN assets jsonb;
-- Remove 'variable' kind
DELETE FROM asset WHERE kind = 'variable';
ALTER TABLE asset ALTER column kind TYPE VARCHAR;
DROP TYPE asset_kind;
CREATE TYPE ASSET_KIND AS ENUM ('s3object', 'resource');
ALTER TABLE asset ALTER column kind TYPE ASSET_KIND using kind::ASSET_KIND;

View File

@@ -0,0 +1,2 @@
-- Rollback cc_token_url column addition
ALTER TABLE account DROP COLUMN IF EXISTS cc_token_url;

View File

@@ -0,0 +1,3 @@
-- Add cc_token_url column for resource-level token URL override in OAuth client credentials flow
-- This allows resources to override the token URL from instance settings when using client credentials
ALTER TABLE account ADD COLUMN cc_token_url VARCHAR(500);

View File

@@ -0,0 +1 @@
-- Add down migration script here

View File

@@ -0,0 +1,2 @@
-- Add up migration script here
ALTER TYPE ASSET_KIND ADD VALUE 'variable';

View File

@@ -0,0 +1 @@
-- Add down migration script here

View File

@@ -0,0 +1,2 @@
-- Add up migration script here
ALTER TABLE resource ALTER COLUMN created_by TYPE VARCHAR(500);

View File

@@ -0,0 +1 @@
-- Add down migration script here

View File

@@ -0,0 +1,2 @@
ALTER TABLE audit ALTER COLUMN id TYPE bigint;
ALTER SEQUENCE audit_id_seq AS bigint;

View File

@@ -7,7 +7,7 @@ use anyhow::anyhow;
use tree_sitter::Node;
use windmill_parser::Arg;
use windmill_parser::MainArgSignature;
use windmill_parser::Typ;
use windmill_parser::{ObjectType, Typ};
#[derive(Debug)]
pub struct CsharpMainSigMeta {
@@ -112,7 +112,7 @@ fn find_typ<'a>(typ_node: Node<'a>, code: &str) -> anyhow::Result<Typ> {
Ok("double") | Ok("System.Double") => Ok(Typ::Float),
Ok("bool") | Ok("System.Boolean") => Ok(Typ::Bool),
Ok("decimal") | Ok("System.Decimal") => Ok(Typ::Float),
Ok("object") => Ok(Typ::Object(vec![])), // TODO: Complete the object type
Ok("object") => Ok(Typ::Object(ObjectType::new(None, Some(vec![])))), // TODO: Complete the object type
Ok(s) => Err(anyhow!("Unknown type `{s}`")),
Err(e) => Err(anyhow!("Error getting type name: {}", e)),
}

View File

@@ -7,7 +7,7 @@ use gosyn::{
use itertools::Itertools;
use regex::Regex;
use windmill_parser::{Arg, MainArgSignature, ObjectProperty, Typ};
use windmill_parser::{Arg, MainArgSignature, ObjectProperty, ObjectType, Typ};
lazy_static::lazy_static! {
pub static ref REQUIRE_PARSE: Regex = Regex::new(r"//require (.*)\n").unwrap();
@@ -142,13 +142,13 @@ fn parse_go_typ(typ: &Expression) -> (Option<String>, Typ) {
"struct {{ {} }}",
otyps.iter().join("; ").to_string()
)),
Typ::Object(typs),
Typ::Object(ObjectType::new(None, Some(typs))),
)
}
Expression::TypeInterface(_) => (Some("interface{}".to_string()), Typ::Object(vec![])),
Expression::TypeInterface(_) => (Some("interface{}".to_string()), Typ::Object(ObjectType::new(None, Some(vec![])))),
Expression::TypeMap(_) => (
Some("map[string]interface{}".to_string()),
Typ::Object(vec![]),
Typ::Object(ObjectType::new(None, Some(vec![]))),
),
_ => (None, Typ::Unknown),
}
@@ -218,10 +218,10 @@ func main(x int, y string, z bool, l []string, o struct { Name string `json:"nam
Arg {
otyp: Some("struct { Name string `json:\"name\"` }".to_string()),
name: "o".to_string(),
typ: Typ::Object(vec![ObjectProperty {
typ: Typ::Object(ObjectType::new(None, Some(vec![ObjectProperty {
key: "name".to_string(),
typ: Box::new(Typ::Str(None))
},]),
},]))),
default: None,
has_default: false,
oidx: None
@@ -229,7 +229,7 @@ func main(x int, y string, z bool, l []string, o struct { Name string `json:"nam
Arg {
otyp: Some("interface{}".to_string()),
name: "n".to_string(),
typ: Typ::Object(vec![]),
typ: Typ::Object(ObjectType::new(None, Some(vec![]))),
default: None,
has_default: false,
oidx: None
@@ -237,7 +237,7 @@ func main(x int, y string, z bool, l []string, o struct { Name string `json:"nam
Arg {
otyp: Some("map[string]interface{}".to_string()),
name: "m".to_string(),
typ: Typ::Object(vec![]),
typ: Typ::Object(ObjectType::new(None, Some(vec![]))),
default: None,
has_default: false,
oidx: None

View File

@@ -9,7 +9,7 @@ use regex_lite::Regex;
use serde_json::json;
use windmill_parser::{Arg, MainArgSignature, Typ};
use windmill_parser::{Arg, MainArgSignature, ObjectType, Typ};
pub fn parse_graphql_sig(code: &str) -> anyhow::Result<MainArgSignature> {
let parsed = parse_graphql_file(&code)?;
@@ -75,7 +75,7 @@ pub fn parse_graphql_typ(typ: &str) -> Typ {
"Int" => Typ::Int,
"Boolean" => Typ::Bool,
"Float" => Typ::Float,
_ => Typ::Object(vec![]),
_ => Typ::Object(ObjectType::new(None, Some(vec![]))),
}
}

View File

@@ -9,7 +9,7 @@ use serde_json::Value;
use tree_sitter::Node;
use windmill_parser::Arg;
use windmill_parser::MainArgSignature;
use windmill_parser::Typ;
use windmill_parser::{ObjectType, Typ};
#[derive(Debug)]
pub struct JavaMainSigMeta {
@@ -101,7 +101,7 @@ fn find_typ<'a>(typ_node: Node<'a>, code: &str) -> anyhow::Result<(Typ, Option<V
Ok("Double") => (Typ::Float, null),
Ok("Boolean") => (Typ::Bool, null),
Ok("Character") => (Typ::Str(None), null),
Ok("Object") => (Typ::Object(vec![]),null), // TODO: Complete the object type
Ok("Object") => (Typ::Object(ObjectType::new(None, Some(vec![]))),null), // TODO: Complete the object type
Ok(s) => bail!("Unknown type `{s}`"),
Err(e) => bail!("Error getting type name: {}", e),
}
@@ -394,7 +394,7 @@ class Main {
Arg {
name: "i".into(),
otyp: Some("Object".into()),
typ: Typ::Object(vec![]),
typ: Typ::Object(ObjectType::new(None, Some(vec![]))),
default: Some(json!(null)),
has_default: true,
oidx: None
@@ -427,7 +427,7 @@ class Main {
Arg {
name: "b".into(),
otyp: Some("Object[]".into()),
typ: Typ::List(Box::new(Typ::Object(vec![]))),
typ: Typ::List(Box::new(Typ::Object(ObjectType::new(None, Some(vec![]))))),
default: Some(json!(null)),
has_default: true,
oidx: None

View File

@@ -4,7 +4,7 @@ use anyhow::{anyhow, bail};
use nu_parser::lex;
use serde_json::{json, Value};
use windmill_parser::{Arg, MainArgSignature, Typ};
use windmill_parser::{Arg, MainArgSignature, ObjectType, Typ};
pub fn parse_nu_signature(code: &str) -> anyhow::Result<MainArgSignature> {
let (tokens, ..) = lex(code.as_bytes(), 0, &[], &[], true);
@@ -162,8 +162,8 @@ pub fn parse_nu_signature(code: &str) -> anyhow::Result<MainArgSignature> {
"int" => Typ::Int,
"float" => Typ::Float,
"number" => Typ::Float,
"record" => Typ::Object(vec![]),
"table" => Typ::List(Box::new(Typ::Object(vec![]))),
"record" => Typ::Object(ObjectType::new(None, Some(vec![]))),
"table" => Typ::List(Box::new(Typ::Object(ObjectType::new(None, Some(vec![]))))),
"nothing" => Typ::Unknown,
// TODO: needs additional work on literal parsing
// "binary" => Typ::Bytes,

View File

@@ -1,7 +1,7 @@
#[cfg(test)]
mod test {
use serde_json::json;
use windmill_parser::{Arg, MainArgSignature, Typ};
use windmill_parser::{Arg, MainArgSignature, ObjectType, Typ};
use windmill_parser_nu::parse_nu_signature;
#[test]
@@ -200,7 +200,7 @@ mod test {
Arg {
name: "a7".into(),
otyp: None,
typ: Typ::Object(vec![]),
typ: Typ::Object(ObjectType::new(None, Some(vec![]))),
default: None,
has_default: false,
oidx: None
@@ -216,7 +216,7 @@ mod test {
Arg {
name: "a9".into(),
otyp: None,
typ: Typ::List(Box::new(Typ::Object(vec![]))),
typ: Typ::List(Box::new(Typ::Object(ObjectType::new(None, Some(vec![]))))),
default: None,
has_default: false,
oidx: None

View File

@@ -1,5 +1,5 @@
use serde_json::Value;
use windmill_parser::{to_snake_case, Arg, MainArgSignature, Typ};
use windmill_parser::{to_snake_case, Arg, MainArgSignature, ObjectType, Typ};
use php_parser_rs::parser::{
self,
@@ -18,7 +18,7 @@ fn parse_php_type(e: Type) -> Typ {
Type::Integer(_) => Typ::Int,
Type::String(_) => Typ::Str(None),
Type::Array(_) => Typ::List(Box::new(Typ::Str(None))),
Type::Object(_) => Typ::Object(vec![]),
Type::Object(_) => Typ::Object(ObjectType::new(None, Some(vec![]))),
Type::Named(_, name) => Typ::Resource(to_snake_case(name.to_string().as_ref())),
_ => Typ::Unknown,
}

View File

@@ -57,27 +57,27 @@ impl AssetsFinder {
})
.ok_or(())?;
use AssetKind::*;
let (kind, access_type, arg) = match ident.as_str() {
"load_s3_file" => (AssetKind::S3Object, Some(R), Arg::Pos(0)),
"load_s3_file_reader" => (AssetKind::S3Object, Some(R), Arg::Pos(0)),
"write_s3_file" => (AssetKind::S3Object, Some(W), Arg::Pos(0)),
"get_resource" => (AssetKind::Resource, None, Arg::Pos(0)),
"set_resource" => (AssetKind::Resource, Some(W), Arg::Named("path")),
"get_boto3_connection_settings" => (AssetKind::Resource, None, Arg::Pos(0)),
"get_polars_connection_settings" => (AssetKind::Resource, None, Arg::Pos(0)),
"get_duckdb_connection_settings" => (AssetKind::Resource, None, Arg::Pos(0)),
"get_variable" => (AssetKind::Variable, Some(R), Arg::Pos(0)),
"set_variable" => (AssetKind::Variable, Some(W), Arg::Pos(0)),
"load_s3_file" => (S3Object, Some(R), Arg::Pos(0, "s3object")),
"load_s3_file_reader" => (S3Object, Some(R), Arg::Pos(0, "s3object")),
"write_s3_file" => (S3Object, Some(W), Arg::Pos(0, "s3object")),
"get_resource" => (Resource, None, Arg::Pos(0, "path")),
"set_resource" => (Resource, Some(W), Arg::Pos(0, "path")),
"get_boto3_connection_settings" => (Resource, None, Arg::Pos(0, "s3_resource_path")),
"get_polars_connection_settings" => (Resource, None, Arg::Pos(0, "s3_resource_path")),
"get_duckdb_connection_settings" => (Resource, None, Arg::Pos(0, "s3_resource_path")),
_ => return Err(()),
};
let arg_val = match arg {
Arg::Pos(i) => node.args.get(i),
Arg::Named(name) => node
.keywords
.iter()
.find(|kw| kw.arg.as_deref() == Some(name))
.map(|kw| &kw.value),
Arg::Pos(i, name) => node.args.get(i).or_else(|| {
// Get arg by name
node.keywords
.iter()
.find(|kw| kw.arg.as_deref() == Some(name))
.map(|kw| &kw.value)
}),
};
match arg_val {
@@ -93,6 +93,6 @@ impl AssetsFinder {
}
enum Arg {
Pos(usize),
Named(&'static str),
// Positional arguments in python can also be used by their name
Pos(usize, &'static str),
}

View File

@@ -11,7 +11,7 @@ use std::collections::HashMap;
use itertools::Itertools;
use serde_json::json;
use windmill_parser::{json_to_typ, Arg, MainArgSignature, Typ};
use windmill_parser::{json_to_typ, Arg, MainArgSignature, ObjectType, Typ};
use rustpython_parser::{
ast::{
@@ -226,7 +226,7 @@ fn parse_typ(id: &str) -> Typ {
"float" => Typ::Float,
"int" => Typ::Int,
"bool" => Typ::Bool,
"dict" => Typ::Object(vec![]),
"dict" => Typ::Object(ObjectType::new(None, Some(vec![]))),
"list" => Typ::List(Box::new(Typ::Unknown)),
"bytes" => Typ::Bytes,
"datetime" => Typ::Datetime,

View File

@@ -14,7 +14,7 @@ use std::{
iter::Peekable,
str::CharIndices,
};
pub use windmill_parser::{Arg, MainArgSignature, Typ};
pub use windmill_parser::{Arg, MainArgSignature, ObjectType, Typ};
pub const SANITIZED_ENUM_STR: &str = "__sanitized_enum__";
pub const SANITIZED_RAW_STRING_STR: &str = "__sanitized_raw_string__";
@@ -231,7 +231,7 @@ lazy_static::lazy_static! {
static ref RE_ARG_BIGQUERY: Regex = Regex::new(r#"(?m)^-- @(\w+) \((\w+(?:\[\])?)\)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap();
// -- $name (type) = default
static ref RE_ARG_DUCKDB: Regex = Regex::new(r#"(?m)^-- \$(\w+) \((\w+)\)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap();
static ref RE_ARG_DUCKDB: Regex = Regex::new(r#"(?m)^-- \$(\w+) \(([A-Za-z0-9_\[\]]+)\)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap();
static ref RE_ARG_SNOWFLAKE: Regex = Regex::new(r#"(?m)^-- \? (\w+) \((\w+)\)(?: ?\= ?(.+))? *(?:\r|\n|$)"#).unwrap();
@@ -737,7 +737,7 @@ pub fn parse_pg_typ(typ: &str) -> Typ {
"bigint" => Typ::Int,
"bool" | "boolean" => Typ::Bool,
"char" | "character" => Typ::Str(None),
"json" | "jsonb" => Typ::Object(vec![]),
"json" | "jsonb" => Typ::Object(ObjectType::new(None, Some(vec![]))),
"smallint" | "int2" => Typ::Int,
"smallserial" | "serial2" => Typ::Int,
"serial" | "serial4" => Typ::Int,
@@ -769,7 +769,7 @@ pub fn parse_bigquery_typ(typ: &str) -> Typ {
match typ {
"string" => Typ::Str(None),
"bytes" => Typ::Bytes,
"json" => Typ::Object(vec![]),
"json" => Typ::Object(ObjectType::new(None, Some(vec![]))),
"timestamp" | "date" | "time" | "datetime" => Typ::Datetime,
"integer" | "int64" => Typ::Int,
"float" | "float64" | "numeric" | "bignumeric" => Typ::Float,

View File

@@ -84,8 +84,6 @@ impl AssetsFinder {
"denoS3LightClientSettings" => (AssetKind::Resource, None, 0),
"duckdbConnectionSettings" => (AssetKind::Resource, None, 0),
"polarsConnectionSettings" => (AssetKind::Resource, None, 0),
"getVariable" => (AssetKind::Variable, Some(R), 0),
"setVariable" => (AssetKind::Variable, Some(W), 0),
_ => return Err(()),
};

View File

@@ -7,19 +7,20 @@
*/
// use deno_core::{serde_v8, v8, JsRuntime, RuntimeOptions};
use serde_json::Value;
use std::collections::HashSet;
use std::collections::{HashMap, HashSet};
use swc_ecma_visit::{noop_visit_type, Visit, VisitWith};
use windmill_parser::{
json_to_typ, to_snake_case, Arg, MainArgSignature, ObjectProperty, OneOfVariant, Typ,
json_to_typ, to_snake_case, Arg, MainArgSignature, ObjectProperty, ObjectType, OneOfVariant,
Typ,
};
use swc_common::{sync::Lrc, FileName, SourceMap, SourceMapper, Span, Spanned};
use swc_ecma_ast::{
ArrayLit, AssignPat, BigInt, BindingIdent, Bool, Decl, ExportDecl, Expr, FnDecl, Ident,
IdentName, Lit, MemberExpr, MemberProp, ModuleDecl, ModuleItem, Number, ObjectLit, ObjectPat,
Param, Pat, Str, TsArrayType, TsEntityName, TsKeywordType, TsKeywordTypeKind, TsLit, TsLitType,
TsOptionalType, TsParenthesizedType, TsPropertySignature, TsType, TsTypeAnn, TsTypeElement,
TsTypeLit, TsTypeRef, TsUnionOrIntersectionType, TsUnionType,
ArrayLit, AssignPat, BigInt, BindingIdent, Bool, Decl, ExportDecl, Expr, Ident, IdentName, Lit,
MemberExpr, MemberProp, ModuleDecl, ModuleItem, Number, ObjectLit, ObjectPat, Param, Pat, Stmt,
Str, TsArrayType, TsEntityName, TsInterfaceDecl, TsKeywordType, TsKeywordTypeKind, TsLit,
TsLitType, TsOptionalType, TsParenthesizedType, TsPropertySignature, TsType, TsTypeAliasDecl,
TsTypeAnn, TsTypeElement, TsTypeLit, TsTypeRef, TsUnionOrIntersectionType, TsUnionType,
};
use swc_ecma_parser::{lexer::Lexer, EsSyntax, Parser, StringInput, Syntax, TsSyntax};
@@ -32,6 +33,19 @@ struct ImportsFinder {
skip_type_only: bool,
}
impl ImportsFinder {
fn process_raw(&mut self, raw: Option<String>) {
if let Some(ref s) = raw {
let s = s.to_string();
if s.starts_with("'") && s.ends_with("'") {
self.imports.insert(s[1..s.len() - 1].to_string());
} else if s.starts_with("\"") && s.ends_with("\"") {
self.imports.insert(s[1..s.len() - 1].to_string());
}
}
}
}
impl Visit for ImportsFinder {
noop_visit_type!();
@@ -59,14 +73,47 @@ impl Visit for ImportsFinder {
}
}
}
if let Some(ref s) = n.src.raw {
let s = s.to_string();
if s.starts_with("'") && s.ends_with("'") {
self.imports.insert(s[1..s.len() - 1].to_string());
} else if s.starts_with("\"") && s.ends_with("\"") {
self.imports.insert(s[1..s.len() - 1].to_string());
self.process_raw(n.src.raw.as_ref().map(|x| x.to_string()));
}
fn visit_export_all(&mut self, node: &swc_ecma_ast::ExportAll) {
if !self.skip_type_only || node.type_only {
return;
}
self.process_raw(node.src.raw.as_ref().map(|x| x.to_string()));
}
fn visit_named_export(&mut self, node: &swc_ecma_ast::NamedExport) {
if node.src.is_none() || !self.skip_type_only || node.type_only {
return;
}
if node.specifiers.len() > 0 {
let mut is_type_only = true;
for specifier in node.specifiers.iter() {
match specifier {
swc_ecma_ast::ExportSpecifier::Named(swc_ecma_ast::ExportNamedSpecifier {
is_type_only,
..
}) if *is_type_only => (),
_ => {
is_type_only = false;
break;
}
}
}
if is_type_only {
return;
}
}
self.process_raw(
node.src
.as_ref()
.unwrap()
.raw
.as_ref()
.map(|x| x.to_string()),
);
}
}
@@ -159,6 +206,11 @@ pub fn parse_expr_for_ids(code: &str) -> anyhow::Result<Vec<(String, String)>> {
Ok(visitor.idents.into_iter().collect())
}
#[derive(Debug)]
pub enum TypeDecl {
Interface(TsInterfaceDecl),
Alias(TsTypeAliasDecl),
}
pub mod asset_parser;
pub use asset_parser::parse_assets;
@@ -168,7 +220,7 @@ pub fn parse_deno_signature(
code: &str,
skip_dflt: bool,
skip_params: bool,
main_override: Option<String>,
entrypoint_override: Option<String>,
) -> anyhow::Result<MainArgSignature> {
let cm: Lrc<SourceMap> = Default::default();
let fm = cm.new_source_file(FileName::Custom("main.ts".into()).into(), code.into());
@@ -188,6 +240,9 @@ pub fn parse_deno_signature(
err_s += &e.into_kind().msg().to_string();
}
let mut has_preprocessor = false;
let mut entrypoint_params = None;
let ast = parser
.parse_module()
.map_err(|e| {
@@ -195,35 +250,71 @@ pub fn parse_deno_signature(
})?
.body;
let has_preprocessor = ast.iter().any(|x| match x {
ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
decl: Decl::Fn(FnDecl { ident: Ident { sym, .. }, .. }),
..
})) => &sym.to_string() == "preprocessor",
_ => false,
});
let entrypoint_function = entrypoint_override.as_deref().unwrap_or("main");
let main_name = main_override.unwrap_or("main".to_string());
let params = ast.into_iter().find_map(|x| match x {
ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
decl: Decl::Fn(FnDecl { ident: Ident { sym, .. }, function, .. }),
..
})) if &sym.to_string() == &main_name => Some(function.params),
_ => None,
});
let mut symbol_table: HashMap<String, TypeDecl> = HashMap::new();
for item in ast {
if let ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl { decl, .. }))
| ModuleItem::Stmt(Stmt::Decl(decl)) = item
{
match decl {
Decl::TsInterface(mut iface) => match symbol_table.get_mut(iface.id.sym.as_str()) {
Some(TypeDecl::Interface(interface)) => {
interface.body.body.append(&mut iface.body.body);
}
None => {
symbol_table.insert(
to_snake_case(iface.id.sym.as_str()),
TypeDecl::Interface(*iface),
);
}
_ => {}
},
Decl::TsTypeAlias(alias) => {
symbol_table.insert(
to_snake_case(alias.id.sym.as_str()),
TypeDecl::Alias(*alias),
);
}
Decl::Fn(fn_decl) => {
let name = fn_decl.ident.sym.to_string();
if name == "preprocessor" {
has_preprocessor = true;
}
if name == entrypoint_function {
entrypoint_params = Some(fn_decl.function.params.clone());
}
}
_ => {}
}
}
}
let mut c: u16 = 0;
let no_main_func = params.is_none();
let no_main_func = entrypoint_params.is_none();
let mut type_resolver = HashMap::new();
let r = MainArgSignature {
star_args: false,
star_kwargs: false,
args: if skip_params {
vec![]
} else {
params
.map(|x| {
x.into_iter()
.map(|x| parse_param(x, &cm, skip_dflt, &mut c))
entrypoint_params
.map(|param| {
param
.into_iter()
.map(|param| {
parse_param(
&symbol_table,
&mut type_resolver,
param,
&cm,
skip_dflt,
&mut c,
)
})
.collect::<anyhow::Result<Vec<Arg>>>()
})
.transpose()?
@@ -236,14 +327,16 @@ pub fn parse_deno_signature(
}
fn parse_param(
x: Param,
symbol_table: &HashMap<String, TypeDecl>,
type_resolver: &mut HashMap<String, (Typ, bool)>,
param: Param,
cm: &Lrc<SourceMap>,
skip_dflt: bool,
counter: &mut u16,
) -> anyhow::Result<Arg> {
let r = match x.pat {
let r = match param.pat {
Pat::Ident(ident) => {
let (name, typ, nullable) = binding_ident_to_arg(&ident);
let (name, typ, nullable) = binding_ident_to_arg(symbol_table, type_resolver, &ident);
Ok(Arg {
otyp: None,
name,
@@ -256,9 +349,9 @@ fn parse_param(
// Pat::Object(ObjectPat { ... }) = todo!()
Pat::Assign(AssignPat { left, right, .. }) => {
let (name, mut typ, _nullable) = match *left {
Pat::Ident(ident) => binding_ident_to_arg(&ident),
Pat::Ident(ident) => binding_ident_to_arg(symbol_table, type_resolver, &ident),
Pat::Object(ObjectPat { type_ann, .. }) => {
let (typ, nullable) = eval_type_ann(&type_ann);
let (typ, nullable) = eval_type_ann(symbol_table, type_resolver, &type_ann);
*counter += 1;
let name = format!("anon{}", counter);
(name, typ, nullable)
@@ -300,16 +393,16 @@ fn parse_param(
Ok(Arg { otyp: None, name, typ, default: dflt, has_default: true, oidx: None })
}
Pat::Object(ObjectPat { type_ann, .. }) => {
let (typ, nullable) = eval_type_ann(&type_ann);
let (typ, nullable) = eval_type_ann(symbol_table, type_resolver, &type_ann);
*counter += 1;
let name = format!("anon{}", counter);
Ok(Arg { otyp: None, name, typ, default: None, has_default: nullable, oidx: None })
}
_ => Err(anyhow::anyhow!(
"parameter syntax unsupported: `{}`: {:#?}",
cm.span_to_snippet(x.span())
.unwrap_or_else(|_| cm.span_to_string(x.span())),
x.pat
cm.span_to_snippet(param.span())
.unwrap_or_else(|_| cm.span_to_string(param.span())),
param.pat
)),
};
r
@@ -328,14 +421,22 @@ fn eval_span(span: Span, cm: &Lrc<SourceMap>) -> Option<Value> {
}
}
fn eval_type_ann(type_ann: &Option<Box<TsTypeAnn>>) -> (Typ, bool) {
fn eval_type_ann(
symbol_table: &HashMap<String, TypeDecl>,
type_resolver: &mut HashMap<String, (Typ, bool)>,
type_ann: &Option<Box<TsTypeAnn>>,
) -> (Typ, bool) {
return type_ann
.as_ref()
.map(|x| tstype_to_typ(&*x.type_ann))
.map(|x| tstype_to_typ(symbol_table, type_resolver, &*x.type_ann, true))
.unwrap_or((Typ::Unknown, false));
}
fn binding_ident_to_arg(BindingIdent { id, type_ann }: &BindingIdent) -> (String, Typ, bool) {
let (typ, nullable) = eval_type_ann(type_ann);
fn binding_ident_to_arg(
symbol_table: &HashMap<String, TypeDecl>,
type_resolver: &mut HashMap<String, (Typ, bool)>,
BindingIdent { id, type_ann }: &BindingIdent,
) -> (String, Typ, bool) {
let (typ, nullable) = eval_type_ann(symbol_table, type_resolver, type_ann);
(id.sym.to_string(), typ, nullable)
}
@@ -365,11 +466,193 @@ pub fn remove_pinned_imports(code: &str) -> anyhow::Result<String> {
Ok(content)
}
fn tstype_to_typ(ts_type: &TsType) -> (Typ, bool) {
fn resolve_type_ref(type_resolver: &HashMap<String, (Typ, bool)>, typ: &mut Typ) {
let mut visited = std::collections::HashSet::new();
resolve_type_ref_with_visited(type_resolver, typ, &mut visited);
}
fn resolve_type_ref_with_visited(
type_resolver: &HashMap<String, (Typ, bool)>,
typ: &mut Typ,
visited: &mut std::collections::HashSet<String>,
) {
match typ {
Typ::Object(ObjectType { props: Some(obj), .. }) => {
for property in obj.iter_mut() {
resolve_type_ref_with_visited(type_resolver, &mut property.typ, visited);
}
}
Typ::List(list) => resolve_type_ref_with_visited(type_resolver, list, visited),
Typ::Object(ObjectType { name: Some(name), props: None }) => {
if visited.contains(name) {
return;
}
let maybe_resolved_type = type_resolver
.get(name)
.map(|rs_typ| {
let mut typ = rs_typ.0.clone();
visited.insert(name.clone());
resolve_type_ref_with_visited(type_resolver, &mut typ, visited);
visited.remove(name);
typ
})
.unwrap_or(Typ::Object(ObjectType::new(Some(name.to_owned()), None)));
*typ = maybe_resolved_type;
}
_ => {}
}
}
fn resolve_interface(
iface: &TsInterfaceDecl,
symbol_table: &HashMap<String, TypeDecl>,
type_resolver: &mut HashMap<String, (Typ, bool)>,
) -> Vec<ObjectProperty> {
let mut properties = vec![];
for ext in &iface.extends {
// If the current interface extends other interfaces,
// retrieve their properties first and add them to the current interface's object definition.
if let Expr::Ident(Ident { sym, .. }) = &*ext.expr {
if let Some(TypeDecl::Interface(parent_iface)) =
symbol_table.get(&to_snake_case(sym.as_str()))
{
properties.extend(resolve_interface(parent_iface, symbol_table, type_resolver));
}
}
}
for member in &iface.body.body {
if let TsTypeElement::TsPropertySignature(sig) = member {
if let Expr::Ident(Ident { sym, .. }) = &*sig.key {
let typ = sig
.type_ann
.as_ref()
.map(|ta| {
Box::new(tstype_to_typ(symbol_table, type_resolver, &ta.type_ann, false).0)
})
.unwrap_or(Box::new(Typ::Unknown));
properties.push(ObjectProperty { key: sym.to_string(), typ });
}
}
}
properties
}
fn resolve_type_alias(
alias: &TsTypeAliasDecl,
symbol_table: &HashMap<String, TypeDecl>,
type_resolver: &mut HashMap<String, (Typ, bool)>,
top_level_call: bool,
) -> (Typ, bool) {
tstype_to_typ(symbol_table, type_resolver, &alias.type_ann, top_level_call)
}
fn resolve_ts_interface_and_type_alias(
type_name: &str,
symbol_table: &HashMap<String, TypeDecl>,
type_resolver: &mut HashMap<String, (Typ, bool)>,
top_level_call: bool,
) -> Option<(Typ, bool)> {
let Some(type_declaration) = symbol_table.get(type_name) else {
return None;
};
if let Some(resolved_type) = type_resolver.get_mut(type_name) {
return Some(resolved_type.to_owned());
}
type_resolver.insert(
type_name.to_owned(),
(
Typ::Object(ObjectType::new(Some(type_name.to_owned()), None)),
false,
),
);
let mut resolved_type = match type_declaration {
TypeDecl::Alias(alias) => {
resolve_type_alias(alias, symbol_table, type_resolver, top_level_call)
}
TypeDecl::Interface(iface) => (
Typ::Object(ObjectType::new(
Some(to_snake_case(&type_name)),
Some(resolve_interface(iface, symbol_table, type_resolver)),
)),
false,
),
};
fn update_name(typ: &mut Typ, type_name: &str) {
match typ {
// OBJECT TYPES:
// Normally, when you declare something like:
// type Postgresql = object
// it will initially resolve to:
// Typ::Object(ObjectType { name: None, .. })
//
// If the object has no name (name == None), we assign `type_name`
// so it becomes:
// Typ::Object(ObjectType { name: Some("postgresql"), .. })
Typ::Object(ObjectType { name, .. }) if name.is_none() => {
*name = Some(type_name.to_owned());
}
// RESOURCE TYPES:
// In some cases, when a type alias points to something unresolved:
// type Postgresql = Foo
// might initially resolve to:
// Typ::Resource("Foo")
//
// This ensures backwards compatibility by updating that resource
// name to the alias name, so it becomes:
// Typ::Resource("postgresql")
Typ::Resource(name) if name != type_name => {
*name = type_name.to_owned();
}
// LIST TYPES:
// For lists, e.g. `type PostgresqlList = [object]`,
// we recursively call `update_name` on the inner type,
// so the same renaming logic applies inside the list.
Typ::List(list) => {
update_name(list, type_name);
}
_ => {}
}
}
update_name(&mut resolved_type.0, type_name);
type_resolver.insert(type_name.to_owned(), resolved_type.clone());
// `top_level_call` indicates whether the current invocation of the function
// is at the topmost level (e.g., the immediate parameters of the main function).
// When true:
// - Type references within object properties (e.g., nested interfaces) are recursively resolved
// up to a default depth to inline and fully materialize their structure.
if top_level_call {
resolve_type_ref(type_resolver, &mut resolved_type.0);
}
Some(resolved_type)
}
fn tstype_to_typ(
symbol_table: &HashMap<String, TypeDecl>,
type_resolver: &mut HashMap<String, (Typ, bool)>,
ts_type: &TsType,
top_level_call: bool,
) -> (Typ, bool) {
match ts_type {
TsType::TsKeywordType(t) => (
match t.kind {
TsKeywordTypeKind::TsObjectKeyword => Typ::Object(vec![]),
TsKeywordTypeKind::TsObjectKeyword => {
Typ::Object(ObjectType::new(None, Some(vec![])))
}
TsKeywordTypeKind::TsBooleanKeyword => Typ::Bool,
TsKeywordTypeKind::TsBigIntKeyword => Typ::Int,
TsKeywordTypeKind::TsNumberKeyword => Typ::Float,
@@ -391,7 +674,17 @@ fn tstype_to_typ(ts_type: &TsType) -> (Typ, bool) {
key: sym.to_string(),
typ: type_ann
.as_ref()
.map(|typ| Box::new(tstype_to_typ(&*typ.type_ann).0))
.map(|typ| {
Box::new(
tstype_to_typ(
symbol_table,
type_resolver,
&*typ.type_ann,
top_level_call,
)
.0,
)
})
.unwrap_or(Box::new(Typ::Unknown)),
}),
_ => None,
@@ -399,21 +692,25 @@ fn tstype_to_typ(ts_type: &TsType) -> (Typ, bool) {
_ => None,
})
.collect();
(Typ::Object(properties), false)
(Typ::Object(ObjectType::new(None, Some(properties))), false)
}
TsType::TsParenthesizedType(TsParenthesizedType { type_ann, .. }) => {
tstype_to_typ(type_ann)
tstype_to_typ(symbol_table, type_resolver, type_ann, top_level_call)
}
// TODO: we can do better here and extract the inner type of array
TsType::TsArrayType(TsArrayType { elem_type, .. }) => {
(Typ::List(Box::new(tstype_to_typ(&**elem_type).0)), false)
}
TsType::TsArrayType(TsArrayType { elem_type, .. }) => (
Typ::List(Box::new(
tstype_to_typ(symbol_table, type_resolver, &**elem_type, top_level_call).0,
)),
false,
),
TsType::TsLitType(TsLitType { lit: TsLit::Str(Str { value, .. }), .. }) => {
(Typ::Str(Some(vec![value.to_string()])), false)
}
TsType::TsOptionalType(TsOptionalType { type_ann, .. }) => {
(tstype_to_typ(type_ann).0, true)
}
TsType::TsOptionalType(TsOptionalType { type_ann, .. }) => (
tstype_to_typ(symbol_table, type_resolver, type_ann, top_level_call).0,
true,
),
TsType::TsUnionOrIntersectionType(TsUnionOrIntersectionType::TsUnionType(
TsUnionType { types, .. },
)) => {
@@ -438,11 +735,18 @@ fn tstype_to_typ(ts_type: &TsType) -> (Typ, bool) {
} else {
0
};
(tstype_to_typ(&types[other_p]).0, true)
(
tstype_to_typ(symbol_table, type_resolver, &types[other_p], top_level_call).0,
true,
)
} else {
if types.len() > 1 {
let one_of_values: Vec<OneOfVariant> =
types.into_iter().map_while(parse_one_of_type).collect();
let one_of_values: Vec<OneOfVariant> = types
.into_iter()
.map_while(|t| {
parse_one_of_type(symbol_table, type_resolver, t, top_level_call)
})
.collect();
if one_of_values.len() == types.len() {
return (Typ::OneOf(one_of_values), false);
@@ -481,6 +785,7 @@ fn tstype_to_typ(ts_type: &TsType) -> (Typ, bool) {
TsEntityName::Ident(Ident { sym, .. }) => sym,
TsEntityName::TsQualifiedName(p) => &*p.right.sym,
};
match sym.to_string().as_str() {
"Resource" => (
Typ::Resource(
@@ -501,24 +806,68 @@ fn tstype_to_typ(ts_type: &TsType) -> (Typ, bool) {
"Base64" => (Typ::Bytes, false),
"Email" => (Typ::Email, false),
"Sql" => (Typ::Sql, false),
x @ _ if x.starts_with("DynSelect_") => (
Typ::DynSelect(x.strip_prefix("DynSelect_").unwrap().to_string()),
symbol @ _ if symbol.starts_with("DynSelect_") => (
Typ::DynSelect(symbol.strip_prefix("DynSelect_").unwrap().to_string()),
false,
),
x @ _ => (Typ::Resource(to_snake_case(x)), false),
symbol @ _ => {
let symbol = to_snake_case(symbol);
resolve_ts_interface_and_type_alias(
&symbol,
symbol_table,
type_resolver,
top_level_call,
)
.unwrap_or_else(|| (Typ::Resource(symbol), false))
}
}
}
_ => (Typ::Unknown, false),
}
}
fn parse_one_of_type(x: &Box<TsType>) -> Option<OneOfVariant> {
fn parse_one_of_type(
symbol_table: &HashMap<String, TypeDecl>,
type_resolver: &mut HashMap<String, (Typ, bool)>,
x: &Box<TsType>,
top_level_call: bool,
) -> Option<OneOfVariant> {
match &**x {
TsType::TsTypeLit(TsTypeLit { members, .. }) => {
let label = one_of_label(members)?;
let properties = one_of_properties(members);
let properties =
one_of_properties(symbol_table, type_resolver, members, top_level_call);
Some(OneOfVariant { label, properties })
}
TsType::TsTypeRef(TsTypeRef { type_name, .. }) => {
let label = type_name.as_ident()?.sym.to_string();
match label.as_str() {
symbol
if ["Resource", "Date", "Base64", "Email", "Sql"]
.iter()
.any(|s| *s == symbol)
|| symbol.starts_with("DynSelect_") =>
{
return None
}
symbol @ _ => {
let Typ::Object(ObjectType { props: Some(properties), .. }) =
resolve_ts_interface_and_type_alias(
symbol,
symbol_table,
type_resolver,
top_level_call,
)
.unwrap_or_else(|| (Typ::Resource(to_snake_case(symbol)), false))
.0
else {
return None;
};
Some(OneOfVariant { label, properties })
}
}
}
_ => None,
}
}
@@ -550,7 +899,12 @@ fn one_of_label(members: &Vec<TsTypeElement>) -> Option<String> {
})
}
fn one_of_properties(members: &Vec<TsTypeElement>) -> Vec<ObjectProperty> {
fn one_of_properties(
symbol_table: &HashMap<String, TypeDecl>,
type_resolver: &mut HashMap<String, (Typ, bool)>,
members: &Vec<TsTypeElement>,
top_level_call: bool,
) -> Vec<ObjectProperty> {
members
.iter()
.filter_map(|x| {
@@ -564,10 +918,12 @@ fn one_of_properties(members: &Vec<TsTypeElement>) -> Vec<ObjectProperty> {
};
let typ = type_ann
.as_ref()
.map(|typ| Box::new(tstype_to_typ(&*typ.type_ann).0))
.unwrap_or(Box::new(Typ::Unknown));
.map(|typ| {
tstype_to_typ(symbol_table, type_resolver, &*typ.type_ann, top_level_call).0
})
.unwrap_or(Typ::Unknown);
Some(ObjectProperty { key: sym.to_string(), typ })
Some(ObjectProperty { key: sym.to_string(), typ: Box::new(typ) })
})
.collect()
}

View File

@@ -1,8 +1,11 @@
#[cfg(test)]
mod tests {
use windmill_parser_ts::parse_expr_for_imports;
use serde_json::json;
use windmill_parser::{Arg, MainArgSignature, ObjectProperty, ObjectType, Typ};
use windmill_parser_ts::{parse_deno_signature, parse_expr_for_imports};
#[test]
fn test_imports() {
fn test_imports_basic() {
let code = r#"
import { foo } from "bar";
import type { foo } from "bar2";
@@ -12,8 +15,645 @@ mod tests {
import { type foo, type bar } from "bar4";
import * as foo from "bar5";
import foo from "bar6";
export * from "bar8";
export { foo } from "bar9";
export { type foo } from "bar10";
export { foo, type bar } from "bar11";
export { type foo, type bar } from "bar12";
export { type foo, bar } from "bar13";
export { bar, type foo } from "bar14";
export type { foo } from "bar15";
"#;
let imports = parse_expr_for_imports(code, true).unwrap();
assert_eq!(imports, vec!["bar", "bar3", "bar5", "bar6", "bar7"]);
assert_eq!(
imports,
["bar", "bar11", "bar13", "bar14", "bar3", "bar5", "bar6", "bar7", "bar8", "bar9"]
);
}
#[test]
fn test_parse_empty_main_signature() {
let code = r#"
export async function main() {
return "Hello World";
}
"#;
let sig = parse_deno_signature(code, false, false, None).unwrap();
assert_eq!(
sig,
MainArgSignature {
star_args: false,
star_kwargs: false,
args: vec![],
no_main_func: Some(false),
has_preprocessor: Some(false),
}
);
}
#[test]
fn test_parse_basic_types() {
let code = r#"
export async function main(
str_param: string,
num_param: number,
bool_param: boolean,
any_param: any
) {
return { str_param, num_param, bool_param, any_param };
}
"#;
let sig = parse_deno_signature(code, false, false, None).unwrap();
assert_eq!(
sig,
MainArgSignature {
star_args: false,
star_kwargs: false,
args: vec![
Arg {
name: "str_param".to_string(),
otyp: None,
typ: Typ::Str(None),
default: None,
has_default: false,
oidx: None,
},
Arg {
name: "num_param".to_string(),
otyp: None,
typ: Typ::Float,
default: None,
has_default: false,
oidx: None,
},
Arg {
name: "bool_param".to_string(),
otyp: None,
typ: Typ::Bool,
default: None,
has_default: false,
oidx: None,
},
Arg {
name: "any_param".to_string(),
otyp: None,
typ: Typ::Unknown,
default: None,
has_default: false,
oidx: None,
},
],
no_main_func: Some(false),
has_preprocessor: Some(false),
}
);
}
#[test]
fn test_parse_with_defaults() {
let code = r#"
export async function main(
name: string = "World",
count: number = 42,
enabled: boolean = true
) {
return { name, count, enabled };
}
"#;
let sig = parse_deno_signature(code, false, false, None).unwrap();
assert_eq!(
sig,
MainArgSignature {
star_args: false,
star_kwargs: false,
args: vec![
Arg {
name: "name".to_string(),
otyp: None,
typ: Typ::Str(None),
default: Some(json!("World")),
has_default: true,
oidx: None,
},
Arg {
name: "count".to_string(),
otyp: None,
typ: Typ::Float,
default: Some(json!(42)),
has_default: true,
oidx: None,
},
Arg {
name: "enabled".to_string(),
otyp: None,
typ: Typ::Bool,
default: Some(json!(true)),
has_default: true,
oidx: None,
},
],
no_main_func: Some(false),
has_preprocessor: Some(false),
}
);
}
#[test]
fn test_parse_array_types() {
let code = r#"
export async function main(
strings: string[],
numbers: number[],
items: any[]
) {
return { strings, numbers, items };
}
"#;
let sig = parse_deno_signature(code, false, false, None).unwrap();
assert_eq!(
sig,
MainArgSignature {
star_args: false,
star_kwargs: false,
args: vec![
Arg {
name: "strings".to_string(),
otyp: None,
typ: Typ::List(Box::new(Typ::Str(None))),
default: None,
has_default: false,
oidx: None,
},
Arg {
name: "numbers".to_string(),
otyp: None,
typ: Typ::List(Box::new(Typ::Float)),
default: None,
has_default: false,
oidx: None,
},
Arg {
name: "items".to_string(),
otyp: None,
typ: Typ::List(Box::new(Typ::Unknown)),
default: None,
has_default: false,
oidx: None,
},
],
no_main_func: Some(false),
has_preprocessor: Some(false),
}
);
}
#[test]
fn test_parse_resource_types() {
let code = r#"
type Postgresql = Resource;
export async function main(
database: Postgresql
) {
return { database };
}
"#;
let sig = parse_deno_signature(code, false, false, None).unwrap();
assert_eq!(
sig,
MainArgSignature {
star_args: false,
star_kwargs: false,
args: vec![Arg {
name: "database".to_string(),
otyp: None,
typ: Typ::Resource("postgresql".to_string()),
default: None,
has_default: false,
oidx: None,
},],
no_main_func: Some(false),
has_preprocessor: Some(false),
}
);
}
#[test]
fn test_parse_array_resource_types() {
let code = r#"
type Postgresql = Foo;
export async function main(
database: Postgresql[]
) {
return { database };
}
"#;
let sig = parse_deno_signature(code, false, false, None).unwrap();
assert_eq!(
sig,
MainArgSignature {
star_args: false,
star_kwargs: false,
args: vec![Arg {
name: "database".to_string(),
otyp: None,
typ: Typ::List(Box::new(Typ::Resource("postgresql".to_string()))),
default: None,
has_default: false,
oidx: None,
},],
no_main_func: Some(false),
has_preprocessor: Some(false),
}
);
}
#[test]
fn test_parse_interface_object() {
let code = r#"
interface UserConfig {
name: string;
age: number;
active?: boolean;
}
export async function main(config: UserConfig) {
return config;
}
"#;
let sig = parse_deno_signature(code, false, false, None).unwrap();
assert_eq!(
sig,
MainArgSignature {
star_args: false,
star_kwargs: false,
args: vec![Arg {
name: "config".to_string(),
otyp: None,
typ: Typ::Object(ObjectType::new(
Some("user_config".to_string()),
Some(vec![
ObjectProperty::new("name".to_string(), Box::new(Typ::Str(None))),
ObjectProperty::new("age".to_string(), Box::new(Typ::Float)),
ObjectProperty::new("active".to_string(), Box::new(Typ::Bool)),
])
)),
default: None,
has_default: false,
oidx: None,
}],
no_main_func: Some(false),
has_preprocessor: Some(false),
}
);
}
#[test]
fn test_parse_array_of_objects() {
let code = r#"
interface Item {
id: string;
value: number;
}
export async function main(items: Item[]) {
return items;
}
"#;
let sig = parse_deno_signature(code, false, false, None).unwrap();
assert_eq!(
sig,
MainArgSignature {
star_args: false,
star_kwargs: false,
args: vec![Arg {
name: "items".to_string(),
otyp: None,
typ: Typ::List(Box::new(Typ::Object(ObjectType::new(
Some("item".to_string()),
Some(vec![
ObjectProperty::new("id".to_string(), Box::new(Typ::Str(None))),
ObjectProperty::new("value".to_string(), Box::new(Typ::Float)),
])
)))),
default: None,
has_default: false,
oidx: None,
}],
no_main_func: Some(false),
has_preprocessor: Some(false),
}
);
}
#[test]
fn test_parse_nested_objects() {
let code = r#"
interface Address {
street: string;
city: string;
}
interface Person {
name: string;
address: Address;
}
export async function main(person: Person) {
return person;
}
"#;
let sig = parse_deno_signature(code, false, false, None).unwrap();
assert_eq!(
sig,
MainArgSignature {
star_args: false,
star_kwargs: false,
args: vec![Arg {
name: "person".to_string(),
otyp: None,
typ: Typ::Object(ObjectType::new(
Some("person".to_string()),
Some(vec![
ObjectProperty::new("name".to_string(), Box::new(Typ::Str(None))),
ObjectProperty::new(
"address".to_string(),
Box::new(Typ::Object(ObjectType::new(
Some("address".to_string()),
Some(vec![
ObjectProperty::new(
"street".to_string(),
Box::new(Typ::Str(None))
),
ObjectProperty::new(
"city".to_string(),
Box::new(Typ::Str(None))
),
])
)))
),
])
)),
default: None,
has_default: false,
oidx: None,
}],
no_main_func: Some(false),
has_preprocessor: Some(false),
}
);
}
#[test]
fn test_parse_builtin_types() {
let code = r#"
export async function main(
date_param: Date,
base64_param: Base64,
email_param: Email,
sql_param: Sql
) {
return { date_param, base64_param, email_param, sql_param };
}
"#;
let sig = parse_deno_signature(code, false, false, None).unwrap();
assert_eq!(
sig,
MainArgSignature {
star_args: false,
star_kwargs: false,
args: vec![
Arg {
name: "date_param".to_string(),
otyp: None,
typ: Typ::Datetime,
default: None,
has_default: false,
oidx: None,
},
Arg {
name: "base64_param".to_string(),
otyp: None,
typ: Typ::Bytes,
default: None,
has_default: false,
oidx: None,
},
Arg {
name: "email_param".to_string(),
otyp: None,
typ: Typ::Email,
default: None,
has_default: false,
oidx: None,
},
Arg {
name: "sql_param".to_string(),
otyp: None,
typ: Typ::Sql,
default: None,
has_default: false,
oidx: None,
},
],
no_main_func: Some(false),
has_preprocessor: Some(false),
}
);
}
#[test]
fn test_parse_optional_parameters() {
let code = r#"
export async function main(
required: string,
optional?: number,
with_default: boolean = false
) {
return { required, optional, with_default };
}
"#;
let sig = parse_deno_signature(code, false, false, None).unwrap();
assert_eq!(
sig,
MainArgSignature {
star_args: false,
star_kwargs: false,
args: vec![
Arg {
name: "required".to_string(),
otyp: None,
typ: Typ::Str(None),
default: None,
has_default: false,
oidx: None,
},
Arg {
name: "optional".to_string(),
otyp: None,
typ: Typ::Float,
default: None,
has_default: true,
oidx: None,
},
Arg {
name: "with_default".to_string(),
otyp: None,
typ: Typ::Bool,
default: Some(json!(false)),
has_default: true,
oidx: None,
},
],
no_main_func: Some(false),
has_preprocessor: Some(false),
}
);
}
#[test]
fn test_parse_complex_interface() {
let code = r#"
interface Config {
timeout: number;
retries: number;
}
export async function main(
config: Config,
tags: string[]
) {
return { config, tags };
}
"#;
let sig = parse_deno_signature(code, false, false, None).unwrap();
assert_eq!(sig.args.len(), 2);
assert_eq!(sig.args[0].name, "config");
assert_eq!(sig.args[0].has_default, false);
assert!(matches!(sig.args[0].typ, Typ::Object(_)));
assert_eq!(sig.args[1].name, "tags");
assert_eq!(sig.args[1].has_default, false);
assert!(matches!(sig.args[1].typ, Typ::List(_)));
}
#[test]
fn test_parse_no_main_function() {
let code = r#"
function helper() {
return "helper";
}
const value = 42;
"#;
let sig = parse_deno_signature(code, false, false, None).unwrap();
assert_eq!(
sig,
MainArgSignature {
star_args: false,
star_kwargs: false,
args: vec![],
no_main_func: Some(true),
has_preprocessor: Some(false),
}
);
}
#[test]
fn test_parse_custom_entrypoint() {
let code = r#"
export async function customMain(param: string) {
return param;
}
"#;
let sig = parse_deno_signature(code, false, false, Some("customMain".to_string())).unwrap();
assert_eq!(
sig,
MainArgSignature {
star_args: false,
star_kwargs: false,
args: vec![Arg {
name: "param".to_string(),
otyp: None,
typ: Typ::Str(None),
default: None,
has_default: false,
oidx: None,
}],
no_main_func: Some(false),
has_preprocessor: Some(false),
}
);
}
#[test]
fn test_parse_dyn_select() {
let code = r#"
export async function main(
selector: DynSelect_my_options
) {
return selector;
}
"#;
let sig = parse_deno_signature(code, false, false, None).unwrap();
assert_eq!(
sig,
MainArgSignature {
star_args: false,
star_kwargs: false,
args: vec![Arg {
name: "selector".to_string(),
otyp: None,
typ: Typ::DynSelect("my_options".to_string()),
default: None,
has_default: false,
oidx: None,
}],
no_main_func: Some(false),
has_preprocessor: Some(false),
}
);
}
#[test]
fn test_parse_invalid_typescript() {
let code = r#"
this is not valid typescript code {
"#;
let result = parse_deno_signature(code, false, false, None);
assert!(result.is_err());
}
#[test]
fn test_parse_with_preprocessor() {
let code = r#"
export async function preprocessor() {
return "preprocessed";
}
export async function main(param: string) {
return param;
}
"#;
let sig = parse_deno_signature(code, false, false, None).unwrap();
assert_eq!(
sig,
MainArgSignature {
star_args: false,
star_kwargs: false,
args: vec![Arg {
name: "param".to_string(),
otyp: None,
typ: Typ::Str(None),
default: None,
has_default: false,
oidx: None,
}],
no_main_func: Some(false),
has_preprocessor: Some(true),
}
);
}
}

View File

@@ -1,79 +0,0 @@
#!/usr/bin/env bash
set -eou pipefail
#-# bun and deno
OUT_DIR="../../../cli/wasm/ts"
mkdir -p $OUT_DIR
wasm-pack build --release --target deno --out-dir $OUT_DIR --features "ts-parser" \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
# sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-ts"/' $OUT_DIR/package.json
rm $OUT_DIR/.gitignore
#-# sql languages, graphql and bash/powershell, since they all use regex
OUT_DIR="../../../cli/wasm/regex"
mkdir -p $OUT_DIR
wasm-pack build --release --target deno --out-dir $OUT_DIR \
--features "sql-parser,graphql-parser,bash-parser" \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
# sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-regex"/' $OUT_DIR/package.json
rm $OUT_DIR/.gitignore
#-# python
OUT_DIR="../../../cli/wasm/python"
mkdir -p $OUT_DIR
wasm-pack build --release --target deno --out-dir $OUT_DIR --features "py-parser" \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
# sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-py"/' $OUT_DIR/package.json
rm $OUT_DIR/.gitignore
#-# go
OUT_DIR="../../../cli/wasm/go"
mkdir -p $OUT_DIR
wasm-pack build --release --target deno --out-dir $OUT_DIR --features "go-parser" \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
# sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-go"/' $OUT_DIR/package.json
rm $OUT_DIR/.gitignore
#-# php
OUT_DIR="../../../cli/wasm/php"
mkdir -p $OUT_DIR
wasm-pack build --release --target deno --out-dir $OUT_DIR --features "php-parser" \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
# sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-php"/' $OUT_DIR/package.json
rm $OUT_DIR/.gitignore
#-# rust
OUT_DIR="../../../cli/wasm/rust"
mkdir -p $OUT_DIR
wasm-pack build --release --target deno --out-dir $OUT_DIR --features "rust-parser" \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
# sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-rust"/' $OUT_DIR/package.json
rm $OUT_DIR/.gitignore
#-# ansible
OUT_DIR="../../../cli/wasm/yaml"
mkdir -p $OUT_DIR
wasm-pack build --release --target deno --out-dir $OUT_DIR --features "ansible-parser" \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
# sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-yaml"/' $OUT_DIR/package.json
rm $OUT_DIR/.gitignore
#-# C# (needs some more stuff to compile C tree sitter into wasm)
OUT_DIR="../../../cli/wasm/csharp"
mkdir -p $OUT_DIR
CFLAGS_wasm32_unknown_unknown="-I$(pwd)/wasm-sysroot -Wbad-function-cast -Wcast-function-type -fno-builtin" RUSTFLAGS="-Zwasm-c-abi=spec" wasm-pack build --release --target deno --out-dir $OUT_DIR --features "csharp-parser"
# sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-csharp"/' $OUT_DIR/package.json
rm $OUT_DIR/.gitignore
#-# Nu
OUT_DIR="../../../cli/wasm/nu"
mkdir -p $OUT_DIR
wasm-pack build --release --target deno --out-dir $OUT_DIR --features "nu-parser" \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
rm $OUT_DIR/.gitignore
#-# Java
OUT_DIR="../../../cli/wasm/java"
mkdir -p $OUT_DIR
CFLAGS_wasm32_unknown_unknown="-I$(pwd)/wasm-sysroot -Wbad-function-cast -Wcast-function-type -fno-builtin" RUSTFLAGS="-Zwasm-c-abi=spec" wasm-pack build --release --target deno --out-dir $OUT_DIR --features "java-parser"
rm $OUT_DIR/.gitignore

View File

@@ -1,68 +0,0 @@
#!/bin/bash
set -eou pipefail
#-# full pkg
OUT_DIR="pkg"
wasm-pack build --release --target web --out-dir $OUT_DIR --all-features \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
#-# bun and deno
OUT_DIR="pkg-ts"
wasm-pack build --release --target web --out-dir $OUT_DIR --features "ts-parser" \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
sed -i '' 's/"windmill-parser-wasm"/"windmill-parser-wasm-ts"/' $OUT_DIR/package.json
#-# sql languages, graphql and bash/powershell, since they all use regex
OUT_DIR="pkg-regex"
wasm-pack build --release --target web --out-dir $OUT_DIR \
--features "sql-parser,graphql-parser,bash-parser" \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
sed -i '' 's/"windmill-parser-wasm"/"windmill-parser-wasm-regex"/' $OUT_DIR/package.json
#-# python
OUT_DIR="pkg-py"
wasm-pack build --release --target web --out-dir $OUT_DIR --features "py-parser" \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
sed -i '' 's/"windmill-parser-wasm"/"windmill-parser-wasm-py"/' $OUT_DIR/package.json
#-# go
OUT_DIR="pkg-go"
wasm-pack build --release --target web --out-dir $OUT_DIR --features "go-parser" \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
sed -i '' 's/"windmill-parser-wasm"/"windmill-parser-wasm-go"/' $OUT_DIR/package.json
#-# php
OUT_DIR="pkg-php"
wasm-pack build --release --target web --out-dir $OUT_DIR --features "php-parser" \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
sed -i '' 's/"windmill-parser-wasm"/"windmill-parser-wasm-php"/' $OUT_DIR/package.json
#-# rust
OUT_DIR="pkg-rust"
wasm-pack build --release --target web --out-dir $OUT_DIR --features "rust-parser" \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
sed -i '' 's/"windmill-parser-wasm"/"windmill-parser-wasm-rust"/' $OUT_DIR/package.json
#-# ansible
OUT_DIR="pkg-yaml"
wasm-pack build --release --target web --out-dir $OUT_DIR --features "ansible-parser" \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
sed -i '' 's/"windmill-parser-wasm"/"windmill-parser-wasm-yaml"/' $OUT_DIR/package.json
#-# C# (needs some more stuff to compile C tree sitter into wasm)
# TODO: hasn't been tested on mac, might need fixing
OUT_DIR="pkg-csharp"
CFLAGS_wasm32_unknown_unknown="-I$(pwd)/wasm-sysroot -Wbad-function-cast -Wcast-function-type -fno-builtin" RUSTFLAGS="-Zwasm-c-abi=spec" wasm-pack build --release --target web --out-dir $OUT_DIR --features "csharp-parser"
sed -i '' 's/"windmill-parser-wasm"/"windmill-parser-wasm-csharp"/' $OUT_DIR/package.json
#-# nu
# TODO: hasn't been tested on mac, might need fixing
OUT_DIR="pkg-nu"
wasm-pack build --release --target web --out-dir $OUT_DIR --features "nu-parser" \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
sed -i '' 's/"windmill-parser-wasm"/"windmill-parser-wasm-nu"/' $OUT_DIR/package.json
#-# Java (needs some more stuff to compile C tree sitter into wasm)
OUT_DIR="pkg-java"
CFLAGS_wasm32_unknown_unknown="-I$(pwd)/wasm-sysroot -Wbad-function-cast -Wcast-function-type -fno-builtin" RUSTFLAGS="-Zwasm-c-abi=spec" wasm-pack build --release --target web --out-dir $OUT_DIR --features "java-parser"
sed -i '' 's/"windmill-parser-wasm"/"windmill-parser-wasm-java"/' $OUT_DIR/package.json

View File

@@ -1,66 +0,0 @@
#!/usr/bin/env bash
set -eou pipefail
#-# full pkg
OUT_DIR="pkg"
wasm-pack build --release --target web --out-dir $OUT_DIR --all-features \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
#-# bun and deno
OUT_DIR="pkg-ts"
wasm-pack build --release --target web --out-dir $OUT_DIR --features "ts-parser" \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-ts"/' $OUT_DIR/package.json
#-# sql languages, graphql and bash/powershell, since they all use regex
OUT_DIR="pkg-regex"
wasm-pack build --release --target web --out-dir $OUT_DIR \
--features "sql-parser,graphql-parser,bash-parser" \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-regex"/' $OUT_DIR/package.json
#-# python
OUT_DIR="pkg-py"
wasm-pack build --release --target web --out-dir $OUT_DIR --features "py-parser" \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-py"/' $OUT_DIR/package.json
#-# go
OUT_DIR="pkg-go"
wasm-pack build --release --target web --out-dir $OUT_DIR --features "go-parser" \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-go"/' $OUT_DIR/package.json
#-# php
OUT_DIR="pkg-php"
wasm-pack build --release --target web --out-dir $OUT_DIR --features "php-parser" \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-php"/' $OUT_DIR/package.json
#-# rust
OUT_DIR="pkg-rust"
wasm-pack build --release --target web --out-dir $OUT_DIR --features "rust-parser" \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-rust"/' $OUT_DIR/package.json
#-# ansible
OUT_DIR="pkg-yaml"
wasm-pack build --release --target web --out-dir $OUT_DIR --features "ansible-parser" \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-yaml"/' $OUT_DIR/package.json
#-# C# (needs some more stuff to compile C tree sitter into wasm)
OUT_DIR="pkg-csharp"
CFLAGS_wasm32_unknown_unknown="-I$(pwd)/wasm-sysroot -Wbad-function-cast -Wcast-function-type -fno-builtin" RUSTFLAGS="-Zwasm-c-abi=spec" wasm-pack build --release --target web --out-dir $OUT_DIR --features "csharp-parser"
sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-csharp"/' $OUT_DIR/package.json
#-# Nu
OUT_DIR="pkg-nu"
wasm-pack build --release --target web --out-dir $OUT_DIR --features "nu-parser" \
-Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-nu"/' $OUT_DIR/package.json
#-# Java (needs some more stuff to compile C tree sitter into wasm)
OUT_DIR="pkg-java"
CFLAGS_wasm32_unknown_unknown="-I$(pwd)/wasm-sysroot -Wbad-function-cast -Wcast-function-type -fno-builtin" RUSTFLAGS="-Zwasm-c-abi=spec" wasm-pack build --release --target web --out-dir $OUT_DIR --features "java-parser"
sed -i 's/"windmill-parser-wasm"/"windmill-parser-wasm-java"/' $OUT_DIR/package.json

View File

@@ -0,0 +1,132 @@
#!/usr/bin/env nu
const targets = [
{
ident: "ts", # OUT_DIR inferred from this
desc: "Bun and Deno"
features: "ts-parser",
env: "default", # available: default, tree-sitter
}, {
ident: "regex",
desc: "Sql languages, Graphql and Bash/Powershell"
features: "sql-parser,graphql-parser,bash-parser",
env: "default",
}, {
ident: "py",
desc: "Python",
features: "py-parser",
env: "default",
}, {
ident: "go",
desc: "Go (Go-lang)",
features: "go-parser",
env: "default",
}, {
ident: "php",
desc: "Php",
features: "php-parser",
env: "default",
}, {
ident: "rust",
desc: "Rust",
features: "rust-parser",
env: "default",
}, {
ident: "yaml",
desc: "Ansible",
features: "ansible-parser",
env: "default",
}, {
ident: "csharp",
desc: "C#",
features: "csharp-parser",
env: "tree-sitter",
}, {
ident: "nu",
desc: "Nu (Nushell)",
features: "nu-parser",
env: "tree-sitter",
}, {
ident: "java",
desc: "Java",
features: "java-parser",
env: "tree-sitter",
# }, {
# ident: "ruby",
# desc: "Ruby",
# features: "ruby-parser",
# env: "tree-sitter",
},
# ^^^ Add new entry here ^^^
];
# NOTE: This is legacy command for building all, but it is not more used
# #-# full pkg
# OUT_DIR="pkg"
# wasm-pack build --release --target web --out-dir $OUT_DIR --all-features \
# -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
# Build all separately
def 'main all' [ --no-opt(-n), --cli] {
if ($no_opt) {
if ($cli) {
$targets | each { main $in.ident -n --cli }
} else {
$targets | each { main $in.ident -n }
}
} else {
if ($cli) {
$targets | each { main $in.ident --cli }
} else {
$targets | each { main $in.ident }
}
}
}
# Build specific language
def main [
target: string, # Language, e.g.: py, ts, rust
--no-opt(-n), # Compile in debug mode for dev
--cli # Compile and place binaries in cli.
] {
let t = $targets | where ident == $target;
if ($t | is-empty) {
let pretty = $targets | each {|t| $"($t.ident) - ($t.desc)"} | str join "\n";
panic $"Target '($target)' does not exist\n\nAvailable targets:\n($pretty)"
} else {
let t = $t | get 0;
mut profile = "";
mut tar = "";
if ($cli) {
$env.OUT_DIR = $"../../../cli/wasm/($t.ident)"
$tar = "deno"
} else {
$env.OUT_DIR = $"pkg-($t.ident)"
$tar = "web"
}
if ($no_opt) {
$profile = "--no-opt"
} else {
$profile = "--release"
}
print $"Building in ($profile) mode ($env.OUT_DIR)"
match $t.env {
"default" => {
wasm-pack build ($profile) --target ($tar) --out-dir $env.OUT_DIR --features ($t.features) -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
},
"tree-sitter" => {
$env.CFLAGS_wasm32_unknown_unknown = $"-I(pwd)/wasm-sysroot -Wbad-function-cast -Wcast-function-type -fno-builtin"
$env.RUSTFLAGS = "-Zwasm-c-abi=spec"
wasm-pack build ($profile) --target ($tar) --out-dir $env.OUT_DIR --features $t.features
},
_ => { panic $"Unknown env template: ($t.env)" },
}
if ($cli) {
rm $"($env.OUT_DIR)/.gitignore"
} else {
let p = $"($env.OUT_DIR)/package.json"
open $p | update name $"windmill-parser-wasm-($t.ident)" | save -f $p
}
}
}

View File

@@ -4,22 +4,9 @@
# and perform installation to frontend
def "main" [
lang: string # Example: nu
--release(-r)
] {
let out_dir = $'pkg-($lang)'
if $release {
open build-pkgs.sh
| split row '#-'
| find $out_dir
| bash -c $"RUST_LOG=trace ($in.0)"
} else {
open build-pkgs.sh
| split row '#-'
| find $out_dir
| str replace "--release" "--no-opt"
| bash -c $"WASM_OPT=-Oz ($in.0)"
}
./build.nu $lang --no-opt
(
cd ../../../frontend; npm install ../backend/parsers/windmill-parser-wasm/($out_dir)
cd ../../../frontend; npm install ../backend/parsers/windmill-parser-wasm/pkg-($lang)
)
}

View File

@@ -30,3 +30,6 @@ popd
pushd "pkg-nu" && npm publish ${args}
popd
pushd "pkg-java" && npm publish ${args}
popd

View File

@@ -1,6 +1,6 @@
use serde_json::json;
use wasm_bindgen_test::wasm_bindgen_test;
use windmill_parser::{Arg, MainArgSignature, ObjectProperty, Typ};
use windmill_parser::{Arg, MainArgSignature, ObjectProperty, ObjectType, Typ};
use windmill_parser_bash::parse_powershell_sig;
use windmill_parser_ts::{parse_deno_signature, parse_expr_for_ids, parse_expr_for_imports};
@@ -115,10 +115,10 @@ export function main(test1?: string, test2: string = \"burkina\",
Arg {
otyp: None,
name: "min_object".to_string(),
typ: Typ::Object(vec![
typ: Typ::Object(ObjectType::new(None, Some(vec![
ObjectProperty { key: "a".to_string(), typ: Box::new(Typ::Str(None)) },
ObjectProperty { key: "b".to_string(), typ: Box::new(Typ::Float) }
]),
]))),
default: None,
has_default: false,
oidx: None
@@ -210,10 +210,10 @@ export function main(test2 = \"burkina\",
Arg {
otyp: None,
name: "min_object".to_string(),
typ: Typ::Object(vec![
typ: Typ::Object(ObjectType::new(None, Some(vec![
ObjectProperty { key: "a".to_string(), typ: Box::new(Typ::Str(None)) },
ObjectProperty { key: "b".to_string(), typ: Box::new(Typ::Int) }
]),
]))),
default: Some(json!({"a": "test", "b": 42})),
has_default: true,
oidx: None

View File

@@ -2,7 +2,7 @@ use std::collections::HashMap;
use anyhow::anyhow;
use serde_json::json;
use windmill_parser::{Arg, MainArgSignature, ObjectProperty, Typ};
use windmill_parser::{Arg, MainArgSignature, ObjectProperty, ObjectType, Typ};
use yaml_rust::{Yaml, YamlEmitter, YamlLoader};
pub fn parse_ansible_sig(inner_content: &str) -> anyhow::Result<MainArgSignature> {
@@ -147,9 +147,9 @@ fn parse_ansible_typ(arg: &Yaml) -> Typ {
})
}
}
Typ::Object(prop_vec)
Typ::Object(ObjectType::new(None, Some(prop_vec)))
} else {
Typ::Object(vec![])
Typ::Object(ObjectType::new(None, Some(vec![])))
}
}
"array" => {

View File

@@ -15,7 +15,6 @@ use AssetUsageAccessType::*;
pub enum AssetKind {
S3Object,
Resource,
Variable,
}
#[derive(Serialize)]
@@ -57,8 +56,6 @@ pub fn parse_asset_syntax(s: &str) -> Option<(AssetKind, &str)> {
Some((AssetKind::Resource, &s[6..]))
} else if s.starts_with("$res:") {
Some((AssetKind::Resource, &s[5..]))
} else if s.starts_with("var://") {
Some((AssetKind::Variable, &s[6..]))
} else {
None
}

View File

@@ -28,6 +28,24 @@ pub struct ObjectProperty {
pub typ: Box<Typ>,
}
impl ObjectProperty {
pub fn new(key: String, typ: Box<Typ>) -> ObjectProperty {
ObjectProperty { key, typ }
}
}
#[derive(Serialize, Clone, Debug, PartialEq)]
pub struct ObjectType {
pub name: Option<String>,
pub props: Option<Vec<ObjectProperty>>,
}
impl ObjectType {
pub fn new(name: Option<String>, props: Option<Vec<ObjectProperty>>) -> ObjectType {
ObjectType { name, props }
}
}
#[derive(Serialize, Clone, Debug, PartialEq)]
#[serde(rename_all(serialize = "lowercase"))]
pub struct OneOfVariant {
@@ -49,7 +67,7 @@ pub enum Typ {
Email,
Sql,
DynSelect(String),
Object(Vec<ObjectProperty>),
Object(ObjectType),
OneOf(Vec<OneOfVariant>),
Unknown,
}
@@ -70,11 +88,14 @@ pub fn json_to_typ(js: &Value) -> Typ {
Value::Number(n) if n.is_i64() => Typ::Int,
Value::Number(_) => Typ::Float,
Value::Bool(_) => Typ::Bool,
Value::Object(o) => Typ::Object(
o.iter()
.map(|(k, v)| ObjectProperty { key: k.to_string(), typ: Box::new(json_to_typ(v)) })
.collect(),
),
Value::Object(o) => Typ::Object(ObjectType::new(
None,
Some(
o.iter()
.map(|(k, v)| ObjectProperty { key: k.to_string(), typ: Box::new(json_to_typ(v)) })
.collect(),
),
)),
Value::Array(a) => Typ::List(Box::new(a.first().map(json_to_typ).unwrap_or(Typ::Unknown))),
_ => Typ::Unknown,
}

View File

@@ -54,8 +54,8 @@ use windmill_common::{
stats_oss::schedule_stats,
triggers::TriggerKind,
utils::{
create_default_worker_suffix, create_ssh_agent_worker_suffix, worker_name_with_suffix,
Mode, GIT_VERSION, HOSTNAME, MODE_AND_ADDONS,
create_default_worker_suffix, worker_name_with_suffix, Mode, GIT_VERSION, HOSTNAME,
MODE_AND_ADDONS,
},
worker::{
reload_custom_tags_setting, Connection, HUB_CACHE_DIR, TMP_DIR, TMP_LOGS_DIR, WORKER_GROUP,
@@ -365,7 +365,7 @@ async fn windmill_main() -> anyhow::Result<()> {
"Creating http client for cluster using base internal url {}",
std::env::var("BASE_INTERNAL_URL").unwrap_or_default()
);
let suffix = create_ssh_agent_worker_suffix(&hostname);
let suffix = create_default_worker_suffix(&hostname);
(
Connection::Http(build_agent_http_client(&suffix)),
Some(suffix),

View File

@@ -65,7 +65,8 @@ use windmill_common::{
users::truncate_token,
utils::{empty_as_none, now_from_db, rd_string, report_critical_error, Mode},
worker::{
load_env_vars, load_init_bash_from_env, load_whitelist_env_vars_from_env,
load_env_vars, load_init_bash_from_env, load_periodic_bash_script_from_env,
load_periodic_bash_script_interval_from_env, load_whitelist_env_vars_from_env,
load_worker_config, reload_custom_tags_setting, store_pull_query,
store_suspended_pull_query, update_min_version, Connection, WorkerConfig,
DEFAULT_TAGS_PER_WORKSPACE, DEFAULT_TAGS_WORKSPACES, INDEXER_CONFIG, SCRIPT_TOKEN_EXPIRY,
@@ -213,6 +214,8 @@ pub async fn initial_load(
priority_tags_sorted: vec![],
dedicated_worker: None,
init_bash: load_init_bash_from_env(),
periodic_script_bash: load_periodic_bash_script_from_env(),
periodic_script_interval_seconds: load_periodic_bash_script_interval_from_env(),
cache_clear: None,
additional_python_paths: None,
pip_local_dependencies: None,
@@ -1574,6 +1577,17 @@ pub async fn reload_worker_config(db: &DB, tx: KillpillSender, kill_if_change: b
tracing::error!("Error cleaning the cache: {e:#}");
}
}
if (*wc).periodic_script_bash != config.periodic_script_bash {
tracing::info!("Periodic script bash config changed, sending killpill. Expecting to be restarted by supervisor.");
let _ = tx.send();
}
if (*wc).periodic_script_interval_seconds != config.periodic_script_interval_seconds
{
tracing::info!("Periodic script interval config changed, sending killpill. Expecting to be restarted by supervisor.");
let _ = tx.send();
}
}
drop(wc);
@@ -1835,12 +1849,14 @@ async fn handle_zombie_jobs(db: &Pool<Postgres>, base_internal_url: &str, worker
);
}
let jobs = sqlx::query_as::<_, QueuedJob>("SELECT * FROM v2_as_queue WHERE id = ANY($1)")
.bind(&timeouts[..])
.fetch_all(db)
.await
.map_err(|e| tracing::error!("Error fetching same worker jobs: {:?}", e))
.unwrap_or_default();
let jobs = sqlx::query_as::<_, QueuedJob>(
"SELECT *, null as workflow_as_code_status FROM v2_as_queue WHERE id = ANY($1)",
)
.bind(&timeouts[..])
.fetch_all(db)
.await
.map_err(|e| tracing::error!("Error fetching same worker jobs: {:?}", e))
.unwrap_or_default();
jobs
};
@@ -1848,7 +1864,7 @@ async fn handle_zombie_jobs(db: &Pool<Postgres>, base_internal_url: &str, worker
let non_restartable_jobs = if *RESTART_ZOMBIE_JOBS {
vec![]
} else {
sqlx::query_as::<_, QueuedJob>("SELECT * FROM v2_as_queue WHERE last_ping < now() - ($1 || ' seconds')::interval
sqlx::query_as::<_, QueuedJob>("SELECT *, null as workflow_as_code_status FROM v2_as_queue WHERE last_ping < now() - ($1 || ' seconds')::interval
AND running = true AND job_kind NOT IN ('flow', 'flowpreview', 'flownode', 'singlescriptflow') AND same_worker = false")
.bind(ZOMBIE_JOB_TIMEOUT.as_str())
.fetch_all(db)
@@ -1873,13 +1889,14 @@ async fn handle_zombie_jobs(db: &Pool<Postgres>, base_internal_url: &str, worker
}
}
let zombie_jobs_restart_limit_reached =
sqlx::query_as::<_, QueuedJob>("SELECT * FROM v2_as_queue WHERE id = ANY($1)")
.bind(&zombie_jobs_uuid_restart_limit_reached[..])
.fetch_all(db)
.await
.ok()
.unwrap_or_else(|| vec![]);
let zombie_jobs_restart_limit_reached = sqlx::query_as::<_, QueuedJob>(
"SELECT *, null as workflow_as_code_status FROM v2_as_queue WHERE id = ANY($1)",
)
.bind(&zombie_jobs_uuid_restart_limit_reached[..])
.fetch_all(db)
.await
.ok()
.unwrap_or_else(|| vec![]);
let timeouts = non_restartable_jobs
.into_iter()

View File

@@ -99,4 +99,4 @@ if [ "$MOVE_NEW_FILES" == "YES" ]; then
echo "File moved '${ce_file}' -->> '${ee_file}'"
fi
done
fi
fi

View File

@@ -27,8 +27,10 @@ use serde::Serialize;
use windmill_common::flows::InputTransform;
use windmill_common::worker::WORKER_CONFIG;
#[cfg(feature = "python")]
use windmill_common::flow_status::{FlowStatus, FlowStatusModule, RestartedFrom};
use windmill_common::{
flow_status::{FlowStatus, FlowStatusModule, RestartedFrom},
flows::{FlowModule, FlowModuleValue, FlowValue},
jobs::{JobKind, JobPayload, RawCode},
jwt::JWT_SECRET,
@@ -114,12 +116,14 @@ fn next_worker_name() -> String {
.unwrap_or(s)
})
.unwrap_or("no thread name");
format!("{id}/{thread_name}")
format!("{id}/worker-{thread_name}")
}
pub struct ApiServer {
pub addr: std::net::SocketAddr,
#[allow(unused)]
tx: tokio::sync::broadcast::Sender<()>,
#[allow(unused)]
task: tokio::task::JoinHandle<anyhow::Result<()>>,
}
@@ -153,6 +157,7 @@ impl ApiServer {
Self { addr, tx, task }
}
#[allow(unused)]
async fn close(self) -> anyhow::Result<()> {
println!("closing api server");
let Self { tx, task, .. } = self;
@@ -193,11 +198,13 @@ async fn set_jwt_secret() -> () {
}
mod suspend_resume {
#[cfg(feature = "deno_core")]
use serde_json::json;
#[cfg(feature = "deno_core")]
use super::*;
#[cfg(feature = "deno_core")]
async fn wait_until_flow_suspends(
flow: Uuid,
mut queue: impl Stream<Item = Uuid> + Unpin,
@@ -218,6 +225,7 @@ mod suspend_resume {
}
}
#[cfg(feature = "deno_core")]
fn flow() -> FlowValue {
serde_json::from_value(serde_json::json!({
"modules": [{
@@ -462,12 +470,12 @@ mod suspend_resume {
}
}
#[cfg(feature = "deno_core")]
mod retry {
use super::*;
use serde_json::json;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use super::*;
/// test helper provides some external state to help steps fail at specific points
struct Server {
addr: std::net::SocketAddr,
@@ -536,6 +544,7 @@ def main(last, port):
"#
}
#[cfg(feature = "deno_core")]
fn flow_forloop_retry() -> FlowValue {
serde_json::from_value(serde_json::json!({
"modules": [{
@@ -1073,6 +1082,7 @@ async fn listen_for_completed_jobs(db: &Pool<Postgres>) -> impl Stream<Item = Uu
listen_for_uuid_on(db, "completed").await
}
#[cfg(feature = "deno_core")]
async fn listen_for_queue(db: &Pool<Postgres>) -> impl Stream<Item = Uuid> + Unpin {
listen_for_uuid_on(db, "queued").await
}
@@ -1147,7 +1157,7 @@ async fn test_deno_flow(db: Pool<Postgres>) {
concurrent_limit: None,
concurrency_time_window_s: None,
is_trigger: None,
asset_fallback_access_types: None,
assets: None,
}
.into(),
stop_after_if: Default::default(),
@@ -1191,7 +1201,7 @@ async fn test_deno_flow(db: Pool<Postgres>) {
concurrent_limit: None,
concurrency_time_window_s: None,
is_trigger: None,
asset_fallback_access_types: None,
assets: None,
}
.into(),
stop_after_if: Default::default(),
@@ -1321,7 +1331,7 @@ async fn test_deno_flow_same_worker(db: Pool<Postgres>) {
concurrent_limit: None,
concurrency_time_window_s: None,
is_trigger: None,
asset_fallback_access_types: None,
assets: None,
}.into(),
stop_after_if: Default::default(),
@@ -1376,7 +1386,7 @@ async fn test_deno_flow_same_worker(db: Pool<Postgres>) {
concurrent_limit: None,
concurrency_time_window_s: None,
is_trigger: None,
asset_fallback_access_types: None,
assets: None,
}.into(),
stop_after_if: Default::default(),
stop_after_all_iters_if: Default::default(),
@@ -1416,7 +1426,7 @@ async fn test_deno_flow_same_worker(db: Pool<Postgres>) {
concurrent_limit: None,
concurrency_time_window_s: None,
is_trigger: None,
asset_fallback_access_types: None,
assets: None,
}.into(),
stop_after_if: Default::default(),
@@ -1482,7 +1492,7 @@ async fn test_deno_flow_same_worker(db: Pool<Postgres>) {
concurrent_limit: None,
concurrency_time_window_s: None,
is_trigger: None,
asset_fallback_access_types: None,
assets: None,
}.into(),
stop_after_if: Default::default(),
stop_after_all_iters_if: Default::default(),

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
# Default directory
EE_DIR="../windmill-ee-private"
@@ -32,4 +32,4 @@ if [[ "$(uname)" == "Darwin" ]]; then
sed -i '' 's/^#samael = { version="0.0.14", features = \["xmlsec"\] }/samael = { version="0.0.14", features = ["xmlsec"] }/' Cargo.toml
# Comment out the git-based samael dependency
sed -i '' 's/^\(samael = { git="https:\/\/github.com\/njaremko\/samael", rev="464d015e3ae393e4b5dd00b4d6baa1b617de0dd6", features = \["xmlsec"\] }\)/# \1/' Cargo.toml
fi
fi

View File

@@ -32,7 +32,7 @@ http_trigger = ["dep:matchit", "dep:thiserror", "dep:sha1", "dep:constant_time_e
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"]
sqs_trigger = ["dep:aws-sdk-sqs", "dep:aws-sdk-sts", "dep:aws-sdk-sso", "dep:aws-sdk-ssooidc", "dep:thiserror", "dep:aws-config", "dep:backon"]
deno_core = ["dep:deno_core", "dep:deno_error"]
gcp_trigger = ["dep:thiserror", "dep:google-cloud-pubsub", "dep:google-cloud-googleapis", "dep:tonic"]
cloud = ["windmill-common/cloud"]
@@ -138,13 +138,17 @@ 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-sdk-sso = { workspace = true, optional = true }
aws-sdk-ssooidc = { workspace = true, optional = true }
aws-sdk-sts = { workspace = true, optional = true }
rustls = { workspace = 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 }
deno_error = { workspace = true, optional = true }
deno_core = { workspace = true, optional = true }
backon = {workspace = true, optional = true}
[build-dependencies]
deno_core = { workspace = true, optional = true }

View File

@@ -1,7 +1,7 @@
openapi: "3.0.3"
info:
version: 1.507.1
version: 1.515.1
title: Windmill API
contact:
@@ -2792,6 +2792,22 @@ paths:
schema:
type: string
/tokens/list/scopes:
get:
summary: list of available scopes
operationId: ListAvailableScopes
tags:
- token
responses:
"200":
description: list of available scopes
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/ScopeDomain"
/users/tokens/create:
post:
summary: create token
@@ -3099,7 +3115,7 @@ paths:
type: array
items:
$ref: "#/components/schemas/ContextualVariable"
/w/{workspace}/workspaces/get_secondary_storage_names:
get:
summary: get secondary storage names
@@ -3397,6 +3413,9 @@ paths:
cc_client_secret:
type: string
description: "OAuth client secret for resource-level credentials (client_credentials flow only)"
cc_token_url:
type: string
description: "OAuth token URL override for resource-level authentication (client_credentials flow only)"
required:
- expires_in
- client
@@ -3439,6 +3458,9 @@ paths:
cc_client_secret:
type: string
description: "OAuth client secret for resource-level authentication"
cc_token_url:
type: string
description: "OAuth token URL override for resource-level authentication"
required:
- cc_client_id
- cc_client_secret
@@ -5074,6 +5096,10 @@ paths:
in: query
schema:
type: boolean
- name: authed
in: query
schema:
type: boolean
responses:
"200":
description: script details
@@ -7543,6 +7569,10 @@ paths:
in: query
schema:
type: boolean
- name: no_code
in: query
schema:
type: boolean
responses:
"200":
description: job details
@@ -7644,7 +7674,43 @@ paths:
progress:
type: integer
flow_status:
$ref: "#/components/schemas/WorkflowStatusRecord"
$ref: "../../openflow.openapi.yaml#/components/schemas/FlowStatus"
workflow_as_code_status:
$ref: "#/components/schemas/WorkflowStatus"
/w/{workspace}/jobs_u/getupdate_sse/{id}:
get:
summary: get job updates via server-sent events
operationId: getJobUpdatesSSE
tags:
- job
parameters:
- $ref: "#/components/parameters/WorkspaceId"
- $ref: "#/components/parameters/JobId"
- name: running
in: query
schema:
type: boolean
- name: log_offset
in: query
schema:
type: integer
- name: get_progress
in: query
schema:
type: boolean
- name: only_result
in: query
schema:
type: boolean
responses:
"200":
description: server-sent events stream of job updates
content:
text/event-stream:
schema:
type: string
/w/{workspace}/jobs_u/get_log_file/{path}:
get:
@@ -13822,20 +13888,27 @@ components:
type: boolean
on_behalf_of_email:
type: string
fallback_access_types:
assets:
type: array
items:
type: object
required: [path, kind, access_type]
required:
- path
- kind
properties:
path:
type: string
kind:
type: string
enum: [s3object, resource]
enum:
- s3object
- resource
access_type:
type: string
enum: [r, w, rw]
alt_access_type:
type: string
enum: [r, w, rw]
required:
- path
@@ -13995,6 +14068,8 @@ components:
the execution of this script will be permissioned_as and by extension its DT_TOKEN.
flow_status:
$ref: "../../openflow.openapi.yaml#/components/schemas/FlowStatus"
workflow_as_code_status:
$ref: "#/components/schemas/WorkflowStatus"
raw_flow:
$ref: "../../openflow.openapi.yaml#/components/schemas/FlowValue"
is_flow_step:
@@ -14102,6 +14177,8 @@ components:
the execution of this script will be permissioned_as and by extension its DT_TOKEN.
flow_status:
$ref: "../../openflow.openapi.yaml#/components/schemas/FlowStatus"
workflow_as_code_status:
$ref: "#/components/schemas/WorkflowStatus"
raw_flow:
$ref: "../../openflow.openapi.yaml#/components/schemas/FlowValue"
is_flow_step:
@@ -14564,36 +14641,41 @@ components:
- type: object
properties:
object:
type: array
items:
type: object
properties:
key:
type: string
typ:
oneOf:
- type: string
enum:
[
"float",
"int",
"bool",
"email",
"unknown",
"bytes",
"dict",
"datetime",
"sql",
]
- type: object
properties:
str: {}
required: [str]
required:
- key
- typ
type: object
properties:
name:
type: string
props:
type: array
items:
type: object
properties:
key:
type: string
typ:
oneOf:
- type: string
enum:
[
"float",
"int",
"bool",
"email",
"unknown",
"bytes",
"dict",
"datetime",
"sql",
]
- type: object
properties:
str: {}
required: [str]
required:
- key
- typ
required:
- object
- object
- type: object
properties:
list:
@@ -16737,6 +16819,39 @@ components:
- edited_at
- execution_mode
ScopeDefinition:
type: object
properties:
value:
type: string
label:
type: string
description:
type: string
nullable: true
requires_resource_path:
type: boolean
required:
- value
- label
- requires_resource_path
ScopeDomain:
type: object
properties:
name:
type: string
description:
type: string
nullable: true
scopes:
type: array
items:
$ref: "#/components/schemas/ScopeDefinition"
required:
- name
- scopes
ListableRawApp:
type: object
properties:
@@ -17556,7 +17671,6 @@ components:
enum:
- s3object
- resource
- variable
Asset:
type: object
properties:

View File

@@ -13,7 +13,7 @@ use crate::{
db::{ApiAuthed, DB},
resources::get_resource_value_interpolated_internal,
users::{require_owner_of_path, OptAuthed},
utils::WithStarredInfoQuery,
utils::{check_scopes, WithStarredInfoQuery},
webhook_util::{WebhookMessage, WebhookShared},
HTTP_CLIENT,
};
@@ -444,6 +444,7 @@ async fn get_app(
Query(query): Query<WithStarredInfoQuery>,
) -> JsonResult<AppWithLastVersionAndStarred> {
let path = path.to_path();
check_scopes(&authed, || format!("apps:read:{}", path))?;
let mut tx = user_db.begin(&authed).await?;
let app_o = if query.with_starred_info.unwrap_or(false) {
@@ -491,6 +492,7 @@ async fn get_app_lite(
Path((w_id, path)): Path<(String, StripPath)>,
) -> JsonResult<AppWithLastVersion> {
let path = path.to_path();
check_scopes(&authed, || format!("apps:read:{}", path))?;
let mut tx = user_db.begin(&authed).await?;
let app_o = sqlx::query_as::<_, AppWithLastVersion>(
@@ -518,6 +520,7 @@ async fn get_app_w_draft(
Path((w_id, path)): Path<(String, StripPath)>,
) -> JsonResult<AppWithLastVersionAndDraft> {
let path = path.to_path();
check_scopes(&authed, || format!("apps:read:{}", path))?;
let mut tx = user_db.begin(&authed).await?;
let app_o = sqlx::query_as::<_, AppWithLastVersionAndDraft>(
@@ -547,6 +550,8 @@ async fn get_app_history(
Extension(user_db): Extension<UserDB>,
Path((w_id, path)): Path<(String, StripPath)>,
) -> JsonResult<Vec<AppHistory>> {
let path = path.to_path();
check_scopes(&authed, || format!("apps:read:{}", &path))?;
let mut tx = user_db.begin(&authed).await?;
let query_result = sqlx::query!(
"SELECT a.id as app_id, av.id as version_id, dm.deployment_msg as deployment_msg
@@ -554,7 +559,7 @@ async fn get_app_history(
WHERE a.workspace_id = $1 AND a.path = $2
ORDER BY created_at DESC",
w_id,
path.to_path(),
path,
).fetch_all(&mut *tx).await?;
tx.commit().await?;
@@ -574,6 +579,8 @@ async fn get_latest_version(
Extension(user_db): Extension<UserDB>,
Path((w_id, path)): Path<(String, StripPath)>,
) -> JsonResult<Option<AppHistory>> {
let path = path.to_path();
check_scopes(&authed, || format!("apps:read:{}", path))?;
let mut tx = user_db.begin(&authed).await?;
let row = sqlx::query!(
"SELECT a.id as app_id, av.id as version_id, dm.deployment_msg as deployment_msg
@@ -581,7 +588,7 @@ async fn get_latest_version(
WHERE a.workspace_id = $1 AND a.path = $2
ORDER BY created_at DESC",
w_id,
path.to_path(),
path,
).fetch_optional(&mut *tx).await?;
tx.commit().await?;
@@ -609,17 +616,19 @@ async fn update_app_history(
.fetch_optional(&mut *tx)
.await?;
if app_path.is_none() {
let Some(app_path) = app_path else {
tx.commit().await?;
return Err(Error::NotFound(
format!("App with ID {app_id} not found").to_string(),
));
}
};
check_scopes(&authed, || format!("apps:write:{}", &app_path))?;
sqlx::query!(
"INSERT INTO deployment_metadata (workspace_id, path, app_version, deployment_msg) VALUES ($1, $2, $3, $4) ON CONFLICT (workspace_id, path, app_version) WHERE app_version IS NOT NULL DO UPDATE SET deployment_msg = $4",
w_id,
app_path.unwrap(),
app_path,
app_version,
app_history_update.deployment_msg,
)
@@ -664,6 +673,9 @@ async fn get_app_by_id(
tx.commit().await?;
let app = not_found_if_none(app_o, "App", id.to_string())?;
check_scopes(&authed, || format!("apps:read:{}", &app.path))?;
Ok(Json(app))
}
@@ -756,6 +768,7 @@ async fn get_secret_id(
Path((w_id, path)): Path<(String, StripPath)>,
) -> Result<String> {
let path = path.to_path();
check_scopes(&authed, || format!("apps:read:{}", path))?;
let mut tx = user_db.begin(&authed).await?;
let id_o = sqlx::query_scalar!(
@@ -861,6 +874,8 @@ async fn create_app_raw<'a>(
)
.await?;
check_scopes(&authed, || format!("apps:write:{}", path))?;
webhook.send_message(
w_id.clone(),
WebhookMessage::CreateApp { workspace: w_id, path: path.clone() },
@@ -899,6 +914,8 @@ async fn create_app(
Json(app): Json<CreateApp>,
) -> Result<(StatusCode, String)> {
let path = app.path.clone();
check_scopes(&authed, || format!("apps:write:{}", &path))?;
let (new_tx, _path, _id) = create_app_internal(authed, db, user_db, &w_id, false, app).await?;
new_tx.commit().await?;
@@ -1101,6 +1118,7 @@ async fn delete_app(
Path((w_id, path)): Path<(String, StripPath)>,
) -> Result<String> {
let path = path.to_path();
check_scopes(&authed, || format!("apps:write:{}", path))?;
if path == "g/all/setup_app" && w_id == "admins" {
return Err(Error::BadRequest(
@@ -1184,6 +1202,7 @@ async fn update_app(
) -> Result<String> {
// create_app_internal(authed, user_db, db, &w_id, &mut app).await?;
let path = path.to_path();
check_scopes(&authed, || format!("apps:write:{}", path))?;
let opath = path.to_string();
let (new_tx, npath, _v_id) =
update_app_internal(authed, db, user_db, &w_id, path, false, ns).await?;
@@ -1210,6 +1229,7 @@ async fn update_app_raw<'a>(
multipart: Multipart,
) -> Result<String> {
let path = path.to_path();
check_scopes(&authed, || format!("apps:write:{}", path))?;
let opath = path.to_string();
let (npath, _id) = process_app_multipart!(
authed,
@@ -2421,10 +2441,9 @@ async fn exists_app(
Extension(db): Extension<DB>,
Path((w_id, path)): Path<(String, StripPath)>,
) -> JsonResult<bool> {
let path = path.to_path();
let exists = sqlx::query_scalar!(
"SELECT EXISTS(SELECT 1 FROM app WHERE path = $1 AND workspace_id = $2)",
path,
path.to_path(),
w_id
)
.fetch_one(&db)

View File

@@ -22,6 +22,7 @@ use tokio::sync::RwLock;
use windmill_common::{
auth::{get_folders_for_user, get_groups_for_user, JWTAuthClaims, TOKEN_PREFIX_LEN},
error::Error,
jwt,
users::{COOKIE_NAME, SUPERADMIN_SECRET_EMAIL},
};
@@ -218,7 +219,9 @@ impl AuthCache {
folders,
scopes: None,
username_override,
token_prefix: Some(token[0..TOKEN_PREFIX_LEN].to_string()),
token_prefix: Some(
token[0..TOKEN_PREFIX_LEN].to_string(),
),
})
} else {
let groups = vec![name.to_string()];
@@ -240,7 +243,9 @@ impl AuthCache {
folders,
scopes: None,
username_override,
token_prefix: Some(token[0..TOKEN_PREFIX_LEN].to_string()),
token_prefix: Some(
token[0..TOKEN_PREFIX_LEN].to_string(),
),
})
}
} else {
@@ -303,7 +308,9 @@ impl AuthCache {
folders,
scopes,
username_override,
token_prefix: Some(token[0..TOKEN_PREFIX_LEN].to_string()),
token_prefix: Some(
token[0..TOKEN_PREFIX_LEN].to_string(),
),
})
}
None if super_admin => Some(ApiAuthed {
@@ -315,7 +322,9 @@ impl AuthCache {
folders: vec![],
scopes,
username_override,
token_prefix: Some(token[0..TOKEN_PREFIX_LEN].to_string()),
token_prefix: Some(
token[0..TOKEN_PREFIX_LEN].to_string(),
),
}),
None => None,
}
@@ -491,6 +500,33 @@ where
}
}
pub fn transform_old_scope_to_new_scope(scopes: Option<&mut Vec<String>>) {
if let Some(scopes) = scopes {
for scope in scopes.iter_mut() {
if scope.starts_with("run:") {
let (_, part_scope) = scope.split_once(":").unwrap();
if let Some((kind, path)) = part_scope.split_once("/") {
//appending a 's' as runnable kind is singular while new scope format expect it to be plural
*scope = format!("jobs:run:{}s:{}", kind, path);
}
} else if scope.starts_with("jobs:") {
// Map old jobs scopes to new format
let new_scope = match scope.as_str() {
"jobs:listjobs" => "jobs:read",
"jobs:runscript" => "jobs:run:scripts",
"jobs:runflow" => "jobs:run:flows",
"jobs:resumeflow" => "jobs:run:flows",
"jobs:deletejob" => "jobs:write",
_ => continue,
};
*scope = new_scope.to_string();
}
}
}
}
fn maybe_get_workspace_id_from_path(path_vec: &[&str]) -> Option<String> {
let workspace_id = if path_vec.len() >= 4 && path_vec[0] == "" && path_vec[2] == "w" {
Some(path_vec[3].to_owned())
@@ -517,7 +553,7 @@ impl<S> FromRequestParts<S> for ApiAuthed
where
S: Send + Sync,
{
type Rejection = (StatusCode, String);
type Rejection = Error;
async fn from_request_parts(
parts: &mut Parts,
@@ -538,7 +574,6 @@ where
} else {
extract_token(parts, state).await
};
if let Some(token) = token_o {
if let Ok(Extension(cache)) =
Extension::<Arc<AuthCache>>::from_request_parts(parts, state).await
@@ -551,21 +586,22 @@ where
let path_vec: Vec<&str> = original_uri.path().split("/").collect();
let workspace_id = maybe_get_workspace_id_from_path(&path_vec);
if let Some(authed) = cache.get_authed(workspace_id.clone(), &token).await {
if authed.scopes.as_ref().is_some_and(|scopes| {
scopes
.iter()
.any(|s| s.starts_with("jobs:") || s.starts_with("run:"))
}) && (path_vec.len() < 3
|| (path_vec[4] != "jobs" && path_vec[4] != "jobs_u"))
{
BRUTE_FORCE_COUNTER.increment().await;
return Err((
StatusCode::UNAUTHORIZED,
format!("Unauthorized scoped token: {:?}", authed.scopes),
));
}
if let Some(mut authed) = cache.get_authed(workspace_id.clone(), &token).await {
if authed.scopes.is_some() {
transform_old_scope_to_new_scope(authed.scopes.as_mut());
let path = original_uri.path();
let method = parts.method.as_str();
if let Err(err) = crate::scopes::check_scopes_for_route(
authed.scopes.as_deref(),
path,
method,
) {
BRUTE_FORCE_COUNTER.increment().await;
return Err(err);
}
}
parts.extensions.insert(authed.clone());
Span::current().record("username", &authed.username.as_str());
@@ -579,7 +615,7 @@ where
}
}
BRUTE_FORCE_COUNTER.increment().await;
Err((StatusCode::UNAUTHORIZED, "Unauthorized".to_owned()))
Err(Error::NotAuthorized("Unauthorized".to_string()))
}
}

View File

@@ -1,9 +1,11 @@
use crate::db::{ApiAuthed, DB};
use crate::jobs::{
filter_list_completed_query, filter_list_queue_query, Job, ListCompletedQuery, ListQueueQuery,
UnifiedJob,
use crate::{
db::{ApiAuthed, DB},
jobs::{
filter_list_completed_query, filter_list_queue_query, Job, ListCompletedQuery,
ListQueueQuery, UnifiedJob,
},
utils::check_scopes,
};
use crate::users::check_scopes;
use axum::extract::Path;
use axum::routing::{delete, get};
use axum::{extract::Query, Extension, Json};
@@ -144,7 +146,7 @@ async fn get_concurrent_intervals(
Query(iq): Query<ExtendedJobsParams>,
Query(lq): Query<ListCompletedQuery>,
) -> JsonResult<ExtendedJobs> {
check_scopes(&authed, || format!("jobs:listjobs"))?;
check_scopes(&authed, || format!("jobs:read"))?;
if lq.success.is_some() && lq.running.is_some_and(|x| x) {
return Err(error::Error::BadRequest(

View File

@@ -18,10 +18,11 @@ use windmill_audit::audit_oss::audit_log;
use windmill_audit::ActionKind;
use windmill_common::{
error::{self},
worker::MIN_PERIODIC_SCRIPT_INTERVAL_SECONDS,
DB,
};
use crate::{db::ApiAuthed, utils::{require_devops_role}};
use crate::{db::ApiAuthed, utils::require_devops_role};
pub fn global_service() -> Router {
Router::new()
@@ -129,6 +130,42 @@ async fn update_config(
));
}
if name.starts_with("worker__") {
let periodic_script_bash = config
.get("periodic_script_bash")
.filter(|v| !v.is_null())
.and_then(|v| v.as_str())
.filter(|s| !s.is_empty());
let periodic_script_interval = config
.get("periodic_script_interval_seconds")
.filter(|v| !v.is_null());
match (periodic_script_bash, periodic_script_interval) {
(Some(_), Some(interval_value)) => {
if let Some(interval) = interval_value.as_u64() {
if interval < MIN_PERIODIC_SCRIPT_INTERVAL_SECONDS {
return Err(error::Error::BadRequest(format!(
"Periodic script interval must be at least {} seconds, got {} seconds",
MIN_PERIODIC_SCRIPT_INTERVAL_SECONDS, interval
)));
}
} else {
return Err(error::Error::BadRequest(
"Periodic script interval must be a valid number".to_string(),
));
}
}
(Some(_), None) => {
return Err(error::Error::BadRequest(
"Periodic script interval must be specified when periodic script is configured"
.to_string(),
));
}
_ => {}
}
}
let mut tx = db.begin().await?;
sqlx::query!(
"INSERT INTO config (name, config) VALUES ($1, $2) ON CONFLICT (name) DO UPDATE SET config = $2",

Some files were not shown because too many files have changed in this diff Show More