sashiko 0.12.2 → 0.13.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 (74) hide show
  1. package/dist/core/app/core.d.ts +23 -0
  2. package/dist/core/app/core.d.ts.map +1 -0
  3. package/dist/core/app/core.js +2 -0
  4. package/dist/core/app/core.js.map +1 -0
  5. package/dist/core/app/options.d.ts +109 -0
  6. package/dist/core/app/options.d.ts.map +1 -0
  7. package/dist/core/app/options.js +2 -0
  8. package/dist/core/app/options.js.map +1 -0
  9. package/dist/core/app.d.ts +20 -177
  10. package/dist/core/app.d.ts.map +1 -1
  11. package/dist/core/app.js +63 -510
  12. package/dist/core/app.js.map +1 -1
  13. package/dist/core/body-parser.d.ts +6 -3
  14. package/dist/core/body-parser.d.ts.map +1 -1
  15. package/dist/core/body-parser.js +8 -6
  16. package/dist/core/body-parser.js.map +1 -1
  17. package/dist/core/compose.d.ts +7 -0
  18. package/dist/core/compose.d.ts.map +1 -1
  19. package/dist/core/compose.js +25 -0
  20. package/dist/core/compose.js.map +1 -1
  21. package/dist/core/context.d.ts +31 -45
  22. package/dist/core/context.d.ts.map +1 -1
  23. package/dist/core/context.js +99 -159
  24. package/dist/core/context.js.map +1 -1
  25. package/dist/core/health.js +1 -1
  26. package/dist/core/index.d.ts +1 -1
  27. package/dist/core/index.d.ts.map +1 -1
  28. package/dist/core/logger.d.ts.map +1 -1
  29. package/dist/core/logger.js +41 -14
  30. package/dist/core/logger.js.map +1 -1
  31. package/dist/core/registry/framework-routes.d.ts +28 -0
  32. package/dist/core/registry/framework-routes.d.ts.map +1 -0
  33. package/dist/core/registry/framework-routes.js +83 -0
  34. package/dist/core/registry/framework-routes.js.map +1 -0
  35. package/dist/core/registry/registry.d.ts +53 -0
  36. package/dist/core/registry/registry.d.ts.map +1 -0
  37. package/dist/core/registry/registry.js +156 -0
  38. package/dist/core/registry/registry.js.map +1 -0
  39. package/dist/core/registry/route-program.d.ts +14 -0
  40. package/dist/core/registry/route-program.d.ts.map +1 -0
  41. package/dist/core/registry/route-program.js +29 -0
  42. package/dist/core/registry/route-program.js.map +1 -0
  43. package/dist/core/response/pipeline.d.ts +51 -0
  44. package/dist/core/response/pipeline.d.ts.map +1 -0
  45. package/dist/core/response/pipeline.js +171 -0
  46. package/dist/core/response/pipeline.js.map +1 -0
  47. package/dist/core/route-table.d.ts +5 -1
  48. package/dist/core/route-table.d.ts.map +1 -1
  49. package/dist/core/route-table.js +1 -1
  50. package/dist/core/route-table.js.map +1 -1
  51. package/dist/core/runtime/request-handler.d.ts +42 -0
  52. package/dist/core/runtime/request-handler.d.ts.map +1 -0
  53. package/dist/core/runtime/request-handler.js +187 -0
  54. package/dist/core/runtime/request-handler.js.map +1 -0
  55. package/dist/core/runtime/server.d.ts +41 -0
  56. package/dist/core/runtime/server.d.ts.map +1 -0
  57. package/dist/core/runtime/server.js +155 -0
  58. package/dist/core/runtime/server.js.map +1 -0
  59. package/dist/core/streaming/sse.d.ts +35 -0
  60. package/dist/core/streaming/sse.d.ts.map +1 -0
  61. package/dist/core/streaming/sse.js +121 -0
  62. package/dist/core/streaming/sse.js.map +1 -0
  63. package/dist/core/symbols.d.ts +14 -0
  64. package/dist/core/symbols.d.ts.map +1 -0
  65. package/dist/core/symbols.js +14 -0
  66. package/dist/core/symbols.js.map +1 -0
  67. package/dist/server/static.d.ts +1 -1
  68. package/dist/server/static.d.ts.map +1 -1
  69. package/dist/server/static.js +1 -1
  70. package/dist/server/static.js.map +1 -1
  71. package/dist/utils/content-type.d.ts.map +1 -1
  72. package/dist/utils/content-type.js +26 -6
  73. package/dist/utils/content-type.js.map +1 -1
  74. package/package.json +1 -1
