Skip to content

Give each tool one address derived at build time, and have core mint and release its bus handle - #422

Draft
CarsonDavis wants to merge 7 commits into
feature/414-bus-handlesfrom
feature/350-tool-identity-v2
Draft

Give each tool one address derived at build time, and have core mint and release its bus handle#422
CarsonDavis wants to merge 7 commits into
feature/414-bus-handlesfrom
feature/350-tool-identity-v2

Conversation

@CarsonDavis

@CarsonDavis CarsonDavis commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator
Category Lines added %
Tests 437 59.9%
Production code 253 34.7%
Docs 36 4.9%
Config 3 0.4%

A tool's bus address now comes from its binding at build time, and the core, not the tool, mints, injects and releases the tool's handle.

Closes #350

Two of the issue's acceptance items, closing a tool's popup on its own teardown and on full teardown, land in the popup service PR stacked on this one, which is the first subscriber to the teardown events this PR adds.

A tool's address is generated from its binding

Previously each modern tool invented its own bus id in its own source, and nothing caught two tools claiming the same id. The fix: the manifest generator derives the address from each binding (AOITool gives aoi, FetchStatsTool gives fetchstats) into the generated registry, the frontend derives it identically, and two bindings deriving the same address fail the build. A tool declares nothing. Demo mission: yes, every tool loads through it.

Core mints the handle, injects it, releases it, and announces teardown

Previously a tool called forPlugin() inside its own make(), so its registrations outlived it and any script could mint any plugin's handle by name. The fix: the modern tool controller mints the handle and sets tool.api before initialize(), releases it after destroy() and on a mid-load throw, then emits plugins:destroyed { pluginId: 'aoi' } per tool and one plugins:allDestroyed per teardown. window.mmgisAPI.forPlugin is gone; in the console it is undefined. Demo mission: yes, closing AOI or Chart exercises it.

What still resolves and what changed on the wire

Nothing inbound broke: panelTools: ["Title", "Card"] and plugins:show:AOITool still land, because every controller entry point resolves a display name, binding or address down to the address. Layer variable lookup now keys on the address with the lowercased display name as fallback, which is why fetch-stats used to silently miss its configured variables. The unused L_.hasTool helper is deleted with it. Outbound, FetchStats' address is fetchstats (was fetch-stats) so its events read plugin:fetchstats:analysisReady, tool cards carry data-tool="aoi" with ids ending -tool-aoi, and panels:getAll().toolIds and plugins:getAll() report addresses. Demo mission: yes, the AOI to FetchStats to Chart chain; variable lookup is covered by tests only.

Classic Layout Stuff

Classic tools get no handle

The classic layout minted a handle nothing consumed, so that mint is deleted. A classic FetchStats now completes an analysis and emits to nobody. Demo mission: no, the demo runs the modern layout.

React tools and the e2e block

React tools are unchanged: they call window.mmgisAPI directly through the shared adapter, so their requests carry no caller and LayerManager's unprefixed providers survive release. An e2e block that minted handles from the page was deleted; injection is covered by the unit specs.

Behaviour changes to note

  • Public bus names changed rather than being preserved. plugin:fetch-stats:* became plugin:fetchstats:* and listing ids went from AOITool to aoi, with no alias, rather than picking addresses matching the already public strings. Inbound still takes the old names, outbound does not, so an out-of-tree subscriber to the old FetchStats events breaks silently.
  • Minting is core-only. forPlugin is off the public surface and mintHandle only reachable by importing the core module, which stops one plugin minting another's address. The cost: anything the modern controller does not load gets no scoped handle, meaning classic tools and external plugins until a bridge hands one across.
  • Release covers the injected handle only. Registrations React tools make straight on the global bus are not released, so load and unload still accumulates those; routing the shared adapter through the handle was the alternative. The teardown events have no in-tree subscriber yet; the popup PR that follows is their first.

Decisions to review

  • Three names resolve inbound, one goes out. The resolver takes display name, address or binding and passes unknown strings through, rather than resolving strictly by address. A display name colliding with another tool's address would misroute show, hide or unload, first match in config order winning.

…and release its bus handle

A tool's address comes from its binding name in the generated manifest, so there is nothing to declare and nothing to collide. The modern tool controller mints the tool's bus handle before its own code runs, injects it, releases it after destroy, and announces each teardown on the bus. The public accessor for minting a handle by name is gone, the classic controller's unused mint is deleted, and layer variable lookup keys on the address.
…ature/350-tool-identity-v2

# Conflicts:
#	docs/pages/APIs/JavaScript/Main/Event-Bus-API.md
#	src/essence/Tools/FetchStats/FetchStatsTool.js
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant