onveloz 0.0.0-beta.32 → 0.0.0-beta.33

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/dist/index.mjs +121 -32
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -1260,7 +1260,7 @@ async function requireAuth(options) {
1260
1260
 
1261
1261
  //#endregion
1262
1262
  //#region src/lib/client.ts
1263
- const CLI_VERSION = "0.0.0-beta.32";
1263
+ const CLI_VERSION = "0.0.0-beta.33";
1264
1264
  const USER_AGENT = `veloz-cli/${CLI_VERSION}`;
1265
1265
  /**
1266
1266
  * Client source — "cli" by default; the init wizard sets this to "cli-wizard"
@@ -24221,7 +24221,7 @@ const LOGO_LINES$1 = [
24221
24221
  ];
24222
24222
  const BRAND_COLOR$1 = "#FF4D00";
24223
24223
  function getVersion() {
24224
- return "0.0.0-beta.32";
24224
+ return "0.0.0-beta.33";
24225
24225
  }
24226
24226
  function printBanner(subtitle) {
24227
24227
  const version$2 = getVersion();
@@ -25327,7 +25327,7 @@ async function fetchLatestVersion() {
25327
25327
  }
25328
25328
  }
25329
25329
  function getCurrentVersion() {
25330
- return "0.0.0-beta.32";
25330
+ return "0.0.0-beta.33";
25331
25331
  }
25332
25332
  /**
25333
25333
  * Install a specific CLI version. Returns true on success.
@@ -30407,7 +30407,7 @@ function PickerMenu({ items, onSelect, onCancel }) {
30407
30407
 
30408
30408
  //#endregion
30409
30409
  //#region src/wizard/ui/primitives/ScreenLayout.tsx
30410
- const version = "0.0.0-beta.32";
30410
+ const version = "0.0.0-beta.33";
30411
30411
  const LOGO_LINES = [
30412
30412
  "██╗ ██╗███████╗██╗ ██████╗ ███████╗",
30413
30413
  "██║ ██║██╔════╝██║ ██╔═══██╗╚══███╔╝",
@@ -30596,6 +30596,7 @@ function createInitialSession() {
30596
30596
  selectedOrgId: null,
30597
30597
  newOrgName: null,
30598
30598
  orgCreateError: null,
30599
+ reauthNotice: null,
30599
30600
  detectedFramework: null,
30600
30601
  detectedFrameworkLabel: null,
30601
30602
  selectedFramework: null,
@@ -30729,29 +30730,45 @@ function AuthScreen({ store }) {
30729
30730
  })]
30730
30731
  })] });
30731
30732
  }
30732
- if (session.authPhase === "browser" || session.authPhase === "polling") return /* @__PURE__ */ jsxs(ScreenLayout, { children: [/* @__PURE__ */ jsx(Spinner, { label: COPY.authPolling }), session.authDeviceCode ? /* @__PURE__ */ jsxs(Box, {
30733
- marginTop: 1,
30734
- flexDirection: "column",
30735
- gap: 1,
30736
- children: [/* @__PURE__ */ jsxs(Box, {
30737
- gap: 1,
30738
- children: [/* @__PURE__ */ jsx(Text, { children: COPY.authDeviceCode }), /* @__PURE__ */ jsx(Text, {
30739
- bold: true,
30740
- color: BRAND_COLOR,
30741
- children: session.authDeviceCode
30742
- })]
30743
- }), session.authVerificationUrl ? /* @__PURE__ */ jsxs(Box, {
30733
+ if (session.authPhase === "browser" || session.authPhase === "polling") return /* @__PURE__ */ jsxs(ScreenLayout, { children: [
30734
+ session.reauthNotice ? /* @__PURE__ */ jsx(Box, {
30735
+ marginBottom: 1,
30736
+ children: /* @__PURE__ */ jsxs(Text, {
30737
+ color: "yellow",
30738
+ children: ["⚠ ", session.reauthNotice]
30739
+ })
30740
+ }) : null,
30741
+ /* @__PURE__ */ jsx(Spinner, { label: COPY.authPolling }),
30742
+ session.authDeviceCode ? /* @__PURE__ */ jsxs(Box, {
30743
+ marginTop: 1,
30744
30744
  flexDirection: "column",
30745
- children: [/* @__PURE__ */ jsx(Text, {
30746
- dimColor: true,
30747
- children: COPY.authBrowserFallback
30748
- }), /* @__PURE__ */ jsx(Text, {
30749
- dimColor: true,
30750
- children: session.authVerificationUrl
30751
- })]
30752
- }) : null]
30753
- }) : null] });
30754
- return /* @__PURE__ */ jsx(ScreenLayout, { children: /* @__PURE__ */ jsx(Spinner, { label: COPY.authChecking }) });
30745
+ gap: 1,
30746
+ children: [/* @__PURE__ */ jsxs(Box, {
30747
+ gap: 1,
30748
+ children: [/* @__PURE__ */ jsx(Text, { children: COPY.authDeviceCode }), /* @__PURE__ */ jsx(Text, {
30749
+ bold: true,
30750
+ color: BRAND_COLOR,
30751
+ children: session.authDeviceCode
30752
+ })]
30753
+ }), session.authVerificationUrl ? /* @__PURE__ */ jsxs(Box, {
30754
+ flexDirection: "column",
30755
+ children: [/* @__PURE__ */ jsx(Text, {
30756
+ dimColor: true,
30757
+ children: COPY.authBrowserFallback
30758
+ }), /* @__PURE__ */ jsx(Text, {
30759
+ dimColor: true,
30760
+ children: session.authVerificationUrl
30761
+ })]
30762
+ }) : null]
30763
+ }) : null
30764
+ ] });
30765
+ return /* @__PURE__ */ jsxs(ScreenLayout, { children: [session.reauthNotice ? /* @__PURE__ */ jsx(Box, {
30766
+ marginBottom: 1,
30767
+ children: /* @__PURE__ */ jsxs(Text, {
30768
+ color: "yellow",
30769
+ children: ["⚠ ", session.reauthNotice]
30770
+ })
30771
+ }) : null, /* @__PURE__ */ jsx(Spinner, { label: COPY.authChecking })] });
30755
30772
  }
