windmill-cli 1.654.0 → 1.655.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 +1650 -1306
  2. package/package.json +1 -1
package/esm/main.js CHANGED
@@ -11785,7 +11785,7 @@ var init_OpenAPI = __esm(() => {
11785
11785
  PASSWORD: undefined,
11786
11786
  TOKEN: getEnv2("WM_TOKEN"),
11787
11787
  USERNAME: undefined,
11788
- VERSION: "1.654.0",
11788
+ VERSION: "1.655.0",
11789
11789
  WITH_CREDENTIALS: true,
11790
11790
  interceptors: {
11791
11791
  request: new Interceptors,
@@ -12347,6 +12347,7 @@ __export(exports_services_gen, {
12347
12347
  globalUserRename: () => globalUserRename,
12348
12348
  globalUserDelete: () => globalUserDelete,
12349
12349
  gitRepoViewerFileUpload: () => gitRepoViewerFileUpload,
12350
+ ghesInstallationCallback: () => ghesInstallationCallback,
12350
12351
  getWorkspaceUsage: () => getWorkspaceUsage,
12351
12352
  getWorkspaceSlackOauthConfig: () => getWorkspaceSlackOauthConfig,
12352
12353
  getWorkspaceName: () => getWorkspaceName,
@@ -12451,6 +12452,7 @@ __export(exports_services_gen, {
12451
12452
  getGlobal: () => getGlobal,
12452
12453
  getGithubAppToken: () => getGithubAppToken,
12453
12454
  getGitCommitHash: () => getGitCommitHash,
12455
+ getGhesConfig: () => getGhesConfig,
12454
12456
  getGcpTrigger: () => getGcpTrigger,
12455
12457
  getFolderUsage: () => getFolderUsage,
12456
12458
  getFolderPermissionHistory: () => getFolderPermissionHistory,
@@ -12660,6 +12662,7 @@ __export(exports_services_gen, {
12660
12662
  connectClientCredentials: () => connectClientCredentials,
12661
12663
  connectCallback: () => connectCallback,
12662
12664
  compareWorkspaces: () => compareWorkspaces,
12665
+ commitKafkaOffsets: () => commitKafkaOffsets,
12663
12666
  clearIndex: () => clearIndex,
12664
12667
  checkS3FolderExists: () => checkS3FolderExists,
12665
12668
  checkInstanceSharingAvailable: () => checkInstanceSharingAvailable,
@@ -13310,6 +13313,21 @@ var backendVersion = () => {
13310
13313
  body: data2.requestBody,
13311
13314
  mediaType: "application/json"
13312
13315
  });
13316
+ }, ghesInstallationCallback = (data2) => {
13317
+ return request(OpenAPI, {
13318
+ method: "POST",
13319
+ url: "/w/{workspace}/github_app/ghes_installation_callback",
13320
+ path: {
13321
+ workspace: data2.workspace
13322
+ },
13323
+ body: data2.requestBody,
13324
+ mediaType: "application/json"
13325
+ });
13326
+ }, getGhesConfig = () => {
13327
+ return request(OpenAPI, {
13328
+ method: "GET",
13329
+ url: "/github_app/ghes_config"
13330
+ });
13313
13331
  }, acceptInvite = (data2) => {
13314
13332
  return request(OpenAPI, {
13315
13333
  method: "POST",
@@ -17229,6 +17247,17 @@ var backendVersion = () => {
17229
17247
  path: data2.path
17230
17248
  }
17231
17249
  });
17250
+ }, commitKafkaOffsets = (data2) => {
17251
+ return request(OpenAPI, {
17252
+ method: "POST",
17253
+ url: "/w/{workspace}/kafka_triggers/commit_offsets/{path}",
17254
+ path: {
17255
+ workspace: data2.workspace,
17256
+ path: data2.path
17257
+ },
17258
+ body: data2.requestBody,
17259
+ mediaType: "application/json"
17260
+ });
17232
17261
  }, createNatsTrigger = (data2) => {
17233
17262
  return request(OpenAPI, {
17234
17263
  method: "POST",
@@ -59333,6 +59362,7 @@ async function bootstrap(opts, scriptPath, language) {
59333
59362
  });
59334
59363
  }
59335
59364
  async function generateMetadata(opts, scriptPath) {
59365
+ warn(colors.yellow('This command is deprecated. Use "wmill generate-metadata" instead.'));
59336
59366
  info("This command only works for workspace scripts, for flows inline scripts use `wmill flow generate-locks`");
59337
59367
  if (scriptPath == "") {
59338
59368
  scriptPath = undefined;
@@ -60551,7 +60581,7 @@ async function generateFlowLockInternal(folder, dryRun, workspace, opts, justUpd
60551
60581
  } else if (dryRun) {
60552
60582
  return remote_path;
60553
60583
  }
60554
- if (Object.keys(filteredDeps).length > 0) {
60584
+ if (Object.keys(filteredDeps).length > 0 && !noStaleMessage) {
60555
60585
  info((await blueColor())(`Found workspace dependencies (${workspaceDependenciesLanguages.map((l) => l.filename).join("/")}) for ${folder}, using them`));
60556
60586
  }
60557
60587
  if (!justUpdateMetadataLock) {
@@ -60564,10 +60594,26 @@ async function generateFlowLockInternal(folder, dryRun, workspace, opts, justUpd
60564
60594
  changedScripts.push(path7);
60565
60595
  }
60566
60596
  }
60567
- info(`Recomputing locks of ${changedScripts.join(", ")} in ${folder}`);
60568
- await replaceInlineScripts(flowValue.value.modules, async (path7) => await readFile7(folder + SEP7 + path7, "utf-8"), exports_log, folder + SEP7, SEP7, changedScripts);
60597
+ if (!noStaleMessage) {
60598
+ info(`Recomputing locks of ${changedScripts.join(", ")} in ${folder}`);
60599
+ }
60600
+ const fileReader = async (path7) => await readFile7(folder + SEP7 + path7, "utf-8");
60601
+ await replaceInlineScripts(flowValue.value.modules, fileReader, exports_log, folder + SEP7, SEP7, changedScripts);
60602
+ if (flowValue.value.failure_module) {
60603
+ await replaceInlineScripts([flowValue.value.failure_module], fileReader, exports_log, folder + SEP7, SEP7, changedScripts);
60604
+ }
60605
+ if (flowValue.value.preprocessor_module) {
60606
+ await replaceInlineScripts([flowValue.value.preprocessor_module], fileReader, exports_log, folder + SEP7, SEP7, changedScripts);
60607
+ }
60569
60608
  flowValue.value = await updateFlow2(workspace, flowValue.value, remote_path, filteredDeps);
60570
- const inlineScripts = extractInlineScripts(flowValue.value.modules, {}, SEP7, opts.defaultTs);
60609
+ const lockAssigner = newPathAssigner(opts.defaultTs ?? "bun");
60610
+ const inlineScripts = extractInlineScripts(flowValue.value.modules, {}, SEP7, opts.defaultTs, lockAssigner);
60611
+ if (flowValue.value.failure_module) {
60612
+ inlineScripts.push(...extractInlineScripts([flowValue.value.failure_module], {}, SEP7, opts.defaultTs, lockAssigner));
60613
+ }
60614
+ if (flowValue.value.preprocessor_module) {
60615
+ inlineScripts.push(...extractInlineScripts([flowValue.value.preprocessor_module], {}, SEP7, opts.defaultTs, lockAssigner));
60616
+ }
60571
60617
  inlineScripts.forEach((s) => {
60572
60618
  writeIfChanged(process.cwd() + SEP7 + folder + SEP7 + s.path, s.content);
60573
60619
  });
@@ -60578,10 +60624,20 @@ async function generateFlowLockInternal(folder, dryRun, workspace, opts, justUpd
60578
60624
  for (const [path7, hash2] of Object.entries(hashes)) {
60579
60625
  await updateMetadataGlobalLock(folder, hash2, path7);
60580
60626
  }
60581
- info(colors.green(`Flow ${remote_path} lockfiles updated`));
60627
+ if (!noStaleMessage) {
60628
+ info(colors.green(`Flow ${remote_path} lockfiles updated`));
60629
+ }
60582
60630
  }
60583
60631
  async function filterWorkspaceDependenciesForFlow(flowValue, rawWorkspaceDependencies, folder) {
60584
- const inlineScripts = extractInlineScripts(structuredClone(flowValue.modules), {}, SEP7, undefined);
60632
+ const clonedValue = structuredClone(flowValue);
60633
+ const depAssigner = newPathAssigner("bun");
60634
+ const inlineScripts = extractInlineScripts(clonedValue.modules, {}, SEP7, undefined, depAssigner);
60635
+ if (clonedValue.failure_module) {
60636
+ inlineScripts.push(...extractInlineScripts([clonedValue.failure_module], {}, SEP7, undefined, depAssigner));
60637
+ }
60638
+ if (clonedValue.preprocessor_module) {
60639
+ inlineScripts.push(...extractInlineScripts([clonedValue.preprocessor_module], {}, SEP7, undefined, depAssigner));
60640
+ }
60585
60641
  const scripts = inlineScripts.filter((s) => !s.is_lock).map((s) => ({ content: s.content, language: s.language }));
60586
60642
  return await filterWorkspaceDependenciesForScripts(scripts, rawWorkspaceDependencies, folder, SEP7);
60587
60643
  }
@@ -60645,6 +60701,7 @@ var init_flow_metadata = __esm(async () => {
60645
60701
  init_log();
60646
60702
  init_yaml();
60647
60703
  init_extractor();
60704
+ init_path_assigner();
60648
60705
  init_script_common();
60649
60706
  init_resource_folders();
60650
60707
  await __promiseAll([
@@ -61038,7 +61095,14 @@ function ZipFSElement(zip, useYaml, defaultTs, resourceTypeToFormatExtension, re
61038
61095
  }
61039
61096
  let inlineScripts;
61040
61097
  try {
61041
- inlineScripts = extractInlineScripts(flow.value.modules, {}, SEP8, defaultTs, undefined, { skipInlineScriptSuffix: getNonDottedPaths() });
61098
+ const assigner = newPathAssigner(defaultTs, { skipInlineScriptSuffix: getNonDottedPaths() });
61099
+ inlineScripts = extractInlineScripts(flow.value.modules, {}, SEP8, defaultTs, assigner, { skipInlineScriptSuffix: getNonDottedPaths() });
61100
+ if (flow.value.failure_module) {
61101
+ inlineScripts.push(...extractInlineScripts([flow.value.failure_module], {}, SEP8, defaultTs, assigner, { skipInlineScriptSuffix: getNonDottedPaths() }));
61102
+ }
61103
+ if (flow.value.preprocessor_module) {
61104
+ inlineScripts.push(...extractInlineScripts([flow.value.preprocessor_module], {}, SEP8, defaultTs, assigner, { skipInlineScriptSuffix: getNonDottedPaths() }));
61105
+ }
61042
61106
  } catch (error2) {
61043
61107
  error(`Failed to extract inline scripts for flow at path: ${p}`);
61044
61108
  throw error2;
@@ -62941,7 +63005,7 @@ function loadParser(pkgName) {
62941
63005
  p = (async () => {
62942
63006
  const mod = await import(pkgName);
62943
63007
  const wasmPath = _require.resolve(`${pkgName}/windmill_parser_wasm_bg.wasm`);
62944
- await mod.default(readFileSync3(wasmPath));
63008
+ await mod.default({ module_or_path: readFileSync3(wasmPath) });
62945
63009
  return mod;
62946
63010
  })();
62947
63011
  _parserCache.set(pkgName, p);
@@ -63035,7 +63099,7 @@ async function generateScriptMetadataInternal(scriptPath, workspace, opts, dryRu
63035
63099
  } else if (dryRun) {
63036
63100
  return `${remotePath} (${language})`;
63037
63101
  }
63038
- if (!justUpdateMetadataLock) {
63102
+ if (!justUpdateMetadataLock && !noStaleMessage) {
63039
63103
  info(colors.gray(`Generating metadata for ${scriptPath}`));
63040
63104
  }
63041
63105
  const metadataParsedContent = metadataWithType?.payload;
@@ -63828,6 +63892,7 @@ var init_raw_apps = __esm(async () => {
63828
63892
  var exports_app_metadata = {};
63829
63893
  __export(exports_app_metadata, {
63830
63894
  inferRunnableSchemaFromFile: () => inferRunnableSchemaFromFile,
63895
+ getAppFolders: () => getAppFolders,
63831
63896
  generateLocksCommand: () => generateLocksCommand,
63832
63897
  generateAppLocksInternal: () => generateAppLocksInternal,
63833
63898
  filterWorkspaceDependenciesForApp: () => filterWorkspaceDependenciesForApp,
@@ -63883,7 +63948,7 @@ async function generateAppLocksInternal(appFolder, rawApp, dryRun, workspace, op
63883
63948
  } else if (dryRun) {
63884
63949
  return remote_path;
63885
63950
  }
63886
- if (Object.keys(filteredDeps).length > 0) {
63951
+ if (Object.keys(filteredDeps).length > 0 && !noStaleMessage) {
63887
63952
  info((await blueColor())(`Found workspace dependencies (${workspaceDependenciesLanguages.map((l) => l.filename).join("/")}) for ${appFolder}, using them`));
63888
63953
  }
63889
63954
  if (!justUpdateMetadataLock) {
@@ -63897,7 +63962,9 @@ async function generateAppLocksInternal(appFolder, rawApp, dryRun, workspace, op
63897
63962
  }
63898
63963
  }
63899
63964
  if (changedScripts.length > 0) {
63900
- info(`Recomputing locks of ${changedScripts.join(", ")} in ${appFolder}`);
63965
+ if (!noStaleMessage) {
63966
+ info(`Recomputing locks of ${changedScripts.join(", ")} in ${appFolder}`);
63967
+ }
63901
63968
  if (rawApp) {
63902
63969
  const runnablesPath = path9.join(appFolder, APP_BACKEND_FOLDER);
63903
63970
  const rawAppFile = appFile;
@@ -63913,7 +63980,7 @@ async function generateAppLocksInternal(appFolder, rawApp, dryRun, workspace, op
63913
63980
  normalAppFile.value = await updateAppInlineScripts(workspace, normalAppFile.value, remote_path, appFolder, filteredDeps, opts.defaultTs);
63914
63981
  writeIfChanged(appFilePath, import_yaml17.stringify(appFile, yamlOptions));
63915
63982
  }
63916
- } else {
63983
+ } else if (!noStaleMessage) {
63917
63984
  info(colors.gray(`No scripts changed in ${appFolder}`));
63918
63985
  }
63919
63986
  }
@@ -63922,7 +63989,9 @@ async function generateAppLocksInternal(appFolder, rawApp, dryRun, workspace, op
63922
63989
  for (const [scriptPath, hash2] of Object.entries(hashes)) {
63923
63990
  await updateMetadataGlobalLock(appFolder, hash2, scriptPath);
63924
63991
  }
63925
- info(colors.green(`App ${remote_path} lockfiles updated`));
63992
+ if (!noStaleMessage) {
63993
+ info(colors.green(`App ${remote_path} lockfiles updated`));
63994
+ }
63926
63995
  }
63927
63996
  async function filterWorkspaceDependenciesForApp(appValue, rawWorkspaceDependencies, folder) {
63928
63997
  const scripts = [];
@@ -66377,6 +66446,7 @@ var init_app = __esm(async () => {
66377
66446
  ]);
66378
66447
  alreadySynced2 = [];
66379
66448
  command11 = new Command().description("app related commands").option("--json", "Output as JSON (for piping to jq)").action(list4).command("list", "list all apps").option("--json", "Output as JSON (for piping to jq)").action(list4).command("get", "get an app's details").arguments("<path:string>").option("--json", "Output as JSON (for piping to jq)").action(get3).command("push", "push a local app ").arguments("<file_path:string> <remote_path:string>").action(push4).command("dev", dev_default).command("lint", lint_default2).command("new", new_default).command("generate-agents", generate_agents_default).command("generate-locks", "re-generate the lockfiles for app runnables inline scripts that have changed").arguments("[app_folder:string]").option("--yes", "Skip confirmation prompt").option("--dry-run", "Perform a dry run without making changes").option("--default-ts <runtime:string>", "Default TypeScript runtime (bun or deno)").action(async (opts, appFolder) => {
66449
+ warn(colors.yellow('This command is deprecated. Use "wmill generate-metadata" instead.'));
66380
66450
  const { generateLocksCommand: generateLocksCommand2 } = await init_app_metadata().then(() => exports_app_metadata);
66381
66451
  await generateLocksCommand2(opts, appFolder);
66382
66452
  });
@@ -69294,7 +69364,14 @@ async function pushFlow(workspace, remotePath, localPath, message) {
69294
69364
  localPath += SEP19;
69295
69365
  }
69296
69366
  const localFlow = await yamlParseFile(localPath + "flow.yaml");
69297
- await replaceInlineScripts(localFlow.value.modules, async (path17) => await readFile14(localPath + path17, "utf-8"), exports_log, localPath, SEP19);
69367
+ const fileReader = async (path17) => await readFile14(localPath + path17, "utf-8");
69368
+ await replaceInlineScripts(localFlow.value.modules, fileReader, exports_log, localPath, SEP19);
69369
+ if (localFlow.value.failure_module) {
69370
+ await replaceInlineScripts([localFlow.value.failure_module], fileReader, exports_log, localPath, SEP19);
69371
+ }
69372
+ if (localFlow.value.preprocessor_module) {
69373
+ await replaceInlineScripts([localFlow.value.preprocessor_module], fileReader, exports_log, localPath, SEP19);
69374
+ }
69298
69375
  if (flow) {
69299
69376
  if (isSuperset(localFlow, flow)) {
69300
69377
  info(colors.green(`Flow ${remotePath} is up to date`));
@@ -69436,7 +69513,14 @@ async function preview2(opts, flowPath) {
69436
69513
  flowPath += SEP19;
69437
69514
  }
69438
69515
  const localFlow = await yamlParseFile(flowPath + "flow.yaml");
69439
- await replaceInlineScripts(localFlow.value.modules, async (path17) => await readFile14(flowPath + path17, "utf-8"), exports_log, flowPath, SEP19);
69516
+ const fileReader = async (path17) => await readFile14(flowPath + path17, "utf-8");
69517
+ await replaceInlineScripts(localFlow.value.modules, fileReader, exports_log, flowPath, SEP19);
69518
+ if (localFlow.value.failure_module) {
69519
+ await replaceInlineScripts([localFlow.value.failure_module], fileReader, exports_log, flowPath, SEP19);
69520
+ }
69521
+ if (localFlow.value.preprocessor_module) {
69522
+ await replaceInlineScripts([localFlow.value.preprocessor_module], fileReader, exports_log, flowPath, SEP19);
69523
+ }
69440
69524
  const input = opts.data ? await resolve6(opts.data) : {};
69441
69525
  if (!opts.silent) {
69442
69526
  info(colors.yellow(`Running flow preview for ${flowPath}...`));
@@ -69466,6 +69550,7 @@ async function preview2(opts, flowPath) {
69466
69550
  }
69467
69551
  }
69468
69552
  async function generateLocks(opts, folder) {
69553
+ warn(colors.yellow('This command is deprecated. Use "wmill generate-metadata" instead.'));
69469
69554
  const workspace = await resolveWorkspace(opts);
69470
69555
  await requireLogin(opts);
69471
69556
  opts = await mergeConfigWithConfigFile(opts);
@@ -72174,25 +72259,25 @@ import { stat as stat15, writeFile as writeFile19, rm as rm4, mkdir as mkdir8 }
72174
72259
 
72175
72260
  // src/guidance/skills.ts
72176
72261
  var SKILLS = [
72177
- { name: "write-script-go", description: "MUST use when writing Go scripts.", languageKey: "go" },
72178
- { name: "write-script-java", description: "MUST use when writing Java scripts.", languageKey: "java" },
72179
- { name: "write-script-graphql", description: "MUST use when writing GraphQL queries.", languageKey: "graphql" },
72180
- { name: "write-script-rust", description: "MUST use when writing Rust scripts.", languageKey: "rust" },
72181
- { name: "write-script-bunnative", description: "MUST use when writing Bun Native scripts.", languageKey: "bunnative" },
72182
- { name: "write-script-postgresql", description: "MUST use when writing PostgreSQL queries.", languageKey: "postgresql" },
72183
- { name: "write-script-php", description: "MUST use when writing PHP scripts.", languageKey: "php" },
72262
+ { name: "write-script-bash", description: "MUST use when writing Bash scripts.", languageKey: "bash" },
72184
72263
  { name: "write-script-bigquery", description: "MUST use when writing BigQuery queries.", languageKey: "bigquery" },
72185
72264
  { name: "write-script-bun", description: "MUST use when writing Bun/TypeScript scripts.", languageKey: "bun" },
72265
+ { name: "write-script-bunnative", description: "MUST use when writing Bun Native scripts.", languageKey: "bunnative" },
72186
72266
  { name: "write-script-csharp", description: "MUST use when writing C# scripts.", languageKey: "csharp" },
72187
- { name: "write-script-mssql", description: "MUST use when writing MS SQL Server queries.", languageKey: "mssql" },
72188
72267
  { name: "write-script-deno", description: "MUST use when writing Deno/TypeScript scripts.", languageKey: "deno" },
72268
+ { name: "write-script-duckdb", description: "MUST use when writing DuckDB queries.", languageKey: "duckdb" },
72269
+ { name: "write-script-go", description: "MUST use when writing Go scripts.", languageKey: "go" },
72270
+ { name: "write-script-graphql", description: "MUST use when writing GraphQL queries.", languageKey: "graphql" },
72271
+ { name: "write-script-java", description: "MUST use when writing Java scripts.", languageKey: "java" },
72272
+ { name: "write-script-mssql", description: "MUST use when writing MS SQL Server queries.", languageKey: "mssql" },
72189
72273
  { name: "write-script-mysql", description: "MUST use when writing MySQL queries.", languageKey: "mysql" },
72274
+ { name: "write-script-nativets", description: "MUST use when writing Native TypeScript scripts.", languageKey: "nativets" },
72275
+ { name: "write-script-php", description: "MUST use when writing PHP scripts.", languageKey: "php" },
72276
+ { name: "write-script-postgresql", description: "MUST use when writing PostgreSQL queries.", languageKey: "postgresql" },
72190
72277
  { name: "write-script-powershell", description: "MUST use when writing PowerShell scripts.", languageKey: "powershell" },
72191
- { name: "write-script-snowflake", description: "MUST use when writing Snowflake queries.", languageKey: "snowflake" },
72192
72278
  { name: "write-script-python3", description: "MUST use when writing Python scripts.", languageKey: "python3" },
72193
- { name: "write-script-duckdb", description: "MUST use when writing DuckDB queries.", languageKey: "duckdb" },
72194
- { name: "write-script-bash", description: "MUST use when writing Bash scripts.", languageKey: "bash" },
72195
- { name: "write-script-nativets", description: "MUST use when writing Native TypeScript scripts.", languageKey: "nativets" },
72279
+ { name: "write-script-rust", description: "MUST use when writing Rust scripts.", languageKey: "rust" },
72280
+ { name: "write-script-snowflake", description: "MUST use when writing Snowflake queries.", languageKey: "snowflake" },
72196
72281
  { name: "write-flow", description: "MUST use when creating flows." },
72197
72282
  { name: "raw-app", description: "MUST use when creating raw apps." },
72198
72283
  { name: "triggers", description: "MUST use when configuring triggers." },
@@ -72201,294 +72286,116 @@ var SKILLS = [
72201
72286
  { name: "cli-commands", description: "MUST use when using the CLI." }
72202
72287
  ];
72203
72288
  var SKILL_CONTENT = {
72204
- "write-script-go": `---
72205
- name: write-script-go
72206
- description: MUST use when writing Go scripts.
72289
+ "write-script-bash": `---
72290
+ name: write-script-bash
72291
+ description: MUST use when writing Bash scripts.
72207
72292
  ---
72208
72293
 
72209
72294
  ## CLI Commands
72210
72295
 
72211
- Place scripts in a folder. After writing, run:
72296
+ Place scripts in a folder. After writing, tell the user they can run:
72212
72297
  - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
72213
72298
  - \`wmill sync push\` - Deploy to Windmill
72214
72299
 
72300
+ Do NOT run these commands yourself. Instead, inform the user that they should run them.
72301
+
72215
72302
  Use \`wmill resource-type list --schema\` to discover available resource types.
72216
72303
 
72217
- # Go
72304
+ # Bash
72218
72305
 
72219
72306
  ## Structure
72220
72307
 
72221
- The file package must be \`inner\` and export a function called \`main\`:
72308
+ Do not include \`#!/bin/bash\`. Arguments are obtained as positional parameters:
72222
72309
 
72223
- \`\`\`go
72224
- package inner
72310
+ \`\`\`bash
72311
+ # Get arguments
72312
+ var1="$1"
72313
+ var2="$2"
72225
72314
 
72226
- func main(param1 string, param2 int) (map[string]interface{}, error) {
72227
- return map[string]interface{}{
72228
- "result": param1,
72229
- "count": param2,
72230
- }, nil
72231
- }
72315
+ echo "Processing $var1 and $var2"
72316
+
72317
+ # Return JSON by echoing to stdout
72318
+ echo "{\\"result\\": \\"$var1\\", \\"count\\": $var2}"
72232
72319
  \`\`\`
72233
72320
 
72234
72321
  **Important:**
72235
- - Package must be \`inner\`
72236
- - Return type must be \`({return_type}, error)\`
72237
- - Function name is \`main\` (lowercase)
72238
-
72239
- ## Return Types
72322
+ - Do not include shebang (\`#!/bin/bash\`)
72323
+ - Arguments are always strings
72324
+ - Access with \`$1\`, \`$2\`, etc.
72240
72325
 
72241
- The return type can be any Go type that can be serialized to JSON:
72326
+ ## Output
72242
72327
 
72243
- \`\`\`go
72244
- package inner
72328
+ The script output is captured as the result. For structured data, output valid JSON:
72245
72329
 
72246
- type Result struct {
72247
- Name string \`json:"name"\`
72248
- Count int \`json:"count"\`
72249
- }
72330
+ \`\`\`bash
72331
+ name="$1"
72332
+ count="$2"
72250
72333
 
72251
- func main(name string, count int) (Result, error) {
72252
- return Result{
72253
- Name: name,
72254
- Count: count,
72255
- }, nil
72334
+ # Output JSON result
72335
+ cat << EOF
72336
+ {
72337
+ "name": "$name",
72338
+ "count": $count,
72339
+ "timestamp": "$(date -Iseconds)"
72256
72340
  }
72341
+ EOF
72257
72342
  \`\`\`
72258
72343
 
72259
- ## Error Handling
72260
-
72261
- Return errors as the second return value:
72262
-
72263
- \`\`\`go
72264
- package inner
72344
+ ## Environment Variables
72265
72345
 
72266
- import "errors"
72346
+ Environment variables set in Windmill are available:
72267
72347
 
72268
- func main(value int) (string, error) {
72269
- if value < 0 {
72270
- return "", errors.New("value must be positive")
72271
- }
72272
- return "success", nil
72273
- }
72348
+ \`\`\`bash
72349
+ # Access environment variable
72350
+ echo "Workspace: $WM_WORKSPACE"
72351
+ echo "Job ID: $WM_JOB_ID"
72274
72352
  \`\`\`
72275
72353
  `,
72276
- "write-script-java": `---
72277
- name: write-script-java
72278
- description: MUST use when writing Java scripts.
72354
+ "write-script-bigquery": `---
72355
+ name: write-script-bigquery
72356
+ description: MUST use when writing BigQuery queries.
72279
72357
  ---
72280
72358
 
72281
72359
  ## CLI Commands
72282
72360
 
72283
- Place scripts in a folder. After writing, run:
72361
+ Place scripts in a folder. After writing, tell the user they can run:
72284
72362
  - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
72285
72363
  - \`wmill sync push\` - Deploy to Windmill
72286
72364
 
72287
- Use \`wmill resource-type list --schema\` to discover available resource types.
72288
-
72289
- # Java
72290
-
72291
- The script must contain a Main public class with a \`public static main()\` method:
72292
-
72293
- \`\`\`java
72294
- public class Main {
72295
- public static Object main(String name, int count) {
72296
- java.util.Map<String, Object> result = new java.util.HashMap<>();
72297
- result.put("name", name);
72298
- result.put("count", count);
72299
- return result;
72300
- }
72301
- }
72302
- \`\`\`
72303
-
72304
- **Important:**
72305
- - Class must be named \`Main\`
72306
- - Method must be \`public static Object main(...)\`
72307
- - Return type is \`Object\` or \`void\`
72308
-
72309
- ## Maven Dependencies
72310
-
72311
- Add dependencies using comments at the top:
72312
-
72313
- \`\`\`java
72314
- //requirements:
72315
- //com.google.code.gson:gson:2.10.1
72316
- //org.apache.httpcomponents:httpclient:4.5.14
72317
-
72318
- import com.google.gson.Gson;
72319
-
72320
- public class Main {
72321
- public static Object main(String input) {
72322
- Gson gson = new Gson();
72323
- return gson.fromJson(input, Object.class);
72324
- }
72325
- }
72326
- \`\`\`
72327
- `,
72328
- "write-script-graphql": `---
72329
- name: write-script-graphql
72330
- description: MUST use when writing GraphQL queries.
72331
- ---
72332
-
72333
- ## CLI Commands
72334
-
72335
- Place scripts in a folder. After writing, run:
72336
- - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
72337
- - \`wmill sync push\` - Deploy to Windmill
72365
+ Do NOT run these commands yourself. Instead, inform the user that they should run them.
72338
72366
 
72339
72367
  Use \`wmill resource-type list --schema\` to discover available resource types.
72340
72368
 
72341
- # GraphQL
72342
-
72343
- ## Structure
72344
-
72345
- Write GraphQL queries or mutations. Arguments can be added as query parameters:
72346
-
72347
- \`\`\`graphql
72348
- query GetUser($id: ID!) {
72349
- user(id: $id) {
72350
- id
72351
- name
72352
- email
72353
- }
72354
- }
72355
- \`\`\`
72356
-
72357
- ## Variables
72358
-
72359
- Variables are passed as script arguments and automatically bound to the query:
72369
+ # BigQuery
72360
72370
 
72361
- \`\`\`graphql
72362
- query SearchProducts($query: String!, $limit: Int = 10) {
72363
- products(search: $query, first: $limit) {
72364
- edges {
72365
- node {
72366
- id
72367
- name
72368
- price
72369
- }
72370
- }
72371
- }
72372
- }
72373
- \`\`\`
72371
+ Arguments use \`@name\` syntax.
72374
72372
 
72375
- ## Mutations
72373
+ Name the parameters by adding comments before the statement:
72376
72374
 
72377
- \`\`\`graphql
72378
- mutation CreateUser($input: CreateUserInput!) {
72379
- createUser(input: $input) {
72380
- id
72381
- name
72382
- createdAt
72383
- }
72384
- }
72375
+ \`\`\`sql
72376
+ -- @name1 (string)
72377
+ -- @name2 (int64) = 0
72378
+ SELECT * FROM users WHERE name = @name1 AND age > @name2;
72385
72379
  \`\`\`
72386
72380
  `,
72387
- "write-script-rust": `---
72388
- name: write-script-rust
72389
- description: MUST use when writing Rust scripts.
72381
+ "write-script-bun": `---
72382
+ name: write-script-bun
72383
+ description: MUST use when writing Bun/TypeScript scripts.
72390
72384
  ---
72391
72385
 
72392
72386
  ## CLI Commands
72393
72387
 
72394
- Place scripts in a folder. After writing, run:
72388
+ Place scripts in a folder. After writing, tell the user they can run:
72395
72389
  - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
72396
72390
  - \`wmill sync push\` - Deploy to Windmill
72397
72391
 
72398
- Use \`wmill resource-type list --schema\` to discover available resource types.
72399
-
72400
- # Rust
72401
-
72402
- ## Structure
72403
-
72404
- The script must contain a function called \`main\` with proper return type:
72405
-
72406
- \`\`\`rust
72407
- use anyhow::anyhow;
72408
- use serde::Serialize;
72409
-
72410
- #[derive(Serialize, Debug)]
72411
- struct ReturnType {
72412
- result: String,
72413
- count: i32,
72414
- }
72415
-
72416
- fn main(param1: String, param2: i32) -> anyhow::Result<ReturnType> {
72417
- Ok(ReturnType {
72418
- result: param1,
72419
- count: param2,
72420
- })
72421
- }
72422
- \`\`\`
72423
-
72424
- **Important:**
72425
- - Arguments should be owned types
72426
- - Return type must be serializable (\`#[derive(Serialize)]\`)
72427
- - Return type is \`anyhow::Result<T>\`
72428
-
72429
- ## Dependencies
72430
-
72431
- Packages must be specified with a partial cargo.toml at the beginning of the script:
72432
-
72433
- \`\`\`rust
72434
- //! \`\`\`cargo
72435
- //! [dependencies]
72436
- //! anyhow = "1.0.86"
72437
- //! reqwest = { version = "0.11", features = ["json"] }
72438
- //! tokio = { version = "1", features = ["full"] }
72439
- //! \`\`\`
72440
-
72441
- use anyhow::anyhow;
72442
- // ... rest of the code
72443
- \`\`\`
72444
-
72445
- **Note:** Serde is already included, no need to add it again.
72446
-
72447
- ## Async Functions
72448
-
72449
- If you need to handle async functions (e.g., using tokio), keep the main function sync and create the runtime inside:
72450
-
72451
- \`\`\`rust
72452
- //! \`\`\`cargo
72453
- //! [dependencies]
72454
- //! anyhow = "1.0.86"
72455
- //! tokio = { version = "1", features = ["full"] }
72456
- //! reqwest = { version = "0.11", features = ["json"] }
72457
- //! \`\`\`
72458
-
72459
- use anyhow::anyhow;
72460
- use serde::Serialize;
72461
-
72462
- #[derive(Serialize, Debug)]
72463
- struct Response {
72464
- data: String,
72465
- }
72466
-
72467
- fn main(url: String) -> anyhow::Result<Response> {
72468
- let rt = tokio::runtime::Runtime::new()?;
72469
- rt.block_on(async {
72470
- let resp = reqwest::get(&url).await?.text().await?;
72471
- Ok(Response { data: resp })
72472
- })
72473
- }
72474
- \`\`\`
72475
- `,
72476
- "write-script-bunnative": `---
72477
- name: write-script-bunnative
72478
- description: MUST use when writing Bun Native scripts.
72479
- ---
72480
-
72481
- ## CLI Commands
72482
-
72483
- Place scripts in a folder. After writing, run:
72484
- - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
72485
- - \`wmill sync push\` - Deploy to Windmill
72392
+ Do NOT run these commands yourself. Instead, inform the user that they should run them.
72486
72393
 
72487
72394
  Use \`wmill resource-type list --schema\` to discover available resource types.
72488
72395
 
72489
- # TypeScript (Bun Native)
72396
+ # TypeScript (Bun)
72490
72397
 
72491
- Native TypeScript execution with fetch only - no external imports allowed.
72398
+ Bun runtime with full npm ecosystem and fastest execution.
72492
72399
 
72493
72400
  ## Structure
72494
72401
 
@@ -72501,7 +72408,7 @@ export async function main(param1: string, param2: number) {
72501
72408
  }
72502
72409
  \`\`\`
72503
72410
 
72504
- Do not call the main function.
72411
+ Do not call the main function. Libraries are installed automatically.
72505
72412
 
72506
72413
  ## Resource Types
72507
72414
 
@@ -72521,18 +72428,20 @@ Before using a resource type, check the \`rt.d.ts\` file in the project root to
72521
72428
 
72522
72429
  ## Imports
72523
72430
 
72524
- **No imports allowed.** Use the globally available \`fetch\` function:
72525
-
72526
72431
  \`\`\`typescript
72527
- export async function main(url: string) {
72528
- const response = await fetch(url);
72529
- return await response.json();
72530
- }
72432
+ import Stripe from "stripe";
72433
+ import { someFunction } from "some-package";
72531
72434
  \`\`\`
72532
72435
 
72533
72436
  ## Windmill Client
72534
72437
 
72535
- The windmill client is not available in native TypeScript mode. Use fetch to call APIs directly.
72438
+ Import the windmill client for platform interactions:
72439
+
72440
+ \`\`\`typescript
72441
+ import * as wmill from "windmill-client";
72442
+ \`\`\`
72443
+
72444
+ See the SDK documentation for available methods.
72536
72445
 
72537
72446
  ## Preprocessor Scripts
72538
72447
 
@@ -72602,36 +72511,6 @@ const result: S3Object = await wmill.writeS3File(
72602
72511
 
72603
72512
  Import: import * as wmill from 'windmill-client'
72604
72513
 
72605
- /**
72606
- * Create a SQL template function for PostgreSQL/datatable queries
72607
- * @param name - Database/datatable name (default: "main")
72608
- * @returns SQL template function for building parameterized queries
72609
- * @example
72610
- * let sql = wmill.datatable()
72611
- * let name = 'Robin'
72612
- * let age = 21
72613
- * await sql\`
72614
- * SELECT * FROM friends
72615
- * WHERE name = \${name} AND age = \${age}::int
72616
- * \`.fetch()
72617
- */
72618
- datatable(name: string = "main"): DatatableSqlTemplateFunction
72619
-
72620
- /**
72621
- * Create a SQL template function for DuckDB/ducklake queries
72622
- * @param name - DuckDB database name (default: "main")
72623
- * @returns SQL template function for building parameterized queries
72624
- * @example
72625
- * let sql = wmill.ducklake()
72626
- * let name = 'Robin'
72627
- * let age = 21
72628
- * await sql\`
72629
- * SELECT * FROM friends
72630
- * WHERE name = \${name} AND age = \${age}
72631
- * \`.fetch()
72632
- */
72633
- ducklake(name: string = "main"): SqlTemplateFunction
72634
-
72635
72514
  /**
72636
72515
  * Initialize the Windmill client with authentication token and base URL
72637
72516
  * @param token - Authentication token (defaults to WM_TOKEN env variable)
@@ -73124,144 +73003,64 @@ waitForApproval(options?: { timeout?: number; form?: object; }): PromiseLike<{ v
73124
73003
  * const results = await parallel(items, process, { concurrency: 5 });
73125
73004
  */
73126
73005
  async parallel<T, R>(items: T[], fn: (item: T) => PromiseLike<R> | R, options?: { concurrency?: number },): Promise<R[]>
73127
- `,
73128
- "write-script-postgresql": `---
73129
- name: write-script-postgresql
73130
- description: MUST use when writing PostgreSQL queries.
73131
- ---
73132
-
73133
- ## CLI Commands
73134
73006
 
73135
- Place scripts in a folder. After writing, run:
73136
- - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
73137
- - \`wmill sync push\` - Deploy to Windmill
73138
-
73139
- Use \`wmill resource-type list --schema\` to discover available resource types.
73140
-
73141
- # PostgreSQL
73142
-
73143
- Arguments are obtained directly in the statement with \`$1::{type}\`, \`$2::{type}\`, etc.
73144
-
73145
- Name the parameters by adding comments at the beginning of the script (without specifying the type):
73146
-
73147
- \`\`\`sql
73148
- -- $1 name1
73149
- -- $2 name2 = default_value
73150
- SELECT * FROM users WHERE name = $1::TEXT AND age > $2::INT;
73151
- \`\`\`
73152
- `,
73153
- "write-script-php": `---
73154
- name: write-script-php
73155
- description: MUST use when writing PHP scripts.
73156
- ---
73157
-
73158
- ## CLI Commands
73159
-
73160
- Place scripts in a folder. After writing, run:
73161
- - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
73162
- - \`wmill sync push\` - Deploy to Windmill
73163
-
73164
- Use \`wmill resource-type list --schema\` to discover available resource types.
73165
-
73166
- # PHP
73167
-
73168
- ## Structure
73169
-
73170
- The script must start with \`<?php\` and contain at least one function called \`main\`:
73171
-
73172
- \`\`\`php
73173
- <?php
73174
-
73175
- function main(string $param1, int $param2) {
73176
- return ["result" => $param1, "count" => $param2];
73177
- }
73178
- \`\`\`
73179
-
73180
- ## Resource Types
73181
-
73182
- On Windmill, credentials and configuration are stored in resources and passed as parameters to main.
73183
-
73184
- You need to **redefine** the type of the resources that are needed before the main function. Always check if the class already exists using \`class_exists\`:
73185
-
73186
- \`\`\`php
73187
- <?php
73188
-
73189
- if (!class_exists('Postgresql')) {
73190
- class Postgresql {
73191
- public string $host;
73192
- public int $port;
73193
- public string $user;
73194
- public string $password;
73195
- public string $dbname;
73196
- }
73197
- }
73198
-
73199
- function main(Postgresql $db) {
73200
- // $db contains the database connection details
73201
- }
73202
- \`\`\`
73203
-
73204
- The resource type name has to be exactly as specified.
73205
-
73206
- ## Library Dependencies
73207
-
73208
- Specify library dependencies as comments before the main function:
73209
-
73210
- \`\`\`php
73211
- <?php
73212
-
73213
- // require:
73214
- // guzzlehttp/guzzle
73215
- // stripe/stripe-php@^10.0
73007
+ /**
73008
+ * Commit Kafka offsets for a trigger with auto_commit disabled.
73009
+ * @param triggerPath - Path to the Kafka trigger (from event.wm_trigger.trigger_path)
73010
+ * @param topic - Kafka topic name (from event.topic)
73011
+ * @param partition - Partition number (from event.partition)
73012
+ * @param offset - Message offset to commit (from event.offset)
73013
+ */
73014
+ async commitKafkaOffsets(triggerPath: string, topic: string, partition: number, offset: number,): Promise<void>
73216
73015
 
73217
- function main() {
73218
- // Libraries are available
73219
- }
73220
- \`\`\`
73016
+ /**
73017
+ * Create a SQL template function for PostgreSQL/datatable queries
73018
+ * @param name - Database/datatable name (default: "main")
73019
+ * @returns SQL template function for building parameterized queries
73020
+ * @example
73021
+ * let sql = wmill.datatable()
73022
+ * let name = 'Robin'
73023
+ * let age = 21
73024
+ * await sql\`
73025
+ * SELECT * FROM friends
73026
+ * WHERE name = \${name} AND age = \${age}::int
73027
+ * \`.fetch()
73028
+ */
73029
+ datatable(name: string = "main"): DatatableSqlTemplateFunction
73221
73030
 
73222
- One dependency per line. No need to require autoload, it is already done.
73031
+ /**
73032
+ * Create a SQL template function for DuckDB/ducklake queries
73033
+ * @param name - DuckDB database name (default: "main")
73034
+ * @returns SQL template function for building parameterized queries
73035
+ * @example
73036
+ * let sql = wmill.ducklake()
73037
+ * let name = 'Robin'
73038
+ * let age = 21
73039
+ * await sql\`
73040
+ * SELECT * FROM friends
73041
+ * WHERE name = \${name} AND age = \${age}
73042
+ * \`.fetch()
73043
+ */
73044
+ ducklake(name: string = "main"): SqlTemplateFunction
73223
73045
  `,
73224
- "write-script-bigquery": `---
73225
- name: write-script-bigquery
73226
- description: MUST use when writing BigQuery queries.
73046
+ "write-script-bunnative": `---
73047
+ name: write-script-bunnative
73048
+ description: MUST use when writing Bun Native scripts.
73227
73049
  ---
73228
73050
 
73229
73051
  ## CLI Commands
73230
73052
 
73231
- Place scripts in a folder. After writing, run:
73053
+ Place scripts in a folder. After writing, tell the user they can run:
73232
73054
  - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
73233
73055
  - \`wmill sync push\` - Deploy to Windmill
73234
73056
 
73235
- Use \`wmill resource-type list --schema\` to discover available resource types.
73236
-
73237
- # BigQuery
73238
-
73239
- Arguments use \`@name\` syntax.
73240
-
73241
- Name the parameters by adding comments before the statement:
73242
-
73243
- \`\`\`sql
73244
- -- @name1 (string)
73245
- -- @name2 (int64) = 0
73246
- SELECT * FROM users WHERE name = @name1 AND age > @name2;
73247
- \`\`\`
73248
- `,
73249
- "write-script-bun": `---
73250
- name: write-script-bun
73251
- description: MUST use when writing Bun/TypeScript scripts.
73252
- ---
73253
-
73254
- ## CLI Commands
73255
-
73256
- Place scripts in a folder. After writing, run:
73257
- - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
73258
- - \`wmill sync push\` - Deploy to Windmill
73057
+ Do NOT run these commands yourself. Instead, inform the user that they should run them.
73259
73058
 
73260
73059
  Use \`wmill resource-type list --schema\` to discover available resource types.
73261
73060
 
73262
- # TypeScript (Bun)
73061
+ # TypeScript (Bun Native)
73263
73062
 
73264
- Bun runtime with full npm ecosystem and fastest execution.
73063
+ Native TypeScript execution with fetch only - no external imports allowed.
73265
73064
 
73266
73065
  ## Structure
73267
73066
 
@@ -73274,7 +73073,7 @@ export async function main(param1: string, param2: number) {
73274
73073
  }
73275
73074
  \`\`\`
73276
73075
 
73277
- Do not call the main function. Libraries are installed automatically.
73076
+ Do not call the main function.
73278
73077
 
73279
73078
  ## Resource Types
73280
73079
 
@@ -73294,20 +73093,18 @@ Before using a resource type, check the \`rt.d.ts\` file in the project root to
73294
73093
 
73295
73094
  ## Imports
73296
73095
 
73096
+ **No imports allowed.** Use the globally available \`fetch\` function:
73097
+
73297
73098
  \`\`\`typescript
73298
- import Stripe from "stripe";
73299
- import { someFunction } from "some-package";
73099
+ export async function main(url: string) {
73100
+ const response = await fetch(url);
73101
+ return await response.json();
73102
+ }
73300
73103
  \`\`\`
73301
73104
 
73302
73105
  ## Windmill Client
73303
73106
 
73304
- Import the windmill client for platform interactions:
73305
-
73306
- \`\`\`typescript
73307
- import * as wmill from "windmill-client";
73308
- \`\`\`
73309
-
73310
- See the SDK documentation for available methods.
73107
+ The windmill client is not available in native TypeScript mode. Use fetch to call APIs directly.
73311
73108
 
73312
73109
  ## Preprocessor Scripts
73313
73110
 
@@ -73377,36 +73174,6 @@ const result: S3Object = await wmill.writeS3File(
73377
73174
 
73378
73175
  Import: import * as wmill from 'windmill-client'
73379
73176
 
73380
- /**
73381
- * Create a SQL template function for PostgreSQL/datatable queries
73382
- * @param name - Database/datatable name (default: "main")
73383
- * @returns SQL template function for building parameterized queries
73384
- * @example
73385
- * let sql = wmill.datatable()
73386
- * let name = 'Robin'
73387
- * let age = 21
73388
- * await sql\`
73389
- * SELECT * FROM friends
73390
- * WHERE name = \${name} AND age = \${age}::int
73391
- * \`.fetch()
73392
- */
73393
- datatable(name: string = "main"): DatatableSqlTemplateFunction
73394
-
73395
- /**
73396
- * Create a SQL template function for DuckDB/ducklake queries
73397
- * @param name - DuckDB database name (default: "main")
73398
- * @returns SQL template function for building parameterized queries
73399
- * @example
73400
- * let sql = wmill.ducklake()
73401
- * let name = 'Robin'
73402
- * let age = 21
73403
- * await sql\`
73404
- * SELECT * FROM friends
73405
- * WHERE name = \${name} AND age = \${age}
73406
- * \`.fetch()
73407
- */
73408
- ducklake(name: string = "main"): SqlTemplateFunction
73409
-
73410
73177
  /**
73411
73178
  * Initialize the Windmill client with authentication token and base URL
73412
73179
  * @param token - Authentication token (defaults to WM_TOKEN env variable)
@@ -73899,6 +73666,45 @@ waitForApproval(options?: { timeout?: number; form?: object; }): PromiseLike<{ v
73899
73666
  * const results = await parallel(items, process, { concurrency: 5 });
73900
73667
  */
73901
73668
  async parallel<T, R>(items: T[], fn: (item: T) => PromiseLike<R> | R, options?: { concurrency?: number },): Promise<R[]>
73669
+
73670
+ /**
73671
+ * Commit Kafka offsets for a trigger with auto_commit disabled.
73672
+ * @param triggerPath - Path to the Kafka trigger (from event.wm_trigger.trigger_path)
73673
+ * @param topic - Kafka topic name (from event.topic)
73674
+ * @param partition - Partition number (from event.partition)
73675
+ * @param offset - Message offset to commit (from event.offset)
73676
+ */
73677
+ async commitKafkaOffsets(triggerPath: string, topic: string, partition: number, offset: number,): Promise<void>
73678
+
73679
+ /**
73680
+ * Create a SQL template function for PostgreSQL/datatable queries
73681
+ * @param name - Database/datatable name (default: "main")
73682
+ * @returns SQL template function for building parameterized queries
73683
+ * @example
73684
+ * let sql = wmill.datatable()
73685
+ * let name = 'Robin'
73686
+ * let age = 21
73687
+ * await sql\`
73688
+ * SELECT * FROM friends
73689
+ * WHERE name = \${name} AND age = \${age}::int
73690
+ * \`.fetch()
73691
+ */
73692
+ datatable(name: string = "main"): DatatableSqlTemplateFunction
73693
+
73694
+ /**
73695
+ * Create a SQL template function for DuckDB/ducklake queries
73696
+ * @param name - DuckDB database name (default: "main")
73697
+ * @returns SQL template function for building parameterized queries
73698
+ * @example
73699
+ * let sql = wmill.ducklake()
73700
+ * let name = 'Robin'
73701
+ * let age = 21
73702
+ * await sql\`
73703
+ * SELECT * FROM friends
73704
+ * WHERE name = \${name} AND age = \${age}
73705
+ * \`.fetch()
73706
+ */
73707
+ ducklake(name: string = "main"): SqlTemplateFunction
73902
73708
  `,
73903
73709
  "write-script-csharp": `---
73904
73710
  name: write-script-csharp
@@ -73907,10 +73713,12 @@ description: MUST use when writing C# scripts.
73907
73713
 
73908
73714
  ## CLI Commands
73909
73715
 
73910
- Place scripts in a folder. After writing, run:
73716
+ Place scripts in a folder. After writing, tell the user they can run:
73911
73717
  - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
73912
73718
  - \`wmill sync push\` - Deploy to Windmill
73913
73719
 
73720
+ Do NOT run these commands yourself. Instead, inform the user that they should run them.
73721
+
73914
73722
  Use \`wmill resource-type list --schema\` to discover available resource types.
73915
73723
 
73916
73724
  # C#
@@ -73954,31 +73762,6 @@ public class Script
73954
73762
  }
73955
73763
  }
73956
73764
  \`\`\`
73957
- `,
73958
- "write-script-mssql": `---
73959
- name: write-script-mssql
73960
- description: MUST use when writing MS SQL Server queries.
73961
- ---
73962
-
73963
- ## CLI Commands
73964
-
73965
- Place scripts in a folder. After writing, run:
73966
- - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
73967
- - \`wmill sync push\` - Deploy to Windmill
73968
-
73969
- Use \`wmill resource-type list --schema\` to discover available resource types.
73970
-
73971
- # Microsoft SQL Server (MSSQL)
73972
-
73973
- Arguments use \`@P1\`, \`@P2\`, etc.
73974
-
73975
- Name the parameters by adding comments before the statement:
73976
-
73977
- \`\`\`sql
73978
- -- @P1 name1 (varchar)
73979
- -- @P2 name2 (int) = 0
73980
- SELECT * FROM users WHERE name = @P1 AND age > @P2;
73981
- \`\`\`
73982
73765
  `,
73983
73766
  "write-script-deno": `---
73984
73767
  name: write-script-deno
@@ -73987,10 +73770,12 @@ description: MUST use when writing Deno/TypeScript scripts.
73987
73770
 
73988
73771
  ## CLI Commands
73989
73772
 
73990
- Place scripts in a folder. After writing, run:
73773
+ Place scripts in a folder. After writing, tell the user they can run:
73991
73774
  - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
73992
73775
  - \`wmill sync push\` - Deploy to Windmill
73993
73776
 
73777
+ Do NOT run these commands yourself. Instead, inform the user that they should run them.
73778
+
73994
73779
  Use \`wmill resource-type list --schema\` to discover available resource types.
73995
73780
 
73996
73781
  # TypeScript (Deno)
@@ -74115,6 +73900,508 @@ const result: S3Object = await wmill.writeS3File(
74115
73900
 
74116
73901
  Import: import * as wmill from 'windmill-client'
74117
73902
 
73903
+ /**
73904
+ * Initialize the Windmill client with authentication token and base URL
73905
+ * @param token - Authentication token (defaults to WM_TOKEN env variable)
73906
+ * @param baseUrl - API base URL (defaults to BASE_INTERNAL_URL or BASE_URL env variable)
73907
+ */
73908
+ setClient(token?: string, baseUrl?: string): void
73909
+
73910
+ /**
73911
+ * Create a client configuration from env variables
73912
+ * @returns client configuration
73913
+ */
73914
+ getWorkspace(): string
73915
+
73916
+ /**
73917
+ * Get a resource value by path
73918
+ * @param path path of the resource, default to internal state path
73919
+ * @param undefinedIfEmpty if the resource does not exist, return undefined instead of throwing an error
73920
+ * @returns resource value
73921
+ */
73922
+ async getResource(path?: string, undefinedIfEmpty?: boolean): Promise<any>
73923
+
73924
+ /**
73925
+ * Get the true root job id
73926
+ * @param jobId job id to get the root job id from (default to current job)
73927
+ * @returns root job id
73928
+ */
73929
+ async getRootJobId(jobId?: string): Promise<string>
73930
+
73931
+ /**
73932
+ * @deprecated Use runScriptByPath or runScriptByHash instead
73933
+ */
73934
+ async runScript(path: string | null = null, hash_: string | null = null, args: Record<string, any> | null = null, verbose: boolean = false): Promise<any>
73935
+
73936
+ /**
73937
+ * Run a script synchronously by its path and wait for the result
73938
+ * @param path - Script path in Windmill
73939
+ * @param args - Arguments to pass to the script
73940
+ * @param verbose - Enable verbose logging
73941
+ * @returns Script execution result
73942
+ */
73943
+ async runScriptByPath(path: string, args: Record<string, any> | null = null, verbose: boolean = false): Promise<any>
73944
+
73945
+ /**
73946
+ * Run a script synchronously by its hash and wait for the result
73947
+ * @param hash_ - Script hash in Windmill
73948
+ * @param args - Arguments to pass to the script
73949
+ * @param verbose - Enable verbose logging
73950
+ * @returns Script execution result
73951
+ */
73952
+ async runScriptByHash(hash_: string, args: Record<string, any> | null = null, verbose: boolean = false): Promise<any>
73953
+
73954
+ /**
73955
+ * Append a text to the result stream
73956
+ * @param text text to append to the result stream
73957
+ */
73958
+ appendToResultStream(text: string): void
73959
+
73960
+ /**
73961
+ * Stream to the result stream
73962
+ * @param stream stream to stream to the result stream
73963
+ */
73964
+ async streamResult(stream: AsyncIterable<string>): Promise<void>
73965
+
73966
+ /**
73967
+ * Run a flow synchronously by its path and wait for the result
73968
+ * @param path - Flow path in Windmill
73969
+ * @param args - Arguments to pass to the flow
73970
+ * @param verbose - Enable verbose logging
73971
+ * @returns Flow execution result
73972
+ */
73973
+ async runFlow(path: string | null = null, args: Record<string, any> | null = null, verbose: boolean = false): Promise<any>
73974
+
73975
+ /**
73976
+ * Wait for a job to complete and return its result
73977
+ * @param jobId - ID of the job to wait for
73978
+ * @param verbose - Enable verbose logging
73979
+ * @returns Job result when completed
73980
+ */
73981
+ async waitJob(jobId: string, verbose: boolean = false): Promise<any>
73982
+
73983
+ /**
73984
+ * Get the result of a completed job
73985
+ * @param jobId - ID of the completed job
73986
+ * @returns Job result
73987
+ */
73988
+ async getResult(jobId: string): Promise<any>
73989
+
73990
+ /**
73991
+ * Get the result of a job if completed, or its current status
73992
+ * @param jobId - ID of the job
73993
+ * @returns Object with started, completed, success, and result properties
73994
+ */
73995
+ async getResultMaybe(jobId: string): Promise<any>
73996
+
73997
+ /**
73998
+ * @deprecated Use runScriptByPathAsync or runScriptByHashAsync instead
73999
+ */
74000
+ async runScriptAsync(path: string | null, hash_: string | null, args: Record<string, any> | null, scheduledInSeconds: number | null = null): Promise<string>
74001
+
74002
+ /**
74003
+ * Run a script asynchronously by its path
74004
+ * @param path - Script path in Windmill
74005
+ * @param args - Arguments to pass to the script
74006
+ * @param scheduledInSeconds - Schedule execution for a future time (in seconds)
74007
+ * @returns Job ID of the created job
74008
+ */
74009
+ async runScriptByPathAsync(path: string, args: Record<string, any> | null = null, scheduledInSeconds: number | null = null): Promise<string>
74010
+
74011
+ /**
74012
+ * Run a script asynchronously by its hash
74013
+ * @param hash_ - Script hash in Windmill
74014
+ * @param args - Arguments to pass to the script
74015
+ * @param scheduledInSeconds - Schedule execution for a future time (in seconds)
74016
+ * @returns Job ID of the created job
74017
+ */
74018
+ async runScriptByHashAsync(hash_: string, args: Record<string, any> | null = null, scheduledInSeconds: number | null = null): Promise<string>
74019
+
74020
+ /**
74021
+ * Run a flow asynchronously by its path
74022
+ * @param path - Flow path in Windmill
74023
+ * @param args - Arguments to pass to the flow
74024
+ * @param scheduledInSeconds - Schedule execution for a future time (in seconds)
74025
+ * @param doNotTrackInParent - If false, tracks state in parent job (only use when fully awaiting the job)
74026
+ * @returns Job ID of the created job
74027
+ */
74028
+ async runFlowAsync(path: string | null, args: Record<string, any> | null, scheduledInSeconds: number | null = null, // can only be set to false if this the job will be fully await and not concurrent with any other job // as otherwise the child flow and its own child will store their state in the parent job which will // lead to incorrectness and failures doNotTrackInParent: boolean = true): Promise<string>
74029
+
74030
+ /**
74031
+ * Resolve a resource value in case the default value was picked because the input payload was undefined
74032
+ * @param obj resource value or path of the resource under the format \`$res:path\`
74033
+ * @returns resource value
74034
+ */
74035
+ async resolveDefaultResource(obj: any): Promise<any>
74036
+
74037
+ /**
74038
+ * Get the state file path from environment variables
74039
+ * @returns State path string
74040
+ */
74041
+ getStatePath(): string
74042
+
74043
+ /**
74044
+ * Set a resource value by path
74045
+ * @param path path of the resource to set, default to state path
74046
+ * @param value new value of the resource to set
74047
+ * @param initializeToTypeIfNotExist if the resource does not exist, initialize it with this type
74048
+ */
74049
+ async setResource(value: any, path?: string, initializeToTypeIfNotExist?: string): Promise<void>
74050
+
74051
+ /**
74052
+ * Set the state
74053
+ * @param state state to set
74054
+ * @deprecated use setState instead
74055
+ */
74056
+ async setInternalState(state: any): Promise<void>
74057
+
74058
+ /**
74059
+ * Set the state
74060
+ * @param state state to set
74061
+ * @param path Optional state resource path override. Defaults to \`getStatePath()\`.
74062
+ */
74063
+ async setState(state: any, path?: string): Promise<void>
74064
+
74065
+ /**
74066
+ * Set the progress
74067
+ * Progress cannot go back and limited to 0% to 99% range
74068
+ * @param percent Progress to set in %
74069
+ * @param jobId? Job to set progress for
74070
+ */
74071
+ async setProgress(percent: number, jobId?: any): Promise<void>
74072
+
74073
+ /**
74074
+ * Get the progress
74075
+ * @param jobId? Job to get progress from
74076
+ * @returns Optional clamped between 0 and 100 progress value
74077
+ */
74078
+ async getProgress(jobId?: any): Promise<number | null>
74079
+
74080
+ /**
74081
+ * Set a flow user state
74082
+ * @param key key of the state
74083
+ * @param value value of the state
74084
+ */
74085
+ async setFlowUserState(key: string, value: any, errorIfNotPossible?: boolean): Promise<void>
74086
+
74087
+ /**
74088
+ * Get a flow user state
74089
+ * @param path path of the variable
74090
+ */
74091
+ async getFlowUserState(key: string, errorIfNotPossible?: boolean): Promise<any>
74092
+
74093
+ /**
74094
+ * Get the internal state
74095
+ * @deprecated use getState instead
74096
+ */
74097
+ async getInternalState(): Promise<any>
74098
+
74099
+ /**
74100
+ * Get the state shared across executions
74101
+ * @param path Optional state resource path override. Defaults to \`getStatePath()\`.
74102
+ */
74103
+ async getState(path?: string): Promise<any>
74104
+
74105
+ /**
74106
+ * Get a variable by path
74107
+ * @param path path of the variable
74108
+ * @returns variable value
74109
+ */
74110
+ async getVariable(path: string): Promise<string>
74111
+
74112
+ /**
74113
+ * Set a variable by path, create if not exist
74114
+ * @param path path of the variable
74115
+ * @param value value of the variable
74116
+ * @param isSecretIfNotExist if the variable does not exist, create it as secret or not (default: false)
74117
+ * @param descriptionIfNotExist if the variable does not exist, create it with this description (default: "")
74118
+ */
74119
+ async setVariable(path: string, value: string, isSecretIfNotExist?: boolean, descriptionIfNotExist?: string): Promise<void>
74120
+
74121
+ /**
74122
+ * Build a PostgreSQL connection URL from a database resource
74123
+ * @param path - Path to the database resource
74124
+ * @returns PostgreSQL connection URL string
74125
+ */
74126
+ async databaseUrlFromResource(path: string): Promise<string>
74127
+
74128
+ async polarsConnectionSettings(s3_resource_path: string | undefined): Promise<any>
74129
+
74130
+ async duckdbConnectionSettings(s3_resource_path: string | undefined): Promise<any>
74131
+
74132
+ /**
74133
+ * Get S3 client settings from a resource or workspace default
74134
+ * @param s3_resource_path - Path to S3 resource (uses workspace default if undefined)
74135
+ * @returns S3 client configuration settings
74136
+ */
74137
+ async denoS3LightClientSettings(s3_resource_path: string | undefined): Promise<DenoS3LightClientSettings>
74138
+
74139
+ /**
74140
+ * Load the content of a file stored in S3. If the s3ResourcePath is undefined, it will default to the workspace S3 resource.
74141
+ *
74142
+ * \`\`\`typescript
74143
+ * let fileContent = await wmill.loadS3FileContent(inputFile)
74144
+ * // if the file is a raw text file, it can be decoded and printed directly:
74145
+ * const text = new TextDecoder().decode(fileContentStream)
74146
+ * console.log(text);
74147
+ * \`\`\`
74148
+ */
74149
+ async loadS3File(s3object: S3Object, s3ResourcePath: string | undefined = undefined): Promise<Uint8Array | undefined>
74150
+
74151
+ /**
74152
+ * Load the content of a file stored in S3 as a stream. If the s3ResourcePath is undefined, it will default to the workspace S3 resource.
74153
+ *
74154
+ * \`\`\`typescript
74155
+ * let fileContentBlob = await wmill.loadS3FileStream(inputFile)
74156
+ * // if the content is plain text, the blob can be read directly:
74157
+ * console.log(await fileContentBlob.text());
74158
+ * \`\`\`
74159
+ */
74160
+ async loadS3FileStream(s3object: S3Object, s3ResourcePath: string | undefined = undefined): Promise<Blob | undefined>
74161
+
74162
+ /**
74163
+ * Persist a file to the S3 bucket. If the s3ResourcePath is undefined, it will default to the workspace S3 resource.
74164
+ *
74165
+ * \`\`\`typescript
74166
+ * const s3object = await writeS3File(s3Object, "Hello Windmill!")
74167
+ * const fileContentAsUtf8Str = (await s3object.toArray()).toString('utf-8')
74168
+ * console.log(fileContentAsUtf8Str)
74169
+ * \`\`\`
74170
+ */
74171
+ async writeS3File(s3object: S3Object | undefined, fileContent: string | Blob, s3ResourcePath: string | undefined = undefined, contentType: string | undefined = undefined, contentDisposition: string | undefined = undefined): Promise<S3Object>
74172
+
74173
+ /**
74174
+ * Sign S3 objects to be used by anonymous users in public apps
74175
+ * @param s3objects s3 objects to sign
74176
+ * @returns signed s3 objects
74177
+ */
74178
+ async signS3Objects(s3objects: S3Object[]): Promise<S3Object[]>
74179
+
74180
+ /**
74181
+ * Sign S3 object to be used by anonymous users in public apps
74182
+ * @param s3object s3 object to sign
74183
+ * @returns signed s3 object
74184
+ */
74185
+ async signS3Object(s3object: S3Object): Promise<S3Object>
74186
+
74187
+ /**
74188
+ * Generate a presigned public URL for an array of S3 objects.
74189
+ * If an S3 object is not signed yet, it will be signed first.
74190
+ * @param s3Objects s3 objects to sign
74191
+ * @returns list of signed public URLs
74192
+ */
74193
+ async getPresignedS3PublicUrls(s3Objects: S3Object[], { baseUrl }: { baseUrl?: string } = {}): Promise<string[]>
74194
+
74195
+ /**
74196
+ * Generate a presigned public URL for an S3 object. If the S3 object is not signed yet, it will be signed first.
74197
+ * @param s3Object s3 object to sign
74198
+ * @returns signed public URL
74199
+ */
74200
+ async getPresignedS3PublicUrl(s3Objects: S3Object, { baseUrl }: { baseUrl?: string } = {}): Promise<string>
74201
+
74202
+ /**
74203
+ * Get URLs needed for resuming a flow after this step
74204
+ * @param approver approver name
74205
+ * @param flowLevel if true, generate resume URLs for the parent flow instead of the specific step.
74206
+ * This allows pre-approvals that can be consumed by any later suspend step in the same flow.
74207
+ * @returns approval page UI URL, resume and cancel API URLs for resuming the flow
74208
+ */
74209
+ async getResumeUrls(approver?: string, flowLevel?: boolean): Promise<{
74210
+ approvalPage: string;
74211
+ resume: string;
74212
+ cancel: string;
74213
+ }>
74214
+
74215
+ /**
74216
+ * @deprecated use getResumeUrls instead
74217
+ */
74218
+ getResumeEndpoints(approver?: string): Promise<{
74219
+ approvalPage: string;
74220
+ resume: string;
74221
+ cancel: string;
74222
+ }>
74223
+
74224
+ /**
74225
+ * Get an OIDC jwt token for auth to external services (e.g: Vault, AWS) (ee only)
74226
+ * @param audience audience of the token
74227
+ * @param expiresIn Optional number of seconds until the token expires
74228
+ * @returns jwt token
74229
+ */
74230
+ async getIdToken(audience: string, expiresIn?: number): Promise<string>
74231
+
74232
+ /**
74233
+ * Convert a base64-encoded string to Uint8Array
74234
+ * @param data - Base64-encoded string
74235
+ * @returns Decoded Uint8Array
74236
+ */
74237
+ base64ToUint8Array(data: string): Uint8Array
74238
+
74239
+ /**
74240
+ * Convert a Uint8Array to base64-encoded string
74241
+ * @param arrayBuffer - Uint8Array to encode
74242
+ * @returns Base64-encoded string
74243
+ */
74244
+ uint8ArrayToBase64(arrayBuffer: Uint8Array): string
74245
+
74246
+ /**
74247
+ * Get email from workspace username
74248
+ * This method is particularly useful for apps that require the email address of the viewer.
74249
+ * Indeed, in the viewer context, WM_USERNAME is set to the username of the viewer but WM_EMAIL is set to the email of the creator of the app.
74250
+ * @param username
74251
+ * @returns email address
74252
+ */
74253
+ async usernameToEmail(username: string): Promise<string>
74254
+
74255
+ /**
74256
+ * Sends an interactive approval request via Slack, allowing optional customization of the message, approver, and form fields.
74257
+ *
74258
+ * **[Enterprise Edition Only]** To include form fields in the Slack approval request, go to **Advanced -> Suspend -> Form**
74259
+ * and define a form. Learn more at [Windmill Documentation](https://www.windmill.dev/docs/flows/flow_approval#form).
74260
+ *
74261
+ * @param {Object} options - The configuration options for the Slack approval request.
74262
+ * @param {string} options.slackResourcePath - The path to the Slack resource in Windmill.
74263
+ * @param {string} options.channelId - The Slack channel ID where the approval request will be sent.
74264
+ * @param {string} [options.message] - Optional custom message to include in the Slack approval request.
74265
+ * @param {string} [options.approver] - Optional user ID or name of the approver for the request.
74266
+ * @param {DefaultArgs} [options.defaultArgsJson] - Optional object defining or overriding the default arguments to a form field.
74267
+ * @param {Enums} [options.dynamicEnumsJson] - Optional object overriding the enum default values of an enum form field.
74268
+ * @param {string} [options.resumeButtonText] - Optional text for the resume button.
74269
+ * @param {string} [options.cancelButtonText] - Optional text for the cancel button.
74270
+ *
74271
+ * @returns {Promise<void>} Resolves when the Slack approval request is successfully sent.
74272
+ *
74273
+ * @throws {Error} If the function is not called within a flow or flow preview.
74274
+ * @throws {Error} If the \`JobService.getSlackApprovalPayload\` call fails.
74275
+ *
74276
+ * **Usage Example:**
74277
+ * \`\`\`typescript
74278
+ * await requestInteractiveSlackApproval({
74279
+ * slackResourcePath: "/u/alex/my_slack_resource",
74280
+ * channelId: "admins-slack-channel",
74281
+ * message: "Please approve this request",
74282
+ * approver: "approver123",
74283
+ * defaultArgsJson: { key1: "value1", key2: 42 },
74284
+ * dynamicEnumsJson: { foo: ["choice1", "choice2"], bar: ["optionA", "optionB"] },
74285
+ * resumeButtonText: "Resume",
74286
+ * cancelButtonText: "Cancel",
74287
+ * });
74288
+ * \`\`\`
74289
+ *
74290
+ * **Note:** This function requires execution within a Windmill flow or flow preview.
74291
+ */
74292
+ async requestInteractiveSlackApproval({ slackResourcePath, channelId, message, approver, defaultArgsJson, dynamicEnumsJson, resumeButtonText, cancelButtonText, }: SlackApprovalOptions): Promise<void>
74293
+
74294
+ /**
74295
+ * Sends an interactive approval request via Teams, allowing optional customization of the message, approver, and form fields.
74296
+ *
74297
+ * **[Enterprise Edition Only]** To include form fields in the Teams approval request, go to **Advanced -> Suspend -> Form**
74298
+ * and define a form. Learn more at [Windmill Documentation](https://www.windmill.dev/docs/flows/flow_approval#form).
74299
+ *
74300
+ * @param {Object} options - The configuration options for the Teams approval request.
74301
+ * @param {string} options.teamName - The Teams team name where the approval request will be sent.
74302
+ * @param {string} options.channelName - The Teams channel name where the approval request will be sent.
74303
+ * @param {string} [options.message] - Optional custom message to include in the Teams approval request.
74304
+ * @param {string} [options.approver] - Optional user ID or name of the approver for the request.
74305
+ * @param {DefaultArgs} [options.defaultArgsJson] - Optional object defining or overriding the default arguments to a form field.
74306
+ * @param {Enums} [options.dynamicEnumsJson] - Optional object overriding the enum default values of an enum form field.
74307
+ *
74308
+ * @returns {Promise<void>} Resolves when the Teams approval request is successfully sent.
74309
+ *
74310
+ * @throws {Error} If the function is not called within a flow or flow preview.
74311
+ * @throws {Error} If the \`JobService.getTeamsApprovalPayload\` call fails.
74312
+ *
74313
+ * **Usage Example:**
74314
+ * \`\`\`typescript
74315
+ * await requestInteractiveTeamsApproval({
74316
+ * teamName: "admins-teams",
74317
+ * channelName: "admins-teams-channel",
74318
+ * message: "Please approve this request",
74319
+ * approver: "approver123",
74320
+ * defaultArgsJson: { key1: "value1", key2: 42 },
74321
+ * dynamicEnumsJson: { foo: ["choice1", "choice2"], bar: ["optionA", "optionB"] },
74322
+ * });
74323
+ * \`\`\`
74324
+ *
74325
+ * **Note:** This function requires execution within a Windmill flow or flow preview.
74326
+ */
74327
+ async requestInteractiveTeamsApproval({ teamName, channelName, message, approver, defaultArgsJson, dynamicEnumsJson, }: TeamsApprovalOptions): Promise<void>
74328
+
74329
+ /**
74330
+ * Parse an S3 object from URI string or record format
74331
+ * @param s3Object - S3 object as URI string (s3://storage/key) or record
74332
+ * @returns S3 object record with storage and s3 key
74333
+ */
74334
+ parseS3Object(s3Object: S3Object): S3ObjectRecord
74335
+
74336
+ setWorkflowCtx(ctx: WorkflowCtx | null): void
74337
+
74338
+ async sleep(seconds: number): Promise<void>
74339
+
74340
+ async step<T>(name: string, fn: () => T | Promise<T>): Promise<T>
74341
+
74342
+ /**
74343
+ * Create a task that dispatches to a separate Windmill script.
74344
+ *
74345
+ * @example
74346
+ * const extract = taskScript("f/data/extract");
74347
+ * // inside workflow: await extract({ url: "https://..." })
74348
+ */
74349
+ taskScript(path: string, options?: TaskOptions): (...args: any[]) => PromiseLike<any>
74350
+
74351
+ /**
74352
+ * Create a task that dispatches to a separate Windmill flow.
74353
+ *
74354
+ * @example
74355
+ * const pipeline = taskFlow("f/etl/pipeline");
74356
+ * // inside workflow: await pipeline({ input: data })
74357
+ */
74358
+ taskFlow(path: string, options?: TaskOptions): (...args: any[]) => PromiseLike<any>
74359
+
74360
+ /**
74361
+ * Mark an async function as a workflow-as-code entry point.
74362
+ *
74363
+ * The function must be **deterministic**: given the same inputs it must call
74364
+ * tasks in the same order on every replay. Branching on task results is fine
74365
+ * (results are replayed from checkpoint), but branching on external state
74366
+ * (current time, random values, external API calls) must use \`step()\` to
74367
+ * checkpoint the value so replays see the same result.
74368
+ */
74369
+ workflow<T>(fn: (...args: any[]) => Promise<T>): void
74370
+
74371
+ /**
74372
+ * Suspend the workflow and wait for an external approval.
74373
+ *
74374
+ * Use \`getResumeUrls()\` (wrapped in \`step()\`) to obtain resume/cancel/approvalPage
74375
+ * URLs before calling this function.
74376
+ *
74377
+ * @example
74378
+ * const urls = await step("urls", () => getResumeUrls());
74379
+ * await step("notify", () => sendEmail(urls.approvalPage));
74380
+ * const { value, approver } = await waitForApproval({ timeout: 3600 });
74381
+ */
74382
+ waitForApproval(options?: { timeout?: number; form?: object; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
74383
+
74384
+ /**
74385
+ * Process items in parallel with optional concurrency control.
74386
+ *
74387
+ * Each item is processed by calling \`fn(item)\`, which should be a task().
74388
+ * Items are dispatched in batches of \`concurrency\` (default: all at once).
74389
+ *
74390
+ * @example
74391
+ * const process = task(async (item: string) => { ... });
74392
+ * const results = await parallel(items, process, { concurrency: 5 });
74393
+ */
74394
+ async parallel<T, R>(items: T[], fn: (item: T) => PromiseLike<R> | R, options?: { concurrency?: number },): Promise<R[]>
74395
+
74396
+ /**
74397
+ * Commit Kafka offsets for a trigger with auto_commit disabled.
74398
+ * @param triggerPath - Path to the Kafka trigger (from event.wm_trigger.trigger_path)
74399
+ * @param topic - Kafka topic name (from event.topic)
74400
+ * @param partition - Partition number (from event.partition)
74401
+ * @param offset - Message offset to commit (from event.offset)
74402
+ */
74403
+ async commitKafkaOffsets(triggerPath: string, topic: string, partition: number, offset: number,): Promise<void>
74404
+
74118
74405
  /**
74119
74406
  * Create a SQL template function for PostgreSQL/datatable queries
74120
74407
  * @param name - Database/datatable name (default: "main")
@@ -74144,6 +74431,414 @@ datatable(name: string = "main"): DatatableSqlTemplateFunction
74144
74431
  * \`.fetch()
74145
74432
  */
74146
74433
  ducklake(name: string = "main"): SqlTemplateFunction
74434
+ `,
74435
+ "write-script-duckdb": `---
74436
+ name: write-script-duckdb
74437
+ description: MUST use when writing DuckDB queries.
74438
+ ---
74439
+
74440
+ ## CLI Commands
74441
+
74442
+ Place scripts in a folder. After writing, tell the user they can run:
74443
+ - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
74444
+ - \`wmill sync push\` - Deploy to Windmill
74445
+
74446
+ Do NOT run these commands yourself. Instead, inform the user that they should run them.
74447
+
74448
+ Use \`wmill resource-type list --schema\` to discover available resource types.
74449
+
74450
+ # DuckDB
74451
+
74452
+ Arguments are defined with comments and used with \`$name\` syntax:
74453
+
74454
+ \`\`\`sql
74455
+ -- $name (text) = default
74456
+ -- $age (integer)
74457
+ SELECT * FROM users WHERE name = $name AND age > $age;
74458
+ \`\`\`
74459
+
74460
+ ## Ducklake Integration
74461
+
74462
+ Attach Ducklake for data lake operations:
74463
+
74464
+ \`\`\`sql
74465
+ -- Main ducklake
74466
+ ATTACH 'ducklake' AS dl;
74467
+
74468
+ -- Named ducklake
74469
+ ATTACH 'ducklake://my_lake' AS dl;
74470
+
74471
+ -- Then query
74472
+ SELECT * FROM dl.schema.table;
74473
+ \`\`\`
74474
+
74475
+ ## External Database Connections
74476
+
74477
+ Connect to external databases using resources:
74478
+
74479
+ \`\`\`sql
74480
+ ATTACH '$res:path/to/resource' AS db (TYPE postgres);
74481
+ SELECT * FROM db.schema.table;
74482
+ \`\`\`
74483
+
74484
+ ## S3 File Operations
74485
+
74486
+ Read files from S3 storage:
74487
+
74488
+ \`\`\`sql
74489
+ -- Default storage
74490
+ SELECT * FROM read_csv('s3:///path/to/file.csv');
74491
+
74492
+ -- Named storage
74493
+ SELECT * FROM read_csv('s3://storage_name/path/to/file.csv');
74494
+
74495
+ -- Parquet files
74496
+ SELECT * FROM read_parquet('s3:///path/to/file.parquet');
74497
+
74498
+ -- JSON files
74499
+ SELECT * FROM read_json('s3:///path/to/file.json');
74500
+ \`\`\`
74501
+ `,
74502
+ "write-script-go": `---
74503
+ name: write-script-go
74504
+ description: MUST use when writing Go scripts.
74505
+ ---
74506
+
74507
+ ## CLI Commands
74508
+
74509
+ Place scripts in a folder. After writing, tell the user they can run:
74510
+ - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
74511
+ - \`wmill sync push\` - Deploy to Windmill
74512
+
74513
+ Do NOT run these commands yourself. Instead, inform the user that they should run them.
74514
+
74515
+ Use \`wmill resource-type list --schema\` to discover available resource types.
74516
+
74517
+ # Go
74518
+
74519
+ ## Structure
74520
+
74521
+ The file package must be \`inner\` and export a function called \`main\`:
74522
+
74523
+ \`\`\`go
74524
+ package inner
74525
+
74526
+ func main(param1 string, param2 int) (map[string]interface{}, error) {
74527
+ return map[string]interface{}{
74528
+ "result": param1,
74529
+ "count": param2,
74530
+ }, nil
74531
+ }
74532
+ \`\`\`
74533
+
74534
+ **Important:**
74535
+ - Package must be \`inner\`
74536
+ - Return type must be \`({return_type}, error)\`
74537
+ - Function name is \`main\` (lowercase)
74538
+
74539
+ ## Return Types
74540
+
74541
+ The return type can be any Go type that can be serialized to JSON:
74542
+
74543
+ \`\`\`go
74544
+ package inner
74545
+
74546
+ type Result struct {
74547
+ Name string \`json:"name"\`
74548
+ Count int \`json:"count"\`
74549
+ }
74550
+
74551
+ func main(name string, count int) (Result, error) {
74552
+ return Result{
74553
+ Name: name,
74554
+ Count: count,
74555
+ }, nil
74556
+ }
74557
+ \`\`\`
74558
+
74559
+ ## Error Handling
74560
+
74561
+ Return errors as the second return value:
74562
+
74563
+ \`\`\`go
74564
+ package inner
74565
+
74566
+ import "errors"
74567
+
74568
+ func main(value int) (string, error) {
74569
+ if value < 0 {
74570
+ return "", errors.New("value must be positive")
74571
+ }
74572
+ return "success", nil
74573
+ }
74574
+ \`\`\`
74575
+ `,
74576
+ "write-script-graphql": `---
74577
+ name: write-script-graphql
74578
+ description: MUST use when writing GraphQL queries.
74579
+ ---
74580
+
74581
+ ## CLI Commands
74582
+
74583
+ Place scripts in a folder. After writing, tell the user they can run:
74584
+ - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
74585
+ - \`wmill sync push\` - Deploy to Windmill
74586
+
74587
+ Do NOT run these commands yourself. Instead, inform the user that they should run them.
74588
+
74589
+ Use \`wmill resource-type list --schema\` to discover available resource types.
74590
+
74591
+ # GraphQL
74592
+
74593
+ ## Structure
74594
+
74595
+ Write GraphQL queries or mutations. Arguments can be added as query parameters:
74596
+
74597
+ \`\`\`graphql
74598
+ query GetUser($id: ID!) {
74599
+ user(id: $id) {
74600
+ id
74601
+ name
74602
+ email
74603
+ }
74604
+ }
74605
+ \`\`\`
74606
+
74607
+ ## Variables
74608
+
74609
+ Variables are passed as script arguments and automatically bound to the query:
74610
+
74611
+ \`\`\`graphql
74612
+ query SearchProducts($query: String!, $limit: Int = 10) {
74613
+ products(search: $query, first: $limit) {
74614
+ edges {
74615
+ node {
74616
+ id
74617
+ name
74618
+ price
74619
+ }
74620
+ }
74621
+ }
74622
+ }
74623
+ \`\`\`
74624
+
74625
+ ## Mutations
74626
+
74627
+ \`\`\`graphql
74628
+ mutation CreateUser($input: CreateUserInput!) {
74629
+ createUser(input: $input) {
74630
+ id
74631
+ name
74632
+ createdAt
74633
+ }
74634
+ }
74635
+ \`\`\`
74636
+ `,
74637
+ "write-script-java": `---
74638
+ name: write-script-java
74639
+ description: MUST use when writing Java scripts.
74640
+ ---
74641
+
74642
+ ## CLI Commands
74643
+
74644
+ Place scripts in a folder. After writing, tell the user they can run:
74645
+ - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
74646
+ - \`wmill sync push\` - Deploy to Windmill
74647
+
74648
+ Do NOT run these commands yourself. Instead, inform the user that they should run them.
74649
+
74650
+ Use \`wmill resource-type list --schema\` to discover available resource types.
74651
+
74652
+ # Java
74653
+
74654
+ The script must contain a Main public class with a \`public static main()\` method:
74655
+
74656
+ \`\`\`java
74657
+ public class Main {
74658
+ public static Object main(String name, int count) {
74659
+ java.util.Map<String, Object> result = new java.util.HashMap<>();
74660
+ result.put("name", name);
74661
+ result.put("count", count);
74662
+ return result;
74663
+ }
74664
+ }
74665
+ \`\`\`
74666
+
74667
+ **Important:**
74668
+ - Class must be named \`Main\`
74669
+ - Method must be \`public static Object main(...)\`
74670
+ - Return type is \`Object\` or \`void\`
74671
+
74672
+ ## Maven Dependencies
74673
+
74674
+ Add dependencies using comments at the top:
74675
+
74676
+ \`\`\`java
74677
+ //requirements:
74678
+ //com.google.code.gson:gson:2.10.1
74679
+ //org.apache.httpcomponents:httpclient:4.5.14
74680
+
74681
+ import com.google.gson.Gson;
74682
+
74683
+ public class Main {
74684
+ public static Object main(String input) {
74685
+ Gson gson = new Gson();
74686
+ return gson.fromJson(input, Object.class);
74687
+ }
74688
+ }
74689
+ \`\`\`
74690
+ `,
74691
+ "write-script-mssql": `---
74692
+ name: write-script-mssql
74693
+ description: MUST use when writing MS SQL Server queries.
74694
+ ---
74695
+
74696
+ ## CLI Commands
74697
+
74698
+ Place scripts in a folder. After writing, tell the user they can run:
74699
+ - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
74700
+ - \`wmill sync push\` - Deploy to Windmill
74701
+
74702
+ Do NOT run these commands yourself. Instead, inform the user that they should run them.
74703
+
74704
+ Use \`wmill resource-type list --schema\` to discover available resource types.
74705
+
74706
+ # Microsoft SQL Server (MSSQL)
74707
+
74708
+ Arguments use \`@P1\`, \`@P2\`, etc.
74709
+
74710
+ Name the parameters by adding comments before the statement:
74711
+
74712
+ \`\`\`sql
74713
+ -- @P1 name1 (varchar)
74714
+ -- @P2 name2 (int) = 0
74715
+ SELECT * FROM users WHERE name = @P1 AND age > @P2;
74716
+ \`\`\`
74717
+ `,
74718
+ "write-script-mysql": `---
74719
+ name: write-script-mysql
74720
+ description: MUST use when writing MySQL queries.
74721
+ ---
74722
+
74723
+ ## CLI Commands
74724
+
74725
+ Place scripts in a folder. After writing, tell the user they can run:
74726
+ - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
74727
+ - \`wmill sync push\` - Deploy to Windmill
74728
+
74729
+ Do NOT run these commands yourself. Instead, inform the user that they should run them.
74730
+
74731
+ Use \`wmill resource-type list --schema\` to discover available resource types.
74732
+
74733
+ # MySQL
74734
+
74735
+ Arguments use \`?\` placeholders.
74736
+
74737
+ Name the parameters by adding comments before the statement:
74738
+
74739
+ \`\`\`sql
74740
+ -- ? name1 (text)
74741
+ -- ? name2 (int) = 0
74742
+ SELECT * FROM users WHERE name = ? AND age > ?;
74743
+ \`\`\`
74744
+ `,
74745
+ "write-script-nativets": `---
74746
+ name: write-script-nativets
74747
+ description: MUST use when writing Native TypeScript scripts.
74748
+ ---
74749
+
74750
+ ## CLI Commands
74751
+
74752
+ Place scripts in a folder. After writing, tell the user they can run:
74753
+ - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
74754
+ - \`wmill sync push\` - Deploy to Windmill
74755
+
74756
+ Do NOT run these commands yourself. Instead, inform the user that they should run them.
74757
+
74758
+ Use \`wmill resource-type list --schema\` to discover available resource types.
74759
+
74760
+ # TypeScript (Native)
74761
+
74762
+ Native TypeScript execution with fetch only - no external imports allowed.
74763
+
74764
+ ## Structure
74765
+
74766
+ Export a single **async** function called \`main\`:
74767
+
74768
+ \`\`\`typescript
74769
+ export async function main(param1: string, param2: number) {
74770
+ // Your code here
74771
+ return { result: param1, count: param2 };
74772
+ }
74773
+ \`\`\`
74774
+
74775
+ Do not call the main function.
74776
+
74777
+ ## Resource Types
74778
+
74779
+ On Windmill, credentials and configuration are stored in resources and passed as parameters to main.
74780
+
74781
+ Use the \`RT\` namespace for resource types:
74782
+
74783
+ \`\`\`typescript
74784
+ export async function main(stripe: RT.Stripe) {
74785
+ // stripe contains API key and config from the resource
74786
+ }
74787
+ \`\`\`
74788
+
74789
+ Only use resource types if you need them to satisfy the instructions. Always use the RT namespace.
74790
+
74791
+ Before using a resource type, check the \`rt.d.ts\` file in the project root to see all available resource types and their fields. This file is generated by \`wmill resource-type generate-namespace\`.
74792
+
74793
+ ## Imports
74794
+
74795
+ **No imports allowed.** Use the globally available \`fetch\` function:
74796
+
74797
+ \`\`\`typescript
74798
+ export async function main(url: string) {
74799
+ const response = await fetch(url);
74800
+ return await response.json();
74801
+ }
74802
+ \`\`\`
74803
+
74804
+ ## Windmill Client
74805
+
74806
+ The windmill client is not available in native TypeScript mode. Use fetch to call APIs directly.
74807
+
74808
+ ## Preprocessor Scripts
74809
+
74810
+ For preprocessor scripts, the function should be named \`preprocessor\` and receives an \`event\` parameter:
74811
+
74812
+ \`\`\`typescript
74813
+ type Event = {
74814
+ kind:
74815
+ | "webhook"
74816
+ | "http"
74817
+ | "websocket"
74818
+ | "kafka"
74819
+ | "email"
74820
+ | "nats"
74821
+ | "postgres"
74822
+ | "sqs"
74823
+ | "mqtt"
74824
+ | "gcp";
74825
+ body: any;
74826
+ headers: Record<string, string>;
74827
+ query: Record<string, string>;
74828
+ };
74829
+
74830
+ export async function preprocessor(event: Event) {
74831
+ return {
74832
+ param1: event.body.field1,
74833
+ param2: event.query.id
74834
+ };
74835
+ }
74836
+ \`\`\`
74837
+
74838
+
74839
+ # TypeScript SDK (windmill-client)
74840
+
74841
+ Import: import * as wmill from 'windmill-client'
74147
74842
 
74148
74843
  /**
74149
74844
  * Initialize the Windmill client with authentication token and base URL
@@ -74637,30 +75332,144 @@ waitForApproval(options?: { timeout?: number; form?: object; }): PromiseLike<{ v
74637
75332
  * const results = await parallel(items, process, { concurrency: 5 });
74638
75333
  */
74639
75334
  async parallel<T, R>(items: T[], fn: (item: T) => PromiseLike<R> | R, options?: { concurrency?: number },): Promise<R[]>
75335
+
75336
+ /**
75337
+ * Commit Kafka offsets for a trigger with auto_commit disabled.
75338
+ * @param triggerPath - Path to the Kafka trigger (from event.wm_trigger.trigger_path)
75339
+ * @param topic - Kafka topic name (from event.topic)
75340
+ * @param partition - Partition number (from event.partition)
75341
+ * @param offset - Message offset to commit (from event.offset)
75342
+ */
75343
+ async commitKafkaOffsets(triggerPath: string, topic: string, partition: number, offset: number,): Promise<void>
75344
+
75345
+ /**
75346
+ * Create a SQL template function for PostgreSQL/datatable queries
75347
+ * @param name - Database/datatable name (default: "main")
75348
+ * @returns SQL template function for building parameterized queries
75349
+ * @example
75350
+ * let sql = wmill.datatable()
75351
+ * let name = 'Robin'
75352
+ * let age = 21
75353
+ * await sql\`
75354
+ * SELECT * FROM friends
75355
+ * WHERE name = \${name} AND age = \${age}::int
75356
+ * \`.fetch()
75357
+ */
75358
+ datatable(name: string = "main"): DatatableSqlTemplateFunction
75359
+
75360
+ /**
75361
+ * Create a SQL template function for DuckDB/ducklake queries
75362
+ * @param name - DuckDB database name (default: "main")
75363
+ * @returns SQL template function for building parameterized queries
75364
+ * @example
75365
+ * let sql = wmill.ducklake()
75366
+ * let name = 'Robin'
75367
+ * let age = 21
75368
+ * await sql\`
75369
+ * SELECT * FROM friends
75370
+ * WHERE name = \${name} AND age = \${age}
75371
+ * \`.fetch()
75372
+ */
75373
+ ducklake(name: string = "main"): SqlTemplateFunction
75374
+ `,
75375
+ "write-script-php": `---
75376
+ name: write-script-php
75377
+ description: MUST use when writing PHP scripts.
75378
+ ---
75379
+
75380
+ ## CLI Commands
75381
+
75382
+ Place scripts in a folder. After writing, tell the user they can run:
75383
+ - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
75384
+ - \`wmill sync push\` - Deploy to Windmill
75385
+
75386
+ Do NOT run these commands yourself. Instead, inform the user that they should run them.
75387
+
75388
+ Use \`wmill resource-type list --schema\` to discover available resource types.
75389
+
75390
+ # PHP
75391
+
75392
+ ## Structure
75393
+
75394
+ The script must start with \`<?php\` and contain at least one function called \`main\`:
75395
+
75396
+ \`\`\`php
75397
+ <?php
75398
+
75399
+ function main(string $param1, int $param2) {
75400
+ return ["result" => $param1, "count" => $param2];
75401
+ }
75402
+ \`\`\`
75403
+
75404
+ ## Resource Types
75405
+
75406
+ On Windmill, credentials and configuration are stored in resources and passed as parameters to main.
75407
+
75408
+ You need to **redefine** the type of the resources that are needed before the main function. Always check if the class already exists using \`class_exists\`:
75409
+
75410
+ \`\`\`php
75411
+ <?php
75412
+
75413
+ if (!class_exists('Postgresql')) {
75414
+ class Postgresql {
75415
+ public string $host;
75416
+ public int $port;
75417
+ public string $user;
75418
+ public string $password;
75419
+ public string $dbname;
75420
+ }
75421
+ }
75422
+
75423
+ function main(Postgresql $db) {
75424
+ // $db contains the database connection details
75425
+ }
75426
+ \`\`\`
75427
+
75428
+ The resource type name has to be exactly as specified.
75429
+
75430
+ ## Library Dependencies
75431
+
75432
+ Specify library dependencies as comments before the main function:
75433
+
75434
+ \`\`\`php
75435
+ <?php
75436
+
75437
+ // require:
75438
+ // guzzlehttp/guzzle
75439
+ // stripe/stripe-php@^10.0
75440
+
75441
+ function main() {
75442
+ // Libraries are available
75443
+ }
75444
+ \`\`\`
75445
+
75446
+ One dependency per line. No need to require autoload, it is already done.
74640
75447
  `,
74641
- "write-script-mysql": `---
74642
- name: write-script-mysql
74643
- description: MUST use when writing MySQL queries.
75448
+ "write-script-postgresql": `---
75449
+ name: write-script-postgresql
75450
+ description: MUST use when writing PostgreSQL queries.
74644
75451
  ---
74645
75452
 
74646
75453
  ## CLI Commands
74647
75454
 
74648
- Place scripts in a folder. After writing, run:
75455
+ Place scripts in a folder. After writing, tell the user they can run:
74649
75456
  - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
74650
75457
  - \`wmill sync push\` - Deploy to Windmill
74651
75458
 
75459
+ Do NOT run these commands yourself. Instead, inform the user that they should run them.
75460
+
74652
75461
  Use \`wmill resource-type list --schema\` to discover available resource types.
74653
75462
 
74654
- # MySQL
75463
+ # PostgreSQL
74655
75464
 
74656
- Arguments use \`?\` placeholders.
75465
+ Arguments are obtained directly in the statement with \`$1::{type}\`, \`$2::{type}\`, etc.
74657
75466
 
74658
- Name the parameters by adding comments before the statement:
75467
+ Name the parameters by adding comments at the beginning of the script (without specifying the type):
74659
75468
 
74660
75469
  \`\`\`sql
74661
- -- ? name1 (text)
74662
- -- ? name2 (int) = 0
74663
- SELECT * FROM users WHERE name = ? AND age > ?;
75470
+ -- $1 name1
75471
+ -- $2 name2 = default_value
75472
+ SELECT * FROM users WHERE name = $1::TEXT AND age > $2::INT;
74664
75473
  \`\`\`
74665
75474
  `,
74666
75475
  "write-script-powershell": `---
@@ -74670,10 +75479,12 @@ description: MUST use when writing PowerShell scripts.
74670
75479
 
74671
75480
  ## CLI Commands
74672
75481
 
74673
- Place scripts in a folder. After writing, run:
75482
+ Place scripts in a folder. After writing, tell the user they can run:
74674
75483
  - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
74675
75484
  - \`wmill sync push\` - Deploy to Windmill
74676
75485
 
75486
+ Do NOT run these commands yourself. Instead, inform the user that they should run them.
75487
+
74677
75488
  Use \`wmill resource-type list --schema\` to discover available resource types.
74678
75489
 
74679
75490
  # PowerShell
@@ -74731,31 +75542,6 @@ $result = @{
74731
75542
 
74732
75543
  $result
74733
75544
  \`\`\`
74734
- `,
74735
- "write-script-snowflake": `---
74736
- name: write-script-snowflake
74737
- description: MUST use when writing Snowflake queries.
74738
- ---
74739
-
74740
- ## CLI Commands
74741
-
74742
- Place scripts in a folder. After writing, run:
74743
- - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
74744
- - \`wmill sync push\` - Deploy to Windmill
74745
-
74746
- Use \`wmill resource-type list --schema\` to discover available resource types.
74747
-
74748
- # Snowflake
74749
-
74750
- Arguments use \`?\` placeholders.
74751
-
74752
- Name the parameters by adding comments before the statement:
74753
-
74754
- \`\`\`sql
74755
- -- ? name1 (text)
74756
- -- ? name2 (number) = 0
74757
- SELECT * FROM users WHERE name = ? AND age > ?;
74758
- \`\`\`
74759
75545
  `,
74760
75546
  "write-script-python3": `---
74761
75547
  name: write-script-python3
@@ -74764,10 +75550,12 @@ description: MUST use when writing Python scripts.
74764
75550
 
74765
75551
  ## CLI Commands
74766
75552
 
74767
- Place scripts in a folder. After writing, run:
75553
+ Place scripts in a folder. After writing, tell the user they can run:
74768
75554
  - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
74769
75555
  - \`wmill sync push\` - Deploy to Windmill
74770
75556
 
75557
+ Do NOT run these commands yourself. Instead, inform the user that they should run them.
75558
+
74771
75559
  Use \`wmill resource-type list --schema\` to discover available resource types.
74772
75560
 
74773
75561
  # Python
@@ -75508,806 +76296,186 @@ def task_script(path: str, timeout: Optional[int] = None, tag: Optional[str] = N
75508
76296
  #
75509
76297
  # @workflow
75510
76298
  # async def main():
75511
- # result = await pipeline(input=data)
75512
- def task_flow(path: str, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
75513
-
75514
- # Decorator marking an async function as a workflow-as-code entry point.
75515
- #
75516
- # The function must be **deterministic**: given the same inputs it must call
75517
- # tasks in the same order on every replay. Branching on task results is fine
75518
- # (results are replayed from checkpoint), but branching on external state
75519
- # (current time, random values, external API calls) must use \`\`step()\`\` to
75520
- # checkpoint the value so replays see the same result.
75521
- def workflow(func)
75522
-
75523
- # Execute \`\`fn\`\` inline and checkpoint the result.
75524
- #
75525
- # On replay the cached value is returned without re-executing \`\`fn\`\`.
75526
- # Use for lightweight deterministic operations (timestamps, random IDs,
75527
- # config reads) that should not incur the overhead of a child job.
75528
- async def step(name: str, fn)
75529
-
75530
- # Server-side sleep — suspend the workflow for the given duration without holding a worker.
75531
- #
75532
- # Inside a @workflow, the parent job suspends and auto-resumes after \`\`seconds\`\`.
75533
- # Outside a workflow, falls back to \`\`asyncio.sleep\`\`.
75534
- async def sleep(seconds: int)
75535
-
75536
- # Suspend the workflow and wait for an external approval.
75537
- #
75538
- # Use \`\`get_resume_urls()\`\` (wrapped in \`\`step()\`\`) to obtain
75539
- # resume/cancel/approval URLs before calling this function.
75540
- #
75541
- # Returns a dict with \`\`value\`\` (form data), \`\`approver\`\`, and \`\`approved\`\`.
75542
- #
75543
- # Example::
75544
- #
75545
- # urls = await step("urls", lambda: get_resume_urls())
75546
- # await step("notify", lambda: send_email(urls["approvalPage"]))
75547
- # result = await wait_for_approval(timeout=3600)
75548
- async def wait_for_approval(timeout: int = 1800, form: dict | None = None) -> dict
75549
-
75550
- # Process items in parallel with optional concurrency control.
75551
- #
75552
- # Each item is processed by calling \`\`fn(item)\`\`, which should be a @task.
75553
- # Items are dispatched in batches of \`\`concurrency\`\` (default: all at once).
75554
- #
75555
- # Example::
75556
- #
75557
- # @task
75558
- # async def process(item: str):
75559
- # ...
75560
- #
75561
- # results = await parallel(items, process, concurrency=5)
75562
- async def parallel(items, fn, concurrency: Optional[int] = None)
75563
-
75564
- `,
75565
- "write-script-duckdb": `---
75566
- name: write-script-duckdb
75567
- description: MUST use when writing DuckDB queries.
75568
- ---
75569
-
75570
- ## CLI Commands
75571
-
75572
- Place scripts in a folder. After writing, run:
75573
- - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
75574
- - \`wmill sync push\` - Deploy to Windmill
75575
-
75576
- Use \`wmill resource-type list --schema\` to discover available resource types.
75577
-
75578
- # DuckDB
75579
-
75580
- Arguments are defined with comments and used with \`$name\` syntax:
75581
-
75582
- \`\`\`sql
75583
- -- $name (text) = default
75584
- -- $age (integer)
75585
- SELECT * FROM users WHERE name = $name AND age > $age;
75586
- \`\`\`
75587
-
75588
- ## Ducklake Integration
75589
-
75590
- Attach Ducklake for data lake operations:
75591
-
75592
- \`\`\`sql
75593
- -- Main ducklake
75594
- ATTACH 'ducklake' AS dl;
75595
-
75596
- -- Named ducklake
75597
- ATTACH 'ducklake://my_lake' AS dl;
75598
-
75599
- -- Then query
75600
- SELECT * FROM dl.schema.table;
75601
- \`\`\`
75602
-
75603
- ## External Database Connections
75604
-
75605
- Connect to external databases using resources:
75606
-
75607
- \`\`\`sql
75608
- ATTACH '$res:path/to/resource' AS db (TYPE postgres);
75609
- SELECT * FROM db.schema.table;
75610
- \`\`\`
75611
-
75612
- ## S3 File Operations
75613
-
75614
- Read files from S3 storage:
75615
-
75616
- \`\`\`sql
75617
- -- Default storage
75618
- SELECT * FROM read_csv('s3:///path/to/file.csv');
75619
-
75620
- -- Named storage
75621
- SELECT * FROM read_csv('s3://storage_name/path/to/file.csv');
75622
-
75623
- -- Parquet files
75624
- SELECT * FROM read_parquet('s3:///path/to/file.parquet');
75625
-
75626
- -- JSON files
75627
- SELECT * FROM read_json('s3:///path/to/file.json');
75628
- \`\`\`
75629
- `,
75630
- "write-script-bash": `---
75631
- name: write-script-bash
75632
- description: MUST use when writing Bash scripts.
75633
- ---
75634
-
75635
- ## CLI Commands
75636
-
75637
- Place scripts in a folder. After writing, run:
75638
- - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
75639
- - \`wmill sync push\` - Deploy to Windmill
75640
-
75641
- Use \`wmill resource-type list --schema\` to discover available resource types.
75642
-
75643
- # Bash
75644
-
75645
- ## Structure
75646
-
75647
- Do not include \`#!/bin/bash\`. Arguments are obtained as positional parameters:
75648
-
75649
- \`\`\`bash
75650
- # Get arguments
75651
- var1="$1"
75652
- var2="$2"
75653
-
75654
- echo "Processing $var1 and $var2"
75655
-
75656
- # Return JSON by echoing to stdout
75657
- echo "{\\"result\\": \\"$var1\\", \\"count\\": $var2}"
75658
- \`\`\`
75659
-
75660
- **Important:**
75661
- - Do not include shebang (\`#!/bin/bash\`)
75662
- - Arguments are always strings
75663
- - Access with \`$1\`, \`$2\`, etc.
75664
-
75665
- ## Output
75666
-
75667
- The script output is captured as the result. For structured data, output valid JSON:
75668
-
75669
- \`\`\`bash
75670
- name="$1"
75671
- count="$2"
75672
-
75673
- # Output JSON result
75674
- cat << EOF
75675
- {
75676
- "name": "$name",
75677
- "count": $count,
75678
- "timestamp": "$(date -Iseconds)"
75679
- }
75680
- EOF
75681
- \`\`\`
75682
-
75683
- ## Environment Variables
75684
-
75685
- Environment variables set in Windmill are available:
75686
-
75687
- \`\`\`bash
75688
- # Access environment variable
75689
- echo "Workspace: $WM_WORKSPACE"
75690
- echo "Job ID: $WM_JOB_ID"
75691
- \`\`\`
75692
- `,
75693
- "write-script-nativets": `---
75694
- name: write-script-nativets
75695
- description: MUST use when writing Native TypeScript scripts.
75696
- ---
75697
-
75698
- ## CLI Commands
75699
-
75700
- Place scripts in a folder. After writing, run:
75701
- - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
75702
- - \`wmill sync push\` - Deploy to Windmill
75703
-
75704
- Use \`wmill resource-type list --schema\` to discover available resource types.
75705
-
75706
- # TypeScript (Native)
75707
-
75708
- Native TypeScript execution with fetch only - no external imports allowed.
75709
-
75710
- ## Structure
75711
-
75712
- Export a single **async** function called \`main\`:
75713
-
75714
- \`\`\`typescript
75715
- export async function main(param1: string, param2: number) {
75716
- // Your code here
75717
- return { result: param1, count: param2 };
75718
- }
75719
- \`\`\`
75720
-
75721
- Do not call the main function.
75722
-
75723
- ## Resource Types
75724
-
75725
- On Windmill, credentials and configuration are stored in resources and passed as parameters to main.
75726
-
75727
- Use the \`RT\` namespace for resource types:
75728
-
75729
- \`\`\`typescript
75730
- export async function main(stripe: RT.Stripe) {
75731
- // stripe contains API key and config from the resource
75732
- }
75733
- \`\`\`
75734
-
75735
- Only use resource types if you need them to satisfy the instructions. Always use the RT namespace.
75736
-
75737
- Before using a resource type, check the \`rt.d.ts\` file in the project root to see all available resource types and their fields. This file is generated by \`wmill resource-type generate-namespace\`.
75738
-
75739
- ## Imports
75740
-
75741
- **No imports allowed.** Use the globally available \`fetch\` function:
75742
-
75743
- \`\`\`typescript
75744
- export async function main(url: string) {
75745
- const response = await fetch(url);
75746
- return await response.json();
75747
- }
75748
- \`\`\`
75749
-
75750
- ## Windmill Client
75751
-
75752
- The windmill client is not available in native TypeScript mode. Use fetch to call APIs directly.
75753
-
75754
- ## Preprocessor Scripts
75755
-
75756
- For preprocessor scripts, the function should be named \`preprocessor\` and receives an \`event\` parameter:
75757
-
75758
- \`\`\`typescript
75759
- type Event = {
75760
- kind:
75761
- | "webhook"
75762
- | "http"
75763
- | "websocket"
75764
- | "kafka"
75765
- | "email"
75766
- | "nats"
75767
- | "postgres"
75768
- | "sqs"
75769
- | "mqtt"
75770
- | "gcp";
75771
- body: any;
75772
- headers: Record<string, string>;
75773
- query: Record<string, string>;
75774
- };
75775
-
75776
- export async function preprocessor(event: Event) {
75777
- return {
75778
- param1: event.body.field1,
75779
- param2: event.query.id
75780
- };
75781
- }
75782
- \`\`\`
75783
-
75784
-
75785
- # TypeScript SDK (windmill-client)
75786
-
75787
- Import: import * as wmill from 'windmill-client'
75788
-
75789
- /**
75790
- * Create a SQL template function for PostgreSQL/datatable queries
75791
- * @param name - Database/datatable name (default: "main")
75792
- * @returns SQL template function for building parameterized queries
75793
- * @example
75794
- * let sql = wmill.datatable()
75795
- * let name = 'Robin'
75796
- * let age = 21
75797
- * await sql\`
75798
- * SELECT * FROM friends
75799
- * WHERE name = \${name} AND age = \${age}::int
75800
- * \`.fetch()
75801
- */
75802
- datatable(name: string = "main"): DatatableSqlTemplateFunction
75803
-
75804
- /**
75805
- * Create a SQL template function for DuckDB/ducklake queries
75806
- * @param name - DuckDB database name (default: "main")
75807
- * @returns SQL template function for building parameterized queries
75808
- * @example
75809
- * let sql = wmill.ducklake()
75810
- * let name = 'Robin'
75811
- * let age = 21
75812
- * await sql\`
75813
- * SELECT * FROM friends
75814
- * WHERE name = \${name} AND age = \${age}
75815
- * \`.fetch()
75816
- */
75817
- ducklake(name: string = "main"): SqlTemplateFunction
75818
-
75819
- /**
75820
- * Initialize the Windmill client with authentication token and base URL
75821
- * @param token - Authentication token (defaults to WM_TOKEN env variable)
75822
- * @param baseUrl - API base URL (defaults to BASE_INTERNAL_URL or BASE_URL env variable)
75823
- */
75824
- setClient(token?: string, baseUrl?: string): void
75825
-
75826
- /**
75827
- * Create a client configuration from env variables
75828
- * @returns client configuration
75829
- */
75830
- getWorkspace(): string
75831
-
75832
- /**
75833
- * Get a resource value by path
75834
- * @param path path of the resource, default to internal state path
75835
- * @param undefinedIfEmpty if the resource does not exist, return undefined instead of throwing an error
75836
- * @returns resource value
75837
- */
75838
- async getResource(path?: string, undefinedIfEmpty?: boolean): Promise<any>
75839
-
75840
- /**
75841
- * Get the true root job id
75842
- * @param jobId job id to get the root job id from (default to current job)
75843
- * @returns root job id
75844
- */
75845
- async getRootJobId(jobId?: string): Promise<string>
75846
-
75847
- /**
75848
- * @deprecated Use runScriptByPath or runScriptByHash instead
75849
- */
75850
- async runScript(path: string | null = null, hash_: string | null = null, args: Record<string, any> | null = null, verbose: boolean = false): Promise<any>
75851
-
75852
- /**
75853
- * Run a script synchronously by its path and wait for the result
75854
- * @param path - Script path in Windmill
75855
- * @param args - Arguments to pass to the script
75856
- * @param verbose - Enable verbose logging
75857
- * @returns Script execution result
75858
- */
75859
- async runScriptByPath(path: string, args: Record<string, any> | null = null, verbose: boolean = false): Promise<any>
75860
-
75861
- /**
75862
- * Run a script synchronously by its hash and wait for the result
75863
- * @param hash_ - Script hash in Windmill
75864
- * @param args - Arguments to pass to the script
75865
- * @param verbose - Enable verbose logging
75866
- * @returns Script execution result
75867
- */
75868
- async runScriptByHash(hash_: string, args: Record<string, any> | null = null, verbose: boolean = false): Promise<any>
75869
-
75870
- /**
75871
- * Append a text to the result stream
75872
- * @param text text to append to the result stream
75873
- */
75874
- appendToResultStream(text: string): void
75875
-
75876
- /**
75877
- * Stream to the result stream
75878
- * @param stream stream to stream to the result stream
75879
- */
75880
- async streamResult(stream: AsyncIterable<string>): Promise<void>
75881
-
75882
- /**
75883
- * Run a flow synchronously by its path and wait for the result
75884
- * @param path - Flow path in Windmill
75885
- * @param args - Arguments to pass to the flow
75886
- * @param verbose - Enable verbose logging
75887
- * @returns Flow execution result
75888
- */
75889
- async runFlow(path: string | null = null, args: Record<string, any> | null = null, verbose: boolean = false): Promise<any>
75890
-
75891
- /**
75892
- * Wait for a job to complete and return its result
75893
- * @param jobId - ID of the job to wait for
75894
- * @param verbose - Enable verbose logging
75895
- * @returns Job result when completed
75896
- */
75897
- async waitJob(jobId: string, verbose: boolean = false): Promise<any>
75898
-
75899
- /**
75900
- * Get the result of a completed job
75901
- * @param jobId - ID of the completed job
75902
- * @returns Job result
75903
- */
75904
- async getResult(jobId: string): Promise<any>
75905
-
75906
- /**
75907
- * Get the result of a job if completed, or its current status
75908
- * @param jobId - ID of the job
75909
- * @returns Object with started, completed, success, and result properties
75910
- */
75911
- async getResultMaybe(jobId: string): Promise<any>
75912
-
75913
- /**
75914
- * @deprecated Use runScriptByPathAsync or runScriptByHashAsync instead
75915
- */
75916
- async runScriptAsync(path: string | null, hash_: string | null, args: Record<string, any> | null, scheduledInSeconds: number | null = null): Promise<string>
75917
-
75918
- /**
75919
- * Run a script asynchronously by its path
75920
- * @param path - Script path in Windmill
75921
- * @param args - Arguments to pass to the script
75922
- * @param scheduledInSeconds - Schedule execution for a future time (in seconds)
75923
- * @returns Job ID of the created job
75924
- */
75925
- async runScriptByPathAsync(path: string, args: Record<string, any> | null = null, scheduledInSeconds: number | null = null): Promise<string>
75926
-
75927
- /**
75928
- * Run a script asynchronously by its hash
75929
- * @param hash_ - Script hash in Windmill
75930
- * @param args - Arguments to pass to the script
75931
- * @param scheduledInSeconds - Schedule execution for a future time (in seconds)
75932
- * @returns Job ID of the created job
75933
- */
75934
- async runScriptByHashAsync(hash_: string, args: Record<string, any> | null = null, scheduledInSeconds: number | null = null): Promise<string>
75935
-
75936
- /**
75937
- * Run a flow asynchronously by its path
75938
- * @param path - Flow path in Windmill
75939
- * @param args - Arguments to pass to the flow
75940
- * @param scheduledInSeconds - Schedule execution for a future time (in seconds)
75941
- * @param doNotTrackInParent - If false, tracks state in parent job (only use when fully awaiting the job)
75942
- * @returns Job ID of the created job
75943
- */
75944
- async runFlowAsync(path: string | null, args: Record<string, any> | null, scheduledInSeconds: number | null = null, // can only be set to false if this the job will be fully await and not concurrent with any other job // as otherwise the child flow and its own child will store their state in the parent job which will // lead to incorrectness and failures doNotTrackInParent: boolean = true): Promise<string>
75945
-
75946
- /**
75947
- * Resolve a resource value in case the default value was picked because the input payload was undefined
75948
- * @param obj resource value or path of the resource under the format \`$res:path\`
75949
- * @returns resource value
75950
- */
75951
- async resolveDefaultResource(obj: any): Promise<any>
75952
-
75953
- /**
75954
- * Get the state file path from environment variables
75955
- * @returns State path string
75956
- */
75957
- getStatePath(): string
75958
-
75959
- /**
75960
- * Set a resource value by path
75961
- * @param path path of the resource to set, default to state path
75962
- * @param value new value of the resource to set
75963
- * @param initializeToTypeIfNotExist if the resource does not exist, initialize it with this type
75964
- */
75965
- async setResource(value: any, path?: string, initializeToTypeIfNotExist?: string): Promise<void>
75966
-
75967
- /**
75968
- * Set the state
75969
- * @param state state to set
75970
- * @deprecated use setState instead
75971
- */
75972
- async setInternalState(state: any): Promise<void>
76299
+ # result = await pipeline(input=data)
76300
+ def task_flow(path: str, timeout: Optional[int] = None, tag: Optional[str] = None, cache_ttl: Optional[int] = None, priority: Optional[int] = None, concurrency_limit: Optional[int] = None, concurrency_key: Optional[str] = None, concurrency_time_window_s: Optional[int] = None)
75973
76301
 
75974
- /**
75975
- * Set the state
75976
- * @param state state to set
75977
- * @param path Optional state resource path override. Defaults to \`getStatePath()\`.
75978
- */
75979
- async setState(state: any, path?: string): Promise<void>
76302
+ # Decorator marking an async function as a workflow-as-code entry point.
76303
+ #
76304
+ # The function must be **deterministic**: given the same inputs it must call
76305
+ # tasks in the same order on every replay. Branching on task results is fine
76306
+ # (results are replayed from checkpoint), but branching on external state
76307
+ # (current time, random values, external API calls) must use \`\`step()\`\` to
76308
+ # checkpoint the value so replays see the same result.
76309
+ def workflow(func)
75980
76310
 
75981
- /**
75982
- * Set the progress
75983
- * Progress cannot go back and limited to 0% to 99% range
75984
- * @param percent Progress to set in %
75985
- * @param jobId? Job to set progress for
75986
- */
75987
- async setProgress(percent: number, jobId?: any): Promise<void>
76311
+ # Execute \`\`fn\`\` inline and checkpoint the result.
76312
+ #
76313
+ # On replay the cached value is returned without re-executing \`\`fn\`\`.
76314
+ # Use for lightweight deterministic operations (timestamps, random IDs,
76315
+ # config reads) that should not incur the overhead of a child job.
76316
+ async def step(name: str, fn)
75988
76317
 
75989
- /**
75990
- * Get the progress
75991
- * @param jobId? Job to get progress from
75992
- * @returns Optional clamped between 0 and 100 progress value
75993
- */
75994
- async getProgress(jobId?: any): Promise<number | null>
76318
+ # Server-side sleep — suspend the workflow for the given duration without holding a worker.
76319
+ #
76320
+ # Inside a @workflow, the parent job suspends and auto-resumes after \`\`seconds\`\`.
76321
+ # Outside a workflow, falls back to \`\`asyncio.sleep\`\`.
76322
+ async def sleep(seconds: int)
75995
76323
 
75996
- /**
75997
- * Set a flow user state
75998
- * @param key key of the state
75999
- * @param value value of the state
76000
- */
76001
- async setFlowUserState(key: string, value: any, errorIfNotPossible?: boolean): Promise<void>
76324
+ # Suspend the workflow and wait for an external approval.
76325
+ #
76326
+ # Use \`\`get_resume_urls()\`\` (wrapped in \`\`step()\`\`) to obtain
76327
+ # resume/cancel/approval URLs before calling this function.
76328
+ #
76329
+ # Returns a dict with \`\`value\`\` (form data), \`\`approver\`\`, and \`\`approved\`\`.
76330
+ #
76331
+ # Example::
76332
+ #
76333
+ # urls = await step("urls", lambda: get_resume_urls())
76334
+ # await step("notify", lambda: send_email(urls["approvalPage"]))
76335
+ # result = await wait_for_approval(timeout=3600)
76336
+ async def wait_for_approval(timeout: int = 1800, form: dict | None = None) -> dict
76002
76337
 
76003
- /**
76004
- * Get a flow user state
76005
- * @param path path of the variable
76006
- */
76007
- async getFlowUserState(key: string, errorIfNotPossible?: boolean): Promise<any>
76338
+ # Process items in parallel with optional concurrency control.
76339
+ #
76340
+ # Each item is processed by calling \`\`fn(item)\`\`, which should be a @task.
76341
+ # Items are dispatched in batches of \`\`concurrency\`\` (default: all at once).
76342
+ #
76343
+ # Example::
76344
+ #
76345
+ # @task
76346
+ # async def process(item: str):
76347
+ # ...
76348
+ #
76349
+ # results = await parallel(items, process, concurrency=5)
76350
+ async def parallel(items, fn, concurrency: Optional[int] = None)
76008
76351
 
76009
- /**
76010
- * Get the internal state
76011
- * @deprecated use getState instead
76012
- */
76013
- async getInternalState(): Promise<any>
76352
+ # Commit Kafka offsets for a trigger with auto_commit disabled.
76353
+ #
76354
+ # Args:
76355
+ # trigger_path: Path to the Kafka trigger (from event['wm_trigger']['trigger_path'])
76356
+ # topic: Kafka topic name (from event['topic'])
76357
+ # partition: Partition number (from event['partition'])
76358
+ # offset: Message offset to commit (from event['offset'])
76359
+ def commit_kafka_offsets(trigger_path: str, topic: str, partition: int, offset: int) -> None
76014
76360
 
76015
- /**
76016
- * Get the state shared across executions
76017
- * @param path Optional state resource path override. Defaults to \`getStatePath()\`.
76018
- */
76019
- async getState(path?: string): Promise<any>
76361
+ `,
76362
+ "write-script-rust": `---
76363
+ name: write-script-rust
76364
+ description: MUST use when writing Rust scripts.
76365
+ ---
76020
76366
 
76021
- /**
76022
- * Get a variable by path
76023
- * @param path path of the variable
76024
- * @returns variable value
76025
- */
76026
- async getVariable(path: string): Promise<string>
76367
+ ## CLI Commands
76027
76368
 
76028
- /**
76029
- * Set a variable by path, create if not exist
76030
- * @param path path of the variable
76031
- * @param value value of the variable
76032
- * @param isSecretIfNotExist if the variable does not exist, create it as secret or not (default: false)
76033
- * @param descriptionIfNotExist if the variable does not exist, create it with this description (default: "")
76034
- */
76035
- async setVariable(path: string, value: string, isSecretIfNotExist?: boolean, descriptionIfNotExist?: string): Promise<void>
76369
+ Place scripts in a folder. After writing, tell the user they can run:
76370
+ - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
76371
+ - \`wmill sync push\` - Deploy to Windmill
76036
76372
 
76037
- /**
76038
- * Build a PostgreSQL connection URL from a database resource
76039
- * @param path - Path to the database resource
76040
- * @returns PostgreSQL connection URL string
76041
- */
76042
- async databaseUrlFromResource(path: string): Promise<string>
76373
+ Do NOT run these commands yourself. Instead, inform the user that they should run them.
76043
76374
 
76044
- async polarsConnectionSettings(s3_resource_path: string | undefined): Promise<any>
76375
+ Use \`wmill resource-type list --schema\` to discover available resource types.
76045
76376
 
76046
- async duckdbConnectionSettings(s3_resource_path: string | undefined): Promise<any>
76377
+ # Rust
76047
76378
 
76048
- /**
76049
- * Get S3 client settings from a resource or workspace default
76050
- * @param s3_resource_path - Path to S3 resource (uses workspace default if undefined)
76051
- * @returns S3 client configuration settings
76052
- */
76053
- async denoS3LightClientSettings(s3_resource_path: string | undefined): Promise<DenoS3LightClientSettings>
76379
+ ## Structure
76054
76380
 
76055
- /**
76056
- * Load the content of a file stored in S3. If the s3ResourcePath is undefined, it will default to the workspace S3 resource.
76057
- *
76058
- * \`\`\`typescript
76059
- * let fileContent = await wmill.loadS3FileContent(inputFile)
76060
- * // if the file is a raw text file, it can be decoded and printed directly:
76061
- * const text = new TextDecoder().decode(fileContentStream)
76062
- * console.log(text);
76063
- * \`\`\`
76064
- */
76065
- async loadS3File(s3object: S3Object, s3ResourcePath: string | undefined = undefined): Promise<Uint8Array | undefined>
76381
+ The script must contain a function called \`main\` with proper return type:
76066
76382
 
76067
- /**
76068
- * Load the content of a file stored in S3 as a stream. If the s3ResourcePath is undefined, it will default to the workspace S3 resource.
76069
- *
76070
- * \`\`\`typescript
76071
- * let fileContentBlob = await wmill.loadS3FileStream(inputFile)
76072
- * // if the content is plain text, the blob can be read directly:
76073
- * console.log(await fileContentBlob.text());
76074
- * \`\`\`
76075
- */
76076
- async loadS3FileStream(s3object: S3Object, s3ResourcePath: string | undefined = undefined): Promise<Blob | undefined>
76383
+ \`\`\`rust
76384
+ use anyhow::anyhow;
76385
+ use serde::Serialize;
76077
76386
 
76078
- /**
76079
- * Persist a file to the S3 bucket. If the s3ResourcePath is undefined, it will default to the workspace S3 resource.
76080
- *
76081
- * \`\`\`typescript
76082
- * const s3object = await writeS3File(s3Object, "Hello Windmill!")
76083
- * const fileContentAsUtf8Str = (await s3object.toArray()).toString('utf-8')
76084
- * console.log(fileContentAsUtf8Str)
76085
- * \`\`\`
76086
- */
76087
- async writeS3File(s3object: S3Object | undefined, fileContent: string | Blob, s3ResourcePath: string | undefined = undefined, contentType: string | undefined = undefined, contentDisposition: string | undefined = undefined): Promise<S3Object>
76387
+ #[derive(Serialize, Debug)]
76388
+ struct ReturnType {
76389
+ result: String,
76390
+ count: i32,
76391
+ }
76088
76392
 
76089
- /**
76090
- * Sign S3 objects to be used by anonymous users in public apps
76091
- * @param s3objects s3 objects to sign
76092
- * @returns signed s3 objects
76093
- */
76094
- async signS3Objects(s3objects: S3Object[]): Promise<S3Object[]>
76393
+ fn main(param1: String, param2: i32) -> anyhow::Result<ReturnType> {
76394
+ Ok(ReturnType {
76395
+ result: param1,
76396
+ count: param2,
76397
+ })
76398
+ }
76399
+ \`\`\`
76095
76400
 
76096
- /**
76097
- * Sign S3 object to be used by anonymous users in public apps
76098
- * @param s3object s3 object to sign
76099
- * @returns signed s3 object
76100
- */
76101
- async signS3Object(s3object: S3Object): Promise<S3Object>
76401
+ **Important:**
76402
+ - Arguments should be owned types
76403
+ - Return type must be serializable (\`#[derive(Serialize)]\`)
76404
+ - Return type is \`anyhow::Result<T>\`
76102
76405
 
76103
- /**
76104
- * Generate a presigned public URL for an array of S3 objects.
76105
- * If an S3 object is not signed yet, it will be signed first.
76106
- * @param s3Objects s3 objects to sign
76107
- * @returns list of signed public URLs
76108
- */
76109
- async getPresignedS3PublicUrls(s3Objects: S3Object[], { baseUrl }: { baseUrl?: string } = {}): Promise<string[]>
76406
+ ## Dependencies
76110
76407
 
76111
- /**
76112
- * Generate a presigned public URL for an S3 object. If the S3 object is not signed yet, it will be signed first.
76113
- * @param s3Object s3 object to sign
76114
- * @returns signed public URL
76115
- */
76116
- async getPresignedS3PublicUrl(s3Objects: S3Object, { baseUrl }: { baseUrl?: string } = {}): Promise<string>
76408
+ Packages must be specified with a partial cargo.toml at the beginning of the script:
76117
76409
 
76118
- /**
76119
- * Get URLs needed for resuming a flow after this step
76120
- * @param approver approver name
76121
- * @param flowLevel if true, generate resume URLs for the parent flow instead of the specific step.
76122
- * This allows pre-approvals that can be consumed by any later suspend step in the same flow.
76123
- * @returns approval page UI URL, resume and cancel API URLs for resuming the flow
76124
- */
76125
- async getResumeUrls(approver?: string, flowLevel?: boolean): Promise<{
76126
- approvalPage: string;
76127
- resume: string;
76128
- cancel: string;
76129
- }>
76410
+ \`\`\`rust
76411
+ //! \`\`\`cargo
76412
+ //! [dependencies]
76413
+ //! anyhow = "1.0.86"
76414
+ //! reqwest = { version = "0.11", features = ["json"] }
76415
+ //! tokio = { version = "1", features = ["full"] }
76416
+ //! \`\`\`
76130
76417
 
76131
- /**
76132
- * @deprecated use getResumeUrls instead
76133
- */
76134
- getResumeEndpoints(approver?: string): Promise<{
76135
- approvalPage: string;
76136
- resume: string;
76137
- cancel: string;
76138
- }>
76418
+ use anyhow::anyhow;
76419
+ // ... rest of the code
76420
+ \`\`\`
76139
76421
 
76140
- /**
76141
- * Get an OIDC jwt token for auth to external services (e.g: Vault, AWS) (ee only)
76142
- * @param audience audience of the token
76143
- * @param expiresIn Optional number of seconds until the token expires
76144
- * @returns jwt token
76145
- */
76146
- async getIdToken(audience: string, expiresIn?: number): Promise<string>
76422
+ **Note:** Serde is already included, no need to add it again.
76147
76423
 
76148
- /**
76149
- * Convert a base64-encoded string to Uint8Array
76150
- * @param data - Base64-encoded string
76151
- * @returns Decoded Uint8Array
76152
- */
76153
- base64ToUint8Array(data: string): Uint8Array
76424
+ ## Async Functions
76154
76425
 
76155
- /**
76156
- * Convert a Uint8Array to base64-encoded string
76157
- * @param arrayBuffer - Uint8Array to encode
76158
- * @returns Base64-encoded string
76159
- */
76160
- uint8ArrayToBase64(arrayBuffer: Uint8Array): string
76426
+ If you need to handle async functions (e.g., using tokio), keep the main function sync and create the runtime inside:
76161
76427
 
76162
- /**
76163
- * Get email from workspace username
76164
- * This method is particularly useful for apps that require the email address of the viewer.
76165
- * Indeed, in the viewer context, WM_USERNAME is set to the username of the viewer but WM_EMAIL is set to the email of the creator of the app.
76166
- * @param username
76167
- * @returns email address
76168
- */
76169
- async usernameToEmail(username: string): Promise<string>
76428
+ \`\`\`rust
76429
+ //! \`\`\`cargo
76430
+ //! [dependencies]
76431
+ //! anyhow = "1.0.86"
76432
+ //! tokio = { version = "1", features = ["full"] }
76433
+ //! reqwest = { version = "0.11", features = ["json"] }
76434
+ //! \`\`\`
76170
76435
 
76171
- /**
76172
- * Sends an interactive approval request via Slack, allowing optional customization of the message, approver, and form fields.
76173
- *
76174
- * **[Enterprise Edition Only]** To include form fields in the Slack approval request, go to **Advanced -> Suspend -> Form**
76175
- * and define a form. Learn more at [Windmill Documentation](https://www.windmill.dev/docs/flows/flow_approval#form).
76176
- *
76177
- * @param {Object} options - The configuration options for the Slack approval request.
76178
- * @param {string} options.slackResourcePath - The path to the Slack resource in Windmill.
76179
- * @param {string} options.channelId - The Slack channel ID where the approval request will be sent.
76180
- * @param {string} [options.message] - Optional custom message to include in the Slack approval request.
76181
- * @param {string} [options.approver] - Optional user ID or name of the approver for the request.
76182
- * @param {DefaultArgs} [options.defaultArgsJson] - Optional object defining or overriding the default arguments to a form field.
76183
- * @param {Enums} [options.dynamicEnumsJson] - Optional object overriding the enum default values of an enum form field.
76184
- * @param {string} [options.resumeButtonText] - Optional text for the resume button.
76185
- * @param {string} [options.cancelButtonText] - Optional text for the cancel button.
76186
- *
76187
- * @returns {Promise<void>} Resolves when the Slack approval request is successfully sent.
76188
- *
76189
- * @throws {Error} If the function is not called within a flow or flow preview.
76190
- * @throws {Error} If the \`JobService.getSlackApprovalPayload\` call fails.
76191
- *
76192
- * **Usage Example:**
76193
- * \`\`\`typescript
76194
- * await requestInteractiveSlackApproval({
76195
- * slackResourcePath: "/u/alex/my_slack_resource",
76196
- * channelId: "admins-slack-channel",
76197
- * message: "Please approve this request",
76198
- * approver: "approver123",
76199
- * defaultArgsJson: { key1: "value1", key2: 42 },
76200
- * dynamicEnumsJson: { foo: ["choice1", "choice2"], bar: ["optionA", "optionB"] },
76201
- * resumeButtonText: "Resume",
76202
- * cancelButtonText: "Cancel",
76203
- * });
76204
- * \`\`\`
76205
- *
76206
- * **Note:** This function requires execution within a Windmill flow or flow preview.
76207
- */
76208
- async requestInteractiveSlackApproval({ slackResourcePath, channelId, message, approver, defaultArgsJson, dynamicEnumsJson, resumeButtonText, cancelButtonText, }: SlackApprovalOptions): Promise<void>
76436
+ use anyhow::anyhow;
76437
+ use serde::Serialize;
76209
76438
 
76210
- /**
76211
- * Sends an interactive approval request via Teams, allowing optional customization of the message, approver, and form fields.
76212
- *
76213
- * **[Enterprise Edition Only]** To include form fields in the Teams approval request, go to **Advanced -> Suspend -> Form**
76214
- * and define a form. Learn more at [Windmill Documentation](https://www.windmill.dev/docs/flows/flow_approval#form).
76215
- *
76216
- * @param {Object} options - The configuration options for the Teams approval request.
76217
- * @param {string} options.teamName - The Teams team name where the approval request will be sent.
76218
- * @param {string} options.channelName - The Teams channel name where the approval request will be sent.
76219
- * @param {string} [options.message] - Optional custom message to include in the Teams approval request.
76220
- * @param {string} [options.approver] - Optional user ID or name of the approver for the request.
76221
- * @param {DefaultArgs} [options.defaultArgsJson] - Optional object defining or overriding the default arguments to a form field.
76222
- * @param {Enums} [options.dynamicEnumsJson] - Optional object overriding the enum default values of an enum form field.
76223
- *
76224
- * @returns {Promise<void>} Resolves when the Teams approval request is successfully sent.
76225
- *
76226
- * @throws {Error} If the function is not called within a flow or flow preview.
76227
- * @throws {Error} If the \`JobService.getTeamsApprovalPayload\` call fails.
76228
- *
76229
- * **Usage Example:**
76230
- * \`\`\`typescript
76231
- * await requestInteractiveTeamsApproval({
76232
- * teamName: "admins-teams",
76233
- * channelName: "admins-teams-channel",
76234
- * message: "Please approve this request",
76235
- * approver: "approver123",
76236
- * defaultArgsJson: { key1: "value1", key2: 42 },
76237
- * dynamicEnumsJson: { foo: ["choice1", "choice2"], bar: ["optionA", "optionB"] },
76238
- * });
76239
- * \`\`\`
76240
- *
76241
- * **Note:** This function requires execution within a Windmill flow or flow preview.
76242
- */
76243
- async requestInteractiveTeamsApproval({ teamName, channelName, message, approver, defaultArgsJson, dynamicEnumsJson, }: TeamsApprovalOptions): Promise<void>
76439
+ #[derive(Serialize, Debug)]
76440
+ struct Response {
76441
+ data: String,
76442
+ }
76244
76443
 
76245
- /**
76246
- * Parse an S3 object from URI string or record format
76247
- * @param s3Object - S3 object as URI string (s3://storage/key) or record
76248
- * @returns S3 object record with storage and s3 key
76249
- */
76250
- parseS3Object(s3Object: S3Object): S3ObjectRecord
76444
+ fn main(url: String) -> anyhow::Result<Response> {
76445
+ let rt = tokio::runtime::Runtime::new()?;
76446
+ rt.block_on(async {
76447
+ let resp = reqwest::get(&url).await?.text().await?;
76448
+ Ok(Response { data: resp })
76449
+ })
76450
+ }
76451
+ \`\`\`
76452
+ `,
76453
+ "write-script-snowflake": `---
76454
+ name: write-script-snowflake
76455
+ description: MUST use when writing Snowflake queries.
76456
+ ---
76251
76457
 
76252
- setWorkflowCtx(ctx: WorkflowCtx | null): void
76458
+ ## CLI Commands
76253
76459
 
76254
- async sleep(seconds: number): Promise<void>
76460
+ Place scripts in a folder. After writing, tell the user they can run:
76461
+ - \`wmill script generate-metadata\` - Generate .script.yaml and .lock files
76462
+ - \`wmill sync push\` - Deploy to Windmill
76255
76463
 
76256
- async step<T>(name: string, fn: () => T | Promise<T>): Promise<T>
76464
+ Do NOT run these commands yourself. Instead, inform the user that they should run them.
76257
76465
 
76258
- /**
76259
- * Create a task that dispatches to a separate Windmill script.
76260
- *
76261
- * @example
76262
- * const extract = taskScript("f/data/extract");
76263
- * // inside workflow: await extract({ url: "https://..." })
76264
- */
76265
- taskScript(path: string, options?: TaskOptions): (...args: any[]) => PromiseLike<any>
76466
+ Use \`wmill resource-type list --schema\` to discover available resource types.
76266
76467
 
76267
- /**
76268
- * Create a task that dispatches to a separate Windmill flow.
76269
- *
76270
- * @example
76271
- * const pipeline = taskFlow("f/etl/pipeline");
76272
- * // inside workflow: await pipeline({ input: data })
76273
- */
76274
- taskFlow(path: string, options?: TaskOptions): (...args: any[]) => PromiseLike<any>
76468
+ # Snowflake
76275
76469
 
76276
- /**
76277
- * Mark an async function as a workflow-as-code entry point.
76278
- *
76279
- * The function must be **deterministic**: given the same inputs it must call
76280
- * tasks in the same order on every replay. Branching on task results is fine
76281
- * (results are replayed from checkpoint), but branching on external state
76282
- * (current time, random values, external API calls) must use \`step()\` to
76283
- * checkpoint the value so replays see the same result.
76284
- */
76285
- workflow<T>(fn: (...args: any[]) => Promise<T>): void
76470
+ Arguments use \`?\` placeholders.
76286
76471
 
76287
- /**
76288
- * Suspend the workflow and wait for an external approval.
76289
- *
76290
- * Use \`getResumeUrls()\` (wrapped in \`step()\`) to obtain resume/cancel/approvalPage
76291
- * URLs before calling this function.
76292
- *
76293
- * @example
76294
- * const urls = await step("urls", () => getResumeUrls());
76295
- * await step("notify", () => sendEmail(urls.approvalPage));
76296
- * const { value, approver } = await waitForApproval({ timeout: 3600 });
76297
- */
76298
- waitForApproval(options?: { timeout?: number; form?: object; }): PromiseLike<{ value: any; approver: string; approved: boolean }>
76472
+ Name the parameters by adding comments before the statement:
76299
76473
 
76300
- /**
76301
- * Process items in parallel with optional concurrency control.
76302
- *
76303
- * Each item is processed by calling \`fn(item)\`, which should be a task().
76304
- * Items are dispatched in batches of \`concurrency\` (default: all at once).
76305
- *
76306
- * @example
76307
- * const process = task(async (item: string) => { ... });
76308
- * const results = await parallel(items, process, { concurrency: 5 });
76309
- */
76310
- async parallel<T, R>(items: T[], fn: (item: T) => PromiseLike<R> | R, options?: { concurrency?: number },): Promise<R[]>
76474
+ \`\`\`sql
76475
+ -- ? name1 (text)
76476
+ -- ? name2 (number) = 0
76477
+ SELECT * FROM users WHERE name = ? AND age > ?;
76478
+ \`\`\`
76311
76479
  `,
76312
76480
  "write-flow": `---
76313
76481
  name: write-flow
@@ -76320,10 +76488,12 @@ description: MUST use when creating flows.
76320
76488
 
76321
76489
  Create a folder ending with \`.flow\` and add a YAML file with the flow definition.
76322
76490
  For rawscript modules, use \`!inline path/to/script.ts\` for the content key.
76323
- After writing:
76491
+ After writing, tell the user they can run:
76324
76492
  - \`wmill flow generate-locks <path_to_flow_folder> --yes\` - Generate lock files for the specific flow you modified (e.g. \`wmill flow generate-locks f/my_folder/my_flow.flow --yes\`)
76325
76493
  - \`wmill sync push\` - Deploy to Windmill
76326
76494
 
76495
+ Do NOT run these commands yourself. Instead, inform the user that they should run them.
76496
+
76327
76497
  ## OpenFlow Schema
76328
76498
 
76329
76499
  The OpenFlow schema (openflow.openapi.yaml) is the source of truth for flow structure. Refer to OPENFLOW_SCHEMA for the complete type definitions.
@@ -76521,7 +76691,7 @@ export async function main(user_id: string) {
76521
76691
  }
76522
76692
  \`\`\`
76523
76693
 
76524
- After creating, generate lock files:
76694
+ After creating, tell the user they can generate lock files by running:
76525
76695
  \`\`\`bash
76526
76696
  wmill app generate-locks
76527
76697
  \`\`\`
@@ -76674,6 +76844,8 @@ data:
76674
76844
 
76675
76845
  ## CLI Commands
76676
76846
 
76847
+ Tell the user they can run these commands (do NOT run them yourself):
76848
+
76677
76849
  | Command | Description |
76678
76850
  |---------|-------------|
76679
76851
  | \`wmill app new\` | Create a new raw app interactively |
@@ -76690,7 +76862,7 @@ data:
76690
76862
  3. **Keep runnables focused** - one function per file
76691
76863
  4. **Use descriptive IDs** - \`get_user.ts\` not \`a.ts\`
76692
76864
  5. **Always whitelist tables** - add to \`data.tables\` before querying
76693
- 6. **Generate locks** - run \`wmill app generate-locks\` after adding/modifying backend runnables
76865
+ 6. **Generate locks** - tell the user to run \`wmill app generate-locks\` after adding/modifying backend runnables
76694
76866
  `,
76695
76867
  triggers: `---
76696
76868
  name: triggers
@@ -76712,6 +76884,8 @@ Examples:
76712
76884
 
76713
76885
  ## CLI Commands
76714
76886
 
76887
+ After writing, tell the user they can run these commands (do NOT run them yourself):
76888
+
76715
76889
  \`\`\`bash
76716
76890
  # Push trigger configuration
76717
76891
  wmill sync push
@@ -76761,6 +76935,8 @@ Windmill uses 6-field cron expressions (includes seconds):
76761
76935
 
76762
76936
  ## CLI Commands
76763
76937
 
76938
+ After writing, tell the user they can run these commands (do NOT run them yourself):
76939
+
76764
76940
  \`\`\`bash
76765
76941
  # Push schedules to Windmill
76766
76942
  wmill sync push
@@ -77016,7 +77192,7 @@ wmill resource-type list --schema
77016
77192
  # Get specific resource type schema
77017
77193
  wmill resource-type get postgresql
77018
77194
 
77019
- # Push resources
77195
+ # Push resources (tell the user to run this, do NOT run it yourself)
77020
77196
  wmill sync push
77021
77197
  \`\`\`
77022
77198
  `,
@@ -77029,8 +77205,6 @@ description: MUST use when using the CLI.
77029
77205
 
77030
77206
  The Windmill CLI (\`wmill\`) provides commands for managing scripts, flows, apps, and other resources.
77031
77207
 
77032
- Current version: 1.651.1
77033
-
77034
77208
  ## Global Options
77035
77209
 
77036
77210
  - \`--workspace <workspace:string>\` - Specify the target workspace. This overrides the default workspace.
@@ -77776,6 +77950,18 @@ properties:
77776
77950
  key:
77777
77951
  type: string
77778
77952
  value: {}
77953
+ auto_offset_reset:
77954
+ type: string
77955
+ enum:
77956
+ - latest
77957
+ - earliest
77958
+ description: Initial offset behavior when consumer group has no committed offset.
77959
+ 'latest' starts from new messages only, 'earliest' starts from the beginning.
77960
+ auto_commit:
77961
+ type: boolean
77962
+ description: When true (default), offsets are committed automatically after receiving
77963
+ each message. When false, you must manually commit offsets using the commit_offsets
77964
+ endpoint.
77779
77965
  error_handler_path:
77780
77966
  type: string
77781
77967
  description: Path to a script or flow to run when the triggered job fails
@@ -78764,6 +78950,164 @@ var push12 = new Command().description("Push completed and queued jobs to worksp
78764
78950
  var command28 = new Command().description("Manage jobs (import/export)").command("pull", pull3).command("push", push12);
78765
78951
  var jobs_default = command28;
78766
78952
 
78953
+ // src/commands/generate-metadata/generate-metadata.ts
78954
+ init_mod3();
78955
+ init_colors2();
78956
+ init_log();
78957
+ init_resource_folders();
78958
+ await __promiseAll([
78959
+ init_confirm(),
78960
+ init_conf(),
78961
+ init_context(),
78962
+ init_auth(),
78963
+ init_metadata(),
78964
+ init_flow_metadata(),
78965
+ init_app_metadata(),
78966
+ init_sync(),
78967
+ init_script(),
78968
+ init_codebase()
78969
+ ]);
78970
+ import { sep as SEP21 } from "node:path";
78971
+ async function generateMetadata2(opts, folder) {
78972
+ if (folder === "") {
78973
+ folder = undefined;
78974
+ }
78975
+ const workspace = await resolveWorkspace(opts);
78976
+ await requireLogin(opts);
78977
+ opts = await mergeConfigWithConfigFile(opts);
78978
+ const rawWorkspaceDependencies = await getRawWorkspaceDependencies();
78979
+ const codebases = await listSyncCodebases(opts);
78980
+ const ignore = await ignoreF(opts);
78981
+ const staleItems = [];
78982
+ const skipScripts = opts.skipScripts ?? false;
78983
+ const skipFlows = opts.skipFlows ?? opts.schemaOnly ?? false;
78984
+ const skipApps = opts.skipApps ?? opts.schemaOnly ?? false;
78985
+ const checking = [];
78986
+ if (!skipScripts)
78987
+ checking.push("scripts");
78988
+ if (!skipFlows)
78989
+ checking.push("flows");
78990
+ if (!skipApps)
78991
+ checking.push("apps");
78992
+ if (checking.length === 0) {
78993
+ info(colors.yellow("Nothing to check (all types skipped)"));
78994
+ return;
78995
+ }
78996
+ info(colors.gray(`Checking ${checking.join(", ")}...`));
78997
+ if (!skipScripts) {
78998
+ const scriptElems = await elementsToMap(await FSFSElement(process.cwd(), codebases, false), (p, isD) => {
78999
+ return !isD && !exts.some((ext2) => p.endsWith(ext2)) || ignore(p, isD) || isFlowPath(p) || isAppPath(p);
79000
+ }, false, {});
79001
+ for (const e of Object.keys(scriptElems)) {
79002
+ const candidate = await generateScriptMetadataInternal(e, workspace, opts, true, true, rawWorkspaceDependencies, codebases, false);
79003
+ if (candidate) {
79004
+ staleItems.push({ type: "script", path: candidate, folder: e });
79005
+ }
79006
+ }
79007
+ }
79008
+ if (!skipFlows) {
79009
+ const flowElems = Object.keys(await elementsToMap(await FSFSElement(process.cwd(), [], true), (p, isD) => {
79010
+ return ignore(p, isD) || !isD && !p.endsWith(SEP21 + "flow.yaml") && !p.endsWith(SEP21 + "flow.json");
79011
+ }, false, {})).map((x) => x.substring(0, x.lastIndexOf(SEP21)));
79012
+ for (const folder2 of flowElems) {
79013
+ const candidate = await generateFlowLockInternal(folder2, true, workspace, opts, false, true);
79014
+ if (candidate) {
79015
+ staleItems.push({ type: "flow", path: candidate, folder: folder2 });
79016
+ }
79017
+ }
79018
+ }
79019
+ if (!skipApps) {
79020
+ const elems = await elementsToMap(await FSFSElement(process.cwd(), [], true), (p, isD) => {
79021
+ return ignore(p, isD) || !isD && !p.endsWith(SEP21 + "raw_app.yaml") && !p.endsWith(SEP21 + "app.yaml");
79022
+ }, false, {});
79023
+ const rawAppFolders = getAppFolders(elems, "raw_app.yaml");
79024
+ const appFolders = getAppFolders(elems, "app.yaml");
79025
+ for (const appFolder of rawAppFolders) {
79026
+ const candidate = await generateAppLocksInternal(appFolder, true, true, workspace, opts, false, true);
79027
+ if (candidate) {
79028
+ staleItems.push({ type: "app", path: candidate, folder: appFolder, isRawApp: true });
79029
+ }
79030
+ }
79031
+ for (const appFolder of appFolders) {
79032
+ const candidate = await generateAppLocksInternal(appFolder, false, true, workspace, opts, false, true);
79033
+ if (candidate) {
79034
+ staleItems.push({ type: "app", path: candidate, folder: appFolder, isRawApp: false });
79035
+ }
79036
+ }
79037
+ }
79038
+ let filteredItems = staleItems;
79039
+ if (folder) {
79040
+ if (folder.endsWith(SEP21)) {
79041
+ folder = folder.substring(0, folder.length - 1);
79042
+ }
79043
+ filteredItems = staleItems.filter((item) => item.folder === folder || item.folder.startsWith(folder + SEP21));
79044
+ }
79045
+ if (filteredItems.length === 0) {
79046
+ info(colors.green("All metadata up-to-date"));
79047
+ return;
79048
+ }
79049
+ const scripts = filteredItems.filter((i) => i.type === "script");
79050
+ const flows = filteredItems.filter((i) => i.type === "flow");
79051
+ const apps2 = filteredItems.filter((i) => i.type === "app");
79052
+ info("");
79053
+ info(`Found ${filteredItems.length} item(s) with stale metadata:`);
79054
+ if (scripts.length > 0) {
79055
+ info(colors.gray(` Scripts (${scripts.length}):`));
79056
+ for (const item of scripts) {
79057
+ info(colors.yellow(` ${item.path}`));
79058
+ }
79059
+ }
79060
+ if (flows.length > 0) {
79061
+ info(colors.gray(` Flows (${flows.length}):`));
79062
+ for (const item of flows) {
79063
+ info(colors.yellow(` ${item.path}`));
79064
+ }
79065
+ }
79066
+ if (apps2.length > 0) {
79067
+ info(colors.gray(` Apps (${apps2.length}):`));
79068
+ for (const item of apps2) {
79069
+ info(colors.yellow(` ${item.path}`));
79070
+ }
79071
+ }
79072
+ if (opts.dryRun) {
79073
+ return;
79074
+ }
79075
+ info("");
79076
+ if (!opts.yes && !await Confirm.prompt({
79077
+ message: "Update metadata?",
79078
+ default: true
79079
+ })) {
79080
+ return;
79081
+ }
79082
+ info("");
79083
+ const total = filteredItems.length;
79084
+ const maxWidth = `[${total}/${total}]`.length;
79085
+ let current = 0;
79086
+ const formatProgress = (n) => {
79087
+ const bracket = `[${n}/${total}]`;
79088
+ return colors.gray(bracket.padEnd(maxWidth, " "));
79089
+ };
79090
+ for (const item of scripts) {
79091
+ current++;
79092
+ info(`${formatProgress(current)} script ${colors.cyan(item.path)}`);
79093
+ await generateScriptMetadataInternal(item.folder, workspace, opts, false, true, rawWorkspaceDependencies, codebases, false);
79094
+ }
79095
+ for (const item of flows) {
79096
+ current++;
79097
+ info(`${formatProgress(current)} flow ${colors.cyan(item.path)}`);
79098
+ await generateFlowLockInternal(item.folder, false, workspace, opts, false, true);
79099
+ }
79100
+ for (const item of apps2) {
79101
+ current++;
79102
+ info(`${formatProgress(current)} app ${colors.cyan(item.path)}`);
79103
+ await generateAppLocksInternal(item.folder, item.isRawApp, false, workspace, opts, false, true);
79104
+ }
79105
+ info("");
79106
+ info(colors.green(`Done. Updated ${total} item(s).`));
79107
+ }
79108
+ var command29 = new Command().description("Generate metadata (locks, schemas) for all scripts, flows, and apps").arguments("[folder:string]").option("--yes", "Skip confirmation prompt").option("--dry-run", "Show what would be updated without making changes").option("--lock-only", "Re-generate only the lock files").option("--schema-only", "Re-generate only script schemas (skips flows and apps)").option("--skip-scripts", "Skip processing scripts").option("--skip-flows", "Skip processing flows").option("--skip-apps", "Skip processing apps").option("-i --includes <patterns:file[]>", "Comma separated patterns to specify which files to include").option("-e --excludes <patterns:file[]>", "Comma separated patterns to specify which files to exclude").action(generateMetadata2);
79109
+ var generate_metadata_default = command29;
79110
+
78767
79111
  // src/commands/docs/docs.ts
78768
79112
  init_mod3();
78769
79113
  init_colors2();
@@ -78834,13 +79178,13 @@ ${await res.text()}`);
78834
79178
  console.log();
78835
79179
  }
78836
79180
  }
78837
- var command29 = new Command().name("docs").description("Search Windmill documentation. Requires Enterprise Edition.").arguments("<query:string>").option("--json", "Output results as JSON.").action(docs);
78838
- var docs_default = command29;
79181
+ var command30 = new Command().name("docs").description("Search Windmill documentation. Requires Enterprise Edition.").arguments("<query:string>").option("--json", "Output results as JSON.").action(docs);
79182
+ var docs_default = command30;
78839
79183
 
78840
79184
  // src/main.ts
78841
79185
  await init_context();
78842
- var VERSION = "1.654.0";
78843
- var command30 = new Command().name("wmill").action(() => info(`Welcome to Windmill CLI ${VERSION}. Use -h for help.`)).description("Windmill CLI").globalOption("--workspace <workspace:string>", "Specify the target workspace. This overrides the default workspace.").globalOption("--debug --verbose", "Show debug/verbose logs").globalOption("--show-diffs", "Show diff informations when syncing (may show sensitive informations)").globalOption("--token <token:string>", "Specify an API token. This will override any stored token.").globalOption("--base-url <baseUrl:string>", "Specify the base URL of the API. If used, --token and --workspace are required and no local remote/workspace already set will be used.").globalOption("--config-dir <configDir:string>", "Specify a custom config directory. Overrides WMILL_CONFIG_DIR environment variable and default ~/.config location.").env("HEADERS <headers:string>", `Specify headers to use for all requests. e.g: "HEADERS='h1: v1, h2: v2'"`).version(VERSION).versionOption(false).command("init", init_default).command("app", app_default).command("flow", flow_default).command("script", script_default).command("workspace", workspace_default).command("resource", resource_default).command("resource-type", resource_type_default).command("user", user_default).command("variable", variable_default).command("hub", hub_default).command("folder", folder_default).command("schedule", schedule_default).command("trigger", trigger_default).command("dev", dev_default2).command("sync", sync_default).command("lint", lint_default).command("gitsync-settings", gitsync_settings_default).command("instance", instance_default).command("worker-groups", worker_groups_default).command("workers", workers_default).command("queues", queues_default).command("dependencies", dependencies_default).command("jobs", jobs_default).command("docs", docs_default).command("version --version", "Show version information").action(async (opts) => {
79186
+ var VERSION = "1.655.0";
79187
+ var command31 = new Command().name("wmill").action(() => info(`Welcome to Windmill CLI ${VERSION}. Use -h for help.`)).description("Windmill CLI").globalOption("--workspace <workspace:string>", "Specify the target workspace. This overrides the default workspace.").globalOption("--debug --verbose", "Show debug/verbose logs").globalOption("--show-diffs", "Show diff informations when syncing (may show sensitive informations)").globalOption("--token <token:string>", "Specify an API token. This will override any stored token.").globalOption("--base-url <baseUrl:string>", "Specify the base URL of the API. If used, --token and --workspace are required and no local remote/workspace already set will be used.").globalOption("--config-dir <configDir:string>", "Specify a custom config directory. Overrides WMILL_CONFIG_DIR environment variable and default ~/.config location.").env("HEADERS <headers:string>", `Specify headers to use for all requests. e.g: "HEADERS='h1: v1, h2: v2'"`).version(VERSION).versionOption(false).command("init", init_default).command("app", app_default).command("flow", flow_default).command("script", script_default).command("workspace", workspace_default).command("resource", resource_default).command("resource-type", resource_type_default).command("user", user_default).command("variable", variable_default).command("hub", hub_default).command("folder", folder_default).command("schedule", schedule_default).command("trigger", trigger_default).command("dev", dev_default2).command("sync", sync_default).command("lint", lint_default).command("gitsync-settings", gitsync_settings_default).command("instance", instance_default).command("worker-groups", worker_groups_default).command("workers", workers_default).command("queues", queues_default).command("dependencies", dependencies_default).command("jobs", jobs_default).command("generate-metadata", generate_metadata_default).command("docs", docs_default).command("version --version", "Show version information").action(async (opts) => {
78844
79188
  console.log("CLI version: " + VERSION);
78845
79189
  try {
78846
79190
  const provider = new NpmProvider({ package: "windmill-cli" });
@@ -78870,20 +79214,20 @@ var command30 = new Command().name("wmill").action(() => info(`Welcome to Windmi
78870
79214
  error(e);
78871
79215
  info("Try running with sudo and otherwise check the result of the command: npm uninstall windmill-cli && npm install -g windmill-cli");
78872
79216
  })).command("completions", new Command().description("Generate shell completions.").command("bash", new Command().description("Generate bash completions.").action(() => {
78873
- process.stdout.write(generateShellCompletions(command30, "bash") + `
79217
+ process.stdout.write(generateShellCompletions(command31, "bash") + `
78874
79218
  `);
78875
79219
  })).command("zsh", new Command().description("Generate zsh completions.").action(() => {
78876
- process.stdout.write(generateShellCompletions(command30, "zsh") + `
79220
+ process.stdout.write(generateShellCompletions(command31, "zsh") + `
78877
79221
  `);
78878
79222
  })).command("fish", new Command().description("Generate fish completions.").action(() => {
78879
- process.stdout.write(generateShellCompletions(command30, "fish") + `
79223
+ process.stdout.write(generateShellCompletions(command31, "fish") + `
78880
79224
  `);
78881
79225
  })));
78882
79226
  async function main2() {
78883
79227
  try {
78884
79228
  const args = process.argv.slice(2);
78885
79229
  if (args.length === 0) {
78886
- command30.showHelp();
79230
+ command31.showHelp();
78887
79231
  }
78888
79232
  const LOG_LEVEL = args.includes("--verbose") || args.includes("--debug") ? "DEBUG" : "INFO";
78889
79233
  setShowDiffs(args.includes("--show-diffs"));
@@ -78893,7 +79237,7 @@ async function main2() {
78893
79237
  if (extraHeaders) {
78894
79238
  OpenAPI.HEADERS = extraHeaders;
78895
79239
  }
78896
- await command30.parse(args);
79240
+ await command31.parse(args);
78897
79241
  } catch (e) {
78898
79242
  if (e && typeof e === "object" && "name" in e && e.name === "ApiError") {
78899
79243
  console.log("Server failed. " + e.statusText + ": " + e.body);
@@ -78918,7 +79262,7 @@ if (isMain()) {
78918
79262
  process.stdin.destroy();
78919
79263
  });
78920
79264
  }
78921
- var main_default = command30;
79265
+ var main_default = command31;
78922
79266
  export {
78923
79267
  add as workspaceAdd,
78924
79268
  workspace_default as workspace,