windmill-cli 1.589.3 → 1.591.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/esm/deps/jsr.io/@windmill-labs/shared-utils/{1.0.10 → 1.0.11}/lib.es.js +4 -4
  2. package/esm/deps.js +1 -1
  3. package/esm/gen/core/OpenAPI.js +1 -1
  4. package/esm/gen/services.gen.js +167 -27
  5. package/esm/src/commands/app/app_metadata.js +81 -47
  6. package/esm/src/commands/app/apps.js +2 -0
  7. package/esm/src/commands/app/bundle.js +6 -2
  8. package/esm/src/commands/app/dev.js +40 -14
  9. package/esm/src/commands/app/lint.js +159 -0
  10. package/esm/src/commands/app/raw_apps.js +169 -24
  11. package/esm/src/commands/init/init.js +8 -0
  12. package/esm/src/commands/resource-type/resource-type.js +29 -2
  13. package/esm/src/commands/script/script.js +11 -0
  14. package/esm/src/commands/sync/sync.js +55 -21
  15. package/esm/src/main.js +1 -1
  16. package/esm/src/utils/resource_types.js +32 -0
  17. package/esm/src/utils/utils.js +8 -0
  18. package/esm/windmill-utils-internal/src/path-utils/path-assigner.js +78 -0
  19. package/package.json +1 -1
  20. package/types/bootstrap/common.d.ts +12 -0
  21. package/types/bootstrap/common.d.ts.map +1 -1
  22. package/types/deps/jsr.io/@windmill-labs/shared-utils/{1.0.10 → 1.0.11}/lib.es.d.ts.map +1 -1
  23. package/types/deps.d.ts +1 -1
  24. package/types/gen/services.gen.d.ts +82 -16
  25. package/types/gen/services.gen.d.ts.map +1 -1
  26. package/types/gen/types.gen.d.ts +582 -62
  27. package/types/gen/types.gen.d.ts.map +1 -1
  28. package/types/src/commands/app/app_metadata.d.ts +1 -1
  29. package/types/src/commands/app/app_metadata.d.ts.map +1 -1
  30. package/types/src/commands/app/apps.d.ts.map +1 -1
  31. package/types/src/commands/app/bundle.d.ts.map +1 -1
  32. package/types/src/commands/app/dev.d.ts.map +1 -1
  33. package/types/src/commands/app/lint.d.ts +12 -0
  34. package/types/src/commands/app/lint.d.ts.map +1 -0
  35. package/types/src/commands/app/metadata.d.ts +2 -3
  36. package/types/src/commands/app/metadata.d.ts.map +1 -1
  37. package/types/src/commands/app/raw_apps.d.ts +26 -1
  38. package/types/src/commands/app/raw_apps.d.ts.map +1 -1
  39. package/types/src/commands/init/init.d.ts.map +1 -1
  40. package/types/src/commands/resource-type/resource-type.d.ts +3 -1
  41. package/types/src/commands/resource-type/resource-type.d.ts.map +1 -1
  42. package/types/src/commands/script/script.d.ts +5 -0
  43. package/types/src/commands/script/script.d.ts.map +1 -1
  44. package/types/src/commands/sync/sync.d.ts +1 -1
  45. package/types/src/commands/sync/sync.d.ts.map +1 -1
  46. package/types/src/main.d.ts +1 -1
  47. package/types/src/utils/resource_types.d.ts +3 -0
  48. package/types/src/utils/resource_types.d.ts.map +1 -0
  49. package/types/src/utils/utils.d.ts +2 -0
  50. package/types/src/utils/utils.d.ts.map +1 -1
  51. package/types/windmill-utils-internal/src/gen/types.gen.d.ts +582 -62
  52. package/types/windmill-utils-internal/src/gen/types.gen.d.ts.map +1 -1
  53. package/types/windmill-utils-internal/src/path-utils/path-assigner.d.ts +22 -0
  54. package/types/windmill-utils-internal/src/path-utils/path-assigner.d.ts.map +1 -1
  55. /package/types/deps/jsr.io/@windmill-labs/shared-utils/{1.0.10 → 1.0.11}/lib.es.d.ts +0 -0
