@ai-matrx/content-ir-react 0.12.7 → 0.13.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/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.13.1 — 2026-09-30
4
+
5
+ - **The settling ingest notifies once.** In 0.13.0 the first `ingestDbRows`
6
+ that settled the tier bumped the ingested kinds AND the epoch, so their
7
+ listeners (and `subscribe` listeners) fired twice. A settling ingest now
8
+ notifies every listener exactly once; later ingests stay per-kind.
9
+
10
+ ### Consumer action
11
+
12
+ - None required. Host tests that assert "ingest reaches only the ingested
13
+ kinds" must start from a SETTLED tier — the ingest that settles it reaches
14
+ every kind by design (0.13.0).
15
+
16
+ ## 0.13.0 — 2026-09-30
17
+
18
+ - **Settling repaints every block that waited on it.** THE COLD-VERDICT RULE
19
+ holds a block whose kind the resolver cannot answer while its tier is
20
+ unsettled. `ensureWarm` settling (a landed list, empty or not, or retries
21
+ exhausted) and the first `ingestDbRows` that settles the tier now bump the
22
+ epoch and call EVERY per-kind listener. Before, only kinds that gained rows
23
+ were told, so a waiting block for any other kind kept its pre-settle
24
+ rendering (raw JSON in hosts that drew it) until something unrelated
25
+ re-rendered it.
26
+ - **A single-kind fetch always answers its waiters.** `requestComponent` now
27
+ bumps that kind when its fetch misses or fails too (a landing already did).
28
+
29
+ ### Consumer action
30
+
31
+ - A host that holds a completed block on a loader while `hasSettled()` is
32
+ false may now rely on the per-kind repaint (`subscribeKind` /
33
+ `getKindVersion`) to release it — no polling, no timer.
34
+
3
35
  ## 0.12.7
4
36
 
5
37
  Automatic changed-only republish (docs/metadata drift since the last tag — see
package/dist/index.cjs CHANGED
@@ -268,6 +268,7 @@ var ComponentResolver = class {
268
268
  * key wins: rows arrive is_default-first / sort_order-asc from the source.
269
269
  */
270
270
  ingestDbRows(rows) {
271
+ const wasSettled = this.hasSettled();
271
272
  const changedKinds = /* @__PURE__ */ new Set();
272
273
  for (const row of rows) {
273
274
  const key = keyOf(row.kind, row.platform, row.role);
@@ -276,11 +277,35 @@ var ComponentResolver = class {
276
277
  changedKinds.add(row.kind);
277
278
  }
278
279
  }
280
+ if (!wasSettled && this.hasSettled()) {
281
+ this.notifySettled();
282
+ return;
283
+ }
279
284
  if (changedKinds.size > 0) {
280
285
  for (const kind of changedKinds) this.bumpKind(kind);
281
286
  this.notifyChanged();
282
287
  }
283
288
  }
289
+ /**
290
+ * Mark the tier settled. THE COLD-VERDICT RULE held every block whose kind
291
+ * the tier could not answer; settling changes that verdict for ALL of them,
292
+ * so the flip bumps the epoch and calls every per-kind listener (as a
293
+ * wholesale replace does). Before 0.13.0 a settle notified only kinds that
294
+ * gained rows, and a waiting block for any other kind kept its pre-settle
295
+ * rendering until something unrelated re-rendered it.
296
+ */
297
+ markSettled() {
298
+ const wasSettled = this.hasSettled();
299
+ this.settled = true;
300
+ if (!wasSettled) this.notifySettled();
301
+ }
302
+ notifySettled() {
303
+ this.epoch += 1;
304
+ for (const set of this.kindListeners.values()) {
305
+ for (const listener of set) listener();
306
+ }
307
+ this.notifyChanged();
308
+ }
284
309
  /**
285
310
  * Refresh landing point: REPLACE the db tier wholesale (same
286
311
  * first-row-per-key contract as {@link ingestDbRows}) so edits, deletions,
@@ -376,6 +401,7 @@ var ComponentResolver = class {
376
401
  return;
377
402
  }
378
403
  this.coldInFlight.add(flightKey);
404
+ const versionBefore = this.kindVersions.get(kind) ?? 0;
379
405
  void (async () => {
380
406
  try {
381
407
  this.ingestColdRows(await loadForKind(kind, platform));
@@ -391,6 +417,9 @@ var ComponentResolver = class {
391
417
  });
392
418
  } finally {
393
419
  this.coldInFlight.delete(flightKey);
420
+ if ((this.kindVersions.get(kind) ?? 0) === versionBefore) {
421
+ this.bumpKind(kind);
422
+ }
394
423
  }
395
424
  })();
396
425
  }
@@ -432,7 +461,7 @@ var ComponentResolver = class {
432
461
  if (!this.warmPromise) {
433
462
  this.warmPromise = loadAll().then((rows) => {
434
463
  this.ingestDbRows(rows);
435
- this.settled = true;
464
+ this.markSettled();
436
465
  this.warmFailures = 0;
437
466
  if (this.warmRetryTimer) {
438
467
  clearTimeout(this.warmRetryTimer);
@@ -450,7 +479,7 @@ var ComponentResolver = class {
450
479
  this.warmFailures += 1;
451
480
  const delay = WARM_RETRY_DELAYS_MS[this.warmFailures - 1] ?? null;
452
481
  if (delay === null) {
453
- this.settled = true;
482
+ this.markSettled();
454
483
  } else if (!this.warmRetryTimer) {
455
484
  this.warmRetryTimer = setTimeout(() => {
456
485
  this.warmRetryTimer = null;