{"version":3,"file":"chunk-graph-builder.mjs","names":[],"sources":["../../src/node.ts","../../src/util.ts","../../src/graph.ts","../../src/node-matcher.ts","../../src/graph-builder.ts"],"sourcesContent":["//\n// Copyright 2023 DXOS.org\n//\n\nimport type * as Context from 'effect/Context';\nimport type * as Effect from 'effect/Effect';\n\nimport { type MakeOptional } from '@dxos/util';\n\n/**\n * Root node ID.\n */\nexport const RootId = 'root';\n\n/**\n * Root node type.\n */\nexport const RootType = 'org.dxos.type.graphRoot';\n\n/**\n * Action node type.\n */\nexport const ActionType = 'org.dxos.type.graphAction';\n\n/**\n * Action group node type.\n */\nexport const ActionGroupType = 'org.dxos.type.graphActionGroup';\n\n/**\n * Represents a node in the graph.\n */\n// TODO(wittjosiah): Use Effect Schema.\n// TODO(burdon): Rename GraphNode. Node is already in the global namespace.\nexport type Node<TData = any, TProperties extends Record<string, any> = Record<string, any>> = Readonly<{\n  /**\n   * Globally unique ID.\n   */\n  // TODO(burdon): Allow string array, which is concatenated.\n  id: string;\n\n  /**\n   * Typename of the data the node represents.\n   */\n  type: string;\n\n  /**\n   * Keys in of the properties which should be cached.\n   * If defined, the node will be included in the cache.\n   * If undefined, the node will not be included in the cache.\n   */\n  cacheable?: string[];\n\n  /**\n   * Properties of the node relevant to displaying the node.\n   */\n  properties: Readonly<TProperties>;\n\n  /**\n   * Data the node represents.\n   */\n  // TODO(burdon): Type system (e.g., minimally provide identifier string vs. TypedObject vs. Graph mixin type system)?\n  //  type field would prevent convoluted sniffing of object properties. And allow direct pass-through for ECHO TypedObjects.\n  data: TData;\n}>;\n\nexport type NodeFilter<TData = any, TProperties extends Record<string, any> = Record<string, any>> = (\n  node: Node<unknown, Record<string, any>>,\n  connectedNode: Node,\n) => node is Node<TData, TProperties>;\n\nexport type RelationDirection = 'outbound' | 'inbound';\n\nexport type Relation = Readonly<{\n  kind: string;\n  direction: RelationDirection;\n}>;\n\nexport type RelationInput = Relation | string;\n\nexport const relation = (kind: string, direction: RelationDirection = 'outbound'): Relation => ({ kind, direction });\n// TODO(wittjosiah): Consider moving these helpers out of the core API.\nexport const childRelation = (direction: RelationDirection = 'outbound'): Relation => relation('child', direction);\nexport const actionRelation = (direction: RelationDirection = 'outbound'): Relation => relation('action', direction);\n\nexport const isGraphNode = (data: unknown): data is Node =>\n  data && typeof data === 'object' && 'id' in data && 'properties' in data && data.properties\n    ? typeof data.properties === 'object' && 'data' in data\n    : false;\n\nexport type NodeArg<TData, TProperties extends Record<string, any> = Record<string, any>> = MakeOptional<\n  Node<TData, TProperties>,\n  'data' | 'properties' | 'cacheable'\n> & {\n  /** Will automatically add nodes with an edge from this node to each. */\n  nodes?: NodeArg<unknown>[];\n\n  /** Will automatically add actions with an edge from this node to each. An action child may itself\n   * be an action group (e.g. a toolbar dropdown group), so groups are accepted alongside actions. */\n  actions?: NodeArg<ActionData<any> | typeof actionGroupSymbol>[];\n\n  /** Will automatically add specified edges. */\n  edges?: [string, RelationInput][];\n};\n\n//\n// Actions\n//\n\nexport type InvokeProps = {\n  /** Node the invoked action is connected to. */\n  parent?: Node;\n\n  /** Path from root to the node in the current tree context. */\n  path?: string[];\n\n  caller?: string;\n\n  /** Input modifiers held during the gesture that triggered the action (e.g. shift-clicking a menu item). */\n  modifiers?: { shift?: boolean };\n};\n\n/**\n * Action data is an Effect-returning function.\n * The Effect is provided with captured context at execution time.\n */\nexport type ActionData<R = never> = (params?: InvokeProps) => Effect.Effect<any, Error, R>;\n\n/**\n * Context captured at extension creation time.\n * Automatically provided to action Effects at execution.\n */\nexport type ActionContext = Context.Context<any>;\n\nexport type Action<TProperties extends Record<string, any> = Record<string, any>> = Readonly<\n  Omit<Node<ActionData, TProperties>, 'properties'> & {\n    properties: Readonly<TProperties>;\n    /** Captured context from extension creation. Provided automatically at action execution. */\n    _actionContext?: ActionContext;\n  }\n>;\n\nexport const isAction = (data: unknown): data is Action =>\n  isGraphNode(data) ? typeof data.data === 'function' && data.type === ActionType : false;\n\nexport const actionGroupSymbol = Symbol('ActionGroup');\n\nexport type ActionGroup<TProperties extends Record<string, any> = Record<string, any>> = Readonly<\n  Omit<Node<typeof actionGroupSymbol, TProperties>, 'properties'> & {\n    properties: Readonly<TProperties>;\n  }\n>;\n\nexport const isActionGroup = (data: unknown): data is ActionGroup =>\n  isGraphNode(data) ? data.data === actionGroupSymbol && data.type === ActionGroupType : false;\n\nexport type ActionLike = Action | ActionGroup;\n\nexport const isActionLike = (data: unknown): data is Action | ActionGroup => isAction(data) || isActionGroup(data);\n\n/**\n * Tests whether a node's `disposition` property (a single string or an array, letting one node opt\n * into multiple surfaces at once) includes any of `key`. Every surface that routes nodes/actions by\n * disposition (toolbar, nav-tree list-item, sigil menu, …) should filter through this rather than\n * comparing `properties.disposition` directly, so a node can multi-target surfaces.\n */\nexport const hasDisposition = (node: Pick<Node, 'properties'>, key: string | string[]): boolean => {\n  const disposition = node.properties.disposition;\n  const dispositions = Array.isArray(disposition) ? disposition : disposition !== undefined ? [disposition] : [];\n  const keys = Array.isArray(key) ? key : [key];\n  return dispositions.some((candidate) => keys.includes(candidate));\n};\n\n//\n// Node Factories\n//\n\n/** Typed factory for constructing a NodeArg. Provides auto-complete and type validation. */\nexport const make = <TData = any, TProperties extends Record<string, any> = Record<string, any>>(\n  arg: NodeArg<TData, TProperties>,\n): NodeArg<TData, TProperties> => arg;\n\n/** Create an action node. Automatically sets `type: ActionType`. */\nexport const makeAction = <R = never>(\n  arg: Omit<NodeArg<ActionData<R>>, 'type' | 'nodes' | 'edges'>,\n): NodeArg<ActionData<R>> => ({\n  ...arg,\n  type: ActionType,\n});\n\n/** Create an action group node. Automatically sets `type` and `data`. */\nexport const makeActionGroup = (\n  arg: Omit<NodeArg<typeof actionGroupSymbol>, 'type' | 'data' | 'nodes' | 'edges'>,\n): NodeArg<typeof actionGroupSymbol> => ({\n  ...arg,\n  type: ActionGroupType,\n  data: actionGroupSymbol,\n});\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { invariant } from '@dxos/invariant';\n\nimport * as Node from './node';\n\n// PRIMARY separates top-level components (e.g., node ID from relation) in compound string keys used within the app-graph package.\nconst PRIMARY = '\\u0001';\n\n// SECONDARY separates sub-components within an encoded value (e.g., relation kind from direction) in the same context.\nconst SECONDARY = '\\u0002';\n\n// PATH separates segments in qualified node IDs (e.g., parent path from local segment).\nconst PATH = '/';\n\n/** Join parts with the primary separator. */\nexport const primaryKey = (...parts: string[]): string => parts.join(PRIMARY);\n\n/** Split a key on the primary separator. */\nexport const primaryParts = (key: string): string[] => key.split(PRIMARY);\n\n/** Join parts with the secondary separator. */\nexport const secondaryKey = (...parts: string[]): string => parts.join(SECONDARY);\n\n/** Split a key on the secondary separator. */\nexport const secondaryParts = (key: string): string[] => key.split(SECONDARY);\n\n/**\n * Normalize a relation input to a full Relation object.\n */\nexport const normalizeRelation = (relation?: Node.RelationInput): Node.Relation =>\n  relation == null ? Node.childRelation() : typeof relation === 'string' ? Node.relation(relation) : relation;\n\n/**\n * Shallow-compare two values: same reference, or same own-keys with === values.\n */\nexport const shallowEqual = (a: unknown, b: unknown): boolean => {\n  if (a === b) {\n    return true;\n  }\n  if (a == null || b == null || typeof a !== 'object' || typeof b !== 'object') {\n    return false;\n  }\n  const keysA = Object.keys(a as Record<string, unknown>);\n  const keysB = Object.keys(b as Record<string, unknown>);\n  if (keysA.length !== keysB.length) {\n    return false;\n  }\n  return keysA.every((k) => (a as Record<string, unknown>)[k] === (b as Record<string, unknown>)[k]);\n};\n\n/**\n * Returns true if two NodeArg arrays are semantically identical (same id, type, data, properties per index).\n * Inline child nodes (the `nodes` field) are compared recursively.\n */\nexport const nodeArgsUnchanged = (prev: Node.NodeArg<any>[], next: Node.NodeArg<any>[]): boolean => {\n  if (prev.length !== next.length) {\n    return false;\n  }\n\n  return prev.every((prevNode, idx) => {\n    const nextNode = next[idx];\n    return (\n      prevNode.id === nextNode.id &&\n      prevNode.type === nextNode.type &&\n      shallowEqual(prevNode.data, nextNode.data) &&\n      shallowEqual(prevNode.properties, nextNode.properties) &&\n      nodeArgsUnchanged(prevNode.nodes ?? [], nextNode.nodes ?? []) &&\n      nodeArgsUnchanged(prevNode.actions ?? [], nextNode.actions ?? [])\n    );\n  });\n};\n\n/**\n * Build a qualified node ID by joining path segments.\n */\nexport const qualifyId = (parentId: string, ...segmentIds: string[]): string => [parentId, ...segmentIds].join(PATH);\n\n/**\n * Validate that a segment ID does not contain the path separator.\n */\nexport const validateSegmentId = (id: string): void => {\n  invariant(!id.includes(PATH), `Node segment ID must not contain '${PATH}': ${id}`);\n};\n\n/**\n * Extract the parent qualified ID (everything before the last path separator).\n * Returns undefined for IDs with no parent (single segment).\n */\nexport const getParentId = (qualifiedId: string): string | undefined => {\n  const lastSlash = qualifiedId.lastIndexOf(PATH);\n  return lastSlash > 0 ? qualifiedId.slice(0, lastSlash) : undefined;\n};\n\n/**\n * Extract the last segment of a qualified ID.\n */\nexport const getSegmentId = (qualifiedId: string): string => {\n  return qualifiedId.split(PATH).pop() ?? qualifiedId;\n};\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport { Atom, Registry } from '@effect-atom/atom';\nimport * as Function from 'effect/Function';\nimport * as Option from 'effect/Option';\nimport * as Pipeable from 'effect/Pipeable';\n\nimport { Event, Trigger } from '@dxos/async';\nimport { todo } from '@dxos/debug';\nimport { invariant } from '@dxos/invariant';\nimport { log } from '@dxos/log';\nimport { type MakeOptional, isNonNullable } from '@dxos/util';\n\nimport * as Node from './node';\nimport { normalizeRelation, primaryKey, primaryParts, secondaryKey, secondaryParts, shallowEqual } from './util';\n\nconst graphSymbol = Symbol('graph');\n\ntype DeepWriteable<T> = {\n  -readonly [K in keyof T]: T[K] extends object ? DeepWriteable<T[K]> : T[K];\n};\n\ntype NodeInternal = DeepWriteable<Node.Node> & { [graphSymbol]: GraphImpl };\n\n/**\n * Get the Graph a Node is currently associated with.\n */\nexport const getGraph = (node: Node.Node): Graph => {\n  const graph = (node as NodeInternal)[graphSymbol];\n  invariant(graph, 'Node is not associated with a graph.');\n  return graph as Graph;\n};\n\nexport type GraphTraversalOptions = {\n  /**\n   * A callback which is called for each node visited during traversal.\n   *\n   * If the callback returns `false`, traversal is stops recursing.\n   */\n  visitor: (node: Node.Node, path: string[]) => boolean | void;\n\n  /**\n   * The node to start traversing from.\n   *\n   * @default ROOT_ID\n   */\n  source?: string;\n\n  /** The relation(s) to traverse graph edges. */\n  relation: Node.RelationInput | Node.RelationInput[];\n};\n\nexport type GraphProps = {\n  registry?: Registry.Registry;\n  nodes?: MakeOptional<Node.Node, 'data' | 'cacheable'>[];\n  edges?: Record<string, Edges>;\n  onExpand?: (id: string, relation: Node.Relation) => void;\n  onInitialize?: (id: string) => Promise<void>;\n  onRemoveNode?: (id: string) => void;\n};\n\nexport type Edge = { source: string; target: string; relation: Node.RelationInput };\nexport type Edges = Record<string, string[]>;\n\n/**\n * Identifier denoting a Graph.\n */\nexport const GraphTypeId: unique symbol = Symbol.for('@dxos/app-graph/Graph');\nexport type GraphTypeId = typeof GraphTypeId;\n\n/**\n * Identifier for the graph kind discriminator.\n */\nexport const GraphKind: unique symbol = Symbol.for('@dxos/app-graph/GraphKind');\nexport type GraphKind = typeof GraphKind;\n\nexport type GraphKindType = 'readable' | 'expandable' | 'writable';\n\nexport interface BaseGraph extends Pipeable.Pipeable {\n  readonly [GraphTypeId]: GraphTypeId;\n  readonly [GraphKind]: GraphKindType;\n  /**\n   * Event emitted when a node is changed.\n   */\n  readonly onNodeChanged: Event<{ id: string; node: Option.Option<Node.Node> }>;\n  /**\n   * Get the atom key for the JSON representation of the graph.\n   */\n  json(id?: string): Atom.Atom<any>;\n  /**\n   * Get the atom key for the node with the given id.\n   */\n  node(id: string): Atom.Atom<Option.Option<Node.Node>>;\n  /**\n   * Get the atom key for the node with the given id.\n   */\n  nodeOrThrow(id: string): Atom.Atom<Node.Node>;\n  /**\n   * Get the atom key for the connections of the node with the given id.\n   */\n  connections(id: string, relation: Node.RelationInput): Atom.Atom<Node.Node[]>;\n  /**\n   * Get the atom key for the actions of the node with the given id.\n   */\n  actions(id: string): Atom.Atom<(Node.Action | Node.ActionGroup)[]>;\n  /**\n   * Get the atom key for the edges of the node with the given id.\n   */\n  edges(id: string): Atom.Atom<Edges>;\n}\n\nexport type ReadableGraph = BaseGraph & { readonly [GraphKind]: 'readable' | 'expandable' | 'writable' };\nexport type ExpandableGraph = BaseGraph & { readonly [GraphKind]: 'expandable' | 'writable' };\nexport type WritableGraph = BaseGraph & { readonly [GraphKind]: 'writable' };\n\n/**\n * Graph interface.\n */\nexport type Graph = WritableGraph;\n\n/**\n * The Graph represents the user interface information architecture of the application constructed via plugins.\n * @internal\n */\nclass GraphImpl implements WritableGraph {\n  readonly [GraphTypeId]: GraphTypeId = GraphTypeId;\n  readonly [GraphKind] = 'writable' as const;\n\n  pipe() {\n    // eslint-disable-next-line prefer-rest-params\n    return Pipeable.pipeArguments(this, arguments);\n  }\n\n  readonly onNodeChanged = new Event<{\n    id: string;\n    node: Option.Option<Node.Node>;\n  }>();\n\n  readonly _onExpand?: GraphProps['onExpand'];\n  readonly _onInitialize?: GraphProps['onInitialize'];\n  readonly _onRemoveNode?: GraphProps['onRemoveNode'];\n\n  readonly _registry: Registry.Registry;\n  readonly _expanded = new Set<string>();\n  readonly _pendingExpands = new Set<string>();\n  readonly _initialized = new Set<string>();\n  readonly _initialEdges = new Map<string, Edges>();\n  readonly _initialNodes = new Map<string, Option.Option<Node.Node>>([\n    [\n      Node.RootId,\n      this._constructNode({\n        id: Node.RootId,\n        type: Node.RootType,\n        data: null,\n        properties: {},\n      }),\n    ],\n  ]);\n\n  /** @internal */\n  readonly _node = Atom.family<string, Atom.Writable<Option.Option<Node.Node>>>((id) => {\n    const initial = this._initialNodes.get(id) ?? Option.none();\n    return Atom.make<Option.Option<Node.Node>>(initial).pipe(Atom.keepAlive, Atom.withLabel(`graph:node:${id}`));\n  });\n\n  readonly _nodeOrThrow = Atom.family<string, Atom.Atom<Node.Node>>((id) => {\n    return Atom.make((get) => {\n      const node = get(this._node(id));\n      invariant(Option.isSome(node), `Node not available: ${id}`);\n      return node.value;\n    });\n  });\n\n  readonly _edges = Atom.family<string, Atom.Writable<Edges>>((id) => {\n    const initial = this._initialEdges.get(id) ?? ({} as Edges);\n    return Atom.make<Edges>(initial).pipe(Atom.keepAlive, Atom.withLabel(`graph:edges:${id}`));\n  });\n\n  // NOTE: Currently the argument to the family needs to be referentially stable for the atom to be referentially stable.\n  // TODO(wittjosiah): Atom feature request, support for something akin to `ComplexMap` to allow for complex arguments.\n  readonly _connections = Atom.family<string, Atom.Atom<Node.Node[]>>((key) => {\n    return Atom.make((get) => {\n      const parts = key ? primaryParts(key) : [];\n      // Empty id (e.g. from `useConnections(graph, undefined, ...)`) yields a key like `\\u0001child\\u0002outbound`,\n      // which has 2 parts but an empty id — treat as no connections rather than throwing.\n      if (parts.length < 2 || !parts[0]) {\n        return [];\n      }\n      const { id, relation } = relationFromConnectionKey(key);\n      const edges = get(this._edges(id));\n      return (edges[relationKey(relation)] ?? [])\n        .map((id) => get(this._node(id)))\n        .filter(Option.isSome)\n        .map((o) => o.value);\n    }).pipe(Atom.withLabel(`graph:connections:${key}`));\n  });\n\n  readonly _actions = Atom.family<string, Atom.Atom<(Node.Action | Node.ActionGroup)[]>>((id) => {\n    return Atom.make((get) => {\n      if (!id) {\n        return [];\n      }\n      return get(this._connections(connectionKey(id, Node.actionRelation()))) as (Node.Action | Node.ActionGroup)[];\n    }).pipe(Atom.withLabel(`graph:actions:${id}`));\n  });\n\n  readonly _json = Atom.family<string, Atom.Atom<any>>((id) => {\n    return Atom.make((get) => {\n      const toJSON = (node: Node.Node, seen: string[] = []): any => {\n        const nodes = get(this._connections(connectionKey(node.id, 'child')));\n        const obj: Record<string, any> = {\n          id: node.id,\n          type: node.type,\n        };\n        if (node.properties.label) {\n          obj.label = node.properties.label;\n        }\n        if (nodes.length) {\n          obj.nodes = nodes\n            .map((n: Node.Node) => {\n              // Break cycles.\n              const nextSeen = [...seen, node.id];\n              return nextSeen.includes(n.id) ? undefined : toJSON(n, nextSeen);\n            })\n            .filter(isNonNullable);\n        }\n        return obj;\n      };\n\n      const root = get(this._nodeOrThrow(id));\n      return toJSON(root);\n    }).pipe(Atom.withLabel(`graph:json:${id}`));\n  });\n\n  constructor({ registry, nodes, edges, onInitialize, onExpand, onRemoveNode }: GraphProps = {}) {\n    this._registry = registry ?? Registry.make();\n    this._onInitialize = onInitialize;\n    this._onExpand = onExpand;\n    this._onRemoveNode = onRemoveNode;\n\n    if (nodes) {\n      nodes.forEach((node) => {\n        this._initialNodes.set(node.id, this._constructNode(node));\n      });\n    }\n\n    if (edges) {\n      Object.entries(edges).forEach(([source, edges]) => {\n        this._initialEdges.set(source, edges);\n      });\n    }\n  }\n\n  json(id = Node.RootId): Atom.Atom<any> {\n    return jsonImpl(this, id);\n  }\n\n  node(id: string): Atom.Atom<Option.Option<Node.Node>> {\n    return nodeImpl(this, id);\n  }\n\n  nodeOrThrow(id: string): Atom.Atom<Node.Node> {\n    return nodeOrThrowImpl(this, id);\n  }\n\n  connections(id: string, relation: Node.RelationInput): Atom.Atom<Node.Node[]> {\n    return connectionsImpl(this, id, relation);\n  }\n\n  actions(id: string): Atom.Atom<(Node.Action | Node.ActionGroup)[]> {\n    return actionsImpl(this, id);\n  }\n\n  edges(id: string): Atom.Atom<Edges> {\n    return edgesImpl(this, id);\n  }\n\n  /** @internal */\n  _constructNode(node: Node.NodeArg<any>): Option.Option<Node.Node> {\n    return Option.some({\n      [graphSymbol]: this,\n      data: null,\n      properties: {},\n      ...node,\n    });\n  }\n}\n\n/**\n * Internal helper to access GraphImpl internals.\n * @internal\n */\nconst getInternal = (graph: BaseGraph): GraphImpl => {\n  return graph as unknown as GraphImpl;\n};\n\n/**\n * Convert the graph to a JSON object.\n */\nexport const toJSON = (graph: BaseGraph, id = Node.RootId): object => {\n  const internal = getInternal(graph);\n  return internal._registry.get(internal._json(id));\n};\n\n/**\n * Implementation helper for json.\n */\nconst jsonImpl = (graph: BaseGraph, id = Node.RootId): Atom.Atom<any> => {\n  const internal = getInternal(graph);\n  return internal._json(id);\n};\n\n/**\n * Implementation helper for node.\n */\nconst nodeImpl = (graph: BaseGraph, id: string): Atom.Atom<Option.Option<Node.Node>> => {\n  const internal = getInternal(graph);\n  return internal._node(id);\n};\n\n/**\n * Implementation helper for nodeOrThrow.\n */\nconst nodeOrThrowImpl = (graph: BaseGraph, id: string): Atom.Atom<Node.Node> => {\n  const internal = getInternal(graph);\n  return internal._nodeOrThrow(id);\n};\n\n/**\n * Implementation helper for connections.\n */\nconst connectionsImpl = (graph: BaseGraph, id: string, relation: Node.RelationInput): Atom.Atom<Node.Node[]> => {\n  const internal = getInternal(graph);\n  return internal._connections(connectionKey(id, relation));\n};\n\n/**\n * Implementation helper for actions.\n */\nconst actionsImpl = (graph: BaseGraph, id: string): Atom.Atom<(Node.Action | Node.ActionGroup)[]> => {\n  const internal = getInternal(graph);\n  return internal._actions(id);\n};\n\n/**\n * Implementation helper for edges.\n */\nconst edgesImpl = (graph: BaseGraph, id: string): Atom.Atom<Edges> => {\n  const internal = getInternal(graph);\n  return internal._edges(id);\n};\n\n/**\n * Implementation helper for getNode.\n */\nconst getNodeImpl = (graph: BaseGraph, id: string): Option.Option<Node.Node> => {\n  const internal = getInternal(graph);\n  return internal._registry.get(nodeImpl(graph, id));\n};\n\n/**\n * Get the node with the given id from the graph's registry.\n */\nexport function getNode(graph: BaseGraph, id: string): Option.Option<Node.Node>;\nexport function getNode(id: string): (graph: BaseGraph) => Option.Option<Node.Node>;\nexport function getNode(\n  graphOrId: BaseGraph | string,\n  id?: string,\n): Option.Option<Node.Node> | ((graph: BaseGraph) => Option.Option<Node.Node>) {\n  if (typeof graphOrId === 'string') {\n    // Curried: getNode(id)\n    const id = graphOrId;\n    return (graph: BaseGraph) => getNodeImpl(graph, id);\n  } else {\n    // Direct: getNode(graph, id)\n    const graph = graphOrId;\n    return getNodeImpl(graph, id!);\n  }\n}\n\n/**\n * Implementation helper for getNodeOrThrow.\n */\nconst getNodeOrThrowImpl = (graph: BaseGraph, id: string): Node.Node => {\n  const internal = getInternal(graph);\n  return internal._registry.get(nodeOrThrowImpl(graph, id));\n};\n\n/**\n * Get the node with the given id from the graph's registry.\n *\n * @throws If the node is Option.none().\n */\nexport function getNodeOrThrow(graph: BaseGraph, id: string): Node.Node;\nexport function getNodeOrThrow(id: string): (graph: BaseGraph) => Node.Node;\nexport function getNodeOrThrow(\n  graphOrId: BaseGraph | string,\n  id?: string,\n): Node.Node | ((graph: BaseGraph) => Node.Node) {\n  if (typeof graphOrId === 'string') {\n    // Curried: getNodeOrThrow(id)\n    const id = graphOrId;\n    return (graph: BaseGraph) => getNodeOrThrowImpl(graph, id);\n  } else {\n    // Direct: getNodeOrThrow(graph, id)\n    const graph = graphOrId;\n    return getNodeOrThrowImpl(graph, id!);\n  }\n}\n\n/**\n * Get the root node of the graph.\n * This is an alias for `getNodeOrThrow(graph, ROOT_ID)`.\n */\nexport function getRoot(graph: BaseGraph): Node.Node {\n  return getNodeOrThrowImpl(graph, Node.RootId);\n}\n\n/**\n * Implementation helper for getConnections.\n */\nconst getConnectionsImpl = (graph: BaseGraph, id: string, relation: Node.RelationInput): Node.Node[] => {\n  const internal = getInternal(graph);\n  return internal._registry.get(connectionsImpl(graph, id, relation));\n};\n\n/**\n * Get all nodes connected to the node with the given id by the given relation from the graph's registry.\n */\nexport function getConnections(graph: BaseGraph, id: string, relation: Node.RelationInput): Node.Node[];\nexport function getConnections(id: string, relation: Node.RelationInput): (graph: BaseGraph) => Node.Node[];\nexport function getConnections(\n  graphOrId: BaseGraph | string,\n  idOrRelation: string | Node.RelationInput,\n  relation?: Node.RelationInput,\n): Node.Node[] | ((graph: BaseGraph) => Node.Node[]) {\n  if (typeof graphOrId === 'string') {\n    // Curried: getConnections(id, relation)\n    const id = graphOrId;\n    const rel = idOrRelation as Node.RelationInput;\n    return (graph: BaseGraph) => getConnectionsImpl(graph, id, rel);\n  } else {\n    // Direct: getConnections(graph, id, relation)\n    const graph = graphOrId;\n    const id = idOrRelation as string;\n    invariant(relation !== undefined, 'Relation is required.');\n    const rel = relation;\n    return getConnectionsImpl(graph, id, rel);\n  }\n}\n\n/**\n * Implementation helper for getActions.\n */\nconst getActionsImpl = (graph: BaseGraph, id: string): Node.Node[] => {\n  const internal = getInternal(graph);\n  return internal._registry.get(actionsImpl(graph, id));\n};\n\n/**\n * Get all actions connected to the node with the given id from the graph's registry.\n */\nexport function getActions(graph: BaseGraph, id: string): Node.Node[];\nexport function getActions(id: string): (graph: BaseGraph) => Node.Node[];\nexport function getActions(\n  graphOrId: BaseGraph | string,\n  id?: string,\n): Node.Node[] | ((graph: BaseGraph) => Node.Node[]) {\n  if (typeof graphOrId === 'string') {\n    // Curried: getActions(id)\n    const id = graphOrId;\n    return (graph: BaseGraph) => getActionsImpl(graph, id);\n  } else {\n    // Direct: getActions(graph, id)\n    const graph = graphOrId;\n    return getActionsImpl(graph, id!);\n  }\n}\n\n/**\n * Implementation helper for getEdges.\n */\nconst getEdgesImpl = (graph: BaseGraph, id: string): Edges => {\n  const internal = getInternal(graph);\n  return internal._registry.get(edgesImpl(graph, id));\n};\n\n/**\n * Get the edges from the node with the given id from the graph's registry.\n */\nexport function getEdges(graph: BaseGraph, id: string): Edges;\nexport function getEdges(id: string): (graph: BaseGraph) => Edges;\nexport function getEdges(graphOrId: BaseGraph | string, id?: string): Edges | ((graph: BaseGraph) => Edges) {\n  if (typeof graphOrId === 'string') {\n    // Curried: getEdges(id)\n    const id = graphOrId;\n    return (graph: BaseGraph) => getEdgesImpl(graph, id);\n  } else {\n    // Direct: getEdges(graph, id)\n    const graph = graphOrId;\n    return getEdgesImpl(graph, id!);\n  }\n}\n\n/**\n * Recursive depth-first traversal of the graph.\n */\n/**\n * Implementation helper for traverse.\n */\nconst traverseImpl = (graph: BaseGraph, options: GraphTraversalOptions, path: string[] = []): void => {\n  const { visitor, source = Node.RootId, relation } = options;\n  // Break cycles.\n  if (path.includes(source)) {\n    return;\n  }\n\n  const node = getNodeOrThrow(graph, source);\n  const shouldContinue = visitor(node, [...path, source]);\n  if (shouldContinue === false) {\n    return;\n  }\n\n  const relations = Array.isArray(relation) ? relation : [relation];\n  const seen = new Set<string>();\n  for (const rel of relations) {\n    for (const connected of getConnections(graph, source, rel)) {\n      if (!seen.has(connected.id)) {\n        seen.add(connected.id);\n        traverseImpl(graph, { source: connected.id, relation, visitor }, [...path, source]);\n      }\n    }\n  }\n};\n\n/**\n * Traverse the graph with the given options.\n */\nexport function traverse(graph: BaseGraph, options: GraphTraversalOptions, path?: string[]): void;\nexport function traverse(options: GraphTraversalOptions, path?: string[]): (graph: BaseGraph) => void;\nexport function traverse(\n  graphOrOptions: BaseGraph | GraphTraversalOptions,\n  optionsOrPath?: GraphTraversalOptions | string[],\n  path?: string[],\n): void | ((graph: BaseGraph) => void) {\n  if (typeof graphOrOptions === 'object' && 'visitor' in graphOrOptions) {\n    // Curried: traverse(options, path?)\n    const options = graphOrOptions as GraphTraversalOptions;\n    const pathArg = Array.isArray(optionsOrPath) ? optionsOrPath : undefined;\n    return (graph: BaseGraph) => traverseImpl(graph, options, pathArg);\n  } else {\n    // Direct: traverse(graph, options, path?)\n    const graph = graphOrOptions as BaseGraph;\n    const options = optionsOrPath as GraphTraversalOptions;\n    const pathArg = path ?? (Array.isArray(optionsOrPath) ? optionsOrPath : undefined);\n    return traverseImpl(graph, options, pathArg);\n  }\n}\n\n/**\n * Implementation helper for getPath.\n */\nconst getPathImpl = (graph: BaseGraph, params: { source?: string; target: string }): Option.Option<string[]> => {\n  return Function.pipe(\n    getNode(graph, params.source ?? 'root'),\n    Option.flatMap((node) => {\n      let found: Option.Option<string[]> = Option.none();\n      traverseImpl(graph, {\n        source: node.id,\n        relation: 'child',\n        visitor: (node, path) => {\n          if (Option.isSome(found)) {\n            return false;\n          }\n\n          if (node.id === params.target) {\n            found = Option.some(path);\n          }\n        },\n      });\n\n      return found;\n    }),\n  );\n};\n\n/**\n * Get the path between two nodes in the graph.\n */\nexport function getPath(graph: BaseGraph, params: { source?: string; target: string }): Option.Option<string[]>;\nexport function getPath(params: { source?: string; target: string }): (graph: BaseGraph) => Option.Option<string[]>;\nexport function getPath(\n  graphOrParams: BaseGraph | { source?: string; target: string },\n  params?: { source?: string; target: string },\n): Option.Option<string[]> | ((graph: BaseGraph) => Option.Option<string[]>) {\n  if (params === undefined && typeof graphOrParams === 'object' && 'target' in graphOrParams) {\n    // Curried: getPath(params)\n    const params = graphOrParams as { source?: string; target: string };\n    return (graph: BaseGraph) => getPathImpl(graph, params);\n  } else {\n    // Direct: getPath(graph, params)\n    const graph = graphOrParams as BaseGraph;\n    return getPathImpl(graph, params!);\n  }\n}\n\n/**\n * Implementation helper for waitForPath.\n */\nconst waitForPathImpl = (\n  graph: BaseGraph,\n  params: { source?: string; target: string },\n  options?: { timeout?: number; interval?: number },\n): Promise<string[]> => {\n  const { timeout = 5_000, interval = 500 } = options ?? {};\n  const path = getPathImpl(graph, params);\n  if (Option.isSome(path)) {\n    return Promise.resolve(path.value);\n  }\n\n  const trigger = new Trigger<string[]>();\n  const i = setInterval(() => {\n    const path = getPathImpl(graph, params);\n    if (Option.isSome(path)) {\n      trigger.wake(path.value);\n    }\n  }, interval);\n\n  return trigger.wait({ timeout }).finally(() => clearInterval(i));\n};\n\n/**\n * Wait for the path between two nodes in the graph to be established.\n */\nexport function waitForPath(\n  graph: BaseGraph,\n  params: { source?: string; target: string },\n  options?: { timeout?: number; interval?: number },\n): Promise<string[]>;\nexport function waitForPath(\n  params: { source?: string; target: string },\n  options?: { timeout?: number; interval?: number },\n): (graph: BaseGraph) => Promise<string[]>;\nexport function waitForPath(\n  graphOrParams: BaseGraph | { source?: string; target: string },\n  paramsOrOptions?: { source?: string; target: string } | { timeout?: number; interval?: number },\n  options?: { timeout?: number; interval?: number },\n): Promise<string[]> | ((graph: BaseGraph) => Promise<string[]>) {\n  if (typeof graphOrParams === 'object' && 'target' in graphOrParams) {\n    // Curried: waitForPath(params, options?)\n    const params = graphOrParams as { source?: string; target: string };\n    const opts = typeof paramsOrOptions === 'object' && !('target' in paramsOrOptions) ? paramsOrOptions : undefined;\n    return (graph: BaseGraph) => waitForPathImpl(graph, params, opts);\n  } else {\n    // Direct: waitForPath(graph, params, options?)\n    const graph = graphOrParams as BaseGraph;\n    const params = paramsOrOptions as { source?: string; target: string };\n    return waitForPathImpl(graph, params, options);\n  }\n}\n\n/**\n * Implementation helper for initialize.\n */\nconst initializeImpl = async <T extends ExpandableGraph | WritableGraph>(graph: T, id: string): Promise<T> => {\n  const internal = getInternal(graph);\n  const initialized = internal._initialized.has(id);\n  log('initialize', { id, initialized });\n  if (!initialized) {\n    internal._initialized.add(id);\n    await internal._onInitialize?.(id);\n  }\n  return graph;\n};\n\n/**\n * Initialize a node in the graph.\n *\n * Fires the `onInitialize` callback to provide initial data for a node.\n *\n * TODO(wittjosiah): Remove? No graph-builder extension declares a `resolver`, so `onInitialize` has\n * nothing to run; callers expand the nodes they need explicitly.\n */\nexport function initialize<T extends ExpandableGraph | WritableGraph>(graph: T, id: string): Promise<T>;\nexport function initialize(id: string): <T extends ExpandableGraph | WritableGraph>(graph: T) => Promise<T>;\nexport function initialize<T extends ExpandableGraph | WritableGraph>(\n  graphOrId: T | string,\n  id?: string,\n): Promise<T> | (<T extends ExpandableGraph | WritableGraph>(graph: T) => Promise<T>) {\n  if (typeof graphOrId === 'string') {\n    // Curried: initialize(id)\n    const id = graphOrId;\n    return <T extends ExpandableGraph | WritableGraph>(graph: T) => initializeImpl(graph, id);\n  } else {\n    // Direct: initialize(graph, id)\n    const graph = graphOrId;\n    return initializeImpl(graph, id!);\n  }\n}\n\n/**\n * Implementation helper for expand.\n * If the node does not exist yet, the expand is recorded as pending and applied when the node is added.\n */\nconst expandImpl = <T extends ExpandableGraph | WritableGraph>(\n  graph: T,\n  id: string,\n  relation: Node.RelationInput,\n): T => {\n  const internal = getInternal(graph);\n  const normalizedRelation = normalizeRelation(relation);\n  const key = primaryKey(id, relationKey(normalizedRelation));\n  const nodeOpt = internal._registry.get(internal._node(id));\n  if (Option.isNone(nodeOpt)) {\n    // Node not yet in graph: record expand to run when the node is added.\n    internal._pendingExpands.add(key);\n    log('expand', { key, deferred: true });\n    return graph;\n  }\n\n  const expanded = internal._expanded.has(key);\n  log('expand', { key, expanded });\n  if (!expanded) {\n    internal._expanded.add(key);\n    internal._onExpand?.(id, normalizedRelation);\n  }\n  return graph;\n};\n\n/**\n * Expand a node in the graph.\n *\n * Fires the `onExpand` callback to add connections to the node.\n */\nexport function expand<T extends ExpandableGraph | WritableGraph>(\n  graph: T,\n  id: string,\n  relation: Node.RelationInput,\n): T;\nexport function expand(\n  id: string,\n  relation: Node.RelationInput,\n): <T extends ExpandableGraph | WritableGraph>(graph: T) => T;\nexport function expand<T extends ExpandableGraph | WritableGraph>(\n  graphOrId: T | string,\n  idOrRelation: string | Node.RelationInput,\n  relation?: Node.RelationInput,\n): T | (<T extends ExpandableGraph | WritableGraph>(graph: T) => T) {\n  if (typeof graphOrId === 'string') {\n    // Curried: expand(id, relation)\n    const id = graphOrId;\n    const rel = idOrRelation as Node.RelationInput;\n    return <T extends ExpandableGraph | WritableGraph>(graph: T) => expandImpl(graph, id, rel);\n  } else {\n    // Direct: expand(graph, id, relation)\n    const graph = graphOrId;\n    const id = idOrRelation as string;\n    invariant(relation !== undefined, 'Relation is required.');\n    const rel = relation;\n    return expandImpl(graph, id, rel);\n  }\n}\n\n/**\n * Implementation helper for sortEdges.\n */\nconst sortEdgesImpl = <T extends ExpandableGraph | WritableGraph>(\n  graph: T,\n  id: string,\n  relation: Node.RelationInput,\n  order: string[],\n): T => {\n  const internal = getInternal(graph);\n  const edgesAtom = internal._edges(id);\n  const edges = internal._registry.get(edgesAtom);\n  const relationId = relationKey(relation);\n  const current = edges[relationId] ?? [];\n  const unsorted = current.filter((id) => !order.includes(id));\n  const sorted = order.filter((id) => current.includes(id));\n  const newOrder = [...sorted, ...unsorted];\n  if (newOrder.length === current.length && newOrder.every((id, i) => id === current[i])) {\n    return graph;\n  }\n  internal._registry.set(edgesAtom, {\n    ...edges,\n    [relationId]: newOrder,\n  });\n  return graph;\n};\n\n/**\n * Sort the edges of the node with the given id.\n */\nexport function sortEdges<T extends ExpandableGraph | WritableGraph>(\n  graph: T,\n  id: string,\n  relation: Node.RelationInput,\n  order: string[],\n): T;\nexport function sortEdges(\n  id: string,\n  relation: Node.RelationInput,\n  order: string[],\n): <T extends ExpandableGraph | WritableGraph>(graph: T) => T;\nexport function sortEdges<T extends ExpandableGraph | WritableGraph>(\n  graphOrId: T | string,\n  idOrRelation?: string | Node.RelationInput,\n  relationOrOrder?: Node.RelationInput | string[],\n  order?: string[],\n): T | (<T extends ExpandableGraph | WritableGraph>(graph: T) => T) {\n  if (typeof graphOrId === 'string') {\n    // Curried: sortEdges(id, relation, order)\n    const id = graphOrId;\n    const relation = idOrRelation as Node.RelationInput;\n    const order = relationOrOrder as string[];\n    return <T extends ExpandableGraph | WritableGraph>(graph: T) => sortEdgesImpl(graph, id, relation, order);\n  } else {\n    // Direct: sortEdges(graph, id, relation, order)\n    const graph = graphOrId;\n    const id = idOrRelation as string;\n    const relation = relationOrOrder as Node.RelationInput;\n    return sortEdgesImpl(graph, id, relation, order!);\n  }\n}\n\n/**\n * Implementation helper for addNodes.\n */\nconst addNodesImpl = <T extends WritableGraph>(graph: T, nodes: Node.NodeArg<any, Record<string, any>>[]): T => {\n  Atom.batch(() => {\n    nodes.map((node) => addNodeImpl(graph, node));\n  });\n  return graph;\n};\n\n/**\n * Add nodes to the graph.\n */\nexport function addNodes<T extends WritableGraph>(graph: T, nodes: Node.NodeArg<any, Record<string, any>>[]): T;\nexport function addNodes(nodes: Node.NodeArg<any, Record<string, any>>[]): <T extends WritableGraph>(graph: T) => T;\nexport function addNodes<T extends WritableGraph>(\n  graphOrNodes: T | Node.NodeArg<any, Record<string, any>>[],\n  nodes?: Node.NodeArg<any, Record<string, any>>[],\n): T | (<T extends WritableGraph>(graph: T) => T) {\n  if (nodes === undefined) {\n    // Curried: addNodes(nodes)\n    const nodes = graphOrNodes as Node.NodeArg<any, Record<string, any>>[];\n    return <T extends WritableGraph>(graph: T) => addNodesImpl(graph, nodes);\n  } else {\n    // Direct: addNodes(graph, nodes)\n    const graph = graphOrNodes as T;\n    return addNodesImpl(graph, nodes);\n  }\n}\n\n/**\n * Implementation helper for addNode.\n */\nconst addNodeImpl = <T extends WritableGraph>(graph: T, nodeArg: Node.NodeArg<any, Record<string, any>>): T => {\n  const internal = getInternal(graph);\n  // Extract known NodeArg fields, preserve any extra fields (like _actionContext) in rest.\n  const {\n    nodes,\n    actions,\n    edges,\n    id,\n    type,\n    data = null,\n    properties = {},\n    ...rest\n  } = nodeArg as Node.NodeArg<any> & {\n    _actionContext?: Node.ActionContext;\n  };\n  const nodeAtom = internal._node(id);\n  const existingNode = internal._registry.get(nodeAtom);\n  Option.match(existingNode, {\n    onSome: (existing) => {\n      const typeChanged = existing.type !== type;\n      const dataChanged = !shallowEqual(existing.data, data);\n      const propertiesChanged = Object.keys(properties).some((key) => existing.properties[key] !== properties[key]);\n      // `changed` is on the visit log because counting `existing node` lines alone measures how often a\n      // node was re-offered, not how often it actually changed — two very different costs.\n      const changed = typeChanged || dataChanged || propertiesChanged;\n      log('existing node', {\n        id,\n        changed,\n        typeChanged,\n        dataChanged,\n        propertiesChanged,\n      });\n      if (changed) {\n        log('updating node', { id, type, data, properties });\n        const newNode = Option.some({\n          ...existing,\n          ...rest,\n          type,\n          data,\n          properties: { ...existing.properties, ...properties },\n        });\n        internal._registry.set(nodeAtom, newNode);\n        graph.onNodeChanged.emit({ id, node: newNode });\n      }\n    },\n    onNone: () => {\n      log('new node', { id, type, data, properties });\n      const newNode = internal._constructNode({ id, type, data, properties, ...rest });\n      internal._registry.set(nodeAtom, newNode);\n      graph.onNodeChanged.emit({ id, node: newNode });\n\n      // Apply any expands that were deferred because this node did not exist yet.\n      const toApply = [...internal._pendingExpands].filter((k) => primaryParts(k)[0] === id);\n      for (const pendingKey of toApply) {\n        internal._pendingExpands.delete(pendingKey);\n        const relation = relationFromKey(primaryParts(pendingKey)[1]);\n        internal._expanded.add(pendingKey);\n        internal._onExpand?.(id, relation);\n      }\n    },\n  });\n\n  if (nodes) {\n    addNodesImpl(graph, nodes);\n    const _edges = nodes.map((node) => ({ source: id, target: node.id, relation: 'child' as const }));\n    addEdgesImpl(graph, _edges);\n    sortEdgesImpl(\n      graph,\n      id,\n      'child',\n      nodes.map((n) => n.id),\n    );\n  }\n\n  if (actions) {\n    addNodesImpl(graph, actions);\n    const actionRelation = Node.actionRelation();\n    const _edges = actions.map((node) => ({ source: id, target: node.id, relation: actionRelation }));\n    addEdgesImpl(graph, _edges);\n    sortEdgesImpl(\n      graph,\n      id,\n      actionRelation,\n      actions.map((node) => node.id),\n    );\n  }\n\n  if (edges) {\n    todo();\n  }\n  return graph;\n};\n\n/**\n * Add a node to the graph.\n */\nexport function addNode<T extends WritableGraph>(graph: T, nodeArg: Node.NodeArg<any, Record<string, any>>): T;\nexport function addNode(nodeArg: Node.NodeArg<any, Record<string, any>>): <T extends WritableGraph>(graph: T) => T;\nexport function addNode<T extends WritableGraph>(\n  graphOrNodeArg: T | Node.NodeArg<any, Record<string, any>>,\n  nodeArg?: Node.NodeArg<any, Record<string, any>>,\n): T | (<T extends WritableGraph>(graph: T) => T) {\n  if (nodeArg === undefined) {\n    // Curried: addNode(nodeArg)\n    const nodeArg = graphOrNodeArg as Node.NodeArg<any, Record<string, any>>;\n    return <T extends WritableGraph>(graph: T) => addNodeImpl(graph, nodeArg);\n  } else {\n    // Direct: addNode(graph, nodeArg)\n    const graph = graphOrNodeArg as T;\n    return addNodeImpl(graph, nodeArg);\n  }\n}\n\n/**\n * Implementation helper for removeNodes.\n */\nconst removeNodesImpl = <T extends WritableGraph>(graph: T, ids: string[], edges = false): T => {\n  Atom.batch(() => {\n    ids.map((id) => removeNodeImpl(graph, id, edges));\n  });\n  return graph;\n};\n\n/**\n * Remove nodes from the graph.\n */\nexport function removeNodes<T extends WritableGraph>(graph: T, ids: string[], edges?: boolean): T;\nexport function removeNodes(ids: string[], edges?: boolean): <T extends WritableGraph>(graph: T) => T;\nexport function removeNodes<T extends WritableGraph>(\n  graphOrIds: T | string[],\n  idsOrEdges?: string[] | boolean,\n  edges?: boolean,\n): T | (<T extends WritableGraph>(graph: T) => T) {\n  if (Array.isArray(graphOrIds)) {\n    // Curried: removeNodes(ids, edges?)\n    const ids = graphOrIds;\n    const edgesArg = typeof idsOrEdges === 'boolean' ? idsOrEdges : false;\n    return <T extends WritableGraph>(graph: T) => removeNodesImpl(graph, ids, edgesArg);\n  } else {\n    // Direct: removeNodes(graph, ids, edges?)\n    const graph = graphOrIds;\n    const ids = idsOrEdges as string[];\n    const edgesArg = edges ?? false;\n    return removeNodesImpl(graph, ids, edgesArg);\n  }\n}\n\n/**\n * Implementation helper for removeNode.\n */\nconst removeNodeImpl = <T extends WritableGraph>(graph: T, id: string, edges = false): T => {\n  const internal = getInternal(graph);\n  const nodeAtom = internal._node(id);\n  // TODO(wittjosiah): Is there a way to mark these atom values for garbage collection?\n  internal._registry.set(nodeAtom, Option.none());\n  graph.onNodeChanged.emit({ id, node: Option.none() });\n  // TODO(wittjosiah): Reset expanded and initialized flags?\n\n  if (edges) {\n    const nodeEdges = internal._registry.get(internal._edges(id));\n    const edgesToRemove: Edge[] = [];\n    for (const [relationKeyValue, relatedIds] of Object.entries(nodeEdges)) {\n      const relation = relationFromKey(relationKeyValue);\n      const isInboundRelation = relation.direction === 'inbound';\n      for (const relatedId of relatedIds) {\n        if (isInboundRelation) {\n          // Inbound edge lists store source node IDs; reconstruct the canonical outbound edge.\n          edgesToRemove.push({ source: relatedId, target: id, relation: inverseRelation(relation) });\n        } else {\n          edgesToRemove.push({ source: id, target: relatedId, relation });\n        }\n      }\n    }\n    removeEdgesImpl(graph, edgesToRemove);\n  }\n\n  internal._onRemoveNode?.(id);\n  return graph;\n};\n\n/**\n * Remove a node from the graph.\n */\nexport function removeNode<T extends WritableGraph>(graph: T, id: string, edges?: boolean): T;\nexport function removeNode(id: string, edges?: boolean): <T extends WritableGraph>(graph: T) => T;\nexport function removeNode<T extends WritableGraph>(\n  graphOrId: T | string,\n  idOrEdges?: string | boolean,\n  edges?: boolean,\n): T | (<T extends WritableGraph>(graph: T) => T) {\n  if (typeof graphOrId === 'string') {\n    // Curried: removeNode(id, edges?)\n    const id = graphOrId;\n    const edgesArg = typeof idOrEdges === 'boolean' ? idOrEdges : false;\n    return <T extends WritableGraph>(graph: T) => removeNodeImpl(graph, id, edgesArg);\n  } else {\n    // Direct: removeNode(graph, id, edges?)\n    const graph = graphOrId;\n    const id = idOrEdges as string;\n    const edgesArg = edges ?? false;\n    return removeNodeImpl(graph, id, edgesArg);\n  }\n}\n\n/**\n * Implementation helper for addEdges.\n */\nconst addEdgesImpl = <T extends WritableGraph>(graph: T, edges: Edge[]): T => {\n  Atom.batch(() => {\n    edges.map((edge) => addEdgeImpl(graph, edge));\n  });\n  return graph;\n};\n\n/**\n * Add edges to the graph.\n */\nexport function addEdges<T extends WritableGraph>(graph: T, edges: Edge[]): T;\nexport function addEdges(edges: Edge[]): <T extends WritableGraph>(graph: T) => T;\nexport function addEdges<T extends WritableGraph>(\n  graphOrEdges: T | Edge[],\n  edges?: Edge[],\n): T | (<T extends WritableGraph>(graph: T) => T) {\n  if (edges === undefined) {\n    // Curried: addEdges(edges)\n    const edges = graphOrEdges as Edge[];\n    return <T extends WritableGraph>(graph: T) => addEdgesImpl(graph, edges);\n  } else {\n    // Direct: addEdges(graph, edges)\n    const graph = graphOrEdges as T;\n    return addEdgesImpl(graph, edges);\n  }\n}\n\n/**\n * Implementation helper for addEdge.\n */\nconst addEdgeImpl = <T extends WritableGraph>(graph: T, edgeArg: Edge): T => {\n  const relation = normalizeRelation(edgeArg.relation);\n  const relationId = relationKey(relation);\n  const inverse = inverseRelation(relation);\n  const inverseId = relationKey(inverse);\n  const internal = getInternal(graph);\n\n  const sourceAtom = internal._edges(edgeArg.source);\n  const source = internal._registry.get(sourceAtom);\n  const sourceList = source[relationId] ?? [];\n  if (!sourceList.includes(edgeArg.target)) {\n    log('add edge', { source: edgeArg.source, target: edgeArg.target, relation: relationId });\n    internal._registry.set(sourceAtom, { ...source, [relationId]: [...sourceList, edgeArg.target] });\n  }\n\n  const targetAtom = internal._edges(edgeArg.target);\n  const target = internal._registry.get(targetAtom);\n  const targetList = target[inverseId] ?? [];\n  if (!targetList.includes(edgeArg.source)) {\n    log('add inverse edge', { source: edgeArg.source, target: edgeArg.target, relation: inverseId });\n    internal._registry.set(targetAtom, { ...target, [inverseId]: [...targetList, edgeArg.source] });\n  }\n\n  return graph;\n};\n\n/**\n * Add an edge to the graph.\n */\nexport function addEdge<T extends WritableGraph>(graph: T, edgeArg: Edge): T;\nexport function addEdge(edgeArg: Edge): <T extends WritableGraph>(graph: T) => T;\nexport function addEdge<T extends WritableGraph>(\n  graphOrEdgeArg: T | Edge,\n  edgeArg?: Edge,\n): T | (<T extends WritableGraph>(graph: T) => T) {\n  if (edgeArg === undefined) {\n    // Curried: addEdge(edgeArg)\n    const edgeArg = graphOrEdgeArg as Edge;\n    return <T extends WritableGraph>(graph: T) => addEdgeImpl(graph, edgeArg);\n  } else {\n    // Direct: addEdge(graph, edgeArg)\n    const graph = graphOrEdgeArg as T;\n    return addEdgeImpl(graph, edgeArg);\n  }\n}\n\n/**\n * Implementation helper for removeEdges.\n */\nconst removeEdgesImpl = <T extends WritableGraph>(graph: T, edges: Edge[], removeOrphans = false): T => {\n  Atom.batch(() => {\n    edges.map((edge) => removeEdgeImpl(graph, edge, removeOrphans));\n  });\n  return graph;\n};\n\n/**\n * Remove edges from the graph.\n */\nexport function removeEdges<T extends WritableGraph>(graph: T, edges: Edge[], removeOrphans?: boolean): T;\nexport function removeEdges(edges: Edge[], removeOrphans?: boolean): <T extends WritableGraph>(graph: T) => T;\nexport function removeEdges<T extends WritableGraph>(\n  graphOrEdges: T | Edge[],\n  edgesOrRemoveOrphans?: Edge[] | boolean,\n  removeOrphans?: boolean,\n): T | (<T extends WritableGraph>(graph: T) => T) {\n  if (Array.isArray(graphOrEdges)) {\n    // Curried: removeEdges(edges, removeOrphans?)\n    const edges = graphOrEdges;\n    const removeOrphansArg = typeof edgesOrRemoveOrphans === 'boolean' ? edgesOrRemoveOrphans : false;\n    return <T extends WritableGraph>(graph: T) => removeEdgesImpl(graph, edges, removeOrphansArg);\n  } else {\n    // Direct: removeEdges(graph, edges, removeOrphans?)\n    const graph = graphOrEdges;\n    const edges = edgesOrRemoveOrphans as Edge[];\n    const removeOrphansArg = removeOrphans ?? false;\n    return removeEdgesImpl(graph, edges, removeOrphansArg);\n  }\n}\n\n/**\n * Implementation helper for removeEdge.\n */\nconst removeEdgeImpl = <T extends WritableGraph>(graph: T, edgeArg: Edge, removeOrphans = false): T => {\n  const relation = normalizeRelation(edgeArg.relation);\n  const relationId = relationKey(relation);\n  const inverse = inverseRelation(relation);\n  const inverseId = relationKey(inverse);\n  const internal = getInternal(graph);\n\n  const sourceAtom = internal._edges(edgeArg.source);\n  const source = internal._registry.get(sourceAtom);\n  const sourceList = source[relationId] ?? [];\n  if (sourceList.includes(edgeArg.target)) {\n    internal._registry.set(sourceAtom, { ...source, [relationId]: sourceList.filter((id) => id !== edgeArg.target) });\n  }\n\n  const targetAtom = internal._edges(edgeArg.target);\n  const target = internal._registry.get(targetAtom);\n  const targetList = target[inverseId] ?? [];\n  if (targetList.includes(edgeArg.source)) {\n    internal._registry.set(targetAtom, { ...target, [inverseId]: targetList.filter((id) => id !== edgeArg.source) });\n  }\n\n  if (removeOrphans) {\n    const sourceAfter = internal._registry.get(sourceAtom);\n    const targetAfter = internal._registry.get(targetAtom);\n    const isEmpty = (edges: Edges) => Object.values(edges).every((ids) => ids.length === 0);\n    if (isEmpty(sourceAfter) && edgeArg.source !== Node.RootId) {\n      removeNodesImpl(graph, [edgeArg.source]);\n    }\n    if (isEmpty(targetAfter) && edgeArg.target !== Node.RootId) {\n      removeNodesImpl(graph, [edgeArg.target]);\n    }\n  }\n  return graph;\n};\n\n/**\n * Remove an edge from the graph.\n */\nexport function removeEdge<T extends WritableGraph>(graph: T, edgeArg: Edge, removeOrphans?: boolean): T;\nexport function removeEdge(edgeArg: Edge, removeOrphans?: boolean): <T extends WritableGraph>(graph: T) => T;\nexport function removeEdge<T extends WritableGraph>(\n  graphOrEdgeArg: T | Edge,\n  edgeArgOrRemoveOrphans?: Edge | boolean,\n  removeOrphans?: boolean,\n): T | (<T extends WritableGraph>(graph: T) => T) {\n  if (\n    edgeArgOrRemoveOrphans === undefined ||\n    typeof edgeArgOrRemoveOrphans === 'boolean' ||\n    'source' in graphOrEdgeArg\n  ) {\n    // Curried: removeEdge(edgeArg, removeOrphans?)\n    const edgeArg = graphOrEdgeArg as Edge;\n    const removeOrphansArg = typeof edgeArgOrRemoveOrphans === 'boolean' ? edgeArgOrRemoveOrphans : false;\n    return <T extends WritableGraph>(graph: T) => removeEdgeImpl(graph, edgeArg, removeOrphansArg);\n  } else {\n    // Direct: removeEdge(graph, edgeArg, removeOrphans?)\n    const graph = graphOrEdgeArg as T;\n    const edgeArg = edgeArgOrRemoveOrphans as Edge;\n    const removeOrphansArg = removeOrphans ?? false;\n    return removeEdgeImpl(graph, edgeArg, removeOrphansArg);\n  }\n}\n\n/**\n * Creates a new Graph instance.\n */\nexport const make = (params?: GraphProps): Graph => {\n  return new GraphImpl(params);\n};\n\n//\n// Utilities\n//\n\nexport const relationKey = (relation: Node.RelationInput): string => {\n  const normalized = normalizeRelation(relation);\n  return secondaryKey(normalized.kind, normalized.direction);\n};\n\nexport const relationFromKey = (encoded: string): Node.Relation => {\n  const parts = secondaryParts(encoded);\n  invariant(parts.length === 2 && parts[0].length > 0 && parts[1].length > 0, `Invalid relation key: ${encoded}`);\n  const [kind, directionRaw] = parts;\n  invariant(directionRaw === 'outbound' || directionRaw === 'inbound', `Invalid relation direction: ${directionRaw}`);\n  return Node.relation(kind, directionRaw);\n};\n\nconst connectionKey = (id: string, relation: Node.RelationInput): string => primaryKey(id, relationKey(relation));\n\nconst relationFromConnectionKey = (key: string): { id: string; relation: Node.Relation } => {\n  const [id, encodedRelation] = primaryParts(key);\n  invariant(id && encodedRelation, `Invalid connection key: ${key}`);\n  return { id, relation: relationFromKey(encodedRelation) };\n};\n\nconst inverseRelation = (relation: Node.RelationInput): Node.Relation => {\n  const normalized = normalizeRelation(relation);\n  return Node.relation(normalized.kind, normalized.direction === 'outbound' ? 'inbound' : 'outbound');\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { Atom } from '@effect-atom/atom';\nimport * as Option from 'effect/Option';\n\nimport { Entity, Obj, type Type } from '@dxos/echo';\n\nimport * as Node from './node';\n\n/**\n * Type for a node matcher function that returns an Option of the matched data.\n * Matchers are used to filter and transform nodes in the app graph.\n *\n * Matchers receive the reactive atom context (`get`) so a match decision can\n * depend on reactive state (e.g. an ECHO query for related objects). Reading an\n * atom via `get` subscribes the extension to it, so the match re-runs when that\n * state changes. Matchers that only inspect the node itself simply ignore `get`.\n *\n * @template TData - The type of data returned when the matcher succeeds.\n *   Defaults to Node.Node, but can be a more specific type (e.g., an ECHO entity).\n */\nexport type NodeMatcher<TData = Node.Node> = (node: Node.Node, get: Atom.Context) => Option.Option<TData>;\n\n//\n// Basic Node Matchers\n//\n\n/**\n * Matches the root node of the graph.\n *\n * @returns Option.some(node) if the node is the root, Option.none() otherwise.\n *\n * @example\n * ```ts\n * GraphBuilder.createExtension({\n *   id: 'myExtension',\n *   match: NodeMatcher.whenRoot,\n *   connector: (node) => Effect.succeed([...]),\n * });\n * ```\n */\nexport const whenRoot = (node: Node.Node): Option.Option<Node.Node> =>\n  node.id === Node.RootId ? Option.some(node) : Option.none();\n\n/**\n * Matches a node by its exact ID.\n *\n * @param id - The node ID to match against.\n * @returns A matcher that returns Option.some(node) if IDs match, Option.none() otherwise.\n *\n * @example\n * ```ts\n * GraphBuilder.createExtension({\n *   id: 'spacesExtension',\n *   match: NodeMatcher.whenId('spaces'),\n *   connector: (node) => Effect.succeed([...]),\n * });\n * ```\n */\nexport const whenId =\n  (id: string) =>\n  (node: Node.Node): Option.Option<Node.Node> =>\n    node.id === id ? Option.some(node) : Option.none();\n\n/**\n * Matches a node by its type string (the `node.type` property).\n *\n * @param type - The node type string to match against.\n * @returns A matcher that returns Option.some(node) if types match, Option.none() otherwise.\n *\n * @example\n * ```ts\n * GraphBuilder.createExtension({\n *   id: 'spaceSettingsExtension',\n *   match: NodeMatcher.whenNodeType('org.dxos.plugin.space.settings'),\n *   connector: (node) => Effect.succeed([...]),\n * });\n * ```\n */\nexport const whenNodeType =\n  (type: string) =>\n  (node: Node.Node): Option.Option<Node.Node> =>\n    node.type === type ? Option.some(node) : Option.none();\n\n//\n// ECHO Data Matchers\n//\n\n/**\n * Matches a node whose data is an instance of the given ECHO schema type.\n * Returns the **typed entity data** (not the node) for direct use in callbacks.\n *\n * Use this when you need to work directly with the typed ECHO entity in your\n * connector or actions callback.\n *\n * @template T - The ECHO schema type to match against.\n * @param type - The ECHO schema (e.g., `Collection.Collection`, `Document.Document`).\n * @returns A matcher that returns Option.some(entity) if the data matches, Option.none() otherwise.\n *\n * @example\n * ```ts\n * GraphBuilder.createExtension({\n *   id: 'collectionExtension',\n *   match: NodeMatcher.whenEchoType(Collection.Collection),\n *   connector: (collection) => {\n *     // `collection` is typed as Collection.Collection\n *     return Effect.succeed(collection.objects.map(...));\n *   },\n * });\n * ```\n *\n * Can be composed directly with {@link whenAll}/{@link whenAny}/{@link whenNot} while\n * preserving the typed entity data in the result.\n *\n * @see {@link whenEchoTypeMatches} - Returns the node instead of data for legacy composition.\n */\nexport const whenEchoType =\n  <T extends Type.AnyEntity>(type: T): NodeMatcher<Type.InstanceType<T>> =>\n  (node: Node.Node): Option.Option<Type.InstanceType<T>> =>\n    Entity.instanceOf(type, node.data) ? Option.some(node.data) : Option.none();\n\n/**\n * Matches a node whose data is any ECHO object.\n * Returns the **object data** (not the node) for direct use in callbacks.\n *\n * Use this when you need to work with any ECHO object regardless of its specific type.\n *\n * @returns Option.some(object) if the node's data is an ECHO object, Option.none() otherwise.\n *\n * @example\n * ```ts\n * GraphBuilder.createExtension({\n *   id: 'objectProperties',\n *   match: NodeMatcher.whenEchoObject,\n *   connector: (object) => {\n *     // `object` is typed as Obj.Unknown\n *     const id = Obj.getURI(object);\n *     return Effect.succeed([{ id: `${id}.settings`, ... }]);\n *   },\n * });\n * ```\n *\n * Can be composed directly with {@link whenAll}/{@link whenAny}/{@link whenNot} while\n * preserving the `Obj.Unknown` data type in the result.\n *\n * @see {@link whenEchoObjectMatches} - Returns the node instead of data for legacy composition.\n */\nexport const whenEchoObject = (node: Node.Node): Option.Option<Obj.Unknown> =>\n  Obj.isObject(node.data) ? Option.some(node.data) : Option.none();\n\n//\n// Composition Matchers\n//\n\n/**\n * Composes multiple matchers with AND logic - all matchers must match for success.\n * The result data type is the intersection of all matchers' data types.\n * Filter matchers like {@link whenNot} return `unknown`, making them transparent\n * in the intersection (since `T & unknown = T`).\n *\n * @param matchers - The matchers to combine. All must return Option.some for success.\n * @returns A matcher whose data type is the intersection of all input matchers' data types.\n *   Returns the first matcher's value when all match, Option.none() otherwise.\n *\n * @example\n * ```ts\n * // Match ECHO objects that are NOT Channels — result is NodeMatcher<Obj.Unknown>.\n * const whenCommentable = NodeMatcher.whenAll(\n *   NodeMatcher.whenEchoObject,\n *   NodeMatcher.whenNot(NodeMatcher.whenEchoTypeMatches(Channel.Channel)),\n * );\n * ```\n */\nexport const whenAll: {\n  <A>(a: NodeMatcher<A>, b: NodeMatcher<unknown>): NodeMatcher<A>;\n  <A>(a: NodeMatcher<unknown>, b: NodeMatcher<A>): NodeMatcher<A>;\n  <A, B>(a: NodeMatcher<A>, b: NodeMatcher<B>): NodeMatcher<A & B>;\n  <A, B, C>(a: NodeMatcher<A>, b: NodeMatcher<B>, c: NodeMatcher<C>): NodeMatcher<A & B & C>;\n  <A, B, C, D>(a: NodeMatcher<A>, b: NodeMatcher<B>, c: NodeMatcher<C>, d: NodeMatcher<D>): NodeMatcher<A & B & C & D>;\n  (...matchers: NodeMatcher<any>[]): NodeMatcher<any>;\n} =\n  (...matchers: NodeMatcher<any>[]): NodeMatcher<any> =>\n  (node: Node.Node, get: Atom.Context) => {\n    let first: Option.Option<any> = Option.none();\n    for (const candidate of matchers) {\n      const result = candidate(node, get);\n      if (Option.isNone(result)) {\n        return Option.none();\n      }\n      if (Option.isNone(first)) {\n        first = result;\n      }\n    }\n    return first;\n  };\n\n/**\n * Composes multiple matchers with OR logic - at least one matcher must match.\n * The result data type is the union of all matchers' data types.\n *\n * @param matchers - The matchers to combine. At least one must return Option.some.\n * @returns A matcher whose data type is the union of all input matchers' data types.\n *   Returns the first matching matcher's value, or Option.none() if none match.\n *\n * @example\n * ```ts\n * // Match nodes that are either Sequences or Routines\n * const whenInvocable = NodeMatcher.whenAny(\n *   NodeMatcher.whenEchoTypeMatches(Sequence),\n *   NodeMatcher.whenEchoTypeMatches(Routine.Routine),\n * );\n * ```\n */\nexport const whenAny: {\n  <A, B>(a: NodeMatcher<A>, b: NodeMatcher<B>): NodeMatcher<A | B>;\n  <A, B, C>(a: NodeMatcher<A>, b: NodeMatcher<B>, c: NodeMatcher<C>): NodeMatcher<A | B | C>;\n  <A, B, C, D>(a: NodeMatcher<A>, b: NodeMatcher<B>, c: NodeMatcher<C>, d: NodeMatcher<D>): NodeMatcher<A | B | C | D>;\n  (...matchers: NodeMatcher<any>[]): NodeMatcher<any>;\n} =\n  (...matchers: NodeMatcher<any>[]): NodeMatcher<any> =>\n  (node: Node.Node, get: Atom.Context) => {\n    for (const candidate of matchers) {\n      const result = candidate(node, get);\n      if (Option.isSome(result)) {\n        return result;\n      }\n    }\n    return Option.none();\n  };\n\n/**\n * Matches a node whose data is an instance of the given ECHO schema type.\n * Returns the **node** (not the data) to enable composition with whenAll/whenAny/whenNot.\n *\n * Use this instead of {@link whenEchoType} when you need to combine matchers.\n * The difference is what's returned:\n * - `whenEchoType` returns the typed entity (for direct use)\n * - `whenEchoTypeMatches` returns the node (for composition)\n *\n * @template T - The ECHO schema type to match against.\n * @param type - The ECHO schema (e.g., `Channel.Channel`, `Document.Document`).\n * @returns A matcher that returns Option.some(node) if the data matches, Option.none() otherwise.\n *\n * @example\n * ```ts\n * // Use with whenAny for OR logic\n * const whenPresentable = NodeMatcher.whenAny(\n *   NodeMatcher.whenEchoTypeMatches(Collection.Collection),\n *   NodeMatcher.whenEchoTypeMatches(Markdown.Document),\n * );\n *\n * // Use with whenNot for exclusion\n * const whenNotChannel = NodeMatcher.whenNot(\n *   NodeMatcher.whenEchoTypeMatches(Channel.Channel),\n * );\n * ```\n *\n * @see {@link whenEchoType} - Use instead when you need the typed entity directly.\n */\nexport const whenEchoTypeMatches =\n  <T extends Type.AnyObj | Type.AnyRelation>(type: T): NodeMatcher =>\n  (node: Node.Node): Option.Option<Node.Node> =>\n    Entity.instanceOf(type, node.data) ? Option.some(node) : Option.none();\n\n/**\n * Matches a node whose data is any ECHO object.\n * Returns the **node** (not the data) to enable composition with whenAll/whenAny/whenNot.\n *\n * Use this instead of {@link whenEchoObject} when you need to combine matchers.\n * The difference is what's returned:\n * - `whenEchoObject` returns the object data (for direct use)\n * - `whenEchoObjectMatches` returns the node (for composition)\n *\n * @returns Option.some(node) if the node's data is an ECHO object, Option.none() otherwise.\n *\n * @example\n * ```ts\n * // Match ECHO objects that are not system types\n * const whenUserObject = NodeMatcher.whenAll(\n *   NodeMatcher.whenEchoObjectMatches,\n *   NodeMatcher.whenNot(NodeMatcher.whenEchoTypeMatches(SystemType)),\n * );\n * ```\n *\n * @see {@link whenEchoObject} - Use instead when you need the object data directly.\n */\nexport const whenEchoObjectMatches = (node: Node.Node): Option.Option<Node.Node> =>\n  Obj.isObject(node.data) ? Option.some(node) : Option.none();\n\n/**\n * Negates a matcher - matches when the given matcher does NOT match.\n * Useful for exclusion patterns like \"any object EXCEPT type X\".\n *\n * Returns `NodeMatcher<unknown>` because negation is a filter — it doesn't provide\n * typed data. This makes it transparent in {@link whenAll} intersections\n * (since `T & unknown = T`).\n *\n * @param matcher - The matcher to negate.\n * @returns A matcher that returns Option.some(node) if the input matcher returns none,\n *   and Option.none() if the input matcher returns some.\n *\n * @example\n * ```ts\n * // Match any ECHO object that is NOT a Channel — result is NodeMatcher<Obj.Unknown>.\n * const whenCommentable = NodeMatcher.whenAll(\n *   NodeMatcher.whenEchoObject,\n *   NodeMatcher.whenNot(NodeMatcher.whenEchoTypeMatches(Channel.Channel)),\n * );\n *\n * // Match any node that is NOT the root\n * const whenNotRoot = NodeMatcher.whenNot(NodeMatcher.whenRoot);\n * ```\n */\nexport const whenNot =\n  (matcher: NodeMatcher<any>): NodeMatcher<unknown> =>\n  (node: Node.Node, get: Atom.Context): Option.Option<unknown> =>\n    Option.isNone(matcher(node, get)) ? Option.some(node) : Option.none();\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { Atom, Registry } from '@effect-atom/atom';\nimport * as Array from 'effect/Array';\nimport type * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport * as Function from 'effect/Function';\nimport * as Option from 'effect/Option';\nimport * as Pipeable from 'effect/Pipeable';\nimport * as Record from 'effect/Record';\n\nimport { type CleanupFn, type Trigger } from '@dxos/async';\nimport { type Type } from '@dxos/echo';\nimport { log } from '@dxos/log';\nimport { type MaybePromise, Position, getDebugName, isNonNullable } from '@dxos/util';\n\nimport { scheduleTask, yieldOrContinue } from '#scheduler';\n\nimport * as Graph from './graph';\nimport * as Node from './node';\nimport * as NodeMatcher from './node-matcher';\nimport {\n  getParentId,\n  nodeArgsUnchanged,\n  normalizeRelation,\n  primaryKey,\n  primaryParts,\n  qualifyId,\n  validateSegmentId,\n} from './util';\n\n//\n// Extension Types\n//\n\n/**\n * Graph builder extension for adding nodes to the graph based on a connection to an existing node.\n *\n * @param params.node The existing node the returned nodes will be connected to.\n */\nexport type ConnectorExtension = (node: Atom.Atom<Option.Option<Node.Node>>) => Atom.Atom<Node.NodeArg<any>[]>;\n\n/**\n * Constrained case of the connector extension for more easily adding actions to the graph.\n */\nexport type ActionsExtension = (\n  node: Atom.Atom<Option.Option<Node.Node>>,\n) => Atom.Atom<Omit<Node.NodeArg<Node.ActionData<any>>, 'type' | 'nodes' | 'edges'>[]>;\n\n/**\n * Constrained case of the connector extension for more easily adding action groups to the graph.\n */\nexport type ActionGroupsExtension = (\n  node: Atom.Atom<Option.Option<Node.Node>>,\n) => Atom.Atom<Omit<Node.NodeArg<typeof Node.actionGroupSymbol>, 'type' | 'data' | 'nodes' | 'edges'>[]>;\n\n/**\n * Graph builder extension for adding nodes to the graph based on a node id.\n *\n * TODO(wittjosiah): Remove? Superseded by the declared `url` binding — URL resolution no longer\n * materializes a node from a bare id. Retained alongside `Graph.initialize`, which fires it.\n */\nexport type ResolverExtension = (id: string) => Atom.Atom<Node.NodeArg<any> | null>;\n\nexport type BuilderExtension = Readonly<{\n  id: string;\n  position?: Position.Position;\n  relation?: Node.RelationInput;\n  /**\n   * URL binding for the nodes this extension's connector produces: the registered prefix key plus how\n   * it resolves. Omitted when the extension's nodes are not URL-addressable. See {@link UrlBinding} and\n   * `path-resolution.ts` for how the key table is derived and used.\n   */\n  url?: UrlBinding;\n  resolver?: ResolverExtension;\n  connector?: (node: Atom.Atom<Option.Option<Node.Node>>) => Atom.Atom<Node.NodeArg<any>[]>;\n}>;\n\n/**\n * How an extension's nodes map to (and from) the URL pair chain — one binding per extension, holding\n * the whole URL contract for the nodes it produces. The `kind` is the *resolution tier*: what a pair\n * with this key resolves against.\n *\n * - `'item'`      — Resolves against the current anchor (workspace) base, addressed by a variable id.\n *                   The default addressable node; may itself have children (e.g. a mailbox). (`doc/<id>`).\n * - `'singleton'` — Resolves against the current anchor base, but is a single fixed node per anchor, so\n *                   it carries no id — its terminal node-id segment is the key itself. (`settings`).\n *\n * The anchor and linked tiers are not declared per extension: they are fixed keys of the URL grammar,\n * configured once on the builder as {@link UrlGrammar}.\n *\n * `path` is how the node is located, in one of two forms:\n * - `string[]` — fixed ancestor node-id segments between the workspace base and the node (the common,\n *   deterministic case): the node is `${Node.RootId}/<workspace>/<...segments>/<id>`. Fixed-depth\n *   dynamic tails beyond the segments are `+`-encoded into the id.\n * - {@link PathResolver} — a dynamic resolver, for data-dependent shapes (e.g. nested collections at\n *   arbitrary depth) that cannot declare static segments.\n *\n * Read by `path-resolution.ts` (which derives the parse table's `hasId`/`anchor` from `kind`) and\n * consumed by `UrlPath.parse`.\n */\nexport type UrlBinding = { key: string; kind: 'item' | 'singleton'; path: string[] | PathResolver };\n\n/**\n * The URL grammar the builder resolves and stamps against, configured once at construction.\n *\n * The two keys are fixed tiers no extension declares (no connector produces their nodes): `anchorKey`\n * establishes the base that following pairs resolve against and is consumed as a rebase\n * (`w/<workspace>`); `linkedKey` addresses the linked-segment child of the preceding item\n * (`companion/<variant>`), resolved structurally. The separators are the id-encoding conventions:\n * `linkedPrefix` marks a linked segment (`<parent>/~<variant>`), and `tailSeparator` joins the\n * fixed-depth node-id segments between a key's static `path` and the object id into one URL id\n * (`db/<slug>+<id>`) so a fixed-depth nested shape needs no resolver.\n */\nexport type UrlGrammar = {\n  anchorKey?: string;\n  linkedKey?: string;\n  linkedPrefix: string;\n  tailSeparator: string;\n};\n\n/** {@link UrlGrammar} as supplied at construction: the separators fall back to their defaults. */\nexport type UrlGrammarProps = Partial<UrlGrammar>;\n\n/** Default linked-segment prefix; mirrors `@dxos/react-ui-attention`'s `linkedSegment`. Internal: read\n * the resolved value from `builder.urlGrammar` rather than the default. */\nconst DEFAULT_LINKED_PREFIX = '~';\n\n/** Default tail separator; never appears in an entity id or a type slug. Internal, as above. */\nconst DEFAULT_TAIL_SEPARATOR = '+';\n\n/** Params passed to a {@link PathResolver} for a single `(key, id)` URL pair. */\nexport type PathResolveParams = {\n  /** The id segment from the `(key, id)` pair. */\n  id: string;\n  /** The workspace segment from the URL. */\n  workspace: string;\n  /** Qualified id of the workspace base node (`${Node.RootId}/<workspace>`). */\n  workspaceBaseId: string;\n};\n\n/**\n * Dynamic forward URL resolver for an extension whose node-id shape is data-dependent and so cannot\n * declare a static {@link UrlBinding.path}. Returns the candidate qualified node id —\n * `path-resolution.ts` then materializes its ancestors and verifies it — or `null` if the id can't be\n * located. Must be self-contained (the declaring plugin closes over any services it needs), so\n * `@dxos/app-graph` stays free of service dependencies.\n */\nexport type PathResolver = (params: PathResolveParams) => Effect.Effect<string | null>;\n\nexport type BuilderExtensions = BuilderExtension | BuilderExtension[] | BuilderExtensions[];\n\n/**\n * The `(key, id?)` URL representation of a node under a given {@link UrlBinding} — the reverse of forward\n * resolution, minus the workspace (always the node id's second segment). A singleton has no id; a\n * resolver-backed key keeps just the object id; a static path encodes the segments between the path and\n * the id, `+`-joined (empty when the node sits at the path — a container whose children are the items).\n */\nexport const urlRepresentation = (\n  nodeId: string,\n  url: UrlBinding,\n  tailSeparator: string = DEFAULT_TAIL_SEPARATOR,\n): { key: string; id?: string } => {\n  // A singleton carries no path-based id: its terminal node-id segment is the key itself.\n  if (url.kind === 'singleton') {\n    return { key: url.key };\n  }\n  const segments = nodeId.split('/');\n  const id =\n    typeof url.path === 'function'\n      ? segments[segments.length - 1]\n      : segments.slice(2 + url.path.length).join(tailSeparator);\n  return { key: url.key, id };\n};\n\n/**\n * A node's own URL pair segment — `/<key>[/<id>]`, with no workspace/anchor prefix — or `undefined` when\n * the node is not addressable in its own right (a container node sitting at the binding's `path`, whose\n * children are the addressable items). A full URL is composed by prefixing `/w/<workspace>`.\n */\nexport const nodeUrlSegment = (\n  nodeId: string,\n  url: UrlBinding,\n  tailSeparator: string = DEFAULT_TAIL_SEPARATOR,\n): string | undefined => {\n  const { key, id } = urlRepresentation(nodeId, url, tailSeparator);\n  if (id === undefined) {\n    return `/${key}`; // singleton\n  }\n  return id === '' ? undefined : `/${key}/${id}`; // empty id: container at the path, not addressable\n};\n\n/**\n * A graph node with its computed {@link nodeUrlSegment} attached at `properties.urlSegment` when the node\n * is URL-addressable. The core {@link Node.Node} stays URL-agnostic; this is the typed view for reading\n * the segment — an open properties record with an explicit `urlSegment` field — mirroring how\n * `@dxos/react-ui-menu` wraps `Node` for menu items.\n */\nexport type BuilderNode<TData = any> = Node.Node<TData, { urlSegment?: string } & Record<string, any>>;\n\n/**\n * Return a copy of `node` (and its inline descendants) with `properties.urlSegment` stamped. A linked\n * node (id ending in a `~<variant>` segment) is stamped from the `linked` tier key, independent of its\n * producing extension's binding; any other node is stamped from `url` (its producer's binding), if any.\n */\nconst stampUrlSegment = (\n  node: Node.NodeArg<any>,\n  url: UrlBinding | undefined,\n  grammar: UrlGrammar,\n): Node.NodeArg<any> => {\n  const lastSegment = node.id.slice(node.id.lastIndexOf('/') + 1);\n  const segment = lastSegment.startsWith(grammar.linkedPrefix)\n    ? grammar.linkedKey && `/${grammar.linkedKey}/${lastSegment.slice(grammar.linkedPrefix.length)}`\n    : url && nodeUrlSegment(node.id, url, grammar.tailSeparator);\n  const nodes = node.nodes?.map((child) => stampUrlSegment(child, url, grammar));\n  if (!segment && !nodes) {\n    return node;\n  }\n  return {\n    ...node,\n    ...(segment && { properties: { ...node.properties, urlSegment: segment } }),\n    ...(nodes && { nodes }),\n  };\n};\n\n//\n// GraphBuilder Core\n//\n\nexport type GraphBuilderTraverseOptions = {\n  visitor: (node: Node.Node, path: string[]) => MaybePromise<boolean | void>;\n  registry?: Registry.Registry;\n  source?: string;\n  relation: Node.RelationInput | Node.RelationInput[];\n};\n\n/**\n * Identifier denoting a GraphBuilder.\n */\nexport const GraphBuilderTypeId: unique symbol = Symbol.for('@dxos/app-graph/GraphBuilder');\nexport type GraphBuilderTypeId = typeof GraphBuilderTypeId;\n\n/**\n * GraphBuilder interface.\n */\nexport interface GraphBuilder extends Pipeable.Pipeable {\n  readonly [GraphBuilderTypeId]: GraphBuilderTypeId;\n  readonly graph: Graph.ExpandableGraph;\n  readonly extensions: Atom.Atom<Record<string, BuilderExtension>>;\n  /** The URL grammar this builder resolves and stamps against (separators always resolved). */\n  readonly urlGrammar: UrlGrammar;\n  /** Read the currently registered extensions synchronously (used for URL key-table derivation). */\n  getExtensions(): Record<string, BuilderExtension>;\n  /**\n   * The id of the extension whose connector produced the given node, if known. Populated as\n   * connectors materialize nodes and cleared on removal; used by `path-resolution.ts` for\n   * reverse (node → URL) mapping.\n   */\n  getNodeExtensionId(nodeId: string): string | undefined;\n}\n\n/**\n * The builder provides an extensible way to compose the construction of the graph.\n * @internal\n */\n// TODO(wittjosiah): Add api for setting subscription set and/or radius.\n//   Should unsubscribe from nodes that are not in the set/radius.\n//   Should track LRU nodes that are not in the set/radius and remove them beyond a certain threshold.\nclass GraphBuilderImpl implements GraphBuilder {\n  readonly [GraphBuilderTypeId]: GraphBuilderTypeId = GraphBuilderTypeId;\n\n  pipe() {\n    // eslint-disable-next-line prefer-rest-params\n    return Pipeable.pipeArguments(this, arguments);\n  }\n\n  // TODO(wittjosiah): Use Context.\n  /** Active subscriptions keyed by composite ID, cleaned up on node removal. */\n  readonly _subscriptions = new Map<string, CleanupFn>();\n  /** Connector updates pending flush, keyed by connector key. */\n  readonly _dirtyConnectors = new Map<\n    string,\n    {\n      nodes: Node.NodeArg<any>[];\n      previous: string[];\n    }\n  >();\n  /** Last-flushed node IDs per connector key, used for edge removal on update. */\n  readonly _connectorPrevious = new Map<string, string[]>();\n  /** All inline-descendant IDs per connector key, used to remove stale inline nodes on update. */\n  readonly _connectorPreviousInlineIds = new Map<string, string[]>();\n  /** Last-flushed node args per connector key, used for change detection. */\n  readonly _connectorPreviousArgs = new Map<string, Node.NodeArg<any>[]>();\n  /** Whether a dirty-flush task is already scheduled. */\n  _flushScheduled = false;\n  /** Resolves when the current flush completes. */\n  _flushPromise: Promise<void> = Promise.resolve();\n  /** Registered builder extensions keyed by extension ID. */\n  readonly _extensions = Atom.make(Record.empty<string, BuilderExtension>()).pipe(\n    Atom.keepAlive,\n    Atom.withLabel('graph-builder:extensions'),\n  );\n  /**\n   * Node id -> id of the extension whose connector produced it. Non-reactive: updated directly\n   * as connectors materialize/remove nodes, so reverse (node → URL) mapping in\n   * `path-resolution.ts` can look up the producing extension without a reactive read.\n   */\n  readonly _nodeExtensions = new Map<string, string>();\n  /** Triggers signalling that a node's resolver has fired at least once. */\n  readonly _initialized: Record<string, Trigger> = {};\n  /** The URL grammar (see {@link UrlGrammar}); the keys are absent when URLs are not in play. */\n  readonly urlGrammar: UrlGrammar;\n  /** Shared atom registry for reactive subscriptions. */\n  readonly _registry: Registry.Registry;\n  /** Backing graph with internal accessors for node atoms and construction. */\n  readonly _graph: Graph.Graph & {\n    _node: (id: string) => Atom.Writable<Option.Option<Node.Node>>;\n    _constructNode: (node: Node.NodeArg<any>) => Option.Option<Node.Node>;\n  };\n\n  constructor({ registry, urlGrammar, ...params }: GraphBuilderProps = {}) {\n    this.urlGrammar = {\n      linkedPrefix: DEFAULT_LINKED_PREFIX,\n      tailSeparator: DEFAULT_TAIL_SEPARATOR,\n      ...urlGrammar,\n    };\n    this._registry = registry ?? Registry.make();\n    const graph = Graph.make({\n      ...params,\n      registry: this._registry,\n      onExpand: (id, relation) => this._onExpand(id, relation),\n      onInitialize: (id) => this._onInitialize(id),\n      onRemoveNode: (id) => this._onRemoveNode(id),\n    });\n    // Access internal methods via type assertion since GraphBuilder needs them\n    this._graph = graph as Graph.Graph & {\n      _node: (id: string) => Atom.Writable<Option.Option<Node.Node>>;\n      _constructNode: (node: Node.NodeArg<any>) => Option.Option<Node.Node>;\n    };\n  }\n\n  get graph(): Graph.ExpandableGraph {\n    return this._graph;\n  }\n\n  get extensions() {\n    return this._extensions;\n  }\n\n  getExtensions(): Record<string, BuilderExtension> {\n    return this._registry.get(this._extensions);\n  }\n\n  getNodeExtensionId(nodeId: string): string | undefined {\n    return this._nodeExtensions.get(nodeId);\n  }\n\n  /** Record `extensionId` as the producer of a qualified node and all of its inline `nodes` descendants. */\n  private _recordProvenance(node: Node.NodeArg<any>, extensionId: string): void {\n    this._nodeExtensions.set(node.id, extensionId);\n    for (const child of node.nodes ?? []) {\n      this._recordProvenance(child, extensionId);\n    }\n  }\n\n  /** Apply a set of node changes for a single connector key. */\n  private _applyConnectorUpdate(key: string, nodes: Node.NodeArg<any>[], previous: string[]): void {\n    const { id, relation } = relationFromConnectorKey(key);\n    const ids = nodes.map((node) => node.id);\n    const removed = previous.filter((pid) => !ids.includes(pid));\n    this._connectorPrevious.set(key, ids);\n    this._connectorPreviousArgs.set(key, nodes);\n\n    const currentInlineIds = collectAllInlineIds(nodes);\n    const previousInlineIds = this._connectorPreviousInlineIds.get(key) ?? [];\n    const staleInlineIds = previousInlineIds.filter((pid) => !currentInlineIds.includes(pid));\n    this._connectorPreviousInlineIds.set(key, currentInlineIds);\n\n    Graph.removeNodes(this._graph, staleInlineIds, true);\n    Graph.removeEdges(\n      this._graph,\n      removed.map((target) => ({ source: id, target, relation })),\n      true,\n    );\n    Graph.addNodes(this._graph, nodes);\n    Graph.addEdges(\n      this._graph,\n      nodes.map((node) => ({ source: id, target: node.id, relation })),\n    );\n    if (ids.length > 0) {\n      const sortedIds = [...nodes]\n        .sort((a, b) => Position.compare({ position: a.properties?.position }, { position: b.properties?.position }))\n        .map((n) => n.id);\n      Graph.sortEdges(this._graph, id, relation, sortedIds);\n    }\n  }\n\n  private _scheduleDirtyFlush(): void {\n    if (!this._flushScheduled) {\n      this._flushScheduled = true;\n      this._flushPromise = scheduleTask(\n        () => {\n          this._flushScheduled = false;\n          while (this._dirtyConnectors.size > 0) {\n            const entries = [...this._dirtyConnectors.entries()];\n            this._dirtyConnectors.clear();\n\n            Atom.batch(() => {\n              for (const [key, { nodes, previous }] of entries) {\n                this._applyConnectorUpdate(key, nodes, previous);\n              }\n            });\n          }\n        },\n        { strategy: 'smooth' },\n      );\n    }\n  }\n\n  /** A connector-produced node, tagged with the id of the extension that produced it (provenance). */\n  private readonly _resolvers = Atom.family<string, Atom.Atom<Option.Option<Node.NodeArg<any>>>>((id) => {\n    return Atom.make((get) => {\n      return Function.pipe(\n        get(this._extensions),\n        Record.values,\n        Array.sortBy(Position.compare),\n        Array.map(({ resolver }) => resolver),\n        Array.filter(isNonNullable),\n        Array.map((resolver) => get(resolver(id))),\n        Array.filter(isNonNullable),\n        Array.head,\n      );\n    });\n  });\n\n  private readonly _connectors = Atom.family<string, Atom.Atom<{ extensionId: string; node: Node.NodeArg<any> }[]>>(\n    (key) => {\n      return Atom.make((get) => {\n        const { id, relation } = relationFromConnectorKey(key);\n        const node = this._graph.node(id);\n\n        const sourceNode = Option.getOrElse(get(node), () => undefined);\n        if (!sourceNode) {\n          return [];\n        }\n\n        const extensions = Function.pipe(\n          get(this._extensions),\n          Record.values,\n          Array.sortBy(Position.compare),\n          Array.filter(\n            (ext): ext is BuilderExtension & { connector: NonNullable<BuilderExtension['connector']> } =>\n              Graph.relationKey(ext.relation ?? 'child') === Graph.relationKey(relation) && ext.connector != null,\n          ),\n        );\n\n        const entries: { extensionId: string; node: Node.NodeArg<any> }[] = [];\n        for (const ext of extensions) {\n          const result = get(ext.connector(node));\n          for (const nodeArg of result) {\n            entries.push({ extensionId: ext.id, node: nodeArg });\n          }\n        }\n\n        return entries;\n      }).pipe(Atom.withLabel(`graph-builder:connectors:${key}`));\n    },\n  );\n\n  private _onExpand(id: string, relation: Node.Relation): void {\n    log('onExpand', { id, relation, registry: getDebugName(this._registry) });\n    this._expandRelation(id, relation);\n\n    // TODO(wittjosiah): Remove. This is for backwards compatibility.\n    if (relation.kind === 'child' && relation.direction === 'outbound') {\n      Graph.expand(this._graph, id, 'action');\n    }\n  }\n\n  private _expandRelation(id: string, relation: Node.RelationInput): void {\n    const key = connectorKey(id, relation);\n    const connectors = this._connectors(key);\n\n    const cancel = this._registry.subscribe(\n      connectors,\n      (entries) => {\n        const extensions = this.getExtensions();\n        const grammar = this.urlGrammar;\n        // Stamp `properties.urlSegment` on each produced node (and its inline descendants) so the computed\n        // segment is readable off the node (see `BuilderNode`): `/<key>[/<id>]` from the producing\n        // extension's binding, or `/<linkedKey>/<variant>` for a `~<variant>` linked node.\n        const nodes = qualifyNodeArgs(id)(entries.map((entry) => entry.node)).map((node, index) =>\n          stampUrlSegment(node, extensions[entries[index].extensionId]?.url, grammar),\n        );\n        // Record provenance for each qualified node — top-level and inline descendants alike — so\n        // reverse (node → URL) mapping can find the producing extension's `url` binding. Inline children\n        // (e.g. a TypeSection's objects, returned in the section node's `nodes` array) are produced by the\n        // same extension, so they carry the same provenance; without this they would have no URL representation.\n        entries.forEach((entry, index) => {\n          this._recordProvenance(nodes[index], entry.extensionId);\n        });\n\n        const previous = this._connectorPrevious.get(key) ?? [];\n        const ids = nodes.map((n) => n.id);\n\n        if (ids.length === previous.length && ids.every((nodeId, idx) => nodeId === previous[idx])) {\n          const prevArgs = this._connectorPreviousArgs.get(key);\n          if (prevArgs && nodeArgsUnchanged(prevArgs, nodes)) {\n            return;\n          }\n        }\n\n        log('update', { id, relation, ids });\n        this._dirtyConnectors.set(key, { nodes, previous });\n        this._scheduleDirtyFlush();\n      },\n      { immediate: true },\n    );\n\n    this._subscriptions.set(subscriptionKey(id, 'expand', key), cancel);\n  }\n\n  private async _onInitialize(id: string) {\n    log('onInitialize', { id });\n    const resolver = this._resolvers(id);\n\n    const cancel = this._registry.subscribe(\n      resolver,\n      (node) => {\n        const trigger = this._initialized[id];\n        const connectorOwned = [...this._connectorPrevious.values()].some((ids) => ids.includes(id));\n        Option.match(node, {\n          onSome: (node) => {\n            if (!connectorOwned) {\n              Graph.addNodes(this._graph, [node]);\n              // Connect resolved node to its parent via a child edge.\n              const parentId = getParentId(id);\n              if (parentId) {\n                Graph.addEdges(this._graph, [{ source: parentId, target: id, relation: 'child' }]);\n              }\n            }\n            trigger?.wake();\n          },\n          onNone: () => {\n            trigger?.wake();\n            if (!connectorOwned) {\n              Graph.removeNodes(this._graph, [id]);\n            }\n          },\n        });\n      },\n      { immediate: true },\n    );\n\n    this._subscriptions.set(subscriptionKey(id, 'init'), cancel);\n  }\n\n  private _onRemoveNode(id: string): void {\n    this._nodeExtensions.delete(id);\n    for (const [key, cleanup] of this._subscriptions) {\n      if (primaryParts(key)[0] === id) {\n        cleanup();\n        this._subscriptions.delete(key);\n      }\n    }\n  }\n}\n\n/** Construction params: the backing graph's props plus the URL grammar's fixed keys. */\nexport type GraphBuilderProps = Pick<Graph.GraphProps, 'registry' | 'nodes' | 'edges'> & {\n  urlGrammar?: UrlGrammarProps;\n};\n\n/**\n * Creates a new GraphBuilder instance.\n */\nexport const make = (params?: GraphBuilderProps): GraphBuilder => {\n  return new GraphBuilderImpl(params);\n};\n\n/**\n * Creates a GraphBuilder from a serialized pickle string.\n */\nexport const from = (pickle?: string, registry?: Registry.Registry, urlGrammar?: UrlGrammarProps): GraphBuilder => {\n  if (!pickle) {\n    return make({ registry, urlGrammar });\n  }\n\n  const { nodes, edges } = JSON.parse(pickle);\n  return make({ nodes, edges, registry, urlGrammar });\n};\n\n/**\n * Implementation helper for addExtension.\n */\nconst addExtensionImpl = (builder: GraphBuilder, extensions: BuilderExtensions): GraphBuilder => {\n  const internal = builder as GraphBuilderImpl;\n  flattenExtensions(extensions).forEach((extension) => {\n    const extensions = internal._registry.get(internal._extensions);\n    internal._registry.set(internal._extensions, Record.set(extensions, extension.id, extension));\n  });\n  return builder;\n};\n\n/**\n * Add extensions to the graph builder.\n */\nexport function addExtension(builder: GraphBuilder, extensions: BuilderExtensions): GraphBuilder;\nexport function addExtension(extensions: BuilderExtensions): (builder: GraphBuilder) => GraphBuilder;\nexport function addExtension(\n  builderOrExtensions: GraphBuilder | BuilderExtensions,\n  extensions?: BuilderExtensions,\n): GraphBuilder | ((builder: GraphBuilder) => GraphBuilder) {\n  if (extensions === undefined) {\n    // Curried: addExtension(extensions)\n    const extensions = builderOrExtensions as BuilderExtensions;\n    return (builder: GraphBuilder) => addExtensionImpl(builder, extensions);\n  } else {\n    // Direct: addExtension(builder, extensions)\n    const builder = builderOrExtensions as GraphBuilder;\n    return addExtensionImpl(builder, extensions);\n  }\n}\n\n/**\n * Implementation helper for removeExtension.\n */\nconst removeExtensionImpl = (builder: GraphBuilder, id: string): GraphBuilder => {\n  const internal = builder as GraphBuilderImpl;\n  const extensions = internal._registry.get(internal._extensions);\n  internal._registry.set(internal._extensions, Record.remove(extensions, id));\n  return builder;\n};\n\n/**\n * Remove an extension from the graph builder.\n */\nexport function removeExtension(builder: GraphBuilder, id: string): GraphBuilder;\nexport function removeExtension(id: string): (builder: GraphBuilder) => GraphBuilder;\nexport function removeExtension(\n  builderOrId: GraphBuilder | string,\n  id?: string,\n): GraphBuilder | ((builder: GraphBuilder) => GraphBuilder) {\n  if (typeof builderOrId === 'string') {\n    // Curried: removeExtension(id)\n    const id = builderOrId;\n    return (builder: GraphBuilder) => removeExtensionImpl(builder, id);\n  } else {\n    // Direct: removeExtension(builder, id)\n    const builder = builderOrId;\n    return removeExtensionImpl(builder, id!);\n  }\n}\n\n/**\n * Implementation helper for explore.\n */\nconst exploreImpl = async (\n  builder: GraphBuilder,\n  options: GraphBuilderTraverseOptions,\n  path: string[] = [],\n): Promise<void> => {\n  const internal = builder as GraphBuilderImpl;\n  const { registry = Registry.make(), source = Node.RootId, relation, visitor } = options;\n  // Break cycles.\n  if (path.includes(source)) {\n    return;\n  }\n\n  await yieldOrContinue('idle');\n\n  const node = registry.get(internal._graph.nodeOrThrow(source));\n  const shouldContinue = await visitor(node, [...path, node.id]);\n  if (shouldContinue === false) {\n    return;\n  }\n\n  const nodes = Function.pipe(\n    internal._registry.get(internal._extensions),\n    Record.values,\n    Array.map((extension) => extension.connector),\n    Array.filter(isNonNullable),\n    Array.flatMap((connector) => registry.get(connector(internal._graph.node(source)))),\n    qualifyNodeArgs(source),\n  );\n\n  await Promise.all(\n    nodes.map((nodeArg) => {\n      registry.set(internal._graph._node(nodeArg.id), internal._graph._constructNode(nodeArg));\n      return exploreImpl(builder, { registry, source: nodeArg.id, relation, visitor }, [...path, node.id]);\n    }),\n  );\n\n  if (registry !== internal._registry) {\n    registry.reset();\n    registry.dispose();\n  }\n};\n\n/**\n * Explore the graph by traversing it with the given options.\n */\nexport function explore(builder: GraphBuilder, options: GraphBuilderTraverseOptions, path?: string[]): Promise<void>;\nexport function explore(\n  options: GraphBuilderTraverseOptions,\n  path?: string[],\n): (builder: GraphBuilder) => Promise<void>;\nexport function explore(\n  builderOrOptions: GraphBuilder | GraphBuilderTraverseOptions,\n  optionsOrPath?: GraphBuilderTraverseOptions | string[],\n  path?: string[],\n): Promise<void> | ((builder: GraphBuilder) => Promise<void>) {\n  if (typeof builderOrOptions === 'object' && 'visitor' in builderOrOptions) {\n    // Curried: explore(options, path?)\n    const options = builderOrOptions as GraphBuilderTraverseOptions;\n    const path = Array.isArray(optionsOrPath) ? optionsOrPath : undefined;\n    return (builder: GraphBuilder) => exploreImpl(builder, options, path);\n  } else {\n    // Direct: explore(builder, options, path?)\n    const builder = builderOrOptions as GraphBuilder;\n    const options = optionsOrPath as GraphBuilderTraverseOptions;\n    const pathArg = path ?? (Array.isArray(optionsOrPath) ? optionsOrPath : undefined);\n    return exploreImpl(builder, options, pathArg);\n  }\n}\n\n/**\n * Implementation helper for destroy.\n */\nconst destroyImpl = (builder: GraphBuilder): void => {\n  const internal = builder as GraphBuilderImpl;\n  internal._subscriptions.forEach((unsubscribe) => unsubscribe());\n  internal._subscriptions.clear();\n};\n\n/**\n * Destroy the graph builder and clean up resources.\n */\nexport function destroy(builder: GraphBuilder): void;\nexport function destroy(): (builder: GraphBuilder) => void;\nexport function destroy(builder?: GraphBuilder): void | ((builder: GraphBuilder) => void) {\n  if (builder === undefined) {\n    // Curried: destroy()\n    return (builder: GraphBuilder) => destroyImpl(builder);\n  } else {\n    // Direct: destroy(builder)\n    return destroyImpl(builder);\n  }\n}\n\n/**\n * Wait for all pending connector updates to be flushed.\n */\nexport const flush = (builder: GraphBuilder): Promise<void> => {\n  return (builder as GraphBuilderImpl)._flushPromise;\n};\n\n//\n// Extension Creation\n//\n\n/**\n * A graph builder extension is used to add nodes to the graph.\n *\n * @param params.id The unique id of the extension.\n * @param params.relation The relation the graph is being expanded from the existing node.\n * @param params.position Affects the order the extensions are processed in.\n * @param params.url URL binding for the nodes this extension produces (key + resolution); see {@link UrlBinding}.\n * @param params.connector A function to add nodes to the graph based on a connection to an existing node.\n * @param params.actions A function to add actions to the graph based on a connection to an existing node.\n * @param params.actionGroups A function to add action groups to the graph based on a connection to an existing node.\n */\nexport type CreateExtensionRawOptions = {\n  id: string;\n  relation?: Node.RelationInput;\n  position?: Position.Position;\n  url?: UrlBinding;\n  resolver?: ResolverExtension;\n  connector?: ConnectorExtension;\n  actions?: ActionsExtension;\n  actionGroups?: ActionGroupsExtension;\n};\n\n/**\n * Whether a graph extension local ID follows NSID conventions: the final\n * dot-separated segment must be camelCase (letters and digits only, starting\n * with a letter — no hyphens or underscores). This mirrors the rule enforced\n * when the id is appended to a plugin's NSID to form a full DXN path.\n *\n * An extension with an invalid id is dropped rather than rejected, so a single\n * malformed contribution cannot crash plugin activation.\n *\n * @example Valid:   'about', 'devtools', 'integrationsSection'\n * @example Invalid: 'integration-article', 'plugin-spec'\n */\nconst isValidLocalId = (id: string): boolean => /^[a-zA-Z][a-zA-Z0-9]*$/.test(id.split('.').pop() ?? '');\n\n/**\n * Create a graph builder extension (low-level API that works directly with Atoms).\n */\nexport const createExtensionRaw = (extension: CreateExtensionRawOptions): BuilderExtension[] => {\n  const {\n    id,\n    position,\n    relation = 'child',\n    url,\n    resolver: _resolver,\n    connector: _connector,\n    actions: _actions,\n    actionGroups: _actionGroups,\n  } = extension;\n  if (!isValidLocalId(id)) {\n    log.warn(\n      'dropping graph extension with invalid id; the final segment must be camelCase (no hyphens or underscores)',\n      {\n        id,\n      },\n    );\n    return [];\n  }\n  const normalizedRelation = normalizeRelation(relation);\n  const getId = (key: string) => `${id}/${key}`;\n\n  const resolver =\n    _resolver && Atom.family((id: string) => _resolver(id).pipe(Atom.withLabel(`graph-builder:_resolver:${id}`)));\n\n  const connector =\n    _connector &&\n    Atom.family((node: Atom.Atom<Option.Option<Node.Node>>) =>\n      _connector(node).pipe(Atom.withLabel(`graph-builder:_connector:${id}`)),\n    );\n\n  const actionGroups =\n    _actionGroups &&\n    Atom.family((node: Atom.Atom<Option.Option<Node.Node>>) =>\n      _actionGroups(node).pipe(Atom.withLabel(`graph-builder:_actionGroups:${id}`)),\n    );\n\n  const actions =\n    _actions &&\n    Atom.family((node: Atom.Atom<Option.Option<Node.Node>>) =>\n      _actions(node).pipe(Atom.withLabel(`graph-builder:_actions:${id}`)),\n    );\n\n  const extensions = [\n    resolver ? ({ id: getId('resolver'), position, resolver } satisfies BuilderExtension) : undefined,\n    connector\n      ? ({\n          id: getId('connector'),\n          position,\n          relation: normalizedRelation,\n          url,\n          connector: Atom.family((node) =>\n            Atom.make((get) => {\n              try {\n                return get(connector(node));\n              } catch (error) {\n                log.warn('Error in connector', { id: getId('connector'), node, error });\n                return [];\n              }\n            }).pipe(Atom.withLabel(`graph-builder:connector:${id}`)),\n          ),\n        } satisfies BuilderExtension)\n      : undefined,\n    actionGroups\n      ? ({\n          id: getId('actionGroups'),\n          position,\n          relation: Node.actionRelation(),\n          connector: Atom.family((node) =>\n            Atom.make((get) => {\n              try {\n                return get(actionGroups(node)).map((arg) => ({\n                  ...arg,\n                  data: Node.actionGroupSymbol,\n                  type: Node.ActionGroupType,\n                }));\n              } catch (error) {\n                log.warn('Error in actionGroups', { id: getId('actionGroups'), node, error });\n                return [];\n              }\n            }).pipe(Atom.withLabel(`graph-builder:connector:actionGroups:${id}`)),\n          ),\n        } satisfies BuilderExtension)\n      : undefined,\n    actions\n      ? ({\n          id: getId('actions'),\n          position,\n          relation: Node.actionRelation(),\n          connector: Atom.family((node) =>\n            Atom.make((get) => {\n              try {\n                return get(actions(node)).map((arg) => ({ ...arg, type: Node.ActionType }));\n              } catch (error) {\n                log.warn('Error in actions', { id: getId('actions'), node, error });\n                return [];\n              }\n            }).pipe(Atom.withLabel(`graph-builder:connector:actions:${id}`)),\n          ),\n        } satisfies BuilderExtension)\n      : undefined,\n  ].filter(isNonNullable);\n\n  // A declaration-only extension: a `url` binding with no connector/actions (e.g. the workspace anchor,\n  // which registers a key for the parser/serializer but produces no nodes of its own). Emit it so the\n  // key table sees the binding; it has no connector so it never runs.\n  if (extensions.length === 0 && url) {\n    return [{ id, position, relation: normalizedRelation, url } satisfies BuilderExtension];\n  }\n\n  return extensions;\n};\n\n/**\n * Options for creating a graph builder extension with simplified API.\n * All callbacks must return Effects for dependency injection.\n * Effects may defect — defects are caught, logged, and the extension returns empty results.\n * Use Effect.orDie on any failable effects inside callbacks.\n */\nexport type CreateExtensionOptions<TMatched = Node.Node, R = never> = {\n  id: string;\n  match: (node: Node.Node, get: Atom.Context) => Option.Option<TMatched>;\n  actions?: (\n    matched: TMatched,\n    get: Atom.Context,\n  ) => Effect.Effect<Omit<Node.NodeArg<Node.ActionData<any>, any>, 'type'>[], never, R>;\n  /** Contribute dropdown action groups (each with nested `actions`) to the matched node; the group's\n   * `type`/`data` are set automatically, so returning `Node.makeActionGroup(...)` output is fine. */\n  actionGroups?: (\n    matched: TMatched,\n    get: Atom.Context,\n  ) => Effect.Effect<Omit<Node.NodeArg<typeof Node.actionGroupSymbol>, 'type' | 'data'>[], never, R>;\n  resolver?: (id: string, get: Atom.Context) => Effect.Effect<Node.NodeArg<any, any> | null, never, R>;\n  connector?: (matched: TMatched, get: Atom.Context) => Effect.Effect<Node.NodeArg<any, any>[], never, R>;\n  relation?: Node.RelationInput;\n  position?: Position.Position;\n  /** URL binding for the nodes this extension produces (key + resolution); see {@link UrlBinding}. */\n  url?: UrlBinding;\n};\n\n/**\n * Run an Effect synchronously with the provided context.\n * Defects are caught, logged, and the fallback value is returned.\n * @internal\n */\nconst runEffectSyncWithFallback = <T, R>(\n  effect: Effect.Effect<T, never, R>,\n  context: Context.Context<R>,\n  extensionId: string,\n  fallback: T,\n): T => {\n  return Effect.runSync(\n    effect.pipe(\n      Effect.provide(context),\n      Effect.catchAllDefect((defect) => {\n        log.warn('Extension failed', { extension: extensionId, defect });\n        return Effect.succeed(fallback);\n      }),\n    ),\n  );\n};\n\n/**\n * Create a graph builder extension with simplified API.\n * Returns an Effect to allow callbacks to access services via dependency injection.\n */\nexport const createExtension = <TMatched = Node.Node, R = never>(\n  options: CreateExtensionOptions<TMatched, R>,\n): Effect.Effect<BuilderExtension[], never, R> =>\n  Effect.map(Effect.context<R>(), (context) => {\n    const { id, match, actions, actionGroups, connector, resolver, relation, position, url } = options;\n\n    const connectorExtension = connector ? createConnectorWithRuntime(id, match, connector, context) : undefined;\n\n    const actionsExtension = actions\n      ? (node: Atom.Atom<Option.Option<Node.Node>>) =>\n          Atom.make((get) =>\n            Function.pipe(\n              get(node),\n              Option.flatMap((matchedNode) => match(matchedNode, get)),\n              Option.map((matched) =>\n                runEffectSyncWithFallback(actions(matched, get), context, id, []).map((action) => ({\n                  ...action,\n                  // Attach captured context for action execution.\n                  _actionContext: context,\n                })),\n              ),\n              Option.getOrElse(() => []),\n            ),\n          )\n      : undefined;\n\n    const actionGroupsExtension = actionGroups\n      ? (node: Atom.Atom<Option.Option<Node.Node>>) =>\n          Atom.make((get) =>\n            Function.pipe(\n              get(node),\n              Option.flatMap((matchedNode) => match(matchedNode, get)),\n              Option.map((matched) =>\n                runEffectSyncWithFallback(actionGroups(matched, get), context, id, []).map((group) => ({\n                  ...group,\n                  // Attach captured context to the group's child actions so they execute with the\n                  // extension's services (e.g. Capability.Service) even without an explicit runner.\n                  actions: group.actions?.map((action) => ({ ...action, _actionContext: context })),\n                })),\n              ),\n              Option.getOrElse(() => []),\n            ),\n          )\n      : undefined;\n\n    const resolverExtension = resolver\n      ? (nodeId: string) =>\n          Atom.make((get) => runEffectSyncWithFallback(resolver(nodeId, get), context, id, null) ?? null)\n      : undefined;\n\n    return createExtensionRaw({\n      id,\n      relation,\n      position,\n      url,\n      resolver: resolverExtension,\n      connector: connectorExtension,\n      actions: actionsExtension,\n      actionGroups: actionGroupsExtension,\n    });\n  });\n\n/**\n * Create a connector extension from a matcher and factory function.\n * The factory's data type is inferred from the matcher's return type.\n */\nexport const createConnector = <TData>(\n  matcher: (node: Node.Node, get: Atom.Context) => Option.Option<TData>,\n  factory: (data: TData, get: Atom.Context) => Node.NodeArg<any>[],\n): ConnectorExtension => {\n  return (node: Atom.Atom<Option.Option<Node.Node>>) =>\n    Atom.make((get) =>\n      Function.pipe(\n        get(node),\n        Option.flatMap((matchedNode) => matcher(matchedNode, get)),\n        Option.map((data) => factory(data, get)),\n        Option.getOrElse(() => []),\n      ),\n    );\n};\n\n/**\n * Create a connector extension from a matcher and factory function with Effect support.\n * The factory must return an Effect. Errors are caught and logged.\n * @internal\n */\nconst createConnectorWithRuntime = <TData, R>(\n  extensionId: string,\n  matcher: (node: Node.Node, get: Atom.Context) => Option.Option<TData>,\n  factory: (data: TData, get: Atom.Context) => Effect.Effect<Node.NodeArg<any>[], never, R>,\n  context: Context.Context<R>,\n): ConnectorExtension => {\n  return (node: Atom.Atom<Option.Option<Node.Node>>) =>\n    Atom.make((get) =>\n      Function.pipe(\n        get(node),\n        Option.flatMap((matchedNode) => matcher(matchedNode, get)),\n        Option.map((data) => runEffectSyncWithFallback(factory(data, get), context, extensionId, [])),\n        Option.getOrElse(() => []),\n      ),\n    );\n};\n\n/**\n * Options for creating a type-based extension.\n * All callbacks must return Effects for dependency injection.\n * Effects may fail - errors are caught, logged, and the extension returns empty results.\n */\nexport type CreateTypeExtensionOptions<T extends Type.AnyEntity = Type.AnyEntity, R = never> = {\n  id: string;\n  type: T;\n  actions?: (\n    object: Type.InstanceType<T>,\n    get: Atom.Context,\n  ) => Effect.Effect<Omit<Node.NodeArg<Node.ActionData<any>>, 'type'>[], never, R>;\n  actionGroups?: (\n    object: Type.InstanceType<T>,\n    get: Atom.Context,\n  ) => Effect.Effect<Omit<Node.NodeArg<typeof Node.actionGroupSymbol>, 'type' | 'data'>[], never, R>;\n  connector?: (object: Type.InstanceType<T>, get: Atom.Context) => Effect.Effect<Node.NodeArg<any>[], never, R>;\n  relation?: Node.RelationInput;\n  position?: Position.Position;\n};\n\n/**\n * Create an extension that matches nodes by schema type.\n * The entity type is inferred from the schema type and works for both object and relation schemas.\n * Returns an Effect to allow callbacks to access services via dependency injection.\n */\nexport const createTypeExtension = <T extends Type.AnyEntity, R = never>(\n  options: CreateTypeExtensionOptions<T, R>,\n): Effect.Effect<BuilderExtension[], never, R> => {\n  const { id, type, actions, actionGroups, connector, relation, position } = options;\n  return createExtension<Type.InstanceType<T>, R>({\n    id,\n    match: NodeMatcher.whenEchoType(type),\n    actions,\n    actionGroups,\n    connector,\n    relation,\n    position,\n  });\n};\n\n//\n// Extension Utilities\n//\n\n/**\n * Qualify node IDs by prefixing with the parent path.\n * Validates that segment IDs do not contain the path separator.\n * Recursively qualifies inline child nodes.\n */\nconst qualifyNodeArgs =\n  (parentId: string) =>\n  (nodes: Node.NodeArg<any>[]): Node.NodeArg<any>[] =>\n    nodes.map((node) => {\n      validateSegmentId(node.id);\n      const qualified = qualifyId(parentId, node.id);\n      return {\n        ...node,\n        id: qualified,\n        nodes: node.nodes ? qualifyNodeArgs(qualified)(node.nodes) : undefined,\n        actions: node.actions ? qualifyNodeArgs(qualified)(node.actions) : undefined,\n      };\n    });\n\n/**\n * Recursively collect all inline-descendant IDs (the `nodes` arrays at every level)\n * from a list of top-level NodeArgs. Top-level IDs are excluded because they are\n * already tracked via `_connectorPrevious`.\n */\nconst collectAllInlineIds = (nodes: Node.NodeArg<any>[]): string[] =>\n  nodes.flatMap((node) => {\n    const childNodes = node.nodes ?? [];\n    const actionNodes = node.actions ?? [];\n    const allInline = [...childNodes, ...actionNodes];\n    return allInline.length > 0 ? [...allInline.map((child) => child.id), ...collectAllInlineIds(allInline)] : [];\n  });\n\nconst connectorKey = (id: string, relation: Node.RelationInput): string => primaryKey(id, Graph.relationKey(relation));\n\nconst relationFromConnectorKey = (key: string): { id: string; relation: Node.Relation } => {\n  const [id, encodedRelation] = primaryParts(key);\n  return { id, relation: Graph.relationFromKey(encodedRelation) };\n};\n\nconst subscriptionKey = (id: string, kind: string, detail?: string): string =>\n  detail != null ? primaryKey(id, kind, detail) : primaryKey(id, kind);\n\nexport const flattenExtensions = (extension: BuilderExtensions, acc: BuilderExtension[] = []): BuilderExtension[] => {\n  if (Array.isArray(extension)) {\n    return [...acc, ...extension.flatMap((ext) => flattenExtensions(ext, acc))];\n  } else {\n    return [...acc, extension];\n  }\n};\n"],"mappings":"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"}