windmill-cli 1.589.2 → 1.590.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 (54) 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 +149 -27
  5. package/esm/src/commands/app/app_metadata.js +87 -54
  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 +49 -17
  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 +74 -16
  25. package/types/gen/services.gen.d.ts.map +1 -1
  26. package/types/gen/types.gen.d.ts +568 -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.map +1 -1
  45. package/types/src/main.d.ts +1 -1
  46. package/types/src/utils/resource_types.d.ts +3 -0
  47. package/types/src/utils/resource_types.d.ts.map +1 -0
  48. package/types/src/utils/utils.d.ts +2 -0
  49. package/types/src/utils/utils.d.ts.map +1 -1
  50. package/types/windmill-utils-internal/src/gen/types.gen.d.ts +568 -62
  51. package/types/windmill-utils-internal/src/gen/types.gen.d.ts.map +1 -1
  52. package/types/windmill-utils-internal/src/path-utils/path-assigner.d.ts +22 -0
  53. package/types/windmill-utils-internal/src/path-utils/path-assigner.d.ts.map +1 -1
  54. /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.2',
35
+ VERSION: '1.590.0',
36
36
  WITH_CREDENTIALS: true,
37
37
  interceptors: {
38
38
  request: new Interceptors(),
@@ -569,30 +569,44 @@ export const existsUsername = (data) => {
569
569
  });
570
570
  };
571
571
  /**
572
- * Returns the set-up statuses of ducklake instance catalog dbs
573
- * @returns DucklakeInstanceCatalogDbStatus Statuses of all ducklake instance catalog dbs
572
+ * Refreshes the password for the custom_instance_user
573
+ * @returns unknown Success
574
574
  * @throws ApiError
575
575
  */
576
- export const getDucklakeInstanceCatalogDbStatus = () => {
576
+ export const refreshCustomInstanceUserPwd = () => {
577
577
  return __request(OpenAPI, {
578
578
  method: 'POST',
579
- url: '/settings/get_ducklake_instance_catalog_db_status'
579
+ url: '/settings/refresh_custom_instance_user_pwd'
580
580
  });
581
581
  };
582
582
  /**
583
- * Runs CREATE DATABASE on the Windmill Postgres and grants access to the ducklake_user
583
+ * Returns the set-up statuses of custom instance pg databases
584
+ * @returns CustomInstanceDb Statuses of all custom instance dbs
585
+ * @throws ApiError
586
+ */
587
+ export const listCustomInstanceDbs = () => {
588
+ return __request(OpenAPI, {
589
+ method: 'POST',
590
+ url: '/settings/list_custom_instance_pg_databases'
591
+ });
592
+ };
593
+ /**
594
+ * Runs CREATE DATABASE on the Windmill Postgres and grants access to the custom_instance_user
584
595
  * @param data The data for the request.
585
596
  * @param data.name The name of the database to create
586
- * @returns DucklakeInstanceCatalogDbStatus status
597
+ * @param data.requestBody
598
+ * @returns CustomInstanceDb status
587
599
  * @throws ApiError
588
600
  */
589
- export const setupDucklakeCatalogDb = (data) => {
601
+ export const setupCustomInstanceDb = (data) => {
590
602
  return __request(OpenAPI, {
591
603
  method: 'POST',
592
- url: '/settings/setup_ducklake_catalog_db/{name}',
604
+ url: '/settings/setup_custom_instance_pg_database/{name}',
593
605
  path: {
594
606
  name: data.name
595
- }
607
+ },
608
+ body: data.requestBody,
609
+ mediaType: 'application/json'
596
610
  });
597
611
  };
598
612
  /**
@@ -1891,6 +1905,22 @@ export const listDucklakes = (data) => {
1891
1905
  }
1892
1906
  });
1893
1907
  };
1908
+ /**
1909
+ * list Datatables
1910
+ * @param data The data for the request.
1911
+ * @param data.workspace
1912
+ * @returns string status
1913
+ * @throws ApiError
1914
+ */
1915
+ export const listDataTables = (data) => {
1916
+ return __request(OpenAPI, {
1917
+ method: 'GET',
1918
+ url: '/w/{workspace}/workspaces/list_datatables',
1919
+ path: {
1920
+ workspace: data.workspace
1921
+ }
1922
+ });
1923
+ };
1894
1924
  /**
1895
1925
  * edit ducklake settings
1896
1926
  * @param data The data for the request.
@@ -1910,6 +1940,25 @@ export const editDucklakeConfig = (data) => {
1910
1940
  mediaType: 'application/json'
1911
1941
  });
1912
1942
  };
1943
+ /**
1944
+ * edit datatable settings
1945
+ * @param data The data for the request.
1946
+ * @param data.workspace
1947
+ * @param data.requestBody DataTable settings
1948
+ * @returns unknown status
1949
+ * @throws ApiError
1950
+ */
1951
+ export const editDataTableConfig = (data) => {
1952
+ return __request(OpenAPI, {
1953
+ method: 'POST',
1954
+ url: '/w/{workspace}/workspaces/edit_datatable_config',
1955
+ path: {
1956
+ workspace: data.workspace
1957
+ },
1958
+ body: data.requestBody,
1959
+ mediaType: 'application/json'
1960
+ });
1961
+ };
1913
1962
  /**
1914
1963
  * edit workspace git sync settings
1915
1964
  * @param data The data for the request.
@@ -2306,6 +2355,7 @@ export const listTokens = (data = {}) => {
2306
2355
  * @param data The data for the request.
2307
2356
  * @param data.workspace
2308
2357
  * @param data.audience
2358
+ * @param data.expiresIn
2309
2359
  * @returns string new oidc token
2310
2360
  * @throws ApiError
2311
2361
  */
@@ -2316,6 +2366,9 @@ export const getOidcToken = (data) => {
2316
2366
  path: {
2317
2367
  workspace: data.workspace,
2318
2368
  audience: data.audience
2369
+ },
2370
+ query: {
2371
+ expires_in: data.expiresIn
2319
2372
  }
2320
2373
  });
