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.
Files changed (259) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +74 -3
  3. package/dist/core/abort.d.ts +23 -0
  4. package/dist/core/abort.d.ts.map +1 -0
  5. package/dist/core/abort.js +23 -0
  6. package/dist/core/abort.js.map +1 -0
  7. package/dist/core/app/core.d.ts +35 -0
  8. package/dist/core/app/core.d.ts.map +1 -0
  9. package/dist/core/app/core.js +2 -0
  10. package/dist/core/app/core.js.map +1 -0
  11. package/dist/core/app/options.d.ts +178 -0
  12. package/dist/core/app/options.d.ts.map +1 -0
  13. package/dist/core/app/options.js +2 -0
  14. package/dist/core/app/options.js.map +1 -0
  15. package/dist/core/app.d.ts +143 -0
  16. package/dist/core/app.d.ts.map +1 -0
  17. package/dist/core/app.js +283 -0
  18. package/dist/core/app.js.map +1 -0
  19. package/dist/core/body-parser.d.ts +14 -0
  20. package/dist/core/body-parser.d.ts.map +1 -0
  21. package/dist/core/body-parser.js +76 -0
  22. package/dist/core/body-parser.js.map +1 -0
  23. package/dist/core/compiler.d.ts +104 -0
  24. package/dist/core/compiler.d.ts.map +1 -0
  25. package/dist/core/compiler.js +151 -0
  26. package/dist/core/compiler.js.map +1 -0
  27. package/dist/core/compose.d.ts +16 -0
  28. package/dist/core/compose.d.ts.map +1 -0
  29. package/dist/core/compose.js +41 -0
  30. package/dist/core/compose.js.map +1 -0
  31. package/dist/core/context.d.ts +290 -0
  32. package/dist/core/context.d.ts.map +1 -0
  33. package/dist/core/context.js +460 -0
  34. package/dist/core/context.js.map +1 -0
  35. package/dist/core/contracts.d.ts +76 -0
  36. package/dist/core/contracts.d.ts.map +1 -0
  37. package/dist/core/contracts.js +87 -0
  38. package/dist/core/contracts.js.map +1 -0
  39. package/dist/core/errors.d.ts +50 -0
  40. package/dist/core/errors.d.ts.map +1 -0
  41. package/dist/core/errors.js +25 -0
  42. package/dist/core/errors.js.map +1 -0
  43. package/dist/core/guard.d.ts +10 -0
  44. package/dist/core/guard.d.ts.map +1 -0
  45. package/dist/core/guard.js +14 -0
  46. package/dist/core/guard.js.map +1 -0
  47. package/dist/core/health.d.ts +37 -0
  48. package/dist/core/health.d.ts.map +1 -0
  49. package/dist/core/health.js +68 -0
  50. package/dist/core/health.js.map +1 -0
  51. package/dist/core/hooks.d.ts +34 -0
  52. package/dist/core/hooks.d.ts.map +1 -0
  53. package/dist/core/hooks.js +27 -0
  54. package/dist/core/hooks.js.map +1 -0
  55. package/dist/core/index.d.ts +30 -0
  56. package/dist/core/index.d.ts.map +1 -0
  57. package/dist/core/index.js +11 -0
  58. package/dist/core/index.js.map +1 -0
  59. package/dist/core/infer.d.ts +68 -0
  60. package/dist/core/infer.d.ts.map +1 -0
  61. package/dist/core/infer.js +2 -0
  62. package/dist/core/infer.js.map +1 -0
  63. package/dist/core/inject.d.ts +27 -0
  64. package/dist/core/inject.d.ts.map +1 -0
  65. package/dist/core/inject.js +85 -0
  66. package/dist/core/inject.js.map +1 -0
  67. package/dist/core/logger.d.ts +57 -0
  68. package/dist/core/logger.d.ts.map +1 -0
  69. package/dist/core/logger.js +134 -0
  70. package/dist/core/logger.js.map +1 -0
  71. package/dist/core/metadata.d.ts +83 -0
  72. package/dist/core/metadata.d.ts.map +1 -0
  73. package/dist/core/metadata.js +91 -0
  74. package/dist/core/metadata.js.map +1 -0
  75. package/dist/core/mounted-group.d.ts +77 -0
  76. package/dist/core/mounted-group.d.ts.map +1 -0
  77. package/dist/core/mounted-group.js +131 -0
  78. package/dist/core/mounted-group.js.map +1 -0
  79. package/dist/core/registry/framework-routes.d.ts +28 -0
  80. package/dist/core/registry/framework-routes.d.ts.map +1 -0
  81. package/dist/core/registry/framework-routes.js +83 -0
  82. package/dist/core/registry/framework-routes.js.map +1 -0
  83. package/dist/core/registry/registry.d.ts +58 -0
  84. package/dist/core/registry/registry.d.ts.map +1 -0
  85. package/dist/core/registry/registry.js +208 -0
  86. package/dist/core/registry/registry.js.map +1 -0
  87. package/dist/core/registry/route-program.d.ts +16 -0
  88. package/dist/core/registry/route-program.d.ts.map +1 -0
  89. package/dist/core/registry/route-program.js +62 -0
  90. package/dist/core/registry/route-program.js.map +1 -0
  91. package/dist/core/request-validation.d.ts +15 -0
  92. package/dist/core/request-validation.d.ts.map +1 -0
  93. package/dist/core/request-validation.js +67 -0
  94. package/dist/core/request-validation.js.map +1 -0
  95. package/dist/core/response/pipeline.d.ts +51 -0
  96. package/dist/core/response/pipeline.d.ts.map +1 -0
  97. package/dist/core/response/pipeline.js +169 -0
  98. package/dist/core/response/pipeline.js.map +1 -0
  99. package/dist/core/route-table.d.ts +58 -0
  100. package/dist/core/route-table.d.ts.map +1 -0
  101. package/dist/core/route-table.js +108 -0
  102. package/dist/core/route-table.js.map +1 -0
  103. package/dist/core/runtime/observer.d.ts +47 -0
  104. package/dist/core/runtime/observer.d.ts.map +1 -0
  105. package/dist/core/runtime/observer.js +125 -0
  106. package/dist/core/runtime/observer.js.map +1 -0
  107. package/dist/core/runtime/request-handler.d.ts +62 -0
  108. package/dist/core/runtime/request-handler.d.ts.map +1 -0
  109. package/dist/core/runtime/request-handler.js +256 -0
  110. package/dist/core/runtime/request-handler.js.map +1 -0
  111. package/dist/core/runtime/server.d.ts +59 -0
  112. package/dist/core/runtime/server.d.ts.map +1 -0
  113. package/dist/core/runtime/server.js +180 -0
  114. package/dist/core/runtime/server.js.map +1 -0
  115. package/dist/core/shutdown.d.ts +41 -0
  116. package/dist/core/shutdown.d.ts.map +1 -0
  117. package/dist/core/shutdown.js +53 -0
  118. package/dist/core/shutdown.js.map +1 -0
  119. package/dist/core/streaming/sse.d.ts +35 -0
  120. package/dist/core/streaming/sse.d.ts.map +1 -0
  121. package/dist/core/streaming/sse.js +121 -0
  122. package/dist/core/streaming/sse.js.map +1 -0
  123. package/dist/core/symbols.d.ts +28 -0
  124. package/dist/core/symbols.d.ts.map +1 -0
  125. package/dist/core/symbols.js +28 -0
  126. package/dist/core/symbols.js.map +1 -0
  127. package/dist/core/telemetry.d.ts +83 -0
  128. package/dist/core/telemetry.d.ts.map +1 -0
  129. package/dist/core/telemetry.js +96 -0
  130. package/dist/core/telemetry.js.map +1 -0
  131. package/dist/core/uploads/receive.d.ts +63 -0
  132. package/dist/core/uploads/receive.d.ts.map +1 -0
  133. package/dist/core/uploads/receive.js +342 -0
  134. package/dist/core/uploads/receive.js.map +1 -0
  135. package/dist/core/uploads/types.d.ts +79 -0
  136. package/dist/core/uploads/types.d.ts.map +1 -0
  137. package/dist/core/uploads/types.js +2 -0
  138. package/dist/core/uploads/types.js.map +1 -0
  139. package/dist/decorators/hooks.d.ts +25 -0
  140. package/dist/decorators/hooks.d.ts.map +1 -0
  141. package/dist/decorators/hooks.js +36 -0
  142. package/dist/decorators/hooks.js.map +1 -0
  143. package/dist/decorators/http.d.ts +21 -0
  144. package/dist/decorators/http.d.ts.map +1 -0
  145. package/dist/decorators/http.js +21 -0
  146. package/dist/decorators/http.js.map +1 -0
  147. package/dist/decorators/index.d.ts +7 -0
  148. package/dist/decorators/index.d.ts.map +1 -0
  149. package/dist/decorators/index.js +7 -0
  150. package/dist/decorators/index.js.map +1 -0
  151. package/dist/decorators/log.d.ts +10 -0
  152. package/dist/decorators/log.d.ts.map +1 -0
  153. package/dist/decorators/log.js +32 -0
  154. package/dist/decorators/log.js.map +1 -0
  155. package/dist/decorators/middlewares.d.ts +28 -0
  156. package/dist/decorators/middlewares.d.ts.map +1 -0
  157. package/dist/decorators/middlewares.js +40 -0
  158. package/dist/decorators/middlewares.js.map +1 -0
  159. package/dist/decorators/router.d.ts +12 -0
  160. package/dist/decorators/router.d.ts.map +1 -0
  161. package/dist/decorators/router.js +20 -0
  162. package/dist/decorators/router.js.map +1 -0
  163. package/dist/decorators/schema.d.ts +8 -0
  164. package/dist/decorators/schema.d.ts.map +1 -0
  165. package/dist/decorators/schema.js +14 -0
  166. package/dist/decorators/schema.js.map +1 -0
  167. package/dist/index.d.ts +7 -0
  168. package/dist/index.d.ts.map +1 -0
  169. package/dist/index.js +10 -0
  170. package/dist/index.js.map +1 -0
  171. package/dist/middlewares/auth.d.ts +41 -0
  172. package/dist/middlewares/auth.d.ts.map +1 -0
  173. package/dist/middlewares/auth.js +74 -0
  174. package/dist/middlewares/auth.js.map +1 -0
  175. package/dist/middlewares/cors.d.ts +30 -0
  176. package/dist/middlewares/cors.d.ts.map +1 -0
  177. package/dist/middlewares/cors.js +69 -0
  178. package/dist/middlewares/cors.js.map +1 -0
  179. package/dist/middlewares/csrf.d.ts +42 -0
  180. package/dist/middlewares/csrf.d.ts.map +1 -0
  181. package/dist/middlewares/csrf.js +70 -0
  182. package/dist/middlewares/csrf.js.map +1 -0
  183. package/dist/middlewares/index.d.ts +6 -0
  184. package/dist/middlewares/index.d.ts.map +1 -0
  185. package/dist/middlewares/index.js +6 -0
  186. package/dist/middlewares/index.js.map +1 -0
  187. package/dist/middlewares/rate-limit.d.ts +35 -0
  188. package/dist/middlewares/rate-limit.d.ts.map +1 -0
  189. package/dist/middlewares/rate-limit.js +45 -0
  190. package/dist/middlewares/rate-limit.js.map +1 -0
  191. package/dist/middlewares/security-headers.d.ts +28 -0
  192. package/dist/middlewares/security-headers.d.ts.map +1 -0
  193. package/dist/middlewares/security-headers.js +42 -0
  194. package/dist/middlewares/security-headers.js.map +1 -0
  195. package/dist/openapi/generate.d.ts +51 -0
  196. package/dist/openapi/generate.d.ts.map +1 -0
  197. package/dist/openapi/generate.js +175 -0
  198. package/dist/openapi/generate.js.map +1 -0
  199. package/dist/schema/serialization.d.ts +2 -0
  200. package/dist/schema/serialization.d.ts.map +1 -0
  201. package/dist/schema/serialization.js +11 -0
  202. package/dist/schema/serialization.js.map +1 -0
  203. package/dist/schema/validation.d.ts +22 -0
  204. package/dist/schema/validation.d.ts.map +1 -0
  205. package/dist/schema/validation.js +68 -0
  206. package/dist/schema/validation.js.map +1 -0
  207. package/dist/server/static.d.ts +45 -0
  208. package/dist/server/static.d.ts.map +1 -0
  209. package/dist/server/static.js +204 -0
  210. package/dist/server/static.js.map +1 -0
  211. package/dist/server/tls.d.ts +48 -0
  212. package/dist/server/tls.d.ts.map +1 -0
  213. package/dist/server/tls.js +60 -0
  214. package/dist/server/tls.js.map +1 -0
  215. package/dist/shims/symbol-metadata.d.ts +2 -0
  216. package/dist/shims/symbol-metadata.d.ts.map +1 -0
  217. package/dist/shims/symbol-metadata.js +8 -0
  218. package/dist/shims/symbol-metadata.js.map +1 -0
  219. package/dist/utils/content-type.d.ts +13 -0
  220. package/dist/utils/content-type.d.ts.map +1 -0
  221. package/dist/utils/content-type.js +75 -0
  222. package/dist/utils/content-type.js.map +1 -0
  223. package/dist/utils/cookie.d.ts +34 -0
  224. package/dist/utils/cookie.d.ts.map +1 -0
  225. package/dist/utils/cookie.js +94 -0
  226. package/dist/utils/cookie.js.map +1 -0
  227. package/dist/utils/index.d.ts +7 -0
  228. package/dist/utils/index.d.ts.map +1 -0
  229. package/dist/utils/index.js +7 -0
  230. package/dist/utils/index.js.map +1 -0
  231. package/dist/utils/mime.d.ts +2 -0
  232. package/dist/utils/mime.d.ts.map +1 -0
  233. package/dist/utils/mime.js +52 -0
  234. package/dist/utils/mime.js.map +1 -0
  235. package/dist/utils/origin-match.d.ts +58 -0
  236. package/dist/utils/origin-match.d.ts.map +1 -0
  237. package/dist/utils/origin-match.js +194 -0
  238. package/dist/utils/origin-match.js.map +1 -0
  239. package/dist/utils/path.d.ts +10 -0
  240. package/dist/utils/path.d.ts.map +1 -0
  241. package/dist/utils/path.js +60 -0
  242. package/dist/utils/path.js.map +1 -0
  243. package/dist/utils/query.d.ts +28 -0
  244. package/dist/utils/query.d.ts.map +1 -0
  245. package/dist/utils/query.js +67 -0
  246. package/dist/utils/query.js.map +1 -0
  247. package/dist/utils/request-target.d.ts +31 -0
  248. package/dist/utils/request-target.d.ts.map +1 -0
  249. package/dist/utils/request-target.js +80 -0
  250. package/dist/utils/request-target.js.map +1 -0
  251. package/dist/utils/safe-json.d.ts +24 -0
  252. package/dist/utils/safe-json.d.ts.map +1 -0
  253. package/dist/utils/safe-json.js +83 -0
  254. package/dist/utils/safe-json.js.map +1 -0
  255. package/dist/utils/trace-context.d.ts +17 -0
  256. package/dist/utils/trace-context.d.ts.map +1 -0
  257. package/dist/utils/trace-context.js +30 -0
  258. package/dist/utils/trace-context.js.map +1 -0
  259. package/package.json +85 -6
