mikser-io 9.37.1 → 9.38.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/configuration.md +2 -2
- package/package.json +1 -1
- package/src/server.js +27 -4
- package/src/utils.js +2 -2
package/docs/configuration.md
CHANGED
|
@@ -58,10 +58,10 @@ These options are part of `runtime.options` and apply to the engine itself.
|
|
|
58
58
|
| `trace` | `-t, --trace` | boolean | `false` | Enable trace-level logging (very verbose). |
|
|
59
59
|
| `threads` | — | number | `4` | Worker thread count for the Piscina pools (`renderWorkers`, `postprocessWorkers`). Both pools are lazy (`minThreads: 0` + `idleTimeout: 30_000`) so INLINE-only workloads spin up zero workers. |
|
|
60
60
|
| `server` | `-s, --server [port]` | number\|boolean | — | When set, the engine creates a shared Express app on `runtime.options.app` and listens on the given port (default `3001`) after all plugins have mounted their routes. Plugins like `api` attach to it instead of starting their own server. The `outputFolder` is also served as a static catch-all route at `/` (plugin routes match first; anything that doesn't match falls through to the rendered output). Requires `express` to be installed. |
|
|
61
|
-
| `junk` | — | array\|false | built-in list | OS and file-manager litter, filtered out of both the scan and the watcher. The dot-prefixed files (`.DS_Store`, `._*`) were already invisible — globby defaults to `dot: false` and the watcher ignores leading dots — but the Windows ones are **not** dotfiles: `Thumbs.db` and `desktop.ini` were measurably scanned *and* watched, and became entities. The list is deliberately conservative (OS/file-manager artifacts and application lock files only, no `*.tmp`, `*.bak` or editor backups), because a filter that silently drops content is worse than the litter it prevents. `false` disables it; an array replaces it. See `isJunkPath` / `JUNK_IGNORE` in `src/utils.js`. Plugins that write metadata next to content add their own patterns with `registerJunk({ ignore, match })` — the engine provides the mechanism and the plugin the knowledge of what its files are called (`mikser-io-
|
|
61
|
+
| `junk` | — | array\|false | built-in list | OS and file-manager litter, filtered out of both the scan and the watcher. The dot-prefixed files (`.DS_Store`, `._*`) were already invisible — globby defaults to `dot: false` and the watcher ignores leading dots — but the Windows ones are **not** dotfiles: `Thumbs.db` and `desktop.ini` were measurably scanned *and* watched, and became entities. The list is deliberately conservative (OS/file-manager artifacts and application lock files only, no `*.tmp`, `*.bak` or editor backups), because a filter that silently drops content is worse than the litter it prevents. `false` disables it; an array replaces it. See `isJunkPath` / `JUNK_IGNORE` in `src/utils.js`. Plugins that write metadata next to content add their own patterns with `registerJunk({ ignore, match })` — the engine provides the mechanism and the plugin the knowledge of what its files are called (`mikser-io-drive` registers `*.nephelemeta`). Plugin registrations survive an array override, since narrowing the OS list is not a request to start importing a library's sidecars. |
|
|
62
62
|
| — (plugin) | — | object | — | `sources({ styles: { folder: 'styles', extensions: ['css'] } })` registers build inputs as catalog entities, one collection per key. A sidecar can then read them with `findEntities()`, whose queries land in the render's `refClosure` — so editing, adding or removing a part re-renders the bundle and nothing else. Reading the same files with `fs` instead works for one build and silently breaks watch, because the engine has no dependency on a file it never saw. Nothing is linked into `outputFolder`: these are inputs, not output. Named `sources` rather than `inputs` because `entity.inputs` already means something adjacent — bytes an output depends on without being entities at all. |
|
|
63
63
|
| `cors` / `no-cors` | `--cors` / `--no-cors` | boolean | — | Toggle CORS on the engine's shared Express app. See `src/server.js` for the extensible header arrays plugins push onto. |
|
|
64
|
-
| `server.requestTimeout` | — | number | node default (`300000`) | Milliseconds a single request may take, set on the underlying `http.Server`. Node's 5-minute default is effectively an **upload size limit expressed in seconds** — a large file over a slow link is indistinguishable from a stalled request, so it is cut off and the caller sees a truncated write rather than a readable error.
|
|
64
|
+
| `server.requestTimeout` | — | number | node default (`300000`) | Milliseconds a single request may take, set on the underlying `http.Server`. Node's 5-minute default is effectively an **upload size limit expressed in seconds** — a large file over a slow link is indistinguishable from a stalled request, so it is cut off and the caller sees a truncated write rather than a readable error. Raised to two hours automatically when any route registers as `streaming` (an upload surface such as `mikser-io-drive`), because Node's default mismeasures exactly those; set this explicitly to override. `0` disables the cap: reasonable on a trusted-network build server, bad facing the internet, where it removes the only bound on how long a client can hold a connection open doing nothing. `headersTimeout` is clamped to stay at or below it. The server is also exposed as `runtime.options.httpServer`. |
|
|
65
65
|
| `url` | `-u, --url <url>` | string | — | Public URL where this mikser is reachable (e.g. `https://blog.me.com`). Validated, trailing slash stripped, stamped on `runtime.options.url`. Read by webhook-capable plugins for push-vs-poll gating (`url.startsWith('https://')`); used by anything that surfaces absolute URLs externally — MCP preview URLs returned to agents, forms share links, email tracking pixels. Plugins that just need internal URLs keep using `runtime.options.port`. |
|
|
66
66
|
|
|
67
67
|
## Engine Substrate
|
package/package.json
CHANGED
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
|
-
//
|
|
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
|
-
|
|
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}
|
|
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
|
})
|
package/src/utils.js
CHANGED
|
@@ -1079,7 +1079,7 @@ export function isFullCycle(rt = runtime) {
|
|
|
1079
1079
|
|
|
1080
1080
|
// ── operating-system and file-manager litter ────────────────────────────
|
|
1081
1081
|
//
|
|
1082
|
-
// Exposing a source folder over a network filesystem (mikser-io-
|
|
1082
|
+
// Exposing a source folder over a network filesystem (mikser-io-drive) or
|
|
1083
1083
|
// simply opening it in a file manager drops metadata files into it. Every one
|
|
1084
1084
|
// of them would otherwise become an entity, render a page, and appear in a
|
|
1085
1085
|
// catalog.
|
|
@@ -1146,7 +1146,7 @@ export const JUNK_IGNORE = [
|
|
|
1146
1146
|
// the engine has no business knowing what a particular library's sidecar file
|
|
1147
1147
|
// is called. What it can provide is the mechanism: a plugin that writes
|
|
1148
1148
|
// metadata next to content says so, and both the scan and the watcher honour
|
|
1149
|
-
// it. (mikser-io-
|
|
1149
|
+
// it. (mikser-io-drive registers `*.nephelemeta` for exactly this reason:
|
|
1150
1150
|
// the collection-level file is dot-prefixed and was already invisible, while
|
|
1151
1151
|
// the per-file one — `page.md.nephelemeta` — is not, and was measurably
|
|
1152
1152
|
// becoming an entity.)
|