mikser-io 9.40.0 → 9.40.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mikser-io",
3
- "version": "9.40.0",
3
+ "version": "9.40.2",
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/explain.js CHANGED
@@ -228,6 +228,16 @@ export async function explain(reference) {
228
228
  : 'unknown',
229
229
  outputHash: snap.outputHash ?? null,
230
230
  parent: snap.parent ?? null,
231
+ // Which keys of its OWN meta the render read, and which keys it
232
+ // read off OTHER entities.
233
+ //
234
+ // refClosure answers "what would re-render this". These answer
235
+ // "what does it actually use", which is the question behind a
236
+ // document that renders to a hole: a key the layout never touches
237
+ // is either a typo or dead weight, and nothing else on this report
238
+ // distinguishes them. Empty when the catalog predates the record.
239
+ metaReads: snap.metaReads ?? [],
240
+ consumedReads: (snap.consumedReads ?? []).map(([id, keys]) => ({ entity: id, keys })),
231
241
  refClosure: (snap.refClosure ?? []).map(entry =>
232
242
  entry.kind === 'query'
233
243
  ? {
@@ -383,6 +393,22 @@ export function formatExplain(report) {
383
393
  const gone = e.gone?.length ? ' [TARGET DELETED SINCE]' : ''
384
394
  out.push(` ${e.kind.padEnd(10)} ${e.target}${bound}${e.hash ? ` ${e.hash}` : ''}${gone}`)
385
395
  }
396
+
397
+ // What the render actually READ, as against what would re-render it.
398
+ // Capped, because a large page reads a lot and a wall of keys buries
399
+ // the rest of the report — the full list is in --json.
400
+ const SHOWN = 12
401
+ const shown = (keys) => keys.length > SHOWN
402
+ ? `${keys.slice(0, SHOWN).join(', ')} … +${keys.length - SHOWN} more`
403
+ : keys.join(', ')
404
+ if (r.metaReads?.length) {
405
+ row('metaReads', `${r.metaReads.length} key${r.metaReads.length === 1 ? '' : 's'} of its own meta`)
406
+ out.push(` ${shown(r.metaReads)}`)
407
+ }
408
+ for (const c of r.consumedReads ?? []) {
409
+ row('consumed', `${c.entity} (${c.keys.length})`)
410
+ out.push(` ${shown(c.keys)}`)
411
+ }
386
412
  }
387
413
 
388
414
  out.push('')
package/src/render.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { readFileSync, existsSync } from 'node:fs'
2
2
  import { readFile, unlink } from 'node:fs/promises'
3
3
  import { createRequire } from 'node:module'
4
- import { createTrack, recordReads, serializeTrack } from './track.js'
4
+ import { createTrack, recordReads, serializeTrack, observeConsumed } from './track.js'
5
5
  import { randomUUID } from 'node:crypto'
6
6
  import path from 'node:path'
7
7
  import _ from 'lodash'
@@ -110,7 +110,8 @@ export default async ({ entity, options, config, context, state, logger, port, t
110
110
  // so the worker makes its own track here and returns its CONTENTS with the
111
111
  // result, where the engine folds them into the real one.
112
112
  const ownTrack = !track
113
- track = track ?? createTrack({ meta: options?.metaReads !== false })
113
+ track = track ?? createTrack({ meta: options?.metaReads !== false,
114
+ consumed: options?.metaReads !== false })
114
115
 
115
116
  logger = logger || {
116
117
  info(...args) {
@@ -259,7 +260,20 @@ export default async ({ entity, options, config, context, state, logger, port, t
259
260
  : typeof result.id === 'string' ? [result.id]
260
261
  : Object.values(result).map(e => e?.id).filter(Boolean)
261
262
  track?.lookup?.(href, ids)
262
- return result
263
+ // The entity goes to the TEMPLATE, which then reads fields off it.
264
+ // Recording those against the entity they belong to is what gives a
265
+ // document that never renders a contract — and this is the second
266
+ // way one reaches a render, alongside a sidecar's findEntity.
267
+ //
268
+ // `lookupUrl` needs no equivalent: it hands back a URL string, so
269
+ // nothing is ever read off an entity by the caller.
270
+ if (!result) return result
271
+ if (typeof result.id === 'string') return observeConsumed(result, track)
272
+ const observedByLang = {}
273
+ for (const [lang, row] of Object.entries(result)) {
274
+ observedByLang[lang] = row?.id ? observeConsumed(row, track) : row
275
+ }
276
+ return observedByLang
263
277
  },
264
278
  // Resolve a served-entity reference to its deployed URL, absolute
265
279
  // when runtime.options.url is set (ADR-0011).