@asenajs/hono-adapter 2.0.0 → 3.1.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.
@@ -28,17 +28,72 @@ export class HonoWebsocketAdapter extends AsenaWebsocketAdapter {
28
28
  return this.activeConnections.get(namespace)?.size || 0;
29
29
  }
30
30
  /**
31
- * Graceful shutdown - closes all connections
32
- * @param _timeoutMs - Timeout for graceful shutdown (default: 5000)
31
+ * Releases everything this adapter owns: heartbeat timers, connection tracking, and the
32
+ * transport.
33
+ *
34
+ * The transport is the part that matters beyond a single process. `BunLocalTransport` has
35
+ * nothing to let go of, but a remote one holds broker state - `RedisTransport` keeps a
36
+ * subscriber connection with a live channel subscription plus a publisher - and `destroy()`
37
+ * had no call site anywhere in the framework, so every stop leaked both. A test suite doing
38
+ * twenty stop/start cycles, or a pod restarting under a rolling deploy, accumulates them until
39
+ * the broker refuses new clients.
40
+ *
41
+ * This method does **not** close sockets, despite the name it has carried since the first
42
+ * version. Closing them is `server.stop(closeActiveConnections)`'s job, and `HonoAdapter.stop()`
43
+ * has already done it by the time this runs; a second pass from here would only race with Bun.
44
+ * Called standalone, it leaves open connections alone - it just stops pinging them.
45
+ *
46
+ * @param timeoutMs - Ceiling for the transport teardown (default: 5000). A remote transport's
47
+ * `destroy()` is network I/O, and the pod being shut down is often precisely the one that
48
+ * cannot reach the broker - without a bound, one unreachable Redis holds the entire shutdown
49
+ * open indefinitely.
33
50
  */
