windmill-cli 1.700.2 → 1.702.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 +196 -71
  2. package/package.json +1 -1
package/esm/main.js CHANGED
@@ -16752,7 +16752,7 @@ var init_OpenAPI = __esm(() => {
16752
16752
  PASSWORD: undefined,
16753
16753
  TOKEN: getEnv3("WM_TOKEN"),
16754
16754
  USERNAME: undefined,
16755
- VERSION: "1.700.2",
16755
+ VERSION: "1.702.0",
16756
16756
  WITH_CREDENTIALS: true,
16757
16757
  interceptors: {
16758
16758
  request: new Interceptors,
@@ -44417,7 +44417,7 @@ var require_zipEntries = __commonJS((exports, module) => {
44417
44417
  if (this.centralDirRecords !== this.files.length) {
44418
44418
  if (this.centralDirRecords !== 0 && this.files.length === 0) {
44419
44419
  throw new Error("Corrupted zip or bug: expected " + this.centralDirRecords + " records in central dir, got " + this.files.length);
44420
- } else {}
44420
+ }
44421
44421
  }
44422
44422
  },
44423
44423
  readEndOfCentral: function() {
@@ -47151,7 +47151,7 @@ async function downloadZip(workspace, plainSecrets, skipVariables, skipResources
47151
47151
  }
47152
47152
  }
47153
47153
  const includeWorkspaceDependenciesValue = !(skipWorkspaceDependencies ?? false);
47154
- const baseParams = `&plain_secret=${plainSecrets ?? false}&skip_variables=${skipVariables ?? false}&skip_resources=${skipResources ?? false}&skip_secrets=${skipSecrets ?? false}&include_schedules=${includeSchedules ?? false}&include_triggers=${includeTriggers ?? false}&include_users=${includeUsers ?? false}&include_groups=${includeGroups ?? false}&include_settings=${includeSettings ?? false}&include_key=${includeKey ?? false}&include_workspace_dependencies=${includeWorkspaceDependenciesValue}&default_ts=${defaultTs ?? "bun"}&skip_resource_types=${skipResourceTypes ?? false}&settings_version=v2`;
47154
+ const baseParams = `&plain_secret=${plainSecrets ?? false}&skip_variables=${skipVariables ?? false}&skip_resources=${skipResources ?? false}&skip_secrets=${skipSecrets ?? false}&include_schedules=${includeSchedules ?? false}&include_triggers=${includeTriggers ?? false}&include_users=${includeUsers ?? false}&include_groups=${includeGroups ?? false}&include_settings=${includeSettings ?? false}&include_key=${includeKey ?? false}&include_workspace_dependencies=${includeWorkspaceDependenciesValue}&default_ts=${defaultTs ?? "bun"}&skip_resource_types=${skipResourceTypes ?? false}&settings_version=v2&preserve_extra_perms=true`;
47155
47155
  const baseUrl2 = workspace.remote + "api/w/" + workspace.workspaceId + "/workspaces/tarball?";
47156
47156
  const zipUrl = baseUrl2 + "archive_type=zip" + baseParams;
47157
47157
  const zipResponse = await fetch(zipUrl, { headers: requestHeaders, method: "GET" });
@@ -55347,7 +55347,7 @@ var require_loader = __commonJS((exports, module) => {
55347
55347
  var error2 = generateError(state, message);
55348
55348
  if (state.onWarning) {
55349
55349
  state.onWarning.call(null, error2);
55350
- } else {}
55350
+ }
55351
55351
  }
55352
55352
  var directiveHandlers = {
55353
55353
  YAML: function handleYamlDirective(state, name, args) {
@@ -55885,7 +55885,7 @@ var require_loader = __commonJS((exports, module) => {
55885
55885
  } else if (detectedIndent) {
55886
55886
  sc.value += common3.repeat(`
55887
55887
  `, emptyLines + 1);
55888
- } else {}
55888
+ }
55889
55889
  detectedIndent = true;
55890
55890
  emptyLines = 0;
55891
55891
  captureStart = state.position;
@@ -61584,6 +61584,109 @@ var require_dist3 = __commonJS((exports) => {
61584
61584
  __exportStar2(require_validation3(), exports);
61585
61585
  });
61586
61586
 
61587
+ // src/core/extra_perms.ts
61588
+ function normalize5(value, source) {
61589
+ const perms = {};
61590
+ const invalidOwners = new Set;
61591
+ if (value === null || value === undefined || typeof value !== "object" || Array.isArray(value)) {
61592
+ if (value !== undefined && value !== null) {
61593
+ error(colors.red(`extra_perms: ${source} is not a {owner: boolean} map — skipping ACL sync to avoid clobbering remote ACLs`));
61594
+ return { perms, invalidOwners, malformedTop: true };
61595
+ }
61596
+ return { perms, invalidOwners, malformedTop: false };
61597
+ }
61598
+ const invalidList = [];
61599
+ for (const [k, v] of Object.entries(value)) {
61600
+ if (typeof v === "boolean") {
61601
+ perms[k] = v;
61602
+ } else {
61603
+ invalidOwners.add(k);
61604
+ invalidList.push(k);
61605
+ }
61606
+ }
61607
+ if (invalidList.length > 0) {
61608
+ error(colors.red(`extra_perms: ${invalidList.length} invalid entry/entries in ${source} (non-boolean value, treating as "no opinion"): ${invalidList.join(", ")}`));
61609
+ }
61610
+ return { perms, invalidOwners, malformedTop: false };
61611
+ }
61612
+ function formatError(e) {
61613
+ if (!e || typeof e !== "object")
61614
+ return String(e);
61615
+ const anyE = e;
61616
+ if (anyE.body !== undefined) {
61617
+ if (typeof anyE.body === "string")
61618
+ return anyE.body;
61619
+ try {
61620
+ return JSON.stringify(anyE.body);
61621
+ } catch {}
61622
+ }
61623
+ if (typeof anyE.message === "string")
61624
+ return anyE.message;
61625
+ try {
61626
+ return JSON.stringify(e);
61627
+ } catch {
61628
+ return String(e);
61629
+ }
61630
+ }
61631
+ async function applyExtraPermsDiff(workspace, kind, path7, local, remote) {
61632
+ if (local === undefined || local === null) {
61633
+ return 0;
61634
+ }
61635
+ const localN = normalize5(local, "local yaml");
61636
+ if (localN.malformedTop) {
61637
+ return 0;
61638
+ }
61639
+ const remoteN = normalize5(remote, "remote response");
61640
+ const localPerms = localN.perms;
61641
+ const remotePerms = remoteN.perms;
61642
+ const toGrant = [];
61643
+ for (const [owner, write] of Object.entries(localPerms)) {
61644
+ if (!(owner in remotePerms) || remotePerms[owner] !== write) {
61645
+ toGrant.push([owner, write]);
61646
+ }
61647
+ }
61648
+ const toRevoke = Object.keys(remotePerms).filter((owner) => !(owner in localPerms) && !localN.invalidOwners.has(owner));
61649
+ if (toGrant.length === 0 && toRevoke.length === 0) {
61650
+ return 0;
61651
+ }
61652
+ let calls = 0;
61653
+ for (const [owner, write] of toGrant) {
61654
+ const access = write ? "write" : "read";
61655
+ try {
61656
+ await addGranularAcls({
61657
+ workspace,
61658
+ kind,
61659
+ path: path7,
61660
+ requestBody: { owner, write }
61661
+ });
61662
+ info(colors.green(` extra_perms: granted ${access} to ${owner} on ${kind}/${path7}`));
61663
+ calls += 1;
61664
+ } catch (e) {
61665
+ error(colors.red(` extra_perms: failed to grant ${access} to ${owner} on ${kind}/${path7}: ${formatError(e)}`));
61666
+ }
61667
+ }
61668
+ for (const owner of toRevoke) {
61669
+ try {
61670
+ await removeGranularAcls({
61671
+ workspace,
61672
+ kind,
61673
+ path: path7,
61674
+ requestBody: { owner }
61675
+ });
61676
+ info(colors.green(` extra_perms: revoked ${owner} on ${kind}/${path7}`));
61677
+ calls += 1;
61678
+ } catch (e) {
61679
+ error(colors.red(` extra_perms: failed to revoke ${owner} on ${kind}/${path7}: ${formatError(e)}`));
61680
+ }
61681
+ }
61682
+ return calls;
61683
+ }
61684
+ var init_extra_perms = __esm(() => {
61685
+ init_services_gen();
61686
+ init_log();
61687
+ init_colors2();
61688
+ });
61689
+
61587
61690
  // src/core/specific_items.ts
61588
61691
  async function resolveWsNameForGitBranch(branchName) {
61589
61692
  const config = await readConfigFile({ warnIfMissing: false });
@@ -62451,6 +62554,7 @@ async function handleFile(path8, workspace, alreadySynced, message, opts, rawWor
62451
62554
  if (typed == undefined || typed.description === remote.description && typed.summary === remote.summary && typed.kind == remote.kind && !remote.archived && (Array.isArray(remote?.lock) ? remote?.lock?.join(`
62452
62555
  `) : remote?.lock ?? "").trim() == (typed?.lock ?? "").trim() && deepEqual(typed.schema, remote.schema) && typed.tag == remote.tag && (typed.ws_error_handler_muted ?? false) == remote.ws_error_handler_muted && typed.dedicated_worker == remote.dedicated_worker && typed.cache_ttl == remote.cache_ttl && typed.concurrency_time_window_s == remote.concurrency_time_window_s && typed.concurrent_limit == remote.concurrent_limit && Boolean(typed.restart_unless_cancelled) == Boolean(remote.restart_unless_cancelled) && Boolean(typed.visible_to_runner_only) == Boolean(remote.visible_to_runner_only) && Boolean(typed.has_preprocessor) == Boolean(remote.has_preprocessor) && typed.priority == Boolean(remote.priority) && typed.timeout == remote.timeout && typed.concurrency_key == remote["concurrency_key"] && typed.debounce_key == remote["debounce_key"] && typed.debounce_delay_s == remote["debounce_delay_s"] && typed.codebase == remote.codebase && (hasOnBehalfOf ? true : typed.on_behalf_of_email == remote.on_behalf_of_email) && deepEqual(typed.envs, remote.envs) && deepEqual(modules ?? null, remote.modules ?? null)) {
62453
62556
  info(colors.green(`Script ${remotePath} is up to date`));
62557
+ await applyExtraPermsDiff(workspaceId, "script", remotePath.replaceAll(SEP4, "/"), typed?.extra_perms, remote?.extra_perms);
62454
62558
  return true;
62455
62559
  }
62456
62560
  }
@@ -62471,6 +62575,7 @@ async function handleFile(path8, workspace, alreadySynced, message, opts, rawWor
62471
62575
  const execTime = await createScript2(bundleContent, workspaceId, body, workspace);
62472
62576
  info(colors.yellow.bold(`Created new script ${remotePath} (${execTime.toFixed(0)}ms)`));
62473
62577
  }
62578
+ await applyExtraPermsDiff(workspaceId, "script", remotePath.replaceAll(SEP4, "/"), typed?.extra_perms, remote?.extra_perms);
62474
62579
  return true;
62475
62580
  }
62476
62581
  return false;
@@ -63213,6 +63318,7 @@ async function setPermissionedAs(opts, scriptPath, email) {
63213
63318
  }
63214
63319
  var import_yaml6, exts, languageAliases, command4, script_default;
63215
63320
  var init_script = __esm(async () => {
63321
+ init_extra_perms();
63216
63322
  init_colors2();
63217
63323
  init_mod3();
63218
63324
  init_mod6();
@@ -64370,12 +64476,16 @@ var init_path_assigner = __esm(() => {
64370
64476
  });
64371
64477
 
64372
64478
  // windmill-utils-internal/src/inline-scripts/extractor.ts
64373
- function extractRawscriptInline(id, summary, rawscript, mapping, separator, assigner) {
64479
+ function extractRawscriptInline(id, summary, rawscript, mapping, separator, assigner, failOnInlineDirective) {
64374
64480
  const [basePath, ext2] = assigner.assignPath(summary ?? id, rawscript.language);
64375
64481
  const mappedPath = mapping[id];
64376
64482
  const path10 = mappedPath ?? basePath + ext2;
64377
64483
  const language = rawscript.language;
64378
64484
  const content = rawscript.content;
64485
+ if (failOnInlineDirective && typeof content === "string" && content.startsWith("!inline ")) {
64486
+ throw new Error(`Refusing to extract corrupted inline script for module '${id}': ` + `rawscript.content is the literal string \`${content.split(`
64487
+ `)[0]}\` ` + `instead of script source. The backend's flow_version.value is corrupt — ` + `re-push from a known-good local copy to repair it.`);
64488
+ }
64379
64489
  const r = [{ path: path10, content, language, is_lock: false }];
64380
64490
  rawscript.content = "!inline " + path10.replaceAll(separator, "/");
64381
64491
  const lock = rawscript.lock;
@@ -64390,19 +64500,20 @@ function extractRawscriptInline(id, summary, rawscript, mapping, separator, assi
64390
64500
  }
64391
64501
  function extractInlineScripts(modules, mapping = {}, separator = "/", defaultTs, pathAssigner, options) {
64392
64502
  const assigner = pathAssigner ?? newPathAssigner(defaultTs ?? "bun", { skipInlineScriptSuffix: options?.skipInlineScriptSuffix });
64503
+ const failOnInlineDirective = options?.failOnInlineDirective ?? false;
64393
64504
  return modules.flatMap((m) => {
64394
64505
  if (m.value.type == "rawscript") {
64395
- return extractRawscriptInline(m.id, m.summary, m.value, mapping, separator, assigner);
64506
+ return extractRawscriptInline(m.id, m.summary, m.value, mapping, separator, assigner, failOnInlineDirective);
64396
64507
  } else if (m.value.type == "forloopflow") {
64397
- return extractInlineScripts(m.value.modules, mapping, separator, defaultTs, assigner);
64508
+ return extractInlineScripts(m.value.modules, mapping, separator, defaultTs, assigner, options);
64398
64509
  } else if (m.value.type == "branchall") {
64399
- return m.value.branches.flatMap((b) => extractInlineScripts(b.modules, mapping, separator, defaultTs, assigner));
64510
+ return m.value.branches.flatMap((b) => extractInlineScripts(b.modules, mapping, separator, defaultTs, assigner, options));
64400
64511
  } else if (m.value.type == "whileloopflow") {
64401
- return extractInlineScripts(m.value.modules, mapping, separator, defaultTs, assigner);
64512
+ return extractInlineScripts(m.value.modules, mapping, separator, defaultTs, assigner, options);
64402
64513
  } else if (m.value.type == "branchone") {
64403
64514
  return [
64404
- ...m.value.branches.flatMap((b) => extractInlineScripts(b.modules, mapping, separator, defaultTs, assigner)),
64405
- ...extractInlineScripts(m.value.default, mapping, separator, defaultTs, assigner)
64515
+ ...m.value.branches.flatMap((b) => extractInlineScripts(b.modules, mapping, separator, defaultTs, assigner, options)),
64516
+ ...extractInlineScripts(m.value.default, mapping, separator, defaultTs, assigner, options)
64406
64517
  ];
64407
64518
  } else if (m.value.type == "aiagent") {
64408
64519
  return (m.value.tools ?? []).flatMap((tool) => {
@@ -64410,7 +64521,7 @@ function extractInlineScripts(modules, mapping = {}, separator = "/", defaultTs,
64410
64521
  if (!toolValue || toolValue.tool_type !== "flowmodule" || toolValue.type !== "rawscript") {
64411
64522
  return [];
64412
64523
  }
64413
- return extractRawscriptInline(tool.id, tool.summary, toolValue, mapping, separator, assigner);
64524
+ return extractRawscriptInline(tool.id, tool.summary, toolValue, mapping, separator, assigner, failOnInlineDirective);
64414
64525
  });
64415
64526
  } else {
64416
64527
  return [];
@@ -64786,12 +64897,16 @@ async function generateFlowLockInternal(folder, dryRun, workspace, opts, justUpd
64786
64897
  const treePath = fileToTreePath.get(k) ?? folderNormalized + "/" + path10.basename(k, path10.extname(k));
64787
64898
  return tree.isStale(treePath);
64788
64899
  }) : changedScripts;
64789
- await replaceInlineScripts(flowValue.value.modules, fileReader, exports_log, folder + SEP7, SEP7, locksToRemove);
64900
+ const missingFiles = [];
64901
+ await replaceInlineScripts(flowValue.value.modules, fileReader, exports_log, folder + SEP7, SEP7, locksToRemove, missingFiles);
64790
64902
  if (flowValue.value.failure_module) {
64791
- await replaceInlineScripts([flowValue.value.failure_module], fileReader, exports_log, folder + SEP7, SEP7, locksToRemove);
64903
+ await replaceInlineScripts([flowValue.value.failure_module], fileReader, exports_log, folder + SEP7, SEP7, locksToRemove, missingFiles);
64792
64904
  }
64793
64905
  if (flowValue.value.preprocessor_module) {
64794
- await replaceInlineScripts([flowValue.value.preprocessor_module], fileReader, exports_log, folder + SEP7, SEP7, locksToRemove);
64906
+ await replaceInlineScripts([flowValue.value.preprocessor_module], fileReader, exports_log, folder + SEP7, SEP7, locksToRemove, missingFiles);
64907
+ }
64908
+ if (missingFiles.length > 0) {
64909
+ throw new Error(`Cannot regenerate lock for flow ${remote_path}: missing inline script file(s): ${missingFiles.join(", ")}. ` + `Either restore the file(s) or remove the !inline reference(s) from flow.yaml before retrying.`);
64795
64910
  }
64796
64911
  const tempScriptRefs = tree?.getTempScriptRefs(folderNormalized);
64797
64912
  const savedNotes = flowValue.value.notes;
@@ -64804,12 +64919,13 @@ async function generateFlowLockInternal(folder, dryRun, workspace, opts, justUpd
64804
64919
  const lockAssigner = newPathAssigner(opts.defaultTs ?? "bun", {
64805
64920
  skipInlineScriptSuffix: getNonDottedPaths()
64806
64921
  });
64807
- const inlineScripts = extractInlineScripts(flowValue.value.modules, currentMapping, SEP7, opts.defaultTs, lockAssigner);
64922
+ const extractOpts = { skipInlineScriptSuffix: getNonDottedPaths(), failOnInlineDirective: true };
64923
+ const inlineScripts = extractInlineScripts(flowValue.value.modules, currentMapping, SEP7, opts.defaultTs, lockAssigner, extractOpts);
64808
64924
  if (flowValue.value.failure_module) {
64809
- inlineScripts.push(...extractInlineScripts([flowValue.value.failure_module], currentMapping, SEP7, opts.defaultTs, lockAssigner));
64925
+ inlineScripts.push(...extractInlineScripts([flowValue.value.failure_module], currentMapping, SEP7, opts.defaultTs, lockAssigner, extractOpts));
64810
64926
  }
64811
64927
  if (flowValue.value.preprocessor_module) {
64812
- inlineScripts.push(...extractInlineScripts([flowValue.value.preprocessor_module], currentMapping, SEP7, opts.defaultTs, lockAssigner));
64928
+ inlineScripts.push(...extractInlineScripts([flowValue.value.preprocessor_module], currentMapping, SEP7, opts.defaultTs, lockAssigner, extractOpts));
64813
64929
  }
64814
64930
  inlineScripts.forEach((s) => {
64815
64931
  writeIfChanged(process.cwd() + SEP7 + folder + SEP7 + s.path, s.content);
@@ -65931,12 +66047,12 @@ function ZipFSElement(zip, useYaml, defaultTs, resourceTypeToFormatExtension, re
65931
66047
  try {
65932
66048
  const assigner = newPathAssigner(defaultTs, { skipInlineScriptSuffix: getNonDottedPaths() });
65933
66049
  const inlineMapping = extractCurrentMapping(flow.value.modules, {}, flow.value.failure_module, flow.value.preprocessor_module);
65934
- inlineScripts = extractInlineScripts(flow.value.modules, inlineMapping, SEP9, defaultTs, assigner, { skipInlineScriptSuffix: getNonDottedPaths() });
66050
+ inlineScripts = extractInlineScripts(flow.value.modules, inlineMapping, SEP9, defaultTs, assigner, { skipInlineScriptSuffix: getNonDottedPaths(), failOnInlineDirective: true });
65935
66051
  if (flow.value.failure_module) {
65936
- inlineScripts.push(...extractInlineScripts([flow.value.failure_module], inlineMapping, SEP9, defaultTs, assigner, { skipInlineScriptSuffix: getNonDottedPaths() }));
66052
+ inlineScripts.push(...extractInlineScripts([flow.value.failure_module], inlineMapping, SEP9, defaultTs, assigner, { skipInlineScriptSuffix: getNonDottedPaths(), failOnInlineDirective: true }));
65937
66053
  }
65938
66054
  if (flow.value.preprocessor_module) {
65939
- inlineScripts.push(...extractInlineScripts([flow.value.preprocessor_module], inlineMapping, SEP9, defaultTs, assigner, { skipInlineScriptSuffix: getNonDottedPaths() }));
66055
+ inlineScripts.push(...extractInlineScripts([flow.value.preprocessor_module], inlineMapping, SEP9, defaultTs, assigner, { skipInlineScriptSuffix: getNonDottedPaths(), failOnInlineDirective: true }));
65940
66056
  }
65941
66057
  } catch (error2) {
65942
66058
  error(`Failed to extract inline scripts for flow at path: ${p}`);
@@ -69433,31 +69549,32 @@ async function pushRawApp(workspace, remotePath, localPath, message) {
69433
69549
  if (localApp.data) {
69434
69550
  value.data = localApp.data;
69435
69551
  }
69552
+ const { extra_perms: localPerms, ...localAppNoPerms } = localApp;
69436
69553
  if (app) {
69437
- const metadataUpToDate = isSuperset({ ...localApp, runnables }, app);
69554
+ const metadataUpToDate = isSuperset({ ...localAppNoPerms, runnables }, app);
69438
69555
  const filesUpToDate = deepEqual(files, app.value?.files);
69439
69556
  if (metadataUpToDate && filesUpToDate) {
69440
69557
  info(colors.green(`App ${remotePath} is up to date`));
69441
- return;
69558
+ } else {
69559
+ const { js, css } = await createBundleRaw();
69560
+ info(colors.bold.yellow(`Updating app ${remotePath}...`));
69561
+ await updateAppRaw({
69562
+ workspace,
69563
+ path: remotePath,
69564
+ formData: {
69565
+ app: {
69566
+ value,
69567
+ path: remotePath,
69568
+ summary: localApp.summary,
69569
+ policy: appForPolicy.policy,
69570
+ deployment_message: message,
69571
+ ...localApp.custom_path ? { custom_path: localApp.custom_path } : {}
69572
+ },
69573
+ js,
69574
+ css
69575
+ }
69576
+ });
69442
69577
  }
69443
- const { js, css } = await createBundleRaw();
69444
- info(colors.bold.yellow(`Updating app ${remotePath}...`));
69445
- await updateAppRaw({
69446
- workspace,
69447
- path: remotePath,
69448
- formData: {
69449
- app: {
69450
- value,
69451
- path: remotePath,
69452
- summary: localApp.summary,
69453
- policy: appForPolicy.policy,
69454
- deployment_message: message,
69455
- ...localApp.custom_path ? { custom_path: localApp.custom_path } : {}
69456
- },
69457
- js,
69458
- css
69459
- }
69460
- });
69461
69578
  } else {
69462
69579
  const { js, css } = await createBundleRaw();
69463
69580
  await createAppRaw({
@@ -69476,6 +69593,7 @@ async function pushRawApp(workspace, remotePath, localPath, message) {
69476
69593
  }
69477
69594
  });
69478
69595
  }
69596
+ await applyExtraPermsDiff(workspace, "raw_app", remotePath, localPerms, app?.extra_perms);
69479
69597
  }
69480
69598
  async function generatingPolicy(app, path14, publicApp) {
69481
69599
  info(colors.gray(`Generating fresh policy for app ${path14}...`));
@@ -69493,6 +69611,7 @@ var init_raw_apps = __esm(async () => {
69493
69611
  init_log();
69494
69612
  init_lib_es();
69495
69613
  init_services_gen();
69614
+ init_extra_perms();
69496
69615
  init_path_assigner();
69497
69616
  await __promiseAll([
69498
69617
  init_auth(),
@@ -72330,21 +72449,22 @@ async function pushApp(workspace, remotePath, localPath, message, permissionedAs
72330
72449
  }
72331
72450
  }
72332
72451
  }
72452
+ const { extra_perms: localPerms, ...localAppBody } = localApp;
72333
72453
  if (app) {
72334
- if (isSuperset(localApp, app)) {
72454
+ if (isSuperset(localAppBody, app)) {
72335
72455
  info(colors.green(`App ${remotePath} is up to date`));
72336
- return;
72456
+ } else {
72457
+ info(colors.bold.yellow(`Updating app ${remotePath}...`));
72458
+ await updateApp({
72459
+ workspace,
72460
+ path: remotePath,
72461
+ requestBody: {
72462
+ deployment_message: message,
72463
+ ...localAppBody,
72464
+ ...preserveFields
72465
+ }
72466
+ });
72337
72467
  }
72338
- info(colors.bold.yellow(`Updating app ${remotePath}...`));
72339
- await updateApp({
72340
- workspace,
72341
- path: remotePath,
72342
- requestBody: {
72343
- deployment_message: message,
72344
- ...localApp,
72345
- ...preserveFields
72346
- }
72347
- });
72348
72468
  } else {
72349
72469
  info(colors.yellow.bold("Creating new app..."));
72350
72470
  await createApp({
@@ -72352,11 +72472,12 @@ async function pushApp(workspace, remotePath, localPath, message, permissionedAs
72352
72472
  requestBody: {
72353
72473
  path: remotePath,
72354
72474
  deployment_message: message,
72355
- ...localApp,
72475
+ ...localAppBody,
72356
72476
  ...preserveFields
72357
72477
  }
72358
72478
  });
72359
72479
  }
72480
+ await applyExtraPermsDiff(workspace, "app", remotePath, localPerms, app?.extra_perms);
72360
72481
  }
72361
72482
  async function generatingPolicy2(app, path19, publicApp) {
72362
72483
  info(colors.gray(`Generating fresh policy for app ${path19}...`));
@@ -72486,6 +72607,7 @@ var init_app = __esm(async () => {
72486
72607
  init_lib_es();
72487
72608
  init_services_gen();
72488
72609
  init_global();
72610
+ init_extra_perms();
72489
72611
  await __promiseAll([
72490
72612
  init_auth(),
72491
72613
  init_context(),
@@ -75684,7 +75806,7 @@ async function pushFlow(workspace, remotePath, localPath, message, permissionedA
75684
75806
  await replaceInlineScripts([localFlow.value.preprocessor_module], fileReader, exports_log, localPath, SEP20, undefined, missingFiles);
75685
75807
  }
75686
75808
  if (missingFiles.length > 0) {
75687
- warn(colors.yellow(`Warning: missing inline script file(s): ${missingFiles.join(", ")}. ` + `The flow will be pushed with unresolved !inline references.`));
75809
+ throw new Error(`Cannot push flow ${remotePath}: missing inline script file(s): ${missingFiles.join(", ")}. ` + `Either restore the file(s) or remove the !inline reference(s) from flow.yaml before pushing.`);
75688
75810
  }
75689
75811
  const hasOnBehalfOf = localFlow.has_on_behalf_of ?? !!localFlow.on_behalf_of_email;
75690
75812
  delete localFlow.has_on_behalf_of;
@@ -75696,22 +75818,23 @@ async function pushFlow(workspace, remotePath, localPath, message, permissionedA
75696
75818
  info(`Preserving ${flow.on_behalf_of_email} as on_behalf_of for flow ${remotePath}`);
75697
75819
  }
75698
75820
  }
75821
+ const { extra_perms: localPerms, ...localFlowBody } = localFlow;
75699
75822
  if (flow) {
75700
- if (isSuperset(localFlow, flow)) {
75823
+ if (isSuperset(localFlowBody, flow)) {
75701
75824
  info(colors.green(`Flow ${remotePath} is up to date`));
75702
- return;
75703
- }
75704
- info(colors.bold.yellow(`Updating flow ${remotePath}...`));
75705
- await updateFlow({
75706
- workspace,
75707
- path: remotePath.replaceAll(SEP20, "/"),
75708
- requestBody: {
75825
+ } else {
75826
+ info(colors.bold.yellow(`Updating flow ${remotePath}...`));
75827
+ await updateFlow({
75828
+ workspace,
75709
75829
  path: remotePath.replaceAll(SEP20, "/"),
75710
- deployment_message: message,
75711
- ...localFlow,
75712
- ...preserveFields
75713
- }
75714
- });
75830
+ requestBody: {
75831
+ path: remotePath.replaceAll(SEP20, "/"),
75832
+ deployment_message: message,
75833
+ ...localFlowBody,
75834
+ ...preserveFields
75835
+ }
75836
+ });
75837
+ }
75715
75838
  } else {
75716
75839
  info(colors.bold.yellow("Creating new flow..."));
75717
75840
  try {
@@ -75720,7 +75843,7 @@ async function pushFlow(workspace, remotePath, localPath, message, permissionedA
75720
75843
  requestBody: {
75721
75844
  path: remotePath.replaceAll(SEP20, "/"),
75722
75845
  deployment_message: message,
75723
- ...localFlow,
75846
+ ...localFlowBody,
75724
75847
  ...preserveFields
75725
75848
  }
75726
75849
  });
@@ -75728,6 +75851,7 @@ async function pushFlow(workspace, remotePath, localPath, message, permissionedA
75728
75851
  throw new Error(`Failed to create flow ${remotePath}: ${e.body ?? e.message}`);
75729
75852
  }
75730
75853
  }
75854
+ await applyExtraPermsDiff(workspace, "flow", remotePath.replaceAll(SEP20, "/"), localPerms, flow?.extra_perms);
75731
75855
  }
75732
75856
  async function push11(opts, filePath, remotePath) {
75733
75857
  if (!validatePath(remotePath)) {
@@ -76154,6 +76278,7 @@ var init_flow = __esm(async () => {
76154
76278
  init_mod6();
76155
76279
  init_log();
76156
76280
  init_services_gen();
76281
+ init_extra_perms();
76157
76282
  await __promiseAll([
76158
76283
  init_types(),
76159
76284
  init_confirm(),
@@ -89676,7 +89801,7 @@ var config_default = command35;
89676
89801
 
89677
89802
  // src/main.ts
89678
89803
  await init_context();
89679
- var VERSION = "1.700.2";
89804
+ var VERSION = "1.702.0";
89680
89805
  async function checkVersionSafe(cmd) {
89681
89806
  const mainCommand = cmd.getMainCommand();
89682
89807
  const upgradeCommand = mainCommand.getCommand("upgrade");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "windmill-cli",
3
- "version": "1.700.2",
3
+ "version": "1.702.0",
4
4
  "description": "CLI for Windmill",
5
5
  "license": "Apache 2.0",
6
6
  "type": "module",