mikser-io 9.37.1 → 9.38.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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/server.js +27 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mikser-io",
3
- "version": "9.37.1",
3
+ "version": "9.38.0",
4
4
  "description": "<p align=\"center\"> <img src=\"mikser-lockup-stacked.svg\" alt=\"mikser\" width=\"198\" /> </p>",
5
5
  "main": "index.js",
6
6
  "exports": {
package/src/server.js CHANGED
@@ -31,6 +31,11 @@ import { onInitialized, onLoad, onLoaded } from './lifecycle.js'
31
31
  // engine.js's onInitialize callback AFTER engine's own options chain
32
32
  // and BEFORE the .parse() call — preserves the order of options in
33
33
  // --help output.
34
+ // Two hours. Long enough for a gigabyte at 1.2 Mbps, which is below any link
35
+ // this runs on, and short enough to remain a bound. Applied only when a
36
+ // streaming route exists, so a plain build server keeps Node's default.
37
+ const STREAMING_REQUEST_TIMEOUT = 2 * 60 * 60 * 1000
38
+
34
39
  export function attachServerCliOptions(commander) {
35
40
  commander
36
41
  ?.option('-s --server [port]', 'start an Express server on the given port (defaults to 3001)')
@@ -224,11 +229,25 @@ export function setupServer() {
224
229
  // large attachments) cannot raise it for itself. Hence a
225
230
  // config knob here rather than in the plugin.
226
231
  //
227
- // `0` disables the cap entirely. That is a deliberate choice
232
+ // Raised automatically when a streaming route is mounted; see
233
+ // below. `0` disables the cap entirely. That is a deliberate choice
228
234
  // for a trusted-network build server and a bad one facing the
229
235
  // internet, where it removes the only bound on how long a
230
236
  // client can hold a connection open doing nothing.
231
- const requestTimeout = runtime.config.server?.requestTimeout
237
+ // A streaming route is one a facade must not buffer — an
238
+ // upload surface, an SSE stream — and it is exactly the shape
239
+ // Node's 5-minute cap mismeasures. `registerRoute` already
240
+ // records which routes those are, so the engine can tell
241
+ // without being told twice.
242
+ //
243
+ // Two hours rather than `0`: a 1GB upload needs better than
244
+ // 1.2 Mbps to fit, which any real link clears, while a finite
245
+ // bound still stops a client holding a connection open
246
+ // forever. Disabling it entirely stays available and stays a
247
+ // deliberate choice.
248
+ const streaming = (runtime.routes ?? []).filter(r => r.streaming)
249
+ const configured = runtime.config.server?.requestTimeout
250
+ const requestTimeout = configured ?? (streaming.length ? STREAMING_REQUEST_TIMEOUT : undefined)
232
251
  if (requestTimeout != null) {
233
252
  httpServer.requestTimeout = requestTimeout
234
253
  // headersTimeout must not exceed requestTimeout, or Node
@@ -237,8 +256,12 @@ export function setupServer() {
237
256
  if (requestTimeout !== 0) {
238
257
  httpServer.headersTimeout = Math.min(httpServer.headersTimeout, requestTimeout)
239
258
  }
240
- logger.info('Server request timeout: %s',
241
- requestTimeout === 0 ? 'disabled' : `${requestTimeout}ms`)
259
+ logger.info('Server request timeout: %s%s',
260
+ requestTimeout === 0 ? 'disabled' : `${Math.round(requestTimeout / 60000)}m`,
261
+ configured == null
262
+ ? ` (raised from Node's 5m default for ${streaming.length} streaming route(s): `
263
+ + `${streaming.map(r => r.path).join(', ')} — set config.server.requestTimeout to override)`
264
+ : '')
242
265
  }
243
266
  runtime.options.httpServer = httpServer
244
267
  })