2321
2374
  };
@@ -6108,6 +6161,25 @@ export const runScriptPreview = (data) => {
6108
6161
  mediaType: 'application/json'
6109
6162
  });
6110
6163
  };
6164
+ /**
6165
+ * run script preview without starting a new job
6166
+ * @param data The data for the request.
6167
+ * @param data.workspace
6168
+ * @param data.requestBody preview
6169
+ * @returns unknown script result
6170
+ * @throws ApiError
6171
+ */
6172
+ export const runScriptPreviewInline = (data) => {
6173
+ return __request(OpenAPI, {
6174
+ method: 'POST',
6175
+ url: '/w/{workspace}/jobs/run_inline/preview',
6176
+ path: {
6177
+ workspace: data.workspace
6178
+ },
6179
+ body: data.requestBody,
6180
+ mediaType: 'application/json'
6181
+ });
6182
+ };
6111
6183
  /**
6112
6184
  * run script preview and wait for result
6113
6185
  * @param data The data for the request.
@@ -6253,6 +6325,8 @@ export const runDynamicSelect = (data) => {
6253
6325
  * @param data.scriptPathExact mask to filter exact matching path
6254
6326
  * @param data.scriptPathStart mask to filter matching starting path
6255
6327
  * @param data.schedulePath mask to filter by schedule path
6328
+ * @param data.triggerPath mask to filter by trigger path
6329
+ * @param data.triggerKind trigger kind (schedule, http, websocket...)
6256
6330
  * @param data.scriptHash mask to filter exact matching path
6257
6331
  * @param data.startedBefore filter on started before (inclusive) timestamp
6258
6332
  * @param data.startedAfter filter on started after (exclusive) timestamp
@@ -6287,6 +6361,8 @@ export const listQueue = (data) => {
6287
6361
  script_path_exact: data.scriptPathExact,
6288
6362
  script_path_start: data.scriptPathStart,
6289
6363
  schedule_path: data.schedulePath,
6364
+ trigger_path: data.triggerPath,
6365
+ trigger_kind: data.triggerKind,
6290
6366
  script_hash: data.scriptHash,
6291
6367
  started_before: data.startedBefore,
6292
6368
  started_after: data.startedAfter,
@@ -6535,6 +6611,52 @@ export const cancelSelection = (data) => {
6535
6611
  mediaType: 'application/json'
6536
6612
  });
6537
6613
  };
6614
+ /**
6615
+ * resume all suspended jobs for a specific trigger
6616
+ * @param data The data for the request.
6617
+ * @param data.workspace
6618
+ * @param data.triggerKind The kind of trigger
6619
+ * @param data.triggerPath The path of the trigger (can contain forward slashes)
6620
+ * @param data.requestBody Optional list of job IDs to reassign
6621
+ * @returns string confirmation message
6622
+ * @throws ApiError
6623
+ */
6624
+ export const resumeSuspendedTriggerJobs = (data) => {
6625
+ return __request(OpenAPI, {
6626
+ method: 'POST',
6627
+ url: '/w/{workspace}/trigger/{trigger_kind}/resume_suspended_trigger_jobs/{trigger_path}',
6628
+ path: {
6629
+ workspace: data.workspace,
6630
+ trigger_kind: data.triggerKind,
6631
+ trigger_path: data.triggerPath
6632
+ },
6633
+ body: data.requestBody,
6634
+ mediaType: 'application/json'
6635
+ });
6636
+ };
6637
+ /**
6638
+ * cancel all suspended jobs for a specific trigger
6639
+ * @param data The data for the request.
6640
+ * @param data.workspace
6641
+ * @param data.triggerKind The kind of trigger
6642
+ * @param data.triggerPath The path of the trigger (can contain forward slashes)
6643
+ * @param data.requestBody Optional list of job IDs to cancel
6644
+ * @returns string confirmation message
6645
+ * @throws ApiError
6646
+ */
6647
+ export const cancelSuspendedTriggerJobs = (data) => {
6648
+ return __request(OpenAPI, {
6649
+ method: 'POST',
6650
+ url: '/w/{workspace}/trigger/{trigger_kind}/cancel_suspended_trigger_jobs/{trigger_path}',
6651
+ path: {
6652
+ workspace: data.workspace,
6653
+ trigger_kind: data.triggerKind,
6654
+ trigger_path: data.triggerPath
6655
+ },
6656
+ body: data.requestBody,
6657
+ mediaType: 'application/json'
6658
+ });
6659
+ };
6538
6660
  /**
6539
6661
  * list all completed jobs
6540
6662
  * @param data The data for the request.
@@ -7941,10 +8063,10 @@ export const existsRoute = (data) => {
7941
8063
  * @returns string http trigger enable/disable
7942
8064
  * @throws ApiError
7943
8065
  */
