@neetru/cli 2.31.0 → 2.32.1
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/CHANGELOG.md +99 -2
- package/README.md +2 -0
- package/dist/cli-kit/choices.d.ts +33 -0
- package/dist/cli-kit/choices.js +32 -0
- package/dist/cli-kit/command-context.d.ts +98 -0
- package/dist/cli-kit/command-context.js +108 -0
- package/dist/cli-kit/errors.d.ts +79 -0
- package/dist/cli-kit/errors.js +94 -0
- package/dist/cli-kit/index.d.ts +8 -0
- package/dist/cli-kit/index.js +8 -0
- package/dist/cli-kit/suggest.d.ts +74 -0
- package/dist/cli-kit/suggest.js +207 -0
- package/dist/commands/admin/oidc-login.js +1 -1
- package/dist/commands/admin/sdk-credential.js +1 -1
- package/dist/commands/autocomplete.d.ts +1 -1
- package/dist/commands/autocomplete.js +1 -0
- package/dist/commands/bug.d.ts +59 -0
- package/dist/commands/bug.js +118 -6
- package/dist/commands/build.d.ts +24 -1
- package/dist/commands/build.js +195 -73
- package/dist/commands/chat.d.ts +94 -1
- package/dist/commands/chat.js +258 -26
- package/dist/commands/customers.js +1 -1
- package/dist/commands/db-move.js +3 -3
- package/dist/commands/db.js +20 -33
- package/dist/commands/deploy.d.ts +91 -2
- package/dist/commands/deploy.js +423 -78
- package/dist/commands/deployments.js +11 -6
- package/dist/commands/dev-context.js +15 -5
- package/dist/commands/docs-produto.d.ts +25 -0
- package/dist/commands/docs-produto.js +70 -8
- package/dist/commands/doctor.js +36 -1
- package/dist/commands/domains.js +85 -4
- package/dist/commands/env.d.ts +9 -3
- package/dist/commands/env.js +23 -3
- package/dist/commands/infra-read.js +2 -2
- package/dist/commands/init.js +8 -1
- package/dist/commands/login.js +35 -8
- package/dist/commands/logs.js +12 -4
- package/dist/commands/mobile.js +33 -9
- package/dist/commands/new.d.ts +29 -1
- package/dist/commands/new.js +92 -4
- package/dist/commands/open.js +16 -6
- package/dist/commands/ops.js +1 -1
- package/dist/commands/products-db.d.ts +1 -0
- package/dist/commands/products-db.js +41 -8
- package/dist/commands/products.d.ts +17 -3
- package/dist/commands/products.js +86 -18
- package/dist/commands/promote.js +30 -5
- package/dist/commands/secrets.d.ts +91 -0
- package/dist/commands/secrets.js +471 -0
- package/dist/commands/servers.js +8 -5
- package/dist/commands/status.js +2 -2
- package/dist/commands/support.js +5 -3
- package/dist/commands/tenants.js +28 -16
- package/dist/commands/upgrade.d.ts +9 -0
- package/dist/commands/upgrade.js +50 -1
- package/dist/commands/vm-memory.js +1 -0
- package/dist/commands/webhooks.d.ts +2 -0
- package/dist/commands/webhooks.js +9 -3
- package/dist/commands/workspaces.js +42 -11
- package/dist/index.js +70 -14
- package/dist/lib/api-client.d.ts +14 -0
- package/dist/lib/api-client.js +59 -6
- package/dist/lib/api-error.d.ts +14 -0
- package/dist/lib/api-error.js +107 -46
- package/dist/lib/build-targets.d.ts +127 -0
- package/dist/lib/build-targets.js +348 -0
- package/dist/lib/cli-error.d.ts +13 -0
- package/dist/lib/cli-error.js +24 -0
- package/dist/lib/cli-write.d.ts +43 -9
- package/dist/lib/cli-write.js +154 -45
- package/dist/lib/config-schema.d.ts +8 -8
- package/dist/lib/db-local/db-json.d.ts +1 -1
- package/dist/lib/db-local/db-json.js +13 -5
- package/dist/lib/db-local/env.d.ts +15 -3
- package/dist/lib/db-local/env.js +37 -10
- package/dist/lib/db-pipeline/build-deps.d.ts +5 -1
- package/dist/lib/db-pipeline/build-deps.js +23 -3
- package/dist/lib/db-pipeline/types.d.ts +6 -2
- package/dist/lib/db-pipeline/types.js +0 -18
- package/dist/lib/deploy-target-contract.d.ts +152 -0
- package/dist/lib/deploy-target-contract.js +411 -0
- package/dist/lib/env-file-do-build.d.ts +19 -0
- package/dist/lib/env-file-do-build.js +44 -0
- package/dist/lib/envs.d.ts +108 -0
- package/dist/lib/envs.js +127 -0
- package/dist/lib/fs-seguro.d.ts +63 -0
- package/dist/lib/fs-seguro.js +108 -0
- package/dist/lib/inquirer-sob-demanda.d.ts +14 -0
- package/dist/lib/inquirer-sob-demanda.js +18 -0
- package/dist/lib/mobile-local/mobile-json.js +10 -4
- package/dist/lib/pickers.d.ts +44 -7
- package/dist/lib/pickers.js +65 -7
- package/dist/lib/product-docs/sync.d.ts +6 -0
- package/dist/lib/product-docs/sync.js +10 -1
- package/dist/lib/public-secret-scan.d.ts +44 -3
- package/dist/lib/public-secret-scan.js +361 -36
- package/dist/lib/render.d.ts +16 -0
- package/dist/lib/render.js +34 -4
- package/dist/lib/segredo-produto.d.ts +124 -0
- package/dist/lib/segredo-produto.js +336 -0
- package/dist/lib/texto-utf8.d.ts +96 -0
- package/dist/lib/texto-utf8.js +196 -0
- package/package.json +2 -1
- package/dist/cli-kit/format.js.map +0 -1
- package/dist/cli-kit/glyphs.js.map +0 -1
- package/dist/cli-kit/index.js.map +0 -1
- package/dist/cli-kit/palette.js.map +0 -1
- package/dist/commands/add.js.map +0 -1
- package/dist/commands/admin/iam-check.js.map +0 -1
- package/dist/commands/admin/oidc-login.js.map +0 -1
- package/dist/commands/admin/sdk-credential.js.map +0 -1
- package/dist/commands/agent-release.js.map +0 -1
- package/dist/commands/agent-write.js.map +0 -1
- package/dist/commands/ai-models.js.map +0 -1
- package/dist/commands/ai.js.map +0 -1
- package/dist/commands/api-catalog.js.map +0 -1
- package/dist/commands/archive.js.map +0 -1
- package/dist/commands/artifact-registry.js.map +0 -1
- package/dist/commands/audit.js.map +0 -1
- package/dist/commands/auth.js.map +0 -1
- package/dist/commands/autocomplete.js.map +0 -1
- package/dist/commands/billing.js.map +0 -1
- package/dist/commands/bootstrap.js.map +0 -1
- package/dist/commands/bug.js.map +0 -1
- package/dist/commands/build.js.map +0 -1
- package/dist/commands/chat-menu.js.map +0 -1
- package/dist/commands/chat.js.map +0 -1
- package/dist/commands/cloud-run.js.map +0 -1
- package/dist/commands/code.js.map +0 -1
- package/dist/commands/config.js.map +0 -1
- package/dist/commands/customers.js.map +0 -1
- package/dist/commands/db-move.js.map +0 -1
- package/dist/commands/db.js.map +0 -1
- package/dist/commands/deploy.js.map +0 -1
- package/dist/commands/deployments.js.map +0 -1
- package/dist/commands/dev-context.js.map +0 -1
- package/dist/commands/dev-up.js.map +0 -1
- package/dist/commands/dev.js.map +0 -1
- package/dist/commands/docs-produto.js.map +0 -1
- package/dist/commands/docs.js.map +0 -1
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/domains.js.map +0 -1
- package/dist/commands/dr.js.map +0 -1
- package/dist/commands/env.js.map +0 -1
- package/dist/commands/hosting-write.js.map +0 -1
- package/dist/commands/infra-read.js.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/login.js.map +0 -1
- package/dist/commands/logout.js.map +0 -1
- package/dist/commands/logs.js.map +0 -1
- package/dist/commands/mobile.js.map +0 -1
- package/dist/commands/mocks.js.map +0 -1
- package/dist/commands/new.js.map +0 -1
- package/dist/commands/open.js.map +0 -1
- package/dist/commands/ops.js.map +0 -1
- package/dist/commands/products-db.js.map +0 -1
- package/dist/commands/products.js.map +0 -1
- package/dist/commands/promote.js.map +0 -1
- package/dist/commands/publish.js.map +0 -1
- package/dist/commands/schema.js.map +0 -1
- package/dist/commands/servers.js.map +0 -1
- package/dist/commands/smoke.js.map +0 -1
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/support.js.map +0 -1
- package/dist/commands/surface-status.js.map +0 -1
- package/dist/commands/tenants.js.map +0 -1
- package/dist/commands/ui.js.map +0 -1
- package/dist/commands/upgrade.js.map +0 -1
- package/dist/commands/validate.js.map +0 -1
- package/dist/commands/vm-memory.js.map +0 -1
- package/dist/commands/vm.js.map +0 -1
- package/dist/commands/webhooks.js.map +0 -1
- package/dist/commands/whoami.js.map +0 -1
- package/dist/commands/workspaces.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/agent-artifact-url.js.map +0 -1
- package/dist/lib/agent-commands.js.map +0 -1
- package/dist/lib/ai/auth-discovery.js.map +0 -1
- package/dist/lib/ai/context.js.map +0 -1
- package/dist/lib/ai/orchestrator.js.map +0 -1
- package/dist/lib/api-client.js.map +0 -1
- package/dist/lib/api-error.js.map +0 -1
- package/dist/lib/auth.js.map +0 -1
- package/dist/lib/cli-read.js.map +0 -1
- package/dist/lib/cli-write.js.map +0 -1
- package/dist/lib/code-agent-budget.js.map +0 -1
- package/dist/lib/code-agent-files.js.map +0 -1
- package/dist/lib/code-agent-gateway.js.map +0 -1
- package/dist/lib/code-agent-git-tools.js.map +0 -1
- package/dist/lib/code-agent-protocol.js.map +0 -1
- package/dist/lib/code-agent-session.js.map +0 -1
- package/dist/lib/code-agent-settings.js.map +0 -1
- package/dist/lib/code-agent-skills.js.map +0 -1
- package/dist/lib/code-agent-subagents.js.map +0 -1
- package/dist/lib/code-agent-tools.js.map +0 -1
- package/dist/lib/code-agent-tui.js.map +0 -1
- package/dist/lib/code-agent-types.js.map +0 -1
- package/dist/lib/code-agent-ui.js.map +0 -1
- package/dist/lib/code-agent-web-tools.js.map +0 -1
- package/dist/lib/code-agent-write-tools.js.map +0 -1
- package/dist/lib/compose-generator.js.map +0 -1
- package/dist/lib/config-schema.js.map +0 -1
- package/dist/lib/config.js.map +0 -1
- package/dist/lib/db-local/db-json.js.map +0 -1
- package/dist/lib/db-local/env.js.map +0 -1
- package/dist/lib/db-local/fingerprint.js.map +0 -1
- package/dist/lib/db-local/index.js.map +0 -1
- package/dist/lib/db-pipeline/build-deps.js.map +0 -1
- package/dist/lib/db-pipeline/errors.js.map +0 -1
- package/dist/lib/db-pipeline/index.js.map +0 -1
- package/dist/lib/db-pipeline/pipeline.js.map +0 -1
- package/dist/lib/db-pipeline/rehearse.js.map +0 -1
- package/dist/lib/db-pipeline/types.js.map +0 -1
- package/dist/lib/dev-local-context.js.map +0 -1
- package/dist/lib/iam-preflight.js.map +0 -1
- package/dist/lib/mobile-local/index.js.map +0 -1
- package/dist/lib/mobile-local/mobile-json.js.map +0 -1
- package/dist/lib/pickers.js.map +0 -1
- package/dist/lib/product-config.js.map +0 -1
- package/dist/lib/product-docs/check.js.map +0 -1
- package/dist/lib/product-docs/config.js.map +0 -1
- package/dist/lib/product-docs/dates.js.map +0 -1
- package/dist/lib/product-docs/frontmatter.js.map +0 -1
- package/dist/lib/product-docs/git.js.map +0 -1
- package/dist/lib/product-docs/markdown.js.map +0 -1
- package/dist/lib/product-docs/ops.js.map +0 -1
- package/dist/lib/product-docs/structure.js.map +0 -1
- package/dist/lib/product-docs/sync.js.map +0 -1
- package/dist/lib/product-docs/taxonomy.js.map +0 -1
- package/dist/lib/product-docs/templates.js.map +0 -1
- package/dist/lib/public-secret-scan.js.map +0 -1
- package/dist/lib/render.js.map +0 -1
- package/dist/lib/schema-cache.js.map +0 -1
- package/dist/lib/sse.js.map +0 -1
- package/dist/lib/telemetry.js.map +0 -1
- package/dist/lib/token-resolver.js.map +0 -1
- package/dist/lib/url-allowlist.js.map +0 -1
- package/dist/lib/version-check.js.map +0 -1
- package/dist/utils/logger.js.map +0 -1
- package/dist/utils/logo.js.map +0 -1
- package/dist/utils/safe-exit.js.map +0 -1
- package/dist/utils/spinner-registry.js.map +0 -1
- package/dist/version.js.map +0 -1
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
export type PackageManagerName = 'npm' | 'pnpm' | 'yarn' | 'bun';
|
|
2
|
+
export interface PackageManagerInfo {
|
|
3
|
+
name: PackageManagerName;
|
|
4
|
+
/**
|
|
5
|
+
* Diretório onde o `install` deve rodar. Em monorepo é a RAIZ do workspace
|
|
6
|
+
* (onde mora o lockfile), não o diretório do app — `pnpm install` dentro de
|
|
7
|
+
* `apps/web` sem o lockfile por perto instala um projeto solto e quebra os
|
|
8
|
+
* links dos pacotes internos do workspace.
|
|
9
|
+
*/
|
|
10
|
+
rootDir: string;
|
|
11
|
+
/** De onde veio a decisão — entra no log pra o dev conseguir auditar. */
|
|
12
|
+
source: 'campo packageManager' | 'lockfile' | 'default';
|
|
13
|
+
/** Lockfile encontrado (basename), quando `source === 'lockfile'`. */
|
|
14
|
+
lockfile?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* `packageManager: "pnpm@9.1.0"` (padrão corepack) → `'pnpm'`.
|
|
18
|
+
* Qualquer coisa fora do enum conhecido devolve `null` em vez de chutar.
|
|
19
|
+
*/
|
|
20
|
+
export declare function parseCampoPackageManager(valor: unknown): PackageManagerName | null;
|
|
21
|
+
/**
|
|
22
|
+
* Um diretório só conta como RAIZ DE WORKSPACE se ele se declara como tal.
|
|
23
|
+
*
|
|
24
|
+
* Isso é a trava contra o pior modo de falha da subida na árvore: um app em
|
|
25
|
+
* `~/projetos/meu-app` sem lockfile próprio NÃO pode herdar o
|
|
26
|
+
* `package-lock.json` que por acaso existe em `~/projetos` — instalar lá
|
|
27
|
+
* mexeria num projeto que não é o do build.
|
|
28
|
+
*/
|
|
29
|
+
export declare function ehRaizDeWorkspace(dir: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Descobre QUAL gerenciador de pacote usar e ONDE rodar o `install`, partindo
|
|
32
|
+
* do diretório do app.
|
|
33
|
+
*
|
|
34
|
+
* Ordem de decisão (da mais forte pra mais fraca):
|
|
35
|
+
* 1. `packageManager` no package.json do próprio app (corepack) — é uma
|
|
36
|
+
* declaração explícita do dono do projeto;
|
|
37
|
+
* 2. lockfile NO PRÓPRIO diretório do app (repo de app único);
|
|
38
|
+
* 3. subindo a árvore: o primeiro ancestral que tem lockfile **e** se declara
|
|
39
|
+
* raiz de workspace (`pnpm-workspace.yaml` ou `workspaces` no package.json).
|
|
40
|
+
* O `packageManager` desse ancestral, se houver, vence o lockfile dele;
|
|
41
|
+
* 4. nada encontrado → `npm` no próprio diretório do app (comportamento
|
|
42
|
+
* histórico — não quebra ninguém que já usava o CLI).
|
|
43
|
+
*
|
|
44
|
+
* A subida PARA no diretório que contém `.git` (inclusive): fora do repo não
|
|
45
|
+
* existe workspace que interesse a este build.
|
|
46
|
+
*/
|
|
47
|
+
export declare function detectPackageManager(appDir: string): PackageManagerInfo;
|
|
48
|
+
export interface Comando {
|
|
49
|
+
cmd: string;
|
|
50
|
+
args: string[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* `install` NÃO-DESTRUTIVO por gerenciador.
|
|
54
|
+
*
|
|
55
|
+
* bug_93f984a já tinha estabelecido a regra pro npm: nunca `npm ci` (apaga
|
|
56
|
+
* node_modules e briga com os file locks do `next dev` no Windows). A mesma
|
|
57
|
+
* regra vale pros outros — nada de `--frozen-lockfile` nem `--immutable`, que
|
|
58
|
+
* falham de cara quando o dev acabou de mexer num package.json do workspace.
|
|
59
|
+
*/
|
|
60
|
+
export declare function comandoInstall(pm: PackageManagerName): Comando;
|
|
61
|
+
/** Roda um script do package.json (`build`, `start`, …). */
|
|
62
|
+
export declare function comandoRunScript(pm: PackageManagerName, script: string): Comando;
|
|
63
|
+
/**
|
|
64
|
+
* Executa um binário de `node_modules/.bin` (`next`, `vite`, `tsc`…).
|
|
65
|
+
*
|
|
66
|
+
* Usado só no caminho Windows do bug_0cf14fba/bug_893891f, onde o CLI desmonta
|
|
67
|
+
* o prefixo de env estilo Unix do script e roda o comando real direto. Com pnpm
|
|
68
|
+
* o `npx` NÃO serve: os binários ficam atrás do store de links do pnpm e o npx
|
|
69
|
+
* acabaria BAIXANDO o pacote do registry em vez de usar o local.
|
|
70
|
+
*/
|
|
71
|
+
export declare function comandoExecBin(pm: PackageManagerName, bin: string, args: string[]): Comando;
|
|
72
|
+
export interface LayoutStandalone {
|
|
73
|
+
/** `<appDir>/.next/standalone` — sempre a RAIZ do tar. */
|
|
74
|
+
standaloneDir: string;
|
|
75
|
+
/**
|
|
76
|
+
* Caminho POSIX do app DENTRO do standalone. `''` em repo de app único;
|
|
77
|
+
* `'apps/web'` num monorepo com `outputFileTracingRoot` na raiz.
|
|
78
|
+
*/
|
|
79
|
+
appPrefix: string;
|
|
80
|
+
/** Entrypoint relativo à raiz do tar: `server.js` ou `apps/web/server.js`. */
|
|
81
|
+
entrypoint: string;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Acha ONDE o `server.js` do Next.js ficou dentro de `.next/standalone`.
|
|
85
|
+
*
|
|
86
|
+
* Em repo de app único ele está na raiz; em monorepo o Next.js aninha o app sob
|
|
87
|
+
* o caminho dele relativo ao `outputFileTracingRoot` (`apps/web/server.js`).
|
|
88
|
+
* Não dá pra deduzir esse prefixo do `next.config` (o `outputFileTracingRoot`
|
|
89
|
+
* pode ser implícito, vindo da detecção de workspace do próprio Next.js), então
|
|
90
|
+
* a verdade é a árvore PÓS-BUILD — a mesma lógica do `isStandaloneBuildDir`.
|
|
91
|
+
*
|
|
92
|
+
* Varredura em largura, pulando `node_modules` (pacote dependente pode ter um
|
|
93
|
+
* `server.js` qualquer e envenenar a busca). Entre candidatos, ganha o que
|
|
94
|
+
* TAMBÉM tem um diretório `.next` ao lado — é o par que o Next.js sempre emite
|
|
95
|
+
* junto (`server.js` + `.next/` com os chunks de servidor). Empate real resolve
|
|
96
|
+
* pelo mais raso e, em seguida, por ordem alfabética (determinismo: dois builds
|
|
97
|
+
* da mesma árvore têm que dar o mesmo tarball).
|
|
98
|
+
*
|
|
99
|
+
* Devolve `null` quando não há standalone nenhum (build não-standalone) ou
|
|
100
|
+
* quando há standalone mas nenhum `server.js` — nesse segundo caso quem chama
|
|
101
|
+
* precisa FALHAR, nunca empacotar um tarball sem entrypoint.
|
|
102
|
+
*/
|
|
103
|
+
export declare function resolveStandaloneLayout(appDir: string): LayoutStandalone | null;
|
|
104
|
+
/**
|
|
105
|
+
* Resolve o `-C` do `tar` que faz `.next/static` e `public` caírem DENTRO do
|
|
106
|
+
* prefixo do app no tarball.
|
|
107
|
+
*
|
|
108
|
+
* O Next.js não copia nenhum dos dois pro standalone (limitação conhecida), e o
|
|
109
|
+
* runtime os procura ao lado do `server.js` — ou seja, dentro do prefixo do app,
|
|
110
|
+
* não na raiz do tar. Era exatamente isso que saía errado em monorepo
|
|
111
|
+
* (bug_678ddc98): o tar levava `./.next/static` e `./public` na raiz enquanto o
|
|
112
|
+
* server rodava de `apps/web/`, e o app subia sem CSS/JS e sem os estáticos.
|
|
113
|
+
*
|
|
114
|
+
* O truque pra gravar o membro já aninhado SEM `--transform` (GNU) nem `-s`
|
|
115
|
+
* (bsdtar), que não são portáveis entre os dois tars: o `appPrefix` é, por
|
|
116
|
+
* construção, `path.relative(outputFileTracingRoot, appDir)` — então o mesmo
|
|
117
|
+
* caminho EXISTE no disco a partir da raiz de tracing. Basta dar `-C <raiz de
|
|
118
|
+
* tracing>` e pedir o membro `apps/web/.next/static`, que o tar grava com o
|
|
119
|
+
* caminho completo.
|
|
120
|
+
*
|
|
121
|
+
* Devolve `null` quando o prefixo não casa com o disco (não deveria acontecer —
|
|
122
|
+
* é a trava contra empacotar caminho inventado).
|
|
123
|
+
*/
|
|
124
|
+
export declare function baseDeInjecaoNoTar(appDir: string, appPrefix: string): {
|
|
125
|
+
chdir: string;
|
|
126
|
+
prefixo: string;
|
|
127
|
+
} | null;
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detecção de ALVO de build — o diretório do app, o gerenciador de pacote e o
|
|
3
|
+
* layout do output `standalone` do Next.js.
|
|
4
|
+
*
|
|
5
|
+
* bug_678ddc988497475d9160d714a5a10992: o `neetru build` nasceu assumindo
|
|
6
|
+
* "um repo = um app na raiz = npm". Três premissas, todas cravadas:
|
|
7
|
+
*
|
|
8
|
+
* 1. `cwd = process.cwd()` (build.ts:905) — não dava pra apontar pra um app
|
|
9
|
+
* dentro de `apps/<app>` sem `cd`;
|
|
10
|
+
* 2. `npm install` (build.ts:616) e `npm run build` (build.ts:664) literais —
|
|
11
|
+
* num repo pnpm/yarn isso resolve o workspace ERRADO (ou nem resolve);
|
|
12
|
+
* 3. `tarStandalone` assumia `.next/standalone/server.js` no TOPO e injetava
|
|
13
|
+
* `.next/static`/`public` na RAIZ do tar (build.ts:412-443), e o
|
|
14
|
+
* entrypoint era a string fixa `'server.js'` (build.ts:673).
|
|
15
|
+
*
|
|
16
|
+
* Num monorepo (pnpm workspaces + Turborepo) o Next.js, ao tracejar a partir
|
|
17
|
+
* de `outputFileTracingRoot`, ANINHA o app dentro do standalone:
|
|
18
|
+
*
|
|
19
|
+
* apps/web/.next/standalone/
|
|
20
|
+
* node_modules/… ← fica na RAIZ do standalone (tracejado/hoisted)
|
|
21
|
+
* packages/ui/… ← pacotes do workspace que o app importa
|
|
22
|
+
* apps/web/server.js ← o entrypoint REAL, aninhado
|
|
23
|
+
* apps/web/.next/…
|
|
24
|
+
*
|
|
25
|
+
* Por isso NÃO dá pra "re-enraizar" o tar em `apps/web`: `server.js` resolve
|
|
26
|
+
* `node_modules` subindo a árvore, e esses `node_modules` moram ACIMA dele.
|
|
27
|
+
* O formato correto é preservar a árvore inteira do standalone e apontar o
|
|
28
|
+
* entrypoint pro caminho aninhado (`apps/web/server.js`), injetando
|
|
29
|
+
* `.next/static` e `public` DENTRO do prefixo do app.
|
|
30
|
+
*
|
|
31
|
+
* Este módulo é propositalmente puro (só `fs` de leitura, zero subprocesso)
|
|
32
|
+
* pra ser testável sem rodar build nenhum.
|
|
33
|
+
*/
|
|
34
|
+
import * as fs from 'node:fs';
|
|
35
|
+
import * as path from 'node:path';
|
|
36
|
+
/**
|
|
37
|
+
* Lockfiles conhecidos, em ordem de PRECEDÊNCIA dentro de um mesmo diretório.
|
|
38
|
+
*
|
|
39
|
+
* pnpm/yarn/bun vêm antes de npm de propósito: `package-lock.json` é o que mais
|
|
40
|
+
* aparece por acidente (um `npm install` distraído num repo pnpm gera um), então
|
|
41
|
+
* ele é o sinal MENOS confiável quando há concorrência. O campo `packageManager`
|
|
42
|
+
* do package.json (padrão corepack) ganha de todos — ver `detectPackageManager`.
|
|
43
|
+
*/
|
|
44
|
+
const LOCKFILES = [
|
|
45
|
+
{ file: 'pnpm-lock.yaml', name: 'pnpm' },
|
|
46
|
+
{ file: 'yarn.lock', name: 'yarn' },
|
|
47
|
+
{ file: 'bun.lockb', name: 'bun' },
|
|
48
|
+
{ file: 'bun.lock', name: 'bun' },
|
|
49
|
+
{ file: 'package-lock.json', name: 'npm' },
|
|
50
|
+
{ file: 'npm-shrinkwrap.json', name: 'npm' },
|
|
51
|
+
];
|
|
52
|
+
/** Teto de subida na árvore — monorepo nenhum aninha app a 12 níveis da raiz. */
|
|
53
|
+
const MAX_SUBIDA = 12;
|
|
54
|
+
function existe(p) {
|
|
55
|
+
try {
|
|
56
|
+
fs.statSync(p);
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function lerJson(p) {
|
|
64
|
+
try {
|
|
65
|
+
return JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* `packageManager: "pnpm@9.1.0"` (padrão corepack) → `'pnpm'`.
|
|
73
|
+
* Qualquer coisa fora do enum conhecido devolve `null` em vez de chutar.
|
|
74
|
+
*/
|
|
75
|
+
export function parseCampoPackageManager(valor) {
|
|
76
|
+
if (typeof valor !== 'string')
|
|
77
|
+
return null;
|
|
78
|
+
const nome = valor.trim().split('@')[0].toLowerCase();
|
|
79
|
+
if (nome === 'npm' || nome === 'pnpm' || nome === 'yarn' || nome === 'bun')
|
|
80
|
+
return nome;
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Um diretório só conta como RAIZ DE WORKSPACE se ele se declara como tal.
|
|
85
|
+
*
|
|
86
|
+
* Isso é a trava contra o pior modo de falha da subida na árvore: um app em
|
|
87
|
+
* `~/projetos/meu-app` sem lockfile próprio NÃO pode herdar o
|
|
88
|
+
* `package-lock.json` que por acaso existe em `~/projetos` — instalar lá
|
|
89
|
+
* mexeria num projeto que não é o do build.
|
|
90
|
+
*/
|
|
91
|
+
export function ehRaizDeWorkspace(dir) {
|
|
92
|
+
if (existe(path.join(dir, 'pnpm-workspace.yaml')))
|
|
93
|
+
return true;
|
|
94
|
+
const pkg = lerJson(path.join(dir, 'package.json'));
|
|
95
|
+
if (!pkg)
|
|
96
|
+
return false;
|
|
97
|
+
const ws = pkg.workspaces;
|
|
98
|
+
// npm/yarn/bun aceitam `workspaces: []` OU `workspaces: { packages: [] }`.
|
|
99
|
+
if (Array.isArray(ws))
|
|
100
|
+
return true;
|
|
101
|
+
if (ws && typeof ws === 'object' && Array.isArray(ws.packages))
|
|
102
|
+
return true;
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
function lockfileDoDir(dir) {
|
|
106
|
+
for (const lf of LOCKFILES) {
|
|
107
|
+
if (existe(path.join(dir, lf.file)))
|
|
108
|
+
return lf;
|
|
109
|
+
}
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Descobre QUAL gerenciador de pacote usar e ONDE rodar o `install`, partindo
|
|
114
|
+
* do diretório do app.
|
|
115
|
+
*
|
|
116
|
+
* Ordem de decisão (da mais forte pra mais fraca):
|
|
117
|
+
* 1. `packageManager` no package.json do próprio app (corepack) — é uma
|
|
118
|
+
* declaração explícita do dono do projeto;
|
|
119
|
+
* 2. lockfile NO PRÓPRIO diretório do app (repo de app único);
|
|
120
|
+
* 3. subindo a árvore: o primeiro ancestral que tem lockfile **e** se declara
|
|
121
|
+
* raiz de workspace (`pnpm-workspace.yaml` ou `workspaces` no package.json).
|
|
122
|
+
* O `packageManager` desse ancestral, se houver, vence o lockfile dele;
|
|
123
|
+
* 4. nada encontrado → `npm` no próprio diretório do app (comportamento
|
|
124
|
+
* histórico — não quebra ninguém que já usava o CLI).
|
|
125
|
+
*
|
|
126
|
+
* A subida PARA no diretório que contém `.git` (inclusive): fora do repo não
|
|
127
|
+
* existe workspace que interesse a este build.
|
|
128
|
+
*/
|
|
129
|
+
export function detectPackageManager(appDir) {
|
|
130
|
+
const campoLocal = parseCampoPackageManager(lerJson(path.join(appDir, 'package.json'))?.packageManager);
|
|
131
|
+
const lockLocal = lockfileDoDir(appDir);
|
|
132
|
+
// O campo local é a declaração mais explícita que existe — mas o `rootDir`
|
|
133
|
+
// ainda pode ser um ancestral (app de monorepo que declara `packageManager`
|
|
134
|
+
// e deixa o lockfile na raiz). Por isso o rootDir é resolvido à parte.
|
|
135
|
+
if (lockLocal) {
|
|
136
|
+
return {
|
|
137
|
+
name: campoLocal ?? lockLocal.name,
|
|
138
|
+
rootDir: appDir,
|
|
139
|
+
source: campoLocal ? 'campo packageManager' : 'lockfile',
|
|
140
|
+
lockfile: campoLocal ? undefined : lockLocal.file,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
let dir = appDir;
|
|
144
|
+
for (let i = 0; i < MAX_SUBIDA; i++) {
|
|
145
|
+
const temGit = existe(path.join(dir, '.git'));
|
|
146
|
+
const pai = path.dirname(dir);
|
|
147
|
+
if (temGit || pai === dir)
|
|
148
|
+
break;
|
|
149
|
+
dir = pai;
|
|
150
|
+
const lock = lockfileDoDir(dir);
|
|
151
|
+
if (!lock) {
|
|
152
|
+
if (existe(path.join(dir, '.git')))
|
|
153
|
+
break;
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
// Lockfile de ancestral só vale se o ancestral É raiz de workspace — ver
|
|
157
|
+
// `ehRaizDeWorkspace` pro porquê (não sequestrar projeto vizinho).
|
|
158
|
+
if (!ehRaizDeWorkspace(dir))
|
|
159
|
+
break;
|
|
160
|
+
const campoRaiz = parseCampoPackageManager(lerJson(path.join(dir, 'package.json'))?.packageManager);
|
|
161
|
+
return {
|
|
162
|
+
name: campoLocal ?? campoRaiz ?? lock.name,
|
|
163
|
+
rootDir: dir,
|
|
164
|
+
source: campoLocal || campoRaiz ? 'campo packageManager' : 'lockfile',
|
|
165
|
+
lockfile: campoLocal || campoRaiz ? undefined : lock.file,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
name: campoLocal ?? 'npm',
|
|
170
|
+
rootDir: appDir,
|
|
171
|
+
source: campoLocal ? 'campo packageManager' : 'default',
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* `install` NÃO-DESTRUTIVO por gerenciador.
|
|
176
|
+
*
|
|
177
|
+
* bug_93f984a já tinha estabelecido a regra pro npm: nunca `npm ci` (apaga
|
|
178
|
+
* node_modules e briga com os file locks do `next dev` no Windows). A mesma
|
|
179
|
+
* regra vale pros outros — nada de `--frozen-lockfile` nem `--immutable`, que
|
|
180
|
+
* falham de cara quando o dev acabou de mexer num package.json do workspace.
|
|
181
|
+
*/
|
|
182
|
+
export function comandoInstall(pm) {
|
|
183
|
+
switch (pm) {
|
|
184
|
+
case 'pnpm':
|
|
185
|
+
return { cmd: 'pnpm', args: ['install', '--no-frozen-lockfile'] };
|
|
186
|
+
case 'yarn':
|
|
187
|
+
// Serve pro yarn classic (1.x) e pro berry — ambos aceitam `install` puro.
|
|
188
|
+
return { cmd: 'yarn', args: ['install'] };
|
|
189
|
+
case 'bun':
|
|
190
|
+
return { cmd: 'bun', args: ['install'] };
|
|
191
|
+
case 'npm':
|
|
192
|
+
default:
|
|
193
|
+
return { cmd: 'npm', args: ['install', '--no-save', '--no-audit', '--no-fund'] };
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/** Roda um script do package.json (`build`, `start`, …). */
|
|
197
|
+
export function comandoRunScript(pm, script) {
|
|
198
|
+
switch (pm) {
|
|
199
|
+
case 'pnpm':
|
|
200
|
+
return { cmd: 'pnpm', args: ['run', script] };
|
|
201
|
+
case 'yarn':
|
|
202
|
+
return { cmd: 'yarn', args: ['run', script] };
|
|
203
|
+
case 'bun':
|
|
204
|
+
return { cmd: 'bun', args: ['run', script] };
|
|
205
|
+
case 'npm':
|
|
206
|
+
default:
|
|
207
|
+
return { cmd: 'npm', args: ['run', script] };
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Executa um binário de `node_modules/.bin` (`next`, `vite`, `tsc`…).
|
|
212
|
+
*
|
|
213
|
+
* Usado só no caminho Windows do bug_0cf14fba/bug_893891f, onde o CLI desmonta
|
|
214
|
+
* o prefixo de env estilo Unix do script e roda o comando real direto. Com pnpm
|
|
215
|
+
* o `npx` NÃO serve: os binários ficam atrás do store de links do pnpm e o npx
|
|
216
|
+
* acabaria BAIXANDO o pacote do registry em vez de usar o local.
|
|
217
|
+
*/
|
|
218
|
+
export function comandoExecBin(pm, bin, args) {
|
|
219
|
+
switch (pm) {
|
|
220
|
+
case 'pnpm':
|
|
221
|
+
return { cmd: 'pnpm', args: ['exec', bin, ...args] };
|
|
222
|
+
case 'yarn':
|
|
223
|
+
return { cmd: 'yarn', args: ['exec', bin, ...args] };
|
|
224
|
+
case 'bun':
|
|
225
|
+
return { cmd: 'bunx', args: [bin, ...args] };
|
|
226
|
+
case 'npm':
|
|
227
|
+
default:
|
|
228
|
+
return { cmd: 'npx', args: [bin, ...args] };
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/** Profundidade máxima de varredura dentro do standalone à procura do server.js. */
|
|
232
|
+
const MAX_PROFUNDIDADE_STANDALONE = 6;
|
|
233
|
+
/**
|
|
234
|
+
* Acha ONDE o `server.js` do Next.js ficou dentro de `.next/standalone`.
|
|
235
|
+
*
|
|
236
|
+
* Em repo de app único ele está na raiz; em monorepo o Next.js aninha o app sob
|
|
237
|
+
* o caminho dele relativo ao `outputFileTracingRoot` (`apps/web/server.js`).
|
|
238
|
+
* Não dá pra deduzir esse prefixo do `next.config` (o `outputFileTracingRoot`
|
|
239
|
+
* pode ser implícito, vindo da detecção de workspace do próprio Next.js), então
|
|
240
|
+
* a verdade é a árvore PÓS-BUILD — a mesma lógica do `isStandaloneBuildDir`.
|
|
241
|
+
*
|
|
242
|
+
* Varredura em largura, pulando `node_modules` (pacote dependente pode ter um
|
|
243
|
+
* `server.js` qualquer e envenenar a busca). Entre candidatos, ganha o que
|
|
244
|
+
* TAMBÉM tem um diretório `.next` ao lado — é o par que o Next.js sempre emite
|
|
245
|
+
* junto (`server.js` + `.next/` com os chunks de servidor). Empate real resolve
|
|
246
|
+
* pelo mais raso e, em seguida, por ordem alfabética (determinismo: dois builds
|
|
247
|
+
* da mesma árvore têm que dar o mesmo tarball).
|
|
248
|
+
*
|
|
249
|
+
* Devolve `null` quando não há standalone nenhum (build não-standalone) ou
|
|
250
|
+
* quando há standalone mas nenhum `server.js` — nesse segundo caso quem chama
|
|
251
|
+
* precisa FALHAR, nunca empacotar um tarball sem entrypoint.
|
|
252
|
+
*/
|
|
253
|
+
export function resolveStandaloneLayout(appDir) {
|
|
254
|
+
const standaloneDir = path.join(appDir, '.next', 'standalone');
|
|
255
|
+
try {
|
|
256
|
+
if (!fs.statSync(standaloneDir).isDirectory())
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
const candidatos = [];
|
|
263
|
+
const fila = [
|
|
264
|
+
{ dir: standaloneDir, prefix: '', profundidade: 0 },
|
|
265
|
+
];
|
|
266
|
+
while (fila.length > 0) {
|
|
267
|
+
const atual = fila.shift();
|
|
268
|
+
let entradas;
|
|
269
|
+
try {
|
|
270
|
+
entradas = fs.readdirSync(atual.dir, { withFileTypes: true });
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
const temServer = entradas.some((e) => e.name === 'server.js' && e.isFile());
|
|
276
|
+
if (temServer) {
|
|
277
|
+
candidatos.push({
|
|
278
|
+
prefix: atual.prefix,
|
|
279
|
+
temNext: entradas.some((e) => e.name === '.next' && e.isDirectory()),
|
|
280
|
+
profundidade: atual.profundidade,
|
|
281
|
+
});
|
|
282
|
+
// Não desce mais por este ramo: achado o app, o que houver abaixo é
|
|
283
|
+
// output dele, não outro app.
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
if (atual.profundidade >= MAX_PROFUNDIDADE_STANDALONE)
|
|
287
|
+
continue;
|
|
288
|
+
for (const e of entradas) {
|
|
289
|
+
if (!e.isDirectory())
|
|
290
|
+
continue;
|
|
291
|
+
// `node_modules` nunca hospeda o app; `.next` abaixo da raiz é output.
|
|
292
|
+
if (e.name === 'node_modules' || e.name === '.next')
|
|
293
|
+
continue;
|
|
294
|
+
fila.push({
|
|
295
|
+
dir: path.join(atual.dir, e.name),
|
|
296
|
+
prefix: atual.prefix ? `${atual.prefix}/${e.name}` : e.name,
|
|
297
|
+
profundidade: atual.profundidade + 1,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if (candidatos.length === 0)
|
|
302
|
+
return null;
|
|
303
|
+
candidatos.sort((a, b) => {
|
|
304
|
+
if (a.temNext !== b.temNext)
|
|
305
|
+
return a.temNext ? -1 : 1;
|
|
306
|
+
if (a.profundidade !== b.profundidade)
|
|
307
|
+
return a.profundidade - b.profundidade;
|
|
308
|
+
return a.prefix.localeCompare(b.prefix);
|
|
309
|
+
});
|
|
310
|
+
const vencedor = candidatos[0];
|
|
311
|
+
return {
|
|
312
|
+
standaloneDir,
|
|
313
|
+
appPrefix: vencedor.prefix,
|
|
314
|
+
entrypoint: vencedor.prefix ? `${vencedor.prefix}/server.js` : 'server.js',
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Resolve o `-C` do `tar` que faz `.next/static` e `public` caírem DENTRO do
|
|
319
|
+
* prefixo do app no tarball.
|
|
320
|
+
*
|
|
321
|
+
* O Next.js não copia nenhum dos dois pro standalone (limitação conhecida), e o
|
|
322
|
+
* runtime os procura ao lado do `server.js` — ou seja, dentro do prefixo do app,
|
|
323
|
+
* não na raiz do tar. Era exatamente isso que saía errado em monorepo
|
|
324
|
+
* (bug_678ddc98): o tar levava `./.next/static` e `./public` na raiz enquanto o
|
|
325
|
+
* server rodava de `apps/web/`, e o app subia sem CSS/JS e sem os estáticos.
|
|
326
|
+
*
|
|
327
|
+
* O truque pra gravar o membro já aninhado SEM `--transform` (GNU) nem `-s`
|
|
328
|
+
* (bsdtar), que não são portáveis entre os dois tars: o `appPrefix` é, por
|
|
329
|
+
* construção, `path.relative(outputFileTracingRoot, appDir)` — então o mesmo
|
|
330
|
+
* caminho EXISTE no disco a partir da raiz de tracing. Basta dar `-C <raiz de
|
|
331
|
+
* tracing>` e pedir o membro `apps/web/.next/static`, que o tar grava com o
|
|
332
|
+
* caminho completo.
|
|
333
|
+
*
|
|
334
|
+
* Devolve `null` quando o prefixo não casa com o disco (não deveria acontecer —
|
|
335
|
+
* é a trava contra empacotar caminho inventado).
|
|
336
|
+
*/
|
|
337
|
+
export function baseDeInjecaoNoTar(appDir, appPrefix) {
|
|
338
|
+
if (!appPrefix)
|
|
339
|
+
return { chdir: appDir, prefixo: '' };
|
|
340
|
+
const niveis = appPrefix.split('/').filter(Boolean);
|
|
341
|
+
const chdir = path.resolve(appDir, ...niveis.map(() => '..'));
|
|
342
|
+
// A igualdade é a prova de que `<chdir>/<appPrefix>` é o MESMO diretório que
|
|
343
|
+
// `appDir` — sem isso o tar gravaria um caminho que não existe.
|
|
344
|
+
if (path.resolve(chdir, ...niveis) !== path.resolve(appDir))
|
|
345
|
+
return null;
|
|
346
|
+
return { chdir, prefixo: `${appPrefix}/` };
|
|
347
|
+
}
|
|
348
|
+
//# sourceMappingURL=build-targets.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Saída do processo a partir de um `NeetruCliError` (bug_89d2497e, etapa 3).
|
|
3
|
+
*
|
|
4
|
+
* O cli-kit monta o erro (puro); aqui ele é impresso — JSON no stdout em
|
|
5
|
+
* `--json`, texto humano no stderr fora dele — e o processo sai com o código
|
|
6
|
+
* de saída DO ERRO. Ponto único: `handleApiError`, `resolveStepUp`, a validação
|
|
7
|
+
* de `--env` e o trap global de `index.ts` passam por aqui.
|
|
8
|
+
*/
|
|
9
|
+
import { NeetruCliError } from '../cli-kit/errors.js';
|
|
10
|
+
/** Imprime o erro e devolve o código de saída — sem encerrar. */
|
|
11
|
+
export declare function emitCliError(error: NeetruCliError, json?: boolean): number;
|
|
12
|
+
/** Imprime o erro e encerra com o código de saída dele. Nunca retorna. */
|
|
13
|
+
export declare function exitWithCliError(error: NeetruCliError, json?: boolean): never;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Saída do processo a partir de um `NeetruCliError` (bug_89d2497e, etapa 3).
|
|
3
|
+
*
|
|
4
|
+
* O cli-kit monta o erro (puro); aqui ele é impresso — JSON no stdout em
|
|
5
|
+
* `--json`, texto humano no stderr fora dele — e o processo sai com o código
|
|
6
|
+
* de saída DO ERRO. Ponto único: `handleApiError`, `resolveStepUp`, a validação
|
|
7
|
+
* de `--env` e o trap global de `index.ts` passam por aqui.
|
|
8
|
+
*/
|
|
9
|
+
import { renderCliError } from '../cli-kit/errors.js';
|
|
10
|
+
import { log } from '../utils/logger.js';
|
|
11
|
+
import { safeExit } from '../utils/safe-exit.js';
|
|
12
|
+
/** Imprime o erro e devolve o código de saída — sem encerrar. */
|
|
13
|
+
export function emitCliError(error, json) {
|
|
14
|
+
if (json)
|
|
15
|
+
console.log(JSON.stringify(error.toJSON()));
|
|
16
|
+
else
|
|
17
|
+
log.error(renderCliError(error));
|
|
18
|
+
return error.exit;
|
|
19
|
+
}
|
|
20
|
+
/** Imprime o erro e encerra com o código de saída dele. Nunca retorna. */
|
|
21
|
+
export function exitWithCliError(error, json) {
|
|
22
|
+
return safeExit(emitCliError(error, json));
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=cli-error.js.map
|
package/dist/lib/cli-write.d.ts
CHANGED
|
@@ -18,6 +18,27 @@ export declare function saveMfaSession(mfaSessionToken: string, expiresAt: strin
|
|
|
18
18
|
* apagado junto com o Bearer token.
|
|
19
19
|
*/
|
|
20
20
|
export declare function clearMfaSession(): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* uid dono de um token de sessão MFA. O Core emite
|
|
23
|
+
* `<uid_base64url>.<issuedAt_hex>.<hmac_sha256_hex>` (`createCliMfaSessionToken`
|
|
24
|
+
* em `src/lib/auth-mfa-session.ts`): o uid é a parte ASSINADA, não segredo — o
|
|
25
|
+
* servidor só aceita a sessão se ele bater com o uid do Bearer. `null` se o
|
|
26
|
+
* formato não for reconhecido.
|
|
27
|
+
*/
|
|
28
|
+
export declare function mfaSessionOwnerUid(token: string): string | null;
|
|
29
|
+
/**
|
|
30
|
+
* Descarta a sessão MFA salva quando ela não é do `uid` que acabou de logar.
|
|
31
|
+
*
|
|
32
|
+
* A8 (2026-10-13): `neetru login` com outra conta trocava o Bearer mas deixava
|
|
33
|
+
* o `mfa-session.json` da conta anterior. O Core recusa sessão de outro uid,
|
|
34
|
+
* então TODO comando destrutivo tomava 401 `mfa_required` por até 1h (e, antes
|
|
35
|
+
* do conserto da precedência em `resolveStepUp`, nem `--mfa-token` salvava).
|
|
36
|
+
* Sessão de dono desconhecido (arquivo corrompido, formato não reconhecido)
|
|
37
|
+
* também sai — o servidor recusaria do mesmo jeito. Sessão do MESMO uid fica
|
|
38
|
+
* (re-login na mesma conta não deve exigir TOTP de novo). Retorna `true` se
|
|
39
|
+
* apagou.
|
|
40
|
+
*/
|
|
41
|
+
export declare function discardMfaSessionOfOtherUid(uid: string): Promise<boolean>;
|
|
21
42
|
export interface ConfirmOptions {
|
|
22
43
|
/** `--yes` / `--force` — pula a confirmação (modo script/CI). */
|
|
23
44
|
yes?: boolean;
|
|
@@ -25,6 +46,17 @@ export interface ConfirmOptions {
|
|
|
25
46
|
/** Saída em JSON — não imprime prompt humano. */
|
|
26
47
|
json?: boolean;
|
|
27
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* O que dizer quando a confirmação não pode ser perguntada (P105 /
|
|
51
|
+
* bug_89d2497e). Cita só as flags de confirmação que o comando EM EXECUÇÃO
|
|
52
|
+
* declara: o texto fixo "use --yes (ou --force)" chegava a 8 comandos que
|
|
53
|
+
* declaram `--yes` mas não `--force` (medido na árvore do Commander em
|
|
54
|
+
* 2026-10-18: `servers pgbouncer sync-userlist`, `products memory set`,
|
|
55
|
+
* `vm memory set`, `db move start|abort|decommission`, `promote execute`,
|
|
56
|
+
* `mobile revoke`) — quem seguisse com `--force` tomava "unknown option".
|
|
57
|
+
* Sem nenhuma das duas (ou fora do Commander, como no menu), não cita flag.
|
|
58
|
+
*/
|
|
59
|
+
export declare function confirmationAdvice(modo: 'json' | 'nao-interativo'): string;
|
|
28
60
|
/**
|
|
29
61
|
* Gate de confirmação pra operações DESTRUTIVAS (suspend, deactivate, delete,
|
|
30
62
|
* rollback, archive, yank). Se `--yes`/`--force` foi passado, retorna sem
|
|
@@ -58,19 +90,21 @@ export interface StepUpOptions extends ConfirmOptions {
|
|
|
58
90
|
}
|
|
59
91
|
/**
|
|
60
92
|
* Resolve o que uma operação destrutiva TOP-TIER precisa mandar pro servidor:
|
|
61
|
-
* - `headers`: `X-Neetru-MFA-
|
|
62
|
-
* (
|
|
93
|
+
* - `headers`: `X-Neetru-MFA-Token` (TOTP fresco) OU `X-Neetru-MFA-Session`
|
|
94
|
+
* (sessão de 1h) e/ou `X-Neetru-Dry-Run`.
|
|
63
95
|
*
|
|
64
96
|
* Ordem de preferência:
|
|
65
97
|
* 1. dry-run: sem MFA, só `X-Neetru-Dry-Run: true`.
|
|
66
|
-
* 2.
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* 3.
|
|
70
|
-
*
|
|
71
|
-
*
|
|
98
|
+
* 2. `--mfa-token` explícito: manda `X-Neetru-MFA-Token` — e também a sessão
|
|
99
|
+
* salva, se houver (o Core tenta a sessão antes e não gasta o TOTP à toa).
|
|
100
|
+
* O código NUNCA é descartado em favor da sessão (A8).
|
|
101
|
+
* 3. Sessão de 1h salva localmente: usa `X-Neetru-MFA-Session` sem pedir
|
|
102
|
+
* TOTP. Silencioso — o operador não precisa saber que a sessão está ativa.
|
|
103
|
+
* 4. Prompt interativo do TOTP. Em `--json`/não-interativo sem código nem
|
|
104
|
+
* sessão, encerra com instrução clara — o servidor recusaria de qualquer
|
|
105
|
+
* forma (fail-closed).
|
|
72
106
|
*
|
|
73
|
-
* feature mfa-session (2026-06-12): o item
|
|
107
|
+
* feature mfa-session (2026-06-12): o item 3 elimina o re-prompt TOTP a cada
|
|
74
108
|
* comando destrutivo quando o operador já rodou `neetru auth mfa-session`.
|
|
75
109
|
*/
|
|
76
110
|
export declare function resolveStepUp(opts: StepUpOptions): Promise<{
|