@ai-matrx/content-ir-react 0.4.0 → 0.5.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,26 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.1 — 2026-08-29
4
+
5
+ - **Body-less warm rows now complete through the canonical cold fetch.**
6
+ `requestComponent` treats a DB resolution with `hasComponentSource=true`
7
+ and `componentSource=null` as incomplete, fetches that kind once, replaces
8
+ the metadata shell with the heavy row, and bumps the per-kind repaint
9
+ version. Hosts no longer need resolver logic to make lazy component bodies
10
+ arrive.
11
+
12
+ ## 0.5.0 — 2026-08-29
13
+
14
+ - **`hasComponentSource` — the seam that lets component BODIES load lazily.**
15
+ `KindComponentRow` gains optional `hasComponentSource` (a host whose warm
16
+ list is body-less supplies it; omitted → derived from `componentSource`,
17
+ so eager hosts change nothing) and `ComponentResolution` carries it
18
+ computed. `routeToDbComponent` now gates on the FLAG, never on body
19
+ presence: a body-less row from a lazy warm list still routes to
20
+ `db_kind_component`, and the renderer fetches/compiles the body per kind
21
+ on demand. A row that truly has no body screams and falls through exactly
22
+ as before. Pinned by a new kind-route test.
23
+
3
24
  ## 0.4.0 — 2026-08-29
4
25
 
5
26
  - **NO EXCEPTIONS for a root `__kind` (Arman's ruling, 2026-08-29).** The
package/dist/index.cjs CHANGED
@@ -126,6 +126,7 @@ var ComponentResolver = class {
126
126
  resolvedBy: "db",
127
127
  componentSource: dbRow.componentSource,
128
128
  propsTransform: dbRow.propsTransform,
129
+ hasComponentSource: dbRow.hasComponentSource ?? Boolean(dbRow.componentSource && dbRow.componentSource.trim()),
129
130
  pinnedKindVersion: dbRow.pinnedKindVersion,
130
131
  updatedAt: dbRow.updatedAt,
131
132
  createdBy: dbRow.createdBy
@@ -142,6 +143,7 @@ var ComponentResolver = class {
142
143
  resolvedBy: "compiled",
143
144
  componentSource: null,
144
145
  propsTransform: null,
146
+ hasComponentSource: false,
145
147
  pinnedKindVersion: null,
146
148
  updatedAt: null,
147
149
  createdBy: null
@@ -219,6 +221,35 @@ var ComponentResolver = class {
219
221
  this.version += 1;
220
222
  for (const listener of this.listeners) listener();
221
223
  }
224
+ /**
225
+ * A warm metadata shell is resolved enough for routing, but not for the
226
+ * host's db-component renderer. Its body must still come from the cold
227
+ * single-kind loader.
228
+ */
229
+ needsColdFetch(kind, platform, role) {
230
+ const resolution = this.resolve(kind, platform, role);
231
+ return resolution === null || resolution.resolvedBy === "db" && resolution.hasComponentSource && resolution.componentSource === null;
232
+ }
233
+ /**
234
+ * Cold rows are the authoritative heavy form of warm metadata shells. Keep
235
+ * the same first-row-per-key winner contract, but replace an existing shell
236
+ * so `componentSource` / `propsTransform` can land and repaint the kind.
237
+ */
238
+ ingestColdRows(rows) {
239
+ const winners = /* @__PURE__ */ new Map();
240
+ for (const row of rows) {
241
+ const key = keyOf(row.kind, row.platform, row.role);
242
+ if (!winners.has(key)) winners.set(key, row);
243
+ }
244
+ if (winners.size === 0) return;
245
+ const changedKinds = /* @__PURE__ */ new Set();
246
+ for (const [key, row] of winners) {
247
+ this.db.set(key, row);
248
+ changedKinds.add(row.kind);
249
+ }
250
+ for (const kind of changedKinds) this.bumpKind(kind);
251
+ this.notifyChanged();
252
+ }
222
253
  /**
223
254
  * The eager lightweight single-kind fetch (streaming path): the moment a
224
255
  * cloud kind is identified mid-stream, pull ONLY that kind's resolver rows
@@ -229,7 +260,7 @@ var ComponentResolver = class {
229
260
  requestComponent(kind, platform, role) {
230
261
  const loadForKind = this.options.loadForKind;
231
262
  if (!loadForKind) return;
232
- if (this.resolve(kind, platform, role)) return;
263
+ if (!this.needsColdFetch(kind, platform, role)) return;
233
264
  const missKey = keyOf(kind, platform, role);
234
265
  const flightKey = `${kind}${KEY_SEPARATOR}${platform}`;
235
266
  if (this.coldInFlight.has(flightKey) || this.coldMisses.has(missKey)) {
@@ -238,8 +269,10 @@ var ComponentResolver = class {
238
269
  this.coldInFlight.add(flightKey);
239
270
  void (async () => {
240
271
  try {
241
- this.ingestDbRows(await loadForKind(kind, platform));
242
- if (!this.resolve(kind, platform, role)) this.coldMisses.add(missKey);
272
+ this.ingestColdRows(await loadForKind(kind, platform));
273
+ if (this.needsColdFetch(kind, platform, role)) {
274
+ this.coldMisses.add(missKey);
275
+ }
243
276
  } catch (error) {
244
277
  this.reportError({
245
278
  source: "content-ir",
@@ -328,7 +361,7 @@ function resetSourcelessDbRowReports() {
328
361
  }
329
362
  function routeToDbComponent(block, kind, resolution, env) {
330
363
  if (!isDbSourceResolution(resolution)) return null;
331
- if (!resolution.componentSource || !resolution.componentSource.trim()) {
364
+ if (!resolution.hasComponentSource) {
332
365
  reportDbRowWithoutSource(kind, env);
333
366
  return null;
334
367
  }