Files
yawn/vendor/fxnode/docs/learn/tutorials/live-composition.md
T

2.0 KiB

Live composition

What you will build

An editor that replaces a version-1 node definition with version 2 and migrates its graph instance atomically.

Prerequisites and checkpoint

Understand composition. Start with the v1 node visible and retain the receipt's revision.

1. Acquire the v1 revision

import type { FxNode, FxNodeView } from "fxnode";

const v1Receipt = await api.composeNode("example.live.parameter", liveNodeV1);
let revision = v1Receipt.revision;

This is an excerpt: await socket dependencies first, compose v1, call setState, attach a view, add its instance through that view, attach the host, and render. Checkpoint: v1 is visible and revision came from its receipt—not a guessed constant.

2. Replace it using the v2 receipt

async function upgrade(root: FxNode, view: FxNodeView) {
  const v2Receipt = await root.composeNode("example.live.parameter", liveNodeV2, {
    expectedRevision: revision,
  });
  revision = v2Receipt.revision;
  await view.whenRendered();
  return v2Receipt;
}

Invoke this on an explicit host action. Checkpoint: inspect v2Receipt.status, graphChanged, graphVersion, and updated revision; the migrated v2 node is visible. Clean up the button/page listeners, host, and API on teardown.

Why?

Composition revision and graph version are separate concurrency domains. A committed rebind can advance both; a no-op advances neither. Compare-and-swap prevents two writers from assuming the same authority.

Complete example

See the working examples/live-composition/main.ts and its definitions.

Read graph state and events and CompositionReceipt, then plan lifecycle cleanup.