@@ -1305,7 +1305,7 @@ function computeS3FileInputPolicy(c, L) {
1305
1305
  function isPartialS3Object(c) {
1306
1306
  return typeof c == "object" && !!c && typeof c.s3 == "string";
1307
1307
  }
1308
- function computeS3ImageViewerPolicy(c) {
1308
+ function computeS3FileViewerPolicy(c) {
1309
1309
  if (c.source.type === "uploadS3" && isPartialS3Object(c.source.value))
1310
1310
  return {
1311
1311
  s3_path: c.source.value.s3,
@@ -1400,9 +1400,9 @@ async function updatePolicy(c, L) {
1400
1400
  else
1401
1401
  return !1;
1402
1402
  }) !== -1 && V.push(computeWorkspaceS3FileInputPolicy());
1403
- let H = R.filter((c) => c.data.type === "imagecomponent").map((c) => {
1403
+ let H = R.filter((c) => c.data.type === "imagecomponent" || c.data.type === "pdfcomponent" || c.data.type === "downloadcomponent").map((c) => {
1404
1404
  let L = c.data.configuration;
1405
- return computeS3ImageViewerPolicy(L);
1405
+ return computeS3FileViewerPolicy(L);
1406
1406
  }).filter(Boolean);
1407
1407
  return {
1408
1408
  ...L ?? {},
@@ -1515,7 +1515,7 @@ async function processRunnable(c, L, R) {
1515
1515
  allow_user_resources: B
1516
1516
  }];
1517
1517
  }
1518
- var rawAppWmillTs_exports = /* @__PURE__ */ __export({ default: () => rawAppWmillTs_default }), rawAppWmillTs_default = "let reqs: Record<string, any> = {}\n\nfunction doRequest(type: string, o: object) {\n return new Promise((resolve, reject) => {\n const reqId = Math.random().toString(36)\n reqs[reqId] = { resolve, reject }\n parent.postMessage({ ...o, type, reqId }, '*')\n })\n}\n\nexport const backend = new Proxy(\n {},\n {\n get(_, runnable_id: string) {\n return (v: any) => {\n return doRequest('backend', { runnable_id, v })\n }\n }\n })\n\nexport const backendAsync = new Proxy(\n {},\n {\n get(_, runnable_id: string) {\n return (v: any) => {\n return doRequest('backendAsync', { runnable_id, v })\n }\n }\n })\n\nexport function waitJob(jobId: string) {\n return doRequest('waitJob', { jobId })\n}\n\nexport function getJob(jobId: string) {\n return doRequest('getJob', { jobId })\n}\n\n\nwindow.addEventListener('message', (e) => {\n if (e.data.type == 'runBgRes' || e.data.type == 'runBgAsyncRes') {\n console.log('Message from parent backend', e.data)\n let job = reqs[e.data.reqId]\n if (job) {\n const result = e.data.result\n if (e.data.error) {\n job.reject(new Error(result.stack ?? result.message))\n } else {\n job.resolve(result)\n }\n } else {\n console.error('No job found for', e.data.reqId)\n }\n }\n})";
1518
+ var rawAppWmillTs_exports = /* @__PURE__ */ __export({ default: () => rawAppWmillTs_default }), rawAppWmillTs_default = "let reqs: Record<string, any> = {}\n\nfunction doRequest(type: string, o: object) {\n return new Promise((resolve, reject) => {\n const reqId = Math.random().toString(36)\n reqs[reqId] = { resolve, reject }\n parent.postMessage({ ...o, type, reqId }, '*')\n })\n}\n\nexport const backend = new Proxy(\n {},\n {\n get(_, runnable_id: string) {\n return (v: any) => {\n return doRequest('backend', { runnable_id, v })\n }\n }\n })\n\nexport const backendAsync = new Proxy(\n {},\n {\n get(_, runnable_id: string) {\n return (v: any) => {\n return doRequest('backendAsync', { runnable_id, v })\n }\n }\n })\n\nexport function waitJob(jobId: string) {\n return doRequest('waitJob', { jobId })\n}\n\nexport function getJob(jobId: string) {\n return doRequest('getJob', { jobId })\n}\n\n\nwindow.addEventListener('message', (e) => {\n if (e.data.type == 'backendRes' || e.data.type == 'backendAsyncRes') {\n console.log('Message from parent backend', e.data)\n let job = reqs[e.data.reqId]\n if (job) {\n const result = e.data.result\n if (e.data.error) {\n job.reject(new Error(result.stack ?? result.message))\n } else {\n job.resolve(result)\n }\n } else {\n console.error('No job found for', e.data.reqId)\n }\n }\n})";
1519
1519
  function capitalize(c) {
1520
1520
  return c ? c.charAt(0).toUpperCase() + c.slice(1) : "";
1521
1521
  }
package/esm/deps.js CHANGED
@@ -48,7 +48,7 @@ export { WebSocketServer, WebSocket } from "ws";
48
48
  export * as getPort from "get-port";
49
49
  export * as open from "open";
50
50
  export * as esMain from "es-main";
51
- export * as windmillUtils from "./deps/jsr.io/@windmill-labs/shared-utils/1.0.10/lib.es.js";
51
+ export * as windmillUtils from "./deps/jsr.io/@windmill-labs/shared-utils/1.0.11/lib.es.js";
52
52
  import { OpenAPI } from "./gen/index.js";
53
53
  export function setClient(token, baseUrl) {
54
54
  if (baseUrl === undefined) {
@@ -32,7 +32,7 @@ export const OpenAPI = {
32
32
  PASSWORD: undefined,
33
33
  TOKEN: getEnv("WM_TOKEN"),
34
34
  USERNAME: undefined,
35
- VERSION: '1.589.3',
35
+ VERSION: '1.591.0',
36
36
  WITH_CREDENTIALS: true,
37
37
  interceptors: {
38
38
  request: new Interceptors(),
@@ -34,6 +34,24 @@ export const getLicenseId = () => {
34
34
  url: '/ee_license'
35
35
  });
36
36
  };
37
+ /**
38
+ * query Windmill AI documentation assistant (EE only)
39
+ * @param data The data for the request.
40
+ * @param data.requestBody query to send to the AI documentation assistant
41
+ * @returns unknown AI documentation assistant response
42
+ * @throws ApiError
43
+ */
44
+ export const queryDocumentation = (data) => {
45
+ return __request(OpenAPI, {
46
+ method: 'POST',
47
+ url: '/inkeep',
48
+ body: data.requestBody,
49
+ mediaType: 'application/json',
50
+ errors: {
51
+ 403: 'Enterprise Edition required'
52
+ }
53
+ });
54
+ };
37
55
  /**
38
56
  * get openapi yaml spec
39
57
  * @returns string openapi yaml file content
@@ -569,30 +587,44 @@ export const existsUsername = (data) => {
569
587
  });
570
588
  };
571
589
  /**
572
- * Returns the set-up statuses of ducklake instance catalog dbs
573
- * @returns DucklakeInstanceCatalogDbStatus Statuses of all ducklake instance catalog dbs
590
+ * Refreshes the password for the custom_instance_user
591
+ * @returns unknown Success
574
592
  * @throws ApiError
575
593
  */
576
- export const getDucklakeInstanceCatalogDbStatus = () => {
594
+ export const refreshCustomInstanceUserPwd = () => {
577
595
  return __request(OpenAPI, {
578
596
  method: 'POST',
579
- url: '/settings/get_ducklake_instance_catalog_db_status'
597
+ url: '/settings/refresh_custom_instance_user_pwd'
580
598
  });
581
599
  };
582
600
  /**
583
- * Runs CREATE DATABASE on the Windmill Postgres and grants access to the ducklake_user
601
+ * Returns the set-up statuses of custom instance pg databases
602
+ * @returns CustomInstanceDb Statuses of all custom instance dbs
603
+ * @throws ApiError
604
+ */
605
+ export const listCustomInstanceDbs = () => {
606
+ return __request(OpenAPI, {
607
+ method: 'POST',
608
+ url: '/settings/list_custom_instance_pg_databases'
609
+ });
610
+ };
611
+ /**
612
+ * Runs CREATE DATABASE on the Windmill Postgres and grants access to the custom_instance_user
584
613
  * @param data The data for the request.
585
614
  * @param data.name The name of the database to create
586
- * @returns DucklakeInstanceCatalogDbStatus status
615
+ * @param data.requestBody
616
+ * @returns CustomInstanceDb status
587
617
  * @throws ApiError
588
618
  */
589
- export const setupDucklakeCatalogDb = (data) => {
619
+ export const setupCustomInstanceDb = (data) => {
590
620
  return __request(OpenAPI, {
591
621
  method: 'POST',
592
- url: '/settings/setup_ducklake_catalog_db/{name}',
622
+ url: '/settings/setup_custom_instance_pg_database/{name}',
593
623
  path: {
594
624
  name: data.name
595
- }
625
+ },
626
+ body: data.requestBody,
627
+ mediaType: 'application/json'
596
628
  });
597
629
  };
598
630
  /**
@@ -1891,6 +1923,22 @@ export const listDucklakes = (data) => {
1891
1923
  }
1892
1924
  });
1893
1925
  };
1926
+ /**
1927
+ * list Datatables
1928
+ * @param data The data for the request.
1929
+ * @param data.workspace
1930
+ * @returns string status
1931
+ * @throws ApiError
1932
+ */
1933
+ export const listDataTables = (data) => {
1934
+ return __request(OpenAPI, {
1935
+ method: 'GET',
1936
+ url: '/w/{workspace}/workspaces/list_datatables',
1937
+ path: {
1938
+ workspace: data.workspace
1939
+ }
1940
+ });
1941
+ };
1894
1942
  /**
1895
1943
  * edit ducklake settings
1896
1944
  * @param data The data for the request.
@@ -1910,6 +1958,25 @@ export const editDucklakeConfig = (data) => {
1910
1958
  mediaType: 'application/json'
1911
1959
  });
1912
1960
  };
1961
+ /**
1962
+ * edit datatable settings
1963
+ * @param data The data for the request.
1964
+ * @param data.workspace
1965
+ * @param data.requestBody DataTable settings
1966
+ * @returns unknown status
1967
+ * @throws ApiError
1968
+ */
1969
+ export const editDataTableConfig = (data) => {
1970
+ return __request(OpenAPI, {
1971
+ method: 'POST',
1972
+ url: '/w/{workspace}/workspaces/edit_datatable_config',
1973
+ path: {
1974
+ workspace: data.workspace
1975
+ },
1976
+ body: data.requestBody,
1977
+ mediaType: 'application/json'
1978
+ });
1979
+ };
1913
1980
  /**
1914
1981
  * edit workspace git sync settings
1915
1982
  * @param data The data for the request.
@@ -2306,6 +2373,7 @@ export const listTokens = (data = {}) => {
2306
2373
  * @param data The data for the request.
2307
2374
  * @param data.workspace
2308
2375
  * @param data.audience
2376
+ * @param data.expiresIn
2309
2377
  * @returns string new oidc token
2310
2378
  * @throws ApiError
2311
2379
  */
@@ -2316,6 +2384,9 @@ export const getOidcToken = (data) => {
2316
2384
  path: {
2317
2385
  workspace: data.workspace,
2318
2386
  audience: data.audience
2387
+ },
2388
+ query: {
2389
+ expires_in: data.expiresIn
2319
2390
  }
2320
2391
  });
2321
2392
  };
@@ -6108,6 +6179,25 @@ export const runScriptPreview = (data) => {
6108
6179
  mediaType: 'application/json'
6109
6180
  });
6110
6181
  };
6182
+ /**
6183
+ * run script preview without starting a new job
6184
+ * @param data The data for the request.
6185
+ * @param data.workspace
6186
+ * @param data.requestBody preview
6187
+ * @returns unknown script result
6188
+ * @throws ApiError
6189
+ */
6190
+ export const runScriptPreviewInline = (data) => {
6191
+ return __request(OpenAPI, {
6192
+ method: 'POST',
6193
+ url: '/w/{workspace}/jobs/run_inline/preview',
6194
+ path: {
6195
+ workspace: data.workspace
6196
+ },
6197
+ body: data.requestBody,
6198
+ mediaType: 'application/json'
6199
+ });
6200
+ };
6111
6201
  /**
6112
6202
  * run script preview and wait for result
6113
6203
  * @param data The data for the request.
@@ -6253,6 +6343,8 @@ export const runDynamicSelect = (data) => {
6253
6343
  * @param data.scriptPathExact mask to filter exact matching path
6254
6344
  * @param data.scriptPathStart mask to filter matching starting path
6255
6345
  * @param data.schedulePath mask to filter by schedule path
6346
+ * @param data.triggerPath mask to filter by trigger path
6347
+ * @param data.triggerKind trigger kind (schedule, http, websocket...)
6256
6348
  * @param data.scriptHash mask to filter exact matching path
6257
6349
  * @param data.startedBefore filter on started before (inclusive) timestamp
6258
6350
  * @param data.startedAfter filter on started after (exclusive) timestamp
@@ -6287,6 +6379,8 @@ export const listQueue = (data) => {
6287
6379
  script_path_exact: data.scriptPathExact,
6288
6380
  script_path_start: data.scriptPathStart,
6289
6381
  schedule_path: data.schedulePath,
6382
+ trigger_path: data.triggerPath,
6383
+ trigger_kind: data.triggerKind,
6290
6384
  script_hash: data.scriptHash,
6291
6385
  started_before: data.startedBefore,
6292
6386
  started_after: data.startedAfter,
@@ -6535,6 +6629,52 @@ export const cancelSelection = (data) => {
6535
6629
  mediaType: 'application/json'
6536
6630
  });
6537
6631
  };
6632
+ /**
6633
+ * resume all suspended jobs for a specific trigger
6634
+ * @param data The data for the request.
6635
+ * @param data.workspace
6636
+ * @param data.triggerKind The kind of trigger
6637
+ * @param data.triggerPath The path of the trigger (can contain forward slashes)
6638
+ * @param data.requestBody Optional list of job IDs to reassign
6639
+ * @returns string confirmation message
6640
+ * @throws ApiError
6641
+ */
6642
+ export const resumeSuspendedTriggerJobs = (data) => {
6643
+ return __request(OpenAPI, {
6644
+ method: 'POST',
6645
+ url: '/w/{workspace}/trigger/{trigger_kind}/resume_suspended_trigger_jobs/{trigger_path}',
6646
+ path: {
6647
+ workspace: data.workspace,
6648
+ trigger_kind: data.triggerKind,
6649
+ trigger_path: data.triggerPath
6650
+ },
6651
+ body: data.requestBody,
6652
+ mediaType: 'application/json'
6653
+ });
6654
+ };
6655
+ /**
6656
+ * cancel all suspended jobs for a specific trigger
6657
+ * @param data The data for the request.
6658
+ * @param data.workspace
6659
+ * @param data.triggerKind The kind of trigger
6660
+ * @param data.triggerPath The path of the trigger (can contain forward slashes)
6661
+ * @param data.requestBody Optional list of job IDs to cancel
6662
+ * @returns string confirmation message
6663
+ * @throws ApiError
6664
+ */
6665
+ export const cancelSuspendedTriggerJobs = (data) => {
6666
+ return __request(OpenAPI, {
6667
+ method: 'POST',
6668
+ url: '/w/{workspace}/trigger/{trigger_kind}/cancel_suspended_trigger_jobs/{trigger_path}',
6669
+ path: {
6670
+ workspace: data.workspace,
6671
+ trigger_kind: data.triggerKind,
6672
+ trigger_path: data.triggerPath
6673
+ },
6674
+ body: data.requestBody,
6675
+ mediaType: 'application/json'
6676
+ });
6677
+ };
6538
6678
  /**
6539
6679
  * list all completed jobs
6540
6680
  * @param data The data for the request.
@@ -7941,10 +8081,10 @@ export const existsRoute = (data) => {
7941
8081
  * @returns string http trigger enable/disable
7942
8082
  * @throws ApiError
7943
8083
  */
7944
- export const setHttpTriggerEnabled = (data) => {
8084
+ export const setHttpTriggerMode = (data) => {
7945
8085
  return __request(OpenAPI, {
7946
8086
  method: 'POST',
7947
- url: '/w/{workspace}/http_triggers/setenabled/{path}',
8087
+ url: '/w/{workspace}/http_triggers/setmode/{path}',
7948
8088
  path: {
7949
8089
  workspace: data.workspace,
7950
8090
  path: data.path
@@ -8084,10 +8224,10 @@ export const existsWebsocketTrigger = (data) => {
8084
8224
  * @returns string websocket trigger enabled set
8085
8225
  * @throws ApiError
8086
8226
  */
8087
- export const setWebsocketTriggerEnabled = (data) => {
8227
+ export const setWebsocketTriggerMode = (data) => {
8088
8228
  return __request(OpenAPI, {
8089
8229
  method: 'POST',
8090
- url: '/w/{workspace}/websocket_triggers/setenabled/{path}',
8230
+ url: '/w/{workspace}/websocket_triggers/setmode/{path}',
8091
8231
  path: {
8092
8232
  workspace: data.workspace,
8093
8233
  path: data.path
@@ -8246,10 +8386,10 @@ export const existsKafkaTrigger = (data) => {
8246
8386
  * @returns string kafka trigger enabled set
8247
8387
  * @throws ApiError
8248
8388
  */
8249
- export const setKafkaTriggerEnabled = (data) => {
8389
+ export const setKafkaTriggerMode = (data) => {
8250
8390
  return __request(OpenAPI, {
8251
8391
  method: 'POST',
8252
- url: '/w/{workspace}/kafka_triggers/setenabled/{path}',
8392
+ url: '/w/{workspace}/kafka_triggers/setmode/{path}',
8253
8393
  path: {
8254
8394
  workspace: data.workspace,
8255
8395
  path: data.path
@@ -8408,10 +8548,10 @@ export const existsNatsTrigger = (data) => {
8408
8548
  * @returns string nats trigger enabled set
8409
8549
  * @throws ApiError
8410
8550
  */
8411
- export const setNatsTriggerEnabled = (data) => {
8551
+ export const setNatsTriggerMode = (data) => {
8412
8552
  return __request(OpenAPI, {
8413
8553
  method: 'POST',
8414
- url: '/w/{workspace}/nats_triggers/setenabled/{path}',
8554
+ url: '/w/{workspace}/nats_triggers/setmode/{path}',
8415
8555
  path: {
8416
8556
  workspace: data.workspace,
8417
8557
  path: data.path
@@ -8570,10 +8710,10 @@ export const existsSqsTrigger = (data) => {
8570
8710
  * @returns string sqs trigger enabled set
8571
8711
  * @throws ApiError
8572
8712
  */
8573
- export const setSqsTriggerEnabled = (data) => {
8713
+ export const setSqsTriggerMode = (data) => {
8574
8714
  return __request(OpenAPI, {
8575
8715
  method: 'POST',
8576
- url: '/w/{workspace}/sqs_triggers/setenabled/{path}',
8716
+ url: '/w/{workspace}/sqs_triggers/setmode/{path}',
8577
8717
  path: {
8578
8718
  workspace: data.workspace,
8579
8719
  path: data.path
@@ -8732,10 +8872,10 @@ export const existsMqttTrigger = (data) => {
8732
8872
  * @returns string mqtt trigger enabled set
8733
8873
  * @throws ApiError
8734
8874
  */
8735
- export const setMqttTriggerEnabled = (data) => {
8875
+ export const setMqttTriggerMode = (data) => {
8736
8876
  return __request(OpenAPI, {
8737
8877
  method: 'POST',
8738
- url: '/w/{workspace}/mqtt_triggers/setenabled/{path}',
8878
+ url: '/w/{workspace}/mqtt_triggers/setmode/{path}',
8739
8879
  path: {
8740
8880
  workspace: data.workspace,
8741
8881
  path: data.path
@@ -8894,10 +9034,10 @@ export const existsGcpTrigger = (data) => {
8894
9034
  * @returns string gcp trigger enabled set
8895
9035
  * @throws ApiError
8896
9036
  */
8897
- export const setGcpTriggerEnabled = (data) => {
9037
+ export const setGcpTriggerMode = (data) => {
8898
9038
  return __request(OpenAPI, {
8899
9039
  method: 'POST',
8900
- url: '/w/{workspace}/gcp_triggers/setenabled/{path}',
9040
+ url: '/w/{workspace}/gcp_triggers/setmode/{path}',
8901
9041
  path: {
8902
9042
  workspace: data.workspace,
8903
9043
  path: data.path
@@ -9353,10 +9493,10 @@ export const existsPostgresTrigger = (data) => {
9353
9493
  * @returns string postgres trigger enabled set
9354
9494
  * @throws ApiError
9355
9495
  */
9356
- export const setPostgresTriggerEnabled = (data) => {
9496
+ export const setPostgresTriggerMode = (data) => {
9357
9497
  return __request(OpenAPI, {
9358
9498
  method: 'POST',
9359
- url: '/w/{workspace}/postgres_triggers/setenabled/{path}',
9499
+ url: '/w/{workspace}/postgres_triggers/setmode/{path}',
9360
9500
  path: {
9361
9501
  workspace: data.workspace,
9362
9502
  path: data.path
@@ -9534,10 +9674,10 @@ export const existsEmailLocalPart = (data) => {
9534
9674
  * @returns string email trigger enable/disable
9535
9675
  * @throws ApiError
9536
9676
  */
9537
- export const setEmailTriggerEnabled = (data) => {
9677
+ export const setEmailTriggerMode = (data) => {
9538
9678
  return __request(OpenAPI, {
9539
9679
  method: 'POST',
9540
- url: '/w/{workspace}/email_triggers/setenabled/{path}',
9680
+ url: '/w/{workspace}/email_triggers/setmode/{path}',
9541
9681
  path: {
9542
9682
  workspace: data.workspace,
9543
9683
  path: data.path
@@ -7,8 +7,9 @@ import { workspaceDependenciesLanguages, } from "../../utils/script_common.js";
7
7
  import { generateHash, getHeaders, writeIfChanged } from "../../utils/utils.js";
8
8
  import { exts } from "../script/script.js";
9
9
  import { FSFSElement, yamlOptions } from "../sync/sync.js";
10
+ import { loadRunnablesFromBackend, writeRunnableToBackend, } from "./raw_apps.js";
10
11
  import { replaceInlineScripts } from "./apps.js";
11
- import { newPathAssigner, } from "../../../windmill-utils-internal/src/path-utils/path-assigner.js";
12
+ import { newPathAssigner, newRawAppPathAssigner, } from "../../../windmill-utils-internal/src/path-utils/path-assigner.js";
12
13
  import { mergeConfigWithConfigFile } from "../../core/conf.js";
13
14
  import { resolveWorkspace } from "../../core/context.js";
14
15
  import { requireLogin } from "../../core/auth.js";
@@ -88,12 +89,19 @@ export async function generateAppLocksInternal(appFolder, rawApp, dryRun, worksp
88
89
  if (changedScripts.length > 0) {
89
90
  log.info(`Recomputing locks of ${changedScripts.join(", ")} in ${appFolder}`);
90
91
  if (rawApp) {
91
- const runnablesPath = path.join(appFolder, APP_BACKEND_FOLDER) + SEP;
92
+ const runnablesPath = path.join(appFolder, APP_BACKEND_FOLDER);
93
+ // Load runnables from separate files (new format) or fall back to raw_app.yaml (old format)
92
94
  const rawAppFile = appFile;
95
+ let runnables = await loadRunnablesFromBackend(runnablesPath);
96
+ if (Object.keys(runnables).length === 0 && rawAppFile.runnables) {
97
+ // Fall back to old format
98
+ runnables = rawAppFile.runnables;
99
+ }
93
100
  // Replace inline scripts for changed runnables
94
- replaceInlineScripts(rawAppFile.runnables, runnablesPath, false);
95
- // Update the app runnables with new locks
96
- rawAppFile.runnables = await updateRawAppRunnables(workspace, rawAppFile.runnables, remote_path, appFolder, rawWorkspaceDependencies, opts.defaultTs);
101
+ replaceInlineScripts(runnables, runnablesPath + SEP, false);
102
+ // Update the app runnables with new locks (writes to separate files)
103
+ await updateRawAppRunnables(workspace, runnables, remote_path, appFolder, rawWorkspaceDependencies, opts.defaultTs);
104
+ // Note: updateRawAppRunnables now writes each runnable to its own file
97
105
  }
98
106
  else {
99
107
  const normalAppFile = appFile;
@@ -101,9 +109,9 @@ export async function generateAppLocksInternal(appFolder, rawApp, dryRun, worksp
101
109
  replaceInlineScripts(normalAppFile.value, appFolder + SEP, false);
102
110
  // Update the app value with new locks
103
111
  normalAppFile.value = await updateAppInlineScripts(workspace, normalAppFile.value, remote_path, appFolder, rawWorkspaceDependencies, opts.defaultTs);
112
+ // Write the updated app file (only for normal apps, raw apps use separate files)
113
+ writeIfChanged(appFilePath, yamlStringify(appFile, yamlOptions));
104
114
  }
105
- // Write the updated app file
106
- writeIfChanged(appFilePath, yamlStringify(appFile, yamlOptions));
107
115
  }
108
116
  else {
109
117
  log.info(colors.gray(`No scripts changed in ${appFolder}`));
@@ -152,8 +160,9 @@ async function traverseAndProcessInlineScripts(obj, processor, currentPath = [])
152
160
  return result;
153
161
  }
154
162
  /**
155
- * Updates locks for all runnables in a raw app, generating locks inline script by inline script
156
- * Also writes content and locks back to the runnables folder
163
+ * Updates locks for all runnables in a raw app, generating locks inline script by inline script.
164
+ * Writes each runnable to its own YAML file in the backend folder (new format).
165
+ * Also writes content and lock files to the runnables folder.
157
166
  */
158
167
  async function updateRawAppRunnables(workspace, runnables, remotePath, appFolder, rawDeps, defaultTs = "bun") {
159
168
  const runnablesFolder = path.join(appFolder, APP_BACKEND_FOLDER);
@@ -164,31 +173,44 @@ async function updateRawAppRunnables(workspace, runnables, remotePath, appFolder
164
173
  catch {
165
174
  // Folder may already exist
166
175
  }
167
- const pathAssigner = newPathAssigner(defaultTs);
168
- // Process each runnable
169
- const updatedRunnables = {};
176
+ const pathAssigner = newRawAppPathAssigner(defaultTs);
170
177
  for (const [runnableId, runnable] of Object.entries(runnables)) {
171
- // Only process inline scripts (runnableByName with inlineScript)
172
- if (runnable?.type !== "runnableByName" || !runnable?.inlineScript) {
173
- updatedRunnables[runnableId] = runnable;
178
+ // Only process inline scripts (runnableByName/inline with inlineScript)
179
+ if ((runnable?.type !== "runnableByName" && runnable?.type !== "inline") ||
180
+ !runnable?.inlineScript) {
181
+ // Write non-inline runnables to their own file as-is
182
+ writeRunnableToBackend(runnablesFolder, runnableId, runnable);
174
183
  continue;
175
184
  }
176
185
  const inlineScript = runnable.inlineScript;
177
186
  const language = inlineScript.language;
178
187
  const content = inlineScript.content;
179
188
  if (!content || !language) {
180
- updatedRunnables[runnableId] = runnable;
189
+ writeRunnableToBackend(runnablesFolder, runnableId, runnable);
181
190
  continue;
182
191
  }
183
192
  // Skip if content is still an !inline reference (should have been replaced by replaceInlineScripts)
184
193
  if (typeof content === "string" && content.startsWith("!inline ")) {
185
194
  log.warn(colors.yellow(`Runnable ${runnableId} content is still an !inline reference, skipping`));
186
- updatedRunnables[runnableId] = runnable;
195
+ writeRunnableToBackend(runnablesFolder, runnableId, runnable);
187
196
  continue;
188
197
  }
189
198
  // Skip frontend scripts - they don't need locks
190
199
  if (language === "frontend") {
191
- updatedRunnables[runnableId] = runnable;
200
+ // Still need to write the runnable YAML file
201
+ const [basePathO, ext] = pathAssigner.assignPath(runnable.name ?? runnableId, language);
202
+ const basePath = basePathO.replaceAll(SEP, "/");
203
+ const contentPath = path.join(runnablesFolder, `${basePath}${ext}`);
204
+ writeIfChanged(contentPath, content);
205
+ // Write simplified runnable YAML - just type: 'inline' plus metadata
206
+ // inlineScript is not needed since content/language can be derived from files
207
+ const simplifiedRunnable = { type: "inline" };
208
+ for (const [key, value] of Object.entries(runnable)) {
209
+ if (key !== "inlineScript" && key !== "type") {
210
+ simplifiedRunnable[key] = value;
211
+ }
212
+ }
213
+ writeRunnableToBackend(runnablesFolder, runnableId, simplifiedRunnable);
192
214
  continue;
193
215
  }
194
216
  log.info(colors.gray(`Generating lock for runnable ${runnableId} (${language})
@@ -196,7 +218,7 @@ async function updateRawAppRunnables(workspace, runnables, remotePath, appFolder
196
218
  try {
197
219
  const lock = await generateInlineScriptLock(workspace, content, language, `${remotePath}/${runnableId}`, rawDeps);
198
220
  // Determine file extension for this language
199
- const [basePathO, ext] = pathAssigner.assignPath(runnable.name, language);
221
+ const [basePathO, ext] = pathAssigner.assignPath(runnable.name ?? runnableId, language);
200
222
  const basePath = basePathO.replaceAll(SEP, "/");
201
223
  const contentPath = path.join(runnablesFolder, `${basePath}${ext}`);
202
224
  const lockPath = path.join(runnablesFolder, `${basePath}lock`);
@@ -206,26 +228,24 @@ async function updateRawAppRunnables(workspace, runnables, remotePath, appFolder
206
228
  if (lock && lock !== "") {
207
229
  writeIfChanged(lockPath, lock);
208
230
  }
209
- // Update the runnable with !inline references (preserve existing schema)
210
- const inlineContentRef = `!inline ${basePath}${ext}`;
211
- const inlineLockRef = lock && lock !== "" ? `!inline ${basePath}lock` : "";
212
- updatedRunnables[runnableId] = {
213
- ...runnable,
214
- inlineScript: {
215
- ...inlineScript,
216
- content: inlineContentRef,
217
- lock: inlineLockRef,
218
- },
219
- };
220
- log.info(colors.gray(` Written ${basePath}${ext}${lock ? ` and ${basePath}lock` : ""}`));
231
+ // Write simplified runnable YAML - just type: 'inline' plus metadata
232
+ // inlineScript is not needed since content/lock/language can be derived from files
233
+ const simplifiedRunnable = { type: "inline" };
234
+ for (const [key, value] of Object.entries(runnable)) {
235
+ if (key !== "inlineScript" && key !== "type") {
236
+ simplifiedRunnable[key] = value;
237
+ }
238
+ }
239
+ // Write the runnable to its own YAML file
240
+ writeRunnableToBackend(runnablesFolder, runnableId, simplifiedRunnable);
241
+ log.info(colors.gray(` Written ${runnableId}.yaml, ${basePath}${ext}${lock ? ` and ${basePath}lock` : ""}`));
221
242
  }
222
243
  catch (error) {
223
244
  log.error(colors.red(`Failed to generate lock for runnable ${runnableId}: ${error.message}`));
224
- // Continue with other runnables even if one fails
225
- updatedRunnables[runnableId] = runnable;
245
+ // Write the original runnable even if lock generation fails
246
+ writeRunnableToBackend(runnablesFolder, runnableId, runnable);
226
247
  }
227
248
  }
228
- return updatedRunnables;
229
249
  }
230
250
  /**
231
251
  * Updates locks for all inline scripts in a normal app, similar to updateRawAppRunnables
@@ -334,33 +354,47 @@ async function generateInlineScriptLock(workspace, content, language, scriptPath
334
354
  /**
335
355
  * Infers schema for a single runnable from its file content.
336
356
  * Used by dev server to update schema in memory (for wmill.d.ts generation).
337
- * Does NOT write to raw_app.yaml - schema is kept in memory only.
357
+ * Does NOT write to the runnable YAML file - schema is kept in memory only.
338
358
  *
339
359
  * @param appFolder - The folder containing the raw app
340
360
  * @param runnableFilePath - The path to the changed runnable file (relative to runnables folder)
341
361
  * @returns The runnable ID and inferred schema, or undefined if inference failed/not applicable
342
362
  */
343
363
  export async function inferRunnableSchemaFromFile(appFolder, runnableFilePath) {
344
- // Extract runnable ID from file path (e.g., "myRunnable.inline_script.ts" -> "myRunnable")
364
+ // Extract runnable ID from file path (e.g., "myRunnable.ts" -> "myRunnable")
345
365
  const fileName = path.basename(runnableFilePath);
346
- // Skip lock files
347
- if (fileName.endsWith(".lock")) {
366
+ // Skip lock files and yaml files (runnable metadata)
367
+ if (fileName.endsWith(".lock") || fileName.endsWith(".yaml")) {
348
368
  return undefined;
349
369
  }
350
- // Match pattern: {runnableId}.inline_script.{ext}
351
- const match = fileName.match(/^(.+)\.inline_script\.[^.]+$/);
370
+ // Match pattern: {runnableId}.{ext} - extract the runnable ID (everything before the last dot)
371
+ const match = fileName.match(/^(.+)\.[^.]+$/);
352
372
  if (!match) {
353
373
  return undefined;
354
374
  }
355
375
  const runnableId = match[1];
356
- // Read the app file to get the language
357
- const appFilePath = path.join(appFolder, "raw_app.yaml");
358
- const appFile = (await yamlParseFile(appFilePath));
359
- if (!appFile.runnables?.[runnableId]) {
360
- log.warn(colors.yellow(`Runnable ${runnableId} not found in raw_app.yaml`));
361
- return undefined;
376
+ // Read the runnable from its separate YAML file (new format)
377
+ const runnableFilePath2 = path.join(appFolder, APP_BACKEND_FOLDER, `${runnableId}.yaml`);
378
+ let runnable;
379
+ try {
380
+ runnable = await yamlParseFile(runnableFilePath2);
381
+ }
382
+ catch {
383
+ // Fall back to reading from raw_app.yaml (old format)
384
+ try {
385
+ const appFilePath = path.join(appFolder, "raw_app.yaml");
386
+ const appFile = (await yamlParseFile(appFilePath));
387
+ if (!appFile.runnables?.[runnableId]) {
388
+ log.warn(colors.yellow(`Runnable ${runnableId} not found in backend folder or raw_app.yaml`));
389
+ return undefined;
390
+ }
391
+ runnable = appFile.runnables[runnableId];
392
+ }
393
+ catch {
394
+ log.warn(colors.yellow(`Could not read runnable ${runnableId} from any source`));
395
+ return undefined;
396
+ }
362
397
  }
363
- const runnable = appFile.runnables[runnableId];
364
398
  // Only process inline scripts
365
399
  if (!runnable?.inlineScript) {
366
400
  return undefined;
@@ -6,6 +6,7 @@ import * as wmill from "../../../gen/services.gen.js";
6
6
  import { isSuperset } from "../../types.js";
7
7
  import { readInlinePathSync } from "../../utils/utils.js";
8
8
  import devCommand from "./dev.js";
9
+ import lintCommand from "./lint.js";
9
10
  import { isVersionsGeq1585 } from "../sync/global.js";
10
11
  const alreadySynced = [];
11
12
  function respecializeFields(fields) {
@@ -190,6 +191,7 @@ const command = new Command()
190
191
  .arguments("<file_path:string> <remote_path:string>")
191
192
  .action(push)
192
193
  .command("dev", devCommand)
194
+ .command("lint", lintCommand)
193
195
  .command("generate-locks", "re-generate the lockfiles for app runnables inline scripts that have changed")
194
196
  .arguments("[app_folder:string]")
195
197
  .option("--yes", "Skip confirmation prompt")
@@ -168,8 +168,12 @@ export async function createBundle(options = {}) {
168
168
  const wmillPlugin = {
169
169
  name: "wmill-virtual",
170
170
  setup(build) {
171
- // Intercept imports of /wmill.ts, /wmill, ./wmill.ts, or ./wmill
172
- build.onResolve({ filter: /^(\.\/|\/)?wmill(\.ts)?$/ }, (args) => {
171
+ // Intercept imports of wmill with various path formats:
172
+ // - wmill, wmill.ts (bare import)
173
+ // - /wmill, /wmill.ts (absolute)
174
+ // - ./wmill, ./wmill.ts (same directory)
175
+ // - ../wmill, ../../wmill, etc. (parent directories)
176
+ build.onResolve({ filter: /^(\.\.\/)+wmill(\.ts)?$|^(\.\/|\/)?wmill(\.ts)?$/ }, (args) => {
173
177
  log.info(colors.yellow(`[wmill-virtual] Intercepted: ${args.path}`));
174
178
  return {
175
179
  path: args.path,