flowingts 0.0.0 → 0.19.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/LICENSE +15 -0
- package/README.md +74 -3
- package/dist/core/abort.d.ts +23 -0
- package/dist/core/abort.d.ts.map +1 -0
- package/dist/core/abort.js +23 -0
- package/dist/core/abort.js.map +1 -0
- package/dist/core/app/core.d.ts +35 -0
- package/dist/core/app/core.d.ts.map +1 -0
- package/dist/core/app/core.js +2 -0
- package/dist/core/app/core.js.map +1 -0
- package/dist/core/app/options.d.ts +178 -0
- package/dist/core/app/options.d.ts.map +1 -0
- package/dist/core/app/options.js +2 -0
- package/dist/core/app/options.js.map +1 -0
- package/dist/core/app.d.ts +143 -0
- package/dist/core/app.d.ts.map +1 -0
- package/dist/core/app.js +283 -0
- package/dist/core/app.js.map +1 -0
- package/dist/core/body-parser.d.ts +14 -0
- package/dist/core/body-parser.d.ts.map +1 -0
- package/dist/core/body-parser.js +76 -0
- package/dist/core/body-parser.js.map +1 -0
- package/dist/core/compiler.d.ts +104 -0
- package/dist/core/compiler.d.ts.map +1 -0
- package/dist/core/compiler.js +151 -0
- package/dist/core/compiler.js.map +1 -0
- package/dist/core/compose.d.ts +16 -0
- package/dist/core/compose.d.ts.map +1 -0
- package/dist/core/compose.js +41 -0
- package/dist/core/compose.js.map +1 -0
- package/dist/core/context.d.ts +290 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +460 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/contracts.d.ts +76 -0
- package/dist/core/contracts.d.ts.map +1 -0
- package/dist/core/contracts.js +87 -0
- package/dist/core/contracts.js.map +1 -0
- package/dist/core/errors.d.ts +50 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +25 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/guard.d.ts +10 -0
- package/dist/core/guard.d.ts.map +1 -0
- package/dist/core/guard.js +14 -0
- package/dist/core/guard.js.map +1 -0
- package/dist/core/health.d.ts +37 -0
- package/dist/core/health.d.ts.map +1 -0
- package/dist/core/health.js +68 -0
- package/dist/core/health.js.map +1 -0
- package/dist/core/hooks.d.ts +34 -0
- package/dist/core/hooks.d.ts.map +1 -0
- package/dist/core/hooks.js +27 -0
- package/dist/core/hooks.js.map +1 -0
- package/dist/core/index.d.ts +30 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +11 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/infer.d.ts +68 -0
- package/dist/core/infer.d.ts.map +1 -0
- package/dist/core/infer.js +2 -0
- package/dist/core/infer.js.map +1 -0
- package/dist/core/inject.d.ts +27 -0
- package/dist/core/inject.d.ts.map +1 -0
- package/dist/core/inject.js +85 -0
- package/dist/core/inject.js.map +1 -0
- package/dist/core/logger.d.ts +57 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +134 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/metadata.d.ts +83 -0
- package/dist/core/metadata.d.ts.map +1 -0
- package/dist/core/metadata.js +91 -0
- package/dist/core/metadata.js.map +1 -0
- package/dist/core/mounted-group.d.ts +77 -0
- package/dist/core/mounted-group.d.ts.map +1 -0
- package/dist/core/mounted-group.js +131 -0
- package/dist/core/mounted-group.js.map +1 -0
- package/dist/core/registry/framework-routes.d.ts +28 -0
- package/dist/core/registry/framework-routes.d.ts.map +1 -0
- package/dist/core/registry/framework-routes.js +83 -0
- package/dist/core/registry/framework-routes.js.map +1 -0
- package/dist/core/registry/registry.d.ts +58 -0
- package/dist/core/registry/registry.d.ts.map +1 -0
- package/dist/core/registry/registry.js +208 -0
- package/dist/core/registry/registry.js.map +1 -0
- package/dist/core/registry/route-program.d.ts +16 -0
- package/dist/core/registry/route-program.d.ts.map +1 -0
- package/dist/core/registry/route-program.js +62 -0
- package/dist/core/registry/route-program.js.map +1 -0
- package/dist/core/request-validation.d.ts +15 -0
- package/dist/core/request-validation.d.ts.map +1 -0
- package/dist/core/request-validation.js +67 -0
- package/dist/core/request-validation.js.map +1 -0
- package/dist/core/response/pipeline.d.ts +51 -0
- package/dist/core/response/pipeline.d.ts.map +1 -0
- package/dist/core/response/pipeline.js +169 -0
- package/dist/core/response/pipeline.js.map +1 -0
- package/dist/core/route-table.d.ts +58 -0
- package/dist/core/route-table.d.ts.map +1 -0
- package/dist/core/route-table.js +108 -0
- package/dist/core/route-table.js.map +1 -0
- package/dist/core/runtime/observer.d.ts +47 -0
- package/dist/core/runtime/observer.d.ts.map +1 -0
- package/dist/core/runtime/observer.js +125 -0
- package/dist/core/runtime/observer.js.map +1 -0
- package/dist/core/runtime/request-handler.d.ts +62 -0
- package/dist/core/runtime/request-handler.d.ts.map +1 -0
- package/dist/core/runtime/request-handler.js +256 -0
- package/dist/core/runtime/request-handler.js.map +1 -0
- package/dist/core/runtime/server.d.ts +59 -0
- package/dist/core/runtime/server.d.ts.map +1 -0
- package/dist/core/runtime/server.js +180 -0
- package/dist/core/runtime/server.js.map +1 -0
- package/dist/core/shutdown.d.ts +41 -0
- package/dist/core/shutdown.d.ts.map +1 -0
- package/dist/core/shutdown.js +53 -0
- package/dist/core/shutdown.js.map +1 -0
- package/dist/core/streaming/sse.d.ts +35 -0
- package/dist/core/streaming/sse.d.ts.map +1 -0
- package/dist/core/streaming/sse.js +121 -0
- package/dist/core/streaming/sse.js.map +1 -0
- package/dist/core/symbols.d.ts +28 -0
- package/dist/core/symbols.d.ts.map +1 -0
- package/dist/core/symbols.js +28 -0
- package/dist/core/symbols.js.map +1 -0
- package/dist/core/telemetry.d.ts +83 -0
- package/dist/core/telemetry.d.ts.map +1 -0
- package/dist/core/telemetry.js +96 -0
- package/dist/core/telemetry.js.map +1 -0
- package/dist/core/uploads/receive.d.ts +63 -0
- package/dist/core/uploads/receive.d.ts.map +1 -0
- package/dist/core/uploads/receive.js +342 -0
- package/dist/core/uploads/receive.js.map +1 -0
- package/dist/core/uploads/types.d.ts +79 -0
- package/dist/core/uploads/types.d.ts.map +1 -0
- package/dist/core/uploads/types.js +2 -0
- package/dist/core/uploads/types.js.map +1 -0
- package/dist/decorators/hooks.d.ts +25 -0
- package/dist/decorators/hooks.d.ts.map +1 -0
- package/dist/decorators/hooks.js +36 -0
- package/dist/decorators/hooks.js.map +1 -0
- package/dist/decorators/http.d.ts +21 -0
- package/dist/decorators/http.d.ts.map +1 -0
- package/dist/decorators/http.js +21 -0
- package/dist/decorators/http.js.map +1 -0
- package/dist/decorators/index.d.ts +7 -0
- package/dist/decorators/index.d.ts.map +1 -0
- package/dist/decorators/index.js +7 -0
- package/dist/decorators/index.js.map +1 -0
- package/dist/decorators/log.d.ts +10 -0
- package/dist/decorators/log.d.ts.map +1 -0
- package/dist/decorators/log.js +32 -0
- package/dist/decorators/log.js.map +1 -0
- package/dist/decorators/middlewares.d.ts +28 -0
- package/dist/decorators/middlewares.d.ts.map +1 -0
- package/dist/decorators/middlewares.js +40 -0
- package/dist/decorators/middlewares.js.map +1 -0
- package/dist/decorators/router.d.ts +12 -0
- package/dist/decorators/router.d.ts.map +1 -0
- package/dist/decorators/router.js +20 -0
- package/dist/decorators/router.js.map +1 -0
- package/dist/decorators/schema.d.ts +8 -0
- package/dist/decorators/schema.d.ts.map +1 -0
- package/dist/decorators/schema.js +14 -0
- package/dist/decorators/schema.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/middlewares/auth.d.ts +41 -0
- package/dist/middlewares/auth.d.ts.map +1 -0
- package/dist/middlewares/auth.js +74 -0
- package/dist/middlewares/auth.js.map +1 -0
- package/dist/middlewares/cors.d.ts +30 -0
- package/dist/middlewares/cors.d.ts.map +1 -0
- package/dist/middlewares/cors.js +69 -0
- package/dist/middlewares/cors.js.map +1 -0
- package/dist/middlewares/csrf.d.ts +42 -0
- package/dist/middlewares/csrf.d.ts.map +1 -0
- package/dist/middlewares/csrf.js +70 -0
- package/dist/middlewares/csrf.js.map +1 -0
- package/dist/middlewares/index.d.ts +6 -0
- package/dist/middlewares/index.d.ts.map +1 -0
- package/dist/middlewares/index.js +6 -0
- package/dist/middlewares/index.js.map +1 -0
- package/dist/middlewares/rate-limit.d.ts +35 -0
- package/dist/middlewares/rate-limit.d.ts.map +1 -0
- package/dist/middlewares/rate-limit.js +45 -0
- package/dist/middlewares/rate-limit.js.map +1 -0
- package/dist/middlewares/security-headers.d.ts +28 -0
- package/dist/middlewares/security-headers.d.ts.map +1 -0
- package/dist/middlewares/security-headers.js +42 -0
- package/dist/middlewares/security-headers.js.map +1 -0
- package/dist/openapi/generate.d.ts +51 -0
- package/dist/openapi/generate.d.ts.map +1 -0
- package/dist/openapi/generate.js +175 -0
- package/dist/openapi/generate.js.map +1 -0
- package/dist/schema/serialization.d.ts +2 -0
- package/dist/schema/serialization.d.ts.map +1 -0
- package/dist/schema/serialization.js +11 -0
- package/dist/schema/serialization.js.map +1 -0
- package/dist/schema/validation.d.ts +22 -0
- package/dist/schema/validation.d.ts.map +1 -0
- package/dist/schema/validation.js +68 -0
- package/dist/schema/validation.js.map +1 -0
- package/dist/server/static.d.ts +45 -0
- package/dist/server/static.d.ts.map +1 -0
- package/dist/server/static.js +204 -0
- package/dist/server/static.js.map +1 -0
- package/dist/server/tls.d.ts +48 -0
- package/dist/server/tls.d.ts.map +1 -0
- package/dist/server/tls.js +60 -0
- package/dist/server/tls.js.map +1 -0
- package/dist/shims/symbol-metadata.d.ts +2 -0
- package/dist/shims/symbol-metadata.d.ts.map +1 -0
- package/dist/shims/symbol-metadata.js +8 -0
- package/dist/shims/symbol-metadata.js.map +1 -0
- package/dist/utils/content-type.d.ts +13 -0
- package/dist/utils/content-type.d.ts.map +1 -0
- package/dist/utils/content-type.js +75 -0
- package/dist/utils/content-type.js.map +1 -0
- package/dist/utils/cookie.d.ts +34 -0
- package/dist/utils/cookie.d.ts.map +1 -0
- package/dist/utils/cookie.js +94 -0
- package/dist/utils/cookie.js.map +1 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +7 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/mime.d.ts +2 -0
- package/dist/utils/mime.d.ts.map +1 -0
- package/dist/utils/mime.js +52 -0
- package/dist/utils/mime.js.map +1 -0
- package/dist/utils/origin-match.d.ts +58 -0
- package/dist/utils/origin-match.d.ts.map +1 -0
- package/dist/utils/origin-match.js +194 -0
- package/dist/utils/origin-match.js.map +1 -0
- package/dist/utils/path.d.ts +10 -0
- package/dist/utils/path.d.ts.map +1 -0
- package/dist/utils/path.js +60 -0
- package/dist/utils/path.js.map +1 -0
- package/dist/utils/query.d.ts +28 -0
- package/dist/utils/query.d.ts.map +1 -0
- package/dist/utils/query.js +67 -0
- package/dist/utils/query.js.map +1 -0
- package/dist/utils/request-target.d.ts +31 -0
- package/dist/utils/request-target.d.ts.map +1 -0
- package/dist/utils/request-target.js +80 -0
- package/dist/utils/request-target.js.map +1 -0
- package/dist/utils/safe-json.d.ts +24 -0
- package/dist/utils/safe-json.d.ts.map +1 -0
- package/dist/utils/safe-json.js +83 -0
- package/dist/utils/safe-json.js.map +1 -0
- package/dist/utils/trace-context.d.ts +17 -0
- package/dist/utils/trace-context.d.ts.map +1 -0
- package/dist/utils/trace-context.js +30 -0
- package/dist/utils/trace-context.js.map +1 -0
- package/package.json +85 -6
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { createReadStream, createWriteStream } from 'node:fs';
|
|
3
|
+
import { readFile, unlink } from 'node:fs/promises';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { Busboy } from '@fastify/busboy';
|
|
7
|
+
import { filetypeinfo } from 'magic-bytes.js';
|
|
8
|
+
import { HttpError } from '../errors.js';
|
|
9
|
+
/** Quantos bytes do começo do arquivo vão para a detecção do conteúdo e para o `verify`. */
|
|
10
|
+
const HEAD_BYTES = 4100;
|
|
11
|
+
const UNITS = { b: 1, kb: 1024, mb: 1024 ** 2, gb: 1024 ** 3 };
|
|
12
|
+
/** `'5mb'` → 5242880. Erro de configuração aparece no registro da rota. */
|
|
13
|
+
export function parseSize(size, where) {
|
|
14
|
+
if (typeof size === 'number' && Number.isFinite(size) && size > 0)
|
|
15
|
+
return Math.floor(size);
|
|
16
|
+
const m = typeof size === 'string' ? /^(\d+(?:\.\d+)?)\s*(b|kb|mb|gb)$/i.exec(size.trim()) : null;
|
|
17
|
+
if (!m)
|
|
18
|
+
throw new Error(`[flowing] ${where}: invalid size ${JSON.stringify(size)} (use a number of bytes or '5mb').`);
|
|
19
|
+
return Math.floor(Number(m[1]) * UNITS[m[2].toLowerCase()]);
|
|
20
|
+
}
|
|
21
|
+
/** Detector padrão: a tabela de assinaturas da `magic-bytes.js`. */
|
|
22
|
+
const magicBytes = (head) => filetypeinfo(head).map((t) => t.mime ?? t.typename);
|
|
23
|
+
/**
|
|
24
|
+
* Detectores de conteúdo (F-46):
|
|
25
|
+
* - `detectors.magicBytes()`: o padrão, sem dependências (centenas de assinaturas; documentos do Office só como ZIP).
|
|
26
|
+
* - `detectors.fileType(fileTypeFromBuffer)`: o `file-type`, instalado pela aplicação, para conferências mais completas
|
|
27
|
+
* (abre o ZIP para confirmar `.docx`, `.xlsx`, `.pptx`).
|
|
28
|
+
*/
|
|
29
|
+
export const detectors = {
|
|
30
|
+
magicBytes: () => magicBytes,
|
|
31
|
+
fileType: (fileTypeFromBuffer) => async (head) => {
|
|
32
|
+
const found = await fileTypeFromBuffer(head);
|
|
33
|
+
return found ? [found.mime] : [];
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
export function uploadSettings(opts = {}) {
|
|
37
|
+
const l = opts.limits ?? {};
|
|
38
|
+
return {
|
|
39
|
+
limits: {
|
|
40
|
+
fileSize: parseSize(l.fileSize ?? '10mb', 'uploads.limits.fileSize'),
|
|
41
|
+
files: l.files ?? 10,
|
|
42
|
+
fields: l.fields ?? 50,
|
|
43
|
+
fieldSize: parseSize(l.fieldSize ?? '100kb', 'uploads.limits.fieldSize'),
|
|
44
|
+
parts: l.parts ?? 60,
|
|
45
|
+
},
|
|
46
|
+
tempDir: opts.tempDir ?? tmpdir(),
|
|
47
|
+
detect: opts.detect ?? magicBytes,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Resolve o `files` do contrato. Uma rota que tenta ampliar um limite global falha aqui, no registro, em vez de ser
|
|
52
|
+
* ignorada em silêncio.
|
|
53
|
+
*/
|
|
54
|
+
export function uploadPlan(files, settings, where) {
|
|
55
|
+
const rules = new Map();
|
|
56
|
+
for (const [name, rule] of Object.entries(files)) {
|
|
57
|
+
const maxSize = rule.maxSize === undefined ? settings.limits.fileSize : parseSize(rule.maxSize, `${where} files.${name}.maxSize`);
|
|
58
|
+
if (maxSize > settings.limits.fileSize) {
|
|
59
|
+
throw new Error(`[flowing] ${where}: files.${name}.maxSize (${maxSize} bytes) is larger than uploads.limits.fileSize ` +
|
|
60
|
+
`(${settings.limits.fileSize} bytes); a route can only restrict the global limits.`);
|
|
61
|
+
}
|
|
62
|
+
const maxCount = rule.maxCount ?? 1;
|
|
63
|
+
if (!Number.isInteger(maxCount) || maxCount < 1)
|
|
64
|
+
throw new Error(`[flowing] ${where}: files.${name}.maxCount must be a positive integer.`);
|
|
65
|
+
rules.set(name, { required: rule.required ?? false, maxSize, maxCount, types: rule.types, verify: rule.verify });
|
|
66
|
+
}
|
|
67
|
+
let largest = 0;
|
|
68
|
+
for (const r of rules.values())
|
|
69
|
+
largest = Math.max(largest, r.maxSize);
|
|
70
|
+
return { rules, settings, largest };
|
|
71
|
+
}
|
|
72
|
+
/** Tipos sem assinatura de conteúdo: só o tipo declarado é conferido. */
|
|
73
|
+
const TEXT_LIKE = /^(text\/|application\/(json|xml|csv|x-ndjson|ld\+json)$|image\/svg\+xml$)/;
|
|
74
|
+
/** Formatos que são um ZIP por dentro: o detector padrão só os reconhece como ZIP. */
|
|
75
|
+
const ZIP_FAMILY = new Set([
|
|
76
|
+
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
77
|
+
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
78
|
+
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
|
79
|
+
'application/vnd.oasis.opendocument.text',
|
|
80
|
+
'application/vnd.oasis.opendocument.spreadsheet',
|
|
81
|
+
'application/vnd.oasis.opendocument.presentation',
|
|
82
|
+
'application/epub+zip',
|
|
83
|
+
'application/java-archive',
|
|
84
|
+
]);
|
|
85
|
+
const matches = (type, accepted) => accepted.some((a) => a === '*/*' || a === type || (a.endsWith('/*') && type.startsWith(a.slice(0, -1))));
|
|
86
|
+
class Spooled {
|
|
87
|
+
fieldname;
|
|
88
|
+
filename;
|
|
89
|
+
mimetype;
|
|
90
|
+
encoding;
|
|
91
|
+
size;
|
|
92
|
+
path;
|
|
93
|
+
detectedType;
|
|
94
|
+
#read = false;
|
|
95
|
+
constructor(fieldname, filename, mimetype, encoding, size, detected, path) {
|
|
96
|
+
this.fieldname = fieldname;
|
|
97
|
+
this.filename = filename;
|
|
98
|
+
this.mimetype = mimetype;
|
|
99
|
+
this.encoding = encoding;
|
|
100
|
+
this.size = size;
|
|
101
|
+
this.path = path;
|
|
102
|
+
this.detectedType = detected;
|
|
103
|
+
}
|
|
104
|
+
stream() {
|
|
105
|
+
if (this.#read)
|
|
106
|
+
throw new Error(`[flowing] the file "${this.fieldname}" was already read; stream() can be called only once.`);
|
|
107
|
+
this.#read = true;
|
|
108
|
+
return createReadStream(this.path);
|
|
109
|
+
}
|
|
110
|
+
buffer() {
|
|
111
|
+
return readFile(this.path);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const UNSAFE_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
|
|
115
|
+
/**
|
|
116
|
+
* Lê um `multipart/form-data` (F-46). Os arquivos vão para temporários com nome gerado, apagados quando a resposta
|
|
117
|
+
* termina (sucesso, erro ou cancelamento). Limites, tipos, conteúdo e obrigatórios são conferidos aqui, antes do
|
|
118
|
+
* handler; os campos de texto são validados depois pelo contrato `body`.
|
|
119
|
+
*/
|
|
120
|
+
export function receiveUploads(ctx, plan) {
|
|
121
|
+
const contentType = ctx.req.headers['content-type'] ?? '';
|
|
122
|
+
if (!/^multipart\/form-data\b/i.test(contentType)) {
|
|
123
|
+
return Promise.reject(new HttpError(415, 'Expected multipart/form-data', 'UNSUPPORTED_MEDIA_TYPE'));
|
|
124
|
+
}
|
|
125
|
+
const { limits, tempDir } = plan.settings;
|
|
126
|
+
const temps = [];
|
|
127
|
+
// Os temporários somem quando a resposta termina, qualquer que seja o caminho.
|
|
128
|
+
ctx.res.once('close', () => {
|
|
129
|
+
for (const path of temps)
|
|
130
|
+
unlink(path).catch(() => { });
|
|
131
|
+
});
|
|
132
|
+
return new Promise((resolve, reject) => {
|
|
133
|
+
const fields = {};
|
|
134
|
+
const files = new Map();
|
|
135
|
+
const counts = new Map();
|
|
136
|
+
const pending = [];
|
|
137
|
+
let failed;
|
|
138
|
+
let settled = false;
|
|
139
|
+
/** Gravações em andamento: fechadas na recusa, senão o descritor do temporário fica aberto. */
|
|
140
|
+
const writing = new Set();
|
|
141
|
+
const fail = (err) => {
|
|
142
|
+
if (failed || settled)
|
|
143
|
+
return;
|
|
144
|
+
failed = err;
|
|
145
|
+
ctx.req.unpipe(parser);
|
|
146
|
+
for (const out of writing)
|
|
147
|
+
out.destroy();
|
|
148
|
+
writing.clear();
|
|
149
|
+
discardRest(ctx, () => reject(err));
|
|
150
|
+
};
|
|
151
|
+
let parser;
|
|
152
|
+
try {
|
|
153
|
+
parser = new Busboy({
|
|
154
|
+
headers: ctx.req.headers,
|
|
155
|
+
limits: {
|
|
156
|
+
fileSize: plan.largest,
|
|
157
|
+
files: limits.files,
|
|
158
|
+
fields: limits.fields,
|
|
159
|
+
fieldSize: limits.fieldSize,
|
|
160
|
+
parts: limits.parts,
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
return reject(new HttpError(400, 'Invalid multipart body', 'INVALID_MULTIPART'));
|
|
166
|
+
}
|
|
167
|
+
parser.on('field', (name, value, _nameTruncated, valueTruncated) => {
|
|
168
|
+
if (failed)
|
|
169
|
+
return;
|
|
170
|
+
if (valueTruncated)
|
|
171
|
+
return fail(new HttpError(413, `Field "${name}" is too large`, 'FIELD_TOO_LARGE'));
|
|
172
|
+
if (UNSAFE_KEYS.has(name))
|
|
173
|
+
return;
|
|
174
|
+
const prev = fields[name];
|
|
175
|
+
fields[name] = prev === undefined ? value : Array.isArray(prev) ? [...prev, value] : [prev, value];
|
|
176
|
+
});
|
|
177
|
+
parser.on('file', (name, stream, filename, encoding, mimetype) => {
|
|
178
|
+
// Corpo truncado: o busboy emite erro no stream da parte. Sem este listener, a exceção derrubava o processo.
|
|
179
|
+
stream.on('error', () => fail(new HttpError(400, 'Invalid multipart body', 'INVALID_MULTIPART')));
|
|
180
|
+
const rule = plan.rules.get(name);
|
|
181
|
+
if (failed || !rule) {
|
|
182
|
+
stream.resume();
|
|
183
|
+
if (!rule)
|
|
184
|
+
fail(new HttpError(400, `Unexpected file field "${name}"`, 'UNEXPECTED_FILE'));
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
// Contado na chegada: os arquivos terminam de gravar fora de ordem.
|
|
188
|
+
const count = (counts.get(name) ?? 0) + 1;
|
|
189
|
+
counts.set(name, count);
|
|
190
|
+
if (count > rule.maxCount) {
|
|
191
|
+
stream.resume();
|
|
192
|
+
return fail(new HttpError(400, `Too many files in "${name}" (max ${rule.maxCount})`, 'TOO_MANY_FILES'));
|
|
193
|
+
}
|
|
194
|
+
const path = join(tempDir, `flowing-upload-${randomUUID()}`);
|
|
195
|
+
temps.push(path);
|
|
196
|
+
const out = createWriteStream(path);
|
|
197
|
+
writing.add(out);
|
|
198
|
+
out.once('close', () => writing.delete(out));
|
|
199
|
+
const head = [];
|
|
200
|
+
let headSize = 0;
|
|
201
|
+
let size = 0;
|
|
202
|
+
stream.on('data', (chunk) => {
|
|
203
|
+
size += chunk.length;
|
|
204
|
+
if (headSize < HEAD_BYTES) {
|
|
205
|
+
head.push(chunk);
|
|
206
|
+
headSize += chunk.length;
|
|
207
|
+
}
|
|
208
|
+
if (size > rule.maxSize) {
|
|
209
|
+
stream.unpipe(out);
|
|
210
|
+
stream.resume();
|
|
211
|
+
fail(new HttpError(413, `File "${name}" is too large (max ${rule.maxSize} bytes)`, 'FILE_TOO_LARGE'));
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
stream.on('limit', () => fail(new HttpError(413, `File "${name}" is too large (max ${rule.maxSize} bytes)`, 'FILE_TOO_LARGE')));
|
|
215
|
+
stream.pipe(out);
|
|
216
|
+
pending.push(new Promise((done, error) => {
|
|
217
|
+
out.on('finish', done);
|
|
218
|
+
out.on('error', error);
|
|
219
|
+
})
|
|
220
|
+
.then(async () => {
|
|
221
|
+
if (failed)
|
|
222
|
+
return;
|
|
223
|
+
const bytes = Buffer.concat(head).subarray(0, HEAD_BYTES);
|
|
224
|
+
const detected = await checkContent(name, rule, mimetype, bytes, plan.settings.detect, {
|
|
225
|
+
fieldname: name,
|
|
226
|
+
filename,
|
|
227
|
+
mimetype,
|
|
228
|
+
encoding,
|
|
229
|
+
size,
|
|
230
|
+
detectedType: undefined,
|
|
231
|
+
});
|
|
232
|
+
const list = files.get(name);
|
|
233
|
+
const file = new Spooled(name, filename, mimetype, encoding, size, detected, path);
|
|
234
|
+
if (list)
|
|
235
|
+
list.push(file);
|
|
236
|
+
else
|
|
237
|
+
files.set(name, [file]);
|
|
238
|
+
})
|
|
239
|
+
.catch((err) => fail(err instanceof HttpError ? err : new HttpError(400, 'Invalid file', 'INVALID_FILE'))));
|
|
240
|
+
});
|
|
241
|
+
parser.on('partsLimit', () => fail(new HttpError(413, 'Too many parts', 'TOO_MANY_PARTS')));
|
|
242
|
+
parser.on('filesLimit', () => fail(new HttpError(413, 'Too many files', 'TOO_MANY_FILES')));
|
|
243
|
+
parser.on('fieldsLimit', () => fail(new HttpError(413, 'Too many fields', 'TOO_MANY_FIELDS')));
|
|
244
|
+
parser.on('error', () => fail(new HttpError(400, 'Invalid multipart body', 'INVALID_MULTIPART')));
|
|
245
|
+
parser.on('finish', () => {
|
|
246
|
+
Promise.all(pending)
|
|
247
|
+
.then(() => {
|
|
248
|
+
if (failed)
|
|
249
|
+
return;
|
|
250
|
+
for (const [name, rule] of plan.rules) {
|
|
251
|
+
if (rule.required && !files.get(name)?.length) {
|
|
252
|
+
return fail(new HttpError(400, `File "${name}" is required`, 'FILE_REQUIRED'));
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
settled = true;
|
|
256
|
+
resolve({ fields, files });
|
|
257
|
+
})
|
|
258
|
+
.catch((err) => fail(err instanceof HttpError ? err : new HttpError(400, 'Invalid file', 'INVALID_FILE')));
|
|
259
|
+
});
|
|
260
|
+
// O cliente desistiu no meio do envio: nada a validar, só limpar (o `close` da resposta apaga os temporários).
|
|
261
|
+
// A conexão caiu antes da resposta (o `aborted` da requisição é obsoleto e dispara no `inject()`).
|
|
262
|
+
ctx.res.once('close', () => fail(new HttpError(400, 'Upload aborted', 'UPLOAD_ABORTED')));
|
|
263
|
+
ctx.req.once('error', () => fail(new HttpError(400, 'Upload aborted', 'UPLOAD_ABORTED')));
|
|
264
|
+
ctx.req.pipe(parser);
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
/** Quanto do corpo recusado ainda vale ler e descartar antes de responder, para manter a conexão. */
|
|
268
|
+
const DRAIN_LIMIT = 1024 * 1024;
|
|
269
|
+
/** Por quanto tempo, no máximo: um cliente lento não segura a resposta (nem a conexão) indefinidamente. */
|
|
270
|
+
const DRAIN_TIMEOUT_MS = 2000;
|
|
271
|
+
/**
|
|
272
|
+
* Depois de recusar um upload, descarta o resto do corpo (lendo e jogando fora, sem acumular) antes de responder. Responder e fechar com o cliente ainda
|
|
273
|
+
* enviando faz o cliente receber EPIPE em vez do 400/413. Acima de `DRAIN_LIMIT`, responde já com
|
|
274
|
+
* `Connection: close` (como o limite do body JSON, B-12): não vale gastar banda com o que será jogado fora. O mesmo
|
|
275
|
+
* vale depois de `DRAIN_TIMEOUT_MS`. Com `Connection: close`, o Node fecha o socket ao fim da resposta: a conexão não
|
|
276
|
+
* volta ao keep-alive com bytes do corpo anterior.
|
|
277
|
+
*/
|
|
278
|
+
function discardRest(ctx, respond) {
|
|
279
|
+
const req = ctx.req;
|
|
280
|
+
if (req.readableEnded || req.destroyed) {
|
|
281
|
+
respond();
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
let drained = 0;
|
|
285
|
+
let done = false;
|
|
286
|
+
const timer = setTimeout(() => finish(true), DRAIN_TIMEOUT_MS);
|
|
287
|
+
timer.unref();
|
|
288
|
+
const finish = (close) => {
|
|
289
|
+
if (done)
|
|
290
|
+
return;
|
|
291
|
+
done = true;
|
|
292
|
+
clearTimeout(timer);
|
|
293
|
+
req.off('data', onData);
|
|
294
|
+
if (close && !ctx.res.headersSent)
|
|
295
|
+
ctx.res.setHeader('Connection', 'close');
|
|
296
|
+
respond();
|
|
297
|
+
};
|
|
298
|
+
const onData = (chunk) => {
|
|
299
|
+
drained += chunk.length;
|
|
300
|
+
if (drained > DRAIN_LIMIT)
|
|
301
|
+
finish(true);
|
|
302
|
+
};
|
|
303
|
+
req.on('data', onData);
|
|
304
|
+
req.once('end', () => finish(false));
|
|
305
|
+
req.once('close', () => finish(true));
|
|
306
|
+
req.resume();
|
|
307
|
+
}
|
|
308
|
+
/** Confere o tipo declarado e, quando possível, o conteúdo; depois o `verify`. Devolve o tipo detectado. */
|
|
309
|
+
async function checkContent(name, rule, declared, head, detect, info) {
|
|
310
|
+
const reject = (why) => {
|
|
311
|
+
throw new HttpError(400, `File "${name}" ${why}`, 'INVALID_FILE_TYPE');
|
|
312
|
+
};
|
|
313
|
+
let detectedType;
|
|
314
|
+
if (rule.types) {
|
|
315
|
+
const type = declared.toLowerCase();
|
|
316
|
+
if (!matches(type, rule.types))
|
|
317
|
+
reject(`has type "${declared}", which is not accepted`);
|
|
318
|
+
const candidates = await detect(head);
|
|
319
|
+
detectedType = candidates[0];
|
|
320
|
+
if (candidates.length > 0) {
|
|
321
|
+
const ok = candidates.some((c) => matches(c, rule.types)) || (ZIP_FAMILY.has(type) && candidates.includes('application/zip'));
|
|
322
|
+
if (!ok)
|
|
323
|
+
reject(`content does not match its type (detected "${candidates[0]}")`);
|
|
324
|
+
}
|
|
325
|
+
else if (!TEXT_LIKE.test(type) && !rule.verify) {
|
|
326
|
+
reject('content could not be recognized as an accepted type');
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
if (rule.verify) {
|
|
330
|
+
let ok = false;
|
|
331
|
+
try {
|
|
332
|
+
ok = await rule.verify(new Uint8Array(head), { ...info, detectedType });
|
|
333
|
+
}
|
|
334
|
+
catch {
|
|
335
|
+
ok = false;
|
|
336
|
+
}
|
|
337
|
+
if (!ok)
|
|
338
|
+
reject('was rejected by its verify rule');
|
|
339
|
+
}
|
|
340
|
+
return detectedType;
|
|
341
|
+
}
|
|
342
|
+
//# sourceMappingURL=receive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"receive.js","sourceRoot":"","sources":["../../../src/core/uploads/receive.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { Readable } from 'node:stream';
|
|
2
|
+
/** Tamanho em bytes, ou com unidade: `'512kb'`, `'5mb'`, `'1gb'` (base 1024). */
|
|
3
|
+
export type Size = number | `${number}${'b' | 'kb' | 'mb' | 'gb'}`;
|
|
4
|
+
/**
|
|
5
|
+
* Regras de um campo de arquivo no contrato da rota (F-46): `files: { pdf: { required: true, maxSize: '5mb' } }`.
|
|
6
|
+
* Tudo é conferido antes do handler; o arquivo inválido gera 400 ou 413 em Problem Details.
|
|
7
|
+
*/
|
|
8
|
+
export interface FileRule {
|
|
9
|
+
/** O campo precisa ter pelo menos um arquivo. Padrão: `false`. */
|
|
10
|
+
required?: boolean;
|
|
11
|
+
/** Tamanho máximo de cada arquivo. Não pode passar do limite global (`uploads.limits.fileSize`). */
|
|
12
|
+
maxSize?: Size;
|
|
13
|
+
/** Quantos arquivos o campo aceita. Padrão: 1. Use `ctx.files(nome)` quando for mais de um. */
|
|
14
|
+
maxCount?: number;
|
|
15
|
+
/**
|
|
16
|
+
* Tipos aceitos (`'application/pdf'`, `'image/*'`). Confere o tipo declarado pelo cliente e, quando o formato tem
|
|
17
|
+
* assinatura conhecida, também os primeiros bytes do arquivo (um executável com nome `.pdf` é recusado). Formatos de
|
|
18
|
+
* texto (CSV, JSON) não têm assinatura: só o tipo declarado é conferido.
|
|
19
|
+
*/
|
|
20
|
+
types?: readonly string[];
|
|
21
|
+
/**
|
|
22
|
+
* Conferência própria do conteúdo, depois dos tipos: recebe os primeiros bytes do arquivo. `false` (ou um erro)
|
|
23
|
+
* recusa o arquivo com 400. Para regras que a detecção por assinatura não cobre.
|
|
24
|
+
*/
|
|
25
|
+
verify?: (head: Uint8Array, file: FileInfo) => boolean | Promise<boolean>;
|
|
26
|
+
}
|
|
27
|
+
/** Os campos de arquivo de um contrato: nome do campo → regras. */
|
|
28
|
+
export type FileRules = Readonly<Record<string, FileRule>>;
|
|
29
|
+
/** O que se sabe de um arquivo recebido. */
|
|
30
|
+
export interface FileInfo {
|
|
31
|
+
/** O nome do campo no formulário. */
|
|
32
|
+
readonly fieldname: string;
|
|
33
|
+
/** O nome enviado pelo cliente. É só um metadado: nunca o use como caminho no disco. */
|
|
34
|
+
readonly filename: string;
|
|
35
|
+
/** O tipo declarado pelo cliente. */
|
|
36
|
+
readonly mimetype: string;
|
|
37
|
+
/** O tipo detectado pelo conteúdo, quando o formato tem assinatura conhecida. */
|
|
38
|
+
readonly detectedType: string | undefined;
|
|
39
|
+
readonly encoding: string;
|
|
40
|
+
/** O tamanho efetivamente recebido, em bytes. */
|
|
41
|
+
readonly size: number;
|
|
42
|
+
}
|
|
43
|
+
/** Um arquivo recebido e validado, guardado num arquivo temporário até o fim da resposta. */
|
|
44
|
+
export interface UploadedFile extends FileInfo {
|
|
45
|
+
/** O conteúdo como stream. Uso único: uma segunda chamada lança. */
|
|
46
|
+
stream(): Readable;
|
|
47
|
+
/** O conteúdo inteiro na memória. Prefira `stream()` para arquivos grandes. */
|
|
48
|
+
buffer(): Promise<Buffer>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Detecta o tipo pelo conteúdo: recebe os primeiros bytes e devolve os tipos possíveis (vazio se não reconhece).
|
|
52
|
+
* O padrão usa a `magic-bytes.js`; `detectors.fileType(fileTypeFromBuffer)` liga o `file-type`.
|
|
53
|
+
*/
|
|
54
|
+
export type ContentDetector = (head: Uint8Array) => readonly string[] | Promise<readonly string[]>;
|
|
55
|
+
/** Configuração de upload do app (`createApp({ uploads })`). */
|
|
56
|
+
export interface UploadsOptions {
|
|
57
|
+
/** Limites globais; o contrato de cada rota só pode restringi-los. */
|
|
58
|
+
limits?: {
|
|
59
|
+
/** Tamanho máximo de cada arquivo. Padrão: `'10mb'`. */
|
|
60
|
+
fileSize?: Size;
|
|
61
|
+
/** Arquivos por requisição. Padrão: 10. */
|
|
62
|
+
files?: number;
|
|
63
|
+
/** Campos de texto por requisição. Padrão: 50. */
|
|
64
|
+
fields?: number;
|
|
65
|
+
/** Tamanho máximo de cada campo de texto. Padrão: `'100kb'`. */
|
|
66
|
+
fieldSize?: Size;
|
|
67
|
+
/** Partes (campos + arquivos) por requisição. Padrão: 60. */
|
|
68
|
+
parts?: number;
|
|
69
|
+
};
|
|
70
|
+
/** Pasta dos arquivos temporários. Padrão: a pasta temporária do sistema. */
|
|
71
|
+
tempDir?: string;
|
|
72
|
+
/** Detector de conteúdo. Padrão: `detectors.magicBytes()`. */
|
|
73
|
+
detect?: ContentDetector;
|
|
74
|
+
}
|
|
75
|
+
/** Os nomes dos campos de arquivo de um contrato; `string` quando a rota não declara `files`. */
|
|
76
|
+
export type FileField<S extends {
|
|
77
|
+
files?: FileRules;
|
|
78
|
+
}> = S['files'] extends FileRules ? Extract<keyof S['files'], string> : string;
|
|
79
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/uploads/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,iFAAiF;AACjF,MAAM,MAAM,IAAI,GAAG,MAAM,GAAG,GAAG,MAAM,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC;AAEnE;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oGAAoG;IACpG,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,+FAA+F;IAC/F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3E;AAED,mEAAmE;AACnE,MAAM,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;AAE3D,4CAA4C;AAC5C,MAAM,WAAW,QAAQ;IACvB,qCAAqC;IACrC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,wFAAwF;IACxF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,qCAAqC;IACrC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,iFAAiF;IACjF,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,iDAAiD;IACjD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,6FAA6F;AAC7F,MAAM,WAAW,YAAa,SAAQ,QAAQ;IAC5C,oEAAoE;IACpE,MAAM,IAAI,QAAQ,CAAC;IACnB,+EAA+E;IAC/E,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CAC3B;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,UAAU,KAAK,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;AAEnG,gEAAgE;AAChE,MAAM,WAAW,cAAc;IAC7B,sEAAsE;IACtE,MAAM,CAAC,EAAE;QACP,wDAAwD;QACxD,QAAQ,CAAC,EAAE,IAAI,CAAC;QAChB,2CAA2C;QAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,kDAAkD;QAClD,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,gEAAgE;QAChE,SAAS,CAAC,EAAE,IAAI,CAAC;QACjB,6DAA6D;QAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8DAA8D;IAC9D,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAED,iGAAiG;AACjG,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS;IAAE,KAAK,CAAC,EAAE,SAAS,CAAA;CAAE,IAAI,CAAC,CAAC,OAAO,CAAC,SAAS,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/uploads/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { OnErrorHook, OnResponseHook } from '../core/app/options.ts';
|
|
2
|
+
import type { OnSendHook } from '../core/context.ts';
|
|
3
|
+
type ClassOrMethodContext = ClassDecoratorContext | ClassMethodDecoratorContext;
|
|
4
|
+
/**
|
|
5
|
+
* `onSend` só para as rotas da classe ou do método (F-43): roda depois dos `onSend` do app, imediatamente
|
|
6
|
+
* antes de escrever a resposta. A assinatura é a do `app.onSend`.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* @OnSend((ctx) => void ctx.header('Cache-Control', 'private, max-age=60'))
|
|
10
|
+
* @Get('/:id/invoice') invoice() {}
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export declare function OnSend(...hooks: OnSendHook[]): (_value: unknown, context: ClassOrMethodContext) => void;
|
|
14
|
+
/**
|
|
15
|
+
* `onResponse` só para as rotas da classe ou do método (F-43): roda exatamente uma vez quando a requisição
|
|
16
|
+
* termina (inclusive cancelada ou em stream), depois dos `onResponse` do app.
|
|
17
|
+
*/
|
|
18
|
+
export declare function OnResponse(...hooks: OnResponseHook[]): (_value: unknown, context: ClassOrMethodContext) => void;
|
|
19
|
+
/**
|
|
20
|
+
* `onError` só para as rotas da classe ou do método (F-43): roda antes dos `onError` do app, do escopo mais
|
|
21
|
+
* específico para o mais externo. Se responder, os de fora (e a resposta padrão) não rodam.
|
|
22
|
+
*/
|
|
23
|
+
export declare function OnError(...hooks: OnErrorHook[]): (_value: unknown, context: ClassOrMethodContext) => void;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/decorators/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAIrD,KAAK,oBAAoB,GAAG,qBAAqB,GAAG,2BAA2B,CAAC;AAWhF;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CAAC,GAAG,KAAK,EAAE,UAAU,EAAE,YAhB3B,OAAO,WAAW,oBAAoB,KAAG,IAAI,CAkB9D;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,GAAG,KAAK,EAAE,cAAc,EAAE,YAxBnC,OAAO,WAAW,oBAAoB,KAAG,IAAI,CA0B9D;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,GAAG,KAAK,EAAE,WAAW,EAAE,YAhC7B,OAAO,WAAW,oBAAoB,KAAG,IAAI,CAkC9D"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { getOrCreateMethod, metadataFor } from '../core/metadata.js';
|
|
2
|
+
/** Na classe (todas as rotas) ou no método; na ordem de leitura, como `@Middlewares` e `@Guards`. */
|
|
3
|
+
function register(decorator, kind, hooks) {
|
|
4
|
+
return (_value, context) => {
|
|
5
|
+
const meta = metadataFor(context, decorator);
|
|
6
|
+
const target = context.kind === 'class' ? meta : getOrCreateMethod(meta, context.name);
|
|
7
|
+
target.hooks[kind].unshift(...hooks);
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* `onSend` só para as rotas da classe ou do método (F-43): roda depois dos `onSend` do app, imediatamente
|
|
12
|
+
* antes de escrever a resposta. A assinatura é a do `app.onSend`.
|
|
13
|
+
*
|
|
14
|
+
* ```ts
|
|
15
|
+
* @OnSend((ctx) => void ctx.header('Cache-Control', 'private, max-age=60'))
|
|
16
|
+
* @Get('/:id/invoice') invoice() {}
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export function OnSend(...hooks) {
|
|
20
|
+
return register('OnSend', 'onSend', hooks);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* `onResponse` só para as rotas da classe ou do método (F-43): roda exatamente uma vez quando a requisição
|
|
24
|
+
* termina (inclusive cancelada ou em stream), depois dos `onResponse` do app.
|
|
25
|
+
*/
|
|
26
|
+
export function OnResponse(...hooks) {
|
|
27
|
+
return register('OnResponse', 'onResponse', hooks);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* `onError` só para as rotas da classe ou do método (F-43): roda antes dos `onError` do app, do escopo mais
|
|
31
|
+
* específico para o mais externo. Se responder, os de fora (e a resposta padrão) não rodam.
|
|
32
|
+
*/
|
|
33
|
+
export function OnError(...hooks) {
|
|
34
|
+
return register('OnError', 'onError', hooks);
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/decorators/hooks.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAIrE,qGAAqG;AACrG,SAAS,QAAQ,CAA8B,SAAiB,EAAE,IAAO,EAAE,KAAqB;IAC9F,OAAO,CAAC,MAAe,EAAE,OAA6B,EAAQ,EAAE;QAC9D,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QACtF,MAAM,CAAC,KAAK,CAAC,IAAI,CAAe,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC;IACtD,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,MAAM,CAAC,GAAG,KAAmB;IAC3C,OAAO,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;AAC7C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,GAAG,KAAuB;IACnD,OAAO,QAAQ,CAAC,YAAY,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC;AACrD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,GAAG,KAAoB;IAC7C,OAAO,QAAQ,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CheckParams } from '../core/infer.ts';
|
|
2
|
+
import { type RouteSchemas } from '../core/metadata.ts';
|
|
3
|
+
declare function methodDecorator(httpMethod: string, path: string, schemas?: RouteSchemas): <This, Args extends [any, ...unknown[]], Return>(_target: (this: This, ...args: Args) => Return, context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>) => void;
|
|
4
|
+
/**
|
|
5
|
+
* Decorators de rota. O segundo argumento, opcional, são os schemas da rota: o mesmo que `@Schema`,
|
|
6
|
+
* na mesma linha do verbo.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* @Get('/:id', byId)
|
|
10
|
+
* getUser(ctx: Context<typeof byId>) {}
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
type Verb = <const P extends string = '/', const S extends RouteSchemas = {}>(path?: P, schemas?: S & CheckParams<P, S>) => ReturnType<typeof methodDecorator>;
|
|
14
|
+
/** Com schema de `params`, as chaves precisam ser exatamente as do path, ou o TypeScript acusa (F-29). */
|
|
15
|
+
export declare const Get: Verb;
|
|
16
|
+
export declare const Post: Verb;
|
|
17
|
+
export declare const Put: Verb;
|
|
18
|
+
export declare const Patch: Verb;
|
|
19
|
+
export declare const Delete: Verb;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/decorators/http.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAgD,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEtG,iBAAS,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,IAGvE,IAAI,EAAE,IAAI,SAAS,CAAC,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC,EAAE,MAAM,WAC3C,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,IAAI,KAAK,MAAM,WACrC,2BAA2B,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC,UAQpF;AAED;;;;;;;;GAQG;AACH,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,GAAG,GAAG,EAAE,KAAK,CAAC,CAAC,SAAS,YAAY,GAAG,EAAE,EAC1E,IAAI,CAAC,EAAE,CAAC,EACR,OAAO,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,KAC5B,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAOxC,0GAA0G;AAC1G,eAAO,MAAM,GAAG,MAAc,CAAC;AAC/B,eAAO,MAAM,IAAI,MAAe,CAAC;AACjC,eAAO,MAAM,GAAG,MAAc,CAAC;AAC/B,eAAO,MAAM,KAAK,MAAgB,CAAC;AACnC,eAAO,MAAM,MAAM,MAAiB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { getOrCreateMethod, mergeSchemas, metadataFor } from '../core/metadata.js';
|
|
2
|
+
function methodDecorator(httpMethod, path, schemas) {
|
|
3
|
+
const label = httpMethod[0] + httpMethod.slice(1).toLowerCase();
|
|
4
|
+
// biome-ignore lint/suspicious/noExplicitAny: o primeiro parâmetro precisa ser bivariante para aceitar Context<S> de qualquer S.
|
|
5
|
+
return (_target, context) => {
|
|
6
|
+
const meta = metadataFor(context, label);
|
|
7
|
+
const m = getOrCreateMethod(meta, context.name);
|
|
8
|
+
m.method = httpMethod;
|
|
9
|
+
m.path = path;
|
|
10
|
+
if (schemas)
|
|
11
|
+
mergeSchemas(m, schemas, `@${label}`);
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
const verb = (httpMethod) => (path, schemas) => methodDecorator(httpMethod, path ?? '/', schemas);
|
|
15
|
+
/** Com schema de `params`, as chaves precisam ser exatamente as do path, ou o TypeScript acusa (F-29). */
|
|
16
|
+
export const Get = verb('GET');
|
|
17
|
+
export const Post = verb('POST');
|
|
18
|
+
export const Put = verb('PUT');
|
|
19
|
+
export const Patch = verb('PATCH');
|
|
20
|
+
export const Delete = verb('DELETE');
|
|
21
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/decorators/http.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,WAAW,EAAqB,MAAM,qBAAqB,CAAC;AAEtG,SAAS,eAAe,CAAC,UAAkB,EAAE,IAAY,EAAE,OAAsB;IAC/E,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IAChE,iIAAiI;IACjI,OAAO,CACL,OAA8C,EAC9C,OAAiF,EACjF,EAAE;QACF,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACzC,MAAM,CAAC,GAAG,iBAAiB,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QAChD,CAAC,CAAC,MAAM,GAAG,UAAU,CAAC;QACtB,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC;QACd,IAAI,OAAO;YAAE,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,KAAK,EAAE,CAAC,CAAC;IACrD,CAAC,CAAC;AACJ,CAAC;AAgBD,MAAM,IAAI,GACR,CAAC,UAAkB,EAAQ,EAAE,CAC7B,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAChB,eAAe,CAAC,UAAU,EAAE,IAAI,IAAI,GAAG,EAAE,OAAO,CAAC,CAAC;AAEtD,0GAA0G;AAC1G,MAAM,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;AAC/B,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;AACjC,MAAM,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;AAC/B,MAAM,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;AACnC,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { Delete, Get, Patch, Post, Put } from './http.ts';
|
|
2
|
+
export { timer, type TimerOptions } from './log.ts';
|
|
3
|
+
export { Router } from './router.ts';
|
|
4
|
+
export { Schema } from './schema.ts';
|
|
5
|
+
export { Guards, Middlewares } from './middlewares.ts';
|
|
6
|
+
export { OnError, OnResponse, OnSend } from './hooks.ts';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/decorators/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,KAAK,EAAE,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { Delete, Get, Patch, Post, Put } from './http.js';
|
|
2
|
+
export { timer } from './log.js';
|
|
3
|
+
export { Router } from './router.js';
|
|
4
|
+
export { Schema } from './schema.js';
|
|
5
|
+
export { Guards, Middlewares } from './middlewares.js';
|
|
6
|
+
export { OnError, OnResponse, OnSend } from './hooks.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/decorators/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,KAAK,EAAqB,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface TimerOptions {
|
|
2
|
+
/** Destino da medição. Padrão: `console.debug`. */
|
|
3
|
+
log?: (message: string, ms: number) => void;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Mede o tempo do handler, inclusive de handlers `async` (B-04).
|
|
7
|
+
* Uso: `@timer()` ou `@timer({ log: (msg, ms) => logger.info({ ms }, msg) })`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function timer(opts?: TimerOptions): <This, Args extends unknown[], Return>(target: (this: This, ...args: Args) => Return, context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Return>) => (this: This, ...args: Args) => Return;
|
|
10
|
+
//# sourceMappingURL=log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../src/decorators/log.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC3B,mDAAmD;IACnD,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AAED;;;GAGG;AACH,wBAAgB,KAAK,CAAC,IAAI,GAAE,YAAiB,IAGnC,IAAI,EAAE,IAAI,SAAS,OAAO,EAAE,EAAE,MAAM,UAClC,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,IAAI,KAAK,MAAM,WACpC,2BAA2B,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC,YAQ1D,IAAI,WAAW,IAAI,KAAG,MAAM,CAgBtD"}
|