windmill-cli 1.769.1 → 1.771.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 (2) hide show
  1. package/esm/main.js +333 -60
  2. package/package.json +1 -1
package/esm/main.js CHANGED
@@ -16784,7 +16784,7 @@ var init_OpenAPI = __esm(() => {
16784
16784
  PASSWORD: undefined,
16785
16785
  TOKEN: getEnv3("WM_TOKEN"),
16786
16786
  USERNAME: undefined,
16787
- VERSION: "1.769.0",
16787
+ VERSION: "1.771.0",
16788
16788
  WITH_CREDENTIALS: true,
16789
16789
  interceptors: {
16790
16790
  request: new Interceptors,
@@ -17103,6 +17103,7 @@ __export(exports_services_gen, {
17103
17103
  updateApp: () => updateApp,
17104
17104
  updateAmqpTrigger: () => updateAmqpTrigger,
17105
17105
  unstar: () => unstar,
17106
+ unresolveCompletedJobs: () => unresolveCompletedJobs,
17106
17107
  unassignGhesInstallation: () => unassignGhesInstallation,
17107
17108
  unarchiveWorkspace: () => unarchiveWorkspace,
17108
17109
  toggleWorkspaceErrorHandlerForScript: () => toggleWorkspaceErrorHandlerForScript,
@@ -17209,6 +17210,7 @@ __export(exports_services_gen, {
17209
17210
  restartWorkerGroup: () => restartWorkerGroup,
17210
17211
  restartFlowAtStep: () => restartFlowAtStep,
17211
17212
  resolveNpmPackageVersion: () => resolveNpmPackageVersion,
17213
+ resolveCompletedJobs: () => resolveCompletedJobs,
17212
17214
  resetPassword: () => resetPassword,
17213
17215
  resetKafkaOffsets: () => resetKafkaOffsets,
17214
17216
  resetDiffTally: () => resetDiffTally,
@@ -17234,8 +17236,10 @@ __export(exports_services_gen, {
17234
17236
  publishHubScript: () => publishHubScript,
17235
17237
  publishHubResources: () => publishHubResources,
17236
17238
  publishHubResourceType: () => publishHubResourceType,
17239
+ publishHubRawAppRecording: () => publishHubRawAppRecording,
17237
17240
  publishHubRawAppEmbed: () => publishHubRawAppEmbed,
17238
17241
  publishHubRawApp: () => publishHubRawApp,
17242
+ publishHubProjectLogo: () => publishHubProjectLogo,
17239
17243
  publishHubPipelineRecording: () => publishHubPipelineRecording,
17240
17244
  publishHubMigrations: () => publishHubMigrations,
17241
17245
  publishHubFlowRecording: () => publishHubFlowRecording,
@@ -17309,6 +17313,7 @@ __export(exports_services_gen, {
17309
17313
  listScriptPaths: () => listScriptPaths,
17310
17314
  listSchedulesWithJobs: () => listSchedulesWithJobs,
17311
17315
  listSchedules: () => listSchedules,
17316
+ listRunnables: () => listRunnables,
17312
17317
  listResourceTypeNames: () => listResourceTypeNames,
17313
17318
  listResourceType: () => listResourceType,
17314
17319
  listResourceNames: () => listResourceNames,
@@ -17437,6 +17442,7 @@ __export(exports_services_gen, {
17437
17442
  getWorkspaceDefaultApp: () => getWorkspaceDefaultApp,
17438
17443
  getWorkspaceAsSuperAdmin: () => getWorkspaceAsSuperAdmin,
17439
17444
  getWebsocketTrigger: () => getWebsocketTrigger,
17445
+ getWacApprovalUrls: () => getWacApprovalUrls,
17440
17446
  getVolumeStorage: () => getVolumeStorage,
17441
17447
  getVariableValue: () => getVariableValue,
17442
17448
  getVariable: () => getVariable,
@@ -21328,6 +21334,26 @@ var backendVersion = () => {
21328
21334
  workspace: data3.workspace
21329
21335
  }
21330
21336
  });
21337
+ }, listRunnables = (data3) => {
21338
+ return request(OpenAPI, {
21339
+ method: "GET",
21340
+ url: "/w/{workspace}/runnables/list",
21341
+ path: {
21342
+ workspace: data3.workspace
21343
+ },
21344
+ query: {
21345
+ order_by: data3.orderBy,
21346
+ order_desc: data3.orderDesc,
21347
+ kinds: data3.kinds,
21348
+ show_archived: data3.showArchived,
21349
+ include_without_main: data3.includeWithoutMain,
21350
+ path_start: data3.pathStart,
21351
+ label: data3.label,
21352
+ search: data3.search,
21353
+ per_page: data3.perPage,
21354
+ cursor: data3.cursor
21355
+ }
21356
+ });
21331
21357
  }, listFlows = (data3) => {
21332
21358
  return request(OpenAPI, {
21333
21359
  method: "GET",
@@ -22374,6 +22400,7 @@ var backendVersion = () => {
22374
22400
  page: data3.page,
22375
22401
  per_page: data3.perPage,
22376
22402
  is_skipped: data3.isSkipped,
22403
+ resolved: data3.resolved,
22377
22404
  is_flow_step: data3.isFlowStep,
22378
22405
  has_null_parent: data3.hasNullParent,
22379
22406
  success: data3.success,
@@ -22491,6 +22518,7 @@ var backendVersion = () => {
22491
22518
  page: data3.page,
22492
22519
  per_page: data3.perPage,
22493
22520
  is_skipped: data3.isSkipped,
22521
+ resolved: data3.resolved,
22494
22522
  is_flow_step: data3.isFlowStep,
22495
22523
  has_null_parent: data3.hasNullParent,
22496
22524
  is_not_schedule: data3.isNotSchedule
@@ -22585,6 +22613,7 @@ var backendVersion = () => {
22585
22613
  per_page: data3.perPage,
22586
22614
  trigger_kind: data3.triggerKind,
22587
22615
  is_skipped: data3.isSkipped,
22616
+ resolved: data3.resolved,
22588
22617
  is_flow_step: data3.isFlowStep,
22589
22618
  has_null_parent: data3.hasNullParent,
22590
22619
  success: data3.success,
@@ -22817,6 +22846,26 @@ var backendVersion = () => {
22817
22846
  id: data3.id
22818
22847
  }
22819
22848
  });
22849
+ }, resolveCompletedJobs = (data3) => {
22850
+ return request(OpenAPI, {
22851
+ method: "POST",
22852
+ url: "/w/{workspace}/jobs/completed/resolve",
22853
+ path: {
22854
+ workspace: data3.workspace
22855
+ },
22856
+ body: data3.requestBody,
22857
+ mediaType: "application/json"
22858
+ });
22859
+ }, unresolveCompletedJobs = (data3) => {
22860
+ return request(OpenAPI, {
22861
+ method: "POST",
22862
+ url: "/w/{workspace}/jobs/completed/unresolve",
22863
+ path: {
22864
+ workspace: data3.workspace
22865
+ },
22866
+ body: data3.requestBody,
22867
+ mediaType: "application/json"
22868
+ });
22820
22869
  }, cancelQueuedJob = (data3) => {
22821
22870
  return request(OpenAPI, {
22822
22871
  method: "POST",
@@ -22895,6 +22944,19 @@ var backendVersion = () => {
22895
22944
  flow_level: data3.flowLevel
22896
22945
  }
22897
22946
  });
22947
+ }, getWacApprovalUrls = (data3) => {
22948
+ return request(OpenAPI, {
22949
+ method: "GET",
22950
+ url: "/w/{workspace}/jobs/wac_approval_urls/{id}/{step_key}",
22951
+ path: {
22952
+ workspace: data3.workspace,
22953
+ id: data3.id,
22954
+ step_key: data3.stepKey
22955
+ },
22956
+ query: {
22957
+ approver: data3.approver
22958
+ }
22959
+ });
22898
22960
  }, getSlackApprovalPayload = (data3) => {
22899
22961
  return request(OpenAPI, {
22900
22962
  method: "GET",
@@ -24818,6 +24880,8 @@ var backendVersion = () => {
24818
24880
  workspace: data3.workspace
24819
24881
  },
24820
24882
  query: {
24883
+ page: data3.page,
24884
+ per_page: data3.perPage,
24821
24885
  only_member_of: data3.onlyMemberOf
24822
24886
  }
24823
24887
  });
@@ -25321,7 +25385,8 @@ var backendVersion = () => {
25321
25385
  workspace: data3.workspace
25322
25386
  },
25323
25387
  query: {
25324
- storage: data3.storage
25388
+ storage: data3.storage,
25389
+ s3_resource_path: data3.s3ResourcePath
25325
25390
  }
25326
25391
  });
25327
25392
  }, getStorageUsage = (data3) => {
@@ -25346,7 +25411,8 @@ var backendVersion = () => {
25346
25411
  max_keys: data3.maxKeys,
25347
25412
  marker: data3.marker,
25348
25413
  prefix: data3.prefix,
25349
- storage: data3.storage
25414
+ storage: data3.storage,
25415
+ s3_resource_path: data3.s3ResourcePath
25350
25416
  }
25351
25417
  });
25352
25418
  }, loadFileMetadata = (data3) => {
@@ -25358,7 +25424,8 @@ var backendVersion = () => {
25358
25424
  },
25359
25425
  query: {
25360
25426
  file_key: data3.fileKey,
25361
- storage: data3.storage
25427
+ storage: data3.storage,
25428
+ s3_resource_path: data3.s3ResourcePath
25362
25429
  }
25363
25430
  });
25364
25431
  }, loadFilePreview = (data3) => {
@@ -25376,7 +25443,8 @@ var backendVersion = () => {
25376
25443
  csv_has_header: data3.csvHasHeader,
25377
25444
  read_bytes_from: data3.readBytesFrom,
25378
25445
  read_bytes_length: data3.readBytesLength,
25379
- storage: data3.storage
25446
+ storage: data3.storage,
25447
+ s3_resource_path: data3.s3ResourcePath
25380
25448
  }
25381
25449
  });
25382
25450
  }, listGitRepoFiles = (data3) => {
@@ -25495,7 +25563,8 @@ var backendVersion = () => {
25495
25563
  },
25496
25564
  query: {
25497
25565
  file_key: data3.fileKey,
25498
- storage: data3.storage
25566
+ storage: data3.storage,
25567
+ s3_resource_path: data3.s3ResourcePath
25499
25568
  }
25500
25569
  });
25501
25570
  }, moveS3File = (data3) => {
@@ -25508,7 +25577,8 @@ var backendVersion = () => {
25508
25577
  query: {
25509
25578
  src_file_key: data3.srcFileKey,
25510
25579
  dest_file_key: data3.destFileKey,
25511
- storage: data3.storage
25580
+ storage: data3.storage,
25581
+ s3_resource_path: data3.s3ResourcePath
25512
25582
  }
25513
25583
  });
25514
25584
  }, fileUpload = (data3) => {
@@ -25680,6 +25750,7 @@ var backendVersion = () => {
25680
25750
  per_page: data3.perPage,
25681
25751
  trigger_kind: data3.triggerKind,
25682
25752
  is_skipped: data3.isSkipped,
25753
+ resolved: data3.resolved,
25683
25754
  is_flow_step: data3.isFlowStep,
25684
25755
  has_null_parent: data3.hasNullParent,
25685
25756
  success: data3.success,
@@ -25996,6 +26067,20 @@ var backendVersion = () => {
25996
26067
  body: data3.requestBody,
25997
26068
  mediaType: "application/json"
25998
26069
  });
26070
+ }, publishHubRawAppRecording = (data3) => {
26071
+ return request(OpenAPI, {
26072
+ method: "POST",
26073
+ url: "/w/{workspace}/hub/raw_apps/{id}/recording",
26074
+ path: {
26075
+ workspace: data3.workspace,
26076
+ id: data3.id
26077
+ },
26078
+ query: {
26079
+ folder: data3.folder
26080
+ },
26081
+ body: data3.requestBody,
26082
+ mediaType: "application/json"
26083
+ });
25999
26084
  }, publishHubScriptRecording = (data3) => {
26000
26085
  return request(OpenAPI, {
26001
26086
  method: "POST",
@@ -26102,6 +26187,20 @@ var backendVersion = () => {
26102
26187
  folder: data3.folder
26103
26188
  }
26104
26189
  });
26190
+ }, publishHubProjectLogo = (data3) => {
26191
+ return request(OpenAPI, {
26192
+ method: "POST",
26193
+ url: "/w/{workspace}/hub/projects/{slug}/logo",
26194
+ path: {
26195
+ workspace: data3.workspace,
26196
+ slug: data3.slug
26197
+ },
26198
+ query: {
26199
+ folder: data3.folder
26200
+ },
26201
+ body: data3.requestBody,
26202
+ mediaType: "application/json"
26203
+ });
26105
26204
  }, submitHubProject = (data3) => {
26106
26205
  return request(OpenAPI, {
26107
26206
  method: "POST",
@@ -26181,6 +26280,7 @@ __export(exports_gen, {
26181
26280
  updateApp: () => updateApp,
26182
26281
  updateAmqpTrigger: () => updateAmqpTrigger,
26183
26282
  unstar: () => unstar,
26283
+ unresolveCompletedJobs: () => unresolveCompletedJobs,
26184
26284
  unassignGhesInstallation: () => unassignGhesInstallation,
26185
26285
  unarchiveWorkspace: () => unarchiveWorkspace,
26186
26286
  toggleWorkspaceErrorHandlerForScript: () => toggleWorkspaceErrorHandlerForScript,
@@ -26287,6 +26387,7 @@ __export(exports_gen, {
26287
26387
  restartWorkerGroup: () => restartWorkerGroup,
26288
26388
  restartFlowAtStep: () => restartFlowAtStep,
26289
26389
  resolveNpmPackageVersion: () => resolveNpmPackageVersion,
26390
+ resolveCompletedJobs: () => resolveCompletedJobs,
26290
26391
  resetPassword: () => resetPassword,
26291
26392
  resetKafkaOffsets: () => resetKafkaOffsets,
26292
26393
  resetDiffTally: () => resetDiffTally,
@@ -26312,8 +26413,10 @@ __export(exports_gen, {
26312
26413
  publishHubScript: () => publishHubScript,
26313
26414
  publishHubResources: () => publishHubResources,
26314
26415
  publishHubResourceType: () => publishHubResourceType,
26416
+ publishHubRawAppRecording: () => publishHubRawAppRecording,
26315
26417
  publishHubRawAppEmbed: () => publishHubRawAppEmbed,
26316
26418
  publishHubRawApp: () => publishHubRawApp,
26419
+ publishHubProjectLogo: () => publishHubProjectLogo,
26317
26420
  publishHubPipelineRecording: () => publishHubPipelineRecording,
26318
26421
  publishHubMigrations: () => publishHubMigrations,
26319
26422
  publishHubFlowRecording: () => publishHubFlowRecording,
@@ -26387,6 +26490,7 @@ __export(exports_gen, {
26387
26490
  listScriptPaths: () => listScriptPaths,
26388
26491
  listSchedulesWithJobs: () => listSchedulesWithJobs,
26389
26492
  listSchedules: () => listSchedules,
26493
+ listRunnables: () => listRunnables,
26390
26494
  listResourceTypeNames: () => listResourceTypeNames,
26391
26495
  listResourceType: () => listResourceType,
26392
26496
  listResourceNames: () => listResourceNames,
@@ -26515,6 +26619,7 @@ __export(exports_gen, {
26515
26619
  getWorkspaceDefaultApp: () => getWorkspaceDefaultApp,
26516
26620
  getWorkspaceAsSuperAdmin: () => getWorkspaceAsSuperAdmin,
26517
26621
  getWebsocketTrigger: () => getWebsocketTrigger,
26622
+ getWacApprovalUrls: () => getWacApprovalUrls,
26518
26623
  getVolumeStorage: () => getVolumeStorage,
26519
26624
  getVariableValue: () => getVariableValue,
26520
26625
  getVariable: () => getVariable,
@@ -27044,7 +27149,7 @@ var init_auth = __esm(async () => {
27044
27149
  });
27045
27150
 
27046
27151
  // src/core/constants.ts
27047
- var WM_FORK_PREFIX = "wm-fork", VERSION = "1.769.0-gitsync.0";
27152
+ var WM_FORK_PREFIX = "wm-fork", VERSION = "1.771.0";
27048
27153
 
27049
27154
  // src/utils/git.ts
27050
27155
  var exports_git = {};
@@ -49576,7 +49681,7 @@ var require_zipEntries = __commonJS((exports, module) => {
49576
49681
  if (this.centralDirRecords !== this.files.length) {
49577
49682
  if (this.centralDirRecords !== 0 && this.files.length === 0) {
49578
49683
  throw new Error("Corrupted zip or bug: expected " + this.centralDirRecords + " records in central dir, got " + this.files.length);
49579
- } else {}
49684
+ }
49580
49685
  }
49581
49686
  },
49582
49687
  readEndOfCentral: function() {
@@ -58010,7 +58115,7 @@ var require_loader = __commonJS((exports, module) => {
58010
58115
  var error2 = generateError(state, message);
58011
58116
  if (state.onWarning) {
58012
58117
  state.onWarning.call(null, error2);
58013
- } else {}
58118
+ }
58014
58119
  }
58015
58120
  var directiveHandlers = {
58016
58121
  YAML: function handleYamlDirective(state, name, args) {
@@ -58548,7 +58653,7 @@ var require_loader = __commonJS((exports, module) => {
58548
58653
  } else if (detectedIndent) {
58549
58654
  sc.value += common3.repeat(`
58550
58655
  `, emptyLines + 1);
58551
- } else {}
58656
+ }
58552
58657
  detectedIndent = true;
58553
58658
  emptyLines = 0;
58554
58659
  captureStart = state.position;
@@ -82066,15 +82171,43 @@ workflow<T>(fn: (...args: any[]) => Promise<T>): void
82066
82171
  /**
82067
82172
  * Suspend the workflow and wait for an external approval.
82068
82173
  *
82069
- * Use \`getResumeUrls()\` (wrapped in \`step()\`) to obtain resume/cancel/approvalPage
82070
- * URLs before calling this function.
82174
+ * Pass \`key\` to name the step, then \`getApprovalUrls(key)\` yields the URLs that
82175
+ * resume exactly this approval — route them through your own channel. Without a
82176
+ * key the steps are named \`approval\`, \`approval_2\`, ...
82071
82177
  *
82072
82178
  * @example
82073
- * const urls = await step("urls", () => getResumeUrls());
82074
- * await step("notify", () => sendEmail(urls.approvalPage));
82075
- * const { value, approver } = await waitForApproval({ timeout: 3600 });
82179
+ * const urls = await step("urls", () => getApprovalUrls("manager"));
82180
+ * await step("notify", () => sendEmail(urls.resume, urls.cancel));
82181
+ * const { value, approver } = await waitForApproval({ key: "manager", timeout: 3600 });
82076
82182
  */
82077
- waitForApproval(options?: { timeout?: number; form?: object; selfApproval?: boolean; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
82183
+ waitForApproval(options?: { timeout?: number; form?: object; selfApproval?: boolean; key?: string; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
82184
+
82185
+ /**
82186
+ * Resume/cancel/approval-page URLs bound to one \`waitForApproval\` step.
82187
+ *
82188
+ * Unlike \`getResumeUrls()\`, which signs a random nonce, these address the very
82189
+ * \`resume_job\` record the step's built-in approval buttons use, so they are
82190
+ * stable across replays and safe to embed in a custom notification.
82191
+ *
82192
+ * \`stepKey\` must match the \`key\` given to \`waitForApproval\`. Keys must be unique
82193
+ * within a workflow; reusing one throws rather than silently renaming it. The URL
82194
+ * only resumes while that step is awaiting approval; used at any other moment it is
82195
+ * rejected rather than banking a row a different approval would consume. Send it
82196
+ * ahead of time — approvers just cannot act before the workflow reaches the step.
82197
+ *
82198
+ * \`resume\` and \`cancel\` are step-bound; \`approvalPage\` is not — it opens the job's
82199
+ * approval page, which acts on whichever approval is pending when it is used.
82200
+ *
82201
+ * @example
82202
+ * const urls = await step("urls", () => getApprovalUrls("manager"));
82203
+ * await step("notify", () => sendEmail(urls.resume, urls.cancel));
82204
+ * await waitForApproval({ key: "manager" });
82205
+ */
82206
+ async getApprovalUrls(stepKey: string = "approval", approver?: string): Promise<{
82207
+ approvalPage: string;
82208
+ resume: string;
82209
+ cancel: string;
82210
+ }>
82078
82211
 
82079
82212
  /**
82080
82213
  * Process items in parallel with optional concurrency control.
@@ -82830,15 +82963,43 @@ workflow<T>(fn: (...args: any[]) => Promise<T>): void
82830
82963
  /**
82831
82964
  * Suspend the workflow and wait for an external approval.
82832
82965
  *
82833
- * Use \`getResumeUrls()\` (wrapped in \`step()\`) to obtain resume/cancel/approvalPage
82834
- * URLs before calling this function.
82966
+ * Pass \`key\` to name the step, then \`getApprovalUrls(key)\` yields the URLs that
82967
+ * resume exactly this approval — route them through your own channel. Without a
82968
+ * key the steps are named \`approval\`, \`approval_2\`, ...
82835
82969
  *
82836
82970
  * @example
82837
- * const urls = await step("urls", () => getResumeUrls());
82838
- * await step("notify", () => sendEmail(urls.approvalPage));
82839
- * const { value, approver } = await waitForApproval({ timeout: 3600 });
82971
+ * const urls = await step("urls", () => getApprovalUrls("manager"));
82972
+ * await step("notify", () => sendEmail(urls.resume, urls.cancel));
82973
+ * const { value, approver } = await waitForApproval({ key: "manager", timeout: 3600 });
82840
82974
  */
82841
- waitForApproval(options?: { timeout?: number; form?: object; selfApproval?: boolean; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
82975
+ waitForApproval(options?: { timeout?: number; form?: object; selfApproval?: boolean; key?: string; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
82976
+
82977
+ /**
82978
+ * Resume/cancel/approval-page URLs bound to one \`waitForApproval\` step.
82979
+ *
82980
+ * Unlike \`getResumeUrls()\`, which signs a random nonce, these address the very
82981
+ * \`resume_job\` record the step's built-in approval buttons use, so they are
82982
+ * stable across replays and safe to embed in a custom notification.
82983
+ *
82984
+ * \`stepKey\` must match the \`key\` given to \`waitForApproval\`. Keys must be unique
82985
+ * within a workflow; reusing one throws rather than silently renaming it. The URL
82986
+ * only resumes while that step is awaiting approval; used at any other moment it is
82987
+ * rejected rather than banking a row a different approval would consume. Send it
82988
+ * ahead of time — approvers just cannot act before the workflow reaches the step.
82989
+ *
82990
+ * \`resume\` and \`cancel\` are step-bound; \`approvalPage\` is not — it opens the job's
82991
+ * approval page, which acts on whichever approval is pending when it is used.
82992
+ *
82993
+ * @example
82994
+ * const urls = await step("urls", () => getApprovalUrls("manager"));
82995
+ * await step("notify", () => sendEmail(urls.resume, urls.cancel));
82996
+ * await waitForApproval({ key: "manager" });
82997
+ */
82998
+ async getApprovalUrls(stepKey: string = "approval", approver?: string): Promise<{
82999
+ approvalPage: string;
83000
+ resume: string;
83001
+ cancel: string;
83002
+ }>
82842
83003
 
82843
83004
  /**
82844
83005
  * Process items in parallel with optional concurrency control.
@@ -83688,15 +83849,43 @@ workflow<T>(fn: (...args: any[]) => Promise<T>): void
83688
83849
  /**
83689
83850
  * Suspend the workflow and wait for an external approval.
83690
83851
  *
83691
- * Use \`getResumeUrls()\` (wrapped in \`step()\`) to obtain resume/cancel/approvalPage
83692
- * URLs before calling this function.
83852
+ * Pass \`key\` to name the step, then \`getApprovalUrls(key)\` yields the URLs that
83853
+ * resume exactly this approval — route them through your own channel. Without a
83854
+ * key the steps are named \`approval\`, \`approval_2\`, ...
83693
83855
  *
83694
83856
  * @example
83695
- * const urls = await step("urls", () => getResumeUrls());
83696
- * await step("notify", () => sendEmail(urls.approvalPage));
83697
- * const { value, approver } = await waitForApproval({ timeout: 3600 });
83857
+ * const urls = await step("urls", () => getApprovalUrls("manager"));
83858
+ * await step("notify", () => sendEmail(urls.resume, urls.cancel));
83859
+ * const { value, approver } = await waitForApproval({ key: "manager", timeout: 3600 });
83698
83860
  */
83699
- waitForApproval(options?: { timeout?: number; form?: object; selfApproval?: boolean; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
83861
+ waitForApproval(options?: { timeout?: number; form?: object; selfApproval?: boolean; key?: string; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
83862
+
83863
+ /**
83864
+ * Resume/cancel/approval-page URLs bound to one \`waitForApproval\` step.
83865
+ *
83866
+ * Unlike \`getResumeUrls()\`, which signs a random nonce, these address the very
83867
+ * \`resume_job\` record the step's built-in approval buttons use, so they are
83868
+ * stable across replays and safe to embed in a custom notification.
83869
+ *
83870
+ * \`stepKey\` must match the \`key\` given to \`waitForApproval\`. Keys must be unique
83871
+ * within a workflow; reusing one throws rather than silently renaming it. The URL
83872
+ * only resumes while that step is awaiting approval; used at any other moment it is
83873
+ * rejected rather than banking a row a different approval would consume. Send it
83874
+ * ahead of time — approvers just cannot act before the workflow reaches the step.
83875
+ *
83876
+ * \`resume\` and \`cancel\` are step-bound; \`approvalPage\` is not — it opens the job's
83877
+ * approval page, which acts on whichever approval is pending when it is used.
83878
+ *
83879
+ * @example
83880
+ * const urls = await step("urls", () => getApprovalUrls("manager"));
83881
+ * await step("notify", () => sendEmail(urls.resume, urls.cancel));
83882
+ * await waitForApproval({ key: "manager" });
83883
+ */
83884
+ async getApprovalUrls(stepKey: string = "approval", approver?: string): Promise<{
83885
+ approvalPage: string;
83886
+ resume: string;
83887
+ cancel: string;
83888
+ }>
83700
83889
 
83701
83890
  /**
83702
83891
  * Process items in parallel with optional concurrency control.
@@ -85282,6 +85471,17 @@ def get_shared_state(path: str = 'state.json') -> None
85282
85471
  # Dictionary with approvalPage, resume, and cancel URLs
85283
85472
  def get_resume_urls(approver: str = None, flow_level: bool = None) -> dict
85284
85473
 
85474
+ # Get the resume URLs bound to one \`\`wait_for_approval\`\` step of this workflow.
85475
+ #
85476
+ # Args:
85477
+ # step_key: Checkpoint key of the approval step, as passed to
85478
+ # \`\`wait_for_approval(key=...)\`\`
85479
+ # approver: Optional approver name
85480
+ #
85481
+ # Returns:
85482
+ # Dictionary with approvalPage, resume, and cancel URLs
85483
+ def get_approval_urls(step_key: str = 'approval', approver: str = None) -> dict
85484
+
85285
85485
  # Sends an interactive approval request via Slack, allowing optional customization of the message, approver, and form fields.
85286
85486
  #
85287
85487
  # **[Enterprise Edition Only]** To include form fields in the Slack approval request, use the "Advanced -> Suspend -> Form" functionality.
@@ -85558,8 +85758,9 @@ async def sleep(seconds: int)
85558
85758
 
85559
85759
  # Suspend the workflow and wait for an external approval.
85560
85760
  #
85561
- # Use \`\`get_resume_urls()\`\` (wrapped in \`\`step()\`\`) to obtain
85562
- # resume/cancel/approval URLs before calling this function.
85761
+ # Pass \`\`key\`\` to name the step, then \`\`get_approval_urls(key)\`\` yields the URLs
85762
+ # that resume exactly this approval route them through your own channel.
85763
+ # Without a key the steps are named \`\`approval\`\`, \`\`approval_2\`\`, ...
85563
85764
  #
85564
85765
  # Returns a dict with \`\`value\`\` (form data), \`\`approver\`\`, and \`\`approved\`\`.
85565
85766
  #
@@ -85567,13 +85768,14 @@ async def sleep(seconds: int)
85567
85768
  # timeout: Approval timeout in seconds (default 1800).
85568
85769
  # form: Optional form schema for the approval page.
85569
85770
  # self_approval: Whether the user who triggered the flow can approve it (default True).
85771
+ # key: Optional checkpoint key naming this approval step.
85570
85772
  #
85571
85773
  # Example::
85572
85774
  #
85573
- # urls = await step("urls", lambda: get_resume_urls())
85574
- # await step("notify", lambda: send_email(urls["approvalPage"]))
85575
- # result = await wait_for_approval(timeout=3600)
85576
- async def wait_for_approval(timeout: int = 1800, form: dict | None = None, self_approval: bool = True) -> dict
85775
+ # urls = await step("urls", lambda: get_approval_urls("manager"))
85776
+ # await step("notify", lambda: send_email(urls["resume"], urls["cancel"]))
85777
+ # result = await wait_for_approval(key="manager", timeout=3600)
85778
+ async def wait_for_approval(timeout: int = 1800, form: dict | None = None, self_approval: bool = True, key: str | None = None) -> dict
85577
85779
 
85578
85780
  # Process items in parallel with optional concurrency control.
85579
85781
  #
@@ -86650,6 +86852,18 @@ const user = await backend.get_user({ user_id: '123' });
86650
86852
 
86651
86853
  The frontend cannot reach datatables, workspace items, or external services on its own — it goes through \`backend.<key>(args)\` for everything server-side.
86652
86854
 
86855
+ ### Keeping data out of recorded demos
86856
+
86857
+ An app can be demoed by recording a session: every interaction becomes a step carrying a snapshot of the page, replayed publicly or on the Hub. Password inputs are masked automatically. Mark anything else that must not appear with \`data-wm-no-record\` — the whole marked subtree is dropped from every snapshot, along with its values and the step's own metadata:
86858
+
86859
+ \`\`\`tsx
86860
+ <label data-wm-no-record>
86861
+ Customer SSN <input value={ssn} onChange={onSsn} />
86862
+ </label>
86863
+ \`\`\`
86864
+
86865
+ Apply it to customer data, internal notes and anything else a viewer of the demo should not see. It costs nothing when the app is never recorded.
86866
+
86653
86867
  ## Backend runnables
86654
86868
 
86655
86869
  Each runnable has a unique key (used to call it from the frontend) and one of four types:
@@ -86752,6 +86966,7 @@ def main(user_id: str):
86752
86966
  3. **Keep runnables focused** — one function per runnable; small surface area.
86753
86967
  4. **Use descriptive keys** — \`get_user\`, not \`a\`.
86754
86968
  5. **Always whitelist tables** — adding a runnable that queries a new table requires the table to be in \`data.tables\` first.
86969
+ 6. **Mark sensitive UI with \`data-wm-no-record\`** — it is what keeps that data out of a recorded demo; passwords are handled for you.
86755
86970
  `,
86756
86971
  triggers: `---
86757
86972
  name: triggers
@@ -87205,7 +87420,7 @@ import {
87205
87420
  step,
87206
87421
  sleep,
87207
87422
  waitForApproval,
87208
- getResumeUrls,
87423
+ getApprovalUrls,
87209
87424
  parallel,
87210
87425
  workflow,
87211
87426
  } from "windmill-client";
@@ -87223,7 +87438,7 @@ export const main = workflow(async (x: string) => {
87223
87438
  Python:
87224
87439
 
87225
87440
  \`\`\`python
87226
- from wmill import task, task_script, task_flow, step, sleep, wait_for_approval, get_resume_urls, parallel, workflow
87441
+ from wmill import task, task_script, task_flow, step, sleep, wait_for_approval, get_approval_urls, parallel, workflow
87227
87442
 
87228
87443
  @task()
87229
87444
  async def process(x: str) -> str:
@@ -87307,12 +87522,13 @@ output = await pipeline(input=data)
87307
87522
  Use \`step()\` for lightweight inline values that must not change during replay:
87308
87523
 
87309
87524
  \`\`\`typescript
87310
- const urls = await step("get_urls", () => getResumeUrls());
87311
87525
  const startedAt = await step("started_at", () => new Date().toISOString());
87312
87526
  \`\`\`
87313
87527
 
87314
87528
  \`\`\`python
87315
- urls = await step("get_urls", lambda: get_resume_urls())
87529
+ from datetime import datetime
87530
+
87531
+ started_at = await step("started_at", lambda: datetime.now().isoformat())
87316
87532
  \`\`\`
87317
87533
 
87318
87534
  Use stable, descriptive step names. Do not generate step names dynamically.
@@ -87337,20 +87553,28 @@ Only parallelize independent steps. Do not read the result of a task before it i
87337
87553
 
87338
87554
  ## Approvals
87339
87555
 
87340
- Generate resume URLs inside \`step()\` before sending them:
87556
+ Name the approval step and generate its URLs inside \`step()\` before sending them.
87557
+ \`getApprovalUrls\` / \`get_approval_urls\` returns the URLs bound to that step, the same
87558
+ ones its built-in approve/reject buttons use:
87341
87559
 
87342
87560
  \`\`\`typescript
87343
- const urls = await step("get_urls", () => getResumeUrls());
87344
- await step("notify", () => sendApprovalEmail(urls.approvalPage));
87345
- const approval = await waitForApproval({ timeout: 3600 });
87561
+ const urls = await step("urls", () => getApprovalUrls("manager"));
87562
+ await step("notify", () => sendApprovalEmail(urls.resume, urls.cancel));
87563
+ const approval = await waitForApproval({ key: "manager", timeout: 3600 });
87346
87564
  \`\`\`
87347
87565
 
87348
87566
  \`\`\`python
87349
- urls = await step("get_urls", lambda: get_resume_urls())
87350
- await step("notify", lambda: send_approval_email(urls["approvalPage"]))
87351
- approval = await wait_for_approval(timeout=3600)
87567
+ urls = await step("urls", lambda: get_approval_urls("manager"))
87568
+ await step("notify", lambda: send_approval_email(urls["resume"], urls["cancel"]))
87569
+ approval = await wait_for_approval(key="manager", timeout=3600)
87352
87570
  \`\`\`
87353
87571
 
87572
+ With several approvals in one workflow, give each its own key so each notification
87573
+ resumes its own step. Keys must be unique — reusing one raises an error rather than
87574
+ silently renaming the step. A minted URL only resumes while its own step is awaiting
87575
+ approval; used at any other moment it is rejected rather than resuming the wrong one. \`getResumeUrls()\` / \`get_resume_urls()\` still works but signs a
87576
+ random nonce, so its URLs are not tied to any particular approval step.
87577
+
87354
87578
  \`selfApproval: false\` and \`self_approval=False\` are Enterprise-only approval behavior. Do not use them unless the user asks for that behavior.
87355
87579
 
87356
87580
  ## Error Handling
@@ -87364,7 +87588,7 @@ TypeScript: avoid broad \`try/catch\` around WAC SDK calls. The SDK uses an inte
87364
87588
 
87365
87589
  ## TypeScript Workflow-as-Code API (windmill-client)
87366
87590
 
87367
- Import: \`import { workflow, task, taskScript, taskFlow, step, sleep, waitForApproval, getResumeUrls, parallel } from "windmill-client"\`
87591
+ Import: \`import { workflow, task, taskScript, taskFlow, step, sleep, waitForApproval, getApprovalUrls, getResumeUrls, parallel } from "windmill-client"\`
87368
87592
 
87369
87593
  \`\`\`typescript
87370
87594
  export interface TaskOptions {
@@ -87434,15 +87658,39 @@ export async function sleep(seconds: number): Promise<void>
87434
87658
  /**
87435
87659
  * Suspend the workflow and wait for an external approval.
87436
87660
  *
87437
- * Use \`getResumeUrls()\` (wrapped in \`step()\`) to obtain resume/cancel/approvalPage
87438
- * URLs before calling this function.
87661
+ * Pass \`key\` to name the step, then \`getApprovalUrls(key)\` yields the URLs that
87662
+ * resume exactly this approval — route them through your own channel. Without a
87663
+ * key the steps are named \`approval\`, \`approval_2\`, ...
87664
+ *
87665
+ * @example
87666
+ * const urls = await step("urls", () => getApprovalUrls("manager"));
87667
+ * await step("notify", () => sendEmail(urls.resume, urls.cancel));
87668
+ * const { value, approver } = await waitForApproval({ key: "manager", timeout: 3600 });
87669
+ */
87670
+ export function waitForApproval(options?: { timeout?: number; form?: object; selfApproval?: boolean; key?: string; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
87671
+
87672
+ /**
87673
+ * Resume/cancel/approval-page URLs bound to one \`waitForApproval\` step.
87674
+ *
87675
+ * Unlike \`getResumeUrls()\`, which signs a random nonce, these address the very
87676
+ * \`resume_job\` record the step's built-in approval buttons use, so they are
87677
+ * stable across replays and safe to embed in a custom notification.
87678
+ *
87679
+ * \`stepKey\` must match the \`key\` given to \`waitForApproval\`. Keys must be unique
87680
+ * within a workflow; reusing one throws rather than silently renaming it. The URL
87681
+ * only resumes while that step is awaiting approval; used at any other moment it is
87682
+ * rejected rather than banking a row a different approval would consume. Send it
87683
+ * ahead of time — approvers just cannot act before the workflow reaches the step.
87684
+ *
87685
+ * \`resume\` and \`cancel\` are step-bound; \`approvalPage\` is not — it opens the job's
87686
+ * approval page, which acts on whichever approval is pending when it is used.
87439
87687
  *
87440
87688
  * @example
87441
- * const urls = await step("urls", () => getResumeUrls());
87442
- * await step("notify", () => sendEmail(urls.approvalPage));
87443
- * const { value, approver } = await waitForApproval({ timeout: 3600 });
87689
+ * const urls = await step("urls", () => getApprovalUrls("manager"));
87690
+ * await step("notify", () => sendEmail(urls.resume, urls.cancel));
87691
+ * await waitForApproval({ key: "manager" });
87444
87692
  */
87445
- export function waitForApproval(options?: { timeout?: number; form?: object; selfApproval?: boolean; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
87693
+ export async function getApprovalUrls(stepKey: string = "approval", approver?: string): Promise<{ approvalPage: string; resume: string; cancel: string; }>
87446
87694
 
87447
87695
  /**
87448
87696
  * Process items in parallel with optional concurrency control.
@@ -87460,7 +87708,7 @@ export async function parallel<T, R>(items: T[], fn: (item: T) => PromiseLike<R>
87460
87708
 
87461
87709
  ## Python Workflow-as-Code API (wmill)
87462
87710
 
87463
- Import: \`from wmill import workflow, task, task_script, task_flow, step, sleep, wait_for_approval, get_resume_urls, parallel, TaskError\`
87711
+ Import: \`from wmill import workflow, task, task_script, task_flow, step, sleep, wait_for_approval, get_approval_urls, get_resume_urls, parallel, TaskError\`
87464
87712
 
87465
87713
  \`\`\`python
87466
87714
  # Raised when a WAC task step failed.
@@ -87548,8 +87796,9 @@ async def sleep(seconds: int)
87548
87796
 
87549
87797
  # Suspend the workflow and wait for an external approval.
87550
87798
  #
87551
- # Use \`\`get_resume_urls()\`\` (wrapped in \`\`step()\`\`) to obtain
87552
- # resume/cancel/approval URLs before calling this function.
87799
+ # Pass \`\`key\`\` to name the step, then \`\`get_approval_urls(key)\`\` yields the URLs
87800
+ # that resume exactly this approval route them through your own channel.
87801
+ # Without a key the steps are named \`\`approval\`\`, \`\`approval_2\`\`, ...
87553
87802
  #
87554
87803
  # Returns a dict with \`\`value\`\` (form data), \`\`approver\`\`, and \`\`approved\`\`.
87555
87804
  #
@@ -87557,13 +87806,37 @@ async def sleep(seconds: int)
87557
87806
  # timeout: Approval timeout in seconds (default 1800).
87558
87807
  # form: Optional form schema for the approval page.
87559
87808
  # self_approval: Whether the user who triggered the flow can approve it (default True).
87809
+ # key: Optional checkpoint key naming this approval step.
87560
87810
  #
87561
87811
  # Example::
87562
87812
  #
87563
- # urls = await step("urls", lambda: get_resume_urls())
87564
- # await step("notify", lambda: send_email(urls["approvalPage"]))
87565
- # result = await wait_for_approval(timeout=3600)
87566
- async def wait_for_approval(timeout: int = 1800, form: dict | None = None, self_approval: bool = True) -> dict
87813
+ # urls = await step("urls", lambda: get_approval_urls("manager"))
87814
+ # await step("notify", lambda: send_email(urls["resume"], urls["cancel"]))
87815
+ # result = await wait_for_approval(key="manager", timeout=3600)
87816
+ async def wait_for_approval(timeout: int = 1800, form: dict | None = None, self_approval: bool = True, key: str | None = None) -> dict
87817
+
87818
+ # Get the resume/cancel/approval-page URLs bound to one \`\`wait_for_approval\`\` step.
87819
+ #
87820
+ # Unlike :func:\`get_resume_urls\`, which signs a random nonce, these address the
87821
+ # very \`\`resume_job\`\` record the step's built-in approval buttons use, so they
87822
+ # are stable across replays and safe to embed in a custom notification.
87823
+ #
87824
+ # Args:
87825
+ # step_key: Checkpoint key of the approval step, as passed to
87826
+ # \`\`wait_for_approval(key=...)\`\`. Keys must be unique within a workflow;
87827
+ # reusing one raises rather than silently renaming it. The URL only
87828
+ # resumes while that step is awaiting approval; used at any other moment
87829
+ # it is rejected rather than banking a row a different approval would
87830
+ # consume. Send it ahead of time — approvers just cannot act before the
87831
+ # workflow reaches the step.
87832
+ # \`\`resume\`\` and \`\`cancel\`\` are step-bound; \`\`approvalPage\`\` is not — it
87833
+ # opens the job's approval page, which acts on whichever approval is
87834
+ # pending when it is used.
87835
+ # approver: Optional approver name
87836
+ #
87837
+ # Returns:
87838
+ # Dictionary with approvalPage, resume, and cancel URLs
87839
+ def get_approval_urls(step_key: str = 'approval', approver: str = None) -> dict
87567
87840
 
87568
87841
  # Process items in parallel with optional concurrency control.
87569
87842
  #
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "windmill-cli",
3
- "version": "1.769.1",
3
+ "version": "1.771.0",
4
4
  "description": "CLI for Windmill",
5
5
  "license": "Apache 2.0",
6
6
  "type": "module",