@@ -0,0 +1,42 @@
1
+ import type http from 'node:http';
2
+ import type { AppCore } from '../app/core.ts';
3
+ import { Context } from '../context.ts';
4
+ import type { FrameworkRoutes } from '../registry/framework-routes.ts';
5
+ import type { RouteRegistry } from '../registry/registry.ts';
6
+ import type { ServerLifecycle } from './server.ts';
7
+ /**
8
+ * Pipeline da requisição: rastreamento, request id, validação do `Host`, headers de segurança, healthchecks,
9
+ * middlewares globais, OpenAPI, roteamento, pipeline da rota e erros.
10
+ */
11
+ export declare class RequestHandler {
12
+ private readonly core;
13
+ private readonly registry;
14
+ private readonly framework;
15
+ private readonly server;
16
+ constructor(core: AppCore, registry: RouteRegistry, framework: FrameworkRoutes, server: ServerLifecycle);
17
+ /**
18
+ * Listener `(req, res)` do app, para usar com qualquer servidor do Node:
19
+ * `https.createServer(opts, app.callback())`, `http2` em modo compat, testes etc. (F-09).
20
+ */
21
+ callback(): (req: http.IncomingMessage, res: http.ServerResponse) => void;
22
+ /** Última barreira (B-08): nada que aconteça numa requisição pode virar unhandledRejection. */
23
+ private safeHandle;
24
+ private fail;
25
+ /** Cadeia global compilada; refeita só quando `app.use()` acrescenta um middleware. */
26
+ private globalChain;
27
+ private readonly readBody;
28
+ handle(ctx: Context): Promise<void>;
29
+ /**
30
+ * Cadeia global (Chain of Responsibility pré-compilada): os middlewares de `app.use()` envolvem o
31
+ * roteamento e a rota, como no Koa. Um `await next()` num middleware global inclui o handler.
32
+ */
33
+ private chain;
34
+ /** Fim da cadeia global: OpenAPI, roteamento, 404/405 e o programa da rota. */
35
+ private route;
36
+ /**
37
+ * Executa os `onError` do usuário. Se um deles lançar, o erro é logado e seguimos
38
+ * para a resposta padrão com o erro **original** — nunca deixamos a Promise rejeitar (B-08).
39
+ */
40
+ private runErrorHandlers;
41
+ }
42
+ //# sourceMappingURL=request-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-handler.d.ts","sourceRoot":"","sources":["../../../src/core/runtime/request-handler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAK9C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAInD;;;GAGG;AACH,qBAAa,cAAc;IAEvB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJzB,YACmB,IAAI,EAAE,OAAO,EACb,QAAQ,EAAE,aAAa,EACvB,SAAS,EAAE,eAAe,EAC1B,MAAM,EAAE,eAAe,EAGzC;IAED;;;OAGG;IACH,QAAQ,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,KAAK,IAAI,CA8DxE;IAED,+FAA+F;YACjF,UAAU;IAQxB,OAAO,CAAC,IAAI;IAMZ,uFAAuF;IACvF,OAAO,CAAC,WAAW,CAAqE;IACxF,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyC;IAE5D,MAAM,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBxC;IAED;;;OAGG;IACH,OAAO,CAAC,KAAK;IAQb,+EAA+E;YACjE,KAAK;IA2BnB;;;OAGG;YACW,gBAAgB;CAY/B"}
@@ -0,0 +1,187 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { performance } from 'node:perf_hooks';
3
+ import { compileChain } from '../compose.js';
4
+ import { bodyReader } from '../body-parser.js';
5
+ import { buildRouteProgram } from '../registry/route-program.js';
6
+ import { kContext, kRouted } from '../symbols.js';
7
+ import { Context } from '../context.js';
8
+ import { problem, sendError, sendProblem } from '../response/pipeline.js';
9
+ const SAFE_REQUEST_ID = /^[A-Za-z0-9._:-]{1,128}$/;
10
+ /**
11
+ * Pipeline da requisição: rastreamento, request id, validação do `Host`, headers de segurança, healthchecks,
12
+ * middlewares globais, OpenAPI, roteamento, pipeline da rota e erros.
13
+ */
14
+ export class RequestHandler {
15
+ core;
16
+ registry;
17
+ framework;
18
+ server;
19
+ constructor(core, registry, framework, server) {
20
+ this.core = core;
21
+ this.registry = registry;
22
+ this.framework = framework;
23
+ this.server = server;
24
+ this.readBody = bodyReader(core.opts.bodyLimit ?? 1024 * 1024, core.opts.protoPoisoning);
25
+ }
26
+ /**
27
+ * Listener `(req, res)` do app, para usar com qualquer servidor do Node:
28
+ * `https.createServer(opts, app.callback())`, `http2` em modo compat, testes etc. (F-09).
29
+ */
30
+ callback() {
31
+ const rid = this.core.opts.requestId ?? {};
32
+ const header = rid.header === false ? undefined : (rid.header ?? 'x-request-id').toLowerCase();
33
+ const trust = rid.trustIncoming ?? true;
34
+ const generate = rid.generate ?? (() => randomUUID());
35
+ // Factory + Flyweight (F-39): a mesma configuração para todos os contextos deste listener, em vez de
36
+ // um objeto de opções novo a cada requisição.
37
+ const contextOptions = {
38
+ queryMaxKeys: this.core.opts.queryMaxKeys,
39
+ logger: this.core.log,
40
+ trustProxy: this.core.opts.trustProxy,
41
+ onSend: this.core.onSendHooks,
42
+ };
43
+ const server = this.server;
44
+ // Listener compartilhado por todas as respostas (antes, uma closure por requisição).
45
+ const onClose = function () {
46
+ server.inflight.delete(this);
47
+ // Durante o close(), cada resposta concluída libera as conexões que ficaram ociosas.
48
+ server.closing?.closeIdleConnections();
49
+ };
50
+ const timed = () => this.core.opts.logRequests === true || this.core.onResponseHooks.length > 0;
51
+ return (req, res) => {
52
+ const started = timed() ? performance.now() : -1;
53
+ server.inflight.add(res);
54
+ if (server.closing)
55
+ res.setHeader('Connection', 'close');
56
+ res.on('close', onClose);
57
+ const incoming = header ? req.headers[header] : undefined;
58
+ const id = trust && typeof incoming === 'string' && SAFE_REQUEST_ID.test(incoming) ? incoming : generate();
59
+ if (header)
60
+ res.setHeader(header, id);
61
+ try {
62
+ const ctx = new Context(req, res, contextOptions, id);
63
+ res[kContext] = ctx;
64
+ // S-09: Host ausente, malformado ou fora da lista permitida → 400, antes de qualquer middleware.
65
+ // Exceção: healthchecks aceitam qualquer host válido, porque sondas chegam com o IP do pod.
66
+ const healthProbe = this.framework.health?.bypassesHostCheck(ctx.method, ctx.path) ?? false;
67
+ if (!ctx.host || (this.core.allowedHosts && !healthProbe && !this.core.allowedHosts(ctx.hostname, ctx.host))) {
68
+ this.core.applySecurityHeaders?.(res);
69
+ sendProblem(ctx, problem(400, 'Invalid Host header', { code: 'INVALID_HOST' }), this.core.opts.formatError);
70
+ return;
71
+ }
72
+ if (started !== -1) {
73
+ res.once('finish', () => {
74
+ const ms = Math.round((performance.now() - started) * 100) / 100;
75
+ if (this.core.opts.logRequests) {
76
+ ctx.log.info({ method: ctx.method, path: ctx.path, status: res.statusCode, ms }, 'request completed');
77
+ }
78
+ for (const hook of this.core.onResponseHooks) {
79
+ Promise.resolve()
80
+ .then(() => hook(ctx, { status: res.statusCode, ms }))
81
+ .catch((err) => ctx.log.error({ err }, 'onResponse hook failed'));
82
+ }
83
+ });
84
+ }
85
+ void this.safeHandle(ctx, id);
86
+ }
87
+ catch (err) {
88
+ this.fail(err, req, res, id);
89
+ }
90
+ };
91
+ }
92
+ /** Última barreira (B-08): nada que aconteça numa requisição pode virar unhandledRejection. */
93
+ async safeHandle(ctx, id) {
94
+ try {
95
+ await this.handle(ctx);
96
+ }
97
+ catch (err) {
98
+ this.fail(err, ctx.req, ctx.res, id);
99
+ }
100
+ }
101
+ fail(err, req, res, id) {
102
+ this.core.log.error({ err, reqId: id, method: req.method, url: req.url }, 'unhandled error while handling request');
103
+ if (!res.headersSent)
104
+ res.statusCode = 500;
105
+ if (!res.writableEnded)
106
+ res.end();
107
+ }
108
+ /** Cadeia global compilada; refeita só quando `app.use()` acrescenta um middleware. */
109
+ globalChain;
110
+ readBody;
111
+ async handle(ctx) {
112
+ // Antes de tudo, para valer inclusive em erros, 404 e preflight (S-04).
113
+ this.core.applySecurityHeaders?.(ctx.res);
114
+ try {
115
+ // Healthchecks antes dos middlewares globais: sondas do load balancer não têm credenciais.
116
+ if (this.framework.health && (await this.framework.health.serve(ctx, this.server.draining || this.server.closing !== undefined)))
117
+ return;
118
+ // O body chega lido aos middlewares globais (invariante 5), sem uma camada de middleware para isso.
119
+ await this.readBody(ctx);
120
+ const chain = this.chain();
121
+ await chain(ctx);
122
+ // Um middleware global que não chama next() e não responde: a rota não roda (antes, rodava mesmo
123
+ // assim). Para a requisição não ficar sem resposta, 404, como no Koa.
124
+ if (!ctx[kRouted] && !ctx.sent) {
125
+ ctx.log.warn({ method: ctx.method, path: ctx.path }, 'a global middleware neither called next() nor sent a response');
126
+ sendProblem(ctx, problem(404, undefined, { code: 'NOT_FOUND' }), this.core.opts.formatError);
127
+ }
128
+ }
129
+ catch (err) {
130
+ await this.runErrorHandlers(err, ctx);
131
+ }
132
+ }
133
+ /**
134
+ * Cadeia global (Chain of Responsibility pré-compilada): os middlewares de `app.use()` envolvem o
135
+ * roteamento e a rota, como no Koa. Um `await next()` num middleware global inclui o handler.
136
+ */
137
+ chain() {
138
+ const mws = this.core.middlewares;
139
+ if (this.globalChain?.size !== mws.length) {
140
+ this.globalChain = { size: mws.length, run: compileChain([...mws], (ctx) => this.route(ctx)) };
141
+ }
142
+ return this.globalChain.run;
143
+ }
144
+ /** Fim da cadeia global: OpenAPI, roteamento, 404/405 e o programa da rota. */
145
+ async route(ctx) {
146
+ ctx[kRouted] = true;
147
+ if (ctx.sent || (await this.framework.serveOpenAPI(ctx)))
148
+ return;
149
+ // F-35: hosts não diferenciam maiúsculas; as regras já são compiladas em minúsculas.
150
+ const hostname = ctx.hostname.toLowerCase();
151
+ const match = this.registry.router.find(ctx.method, ctx.path, hostname);
152
+ if (!match) {
153
+ const allowed = this.registry.router.allowedMethods(ctx.path, hostname);
154
+ if (allowed.length > 0) {
155
+ ctx.res.setHeader('Allow', allowed.join(', '));
156
+ // F-08: OPTIONS automático para qualquer path com rotas.
157
+ if (ctx.method === 'OPTIONS')
158
+ return void ctx.status(204).res.end();
159
+ return void sendProblem(ctx, problem(405, undefined, { code: 'METHOD_NOT_ALLOWED', details: { allowed } }), this.core.opts.formatError);
160
+ }
161
+ return void sendProblem(ctx, problem(404, undefined, { code: 'NOT_FOUND' }), this.core.opts.formatError);
162
+ }
163
+ ctx.params = match.params;
164
+ // O programa é montado no commit do registro; o fallback cobre rotas registradas por fora dele.
165
+ const run = (match.route.run ??= buildRouteProgram(match.route, this.core.serializers));
166
+ await run(ctx);
167
+ }
168
+ /**
169
+ * Executa os `onError` do usuário. Se um deles lançar, o erro é logado e seguimos
170
+ * para a resposta padrão com o erro **original** — nunca deixamos a Promise rejeitar (B-08).
171
+ */
172
+ async runErrorHandlers(err, ctx) {
173
+ for (const h of this.core.errorHandlers) {
174
+ try {
175
+ await h(err, ctx);
176
+ }
177
+ catch (handlerErr) {
178
+ ctx.log.error({ err: handlerErr, method: ctx.method, path: ctx.path }, 'onError handler failed');
179
+ break;
180
+ }
181
+ if (ctx.res.writableEnded)
182
+ return;
183
+ }
184
+ sendError(ctx, err, this.core.opts.formatError);
185
+ }
186
+ }
187
+ //# sourceMappingURL=request-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-handler.js","sourceRoot":"","sources":["../../../src/core/runtime/request-handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import http from 'node:http';
2
+ import https from 'node:https';
3
+ import type { AppCore } from '../app/core.ts';
4
+ import type { ListenOptions } from '../app/options.ts';
5
+ import { type ShutdownTarget } from '../shutdown.ts';
6
+ import { type TlsOptions } from '../../server/tls.ts';
7
+ /** Servidor HTTP/HTTPS do app: `listen`, `close`, troca de certificados, drain e shutdown por sinal (F-07, F-33). */
8
+ export declare class ServerLifecycle {
9
+ private readonly core;
10
+ /** Listener `(req, res)` do app, criado a cada `listen()`. */
11
+ private readonly listener;
12
+ server: http.Server | https.Server | undefined;
13
+ private tlsState;
14
+ /** Respostas em andamento, para o `close()` e o shutdown. */
15
+ readonly inflight: Set<http.ServerResponse<http.IncomingMessage>>;
16
+ closing: http.Server | https.Server | undefined;
17
+ draining: boolean;
18
+ private closeHooksPending;
19
+ constructor(core: AppCore,
20
+ /** Listener `(req, res)` do app, criado a cada `listen()`. */
21
+ listener: () => http.RequestListener);
22
+ listen(options: ListenOptions & {
23
+ tls: TlsOptions;
24
+ }): Promise<https.Server>;
25
+ listen(options?: number | ListenOptions): Promise<http.Server>;
26
+ /**
27
+ * Troca os certificados sem reiniciar nem derrubar conexões (renovação, ACME externo). Conexões novas
28
+ * usam os novos; as abertas seguem com os antigos. Um certificado inválido lança erro e mantém os atuais.
29
+ */
30
+ reloadTLS(tls: TlsOptions): void;
31
+ /** Ponte entre este app e o coordenador de sinais (F-07). */
32
+ readonly shutdownTarget: ShutdownTarget;
33
+ /**
34
+ * Para de aceitar conexões, encerra as ociosas e espera as requisições em andamento terminarem.
35
+ * Depois de `graceMs`, força o fechamento das restantes.
36
+ */
37
+ close(graceMs?: number): Promise<void>;
38
+ /** `onClose` uma vez por ciclo (até o próximo `listen`); todos rodam mesmo se algum falhar (F-04). */
39
+ runCloseHooks(): Promise<void>;
40
+ }
41
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/core/runtime/server.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,KAAK,MAAM,YAAY,CAAC;AAC/B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGvD,OAAO,EAAuB,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAE1E,OAAO,EAA6B,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjF,qHAAqH;AACrH,qBAAa,eAAe;IAUxB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,8DAA8D;IAC9D,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAX3B,MAAM,EAAE,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC;IAC/C,OAAO,CAAC,QAAQ,CAA6C;IAC7D,6DAA6D;IAC7D,QAAQ,CAAC,QAAQ,iDAAkC;IACnD,OAAO,EAAE,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC;IAChD,QAAQ,UAAS;IACjB,OAAO,CAAC,iBAAiB,CAAQ;IAEjC,YACmB,IAAI,EAAE,OAAO;IAC9B,8DAA8D;IAC7C,QAAQ,EAAE,MAAM,IAAI,CAAC,eAAe,EAQtD;IAEK,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG;QAAE,GAAG,EAAE,UAAU,CAAA;KAAE,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5E,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAkCrE;;;OAGG;IACH,SAAS,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CAS/B;IAED,6DAA6D;IAC7D,QAAQ,CAAC,cAAc,EAAE,cAAc,CAoBrC;IAEF;;;OAGG;IACG,KAAK,CAAC,OAAO,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CA0B3C;IAED,sGAAsG;IAChG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAanC;CACF"}
@@ -0,0 +1,155 @@
1
+ import http from 'node:http';
2
+ import https from 'node:https';
3
+ import { shutdownCoordinator } from '../shutdown.js';
4
+ import { kAbort, kContext } from '../symbols.js';
5
+ import { compileTls } from '../../server/tls.js';
6
+ /** Servidor HTTP/HTTPS do app: `listen`, `close`, troca de certificados, drain e shutdown por sinal (F-07, F-33). */
7
+ export class ServerLifecycle {
8
+ core;
9
+ listener;
10
+ server;
11
+ tlsState;
12
+ /** Respostas em andamento, para o `close()` e o shutdown. */
13
+ inflight = new Set();
14
+ closing;
15
+ draining = false;
16
+ closeHooksPending = true;
17
+ constructor(core,
18
+ /** Listener `(req, res)` do app, criado a cada `listen()`. */
19
+ listener) {
20
+ this.core = core;
21
+ this.listener = listener;
22
+ const sd = core.opts.shutdown || {};
23
+ Object.assign(this.shutdownTarget, {
24
+ log: core.log,
25
+ signals: sd.signals ?? ['SIGINT', 'SIGTERM'],
26
+ exitOnShutdown: sd.exit ?? true,
27
+ });
28
+ }
29
+ async listen(options = {}) {
30
+ if (this.server)
31
+ throw new Error('[sashiko] app is already listening; call app.close() first.');
32
+ const { port = 3000, host = '127.0.0.1', tls } = typeof options === 'number' ? { port: options } : options;
33
+ let server;
34
+ if (tls) {
35
+ const sni = { current: { find: () => undefined } };
36
+ const compiled = compileTls(tls, sni);
37
+ server = https.createServer(compiled.options, this.listener());
38
+ this.tlsState = { sni };
39
+ }
40
+ else {
41
+ server = http.createServer(this.listener());
42
+ this.tlsState = undefined;
43
+ }
44
+ const t = this.core.opts.timeouts ?? {};
45
+ server.requestTimeout = t.requestTimeout ?? 30_000;
46
+ server.headersTimeout = Math.min(t.headersTimeout ?? 10_000, server.requestTimeout || Infinity);
47
+ server.keepAliveTimeout = t.keepAliveTimeout ?? 5_000;
48
+ await new Promise((resolve, reject) => {
49
+ server.once('error', reject);
50
+ server.listen(port, host, () => {
51
+ server.off('error', reject);
52
+ resolve();
53
+ });
54
+ });
55
+ this.server = server;
56
+ this.closeHooksPending = true;
57
+ this.draining = false;
58
+ if (this.core.opts.shutdown !== false)
59
+ shutdownCoordinator.register(this.shutdownTarget);
60
+ return server;
61
+ }
62
+ /**
63
+ * Troca os certificados sem reiniciar nem derrubar conexões (renovação, ACME externo). Conexões novas
64
+ * usam os novos; as abertas seguem com os antigos. Um certificado inválido lança erro e mantém os atuais.
65
+ */
66
+ reloadTLS(tls) {
67
+ const server = this.server;
68
+ if (!server || !this.tlsState || !(server instanceof https.Server)) {
69
+ throw new Error('[sashiko] reloadTLS(): the app is not listening with { tls }.');
70
+ }
71
+ const next = { current: this.tlsState.sni.current };
72
+ const compiled = compileTls(tls, next); // valida tudo antes de trocar
73
+ if (compiled.main)
74
+ server.setSecureContext(compiled.main);
75
+ this.tlsState.sni.current = next.current;
76
+ }
77
+ /** Ponte entre este app e o coordenador de sinais (F-07). */
78
+ shutdownTarget = {
79
+ log: undefined, // definido no construtor
80
+ signals: [],
81
+ exitOnShutdown: true,
82
+ shutdown: async (signal) => {
83
+ const opts = this.core.opts.shutdown || {};
84
+ try {
85
+ this.draining = true;
86
+ if (opts.drainDelayMs) {
87
+ this.core.log.info({ signal, drainDelayMs: opts.drainDelayMs }, 'draining before shutdown');
88
+ await new Promise((r) => setTimeout(r, opts.drainDelayMs));
89
+ }
90
+ await this.close(opts.timeoutMs ?? 10_000);
91
+ await opts.onShutdown?.(signal);
92
+ return true;
93
+ }
94
+ catch (err) {
95
+ this.core.log.error({ err, signal }, 'error during graceful shutdown');
96
+ return false;
97
+ }
98
+ },
99
+ };
100
+ /**
101
+ * Para de aceitar conexões, encerra as ociosas e espera as requisições em andamento terminarem.
102
+ * Depois de `graceMs`, força o fechamento das restantes.
103
+ */
104
+ async close(graceMs = 10_000) {
105
+ const server = this.server;
106
+ if (!server)
107
+ return this.runCloseHooks();
108
+ this.server = undefined;
109
+ this.closing = server;
110
+ // Respostas que ainda não enviaram headers avisam o cliente para não reusar a conexão.
111
+ for (const res of this.inflight)
112
+ if (!res.headersSent)
113
+ res.setHeader('Connection', 'close');
114
+ // Streams longos (SSE, NDJSON) não terminam sozinhos: o `ctx.signal` é cancelado para eles fecharem
115
+ // já, em vez de segurar o encerramento até o prazo. Requisições comuns seguem até terminar.
116
+ for (const res of this.inflight) {
117
+ const ctx = res[kContext];
118
+ if (ctx?.streamingResponse)
119
+ ctx[kAbort]('server shutting down');
120
+ }
121
+ const force = setTimeout(() => server.closeAllConnections(), graceMs);
122
+ force.unref();
123
+ try {
124
+ await new Promise((resolve, reject) => {
125
+ server.close((err) => (err ? reject(err) : resolve()));
126
+ server.closeIdleConnections();
127
+ });
128
+ }
129
+ finally {
130
+ clearTimeout(force);
131
+ this.closing = undefined;
132
+ shutdownCoordinator.unregister(this.shutdownTarget);
133
+ }
134
+ await this.runCloseHooks();
135
+ }
136
+ /** `onClose` uma vez por ciclo (até o próximo `listen`); todos rodam mesmo se algum falhar (F-04). */
137
+ async runCloseHooks() {
138
+ if (!this.closeHooksPending)
139
+ return;
140
+ this.closeHooksPending = false;
141
+ const errors = [];
142
+ for (const hook of this.core.onCloseHooks) {
143
+ try {
144
+ await hook();
145
+ }
146
+ catch (err) {
147
+ errors.push(err);
148
+ this.core.log.error({ err }, 'onClose hook failed');
149
+ }
150
+ }
151
+ if (errors.length > 0)
152
+ throw new AggregateError(errors, `[sashiko] ${errors.length} onClose hook(s) failed`);
153
+ }
154
+ }
155
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/core/runtime/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Server-Sent Events (F-13). Fica fora do `Context`, que só delega: o modelo da requisição não carrega a
3
+ * lógica de cada forma de envio.
4
+ */
5
+ import type { Context } from '../context.ts';
6
+ /** Um evento de Server-Sent Events (F-13). `data` em objeto vira JSON; strings com várias linhas são divididas. */
7
+ export interface SseEvent {
8
+ data: unknown;
9
+ event?: string;
10
+ id?: string;
11
+ /** Sugestão de espera para o navegador reconectar, em ms. */
12
+ retry?: number;
13
+ }
14
+ /** Conexão SSE aberta por `ctx.sse()`. */
15
+ export interface SseStream {
16
+ send(event: SseEvent | string): void;
17
+ /** Comentário (`: texto`), ignorado pelo navegador; útil como keep-alive. */
18
+ comment(text: string): void;
19
+ /** Encerra a resposta. */
20
+ close(): void;
21
+ /** Chamado quando a conexão termina: o cliente desconectou, `close()` ou encerramento do app. */
22
+ onClose(listener: () => void): void;
23
+ readonly closed: boolean;
24
+ /** `Last-Event-ID` enviado pelo navegador ao reconectar. */
25
+ readonly lastEventId: string | undefined;
26
+ }
27
+ export interface SseOptions {
28
+ /** Comentário periódico para proxies não derrubarem a conexão ociosa. Padrão: 15000 ms; `0` desliga. */
29
+ heartbeatMs?: number;
30
+ /** `retry:` enviado na abertura. */
31
+ retry?: number;
32
+ }
33
+ /** Abre a conexão SSE de `ctx`. `markStreaming` marca a resposta como stream (estado privado do `Context`). */
34
+ export declare function openSse(ctx: Context, opts: SseOptions, markStreaming: () => void): SseStream;
35
+ //# sourceMappingURL=sse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../../src/core/streaming/sse.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C,mHAAmH;AACnH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,0CAA0C;AAC1C,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAC;IACrC,6EAA6E;IAC7E,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,0BAA0B;IAC1B,KAAK,IAAI,IAAI,CAAC;IACd,iGAAiG;IACjG,OAAO,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,4DAA4D;IAC5D,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1C;AAED,MAAM,WAAW,UAAU;IACzB,wGAAwG;IACxG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAoCD,+GAA+G;AAC/G,wBAAgB,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,IAAI,GAAG,SAAS,CAqE5F"}
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Campos de uma linha SSE não podem ter quebra de linha (seria injeção de evento); `id` também não pode
3
+ * ter U+0000, que faz o navegador ignorar o campo.
4
+ */
5
+ const sseField = (name, value) => {
6
+ if (/[\r\n]/.test(value))
7
+ throw new Error(`[sashiko] ctx.sse(): "${name}" cannot contain line breaks.`);
8
+ if (name === 'id' && value.includes('\0'))
9
+ throw new Error('[sashiko] ctx.sse(): "id" cannot contain U+0000.');
10
+ return `${name}: ${value}\n`;
11
+ };
12
+ /** Maior intervalo dos timers do Node; acima disso, ele usa 1 ms (heartbeat contínuo). */
13
+ const MAX_TIMER_MS = 2_147_483_647;
14
+ /** `retry` e `heartbeatMs`: inteiro não negativo, como o protocolo exige, e dentro do limite dos timers. */
15
+ const nonNegativeInt = (name, value) => {
16
+ if (!Number.isInteger(value) || value < 0 || value > MAX_TIMER_MS) {
17
+ throw new Error(`[sashiko] ctx.sse(): "${name}" must be an integer between 0 and ${MAX_TIMER_MS} (got ${value}).`);
18
+ }
19
+ return value;
20
+ };
21
+ /** `data` do evento: strings como estão; o resto em JSON. Valor que não vira JSON gera erro claro, sem escrever nada. */
22
+ function sseData(data) {
23
+ if (typeof data === 'string')
24
+ return data;
25
+ let text;
26
+ try {
27
+ text = JSON.stringify(data);
28
+ }
29
+ catch (err) {
30
+ throw new Error(`[sashiko] ctx.sse(): "data" is not JSON-serializable (${err.message}).`, { cause: err });
31
+ }
32
+ if (text === undefined)
33
+ throw new Error(`[sashiko] ctx.sse(): "data" of type ${typeof data} is not JSON-serializable.`);
34
+ return text;
35
+ }
36
+ /** Abre a conexão SSE de `ctx`. `markStreaming` marca a resposta como stream (estado privado do `Context`). */
37
+ export function openSse(ctx, opts, markStreaming) {
38
+ if (ctx.sent)
39
+ throw new Error('[sashiko] ctx.sse(): the response was already sent.');
40
+ // Valida antes de abrir a resposta: um erro aqui ainda vira um 500 normal.
41
+ const heartbeatMs = nonNegativeInt('heartbeatMs', opts.heartbeatMs ?? 15_000);
42
+ if (opts.retry !== undefined)
43
+ nonNegativeInt('retry', opts.retry);
44
+ const res = ctx.res;
45
+ markStreaming();
46
+ res.statusCode = 200;
47
+ res.setHeader('Content-Type', 'text/event-stream; charset=utf-8');
48
+ res.setHeader('Cache-Control', 'no-cache, no-transform');
49
+ res.setHeader('X-Accel-Buffering', 'no');
50
+ res.removeHeader('Content-Length');
51
+ res.flushHeaders();
52
+ const listeners = [];
53
+ let closed = false;
54
+ const finish = () => {
55
+ if (closed)
56
+ return;
57
+ closed = true;
58
+ clearInterval(heartbeat);
59
+ for (const l of listeners.splice(0)) {
60
+ try {
61
+ l();
62
+ }
63
+ catch (err) {
64
+ ctx.log.error({ err }, 'sse onClose listener failed');
65
+ }
66
+ }
67
+ };
68
+ const write = (chunk) => {
69
+ if (!closed && !res.writableEnded)
70
+ res.write(chunk);
71
+ };
72
+ const heartbeat = setInterval(() => write(': ping\n\n'), heartbeatMs || 2 ** 31 - 1);
73
+ heartbeat.unref();
74
+ if (!heartbeatMs)
75
+ clearInterval(heartbeat);
76
+ res.once('close', finish);
77
+ const signal = ctx.signal;
78
+ signal.addEventListener('abort', () => stream.close(), { once: true });
79
+ if (opts.retry !== undefined)
80
+ write(`retry: ${opts.retry}\n\n`);
81
+ const stream = {
82
+ send: (event) => {
83
+ const e = typeof event === 'string' ? { data: event } : event;
84
+ let out = '';
85
+ if (e.event !== undefined)
86
+ out += sseField('event', e.event);
87
+ if (e.id !== undefined)
88
+ out += sseField('id', e.id);
89
+ if (e.retry !== undefined)
90
+ out += `retry: ${nonNegativeInt('retry', e.retry)}\n`;
91
+ if (e.data === undefined)
92
+ throw new Error('[sashiko] ctx.sse(): "data" is required; use "" for an empty event.');
93
+ const text = sseData(e.data);
94
+ for (const line of text.split(/\r\n|\r|\n/))
95
+ out += `data: ${line}\n`;
96
+ write(`${out}\n`);
97
+ },
98
+ comment: (text) => write(`: ${text.replace(/[\r\n]+/g, ' ')}\n\n`),
99
+ close: () => {
100
+ if (!res.writableEnded)
101
+ res.end();
102
+ finish();
103
+ },
104
+ onClose: (listener) => {
105
+ if (closed)
106
+ listener();
107
+ else
108
+ listeners.push(listener);
109
+ },
110
+ get closed() {
111
+ return closed;
112
+ },
113
+ lastEventId: ctx.get('last-event-id'),
114
+ };
115
+ // O cliente pode ter desconectado antes do `ctx.sse()` (num `await` anterior): o 'close' e o 'abort' já
116
+ // passaram, e os listeners acima nunca rodariam. Encerra já, limpando o heartbeat e chamando `onClose`.
117
+ if (signal.aborted)
118
+ stream.close();
119
+ return stream;
120
+ }
121
+ //# sourceMappingURL=sse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse.js","sourceRoot":"","sources":["../../../src/core/streaming/sse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /** Símbolos internos do core. Ficam num módulo próprio para quem os usa não depender do `Context` em tempo de execução. */
2
+ /** @internal Envio cru, sem pipeline: usado pelo próprio pipeline, por erros e por 404/405. */
3
+ export declare const kRawSend: unique symbol;
4
+ /** @internal Cancela o `ctx.signal` (encerramento do app) (F-13). */
5
+ export declare const kAbort: unique symbol;
6
+ /** @internal Envio de arquivo em andamento, que o app aguarda mesmo sem `await` no handler (F-13). */
7
+ export declare const kPendingSend: unique symbol;
8
+ /** @internal Liga o contexto aos schemas de resposta da rota, antes do handler (F-32). */
9
+ export declare const kBindResponse: unique symbol;
10
+ /** @internal A cadeia global chegou ao roteamento (o último middleware chamou `next()`). */
11
+ export declare const kRouted: unique symbol;
12
+ /** @internal O `Context` de uma resposta em andamento, guardado na própria `ServerResponse` (F-39). */
13
+ export declare const kContext: unique symbol;
14
+ //# sourceMappingURL=symbols.d.ts.map