onveloz 0.0.0-beta.32 → 0.0.0-beta.34
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.
- package/dist/index.mjs +162 -58
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -222,32 +222,32 @@ const SERVICE_SIZES = {
|
|
|
222
222
|
};
|
|
223
223
|
const SERVICE_SIZE_KEYS = Object.keys(SERVICE_SIZES);
|
|
224
224
|
const HOURS_PER_MONTH = 720;
|
|
225
|
-
/** Service monthly prices in cents. */
|
|
225
|
+
/** Service monthly prices in cents. Magalu Cloud base + 10% margin. */
|
|
226
226
|
const SERVICE_MONTHLY_PRICES = {
|
|
227
|
-
basico:
|
|
228
|
-
essencial:
|
|
229
|
-
turbo:
|
|
230
|
-
"turbo-plus":
|
|
231
|
-
nitro:
|
|
232
|
-
"nitro-plus":
|
|
227
|
+
basico: 500,
|
|
228
|
+
essencial: 2e3,
|
|
229
|
+
turbo: 4e3,
|
|
230
|
+
"turbo-plus": 7e3,
|
|
231
|
+
nitro: 9500,
|
|
232
|
+
"nitro-plus": 17e3
|
|
233
233
|
};
|
|
234
|
-
/** Disk-based DB monthly prices in cents
|
|
234
|
+
/** Disk-based DB monthly prices in cents. Service price + 15% managed premium. */
|
|
235
235
|
const DATABASE_MONTHLY_PRICES = {
|
|
236
|
-
basico:
|
|
237
|
-
essencial:
|
|
238
|
-
turbo:
|
|
239
|
-
"turbo-plus":
|
|
240
|
-
nitro:
|
|
241
|
-
"nitro-plus":
|
|
236
|
+
basico: 600,
|
|
237
|
+
essencial: 2300,
|
|
238
|
+
turbo: 4600,
|
|
239
|
+
"turbo-plus": 8e3,
|
|
240
|
+
nitro: 11e3,
|
|
241
|
+
"nitro-plus": 19500
|
|
242
242
|
};
|
|
243
|
-
/** Redis monthly prices in cents. */
|
|
243
|
+
/** Redis monthly prices in cents. Matches disk-DB pricing. */
|
|
244
244
|
const REDIS_MONTHLY_PRICES = {
|
|
245
|
-
basico:
|
|
246
|
-
essencial:
|
|
247
|
-
turbo:
|
|
248
|
-
"turbo-plus":
|
|
249
|
-
nitro:
|
|
250
|
-
"nitro-plus":
|
|
245
|
+
basico: 600,
|
|
246
|
+
essencial: 2300,
|
|
247
|
+
turbo: 4600,
|
|
248
|
+
"turbo-plus": 8e3,
|
|
249
|
+
nitro: 11e3,
|
|
250
|
+
"nitro-plus": 19500
|
|
251
251
|
};
|
|
252
252
|
/** Hourly rates derived from monthly prices (cents per instance per hour). */
|
|
253
253
|
const SERVICE_HOURLY_RATES = Object.fromEntries(Object.entries(SERVICE_MONTHLY_PRICES).map(([k, v]) => [k, v / HOURS_PER_MONTH]));
|
|
@@ -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.
|
|
1263
|
+
const CLI_VERSION = "0.0.0-beta.34";
|
|
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.
|
|
24224
|
+
return "0.0.0-beta.34";
|
|
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.
|
|
25330
|
+
return "0.0.0-beta.34";
|
|
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.
|
|
30410
|
+
const version = "0.0.0-beta.34";
|
|
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: [
|
|
30733
|
-
|
|
30734
|
-
|
|
30735
|
-
|
|
30736
|
-
|
|
30737
|
-
|
|
30738
|
-
|
|
30739
|
-
|
|
30740
|
-
|
|
30741
|
-
|
|
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
|
-
|
|
30746
|
-
|
|
30747
|
-
|
|
30748
|
-
|
|
30749
|
-
|
|
30750
|
-
|
|
30751
|
-
|
|
30752
|
-
|
|
30753
|
-
|
|
30754
|
-
|
|
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
|
-
|
|
34174
|
-
"
|
|
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
|
|
34292
|
+
if (process.stdout.isTTY) process.stdout.write("\x1B[0m");
|
|
34267
34293
|
};
|
|
34268
34294
|
process.on("exit", cleanup);
|
|
34269
34295
|
let sigintCount = 0;
|
|
@@ -34304,16 +34330,35 @@ 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);
|
|
34310
34350
|
return stack ? `${prefix}: ${message}\n${stack}` : `${prefix}: ${message}`;
|
|
34311
34351
|
}
|
|
34312
|
-
|
|
34313
|
-
|
|
34314
|
-
|
|
34315
|
-
|
|
34316
|
-
|
|
34352
|
+
const TERMINAL_SIGNALS = [
|
|
34353
|
+
"SIGHUP",
|
|
34354
|
+
"SIGTERM",
|
|
34355
|
+
"SIGQUIT"
|
|
34356
|
+
];
|
|
34357
|
+
const SIGNAL_EXIT_CODES = {
|
|
34358
|
+
SIGHUP: 129,
|
|
34359
|
+
SIGTERM: 143,
|
|
34360
|
+
SIGQUIT: 131
|
|
34361
|
+
};
|
|
34317
34362
|
function installCrashHandlers(logger) {
|
|
34318
34363
|
const handleCrash = (kind, err) => {
|
|
34319
34364
|
const { message, stack } = describeError(err);
|
|
@@ -34324,13 +34369,23 @@ function installCrashHandlers(logger) {
|
|
|
34324
34369
|
process.stderr.write(`[veloz init] ${kind}: ${message}\n`);
|
|
34325
34370
|
finalizeAndUploadOnce(logger, "error", { error: formatErrorForMeta(kind, err) }).catch(() => {}).finally(() => process.exit(1));
|
|
34326
34371
|
};
|
|
34372
|
+
const handleSignal = (signal) => {
|
|
34373
|
+
logger.log("signal", `${signal} received`);
|
|
34374
|
+
finalizeAndUploadOnce(logger, "abort", { error: `signal ${signal}` }).catch(() => {}).finally(() => process.exit(SIGNAL_EXIT_CODES[signal]));
|
|
34375
|
+
};
|
|
34327
34376
|
const onUncaught = (err) => handleCrash("uncaughtException", err);
|
|
34328
34377
|
const onUnhandled = (reason) => handleCrash("unhandledRejection", reason);
|
|
34378
|
+
const signalHandlers = TERMINAL_SIGNALS.map((signal) => {
|
|
34379
|
+
const handler = () => handleSignal(signal);
|
|
34380
|
+
process.on(signal, handler);
|
|
34381
|
+
return [signal, handler];
|
|
34382
|
+
});
|
|
34329
34383
|
process.on("uncaughtException", onUncaught);
|
|
34330
34384
|
process.on("unhandledRejection", onUnhandled);
|
|
34331
34385
|
return () => {
|
|
34332
34386
|
process.off("uncaughtException", onUncaught);
|
|
34333
34387
|
process.off("unhandledRejection", onUnhandled);
|
|
34388
|
+
for (const [signal, handler] of signalHandlers) process.off(signal, handler);
|
|
34334
34389
|
};
|
|
34335
34390
|
}
|
|
34336
34391
|
/** Detect repo using the lazy local filesystem layer. */
|
|
@@ -34421,6 +34476,29 @@ async function runInitFlow(c, logger, cwd) {
|
|
|
34421
34476
|
const tui = startTUI();
|
|
34422
34477
|
const { store } = tui;
|
|
34423
34478
|
logger.log("tui", "TUI started");
|
|
34479
|
+
try {
|
|
34480
|
+
return await runInteractiveFlow({
|
|
34481
|
+
tui,
|
|
34482
|
+
store,
|
|
34483
|
+
logger,
|
|
34484
|
+
cwd,
|
|
34485
|
+
analysis,
|
|
34486
|
+
detectedFrameworkId,
|
|
34487
|
+
detectedLabel,
|
|
34488
|
+
forcedFramework
|
|
34489
|
+
});
|
|
34490
|
+
} catch (err) {
|
|
34491
|
+
try {
|
|
34492
|
+
tui.unmount();
|
|
34493
|
+
} catch {}
|
|
34494
|
+
const { message } = describeError(err);
|
|
34495
|
+
process.stderr.write(`\n✗ Erro: ${message}\n`);
|
|
34496
|
+
process.stderr.write(` Logs de depuração: ${logger.dir}\n\n`);
|
|
34497
|
+
throw err;
|
|
34498
|
+
}
|
|
34499
|
+
}
|
|
34500
|
+
async function runInteractiveFlow(opts) {
|
|
34501
|
+
const { tui, store, logger, cwd, analysis, detectedFrameworkId, detectedLabel, forcedFramework } = opts;
|
|
34424
34502
|
store.setDetection({
|
|
34425
34503
|
framework: detectedFrameworkId,
|
|
34426
34504
|
frameworkLabel: detectedLabel,
|
|
@@ -34842,6 +34920,31 @@ async function listOrganizations() {
|
|
|
34842
34920
|
}));
|
|
34843
34921
|
}
|
|
34844
34922
|
/**
|
|
34923
|
+
* Fetch orgs, handling an expired local API key by transparently re-running
|
|
34924
|
+
* the device auth flow inside the TUI. The user sees: "Verificando autenticação…"
|
|
34925
|
+
* → "Sessão expirou, autenticando novamente…" → device-code screen →
|
|
34926
|
+
* org picker, without ever bailing back to the shell.
|
|
34927
|
+
*/
|
|
34928
|
+
async function listOrgsOrReauth(store) {
|
|
34929
|
+
const logger = getSessionLogger();
|
|
34930
|
+
try {
|
|
34931
|
+
return await listOrganizations();
|
|
34932
|
+
} catch (err) {
|
|
34933
|
+
if (!isUnauthorizedError(err)) throw err;
|
|
34934
|
+
logger.log("auth", "stale api key detected (401) — forcing re-login", { message: describeError(err).message });
|
|
34935
|
+
store.setReauthNotice("Sua sessão expirou. Vamos autenticar novamente para continuar.");
|
|
34936
|
+
saveConfig({ apiKey: "" });
|
|
34937
|
+
const config = loadConfig();
|
|
34938
|
+
store.setAuthPhase("browser");
|
|
34939
|
+
const token = await performDeviceAuth(store, config.apiUrl);
|
|
34940
|
+
if (!token) throw new Error("Autenticação cancelada ou expirada.");
|
|
34941
|
+
logger.log("auth", "re-login succeeded — retrying org fetch");
|
|
34942
|
+
saveConfig({ apiKey: token });
|
|
34943
|
+
store.clearReauthNotice();
|
|
34944
|
+
return await listOrganizations();
|
|
34945
|
+
}
|
|
34946
|
+
}
|
|
34947
|
+
/**
|
|
34845
34948
|
* Create a new organization via Better Auth. The slug is derived from the name
|
|
34846
34949
|
* and suffixed with a random token when a collision occurs.
|
|
34847
34950
|
*/
|
|
@@ -34910,8 +35013,9 @@ async function resolveAuthAndOrg(store) {
|
|
|
34910
35013
|
}
|
|
34911
35014
|
} else logger.log("auth", "already authenticated from config");
|
|
34912
35015
|
logger.log("auth", "fetching organizations");
|
|
34913
|
-
const orgs = await
|
|
35016
|
+
const orgs = await listOrgsOrReauth(store);
|
|
34914
35017
|
logger.log("auth", "organizations loaded", { count: orgs.length });
|
|
35018
|
+
config = loadConfig();
|
|
34915
35019
|
let chosen;
|
|
34916
35020
|
if (orgs.length === 0) {
|
|
34917
35021
|
store.setAuthPhase("org-create");
|
|
@@ -34962,7 +35066,7 @@ async function runOrgCreationFlow(store, apiUrl) {
|
|
|
34962
35066
|
//#region src/index.ts
|
|
34963
35067
|
if (process.argv.includes("--mcp")) process.env.VELOZ_MCP = "true";
|
|
34964
35068
|
const cli = Cli.create("veloz", {
|
|
34965
|
-
version: "0.0.0-beta.
|
|
35069
|
+
version: "0.0.0-beta.34",
|
|
34966
35070
|
description: "CLI da plataforma Veloz — deploy rápido para o Brasil",
|
|
34967
35071
|
env: z.object({ VELOZ_ENV: z.string().optional().describe("Ambiente alvo (ex: preview, staging)") }),
|
|
34968
35072
|
mcp: { command: "npx -y onveloz --mcp" }
|