34
- async shutdown(_timeoutMs = 5000) {
51
+ async shutdown(timeoutMs = 5000) {
35
52
  this.logger.info('Starting WebSocket graceful shutdown...');
36
53
  // Stop all heartbeats
37
54
  this.clearAllHeartbeats();
38
55
  // Clear connection tracking
39
56
  this.activeConnections.clear();
57
+ await this.destroyTransport(timeoutMs);
40
58
  this.logger.info('WebSocket shutdown complete');
41
59
  }
60
+ /**
61
+ * Runs the transport's `destroy()` under a ceiling, containing every failure.
62
+ *
63
+ * A transport that throws or hangs must not abort the rest of the shutdown - the same policy
64
+ * the core applies to `@OnStop` hooks, and for the same reason: a shutdown that gives up
65
+ * halfway leaves more behind than one that limps to the end. The timer is cleared on the happy
66
+ * path too, so a fast teardown is not held up by a pending timeout.
67
+ *
68
+ * The transport reference is kept rather than cleared. Dropping it would silently downgrade a
69
+ * restarted server to `BunLocalTransport`, and every remote `destroy()` in the ecosystem is
70
+ * already idempotent.
71
+ *
72
+ * @param timeoutMs - Ceiling in milliseconds
73
+ */
74
+ async destroyTransport(timeoutMs) {
75
+ const transport = this._transport;
76
+ if (typeof transport?.destroy !== 'function') {
77
+ return;
78
+ }
79
+ let timer;
80
+ try {
81
+ await Promise.race([
82
+ transport.destroy(),
83
+ new Promise((_resolve, reject) => {
84
+ timer = setTimeout(() => reject(new Error(`WebSocket transport destroy() did not finish within ${timeoutMs}ms`)), timeoutMs);
85
+ }),
86
+ ]);
87
+ }
88
+ catch (error) {
89
+ this.logger.error('WebSocket transport teardown failed, continuing shutdown:', error);
90
+ }
91
+ finally {
92
+ if (timer) {
93
+ clearTimeout(timer);
94
+ }
95
+ }
96
+ }
42
97
  registerWebSocket(webSocketService) {
43
98
  if (!webSocketService) {
44
99
  throw new Error('WebSocket service is required');
@@ -72,16 +127,35 @@ export class HonoWebsocketAdapter extends AsenaWebsocketAdapter {
72
127
  if (!this.websockets || this.websockets.size < 1) {
73
128
  return;
74
129
  }
75
- // Initialize transport (default: BunLocalTransport)
76
- const transport = this._transport ?? new BunLocalTransport();
77
- await transport.init?.(server);
130
+ // Assigned to the field, not a local: sockets and destroyTransport() read `this._transport`.
131
+ this._transport ??= new BunLocalTransport();
132
+ await this._transport.init?.(server);
133
+ this.warnIfTransportLacksPublishRemote();
78
134
  // Create a single shared wrapper for all WebSocket services
79
- const sharedServer = new AsenaWebSocketServer(transport);
135
+ const sharedServer = new AsenaWebSocketServer(this._transport);
80
136
  // Assign the shared wrapper to all services
81
137
  for (const websocket of this.websockets.values()) {
82
138
  websocket.server = sharedServer;
83
139
  }
84
140
  }
141
+ /**
142
+ * Warns once, at startup, when the configured transport predates `publishRemote()`.
143
+ *
144
+ * Such a transport still works: `socket.publish()` falls back to its `publish()`, which does
145
+ * local delivery as well - so the sender receives its own message, unlike every other
146
+ * configuration. Warning here rather than per message keeps a hot path clean, and warning at
147
+ * all is the point: the alternative reading, treating the missing method as "no cross-pod
148
+ * delivery wanted", would drop messages between pods in silence.
149
+ */
150
+ warnIfTransportLacksPublishRemote() {
151
+ if (typeof this._transport?.publishRemote === 'function') {
152
+ return;
153
+ }
154
+ this.logger.warn('WebSocket transport does not implement publishRemote(). socket.publish() will fall back to ' +
155
+ 'transport.publish(), which delivers to the publishing socket as well. Implement ' +
156
+ 'publishRemote() (broker publish only, no local delivery) to keep the sender excluded. ' +
157
+ 'The fallback is removed in the next major version.');
158
+ }
85
159
  prepareWebSocket(options) {
86
160
  if (this.websockets?.size < 1) {
87
161
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"HonoWebsocketAdapter.js","sourceRoot":"","sources":["../../lib/HonoWebsocketAdapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"HonoWebsocketAdapter.js","sourceRoot":"","sources":["../../lib/HonoWebsocketAdapter.ts"],"names":[],"mappings":"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"}
@@ -6,19 +6,25 @@ import { type ZodError } from 'zod';
6
6
  * application's `ConfigService.onError` like every other error instead of being
7
7
  * answered inside the validator middleware.
8
8
  *
9
- * Extends Hono's `HTTPException` with status 400 deliberately: an existing handler
10
- * that branches on `error instanceof HTTPException` and replies with `error.status`
11
- * keeps answering 400, so adopting this does not silently turn validation failures
12
- * into 500s.
9
+ * Extends Hono's `HTTPException` with status 400 deliberately: a handler that matches
10
+ * with `isHttpException()` - or with the older `error instanceof HTTPException` - and
11
+ * replies with `error.status` keeps answering 400, so adopting this does not silently
12
+ * turn validation failures into 500s.
13
+ *
14
+ * Note it does *not* extend `HttpException` from `@asenajs/asena/adapter`, the class
15
+ * applications throw. Both are branded, so `isHttpException()` cannot tell them apart and
16
+ * does not need to; `instanceof` can, which is one more reason not to reach for it.
13
17
  *
14
18
  * @example
15
19
  * ```typescript
16
20
  * public onError(error: Error, context: Context) {
21
+ * // Before isHttpException: ValidationError is an HTTP exception too, so the
22
+ * // generic branch below would otherwise swallow it.
17
23
  * if (isValidationError(error)) {
18
24
  * return context.send({ success: false, errors: error.issues }, 400);
19
25
  * }
20
26
  *
21
- * if (error instanceof HTTPException) {
27
+ * if (isHttpException(error)) {
22
28
  * return context.send({ error: error.message }, error.status);
23
29
  * }
24
30
  *
@@ -62,10 +68,52 @@ export declare class ValidationError extends HTTPException implements Validation
62
68
  *
63
69
  * Without this the brand is a trap rather than a feature: the JSDoc on `isHttpException` tells
64
70
  * users to write `if (isHttpException(error)) ... else 500`, and on this adapter every
65
- * deliberate 401/403/404/429 would take the else branch and answer 500. `hono` is a *peer*
66
- * dependency, so two copies of it are more likely here than two copies of the adapter - which
67
- * is the situation the brand exists for in the first place.
71
+ * deliberate 401/403/404/429 raised by `hono/basic-auth`, `hono/jwt` or hono's own validator
72
+ * would take the else branch and answer 500.
73
+ *
74
+ * The brand covers one copy of `hono` and cannot reach another: it is installed on the prototype
75
+ * of the class *this* package resolved. Since 3.0.0 `hono` is a **peer** dependency, so this
76
+ * package has no resolution slot of its own and an application normally resolves exactly one copy
77
+ * - which is what makes the brand sufficient rather than a trap. Before that it was a regular
78
+ * dependency, and a downstream application that bumped its own `hono` range ended up with a second
79
+ * nested copy whose `HTTPException` was unbranded: every deliberate 400/403 answered 500 while the
80
+ * API kept responding. `warnOnNestedHono` below reports the one shape that can still produce it.
81
+ *
82
+ * Import `HTTPException` from `@asenajs/hono-adapter` rather than from `hono/http-exception` to
83
+ * stay on this package's copy regardless. The adapter's default response also checks
84
+ * `instanceof HTTPException` before the brand, so a hono exception is answered correctly even if
85
+ * this function never ran.
68
86
  *
69
87
  * Idempotent, and called from the HonoAdapter constructor.
70
88
  */
71
89
  export declare const brandHonoHttpException: () => void;
90
+ /**
91
+ * Warns when this package resolved a *nested* copy of `hono`.
92
+ *
93
+ * `hono` is a peer dependency, so it should always resolve from the application's own
94
+ * `node_modules`. A path under `@asenajs/hono-adapter/node_modules/hono` means a second copy was
95
+ * installed privately for this package - the exact topology that makes `brandHonoHttpException()`
96
+ * useless, because the brand lands on the prototype of *this* copy's class and an `HTTPException`
97
+ * the application threw from its own copy is neither `instanceof` it nor branded, so it is
98
+ * answered 500.
99
+ *
100
+ * This does not - and cannot - detect the *application's* copy. `import.meta.resolve` always
101
+ * answers relative to this module, Node resolution is per-importer so there is no single "the
102
+ * application's hono" to compare against, and after `asena build` or `bun build --compile` there
103
+ * is no `node_modules` to inspect at all. What it can prove is the asymmetric half: if *our* copy
104
+ * is nested, there are two. That is enough, because under a peer dependency a nested copy is the
105
+ * only way this package acquires one.
106
+ *
107
+ * Worth having even though the peer move makes the topology rare: `bun install` has been observed
108
+ * to drop the lockfile entry for a nested copy while leaving the directory on disk, so an
109
+ * application upgrading in place can still be broken by a leftover it cannot see.
110
+ *
111
+ * The path predicate is {@link isNestedHonoPath}, exported so it can be tested against both
112
+ * layouts directly - inside this repo `import.meta.resolve` always answers
113
+ * `hono-adapter/node_modules/hono`, which is the package's own root and deliberately does *not*
114
+ * match, so a test driving the real resolver could only ever assert the negative case.
115
+ */
116
+ export declare const isNestedHonoPath: (resolved: string) => boolean;
117
+ export declare const warnOnNestedHono: (logger?: {
118
+ warn: (message: string) => void;
119
+ }) => void;
@@ -6,19 +6,25 @@ import { flattenError } from 'zod';
6
6
  * application's `ConfigService.onError` like every other error instead of being
7
7
  * answered inside the validator middleware.
8
8
  *
9
- * Extends Hono's `HTTPException` with status 400 deliberately: an existing handler
10
- * that branches on `error instanceof HTTPException` and replies with `error.status`
11
- * keeps answering 400, so adopting this does not silently turn validation failures
12
- * into 500s.
9
+ * Extends Hono's `HTTPException` with status 400 deliberately: a handler that matches
10
+ * with `isHttpException()` - or with the older `error instanceof HTTPException` - and
11
+ * replies with `error.status` keeps answering 400, so adopting this does not silently
12
+ * turn validation failures into 500s.
13
+ *
14
+ * Note it does *not* extend `HttpException` from `@asenajs/asena/adapter`, the class
15
+ * applications throw. Both are branded, so `isHttpException()` cannot tell them apart and
16
+ * does not need to; `instanceof` can, which is one more reason not to reach for it.
13
17
  *
14
18
  * @example
15
19
  * ```typescript
16
20
  * public onError(error: Error, context: Context) {
21
+ * // Before isHttpException: ValidationError is an HTTP exception too, so the
22
+ * // generic branch below would otherwise swallow it.
17
23
  * if (isValidationError(error)) {
18
24
  * return context.send({ success: false, errors: error.issues }, 400);
19
25
  * }
20
26
  *
21
- * if (error instanceof HTTPException) {
27
+ * if (isHttpException(error)) {
22
28
  * return context.send({ error: error.message }, error.status);
23
29
  * }
24
30
  *
@@ -81,9 +87,21 @@ export class ValidationError extends HTTPException {
81
87
  *
82
88
  * Without this the brand is a trap rather than a feature: the JSDoc on `isHttpException` tells
83
89
  * users to write `if (isHttpException(error)) ... else 500`, and on this adapter every
84
- * deliberate 401/403/404/429 would take the else branch and answer 500. `hono` is a *peer*
85
- * dependency, so two copies of it are more likely here than two copies of the adapter - which
86
- * is the situation the brand exists for in the first place.
90
+ * deliberate 401/403/404/429 raised by `hono/basic-auth`, `hono/jwt` or hono's own validator
91
+ * would take the else branch and answer 500.
92
+ *
93
+ * The brand covers one copy of `hono` and cannot reach another: it is installed on the prototype
94
+ * of the class *this* package resolved. Since 3.0.0 `hono` is a **peer** dependency, so this
95
+ * package has no resolution slot of its own and an application normally resolves exactly one copy
96
+ * - which is what makes the brand sufficient rather than a trap. Before that it was a regular
97
+ * dependency, and a downstream application that bumped its own `hono` range ended up with a second
98
+ * nested copy whose `HTTPException` was unbranded: every deliberate 400/403 answered 500 while the
99
+ * API kept responding. `warnOnNestedHono` below reports the one shape that can still produce it.
100
+ *
101
+ * Import `HTTPException` from `@asenajs/hono-adapter` rather than from `hono/http-exception` to
102
+ * stay on this package's copy regardless. The adapter's default response also checks
103
+ * `instanceof HTTPException` before the brand, so a hono exception is answered correctly even if
104
+ * this function never ran.
87
105
  *
88
106
  * Idempotent, and called from the HonoAdapter constructor.
89
107
  */
@@ -97,4 +115,48 @@ export const brandHonoHttpException = () => {
97
115
  configurable: true,
98
116
  });
99
117
  };
118
+ /**
119
+ * Warns when this package resolved a *nested* copy of `hono`.
120
+ *
121
+ * `hono` is a peer dependency, so it should always resolve from the application's own
122
+ * `node_modules`. A path under `@asenajs/hono-adapter/node_modules/hono` means a second copy was
123
+ * installed privately for this package - the exact topology that makes `brandHonoHttpException()`
124
+ * useless, because the brand lands on the prototype of *this* copy's class and an `HTTPException`
125
+ * the application threw from its own copy is neither `instanceof` it nor branded, so it is
126
+ * answered 500.
127
+ *
128
+ * This does not - and cannot - detect the *application's* copy. `import.meta.resolve` always
129
+ * answers relative to this module, Node resolution is per-importer so there is no single "the
130
+ * application's hono" to compare against, and after `asena build` or `bun build --compile` there
131
+ * is no `node_modules` to inspect at all. What it can prove is the asymmetric half: if *our* copy
132
+ * is nested, there are two. That is enough, because under a peer dependency a nested copy is the
133
+ * only way this package acquires one.
134
+ *
135
+ * Worth having even though the peer move makes the topology rare: `bun install` has been observed
136
+ * to drop the lockfile entry for a nested copy while leaving the directory on disk, so an
137
+ * application upgrading in place can still be broken by a leftover it cannot see.
138
+ *
139
+ * The path predicate is {@link isNestedHonoPath}, exported so it can be tested against both
140
+ * layouts directly - inside this repo `import.meta.resolve` always answers
141
+ * `hono-adapter/node_modules/hono`, which is the package's own root and deliberately does *not*
142
+ * match, so a test driving the real resolver could only ever assert the negative case.
143
+ */
144
+ export const isNestedHonoPath = (resolved) => resolved.includes('@asenajs/hono-adapter/node_modules/hono');
145
+ export const warnOnNestedHono = (logger) => {
146
+ try {
147
+ const resolved = import.meta.resolve('hono/http-exception');
148
+ if (!isNestedHonoPath(resolved)) {
149
+ return;
150
+ }
151
+ (logger ?? console).warn(`A nested copy of \`hono\` was found at ${resolved}.\n` +
152
+ ` \`hono\` is a peer dependency of @asenajs/hono-adapter and must resolve from your\n` +
153
+ ` application's node_modules. With two copies, an HTTPException thrown from your copy is\n` +
154
+ ` not recognised by isHttpException() and will be answered as 500.\n` +
155
+ ` Fix: rm -rf node_modules bun.lock && bun install`);
156
+ }
157
+ catch {
158
+ // `import.meta.resolve` is unavailable or throws under some bundlers and in compiled binaries.
159
+ // A diagnostic must never be the reason a server fails to boot.
160
+ }
161
+ };
100
162
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../lib/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EACL,cAAc,EAEd,gBAAgB,GAGjB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,YAAY,EAAiB,MAAM,KAAK,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,OAAO,eAAgB,SAAQ,aAAa;IAChC,CAAC,gBAAgB,CAAC,GAAG,IAAa,CAAC;IAEnD;;;OAGG;IACa,CAAC,cAAc,CAAC,GAAG,IAAa,CAAC;IAEjD,qFAAqF;IACrE,MAAM,CAAS;IAE/B,6CAA6C;IAC7B,MAAM,CAAoB;IAE1C,mEAAmE;IACnD,KAAK,CAAW;IAEhC,YAAmB,KAAe,EAAE,MAAc;QAChD,KAAK,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC,CAAC;QAE7C,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACzC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YAC/F,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,IAAI,EAAE,KAAK,CAAC,IAAI;SACjB,CAAC,CAAC,CAAC;IACN,CAAC;IAED;;;;;;;;;;OAUG;IACa,WAAW;QACzB,OAAO,IAAI,QAAQ,CACjB,IAAI,CAAC,SAAS,CAAC;YACb,KAAK,EAAE,mBAAmB;YAC1B,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC;YACjC,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,EACF;YACE,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;SAChD,CACF,CAAC;IACJ,CAAC;CACF;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAS,EAAE;IAC/C,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,cAAc,CAAC,EAAE,CAAC;QAClF,OAAO;IACT,CAAC;IAED,MAAM,CAAC,cAAc,CAAC,aAAa,CAAC,SAAS,EAAE,cAAc,EAAE;QAC7D,KAAK,EAAE,IAAI;QACX,UAAU,EAAE,KAAK;QACjB,YAAY,EAAE,IAAI;KACnB,CAAC,CAAC;AACL,CAAC,CAAC"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../lib/errors.ts"],"names":[],"mappings":"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"}
@@ -86,9 +86,10 @@ export interface CorsOptions {
86
86
  *
87
87
  * **CORS Flow:**
88
88
  * 1. Check if request has Origin header (if not, skip CORS)
89
- * 2. Validate origin against allowed origins
90
- * 3. Handle preflight OPTIONS request → return 204 immediately
91
- * 4. For other requests → set CORS headers and call next()
89
+ * 2. Advertise that the response varies by Origin (unless the config is the literal '*')
90
+ * 3. Validate origin - when it is not allowed, emit no CORS headers and carry on
91
+ * 4. Handle preflight OPTIONS request → return 204 immediately
92
+ * 5. For other requests → set CORS headers and call next()
92
93
  */
93
94
  export declare class CorsMiddleware extends MiddlewareService {
94
95
  private readonly origin;
@@ -123,9 +124,17 @@ export declare class CorsMiddleware extends MiddlewareService {
123
124
  *
124
125
  * Execution flow:
125
126
  * 1. Check if Origin header present (if not, skip CORS)
126
- * 2. Validate origin
127
- * 3. Handle preflight OPTIONS → return 204 No Content
128
- * 4. Set CORS headers for actual request → call next()
127
+ * 2. Advertise that the response varies by Origin (unless the config is the literal '*')
128
+ * 3. Validate origin - when it is not allowed, emit no CORS headers and carry on
129
+ * 4. Handle preflight OPTIONS → return 204 No Content
130
+ * 5. Set CORS headers for actual request → call next()
131
+ *
132
+ * A disallowed origin is *not* answered with 403. CORS is a policy the browser enforces on
133
+ * behalf of the user, not an access-control decision the server makes: the correct denial is a
134
+ * normal response with no `Access-Control-Allow-Origin`, which the browser then refuses to
135
+ * expose. Rejecting outright also turned away every non-browser caller that happens to send an
136
+ * Origin header - server-to-server clients, proxies, webviews - and forced applications to
137
+ * register this middleware conditionally when CORS was already terminated at the ingress.
129
138
  *
130
139
  * @param context - Hono context wrapper
131
140
  * @param next - Function to call next middleware or handler
@@ -41,9 +41,10 @@ import { MiddlewareService } from '../defaults';
41
41
  *
42
42
  * **CORS Flow:**
43
43
  * 1. Check if request has Origin header (if not, skip CORS)
44
- * 2. Validate origin against allowed origins
45
- * 3. Handle preflight OPTIONS request → return 204 immediately
46
- * 4. For other requests → set CORS headers and call next()
44
+ * 2. Advertise that the response varies by Origin (unless the config is the literal '*')
45
+ * 3. Validate origin - when it is not allowed, emit no CORS headers and carry on
46
+ * 4. Handle preflight OPTIONS request → return 204 immediately
47
+ * 5. For other requests → set CORS headers and call next()
47
48
  */
48
49
  export class CorsMiddleware extends MiddlewareService {
49
50
  origin;
@@ -87,9 +88,17 @@ export class CorsMiddleware extends MiddlewareService {
87
88
  *
88
89
  * Execution flow:
89
90
  * 1. Check if Origin header present (if not, skip CORS)
90
- * 2. Validate origin
91
- * 3. Handle preflight OPTIONS → return 204 No Content
92
- * 4. Set CORS headers for actual request → call next()
91
+ * 2. Advertise that the response varies by Origin (unless the config is the literal '*')
92
+ * 3. Validate origin - when it is not allowed, emit no CORS headers and carry on
93
+ * 4. Handle preflight OPTIONS → return 204 No Content
94
+ * 5. Set CORS headers for actual request → call next()
95
+ *
96
+ * A disallowed origin is *not* answered with 403. CORS is a policy the browser enforces on
97
+ * behalf of the user, not an access-control decision the server makes: the correct denial is a
98
+ * normal response with no `Access-Control-Allow-Origin`, which the browser then refuses to
99
+ * expose. Rejecting outright also turned away every non-browser caller that happens to send an
100
+ * Origin header - server-to-server clients, proxies, webviews - and forced applications to
101
+ * register this middleware conditionally when CORS was already terminated at the ingress.
93
102
  *
94
103
  * @param context - Hono context wrapper
95
104
  * @param next - Function to call next middleware or handler
@@ -103,32 +112,29 @@ export class CorsMiddleware extends MiddlewareService {
103
112
  }
104
113
  // Validate origin
105
114
  const allowedOrigin = this.getAllowedOrigin(origin);
106
- if (!allowedOrigin) {
107
- // Origin not allowed → block request
108
- return new Response('CORS: Origin not allowed', { status: 403 });
109
- }
110
- // Set CORS headers via AsenaContext abstraction
111
- context.setResponseHeader('Access-Control-Allow-Origin', allowedOrigin);
112
- if (this.credentials) {
113
- context.setResponseHeader('Access-Control-Allow-Credentials', 'true');
115
+ // Non-'*' configs make the response depend on the Origin, refusals included; a shared cache
116
+ // that does not key on it hands one origin's response to another.
117
+ if (this.origin !== '*') {
118
+ context.setResponseHeader('Vary', 'Origin');
114
119
  }
115
- if (this.exposedHeaders) {
116
- context.setResponseHeader('Access-Control-Expose-Headers', this.exposedHeaders);
120
+ if (allowedOrigin) {
121
+ context.setResponseHeader('Access-Control-Allow-Origin', allowedOrigin);
122
+ if (this.credentials) {
123
+ context.setResponseHeader('Access-Control-Allow-Credentials', 'true');
124
+ }
125
+ if (this.exposedHeaders) {
126
+ context.setResponseHeader('Access-Control-Expose-Headers', this.exposedHeaders);
127
+ }
117
128
  }
118
129
  // Handle preflight OPTIONS request
119
130
  if (context.req.method === 'OPTIONS') {
120
- // Build headers object for preflight response
121
- const headers = {
122
- 'Access-Control-Allow-Origin': allowedOrigin,
123
- 'Access-Control-Allow-Methods': this.methods,
124
- 'Access-Control-Allow-Headers': this.allowedHeaders,
125
- 'Access-Control-Max-Age': this.maxAge,
126
- };
127
- if (this.credentials) {
128
- headers['Access-Control-Allow-Credentials'] = 'true';
131
+ if (allowedOrigin) {
132
+ context.setResponseHeader('Access-Control-Allow-Methods', this.methods);
133
+ context.setResponseHeader('Access-Control-Allow-Headers', this.allowedHeaders);
134
+ context.setResponseHeader('Access-Control-Max-Age', this.maxAge);
129
135
  }
130
- // Return 204 No Content for preflight
131
- return new Response(null, { status: 204, headers });
136
+ // Accumulated headers, not a fresh object: earlier middlewares' headers survive the 204.
137
+ return new Response(null, { status: 204, headers: context.res.headers });
132
138
  }
133
139
  // For actual requests, continue to handler
134
140
  return await next();
@@ -1 +1 @@
1
- {"version":3,"file":"CorsMiddleware.js","sourceRoot":"","sources":["../../../lib/middlewares/CorsMiddleware.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CorsMiddleware.js","sourceRoot":"","sources":["../../../lib/middlewares/CorsMiddleware.ts"],"names":[],"mappings":"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"}
@@ -294,9 +294,20 @@ export declare class RateLimiterMiddleware extends MiddlewareService {
294
294
  */
295
295
  handle(context: Context, next: () => Promise<void>): Promise<any>;
296
296
  /**
297
- * Cleanup resources (stop cleanup timer)
297
+ * Cleanup resources (stop cleanup timer, drop bucket state)
298
298
  *
299
- * Call this when shutting down the application.
299
+ * `@OnStop` hands this to the component lifecycle, so `server.stop()` calls it instead of the
300
+ * application having to remember to. The hook is inherited, so the `@Middleware()` subclass
301
+ * users actually register gets it without repeating the decorator - and it only fires for
302
+ * singletons, which is what a rate limiter has to be to share one bucket map across requests.
303
+ *
304
+ * The timer is `unref()`'d, so it never held the process open. What it does do is survive a
305
+ * stop/start cycle *inside* one process - twenty of them is an ordinary test suite - leaving a
306
+ * timer per stopped server still sweeping a bucket map nobody reads. The buckets go with it:
307
+ * a restarted server must not inherit the rate-limit state of the one before it, or the first
308
+ * requests after a restart get counted against a window that has already closed.
309
+ *
310
+ * Safe to call twice; the second call has nothing left to do.
300
311
  */
301
312
  destroy(): void;
302
313
  /**
@@ -46,7 +46,17 @@
46
46
  * public login() { ... }
47
47
  * ```
48
48
  */
49
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
50
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
51
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
52
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
53
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
54
+ };
55
+ var __metadata = (this && this.__metadata) || function (k, v) {
56
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
57
+ };
49
58
  import { MiddlewareService } from '../defaults';
59
+ import { OnStop } from '@asenajs/asena/decorators/ioc';
50
60
  /**
51
61
  * Rate Limiter Middleware
52
62
  *
@@ -238,14 +248,27 @@ export class RateLimiterMiddleware extends MiddlewareService {
238
248
  return await next();
239
249
  }
240
250
  /**
241
- * Cleanup resources (stop cleanup timer)
251
+ * Cleanup resources (stop cleanup timer, drop bucket state)
242
252
  *
243
- * Call this when shutting down the application.
253
+ * `@OnStop` hands this to the component lifecycle, so `server.stop()` calls it instead of the
254
+ * application having to remember to. The hook is inherited, so the `@Middleware()` subclass
255
+ * users actually register gets it without repeating the decorator - and it only fires for
256
+ * singletons, which is what a rate limiter has to be to share one bucket map across requests.
257
+ *
258
+ * The timer is `unref()`'d, so it never held the process open. What it does do is survive a
259
+ * stop/start cycle *inside* one process - twenty of them is an ordinary test suite - leaving a
260
+ * timer per stopped server still sweeping a bucket map nobody reads. The buckets go with it:
261
+ * a restarted server must not inherit the rate-limit state of the one before it, or the first
262
+ * requests after a restart get counted against a window that has already closed.
263
+ *
264
+ * Safe to call twice; the second call has nothing left to do.
244
265
  */
245
266
  destroy() {
246
267
  if (this.cleanupTimer) {
247
268
  clearInterval(this.cleanupTimer);
269
+ this.cleanupTimer = undefined;
248
270
  }
271
+ this.buckets.clear();
249
272
  }
250
273
  /**
251
274
  * Get current bucket state for a client (for testing/debugging)
@@ -300,4 +323,10 @@ export class RateLimiterMiddleware extends MiddlewareService {
300
323
  this.cleanupTimer.unref();
301
324
  }
302
325
  }
326
+ __decorate([
327
+ OnStop(),
328
+ __metadata("design:type", Function),
329
+ __metadata("design:paramtypes", []),
330
+ __metadata("design:returntype", void 0)
331
+ ], RateLimiterMiddleware.prototype, "destroy", null);
303
332
  //# sourceMappingURL=RateLimiterMiddleware.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"RateLimiterMiddleware.js","sourceRoot":"","sources":["../../../lib/middlewares/RateLimiterMiddleware.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RateLimiterMiddleware.js","sourceRoot":"","sources":["../../../lib/middlewares/RateLimiterMiddleware.ts"],"names":[],"mappings":"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"}