Deep Linking
Send a user to a view inside a devframe (from another dock, a coding agent, or a copied URL) two ways: the hub relays a dock activation to focus a dock in place; a standalone SPA reads its URL hash to restore the view.
Focusing a dock inside a hub
The active dock is state local to the host page. A mounted devframe, in its own iframe and RPC client, reaches it via the hub: hub:docks:activate switches the active dock, carrying an opaque params bag the target reads:
await rpc.call('hub:docks:activate', {
dockId: 'devframes:plugin:data-inspector',
params: { sourceId: 'my-plugin:store' },
})The hub broadcasts the request and mirrors it into the devframe:docks:active slot, so a dock mounting because of the switch converges on it. The target subscribes, filters on its dockId, and reads params; see Cross-iframe dock activation.
Focus is one-shot: the terminals dock reads params.sessionId, the Data Inspector params.sourceId; a target naming something unregistered waits, then fires once. An id that never arrives is a no-op; an unknown dockId warns (DF8107).
Standalone URL deep links
Standalone, a devframe SPA owns its own URL. Encode the shareable view in the hash (#…): it round-trips a copied link, survives reload, and stays clear of the handshake query string (?devframe_auth_token=). Parse with URLSearchParams:
// read on load
const params = new URLSearchParams(location.hash.replace(/^#/, ''))
const sourceId = params.get('source')
// write back, without stacking history entries
history.replaceState(history.state, '', `#${params.toString()}`)
// react to back/forward and manual edits
window.addEventListener('hashchange', applyState)The terminals dock keys a selection as #id=<sessionId>; the Data Inspector encodes its workbench (#source=…&query=… plus filter/auto-rerun flags). replaceState writes never fire hashchange, so boot read, live listener, and write-back don't loop.
Keep credentials out of anything shareable: a handshake token belongs in the query string, scrubbed once read (as the Data Inspector does), never in a copyable hash.
Cross-Devframe Services
ctx.services lets one devframe expose a typed, namespaced capability visible to every devframe. Two tiers: in-process services (provide/get) share live objects between devframes; wire services also register RPC and advertise to RPC clients.
Build Your Own JSON-Render Frontend
@devframes/json-render-ui is the reference frontend, not the protocol; any implementation of the renderer contract replaces it. The Next hub witness ships a React one at src/client/json-render/.