void 0.10.1 → 0.10.2

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 (25) hide show
  1. package/dist/{auth-cmd-DBnbrX9Y.mjs → auth-cmd-DLvXvN-0.mjs} +2 -2
  2. package/dist/{cache-DNX0hLsO.mjs → cache-CHFZmqa5.mjs} +1 -1
  3. package/dist/{cancel-deploy-CDzkVaYZ.mjs → cancel-deploy-BwpT4U4a.mjs} +1 -1
  4. package/dist/cli/cli.mjs +90 -22
  5. package/dist/{client-D4awzTnj.mjs → client-CTHvucDv.mjs} +18 -1
  6. package/dist/{create-project-CGodxfzH.mjs → create-project-CruTH_TQ.mjs} +1 -1
  7. package/dist/{db-ERzz4oly.mjs → db-BxnfKs7f.mjs} +1 -1
  8. package/dist/{delete-CJZGDLBR.mjs → delete-IQe1O4Re.mjs} +1 -1
  9. package/dist/{deploy-Cwa5sooV.mjs → deploy-CuxXxVgz.mjs} +138 -4
  10. package/dist/{domain-WvoAHE6w.mjs → domain-Bq6kzr_T.mjs} +1 -1
  11. package/dist/{env-Cx4czPsR.mjs → env-BD3U_0Av.mjs} +1 -1
  12. package/dist/{github-cmd-CUB041gj.mjs → github-cmd-CD0Z8KCF.mjs} +134 -1
  13. package/dist/index.mjs +4 -4
  14. package/dist/{init-DvaRDMIc.mjs → init-CTe46nIr.mjs} +11 -20
  15. package/dist/{link-CpbWJY3P.mjs → link-BGFW4pHD.mjs} +2 -2
  16. package/dist/{list-BkwE5vH4.mjs → list-CbGxdbe7.mjs} +1 -1
  17. package/dist/{login-Ca6mhQVI.mjs → login-v4wle1vn.mjs} +1 -1
  18. package/dist/{logs-ArQzZquo.mjs → logs-BFgY5Vqc.mjs} +1 -1
  19. package/dist/{mcp-Cc2MMXdQ.mjs → mcp-STKL-uWs.mjs} +1 -1
  20. package/dist/{project-cmd-CWZeawuN.mjs → project-cmd-DZh-vbEL.mjs} +8 -8
  21. package/dist/{rollback-BJ60ktsW.mjs → rollback-o0M0Qo_n.mjs} +1 -1
  22. package/dist/{secret-BRbXyu7E.mjs → secret-gs_yyGZL.mjs} +1 -1
  23. package/package.json +2 -2
  24. package/skills/void/docs/guide/deployment.md +1 -12
  25. package/skills/void/docs/reference/cli.md +25 -1
@@ -1,6 +1,6 @@
1
- import { d as getToken, h as removeToken, n as PlatformClient } from "./client-D4awzTnj.mjs";
1
+ import { f as getToken, g as removeToken, n as PlatformClient } from "./client-CTHvucDv.mjs";
2
2
  import { c as R } from "./dist-abzUneor.mjs";
3
- import { n as runLoginCommand } from "./login-Ca6mhQVI.mjs";
3
+ import { n as runLoginCommand } from "./login-v4wle1vn.mjs";
4
4
  import { execSync } from "node:child_process";
5
5
  //#region src/cli/auth-cmd.ts
6
6
  async function runAuthCommand(root, args) {
@@ -1,5 +1,5 @@
1
1
  import { i as dim, n as cliTitle, r as createSpinner } from "./output-DeiS4oEX.mjs";
2
- import { d as getToken, n as PlatformClient } from "./client-D4awzTnj.mjs";
2
+ import { f as getToken, n as PlatformClient } from "./client-CTHvucDv.mjs";
3
3
  import { c as R, g as ge, y as ye } from "./dist-abzUneor.mjs";
4
4
  import { r as readProjectConfig } from "./project-CH9pdo16.mjs";
5
5
  import { r as resolveProjectBySlug, t as getRequestedProjectSlug } from "./resolve-project-D4O1_fZz.mjs";
@@ -1,5 +1,5 @@
1
1
  import { n as cliTitle } from "./output-DeiS4oEX.mjs";
2
- import { d as getToken, n as PlatformClient } from "./client-D4awzTnj.mjs";
2
+ import { f as getToken, n as PlatformClient } from "./client-CTHvucDv.mjs";
3
3
  import { c as R, g as ge, v as ue, x as q, y as ye } from "./dist-abzUneor.mjs";
4
4
  import { r as readProjectConfig } from "./project-CH9pdo16.mjs";
5
5
  //#region src/cli/cancel-deploy.ts
package/dist/cli/cli.mjs CHANGED
@@ -590,6 +590,11 @@ const githubSubcommands = [
590
590
  arg: "[project]",
591
591
  description: "Connect a repository to a project for auto-deploy"
592
592
  },
593
+ {
594
+ name: "update",
595
+ arg: "[project]",
596
+ description: "Update an existing connection's branch or build executor"
597
+ },
593
598
  {
594
599
  name: "link",
595
600
  description: "Link your GitHub account to Void"
@@ -657,7 +662,41 @@ function parseGithubArgs(args) {
657
662
  executor
658
663
  };
659
664
  }
660
- throw new Error("github: Usage: void github <install|installations|connect|link>.");
665
+ if (subcommand === "update") {
666
+ let projectName = "";
667
+ let branch;
668
+ let executor;
669
+ for (let i = 0; i < rest.length; i++) {
670
+ const arg = rest[i];
671
+ if (arg === "--branch") {
672
+ if (i + 1 >= rest.length) throw new Error("github: --branch requires a value.");
673
+ const value = rest[++i];
674
+ if (value.trim() === "") throw new Error("github: --branch requires a value.");
675
+ branch = value.trim();
676
+ } else if (arg === "--project") {
677
+ if (i + 1 >= rest.length) throw new Error("github: --project requires a value.");
678
+ const value = rest[++i];
679
+ if (value.trim() === "") throw new Error("github: --project requires a value.");
680
+ if (projectName) throw new Error(`github: Unexpected argument '${value}'.`);
681
+ projectName = value;
682
+ } else if (arg === "--executor") {
683
+ if (i + 1 >= rest.length) throw new Error("github: --executor requires a value.");
684
+ const value = rest[++i];
685
+ if (value.trim() === "") throw new Error("github: --executor requires a value.");
686
+ if (value !== "container" && value !== "github_actions") throw new Error("github: invalid --executor (expected container|github_actions).");
687
+ executor = value;
688
+ } else if (arg.startsWith("-")) throw new Error(`github: Unexpected argument '${arg}'.`);
689
+ else if (projectName) throw new Error(`github: Unexpected argument '${arg}'.`);
690
+ else projectName = arg;
691
+ }
692
+ return {
693
+ subcommand,
694
+ projectName,
695
+ branch,
696
+ executor
697
+ };
698
+ }
699
+ throw new Error("github: Usage: void github <install|installations|connect|update|link>.");
661
700
  }
662
701
  //#endregion
663
702
  //#region src/cli/ascii.ts
@@ -967,6 +1006,10 @@ const HELP_TREE = {
967
1006
  command: "connect [project]",
968
1007
  description: "Connect a repository to a project for auto-deploy"
969
1008
  },
1009
+ {
1010
+ command: "update [project]",
1011
+ description: "Update an existing connection's branch or build executor"
1012
+ },
970
1013
  {
971
1014
  command: "link",
972
1015
  description: "Link your GitHub account to Void"
@@ -1008,6 +1051,31 @@ const HELP_TREE = {
1008
1051
  command: "void github connect my-app --installation 42 --repo owner/repo --branch main",
1009
1052
  description: "Non-interactive connect (all flags explicit)"
1010
1053
  }]
1054
+ },
1055
+ update: {
1056
+ summary: "Update an existing connection's branch or build executor.",
1057
+ usage: ["void github update [project] [options]"],
1058
+ options: [
1059
+ {
1060
+ command: "--project <name>",
1061
+ description: "Project name (alias for positional)"
1062
+ },
1063
+ {
1064
+ command: "--branch <name>",
1065
+ description: "New branch to deploy from"
1066
+ },
1067
+ {
1068
+ command: "--executor <type>",
1069
+ description: "New build executor: container | github_actions"
1070
+ }
1071
+ ],
1072
+ examples: [{
1073
+ command: "void github update my-app --executor github_actions",
1074
+ description: "Switch an existing connection to the GitHub Actions executor"
1075
+ }, {
1076
+ command: "void github update my-app --branch release",
1077
+ description: "Change the deploy branch"
1078
+ }]
1011
1079
  }
