@dxos/app-graph 0.6.5 → 0.6.6-staging.23d123d

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -32,6 +32,7 @@ var ROOT_ID = "root";
32
32
  var ROOT_TYPE = "dxos.org/type/GraphRoot";
33
33
  var ACTION_TYPE = "dxos.org/type/GraphAction";
34
34
  var ACTION_GROUP_TYPE = "dxos.org/type/GraphActionGroup";
35
+ var DEFAULT_FILTER = (node) => untracked(() => !isActionLike(node));
35
36
  var Graph = class {
36
37
  constructor({ onInitialNode, onInitialNodes, onRemoveNode } = {}) {
37
38
  this._waitingForNodes = {};
@@ -97,7 +98,7 @@ var Graph = class {
97
98
  const root = this.findNode(id);
98
99
  invariant(root, `Node not found: ${id}`, {
99
100
  F: __dxlog_file,
100
- L: 134,
101
+ L: 137,
101
102
  S: this,
102
103
  A: [
103
104
  "root",
@@ -144,14 +145,14 @@ var Graph = class {
144
145
  * Nodes that this node is connected to in default order.
145
146
  */
146
147
  nodes(node, options = {}) {
147
- const { relation, expansion, filter, type } = options;
148
+ const { relation, expansion, filter = DEFAULT_FILTER, type } = options;
148
149
  const nodes = this._getNodes({
149
150
  node,
150
151
  relation,
151
152
  expansion,
152
153
  type
153
154
  });
154
- return nodes.filter((n) => untracked(() => !isActionLike(n))).filter((n) => filter?.(n, node) ?? true);
155
+ return nodes.filter((n) => filter(n, node));
155
156
  }
156
157
  /**
157
158
  * Edges that this node is connected to in default order.
@@ -414,10 +415,10 @@ var Graph = class {
414
415
  * Remove edges from the graph.
415
416
  * @internal
416
417
  */
417
- _removeEdges(edges) {
418
- batch(() => edges.forEach((edge) => this._removeEdge(edge)));
418
+ _removeEdges(edges, removeOrphans = false) {
419
+ batch(() => edges.forEach((edge) => this._removeEdge(edge, removeOrphans)));
419
420
  }
420
- _removeEdge({ source, target }) {
421
+ _removeEdge({ source, target }, removeOrphans = false) {
421
422
  untracked(() => {
422
423
  batch(() => {
423
424
  const outboundIndex = this._edges[source]?.outbound.findIndex((id) => id === target);
@@ -428,6 +429,14 @@ var Graph = class {
428
429
  if (inboundIndex !== void 0 && inboundIndex !== -1) {
429
430
  this._edges[target].inbound.splice(inboundIndex, 1);
430
431
  }
432
+ if (removeOrphans) {
433
+ if (this._edges[source]?.outbound.length === 0 && this._edges[source]?.inbound.length === 0 && source !== ROOT_ID) {
434
+ this._removeNode(source, true);
435
+ }
436
+ if (this._edges[target]?.outbound.length === 0 && this._edges[target]?.inbound.length === 0 && target !== ROOT_ID) {
437
+ this._removeNode(target, true);
438
+ }
439
+ }
431
440
  });
432
441
  });
433
442
  }
@@ -473,7 +482,7 @@ var Graph = class {
473
482
  import { effect as effect2, signal } from "@preact/signals-core";
474
483
  import { create as create2 } from "@dxos/echo-schema";
475
484
  import { invariant as invariant2 } from "@dxos/invariant";
476
- import { nonNullable as nonNullable2 } from "@dxos/util";
485
+ import { isNode, nonNullable as nonNullable2 } from "@dxos/util";
477
486
  var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/sdk/app-graph/src/graph-builder.ts";
478
487
  var createExtension = (extension) => {
479
488
  const { id, resolver, connector, actions, actionGroups, ...rest } = extension;
@@ -528,7 +537,7 @@ var memoize = (fn, key = "result") => {
528
537
  const dispatcher = BuilderInternal.currentDispatcher;
529
538
  invariant2(dispatcher?.currentExtension, "memoize must be called within an extension", {
530
539
  F: __dxlog_file2,
531
- L: 129,
540
+ L: 128,
532
541
  S: void 0,
533
542
  A: [
534
543
  "dispatcher?.currentExtension",
@@ -552,7 +561,7 @@ var cleanup = (fn) => {
552
561
  const dispatcher = BuilderInternal.currentDispatcher;
553
562
  invariant2(dispatcher, "cleanup must be called within an extension", {
554
563
  F: __dxlog_file2,
555
- L: 144,
564
+ L: 143,
556
565
  S: void 0,
557
566
  A: [
558
567
  "dispatcher",
@@ -617,26 +626,39 @@ var GraphBuilder = class {
617
626
  this._connectorSubscriptions.clear();
618
627
  }
619
628
  /**
620
- * Traverse a graph using just the connector extensions, without subscribing to any signals or persisting any nodes.
629
+ * A graph traversal using just the connector extensions, without subscribing to any signals or persisting any nodes.
621
630
  */
622
- // TODO(wittjosiah): Rename? This is not traversing the graph proper.
623
- async traverse({ node, relation = "outbound", visitor }, path = []) {
631
+ async explore({ node = this._graph.root, relation = "outbound", visitor }, path = []) {
624
632
  if (path.includes(node.id)) {
625
633
  return;
626
634
  }
627
- visitor(node, [
635
+ if (!isNode()) {
636
+ const { yieldOrContinue } = await import("main-thread-scheduling");
637
+ await yieldOrContinue("idle");
638
+ }
639
+ const shouldContinue = await visitor(node, [
628
640
  ...path,
629
641
  node.id
630
642
  ]);
631
- const nodes = Object.values(this._extensions).filter((extension) => relation === (extension.relation ?? "outbound")).flatMap((extension) => extension.connector?.({
632
- node
633
- }) ?? []).map((arg) => ({
643
+ if (shouldContinue === false) {
644
+ return;
645
+ }
646
+ const nodes = Object.values(this._extensions).filter((extension) => relation === (extension.relation ?? "outbound")).filter((extension) => !extension.filter || extension.filter(node)).flatMap((extension) => {
647
+ this._dispatcher.currentExtension = extension.id;
648
+ this._dispatcher.stateIndex = 0;
649
+ BuilderInternal.currentDispatcher = this._dispatcher;
650
+ const result = extension.connector?.({
651
+ node
652
+ }) ?? [];
653
+ BuilderInternal.currentDispatcher = void 0;
654
+ return result;
655
+ }).map((arg) => ({
634
656
  id: arg.id,
635
657
  type: arg.type,
636
658
  data: arg.data ?? null,
637
659
  properties: arg.properties ?? {}
638
660
  }));
639
- await Promise.all(nodes.map((n) => this.traverse({
661
+ await Promise.all(nodes.map((n) => this.explore({
640
662
  node: n,
641
663
  relation,
642
664
  visitor
@@ -698,7 +720,10 @@ var GraphBuilder = class {
698
720
  const ids = nodes.map((n) => n.id);
699
721
  const removed = previous.filter((id) => !ids.includes(id));
700
722
  previous = ids;
701
- this.graph._removeNodes(removed, true);
723
+ this.graph._removeEdges(removed.map((target) => ({
724
+ source: node.id,
725
+ target
726
+ })), true);
702
727
  this.graph._addNodes(nodes);
703
728
  this.graph._addEdges(nodes.map(({ id }) => nodesRelation === "outbound" ? {
704
729
  source: node.id,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/graph.ts", "../../../src/node.ts", "../../../src/graph-builder.ts"],
4
- "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { batch, effect, untracked } from '@preact/signals-core';\n\nimport { asyncTimeout, Trigger } from '@dxos/async';\nimport { type ReactiveObject, create } from '@dxos/echo-schema';\nimport { invariant } from '@dxos/invariant';\nimport { nonNullable } from '@dxos/util';\n\nimport { type Relation, type Node, type NodeArg, type NodeFilter, isActionLike } from './node';\n\nconst graphSymbol = Symbol('graph');\ntype DeepWriteable<T> = { -readonly [K in keyof T]: DeepWriteable<T[K]> };\ntype NodeInternal = DeepWriteable<Node> & { [graphSymbol]: Graph };\n\nexport const getGraph = (node: Node): Graph => {\n const graph = (node as NodeInternal)[graphSymbol];\n invariant(graph, 'Node is not associated with a graph.');\n return graph;\n};\n\nexport const ROOT_ID = 'root';\nexport const ROOT_TYPE = 'dxos.org/type/GraphRoot';\nexport const ACTION_TYPE = 'dxos.org/type/GraphAction';\nexport const ACTION_GROUP_TYPE = 'dxos.org/type/GraphActionGroup';\n\nexport type NodesOptions<T = any, U extends Record<string, any> = Record<string, any>> = {\n relation?: Relation;\n filter?: NodeFilter<T, U>;\n expansion?: boolean;\n type?: string;\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, path: string[]) => boolean | void;\n\n /**\n * The node to start traversing from.\n *\n * @default root\n */\n node?: Node;\n\n /**\n * The relation to traverse graph edges.\n *\n * @default 'outbound'\n */\n relation?: Relation;\n\n /**\n * Allow traversal to trigger expansion of the graph via `onInitialNodes`.\n */\n expansion?: boolean;\n};\n\n/**\n * The Graph represents the structure of the application constructed via plugins.\n */\nexport class Graph {\n private readonly _onInitialNode?: (id: string) => Promise<void>;\n private readonly _onInitialNodes?: (node: Node, relation: Relation, type?: string) => Promise<void>;\n private readonly _onRemoveNode?: (id: string) => Promise<void>;\n\n private readonly _waitingForNodes: Record<string, Trigger<Node>> = {};\n private readonly _initialized: Record<string, boolean> = {};\n\n /**\n * @internal\n */\n readonly _nodes: Record<string, ReactiveObject<NodeInternal>> = {};\n\n /**\n * @internal\n */\n readonly _edges: Record<string, ReactiveObject<{ inbound: string[]; outbound: string[] }>> = {};\n\n constructor({\n onInitialNode,\n onInitialNodes,\n onRemoveNode,\n }: {\n onInitialNode?: Graph['_onInitialNode'];\n onInitialNodes?: Graph['_onInitialNodes'];\n onRemoveNode?: Graph['_onRemoveNode'];\n } = {}) {\n this._onInitialNode = onInitialNode;\n this._onInitialNodes = onInitialNodes;\n this._onRemoveNode = onRemoveNode;\n this._nodes[ROOT_ID] = this._constructNode({ id: ROOT_ID, type: ROOT_TYPE, properties: {}, data: null });\n this._edges[ROOT_ID] = create({ inbound: [], outbound: [] });\n }\n\n /**\n * Alias for `findNode('root')`.\n */\n get root() {\n return this.findNode(ROOT_ID)!;\n }\n\n /**\n * Convert the graph to a JSON object.\n */\n toJSON({ id = ROOT_ID, maxLength = 32 }: { id?: string; maxLength?: number } = {}) {\n const toJSON = (node: Node, seen: string[] = []): any => {\n const nodes = this.nodes(node);\n const obj: Record<string, any> = {\n id: node.id.length > maxLength ? `${node.id.slice(0, maxLength - 3)}...` : 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) => {\n // Break cycles.\n const nextSeen = [...seen, node.id];\n return nextSeen.includes(n.id) ? undefined : toJSON(n, nextSeen);\n })\n .filter(nonNullable);\n }\n return obj;\n };\n\n const root = this.findNode(id);\n invariant(root, `Node not found: ${id}`);\n return toJSON(root);\n }\n\n /**\n * Find the node with the given id in the graph.\n *\n * If a node is not found within the graph and an `onInitialNode` callback is provided,\n * it is called with the id and type of the node, potentially initializing the node.\n */\n findNode(id: string): Node | undefined {\n const existingNode = this._nodes[id];\n if (!existingNode) {\n void this._onInitialNode?.(id);\n }\n\n return existingNode;\n }\n\n /**\n * Wait for a node to be added to the graph.\n *\n * If the node is already present in the graph, the promise resolves immediately.\n *\n * @param id The id of the node to wait for.\n * @param timeout The time in milliseconds to wait for the node to be added.\n */\n async waitForNode(id: string, timeout?: number): Promise<Node> {\n const trigger = this._waitingForNodes[id] ?? (this._waitingForNodes[id] = new Trigger<Node>());\n const node = this.findNode(id);\n if (node) {\n delete this._waitingForNodes[id];\n return node;\n }\n\n if (timeout === undefined) {\n return trigger.wait();\n } else {\n return asyncTimeout(trigger.wait(), timeout, `Node not found: ${id}`);\n }\n }\n\n /**\n * Nodes that this node is connected to in default order.\n */\n nodes<T = any, U extends Record<string, any> = Record<string, any>>(node: Node, options: NodesOptions<T, U> = {}) {\n const { relation, expansion, filter, type } = options;\n const nodes = this._getNodes({ node, relation, expansion, type });\n return nodes.filter((n) => untracked(() => !isActionLike(n))).filter((n) => filter?.(n, node) ?? true);\n }\n\n /**\n * Edges that this node is connected to in default order.\n */\n edges(node: Node, { relation = 'outbound' }: { relation?: Relation } = {}) {\n return this._edges[node.id]?.[relation] ?? [];\n }\n\n /**\n * Actions or action groups that this node is connected to in default order.\n */\n actions(node: Node, { expansion }: { expansion?: boolean } = {}) {\n return [\n ...this._getNodes({ node, expansion, type: ACTION_GROUP_TYPE }),\n ...this._getNodes({ node, expansion, type: ACTION_TYPE }),\n ];\n }\n\n async expand(node: Node, relation: Relation = 'outbound', type?: string) {\n const key = this._key(node, relation, type);\n const initialized = this._initialized[key];\n if (!initialized && this._onInitialNodes) {\n await this._onInitialNodes(node, relation, type);\n this._initialized[key] = true;\n }\n }\n\n private _key(node: Node, relation: Relation, type?: string) {\n return `${node.id}-${relation}-${type}`;\n }\n\n /**\n * Recursive depth-first traversal of the graph.\n *\n * @param options.node The node to start traversing from.\n * @param options.relation The relation to traverse graph edges.\n * @param options.visitor A callback which is called for each node visited during traversal.\n */\n traverse(\n { visitor, node = this.root, relation = 'outbound', expansion }: GraphTraversalOptions,\n path: string[] = [],\n ): void {\n // Break cycles.\n if (path.includes(node.id)) {\n return;\n }\n\n const shouldContinue = visitor(node, [...path, node.id]);\n if (shouldContinue === false) {\n return;\n }\n\n Object.values(this._getNodes({ node, relation, expansion })).forEach((child) =>\n this.traverse({ node: child, relation, visitor, expansion }, [...path, node.id]),\n );\n }\n\n /**\n * Recursive depth-first traversal of the graph wrapping each visitor call in an effect.\n *\n * @param options.node The node to start traversing from.\n * @param options.relation The relation to traverse graph edges.\n * @param options.visitor A callback which is called for each node visited during traversal.\n */\n subscribeTraverse(\n { visitor, node = this.root, relation = 'outbound', expansion }: GraphTraversalOptions,\n currentPath: string[] = [],\n ) {\n return effect(() => {\n const path = [...currentPath, node.id];\n const result = visitor(node, path);\n if (result === false) {\n return;\n }\n\n const nodes = this._getNodes({ node, relation, expansion });\n const nodeSubscriptions = nodes.map((n) => this.subscribeTraverse({ node: n, visitor, expansion }, path));\n\n return () => {\n nodeSubscriptions.forEach((unsubscribe) => unsubscribe());\n };\n });\n }\n\n /**\n * Get the path between two nodes in the graph.\n */\n getPath({ source = 'root', target }: { source?: string; target: string }): string[] | undefined {\n const start = this.findNode(source);\n if (!start) {\n return undefined;\n }\n\n let found: string[] | undefined;\n this.traverse({\n node: start,\n visitor: (node, path) => {\n if (found) {\n return false;\n }\n\n if (node.id === target) {\n found = path;\n }\n },\n });\n\n return found;\n }\n\n /**\n * Add nodes to the graph.\n *\n * @internal\n */\n _addNodes<TData = null, TProperties extends Record<string, any> = Record<string, any>>(\n nodes: NodeArg<TData, TProperties>[],\n ): Node<TData, TProperties>[] {\n return batch(() => nodes.map((node) => this._addNode(node)));\n }\n\n private _addNode<TData, TProperties extends Record<string, any> = Record<string, any>>({\n nodes,\n edges,\n ..._node\n }: NodeArg<TData, TProperties>): Node<TData, TProperties> {\n return untracked(() => {\n const existingNode = this._nodes[_node.id];\n const node = existingNode ?? this._constructNode({ data: null, properties: {}, ..._node });\n if (existingNode) {\n const { data, properties, type } = _node;\n if (data && data !== node.data) {\n node.data = data;\n }\n\n if (type !== node.type) {\n node.type = type;\n }\n\n for (const key in properties) {\n if (properties[key] !== node.properties[key]) {\n node.properties[key] = properties[key];\n }\n }\n } else {\n this._nodes[node.id] = node;\n this._edges[node.id] = create({ inbound: [], outbound: [] });\n }\n\n const trigger = this._waitingForNodes[node.id];\n if (trigger) {\n trigger.wake(node);\n delete this._waitingForNodes[node.id];\n }\n\n if (nodes) {\n nodes.forEach((subNode) => {\n this._addNode(subNode);\n this._addEdge({ source: node.id, target: subNode.id });\n });\n }\n\n if (edges) {\n edges.forEach(([id, relation]) =>\n relation === 'outbound'\n ? this._addEdge({ source: node.id, target: id })\n : this._addEdge({ source: id, target: node.id }),\n );\n }\n\n return node as unknown as Node<TData, TProperties>;\n });\n }\n\n /**\n * Remove nodes from the graph.\n *\n * @param ids The id of the node to remove.\n * @param edges Whether to remove edges connected to the node from the graph as well.\n * @internal\n */\n _removeNodes(ids: string[], edges = false) {\n batch(() => ids.forEach((id) => this._removeNode(id, edges)));\n }\n\n private _removeNode(id: string, edges = false) {\n untracked(() => {\n const node = this.findNode(id);\n if (!node) {\n return;\n }\n\n if (edges) {\n // Remove edges from connected nodes.\n this._getNodes({ node }).forEach((node) => {\n this._removeEdge({ source: id, target: node.id });\n });\n this._getNodes({ node, relation: 'inbound' }).forEach((node) => {\n this._removeEdge({ source: node.id, target: id });\n });\n\n // Remove edges from node.\n delete this._edges[id];\n }\n\n // Remove node.\n delete this._nodes[id];\n Object.keys(this._initialized)\n .filter((key) => key.startsWith(id))\n .forEach((key) => {\n delete this._initialized[key];\n });\n void this._onRemoveNode?.(id);\n });\n }\n\n /**\n * Add edges to the graph.\n *\n * @internal\n */\n _addEdges(edges: { source: string; target: string }[]) {\n batch(() => edges.forEach((edge) => this._addEdge(edge)));\n }\n\n private _addEdge({ source, target }: { source: string; target: string }) {\n untracked(() => {\n if (!this._edges[source]) {\n this._edges[source] = create({ inbound: [], outbound: [] });\n }\n if (!this._edges[target]) {\n this._edges[target] = create({ inbound: [], outbound: [] });\n }\n\n const sourceEdges = this._edges[source];\n if (!sourceEdges.outbound.includes(target)) {\n sourceEdges.outbound.push(target);\n }\n\n const targetEdges = this._edges[target];\n if (!targetEdges.inbound.includes(source)) {\n targetEdges.inbound.push(source);\n }\n });\n }\n\n /**\n * Remove edges from the graph.\n * @internal\n */\n _removeEdges(edges: { source: string; target: string }[]) {\n batch(() => edges.forEach((edge) => this._removeEdge(edge)));\n }\n\n private _removeEdge({ source, target }: { source: string; target: string }) {\n untracked(() => {\n batch(() => {\n const outboundIndex = this._edges[source]?.outbound.findIndex((id) => id === target);\n if (outboundIndex !== undefined && outboundIndex !== -1) {\n this._edges[source].outbound.splice(outboundIndex, 1);\n }\n\n const inboundIndex = this._edges[target]?.inbound.findIndex((id) => id === source);\n if (inboundIndex !== undefined && inboundIndex !== -1) {\n this._edges[target].inbound.splice(inboundIndex, 1);\n }\n });\n });\n }\n\n /**\n * Sort edges for a node.\n *\n * Edges not included in the sorted list are appended to the end of the list.\n *\n * @param nodeId The id of the node to sort edges for.\n * @param relation The relation of the edges from the node to sort.\n * @param edges The ordered list of edges.\n * @ignore\n */\n _sortEdges(nodeId: string, relation: Relation, edges: string[]) {\n untracked(() => {\n batch(() => {\n const current = this._edges[nodeId];\n if (current) {\n const unsorted = current[relation].filter((id) => !edges.includes(id)) ?? [];\n const sorted = edges.filter((id) => current[relation].includes(id)) ?? [];\n current[relation].splice(0, current[relation].length, ...[...sorted, ...unsorted]);\n }\n });\n });\n }\n\n private _constructNode = (node: Omit<Node, typeof graphSymbol>) => {\n return create<NodeInternal>({ ...node, [graphSymbol]: this });\n };\n\n private _getNodes({\n node,\n relation = 'outbound',\n type,\n expansion,\n }: {\n node: Node;\n relation?: Relation;\n type?: string;\n expansion?: boolean;\n }): Node[] {\n if (expansion) {\n void this.expand(node, relation, type);\n }\n\n const edges = this._edges[node.id];\n if (!edges) {\n return [];\n } else {\n return edges[relation]\n .map((id) => this._nodes[id])\n .filter(nonNullable)\n .filter((n) => !type || n.type === type);\n }\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { type MaybePromise, type MakeOptional } from '@dxos/util';\n\n/**\n * Represents a node in the graph.\n */\n// TODO(wittjosiah): Use Effect Schema.\nexport type Node<TData = any, TProperties extends Record<string, any> = Record<string, any>> = Readonly<{\n /**\n * Globally unique ID.\n */\n id: string;\n\n /**\n * Typename of the data the node represents.\n */\n type: 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<T = any, U extends Record<string, any> = Record<string, any>> = (\n node: Node<unknown, Record<string, any>>,\n connectedNode: Node,\n) => node is Node<T, U>;\n\nexport type Relation = 'outbound' | 'inbound';\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'\n> & {\n /** Will automatically add nodes with an edge from this node to each. */\n nodes?: NodeArg<unknown>[];\n\n /** Will automatically add specified edges. */\n edges?: [string, Relation][];\n};\n\n//\n// Actions\n//\n\nexport type InvokeParams = {\n /** Node the invoked action is connected to. */\n node: Node;\n\n caller?: string;\n};\n\nexport type ActionData = (params: InvokeParams) => MaybePromise<void>;\n\nexport type Action<TProperties extends Record<string, any> = Record<string, any>> = Readonly<\n Omit<Node<ActionData, TProperties>, 'properties'> & {\n properties: Readonly<TProperties>;\n }\n>;\n\nexport const isAction = (data: unknown): data is Action =>\n isGraphNode(data) ? typeof data.data === 'function' : false;\n\nexport const actionGroupSymbol = Symbol('ActionGroup');\n\nexport type ActionGroup = Readonly<\n Omit<Node<typeof actionGroupSymbol, Record<string, any>>, 'properties'> & {\n properties: Readonly<Record<string, any>>;\n }\n>;\n\nexport const isActionGroup = (data: unknown): data is ActionGroup =>\n isGraphNode(data) ? data.data === actionGroupSymbol : false;\n\nexport type ActionLike = Action | ActionGroup;\n\nexport const isActionLike = (data: unknown): data is Action | ActionGroup => isAction(data) || isActionGroup(data);\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Signal, effect, signal } from '@preact/signals-core';\n// import { yieldOrContinue } from 'main-thread-scheduling';\n\nimport { type UnsubscribeCallback } from '@dxos/async';\nimport { create } from '@dxos/echo-schema';\nimport { invariant } from '@dxos/invariant';\nimport { nonNullable } from '@dxos/util';\n\nimport { ACTION_GROUP_TYPE, ACTION_TYPE, Graph } from './graph';\nimport { type Relation, type NodeArg, type Node, type ActionData, actionGroupSymbol } from './node';\n\n/**\n * Graph builder extension for adding nodes to the graph based on just the node id.\n * This is useful for creating the first node in a graph or for hydrating cached nodes with data.\n *\n * @param params.id The id of the node to resolve.\n */\nexport type ResolverExtension = (params: { id: string }) => NodeArg<any> | undefined;\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<T = any> = (params: { node: Node<T> }) => NodeArg<any>[] | undefined;\n\n/**\n * Constrained case of the connector extension for more easily adding actions to the graph.\n */\nexport type ActionsExtension<T = any> = (params: {\n node: Node<T>;\n}) => Omit<NodeArg<ActionData>, 'type' | 'nodes' | 'edges'>[] | undefined;\n\n/**\n * Constrained case of the connector extension for more easily adding action groups to the graph.\n */\nexport type ActionGroupsExtension<T = any> = (params: {\n node: Node<T>;\n}) => Omit<NodeArg<typeof actionGroupSymbol>, 'type' | 'data' | 'nodes' | 'edges'>[] | undefined;\n\ntype GuardedNodeType<T> = T extends (value: any) => value is infer N ? (N extends Node<infer D> ? D : unknown) : never;\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.type If provided, all nodes returned are expected to have this type.\n * @param params.filter A filter function to determine if an extension should act on a node.\n * @param params.resolver A function to add nodes to the graph based on just the node id.\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 CreateExtensionOptions<T = any> = {\n id: string;\n relation?: Relation;\n type?: string;\n filter?: (node: Node) => node is Node<T>;\n resolver?: ResolverExtension;\n connector?: ConnectorExtension<GuardedNodeType<CreateExtensionOptions<T>['filter']>>;\n actions?: ActionsExtension<GuardedNodeType<CreateExtensionOptions<T>['filter']>>;\n actionGroups?: ActionGroupsExtension<GuardedNodeType<CreateExtensionOptions<T>['filter']>>;\n};\n\n/**\n * Create a graph builder extension.\n */\nexport const createExtension = <T = any>(extension: CreateExtensionOptions<T>): BuilderExtension[] => {\n const { id, resolver, connector, actions, actionGroups, ...rest } = extension;\n const getId = (key: string) => `${id}/${key}`;\n return [\n resolver ? { id: getId('resolver'), resolver } : undefined,\n connector ? { ...rest, id: getId('connector'), connector } : undefined,\n actionGroups\n ? ({\n ...rest,\n id: getId('actionGroups'),\n type: ACTION_GROUP_TYPE,\n relation: 'outbound',\n connector: ({ node }) =>\n actionGroups({ node })?.map((arg) => ({ ...arg, data: actionGroupSymbol, type: ACTION_GROUP_TYPE })),\n } satisfies BuilderExtension)\n : undefined,\n actions\n ? ({\n ...rest,\n id: getId('actions'),\n type: ACTION_TYPE,\n relation: 'outbound',\n connector: ({ node }) => actions({ node })?.map((arg) => ({ ...arg, type: ACTION_TYPE })),\n } satisfies BuilderExtension)\n : undefined,\n ].filter(nonNullable);\n};\n\nexport type GraphBuilderTraverseOptions = {\n node: Node;\n relation?: Relation;\n visitor: (node: Node, path: string[]) => void;\n};\n\n/**\n * The dispatcher is used to keep track of the current extension and state when memoizing functions.\n */\nclass Dispatcher {\n currentExtension?: string;\n stateIndex = 0;\n state: Record<string, any[]> = {};\n cleanup: (() => void)[] = [];\n}\n\nclass BuilderInternal {\n // This must be static to avoid passing the dispatcher instance to every memoized function.\n // If the dispatcher is not set that means that the memoized function is being called outside of the graph builder.\n static currentDispatcher?: Dispatcher;\n}\n\n/**\n * Allows code to be memoized within the context of a graph builder extension.\n * This is useful for creating instances which should be subscribed to rather than recreated.\n */\nexport const memoize = <T>(fn: () => T, key = 'result'): T => {\n const dispatcher = BuilderInternal.currentDispatcher;\n invariant(dispatcher?.currentExtension, 'memoize must be called within an extension');\n const all = dispatcher.state[dispatcher.currentExtension][dispatcher.stateIndex] ?? {};\n const current = all[key];\n const result = current ? current.result : fn();\n dispatcher.state[dispatcher.currentExtension][dispatcher.stateIndex] = { ...all, [key]: { result } };\n dispatcher.stateIndex++;\n return result;\n};\n\n/**\n * Register a cleanup function to be called when the graph builder is destroyed.\n */\nexport const cleanup = (fn: () => void): void => {\n memoize(() => {\n const dispatcher = BuilderInternal.currentDispatcher;\n invariant(dispatcher, 'cleanup must be called within an extension');\n dispatcher.cleanup.push(fn);\n });\n};\n\n/**\n * Convert a subscribe/get pair into a signal.\n */\nexport const toSignal = <T>(\n subscribe: (onChange: () => void) => () => void,\n get: () => T | undefined,\n key?: string,\n) => {\n const thisSignal = memoize(() => {\n return signal(get());\n }, key);\n const unsubscribe = memoize(() => {\n return subscribe(() => (thisSignal.value = get()));\n }, key);\n cleanup(() => {\n unsubscribe();\n });\n return thisSignal.value;\n};\n\nexport type BuilderExtension = {\n id: string;\n resolver?: ResolverExtension;\n connector?: ConnectorExtension;\n // Only for connector.\n relation?: Relation;\n type?: string;\n filter?: (node: Node) => boolean;\n};\n\ntype ExtensionArg = BuilderExtension | BuilderExtension[] | ExtensionArg[];\n\n/**\n * The builder provides an extensible way to compose the construction of the graph.\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.\nexport class GraphBuilder {\n private readonly _dispatcher = new Dispatcher();\n private readonly _extensions = create<Record<string, BuilderExtension>>({});\n private readonly _resolverSubscriptions = new Map<string, UnsubscribeCallback>();\n private readonly _connectorSubscriptions = new Map<string, UnsubscribeCallback>();\n private readonly _nodeChanged: Record<string, Signal<{}>> = {};\n private _graph: Graph;\n\n constructor() {\n this._graph = new Graph({\n onInitialNode: (id) => this._onInitialNode(id),\n onInitialNodes: (node, relation, type) => this._onInitialNodes(node, relation, type),\n onRemoveNode: (id) => this._onRemoveNode(id),\n });\n }\n\n get graph() {\n return this._graph;\n }\n\n /**\n * Register a node builder which will be called in order to construct the graph.\n */\n addExtension(extension: ExtensionArg): GraphBuilder {\n if (Array.isArray(extension)) {\n extension.forEach((ext) => this.addExtension(ext));\n return this;\n }\n\n this._dispatcher.state[extension.id] = [];\n this._extensions[extension.id] = extension;\n return this;\n }\n\n /**\n * Remove a node builder from the graph builder.\n */\n removeExtension(id: string): GraphBuilder {\n delete this._extensions[id];\n return this;\n }\n\n destroy() {\n this._dispatcher.cleanup.forEach((fn) => fn());\n this._resolverSubscriptions.forEach((unsubscribe) => unsubscribe());\n this._connectorSubscriptions.forEach((unsubscribe) => unsubscribe());\n this._resolverSubscriptions.clear();\n this._connectorSubscriptions.clear();\n }\n\n /**\n * Traverse a graph using just the connector extensions, without subscribing to any signals or persisting any nodes.\n */\n // TODO(wittjosiah): Rename? This is not traversing the graph proper.\n async traverse({ node, relation = 'outbound', visitor }: GraphBuilderTraverseOptions, path: string[] = []) {\n // Break cycles.\n if (path.includes(node.id)) {\n return;\n }\n\n // TODO(wittjosiah): Failed in test environment. ESM only?\n // await yieldOrContinue('idle');\n visitor(node, [...path, node.id]);\n\n const nodes = Object.values(this._extensions)\n .filter((extension) => relation === (extension.relation ?? 'outbound'))\n .flatMap((extension) => extension.connector?.({ node }) ?? [])\n .map(\n (arg): Node => ({\n id: arg.id,\n type: arg.type,\n data: arg.data ?? null,\n properties: arg.properties ?? {},\n }),\n );\n\n await Promise.all(nodes.map((n) => this.traverse({ node: n, relation, visitor }, [...path, node.id])));\n }\n\n private async _onInitialNode(nodeId: string) {\n this._nodeChanged[nodeId] = this._nodeChanged[nodeId] ?? signal({});\n this._resolverSubscriptions.set(\n nodeId,\n effect(() => {\n for (const { id, resolver } of Object.values(this._extensions)) {\n if (!resolver) {\n continue;\n }\n this._dispatcher.currentExtension = id;\n this._dispatcher.stateIndex = 0;\n BuilderInternal.currentDispatcher = this._dispatcher;\n const node = resolver({ id: nodeId });\n BuilderInternal.currentDispatcher = undefined;\n if (node) {\n this.graph._addNodes([node]);\n if (this._nodeChanged[node.id]) {\n this._nodeChanged[node.id].value = {};\n }\n break;\n }\n }\n }),\n );\n }\n\n private async _onInitialNodes(node: Node, nodesRelation: Relation, nodesType?: string) {\n this._nodeChanged[node.id] = this._nodeChanged[node.id] ?? signal({});\n let first = true;\n let previous: string[] = [];\n this._connectorSubscriptions.set(\n node.id,\n effect(() => {\n // TODO(wittjosiah): This is a workaround for a race between the node removal and the effect re-running.\n // To cause this case to happen, remove a collection and then undo the removal.\n if (!first && !this._connectorSubscriptions.has(node.id)) {\n return;\n }\n first = false;\n\n // Subscribe to extensions being added.\n Object.keys(this._extensions);\n // Subscribe to connected node changes.\n this._nodeChanged[node.id].value;\n\n // TODO(wittjosiah): Consider allowing extensions to collaborate on the same node by merging their results.\n const nodes: NodeArg<any>[] = [];\n for (const { id, connector, filter, type, relation = 'outbound' } of Object.values(this._extensions)) {\n if (\n !connector ||\n relation !== nodesRelation ||\n (nodesType && type !== nodesType) ||\n (filter && !filter(node))\n ) {\n continue;\n }\n\n this._dispatcher.currentExtension = id;\n this._dispatcher.stateIndex = 0;\n BuilderInternal.currentDispatcher = this._dispatcher;\n nodes.push(...(connector({ node }) ?? []));\n BuilderInternal.currentDispatcher = undefined;\n }\n const ids = nodes.map((n) => n.id);\n const removed = previous.filter((id) => !ids.includes(id));\n previous = ids;\n\n this.graph._removeNodes(removed, true);\n this.graph._addNodes(nodes);\n this.graph._addEdges(\n nodes.map(({ id }) =>\n nodesRelation === 'outbound' ? { source: node.id, target: id } : { source: id, target: node.id },\n ),\n );\n this.graph._sortEdges(\n node.id,\n nodesRelation,\n nodes.map(({ id }) => id),\n );\n nodes.forEach((n) => {\n if (this._nodeChanged[n.id]) {\n this._nodeChanged[n.id].value = {};\n }\n });\n }),\n );\n }\n\n private async _onRemoveNode(nodeId: string) {\n this._resolverSubscriptions.get(nodeId)?.();\n this._connectorSubscriptions.get(nodeId)?.();\n this._resolverSubscriptions.delete(nodeId);\n this._connectorSubscriptions.delete(nodeId);\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["batch", "effect", "untracked", "asyncTimeout", "Trigger", "create", "invariant", "nonNullable", "isGraphNode", "data", "properties", "isAction", "actionGroupSymbol", "Symbol", "isActionGroup", "isActionLike", "graphSymbol", "Symbol", "getGraph", "node", "graph", "invariant", "ROOT_ID", "ROOT_TYPE", "ACTION_TYPE", "ACTION_GROUP_TYPE", "Graph", "constructor", "onInitialNode", "onInitialNodes", "onRemoveNode", "_waitingForNodes", "_initialized", "_nodes", "_edges", "_constructNode", "create", "_onInitialNode", "_onInitialNodes", "_onRemoveNode", "id", "type", "properties", "data", "inbound", "outbound", "root", "findNode", "toJSON", "maxLength", "seen", "nodes", "obj", "length", "slice", "label", "map", "n", "nextSeen", "includes", "undefined", "filter", "nonNullable", "existingNode", "waitForNode", "timeout", "trigger", "Trigger", "wait", "asyncTimeout", "options", "relation", "expansion", "_getNodes", "untracked", "isActionLike", "edges", "actions", "expand", "key", "_key", "initialized", "traverse", "visitor", "path", "shouldContinue", "Object", "values", "forEach", "child", "subscribeTraverse", "currentPath", "effect", "result", "nodeSubscriptions", "unsubscribe", "getPath", "source", "target", "start", "found", "_addNodes", "batch", "_addNode", "_node", "wake", "subNode", "_addEdge", "_removeNodes", "ids", "_removeNode", "_removeEdge", "keys", "startsWith", "_addEdges", "edge", "sourceEdges", "push", "targetEdges", "_removeEdges", "outboundIndex", "findIndex", "splice", "inboundIndex", "_sortEdges", "nodeId", "current", "unsorted", "sorted", "effect", "signal", "create", "invariant", "nonNullable", "createExtension", "extension", "id", "resolver", "connector", "actions", "actionGroups", "rest", "getId", "key", "undefined", "type", "ACTION_GROUP_TYPE", "relation", "node", "map", "arg", "data", "actionGroupSymbol", "ACTION_TYPE", "filter", "nonNullable", "Dispatcher", "stateIndex", "state", "cleanup", "BuilderInternal", "memoize", "fn", "dispatcher", "currentDispatcher", "invariant", "currentExtension", "all", "current", "result", "push", "toSignal", "subscribe", "get", "thisSignal", "signal", "unsubscribe", "value", "GraphBuilder", "constructor", "_dispatcher", "_extensions", "create", "_resolverSubscriptions", "Map", "_connectorSubscriptions", "_nodeChanged", "_graph", "Graph", "onInitialNode", "_onInitialNode", "onInitialNodes", "_onInitialNodes", "onRemoveNode", "_onRemoveNode", "graph", "addExtension", "Array", "isArray", "forEach", "ext", "removeExtension", "destroy", "clear", "traverse", "visitor", "path", "includes", "nodes", "Object", "values", "flatMap", "properties", "Promise", "n", "nodeId", "set", "effect", "_addNodes", "nodesRelation", "nodesType", "first", "previous", "has", "keys", "ids", "removed", "_removeNodes", "_addEdges", "source", "target", "_sortEdges", "delete"]
4
+ "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { batch, effect, untracked } from '@preact/signals-core';\n\nimport { asyncTimeout, Trigger } from '@dxos/async';\nimport { type ReactiveObject, create } from '@dxos/echo-schema';\nimport { invariant } from '@dxos/invariant';\nimport { nonNullable } from '@dxos/util';\n\nimport { type Relation, type Node, type NodeArg, type NodeFilter, isActionLike } from './node';\n\nconst graphSymbol = Symbol('graph');\ntype DeepWriteable<T> = { -readonly [K in keyof T]: DeepWriteable<T[K]> };\ntype NodeInternal = DeepWriteable<Node> & { [graphSymbol]: Graph };\n\nexport const getGraph = (node: Node): Graph => {\n const graph = (node as NodeInternal)[graphSymbol];\n invariant(graph, 'Node is not associated with a graph.');\n return graph;\n};\n\nexport const ROOT_ID = 'root';\nexport const ROOT_TYPE = 'dxos.org/type/GraphRoot';\nexport const ACTION_TYPE = 'dxos.org/type/GraphAction';\nexport const ACTION_GROUP_TYPE = 'dxos.org/type/GraphActionGroup';\n\nexport type NodesOptions<T = any, U extends Record<string, any> = Record<string, any>> = {\n relation?: Relation;\n filter?: NodeFilter<T, U>;\n expansion?: boolean;\n type?: string;\n};\n\n// TODO(wittjosiah): Consider having default be undefined. This is current default for backwards compatibility.\nconst DEFAULT_FILTER = (node: Node) => untracked(() => !isActionLike(node));\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, path: string[]) => boolean | void;\n\n /**\n * The node to start traversing from.\n *\n * @default root\n */\n node?: Node;\n\n /**\n * The relation to traverse graph edges.\n *\n * @default 'outbound'\n */\n relation?: Relation;\n\n /**\n * Allow traversal to trigger expansion of the graph via `onInitialNodes`.\n */\n expansion?: boolean;\n};\n\n/**\n * The Graph represents the structure of the application constructed via plugins.\n */\nexport class Graph {\n private readonly _onInitialNode?: (id: string) => Promise<void>;\n private readonly _onInitialNodes?: (node: Node, relation: Relation, type?: string) => Promise<void>;\n private readonly _onRemoveNode?: (id: string) => Promise<void>;\n\n private readonly _waitingForNodes: Record<string, Trigger<Node>> = {};\n private readonly _initialized: Record<string, boolean> = {};\n\n /**\n * @internal\n */\n readonly _nodes: Record<string, ReactiveObject<NodeInternal>> = {};\n\n /**\n * @internal\n */\n readonly _edges: Record<string, ReactiveObject<{ inbound: string[]; outbound: string[] }>> = {};\n\n constructor({\n onInitialNode,\n onInitialNodes,\n onRemoveNode,\n }: {\n onInitialNode?: Graph['_onInitialNode'];\n onInitialNodes?: Graph['_onInitialNodes'];\n onRemoveNode?: Graph['_onRemoveNode'];\n } = {}) {\n this._onInitialNode = onInitialNode;\n this._onInitialNodes = onInitialNodes;\n this._onRemoveNode = onRemoveNode;\n this._nodes[ROOT_ID] = this._constructNode({ id: ROOT_ID, type: ROOT_TYPE, properties: {}, data: null });\n this._edges[ROOT_ID] = create({ inbound: [], outbound: [] });\n }\n\n /**\n * Alias for `findNode('root')`.\n */\n get root() {\n return this.findNode(ROOT_ID)!;\n }\n\n /**\n * Convert the graph to a JSON object.\n */\n toJSON({ id = ROOT_ID, maxLength = 32 }: { id?: string; maxLength?: number } = {}) {\n const toJSON = (node: Node, seen: string[] = []): any => {\n const nodes = this.nodes(node);\n const obj: Record<string, any> = {\n id: node.id.length > maxLength ? `${node.id.slice(0, maxLength - 3)}...` : 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) => {\n // Break cycles.\n const nextSeen = [...seen, node.id];\n return nextSeen.includes(n.id) ? undefined : toJSON(n, nextSeen);\n })\n .filter(nonNullable);\n }\n return obj;\n };\n\n const root = this.findNode(id);\n invariant(root, `Node not found: ${id}`);\n return toJSON(root);\n }\n\n /**\n * Find the node with the given id in the graph.\n *\n * If a node is not found within the graph and an `onInitialNode` callback is provided,\n * it is called with the id and type of the node, potentially initializing the node.\n */\n findNode(id: string): Node | undefined {\n const existingNode = this._nodes[id];\n if (!existingNode) {\n void this._onInitialNode?.(id);\n }\n\n return existingNode;\n }\n\n /**\n * Wait for a node to be added to the graph.\n *\n * If the node is already present in the graph, the promise resolves immediately.\n *\n * @param id The id of the node to wait for.\n * @param timeout The time in milliseconds to wait for the node to be added.\n */\n async waitForNode(id: string, timeout?: number): Promise<Node> {\n const trigger = this._waitingForNodes[id] ?? (this._waitingForNodes[id] = new Trigger<Node>());\n const node = this.findNode(id);\n if (node) {\n delete this._waitingForNodes[id];\n return node;\n }\n\n if (timeout === undefined) {\n return trigger.wait();\n } else {\n return asyncTimeout(trigger.wait(), timeout, `Node not found: ${id}`);\n }\n }\n\n /**\n * Nodes that this node is connected to in default order.\n */\n nodes<T = any, U extends Record<string, any> = Record<string, any>>(node: Node, options: NodesOptions<T, U> = {}) {\n const { relation, expansion, filter = DEFAULT_FILTER, type } = options;\n const nodes = this._getNodes({ node, relation, expansion, type });\n return nodes.filter((n) => filter(n, node));\n }\n\n /**\n * Edges that this node is connected to in default order.\n */\n edges(node: Node, { relation = 'outbound' }: { relation?: Relation } = {}) {\n return this._edges[node.id]?.[relation] ?? [];\n }\n\n /**\n * Actions or action groups that this node is connected to in default order.\n */\n actions(node: Node, { expansion }: { expansion?: boolean } = {}) {\n return [\n ...this._getNodes({ node, expansion, type: ACTION_GROUP_TYPE }),\n ...this._getNodes({ node, expansion, type: ACTION_TYPE }),\n ];\n }\n\n async expand(node: Node, relation: Relation = 'outbound', type?: string) {\n const key = this._key(node, relation, type);\n const initialized = this._initialized[key];\n if (!initialized && this._onInitialNodes) {\n await this._onInitialNodes(node, relation, type);\n this._initialized[key] = true;\n }\n }\n\n private _key(node: Node, relation: Relation, type?: string) {\n return `${node.id}-${relation}-${type}`;\n }\n\n /**\n * Recursive depth-first traversal of the graph.\n *\n * @param options.node The node to start traversing from.\n * @param options.relation The relation to traverse graph edges.\n * @param options.visitor A callback which is called for each node visited during traversal.\n */\n traverse(\n { visitor, node = this.root, relation = 'outbound', expansion }: GraphTraversalOptions,\n path: string[] = [],\n ): void {\n // Break cycles.\n if (path.includes(node.id)) {\n return;\n }\n\n const shouldContinue = visitor(node, [...path, node.id]);\n if (shouldContinue === false) {\n return;\n }\n\n Object.values(this._getNodes({ node, relation, expansion })).forEach((child) =>\n this.traverse({ node: child, relation, visitor, expansion }, [...path, node.id]),\n );\n }\n\n /**\n * Recursive depth-first traversal of the graph wrapping each visitor call in an effect.\n *\n * @param options.node The node to start traversing from.\n * @param options.relation The relation to traverse graph edges.\n * @param options.visitor A callback which is called for each node visited during traversal.\n */\n subscribeTraverse(\n { visitor, node = this.root, relation = 'outbound', expansion }: GraphTraversalOptions,\n currentPath: string[] = [],\n ) {\n return effect(() => {\n const path = [...currentPath, node.id];\n const result = visitor(node, path);\n if (result === false) {\n return;\n }\n\n const nodes = this._getNodes({ node, relation, expansion });\n const nodeSubscriptions = nodes.map((n) => this.subscribeTraverse({ node: n, visitor, expansion }, path));\n\n return () => {\n nodeSubscriptions.forEach((unsubscribe) => unsubscribe());\n };\n });\n }\n\n /**\n * Get the path between two nodes in the graph.\n */\n getPath({ source = 'root', target }: { source?: string; target: string }): string[] | undefined {\n const start = this.findNode(source);\n if (!start) {\n return undefined;\n }\n\n let found: string[] | undefined;\n this.traverse({\n node: start,\n visitor: (node, path) => {\n if (found) {\n return false;\n }\n\n if (node.id === target) {\n found = path;\n }\n },\n });\n\n return found;\n }\n\n /**\n * Add nodes to the graph.\n *\n * @internal\n */\n _addNodes<TData = null, TProperties extends Record<string, any> = Record<string, any>>(\n nodes: NodeArg<TData, TProperties>[],\n ): Node<TData, TProperties>[] {\n return batch(() => nodes.map((node) => this._addNode(node)));\n }\n\n private _addNode<TData, TProperties extends Record<string, any> = Record<string, any>>({\n nodes,\n edges,\n ..._node\n }: NodeArg<TData, TProperties>): Node<TData, TProperties> {\n return untracked(() => {\n const existingNode = this._nodes[_node.id];\n const node = existingNode ?? this._constructNode({ data: null, properties: {}, ..._node });\n if (existingNode) {\n const { data, properties, type } = _node;\n if (data && data !== node.data) {\n node.data = data;\n }\n\n if (type !== node.type) {\n node.type = type;\n }\n\n for (const key in properties) {\n if (properties[key] !== node.properties[key]) {\n node.properties[key] = properties[key];\n }\n }\n } else {\n this._nodes[node.id] = node;\n this._edges[node.id] = create({ inbound: [], outbound: [] });\n }\n\n const trigger = this._waitingForNodes[node.id];\n if (trigger) {\n trigger.wake(node);\n delete this._waitingForNodes[node.id];\n }\n\n if (nodes) {\n nodes.forEach((subNode) => {\n this._addNode(subNode);\n this._addEdge({ source: node.id, target: subNode.id });\n });\n }\n\n if (edges) {\n edges.forEach(([id, relation]) =>\n relation === 'outbound'\n ? this._addEdge({ source: node.id, target: id })\n : this._addEdge({ source: id, target: node.id }),\n );\n }\n\n return node as unknown as Node<TData, TProperties>;\n });\n }\n\n /**\n * Remove nodes from the graph.\n *\n * @param ids The id of the node to remove.\n * @param edges Whether to remove edges connected to the node from the graph as well.\n * @internal\n */\n _removeNodes(ids: string[], edges = false) {\n batch(() => ids.forEach((id) => this._removeNode(id, edges)));\n }\n\n private _removeNode(id: string, edges = false) {\n untracked(() => {\n const node = this.findNode(id);\n if (!node) {\n return;\n }\n\n if (edges) {\n // Remove edges from connected nodes.\n this._getNodes({ node }).forEach((node) => {\n this._removeEdge({ source: id, target: node.id });\n });\n this._getNodes({ node, relation: 'inbound' }).forEach((node) => {\n this._removeEdge({ source: node.id, target: id });\n });\n\n // Remove edges from node.\n delete this._edges[id];\n }\n\n // Remove node.\n delete this._nodes[id];\n Object.keys(this._initialized)\n .filter((key) => key.startsWith(id))\n .forEach((key) => {\n delete this._initialized[key];\n });\n void this._onRemoveNode?.(id);\n });\n }\n\n /**\n * Add edges to the graph.\n *\n * @internal\n */\n _addEdges(edges: { source: string; target: string }[]) {\n batch(() => edges.forEach((edge) => this._addEdge(edge)));\n }\n\n private _addEdge({ source, target }: { source: string; target: string }) {\n untracked(() => {\n if (!this._edges[source]) {\n this._edges[source] = create({ inbound: [], outbound: [] });\n }\n if (!this._edges[target]) {\n this._edges[target] = create({ inbound: [], outbound: [] });\n }\n\n const sourceEdges = this._edges[source];\n if (!sourceEdges.outbound.includes(target)) {\n sourceEdges.outbound.push(target);\n }\n\n const targetEdges = this._edges[target];\n if (!targetEdges.inbound.includes(source)) {\n targetEdges.inbound.push(source);\n }\n });\n }\n\n /**\n * Remove edges from the graph.\n * @internal\n */\n _removeEdges(edges: { source: string; target: string }[], removeOrphans = false) {\n batch(() => edges.forEach((edge) => this._removeEdge(edge, removeOrphans)));\n }\n\n private _removeEdge({ source, target }: { source: string; target: string }, removeOrphans = false) {\n untracked(() => {\n batch(() => {\n const outboundIndex = this._edges[source]?.outbound.findIndex((id) => id === target);\n if (outboundIndex !== undefined && outboundIndex !== -1) {\n this._edges[source].outbound.splice(outboundIndex, 1);\n }\n\n const inboundIndex = this._edges[target]?.inbound.findIndex((id) => id === source);\n if (inboundIndex !== undefined && inboundIndex !== -1) {\n this._edges[target].inbound.splice(inboundIndex, 1);\n }\n\n if (removeOrphans) {\n if (\n this._edges[source]?.outbound.length === 0 &&\n this._edges[source]?.inbound.length === 0 &&\n source !== ROOT_ID\n ) {\n this._removeNode(source, true);\n }\n if (\n this._edges[target]?.outbound.length === 0 &&\n this._edges[target]?.inbound.length === 0 &&\n target !== ROOT_ID\n ) {\n this._removeNode(target, true);\n }\n }\n });\n });\n }\n\n /**\n * Sort edges for a node.\n *\n * Edges not included in the sorted list are appended to the end of the list.\n *\n * @param nodeId The id of the node to sort edges for.\n * @param relation The relation of the edges from the node to sort.\n * @param edges The ordered list of edges.\n * @ignore\n */\n _sortEdges(nodeId: string, relation: Relation, edges: string[]) {\n untracked(() => {\n batch(() => {\n const current = this._edges[nodeId];\n if (current) {\n const unsorted = current[relation].filter((id) => !edges.includes(id)) ?? [];\n const sorted = edges.filter((id) => current[relation].includes(id)) ?? [];\n current[relation].splice(0, current[relation].length, ...[...sorted, ...unsorted]);\n }\n });\n });\n }\n\n private _constructNode = (node: Omit<Node, typeof graphSymbol>) => {\n return create<NodeInternal>({ ...node, [graphSymbol]: this });\n };\n\n private _getNodes({\n node,\n relation = 'outbound',\n type,\n expansion,\n }: {\n node: Node;\n relation?: Relation;\n type?: string;\n expansion?: boolean;\n }): Node[] {\n if (expansion) {\n void this.expand(node, relation, type);\n }\n\n const edges = this._edges[node.id];\n if (!edges) {\n return [];\n } else {\n return edges[relation]\n .map((id) => this._nodes[id])\n .filter(nonNullable)\n .filter((n) => !type || n.type === type);\n }\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { type MaybePromise, type MakeOptional } from '@dxos/util';\n\n/**\n * Represents a node in the graph.\n */\n// TODO(wittjosiah): Use Effect Schema.\nexport type Node<TData = any, TProperties extends Record<string, any> = Record<string, any>> = Readonly<{\n /**\n * Globally unique ID.\n */\n id: string;\n\n /**\n * Typename of the data the node represents.\n */\n type: 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<T = any, U extends Record<string, any> = Record<string, any>> = (\n node: Node<unknown, Record<string, any>>,\n connectedNode: Node,\n) => node is Node<T, U>;\n\nexport type Relation = 'outbound' | 'inbound';\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'\n> & {\n /** Will automatically add nodes with an edge from this node to each. */\n nodes?: NodeArg<unknown>[];\n\n /** Will automatically add specified edges. */\n edges?: [string, Relation][];\n};\n\n//\n// Actions\n//\n\nexport type InvokeParams = {\n /** Node the invoked action is connected to. */\n node: Node;\n\n caller?: string;\n};\n\nexport type ActionData = (params: InvokeParams) => MaybePromise<void>;\n\nexport type Action<TProperties extends Record<string, any> = Record<string, any>> = Readonly<\n Omit<Node<ActionData, TProperties>, 'properties'> & {\n properties: Readonly<TProperties>;\n }\n>;\n\nexport const isAction = (data: unknown): data is Action =>\n isGraphNode(data) ? typeof data.data === 'function' : false;\n\nexport const actionGroupSymbol = Symbol('ActionGroup');\n\nexport type ActionGroup = Readonly<\n Omit<Node<typeof actionGroupSymbol, Record<string, any>>, 'properties'> & {\n properties: Readonly<Record<string, any>>;\n }\n>;\n\nexport const isActionGroup = (data: unknown): data is ActionGroup =>\n isGraphNode(data) ? data.data === actionGroupSymbol : false;\n\nexport type ActionLike = Action | ActionGroup;\n\nexport const isActionLike = (data: unknown): data is Action | ActionGroup => isAction(data) || isActionGroup(data);\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Signal, effect, signal } from '@preact/signals-core';\n\nimport { type UnsubscribeCallback } from '@dxos/async';\nimport { create } from '@dxos/echo-schema';\nimport { invariant } from '@dxos/invariant';\nimport { isNode, type MaybePromise, nonNullable } from '@dxos/util';\n\nimport { ACTION_GROUP_TYPE, ACTION_TYPE, Graph } from './graph';\nimport { type Relation, type NodeArg, type Node, type ActionData, actionGroupSymbol } from './node';\n\n/**\n * Graph builder extension for adding nodes to the graph based on just the node id.\n * This is useful for creating the first node in a graph or for hydrating cached nodes with data.\n *\n * @param params.id The id of the node to resolve.\n */\nexport type ResolverExtension = (params: { id: string }) => NodeArg<any> | undefined;\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<T = any> = (params: { node: Node<T> }) => NodeArg<any>[] | undefined;\n\n/**\n * Constrained case of the connector extension for more easily adding actions to the graph.\n */\nexport type ActionsExtension<T = any> = (params: {\n node: Node<T>;\n}) => Omit<NodeArg<ActionData>, 'type' | 'nodes' | 'edges'>[] | undefined;\n\n/**\n * Constrained case of the connector extension for more easily adding action groups to the graph.\n */\nexport type ActionGroupsExtension<T = any> = (params: {\n node: Node<T>;\n}) => Omit<NodeArg<typeof actionGroupSymbol>, 'type' | 'data' | 'nodes' | 'edges'>[] | undefined;\n\ntype GuardedNodeType<T> = T extends (value: any) => value is infer N ? (N extends Node<infer D> ? D : unknown) : never;\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.type If provided, all nodes returned are expected to have this type.\n * @param params.filter A filter function to determine if an extension should act on a node.\n * @param params.resolver A function to add nodes to the graph based on just the node id.\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 CreateExtensionOptions<T = any> = {\n id: string;\n relation?: Relation;\n type?: string;\n filter?: (node: Node) => node is Node<T>;\n resolver?: ResolverExtension;\n connector?: ConnectorExtension<GuardedNodeType<CreateExtensionOptions<T>['filter']>>;\n actions?: ActionsExtension<GuardedNodeType<CreateExtensionOptions<T>['filter']>>;\n actionGroups?: ActionGroupsExtension<GuardedNodeType<CreateExtensionOptions<T>['filter']>>;\n};\n\n/**\n * Create a graph builder extension.\n */\nexport const createExtension = <T = any>(extension: CreateExtensionOptions<T>): BuilderExtension[] => {\n const { id, resolver, connector, actions, actionGroups, ...rest } = extension;\n const getId = (key: string) => `${id}/${key}`;\n return [\n resolver ? { id: getId('resolver'), resolver } : undefined,\n connector ? { ...rest, id: getId('connector'), connector } : undefined,\n actionGroups\n ? ({\n ...rest,\n id: getId('actionGroups'),\n type: ACTION_GROUP_TYPE,\n relation: 'outbound',\n connector: ({ node }) =>\n actionGroups({ node })?.map((arg) => ({ ...arg, data: actionGroupSymbol, type: ACTION_GROUP_TYPE })),\n } satisfies BuilderExtension)\n : undefined,\n actions\n ? ({\n ...rest,\n id: getId('actions'),\n type: ACTION_TYPE,\n relation: 'outbound',\n connector: ({ node }) => actions({ node })?.map((arg) => ({ ...arg, type: ACTION_TYPE })),\n } satisfies BuilderExtension)\n : undefined,\n ].filter(nonNullable);\n};\n\nexport type GraphBuilderTraverseOptions = {\n visitor: (node: Node, path: string[]) => MaybePromise<boolean | void>;\n node?: Node;\n relation?: Relation;\n};\n\n/**\n * The dispatcher is used to keep track of the current extension and state when memoizing functions.\n */\nclass Dispatcher {\n currentExtension?: string;\n stateIndex = 0;\n state: Record<string, any[]> = {};\n cleanup: (() => void)[] = [];\n}\n\nclass BuilderInternal {\n // This must be static to avoid passing the dispatcher instance to every memoized function.\n // If the dispatcher is not set that means that the memoized function is being called outside of the graph builder.\n static currentDispatcher?: Dispatcher;\n}\n\n/**\n * Allows code to be memoized within the context of a graph builder extension.\n * This is useful for creating instances which should be subscribed to rather than recreated.\n */\nexport const memoize = <T>(fn: () => T, key = 'result'): T => {\n const dispatcher = BuilderInternal.currentDispatcher;\n invariant(dispatcher?.currentExtension, 'memoize must be called within an extension');\n const all = dispatcher.state[dispatcher.currentExtension][dispatcher.stateIndex] ?? {};\n const current = all[key];\n const result = current ? current.result : fn();\n dispatcher.state[dispatcher.currentExtension][dispatcher.stateIndex] = { ...all, [key]: { result } };\n dispatcher.stateIndex++;\n return result;\n};\n\n/**\n * Register a cleanup function to be called when the graph builder is destroyed.\n */\nexport const cleanup = (fn: () => void): void => {\n memoize(() => {\n const dispatcher = BuilderInternal.currentDispatcher;\n invariant(dispatcher, 'cleanup must be called within an extension');\n dispatcher.cleanup.push(fn);\n });\n};\n\n/**\n * Convert a subscribe/get pair into a signal.\n */\nexport const toSignal = <T>(\n subscribe: (onChange: () => void) => () => void,\n get: () => T | undefined,\n key?: string,\n) => {\n const thisSignal = memoize(() => {\n return signal(get());\n }, key);\n const unsubscribe = memoize(() => {\n return subscribe(() => (thisSignal.value = get()));\n }, key);\n cleanup(() => {\n unsubscribe();\n });\n return thisSignal.value;\n};\n\nexport type BuilderExtension = {\n id: string;\n resolver?: ResolverExtension;\n connector?: ConnectorExtension;\n // Only for connector.\n relation?: Relation;\n type?: string;\n filter?: (node: Node) => boolean;\n};\n\ntype ExtensionArg = BuilderExtension | BuilderExtension[] | ExtensionArg[];\n\n/**\n * The builder provides an extensible way to compose the construction of the graph.\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.\nexport class GraphBuilder {\n private readonly _dispatcher = new Dispatcher();\n private readonly _extensions = create<Record<string, BuilderExtension>>({});\n private readonly _resolverSubscriptions = new Map<string, UnsubscribeCallback>();\n private readonly _connectorSubscriptions = new Map<string, UnsubscribeCallback>();\n private readonly _nodeChanged: Record<string, Signal<{}>> = {};\n private _graph: Graph;\n\n constructor() {\n this._graph = new Graph({\n onInitialNode: (id) => this._onInitialNode(id),\n onInitialNodes: (node, relation, type) => this._onInitialNodes(node, relation, type),\n onRemoveNode: (id) => this._onRemoveNode(id),\n });\n }\n\n get graph() {\n return this._graph;\n }\n\n /**\n * Register a node builder which will be called in order to construct the graph.\n */\n addExtension(extension: ExtensionArg): GraphBuilder {\n if (Array.isArray(extension)) {\n extension.forEach((ext) => this.addExtension(ext));\n return this;\n }\n\n this._dispatcher.state[extension.id] = [];\n this._extensions[extension.id] = extension;\n return this;\n }\n\n /**\n * Remove a node builder from the graph builder.\n */\n removeExtension(id: string): GraphBuilder {\n delete this._extensions[id];\n return this;\n }\n\n destroy() {\n this._dispatcher.cleanup.forEach((fn) => fn());\n this._resolverSubscriptions.forEach((unsubscribe) => unsubscribe());\n this._connectorSubscriptions.forEach((unsubscribe) => unsubscribe());\n this._resolverSubscriptions.clear();\n this._connectorSubscriptions.clear();\n }\n\n /**\n * A graph traversal using just the connector extensions, without subscribing to any signals or persisting any nodes.\n */\n async explore(\n { node = this._graph.root, relation = 'outbound', visitor }: GraphBuilderTraverseOptions,\n path: string[] = [],\n ) {\n // Break cycles.\n if (path.includes(node.id)) {\n return;\n }\n\n // TODO(wittjosiah): This is a workaround for esm not working in the test runner.\n // Switching to vitest is blocked by having node esm versions of echo-schema & echo-signals.\n if (!isNode()) {\n const { yieldOrContinue } = await import('main-thread-scheduling');\n await yieldOrContinue('idle');\n }\n const shouldContinue = await visitor(node, [...path, node.id]);\n if (shouldContinue === false) {\n return;\n }\n\n const nodes = Object.values(this._extensions)\n .filter((extension) => relation === (extension.relation ?? 'outbound'))\n .filter((extension) => !extension.filter || extension.filter(node))\n .flatMap((extension) => {\n this._dispatcher.currentExtension = extension.id;\n this._dispatcher.stateIndex = 0;\n BuilderInternal.currentDispatcher = this._dispatcher;\n const result = extension.connector?.({ node }) ?? [];\n BuilderInternal.currentDispatcher = undefined;\n return result;\n })\n .map(\n (arg): Node => ({\n id: arg.id,\n type: arg.type,\n data: arg.data ?? null,\n properties: arg.properties ?? {},\n }),\n );\n\n await Promise.all(nodes.map((n) => this.explore({ node: n, relation, visitor }, [...path, node.id])));\n }\n\n private async _onInitialNode(nodeId: string) {\n this._nodeChanged[nodeId] = this._nodeChanged[nodeId] ?? signal({});\n this._resolverSubscriptions.set(\n nodeId,\n effect(() => {\n for (const { id, resolver } of Object.values(this._extensions)) {\n if (!resolver) {\n continue;\n }\n this._dispatcher.currentExtension = id;\n this._dispatcher.stateIndex = 0;\n BuilderInternal.currentDispatcher = this._dispatcher;\n const node = resolver({ id: nodeId });\n BuilderInternal.currentDispatcher = undefined;\n if (node) {\n this.graph._addNodes([node]);\n if (this._nodeChanged[node.id]) {\n this._nodeChanged[node.id].value = {};\n }\n break;\n }\n }\n }),\n );\n }\n\n private async _onInitialNodes(node: Node, nodesRelation: Relation, nodesType?: string) {\n this._nodeChanged[node.id] = this._nodeChanged[node.id] ?? signal({});\n let first = true;\n let previous: string[] = [];\n this._connectorSubscriptions.set(\n node.id,\n effect(() => {\n // TODO(wittjosiah): This is a workaround for a race between the node removal and the effect re-running.\n // To cause this case to happen, remove a collection and then undo the removal.\n if (!first && !this._connectorSubscriptions.has(node.id)) {\n return;\n }\n first = false;\n\n // Subscribe to extensions being added.\n Object.keys(this._extensions);\n // Subscribe to connected node changes.\n this._nodeChanged[node.id].value;\n\n // TODO(wittjosiah): Consider allowing extensions to collaborate on the same node by merging their results.\n const nodes: NodeArg<any>[] = [];\n for (const { id, connector, filter, type, relation = 'outbound' } of Object.values(this._extensions)) {\n if (\n !connector ||\n relation !== nodesRelation ||\n (nodesType && type !== nodesType) ||\n (filter && !filter(node))\n ) {\n continue;\n }\n\n this._dispatcher.currentExtension = id;\n this._dispatcher.stateIndex = 0;\n BuilderInternal.currentDispatcher = this._dispatcher;\n nodes.push(...(connector({ node }) ?? []));\n BuilderInternal.currentDispatcher = undefined;\n }\n const ids = nodes.map((n) => n.id);\n const removed = previous.filter((id) => !ids.includes(id));\n previous = ids;\n\n // Remove edges and only remove nodes that are orphaned.\n this.graph._removeEdges(\n removed.map((target) => ({ source: node.id, target })),\n true,\n );\n this.graph._addNodes(nodes);\n this.graph._addEdges(\n nodes.map(({ id }) =>\n nodesRelation === 'outbound' ? { source: node.id, target: id } : { source: id, target: node.id },\n ),\n );\n this.graph._sortEdges(\n node.id,\n nodesRelation,\n nodes.map(({ id }) => id),\n );\n nodes.forEach((n) => {\n if (this._nodeChanged[n.id]) {\n this._nodeChanged[n.id].value = {};\n }\n });\n }),\n );\n }\n\n private async _onRemoveNode(nodeId: string) {\n this._resolverSubscriptions.get(nodeId)?.();\n this._connectorSubscriptions.get(nodeId)?.();\n this._resolverSubscriptions.delete(nodeId);\n this._connectorSubscriptions.delete(nodeId);\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["batch", "effect", "untracked", "asyncTimeout", "Trigger", "create", "invariant", "nonNullable", "isGraphNode", "data", "properties", "isAction", "actionGroupSymbol", "Symbol", "isActionGroup", "isActionLike", "graphSymbol", "Symbol", "getGraph", "node", "graph", "invariant", "ROOT_ID", "ROOT_TYPE", "ACTION_TYPE", "ACTION_GROUP_TYPE", "DEFAULT_FILTER", "untracked", "isActionLike", "Graph", "constructor", "onInitialNode", "onInitialNodes", "onRemoveNode", "_waitingForNodes", "_initialized", "_nodes", "_edges", "_constructNode", "create", "_onInitialNode", "_onInitialNodes", "_onRemoveNode", "id", "type", "properties", "data", "inbound", "outbound", "root", "findNode", "toJSON", "maxLength", "seen", "nodes", "obj", "length", "slice", "label", "map", "n", "nextSeen", "includes", "undefined", "filter", "nonNullable", "existingNode", "waitForNode", "timeout", "trigger", "Trigger", "wait", "asyncTimeout", "options", "relation", "expansion", "_getNodes", "edges", "actions", "expand", "key", "_key", "initialized", "traverse", "visitor", "path", "shouldContinue", "Object", "values", "forEach", "child", "subscribeTraverse", "currentPath", "effect", "result", "nodeSubscriptions", "unsubscribe", "getPath", "source", "target", "start", "found", "_addNodes", "batch", "_addNode", "_node", "wake", "subNode", "_addEdge", "_removeNodes", "ids", "_removeNode", "_removeEdge", "keys", "startsWith", "_addEdges", "edge", "sourceEdges", "push", "targetEdges", "_removeEdges", "removeOrphans", "outboundIndex", "findIndex", "splice", "inboundIndex", "_sortEdges", "nodeId", "current", "unsorted", "sorted", "effect", "signal", "create", "invariant", "isNode", "nonNullable", "createExtension", "extension", "id", "resolver", "connector", "actions", "actionGroups", "rest", "getId", "key", "undefined", "type", "ACTION_GROUP_TYPE", "relation", "node", "map", "arg", "data", "actionGroupSymbol", "ACTION_TYPE", "filter", "nonNullable", "Dispatcher", "stateIndex", "state", "cleanup", "BuilderInternal", "memoize", "fn", "dispatcher", "currentDispatcher", "invariant", "currentExtension", "all", "current", "result", "push", "toSignal", "subscribe", "get", "thisSignal", "signal", "unsubscribe", "value", "GraphBuilder", "constructor", "_dispatcher", "_extensions", "create", "_resolverSubscriptions", "Map", "_connectorSubscriptions", "_nodeChanged", "_graph", "Graph", "onInitialNode", "_onInitialNode", "onInitialNodes", "_onInitialNodes", "onRemoveNode", "_onRemoveNode", "graph", "addExtension", "Array", "isArray", "forEach", "ext", "removeExtension", "destroy", "clear", "explore", "root", "visitor", "path", "includes", "isNode", "yieldOrContinue", "shouldContinue", "nodes", "Object", "values", "flatMap", "properties", "Promise", "n", "nodeId", "set", "effect", "_addNodes", "nodesRelation", "nodesType", "first", "previous", "has", "keys", "ids", "removed", "_removeEdges", "target", "source", "_addEdges", "_sortEdges", "delete"]
7
7
  }
@@ -1 +1 @@
1
- {"inputs":{"packages/sdk/app-graph/src/node.ts":{"bytes":5259,"imports":[],"format":"esm"},"packages/sdk/app-graph/src/graph.ts":{"bytes":51067,"imports":[{"path":"@preact/signals-core","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"packages/sdk/app-graph/src/node.ts","kind":"import-statement","original":"./node"}],"format":"esm"},"packages/sdk/app-graph/src/graph-builder.ts":{"bytes":39059,"imports":[{"path":"@preact/signals-core","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"packages/sdk/app-graph/src/graph.ts","kind":"import-statement","original":"./graph"},{"path":"packages/sdk/app-graph/src/node.ts","kind":"import-statement","original":"./node"}],"format":"esm"},"packages/sdk/app-graph/src/index.ts":{"bytes":672,"imports":[{"path":"packages/sdk/app-graph/src/graph.ts","kind":"import-statement","original":"./graph"},{"path":"packages/sdk/app-graph/src/graph-builder.ts","kind":"import-statement","original":"./graph-builder"},{"path":"packages/sdk/app-graph/src/node.ts","kind":"import-statement","original":"./node"}],"format":"esm"}},"outputs":{"packages/sdk/app-graph/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":48553},"packages/sdk/app-graph/dist/lib/browser/index.mjs":{"imports":[{"path":"@preact/signals-core","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"@preact/signals-core","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"exports":["ACTION_GROUP_TYPE","ACTION_TYPE","Graph","GraphBuilder","ROOT_ID","ROOT_TYPE","actionGroupSymbol","cleanup","createExtension","getGraph","isAction","isActionGroup","isActionLike","isGraphNode","memoize","toSignal"],"entryPoint":"packages/sdk/app-graph/src/index.ts","inputs":{"packages/sdk/app-graph/src/graph.ts":{"bytesInOutput":12485},"packages/sdk/app-graph/src/node.ts":{"bytesInOutput":477},"packages/sdk/app-graph/src/index.ts":{"bytesInOutput":0},"packages/sdk/app-graph/src/graph-builder.ts":{"bytesInOutput":7661}},"bytes":21066}}}
1
+ {"inputs":{"packages/sdk/app-graph/src/node.ts":{"bytes":5259,"imports":[],"format":"esm"},"packages/sdk/app-graph/src/graph.ts":{"bytes":53358,"imports":[{"path":"@preact/signals-core","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"packages/sdk/app-graph/src/node.ts","kind":"import-statement","original":"./node"}],"format":"esm"},"packages/sdk/app-graph/src/graph-builder.ts":{"bytes":41710,"imports":[{"path":"@preact/signals-core","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"packages/sdk/app-graph/src/graph.ts","kind":"import-statement","original":"./graph"},{"path":"packages/sdk/app-graph/src/node.ts","kind":"import-statement","original":"./node"},{"path":"main-thread-scheduling","kind":"dynamic-import","external":true}],"format":"esm"},"packages/sdk/app-graph/src/index.ts":{"bytes":672,"imports":[{"path":"packages/sdk/app-graph/src/graph.ts","kind":"import-statement","original":"./graph"},{"path":"packages/sdk/app-graph/src/graph-builder.ts","kind":"import-statement","original":"./graph-builder"},{"path":"packages/sdk/app-graph/src/node.ts","kind":"import-statement","original":"./node"}],"format":"esm"}},"outputs":{"packages/sdk/app-graph/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":50969},"packages/sdk/app-graph/dist/lib/browser/index.mjs":{"imports":[{"path":"@preact/signals-core","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"@preact/signals-core","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"main-thread-scheduling","kind":"dynamic-import","external":true}],"exports":["ACTION_GROUP_TYPE","ACTION_TYPE","Graph","GraphBuilder","ROOT_ID","ROOT_TYPE","actionGroupSymbol","cleanup","createExtension","getGraph","isAction","isActionGroup","isActionLike","isGraphNode","memoize","toSignal"],"entryPoint":"packages/sdk/app-graph/src/index.ts","inputs":{"packages/sdk/app-graph/src/graph.ts":{"bytesInOutput":12978},"packages/sdk/app-graph/src/node.ts":{"bytesInOutput":477},"packages/sdk/app-graph/src/index.ts":{"bytesInOutput":0},"packages/sdk/app-graph/src/graph-builder.ts":{"bytesInOutput":8234}},"bytes":22132}}}
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
  var node_exports = {};
20
30
  __export(node_exports, {
@@ -69,6 +79,7 @@ var ROOT_ID = "root";
69
79
  var ROOT_TYPE = "dxos.org/type/GraphRoot";
70
80
  var ACTION_TYPE = "dxos.org/type/GraphAction";
71
81
  var ACTION_GROUP_TYPE = "dxos.org/type/GraphActionGroup";
82
+ var DEFAULT_FILTER = (node) => (0, import_signals_core.untracked)(() => !isActionLike(node));
72
83
  var Graph = class {
73
84
  constructor({ onInitialNode, onInitialNodes, onRemoveNode } = {}) {
74
85
  this._waitingForNodes = {};
@@ -128,7 +139,7 @@ var Graph = class {
128
139
  const root = this.findNode(id);
129
140
  (0, import_invariant.invariant)(root, `Node not found: ${id}`, {
130
141
  F: __dxlog_file,
131
- L: 134,
142
+ L: 137,
132
143
  S: this,
133
144
  A: [
134
145
  "root",
@@ -175,14 +186,14 @@ var Graph = class {
175
186
  * Nodes that this node is connected to in default order.
176
187
  */
177
188
  nodes(node, options = {}) {
178
- const { relation, expansion, filter, type } = options;
189
+ const { relation, expansion, filter = DEFAULT_FILTER, type } = options;
179
190
  const nodes = this._getNodes({
180
191
  node,
181
192
  relation,
182
193
  expansion,
183
194
  type
184
195
  });
185
- return nodes.filter((n) => (0, import_signals_core.untracked)(() => !isActionLike(n))).filter((n) => filter?.(n, node) ?? true);
196
+ return nodes.filter((n) => filter(n, node));
186
197
  }
187
198
  /**
188
199
  * Edges that this node is connected to in default order.
@@ -445,10 +456,10 @@ var Graph = class {
445
456
  * Remove edges from the graph.
446
457
  * @internal
447
458
  */
448
- _removeEdges(edges) {
449
- (0, import_signals_core.batch)(() => edges.forEach((edge) => this._removeEdge(edge)));
459
+ _removeEdges(edges, removeOrphans = false) {
460
+ (0, import_signals_core.batch)(() => edges.forEach((edge) => this._removeEdge(edge, removeOrphans)));
450
461
  }
451
- _removeEdge({ source, target }) {
462
+ _removeEdge({ source, target }, removeOrphans = false) {
452
463
  (0, import_signals_core.untracked)(() => {
453
464
  (0, import_signals_core.batch)(() => {
454
465
  const outboundIndex = this._edges[source]?.outbound.findIndex((id) => id === target);
@@ -459,6 +470,14 @@ var Graph = class {
459
470
  if (inboundIndex !== void 0 && inboundIndex !== -1) {
460
471
  this._edges[target].inbound.splice(inboundIndex, 1);
461
472
  }
473
+ if (removeOrphans) {
474
+ if (this._edges[source]?.outbound.length === 0 && this._edges[source]?.inbound.length === 0 && source !== ROOT_ID) {
475
+ this._removeNode(source, true);
476
+ }
477
+ if (this._edges[target]?.outbound.length === 0 && this._edges[target]?.inbound.length === 0 && target !== ROOT_ID) {
478
+ this._removeNode(target, true);
479
+ }
480
+ }
462
481
  });
463
482
  });
464
483
  }
@@ -553,7 +572,7 @@ var memoize = (fn, key = "result") => {
553
572
  const dispatcher = BuilderInternal.currentDispatcher;
554
573
  (0, import_invariant2.invariant)(dispatcher?.currentExtension, "memoize must be called within an extension", {
555
574
  F: __dxlog_file2,
556
- L: 129,
575
+ L: 128,
557
576
  S: void 0,
558
577
  A: [
559
578
  "dispatcher?.currentExtension",
@@ -577,7 +596,7 @@ var cleanup = (fn) => {
577
596
  const dispatcher = BuilderInternal.currentDispatcher;
578
597
  (0, import_invariant2.invariant)(dispatcher, "cleanup must be called within an extension", {
579
598
  F: __dxlog_file2,
580
- L: 144,
599
+ L: 143,
581
600
  S: void 0,
582
601
  A: [
583
602
  "dispatcher",
@@ -642,26 +661,39 @@ var GraphBuilder = class {
642
661
  this._connectorSubscriptions.clear();
643
662
  }
644
663
  /**
645
- * Traverse a graph using just the connector extensions, without subscribing to any signals or persisting any nodes.
664
+ * A graph traversal using just the connector extensions, without subscribing to any signals or persisting any nodes.
646
665
  */
647
- // TODO(wittjosiah): Rename? This is not traversing the graph proper.
648
- async traverse({ node, relation = "outbound", visitor }, path = []) {
666
+ async explore({ node = this._graph.root, relation = "outbound", visitor }, path = []) {
649
667
  if (path.includes(node.id)) {
650
668
  return;
651
669
  }
652
- visitor(node, [
670
+ if (!(0, import_util2.isNode)()) {
671
+ const { yieldOrContinue } = await import("main-thread-scheduling");
672
+ await yieldOrContinue("idle");
673
+ }
674
+ const shouldContinue = await visitor(node, [
653
675
  ...path,
654
676
  node.id
655
677
  ]);
656
- const nodes = Object.values(this._extensions).filter((extension) => relation === (extension.relation ?? "outbound")).flatMap((extension) => extension.connector?.({
657
- node
658
- }) ?? []).map((arg) => ({
678
+ if (shouldContinue === false) {
679
+ return;
680
+ }
681
+ const nodes = Object.values(this._extensions).filter((extension) => relation === (extension.relation ?? "outbound")).filter((extension) => !extension.filter || extension.filter(node)).flatMap((extension) => {
682
+ this._dispatcher.currentExtension = extension.id;
683
+ this._dispatcher.stateIndex = 0;
684
+ BuilderInternal.currentDispatcher = this._dispatcher;
685
+ const result = extension.connector?.({
686
+ node
687
+ }) ?? [];
688
+ BuilderInternal.currentDispatcher = void 0;
689
+ return result;
690
+ }).map((arg) => ({
659
691
  id: arg.id,
660
692
  type: arg.type,
661
693
  data: arg.data ?? null,
662
694
  properties: arg.properties ?? {}
663
695
  }));
664
- await Promise.all(nodes.map((n) => this.traverse({
696
+ await Promise.all(nodes.map((n) => this.explore({
665
697
  node: n,
666
698
  relation,
667
699
  visitor
@@ -723,7 +755,10 @@ var GraphBuilder = class {
723
755
  const ids = nodes.map((n) => n.id);
724
756
  const removed = previous.filter((id) => !ids.includes(id));
725
757
  previous = ids;
726
- this.graph._removeNodes(removed, true);
758
+ this.graph._removeEdges(removed.map((target) => ({
759
+ source: node.id,
760
+ target
761
+ })), true);
727
762
  this.graph._addNodes(nodes);
728
763
  this.graph._addEdges(nodes.map(({ id }) => nodesRelation === "outbound" ? {
729
764
  source: node.id,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/graph.ts", "../../../src/node.ts", "../../../src/graph-builder.ts"],
4
- "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { batch, effect, untracked } from '@preact/signals-core';\n\nimport { asyncTimeout, Trigger } from '@dxos/async';\nimport { type ReactiveObject, create } from '@dxos/echo-schema';\nimport { invariant } from '@dxos/invariant';\nimport { nonNullable } from '@dxos/util';\n\nimport { type Relation, type Node, type NodeArg, type NodeFilter, isActionLike } from './node';\n\nconst graphSymbol = Symbol('graph');\ntype DeepWriteable<T> = { -readonly [K in keyof T]: DeepWriteable<T[K]> };\ntype NodeInternal = DeepWriteable<Node> & { [graphSymbol]: Graph };\n\nexport const getGraph = (node: Node): Graph => {\n const graph = (node as NodeInternal)[graphSymbol];\n invariant(graph, 'Node is not associated with a graph.');\n return graph;\n};\n\nexport const ROOT_ID = 'root';\nexport const ROOT_TYPE = 'dxos.org/type/GraphRoot';\nexport const ACTION_TYPE = 'dxos.org/type/GraphAction';\nexport const ACTION_GROUP_TYPE = 'dxos.org/type/GraphActionGroup';\n\nexport type NodesOptions<T = any, U extends Record<string, any> = Record<string, any>> = {\n relation?: Relation;\n filter?: NodeFilter<T, U>;\n expansion?: boolean;\n type?: string;\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, path: string[]) => boolean | void;\n\n /**\n * The node to start traversing from.\n *\n * @default root\n */\n node?: Node;\n\n /**\n * The relation to traverse graph edges.\n *\n * @default 'outbound'\n */\n relation?: Relation;\n\n /**\n * Allow traversal to trigger expansion of the graph via `onInitialNodes`.\n */\n expansion?: boolean;\n};\n\n/**\n * The Graph represents the structure of the application constructed via plugins.\n */\nexport class Graph {\n private readonly _onInitialNode?: (id: string) => Promise<void>;\n private readonly _onInitialNodes?: (node: Node, relation: Relation, type?: string) => Promise<void>;\n private readonly _onRemoveNode?: (id: string) => Promise<void>;\n\n private readonly _waitingForNodes: Record<string, Trigger<Node>> = {};\n private readonly _initialized: Record<string, boolean> = {};\n\n /**\n * @internal\n */\n readonly _nodes: Record<string, ReactiveObject<NodeInternal>> = {};\n\n /**\n * @internal\n */\n readonly _edges: Record<string, ReactiveObject<{ inbound: string[]; outbound: string[] }>> = {};\n\n constructor({\n onInitialNode,\n onInitialNodes,\n onRemoveNode,\n }: {\n onInitialNode?: Graph['_onInitialNode'];\n onInitialNodes?: Graph['_onInitialNodes'];\n onRemoveNode?: Graph['_onRemoveNode'];\n } = {}) {\n this._onInitialNode = onInitialNode;\n this._onInitialNodes = onInitialNodes;\n this._onRemoveNode = onRemoveNode;\n this._nodes[ROOT_ID] = this._constructNode({ id: ROOT_ID, type: ROOT_TYPE, properties: {}, data: null });\n this._edges[ROOT_ID] = create({ inbound: [], outbound: [] });\n }\n\n /**\n * Alias for `findNode('root')`.\n */\n get root() {\n return this.findNode(ROOT_ID)!;\n }\n\n /**\n * Convert the graph to a JSON object.\n */\n toJSON({ id = ROOT_ID, maxLength = 32 }: { id?: string; maxLength?: number } = {}) {\n const toJSON = (node: Node, seen: string[] = []): any => {\n const nodes = this.nodes(node);\n const obj: Record<string, any> = {\n id: node.id.length > maxLength ? `${node.id.slice(0, maxLength - 3)}...` : 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) => {\n // Break cycles.\n const nextSeen = [...seen, node.id];\n return nextSeen.includes(n.id) ? undefined : toJSON(n, nextSeen);\n })\n .filter(nonNullable);\n }\n return obj;\n };\n\n const root = this.findNode(id);\n invariant(root, `Node not found: ${id}`);\n return toJSON(root);\n }\n\n /**\n * Find the node with the given id in the graph.\n *\n * If a node is not found within the graph and an `onInitialNode` callback is provided,\n * it is called with the id and type of the node, potentially initializing the node.\n */\n findNode(id: string): Node | undefined {\n const existingNode = this._nodes[id];\n if (!existingNode) {\n void this._onInitialNode?.(id);\n }\n\n return existingNode;\n }\n\n /**\n * Wait for a node to be added to the graph.\n *\n * If the node is already present in the graph, the promise resolves immediately.\n *\n * @param id The id of the node to wait for.\n * @param timeout The time in milliseconds to wait for the node to be added.\n */\n async waitForNode(id: string, timeout?: number): Promise<Node> {\n const trigger = this._waitingForNodes[id] ?? (this._waitingForNodes[id] = new Trigger<Node>());\n const node = this.findNode(id);\n if (node) {\n delete this._waitingForNodes[id];\n return node;\n }\n\n if (timeout === undefined) {\n return trigger.wait();\n } else {\n return asyncTimeout(trigger.wait(), timeout, `Node not found: ${id}`);\n }\n }\n\n /**\n * Nodes that this node is connected to in default order.\n */\n nodes<T = any, U extends Record<string, any> = Record<string, any>>(node: Node, options: NodesOptions<T, U> = {}) {\n const { relation, expansion, filter, type } = options;\n const nodes = this._getNodes({ node, relation, expansion, type });\n return nodes.filter((n) => untracked(() => !isActionLike(n))).filter((n) => filter?.(n, node) ?? true);\n }\n\n /**\n * Edges that this node is connected to in default order.\n */\n edges(node: Node, { relation = 'outbound' }: { relation?: Relation } = {}) {\n return this._edges[node.id]?.[relation] ?? [];\n }\n\n /**\n * Actions or action groups that this node is connected to in default order.\n */\n actions(node: Node, { expansion }: { expansion?: boolean } = {}) {\n return [\n ...this._getNodes({ node, expansion, type: ACTION_GROUP_TYPE }),\n ...this._getNodes({ node, expansion, type: ACTION_TYPE }),\n ];\n }\n\n async expand(node: Node, relation: Relation = 'outbound', type?: string) {\n const key = this._key(node, relation, type);\n const initialized = this._initialized[key];\n if (!initialized && this._onInitialNodes) {\n await this._onInitialNodes(node, relation, type);\n this._initialized[key] = true;\n }\n }\n\n private _key(node: Node, relation: Relation, type?: string) {\n return `${node.id}-${relation}-${type}`;\n }\n\n /**\n * Recursive depth-first traversal of the graph.\n *\n * @param options.node The node to start traversing from.\n * @param options.relation The relation to traverse graph edges.\n * @param options.visitor A callback which is called for each node visited during traversal.\n */\n traverse(\n { visitor, node = this.root, relation = 'outbound', expansion }: GraphTraversalOptions,\n path: string[] = [],\n ): void {\n // Break cycles.\n if (path.includes(node.id)) {\n return;\n }\n\n const shouldContinue = visitor(node, [...path, node.id]);\n if (shouldContinue === false) {\n return;\n }\n\n Object.values(this._getNodes({ node, relation, expansion })).forEach((child) =>\n this.traverse({ node: child, relation, visitor, expansion }, [...path, node.id]),\n );\n }\n\n /**\n * Recursive depth-first traversal of the graph wrapping each visitor call in an effect.\n *\n * @param options.node The node to start traversing from.\n * @param options.relation The relation to traverse graph edges.\n * @param options.visitor A callback which is called for each node visited during traversal.\n */\n subscribeTraverse(\n { visitor, node = this.root, relation = 'outbound', expansion }: GraphTraversalOptions,\n currentPath: string[] = [],\n ) {\n return effect(() => {\n const path = [...currentPath, node.id];\n const result = visitor(node, path);\n if (result === false) {\n return;\n }\n\n const nodes = this._getNodes({ node, relation, expansion });\n const nodeSubscriptions = nodes.map((n) => this.subscribeTraverse({ node: n, visitor, expansion }, path));\n\n return () => {\n nodeSubscriptions.forEach((unsubscribe) => unsubscribe());\n };\n });\n }\n\n /**\n * Get the path between two nodes in the graph.\n */\n getPath({ source = 'root', target }: { source?: string; target: string }): string[] | undefined {\n const start = this.findNode(source);\n if (!start) {\n return undefined;\n }\n\n let found: string[] | undefined;\n this.traverse({\n node: start,\n visitor: (node, path) => {\n if (found) {\n return false;\n }\n\n if (node.id === target) {\n found = path;\n }\n },\n });\n\n return found;\n }\n\n /**\n * Add nodes to the graph.\n *\n * @internal\n */\n _addNodes<TData = null, TProperties extends Record<string, any> = Record<string, any>>(\n nodes: NodeArg<TData, TProperties>[],\n ): Node<TData, TProperties>[] {\n return batch(() => nodes.map((node) => this._addNode(node)));\n }\n\n private _addNode<TData, TProperties extends Record<string, any> = Record<string, any>>({\n nodes,\n edges,\n ..._node\n }: NodeArg<TData, TProperties>): Node<TData, TProperties> {\n return untracked(() => {\n const existingNode = this._nodes[_node.id];\n const node = existingNode ?? this._constructNode({ data: null, properties: {}, ..._node });\n if (existingNode) {\n const { data, properties, type } = _node;\n if (data && data !== node.data) {\n node.data = data;\n }\n\n if (type !== node.type) {\n node.type = type;\n }\n\n for (const key in properties) {\n if (properties[key] !== node.properties[key]) {\n node.properties[key] = properties[key];\n }\n }\n } else {\n this._nodes[node.id] = node;\n this._edges[node.id] = create({ inbound: [], outbound: [] });\n }\n\n const trigger = this._waitingForNodes[node.id];\n if (trigger) {\n trigger.wake(node);\n delete this._waitingForNodes[node.id];\n }\n\n if (nodes) {\n nodes.forEach((subNode) => {\n this._addNode(subNode);\n this._addEdge({ source: node.id, target: subNode.id });\n });\n }\n\n if (edges) {\n edges.forEach(([id, relation]) =>\n relation === 'outbound'\n ? this._addEdge({ source: node.id, target: id })\n : this._addEdge({ source: id, target: node.id }),\n );\n }\n\n return node as unknown as Node<TData, TProperties>;\n });\n }\n\n /**\n * Remove nodes from the graph.\n *\n * @param ids The id of the node to remove.\n * @param edges Whether to remove edges connected to the node from the graph as well.\n * @internal\n */\n _removeNodes(ids: string[], edges = false) {\n batch(() => ids.forEach((id) => this._removeNode(id, edges)));\n }\n\n private _removeNode(id: string, edges = false) {\n untracked(() => {\n const node = this.findNode(id);\n if (!node) {\n return;\n }\n\n if (edges) {\n // Remove edges from connected nodes.\n this._getNodes({ node }).forEach((node) => {\n this._removeEdge({ source: id, target: node.id });\n });\n this._getNodes({ node, relation: 'inbound' }).forEach((node) => {\n this._removeEdge({ source: node.id, target: id });\n });\n\n // Remove edges from node.\n delete this._edges[id];\n }\n\n // Remove node.\n delete this._nodes[id];\n Object.keys(this._initialized)\n .filter((key) => key.startsWith(id))\n .forEach((key) => {\n delete this._initialized[key];\n });\n void this._onRemoveNode?.(id);\n });\n }\n\n /**\n * Add edges to the graph.\n *\n * @internal\n */\n _addEdges(edges: { source: string; target: string }[]) {\n batch(() => edges.forEach((edge) => this._addEdge(edge)));\n }\n\n private _addEdge({ source, target }: { source: string; target: string }) {\n untracked(() => {\n if (!this._edges[source]) {\n this._edges[source] = create({ inbound: [], outbound: [] });\n }\n if (!this._edges[target]) {\n this._edges[target] = create({ inbound: [], outbound: [] });\n }\n\n const sourceEdges = this._edges[source];\n if (!sourceEdges.outbound.includes(target)) {\n sourceEdges.outbound.push(target);\n }\n\n const targetEdges = this._edges[target];\n if (!targetEdges.inbound.includes(source)) {\n targetEdges.inbound.push(source);\n }\n });\n }\n\n /**\n * Remove edges from the graph.\n * @internal\n */\n _removeEdges(edges: { source: string; target: string }[]) {\n batch(() => edges.forEach((edge) => this._removeEdge(edge)));\n }\n\n private _removeEdge({ source, target }: { source: string; target: string }) {\n untracked(() => {\n batch(() => {\n const outboundIndex = this._edges[source]?.outbound.findIndex((id) => id === target);\n if (outboundIndex !== undefined && outboundIndex !== -1) {\n this._edges[source].outbound.splice(outboundIndex, 1);\n }\n\n const inboundIndex = this._edges[target]?.inbound.findIndex((id) => id === source);\n if (inboundIndex !== undefined && inboundIndex !== -1) {\n this._edges[target].inbound.splice(inboundIndex, 1);\n }\n });\n });\n }\n\n /**\n * Sort edges for a node.\n *\n * Edges not included in the sorted list are appended to the end of the list.\n *\n * @param nodeId The id of the node to sort edges for.\n * @param relation The relation of the edges from the node to sort.\n * @param edges The ordered list of edges.\n * @ignore\n */\n _sortEdges(nodeId: string, relation: Relation, edges: string[]) {\n untracked(() => {\n batch(() => {\n const current = this._edges[nodeId];\n if (current) {\n const unsorted = current[relation].filter((id) => !edges.includes(id)) ?? [];\n const sorted = edges.filter((id) => current[relation].includes(id)) ?? [];\n current[relation].splice(0, current[relation].length, ...[...sorted, ...unsorted]);\n }\n });\n });\n }\n\n private _constructNode = (node: Omit<Node, typeof graphSymbol>) => {\n return create<NodeInternal>({ ...node, [graphSymbol]: this });\n };\n\n private _getNodes({\n node,\n relation = 'outbound',\n type,\n expansion,\n }: {\n node: Node;\n relation?: Relation;\n type?: string;\n expansion?: boolean;\n }): Node[] {\n if (expansion) {\n void this.expand(node, relation, type);\n }\n\n const edges = this._edges[node.id];\n if (!edges) {\n return [];\n } else {\n return edges[relation]\n .map((id) => this._nodes[id])\n .filter(nonNullable)\n .filter((n) => !type || n.type === type);\n }\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { type MaybePromise, type MakeOptional } from '@dxos/util';\n\n/**\n * Represents a node in the graph.\n */\n// TODO(wittjosiah): Use Effect Schema.\nexport type Node<TData = any, TProperties extends Record<string, any> = Record<string, any>> = Readonly<{\n /**\n * Globally unique ID.\n */\n id: string;\n\n /**\n * Typename of the data the node represents.\n */\n type: 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<T = any, U extends Record<string, any> = Record<string, any>> = (\n node: Node<unknown, Record<string, any>>,\n connectedNode: Node,\n) => node is Node<T, U>;\n\nexport type Relation = 'outbound' | 'inbound';\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'\n> & {\n /** Will automatically add nodes with an edge from this node to each. */\n nodes?: NodeArg<unknown>[];\n\n /** Will automatically add specified edges. */\n edges?: [string, Relation][];\n};\n\n//\n// Actions\n//\n\nexport type InvokeParams = {\n /** Node the invoked action is connected to. */\n node: Node;\n\n caller?: string;\n};\n\nexport type ActionData = (params: InvokeParams) => MaybePromise<void>;\n\nexport type Action<TProperties extends Record<string, any> = Record<string, any>> = Readonly<\n Omit<Node<ActionData, TProperties>, 'properties'> & {\n properties: Readonly<TProperties>;\n }\n>;\n\nexport const isAction = (data: unknown): data is Action =>\n isGraphNode(data) ? typeof data.data === 'function' : false;\n\nexport const actionGroupSymbol = Symbol('ActionGroup');\n\nexport type ActionGroup = Readonly<\n Omit<Node<typeof actionGroupSymbol, Record<string, any>>, 'properties'> & {\n properties: Readonly<Record<string, any>>;\n }\n>;\n\nexport const isActionGroup = (data: unknown): data is ActionGroup =>\n isGraphNode(data) ? data.data === actionGroupSymbol : false;\n\nexport type ActionLike = Action | ActionGroup;\n\nexport const isActionLike = (data: unknown): data is Action | ActionGroup => isAction(data) || isActionGroup(data);\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Signal, effect, signal } from '@preact/signals-core';\n// import { yieldOrContinue } from 'main-thread-scheduling';\n\nimport { type UnsubscribeCallback } from '@dxos/async';\nimport { create } from '@dxos/echo-schema';\nimport { invariant } from '@dxos/invariant';\nimport { nonNullable } from '@dxos/util';\n\nimport { ACTION_GROUP_TYPE, ACTION_TYPE, Graph } from './graph';\nimport { type Relation, type NodeArg, type Node, type ActionData, actionGroupSymbol } from './node';\n\n/**\n * Graph builder extension for adding nodes to the graph based on just the node id.\n * This is useful for creating the first node in a graph or for hydrating cached nodes with data.\n *\n * @param params.id The id of the node to resolve.\n */\nexport type ResolverExtension = (params: { id: string }) => NodeArg<any> | undefined;\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<T = any> = (params: { node: Node<T> }) => NodeArg<any>[] | undefined;\n\n/**\n * Constrained case of the connector extension for more easily adding actions to the graph.\n */\nexport type ActionsExtension<T = any> = (params: {\n node: Node<T>;\n}) => Omit<NodeArg<ActionData>, 'type' | 'nodes' | 'edges'>[] | undefined;\n\n/**\n * Constrained case of the connector extension for more easily adding action groups to the graph.\n */\nexport type ActionGroupsExtension<T = any> = (params: {\n node: Node<T>;\n}) => Omit<NodeArg<typeof actionGroupSymbol>, 'type' | 'data' | 'nodes' | 'edges'>[] | undefined;\n\ntype GuardedNodeType<T> = T extends (value: any) => value is infer N ? (N extends Node<infer D> ? D : unknown) : never;\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.type If provided, all nodes returned are expected to have this type.\n * @param params.filter A filter function to determine if an extension should act on a node.\n * @param params.resolver A function to add nodes to the graph based on just the node id.\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 CreateExtensionOptions<T = any> = {\n id: string;\n relation?: Relation;\n type?: string;\n filter?: (node: Node) => node is Node<T>;\n resolver?: ResolverExtension;\n connector?: ConnectorExtension<GuardedNodeType<CreateExtensionOptions<T>['filter']>>;\n actions?: ActionsExtension<GuardedNodeType<CreateExtensionOptions<T>['filter']>>;\n actionGroups?: ActionGroupsExtension<GuardedNodeType<CreateExtensionOptions<T>['filter']>>;\n};\n\n/**\n * Create a graph builder extension.\n */\nexport const createExtension = <T = any>(extension: CreateExtensionOptions<T>): BuilderExtension[] => {\n const { id, resolver, connector, actions, actionGroups, ...rest } = extension;\n const getId = (key: string) => `${id}/${key}`;\n return [\n resolver ? { id: getId('resolver'), resolver } : undefined,\n connector ? { ...rest, id: getId('connector'), connector } : undefined,\n actionGroups\n ? ({\n ...rest,\n id: getId('actionGroups'),\n type: ACTION_GROUP_TYPE,\n relation: 'outbound',\n connector: ({ node }) =>\n actionGroups({ node })?.map((arg) => ({ ...arg, data: actionGroupSymbol, type: ACTION_GROUP_TYPE })),\n } satisfies BuilderExtension)\n : undefined,\n actions\n ? ({\n ...rest,\n id: getId('actions'),\n type: ACTION_TYPE,\n relation: 'outbound',\n connector: ({ node }) => actions({ node })?.map((arg) => ({ ...arg, type: ACTION_TYPE })),\n } satisfies BuilderExtension)\n : undefined,\n ].filter(nonNullable);\n};\n\nexport type GraphBuilderTraverseOptions = {\n node: Node;\n relation?: Relation;\n visitor: (node: Node, path: string[]) => void;\n};\n\n/**\n * The dispatcher is used to keep track of the current extension and state when memoizing functions.\n */\nclass Dispatcher {\n currentExtension?: string;\n stateIndex = 0;\n state: Record<string, any[]> = {};\n cleanup: (() => void)[] = [];\n}\n\nclass BuilderInternal {\n // This must be static to avoid passing the dispatcher instance to every memoized function.\n // If the dispatcher is not set that means that the memoized function is being called outside of the graph builder.\n static currentDispatcher?: Dispatcher;\n}\n\n/**\n * Allows code to be memoized within the context of a graph builder extension.\n * This is useful for creating instances which should be subscribed to rather than recreated.\n */\nexport const memoize = <T>(fn: () => T, key = 'result'): T => {\n const dispatcher = BuilderInternal.currentDispatcher;\n invariant(dispatcher?.currentExtension, 'memoize must be called within an extension');\n const all = dispatcher.state[dispatcher.currentExtension][dispatcher.stateIndex] ?? {};\n const current = all[key];\n const result = current ? current.result : fn();\n dispatcher.state[dispatcher.currentExtension][dispatcher.stateIndex] = { ...all, [key]: { result } };\n dispatcher.stateIndex++;\n return result;\n};\n\n/**\n * Register a cleanup function to be called when the graph builder is destroyed.\n */\nexport const cleanup = (fn: () => void): void => {\n memoize(() => {\n const dispatcher = BuilderInternal.currentDispatcher;\n invariant(dispatcher, 'cleanup must be called within an extension');\n dispatcher.cleanup.push(fn);\n });\n};\n\n/**\n * Convert a subscribe/get pair into a signal.\n */\nexport const toSignal = <T>(\n subscribe: (onChange: () => void) => () => void,\n get: () => T | undefined,\n key?: string,\n) => {\n const thisSignal = memoize(() => {\n return signal(get());\n }, key);\n const unsubscribe = memoize(() => {\n return subscribe(() => (thisSignal.value = get()));\n }, key);\n cleanup(() => {\n unsubscribe();\n });\n return thisSignal.value;\n};\n\nexport type BuilderExtension = {\n id: string;\n resolver?: ResolverExtension;\n connector?: ConnectorExtension;\n // Only for connector.\n relation?: Relation;\n type?: string;\n filter?: (node: Node) => boolean;\n};\n\ntype ExtensionArg = BuilderExtension | BuilderExtension[] | ExtensionArg[];\n\n/**\n * The builder provides an extensible way to compose the construction of the graph.\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.\nexport class GraphBuilder {\n private readonly _dispatcher = new Dispatcher();\n private readonly _extensions = create<Record<string, BuilderExtension>>({});\n private readonly _resolverSubscriptions = new Map<string, UnsubscribeCallback>();\n private readonly _connectorSubscriptions = new Map<string, UnsubscribeCallback>();\n private readonly _nodeChanged: Record<string, Signal<{}>> = {};\n private _graph: Graph;\n\n constructor() {\n this._graph = new Graph({\n onInitialNode: (id) => this._onInitialNode(id),\n onInitialNodes: (node, relation, type) => this._onInitialNodes(node, relation, type),\n onRemoveNode: (id) => this._onRemoveNode(id),\n });\n }\n\n get graph() {\n return this._graph;\n }\n\n /**\n * Register a node builder which will be called in order to construct the graph.\n */\n addExtension(extension: ExtensionArg): GraphBuilder {\n if (Array.isArray(extension)) {\n extension.forEach((ext) => this.addExtension(ext));\n return this;\n }\n\n this._dispatcher.state[extension.id] = [];\n this._extensions[extension.id] = extension;\n return this;\n }\n\n /**\n * Remove a node builder from the graph builder.\n */\n removeExtension(id: string): GraphBuilder {\n delete this._extensions[id];\n return this;\n }\n\n destroy() {\n this._dispatcher.cleanup.forEach((fn) => fn());\n this._resolverSubscriptions.forEach((unsubscribe) => unsubscribe());\n this._connectorSubscriptions.forEach((unsubscribe) => unsubscribe());\n this._resolverSubscriptions.clear();\n this._connectorSubscriptions.clear();\n }\n\n /**\n * Traverse a graph using just the connector extensions, without subscribing to any signals or persisting any nodes.\n */\n // TODO(wittjosiah): Rename? This is not traversing the graph proper.\n async traverse({ node, relation = 'outbound', visitor }: GraphBuilderTraverseOptions, path: string[] = []) {\n // Break cycles.\n if (path.includes(node.id)) {\n return;\n }\n\n // TODO(wittjosiah): Failed in test environment. ESM only?\n // await yieldOrContinue('idle');\n visitor(node, [...path, node.id]);\n\n const nodes = Object.values(this._extensions)\n .filter((extension) => relation === (extension.relation ?? 'outbound'))\n .flatMap((extension) => extension.connector?.({ node }) ?? [])\n .map(\n (arg): Node => ({\n id: arg.id,\n type: arg.type,\n data: arg.data ?? null,\n properties: arg.properties ?? {},\n }),\n );\n\n await Promise.all(nodes.map((n) => this.traverse({ node: n, relation, visitor }, [...path, node.id])));\n }\n\n private async _onInitialNode(nodeId: string) {\n this._nodeChanged[nodeId] = this._nodeChanged[nodeId] ?? signal({});\n this._resolverSubscriptions.set(\n nodeId,\n effect(() => {\n for (const { id, resolver } of Object.values(this._extensions)) {\n if (!resolver) {\n continue;\n }\n this._dispatcher.currentExtension = id;\n this._dispatcher.stateIndex = 0;\n BuilderInternal.currentDispatcher = this._dispatcher;\n const node = resolver({ id: nodeId });\n BuilderInternal.currentDispatcher = undefined;\n if (node) {\n this.graph._addNodes([node]);\n if (this._nodeChanged[node.id]) {\n this._nodeChanged[node.id].value = {};\n }\n break;\n }\n }\n }),\n );\n }\n\n private async _onInitialNodes(node: Node, nodesRelation: Relation, nodesType?: string) {\n this._nodeChanged[node.id] = this._nodeChanged[node.id] ?? signal({});\n let first = true;\n let previous: string[] = [];\n this._connectorSubscriptions.set(\n node.id,\n effect(() => {\n // TODO(wittjosiah): This is a workaround for a race between the node removal and the effect re-running.\n // To cause this case to happen, remove a collection and then undo the removal.\n if (!first && !this._connectorSubscriptions.has(node.id)) {\n return;\n }\n first = false;\n\n // Subscribe to extensions being added.\n Object.keys(this._extensions);\n // Subscribe to connected node changes.\n this._nodeChanged[node.id].value;\n\n // TODO(wittjosiah): Consider allowing extensions to collaborate on the same node by merging their results.\n const nodes: NodeArg<any>[] = [];\n for (const { id, connector, filter, type, relation = 'outbound' } of Object.values(this._extensions)) {\n if (\n !connector ||\n relation !== nodesRelation ||\n (nodesType && type !== nodesType) ||\n (filter && !filter(node))\n ) {\n continue;\n }\n\n this._dispatcher.currentExtension = id;\n this._dispatcher.stateIndex = 0;\n BuilderInternal.currentDispatcher = this._dispatcher;\n nodes.push(...(connector({ node }) ?? []));\n BuilderInternal.currentDispatcher = undefined;\n }\n const ids = nodes.map((n) => n.id);\n const removed = previous.filter((id) => !ids.includes(id));\n previous = ids;\n\n this.graph._removeNodes(removed, true);\n this.graph._addNodes(nodes);\n this.graph._addEdges(\n nodes.map(({ id }) =>\n nodesRelation === 'outbound' ? { source: node.id, target: id } : { source: id, target: node.id },\n ),\n );\n this.graph._sortEdges(\n node.id,\n nodesRelation,\n nodes.map(({ id }) => id),\n );\n nodes.forEach((n) => {\n if (this._nodeChanged[n.id]) {\n this._nodeChanged[n.id].value = {};\n }\n });\n }),\n );\n }\n\n private async _onRemoveNode(nodeId: string) {\n this._resolverSubscriptions.get(nodeId)?.();\n this._connectorSubscriptions.get(nodeId)?.();\n this._resolverSubscriptions.delete(nodeId);\n this._connectorSubscriptions.delete(nodeId);\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["import_signals_core", "import_echo_schema", "import_invariant", "import_util", "isGraphNode", "data", "properties", "isAction", "actionGroupSymbol", "Symbol", "isActionGroup", "isActionLike", "graphSymbol", "getGraph", "node", "graph", "invariant", "ROOT_ID", "ROOT_TYPE", "ACTION_TYPE", "ACTION_GROUP_TYPE", "Graph", "constructor", "onInitialNode", "onInitialNodes", "onRemoveNode", "_waitingForNodes", "_initialized", "_constructNode", "create", "_onInitialNode", "_onInitialNodes", "_onRemoveNode", "_nodes", "id", "type", "_edges", "inbound", "outbound", "root", "findNode", "toJSON", "maxLength", "seen", "nodes", "obj", "length", "slice", "label", "map", "n", "nextSeen", "includes", "undefined", "filter", "nonNullable", "existingNode", "waitForNode", "timeout", "trigger", "Trigger", "wait", "asyncTimeout", "options", "relation", "expansion", "_getNodes", "untracked", "edges", "actions", "expand", "key", "_key", "initialized", "traverse", "visitor", "path", "shouldContinue", "Object", "values", "forEach", "child", "subscribeTraverse", "currentPath", "effect", "result", "nodeSubscriptions", "unsubscribe", "getPath", "source", "target", "start", "found", "_addNodes", "batch", "_addNode", "_node", "wake", "subNode", "_addEdge", "_removeNodes", "ids", "_removeNode", "_removeEdge", "keys", "startsWith", "_addEdges", "edge", "sourceEdges", "push", "targetEdges", "_removeEdges", "outboundIndex", "findIndex", "splice", "inboundIndex", "_sortEdges", "nodeId", "current", "unsorted", "sorted", "createExtension", "extension", "resolver", "connector", "actionGroups", "rest", "getId", "arg", "Dispatcher", "stateIndex", "state", "cleanup", "BuilderInternal", "memoize", "fn", "dispatcher", "currentDispatcher", "currentExtension", "all", "toSignal", "subscribe", "get", "thisSignal", "signal", "value", "GraphBuilder", "_dispatcher", "_extensions", "_resolverSubscriptions", "Map", "_connectorSubscriptions", "_nodeChanged", "_graph", "addExtension", "Array", "isArray", "ext", "removeExtension", "destroy", "clear", "flatMap", "Promise", "set", "nodesRelation", "nodesType", "first", "previous", "has", "removed", "delete"]
4
+ "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { batch, effect, untracked } from '@preact/signals-core';\n\nimport { asyncTimeout, Trigger } from '@dxos/async';\nimport { type ReactiveObject, create } from '@dxos/echo-schema';\nimport { invariant } from '@dxos/invariant';\nimport { nonNullable } from '@dxos/util';\n\nimport { type Relation, type Node, type NodeArg, type NodeFilter, isActionLike } from './node';\n\nconst graphSymbol = Symbol('graph');\ntype DeepWriteable<T> = { -readonly [K in keyof T]: DeepWriteable<T[K]> };\ntype NodeInternal = DeepWriteable<Node> & { [graphSymbol]: Graph };\n\nexport const getGraph = (node: Node): Graph => {\n const graph = (node as NodeInternal)[graphSymbol];\n invariant(graph, 'Node is not associated with a graph.');\n return graph;\n};\n\nexport const ROOT_ID = 'root';\nexport const ROOT_TYPE = 'dxos.org/type/GraphRoot';\nexport const ACTION_TYPE = 'dxos.org/type/GraphAction';\nexport const ACTION_GROUP_TYPE = 'dxos.org/type/GraphActionGroup';\n\nexport type NodesOptions<T = any, U extends Record<string, any> = Record<string, any>> = {\n relation?: Relation;\n filter?: NodeFilter<T, U>;\n expansion?: boolean;\n type?: string;\n};\n\n// TODO(wittjosiah): Consider having default be undefined. This is current default for backwards compatibility.\nconst DEFAULT_FILTER = (node: Node) => untracked(() => !isActionLike(node));\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, path: string[]) => boolean | void;\n\n /**\n * The node to start traversing from.\n *\n * @default root\n */\n node?: Node;\n\n /**\n * The relation to traverse graph edges.\n *\n * @default 'outbound'\n */\n relation?: Relation;\n\n /**\n * Allow traversal to trigger expansion of the graph via `onInitialNodes`.\n */\n expansion?: boolean;\n};\n\n/**\n * The Graph represents the structure of the application constructed via plugins.\n */\nexport class Graph {\n private readonly _onInitialNode?: (id: string) => Promise<void>;\n private readonly _onInitialNodes?: (node: Node, relation: Relation, type?: string) => Promise<void>;\n private readonly _onRemoveNode?: (id: string) => Promise<void>;\n\n private readonly _waitingForNodes: Record<string, Trigger<Node>> = {};\n private readonly _initialized: Record<string, boolean> = {};\n\n /**\n * @internal\n */\n readonly _nodes: Record<string, ReactiveObject<NodeInternal>> = {};\n\n /**\n * @internal\n */\n readonly _edges: Record<string, ReactiveObject<{ inbound: string[]; outbound: string[] }>> = {};\n\n constructor({\n onInitialNode,\n onInitialNodes,\n onRemoveNode,\n }: {\n onInitialNode?: Graph['_onInitialNode'];\n onInitialNodes?: Graph['_onInitialNodes'];\n onRemoveNode?: Graph['_onRemoveNode'];\n } = {}) {\n this._onInitialNode = onInitialNode;\n this._onInitialNodes = onInitialNodes;\n this._onRemoveNode = onRemoveNode;\n this._nodes[ROOT_ID] = this._constructNode({ id: ROOT_ID, type: ROOT_TYPE, properties: {}, data: null });\n this._edges[ROOT_ID] = create({ inbound: [], outbound: [] });\n }\n\n /**\n * Alias for `findNode('root')`.\n */\n get root() {\n return this.findNode(ROOT_ID)!;\n }\n\n /**\n * Convert the graph to a JSON object.\n */\n toJSON({ id = ROOT_ID, maxLength = 32 }: { id?: string; maxLength?: number } = {}) {\n const toJSON = (node: Node, seen: string[] = []): any => {\n const nodes = this.nodes(node);\n const obj: Record<string, any> = {\n id: node.id.length > maxLength ? `${node.id.slice(0, maxLength - 3)}...` : 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) => {\n // Break cycles.\n const nextSeen = [...seen, node.id];\n return nextSeen.includes(n.id) ? undefined : toJSON(n, nextSeen);\n })\n .filter(nonNullable);\n }\n return obj;\n };\n\n const root = this.findNode(id);\n invariant(root, `Node not found: ${id}`);\n return toJSON(root);\n }\n\n /**\n * Find the node with the given id in the graph.\n *\n * If a node is not found within the graph and an `onInitialNode` callback is provided,\n * it is called with the id and type of the node, potentially initializing the node.\n */\n findNode(id: string): Node | undefined {\n const existingNode = this._nodes[id];\n if (!existingNode) {\n void this._onInitialNode?.(id);\n }\n\n return existingNode;\n }\n\n /**\n * Wait for a node to be added to the graph.\n *\n * If the node is already present in the graph, the promise resolves immediately.\n *\n * @param id The id of the node to wait for.\n * @param timeout The time in milliseconds to wait for the node to be added.\n */\n async waitForNode(id: string, timeout?: number): Promise<Node> {\n const trigger = this._waitingForNodes[id] ?? (this._waitingForNodes[id] = new Trigger<Node>());\n const node = this.findNode(id);\n if (node) {\n delete this._waitingForNodes[id];\n return node;\n }\n\n if (timeout === undefined) {\n return trigger.wait();\n } else {\n return asyncTimeout(trigger.wait(), timeout, `Node not found: ${id}`);\n }\n }\n\n /**\n * Nodes that this node is connected to in default order.\n */\n nodes<T = any, U extends Record<string, any> = Record<string, any>>(node: Node, options: NodesOptions<T, U> = {}) {\n const { relation, expansion, filter = DEFAULT_FILTER, type } = options;\n const nodes = this._getNodes({ node, relation, expansion, type });\n return nodes.filter((n) => filter(n, node));\n }\n\n /**\n * Edges that this node is connected to in default order.\n */\n edges(node: Node, { relation = 'outbound' }: { relation?: Relation } = {}) {\n return this._edges[node.id]?.[relation] ?? [];\n }\n\n /**\n * Actions or action groups that this node is connected to in default order.\n */\n actions(node: Node, { expansion }: { expansion?: boolean } = {}) {\n return [\n ...this._getNodes({ node, expansion, type: ACTION_GROUP_TYPE }),\n ...this._getNodes({ node, expansion, type: ACTION_TYPE }),\n ];\n }\n\n async expand(node: Node, relation: Relation = 'outbound', type?: string) {\n const key = this._key(node, relation, type);\n const initialized = this._initialized[key];\n if (!initialized && this._onInitialNodes) {\n await this._onInitialNodes(node, relation, type);\n this._initialized[key] = true;\n }\n }\n\n private _key(node: Node, relation: Relation, type?: string) {\n return `${node.id}-${relation}-${type}`;\n }\n\n /**\n * Recursive depth-first traversal of the graph.\n *\n * @param options.node The node to start traversing from.\n * @param options.relation The relation to traverse graph edges.\n * @param options.visitor A callback which is called for each node visited during traversal.\n */\n traverse(\n { visitor, node = this.root, relation = 'outbound', expansion }: GraphTraversalOptions,\n path: string[] = [],\n ): void {\n // Break cycles.\n if (path.includes(node.id)) {\n return;\n }\n\n const shouldContinue = visitor(node, [...path, node.id]);\n if (shouldContinue === false) {\n return;\n }\n\n Object.values(this._getNodes({ node, relation, expansion })).forEach((child) =>\n this.traverse({ node: child, relation, visitor, expansion }, [...path, node.id]),\n );\n }\n\n /**\n * Recursive depth-first traversal of the graph wrapping each visitor call in an effect.\n *\n * @param options.node The node to start traversing from.\n * @param options.relation The relation to traverse graph edges.\n * @param options.visitor A callback which is called for each node visited during traversal.\n */\n subscribeTraverse(\n { visitor, node = this.root, relation = 'outbound', expansion }: GraphTraversalOptions,\n currentPath: string[] = [],\n ) {\n return effect(() => {\n const path = [...currentPath, node.id];\n const result = visitor(node, path);\n if (result === false) {\n return;\n }\n\n const nodes = this._getNodes({ node, relation, expansion });\n const nodeSubscriptions = nodes.map((n) => this.subscribeTraverse({ node: n, visitor, expansion }, path));\n\n return () => {\n nodeSubscriptions.forEach((unsubscribe) => unsubscribe());\n };\n });\n }\n\n /**\n * Get the path between two nodes in the graph.\n */\n getPath({ source = 'root', target }: { source?: string; target: string }): string[] | undefined {\n const start = this.findNode(source);\n if (!start) {\n return undefined;\n }\n\n let found: string[] | undefined;\n this.traverse({\n node: start,\n visitor: (node, path) => {\n if (found) {\n return false;\n }\n\n if (node.id === target) {\n found = path;\n }\n },\n });\n\n return found;\n }\n\n /**\n * Add nodes to the graph.\n *\n * @internal\n */\n _addNodes<TData = null, TProperties extends Record<string, any> = Record<string, any>>(\n nodes: NodeArg<TData, TProperties>[],\n ): Node<TData, TProperties>[] {\n return batch(() => nodes.map((node) => this._addNode(node)));\n }\n\n private _addNode<TData, TProperties extends Record<string, any> = Record<string, any>>({\n nodes,\n edges,\n ..._node\n }: NodeArg<TData, TProperties>): Node<TData, TProperties> {\n return untracked(() => {\n const existingNode = this._nodes[_node.id];\n const node = existingNode ?? this._constructNode({ data: null, properties: {}, ..._node });\n if (existingNode) {\n const { data, properties, type } = _node;\n if (data && data !== node.data) {\n node.data = data;\n }\n\n if (type !== node.type) {\n node.type = type;\n }\n\n for (const key in properties) {\n if (properties[key] !== node.properties[key]) {\n node.properties[key] = properties[key];\n }\n }\n } else {\n this._nodes[node.id] = node;\n this._edges[node.id] = create({ inbound: [], outbound: [] });\n }\n\n const trigger = this._waitingForNodes[node.id];\n if (trigger) {\n trigger.wake(node);\n delete this._waitingForNodes[node.id];\n }\n\n if (nodes) {\n nodes.forEach((subNode) => {\n this._addNode(subNode);\n this._addEdge({ source: node.id, target: subNode.id });\n });\n }\n\n if (edges) {\n edges.forEach(([id, relation]) =>\n relation === 'outbound'\n ? this._addEdge({ source: node.id, target: id })\n : this._addEdge({ source: id, target: node.id }),\n );\n }\n\n return node as unknown as Node<TData, TProperties>;\n });\n }\n\n /**\n * Remove nodes from the graph.\n *\n * @param ids The id of the node to remove.\n * @param edges Whether to remove edges connected to the node from the graph as well.\n * @internal\n */\n _removeNodes(ids: string[], edges = false) {\n batch(() => ids.forEach((id) => this._removeNode(id, edges)));\n }\n\n private _removeNode(id: string, edges = false) {\n untracked(() => {\n const node = this.findNode(id);\n if (!node) {\n return;\n }\n\n if (edges) {\n // Remove edges from connected nodes.\n this._getNodes({ node }).forEach((node) => {\n this._removeEdge({ source: id, target: node.id });\n });\n this._getNodes({ node, relation: 'inbound' }).forEach((node) => {\n this._removeEdge({ source: node.id, target: id });\n });\n\n // Remove edges from node.\n delete this._edges[id];\n }\n\n // Remove node.\n delete this._nodes[id];\n Object.keys(this._initialized)\n .filter((key) => key.startsWith(id))\n .forEach((key) => {\n delete this._initialized[key];\n });\n void this._onRemoveNode?.(id);\n });\n }\n\n /**\n * Add edges to the graph.\n *\n * @internal\n */\n _addEdges(edges: { source: string; target: string }[]) {\n batch(() => edges.forEach((edge) => this._addEdge(edge)));\n }\n\n private _addEdge({ source, target }: { source: string; target: string }) {\n untracked(() => {\n if (!this._edges[source]) {\n this._edges[source] = create({ inbound: [], outbound: [] });\n }\n if (!this._edges[target]) {\n this._edges[target] = create({ inbound: [], outbound: [] });\n }\n\n const sourceEdges = this._edges[source];\n if (!sourceEdges.outbound.includes(target)) {\n sourceEdges.outbound.push(target);\n }\n\n const targetEdges = this._edges[target];\n if (!targetEdges.inbound.includes(source)) {\n targetEdges.inbound.push(source);\n }\n });\n }\n\n /**\n * Remove edges from the graph.\n * @internal\n */\n _removeEdges(edges: { source: string; target: string }[], removeOrphans = false) {\n batch(() => edges.forEach((edge) => this._removeEdge(edge, removeOrphans)));\n }\n\n private _removeEdge({ source, target }: { source: string; target: string }, removeOrphans = false) {\n untracked(() => {\n batch(() => {\n const outboundIndex = this._edges[source]?.outbound.findIndex((id) => id === target);\n if (outboundIndex !== undefined && outboundIndex !== -1) {\n this._edges[source].outbound.splice(outboundIndex, 1);\n }\n\n const inboundIndex = this._edges[target]?.inbound.findIndex((id) => id === source);\n if (inboundIndex !== undefined && inboundIndex !== -1) {\n this._edges[target].inbound.splice(inboundIndex, 1);\n }\n\n if (removeOrphans) {\n if (\n this._edges[source]?.outbound.length === 0 &&\n this._edges[source]?.inbound.length === 0 &&\n source !== ROOT_ID\n ) {\n this._removeNode(source, true);\n }\n if (\n this._edges[target]?.outbound.length === 0 &&\n this._edges[target]?.inbound.length === 0 &&\n target !== ROOT_ID\n ) {\n this._removeNode(target, true);\n }\n }\n });\n });\n }\n\n /**\n * Sort edges for a node.\n *\n * Edges not included in the sorted list are appended to the end of the list.\n *\n * @param nodeId The id of the node to sort edges for.\n * @param relation The relation of the edges from the node to sort.\n * @param edges The ordered list of edges.\n * @ignore\n */\n _sortEdges(nodeId: string, relation: Relation, edges: string[]) {\n untracked(() => {\n batch(() => {\n const current = this._edges[nodeId];\n if (current) {\n const unsorted = current[relation].filter((id) => !edges.includes(id)) ?? [];\n const sorted = edges.filter((id) => current[relation].includes(id)) ?? [];\n current[relation].splice(0, current[relation].length, ...[...sorted, ...unsorted]);\n }\n });\n });\n }\n\n private _constructNode = (node: Omit<Node, typeof graphSymbol>) => {\n return create<NodeInternal>({ ...node, [graphSymbol]: this });\n };\n\n private _getNodes({\n node,\n relation = 'outbound',\n type,\n expansion,\n }: {\n node: Node;\n relation?: Relation;\n type?: string;\n expansion?: boolean;\n }): Node[] {\n if (expansion) {\n void this.expand(node, relation, type);\n }\n\n const edges = this._edges[node.id];\n if (!edges) {\n return [];\n } else {\n return edges[relation]\n .map((id) => this._nodes[id])\n .filter(nonNullable)\n .filter((n) => !type || n.type === type);\n }\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { type MaybePromise, type MakeOptional } from '@dxos/util';\n\n/**\n * Represents a node in the graph.\n */\n// TODO(wittjosiah): Use Effect Schema.\nexport type Node<TData = any, TProperties extends Record<string, any> = Record<string, any>> = Readonly<{\n /**\n * Globally unique ID.\n */\n id: string;\n\n /**\n * Typename of the data the node represents.\n */\n type: 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<T = any, U extends Record<string, any> = Record<string, any>> = (\n node: Node<unknown, Record<string, any>>,\n connectedNode: Node,\n) => node is Node<T, U>;\n\nexport type Relation = 'outbound' | 'inbound';\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'\n> & {\n /** Will automatically add nodes with an edge from this node to each. */\n nodes?: NodeArg<unknown>[];\n\n /** Will automatically add specified edges. */\n edges?: [string, Relation][];\n};\n\n//\n// Actions\n//\n\nexport type InvokeParams = {\n /** Node the invoked action is connected to. */\n node: Node;\n\n caller?: string;\n};\n\nexport type ActionData = (params: InvokeParams) => MaybePromise<void>;\n\nexport type Action<TProperties extends Record<string, any> = Record<string, any>> = Readonly<\n Omit<Node<ActionData, TProperties>, 'properties'> & {\n properties: Readonly<TProperties>;\n }\n>;\n\nexport const isAction = (data: unknown): data is Action =>\n isGraphNode(data) ? typeof data.data === 'function' : false;\n\nexport const actionGroupSymbol = Symbol('ActionGroup');\n\nexport type ActionGroup = Readonly<\n Omit<Node<typeof actionGroupSymbol, Record<string, any>>, 'properties'> & {\n properties: Readonly<Record<string, any>>;\n }\n>;\n\nexport const isActionGroup = (data: unknown): data is ActionGroup =>\n isGraphNode(data) ? data.data === actionGroupSymbol : false;\n\nexport type ActionLike = Action | ActionGroup;\n\nexport const isActionLike = (data: unknown): data is Action | ActionGroup => isAction(data) || isActionGroup(data);\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Signal, effect, signal } from '@preact/signals-core';\n\nimport { type UnsubscribeCallback } from '@dxos/async';\nimport { create } from '@dxos/echo-schema';\nimport { invariant } from '@dxos/invariant';\nimport { isNode, type MaybePromise, nonNullable } from '@dxos/util';\n\nimport { ACTION_GROUP_TYPE, ACTION_TYPE, Graph } from './graph';\nimport { type Relation, type NodeArg, type Node, type ActionData, actionGroupSymbol } from './node';\n\n/**\n * Graph builder extension for adding nodes to the graph based on just the node id.\n * This is useful for creating the first node in a graph or for hydrating cached nodes with data.\n *\n * @param params.id The id of the node to resolve.\n */\nexport type ResolverExtension = (params: { id: string }) => NodeArg<any> | undefined;\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<T = any> = (params: { node: Node<T> }) => NodeArg<any>[] | undefined;\n\n/**\n * Constrained case of the connector extension for more easily adding actions to the graph.\n */\nexport type ActionsExtension<T = any> = (params: {\n node: Node<T>;\n}) => Omit<NodeArg<ActionData>, 'type' | 'nodes' | 'edges'>[] | undefined;\n\n/**\n * Constrained case of the connector extension for more easily adding action groups to the graph.\n */\nexport type ActionGroupsExtension<T = any> = (params: {\n node: Node<T>;\n}) => Omit<NodeArg<typeof actionGroupSymbol>, 'type' | 'data' | 'nodes' | 'edges'>[] | undefined;\n\ntype GuardedNodeType<T> = T extends (value: any) => value is infer N ? (N extends Node<infer D> ? D : unknown) : never;\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.type If provided, all nodes returned are expected to have this type.\n * @param params.filter A filter function to determine if an extension should act on a node.\n * @param params.resolver A function to add nodes to the graph based on just the node id.\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 CreateExtensionOptions<T = any> = {\n id: string;\n relation?: Relation;\n type?: string;\n filter?: (node: Node) => node is Node<T>;\n resolver?: ResolverExtension;\n connector?: ConnectorExtension<GuardedNodeType<CreateExtensionOptions<T>['filter']>>;\n actions?: ActionsExtension<GuardedNodeType<CreateExtensionOptions<T>['filter']>>;\n actionGroups?: ActionGroupsExtension<GuardedNodeType<CreateExtensionOptions<T>['filter']>>;\n};\n\n/**\n * Create a graph builder extension.\n */\nexport const createExtension = <T = any>(extension: CreateExtensionOptions<T>): BuilderExtension[] => {\n const { id, resolver, connector, actions, actionGroups, ...rest } = extension;\n const getId = (key: string) => `${id}/${key}`;\n return [\n resolver ? { id: getId('resolver'), resolver } : undefined,\n connector ? { ...rest, id: getId('connector'), connector } : undefined,\n actionGroups\n ? ({\n ...rest,\n id: getId('actionGroups'),\n type: ACTION_GROUP_TYPE,\n relation: 'outbound',\n connector: ({ node }) =>\n actionGroups({ node })?.map((arg) => ({ ...arg, data: actionGroupSymbol, type: ACTION_GROUP_TYPE })),\n } satisfies BuilderExtension)\n : undefined,\n actions\n ? ({\n ...rest,\n id: getId('actions'),\n type: ACTION_TYPE,\n relation: 'outbound',\n connector: ({ node }) => actions({ node })?.map((arg) => ({ ...arg, type: ACTION_TYPE })),\n } satisfies BuilderExtension)\n : undefined,\n ].filter(nonNullable);\n};\n\nexport type GraphBuilderTraverseOptions = {\n visitor: (node: Node, path: string[]) => MaybePromise<boolean | void>;\n node?: Node;\n relation?: Relation;\n};\n\n/**\n * The dispatcher is used to keep track of the current extension and state when memoizing functions.\n */\nclass Dispatcher {\n currentExtension?: string;\n stateIndex = 0;\n state: Record<string, any[]> = {};\n cleanup: (() => void)[] = [];\n}\n\nclass BuilderInternal {\n // This must be static to avoid passing the dispatcher instance to every memoized function.\n // If the dispatcher is not set that means that the memoized function is being called outside of the graph builder.\n static currentDispatcher?: Dispatcher;\n}\n\n/**\n * Allows code to be memoized within the context of a graph builder extension.\n * This is useful for creating instances which should be subscribed to rather than recreated.\n */\nexport const memoize = <T>(fn: () => T, key = 'result'): T => {\n const dispatcher = BuilderInternal.currentDispatcher;\n invariant(dispatcher?.currentExtension, 'memoize must be called within an extension');\n const all = dispatcher.state[dispatcher.currentExtension][dispatcher.stateIndex] ?? {};\n const current = all[key];\n const result = current ? current.result : fn();\n dispatcher.state[dispatcher.currentExtension][dispatcher.stateIndex] = { ...all, [key]: { result } };\n dispatcher.stateIndex++;\n return result;\n};\n\n/**\n * Register a cleanup function to be called when the graph builder is destroyed.\n */\nexport const cleanup = (fn: () => void): void => {\n memoize(() => {\n const dispatcher = BuilderInternal.currentDispatcher;\n invariant(dispatcher, 'cleanup must be called within an extension');\n dispatcher.cleanup.push(fn);\n });\n};\n\n/**\n * Convert a subscribe/get pair into a signal.\n */\nexport const toSignal = <T>(\n subscribe: (onChange: () => void) => () => void,\n get: () => T | undefined,\n key?: string,\n) => {\n const thisSignal = memoize(() => {\n return signal(get());\n }, key);\n const unsubscribe = memoize(() => {\n return subscribe(() => (thisSignal.value = get()));\n }, key);\n cleanup(() => {\n unsubscribe();\n });\n return thisSignal.value;\n};\n\nexport type BuilderExtension = {\n id: string;\n resolver?: ResolverExtension;\n connector?: ConnectorExtension;\n // Only for connector.\n relation?: Relation;\n type?: string;\n filter?: (node: Node) => boolean;\n};\n\ntype ExtensionArg = BuilderExtension | BuilderExtension[] | ExtensionArg[];\n\n/**\n * The builder provides an extensible way to compose the construction of the graph.\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.\nexport class GraphBuilder {\n private readonly _dispatcher = new Dispatcher();\n private readonly _extensions = create<Record<string, BuilderExtension>>({});\n private readonly _resolverSubscriptions = new Map<string, UnsubscribeCallback>();\n private readonly _connectorSubscriptions = new Map<string, UnsubscribeCallback>();\n private readonly _nodeChanged: Record<string, Signal<{}>> = {};\n private _graph: Graph;\n\n constructor() {\n this._graph = new Graph({\n onInitialNode: (id) => this._onInitialNode(id),\n onInitialNodes: (node, relation, type) => this._onInitialNodes(node, relation, type),\n onRemoveNode: (id) => this._onRemoveNode(id),\n });\n }\n\n get graph() {\n return this._graph;\n }\n\n /**\n * Register a node builder which will be called in order to construct the graph.\n */\n addExtension(extension: ExtensionArg): GraphBuilder {\n if (Array.isArray(extension)) {\n extension.forEach((ext) => this.addExtension(ext));\n return this;\n }\n\n this._dispatcher.state[extension.id] = [];\n this._extensions[extension.id] = extension;\n return this;\n }\n\n /**\n * Remove a node builder from the graph builder.\n */\n removeExtension(id: string): GraphBuilder {\n delete this._extensions[id];\n return this;\n }\n\n destroy() {\n this._dispatcher.cleanup.forEach((fn) => fn());\n this._resolverSubscriptions.forEach((unsubscribe) => unsubscribe());\n this._connectorSubscriptions.forEach((unsubscribe) => unsubscribe());\n this._resolverSubscriptions.clear();\n this._connectorSubscriptions.clear();\n }\n\n /**\n * A graph traversal using just the connector extensions, without subscribing to any signals or persisting any nodes.\n */\n async explore(\n { node = this._graph.root, relation = 'outbound', visitor }: GraphBuilderTraverseOptions,\n path: string[] = [],\n ) {\n // Break cycles.\n if (path.includes(node.id)) {\n return;\n }\n\n // TODO(wittjosiah): This is a workaround for esm not working in the test runner.\n // Switching to vitest is blocked by having node esm versions of echo-schema & echo-signals.\n if (!isNode()) {\n const { yieldOrContinue } = await import('main-thread-scheduling');\n await yieldOrContinue('idle');\n }\n const shouldContinue = await visitor(node, [...path, node.id]);\n if (shouldContinue === false) {\n return;\n }\n\n const nodes = Object.values(this._extensions)\n .filter((extension) => relation === (extension.relation ?? 'outbound'))\n .filter((extension) => !extension.filter || extension.filter(node))\n .flatMap((extension) => {\n this._dispatcher.currentExtension = extension.id;\n this._dispatcher.stateIndex = 0;\n BuilderInternal.currentDispatcher = this._dispatcher;\n const result = extension.connector?.({ node }) ?? [];\n BuilderInternal.currentDispatcher = undefined;\n return result;\n })\n .map(\n (arg): Node => ({\n id: arg.id,\n type: arg.type,\n data: arg.data ?? null,\n properties: arg.properties ?? {},\n }),\n );\n\n await Promise.all(nodes.map((n) => this.explore({ node: n, relation, visitor }, [...path, node.id])));\n }\n\n private async _onInitialNode(nodeId: string) {\n this._nodeChanged[nodeId] = this._nodeChanged[nodeId] ?? signal({});\n this._resolverSubscriptions.set(\n nodeId,\n effect(() => {\n for (const { id, resolver } of Object.values(this._extensions)) {\n if (!resolver) {\n continue;\n }\n this._dispatcher.currentExtension = id;\n this._dispatcher.stateIndex = 0;\n BuilderInternal.currentDispatcher = this._dispatcher;\n const node = resolver({ id: nodeId });\n BuilderInternal.currentDispatcher = undefined;\n if (node) {\n this.graph._addNodes([node]);\n if (this._nodeChanged[node.id]) {\n this._nodeChanged[node.id].value = {};\n }\n break;\n }\n }\n }),\n );\n }\n\n private async _onInitialNodes(node: Node, nodesRelation: Relation, nodesType?: string) {\n this._nodeChanged[node.id] = this._nodeChanged[node.id] ?? signal({});\n let first = true;\n let previous: string[] = [];\n this._connectorSubscriptions.set(\n node.id,\n effect(() => {\n // TODO(wittjosiah): This is a workaround for a race between the node removal and the effect re-running.\n // To cause this case to happen, remove a collection and then undo the removal.\n if (!first && !this._connectorSubscriptions.has(node.id)) {\n return;\n }\n first = false;\n\n // Subscribe to extensions being added.\n Object.keys(this._extensions);\n // Subscribe to connected node changes.\n this._nodeChanged[node.id].value;\n\n // TODO(wittjosiah): Consider allowing extensions to collaborate on the same node by merging their results.\n const nodes: NodeArg<any>[] = [];\n for (const { id, connector, filter, type, relation = 'outbound' } of Object.values(this._extensions)) {\n if (\n !connector ||\n relation !== nodesRelation ||\n (nodesType && type !== nodesType) ||\n (filter && !filter(node))\n ) {\n continue;\n }\n\n this._dispatcher.currentExtension = id;\n this._dispatcher.stateIndex = 0;\n BuilderInternal.currentDispatcher = this._dispatcher;\n nodes.push(...(connector({ node }) ?? []));\n BuilderInternal.currentDispatcher = undefined;\n }\n const ids = nodes.map((n) => n.id);\n const removed = previous.filter((id) => !ids.includes(id));\n previous = ids;\n\n // Remove edges and only remove nodes that are orphaned.\n this.graph._removeEdges(\n removed.map((target) => ({ source: node.id, target })),\n true,\n );\n this.graph._addNodes(nodes);\n this.graph._addEdges(\n nodes.map(({ id }) =>\n nodesRelation === 'outbound' ? { source: node.id, target: id } : { source: id, target: node.id },\n ),\n );\n this.graph._sortEdges(\n node.id,\n nodesRelation,\n nodes.map(({ id }) => id),\n );\n nodes.forEach((n) => {\n if (this._nodeChanged[n.id]) {\n this._nodeChanged[n.id].value = {};\n }\n });\n }),\n );\n }\n\n private async _onRemoveNode(nodeId: string) {\n this._resolverSubscriptions.get(nodeId)?.();\n this._connectorSubscriptions.get(nodeId)?.();\n this._resolverSubscriptions.delete(nodeId);\n this._connectorSubscriptions.delete(nodeId);\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["import_signals_core", "import_echo_schema", "import_invariant", "import_util", "isGraphNode", "data", "properties", "isAction", "actionGroupSymbol", "Symbol", "isActionGroup", "isActionLike", "graphSymbol", "getGraph", "node", "graph", "invariant", "ROOT_ID", "ROOT_TYPE", "ACTION_TYPE", "ACTION_GROUP_TYPE", "DEFAULT_FILTER", "untracked", "Graph", "constructor", "onInitialNode", "onInitialNodes", "onRemoveNode", "_waitingForNodes", "_initialized", "_constructNode", "create", "_onInitialNode", "_onInitialNodes", "_onRemoveNode", "_nodes", "id", "type", "_edges", "inbound", "outbound", "root", "findNode", "toJSON", "maxLength", "seen", "nodes", "obj", "length", "slice", "label", "map", "n", "nextSeen", "includes", "undefined", "filter", "nonNullable", "existingNode", "waitForNode", "timeout", "trigger", "Trigger", "wait", "asyncTimeout", "options", "relation", "expansion", "_getNodes", "edges", "actions", "expand", "key", "_key", "initialized", "traverse", "visitor", "path", "shouldContinue", "Object", "values", "forEach", "child", "subscribeTraverse", "currentPath", "effect", "result", "nodeSubscriptions", "unsubscribe", "getPath", "source", "target", "start", "found", "_addNodes", "batch", "_addNode", "_node", "wake", "subNode", "_addEdge", "_removeNodes", "ids", "_removeNode", "_removeEdge", "keys", "startsWith", "_addEdges", "edge", "sourceEdges", "push", "targetEdges", "_removeEdges", "removeOrphans", "outboundIndex", "findIndex", "splice", "inboundIndex", "_sortEdges", "nodeId", "current", "unsorted", "sorted", "createExtension", "extension", "resolver", "connector", "actionGroups", "rest", "getId", "arg", "Dispatcher", "stateIndex", "state", "cleanup", "BuilderInternal", "memoize", "fn", "dispatcher", "currentDispatcher", "currentExtension", "all", "toSignal", "subscribe", "get", "thisSignal", "signal", "value", "GraphBuilder", "_dispatcher", "_extensions", "_resolverSubscriptions", "Map", "_connectorSubscriptions", "_nodeChanged", "_graph", "addExtension", "Array", "isArray", "ext", "removeExtension", "destroy", "clear", "explore", "isNode", "yieldOrContinue", "flatMap", "Promise", "set", "nodesRelation", "nodesType", "first", "previous", "has", "removed", "delete"]
7
7
  }
@@ -1 +1 @@
1
- {"inputs":{"packages/sdk/app-graph/src/node.ts":{"bytes":5259,"imports":[],"format":"esm"},"packages/sdk/app-graph/src/graph.ts":{"bytes":51067,"imports":[{"path":"@preact/signals-core","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"packages/sdk/app-graph/src/node.ts","kind":"import-statement","original":"./node"}],"format":"esm"},"packages/sdk/app-graph/src/graph-builder.ts":{"bytes":39059,"imports":[{"path":"@preact/signals-core","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"packages/sdk/app-graph/src/graph.ts","kind":"import-statement","original":"./graph"},{"path":"packages/sdk/app-graph/src/node.ts","kind":"import-statement","original":"./node"}],"format":"esm"},"packages/sdk/app-graph/src/index.ts":{"bytes":672,"imports":[{"path":"packages/sdk/app-graph/src/graph.ts","kind":"import-statement","original":"./graph"},{"path":"packages/sdk/app-graph/src/graph-builder.ts","kind":"import-statement","original":"./graph-builder"},{"path":"packages/sdk/app-graph/src/node.ts","kind":"import-statement","original":"./node"}],"format":"esm"}},"outputs":{"packages/sdk/app-graph/dist/lib/node/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":48553},"packages/sdk/app-graph/dist/lib/node/index.cjs":{"imports":[{"path":"@preact/signals-core","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"@preact/signals-core","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true}],"exports":["ACTION_GROUP_TYPE","ACTION_TYPE","Graph","GraphBuilder","ROOT_ID","ROOT_TYPE","actionGroupSymbol","cleanup","createExtension","getGraph","isAction","isActionGroup","isActionLike","isGraphNode","memoize","toSignal"],"entryPoint":"packages/sdk/app-graph/src/index.ts","inputs":{"packages/sdk/app-graph/src/graph.ts":{"bytesInOutput":12485},"packages/sdk/app-graph/src/node.ts":{"bytesInOutput":477},"packages/sdk/app-graph/src/index.ts":{"bytesInOutput":0},"packages/sdk/app-graph/src/graph-builder.ts":{"bytesInOutput":7661}},"bytes":21066}}}
1
+ {"inputs":{"packages/sdk/app-graph/src/node.ts":{"bytes":5259,"imports":[],"format":"esm"},"packages/sdk/app-graph/src/graph.ts":{"bytes":53358,"imports":[{"path":"@preact/signals-core","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"packages/sdk/app-graph/src/node.ts","kind":"import-statement","original":"./node"}],"format":"esm"},"packages/sdk/app-graph/src/graph-builder.ts":{"bytes":41710,"imports":[{"path":"@preact/signals-core","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"packages/sdk/app-graph/src/graph.ts","kind":"import-statement","original":"./graph"},{"path":"packages/sdk/app-graph/src/node.ts","kind":"import-statement","original":"./node"},{"path":"main-thread-scheduling","kind":"dynamic-import","external":true}],"format":"esm"},"packages/sdk/app-graph/src/index.ts":{"bytes":672,"imports":[{"path":"packages/sdk/app-graph/src/graph.ts","kind":"import-statement","original":"./graph"},{"path":"packages/sdk/app-graph/src/graph-builder.ts","kind":"import-statement","original":"./graph-builder"},{"path":"packages/sdk/app-graph/src/node.ts","kind":"import-statement","original":"./node"}],"format":"esm"}},"outputs":{"packages/sdk/app-graph/dist/lib/node/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":50969},"packages/sdk/app-graph/dist/lib/node/index.cjs":{"imports":[{"path":"@preact/signals-core","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"@preact/signals-core","kind":"import-statement","external":true},{"path":"@dxos/echo-schema","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/util","kind":"import-statement","external":true},{"path":"main-thread-scheduling","kind":"dynamic-import","external":true}],"exports":["ACTION_GROUP_TYPE","ACTION_TYPE","Graph","GraphBuilder","ROOT_ID","ROOT_TYPE","actionGroupSymbol","cleanup","createExtension","getGraph","isAction","isActionGroup","isActionLike","isGraphNode","memoize","toSignal"],"entryPoint":"packages/sdk/app-graph/src/index.ts","inputs":{"packages/sdk/app-graph/src/graph.ts":{"bytesInOutput":12978},"packages/sdk/app-graph/src/node.ts":{"bytesInOutput":477},"packages/sdk/app-graph/src/index.ts":{"bytesInOutput":0},"packages/sdk/app-graph/src/graph-builder.ts":{"bytesInOutput":8234}},"bytes":22132}}}
@@ -1,3 +1,4 @@
1
+ import { type MaybePromise } from '@dxos/util';
1
2
  import { Graph } from './graph';
2
3
  import { type Relation, type NodeArg, type Node, type ActionData, actionGroupSymbol } from './node';
3
4
  /**
@@ -57,9 +58,9 @@ export type CreateExtensionOptions<T = any> = {
57
58
  */
58
59
  export declare const createExtension: <T = any>(extension: CreateExtensionOptions<T>) => BuilderExtension[];
59
60
  export type GraphBuilderTraverseOptions = {
60
- node: Node;
61
+ visitor: (node: Node, path: string[]) => MaybePromise<boolean | void>;
62
+ node?: Node;
61
63
  relation?: Relation;
62
- visitor: (node: Node, path: string[]) => void;
63
64
  };
64
65
  /**
65
66
  * Allows code to be memoized within the context of a graph builder extension.
@@ -105,9 +106,9 @@ export declare class GraphBuilder {
105
106
  removeExtension(id: string): GraphBuilder;
106
107
  destroy(): void;
107
108
  /**
108
- * Traverse a graph using just the connector extensions, without subscribing to any signals or persisting any nodes.
109
+ * A graph traversal using just the connector extensions, without subscribing to any signals or persisting any nodes.
109
110
  */
110
- traverse({ node, relation, visitor }: GraphBuilderTraverseOptions, path?: string[]): Promise<void>;
111
+ explore({ node, relation, visitor }: GraphBuilderTraverseOptions, path?: string[]): Promise<void>;
111
112
  private _onInitialNode;
112
113
  private _onInitialNodes;
113
114
  private _onRemoveNode;
@@ -1 +1 @@
1
- {"version":3,"file":"graph-builder.d.ts","sourceRoot":"","sources":["../../../src/graph-builder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"graph-builder.d.ts","sourceRoot":"","sources":["../../../src/graph-builder.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../../src/graph.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../../src/graph.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/app-graph",
3
- "version": "0.6.5",
3
+ "version": "0.6.6-staging.23d123d",
4
4
  "description": "Constructs knowledge graphs for the purpose of building applications on top of",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -26,13 +26,13 @@
26
26
  "dependencies": {
27
27
  "@preact/signals-core": "^1.6.0",
28
28
  "main-thread-scheduling": "^14.1.1",
29
- "@dxos/echo-signals": "0.6.5",
30
- "@dxos/echo-schema": "0.6.5",
31
- "@dxos/debug": "0.6.5",
32
- "@dxos/invariant": "0.6.5",
33
- "@dxos/log": "0.6.5",
34
- "@dxos/async": "0.6.5",
35
- "@dxos/util": "0.6.5"
29
+ "@dxos/async": "0.6.6-staging.23d123d",
30
+ "@dxos/debug": "0.6.6-staging.23d123d",
31
+ "@dxos/echo-signals": "0.6.6-staging.23d123d",
32
+ "@dxos/echo-schema": "0.6.6-staging.23d123d",
33
+ "@dxos/invariant": "0.6.6-staging.23d123d",
34
+ "@dxos/log": "0.6.6-staging.23d123d",
35
+ "@dxos/util": "0.6.6-staging.23d123d"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@phosphor-icons/react": "^2.1.5",
@@ -41,11 +41,11 @@
41
41
  "react": "~18.2.0",
42
42
  "react-dom": "~18.2.0",
43
43
  "vite": "^5.3.4",
44
- "@dxos/random": "0.6.5",
45
- "@dxos/react-client": "0.6.5",
46
- "@dxos/react-ui": "0.6.5",
47
- "@dxos/react-ui-theme": "0.6.5",
48
- "@dxos/storybook-utils": "0.6.5"
44
+ "@dxos/random": "0.6.6-staging.23d123d",
45
+ "@dxos/react-client": "0.6.6-staging.23d123d",
46
+ "@dxos/react-ui-theme": "0.6.6-staging.23d123d",
47
+ "@dxos/storybook-utils": "0.6.6-staging.23d123d",
48
+ "@dxos/react-ui": "0.6.6-staging.23d123d"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "react": "^18.0.0",
@@ -323,7 +323,7 @@ describe('GraphBuilder', () => {
323
323
  });
324
324
  });
325
325
 
326
- describe('traverse', () => {
326
+ describe('explore', () => {
327
327
  test('works', async () => {
328
328
  const builder = new GraphBuilder();
329
329
  builder.addExtension(
@@ -338,7 +338,7 @@ describe('GraphBuilder', () => {
338
338
  const graph = builder.graph;
339
339
 
340
340
  let count = 0;
341
- await builder.traverse({
341
+ await builder.explore({
342
342
  node: graph.root,
343
343
  visitor: () => {
344
344
  count++;
@@ -3,12 +3,11 @@
3
3
  //
4
4
 
5
5
  import { type Signal, effect, signal } from '@preact/signals-core';
6
- // import { yieldOrContinue } from 'main-thread-scheduling';
7
6
 
8
7
  import { type UnsubscribeCallback } from '@dxos/async';
9
8
  import { create } from '@dxos/echo-schema';
10
9
  import { invariant } from '@dxos/invariant';
11
- import { nonNullable } from '@dxos/util';
10
+ import { isNode, type MaybePromise, nonNullable } from '@dxos/util';
12
11
 
13
12
  import { ACTION_GROUP_TYPE, ACTION_TYPE, Graph } from './graph';
14
13
  import { type Relation, type NodeArg, type Node, type ActionData, actionGroupSymbol } from './node';
@@ -99,9 +98,9 @@ export const createExtension = <T = any>(extension: CreateExtensionOptions<T>):
99
98
  };
100
99
 
101
100
  export type GraphBuilderTraverseOptions = {
102
- node: Node;
101
+ visitor: (node: Node, path: string[]) => MaybePromise<boolean | void>;
102
+ node?: Node;
103
103
  relation?: Relation;
104
- visitor: (node: Node, path: string[]) => void;
105
104
  };
106
105
 
107
106
  /**
@@ -235,22 +234,39 @@ export class GraphBuilder {
235
234
  }
236
235
 
237
236
  /**
238
- * Traverse a graph using just the connector extensions, without subscribing to any signals or persisting any nodes.
237
+ * A graph traversal using just the connector extensions, without subscribing to any signals or persisting any nodes.
239
238
  */
240
- // TODO(wittjosiah): Rename? This is not traversing the graph proper.
241
- async traverse({ node, relation = 'outbound', visitor }: GraphBuilderTraverseOptions, path: string[] = []) {
239
+ async explore(
240
+ { node = this._graph.root, relation = 'outbound', visitor }: GraphBuilderTraverseOptions,
241
+ path: string[] = [],
242
+ ) {
242
243
  // Break cycles.
243
244
  if (path.includes(node.id)) {
244
245
  return;
245
246
  }
246
247
 
247
- // TODO(wittjosiah): Failed in test environment. ESM only?
248
- // await yieldOrContinue('idle');
249
- visitor(node, [...path, node.id]);
248
+ // TODO(wittjosiah): This is a workaround for esm not working in the test runner.
249
+ // Switching to vitest is blocked by having node esm versions of echo-schema & echo-signals.
250
+ if (!isNode()) {
251
+ const { yieldOrContinue } = await import('main-thread-scheduling');
252
+ await yieldOrContinue('idle');
253
+ }
254
+ const shouldContinue = await visitor(node, [...path, node.id]);
255
+ if (shouldContinue === false) {
256
+ return;
257
+ }
250
258
 
251
259
  const nodes = Object.values(this._extensions)
252
260
  .filter((extension) => relation === (extension.relation ?? 'outbound'))
253
- .flatMap((extension) => extension.connector?.({ node }) ?? [])
261
+ .filter((extension) => !extension.filter || extension.filter(node))
262
+ .flatMap((extension) => {
263
+ this._dispatcher.currentExtension = extension.id;
264
+ this._dispatcher.stateIndex = 0;
265
+ BuilderInternal.currentDispatcher = this._dispatcher;
266
+ const result = extension.connector?.({ node }) ?? [];
267
+ BuilderInternal.currentDispatcher = undefined;
268
+ return result;
269
+ })
254
270
  .map(
255
271
  (arg): Node => ({
256
272
  id: arg.id,
@@ -260,7 +276,7 @@ export class GraphBuilder {
260
276
  }),
261
277
  );
262
278
 
263
- await Promise.all(nodes.map((n) => this.traverse({ node: n, relation, visitor }, [...path, node.id])));
279
+ await Promise.all(nodes.map((n) => this.explore({ node: n, relation, visitor }, [...path, node.id])));
264
280
  }
265
281
 
266
282
  private async _onInitialNode(nodeId: string) {
@@ -330,7 +346,11 @@ export class GraphBuilder {
330
346
  const removed = previous.filter((id) => !ids.includes(id));
331
347
  previous = ids;
332
348
 
333
- this.graph._removeNodes(removed, true);
349
+ // Remove edges and only remove nodes that are orphaned.
350
+ this.graph._removeEdges(
351
+ removed.map((target) => ({ source: node.id, target })),
352
+ true,
353
+ );
334
354
  this.graph._addNodes(nodes);
335
355
  this.graph._addEdges(
336
356
  nodes.map(({ id }) =>
package/src/graph.ts CHANGED
@@ -33,6 +33,9 @@ export type NodesOptions<T = any, U extends Record<string, any> = Record<string,
33
33
  type?: string;
34
34
  };
35
35
 
36
+ // TODO(wittjosiah): Consider having default be undefined. This is current default for backwards compatibility.
37
+ const DEFAULT_FILTER = (node: Node) => untracked(() => !isActionLike(node));
38
+
36
39
  export type GraphTraversalOptions = {
37
40
  /**
38
41
  * A callback which is called for each node visited during traversal.
@@ -177,9 +180,9 @@ export class Graph {
177
180
  * Nodes that this node is connected to in default order.
178
181
  */
179
182
  nodes<T = any, U extends Record<string, any> = Record<string, any>>(node: Node, options: NodesOptions<T, U> = {}) {
180
- const { relation, expansion, filter, type } = options;
183
+ const { relation, expansion, filter = DEFAULT_FILTER, type } = options;
181
184
  const nodes = this._getNodes({ node, relation, expansion, type });
182
- return nodes.filter((n) => untracked(() => !isActionLike(n))).filter((n) => filter?.(n, node) ?? true);
185
+ return nodes.filter((n) => filter(n, node));
183
186
  }
184
187
 
185
188
  /**
@@ -431,11 +434,11 @@ export class Graph {
431
434
  * Remove edges from the graph.
432
435
  * @internal
433
436
  */
434
- _removeEdges(edges: { source: string; target: string }[]) {
435
- batch(() => edges.forEach((edge) => this._removeEdge(edge)));
437
+ _removeEdges(edges: { source: string; target: string }[], removeOrphans = false) {
438
+ batch(() => edges.forEach((edge) => this._removeEdge(edge, removeOrphans)));
436
439
  }
437
440
 
438
- private _removeEdge({ source, target }: { source: string; target: string }) {
441
+ private _removeEdge({ source, target }: { source: string; target: string }, removeOrphans = false) {
439
442
  untracked(() => {
440
443
  batch(() => {
441
444
  const outboundIndex = this._edges[source]?.outbound.findIndex((id) => id === target);
@@ -447,6 +450,23 @@ export class Graph {
447
450
  if (inboundIndex !== undefined && inboundIndex !== -1) {
448
451
  this._edges[target].inbound.splice(inboundIndex, 1);
449
452
  }
453
+
454
+ if (removeOrphans) {
455
+ if (
456
+ this._edges[source]?.outbound.length === 0 &&
457
+ this._edges[source]?.inbound.length === 0 &&
458
+ source !== ROOT_ID
459
+ ) {
460
+ this._removeNode(source, true);
461
+ }
462
+ if (
463
+ this._edges[target]?.outbound.length === 0 &&
464
+ this._edges[target]?.inbound.length === 0 &&
465
+ target !== ROOT_ID
466
+ ) {
467
+ this._removeNode(target, true);
468
+ }
469
+ }
450
470
  });
451
471
  });
452
472
  }