Found while working #6170 (PR #6352); out of that card's scope, filed unassigned.
The fact
packages/plugin-timeline calls ComponentRegistry.register with the key 'timeline' twice:
| site |
component |
namespace |
src/renderer.tsx:498 |
TimelineRenderer (presentational) |
plugin-timeline |
src/index.tsx:366 |
ObjectTimelineRenderer (object-bound) |
view |
Both are namespaced, neither passes skipFallback, so each also claims the bare timeline key (Registry.ts:246-266).
index.tsx:300 is export * from './renderer';, which is requested before the import at line 307, so renderer.tsx evaluates first and claims bare timeline → TimelineRenderer. The call at index.tsx:366 then overwrites it. So a node authored type: 'timeline' resolves to ObjectTimelineRenderer, which delegates inward to TimelineRenderer (ObjectTimeline.tsx:443).
Why it is worth a card
The outcome is probably intended — the object-bound wrapper is the right entry point, and it does reach the presentational renderer. What is not fine is how it is decided: by the order two module requests happen to appear in one file. Reorder those two lines and type: 'timeline' silently becomes the presentational renderer, which reads none of the object-bound keys — an authored timeline would stop fetching, with no error.
Registry.register carries a collision guard for exactly this shape, whose message names the remedy:
Component "timeline" bare-name fallback is being overwritten by "view:timeline". If this is intentional keep going; otherwise register "view:timeline" with { skipFallback: true } so it doesn't claim the bare "timeline" key.
So the repo already believes this needs a deliberate answer. Either declare the intent (and pin it), or give the presentational registration skipFallback: true.
Worth checking whether other plugins have the same double-claim; the guard warns at runtime only, so nothing fails CI today.
Reproduce
grep -n "ComponentRegistry.register" packages/plugin-timeline/src/*.tsx
sed -n '296,310p' packages/plugin-timeline/src/index.tsx
sed -n '242,268p' packages/core/src/registry/Registry.ts
Refs: #6170, PR #6352. Related: #5106 (the doc-types gate never judges the namespace half of a registration row).
Found while working #6170 (PR #6352); out of that card's scope, filed unassigned.
The fact
packages/plugin-timelinecallsComponentRegistry.registerwith the key'timeline'twice:src/renderer.tsx:498TimelineRenderer(presentational)plugin-timelinesrc/index.tsx:366ObjectTimelineRenderer(object-bound)viewBoth are namespaced, neither passes
skipFallback, so each also claims the baretimelinekey (Registry.ts:246-266).index.tsx:300isexport * from './renderer';, which is requested before theimportat line 307, sorenderer.tsxevaluates first and claims baretimeline→TimelineRenderer. The call atindex.tsx:366then overwrites it. So a node authoredtype: 'timeline'resolves toObjectTimelineRenderer, which delegates inward toTimelineRenderer(ObjectTimeline.tsx:443).Why it is worth a card
The outcome is probably intended — the object-bound wrapper is the right entry point, and it does reach the presentational renderer. What is not fine is how it is decided: by the order two module requests happen to appear in one file. Reorder those two lines and
type: 'timeline'silently becomes the presentational renderer, which reads none of the object-bound keys — an authored timeline would stop fetching, with no error.Registry.registercarries a collision guard for exactly this shape, whose message names the remedy:So the repo already believes this needs a deliberate answer. Either declare the intent (and pin it), or give the presentational registration
skipFallback: true.Worth checking whether other plugins have the same double-claim; the guard warns at runtime only, so nothing fails CI today.
Reproduce
Refs: #6170, PR #6352. Related: #5106 (the doc-types gate never judges the namespace half of a registration row).