mikser-io 9.62.0 → 9.63.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 +36 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mikser-io",
3
- "version": "9.62.0",
3
+ "version": "9.63.0",
4
4
  "description": "A mixer for content: entities in, configurable render pipelines, outputs of any kind. Static sites are the canonical recipe, not the definition — the same engine renders PDFs, emails and whatever a renderer plugin produces. Files are the source of truth, every lifecycle phase is observable, and the build graph is queryable by an agent.",
5
5
  "main": "index.js",
6
6
  "exports": {
package/src/server.js CHANGED
@@ -22,11 +22,25 @@
22
22
 
23
23
  import path from 'node:path'
24
24
  import { fileURLToPath } from 'node:url'
25
+ import { networkInterfaces } from 'node:os'
25
26
 
26
27
  import runtime from './runtime.js'
27
28
  import { useLogger } from './engine.js'
28
29
  import { onInitialized, onLoad, onLoaded } from './lifecycle.js'
29
30
 
31
+ // Every non-loopback IPv4 address this machine answers on.
32
+ //
33
+ // IPv4 only, deliberately. The non-internal IPv6 addresses on a typical
34
+ // machine are link-local (fe80::), which need a zone index to be usable and
35
+ // are not what anyone is going to type into a phone — listing them would make
36
+ // the useful lines harder to find, which is the opposite of the point.
37
+ export function localAddresses() {
38
+ return Object.values(networkInterfaces())
39
+ .flat()
40
+ .filter(iface => iface && iface.family === 'IPv4' && !iface.internal)
41
+ .map(iface => iface.address)
42
+ }
43
+
30
44
  // Extend the engine's commander with server-related flags. Called by
31
45
  // engine.js's onInitialize callback AFTER engine's own options chain
32
46
  // and BEFORE the .parse() call — preserves the order of options in
@@ -214,6 +228,28 @@ export function setupServer() {
214
228
  // back to the bind URL when no public origin is set.
215
229
  const externalUrl = runtime.options.url ?? `http://localhost:${runtime.options.port}`
216
230
  logger.info('Server listening: %s', externalUrl)
231
+
232
+ // The addresses that are NOT localhost.
233
+ //
234
+ // listen(port) binds every interface, so the server is
235
+ // already reachable from a phone or a second machine —
236
+ // and the one address printed above is the single one
237
+ // that will not work from either. Anyone testing a
238
+ // layout on a real device has to go and find their own
239
+ // IP, every time, on a machine that already knows it.
240
+ //
241
+ // Only when no public URL is configured. Behind a proxy
242
+ // or a tunnel the LAN address is not how the site is
243
+ // reached, and offering it would be an invitation to
244
+ // debug the wrong origin.
245
+ if (!runtime.options.url) {
246
+ const lan = localAddresses()
247
+ if (lan.length) {
248
+ logger.info('Also on: %s', lan
249
+ .map(address => `http://${address}:${runtime.options.port}`)
250
+ .join(' '))
251
+ }
252
+ }
217
253
  resolve()
218
254
  })
219
255