@@ -0,0 +1,460 @@
1
+ import { Readable } from 'node:stream';
2
+ import { ReadStream } from 'node:fs';
3
+ import { HttpError } from './errors.js';
4
+ import { parseCustomQuery, parseQuery } from '../utils/query.js';
5
+ import { parseCookies, serializeCookie } from '../utils/cookie.js';
6
+ import { hostnameOf, isValidHost, pickForwarded, splitRequestTarget } from '../utils/request-target.js';
7
+ import { silentLogger } from './logger.js';
8
+ import { sendResult } from './response/pipeline.js';
9
+ import { RequestAbortedError } from './abort.js';
10
+ import { parseTraceparent } from '../utils/trace-context.js';
11
+ import { kAbort, kBindResponse, kContracts, kError, kHooks, kPendingSend, kPhase, kRawSend, kRoute, kRouted, kTelemetry, kFiles, } from './symbols.js';
12
+ import { sendFile } from '../server/static.js';
13
+ import { openSse } from './streaming/sse.js';
14
+ import { NATIVE_CONTRACTS } from './contracts.js';
15
+ export { kAbort, kBindResponse, kPendingSend, kRawSend } from './symbols.js';
16
+ /** Erros de stream que só significam que o cliente foi embora (P-12). */
17
+ const CLIENT_GONE = new Set(['ECONNRESET', 'EPIPE', 'ERR_STREAM_PREMATURE_CLOSE', 'ERR_STREAM_UNABLE_TO_PIPE', 'ERR_STREAM_DESTROYED']);
18
+ function isClientDisconnect(err) {
19
+ return typeof err === 'object' && err !== null && CLIENT_GONE.has(err.code ?? '');
20
+ }
21
+ /**
22
+ * Envia um stream para a resposta (F-45). `.pipe()` em vez do `pipeline()`: o `pipeline()` alocava promessas e
23
+ * listeners por resposta que, num download em andamento, sobreviviam às coletas rápidas do V8 e eram promovidos;
24
+ * no cenário de arquivos estáticos, era o maior responsável pelo RSS de pico. O que o `pipeline()` fazia continua:
25
+ * erro na origem loga e destrói a resposta; resposta fechada antes do fim (cliente desistiu) destrói a origem,
26
+ * liberando o descritor do arquivo.
27
+ */
28
+ function pipeStream(ctx, body) {
29
+ const res = ctx.res;
30
+ body.once('error', (err) => {
31
+ // P-12: o cliente desistir é normal e não é erro do servidor.
32
+ const clientGone = isClientDisconnect(err);
33
+ ctx.log[clientGone ? 'debug' : 'error']({ err, method: ctx.method, path: ctx.path }, clientGone ? 'client disconnected during stream' : 'stream failed');
34
+ res.destroy(err);
35
+ });
36
+ res.once('close', () => {
37
+ if (res.writableFinished || body.destroyed)
38
+ return;
39
+ ctx.log.debug({ method: ctx.method, path: ctx.path }, 'client disconnected during stream');
40
+ body.destroy();
41
+ });
42
+ body.pipe(res);
43
+ }
44
+ export class Context {
45
+ req;
46
+ res;
47
+ method;
48
+ path;
49
+ /** Id da requisição, também enviado no header `X-Request-Id` (F-06). */
50
+ id;
51
+ /** Parâmetros de rota; tipados pelo schema `params` quando informado em `Context<S>`. */
52
+ get params() {
53
+ this.routeParams ??= {};
54
+ return this.routeParams;
55
+ }
56
+ set params(value) {
57
+ this.routeParams = value;
58
+ }
59
+ routeParams;
60
+ /**
61
+ * A rota que atende esta requisição (F-38): template com o prefixo, classe, método e a regra de host que
62
+ * venceu. `undefined` antes do roteamento e quando nenhuma rota atende (404, 405, healthcheck, OpenAPI).
63
+ * Use `ctx.route.path` como rótulo de métrica, nunca `ctx.path`.
64
+ */
65
+ get route() {
66
+ return this[kRoute];
67
+ }
68
+ /** @internal */
69
+ [kRoute];
70
+ /** @internal O motor dos contratos do app (F-27). */
71
+ get [kContracts]() {
72
+ return this.opts.contracts ?? NATIVE_CONTRACTS;
73
+ }
74
+ /** @internal Etapa atual do pipeline, para a fase do `onError` (F-38). */
75
+ [kPhase] = 'middleware';
76
+ /** @internal A cadeia global chegou ao roteamento (o último middleware chamou `next()`). */
77
+ [kRouted] = false;
78
+ /** @internal O erro tratado pelo pipeline de erros, para o `onResponse` (F-38). */
79
+ [kError];
80
+ /** @internal Estado do `telemetry` desta requisição; só o módulo do telemetry lê e escreve (F-38). */
81
+ [kTelemetry];
82
+ /** @internal Arquivos do upload (F-46); definido só nas rotas com `files`, e então o body veio de um formulário. */
83
+ [kFiles];
84
+ /** Query string; tipada pelo schema `query` (já com coerção e defaults aplicados). Lida no primeiro acesso. */
85
+ get query() {
86
+ if (this.parsedQuery === undefined) {
87
+ const custom = this.opts.queryParser;
88
+ if (custom) {
89
+ try {
90
+ this.parsedQuery = parseCustomQuery(custom, this.target.search);
91
+ }
92
+ catch {
93
+ // A mensagem do parser pode expor detalhes internos: o cliente recebe só o motivo genérico.
94
+ throw new HttpError(400, 'Invalid query string', 'INVALID_QUERY');
95
+ }
96
+ }
97
+ else {
98
+ this.parsedQuery = parseQuery(new URLSearchParams(this.target.search), this.opts.queryMaxKeys);
99
+ }
100
+ }
101
+ return this.parsedQuery;
102
+ }
103
+ set query(value) {
104
+ this.parsedQuery = value;
105
+ }
106
+ /** URL completa da requisição, com o host validado (S-09). Criada no primeiro acesso. */
107
+ get url() {
108
+ this.fullUrl ??= new URL(`${this.protocol}://${this.host || 'localhost'}${this.target.pathname}${this.target.search}`);
109
+ return this.fullUrl;
110
+ }
111
+ /** Logger da requisição, já com `reqId` (F-06). Criado no primeiro acesso. */
112
+ get log() {
113
+ if (!this.requestLog) {
114
+ // Com `telemetry`, os ids do span desta requisição; sem, o `traceId` recebido no `traceparent`.
115
+ const ids = this.opts.spanIds?.(this);
116
+ const traceId = ids?.traceId ?? this.trace?.traceId;
117
+ const base = this.opts.logger ?? silentLogger;
118
+ this.requestLog = base.child(ids ? { reqId: this.id, traceId: ids.traceId, spanId: ids.spanId } : traceId ? { reqId: this.id, traceId } : { reqId: this.id });
119
+ }
120
+ return this.requestLog;
121
+ }
122
+ /**
123
+ * Contexto de trace W3C recebido no `traceparent` (F-38), já validado: `{ traceId, parentSpanId, sampled,
124
+ * tracestate }`, ou `undefined` se não veio ou é inválido. Os logs do `ctx.log` levam o `traceId`.
125
+ */
126
+ get trace() {
127
+ if (this.traceContext === null) {
128
+ this.traceContext = parseTraceparent(this.req.headers.traceparent, this.req.headers.tracestate);
129
+ }
130
+ return this.traceContext;
131
+ }
132
+ traceContext = null;
133
+ // Campos preguiçosos (F-39, fase 2): calculados no primeiro acesso e guardados. Dependem só da
134
+ // requisição e da configuração do app, que não mudam durante a requisição.
135
+ /**
136
+ * Configuração do app, **a mesma referência** para todas as requisições (Flyweight, F-41): o `Context` lê
137
+ * dela em vez de copiar `trustProxy`, `onSend`, `queryMaxKeys` e o logger campo a campo.
138
+ */
139
+ opts;
140
+ target;
141
+ parsedQuery;
142
+ fullUrl;
143
+ requestLog;
144
+ memoHost;
145
+ memoHostname;
146
+ memoProtocol;
147
+ /**
148
+ * Um arquivo do upload, já recebido e validado pelo contrato `files` (F-46). Com `required: true`, nunca é
149
+ * `undefined`. Para campos com `maxCount` maior que 1, use `files()`.
150
+ */
151
+ file(name) {
152
+ return this[kFiles]?.get(name)?.[0];
153
+ }
154
+ /** Todos os arquivos de um campo do upload (F-46), na ordem em que chegaram; vazio se nenhum veio. */
155
+ files(name) {
156
+ return this[kFiles]?.get(name) ?? [];
157
+ }
158
+ /** Body; tipado pelo schema `body`. */
159
+ body = undefined;
160
+ /** Estado por requisição, criado no primeiro acesso (F-41). */
161
+ get state() {
162
+ this.requestState ??= {};
163
+ return this.requestState;
164
+ }
165
+ set state(value) {
166
+ this.requestState = value;
167
+ }
168
+ requestState;
169
+ /** `true` quando o handler chamou `ctx.status()`. Usado para escolher o schema de resposta (B-05). */
170
+ statusExplicit = false;
171
+ streaming = false;
172
+ abortController;
173
+ /**
174
+ * Cancelado quando o cliente desconecta antes do fim da resposta, ou quando o app está encerrando
175
+ * (F-13). Passe para consultas e `fetch` longos: `db.query(sql, { signal: ctx.signal })`.
176
+ */
177
+ get signal() {
178
+ if (!this.abortController) {
179
+ const controller = new AbortController();
180
+ this.abortController = controller;
181
+ if (this.res.writableEnded)
182
+ return controller.signal;
183
+ // O cliente pode ter desconectado antes do primeiro acesso ao signal (num `await` anterior):
184
+ // o evento 'close' já passou, então o estado precisa ser conferido agora.
185
+ if (this.res.destroyed || this.req.destroyed || this.req.socket?.destroyed) {
186
+ controller.abort(new RequestAbortedError('CLIENT_DISCONNECTED'));
187
+ return controller.signal;
188
+ }
189
+ this.res.once('close', () => {
190
+ // `writableEnded`: a resposta foi encerrada pelo app. `writableFinished` dependeria de o socket ter
191
+ // recebido tudo, e no inject (sem socket) uma resposta bem-sucedida pareceria uma desconexão.
192
+ if (!this.res.writableEnded)
193
+ controller.abort(new RequestAbortedError('CLIENT_DISCONNECTED'));
194
+ });
195
+ }
196
+ return this.abortController.signal;
197
+ }
198
+ /**
199
+ * Por que esta requisição foi cancelada (`CLIENT_DISCONNECTED`, `SHUTDOWN`), ou `undefined` se não foi.
200
+ * Atalho tipado para `ctx.signal.reason.code` (F-38).
201
+ */
202
+ get abortReason() {
203
+ const reason = this.abortController?.signal.reason;
204
+ return reason instanceof RequestAbortedError ? reason.code : undefined;
205
+ }
206
+ /** @internal `true` em respostas de streaming (SSE, NDJSON, `Readable`) já iniciadas. */
207
+ get streamingResponse() {
208
+ return this.streaming;
209
+ }
210
+ markStreaming() {
211
+ if (this.streaming)
212
+ return;
213
+ this.streaming = true;
214
+ this.opts.onStream?.(this);
215
+ }
216
+ /** @internal */
217
+ [kAbort](code) {
218
+ void this.signal;
219
+ this.abortController?.abort(new RequestAbortedError(code));
220
+ }
221
+ /**
222
+ * Abre uma conexão de Server-Sent Events (F-13). A resposta fica aberta até `close()`, a desconexão do
223
+ * cliente ou o encerramento do app, que fecha estas conexões primeiro para o shutdown não esperar por elas.
224
+ *
225
+ * ```ts
226
+ * const stream = ctx.sse();
227
+ * const off = bus.on('order', (o) => stream.send({ event: 'order', id: o.id, data: o }));
228
+ * stream.onClose(off);
229
+ * ```
230
+ */
231
+ sse(opts = {}) {
232
+ return openSse(this, opts, () => this.markStreaming());
233
+ }
234
+ /**
235
+ * Envia um arquivo com `Content-Type`, `ETag`/`Last-Modified` (304) e `Range` (206), em stream (F-13).
236
+ * Com `root`, o path é relativo e não pode sair dela; sem `root`, precisa ser absoluto.
237
+ * Arquivo inexistente responde 404.
238
+ */
239
+ sendFile(path, opts) {
240
+ // O app aguarda este envio mesmo que o handler esqueça o `await`/`return`: sem isso, a resposta sairia
241
+ // vazia e um erro (404, por exemplo) viraria um unhandledRejection.
242
+ const pending = sendFile(this, path, opts);
243
+ this[kPendingSend] = pending;
244
+ return pending;
245
+ }
246
+ /** @internal */
247
+ [kPendingSend];
248
+ /**
249
+ * Corpo exatamente como foi escrito (F-04), depois do envio. Fica `undefined` em streams e em
250
+ * respostas sem corpo. Útil para cache: `await next(); store.set(key, ctx.sentBody)`.
251
+ */
252
+ get sentBody() {
253
+ // Convertido só se alguém ler (F-39): antes, toda resposta copiava o corpo para um Buffer.
254
+ if (this.sentBuffer === undefined && this.sentRaw !== undefined) {
255
+ this.sentBuffer = typeof this.sentRaw === 'string' ? Buffer.from(this.sentRaw) : Buffer.from(this.sentRaw);
256
+ }
257
+ return this.sentBuffer;
258
+ }
259
+ set sentBody(value) {
260
+ this.sentBuffer = value;
261
+ this.sentRaw = undefined;
262
+ }
263
+ sentRaw;
264
+ sentBuffer;
265
+ /** `Content-Type` da resposta enviada, junto com `sentBody`. */
266
+ sentType;
267
+ bound;
268
+ /**
269
+ * @param opts configuração; o app passa **o mesmo objeto** para todas as requisições (Flyweight), e o
270
+ * que muda por requisição (`id`) vem à parte.
271
+ */
272
+ constructor(req, res, opts = {}, id) {
273
+ this.req = req;
274
+ this.res = res;
275
+ this.method = req.method ?? 'GET';
276
+ this.opts = opts;
277
+ // S-09: o path vem do request-target com base fixa; o host do cliente nunca entra no parsing.
278
+ this.target = splitRequestTarget(req.url);
279
+ this.path = this.target.pathname;
280
+ this.id = id ?? opts.id ?? '';
281
+ }
282
+ /**
283
+ * IP do cliente. Por padrão, o do socket. Com `trustProxy`, vem do `X-Forwarded-For`, que só deve
284
+ * ser ligado atrás de um proxy que reescreve esse header (S-09).
285
+ */
286
+ get ip() {
287
+ return pickForwarded(this.req.headers['x-forwarded-for'], this.opts.trustProxy ?? false) ?? this.req.socket.remoteAddress ?? '';
288
+ }
289
+ /**
290
+ * Host da requisição (`api.exemplo.com:8080`), **validado**: um valor inválido vira `''`.
291
+ * Com `trustProxy`, vem do `X-Forwarded-Host`. Para links absolutos, prefira uma URL base
292
+ * configurada em vez do host pedido pelo cliente (S-09).
293
+ */
294
+ get host() {
295
+ if (this.memoHost === undefined) {
296
+ const forwarded = pickForwarded(this.req.headers['x-forwarded-host'], this.opts.trustProxy ?? false);
297
+ const raw = forwarded !== undefined ? forwarded : this.req.headers.host;
298
+ this.memoHost = isValidHost(raw) ? raw : '';
299
+ }
300
+ return this.memoHost;
301
+ }
302
+ /** `host` sem a porta. */
303
+ get hostname() {
304
+ this.memoHostname ??= this.host ? hostnameOf(this.host) : '';
305
+ return this.memoHostname;
306
+ }
307
+ /** `https` se a conexão for TLS ou, com `trustProxy`, se o `X-Forwarded-Proto` disser; senão `http`. */
308
+ get protocol() {
309
+ if (this.memoProtocol === undefined) {
310
+ const forwarded = pickForwarded(this.req.headers['x-forwarded-proto'], this.opts.trustProxy ?? false)?.toLowerCase();
311
+ this.memoProtocol =
312
+ forwarded === 'https' || forwarded === 'http'
313
+ ? forwarded
314
+ : this.req.socket.encrypted
315
+ ? 'https'
316
+ : 'http';
317
+ }
318
+ return this.memoProtocol;
319
+ }
320
+ /**
321
+ * Define o status. Com schemas de resposta, aceita só os status declarados e o encadeamento tipa o
322
+ * corpo: `ctx.status(202).json({ jobId })` (F-32).
323
+ */
324
+ status(code) {
325
+ this.res.statusCode = code;
326
+ this.statusExplicit = true;
327
+ return this;
328
+ }
329
+ /**
330
+ * `true` quando a resposta já foi enviada (ou está sendo, no caso de streams).
331
+ * Depois disso o framework não escreve mais nada na resposta.
332
+ */
333
+ get sent() {
334
+ return this.streaming || this.res.writableEnded;
335
+ }
336
+ /** Lê um header da requisição (case-insensitive). Headers repetidos são unidos com `, `. */
337
+ get(name) {
338
+ const value = this.req.headers[name.toLowerCase()];
339
+ return Array.isArray(value) ? value.join(', ') : value;
340
+ }
341
+ parsedCookies;
342
+ /** Cookies da requisição (objeto sem protótipo; em nomes repetidos vale o primeiro). */
343
+ get cookies() {
344
+ return (this.parsedCookies ??= parseCookies(this.get('cookie')));
345
+ }
346
+ /**
347
+ * Adiciona um `Set-Cookie`. Padrões: `HttpOnly`, `Secure`, `SameSite=Lax` e `Path=/`.
348
+ * Se usar cookies para autenticar, ative também o middleware `csrf()`.
349
+ */
350
+ setCookie(name, value, opts) {
351
+ this.res.appendHeader('Set-Cookie', serializeCookie(name, value, opts));
352
+ return this;
353
+ }
354
+ /** Remove um cookie. Informe o mesmo `path` e `domain` usados ao criá-lo. */
355
+ clearCookie(name, opts = {}) {
356
+ return this.setCookie(name, '', { ...opts, maxAge: 0, expires: new Date(0) });
357
+ }
358
+ /** Define um header da resposta. */
359
+ header(name, value) {
360
+ this.res.setHeader(name, value);
361
+ return this;
362
+ }
363
+ /**
364
+ * Envia JSON. No handler, passa pelo mesmo pipeline do `return`: schema do status, remoção de
365
+ * campos não declarados e status padrão (F-32).
366
+ */
367
+ json(data) {
368
+ return this.dispatch(data, 'json');
369
+ }
370
+ /** Resposta em texto puro (`text/plain; charset=utf-8`), pelo mesmo pipeline do `return`. */
371
+ text(data) {
372
+ return this.dispatch(data, 'text');
373
+ }
374
+ /**
375
+ * Envia o corpo pelo mesmo pipeline do `return` (F-32): com `contentType` informado, usa esse tipo;
376
+ * senão, a negociação do `Accept` ou o tipo do valor (string, Buffer, stream, objeto → JSON).
377
+ * Para HTML, faça o escape do conteúdo dinâmico antes: o framework não faz isso por você (S-02).
378
+ */
379
+ send(body, contentType) {
380
+ if (this.sent)
381
+ return this;
382
+ if (contentType)
383
+ this.res.setHeader('Content-Type', contentType);
384
+ return this.dispatch(body, 'auto');
385
+ }
386
+ dispatch(body, mode) {
387
+ if (this.sent)
388
+ return this;
389
+ // Antes do handler (middlewares, guards) não há schema ligado: vale só o tipo do conteúdo.
390
+ const plan = this.bound;
391
+ if (plan)
392
+ sendResult(this, plan.response, body, plan.serializers, mode, plan.defaultStatus);
393
+ else
394
+ sendResult(this, undefined, body, undefined, mode);
395
+ return this;
396
+ }
397
+ /** @internal Liga os schemas de resposta da rota (o app chama antes do handler). */
398
+ [kBindResponse](plan) {
399
+ this.bound = plan;
400
+ }
401
+ /** @internal Envio cru, sem schema: string, bytes ou stream. */
402
+ [kRawSend](body, contentType) {
403
+ if (this.sent)
404
+ return this;
405
+ const type = contentType ?? this.res.getHeader('Content-Type') ?? 'application/octet-stream';
406
+ if (body instanceof Readable) {
407
+ this.res.setHeader('Content-Type', type);
408
+ // Arquivo do disco termina sozinho: fica fora do conjunto que o `close()` cancela (F-45).
409
+ if (body instanceof ReadStream)
410
+ this.streaming = true;
411
+ else
412
+ this.markStreaming();
413
+ pipeStream(this, body);
414
+ return this;
415
+ }
416
+ // Content-Type escrito uma vez só, depois do onSend (antes: duas vezes por resposta).
417
+ const global = this.opts.onSend;
418
+ const scoped = this[kRoute]?.[kHooks]?.onSend;
419
+ const payload = (global && global.length > 0) || scoped ? this.runOnSend({ body, contentType: type }, scoped) : { body, contentType: type };
420
+ this.res.setHeader('Content-Type', payload.contentType);
421
+ this.sentRaw = payload.body;
422
+ this.sentBuffer = undefined;
423
+ this.sentType = payload.contentType;
424
+ this.res.end(payload.body);
425
+ return this;
426
+ }
427
+ /** Aplica os `onSend` do app e depois os da rota (F-43); se algum lançar, loga e envia o payload original (F-04). */
428
+ runOnSend(original, scoped) {
429
+ let payload = original;
430
+ try {
431
+ for (const hook of this.opts.onSend ?? [])
432
+ payload = hook(this, payload) ?? payload;
433
+ if (scoped)
434
+ for (const hook of scoped)
435
+ payload = hook(this, payload) ?? payload;
436
+ return payload;
437
+ }
438
+ catch (err) {
439
+ this.log.error({ err, method: this.method, path: this.path }, 'onSend hook failed; sending original response');
440
+ return original;
441
+ }
442
+ }
443
+ /**
444
+ * Redireciona (padrão 302). Não use `url` vinda do usuário sem validar: isso abre um
445
+ * open redirect. Prefira caminhos relativos ou uma lista de destinos permitidos.
446
+ */
447
+ redirect(url, status = 302) {
448
+ if (this.sent)
449
+ return this;
450
+ this.res.statusCode = status;
451
+ this.statusExplicit = true;
452
+ this.res.setHeader('Location', url);
453
+ this.res.end();
454
+ return this;
455
+ }
456
+ throw(status, message, code) {
457
+ throw new HttpError(status, message, code);
458
+ }
459
+ }
460
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/core/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ import { type ValidationIssue, type ValidationTarget } from '../schema/validation.ts';
2
+ /**
3
+ * O motor dos contratos das rotas (F-27): quem valida a entrada, filtra a saída e descreve o schema para o OpenAPI.
4
+ * Um por app, explícito: `createApp({ contracts: contracts.standard() })`. Sem a opção, vale o `contracts.native()`.
5
+ * Um schema que não pertence ao motor do app é recusado no registro da rota: não há mistura.
6
+ */
7
+ export interface Contracts {
8
+ /** `native` (o padrão do FlowingTS) ou `standard` (Zod, Valibot, ArkType). */
9
+ readonly kind: 'native' | 'standard';
10
+ /** O schema é deste motor? Conferido no registro de cada rota. */
11
+ owns(schema: unknown): boolean;
12
+ /**
13
+ * Valida uma parte da entrada. `value` é o valor a usar daí em diante (o motor pode convertê-lo ou aplicar
14
+ * valores padrão). Pode ser assíncrono no motor `standard`.
15
+ */
16
+ check(schema: unknown, data: unknown, target: ValidationTarget): CheckResult | Promise<CheckResult>;
17
+ /** Serializa uma resposta JSON pelo schema, sem campos não declarados. Lança se a saída não corresponde. */
18
+ serialize(schema: unknown, data: unknown): string;
19
+ /** Valida a saída e devolve uma cópia sem campos não declarados (respostas em outros formatos). */
20
+ strip(schema: unknown, data: unknown): CheckResult;
21
+ /** O JSON Schema do schema, para o OpenAPI; `undefined` se o motor não sabe convertê-lo. */
22
+ toJsonSchema(schema: unknown): object | undefined;
23
+ }
24
+ export type CheckResult = {
25
+ ok: true;
26
+ value: unknown;
27
+ } | {
28
+ ok: false;
29
+ issues: ValidationIssue[];
30
+ };
31
+ /** O mínimo da especificação Standard Schema v1 que o FlowingTS usa. */
32
+ export interface StandardSchemaV1<Input = unknown, Output = Input> {
33
+ readonly '~standard': {
34
+ readonly version: 1;
35
+ readonly vendor: string;
36
+ readonly validate: (value: unknown) => StandardResult<Output> | Promise<StandardResult<Output>>;
37
+ readonly types?: {
38
+ readonly input: Input;
39
+ readonly output: Output;
40
+ } | undefined;
41
+ };
42
+ }
43
+ type StandardResult<Output> = {
44
+ readonly value: Output;
45
+ readonly issues?: undefined;
46
+ } | {
47
+ readonly issues: ReadonlyArray<{
48
+ readonly message: string;
49
+ readonly path?: ReadonlyArray<PropertyKey | {
50
+ readonly key: PropertyKey;
51
+ }> | undefined;
52
+ }>;
53
+ };
54
+ export interface StandardContractsOptions {
55
+ /**
56
+ * Converte um schema em JSON Schema, para o OpenAPI. Com Zod 4: `{ toJSONSchema: (s) => z.toJSONSchema(s) }`.
57
+ * Sem esta opção, as rotas aparecem no OpenAPI sem os schemas.
58
+ */
59
+ toJSONSchema?: (schema: StandardSchemaV1) => object;
60
+ }
61
+ declare function standard(opts?: StandardContractsOptions): Contracts;
62
+ /**
63
+ * Os motores de contrato do FlowingTS (F-27):
64
+ * - `contracts.native()`: o padrão (schemas TypeBox / JSON Schema, validados pelo Ajv, saída pelo serializador
65
+ * compilado). Usado quando o app não declara nada.
66
+ * - `contracts.standard()`: schemas Standard Schema (Zod, Valibot, ArkType). Sem coerção automática: em `params`
67
+ * e `query`, use os conversores da biblioteca (`z.coerce.number()`).
68
+ */
69
+ export declare const contracts: {
70
+ native: () => Contracts;
71
+ standard: typeof standard;
72
+ };
73
+ /** O motor padrão, para quem não configurou nada. */
74
+ export declare const NATIVE_CONTRACTS: Contracts;
75
+ export {};
76
+ //# sourceMappingURL=contracts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../../src/core/contracts.ts"],"names":[],"mappings":"AACA,OAAO,EAA2B,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE/G;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,8EAA8E;IAC9E,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,UAAU,CAAC;IACrC,kEAAkE;IAClE,IAAI,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC;IAC/B;;;OAGG;IACH,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,gBAAgB,GAAG,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACpG,4GAA4G;IAC5G,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;IAClD,mGAAmG;IACnG,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,WAAW,CAAC;IACnD,4FAA4F;IAC5F,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;CACnD;AAED,MAAM,MAAM,WAAW,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,eAAe,EAAE,CAAA;CAAE,CAAC;AA6BlG,wEAAwE;AACxE,MAAM,WAAW,gBAAgB,CAAC,KAAK,GAAG,OAAO,EAAE,MAAM,GAAG,KAAK;IAC/D,QAAQ,CAAC,WAAW,EAAE;QACpB,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;QACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,cAAc,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;QAChG,QAAQ,CAAC,KAAK,CAAC,EAAE;YAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;YAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;SAAE,GAAG,SAAS,CAAC;KACjF,CAAC;CACH;AAED,KAAK,cAAc,CAAC,MAAM,IACtB;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAA;CAAE,GACvD;IACE,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;QAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,WAAW,GAAG;YAAE,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAA;SAAE,CAAC,GAAG,SAAS,CAAC;KACxF,CAAC,CAAC;CACJ,CAAC;AA+BN,MAAM,WAAW,wBAAwB;IACvC;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,MAAM,CAAC;CACrD;AAED,iBAAS,QAAQ,CAAC,IAAI,GAAE,wBAA6B,GAAG,SAAS,CA0BhE;AAED;;;;;;GAMG;AACH,eAAO,MAAM,SAAS;kBACR,SAAS;;CAEtB,CAAC;AAEF,qDAAqD;AACrD,eAAO,MAAM,gBAAgB,WAAS,CAAC"}
@@ -0,0 +1,87 @@
1
+ import { serialize } from '../schema/serialization.js';
2
+ import { stripToSchema, validate } from '../schema/validation.js';
3
+ // ---------------------------------------------------------------------------------------------------------------
4
+ // Nativo: o comportamento de sempre (JSON Schema, que o TypeBox gera).
5
+ // ---------------------------------------------------------------------------------------------------------------
6
+ const isStandard = (schema) => typeof schema === 'object' &&
7
+ schema !== null &&
8
+ typeof schema['~standard']?.validate === 'function';
9
+ const NATIVE = {
10
+ kind: 'native',
11
+ owns: (schema) => typeof schema === 'object' && schema !== null && !isStandard(schema),
12
+ check(schema, data, target) {
13
+ // O Ajv converte e aplica os padrões no próprio objeto: o valor validado é o mesmo.
14
+ const issues = validate(schema, data, target);
15
+ return issues ? { ok: false, issues } : { ok: true, value: data };
16
+ },
17
+ serialize: (schema, data) => serialize(schema, data),
18
+ strip: (schema, data) => stripToSchema(schema, data),
19
+ toJsonSchema: (schema) => schema,
20
+ };
21
+ /** O caminho de uma issue no formato das demais (JSON Pointer): `['items', 0, 'id']` → `/items/0/id`. */
22
+ function pointer(path) {
23
+ if (!path || path.length === 0)
24
+ return '/';
25
+ return `/${path
26
+ .map((seg) => String(typeof seg === 'object' && seg !== null ? seg.key : seg)
27
+ .replace(/~/g, '~0')
28
+ .replace(/\//g, '~1'))
29
+ .join('/')}`;
30
+ }
31
+ function toCheck(result) {
32
+ if (result.issues)
33
+ return { ok: false, issues: result.issues.map((i) => ({ path: pointer(i.path), message: i.message })) };
34
+ return { ok: true, value: result.value };
35
+ }
36
+ const isThenable = (value) => typeof value === 'object' && value !== null && typeof value.then === 'function';
37
+ /** A resposta é síncrona: um schema com validação assíncrona não serve para a saída. */
38
+ function checkSync(schema, data) {
39
+ const result = schema['~standard'].validate(data);
40
+ if (isThenable(result)) {
41
+ throw new Error('[flowing] contracts.standard(): response schemas must validate synchronously (no async refinements).');
42
+ }
43
+ return toCheck(result);
44
+ }
45
+ function standard(opts = {}) {
46
+ return {
47
+ kind: 'standard',
48
+ owns: isStandard,
49
+ check(schema, data) {
50
+ const result = schema['~standard'].validate(data);
51
+ return isThenable(result) ? Promise.resolve(result).then(toCheck) : toCheck(result);
52
+ },
53
+ serialize(schema, data) {
54
+ const checked = checkSync(schema, data);
55
+ if (!checked.ok) {
56
+ throw new Error(`response does not match its schema: ${checked.issues.map((i) => `${i.path} ${i.message}`).join('; ')}`);
57
+ }
58
+ // O schema devolve o valor sem os campos não declarados (o z.object faz isso por padrão).
59
+ return JSON.stringify(checked.value);
60
+ },
61
+ strip: (schema, data) => checkSync(schema, data),
62
+ toJsonSchema(schema) {
63
+ if (!opts.toJSONSchema)
64
+ return undefined;
65
+ try {
66
+ return opts.toJSONSchema(schema);
67
+ }
68
+ catch {
69
+ return undefined;
70
+ }
71
+ },
72
+ };
73
+ }
74
+ /**
75
+ * Os motores de contrato do FlowingTS (F-27):
76
+ * - `contracts.native()`: o padrão (schemas TypeBox / JSON Schema, validados pelo Ajv, saída pelo serializador
77
+ * compilado). Usado quando o app não declara nada.
78
+ * - `contracts.standard()`: schemas Standard Schema (Zod, Valibot, ArkType). Sem coerção automática: em `params`
79
+ * e `query`, use os conversores da biblioteca (`z.coerce.number()`).
80
+ */
81
+ export const contracts = {
82
+ native: () => NATIVE,
83
+ standard,
84
+ };
85
+ /** O motor padrão, para quem não configurou nada. */
86
+ export const NATIVE_CONTRACTS = NATIVE;
87
+ //# sourceMappingURL=contracts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contracts.js","sourceRoot":"","sources":["../../src/core/contracts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAA+C,MAAM,yBAAyB,CAAC;AA2B/G,kHAAkH;AAClH,uEAAuE;AACvE,kHAAkH;AAElH,MAAM,UAAU,GAAG,CAAC,MAAe,EAA8B,EAAE,CACjE,OAAO,MAAM,KAAK,QAAQ;IAC1B,MAAM,KAAK,IAAI;IACf,OAAQ,MAAmD,CAAC,WAAW,CAAC,EAAE,QAAQ,KAAK,UAAU,CAAC;AAEpG,MAAM,MAAM,GAAc;IACxB,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;IACtF,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM;QACxB,oFAAoF;QACpF,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAgB,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QACxD,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACpE,CAAC;IACD,SAAS,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,MAAgB,EAAE,IAAI,CAAC;IAC9D,KAAK,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,MAAgB,EAAE,IAAI,CAAC;IAC9D,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAgB;CAC3C,CAAC;AA0BF,yGAAyG;AACzG,SAAS,OAAO,CAAC,IAA4E;IAC3F,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC;IAC3C,OAAO,IAAI,IAAI;SACZ,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CACX,MAAM,CAAC,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;SAC5D,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CACxB;SACA,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;AACjB,CAAC;AAED,SAAS,OAAO,CAAI,MAAyB;IAC3C,IAAI,MAAM,CAAC,MAAM;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC;IAC3H,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,KAAc,EAAiC,EAAE,CACnE,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,OAAQ,KAA4B,CAAC,IAAI,KAAK,UAAU,CAAC;AAE1G,wFAAwF;AACxF,SAAS,SAAS,CAAC,MAAe,EAAE,IAAa;IAC/C,MAAM,MAAM,GAAI,MAA2B,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACxE,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,sGAAsG,CAAC,CAAC;IAC1H,CAAC;IACD,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC;AACzB,CAAC;AAUD,SAAS,QAAQ,CAAC,IAAI,GAA6B,EAAE;IACnD,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,UAAU;QAChB,KAAK,CAAC,MAAM,EAAE,IAAI;YAChB,MAAM,MAAM,GAAI,MAA2B,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACxE,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACtF,CAAC;QACD,SAAS,CAAC,MAAM,EAAE,IAAI;YACpB,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YACxC,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;gBAChB,MAAM,IAAI,KAAK,CAAC,uCAAuC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC3H,CAAC;YACD,0FAA0F;YAC1F,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACvC,CAAC;QACD,KAAK,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC;QAChD,YAAY,CAAC,MAAM;YACjB,IAAI,CAAC,IAAI,CAAC,YAAY;gBAAE,OAAO,SAAS,CAAC;YACzC,IAAI,CAAC;gBACH,OAAO,IAAI,CAAC,YAAY,CAAC,MAA0B,CAAC,CAAC;YACvD,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,SAAS,CAAC;YACnB,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,MAAM,EAAE,GAAc,EAAE,CAAC,MAAM;IAC/B,QAAQ;CACT,CAAC;AAEF,qDAAqD;AACrD,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC"}