@neetru/sdk 3.4.1 → 3.4.3

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/build-guard.ts"],"names":[],"mappings":";;;;AAwFO,SAAS,oBAAA,CACd,UAAA,EACA,OAAA,GAAuC,EAAC,EACrC;AACH,EAAA,MAAM,cAAc,UAAA,CAAW,OAAA;AAE/B,EAAA,OAAO;AAAA,IACL,GAAG,UAAA;AAAA,IACH,OAAA,CAAQ,QAAiB,OAAA,EAAyC;AAChE,MAAA,MAAM,SAAS,OAAO,WAAA,KAAgB,aAAa,WAAA,CAAY,MAAA,EAAQ,OAAO,CAAA,GAAI,MAAA;AAKlF,MAAA,IAAI,CAAC,OAAA,CAAQ,GAAA,IAAO,OAAA,CAAQ,QAAA,EAAU;AACpC,QAAA,IAAI;AACF,UAAA,MAAM,SAAc,IAAA,CAAA,OAAA,CAAQ,OAAA,CAAQ,KAAI,EAAG,OAAA,CAAQ,aAAa,OAAO,CAAA;AACvE,UAAG,EAAA,CAAA,SAAA,CAAU,MAAA,EAAQ,EAAE,SAAA,EAAW,MAAM,CAAA;AACxC,UAAA,MAAM,QAAA,GAAgC;AAAA,YACpC,QAAA,EAAU,OAAA,CAAQ,GAAA,CAAI,sBAAA,IAA0B,IAAA;AAAA,YAChD,SAAA,EAAW,OAAA,CAAQ,GAAA,CAAI,6BAAA,IAAiC,IAAA;AAAA,YACxD,YAAA,EAAc,OAAA,CAAQ,GAAA,CAAI,iCAAA,IAAqC,IAAA;AAAA,YAC/D,OAAA,EAAA,iBAAS,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,WAClC;AACA,UAAG,EAAA,CAAA,aAAA;AAAA,YACI,IAAA,CAAA,IAAA,CAAK,QAAQ,4BAA4B,CAAA;AAAA,YAC9C,IAAA,CAAK,SAAA,CAAU,QAAA,EAAU,IAAA,EAAM,CAAC,CAAA;AAAA,YAChC;AAAA,WACF;AAAA,QACF,SAAS,GAAA,EAAK;AAMZ,UAAA,IAAI,OAAO,YAAY,WAAA,EAAa;AAClC,YAAA,OAAA,CAAQ,IAAA;AAAA,cACN,wGAAA;AAAA,cACA;AAAA,aACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,MAAA,OAAO,MAAA;AAAA,IACT;AAAA,GACF;AACF","file":"build-guard.mjs","sourcesContent":["/**\r\n * `withNeetruBuildGuard` — wrapper de `next.config.mjs` que grava\r\n * `.next/neetru-build-manifest.json` ao final do build com os valores\r\n * `NEXT_PUBLIC_NEETRU_*` que realmente foram resolvidos pelo Next.js.\r\n *\r\n * Existe pra fechar um bug de precedência de env do Next.js (incidente\r\n * 2026-07-22, pdv-agiliza): `.env.local` (fica no disco do dev) vence\r\n * `.env.production` durante `next build` pra qualquer chave em comum —\r\n * então um build \"de prod\" podia compilar com `NEXT_PUBLIC_NEETRU_ENV=dev`\r\n * sem nenhum aviso, ativando `MockAuth` no bundle do browser em produção\r\n * (o botão \"Entrar com Neetru\" não fazia nada, porque `MockAuth.signIn()`\r\n * só finge um login em memória — nunca navega pro IdP real).\r\n *\r\n * O manifesto não inspeciona o JS compilado (minificação/webpack\r\n * `DefinePlugin` tornam isso frágil — o nome da chave some, só sobra o\r\n * literal). Em vez disso grava, em texto puro, o que o processo Node do\r\n * build efetivamente tinha em `process.env` no momento da compilação\r\n * server-side — reflete fielmente a resolução real do Next.js/dotenv,\r\n * incluindo qualquer override via spawn-env (`@neetru/cli` injeta\r\n * `NEXT_PUBLIC_NEETRU_ENV` assim desde a v2.26.2). `neetru build` lê este\r\n * arquivo depois do build e recusa empacotar o tarball se o valor não\r\n * bater com o ambiente esperado do deploy.\r\n *\r\n * Uso, em `next.config.mjs`:\r\n * ```js\r\n * import { withNeetruBuildGuard } from '@neetru/sdk/build-guard';\r\n * export default withNeetruBuildGuard({ ...nextConfig });\r\n * ```\r\n *\r\n * Subpath dedicado (`@neetru/sdk/build-guard`, não o barrel `.`) de\r\n * propósito: este arquivo é o único no SDK que importa `node:fs`/`node:path`\r\n * estaticamente. O entry `.` promete rodar em browser/Node/Edge sem Node\r\n * builtins — reexportar o guard ali vazaria essa dependência pro bundle\r\n * universal (achado real da revisão: `esbuild --platform=browser` falha com\r\n * \"Could not resolve fs/path\" se o guard entra no barrel principal).\r\n *\r\n * IMPORTANTE — isto NÃO é uma checagem universal de \"o env está certo\": o\r\n * guard grava literalmente as 3 env vars `NEXT_PUBLIC_NEETRU_ENV` /\r\n * `_PRODUCT_ID` / `_OIDC_CLIENT_ID`, que são a convenção recomendada de\r\n * bootstrap Next.js do ecossistema Neetru (o que `neetru-pdvagiliza` e\r\n * outros produtos usam em `src/lib/neetru/client.ts` pra montar\r\n * `createNeetruClient({env, productId, oidcClientId})`) — **não** é o mesmo\r\n * que o fallback interno `NEETRU_ENV`/`globalThis.NEETRU_ENV` que\r\n * `resolveEnv()` (`src/auth.ts`) usa quando NENHUM `env` é passado\r\n * explicitamente pro client. Se o seu produto bootstrap o client de outra\r\n * forma (nome de env var diferente, ou sem prefixo `NEXT_PUBLIC_`, ou\r\n * hardcoded), este guard não detecta drift pra esse caso — ele só confirma\r\n * que a convenção documentada acima foi respeitada.\r\n *\r\n * Composável com qualquer wrapper que já use a chave `webpack` do config\r\n * (ex: `next-pwa`) — a função `webpack` anterior, se houver, é chamada\r\n * primeiro e o retorno dela é repassado adiante sem alteração.\r\n */\r\nimport * as fs from 'node:fs';\r\nimport * as path from 'node:path';\r\n\r\n/** Formato do `.next/neetru-build-manifest.json`. */\r\nexport interface NeetruBuildManifest {\r\n /** `NEXT_PUBLIC_NEETRU_ENV` resolvido no momento do build (`dev|workspace|prod`), ou `null` se ausente. */\r\n builtEnv: string | null;\r\n /** `NEXT_PUBLIC_NEETRU_PRODUCT_ID` resolvido, ou `null`. */\r\n productId: string | null;\r\n /** `NEXT_PUBLIC_NEETRU_OIDC_CLIENT_ID` resolvido, ou `null`. */\r\n oidcClientId: string | null;\r\n /** ISO timestamp de quando o manifesto foi gravado. */\r\n builtAt: string;\r\n}\r\n\r\nexport interface WithNeetruBuildGuardOptions {\r\n /** Diretório de saída do Next (default `.next`, relativo ao cwd do build). */\r\n outputDir?: string;\r\n}\r\n\r\n/**\r\n * Formato mínimo de `next.config.mjs` que o wrapper precisa entender — só\r\n * o suficiente pra compor a chave `webpack` sem acoplar o SDK ao pacote\r\n * `next` como dependência de tipos.\r\n */\r\ntype MinimalWebpackContext = {\r\n buildId: string;\r\n dev: boolean;\r\n isServer: boolean;\r\n [key: string]: unknown;\r\n};\r\ntype MinimalNextConfig = Record<string, unknown> & {\r\n webpack?: (config: unknown, context: MinimalWebpackContext) => unknown;\r\n};\r\n\r\nexport function withNeetruBuildGuard<T extends MinimalNextConfig>(\r\n nextConfig: T,\r\n options: WithNeetruBuildGuardOptions = {},\r\n): T {\r\n const prevWebpack = nextConfig.webpack;\r\n\r\n return {\r\n ...nextConfig,\r\n webpack(config: unknown, context: MinimalWebpackContext): unknown {\r\n const result = typeof prevWebpack === 'function' ? prevWebpack(config, context) : config;\r\n\r\n // Grava só na passada server (roda 1x por build, diferente da passada\r\n // client que pode rodar múltiplas vezes) e só fora de `next dev` —\r\n // `next build` é sempre produção de artefato de deploy.\r\n if (!context.dev && context.isServer) {\r\n try {\r\n const outDir = path.resolve(process.cwd(), options.outputDir ?? '.next');\r\n fs.mkdirSync(outDir, { recursive: true });\r\n const manifest: NeetruBuildManifest = {\r\n builtEnv: process.env.NEXT_PUBLIC_NEETRU_ENV ?? null,\r\n productId: process.env.NEXT_PUBLIC_NEETRU_PRODUCT_ID ?? null,\r\n oidcClientId: process.env.NEXT_PUBLIC_NEETRU_OIDC_CLIENT_ID ?? null,\r\n builtAt: new Date().toISOString(),\r\n };\r\n fs.writeFileSync(\r\n path.join(outDir, 'neetru-build-manifest.json'),\r\n JSON.stringify(manifest, null, 2),\r\n 'utf8',\r\n );\r\n } catch (err) {\r\n // Best-effort — o guard nunca pode quebrar o build do produto,\r\n // mas uma falha de escrita silenciosa aqui esconderia o problema\r\n // (achado da revisão: sem log, ninguém percebe que o manifesto não\r\n // foi gravado e `neetru build` trata \"manifesto ausente\" como\r\n // aviso, não bloqueio — visibilidade aqui é a única forma de notar).\r\n if (typeof console !== 'undefined') {\r\n console.warn(\r\n '[neetru-sdk] withNeetruBuildGuard: falha ao gravar neetru-build-manifest.json (ignorado, build segue):',\r\n err,\r\n );\r\n }\r\n }\r\n }\r\n\r\n return result;\r\n },\r\n } as T;\r\n}\r\n"]}
1
+ {"version":3,"sources":["../src/build-guard.ts"],"names":[],"mappings":"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","file":"build-guard.mjs","sourcesContent":["/**\r\n * `withNeetruBuildGuard` — wrapper de `next.config.mjs` que grava\r\n * `.next/neetru-build-manifest.json` ao final do build com os valores\r\n * `NEXT_PUBLIC_NEETRU_*` que realmente foram resolvidos pelo Next.js.\r\n *\r\n * Existe pra fechar um bug de precedência de env do Next.js (incidente\r\n * 2026-07-22, pdv-agiliza): `.env.local` (fica no disco do dev) vence\r\n * `.env.production` durante `next build` pra qualquer chave em comum —\r\n * então um build \"de prod\" podia compilar com `NEXT_PUBLIC_NEETRU_ENV=dev`\r\n * sem nenhum aviso, ativando `MockAuth` no bundle do browser em produção\r\n * (o botão \"Entrar com Neetru\" não fazia nada, porque `MockAuth.signIn()`\r\n * só finge um login em memória — nunca navega pro IdP real).\r\n *\r\n * O manifesto não inspeciona o JS compilado (minificação/webpack\r\n * `DefinePlugin` tornam isso frágil — o nome da chave some, só sobra o\r\n * literal). Em vez disso grava, em texto puro, o que o processo Node do\r\n * build efetivamente tinha em `process.env` no momento da compilação\r\n * server-side — reflete fielmente a resolução real do Next.js/dotenv,\r\n * incluindo qualquer override via spawn-env (`@neetru/cli` injeta\r\n * `NEXT_PUBLIC_NEETRU_ENV` assim desde a v2.26.2). `neetru build` lê este\r\n * arquivo depois do build e recusa empacotar o tarball se o valor não\r\n * bater com o ambiente esperado do deploy.\r\n *\r\n * Uso, em `next.config.mjs`:\r\n * ```js\r\n * import { withNeetruBuildGuard } from '@neetru/sdk/build-guard';\r\n * export default withNeetruBuildGuard({ ...nextConfig });\r\n * ```\r\n *\r\n * Subpath dedicado (`@neetru/sdk/build-guard`, não o barrel `.`) de\r\n * propósito: este arquivo é o único no SDK que importa `node:fs`/`node:path`\r\n * estaticamente. O entry `.` promete rodar em browser/Node/Edge sem Node\r\n * builtins — reexportar o guard ali vazaria essa dependência pro bundle\r\n * universal (achado real da revisão: `esbuild --platform=browser` falha com\r\n * \"Could not resolve fs/path\" se o guard entra no barrel principal).\r\n *\r\n * IMPORTANTE — isto NÃO é uma checagem universal de \"o env está certo\": o\r\n * guard grava literalmente as 3 env vars `NEXT_PUBLIC_NEETRU_ENV` /\r\n * `_PRODUCT_ID` / `_OIDC_CLIENT_ID`, que são a convenção recomendada de\r\n * bootstrap Next.js do ecossistema Neetru (o que `neetru-pdvagiliza` e\r\n * outros produtos usam em `src/lib/neetru/client.ts` pra montar\r\n * `createNeetruClient({env, productId, oidcClientId})`) — **não** é o mesmo\r\n * que o fallback interno `NEETRU_ENV`/`globalThis.NEETRU_ENV` que\r\n * `resolveEnv()` (`src/auth.ts`) usa quando NENHUM `env` é passado\r\n * explicitamente pro client. Se o seu produto bootstrap o client de outra\r\n * forma (nome de env var diferente, ou sem prefixo `NEXT_PUBLIC_`, ou\r\n * hardcoded), este guard não detecta drift pra esse caso — ele só confirma\r\n * que a convenção documentada acima foi respeitada.\r\n *\r\n * FAIL-LOUD em produção (incidente gestovendas 2026-09-06): além de gravar o\r\n * manifesto, quando o env-alvo resolvido é **prod** o guard FALHA o build\r\n * (`throw NeetruBuildGuardError` → `next build` sai com código ≠ 0) se\r\n * `NEXT_PUBLIC_NEETRU_OIDC_CLIENT_ID` ou `NEXT_PUBLIC_NEETRU_PRODUCT_ID`\r\n * estiver ausente/vazio. Sem esse par o SDK não monta o `client_id` do login\r\n * OIDC — o `NeetruLoginButton` não redireciona e o login quebra EM SILÊNCIO\r\n * em produção (foi exatamente o que aconteceu quando a recriação do workspace\r\n * do gestovendas perdeu a env var e shippou um build de prod com o client_id\r\n * vazio). `dev`/`workspace` NÃO exigem o par (usam MockAuth/sandbox) — só prod\r\n * enforça, pra nunca quebrar build local. A checagem de valor pura vive em\r\n * `assertNeetruProdBuildEnv` (exportada, testável sem rodar webpack).\r\n *\r\n * TRACE DO STANDALONE — pg + drizzle-orm (Fase 2, causa-2 do outage PDV\r\n * 2026-09-07): `client.db.sql` carrega `pg` e `drizzle-orm/node-postgres` por\r\n * `import()` DINÂMICO com o magic comment `webpackIgnore`\r\n * (`src/db/sql/sql-client.ts`) — de propósito, pra `pg` (server-only, puxa\r\n * `fs`/`tls`/`net`) nunca entrar no bundle do browser. O efeito colateral: o\r\n * trace estático do Next (`@vercel/nft`) não enxerga esses `import()` e, num\r\n * `output: 'standalone'` enxuto, NÃO copia `pg`/`drizzle-orm` pra\r\n * `.next/standalone/node_modules` → runtime quebra com `Cannot find package\r\n * 'pg'` (o bundle gordo antigo os incluía por acidente; o enxuto, correto,\r\n * não). O guard conserta isso de forma NATIVA do Next, pra TODO produto que\r\n * já adota `withNeetruBuildGuard`, injetando duas chaves no config:\r\n * - `outputFileTracingIncludes: { '*': [...closure] }` (O CONSERTO REAL) —\r\n * FORÇA o nft a copiar o FECHO TRANSITIVO de runtime de `pg` + `drizzle-orm`\r\n * pro standalone, computado PROGRAMATICAMENTE do node_modules instalado do\r\n * produto (`resolveSqlRuntimeClosure`): `pg → pg-pool/pg-protocol/pg-types →\r\n * postgres-array/postgres-bytea/… → …`. Um glob `./node_modules/pkg/**` por\r\n * pacote do closure. A chave `'*'` casa todas as rotas (Next casa a chave\r\n * com `picomatch(..., { contains: true })`).\r\n * - `serverExternalPackages: [...existentes, 'pg', 'drizzle-orm']` (REFORÇO) —\r\n * inofensivo e ajuda caminhos de import VISÍVEIS ao nft, MAS não conserta o\r\n * caso `webpackIgnore`: `serverExternalPackages` só traça imports que o nft\r\n * ENXERGA (por isso funciona pro `mongodb`/`firebase-admin` do Core, que são\r\n * `require()` visíveis) — o `import()` webpackIgnore'd do SDK é invisível, e\r\n * `serverExternalPackages:['pg']` sozinho NÃO copia `pg` nem seu closure.\r\n * POR QUE PROGRAMÁTICO (não glob fixo): o glob `./node_modules/pg/**` cobre só o\r\n * DIR do `pg`, não os transitivos HOISTADOS na raiz (npm 7+) — foi o buraco que\r\n * deixou `Cannot find module 'postgres-array'` quebrar o deploy de 2026-09-07\r\n * mesmo com as duas chaves setadas. Só o disco instalado sabe o closure real →\r\n * à prova de whack-a-mole. O walker lê `package.json` DIRETO do filesystem (não\r\n * `require.resolve`, que dá `ERR_PACKAGE_PATH_NOT_EXPORTED` em pacotes com\r\n * `exports` fechando `./package.json` — drizzle-orm/pg-protocol/pg-pool fazem\r\n * isso, e era outro jeito de perder pacotes do closure).\r\n * Ambas as chaves MESCLAM (concat + dedupe) com o que o produto já tiver — nunca\r\n * sobrescrevem. `pglite`/`pg-mem` (MOCK/teste, `src/mocks.ts`) NÃO entram — só o\r\n * caminho real (`pg` + `drizzle-orm/node-postgres`). Produto SEM SQL:\r\n * `pg`/`drizzle-orm` não resolvem → closure `[]` → nenhuma chave adicionada →\r\n * peso morto ZERO. Chaves canônicas do Next 15 (Core, pdv-agiliza 15.5,\r\n * gestovendas 15.5) — top-level, não `experimental.*`.\r\n *\r\n * Composável com qualquer wrapper que já use a chave `webpack` do config\r\n * (ex: `next-pwa`) — a função `webpack` anterior, se houver, é chamada\r\n * primeiro e o retorno dela é repassado adiante sem alteração.\r\n */\r\nimport * as fs from 'node:fs';\r\nimport * as path from 'node:path';\r\n\r\n/** Formato do `.next/neetru-build-manifest.json`. */\r\nexport interface NeetruBuildManifest {\r\n /** `NEXT_PUBLIC_NEETRU_ENV` resolvido no momento do build (`dev|workspace|prod`), ou `null` se ausente. */\r\n builtEnv: string | null;\r\n /** `NEXT_PUBLIC_NEETRU_PRODUCT_ID` resolvido, ou `null`. */\r\n productId: string | null;\r\n /** `NEXT_PUBLIC_NEETRU_OIDC_CLIENT_ID` resolvido, ou `null`. */\r\n oidcClientId: string | null;\r\n /** ISO timestamp de quando o manifesto foi gravado. */\r\n builtAt: string;\r\n}\r\n\r\nexport interface WithNeetruBuildGuardOptions {\r\n /** Diretório de saída do Next (default `.next`, relativo ao cwd do build). */\r\n outputDir?: string;\r\n}\r\n\r\n/**\r\n * Erro lançado pelo guard quando um build de PRODUÇÃO está sem uma env var\r\n * obrigatória (OIDC client_id / productId). Classe dedicada pra o caller\r\n * poder distinguir \"guard reprovou de propósito\" de uma falha genérica de\r\n * build. Lançar dentro da função `webpack` do `next.config` faz o\r\n * `next build` sair com código ≠ 0 (fail-loud) — que é justamente o objetivo.\r\n */\r\nexport class NeetruBuildGuardError extends Error {\r\n constructor(message: string) {\r\n super(message);\r\n this.name = 'NeetruBuildGuardError';\r\n }\r\n}\r\n\r\n/** `''`/whitespace/`null`/`undefined` contam como \"ausente\". */\r\nfunction isBlankEnvValue(v: string | null | undefined): boolean {\r\n return v == null || v.trim() === '';\r\n}\r\n\r\n/**\r\n * Checagem pura (sem I/O, sem webpack) que decide se um build DEVE falhar por\r\n * env var obrigatória faltando. Exportada pra ser testável isoladamente e pra\r\n * o CLI poder reusar a mesma regra se quiser.\r\n *\r\n * Regra: SÓ o env-alvo `prod` exige o par OIDC completo\r\n * (`NEXT_PUBLIC_NEETRU_OIDC_CLIENT_ID` + `NEXT_PUBLIC_NEETRU_PRODUCT_ID`).\r\n * `dev`/`workspace`/qualquer outro valor (ou ausência) NÃO enforçam — usam\r\n * MockAuth/sandbox e não montam o client OIDC real, então não podem quebrar\r\n * build local. Lança `NeetruBuildGuardError` com mensagem acionável quando\r\n * reprova; retorna `void` quando passa.\r\n */\r\nexport function assertNeetruProdBuildEnv(\r\n resolved: Pick<NeetruBuildManifest, 'builtEnv' | 'productId' | 'oidcClientId'>,\r\n): void {\r\n // Só produção monta o client_id OIDC real. dev/workspace seguem permissivos.\r\n if (resolved.builtEnv !== 'prod') return;\r\n\r\n const missing: string[] = [];\r\n if (isBlankEnvValue(resolved.oidcClientId)) missing.push('NEXT_PUBLIC_NEETRU_OIDC_CLIENT_ID');\r\n if (isBlankEnvValue(resolved.productId)) missing.push('NEXT_PUBLIC_NEETRU_PRODUCT_ID');\r\n if (missing.length === 0) return;\r\n\r\n const plural = missing.length > 1;\r\n throw new NeetruBuildGuardError(\r\n [\r\n '[neetru-sdk] BUILD DE PRODUÇÃO ABORTADO (withNeetruBuildGuard).',\r\n '',\r\n `Variáve${plural ? 'is' : 'l'} de ambiente obrigatóri${plural ? 'as' : 'a'} ausente${plural ? 's' : ''}/vazia${plural ? 's' : ''} no build de produção (NEXT_PUBLIC_NEETRU_ENV=prod):`,\r\n ...missing.map((v) => ` • ${v}`),\r\n '',\r\n `Sem ${plural ? 'essas variáveis' : 'essa variável'} o SDK não consegue montar o client_id do login OIDC — o botão \"Entrar com Neetru\" (NeetruLoginButton) NÃO redireciona e o login do produto quebra EM SILÊNCIO em produção (incidente gestovendas 2026-09-06: workspace recriado perdeu a env var e shippou um build de prod com o client_id vazio).`,\r\n '',\r\n 'Como corrigir — defina no .env.production do produto (ou no ambiente do build de deploy):',\r\n ...missing.map((v) => ` ${v}=<valor real vindo do catálogo do produto no Core>`),\r\n '',\r\n 'dev/workspace NÃO exigem essas variáveis (usam MockAuth/sandbox) — só o build de produção enforça.',\r\n ].join('\\n'),\r\n );\r\n}\r\n\r\n/**\r\n * Formato mínimo de `next.config.mjs` que o wrapper precisa entender — só\r\n * o suficiente pra compor a chave `webpack` sem acoplar o SDK ao pacote\r\n * `next` como dependência de tipos.\r\n */\r\ntype MinimalWebpackContext = {\r\n buildId: string;\r\n dev: boolean;\r\n isServer: boolean;\r\n [key: string]: unknown;\r\n};\r\ntype MinimalNextConfig = Record<string, unknown> & {\r\n webpack?: (config: unknown, context: MinimalWebpackContext) => unknown;\r\n serverExternalPackages?: string[];\r\n outputFileTracingIncludes?: Record<string, string[]>;\r\n};\r\n\r\n// ─── Trace do standalone: closure de runtime SQL (causa-2 outage PDV 2026-09-07) ─\r\n\r\n/**\r\n * Pacotes-SEMENTE do caminho SQL de produção do SDK: `client.db.sql` carrega\r\n * `pg` e `drizzle-orm/node-postgres` por `import()` dinâmico com `webpackIgnore`\r\n * (`src/db/sql/sql-client.ts`). `pglite`/`pg-mem` são mock/teste (`src/mocks.ts`)\r\n * e NÃO entram aqui. A partir destas sementes o guard computa o FECHO\r\n * TRANSITIVO de runtime (ver `resolveSqlRuntimeClosure`).\r\n */\r\nexport const NEETRU_SQL_SERVER_EXTERNAL_PACKAGES: readonly string[] = ['pg', 'drizzle-orm'];\r\n\r\n/**\r\n * Chave do `outputFileTracingIncludes`: `'*'` casa TODAS as rotas — o Next\r\n * casa a chave contra o path da rota com `picomatch(key, { contains: true })`,\r\n * então `'*'` (qualquer sequência) bate em qualquer rota.\r\n */\r\nexport const NEETRU_SQL_TRACE_INCLUDE_KEY = '*';\r\n\r\n/** Coage um valor desconhecido de config pra `string[]` (descarta não-strings). */\r\nfunction toStringArray(value: unknown): string[] {\r\n return Array.isArray(value) ? value.filter((v): v is string => typeof v === 'string') : [];\r\n}\r\n\r\n/**\r\n * Acha o `package.json` de um pacote LENDO O FILESYSTEM (não `require.resolve`):\r\n * caminha os `node_modules` a partir de `parentDir` subindo até a raiz, e cai no\r\n * `node_modules` de `fromDir` por último. Resolve tanto dep HOISTADA (raiz) quanto\r\n * NESTED (`.../node_modules/pai/node_modules/dep`).\r\n *\r\n * Por que filesystem e não `require.resolve(dep + '/package.json')`: pacotes\r\n * modernos com campo `exports` (ex: `drizzle-orm`, `pg-protocol`, `pg-pool`)\r\n * BLOQUEIAM o subpath `./package.json` no `exports` → `require.resolve` lança\r\n * `ERR_PACKAGE_PATH_NOT_EXPORTED` e o walker perderia esses pacotes (foi\r\n * exatamente o buraco que deixou `postgres-array` fora). Ler o arquivo direto do\r\n * disco ignora o `exports` e é à prova disso.\r\n */\r\nfunction findPackageJsonPath(\r\n pkgName: string,\r\n parentDir: string,\r\n fromDir: string,\r\n): string | null {\r\n const bases: string[] = [];\r\n let dir = parentDir;\r\n // Sobe a árvore a partir do dir do pacote-pai (cobre nested + hoisted).\r\n for (;;) {\r\n bases.push(dir);\r\n const parent = path.dirname(dir);\r\n if (parent === dir) break;\r\n dir = parent;\r\n }\r\n if (!bases.includes(fromDir)) bases.push(fromDir);\r\n\r\n for (const base of bases) {\r\n // `path.join` lida com nome escopado (`@scope/name`) e separador de SO.\r\n const candidate = path.join(base, 'node_modules', pkgName, 'package.json');\r\n try {\r\n if (fs.existsSync(candidate)) return candidate;\r\n } catch {\r\n // Filesystem hostil (permissão/EBUSY) — ignora este candidato.\r\n }\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Computa o FECHO TRANSITIVO de runtime das sementes SQL (`pg`, `drizzle-orm`) a\r\n * partir da raiz do produto (`fromDir`), retornando o conjunto ORDENADO de nomes\r\n * de pacote a forçar no trace do standalone.\r\n *\r\n * Algoritmo: a partir de cada semente, lê o `package.json`, coleta `dependencies`\r\n * + `optionalDependencies` (NÃO devDeps, NÃO peerDeps — não são o closure de\r\n * runtime) e recursa. Ciclos são cortados por um `visited` set; dep não-instalada\r\n * (optional já podada, ou peer não presente) é simplesmente pulada — nunca lança.\r\n *\r\n * PROGRAMÁTICO (não glob fixo) DE PROPÓSITO: `pg → pg-types → postgres-array →\r\n * …` é uma cadeia real que um glob `./node_modules/pg/**` NÃO cobre quando os\r\n * transitivos estão HOISTADOS na raiz (npm 7+). Só o disco instalado sabe o\r\n * closure real → à prova de whack-a-mole (o `Cannot find module 'postgres-array'`\r\n * do deploy de 2026-09-07 foi exatamente esse buraco). Se `pg`/`drizzle-orm` NÃO\r\n * resolvem (produto sem SQL), o closure é `[]` → nenhum glob, zero peso morto.\r\n *\r\n * PURO e testável: só toca filesystem (leitura), sem efeitos. `fromDir` inválido\r\n * ou erro inesperado → `[]` (o caller nunca pode quebrar o `next.config`).\r\n */\r\nexport function resolveSqlRuntimeClosure(fromDir: string): string[] {\r\n if (typeof fromDir !== 'string' || fromDir.trim() === '') return [];\r\n\r\n const visited = new Set<string>();\r\n const closure = new Set<string>();\r\n\r\n const walk = (pkgName: string, parentDir: string): void => {\r\n if (visited.has(pkgName)) return;\r\n visited.add(pkgName);\r\n\r\n const pkgJsonPath = findPackageJsonPath(pkgName, parentDir, fromDir);\r\n if (!pkgJsonPath) return; // não instalado — pula sem quebrar\r\n\r\n closure.add(pkgName);\r\n\r\n let manifest: { dependencies?: Record<string, string>; optionalDependencies?: Record<string, string> };\r\n try {\r\n manifest = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8'));\r\n } catch {\r\n return; // package.json ilegível/corrompido — inclui o próprio, para aqui\r\n }\r\n\r\n const deps = {\r\n ...(manifest.dependencies ?? {}),\r\n ...(manifest.optionalDependencies ?? {}),\r\n };\r\n const pkgDir = path.dirname(pkgJsonPath);\r\n for (const dep of Object.keys(deps)) walk(dep, pkgDir);\r\n };\r\n\r\n try {\r\n for (const seed of NEETRU_SQL_SERVER_EXTERNAL_PACKAGES) walk(seed, fromDir);\r\n } catch {\r\n return []; // qualquer imprevisto → sem globs (build do produto nunca quebra)\r\n }\r\n\r\n return [...closure].sort();\r\n}\r\n\r\n/**\r\n * Converte o closure em globs de `outputFileTracingIncludes` (um por pacote).\r\n * `./node_modules/${pkg}/**` cobre: (a) o pacote hoistado na raiz; (b) qualquer\r\n * cópia NESTED via o `**` do pacote-pai (o glob-raiz de um pacote só-nested vira\r\n * no-op inofensivo). Nome escopado (`@scope/name`) já vem correto no path.\r\n */\r\nexport function sqlClosureToTraceGlobs(closure: readonly string[]): string[] {\r\n return closure.map((pkg) => `./node_modules/${pkg}/**`);\r\n}\r\n\r\n/**\r\n * Mescla `serverExternalPackages` do produto com `pg`/`drizzle-orm` (concat +\r\n * dedupe, preservando a ordem: existentes primeiro). NUNCA sobrescreve o que o\r\n * produto já declarou (ex: o Core lista `mongodb`, `firebase-admin`, …).\r\n *\r\n * Mantido como reforço (inofensivo, ajuda caminhos de import VISÍVEIS ao nft),\r\n * mas NÃO é o que conserta o caso `webpackIgnore` — `serverExternalPackages` só\r\n * traça imports que o nft ENXERGA; o `import()` webpackIgnore'd é invisível, por\r\n * isso o `outputFileTracingIncludes` computado é o que realmente resolve.\r\n */\r\nexport function mergeServerExternalPackages(existing: unknown): string[] {\r\n const out = toStringArray(existing);\r\n for (const pkg of NEETRU_SQL_SERVER_EXTERNAL_PACKAGES) {\r\n if (!out.includes(pkg)) out.push(pkg);\r\n }\r\n return out;\r\n}\r\n\r\n/**\r\n * Mescla `outputFileTracingIncludes` do produto com os `globs` do closure SQL\r\n * sob a chave `'*'`. Preserva todas as chaves/globs existentes; na chave `'*'`\r\n * concatena + dedupe (existentes primeiro). `globs` vazio (produto sem SQL) →\r\n * nenhuma chave `'*'` criada além do que o produto já tinha.\r\n */\r\nexport function mergeOutputFileTracingIncludes(\r\n existing: unknown,\r\n globs: readonly string[],\r\n): Record<string, string[]> {\r\n const merged: Record<string, string[]> = {};\r\n if (existing && typeof existing === 'object' && !Array.isArray(existing)) {\r\n for (const [key, value] of Object.entries(existing as Record<string, unknown>)) {\r\n merged[key] = toStringArray(value);\r\n }\r\n }\r\n if (globs.length === 0) return merged; // sem closure → não mexe (zero peso morto)\r\n\r\n const combined = [...(merged[NEETRU_SQL_TRACE_INCLUDE_KEY] ?? [])];\r\n for (const glob of globs) {\r\n if (!combined.includes(glob)) combined.push(glob);\r\n }\r\n merged[NEETRU_SQL_TRACE_INCLUDE_KEY] = combined;\r\n return merged;\r\n}\r\n\r\nexport function withNeetruBuildGuard<T extends MinimalNextConfig>(\r\n nextConfig: T,\r\n options: WithNeetruBuildGuardOptions = {},\r\n): T {\r\n const prevWebpack = nextConfig.webpack;\r\n\r\n // Trace do standalone (causa-2 outage PDV 2026-09-07): computa o FECHO\r\n // TRANSITIVO de `pg` + `drizzle-orm` (carregados por import() dinâmico\r\n // webpackIgnore no `client.db.sql`, logo INVISÍVEIS ao nft) a partir do\r\n // node_modules REAL do produto, e força cada pacote do closure no\r\n // `outputFileTracingIncludes`. Produto sem SQL → closure vazio → zero peso\r\n // morto. `resolveSqlRuntimeClosure` é graceful (nunca lança); ainda assim\r\n // envolvo em try/catch como cinto-e-suspensório — o guard JAMAIS pode quebrar\r\n // o next.config de um produto. Roda no BUILD do produto, não em runtime.\r\n let sqlTraceGlobs: string[] = [];\r\n try {\r\n sqlTraceGlobs = sqlClosureToTraceGlobs(resolveSqlRuntimeClosure(process.cwd()));\r\n } catch {\r\n sqlTraceGlobs = [];\r\n }\r\n\r\n return {\r\n ...nextConfig,\r\n // `serverExternalPackages` é reforço (não o conserto do caso webpackIgnore);\r\n // o `outputFileTracingIncludes` computado é o que realmente inclui o closure.\r\n serverExternalPackages: mergeServerExternalPackages(nextConfig.serverExternalPackages),\r\n outputFileTracingIncludes: mergeOutputFileTracingIncludes(\r\n nextConfig.outputFileTracingIncludes,\r\n sqlTraceGlobs,\r\n ),\r\n webpack(config: unknown, context: MinimalWebpackContext): unknown {\r\n const result = typeof prevWebpack === 'function' ? prevWebpack(config, context) : config;\r\n\r\n // Grava só na passada server (roda 1x por build, diferente da passada\r\n // client que pode rodar múltiplas vezes) e só fora de `next dev` —\r\n // `next build` é sempre produção de artefato de deploy.\r\n if (!context.dev && context.isServer) {\r\n const manifest: NeetruBuildManifest = {\r\n builtEnv: process.env.NEXT_PUBLIC_NEETRU_ENV ?? null,\r\n productId: process.env.NEXT_PUBLIC_NEETRU_PRODUCT_ID ?? null,\r\n oidcClientId: process.env.NEXT_PUBLIC_NEETRU_OIDC_CLIENT_ID ?? null,\r\n builtAt: new Date().toISOString(),\r\n };\r\n\r\n try {\r\n const outDir = path.resolve(process.cwd(), options.outputDir ?? '.next');\r\n fs.mkdirSync(outDir, { recursive: true });\r\n fs.writeFileSync(\r\n path.join(outDir, 'neetru-build-manifest.json'),\r\n JSON.stringify(manifest, null, 2),\r\n 'utf8',\r\n );\r\n } catch (err) {\r\n // Best-effort — a FALHA DE ESCRITA do manifesto nunca pode quebrar o\r\n // build do produto, mas uma falha silenciosa aqui esconderia o\r\n // problema (achado da revisão: sem log, ninguém percebe que o\r\n // manifesto não foi gravado e `neetru build` trata \"manifesto\r\n // ausente\" como aviso, não bloqueio — visibilidade aqui é a única\r\n // forma de notar).\r\n if (typeof console !== 'undefined') {\r\n console.warn(\r\n '[neetru-sdk] withNeetruBuildGuard: falha ao gravar neetru-build-manifest.json (ignorado, build segue):',\r\n err,\r\n );\r\n }\r\n }\r\n\r\n // FAIL-LOUD (incidente gestovendas 2026-09-06): DEPOIS de gravar o\r\n // manifesto (best-effort) e FORA do try/catch acima — este throw é\r\n // DE PROPÓSITO e DEVE escapar pra falhar o `next build` (exit ≠ 0)\r\n // quando um build de produção está sem o client_id/productId do OIDC.\r\n // Só prod enforça; dev/workspace passam direto (ver\r\n // assertNeetruProdBuildEnv).\r\n assertNeetruProdBuildEnv(manifest);\r\n }\r\n\r\n return result;\r\n },\r\n } as T;\r\n}\r\n"]}
package/dist/db.cjs CHANGED
@@ -683,13 +683,17 @@ var init_lease = __esm({
683
683
  // src/db/sql/sql-client.ts
684
684
  var sql_client_exports = {};
685
685
  __export(sql_client_exports, {
686
+ DEFAULT_POOL_CONNECT_TIMEOUT_MS: () => DEFAULT_POOL_CONNECT_TIMEOUT_MS,
687
+ DEFAULT_POOL_IDLE_MS: () => DEFAULT_POOL_IDLE_MS,
688
+ DEFAULT_POOL_MAX: () => DEFAULT_POOL_MAX,
686
689
  LEASE_ENDPOINT: () => LEASE_ENDPOINT,
687
690
  LEASE_RENEW_ENDPOINT: () => LEASE_RENEW_ENDPOINT,
688
691
  createDrizzleHandle: () => createDrizzleHandle,
689
692
  createHttpLeaseFetcher: () => createHttpLeaseFetcher,
690
693
  createPgPool: () => createPgPool,
691
694
  createSqlClientFromConfig: () => createSqlClientFromConfig,
692
- createSqlClientWithDeps: () => createSqlClientWithDeps
695
+ createSqlClientWithDeps: () => createSqlClientWithDeps,
696
+ resolvePoolTuning: () => resolvePoolTuning
693
697
  });
694
698
  function mapEnvToCore(sdkEnv) {
695
699
  if (sdkEnv === "workspace") return "staging";
@@ -778,6 +782,30 @@ function parseLease(raw) {
778
782
  expiresAt: req("expiresAt", "string")
779
783
  };
780
784
  }
785
+ function readEnvInt(name, def, min, max) {
786
+ const raw = typeof process !== "undefined" ? process.env?.[name] : void 0;
787
+ if (raw === void 0 || raw.trim() === "") return def;
788
+ const n = Number.parseInt(raw.trim(), 10);
789
+ if (!Number.isFinite(n) || n < min || n > max) return def;
790
+ return n;
791
+ }
792
+ function resolvePoolTuning() {
793
+ return {
794
+ // Teto 100: bem abaixo do `max_client_conn = 500` do PgBouncer, com folga
795
+ // para múltiplas instâncias do app dividirem o mesmo front-door.
796
+ max: readEnvInt("NEETRU_DB_POOL_MAX", DEFAULT_POOL_MAX, 1, 100),
797
+ // Teto 15min = janela do cert; piso 1s.
798
+ idleTimeoutMillis: readEnvInt("NEETRU_DB_POOL_IDLE_MS", DEFAULT_POOL_IDLE_MS, 1e3, 9e5),
799
+ connectionTimeoutMillis: readEnvInt(
800
+ "NEETRU_DB_POOL_CONNECT_TIMEOUT_MS",
801
+ DEFAULT_POOL_CONNECT_TIMEOUT_MS,
802
+ 1e3,
803
+ 12e4
804
+ ),
805
+ keepAlive: true,
806
+ keepAliveInitialDelayMillis: 1e4
807
+ };
808
+ }
781
809
  async function createPgPool(lease) {
782
810
  const { Pool } = await import(
783
811
  /* webpackIgnore: true */
@@ -796,9 +824,7 @@ async function createPgPool(lease) {
796
824
  user: lease.user,
797
825
  password: lease.password,
798
826
  ssl,
799
- max: 3,
800
- idleTimeoutMillis: 3e4,
801
- connectionTimeoutMillis: 1e4
827
+ ...resolvePoolTuning()
802
828
  });
803
829
  }
804
830
  async function createDrizzleHandle(pool, schema) {
@@ -933,9 +959,9 @@ async function createSqlClientFromConfig(config, schema, options) {
933
959
  user: lease.user,
934
960
  password: lease.password,
935
961
  ssl,
936
- max: 3,
937
- idleTimeoutMillis: 3e4,
938
- connectionTimeoutMillis: 1e4
962
+ // Tuning centralizado (env-tunável) — ver resolvePoolTuning + auditoria
963
+ // docs/_review/AUDITORIA_DB_CONN_PERF_2026-09-06.md no Core.
964
+ ...resolvePoolTuning()
939
965
  });
940
966
  };
941
967
  const createDrizzle = (pool, s) => {
@@ -958,7 +984,7 @@ async function createSqlClientFromConfig(config, schema, options) {
958
984
  options
959
985
  );
960
986
  }
961
- var LEASE_ENDPOINT, LEASE_RENEW_ENDPOINT;
987
+ var LEASE_ENDPOINT, LEASE_RENEW_ENDPOINT, DEFAULT_POOL_MAX, DEFAULT_POOL_IDLE_MS, DEFAULT_POOL_CONNECT_TIMEOUT_MS;
962
988
  var init_sql_client = __esm({
963
989
  "src/db/sql/sql-client.ts"() {
964
990
  init_db_errors();
@@ -967,6 +993,9 @@ var init_sql_client = __esm({
967
993
  init_resilient_pool();
968
994
  LEASE_ENDPOINT = "/api/sdk/v1/db/lease";
969
995
  LEASE_RENEW_ENDPOINT = "/api/sdk/v1/db/lease/renew";
996
+ DEFAULT_POOL_MAX = 10;
997
+ DEFAULT_POOL_IDLE_MS = 6e4;
998
+ DEFAULT_POOL_CONNECT_TIMEOUT_MS = 1e4;
970
999
  }
971
1000
  });
972
1001