30756
30773
  function OrgCreateForm({ store }) {
30757
30774
  const [value, setValue] = useState("");
@@ -33884,6 +33901,15 @@ var WizardStore = class {
33884
33901
  this.$session.setKey("authPhase", "browser");
33885
33902
  this.emitChange();
33886
33903
  }
33904
+ /** Show a banner on AuthScreen explaining why we're re-running device auth. */
33905
+ setReauthNotice(message) {
33906
+ this.$session.setKey("reauthNotice", message);
33907
+ this.emitChange();
33908
+ }
33909
+ clearReauthNotice() {
33910
+ this.$session.setKey("reauthNotice", null);
33911
+ this.emitChange();
33912
+ }
33887
33913
  setAvailableOrgs(orgs) {
33888
33914
  this.$session.setKey("availableOrgs", orgs);
33889
33915
  this.$session.setKey("authPhase", "org-select");
@@ -34157,7 +34183,6 @@ async function uploadInitTelemetry(sessionDir) {
34157
34183
  return;
34158
34184
  }
34159
34185
  const authConfig = loadConfig();
34160
- if (!authConfig.apiKey) return;
34161
34186
  const files = readdirSync(sessionDir).filter((name) => {
34162
34187
  const full = join(sessionDir, name);
34163
34188
  try {
@@ -34170,9 +34195,10 @@ async function uploadInitTelemetry(sessionDir) {
34170
34195
  if (files.length === 0) return;
34171
34196
  const client = createClient(authConfig.apiUrl, () => {
34172
34197
  const headers = {
34173
- Authorization: `Bearer ${authConfig.apiKey}`,
34174
- "User-Agent": "veloz-cli/telemetry"
34198
+ "User-Agent": "veloz-cli/telemetry",
34199
+ "X-Veloz-Client-Source": "cli-wizard"
34175
34200
  };
34201
+ if (authConfig.apiKey) headers.Authorization = `Bearer ${authConfig.apiKey}`;
34176
34202
  if (authConfig.organizationId) headers["X-Organization-Id"] = authConfig.organizationId;
34177
34203
  return headers;
34178
34204
  });
@@ -34263,7 +34289,7 @@ function startTUI(cwd) {
34263
34289
  }));
34264
34290
  teardown = unmount;
34265
34291
  const cleanup = () => {
34266
- if (process.stdout.isTTY) process.stdout.write("\x1B[0m\x1B[2J\x1B[H");
34292
+ if (process.stdout.isTTY) process.stdout.write("\x1B[0m");
34267
34293
  };
34268
34294
  process.on("exit", cleanup);
34269
34295
  let sigintCount = 0;
@@ -34304,6 +34330,20 @@ function describeError(err) {
34304
34330
  };
34305
34331
  return { message: typeof err === "string" ? err : JSON.stringify(err) };
34306
34332
  }
34333
+ /**
34334
+ * Detect an ORPC / HTTP 401 from a thrown value. Covers the three shapes we see
34335
+ * in practice: ORPCError instances (`.code === "UNAUTHORIZED"`), ORPC fetch
34336
+ * failures that preserve `.status === 401`, and raw Error messages containing
34337
+ * "Unauthorized".
34338
+ */
34339
+ function isUnauthorizedError(err) {
34340
+ if (!err || typeof err !== "object") return false;
34341
+ const e = err;
34342
+ if (e.code === "UNAUTHORIZED") return true;
34343
+ if (e.status === 401) return true;
34344
+ if (typeof e.message === "string" && /unauthorized/i.test(e.message)) return true;
34345
+ return false;
34346
+ }
34307
34347
  /** Compose the error string we persist on `meta.error`. */
34308
34348
  function formatErrorForMeta(prefix, err) {
34309
34349
  const { message, stack } = describeError(err);
@@ -34421,6 +34461,29 @@ async function runInitFlow(c, logger, cwd) {
34421
34461
  const tui = startTUI();
34422
34462
  const { store } = tui;
34423
34463
  logger.log("tui", "TUI started");
34464
+ try {
34465
+ return await runInteractiveFlow({
34466
+ tui,
34467
+ store,
34468
+ logger,
34469
+ cwd,
34470
+ analysis,
34471
+ detectedFrameworkId,
34472
+ detectedLabel,
34473
+ forcedFramework
34474
+ });
34475
+ } catch (err) {
34476
+ try {
34477
+ tui.unmount();
34478
+ } catch {}
34479
+ const { message } = describeError(err);
34480
+ process.stderr.write(`\n✗ Erro: ${message}\n`);
34481
+ process.stderr.write(` Logs de depuração: ${logger.dir}\n\n`);
34482
+ throw err;
34483
+ }
34484
+ }
34485
+ async function runInteractiveFlow(opts) {
34486
+ const { tui, store, logger, cwd, analysis, detectedFrameworkId, detectedLabel, forcedFramework } = opts;
34424
34487
  store.setDetection({
34425
34488
  framework: detectedFrameworkId,
34426
34489
  frameworkLabel: detectedLabel,
@@ -34842,6 +34905,31 @@ async function listOrganizations() {
34842
34905
  }));
34843
34906
  }
34844
34907
  /**
34908
+ * Fetch orgs, handling an expired local API key by transparently re-running
34909
+ * the device auth flow inside the TUI. The user sees: "Verificando autenticação…"
34910
+ * → "Sessão expirou, autenticando novamente…" → device-code screen →
34911
+ * org picker, without ever bailing back to the shell.
34912
+ */
34913
+ async function listOrgsOrReauth(store) {
34914
+ const logger = getSessionLogger();
34915
+ try {
34916
+ return await listOrganizations();
34917
+ } catch (err) {
34918
+ if (!isUnauthorizedError(err)) throw err;
34919
+ logger.log("auth", "stale api key detected (401) — forcing re-login", { message: describeError(err).message });
34920
+ store.setReauthNotice("Sua sessão expirou. Vamos autenticar novamente para continuar.");
34921
+ saveConfig({ apiKey: "" });
34922
+ const config = loadConfig();
34923
+ store.setAuthPhase("browser");
34924
+ const token = await performDeviceAuth(store, config.apiUrl);
34925
+ if (!token) throw new Error("Autenticação cancelada ou expirada.");
34926
+ logger.log("auth", "re-login succeeded — retrying org fetch");
34927
+ saveConfig({ apiKey: token });
34928
+ store.clearReauthNotice();
34929
+ return await listOrganizations();
34930
+ }
34931
+ }
34932
+ /**
34845
34933
  * Create a new organization via Better Auth. The slug is derived from the name
34846
34934
  * and suffixed with a random token when a collision occurs.
34847
34935
  */
@@ -34910,8 +34998,9 @@ async function resolveAuthAndOrg(store) {
34910
34998
  }
34911
34999
  } else logger.log("auth", "already authenticated from config");
34912
35000
  logger.log("auth", "fetching organizations");
34913
- const orgs = await listOrganizations();
35001
+ const orgs = await listOrgsOrReauth(store);
34914
35002
  logger.log("auth", "organizations loaded", { count: orgs.length });
35003
+ config = loadConfig();
34915
35004
  let chosen;
34916
35005
  if (orgs.length === 0) {
34917
35006
  store.setAuthPhase("org-create");
@@ -34962,7 +35051,7 @@ async function runOrgCreationFlow(store, apiUrl) {
34962
35051
  //#region src/index.ts
34963
35052
  if (process.argv.includes("--mcp")) process.env.VELOZ_MCP = "true";
34964
35053
  const cli = Cli.create("veloz", {
34965
- version: "0.0.0-beta.32",
35054
+ version: "0.0.0-beta.33",
34966
35055
  description: "CLI da plataforma Veloz — deploy rápido para o Brasil",
34967
35056
  env: z.object({ VELOZ_ENV: z.string().optional().describe("Ambiente alvo (ex: preview, staging)") }),
34968
35057
  mcp: { command: "npx -y onveloz --mcp" }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "onveloz",
3
- "version": "0.0.0-beta.32",
3
+ "version": "0.0.0-beta.33",
4
4
  "description": "CLI da plataforma Veloz — deploy rápido para o Brasil",
5
5
  "keywords": [
6
6
  "brasil",