1012
1080
  }
1013
1081
  },
@@ -1715,7 +1783,7 @@ else if (command === "deploy") {
1715
1783
  R.error(err instanceof Error ? err.message : String(err));
1716
1784
  process.exit(1);
1717
1785
  }
1718
- import("../deploy-Cwa5sooV.mjs").then((n) => n.t).then(({ runDeploy }) => {
1786
+ import("../deploy-CuxXxVgz.mjs").then((n) => n.t).then(({ runDeploy }) => {
1719
1787
  runDeploy(root, {
1720
1788
  projectSlug: deployArgs.projectSlug,
1721
1789
  dir: deployArgs.dir,
@@ -1727,14 +1795,14 @@ else if (command === "deploy") {
1727
1795
  process.exit(1);
1728
1796
  });
1729
1797
  });
1730
- } else if (command === "auth") runSubcommandGroup("auth", authSubcommands, parseAuthArgs, (root, parsed) => import("../auth-cmd-DBnbrX9Y.mjs").then(({ runAuthCommand }) => runAuthCommand(root, parsed)));
1731
- else if (command === "project") runSubcommandGroup("project", projectSubcommands, parseProjectArgs, (root, parsed) => import("../project-cmd-CWZeawuN.mjs").then(({ runProjectCommand }) => runProjectCommand(root, parsed)));
1732
- else if (command === "secret") runSubcommandGroup("secret", secretSubcommands, parseSecretArgs, (root, parsed) => import("../secret-BRbXyu7E.mjs").then(({ runSecretCommand }) => runSecretCommand(root, parsed)));
1733
- else if (command === "domain") runSubcommandGroup("domain", domainSubcommands, parseDomainArgs, (root, parsed) => import("../domain-WvoAHE6w.mjs").then(({ runDomainCommand }) => runDomainCommand(root, parsed)));
1734
- else if (command === "db") runSubcommandGroup("db", dbSubcommands, parseDbArgs, (root, parsed) => import("../db-ERzz4oly.mjs").then(({ runDbCommand }) => runDbCommand(root, parsed)));
1735
- else if (command === "env") runSubcommandGroup("env", envSubcommands, parseEnvArgs, (root, parsed) => import("../env-Cx4czPsR.mjs").then(({ runEnvCommand }) => runEnvCommand(root, parsed)));
1798
+ } else if (command === "auth") runSubcommandGroup("auth", authSubcommands, parseAuthArgs, (root, parsed) => import("../auth-cmd-DLvXvN-0.mjs").then(({ runAuthCommand }) => runAuthCommand(root, parsed)));
1799
+ else if (command === "project") runSubcommandGroup("project", projectSubcommands, parseProjectArgs, (root, parsed) => import("../project-cmd-DZh-vbEL.mjs").then(({ runProjectCommand }) => runProjectCommand(root, parsed)));
1800
+ else if (command === "secret") runSubcommandGroup("secret", secretSubcommands, parseSecretArgs, (root, parsed) => import("../secret-gs_yyGZL.mjs").then(({ runSecretCommand }) => runSecretCommand(root, parsed)));
1801
+ else if (command === "domain") runSubcommandGroup("domain", domainSubcommands, parseDomainArgs, (root, parsed) => import("../domain-Bq6kzr_T.mjs").then(({ runDomainCommand }) => runDomainCommand(root, parsed)));
1802
+ else if (command === "db") runSubcommandGroup("db", dbSubcommands, parseDbArgs, (root, parsed) => import("../db-BxnfKs7f.mjs").then(({ runDbCommand }) => runDbCommand(root, parsed)));
1803
+ else if (command === "env") runSubcommandGroup("env", envSubcommands, parseEnvArgs, (root, parsed) => import("../env-BD3U_0Av.mjs").then(({ runEnvCommand }) => runEnvCommand(root, parsed)));
1736
1804
  else if (command === "gen") runSubcommandGroup("gen", genSubcommands, parseGenArgs, (root, parsed) => import("../gen-Dgi4D7GC.mjs").then(({ runGenCommand }) => runGenCommand(root, parsed)));
1737
- else if (command === "github") runSubcommandGroup("github", githubSubcommands, parseGithubArgs, (root, parsed) => import("../github-cmd-CUB041gj.mjs").then(({ runGithubCommand }) => runGithubCommand(root, parsed)));
1805
+ else if (command === "github") runSubcommandGroup("github", githubSubcommands, parseGithubArgs, (root, parsed) => import("../github-cmd-CD0Z8KCF.mjs").then(({ runGithubCommand }) => runGithubCommand(root, parsed)));
1738
1806
  else if (command === "prepare") {
1739
1807
  const root = process.cwd();
1740
1808
  let prepareArgs;
@@ -1752,7 +1820,7 @@ else if (command === "prepare") {
1752
1820
  });
1753
1821
  } else if (command === "init") {
1754
1822
  const root = process.cwd();
1755
- import("../init-DvaRDMIc.mjs").then(({ runInitCommand, parseInitArgs }) => {
1823
+ import("../init-CTe46nIr.mjs").then(({ runInitCommand, parseInitArgs }) => {
1756
1824
  let initArgs;
1757
1825
  try {
1758
1826
  initArgs = parseInitArgs(args.slice(1));
@@ -1765,7 +1833,7 @@ else if (command === "prepare") {
1765
1833
  process.exit(1);
1766
1834
  });
1767
1835
  });
1768
- } else if (command === "mcp") import("../mcp-Cc2MMXdQ.mjs").then(({ runMcp }) => {
1836
+ } else if (command === "mcp") import("../mcp-STKL-uWs.mjs").then(({ runMcp }) => {
1769
1837
  runMcp();
1770
1838
  });
1771
1839
  else if (command === "-v" || command === "--version") {
@@ -1806,7 +1874,7 @@ else if (command === "-v" || command === "--version") {
1806
1874
  },
1807
1875
  {
1808
1876
  name: "github",
1809
- hint: "install | installations | connect | link",
1877
+ hint: "install | installations | connect | update | link",
1810
1878
  description: "Connect a GitHub repository for automatic deploys"
1811
1879
  },
1812
1880
  {
@@ -1846,27 +1914,27 @@ else if (command === "-v" || command === "--version") {
1846
1914
  const root = process.cwd();
1847
1915
  switch (cmd) {
1848
1916
  case "init": {
1849
- const { runInitCommand, parseInitArgs } = await import("../init-DvaRDMIc.mjs");
1917
+ const { runInitCommand, parseInitArgs } = await import("../init-CTe46nIr.mjs");
1850
1918
  await runInitCommand(root, parseInitArgs([]));
1851
1919
  return;
1852
1920
  }
1853
1921
  case "deploy": {
1854
- const { runDeploy } = await import("../deploy-Cwa5sooV.mjs").then((n) => n.t);
1922
+ const { runDeploy } = await import("../deploy-CuxXxVgz.mjs").then((n) => n.t);
1855
1923
  await runDeploy(root);
1856
1924
  return;
1857
1925
  }
1858
1926
  case "mcp": {
1859
- const { runMcp } = await import("../mcp-Cc2MMXdQ.mjs");
1927
+ const { runMcp } = await import("../mcp-STKL-uWs.mjs");
1860
1928
  runMcp();
1861
1929
  return;
1862
1930
  }
1863
- case "auth": return runSubcommandGroup("auth", authSubcommands, parseAuthArgs, (r, p) => import("../auth-cmd-DBnbrX9Y.mjs").then(({ runAuthCommand }) => runAuthCommand(r, p)));
1864
- case "project": return runSubcommandGroup("project", projectSubcommands, parseProjectArgs, (r, p) => import("../project-cmd-CWZeawuN.mjs").then(({ runProjectCommand }) => runProjectCommand(r, p)));
1865
- case "secret": return runSubcommandGroup("secret", secretSubcommands, parseSecretArgs, (r, p) => import("../secret-BRbXyu7E.mjs").then(({ runSecretCommand }) => runSecretCommand(r, p)));
1866
- case "domain": return runSubcommandGroup("domain", domainSubcommands, parseDomainArgs, (r, p) => import("../domain-WvoAHE6w.mjs").then(({ runDomainCommand }) => runDomainCommand(r, p)));
1867
- case "github": return runSubcommandGroup("github", githubSubcommands, parseGithubArgs, (r, p) => import("../github-cmd-CUB041gj.mjs").then(({ runGithubCommand }) => runGithubCommand(r, p)));
1868
- case "db": return runSubcommandGroup("db", dbSubcommands, parseDbArgs, (r, p) => import("../db-ERzz4oly.mjs").then(({ runDbCommand }) => runDbCommand(r, p)));
1869
- case "env": return runSubcommandGroup("env", envSubcommands, parseEnvArgs, (r, p) => import("../env-Cx4czPsR.mjs").then(({ runEnvCommand }) => runEnvCommand(r, p)));
1931
+ case "auth": return runSubcommandGroup("auth", authSubcommands, parseAuthArgs, (r, p) => import("../auth-cmd-DLvXvN-0.mjs").then(({ runAuthCommand }) => runAuthCommand(r, p)));
1932
+ case "project": return runSubcommandGroup("project", projectSubcommands, parseProjectArgs, (r, p) => import("../project-cmd-DZh-vbEL.mjs").then(({ runProjectCommand }) => runProjectCommand(r, p)));
1933
+ case "secret": return runSubcommandGroup("secret", secretSubcommands, parseSecretArgs, (r, p) => import("../secret-gs_yyGZL.mjs").then(({ runSecretCommand }) => runSecretCommand(r, p)));
1934
+ case "domain": return runSubcommandGroup("domain", domainSubcommands, parseDomainArgs, (r, p) => import("../domain-Bq6kzr_T.mjs").then(({ runDomainCommand }) => runDomainCommand(r, p)));
1935
+ case "github": return runSubcommandGroup("github", githubSubcommands, parseGithubArgs, (r, p) => import("../github-cmd-CD0Z8KCF.mjs").then(({ runGithubCommand }) => runGithubCommand(r, p)));
1936
+ case "db": return runSubcommandGroup("db", dbSubcommands, parseDbArgs, (r, p) => import("../db-BxnfKs7f.mjs").then(({ runDbCommand }) => runDbCommand(r, p)));
1937
+ case "env": return runSubcommandGroup("env", envSubcommands, parseEnvArgs, (r, p) => import("../env-BD3U_0Av.mjs").then(({ runEnvCommand }) => runEnvCommand(r, p)));
1870
1938
  case "gen": return runSubcommandGroup("gen", genSubcommands, parseGenArgs, (r, p) => import("../gen-Dgi4D7GC.mjs").then(({ runGenCommand }) => runGenCommand(r, p)));
1871
1939
  case "prepare": {
1872
1940
  const { runPrepareCommand } = await import("../prepare-DH2WnEpD.mjs");
@@ -861,6 +861,23 @@ var PlatformClient = class {
861
861
  if (!res.ok) await throwPlatformApiError("Failed to connect GitHub repository", res);
862
862
  return res.json();
863
863
  }
864
+ async getGithubConnection(projectId) {
865
+ const res = await fetch(`${this.baseUrl}/projects/${projectId}/github`, { headers: { ...this.authHeaders } });
866
+ if (!res.ok) await throwPlatformApiError("Failed to get GitHub connection", res);
867
+ return res.json();
868
+ }
869
+ async updateGithubConnection(projectId, body) {
870
+ const res = await fetch(`${this.baseUrl}/projects/${projectId}/github`, {
871
+ method: "PATCH",
872
+ headers: {
873
+ "Content-Type": "application/json",
874
+ ...this.authHeaders
875
+ },
876
+ body: JSON.stringify(body)
877
+ });
878
+ if (!res.ok) await throwPlatformApiError("Failed to update GitHub connection", res);
879
+ return res.json();
880
+ }
864
881
  async getGithubLinkUrl(redirect, codeChallenge) {
865
882
  const params = new URLSearchParams({
866
883
  redirect,
@@ -888,4 +905,4 @@ var PlatformClient = class {
888
905
  }
889
906
  };
890
907
  //#endregion
891
- export { saveToken as _, isExpiredTokenError as a, createCodeChallenge as c, getToken as d, getTokenSource as f, runLogin as g, removeToken as h, isCliOutdatedError as i, createCodeVerifier as l, openBrowser as m, PlatformClient as n, parsePlatformErrorBody as o, isStagingMode as p, client_exports as r, awaitBrowserCallback as s, PlatformApiError as t, getSiteDomain as u };
908
+ export { runLogin as _, isExpiredTokenError as a, createCodeChallenge as c, getSiteDomain as d, getToken as f, removeToken as g, openBrowser as h, isCliOutdatedError as i, createCodeVerifier as l, isStagingMode as m, PlatformClient as n, parsePlatformErrorBody as o, getTokenSource as p, client_exports as r, awaitBrowserCallback as s, PlatformApiError as t, getApiUrl as u, saveToken as v, ensureCloudflaredToken as y };
@@ -1,6 +1,6 @@
1
1
  import { n as __exportAll } from "./chunk-DJd-R1mw.mjs";
2
2
  import { s as import_picocolors } from "./output-DeiS4oEX.mjs";
3
- import { t as PlatformApiError, u as getSiteDomain } from "./client-D4awzTnj.mjs";
3
+ import { d as getSiteDomain, t as PlatformApiError } from "./client-CTHvucDv.mjs";
4
4
  import { _ as me, c as R, i as Ee, l as Re, v as ue, x as q } from "./dist-abzUneor.mjs";
5
5
  import { a as writeProjectConfig } from "./project-CH9pdo16.mjs";
6
6
  import { n as validateProjectSlug } from "./project-slug-rX3kTOfY.mjs";
@@ -2,7 +2,7 @@ import { a as join, c as resolve, r as extname, s as relative } from "./pathe.M-
2
2
  import { i as dim, n as cliTitle, s as import_picocolors } from "./output-DeiS4oEX.mjs";
3
3
  import { n as readProjectPaths } from "./project-paths-CCMrHYQm.mjs";
4
4
  import { t as cfAccessHeaders } from "./cf-access-DKDsgwOU.mjs";
5
- import { d as getToken, n as PlatformClient, p as isStagingMode, t as PlatformApiError } from "./client-D4awzTnj.mjs";
5
+ import { f as getToken, m as isStagingMode, n as PlatformClient, t as PlatformApiError } from "./client-CTHvucDv.mjs";
6
6
  import { c as R, g as ge, v as ue, x as q, y as ye } from "./dist-abzUneor.mjs";
7
7
  import { r as readProjectConfig } from "./project-CH9pdo16.mjs";
8
8
  import { c as getDatabaseDialect, f as readConfig, p as resolveBindingNames } from "./config-8dLIngKW.mjs";
@@ -1,5 +1,5 @@
1
1
  import { n as cliTitle, r as createSpinner } from "./output-DeiS4oEX.mjs";
2
- import { d as getToken, n as PlatformClient } from "./client-D4awzTnj.mjs";
2
+ import { f as getToken, n as PlatformClient } from "./client-CTHvucDv.mjs";
3
3
  import { _ as me, c as R, g as ge, l as Re, u as Se, x as q, y as ye } from "./dist-abzUneor.mjs";
4
4
  import { i as removeProjectConfig, r as readProjectConfig } from "./project-CH9pdo16.mjs";
5
5
  import { r as resolveProjectBySlug } from "./resolve-project-D4O1_fZz.mjs";
@@ -3,7 +3,8 @@ import { a as join, c as resolve, i as isAbsolute, n as dirname, r as extname, s
3
3
  import { n as cliTitle, r as createSpinner, s as import_picocolors } from "./output-DeiS4oEX.mjs";
4
4
  import { i as resolveProjectPaths, n as readProjectPaths } from "./project-paths-CCMrHYQm.mjs";
5
5
  import { t as findVoidAuthConfig } from "./config-hhMYPVRT.mjs";
6
- import { a as isExpiredTokenError, d as getToken, f as getTokenSource, i as isCliOutdatedError, n as PlatformClient, o as parsePlatformErrorBody, p as isStagingMode, t as PlatformApiError } from "./client-D4awzTnj.mjs";
6
+ import { t as cfAccessHeaders } from "./cf-access-DKDsgwOU.mjs";
7
+ import { a as isExpiredTokenError, f as getToken, i as isCliOutdatedError, m as isStagingMode, n as PlatformClient, o as parsePlatformErrorBody, p as getTokenSource, t as PlatformApiError, u as getApiUrl, y as ensureCloudflaredToken } from "./client-CTHvucDv.mjs";
7
8
  import { c as R, g as ge, u as Se, v as ue, x as q, y as ye } from "./dist-abzUneor.mjs";
8
9
  import { a as writeProjectConfig, r as readProjectConfig } from "./project-CH9pdo16.mjs";
9
10
  import { c as getDatabaseDialect, f as readConfig, l as isNodeTarget, p as resolveBindingNames } from "./config-8dLIngKW.mjs";
@@ -19,11 +20,11 @@ import { n as buildMigrationPlanBundle } from "./plan-aD3wRDqF.mjs";
19
20
  import { r as validateMigrations, t as assertJournalCoherence } from "./validate-CNWm-PsL.mjs";
20
21
  import { t as scanPages } from "./scan-VCAM1oh3.mjs";
21
22
  import { n as STAGING_PROXY_URL, t as DEFAULT_PROXY_URL } from "./proxy-M3pxItg2.mjs";
22
- import { i as promptProjectSetupAction, n as promptAndCreateProject, r as promptProjectSelection } from "./create-project-CGodxfzH.mjs";
23
+ import { i as promptProjectSetupAction, n as promptAndCreateProject, r as promptProjectSelection } from "./create-project-CruTH_TQ.mjs";
23
24
  import { r as resolveProjectBySlug, t as getRequestedProjectSlug } from "./resolve-project-D4O1_fZz.mjs";
24
25
  import { t as collectGitDeployMetadata } from "./git-metadata-Ce0AtSZL.mjs";
25
26
  import { n as lintDuplicateSources, r as mergeRoutingRules, t as lintDestinationSplats } from "./headers-BNWymgnH.mjs";
26
- import { t as promptForLoginToken } from "./login-Ca6mhQVI.mjs";
27
+ import { t as promptForLoginToken } from "./login-v4wle1vn.mjs";
27
28
  import { i as resolveProjectCommand, n as detectPreset, r as formatProjectCommand, t as FRAMEWORK_PRESETS } from "./preset-B7ZQZn0u.mjs";
28
29
  import { createRequire } from "node:module";
29
30
  import { copyFileSync, cpSync, createWriteStream, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, renameSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
@@ -1168,6 +1169,129 @@ function sleep(ms) {
1168
1169
  return new Promise((resolve) => setTimeout(resolve, ms));
1169
1170
  }
1170
1171
  //#endregion
1172
+ //#region src/cli/github-oidc.ts
1173
+ /**
1174
+ * GitHub Actions OIDC → Void deploy-token exchange.
1175
+ *
1176
+ * When `void deploy` runs inside GitHub Actions with no explicit `VOID_TOKEN`,
1177
+ * the CLI mints a short-lived GitHub OIDC token (audience `void`) and exchanges
1178
+ * it at `POST $VOID_API_URL/auth/github-oidc` for a short-lived, project-scoped
1179
+ * Void deploy token. Doing the exchange in-process lets the scaffolded workflow
1180
+ * collapse to a single `void deploy` step — no curl/jq token-exchange step.
1181
+ *
1182
+ * Server contract (platform `POST /auth/github-oidc` handler):
1183
+ * request { oidcToken: string, project: string } (project = slug)
1184
+ * response { token: string, projectId, buildId }
1185
+ */
1186
+ const OIDC_AUDIENCE = "void";
1187
+ /**
1188
+ * True when the process is running inside GitHub Actions with the OIDC token
1189
+ * request endpoint available — i.e. the workflow granted
1190
+ * `permissions: id-token: write`, so GitHub injected the request URL + token.
1191
+ */
1192
+ function isGithubActionsOidcAvailable(env = process.env) {
1193
+ return env.GITHUB_ACTIONS === "true" && typeof env.ACTIONS_ID_TOKEN_REQUEST_URL === "string" && env.ACTIONS_ID_TOKEN_REQUEST_URL.length > 0 && typeof env.ACTIONS_ID_TOKEN_REQUEST_TOKEN === "string" && env.ACTIONS_ID_TOKEN_REQUEST_TOKEN.length > 0;
1194
+ }
1195
+ /**
1196
+ * Mint a GitHub Actions OIDC token (audience `void`) and exchange it for a
1197
+ * short-lived, project-scoped Void deploy token.
1198
+ *
1199
+ * Two hops:
1200
+ * 1. GET $ACTIONS_ID_TOKEN_REQUEST_URL&audience=void (Bearer request token)
1201
+ * → `.value` is the OIDC JWT.
1202
+ * 2. POST $apiUrl/auth/github-oidc { oidcToken, project }
1203
+ * → `.token` is the Void deploy token.
1204
+ *
1205
+ * Throws a clear, actionable error (including the HTTP status and server error
1206
+ * body when available) on any non-OK response or missing field.
1207
+ */
1208
+ async function exchangeGithubOidcForDeployToken(apiUrl, project, env = process.env) {
1209
+ const requestUrl = env.ACTIONS_ID_TOKEN_REQUEST_URL;
1210
+ const requestToken = env.ACTIONS_ID_TOKEN_REQUEST_TOKEN;
1211
+ if (!requestUrl || !requestToken) throw new Error("github-oidc: GitHub Actions OIDC is unavailable (missing ACTIONS_ID_TOKEN_REQUEST_URL/TOKEN). Ensure the workflow grants `permissions: id-token: write`.");
1212
+ return exchangeOidcTokenAtApi(apiUrl, project, await requestGithubOidcToken(requestUrl, requestToken));
1213
+ }
1214
+ /**
1215
+ * GET the GitHub Actions OIDC token for audience `void`. GitHub's request URL
1216
+ * already carries a query string, so `audience` is appended alongside it.
1217
+ */
1218
+ async function requestGithubOidcToken(requestUrl, requestToken) {
1219
+ const url = new URL(requestUrl);
1220
+ url.searchParams.set("audience", OIDC_AUDIENCE);
1221
+ let res;
1222
+ try {
1223
+ res = await fetch(url, { headers: { Authorization: `Bearer ${requestToken}` } });
1224
+ } catch (err) {
1225
+ throw new Error(`github-oidc: Failed to reach the GitHub OIDC token endpoint: ${errText(err)}`);
1226
+ }
1227
+ if (!res.ok) {
1228
+ const body = await safeText(res);
1229
+ throw new Error(`github-oidc: Failed to mint a GitHub OIDC token (${res.status})${body ? `: ${body}` : ""}.`);
1230
+ }
1231
+ let body;
1232
+ try {
1233
+ body = await res.json();
1234
+ } catch {
1235
+ throw new Error("github-oidc: GitHub OIDC token endpoint returned an invalid response.");
1236
+ }
1237
+ const value = body?.value;
1238
+ if (typeof value !== "string" || value.length === 0) throw new Error("github-oidc: GitHub OIDC token endpoint did not return a token value.");
1239
+ return value;
1240
+ }
1241
+ /** POST the OIDC JWT to the Void API and return the minted deploy token. */
1242
+ async function exchangeOidcTokenAtApi(apiUrl, project, oidcToken) {
1243
+ const url = `${apiUrl.endsWith("/") ? apiUrl.slice(0, -1) : apiUrl}/auth/github-oidc`;
1244
+ ensureCloudflaredToken(apiUrl);
1245
+ let res;
1246
+ try {
1247
+ res = await fetch(url, {
1248
+ method: "POST",
1249
+ headers: {
1250
+ "Content-Type": "application/json",
1251
+ ...cfAccessHeaders(process.env)
1252
+ },
1253
+ body: JSON.stringify({
1254
+ oidcToken,
1255
+ project
1256
+ })
1257
+ });
1258
+ } catch (err) {
1259
+ throw new Error(`github-oidc: Failed to reach ${url}: ${errText(err)}`);
1260
+ }
1261
+ if (!res.ok) {
1262
+ const body = await safeText(res);
1263
+ throw new Error(`github-oidc: OIDC token exchange failed (${res.status})${body ? `: ${body}` : ""}. Confirm the repository is connected to project "${project}" with the github_actions executor.`);
1264
+ }
1265
+ let body;
1266
+ try {
1267
+ body = await res.json();
1268
+ } catch {
1269
+ throw new Error("github-oidc: OIDC token exchange returned an invalid response.");
1270
+ }
1271
+ const token = body?.token;
1272
+ if (typeof token !== "string" || token.length === 0) throw new Error("github-oidc: OIDC token exchange did not return a deploy token.");
1273
+ return token;
1274
+ }
1275
+ /**
1276
+ * Emit a GitHub Actions `::add-mask::` workflow command so `value` is redacted
1277
+ * from workflow logs. No-op when not running inside GitHub Actions. GitHub reads
1278
+ * workflow commands from stdout.
1279
+ */
1280
+ function maskGithubActionsSecret(value, env = process.env) {
1281
+ if (env.GITHUB_ACTIONS !== "true" || !value) return;
1282
+ process.stdout.write(`::add-mask::${value}\n`);
1283
+ }
1284
+ function errText(err) {
1285
+ return err instanceof Error ? err.message : String(err);
1286
+ }
1287
+ async function safeText(res) {
1288
+ try {
1289
+ return (await res.text()).trim();
1290
+ } catch {
1291
+ return "";
1292
+ }
1293
+ }
1294
+ //#endregion
1171
1295
  //#region src/cli/log-file.ts
1172
1296
  /**
1173
1297
  * Walk `err.cause` up to 6 levels and return a plain JSON-friendly chain.
@@ -2377,7 +2501,17 @@ function buildEnv(extra) {
2377
2501
  async function runDeployInner(root, options, cliLog) {
2378
2502
  let reauthenticated = false;
2379
2503
  while (true) try {
2380
- const token = getToken(root);
2504
+ let token = process.env.VOID_TOKEN ?? null;
2505
+ if (!token && isGithubActionsOidcAvailable()) {
2506
+ const slug = getRequestedProjectSlug(options) ?? readProjectConfig(root)?.slug;
2507
+ if (!slug) throw new Error("deploy: running in GitHub Actions but the project is unknown — pass --project <slug> or link the project.");
2508
+ cliLog.info("github_oidc_exchange_start", { slug });
2509
+ token = await exchangeGithubOidcForDeployToken(getApiUrl(root), slug);
2510
+ maskGithubActionsSecret(token);
2511
+ process.env.VOID_TOKEN = token;
2512
+ cliLog.info("github_oidc_exchange_success", { slug });
2513
+ }
2514
+ token ??= getToken(root);
2381
2515
  if (!token) {
2382
2516
  R.error("No auth token found. Run `void auth login` first.");
2383
2517
  process.exit(1);
@@ -1,5 +1,5 @@
1
1
  import { s as import_picocolors } from "./output-DeiS4oEX.mjs";
2
- import { d as getToken, n as PlatformClient } from "./client-D4awzTnj.mjs";
2
+ import { f as getToken, n as PlatformClient } from "./client-CTHvucDv.mjs";
3
3
  import { c as R, u as Se } from "./dist-abzUneor.mjs";
4
4
  import { r as readProjectConfig } from "./project-CH9pdo16.mjs";
5
5
  //#region src/cli/domain.ts
@@ -1,6 +1,6 @@
1
1
  import { a as join } from "./pathe.M-eThtNZ-BrPhGF_K.mjs";
2
2
  import { n as cliTitle } from "./output-DeiS4oEX.mjs";
3
- import { d as getToken, n as PlatformClient } from "./client-D4awzTnj.mjs";
3
+ import { f as getToken, n as PlatformClient } from "./client-CTHvucDv.mjs";
4
4
  import { c as R, g as ge, u as Se, y as ye } from "./dist-abzUneor.mjs";
5
5
  import { r as readProjectConfig } from "./project-CH9pdo16.mjs";
6
6
  import { r as generateEnvTypes, t as findEnvFile } from "./env-types-CaJaIRXU.mjs";
@@ -1,5 +1,5 @@
1
1
  import { s as import_picocolors } from "./output-DeiS4oEX.mjs";
2
- import { c as createCodeChallenge, d as getToken, l as createCodeVerifier, m as openBrowser, n as PlatformClient, o as parsePlatformErrorBody, s as awaitBrowserCallback, t as PlatformApiError } from "./client-D4awzTnj.mjs";
2
+ import { c as createCodeChallenge, f as getToken, h as openBrowser, l as createCodeVerifier, n as PlatformClient, o as parsePlatformErrorBody, s as awaitBrowserCallback, t as PlatformApiError } from "./client-CTHvucDv.mjs";
3
3
  import { _ as me, c as R, i as Ee, l as Re, x as q } from "./dist-abzUneor.mjs";
4
4
  import { r as readProjectConfig } from "./project-CH9pdo16.mjs";
5
5
  import { r as resolveProjectBySlug, t as getRequestedProjectSlug } from "./resolve-project-D4O1_fZz.mjs";
@@ -22,6 +22,18 @@ function describeConnectError(status, errorCode) {
22
22
  return null;
23
23
  }
24
24
  /**
25
+ * Like {@link describeConnectError}, but for `void github update`. The update
26
+ * flow starts from an EXISTING connection, so a 404 "connection not found"
27
+ * (the project has no GitHub connection, or it was disconnected between the
28
+ * read and the write) is the common case and gets a "connect first" message.
29
+ * Everything else defers to the shared connect mapping.
30
+ */
31
+ function describeUpdateError(status, errorCode) {
32
+ const code = errorCode ?? "";
33
+ if (status === 404 && code.includes("connection not found")) return "This project is not connected to a GitHub repository. Run `void github connect` first.";
34
+ return describeConnectError(status, code);
35
+ }
36
+ /**
25
37
  * Extract `owner/repo` from a `https://github.com/owner/repo(.git)?` URL.
26
38
  * Returns null for non-GitHub URLs or null input.
27
39
  */
@@ -61,6 +73,7 @@ async function runGithubCommand(root, args) {
61
73
  case "install": return runInstall(root, client);
62
74
  case "installations": return runInstallations(client);
63
75
  case "connect": return runConnect(root, client, args);
76
+ case "update": return runGithubUpdate(root, client, args);
64
77
  case "link": return runGithubLink(root, client);
65
78
  }
66
79
  }
@@ -304,5 +317,125 @@ async function runConnect(root, client, args) {
304
317
  }
305
318
  R.success(`Connected ${repoFullName} (${branch}) → project. Push to ${branch} to deploy.`);
306
319
  }
320
+ async function runGithubUpdate(root, client, args) {
321
+ const isTTY = process.stdin.isTTY === true;
322
+ if (!isTTY && args.branch === void 0 && args.executor === void 0) {
323
+ R.error("update: Nothing to update. Pass --branch <name> and/or --executor <container|github_actions>.");
324
+ process.exit(1);
325
+ }
326
+ let projectId;
327
+ const requestedSlug = getRequestedProjectSlug({ projectSlug: args.projectName || void 0 });
328
+ if (requestedSlug) {
329
+ const resolved = resolveProjectBySlug(await client.listProjects(), requestedSlug);
330
+ if (!resolved) {
331
+ R.error(`update: No project found with slug '${requestedSlug}'.`);
332
+ process.exit(1);
333
+ }
334
+ projectId = resolved.projectId;
335
+ } else {
336
+ const linked = readProjectConfig(root);
337
+ if (linked) projectId = linked.projectId;
338
+ else if (!isTTY) {
339
+ R.error("update: No project specified. Pass a project name or --project <name>, set VOID_PROJECT, or link one with `void project link`.");
340
+ process.exit(1);
341
+ } else {
342
+ const projects = await client.listProjects();
343
+ if (projects.length === 0) {
344
+ R.error("No projects found. Create one first with `void deploy`.");
345
+ process.exit(1);
346
+ }
347
+ const picked = await Ee({
348
+ message: "Select a project:",
349
+ options: projects.map((p) => ({
350
+ value: p.id,
351
+ label: p.slug
352
+ }))
353
+ });
354
+ if (q(picked)) {
355
+ me("Cancelled.");
356
+ process.exit(0);
357
+ }
358
+ projectId = picked;
359
+ }
360
+ }
361
+ let current;
362
+ try {
363
+ current = await client.getGithubConnection(projectId);
364
+ } catch (err) {
365
+ if (err instanceof PlatformApiError) {
366
+ const body = parsePlatformErrorBody(err.body);
367
+ const code = body?.error ?? body?.message ?? "";
368
+ const message = describeUpdateError(err.status, code);
369
+ if (message !== null) {
370
+ R.error(`update: ${message}`);
371
+ process.exit(1);
372
+ }
373
+ }
374
+ throw err;
375
+ }
376
+ let branch;
377
+ let executor;
378
+ if (isTTY) {
379
+ if (args.branch !== void 0) branch = args.branch;
380
+ else {
381
+ const input = await Re({
382
+ message: "Branch to deploy from:",
383
+ placeholder: current.branch,
384
+ initialValue: current.branch
385
+ });
386
+ if (q(input)) {
387
+ me("Cancelled.");
388
+ process.exit(0);
389
+ }
390
+ branch = input.trim() || current.branch;
391
+ }
392
+ if (args.executor !== void 0) executor = args.executor;
393
+ else {
394
+ const picked = await Ee({
395
+ message: "Build executor:",
396
+ options: [{
397
+ value: "container",
398
+ label: "container"
399
+ }, {
400
+ value: "github_actions",
401
+ label: "github_actions"
402
+ }],
403
+ initialValue: current.build_executor
404
+ });
405
+ if (q(picked)) {
406
+ me("Cancelled.");
407
+ process.exit(0);
408
+ }
409
+ executor = picked;
410
+ }
411
+ } else {
412
+ branch = args.branch ?? current.branch;
413
+ executor = args.executor ?? current.build_executor;
414
+ }
415
+ const patch = {};
416
+ if (branch !== current.branch) patch.branch = branch;
417
+ if (executor !== current.build_executor) patch.buildExecutor = executor;
418
+ if (patch.branch === void 0 && patch.buildExecutor === void 0) {
419
+ R.info(`No changes. ${current.repo_full_name} already deploys from ${current.branch} via ${current.build_executor}.`);
420
+ return;
421
+ }
422
+ let updated;
423
+ try {
424
+ updated = await client.updateGithubConnection(projectId, patch);
425
+ } catch (err) {
426
+ if (err instanceof PlatformApiError) {
427
+ const body = parsePlatformErrorBody(err.body);
428
+ const code = body?.error ?? body?.message ?? "";
429
+ const message = describeUpdateError(err.status, code);
430
+ if (message !== null) {
431
+ R.error(`update: ${message}`);
432
+ process.exit(1);
433
+ }
434
+ throw err;
435
+ }
436
+ throw err;
437
+ }
438
+ R.success(`Updated ${updated.repo_full_name} → branch ${updated.branch}, executor ${updated.build_executor}.`);
439
+ }
307
440
  //#endregion
308
441
  export { runGithubCommand };
package/dist/index.mjs CHANGED
@@ -1,10 +1,10 @@
1
1
  import { r as __toESM } from "./chunk-DJd-R1mw.mjs";
2
2
  import { a as join, n as dirname, s as relative } from "./pathe.M-eThtNZ-BrPhGF_K.mjs";
3
3
  import { u as require_picocolors } from "./output-DeiS4oEX.mjs";
4
- import { C as hasApiRoutes, S as resolveSandboxConfig, T as resolveAssetRoutingPolicy, _ as readWranglerCompat, a as prerenderPagesNode, b as SANDBOX_MIGRATION_TAG, c as stripInternalEnvKeys, d as ensureWranglerCompatibilityDate, f as ensureWranglerNodejsAlsFlag, g as readExistingLiveBindingConfig, h as normalizeWranglerCompatibilityFlags, i as prerenderPages, l as LIVE_MIGRATION_TAG, m as nextDurableObjectMigrationTag, n as resolveDistDir, o as filterLoadedEnv, p as hasDurableObjectSqliteMigration, r as resolveWorkerDirName, s as resolveRemoteMode, u as ensureWranglerCompat, v as resolveLiveBindingConfig, w as hasDocumentRoutes, x as isSandboxEnabled, y as syncWranglerBindings } from "./deploy-Cwa5sooV.mjs";
4
+ import { C as hasApiRoutes, S as resolveSandboxConfig, T as resolveAssetRoutingPolicy, _ as readWranglerCompat, a as prerenderPagesNode, b as SANDBOX_MIGRATION_TAG, c as stripInternalEnvKeys, d as ensureWranglerCompatibilityDate, f as ensureWranglerNodejsAlsFlag, g as readExistingLiveBindingConfig, h as normalizeWranglerCompatibilityFlags, i as prerenderPages, l as LIVE_MIGRATION_TAG, m as nextDurableObjectMigrationTag, n as resolveDistDir, o as filterLoadedEnv, p as hasDurableObjectSqliteMigration, r as resolveWorkerDirName, s as resolveRemoteMode, u as ensureWranglerCompat, v as resolveLiveBindingConfig, w as hasDocumentRoutes, x as isSandboxEnabled, y as syncWranglerBindings } from "./deploy-CuxXxVgz.mjs";
5
5
  import { i as resolveProjectPaths, n as readProjectPaths, t as assertNoRootSourceConventionConflicts } from "./project-paths-CCMrHYQm.mjs";
6
6
  import { n as loadVoidAuthConfig, t as findVoidAuthConfig } from "./config-hhMYPVRT.mjs";
7
- import { d as getToken, p as isStagingMode } from "./client-D4awzTnj.mjs";
7
+ import { f as getToken, m as isStagingMode } from "./client-CTHvucDv.mjs";
8
8
  import { r as readProjectConfig } from "./project-CH9pdo16.mjs";
9
9
  import { n as ensureProjectTsconfig, r as writeFileIfChanged } from "./project-tsconfig-BTNuNoJ0.mjs";
10
10
  import { c as getDatabaseDialect, f as readConfig, l as isNodeTarget, p as resolveBindingNames } from "./config-8dLIngKW.mjs";
@@ -4916,7 +4916,7 @@ const STAGING_API_URL = "https://api.staging.void.cloud";
4916
4916
  */
4917
4917
  async function runAiSetupPrompt(root, token, staging, server) {
4918
4918
  const { select, text, isCancel, log } = await import("./dist-abzUneor.mjs").then((n) => n.p);
4919
- const { PlatformClient } = await import("./client-D4awzTnj.mjs").then((n) => n.r);
4919
+ const { PlatformClient } = await import("./client-CTHvucDv.mjs").then((n) => n.r);
4920
4920
  const { writeProjectConfig } = await import("./project-CH9pdo16.mjs").then((n) => n.n);
4921
4921
  const { inferDefaultSlug } = await import("./resolve-project-D4O1_fZz.mjs").then((n) => n.i);
4922
4922
  const client = new PlatformClient(token, staging ? STAGING_API_URL : DEFAULT_API_URL);
@@ -4945,7 +4945,7 @@ async function runAiSetupPrompt(root, token, staging, server) {
4945
4945
  let slug;
4946
4946
  if (result === "__create__") {
4947
4947
  const { validateProjectSlug } = await import("./project-slug-rX3kTOfY.mjs").then((n) => n.t);
4948
- const { createProjectWithSlugRetry } = await import("./create-project-CGodxfzH.mjs").then((n) => n.t);
4948
+ const { createProjectWithSlugRetry } = await import("./create-project-CruTH_TQ.mjs").then((n) => n.t);
4949
4949
  let created;
4950
4950
  try {
4951
4951
  created = await createProjectWithSlugRetry(client, inferDefaultSlug(root), async (defaultSlug) => {
@@ -1,7 +1,7 @@
1
1
  import { a as join, c as resolve, i as isAbsolute, n as dirname, s as relative, t as basename } from "./pathe.M-eThtNZ-BrPhGF_K.mjs";
2
2
  import { n as cliTitle } from "./output-DeiS4oEX.mjs";
3
3
  import { n as readProjectPaths } from "./project-paths-CCMrHYQm.mjs";
4
- import { d as getToken, n as PlatformClient, p as isStagingMode } from "./client-D4awzTnj.mjs";
4
+ import { f as getToken, m as isStagingMode, n as PlatformClient } from "./client-CTHvucDv.mjs";
5
5
  import { _ as me, c as R, g as ge, i as Ee, l as Re, u as Se, v as ue, x as q, y as ye } from "./dist-abzUneor.mjs";
6
6
  import { a as writeProjectConfig, r as readProjectConfig } from "./project-CH9pdo16.mjs";
7
7
  import { n as ensureProjectTsconfig, t as createProjectTsconfig } from "./project-tsconfig-BTNuNoJ0.mjs";
@@ -11,8 +11,8 @@ import { r as parseDotenvFile, t as expandDotenv } from "./dotenv-lS94ymhM.mjs";
11
11
  import { t as MagicString } from "./magic-string.es-C1Fb0uxq.mjs";
12
12
  import { n as writeDrizzleConfig } from "./config--wXmVOoe.mjs";
13
13
  import { n as getAgentById, r as getPackageDir, t as detectAgents } from "./agents-MhSzNMiC.mjs";
14
- import { n as promptAndCreateProject, r as promptProjectSelection } from "./create-project-CGodxfzH.mjs";
15
- import { t as promptForLoginToken } from "./login-Ca6mhQVI.mjs";
14
+ import { n as promptAndCreateProject, r as promptProjectSelection } from "./create-project-CruTH_TQ.mjs";
15
+ import { t as promptForLoginToken } from "./login-v4wle1vn.mjs";
16
16
  import { r as formatProjectCommand } from "./preset-B7ZQZn0u.mjs";
17
17
  import { n as findInstalledYarnPnpRuntime, r as hasLocalLockfile, t as buildDrizzleKitSpawnEnv } from "./yarn-pnp-DhCHHLAz.mjs";
18
18
  import { createRequire } from "node:module";
@@ -1805,10 +1805,12 @@ function getWorkflowSetupSteps(root, pm) {
1805
1805
  }
1806
1806
  /**
1807
1807
  * Scaffold the GitHub Actions workflow that deploys via GitHub OIDC — no
1808
- * long-lived secret stored in the repo. The job requests an OIDC token from
1809
- * GitHub (audience `void`), exchanges it at `POST $VOID_API_URL/auth/github-oidc`
1810
- * for a short-lived (15-min) project-scoped deploy token, then runs
1811
- * `void deploy --project <slug>` with that token exported as `VOID_TOKEN`.
1808
+ * long-lived secret stored in the repo. `void deploy` itself detects GitHub
1809
+ * Actions, mints an OIDC token (audience `void`), exchanges it at
1810
+ * `POST $VOID_API_URL/auth/github-oidc` for a short-lived, project-scoped deploy
1811
+ * token, and uses it — so the workflow is a single `void deploy` step (no
1812
+ * curl/jq). `permissions: id-token: write` is still required: it is what lets
1813
+ * the job (and thus the CLI) mint the OIDC token.
1812
1814
  *
1813
1815
  * `slug` is the linked project slug when known (from `.void/project.json`);
1814
1816
  * otherwise a `${{ vars.VOID_PROJECT }}` placeholder is emitted with a comment
@@ -1830,8 +1832,8 @@ concurrency:
1830
1832
  cancel-in-progress: true
1831
1833
 
1832
1834
  # id-token: write lets the job mint a GitHub OIDC token. No long-lived
1833
- # VOID_TOKEN secret is stored — the token below is exchanged for a
1834
- # short-lived, project-scoped deploy token at deploy time.
1835
+ # VOID_TOKEN secret is stored — \`void deploy\` mints that OIDC token and
1836
+ # exchanges it for a short-lived, project-scoped deploy token at deploy time.
1835
1837
  permissions:
1836
1838
  id-token: write
1837
1839
  contents: read
@@ -1850,17 +1852,6 @@ jobs:
1850
1852
  - uses: actions/checkout@v6
1851
1853
  ${setup}
1852
1854
  ${install}
1853
- - name: Exchange GitHub OIDC token for a Void deploy token
1854
- run: |
1855
- OIDC_TOKEN="$(curl -sf \\
1856
- -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \\
1857
- "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=void" | jq -r '.value')"
1858
- VOID_TOKEN="$(curl -sf \\
1859
- -H 'Content-Type: application/json' \\
1860
- -d "$(jq -n --arg t "$OIDC_TOKEN" --arg p "$VOID_PROJECT" '{oidcToken: $t, project: $p}')" \\
1861
- "$VOID_API_URL/auth/github-oidc" | jq -r '.token')"
1862
- echo "::add-mask::$VOID_TOKEN"
1863
- echo "VOID_TOKEN=$VOID_TOKEN" >> "$GITHUB_ENV"
1864
1855
  - name: Deploy
1865
1856
  run: ${runner} deploy --project "$VOID_PROJECT"
1866
1857
  `;
@@ -1,8 +1,8 @@
1
1
  import { n as cliTitle, s as import_picocolors } from "./output-DeiS4oEX.mjs";
2
- import { d as getToken, n as PlatformClient, u as getSiteDomain } from "./client-D4awzTnj.mjs";
2
+ import { d as getSiteDomain, f as getToken, n as PlatformClient } from "./client-CTHvucDv.mjs";
3
3
  import { _ as me, c as R, g as ge, y as ye } from "./dist-abzUneor.mjs";
4
4
  import { a as writeProjectConfig, r as readProjectConfig } from "./project-CH9pdo16.mjs";
5
- import { n as promptAndCreateProject, r as promptProjectSelection } from "./create-project-CGodxfzH.mjs";
5
+ import { n as promptAndCreateProject, r as promptProjectSelection } from "./create-project-CruTH_TQ.mjs";
6
6
  import { r as resolveProjectBySlug } from "./resolve-project-D4O1_fZz.mjs";
7
7
  //#region src/cli/link.ts
8
8
  async function runLink(root, slug) {
@@ -1,5 +1,5 @@
1
1
  import { a as ensureUtc, i as dim, l as tablePrefix, n as cliTitle, s as import_picocolors } from "./output-DeiS4oEX.mjs";
2
- import { d as getToken, n as PlatformClient } from "./client-D4awzTnj.mjs";
2
+ import { f as getToken, n as PlatformClient } from "./client-CTHvucDv.mjs";
3
3
  import { c as R, g as ge, y as ye } from "./dist-abzUneor.mjs";
4
4
  import { r as readProjectConfig } from "./project-CH9pdo16.mjs";
5
5
  import { r as resolveProjectBySlug } from "./resolve-project-D4O1_fZz.mjs";
@@ -1,5 +1,5 @@
1
1
  import { n as cliTitle, r as createSpinner, s as import_picocolors } from "./output-DeiS4oEX.mjs";
2
- import { _ as saveToken, a as isExpiredTokenError, d as getToken, f as getTokenSource, g as runLogin, h as removeToken, n as PlatformClient, p as isStagingMode } from "./client-D4awzTnj.mjs";
2
+ import { _ as runLogin, a as isExpiredTokenError, f as getToken, g as removeToken, m as isStagingMode, n as PlatformClient, p as getTokenSource, v as saveToken } from "./client-CTHvucDv.mjs";
3
3
  import { _ as me, c as R, g as ge, i as Ee, x as q, y as ye } from "./dist-abzUneor.mjs";
4
4
  //#region src/cli/login.ts
5
5
  async function promptForLoginToken(root = process.cwd()) {
@@ -1,5 +1,5 @@
1
1
  import { i as dim, n as cliTitle, s as import_picocolors } from "./output-DeiS4oEX.mjs";
2
- import { d as getToken, n as PlatformClient } from "./client-D4awzTnj.mjs";
2
+ import { f as getToken, n as PlatformClient } from "./client-CTHvucDv.mjs";
3
3
  import { c as R, g as ge, y as ye } from "./dist-abzUneor.mjs";
4
4
  import { r as readProjectConfig } from "./project-CH9pdo16.mjs";
5
5
  //#region src/cli/logs.ts
@@ -1,5 +1,5 @@
1
1
  import { a as join, n as dirname } from "./pathe.M-eThtNZ-BrPhGF_K.mjs";
2
- import { d as getToken, n as PlatformClient } from "./client-D4awzTnj.mjs";
2
+ import { f as getToken, n as PlatformClient } from "./client-CTHvucDv.mjs";
3
3
  import { a as writeProjectConfig } from "./project-CH9pdo16.mjs";
4
4
  import { existsSync, readFileSync, readdirSync } from "node:fs";
5
5
  import { fileURLToPath } from "node:url";
@@ -1,5 +1,5 @@
1
1
  import { i as dim, l as tablePrefix, n as cliTitle, s as import_picocolors } from "./output-DeiS4oEX.mjs";
2
- import { d as getToken, n as PlatformClient, u as getSiteDomain } from "./client-D4awzTnj.mjs";
2
+ import { d as getSiteDomain, f as getToken, n as PlatformClient } from "./client-CTHvucDv.mjs";
3
3
  import { c as R, g as ge, y as ye } from "./dist-abzUneor.mjs";
4
4
  //#region src/cli/projects.ts
5
5
  async function runProjectsCommand(root) {
@@ -34,32 +34,32 @@ async function runProjectsCommand(root) {
34
34
  //#region src/cli/project-cmd.ts
35
35
  async function runProjectCommand(root, args) {
36
36
  if (args.subcommand === "status") {
37
- const { runListCommand } = await import("./list-BkwE5vH4.mjs");
37
+ const { runListCommand } = await import("./list-CbGxdbe7.mjs");
38
38
  return runListCommand(root, args.name || void 0);
39
39
  }
40
40
  if (args.subcommand === "link") {
41
- const { runLink } = await import("./link-CpbWJY3P.mjs");
41
+ const { runLink } = await import("./link-BGFW4pHD.mjs");
42
42
  return runLink(root, args.name || void 0);
43
43
  }
44
44
  if (args.subcommand === "list") return runProjectsCommand(root);
45
45
  if (args.subcommand === "logs") {
46
- const { runLogsCommand } = await import("./logs-ArQzZquo.mjs");
46
+ const { runLogsCommand } = await import("./logs-BFgY5Vqc.mjs");
47
47
  return runLogsCommand(root, args.filter, args.range, args.deployment || void 0, args.level || void 0);
48
48
  }
49
49
  if (args.subcommand === "rollback") {
50
- const { runRollbackCommand } = await import("./rollback-BJ60ktsW.mjs");
50
+ const { runRollbackCommand } = await import("./rollback-o0M0Qo_n.mjs");
51
51
  return runRollbackCommand(root, args.deployId || void 0);
52
52
  }
53
53
  if (args.subcommand === "cancel") {
54
- const { runCancelDeployCommand } = await import("./cancel-deploy-CDzkVaYZ.mjs");
54
+ const { runCancelDeployCommand } = await import("./cancel-deploy-BwpT4U4a.mjs");
55
55
  return runCancelDeployCommand(root, args.deployId || void 0);
56
56
  }
57
57
  if (args.subcommand === "delete") {
58
- const { runDeleteCommand } = await import("./delete-CJZGDLBR.mjs");
58
+ const { runDeleteCommand } = await import("./delete-IQe1O4Re.mjs");
59
59
  return runDeleteCommand(root, args.name || void 0, { force: args.force });
60
60
  }
61
61
  if (args.subcommand === "purge-cache") {
62
- const { runPurgeCacheCommand } = await import("./cache-DNX0hLsO.mjs");
62
+ const { runPurgeCacheCommand } = await import("./cache-CHFZmqa5.mjs");
63
63
  return runPurgeCacheCommand(root, args.projectSlug || void 0);
64
64
  }
65
65
  }
@@ -1,5 +1,5 @@
1
1
  import { a as ensureUtc, i as dim, n as cliTitle, r as createSpinner, s as import_picocolors } from "./output-DeiS4oEX.mjs";
2
- import { d as getToken, n as PlatformClient } from "./client-D4awzTnj.mjs";
2
+ import { f as getToken, n as PlatformClient } from "./client-CTHvucDv.mjs";
3
3
  import { _ as me, c as R, g as ge, i as Ee, v as ue, x as q, y as ye } from "./dist-abzUneor.mjs";
4
4
  import { r as readProjectConfig } from "./project-CH9pdo16.mjs";
5
5
  //#region src/cli/rollback.ts
@@ -1,5 +1,5 @@
1
1
  import { n as cliTitle } from "./output-DeiS4oEX.mjs";
2
- import { d as getToken, n as PlatformClient } from "./client-D4awzTnj.mjs";
2
+ import { f as getToken, n as PlatformClient } from "./client-CTHvucDv.mjs";
3
3
  import { _ as me, c as R, g as ge, n as Ce, u as Se, v as ue, x as q, y as ye } from "./dist-abzUneor.mjs";
4
4
  import { r as readProjectConfig } from "./project-CH9pdo16.mjs";
5
5
  import { r as resolveProjectBySlug, t as getRequestedProjectSlug } from "./resolve-project-D4O1_fZz.mjs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "void",
3
- "version": "0.10.1",
3
+ "version": "0.10.2",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/voidzero-dev/void.git",
@@ -353,7 +353,7 @@
353
353
  "valibot": ">=1.0.0-beta.7",
354
354
  "vite": "^8.0.0",
355
355
  "zod": "^3.25.0 || ^4.0.0",
356
- "@void/md": "0.10.1"
356
+ "@void/md": "0.10.2"
357
357
  },
358
358
  "peerDependenciesMeta": {
359
359
  "@void/md": {
@@ -66,7 +66,7 @@ If your CI pipeline runs typechecking or other static analysis before deploy, ru
66
66
 
67
67
  You can deploy from a GitHub repo on every push to `main`. Running `void init --github` generates `.github/workflows/void-deploy.yml` in your project.
68
68
 
69
- The workflow authenticates with [GitHub OIDC](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect) — there is **no long-lived `VOID_TOKEN` secret to store or rotate**. The job requests a short-lived OIDC token from GitHub, exchanges it at `POST $VOID_API_URL/auth/github-oidc` for a short-lived project-scoped deploy token (about 15 minutes on the free tier; longer on higher plans, capped at ~60 minutes), then runs `void deploy --project <slug>`:
69
+ The workflow authenticates with [GitHub OIDC](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect) — there is **no long-lived `VOID_TOKEN` secret to store or rotate**. `void deploy` detects GitHub Actions and does the exchange itself: it requests a short-lived OIDC token from GitHub (audience `void`), exchanges it at `POST $VOID_API_URL/auth/github-oidc` for a short-lived project-scoped deploy token (about 15 minutes on the free tier; longer on higher plans, capped at ~60 minutes), and deploys — so the workflow is a single `void deploy` step. `permissions: id-token: write` is still required: it is what lets the job (and the CLI) mint the OIDC token.
70
70
 
71
71
  ```yaml
72
72
  name: Deploy to Void
@@ -98,17 +98,6 @@ jobs:
98
98
  node-version: lts/*
99
99
  cache: npm
100
100
  - run: npm ci
101
- - name: Exchange GitHub OIDC token for a Void deploy token
102
- run: |
103
- OIDC_TOKEN="$(curl -sf \
104
- -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
105
- "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=void" | jq -r '.value')"
106
- VOID_TOKEN="$(curl -sf \
107
- -H 'Content-Type: application/json' \
108
- -d "$(jq -n --arg t "$OIDC_TOKEN" --arg p "$VOID_PROJECT" '{oidcToken: $t, project: $p}')" \
109
- "$VOID_API_URL/auth/github-oidc" | jq -r '.token')"
110
- echo "::add-mask::$VOID_TOKEN"
111
- echo "VOID_TOKEN=$VOID_TOKEN" >> "$GITHUB_ENV"
112
101
  - name: Deploy
113
102
  run: npx void deploy --project "$VOID_PROJECT"
114
103
  ```
@@ -86,7 +86,7 @@ After that, the full interactive flow walks through:
86
86
  4. **Skills:** links Void skills using the same detected or selected agent context.
87
87
  5. **MCP config:** writes MCP server config using that same agent context.
88
88
  6. **Demo code:** for existing non-Pages projects, optionally scaffolds a `db/migrations/` directory plus an API route and typed fetch example.
89
- 7. **GitHub Actions:** optionally creates `.github/workflows/void-deploy.yml`. The workflow deploys on pushes to `main` and authenticates via [GitHub OIDC](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect) — no long-lived `VOID_TOKEN` secret is stored in the repo. The job requests an OIDC token (audience `void`), exchanges it at `POST $VOID_API_URL/auth/github-oidc` for a short-lived project-scoped deploy token, then runs `void deploy --project <slug>` with the right package manager. The project slug is baked in from your linked project (`.void/project.json`) when known; otherwise the workflow reads a `VOID_PROJECT` repository variable.
89
+ 7. **GitHub Actions:** optionally creates `.github/workflows/void-deploy.yml`. The workflow deploys on pushes to `main` and authenticates via [GitHub OIDC](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect) — no long-lived `VOID_TOKEN` secret is stored in the repo. The workflow is a single `void deploy` step: when it runs in GitHub Actions, `void deploy` mints an OIDC token (audience `void`), exchanges it at `POST $VOID_API_URL/auth/github-oidc` for a short-lived project-scoped deploy token, and deploys. `permissions: id-token: write` is retained so the CLI can mint that token. The project slug is baked in from your linked project (`.void/project.json`) when known; otherwise the workflow reads a `VOID_PROJECT` repository variable.
90
90
  8. **`env.ts` scaffold:** if the project has no `env.ts` but has `.env` / `.env.example` / `.env.local` / `.env.development*` files on disk, generates an `env.ts` pre-populated with their keys. Values get conservative type inference (`boolean`/`url`/`number`/`string`) — the file carries a banner nudging you to tighten anything the heuristic got wrong.
91
91
  9. **Project setup:** optionally logs you in, lets you select or create a project, and writes `.void/project.json` so your first deploy can just be `void deploy`.
92
92
 
@@ -627,6 +627,30 @@ void github connect my-app \
627
627
 
628
628
  **Project resolution** follows the same order as deploy: positional / `--project`, `VOID_PROJECT`, linked project (`.void/project.json`).
629
629
 
630
+ ### `void github update`
631
+
632
+ ```
633
+ void github update [project] [options]
634
+ ```
635
+
636
+ Update an existing connection's deploy **branch** and/or **build executor**. Use this to change settings on a project that is already connected — for example, flipping the executor from `container` to `github_actions` for a monorepo whose Void app lives in a subdirectory, or moving the deploy branch. The project must already be connected (run `void github connect` first); the repository and installation are not changed.
637
+
638
+ **Options**
639
+
640
+ | Flag | Description |
641
+ | ------------------- | --------------------------------------------------- |
642
+ | `--project <name>` | Project name (alias for the positional argument) |
643
+ | `--branch <name>` | New branch to deploy from |
644
+ | `--executor <type>` | New build executor: `container` or `github_actions` |
645
+
646
+ Interactively (TTY), `void github update` shows the current branch and executor and prompts for new values, defaulting each to the current setting. When stdin is not a TTY, it never prompts: pass at least one of `--branch` / `--executor`, or it fails closed. If nothing actually changes, the command reports "no changes" and does not call the API.
647
+
648
+ ```
649
+ void github update my-app --executor github_actions
650
+ ```
651
+
652
+ **Project resolution** follows the same order as deploy: positional / `--project`, `VOID_PROJECT`, linked project (`.void/project.json`).
653
+
630
654
  ## Custom Domains
631
655
 
632
656
  ### `void domain add`