7944
- export const setHttpTriggerEnabled = (data) => {
8066
+ export const setHttpTriggerMode = (data) => {
7945
8067
  return __request(OpenAPI, {
7946
8068
  method: 'POST',
7947
- url: '/w/{workspace}/http_triggers/setenabled/{path}',
8069
+ url: '/w/{workspace}/http_triggers/setmode/{path}',
7948
8070
  path: {
7949
8071
  workspace: data.workspace,
7950
8072
  path: data.path
@@ -8084,10 +8206,10 @@ export const existsWebsocketTrigger = (data) => {
8084
8206
  * @returns string websocket trigger enabled set
8085
8207
  * @throws ApiError
8086
8208
  */
8087
- export const setWebsocketTriggerEnabled = (data) => {
8209
+ export const setWebsocketTriggerMode = (data) => {
8088
8210
  return __request(OpenAPI, {
8089
8211
  method: 'POST',
8090
- url: '/w/{workspace}/websocket_triggers/setenabled/{path}',
8212
+ url: '/w/{workspace}/websocket_triggers/setmode/{path}',
8091
8213
  path: {
8092
8214
  workspace: data.workspace,
8093
8215
  path: data.path
@@ -8246,10 +8368,10 @@ export const existsKafkaTrigger = (data) => {
8246
8368
  * @returns string kafka trigger enabled set
8247
8369
  * @throws ApiError
8248
8370
  */
8249
- export const setKafkaTriggerEnabled = (data) => {
8371
+ export const setKafkaTriggerMode = (data) => {
8250
8372
  return __request(OpenAPI, {
8251
8373
  method: 'POST',
8252
- url: '/w/{workspace}/kafka_triggers/setenabled/{path}',
8374
+ url: '/w/{workspace}/kafka_triggers/setmode/{path}',
8253
8375
  path: {
8254
8376
  workspace: data.workspace,
8255
8377
  path: data.path
@@ -8408,10 +8530,10 @@ export const existsNatsTrigger = (data) => {
8408
8530
  * @returns string nats trigger enabled set
8409
8531
  * @throws ApiError
8410
8532
  */
8411
- export const setNatsTriggerEnabled = (data) => {
8533
+ export const setNatsTriggerMode = (data) => {
8412
8534
  return __request(OpenAPI, {
8413
8535
  method: 'POST',
8414
- url: '/w/{workspace}/nats_triggers/setenabled/{path}',
8536
+ url: '/w/{workspace}/nats_triggers/setmode/{path}',
8415
8537
  path: {
8416
8538
  workspace: data.workspace,
8417
8539
  path: data.path
@@ -8570,10 +8692,10 @@ export const existsSqsTrigger = (data) => {
8570
8692
  * @returns string sqs trigger enabled set
8571
8693
  * @throws ApiError
8572
8694
  */
8573
- export const setSqsTriggerEnabled = (data) => {
8695
+ export const setSqsTriggerMode = (data) => {
8574
8696
  return __request(OpenAPI, {
8575
8697
  method: 'POST',
8576
- url: '/w/{workspace}/sqs_triggers/setenabled/{path}',
8698
+ url: '/w/{workspace}/sqs_triggers/setmode/{path}',
8577
8699
  path: {
8578
8700
  workspace: data.workspace,
8579
8701
  path: data.path
@@ -8732,10 +8854,10 @@ export const existsMqttTrigger = (data) => {
8732
8854
  * @returns string mqtt trigger enabled set
8733
8855
  * @throws ApiError
8734
8856
  */
8735
- export const setMqttTriggerEnabled = (data) => {
8857
+ export const setMqttTriggerMode = (data) => {
8736
8858
  return __request(OpenAPI, {
8737
8859
  method: 'POST',
8738
- url: '/w/{workspace}/mqtt_triggers/setenabled/{path}',
8860
+ url: '/w/{workspace}/mqtt_triggers/setmode/{path}',
8739
8861
  path: {
8740
8862
  workspace: data.workspace,
8741
8863
  path: data.path
@@ -8894,10 +9016,10 @@ export const existsGcpTrigger = (data) => {
8894
9016
  * @returns string gcp trigger enabled set
8895
9017
  * @throws ApiError
8896
9018
  */
8897
- export const setGcpTriggerEnabled = (data) => {
9019
+ export const setGcpTriggerMode = (data) => {
8898
9020
  return __request(OpenAPI, {
8899
9021
  method: 'POST',
8900
- url: '/w/{workspace}/gcp_triggers/setenabled/{path}',
9022
+ url: '/w/{workspace}/gcp_triggers/setmode/{path}',
8901
9023
  path: {
8902
9024
  workspace: data.workspace,
8903
9025
  path: data.path
@@ -9353,10 +9475,10 @@ export const existsPostgresTrigger = (data) => {
9353
9475
  * @returns string postgres trigger enabled set
9354
9476
  * @throws ApiError
9355
9477
  */
9356
- export const setPostgresTriggerEnabled = (data) => {
9478
+ export const setPostgresTriggerMode = (data) => {
9357
9479
  return __request(OpenAPI, {
9358
9480
  method: 'POST',
9359
- url: '/w/{workspace}/postgres_triggers/setenabled/{path}',
9481
+ url: '/w/{workspace}/postgres_triggers/setmode/{path}',
9360
9482
  path: {
9361
9483
  workspace: data.workspace,
9362
9484
  path: data.path
@@ -9534,10 +9656,10 @@ export const existsEmailLocalPart = (data) => {
9534
9656
  * @returns string email trigger enable/disable
9535
9657
  * @throws ApiError
9536
9658
  */
9537
- export const setEmailTriggerEnabled = (data) => {
9659
+ export const setEmailTriggerMode = (data) => {
9538
9660
  return __request(OpenAPI, {
9539
9661
  method: 'POST',
9540
- url: '/w/{workspace}/email_triggers/setenabled/{path}',
9662
+ url: '/w/{workspace}/email_triggers/setmode/{path}',
9541
9663
  path: {
9542
9664
  workspace: data.workspace,
9543
9665
  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
@@ -244,17 +264,16 @@ async function updateAppInlineScripts(workspace, appValue, remotePath, appFolder
244
264
  log.warn(colors.yellow(`Inline script at ${context.path.join(".")} is still an !inline reference, skipping`));
245
265
  return inlineScript;
246
266
  }
247
- // Skip frontend scripts - they don't need locks
248
- if (language === "frontend") {
249
- return inlineScript;
250
- }
251
267
  // Get the name from the parent object (following extractInlineScriptsForApps pattern)
252
268
  // For normal apps, the name is stored in the component's "name" property
253
269
  const scriptName = context.parentObject?.["name"] || "unnamed";
254
270
  const scriptPath = `${remotePath}/${context.path.join("/")}`;
255
- log.info(colors.gray(`Generating lock for inline script "${scriptName}" at ${context.path.join(".")} (${language})`));
256
271
  try {
257
- const lock = await generateInlineScriptLock(workspace, content, language, scriptPath, rawDeps);
272
+ let lock;
273
+ if (language !== "frontend") {
274
+ log.info(colors.gray(`Generating lock for inline script "${scriptName}" at ${context.path.join(".")} (${language})`));
275
+ lock = await generateInlineScriptLock(workspace, content, language, scriptPath, rawDeps);
276
+ }
258
277
  // Determine file extension for this language (following extractInlineScriptsForApps pattern)
259
278
  const [basePathO, ext] = pathAssigner.assignPath(scriptName, language);
260
279
  const basePath = basePathO.replaceAll(SEP, "/");
@@ -273,7 +292,7 @@ async function updateAppInlineScripts(workspace, appValue, remotePath, appFolder
273
292
  return {
274
293
  ...inlineScript,
275
294
  content: inlineContentRef,
276
- lock: inlineLockRef,
295
+ ...(lock ? { lock: inlineLockRef } : {}),
277
296
  };
278
297
  }
279
298
  catch (error) {
@@ -335,33 +354,47 @@ async function generateInlineScriptLock(workspace, content, language, scriptPath
335
354
  /**
336
355
  * Infers schema for a single runnable from its file content.
337
356
  * Used by dev server to update schema in memory (for wmill.d.ts generation).
338
- * 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.
339
358
  *
340
359
  * @param appFolder - The folder containing the raw app
341
360
  * @param runnableFilePath - The path to the changed runnable file (relative to runnables folder)
342
361
  * @returns The runnable ID and inferred schema, or undefined if inference failed/not applicable
343
362
  */
344
363
  export async function inferRunnableSchemaFromFile(appFolder, runnableFilePath) {
345
- // 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")
346
365
  const fileName = path.basename(runnableFilePath);
347
- // Skip lock files
348
- if (fileName.endsWith(".lock")) {
366
+ // Skip lock files and yaml files (runnable metadata)
367
+ if (fileName.endsWith(".lock") || fileName.endsWith(".yaml")) {
349
368
  return undefined;
350
369
  }
351
- // Match pattern: {runnableId}.inline_script.{ext}
352
- 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(/^(.+)\.[^.]+$/);
353
372
  if (!match) {
354
373
  return undefined;
355
374
  }
356
375
  const runnableId = match[1];
357
- // Read the app file to get the language
358
- const appFilePath = path.join(appFolder, "raw_app.yaml");
359
- const appFile = (await yamlParseFile(appFilePath));
360
- if (!appFile.runnables?.[runnableId]) {
361
- log.warn(colors.yellow(`Runnable ${runnableId} not found in raw_app.yaml`));
362
- 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
+ }
363
397
  }
364
- const runnable = appFile.runnables[runnableId];
365
398
  // Only process inline scripts
366
399
  if (!runnable?.inlineScript) {
367
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")