feat: pluginize charts/maps/canvas via registries + editor skew safety (0205) - #204
Merged
Conversation
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Convert the hardcoded ChartKind union + buildChartOption switch into a runtime registry mirroring WidgetRegistry/ViewRegistry. Built-in kinds (bar/line/area/pie) register lazily and import-order-safe; plugins can now contribute new kinds (gantt, scatter…) with no core change. resolveChartOption dispatches through the registry and renders a graceful fallback for unknown kinds (XChart shows a text fallback). ChartSpec.kind widened to an open string. Exploration 0205, Tier 2. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the hardcoded BASEMAP_PRESETS array as the source of truth with a runtime BasemapRegistry. Built-in basemaps (protomaps-light/dark/blank) register lazily; plugins can contribute new basemaps (satellite, topo, custom tilesets) with no core change. resolveBasemapStyle dispatches through the registry and falls back to the always-offline blank basemap for unknown ids; MapCanvas derives pmtiles-protocol registration from the definition; LayerPanel lists registry presets (reactive to plugin registrations). Exploration 0205, Tier 2. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extract the pure path geometry into shape-paths.ts and add a ShapeRegistry so the hardcoded ShapeType union + createShapePath switch becomes an extension seam. Built-in shapes register lazily; plugins can contribute new shapes (pentagon, cross…) with no core change. ShapeNodeComponent + ShapePicker render via resolveShapePath/shapeTypes (reactive to plugin registration, fallback to rectangle for unknown). createShapePath/SHAPE_TYPES re-exported for back-compat. Exploration 0205, Tier 2. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The editor is already a TipTap plugin architecture; the load-bearing line is schema (Node/Mark) vs behavior extensions. Add extension-tiers.ts: a drift-proof classifier (inspects TipTap's own extension.type), partitionExtensions (bundle schema statically, lazy-load behavior), schemaSkewRisks, and REQUIRED_SCHEMA_NODES. useEditorExtensions now warns in dev when a plugin contributes a schema-defining extension (silent Yjs content-loss vector across version skew). Exploration 0205, Tier 2 + skew-safety. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add editor-schema-safety: classify a plugin's editor contributions by whether their TipTap extension is a Node/Mark (persisted schema) vs behavior-only. The PluginRegistry now warns in dev when a contribution adds schema, since a node a collaborator lacks causes ProseMirror to silently drop content under Yjs collab. No editor dependency needed (classifies by extension.type). Exploration 0205, schema-skew guard. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Dogfood the chart-type registry: ChartsExtraPlugin registers donut + horizontal bar kinds into chartTypeRegistry on activation — proving a new chart type ships as a plugin with no core change. Both reuse echarts components XChart already loads (pie/bar), so the bundle doesn't grow. Catalogued in registry/first-party.json (drift-guarded) and added to BUNDLED_PLUGINS. Exploration 0205, Tier 3 (dogfood). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Author guide docs/guides/extend-with-registries.md (add a chart type / basemap / shape, the editor Yjs skew rule, the storage-adapter seam) and update the exploration's implementation/validation checklists to reflect what landed vs the deferred follow-ups. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the (string & {}) open-union idiom with (string & NonNullable<unknown>)
in charts/canvas/maps to clear @typescript-eslint/ban-types, and auto-fix
import/order in the editor hook + plugins files.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
|
✓ Changelog fragment found — thanks! |
#204) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
|
Preview removed for PR #204. |
Contributor
🖼️ UI changes in this PRInteractionsAuto-captured by CI · run. Informational — not a blocking check. |
crs48
added a commit
that referenced
this pull request
Jun 19, 2026
…205) ## Summary The public **/plugins** page (and the in-app marketplace) still showed only 3 plugins after [#204](#204), even though that PR added `fyi.xnet.charts-extra` to `registry/first-party.json`. **Root cause:** the site reads the committed flat index `registry/registry.json` (via `site/src/data/plugins.ts`), which is regenerated from `first-party.json` + `community.json` by `scripts/build-plugin-index.mjs`. The `Plugins Registry` workflow's `rebuild` job fired on the merge to main and produced the correct index — but its `git push` was **rejected by branch protection** (`GH013: Changes must be made through a pull request`; `github-actions[bot]` is not a ruleset bypass actor). So `registry.json` was never updated. This PR lands the regenerated index through a normal PR. ## Change - `registry/registry.json` — regenerated: **4 built-in + 0 community** (adds the Extra Charts entry). `node scripts/build-plugin-index.mjs --check` passes. `revoked.json` unchanged. After deploy, https://xnet.fyi/plugins/ will list 4 plugins (a new "visualization" category filter appears). ## Note on the systemic gap This will recur for every future `first-party.json` change: the auto-rebuild bot can't push to `main`. Fixing it properly means making the rebuild job's committer a ruleset **bypass actor** (the same fix applied to the changelog PR-stamping App in exploration 0203), or having the job open a PR instead of pushing. Out of scope here — flagged for follow-up. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Summary
Implements exploration 0205 — Decomposing the app into plugins. The thesis: pursue "as many plugins as is healthy, not as many as possible." This PR lands the safe, high-leverage slice — the Tier-2 registry seams (the cleanest answer to "can charts/canvas/maps be plugins?"), the editor schema/behavior tiering that makes "the editor as plugins" safe, a schema-skew guard, a dogfooded bundled plugin, and author docs — while explicitly not pluginizing the hot path (SQLite engine, Yjs sync loop, editor schema nodes).
Also includes the exploration document itself.
What changed
ChartTypeRegistry—ChartKindunion +buildChartOptionswitch → registry.resolveChartOptiondispatches; unknown kinds get a graceful fallback (XChart shows a text fallback).BasemapRegistry—BASEMAP_PRESETS→ registry.resolveBasemapStylefalls back to the offlineblankbasemap;LayerPanellists the registry.ShapeRegistry— extracted pureshape-paths.ts;ShapeTypeswitch → registry. Picker + node render viaresolveShapePath/shapeTypes(fallback to rectangle).extension-tiers.ts— drift-proof schema-vs-behavior classifier (reads TipTapextension.type),partitionExtensions,schemaSkewRisks,REQUIRED_SCHEMA_NODES. Dev warning when a plugin contributes a schema node/mark.editor-schema-safety.ts—PluginRegistrywarns in dev when a plugin's editor contribution adds persisted schema (silent Yjs content-loss vector across version skew).ChartsExtraPlugin— first-party dogfood registeringdonut+hbarviachartTypeRegistry, proving a new chart type ships as a plugin with no core change. Catalogued inregistry/first-party.json(drift-guarded).docs/guides/extend-with-registries.md(add a chart type / basemap / shape, the editor skew rule, the storage-adapter seam).All registries share one shape (mirroring the existing
WidgetRegistry/ViewRegistry): lazy, import-order-safe built-ins that re-populate afterclear(),Disposableunregister,onChangelisteners.Why this scope
Every system that succeeded at "almost everything is a plugin" (VS Code, Obsidian, Figma, Logseq) kept rendering, the editor model, and the data engine in a hardened core. This PR pluginizes at the registry/contribution seam and keeps:
Deferred follow-ups (documented in the exploration)
Pluggable top-level routes; re-shipping Tasks/Experiments as a
FeatureModule; canvas tool/layout registries; comment inspector contribution; the full all-peers-have-schema sync gate. These are genuinely multi-PR and higher risk.Testing
tsc --noEmitclean for charts, maps, canvas, editor, plugins, and apps/web (0 errors).eslintclean on all changed files;prettier --checkclean onpackages/**+apps/**.🤖 Generated with Claude Code