@mybuildex/pkg 0.8.0 → 0.10.0
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/README.md +26 -0
- package/dist/build/autoload-static.d.ts +10 -0
- package/dist/build/autoload-static.js +155 -0
- package/dist/build/autoload-static.js.map +1 -0
- package/dist/build/bundle.d.ts +28 -0
- package/dist/build/bundle.js +84 -0
- package/dist/build/bundle.js.map +1 -0
- package/dist/build/cli.d.ts +2 -0
- package/dist/build/cli.js +60 -0
- package/dist/build/cli.js.map +1 -0
- package/dist/build/verify-bundle.d.ts +20 -0
- package/dist/build/verify-bundle.js +116 -0
- package/dist/build/verify-bundle.js.map +1 -0
- package/dist/http/gcf-handler.d.ts +9 -0
- package/dist/http/gcf-handler.js +7 -1
- package/dist/http/gcf-handler.js.map +1 -1
- package/dist/redis/client.d.ts +1 -1
- package/dist/redis/client.js +4 -20
- package/dist/redis/client.js.map +1 -1
- package/dist/tenant/permissions.d.ts +11 -2
- package/dist/tenant/permissions.js +40 -2
- package/dist/tenant/permissions.js.map +1 -1
- package/package.json +10 -2
package/README.md
CHANGED
|
@@ -51,6 +51,32 @@ createAuthMiddleware({
|
|
|
51
51
|
createTenantMiddleware({getTenantClient, defaultClient, strictTenant: true});
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
+
## 0.10.0 — bundle da API e boot antecipado
|
|
55
|
+
|
|
56
|
+
Tudo opt-in: API que não usa não muda. Medido no piloto da `v3_peoples` (04/10/2026): boot do código da API de 4,8 s para 1,45 s e primeiro GET em instância fria de 4,6 s para 0,79 s.
|
|
57
|
+
|
|
58
|
+
- **`mybuildex-bundle`** (comando de build) — empacota `dist/index.js` em `dist/bundle.js` com o esbuild. No Cloud Run cada `require()` custa ~3 ms e o boot lia ~1.280 arquivos; o bundle troca isso por um arquivo. O `@fastify/autoload` não funciona dentro de um bundle (ele varre a pasta de módulos em runtime), então o comando faz a mesma varredura no build e gera um plugin estático equivalente (`dist/autoload-static.js`), com as regras do autoload 5.x. Depois **confere** que as rotas do bundle são idênticas às do autoload (compara o swagger das duas entradas) e quebra o build se divergirem. `src/app.ts` não muda; dev e teste seguem no autoload de verdade.
|
|
59
|
+
|
|
60
|
+
```jsonc
|
|
61
|
+
// package.json da API
|
|
62
|
+
"main": "dist/bundle.js",
|
|
63
|
+
"scripts": { "build": "tsc && mybuildex-bundle", "gcp-build": "npm run build" },
|
|
64
|
+
"devDependencies": { "esbuild": "^0.28.2" },
|
|
65
|
+
// opcional: libs que a API só carrega sob demanda ficam fora do bundle
|
|
66
|
+
"mybuildex": { "bundle": { "external": ["exceljs", "pdf-lib"] } }
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Ficam sempre fora do bundle (vêm do `node_modules`): `@fastify/swagger-ui`, `firebase-admin`, `@google-cloud/storage`, `redis`, `@google/genai` e o WASM do Prisma. A verificação sobe a API com banco falso (porta morta) e precisa do que ela precisa para carregar (ex.: `firebase.json`); `verifyEnv` passa env a mais, `--no-verify` pula. Não cobre `autoHooks` (o comando lança). Stack trace passa a apontar para o `bundle.js`.
|
|
70
|
+
- **`createGcfHandler({server, eagerBoot: true})`** — dispara o `ready()` logo depois da carga do módulo, em vez de esperar a primeira request: a instância que sobe antes do tráfego chega pronta. As garantias do wrapper valem igual (sem `unhandledRejection`; falha de boot vira 503 + saída na request seguinte).
|
|
71
|
+
|
|
72
|
+
## 0.9.0 — cold start e tamanho do bundle
|
|
73
|
+
|
|
74
|
+
**Muda a instalação** (⚠️): a CLI `prisma` saiu das `dependencies` do pacote.
|
|
75
|
+
|
|
76
|
+
- ⚠️ `prisma` (CLI) não vem mais junto. Ela só serve para `prisma generate`/`db pull`, mas como dependência de produção arrastava `@prisma/studio-core`, `@prisma/dev`, `pglite`, `effect` e `@prisma/engines` para a imagem de toda API (~250 MB). A API que roda `prisma generate` declara a CLI nela, na MESMA versão do `@prisma/client` deste pacote: `npm i -D prisma@7.10.0`. `@prisma/client`, `@prisma/adapter-mariadb` e `mariadb` continuam vindo daqui.
|
|
77
|
+
- `createRedisClient()` só carrega o `redis` quando há o que conectar (env `REDIS` ou `options`). API sem Redis deixa de carregar ~480 módulos no cold start. Nada muda para quem usa.
|
|
78
|
+
- `createPermissionsResolver({memoryCacheTtlMs})` — cache em memória da instância, por `idSchool:uid`, **opt-in** (default desligado) e só usado **sem** `redis`. Sem Redis a consulta de permissões rodava em toda request autenticada. Não há invalidação entre instâncias: mudança de permissão leva até o TTL para valer, então mantenha curto (o cache de token e o de vínculo usam 120 s). Erro de consulta nunca é guardado; `resolver.clearCache()` esvazia.
|
|
79
|
+
|
|
54
80
|
## 0.8.0 — API single-tenant só aceita token do tenant default
|
|
55
81
|
|
|
56
82
|
**Muda comportamento por padrão** (⚠️) em quem usa `tenantAware: false` — hoje só o `v1_core`.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface AutoloadEntry {
|
|
2
|
+
/** Caminho absoluto do arquivo. */
|
|
3
|
+
file: string;
|
|
4
|
+
/** Prefixo de diretório que o autoload daria (undefined na raiz). */
|
|
5
|
+
prefix: string | undefined;
|
|
6
|
+
}
|
|
7
|
+
/** A mesma varredura do findPlugins do autoload (dirNameRoutePrefix: true, sem autoHooks). */
|
|
8
|
+
export declare function findAutoloadEntries(dir: string, prefix?: string, found?: AutoloadEntry[]): AutoloadEntry[];
|
|
9
|
+
/** Código-fonte (CommonJS) do plugin estático; `fromDir` é a pasta onde ele será gravado. */
|
|
10
|
+
export declare function renderAutoloadStatic(entries: AutoloadEntry[], fromDir: string): string;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.findAutoloadEntries = findAutoloadEntries;
|
|
7
|
+
exports.renderAutoloadStatic = renderAutoloadStatic;
|
|
8
|
+
// Equivalente ESTÁTICO do @fastify/autoload, gerado em tempo de build.
|
|
9
|
+
//
|
|
10
|
+
// O autoload varre a pasta de módulos em RUNTIME (readdir) e dá require() em
|
|
11
|
+
// cada arquivo pelo caminho. Dentro de um bundle essa pasta não é lida — os
|
|
12
|
+
// módulos estão embutidos — então o autoload não acharia rota nenhuma (ou
|
|
13
|
+
// acharia os arquivos soltos e carregaria tudo de novo, fora do bundle).
|
|
14
|
+
//
|
|
15
|
+
// Aqui a MESMA varredura roda no build (findAutoloadEntries) e vira um plugin
|
|
16
|
+
// com um require() fixo por arquivo (renderAutoloadStatic), que o bundler
|
|
17
|
+
// embute. As regras de "é plugin?", autoPrefix, prefixOverride, autoConfig e
|
|
18
|
+
// dependências são as do autoload 5.x (loadPlugin/registerPlugin), copiadas.
|
|
19
|
+
// Não cobre autoHooks: a varredura lança se encontrar um.
|
|
20
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
21
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
22
|
+
// Padrões copiados dos defaults do @fastify/autoload 5.x.
|
|
23
|
+
const scriptPattern = /(?:(?:^.?|\.[^d]|[^.]d|[^.][^d])\.ts|\.js|\.cjs|\.mjs|\.cts|\.mts)$/iu;
|
|
24
|
+
const indexPattern = /^index(?:\.ts|\.js|\.cjs|\.mjs|\.cts|\.mts)$/iu;
|
|
25
|
+
const autoHooksPattern = /^[_.]?auto_?hooks(?:\.ts|\.js|\.cjs|\.mjs|\.cts|\.mts)$/iu;
|
|
26
|
+
/** A mesma varredura do findPlugins do autoload (dirNameRoutePrefix: true, sem autoHooks). */
|
|
27
|
+
function findAutoloadEntries(dir, prefix, found = []) {
|
|
28
|
+
const list = node_fs_1.default.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
29
|
+
if (list.some((d) => autoHooksPattern.test(d.name))) {
|
|
30
|
+
throw new Error(`autohooks em ${dir}: o autoload estático não cobre autoHooks`);
|
|
31
|
+
}
|
|
32
|
+
const indexDirent = list.find((d) => indexPattern.test(d.name));
|
|
33
|
+
if (indexDirent) {
|
|
34
|
+
found.push({ file: node_path_1.default.join(dir, indexDirent.name), prefix });
|
|
35
|
+
if (!list.some((d) => d.isDirectory()))
|
|
36
|
+
return found;
|
|
37
|
+
}
|
|
38
|
+
if (list.some((d) => d.name === "package.json") && !indexDirent) {
|
|
39
|
+
throw new Error(`@fastify/autoload não importaria o plugin em '${dir}' (package.json sem index)`);
|
|
40
|
+
}
|
|
41
|
+
for (const dirent of list) {
|
|
42
|
+
const file = node_path_1.default.join(dir, dirent.name);
|
|
43
|
+
if (dirent.isDirectory()) {
|
|
44
|
+
findAutoloadEntries(file, (prefix ? `${prefix}/` : "/") + dirent.name, found);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (indexDirent)
|
|
48
|
+
continue;
|
|
49
|
+
if (dirent.isFile() && scriptPattern.test(dirent.name))
|
|
50
|
+
found.push({ file, prefix });
|
|
51
|
+
}
|
|
52
|
+
return found;
|
|
53
|
+
}
|
|
54
|
+
/** Código-fonte (CommonJS) do plugin estático; `fromDir` é a pasta onde ele será gravado. */
|
|
55
|
+
function renderAutoloadStatic(entries, fromDir) {
|
|
56
|
+
const rel = (file) => {
|
|
57
|
+
const r = node_path_1.default.relative(fromDir, file).split(node_path_1.default.sep).join("/");
|
|
58
|
+
return r.startsWith(".") ? r : `./${r}`;
|
|
59
|
+
};
|
|
60
|
+
const lines = entries.map((e) => ` {file: ${JSON.stringify(rel(e.file))}, prefix: ${JSON.stringify(e.prefix)}, load: () => require(${JSON.stringify(rel(e.file))})},`);
|
|
61
|
+
return `// GERADO pelo mybuildex-bundle (@mybuildex/pkg) — NÃO EDITAR.
|
|
62
|
+
// Equivalente estático do @fastify/autoload: lista fixa de arquivos (um
|
|
63
|
+
// require por arquivo, que o bundler embute) com as regras do autoload 5.x.
|
|
64
|
+
"use strict";
|
|
65
|
+
|
|
66
|
+
const entries = [
|
|
67
|
+
${lines.join("\n")}
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
function isRouteObject(input) {
|
|
71
|
+
return !!input && Object.prototype.toString.call(input) === "[object Object]" &&
|
|
72
|
+
Object.prototype.hasOwnProperty.call(input, "method");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function isPluginOrModule(input) {
|
|
76
|
+
const inputType = Object.prototype.toString.call(input);
|
|
77
|
+
if (/\\[object (?:AsyncFunction|Function|Module)\\]/u.test(inputType)) return true;
|
|
78
|
+
if (Object.prototype.hasOwnProperty.call(input, "default")) return isPluginOrModule(input.default);
|
|
79
|
+
return isRouteObject(input);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function wrapRoutes(content) {
|
|
83
|
+
if (isRouteObject(content)) {
|
|
84
|
+
return async function (fastify) {
|
|
85
|
+
fastify.route(content);
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
return content;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function loadPlugin(entry, overrideConfig) {
|
|
92
|
+
const content = entry.load();
|
|
93
|
+
if (isPluginOrModule(content) === false) return undefined;
|
|
94
|
+
|
|
95
|
+
const plugin = wrapRoutes(content.default || content);
|
|
96
|
+
const pluginConfig = (content.default && content.default.autoConfig) || content.autoConfig || {};
|
|
97
|
+
const pluginOptions = Object.assign({}, pluginConfig, overrideConfig);
|
|
98
|
+
const pluginMeta = plugin[Symbol.for("plugin-meta")] || {};
|
|
99
|
+
|
|
100
|
+
if (plugin.autoload === false || content.autoload === false) return undefined;
|
|
101
|
+
if (plugin.autoConfig !== undefined) plugin.autoConfig = undefined;
|
|
102
|
+
|
|
103
|
+
pluginOptions.prefix = (pluginOptions.prefix && pluginOptions.prefix.endsWith("/")) ? pluginOptions.prefix.slice(0, -1) : pluginOptions.prefix;
|
|
104
|
+
const prefixOverride = plugin.prefixOverride !== undefined ? plugin.prefixOverride : content.prefixOverride !== undefined ? content.prefixOverride : undefined;
|
|
105
|
+
const prefix = (plugin.autoPrefix !== undefined ? plugin.autoPrefix : content.autoPrefix !== undefined ? content.autoPrefix : undefined) || entry.prefix;
|
|
106
|
+
if (prefixOverride !== undefined) {
|
|
107
|
+
pluginOptions.prefix = prefixOverride;
|
|
108
|
+
} else if (prefix) {
|
|
109
|
+
pluginOptions.prefix = (pluginOptions.prefix || "") + prefix.replace(/\\/+/gu, "/");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
plugin,
|
|
114
|
+
filename: entry.file,
|
|
115
|
+
name: pluginMeta.name || entry.file,
|
|
116
|
+
dependencies: pluginMeta.dependencies,
|
|
117
|
+
options: pluginOptions,
|
|
118
|
+
registered: false,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function registerPlugin(fastify, meta, allPlugins, parentPlugins = {}) {
|
|
123
|
+
const {plugin, name, options, dependencies = []} = meta;
|
|
124
|
+
if (parentPlugins[name]) throw new Error("Cyclic dependency");
|
|
125
|
+
if (meta.registered) return;
|
|
126
|
+
parentPlugins[name] = true;
|
|
127
|
+
for (const dependency of dependencies) {
|
|
128
|
+
if (allPlugins[dependency]) registerPlugin(fastify, allPlugins[dependency], allPlugins, {...parentPlugins});
|
|
129
|
+
}
|
|
130
|
+
fastify.register(plugin, options);
|
|
131
|
+
meta.registered = true;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const autoloadStatic = async function autoloadStatic(fastify, options) {
|
|
135
|
+
const pluginsMeta = {};
|
|
136
|
+
for (const entry of entries) {
|
|
137
|
+
const meta = loadPlugin(entry, options && options.options);
|
|
138
|
+
if (meta) pluginsMeta[meta.name] = meta;
|
|
139
|
+
}
|
|
140
|
+
const metas = Object.values(pluginsMeta);
|
|
141
|
+
for (const entry of entries) {
|
|
142
|
+
const meta = metas.find((m) => m.filename === entry.file);
|
|
143
|
+
if (meta) registerPlugin(fastify, meta, pluginsMeta);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// não cria contexto novo, igual ao autoload (e ao fastify-plugin)
|
|
148
|
+
autoloadStatic[Symbol.for("skip-override")] = true;
|
|
149
|
+
|
|
150
|
+
module.exports = autoloadStatic;
|
|
151
|
+
module.exports.fastifyAutoload = autoloadStatic;
|
|
152
|
+
module.exports.default = autoloadStatic;
|
|
153
|
+
`;
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=autoload-static.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autoload-static.js","sourceRoot":"","sources":["../../src/build/autoload-static.ts"],"names":[],"mappings":";;;;;AA4BA,kDAuBC;AAGD,oDAoGC;AA1JD,uEAAuE;AACvE,EAAE;AACF,6EAA6E;AAC7E,4EAA4E;AAC5E,0EAA0E;AAC1E,yEAAyE;AACzE,EAAE;AACF,8EAA8E;AAC9E,0EAA0E;AAC1E,6EAA6E;AAC7E,6EAA6E;AAC7E,0DAA0D;AAC1D,sDAAyB;AACzB,0DAA6B;AAS7B,0DAA0D;AAC1D,MAAM,aAAa,GAAG,uEAAuE,CAAC;AAC9F,MAAM,YAAY,GAAG,gDAAgD,CAAC;AACtE,MAAM,gBAAgB,GAAG,2DAA2D,CAAC;AAErF,8FAA8F;AAC9F,SAAgB,mBAAmB,CAAC,GAAW,EAAE,MAAe,EAAE,QAAyB,EAAE;IACzF,MAAM,IAAI,GAAG,iBAAE,CAAC,WAAW,CAAC,GAAG,EAAE,EAAC,aAAa,EAAE,IAAI,EAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACrG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,gBAAgB,GAAG,2CAA2C,CAAC,CAAC;IACpF,CAAC;IACD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAChE,IAAI,WAAW,EAAE,CAAC;QACd,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,mBAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,EAAC,CAAC,CAAC;QAC7D,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;YAAE,OAAO,KAAK,CAAC;IACzD,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,cAAc,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QAC9D,MAAM,IAAI,KAAK,CAAC,iDAAiD,GAAG,4BAA4B,CAAC,CAAC;IACtG,CAAC;IACD,KAAK,MAAM,MAAM,IAAI,IAAI,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,mBAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QACzC,IAAI,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;YACvB,mBAAmB,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAC9E,SAAS;QACb,CAAC;QACD,IAAI,WAAW;YAAE,SAAS;QAC1B,IAAI,MAAM,CAAC,MAAM,EAAE,IAAI,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,MAAM,EAAC,CAAC,CAAC;IACvF,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,6FAA6F;AAC7F,SAAgB,oBAAoB,CAAC,OAAwB,EAAE,OAAe;IAC1E,MAAM,GAAG,GAAG,CAAC,IAAY,EAAE,EAAE;QACzB,MAAM,CAAC,GAAG,mBAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,mBAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;IAC5C,CAAC,CAAC;IACF,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAC5B,cAAc,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,yBAAyB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC;IAC7I,OAAO;;;;;;EAMT,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsFjB,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Pacotes que ficam FORA do bundle (continuam vindo do node_modules em runtime). */
|
|
2
|
+
export declare const DEFAULT_BUNDLE_EXTERNAL: readonly string[];
|
|
3
|
+
export interface BundleOptions {
|
|
4
|
+
/** Raiz da API (default: process.cwd()). */
|
|
5
|
+
root?: string;
|
|
6
|
+
/** Pasta do compilado, relativa à raiz (default: "dist"). */
|
|
7
|
+
distDir?: string;
|
|
8
|
+
/** Entrada, relativa a distDir (default: "index.js"). */
|
|
9
|
+
entry?: string;
|
|
10
|
+
/** Saída, relativa a distDir (default: "bundle.js"). */
|
|
11
|
+
outfile?: string;
|
|
12
|
+
/** Pasta que o @fastify/autoload varre, relativa a distDir (default: "modules"). */
|
|
13
|
+
modulesDir?: string;
|
|
14
|
+
/** Pacotes a mais fora do bundle — tipicamente os que a API só carrega sob
|
|
15
|
+
* demanda (`await import("exceljs")`). Somam aos DEFAULT_BUNDLE_EXTERNAL. */
|
|
16
|
+
external?: string[];
|
|
17
|
+
/** `target` do esbuild (default: "node22"). */
|
|
18
|
+
target?: string;
|
|
19
|
+
/** Log (default: console.log). */
|
|
20
|
+
log?: (message: string) => void;
|
|
21
|
+
}
|
|
22
|
+
export interface BundleResult {
|
|
23
|
+
outfile: string;
|
|
24
|
+
bytes: number;
|
|
25
|
+
inputs: number;
|
|
26
|
+
autoloadEntries: number;
|
|
27
|
+
}
|
|
28
|
+
export declare function bundleApi(options?: BundleOptions): Promise<BundleResult>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.DEFAULT_BUNDLE_EXTERNAL = void 0;
|
|
7
|
+
exports.bundleApi = bundleApi;
|
|
8
|
+
// Empacota a API num arquivo só para o cold start.
|
|
9
|
+
//
|
|
10
|
+
// POR QUÊ: no Cloud Run cada require() custa ~3 ms (medido na v3_peoples em
|
|
11
|
+
// 04/10/2026: 79% do boot era require de ~1.280 arquivos; com o bundle o boot
|
|
12
|
+
// caiu de 4,8 s para 1,45 s). Um arquivo só troca mais de mil leituras por uma.
|
|
13
|
+
//
|
|
14
|
+
// O @fastify/autoload não funciona dentro de um bundle; aqui ele é trocado
|
|
15
|
+
// (alias) pelo equivalente estático gerado em ./autoload-static. O código da
|
|
16
|
+
// API não muda: dev e teste seguem no autoload de verdade.
|
|
17
|
+
//
|
|
18
|
+
// Só ferramenta de BUILD: nada daqui é exportado pelo index do pacote, e o
|
|
19
|
+
// esbuild é dependência de desenvolvimento da API (peer opcional daqui).
|
|
20
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
21
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
22
|
+
const autoload_static_1 = require("./autoload-static");
|
|
23
|
+
/** Pacotes que ficam FORA do bundle (continuam vindo do node_modules em runtime). */
|
|
24
|
+
exports.DEFAULT_BUNDLE_EXTERNAL = [
|
|
25
|
+
// serve arquivos estáticos da própria pasta (path.join(__dirname, "static"))
|
|
26
|
+
"@fastify/swagger-ui",
|
|
27
|
+
// carrega os serviços por require() sob demanda; no boot são poucos arquivos
|
|
28
|
+
"firebase-admin",
|
|
29
|
+
// só carregam quando usados: dentro do bundle só aumentariam o arquivo que
|
|
30
|
+
// o Node lê em todo cold start
|
|
31
|
+
"@google-cloud/storage",
|
|
32
|
+
"redis",
|
|
33
|
+
"@google/genai",
|
|
34
|
+
// WASM do query compiler do Prisma (MBs em base64): o client gerado só o
|
|
35
|
+
// importa na primeira query
|
|
36
|
+
"@prisma/client/runtime/*.wasm-base64.js",
|
|
37
|
+
];
|
|
38
|
+
function loadEsbuild(root) {
|
|
39
|
+
try {
|
|
40
|
+
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
41
|
+
return require(require.resolve("esbuild", { paths: [root, __dirname] }));
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
throw new Error("mybuildex-bundle precisa do esbuild na API: npm i -D esbuild");
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async function bundleApi(options = {}) {
|
|
48
|
+
const root = node_path_1.default.resolve(options.root ?? process.cwd());
|
|
49
|
+
const dist = node_path_1.default.join(root, options.distDir ?? "dist");
|
|
50
|
+
const entry = node_path_1.default.join(dist, options.entry ?? "index.js");
|
|
51
|
+
const outfile = node_path_1.default.join(dist, options.outfile ?? "bundle.js");
|
|
52
|
+
const modulesDir = node_path_1.default.join(dist, options.modulesDir ?? "modules");
|
|
53
|
+
const shim = node_path_1.default.join(dist, "autoload-static.js");
|
|
54
|
+
const log = options.log ?? ((message) => console.log(message));
|
|
55
|
+
if (!node_fs_1.default.existsSync(entry))
|
|
56
|
+
throw new Error(`${node_path_1.default.relative(root, entry)} não existe: rode o tsc antes`);
|
|
57
|
+
const alias = {};
|
|
58
|
+
let autoloadEntries = 0;
|
|
59
|
+
if (node_fs_1.default.existsSync(modulesDir)) {
|
|
60
|
+
const entries = (0, autoload_static_1.findAutoloadEntries)(modulesDir);
|
|
61
|
+
node_fs_1.default.writeFileSync(shim, (0, autoload_static_1.renderAutoloadStatic)(entries, dist));
|
|
62
|
+
alias["@fastify/autoload"] = shim;
|
|
63
|
+
autoloadEntries = entries.length;
|
|
64
|
+
}
|
|
65
|
+
const esbuild = loadEsbuild(root);
|
|
66
|
+
const result = await esbuild.build({
|
|
67
|
+
entryPoints: [entry],
|
|
68
|
+
outfile,
|
|
69
|
+
bundle: true,
|
|
70
|
+
platform: "node",
|
|
71
|
+
target: options.target ?? "node22",
|
|
72
|
+
format: "cjs",
|
|
73
|
+
external: [...exports.DEFAULT_BUNDLE_EXTERNAL, ...(options.external ?? [])],
|
|
74
|
+
alias,
|
|
75
|
+
legalComments: "none",
|
|
76
|
+
logLevel: "warning",
|
|
77
|
+
metafile: true,
|
|
78
|
+
});
|
|
79
|
+
const bytes = node_fs_1.default.statSync(outfile).size;
|
|
80
|
+
const inputs = Object.keys(result.metafile.inputs).length;
|
|
81
|
+
log(`bundle: ${node_path_1.default.relative(root, outfile)} ${(bytes / 1e6).toFixed(1)} MB (${inputs} arquivos embutidos, ${autoloadEntries} arquivos de módulo no autoload estático)`);
|
|
82
|
+
return { outfile, bytes, inputs, autoloadEntries };
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=bundle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundle.js","sourceRoot":"","sources":["../../src/build/bundle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
// mybuildex-bundle — empacota a API (dist/index.js -> dist/bundle.js) e confere
|
|
8
|
+
// que as rotas do bundle são idênticas às do @fastify/autoload.
|
|
9
|
+
//
|
|
10
|
+
// Uso na API (package.json):
|
|
11
|
+
// "main": "dist/bundle.js",
|
|
12
|
+
// "scripts": { "build": "tsc && mybuildex-bundle" }
|
|
13
|
+
//
|
|
14
|
+
// Configuração opcional, no package.json da API:
|
|
15
|
+
// "mybuildex": { "bundle": {
|
|
16
|
+
// "external": ["exceljs", "pdf-lib"], // libs que a API só carrega sob demanda
|
|
17
|
+
// "verifyEnv": {"MINHA_ENV": "x"}, // env a mais para a API carregar na verificação
|
|
18
|
+
// "swaggerPath": "/documentation/json",
|
|
19
|
+
// "entry": "index.js", "outfile": "bundle.js", "modulesDir": "modules", "distDir": "dist"
|
|
20
|
+
// } }
|
|
21
|
+
//
|
|
22
|
+
// Flags: --no-verify (só empacota). MYBUILDEX_BUNDLE_VERIFY=0 faz o mesmo.
|
|
23
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
24
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
25
|
+
const bundle_1 = require("./bundle");
|
|
26
|
+
const verify_bundle_1 = require("./verify-bundle");
|
|
27
|
+
async function main() {
|
|
28
|
+
const root = process.cwd();
|
|
29
|
+
const pkgFile = node_path_1.default.join(root, "package.json");
|
|
30
|
+
const pkg = node_fs_1.default.existsSync(pkgFile) ? JSON.parse(node_fs_1.default.readFileSync(pkgFile, "utf8")) : {};
|
|
31
|
+
const config = pkg?.mybuildex?.bundle ?? {};
|
|
32
|
+
const skipVerify = process.argv.includes("--no-verify") || process.env.MYBUILDEX_BUNDLE_VERIFY === "0";
|
|
33
|
+
await (0, bundle_1.bundleApi)({
|
|
34
|
+
root,
|
|
35
|
+
distDir: config.distDir,
|
|
36
|
+
entry: config.entry,
|
|
37
|
+
outfile: config.outfile,
|
|
38
|
+
modulesDir: config.modulesDir,
|
|
39
|
+
external: config.external,
|
|
40
|
+
target: config.target,
|
|
41
|
+
});
|
|
42
|
+
if (skipVerify) {
|
|
43
|
+
console.log("verify-bundle: pulado (--no-verify)");
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const { routes } = (0, verify_bundle_1.verifyBundle)({
|
|
47
|
+
root,
|
|
48
|
+
distDir: config.distDir,
|
|
49
|
+
entry: config.entry,
|
|
50
|
+
outfile: config.outfile,
|
|
51
|
+
swaggerPath: config.swaggerPath,
|
|
52
|
+
env: config.verifyEnv,
|
|
53
|
+
});
|
|
54
|
+
console.log(`verify-bundle: ok — ${routes} rotas idênticas no autoload e no bundle`);
|
|
55
|
+
}
|
|
56
|
+
main().catch((error) => {
|
|
57
|
+
console.error(error?.message ?? error);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
});
|
|
60
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/build/cli.ts"],"names":[],"mappings":";;;;;;AACA,gFAAgF;AAChF,gEAAgE;AAChE,EAAE;AACF,6BAA6B;AAC7B,8BAA8B;AAC9B,sDAAsD;AACtD,EAAE;AACF,iDAAiD;AACjD,+BAA+B;AAC/B,0FAA0F;AAC1F,kGAAkG;AAClG,8CAA8C;AAC9C,gGAAgG;AAChG,QAAQ;AACR,EAAE;AACF,2EAA2E;AAC3E,sDAAyB;AACzB,0DAA6B;AAC7B,qCAAmC;AACnC,mDAA6C;AAE7C,KAAK,UAAU,IAAI;IACf,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC3B,MAAM,OAAO,GAAG,mBAAI,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,iBAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,iBAAE,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACvF,MAAM,MAAM,GAAG,GAAG,EAAE,SAAS,EAAE,MAAM,IAAI,EAAE,CAAC;IAC5C,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,uBAAuB,KAAK,GAAG,CAAC;IAEvG,MAAM,IAAA,kBAAS,EAAC;QACZ,IAAI;QACJ,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,MAAM,EAAE,MAAM,CAAC,MAAM;KACxB,CAAC,CAAC;IAEH,IAAI,UAAU,EAAE,CAAC;QACb,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;QACnD,OAAO;IACX,CAAC;IACD,MAAM,EAAC,MAAM,EAAC,GAAG,IAAA,4BAAY,EAAC;QAC1B,IAAI;QACJ,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,GAAG,EAAE,MAAM,CAAC,SAAS;KACxB,CAAC,CAAC;IACH,OAAO,CAAC,GAAG,CAAC,uBAAuB,MAAM,0CAA0C,CAAC,CAAC;AACzF,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,IAAI,KAAK,CAAC,CAAC;IACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface VerifyBundleOptions {
|
|
2
|
+
/** Raiz da API (default: process.cwd()). */
|
|
3
|
+
root?: string;
|
|
4
|
+
/** Pasta do compilado, relativa à raiz (default: "dist"). */
|
|
5
|
+
distDir?: string;
|
|
6
|
+
/** Entrada original, relativa a distDir (default: "index.js"). */
|
|
7
|
+
entry?: string;
|
|
8
|
+
/** Bundle, relativo a distDir (default: "bundle.js"). */
|
|
9
|
+
outfile?: string;
|
|
10
|
+
/** Caminho do JSON do swagger (default: "/documentation/json"). */
|
|
11
|
+
swaggerPath?: string;
|
|
12
|
+
/** Variáveis de ambiente a mais para a API carregar na verificação. */
|
|
13
|
+
env?: Record<string, string>;
|
|
14
|
+
/** Tempo máximo por entrada, ms (default: 120000). */
|
|
15
|
+
timeoutMs?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface VerifyBundleResult {
|
|
18
|
+
routes: number;
|
|
19
|
+
}
|
|
20
|
+
export declare function verifyBundle(options?: VerifyBundleOptions): VerifyBundleResult;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.verifyBundle = verifyBundle;
|
|
7
|
+
// Confere que o bundle (autoload estático) expõe EXATAMENTE as mesmas rotas
|
|
8
|
+
// que a entrada original com o @fastify/autoload de verdade.
|
|
9
|
+
//
|
|
10
|
+
// Sobe cada entrada num processo próprio, pede o JSON do swagger (ele lista
|
|
11
|
+
// toda rota registrada, com método, caminho e schema) e compara. Também
|
|
12
|
+
// garante que o bundle não leu arquivo solto do dist/ — se leu, o autoload
|
|
13
|
+
// estático não está valendo. Qualquer diferença lança: um bundle com rota
|
|
14
|
+
// faltando não pode chegar no deploy.
|
|
15
|
+
//
|
|
16
|
+
// Não toca em banco: DATABASE_URL aponta para uma porta morta e só o swagger
|
|
17
|
+
// é chamado. Precisa do que a API precisa para CARREGAR (ex.: firebase.json).
|
|
18
|
+
const node_child_process_1 = require("node:child_process");
|
|
19
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
20
|
+
// Roda dentro do processo filho: carrega a entrada e devolve o swagger.
|
|
21
|
+
const WORKER = `
|
|
22
|
+
const http = require("node:http");
|
|
23
|
+
const path = require("node:path");
|
|
24
|
+
const entry = path.resolve(process.argv[1]);
|
|
25
|
+
const swaggerPath = process.argv[2];
|
|
26
|
+
const silent = () => {};
|
|
27
|
+
console.log = silent; console.warn = silent; console.error = silent;
|
|
28
|
+
process.on("unhandledRejection", silent);
|
|
29
|
+
const mod = require(entry);
|
|
30
|
+
const handler = typeof mod === "function" ? mod : (mod.default || Object.values(mod).find((v) => typeof v === "function"));
|
|
31
|
+
const server = http.createServer((req, res) => handler(req, res));
|
|
32
|
+
server.listen(0, "127.0.0.1", () => {
|
|
33
|
+
http.get({host: "127.0.0.1", port: server.address().port, path: swaggerPath}, (res) => {
|
|
34
|
+
let body = "";
|
|
35
|
+
res.on("data", (c) => body += c);
|
|
36
|
+
res.on("end", () => {
|
|
37
|
+
const loose = Object.keys(require.cache).filter((f) => f.startsWith(path.dirname(entry) + path.sep) && f !== entry);
|
|
38
|
+
// sai só depois de o pipe aceitar tudo: exit() direto truncaria o JSON
|
|
39
|
+
process.stdout.write(JSON.stringify({status: res.statusCode, body, loose: loose.length}), () => process.exit(0));
|
|
40
|
+
});
|
|
41
|
+
}).on("error", (e) => { process.stderr.write(String(e)); process.exit(1); });
|
|
42
|
+
});
|
|
43
|
+
`;
|
|
44
|
+
// JSON com as chaves ordenadas: a ORDEM das rotas no swagger não é estável
|
|
45
|
+
// nem entre duas execuções do próprio autoload (ele varre as pastas em
|
|
46
|
+
// paralelo), então só o conteúdo é comparado.
|
|
47
|
+
function canonical(value) {
|
|
48
|
+
if (Array.isArray(value))
|
|
49
|
+
return value.map(canonical);
|
|
50
|
+
if (value && typeof value === "object") {
|
|
51
|
+
return Object.fromEntries(Object.keys(value).sort().map((key) => [key, canonical(value[key])]));
|
|
52
|
+
}
|
|
53
|
+
return value;
|
|
54
|
+
}
|
|
55
|
+
function operations(doc) {
|
|
56
|
+
const list = [];
|
|
57
|
+
for (const [route, methods] of Object.entries(doc?.paths ?? {})) {
|
|
58
|
+
for (const method of Object.keys(methods))
|
|
59
|
+
list.push(`${method.toUpperCase()} ${route}`);
|
|
60
|
+
}
|
|
61
|
+
return list.sort();
|
|
62
|
+
}
|
|
63
|
+
function verifyBundle(options = {}) {
|
|
64
|
+
const root = node_path_1.default.resolve(options.root ?? process.cwd());
|
|
65
|
+
const dist = node_path_1.default.join(root, options.distDir ?? "dist");
|
|
66
|
+
const swaggerPath = options.swaggerPath ?? "/documentation/json";
|
|
67
|
+
const swaggerOf = (file) => {
|
|
68
|
+
const label = node_path_1.default.relative(root, file);
|
|
69
|
+
const result = (0, node_child_process_1.spawnSync)(process.execPath, ["-e", WORKER, file, swaggerPath], {
|
|
70
|
+
cwd: root,
|
|
71
|
+
encoding: "utf8",
|
|
72
|
+
timeout: options.timeoutMs ?? 120000,
|
|
73
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
74
|
+
env: {
|
|
75
|
+
...process.env,
|
|
76
|
+
DATABASE_URL: "mysql://verify:verify@127.0.0.1:1/verify_school_1?connection_limit=1",
|
|
77
|
+
HTTP: "https",
|
|
78
|
+
DOMAIN: "verify.local/api",
|
|
79
|
+
PROJECTID: process.env.PROJECTID || "verify",
|
|
80
|
+
APIKEY: process.env.APIKEY || "verify",
|
|
81
|
+
STORAGEBUCKET: process.env.STORAGEBUCKET || "verify.appspot.com",
|
|
82
|
+
REDIS: "",
|
|
83
|
+
...(options.env ?? {}),
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
if (result.status !== 0 || !result.stdout) {
|
|
87
|
+
throw new Error(`verify-bundle: ${label} não subiu (status ${result.status}): ${(result.stderr || "").slice(0, 2000)}`);
|
|
88
|
+
}
|
|
89
|
+
const out = JSON.parse(result.stdout);
|
|
90
|
+
if (out.status !== 200)
|
|
91
|
+
throw new Error(`verify-bundle: ${label} respondeu ${out.status} em ${swaggerPath}`);
|
|
92
|
+
return { doc: JSON.parse(out.body), loose: out.loose };
|
|
93
|
+
};
|
|
94
|
+
const original = swaggerOf(node_path_1.default.join(dist, options.entry ?? "index.js"));
|
|
95
|
+
const bundle = swaggerOf(node_path_1.default.join(dist, options.outfile ?? "bundle.js"));
|
|
96
|
+
const a = operations(original.doc);
|
|
97
|
+
const b = operations(bundle.doc);
|
|
98
|
+
const missing = a.filter((op) => !b.includes(op));
|
|
99
|
+
const extra = b.filter((op) => !a.includes(op));
|
|
100
|
+
const problems = [];
|
|
101
|
+
if (a.length === 0)
|
|
102
|
+
problems.push("a entrada original não registrou rota nenhuma (o build está quebrado antes do bundle)");
|
|
103
|
+
if (missing.length)
|
|
104
|
+
problems.push(`rotas que o autoload registra e o bundle NÃO: ${missing.slice(0, 20).join(", ")}`);
|
|
105
|
+
if (extra.length)
|
|
106
|
+
problems.push(`rotas só no bundle: ${extra.slice(0, 20).join(", ")}`);
|
|
107
|
+
if (!missing.length && !extra.length && JSON.stringify(canonical(original.doc)) !== JSON.stringify(canonical(bundle.doc))) {
|
|
108
|
+
problems.push("mesmas rotas, mas o swagger (schemas/tags) difere entre o autoload e o bundle");
|
|
109
|
+
}
|
|
110
|
+
if (bundle.loose > 0)
|
|
111
|
+
problems.push(`o bundle carregou ${bundle.loose} arquivo(s) soltos de ${options.distDir ?? "dist"}/ — o autoload estático não está valendo`);
|
|
112
|
+
if (problems.length)
|
|
113
|
+
throw new Error("verify-bundle: FALHOU\n - " + problems.join("\n - "));
|
|
114
|
+
return { routes: a.length };
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=verify-bundle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-bundle.js","sourceRoot":"","sources":["../../src/build/verify-bundle.ts"],"names":[],"mappings":"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"}
|
|
@@ -23,5 +23,14 @@ export interface GcfHandlerOptions {
|
|
|
23
23
|
exitDelayMs?: number;
|
|
24
24
|
/** Função de saída (default: process.exit) — injetável para teste */
|
|
25
25
|
exit?: (code: number) => void;
|
|
26
|
+
/** Boot antecipado (default: false). Dispara o ready() logo depois da
|
|
27
|
+
* carga do módulo, em vez de esperar a primeira request: a instância que
|
|
28
|
+
* sobe antes do tráfego (rollout, autoscaling) chega pronta, e o boot roda
|
|
29
|
+
* na janela de CPU extra do startup do Cloud Run. Medido na v3_peoples em
|
|
30
|
+
* 04/10/2026: eram 2,6 s de boot DENTRO da primeira request. As três
|
|
31
|
+
* garantias do wrapper valem igual — a rejeição do boot antecipado já
|
|
32
|
+
* nasce com handler, e uma falha continua virando 503 + saída na request
|
|
33
|
+
* seguinte. */
|
|
34
|
+
eagerBoot?: boolean;
|
|
26
35
|
}
|
|
27
36
|
export declare function createGcfHandler(options: GcfHandlerOptions): (req: any, res: any) => Promise<void>;
|
package/dist/http/gcf-handler.js
CHANGED
|
@@ -35,7 +35,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
35
35
|
exports.createGcfHandler = createGcfHandler;
|
|
36
36
|
const plugin_1 = require("../cors/plugin");
|
|
37
37
|
function createGcfHandler(options) {
|
|
38
|
-
const { server, origin = "*", methods = plugin_1.DEFAULT_CORS.methods.join(","), headers = "*", maxAge = "3600", handlePreflight = true, bootFailureStatus = 503, bootFailureMessage = "Serviço iniciando, tente novamente em instantes", exitOnBootFailure = true, exitDelayMs = 2000, exit = (code) => process.exit(code), } = options;
|
|
38
|
+
const { server, origin = "*", methods = plugin_1.DEFAULT_CORS.methods.join(","), headers = "*", maxAge = "3600", handlePreflight = true, bootFailureStatus = 503, bootFailureMessage = "Serviço iniciando, tente novamente em instantes", exitOnBootFailure = true, exitDelayMs = 2000, exit = (code) => process.exit(code), eagerBoot = false, } = options;
|
|
39
39
|
// null = ainda não bootou (ou o boot anterior falhou e será re-tentado)
|
|
40
40
|
let readyPromise = null;
|
|
41
41
|
function getReady() {
|
|
@@ -49,6 +49,12 @@ function createGcfHandler(options) {
|
|
|
49
49
|
}
|
|
50
50
|
return readyPromise;
|
|
51
51
|
}
|
|
52
|
+
// nextTick: só depois que o módulo da API terminou de carregar — registros
|
|
53
|
+
// feitos DEPOIS do createGcfHandler (plugins, content type parsers) ainda
|
|
54
|
+
// entram. O catch vazio é o que impede o unhandledRejection aqui: sem
|
|
55
|
+
// request esperando, ninguém mais trataria a falha.
|
|
56
|
+
if (eagerBoot)
|
|
57
|
+
process.nextTick(() => getReady().catch(() => { }));
|
|
52
58
|
let exitScheduled = false;
|
|
53
59
|
// Sai só DEPOIS que a resposta foi escrita no socket: process.exit() no
|
|
54
60
|
// mesmo tick cortaria o 503 e o browser voltaria a ver "erro de CORS".
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gcf-handler.js","sourceRoot":"","sources":["../../src/http/gcf-handler.ts"],"names":[],"mappings":";AAAA,4EAA4E;AAC5E,uDAAuD;AACvD,EAAE;AACF,2EAA2E;AAC3E,6EAA6E;AAC7E,2DAA2D;AAC3D,+EAA+E;AAC/E,mEAAmE;AACnE,2EAA2E;AAC3E,uEAAuE;AACvE,6EAA6E;AAC7E,wEAAwE;AACxE,qDAAqD;AACrD,EAAE;AACF,gCAAgC;AAChC,+EAA+E;AAC/E,4EAA4E;AAC5E,6EAA6E;AAC7E,+EAA+E;AAC/E,2EAA2E;AAC3E,yEAAyE;AACzE,+EAA+E;AAC/E,8EAA8E;AAC9E,4EAA4E;AAC5E,+BAA+B;AAC/B,6EAA6E;AAC7E,+EAA+E;AAC/E,0EAA0E;AAC1E,0CAA0C;AAC1C,EAAE;AACF,wEAAwE;AACxE,6EAA6E;;
|
|
1
|
+
{"version":3,"file":"gcf-handler.js","sourceRoot":"","sources":["../../src/http/gcf-handler.ts"],"names":[],"mappings":"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"}
|
package/dist/redis/client.d.ts
CHANGED
package/dist/redis/client.js
CHANGED
|
@@ -3,25 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.DEFAULT_REDIS_CONNECT_TIMEOUT_MS = void 0;
|
|
4
4
|
exports.resolveRedisOptions = resolveRedisOptions;
|
|
5
5
|
exports.createRedisClient = createRedisClient;
|
|
6
|
-
// Cliente Redis padrão das APIs. Antes cada API criava o
|
|
7
|
-
// seu (v1_pedagogico: infra.ts; v3_peoples: config/redis.ts) — a conexão
|
|
8
|
-
// agora mora aqui, UMA vez.
|
|
9
|
-
//
|
|
10
|
-
// Contrato: a env `REDIS` traz o JSON das opções do `createClient` do
|
|
11
|
-
// node-redis (vem do Secret Manager pelo workflow deploy-firebase-api-with-redis).
|
|
12
|
-
//
|
|
13
|
-
// Best-effort — nunca derruba o boot:
|
|
14
|
-
// - sem `REDIS`, JSON inválido ou falha na conexão → `undefined` (a API
|
|
15
|
-
// segue sem cache; quem usa testa o cliente antes);
|
|
16
|
-
// - timeout na conexão (default 3 s): o reconnect padrão do node-redis tenta
|
|
17
|
-
// para sempre e deixaria o boot da function preso esperando;
|
|
18
|
-
// - `disableOfflineQueue: true` por padrão: com a conexão caída, o comando
|
|
19
|
-
// falha na hora em vez de ficar na fila segurando a request (quem usa já
|
|
20
|
-
// trata erro como "sem cache"). As opções da env podem sobrescrever.
|
|
21
|
-
//
|
|
22
|
-
// O cliente devolvido serve direto como `redis` do createTenantMembershipAssert
|
|
23
|
-
// e do createPermissionsResolver (get/setEx).
|
|
24
|
-
const redis_1 = require("redis");
|
|
25
6
|
exports.DEFAULT_REDIS_CONNECT_TIMEOUT_MS = 3000;
|
|
26
7
|
/** Opções finais do createClient (exportado para teste). */
|
|
27
8
|
function resolveRedisOptions(options) {
|
|
@@ -38,13 +19,16 @@ function resolveRedisOptions(options) {
|
|
|
38
19
|
}
|
|
39
20
|
async function createRedisClient(options = {}) {
|
|
40
21
|
const log = options.log ?? ((message, error) => console.error(message, error));
|
|
41
|
-
const factory = options.createClient ?? redis_1.createClient;
|
|
42
22
|
const timeoutMs = options.connectTimeoutMs ?? exports.DEFAULT_REDIS_CONNECT_TIMEOUT_MS;
|
|
43
23
|
let client;
|
|
44
24
|
try {
|
|
45
25
|
const clientOptions = resolveRedisOptions(options);
|
|
46
26
|
if (!clientOptions)
|
|
47
27
|
return undefined;
|
|
28
|
+
// `redis` só carrega quando há o que conectar: API sem a env REDIS não
|
|
29
|
+
// paga os ~480 módulos do node-redis no cold start.
|
|
30
|
+
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
31
|
+
const factory = options.createClient ?? require("redis").createClient;
|
|
48
32
|
client = factory(clientOptions);
|
|
49
33
|
client.on?.("error", (err) => log("Redis Client Error", err));
|
|
50
34
|
let timer;
|
package/dist/redis/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/redis/client.ts"],"names":[],"mappings":";;;AAsCA,kDASC;AAED,
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/redis/client.ts"],"names":[],"mappings":";;;AAsCA,kDASC;AAED,8CAiCC;AA5DY,QAAA,gCAAgC,GAAG,IAAI,CAAC;AAerD,4DAA4D;AAC5D,SAAgB,mBAAmB,CAAC,OAA4B;IAC5D,IAAI,IAAI,GAAG,OAAO,EAAE,OAAO,CAAC;IAC5B,IAAI,CAAC,IAAI,EAAE,CAAC;QACR,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;QAChD,IAAI,CAAC,GAAG;YAAE,OAAO,SAAS,CAAC;QAC3B,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACnC,CAAC;IACD,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;IAChJ,OAAO,EAAC,mBAAmB,EAAE,IAAI,EAAE,GAAG,IAAI,EAAC,CAAC;AAChD,CAAC;AAEM,KAAK,UAAU,iBAAiB,CAAC,UAA8B,EAAE;IACpE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,OAAe,EAAE,KAAe,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;IACjG,MAAM,SAAS,GAAG,OAAO,CAAC,gBAAgB,IAAI,wCAAgC,CAAC;IAE/E,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACD,MAAM,aAAa,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;QACnD,IAAI,CAAC,aAAa;YAAE,OAAO,SAAS,CAAC;QACrC,uEAAuE;QACvE,oDAAoD;QACpD,uDAAuD;QACvD,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,IAAK,OAAO,CAAC,OAAO,CAA4B,CAAC,YAAY,CAAC;QAClG,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;QAChC,MAAM,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC,GAAY,EAAE,EAAE,CAAC,GAAG,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC,CAAC;QACvE,IAAI,KAAgD,CAAC;QACrD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;YACtC,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,cAAc,SAAS,eAAe,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;QACnG,CAAC,CAAC,CAAC;QACH,IAAI,CAAC;YACD,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;QACpD,CAAC;gBAAS,CAAC;YACP,YAAY,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;QACD,OAAO,MAAqB,CAAC;IACjC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,GAAG,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC;QAC/B,IAAI,CAAC;YACD,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC;YACL,wBAAwB;QAC5B,CAAC;QACD,OAAO,SAAS,CAAC;IACrB,CAAC;AACL,CAAC"}
|
|
@@ -3,10 +3,16 @@ export interface PermissionsRedisLike {
|
|
|
3
3
|
setEx(key: string, ttlSeconds: number, value: string): Promise<unknown>;
|
|
4
4
|
}
|
|
5
5
|
export interface PermissionsResolverOptions {
|
|
6
|
-
/** Client Redis opcional (get/setEx). Sem ele, consulta o banco a cada request
|
|
6
|
+
/** Client Redis opcional (get/setEx). Sem ele, consulta o banco a cada request
|
|
7
|
+
* (ou a cada `memoryCacheTtlMs`, quando ligado). */
|
|
7
8
|
redis?: PermissionsRedisLike;
|
|
8
9
|
/** TTL do cache, segundos (default 3600). */
|
|
9
10
|
cacheTtlSeconds?: number;
|
|
11
|
+
/** Cache em memória da instância, ms (default 0 = desligado). Só vale SEM
|
|
12
|
+
* `redis`. Erro de consulta nunca é guardado. */
|
|
13
|
+
memoryCacheTtlMs?: number;
|
|
14
|
+
/** Máximo de entradas do cache em memória (default 5000). */
|
|
15
|
+
memoryCacheMaxSize?: number;
|
|
10
16
|
/** Identificadores de cada papel (default en + pt: teacher/professor,
|
|
11
17
|
* student/aluno, responsible/responsavel). */
|
|
12
18
|
roles?: {
|
|
@@ -21,7 +27,10 @@ export interface PermissionsResolverOptions {
|
|
|
21
27
|
}
|
|
22
28
|
/** A mesma consulta que as APIs usavam, com o uid como parâmetro. */
|
|
23
29
|
export declare function defaultPermissionsQuery(prisma: any, uid: string): Promise<string[]>;
|
|
24
|
-
export declare function createPermissionsResolver(options?: PermissionsResolverOptions):
|
|
30
|
+
export declare function createPermissionsResolver(options?: PermissionsResolverOptions): {
|
|
31
|
+
(req: any, idSchool: string | null): Promise<void>;
|
|
32
|
+
clearCache(): void;
|
|
33
|
+
};
|
|
25
34
|
/** Chave da versão do cache de permissões de uma escola. */
|
|
26
35
|
export declare function permissionsVersionKey(idSchool: string | number): string;
|
|
27
36
|
/** Chave do cache de permissões de um usuário numa versão. */
|
|
@@ -22,6 +22,12 @@
|
|
|
22
22
|
// inteira com um INCR (invalidatePermissionsCache) — atômico e O(1), sem o
|
|
23
23
|
// `KEYS perms:<id>:*` que varria o Redis todo. Chaves de versões antigas
|
|
24
24
|
// morrem pelo TTL.
|
|
25
|
+
//
|
|
26
|
+
// Sem Redis (a maioria das APIs não recebe a env REDIS) a consulta rodava a
|
|
27
|
+
// cada request. `memoryCacheTtlMs` (opt-in, 0.9.0) liga um cache em memória
|
|
28
|
+
// da instância, por `idSchool:uid`. Não há invalidação entre instâncias:
|
|
29
|
+
// mudança de permissão leva até o TTL para valer — manter curto, na ordem
|
|
30
|
+
// do cache de token e de vínculo (120 s). Com `redis` ele é ignorado.
|
|
25
31
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
32
|
exports.defaultPermissionsQuery = defaultPermissionsQuery;
|
|
27
33
|
exports.createPermissionsResolver = createPermissionsResolver;
|
|
@@ -54,7 +60,33 @@ function createPermissionsResolver(options = {}) {
|
|
|
54
60
|
const responsible = asList(options.roles?.responsible, roles_1.RESPONSIBLE_ACLS);
|
|
55
61
|
const query = options.query ?? defaultPermissionsQuery;
|
|
56
62
|
const log = options.logger ?? ((m, e) => console.error(m, e));
|
|
57
|
-
|
|
63
|
+
const memoryTtlMs = options.redis ? 0 : Math.max(0, Number(options.memoryCacheTtlMs) || 0);
|
|
64
|
+
const memoryMaxSize = options.memoryCacheMaxSize ?? 5000;
|
|
65
|
+
const memory = new Map();
|
|
66
|
+
function fromMemory(key) {
|
|
67
|
+
const hit = memory.get(key);
|
|
68
|
+
if (!hit)
|
|
69
|
+
return null;
|
|
70
|
+
if (hit.expMs <= Date.now()) {
|
|
71
|
+
memory.delete(key);
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
// cópia: o handler pode mexer em req.permissions sem sujar o cache
|
|
75
|
+
return [...hit.permissions];
|
|
76
|
+
}
|
|
77
|
+
function toMemory(key, permissions) {
|
|
78
|
+
memory.set(key, { expMs: Date.now() + memoryTtlMs, permissions: [...permissions] });
|
|
79
|
+
if (memory.size > memoryMaxSize) {
|
|
80
|
+
const it = memory.keys();
|
|
81
|
+
for (let i = 0; i < 100 && memory.size > memoryMaxSize; i++) {
|
|
82
|
+
const k = it.next().value;
|
|
83
|
+
if (k === undefined)
|
|
84
|
+
break;
|
|
85
|
+
memory.delete(k);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const resolvePermissions = async function resolvePermissions(req, idSchool) {
|
|
58
90
|
if (!idSchool)
|
|
59
91
|
return;
|
|
60
92
|
req.is_full = false;
|
|
@@ -70,8 +102,9 @@ function createPermissionsResolver(options = {}) {
|
|
|
70
102
|
if (req.internal === true)
|
|
71
103
|
return;
|
|
72
104
|
let cacheKey = null;
|
|
105
|
+
const memoryKey = memoryTtlMs > 0 ? `${idSchool}:${uid}` : null;
|
|
73
106
|
try {
|
|
74
|
-
let permissions = null;
|
|
107
|
+
let permissions = memoryKey ? fromMemory(memoryKey) : null;
|
|
75
108
|
if (options.redis) {
|
|
76
109
|
try {
|
|
77
110
|
const version = await readPermissionsVersion(options.redis, idSchool);
|
|
@@ -97,6 +130,8 @@ function createPermissionsResolver(options = {}) {
|
|
|
97
130
|
}
|
|
98
131
|
if (!permissions) {
|
|
99
132
|
permissions = await query(req.prisma, uid);
|
|
133
|
+
if (memoryKey)
|
|
134
|
+
toMemory(memoryKey, permissions);
|
|
100
135
|
if (options.redis && cacheKey) {
|
|
101
136
|
try {
|
|
102
137
|
await options.redis.setEx(cacheKey, ttl, JSON.stringify(permissions));
|
|
@@ -124,6 +159,9 @@ function createPermissionsResolver(options = {}) {
|
|
|
124
159
|
req.permissions_error = true;
|
|
125
160
|
}
|
|
126
161
|
};
|
|
162
|
+
/** Esvazia o cache em memória (teste, ou mudança de permissão feita pela própria instância). */
|
|
163
|
+
resolvePermissions.clearCache = () => memory.clear();
|
|
164
|
+
return resolvePermissions;
|
|
127
165
|
}
|
|
128
166
|
// --------------------------------------------------- versão do cache ----
|
|
129
167
|
const SCHOOL_RE = /^\d+$/;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../src/tenant/permissions.ts"],"names":[],"mappings":";AAAA,wEAAwE;AACxE,4EAA4E;AAC5E,8DAA8D;AAC9D,4EAA4E;AAC5E,2EAA2E;AAC3E,kBAAkB;AAClB,EAAE;AACF,SAAS;AACT,4DAA4D;AAC5D,yEAAyE;AACzE,2EAA2E;AAC3E,yEAAyE;AACzE,kEAAkE;AAClE,kEAAkE;AAClE,+EAA+E;AAC/E,0DAA0D;AAC1D,oCAAoC;AACpC,EAAE;AACF,2EAA2E;AAC3E,sEAAsE;AACtE,2EAA2E;AAC3E,yEAAyE;AACzE,mBAAmB;;
|
|
1
|
+
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../src/tenant/permissions.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mybuildex/pkg",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Infra comum das APIs MyBuilder: multitenancy Prisma (pool único), middleware de tenant e CORS",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -21,6 +21,9 @@
|
|
|
21
21
|
],
|
|
22
22
|
"main": "dist/index.js",
|
|
23
23
|
"types": "dist/index.d.ts",
|
|
24
|
+
"bin": {
|
|
25
|
+
"mybuildex-bundle": "dist/build/cli.js"
|
|
26
|
+
},
|
|
24
27
|
"files": [
|
|
25
28
|
"dist"
|
|
26
29
|
],
|
|
@@ -42,21 +45,26 @@
|
|
|
42
45
|
"firebase": "^10.6.0",
|
|
43
46
|
"firebase-admin": "^11.11.0",
|
|
44
47
|
"mariadb": "3.4.5",
|
|
45
|
-
"prisma": "7.10.0",
|
|
46
48
|
"redis": "^5.12.1"
|
|
47
49
|
},
|
|
48
50
|
"peerDependencies": {
|
|
51
|
+
"esbuild": ">=0.20",
|
|
49
52
|
"fastify": ">=4"
|
|
50
53
|
},
|
|
51
54
|
"peerDependenciesMeta": {
|
|
55
|
+
"esbuild": {
|
|
56
|
+
"optional": true
|
|
57
|
+
},
|
|
52
58
|
"fastify": {
|
|
53
59
|
"optional": true
|
|
54
60
|
}
|
|
55
61
|
},
|
|
56
62
|
"devDependencies": {
|
|
63
|
+
"@fastify/autoload": "^5.0.0",
|
|
57
64
|
"@google-cloud/functions-framework": "^3.5.1",
|
|
58
65
|
"@types/express": "^4.17.25",
|
|
59
66
|
"@types/node": "^22.0.0",
|
|
67
|
+
"esbuild": "^0.28.2",
|
|
60
68
|
"express": "^4.22.2",
|
|
61
69
|
"fastify": "^4.26.2",
|
|
62
70
|
"typescript": "^5.5.0",
|