@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,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contrato de compatibilidade `--target` × runtime × flags do `neetru deploy`.
|
|
3
|
+
*
|
|
4
|
+
* bug_a8375858 (o caso que motivou o módulo): um produto `runtime: nextjs`
|
|
5
|
+
* rodou `deploy --target workspace --artifact <tarball de 20 MB>`. A CLI leu o
|
|
6
|
+
* tarball como TEXTO (`readFile(…, 'utf8')`), o gzip virou ~35 MB de U+FFFD,
|
|
7
|
+
* subiu pro GCS como `source-*.ts`, e o Core respondeu
|
|
8
|
+
* **413 "Falha ao resolver a source do deploy"** — que manda o dev caçar
|
|
9
|
+
* TAMANHO quando o problema era TIPO DE ALVO. Dois uploads de 35 MB e meia
|
|
10
|
+
* hora perdida.
|
|
11
|
+
*
|
|
12
|
+
* ─── O padrão, em uma frase ─────────────────────────────────────────────────
|
|
13
|
+
*
|
|
14
|
+
* "Uma flag (ou campo do neetru.config.json) cujo significado depende do
|
|
15
|
+
* `--target` é aceita pela CLI, silenciosamente reinterpretada ou
|
|
16
|
+
* descartada, e só aparece como erro do Core DEPOIS do passo caro — ou não
|
|
17
|
+
* aparece nunca."
|
|
18
|
+
*
|
|
19
|
+
* Antes deste módulo o padrão era combatido um `if` por vez (bug_ec17af08
|
|
20
|
+
* cobriu cloud-run+`--artifact`; bug_b919e729 cobriu o espelho disso no Core),
|
|
21
|
+
* e cada combinação nova nascia desprotegida. Aqui ele vira UMA TABELA: cada
|
|
22
|
+
* alvo declara o que RECEBE, o que REJEITA (erro antes de qualquer trabalho
|
|
23
|
+
* caro) e o que DESCARTA (aviso — a flag some mas o deploy segue certo).
|
|
24
|
+
*
|
|
25
|
+
* ─── Regra pra classificar erro vs aviso (a que o código segue) ──────────────
|
|
26
|
+
*
|
|
27
|
+
* ERRO — a flag diz O QUE subir (pacote, URL de artefato, imagem) e o alvo
|
|
28
|
+
* subiria OUTRA coisa:
|
|
29
|
+
* · workspace sobe só um handler .ts → erro em `--artifact` com
|
|
30
|
+
* pacote, `--artifact-url`, `--artifact-sha256`, `--image`,
|
|
31
|
+
* `--registry`, `--registry-repo`;
|
|
32
|
+
* · cloud-run sobe só imagem → erro em `--artifact`,
|
|
33
|
+
* `--artifact-url`, `--artifact-sha256`.
|
|
34
|
+
* Nesses casos o Core também recusaria o payload (superRefine do
|
|
35
|
+
* `deploy-request.ts`), só que DEPOIS do build/upload caro.
|
|
36
|
+
* AVISO — a flag NÃO diz o que subir (servidor, porta, stack, env-file,
|
|
37
|
+
* domínio, build local, empacotamento local, `runtime` do config):
|
|
38
|
+
* ela é descartada e o deploy segue subindo a coisa certa.
|
|
39
|
+
*
|
|
40
|
+
* EXCEÇÃO REGISTRADA — vm + `--image` / `--registry` / `--registry-repo` é
|
|
41
|
+
* AVISO, embora a flag diga o que subir. O deploy vm sobe o tarball (o body
|
|
42
|
+
* nem tem campo de imagem, e o Core não recusa nada por isso), e virar erro
|
|
43
|
+
* quebraria script/CI que passa o mesmo conjunto de flags genéricas pra
|
|
44
|
+
* mais de um alvo. Decisão tomada na revisão do PR #74 (2026-10-12).
|
|
45
|
+
*
|
|
46
|
+
* O pacote que chega ao workspace por um caminho que a tabela não enxerga —
|
|
47
|
+
* campo `source` do neetru.config.json, ou extensão que nenhuma lista prevê —
|
|
48
|
+
* é recusado depois da leitura, PELO CONTEÚDO (`farejarConteudoDePacote`),
|
|
49
|
+
* com o mesmo código de erro. O teto de 2 MiB fica só pra handler grande.
|
|
50
|
+
*
|
|
51
|
+
* Módulo propositalmente PURO (zero fs, zero rede, zero processo) pra ser
|
|
52
|
+
* testável sem rodar deploy nenhum: quem lê o arquivo é o `deploy.ts`.
|
|
53
|
+
*/
|
|
54
|
+
/** Alvos aceitos pelo `neetru deploy` (espelha `DEPLOY_TARGETS` do Core). */
|
|
55
|
+
export type DeployTarget = 'workspace' | 'cloud-run' | 'vm';
|
|
56
|
+
/** Runtimes declaráveis no `neetru.config.json` (espelha `RUNTIMES`). */
|
|
57
|
+
export type ProductRuntime = 'nextjs' | 'node-api';
|
|
58
|
+
/**
|
|
59
|
+
* Teto ABSOLUTO da source de um deploy workspace, em bytes UTF-8.
|
|
60
|
+
*
|
|
61
|
+
* Espelha `WORKSPACE_SOURCE_MAX_BYTES` do Core
|
|
62
|
+
* (`src/lib/schemas/deploy-request.ts`), que o aplica nos DOIS caminhos:
|
|
63
|
+
* `source` inline (zod `.max()`) e `sourceUrl` baixada do GCS
|
|
64
|
+
* (`fetchWorkspaceSource` → `SourceFetchError(413, 'source_too_large')`).
|
|
65
|
+
*
|
|
66
|
+
* A CLI tinha só o limiar de 1.5 MiB do bug_eae4bef6, que decide *inline vs
|
|
67
|
+
* GCS* — e nunca o teto do Core. Resultado: tudo entre 2 MiB e infinito subia
|
|
68
|
+
* pro GCS e voltava como 413 opaco. Conhecer o teto aqui é o que permite
|
|
69
|
+
* recusar local com o número real.
|
|
70
|
+
*/
|
|
71
|
+
export declare const WORKSPACE_SOURCE_MAX_BYTES: number;
|
|
72
|
+
/** `true` quando o caminho aponta um pacote de aplicação, não um handler. */
|
|
73
|
+
export declare function pareceArquivoDePacote(caminho: string): boolean;
|
|
74
|
+
/** Quantos bytes do começo do arquivo o farejador olha. */
|
|
75
|
+
export declare const BYTES_FAREJADOS: number;
|
|
76
|
+
/**
|
|
77
|
+
* Olha os BYTES CRUS do começo da source de um deploy workspace e diz se ela é
|
|
78
|
+
* pacote/binário. Devolve o motivo em PT-BR, ou `null` quando parece texto.
|
|
79
|
+
*
|
|
80
|
+
* Por que pelo conteúdo: a recusa por extensão só olhava `--artifact`. Um
|
|
81
|
+
* pacote apontado pelo `source` do neetru.config.json, ou com extensão que a
|
|
82
|
+
* lista não prevê, só batia no teto de 2 MiB. E lido como UTF-8 um binário
|
|
83
|
+
* incha ~1,75x (cada byte inválido vira U+FFFD, 3 bytes), então um pacote
|
|
84
|
+
* abaixo de ~1,15 MiB passava no teto, subia e voltava do Core como erro de
|
|
85
|
+
* COMPILAÇÃO do esbuild, que não diz a causa (revisão do PR #74).
|
|
86
|
+
*
|
|
87
|
+
* Tem que receber os bytes CRUS: depois de decodificado em UTF-8 o gzip já
|
|
88
|
+
* virou U+FFFD e a assinatura sumiu.
|
|
89
|
+
*/
|
|
90
|
+
export declare function farejarConteudoDePacote(inicio: Uint8Array): string | null;
|
|
91
|
+
/** Flags do `neetru deploy` que mudam de sentido conforme o `--target`. */
|
|
92
|
+
export interface DeployFlagsSnapshot {
|
|
93
|
+
artifact?: string;
|
|
94
|
+
artifactUrl?: string;
|
|
95
|
+
artifactSha256?: string;
|
|
96
|
+
image?: string;
|
|
97
|
+
registry?: string;
|
|
98
|
+
registryRepo?: string;
|
|
99
|
+
buildLocal?: boolean;
|
|
100
|
+
server?: string;
|
|
101
|
+
port?: number;
|
|
102
|
+
stack?: string;
|
|
103
|
+
/** Lido só em vm e cloud-run (`loadEnvFile`); workspace nunca olha. */
|
|
104
|
+
envFile?: string;
|
|
105
|
+
/** Usado só em vm (subdomínio do vhost). */
|
|
106
|
+
domain?: string;
|
|
107
|
+
/** Empacotamento local do tarball — só existe em vm. */
|
|
108
|
+
localArtifact?: boolean;
|
|
109
|
+
}
|
|
110
|
+
export interface DeployContractError {
|
|
111
|
+
/** Código estável — vai pro `{ok:false,error}` do `--json`. */
|
|
112
|
+
code: string;
|
|
113
|
+
/** Mensagem PT-BR que diz O QUE FAZER, não só o que está errado. */
|
|
114
|
+
message: string;
|
|
115
|
+
}
|
|
116
|
+
export interface DeployContractVerdict {
|
|
117
|
+
errors: DeployContractError[];
|
|
118
|
+
warnings: string[];
|
|
119
|
+
}
|
|
120
|
+
export interface DeployContractInput {
|
|
121
|
+
target: DeployTarget;
|
|
122
|
+
/** `runtime` do neetru.config.json. Ausente = sem opinião (não bloqueia). */
|
|
123
|
+
runtime?: string;
|
|
124
|
+
flags: DeployFlagsSnapshot;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Avalia a combinação `target × runtime × flags` ANTES de qualquer build,
|
|
128
|
+
* upload ou chamada ao Core.
|
|
129
|
+
*
|
|
130
|
+
* Fail-open pro desconhecido: `runtime` ausente ou fora do enum nunca bloqueia
|
|
131
|
+
* (repos anteriores ao campo continuam deployando). Fail-closed só no que está
|
|
132
|
+
* provado impossível.
|
|
133
|
+
*/
|
|
134
|
+
export declare function checkDeployTargetContract(input: DeployContractInput): DeployContractVerdict;
|
|
135
|
+
/** De onde veio o arquivo de source de um deploy workspace. */
|
|
136
|
+
export type OrigemDaSource = 'artifact' | 'config' | 'padrao';
|
|
137
|
+
/**
|
|
138
|
+
* Mensagem da recusa de uma source de workspace que é pacote, achada pelo nome
|
|
139
|
+
* ou pelo conteúdo DEPOIS da leitura. Usa o mesmo código de erro da recusa por
|
|
140
|
+
* `--artifact` (`artifact_nao_eh_handler_workspace`): é o mesmo erro, achado
|
|
141
|
+
* por outra porta.
|
|
142
|
+
*/
|
|
143
|
+
export declare function mensagemSourceNaoEhHandler(relPath: string, motivo: string, origem: OrigemDaSource): string;
|
|
144
|
+
/**
|
|
145
|
+
* Mensagem do estouro do teto de source do workspace, usada depois que a
|
|
146
|
+
* source já foi lida e o farejador de pacote não a recusou: na prática, um
|
|
147
|
+
* handler que ficou grande demais.
|
|
148
|
+
*
|
|
149
|
+
* Diz o número real, o teto real, e o alvo certo — em vez do 413 do Core, que
|
|
150
|
+
* diz só "Falha ao resolver a source do deploy".
|
|
151
|
+
*/
|
|
152
|
+
export declare function mensagemSourceAcimaDoTeto(relPath: string, bytes: number, runtime?: string): string;
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contrato de compatibilidade `--target` × runtime × flags do `neetru deploy`.
|
|
3
|
+
*
|
|
4
|
+
* bug_a8375858 (o caso que motivou o módulo): um produto `runtime: nextjs`
|
|
5
|
+
* rodou `deploy --target workspace --artifact <tarball de 20 MB>`. A CLI leu o
|
|
6
|
+
* tarball como TEXTO (`readFile(…, 'utf8')`), o gzip virou ~35 MB de U+FFFD,
|
|
7
|
+
* subiu pro GCS como `source-*.ts`, e o Core respondeu
|
|
8
|
+
* **413 "Falha ao resolver a source do deploy"** — que manda o dev caçar
|
|
9
|
+
* TAMANHO quando o problema era TIPO DE ALVO. Dois uploads de 35 MB e meia
|
|
10
|
+
* hora perdida.
|
|
11
|
+
*
|
|
12
|
+
* ─── O padrão, em uma frase ─────────────────────────────────────────────────
|
|
13
|
+
*
|
|
14
|
+
* "Uma flag (ou campo do neetru.config.json) cujo significado depende do
|
|
15
|
+
* `--target` é aceita pela CLI, silenciosamente reinterpretada ou
|
|
16
|
+
* descartada, e só aparece como erro do Core DEPOIS do passo caro — ou não
|
|
17
|
+
* aparece nunca."
|
|
18
|
+
*
|
|
19
|
+
* Antes deste módulo o padrão era combatido um `if` por vez (bug_ec17af08
|
|
20
|
+
* cobriu cloud-run+`--artifact`; bug_b919e729 cobriu o espelho disso no Core),
|
|
21
|
+
* e cada combinação nova nascia desprotegida. Aqui ele vira UMA TABELA: cada
|
|
22
|
+
* alvo declara o que RECEBE, o que REJEITA (erro antes de qualquer trabalho
|
|
23
|
+
* caro) e o que DESCARTA (aviso — a flag some mas o deploy segue certo).
|
|
24
|
+
*
|
|
25
|
+
* ─── Regra pra classificar erro vs aviso (a que o código segue) ──────────────
|
|
26
|
+
*
|
|
27
|
+
* ERRO — a flag diz O QUE subir (pacote, URL de artefato, imagem) e o alvo
|
|
28
|
+
* subiria OUTRA coisa:
|
|
29
|
+
* · workspace sobe só um handler .ts → erro em `--artifact` com
|
|
30
|
+
* pacote, `--artifact-url`, `--artifact-sha256`, `--image`,
|
|
31
|
+
* `--registry`, `--registry-repo`;
|
|
32
|
+
* · cloud-run sobe só imagem → erro em `--artifact`,
|
|
33
|
+
* `--artifact-url`, `--artifact-sha256`.
|
|
34
|
+
* Nesses casos o Core também recusaria o payload (superRefine do
|
|
35
|
+
* `deploy-request.ts`), só que DEPOIS do build/upload caro.
|
|
36
|
+
* AVISO — a flag NÃO diz o que subir (servidor, porta, stack, env-file,
|
|
37
|
+
* domínio, build local, empacotamento local, `runtime` do config):
|
|
38
|
+
* ela é descartada e o deploy segue subindo a coisa certa.
|
|
39
|
+
*
|
|
40
|
+
* EXCEÇÃO REGISTRADA — vm + `--image` / `--registry` / `--registry-repo` é
|
|
41
|
+
* AVISO, embora a flag diga o que subir. O deploy vm sobe o tarball (o body
|
|
42
|
+
* nem tem campo de imagem, e o Core não recusa nada por isso), e virar erro
|
|
43
|
+
* quebraria script/CI que passa o mesmo conjunto de flags genéricas pra
|
|
44
|
+
* mais de um alvo. Decisão tomada na revisão do PR #74 (2026-10-12).
|
|
45
|
+
*
|
|
46
|
+
* O pacote que chega ao workspace por um caminho que a tabela não enxerga —
|
|
47
|
+
* campo `source` do neetru.config.json, ou extensão que nenhuma lista prevê —
|
|
48
|
+
* é recusado depois da leitura, PELO CONTEÚDO (`farejarConteudoDePacote`),
|
|
49
|
+
* com o mesmo código de erro. O teto de 2 MiB fica só pra handler grande.
|
|
50
|
+
*
|
|
51
|
+
* Módulo propositalmente PURO (zero fs, zero rede, zero processo) pra ser
|
|
52
|
+
* testável sem rodar deploy nenhum: quem lê o arquivo é o `deploy.ts`.
|
|
53
|
+
*/
|
|
54
|
+
/**
|
|
55
|
+
* Teto ABSOLUTO da source de um deploy workspace, em bytes UTF-8.
|
|
56
|
+
*
|
|
57
|
+
* Espelha `WORKSPACE_SOURCE_MAX_BYTES` do Core
|
|
58
|
+
* (`src/lib/schemas/deploy-request.ts`), que o aplica nos DOIS caminhos:
|
|
59
|
+
* `source` inline (zod `.max()`) e `sourceUrl` baixada do GCS
|
|
60
|
+
* (`fetchWorkspaceSource` → `SourceFetchError(413, 'source_too_large')`).
|
|
61
|
+
*
|
|
62
|
+
* A CLI tinha só o limiar de 1.5 MiB do bug_eae4bef6, que decide *inline vs
|
|
63
|
+
* GCS* — e nunca o teto do Core. Resultado: tudo entre 2 MiB e infinito subia
|
|
64
|
+
* pro GCS e voltava como 413 opaco. Conhecer o teto aqui é o que permite
|
|
65
|
+
* recusar local com o número real.
|
|
66
|
+
*/
|
|
67
|
+
export const WORKSPACE_SOURCE_MAX_BYTES = 2 * 1024 * 1024;
|
|
68
|
+
/** Bytes em KB inteiros, como as mensagens deste módulo mostram (`2048 KB`). */
|
|
69
|
+
function emKB(bytes) {
|
|
70
|
+
return `${Math.round(bytes / 1024)} KB`;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Extensões que identificam um PACOTE (tarball, zip, compactado), nunca um
|
|
74
|
+
* handler `.ts`. Só entra o que é inequívoco. A lista é a porta BARATA (nem
|
|
75
|
+
* lê o arquivo); a porta que não depende do nome é `farejarConteudoDePacote`.
|
|
76
|
+
*
|
|
77
|
+
* `.gz`/`.bz2`/`.xz`/`.zst` sozinhos também entram (revisão do PR #74): um
|
|
78
|
+
* arquivo compactado nunca é um handler, com ou sem `.tar` antes.
|
|
79
|
+
*/
|
|
80
|
+
const EXTENSOES_DE_PACOTE = [
|
|
81
|
+
'.tar.gz',
|
|
82
|
+
'.tar.bz2',
|
|
83
|
+
'.tar.xz',
|
|
84
|
+
'.tar.zst',
|
|
85
|
+
'.tgz',
|
|
86
|
+
'.tbz2',
|
|
87
|
+
'.txz',
|
|
88
|
+
'.tzst',
|
|
89
|
+
'.tar',
|
|
90
|
+
'.zip',
|
|
91
|
+
'.gz',
|
|
92
|
+
'.bz2',
|
|
93
|
+
'.xz',
|
|
94
|
+
'.zst',
|
|
95
|
+
'.7z',
|
|
96
|
+
'.rar',
|
|
97
|
+
];
|
|
98
|
+
/** `true` quando o caminho aponta um pacote de aplicação, não um handler. */
|
|
99
|
+
export function pareceArquivoDePacote(caminho) {
|
|
100
|
+
const normalizado = caminho.trim().toLowerCase().replace(/\\/g, '/');
|
|
101
|
+
const base = normalizado.slice(normalizado.lastIndexOf('/') + 1);
|
|
102
|
+
return EXTENSOES_DE_PACOTE.some((ext) => base.endsWith(ext));
|
|
103
|
+
}
|
|
104
|
+
/** Quantos bytes do começo do arquivo o farejador olha. */
|
|
105
|
+
export const BYTES_FAREJADOS = 8 * 1024;
|
|
106
|
+
/**
|
|
107
|
+
* Assinaturas ("magic bytes") de pacote. Uso a assinatura COMPLETA quando os
|
|
108
|
+
* primeiros bytes são texto imprimível (`Rar!`, `7z`, `BZh`), pra que um
|
|
109
|
+
* handler que por acaso comece com esse texto não seja recusado.
|
|
110
|
+
*/
|
|
111
|
+
const ASSINATURAS_DE_PACOTE = [
|
|
112
|
+
{ formato: 'gzip', bytes: [0x1f, 0x8b] },
|
|
113
|
+
{ formato: 'zip', bytes: [0x50, 0x4b, 0x03, 0x04] },
|
|
114
|
+
{ formato: 'zip', bytes: [0x50, 0x4b, 0x05, 0x06] }, // zip vazio
|
|
115
|
+
{ formato: 'xz', bytes: [0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00] },
|
|
116
|
+
{ formato: 'zstd', bytes: [0x28, 0xb5, 0x2f, 0xfd] },
|
|
117
|
+
{ formato: '7z', bytes: [0x37, 0x7a, 0xbc, 0xaf, 0x27, 0x1c] },
|
|
118
|
+
{ formato: 'rar', bytes: [0x52, 0x61, 0x72, 0x21, 0x1a, 0x07] },
|
|
119
|
+
// tar sem compressão: o campo `magic` do cabeçalho, no offset 257 — POSIX
|
|
120
|
+
// `ustar\0` ou GNU `ustar \0`. COM o NUL de propósito (confirmação final do
|
|
121
|
+
// PR #74): só "ustar" casava texto comum — um comentário com "ajustar" ou
|
|
122
|
+
// "custar" em que `ustar` caísse no byte 257 era recusado como "arquivo tar".
|
|
123
|
+
// Texto nunca tem NUL; tar de verdade sempre tem.
|
|
124
|
+
{ formato: 'tar', bytes: [0x75, 0x73, 0x74, 0x61, 0x72, 0x00], offset: 257 },
|
|
125
|
+
{ formato: 'tar', bytes: [0x75, 0x73, 0x74, 0x61, 0x72, 0x20, 0x20, 0x00], offset: 257 },
|
|
126
|
+
];
|
|
127
|
+
function comecaCom(bytes, assinatura, offset = 0) {
|
|
128
|
+
if (bytes.length < offset + assinatura.length)
|
|
129
|
+
return false;
|
|
130
|
+
return assinatura.every((b, i) => bytes[offset + i] === b);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* bzip2: "BZh" + nível ('1'..'9') + magia de bloco (`31 41 59 26 53 59`) ou de
|
|
134
|
+
* fim de stream (`17 72 45 38 50 90`). Só "BZh" seria texto comum.
|
|
135
|
+
*/
|
|
136
|
+
function pareceBzip2(bytes) {
|
|
137
|
+
if (!comecaCom(bytes, [0x42, 0x5a, 0x68]))
|
|
138
|
+
return false;
|
|
139
|
+
if (bytes.length < 10 || bytes[3] < 0x31 || bytes[3] > 0x39)
|
|
140
|
+
return false;
|
|
141
|
+
return (comecaCom(bytes, [0x31, 0x41, 0x59, 0x26, 0x53, 0x59], 4) ||
|
|
142
|
+
comecaCom(bytes, [0x17, 0x72, 0x45, 0x38, 0x50, 0x90], 4));
|
|
143
|
+
}
|
|
144
|
+
/** Formato do pacote cuja assinatura abre `inicio`, ou `null` se nenhuma casa. */
|
|
145
|
+
function formatoDePacote(inicio) {
|
|
146
|
+
for (const a of ASSINATURAS_DE_PACOTE) {
|
|
147
|
+
if (comecaCom(inicio, a.bytes, a.offset))
|
|
148
|
+
return a.formato;
|
|
149
|
+
}
|
|
150
|
+
if (pareceBzip2(inicio))
|
|
151
|
+
return 'bzip2';
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Olha os BYTES CRUS do começo da source de um deploy workspace e diz se ela é
|
|
156
|
+
* pacote/binário. Devolve o motivo em PT-BR, ou `null` quando parece texto.
|
|
157
|
+
*
|
|
158
|
+
* Por que pelo conteúdo: a recusa por extensão só olhava `--artifact`. Um
|
|
159
|
+
* pacote apontado pelo `source` do neetru.config.json, ou com extensão que a
|
|
160
|
+
* lista não prevê, só batia no teto de 2 MiB. E lido como UTF-8 um binário
|
|
161
|
+
* incha ~1,75x (cada byte inválido vira U+FFFD, 3 bytes), então um pacote
|
|
162
|
+
* abaixo de ~1,15 MiB passava no teto, subia e voltava do Core como erro de
|
|
163
|
+
* COMPILAÇÃO do esbuild, que não diz a causa (revisão do PR #74).
|
|
164
|
+
*
|
|
165
|
+
* Tem que receber os bytes CRUS: depois de decodificado em UTF-8 o gzip já
|
|
166
|
+
* virou U+FFFD e a assinatura sumiu.
|
|
167
|
+
*/
|
|
168
|
+
export function farejarConteudoDePacote(inicio) {
|
|
169
|
+
const formato = formatoDePacote(inicio);
|
|
170
|
+
if (formato)
|
|
171
|
+
return `o conteúdo tem a assinatura de um arquivo ${formato}`;
|
|
172
|
+
if (inicio.subarray(0, BYTES_FAREJADOS).includes(0x00)) {
|
|
173
|
+
return (`o conteúdo tem byte NUL nos primeiros ${emKB(BYTES_FAREJADOS)}, então é binário e ` +
|
|
174
|
+
'não texto (ou foi salvo em UTF-16, e o Core só lê UTF-8)');
|
|
175
|
+
}
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
/** Nome da flag como o dev digita — entra nas mensagens. */
|
|
179
|
+
const NOME_DA_FLAG = {
|
|
180
|
+
artifact: '--artifact',
|
|
181
|
+
artifactUrl: '--artifact-url',
|
|
182
|
+
artifactSha256: '--artifact-sha256',
|
|
183
|
+
image: '--image',
|
|
184
|
+
registry: '--registry',
|
|
185
|
+
registryRepo: '--registry-repo',
|
|
186
|
+
buildLocal: '--build-local',
|
|
187
|
+
server: '--server',
|
|
188
|
+
port: '--port',
|
|
189
|
+
stack: '--stack',
|
|
190
|
+
envFile: '--env-file',
|
|
191
|
+
domain: '--domain',
|
|
192
|
+
localArtifact: '--local-artifact',
|
|
193
|
+
};
|
|
194
|
+
function presente(flags, k) {
|
|
195
|
+
const v = flags[k];
|
|
196
|
+
if (v === undefined || v === null)
|
|
197
|
+
return false;
|
|
198
|
+
if (typeof v === 'string')
|
|
199
|
+
return v.length > 0;
|
|
200
|
+
if (typeof v === 'boolean')
|
|
201
|
+
return v;
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
function listaDeFlags(flags, chaves) {
|
|
205
|
+
return chaves.filter((k) => presente(flags, k));
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Texto do destino `vm` com o artefato que o dev JÁ tem na mão — a mensagem
|
|
209
|
+
* precisa poder ser copiada e colada, não só explicar o conceito.
|
|
210
|
+
*/
|
|
211
|
+
function linhaDeComandoVm(flags) {
|
|
212
|
+
// Entre aspas: caminho do Windows com espaço quebrava o copia-e-cola.
|
|
213
|
+
if (flags.artifact)
|
|
214
|
+
return ` neetru deploy --target vm --artifact "${flags.artifact}"`;
|
|
215
|
+
if (flags.artifactUrl) {
|
|
216
|
+
const sha = flags.artifactSha256 ? ` --artifact-sha256 ${flags.artifactSha256}` : '';
|
|
217
|
+
return ` neetru deploy --target vm --artifact-url ${flags.artifactUrl}${sha}`;
|
|
218
|
+
}
|
|
219
|
+
return ' neetru deploy --target vm --artifact <tarball .tar.gz>';
|
|
220
|
+
}
|
|
221
|
+
function linhaDeComandoCloudRun(flags) {
|
|
222
|
+
if (flags.image)
|
|
223
|
+
return ` neetru deploy --target cloud-run --image ${flags.image}`;
|
|
224
|
+
if (flags.registry)
|
|
225
|
+
return ` neetru deploy --target cloud-run --registry ${flags.registry}`;
|
|
226
|
+
return ' neetru deploy --target cloud-run --image <uri>';
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* O que cada alvo RECEBE — frase curta reusada em várias mensagens pra que o
|
|
230
|
+
* dev leia a mesma definição em qualquer erro.
|
|
231
|
+
*/
|
|
232
|
+
const O_QUE_O_ALVO_RECEBE = {
|
|
233
|
+
workspace: 'UM handler .ts (o Core compila com esbuild e roda no runtime compartilhado)',
|
|
234
|
+
'cloud-run': 'UMA imagem de container OCI já buildada e pushada',
|
|
235
|
+
vm: 'UM tarball de aplicação já buildado (artefato + sha256 + stack)',
|
|
236
|
+
};
|
|
237
|
+
// ─── checagem ────────────────────────────────────────────────────────────────
|
|
238
|
+
/**
|
|
239
|
+
* Avalia a combinação `target × runtime × flags` ANTES de qualquer build,
|
|
240
|
+
* upload ou chamada ao Core.
|
|
241
|
+
*
|
|
242
|
+
* Fail-open pro desconhecido: `runtime` ausente ou fora do enum nunca bloqueia
|
|
243
|
+
* (repos anteriores ao campo continuam deployando). Fail-closed só no que está
|
|
244
|
+
* provado impossível.
|
|
245
|
+
*/
|
|
246
|
+
export function checkDeployTargetContract(input) {
|
|
247
|
+
const { target, runtime, flags } = input;
|
|
248
|
+
const errors = [];
|
|
249
|
+
const warnings = [];
|
|
250
|
+
const rejeitar = (chaves, code, corpo) => {
|
|
251
|
+
const achadas = listaDeFlags(flags, chaves);
|
|
252
|
+
if (achadas.length === 0)
|
|
253
|
+
return;
|
|
254
|
+
errors.push({ code, message: corpo(achadas.map((k) => NOME_DA_FLAG[k]).join(' / ')) });
|
|
255
|
+
};
|
|
256
|
+
const avisarDescarte = (chaves) => {
|
|
257
|
+
for (const k of listaDeFlags(flags, chaves)) {
|
|
258
|
+
warnings.push(`${NOME_DA_FLAG[k]} não tem efeito em --target ${target} — a flag é descartada. ` +
|
|
259
|
+
`O alvo ${target} recebe ${O_QUE_O_ALVO_RECEBE[target]}.`);
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
if (target === 'workspace') {
|
|
263
|
+
// ── runtime ──────────────────────────────────────────────────────────
|
|
264
|
+
// Uma app Next.js não roda no workspace: o Core compila a source com
|
|
265
|
+
// esbuild em `platform:'browser'`, `external: []`, `format:'iife'`, teto de
|
|
266
|
+
// 2 MiB, e executa num `vm.Context` (`_workspace-build-helpers.ts`).
|
|
267
|
+
//
|
|
268
|
+
// Mas isto é AVISO, não erro (revisão do PR #74, 2026-10-12): `runtime` é
|
|
269
|
+
// OBRIGATÓRIO no config (`config-schema.ts`) e o `neetru init` grava
|
|
270
|
+
// `nextjs` por padrão. Erro duro aqui quebraria todo produto recém-criado
|
|
271
|
+
// que faz deploy de handler no workspace — e a única saída seria apagar o
|
|
272
|
+
// `runtime`, o que faz `validate`/`doctor`/`publish` recusarem o config. O
|
|
273
|
+
// caso do bug_a8375858 (pacote no workspace) continua ERRO por duas portas
|
|
274
|
+
// que não dependem do runtime: a extensão de `--artifact` (logo abaixo) e
|
|
275
|
+
// o CONTEÚDO da source, farejado depois da leitura em `runWorkspaceDeploy`
|
|
276
|
+
// (`farejarConteudoDePacote`), que pega também o `source` do config.
|
|
277
|
+
if (runtime === 'nextjs') {
|
|
278
|
+
warnings.push('--target workspace com runtime "nextjs": o workspace roda ' +
|
|
279
|
+
`${O_QUE_O_ALVO_RECEBE.workspace}, não uma aplicação Next.js com servidor, ` +
|
|
280
|
+
'node_modules e estáticos. Se o que você quer subir é o app, o alvo é ' +
|
|
281
|
+
'`--target vm` (ou `--target cloud-run` com imagem).');
|
|
282
|
+
}
|
|
283
|
+
else if (runtime === 'node-api') {
|
|
284
|
+
// `neetru init --type node-api` scaffolda um servidor Fastify
|
|
285
|
+
// (`start: node dist/index.js`), que também não é um handler. Mas
|
|
286
|
+
// nada impede que um repo marcado `node-api` tenha um handler.ts de
|
|
287
|
+
// verdade, então aqui é AVISO: não quebra quem já deploya assim.
|
|
288
|
+
warnings.push('--target workspace com runtime "node-api": o workspace espera UM handler .ts, ' +
|
|
289
|
+
'não o servidor Fastify que `neetru init --type node-api` scaffolda. ' +
|
|
290
|
+
'Se o arquivo apontado é o entrypoint da aplicação, o alvo é `--target vm`.');
|
|
291
|
+
}
|
|
292
|
+
// ── artefato de aplicação apontado como se fosse handler ─────────────
|
|
293
|
+
// O erro central do bug_a8375858. Vale mesmo sem `runtime` no config.
|
|
294
|
+
if (flags.artifact && pareceArquivoDePacote(flags.artifact)) {
|
|
295
|
+
errors.push({
|
|
296
|
+
code: 'artifact_nao_eh_handler_workspace',
|
|
297
|
+
message: `--artifact "${flags.artifact}" é um pacote de aplicação, não um handler.\n` +
|
|
298
|
+
' Em --target workspace a CLI lê o arquivo de --artifact como TEXTO e manda\n' +
|
|
299
|
+
' o conteúdo pro Core compilar. Um pacote vira texto corrompido: se passar do\n' +
|
|
300
|
+
` teto de ${emKB(WORKSPACE_SOURCE_MAX_BYTES)} do Core volta como HTTP 413\n` +
|
|
301
|
+
' ("Falha ao resolver a source do deploy"); se for menor, como erro de\n' +
|
|
302
|
+
' compilação. Parece problema de TAMANHO ou de código e não é: é o TIPO do alvo.\n' +
|
|
303
|
+
'\n' +
|
|
304
|
+
' Troque o alvo:\n' +
|
|
305
|
+
linhaDeComandoVm(flags),
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
rejeitar(['artifactUrl', 'artifactSha256'], 'artefato_pre_buildado_nao_se_aplica_workspace', (nomes) => `--target workspace não usa ${nomes} (artefato pré-buildado).\n` +
|
|
309
|
+
` O workspace recebe ${O_QUE_O_ALVO_RECEBE.workspace}; o Core builda a source.\n` +
|
|
310
|
+
'\n' +
|
|
311
|
+
' Artefato pré-buildado é alvo vm:\n' +
|
|
312
|
+
linhaDeComandoVm(flags));
|
|
313
|
+
rejeitar(['image', 'registry', 'registryRepo'], 'imagem_nao_se_aplica_workspace', (nomes) => `--target workspace não usa ${nomes} (imagem de container).\n` +
|
|
314
|
+
` O workspace recebe ${O_QUE_O_ALVO_RECEBE.workspace}.\n` +
|
|
315
|
+
'\n' +
|
|
316
|
+
' Imagem de container é alvo cloud-run:\n' +
|
|
317
|
+
linhaDeComandoCloudRun(flags));
|
|
318
|
+
// `--env-file`, `--domain` e `--local-artifact` também sumiam calados aqui:
|
|
319
|
+
// `runWorkspaceDeploy` nunca lê nenhum dos três (revisão do PR #74).
|
|
320
|
+
avisarDescarte(['server', 'port', 'stack', 'buildLocal', 'envFile', 'domain', 'localArtifact']);
|
|
321
|
+
return { errors, warnings };
|
|
322
|
+
}
|
|
323
|
+
if (target === 'cloud-run') {
|
|
324
|
+
// bug_ec17af08 — mantido com o MESMO código que já estava em
|
|
325
|
+
// `runCloudRunDeploy`; só mudou de lugar pra haver uma tabela só. O texto
|
|
326
|
+
// também é o mesmo, exceto o arquivo do comando sugerido, que agora sai
|
|
327
|
+
// entre aspas (caminho com espaço quebrava o copia-e-cola).
|
|
328
|
+
// `--artifact-sha256` entrou no mesmo grupo: é par de `--artifact-url` e
|
|
329
|
+
// antes passava sozinho sem reclamação nenhuma.
|
|
330
|
+
const arquivoDoDev = flags.artifact ?? flags.artifactUrl;
|
|
331
|
+
rejeitar(['artifact', 'artifactUrl', 'artifactSha256'], 'artifact_not_supported_cloud_run', (nomes) => `target=cloud-run não aceita ${nomes} (tarball source).\n` +
|
|
332
|
+
' Cloud Run precisa de uma imagem de container OCI já buildada e pushada.\n' +
|
|
333
|
+
'\n' +
|
|
334
|
+
' Opções:\n' +
|
|
335
|
+
' 1. --image <uri> — URI de imagem já no Artifact Registry.\n' +
|
|
336
|
+
' Exemplo: --image=us-central1-docker.pkg.dev/neetru/gestovendas-staging/app:1.0.0\n' +
|
|
337
|
+
'\n' +
|
|
338
|
+
' 2. --registry <host|host/project/repo> — CLI usa Cloud Build remoto automaticamente.\n' +
|
|
339
|
+
' Não exige Docker instalado. Requer gcloud autenticado.\n' +
|
|
340
|
+
' Exemplo: --registry=us-central1-docker.pkg.dev/neetru/gestovendas-staging\n' +
|
|
341
|
+
'\n' +
|
|
342
|
+
' 3. Mude o target pra vm ou workspace se quiser usar o tarball:\n' +
|
|
343
|
+
` --target=vm --artifact=${arquivoDoDev ? `"${arquivoDoDev}"` : '<file>'}`);
|
|
344
|
+
// O Core recusa `serverId` em cloud-run (`deploy-request.ts` superRefine),
|
|
345
|
+
// mas a CLI nem chega a mandar — `pickServer` só roda em target=vm. Ou
|
|
346
|
+
// seja: hoje a flag some calada. Aviso, não erro.
|
|
347
|
+
// `--domain` e `--local-artifact` só existem em vm (revisão do PR #74).
|
|
348
|
+
avisarDescarte(['server', 'domain', 'localArtifact']);
|
|
349
|
+
return { errors, warnings };
|
|
350
|
+
}
|
|
351
|
+
// target === 'vm'
|
|
352
|
+
// `--image`/`--registry`/`--registry-repo`/`--build-local` são de cloud-run e
|
|
353
|
+
// em vm somem sem dizer nada: o body do deploy vm nem tem campo pra eles, e o
|
|
354
|
+
// schema do Core (sem `.strict()`) descartaria em silêncio de qualquer jeito.
|
|
355
|
+
// `--image`/`--registry`/`--registry-repo` são a EXCEÇÃO REGISTRADA no
|
|
356
|
+
// cabeçalho: nomeiam o que subir e mesmo assim ficam como aviso, porque o
|
|
357
|
+
// deploy vm sobe o tarball e erro aqui quebraria script com flags genéricas.
|
|
358
|
+
//
|
|
359
|
+
// `--port` fica de fora de propósito: `runDeploy` já emite o aviso dele
|
|
360
|
+
// (P6/bug_6d92ef71, com texto específico sobre alocação de porta pelo Core).
|
|
361
|
+
avisarDescarte(['image', 'registry', 'registryRepo', 'buildLocal']);
|
|
362
|
+
return { errors, warnings };
|
|
363
|
+
}
|
|
364
|
+
const DE_ONDE_VEIO = {
|
|
365
|
+
artifact: 'apontado por --artifact',
|
|
366
|
+
config: 'apontado pelo campo "source" do neetru.config.json',
|
|
367
|
+
padrao: 'achado na busca padrão do handler (sem --artifact e sem "source" no config)',
|
|
368
|
+
};
|
|
369
|
+
/**
|
|
370
|
+
* Mensagem da recusa de uma source de workspace que é pacote, achada pelo nome
|
|
371
|
+
* ou pelo conteúdo DEPOIS da leitura. Usa o mesmo código de erro da recusa por
|
|
372
|
+
* `--artifact` (`artifact_nao_eh_handler_workspace`): é o mesmo erro, achado
|
|
373
|
+
* por outra porta.
|
|
374
|
+
*/
|
|
375
|
+
export function mensagemSourceNaoEhHandler(relPath, motivo, origem) {
|
|
376
|
+
return (`"${relPath}" não é um handler .ts: ${motivo}.\n` +
|
|
377
|
+
` (${DE_ONDE_VEIO[origem]})\n` +
|
|
378
|
+
'\n' +
|
|
379
|
+
' Em --target workspace a CLI lê a source como TEXTO e manda pro Core compilar.\n' +
|
|
380
|
+
' Um pacote vira texto corrompido e volta como erro de compilação (ou HTTP 413)\n' +
|
|
381
|
+
' que não diz a causa. Nada foi enviado.\n' +
|
|
382
|
+
'\n' +
|
|
383
|
+
` Se é o pacote da aplicação, o alvo certo é vm (que recebe ${O_QUE_O_ALVO_RECEBE.vm}):\n` +
|
|
384
|
+
` neetru deploy --target vm --artifact "${relPath}"\n` +
|
|
385
|
+
(origem === 'config'
|
|
386
|
+
? ' Se o handler é outro arquivo, corrija o "source" do neetru.config.json.\n'
|
|
387
|
+
: ''));
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Mensagem do estouro do teto de source do workspace, usada depois que a
|
|
391
|
+
* source já foi lida e o farejador de pacote não a recusou: na prática, um
|
|
392
|
+
* handler que ficou grande demais.
|
|
393
|
+
*
|
|
394
|
+
* Diz o número real, o teto real, e o alvo certo — em vez do 413 do Core, que
|
|
395
|
+
* diz só "Falha ao resolver a source do deploy".
|
|
396
|
+
*/
|
|
397
|
+
export function mensagemSourceAcimaDoTeto(relPath, bytes, runtime) {
|
|
398
|
+
return (`A source do deploy workspace tem ${emKB(bytes)} — o Core aceita no máximo ${emKB(WORKSPACE_SOURCE_MAX_BYTES)}.\n` +
|
|
399
|
+
` arquivo: ${relPath}\n` +
|
|
400
|
+
'\n' +
|
|
401
|
+
' Acima desse teto o Core responde HTTP 413 "Falha ao resolver a source do deploy",\n' +
|
|
402
|
+
' que parece problema de rede/tamanho de upload e não é: é o teto do alvo.\n' +
|
|
403
|
+
'\n' +
|
|
404
|
+
` Se "${relPath}" é um pacote de aplicação (tarball/zip) e não um handler .ts,\n` +
|
|
405
|
+
' o alvo certo é vm:\n' +
|
|
406
|
+
` neetru deploy --target vm --artifact "${relPath}"\n` +
|
|
407
|
+
(runtime === 'nextjs'
|
|
408
|
+
? `\n (o neetru.config.json deste produto declara runtime "nextjs" — workspace não serve esse runtime)\n`
|
|
409
|
+
: ''));
|
|
410
|
+
}
|
|
411
|
+
//# sourceMappingURL=deploy-target-contract.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* O `--env-file` do `neetru build` (bug_25ff8581): cada linha `CHAVE=valor`
|
|
3
|
+
* vira variável do PROCESSO do build (o spawn do bundler), e não um `.env` que
|
|
4
|
+
* o bundler lê. Por isso a regra é a da CLI, mais simples que a do dotenv:
|
|
5
|
+
*
|
|
6
|
+
* KEY=value (sem aspas; o `#` depois do `=` faz parte do valor)
|
|
7
|
+
* KEY="value with spaces" (aspas duplas)
|
|
8
|
+
* KEY='value' (aspas simples)
|
|
9
|
+
* # comentário (ignorado)
|
|
10
|
+
* linha vazia (ignorada)
|
|
11
|
+
*
|
|
12
|
+
* Não suporta multi-line values nem expande `$VAR`.
|
|
13
|
+
*
|
|
14
|
+
* Mora aqui, e não em `commands/build.ts`, porque a varredura de segredo do
|
|
15
|
+
* deploy (`collectPublicEnvSecrets`) precisa da MESMA regra para procurar o
|
|
16
|
+
* valor que o build injetou (rodada final 5 do cli#81). Quem recebe o texto já
|
|
17
|
+
* decodificado e sem a marca BOM é quem chama.
|
|
18
|
+
*/
|
|
19
|
+
export declare function variaveisDoEnvFile(conteudo: string): Record<string, string>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* O `--env-file` do `neetru build` (bug_25ff8581): cada linha `CHAVE=valor`
|
|
3
|
+
* vira variável do PROCESSO do build (o spawn do bundler), e não um `.env` que
|
|
4
|
+
* o bundler lê. Por isso a regra é a da CLI, mais simples que a do dotenv:
|
|
5
|
+
*
|
|
6
|
+
* KEY=value (sem aspas; o `#` depois do `=` faz parte do valor)
|
|
7
|
+
* KEY="value with spaces" (aspas duplas)
|
|
8
|
+
* KEY='value' (aspas simples)
|
|
9
|
+
* # comentário (ignorado)
|
|
10
|
+
* linha vazia (ignorada)
|
|
11
|
+
*
|
|
12
|
+
* Não suporta multi-line values nem expande `$VAR`.
|
|
13
|
+
*
|
|
14
|
+
* Mora aqui, e não em `commands/build.ts`, porque a varredura de segredo do
|
|
15
|
+
* deploy (`collectPublicEnvSecrets`) precisa da MESMA regra para procurar o
|
|
16
|
+
* valor que o build injetou (rodada final 5 do cli#81). Quem recebe o texto já
|
|
17
|
+
* decodificado e sem a marca BOM é quem chama.
|
|
18
|
+
*/
|
|
19
|
+
export function variaveisDoEnvFile(conteudo) {
|
|
20
|
+
const vars = {};
|
|
21
|
+
for (const line of conteudo.split(/\r?\n/)) {
|
|
22
|
+
const trimmed = line.trim();
|
|
23
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
24
|
+
continue;
|
|
25
|
+
const eq = trimmed.indexOf('=');
|
|
26
|
+
if (eq === -1)
|
|
27
|
+
continue;
|
|
28
|
+
const key = trimmed.slice(0, eq).trim();
|
|
29
|
+
let val = trimmed.slice(eq + 1).trim();
|
|
30
|
+
// Remove aspas simétricas.
|
|
31
|
+
if (val.length >= 2) {
|
|
32
|
+
const open = val[0];
|
|
33
|
+
const close = val[val.length - 1];
|
|
34
|
+
if ((open === '"' && close === '"') || (open === "'" && close === "'")) {
|
|
35
|
+
val = val.slice(1, -1);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (!key)
|
|
39
|
+
continue;
|
|
40
|
+
vars[key] = val;
|
|
41
|
+
}
|
|
42
|
+
return vars;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=env-file-do-build.js.map
|