mikser-io 9.15.0 → 9.15.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mikser-io",
3
- "version": "9.15.0",
3
+ "version": "9.15.1",
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/manifest.js CHANGED
@@ -440,6 +440,22 @@ export function createManifest(db) {
440
440
  })
441
441
  }
442
442
  }
443
+ if (track?.lookups) {
444
+ for (const target of track.lookups) {
445
+ // findById is extension-tolerant and also resolves a
446
+ // meta.href, so the hash is the resolved entity's when
447
+ // there is one. No hash means "nothing resolved" —
448
+ // shouldSkip treats a hashless edge whose target mutated
449
+ // as a re-render, which is what should happen when a page
450
+ // that was linked-to-but-missing finally appears.
451
+ const resolved = findById(target)
452
+ edges.push({
453
+ kind: 'lookup',
454
+ target,
455
+ hash: resolved ? inputHashOf(resolved) : undefined,
456
+ })
457
+ }
458
+ }
443
459
  if (track?.queries) {
444
460
  for (const filter of track.queries) {
445
461
  edges.push({ kind: 'query', filter })
package/src/render.js CHANGED
@@ -187,10 +187,28 @@ export default async ({ entity, options, config, context, state, logger, port, t
187
187
  // state.layouts.sitemap map that was serialized per render
188
188
  // task. Goes through the same WAL-backed read-only handle
189
189
  // every worker shares with the engine writer.
190
- lookupHref: lookupHrefViaDb,
190
+ // Both lookups RECORD what they were asked for, via track.lookup.
191
+ //
192
+ // They read the catalog directly, and until this they told nobody —
193
+ // so nothing knew a page depended on the page it links to. Renaming
194
+ // a target left every page linking to it pointing at a file that no
195
+ // longer existed, on a green build, because manifest.shouldSkip had
196
+ // no edge to check. A sidecar's findEntities() was tracked all along;
197
+ // these two were the asymmetry.
198
+ //
199
+ // The recorded target is the string the template asked for, not the
200
+ // resolved id — see track.lookup for why that also covers a target that
201
+ // does not exist yet.
202
+ lookupHref: (href) => {
203
+ track?.lookup?.(href)
204
+ return lookupHrefViaDb(href)
205
+ },
191
206
  // Resolve a served-entity reference to its deployed URL, absolute
192
207
  // when runtime.options.url is set (ADR-0011).
193
- lookupUrl: (ref, preset) => lookupUrlViaDb(ref, preset, options.url),
208
+ lookupUrl: (ref, preset) => {
209
+ if (typeof ref === 'string') track?.lookup?.(ref)
210
+ return lookupUrlViaDb(ref, preset, options.url)
211
+ },
194
212
  content() {
195
213
  return readFileSync(entity.source, { encoding: 'utf8' })
196
214
  },
package/src/track.js CHANGED
@@ -40,8 +40,36 @@ export function filterKey(filter) {
40
40
  // The returned object exposes `partials: Set<string>` and
41
41
  // `queries: Array<filter | null>` directly. Consumers iterate either
42
42
  // shape; both are owned by the track for the lifetime of the run.
43
- export function createTrack({ partial = true, query = true } = {}) {
43
+ export function createTrack({ partial = true, query = true, lookup = true } = {}) {
44
44
  const track = {}
45
+ if (lookup) {
46
+ // Lookups a TEMPLATE made by name: runtime.href('/contacts'),
47
+ // runtime.lookupUrl('/media/clip.mp4'). Both read the catalog
48
+ // directly, and until this existed neither told anyone — so nothing
49
+ // recorded that a page depends on the page it links to.
50
+ //
51
+ // Measured consequence: rename contacts.md to contact-us.md and only
52
+ // the renamed page re-renders. Every page linking to it keeps a href
53
+ // pointing at a file that no longer exists, on a green build.
54
+ //
55
+ // The edge kind is 'lookup', NOT 'ref': mikser_refs divides ownership
56
+ // by kind — indexEntity owns kind='ref' (static frontmatter $-refs)
57
+ // and clears it per source, while replaceDynamic owns everything
58
+ // else. Writing these as 'ref' got them inserted by replaceDynamic
59
+ // and then wiped by the next indexEntity, so the edge existed in
60
+ // the manifest and never in the refs index — recorded, and still
61
+ // never scheduling a re-render.
62
+ //
63
+ // The target is the STRING the template asked for, not the resolved
64
+ // entity's id, and that is deliberate: lookupKeys() expands a mutated
65
+ // entity into its id, its meta.href AND its id-minus-extension, so an
66
+ // edge on '/contacts' fires whether the target was edited, renamed,
67
+ // deleted, or created for the first time. Recording the resolved id
68
+ // instead would miss the case where nothing resolved yet.
69
+ const lookups = new Set()
70
+ track.lookups = lookups
71
+ track.lookup = (target) => { if (target && typeof target === 'string') lookups.add(target) }
72
+ }
45
73
  if (partial) {
46
74
  const partials = new Set()
47
75
  track.partials = partials