@dxos/app-graph 0.6.4-staging.b86a0c7 → 0.6.5-staging.097cf0c
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.
- package/dist/lib/browser/index.mjs +19 -16
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +19 -16
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/types/src/graph-builder.d.ts.map +1 -1
- package/dist/types/src/graph.d.ts +1 -0
- package/dist/types/src/graph.d.ts.map +1 -1
- package/package.json +24 -20
- package/src/graph-builder.test.ts +69 -1
- package/src/graph-builder.ts +28 -27
- package/src/graph.test.ts +31 -0
- package/src/graph.ts +10 -2
|
@@ -177,13 +177,16 @@ var Graph = class {
|
|
|
177
177
|
];
|
|
178
178
|
}
|
|
179
179
|
async expand(node, relation = "outbound", type) {
|
|
180
|
-
const key =
|
|
180
|
+
const key = this._key(node, relation, type);
|
|
181
181
|
const initialized = this._initialized[key];
|
|
182
182
|
if (!initialized && this._onInitialNodes) {
|
|
183
183
|
await this._onInitialNodes(node, relation, type);
|
|
184
184
|
this._initialized[key] = true;
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
|
+
_key(node, relation, type) {
|
|
188
|
+
return `${node.id}-${relation}-${type}`;
|
|
189
|
+
}
|
|
187
190
|
/**
|
|
188
191
|
* Recursive depth-first traversal of the graph.
|
|
189
192
|
*
|
|
@@ -369,6 +372,9 @@ var Graph = class {
|
|
|
369
372
|
delete this._edges[id];
|
|
370
373
|
}
|
|
371
374
|
delete this._nodes[id];
|
|
375
|
+
Object.keys(this._initialized).filter((key) => key.startsWith(id)).forEach((key) => {
|
|
376
|
+
delete this._initialized[key];
|
|
377
|
+
});
|
|
372
378
|
void this._onRemoveNode?.(id);
|
|
373
379
|
});
|
|
374
380
|
}
|
|
@@ -641,12 +647,11 @@ var GraphBuilder = class {
|
|
|
641
647
|
}
|
|
642
648
|
async _onInitialNode(nodeId) {
|
|
643
649
|
this._nodeChanged[nodeId] = this._nodeChanged[nodeId] ?? signal({});
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
const unsubscribe = effect2(() => {
|
|
650
|
+
this._resolverSubscriptions.set(nodeId, effect2(() => {
|
|
651
|
+
for (const { id, resolver } of Object.values(this._extensions)) {
|
|
652
|
+
if (!resolver) {
|
|
653
|
+
continue;
|
|
654
|
+
}
|
|
650
655
|
this._dispatcher.currentExtension = id;
|
|
651
656
|
this._dispatcher.stateIndex = 0;
|
|
652
657
|
BuilderInternal.currentDispatcher = this._dispatcher;
|
|
@@ -655,28 +660,26 @@ var GraphBuilder = class {
|
|
|
655
660
|
});
|
|
656
661
|
BuilderInternal.currentDispatcher = void 0;
|
|
657
662
|
if (node) {
|
|
658
|
-
resolved = true;
|
|
659
663
|
this.graph._addNodes([
|
|
660
664
|
node
|
|
661
665
|
]);
|
|
662
666
|
if (this._nodeChanged[node.id]) {
|
|
663
667
|
this._nodeChanged[node.id].value = {};
|
|
664
668
|
}
|
|
669
|
+
break;
|
|
665
670
|
}
|
|
666
|
-
});
|
|
667
|
-
if (resolved) {
|
|
668
|
-
this._resolverSubscriptions.get(nodeId)?.();
|
|
669
|
-
this._resolverSubscriptions.set(nodeId, unsubscribe);
|
|
670
|
-
break;
|
|
671
|
-
} else {
|
|
672
|
-
unsubscribe();
|
|
673
671
|
}
|
|
674
|
-
}
|
|
672
|
+
}));
|
|
675
673
|
}
|
|
676
674
|
async _onInitialNodes(node, nodesRelation, nodesType) {
|
|
677
675
|
this._nodeChanged[node.id] = this._nodeChanged[node.id] ?? signal({});
|
|
676
|
+
let first = true;
|
|
678
677
|
let previous = [];
|
|
679
678
|
this._connectorSubscriptions.set(node.id, effect2(() => {
|
|
679
|
+
if (!first && !this._connectorSubscriptions.has(node.id)) {
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
first = false;
|
|
680
683
|
Object.keys(this._extensions);
|
|
681
684
|
this._nodeChanged[node.id].value;
|
|
682
685
|
const nodes = [];
|
|
@@ -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 // TODO(wittjosiah): Factor out helper.\n const key = `${node.id}-${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 /**\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 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 let resolved = false;\n for (const { id, resolver } of Object.values(this._extensions)) {\n if (resolved || !resolver) {\n continue;\n }\n\n const unsubscribe = effect(() => {\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 resolved = true;\n this.graph._addNodes([node]);\n if (this._nodeChanged[node.id]) {\n this._nodeChanged[node.id].value = {};\n }\n }\n });\n\n if (resolved) {\n this._resolverSubscriptions.get(nodeId)?.();\n this._resolverSubscriptions.set(nodeId, unsubscribe);\n break;\n } else {\n unsubscribe();\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 previous: string[] = [];\n this._connectorSubscriptions.set(\n node.id,\n effect(() => {\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", "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", "_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", "
|
|
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"]
|
|
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":
|
|
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}}}
|
package/dist/lib/node/index.cjs
CHANGED
|
@@ -208,13 +208,16 @@ var Graph = class {
|
|
|
208
208
|
];
|
|
209
209
|
}
|
|
210
210
|
async expand(node, relation = "outbound", type) {
|
|
211
|
-
const key =
|
|
211
|
+
const key = this._key(node, relation, type);
|
|
212
212
|
const initialized = this._initialized[key];
|
|
213
213
|
if (!initialized && this._onInitialNodes) {
|
|
214
214
|
await this._onInitialNodes(node, relation, type);
|
|
215
215
|
this._initialized[key] = true;
|
|
216
216
|
}
|
|
217
217
|
}
|
|
218
|
+
_key(node, relation, type) {
|
|
219
|
+
return `${node.id}-${relation}-${type}`;
|
|
220
|
+
}
|
|
218
221
|
/**
|
|
219
222
|
* Recursive depth-first traversal of the graph.
|
|
220
223
|
*
|
|
@@ -400,6 +403,9 @@ var Graph = class {
|
|
|
400
403
|
delete this._edges[id];
|
|
401
404
|
}
|
|
402
405
|
delete this._nodes[id];
|
|
406
|
+
Object.keys(this._initialized).filter((key) => key.startsWith(id)).forEach((key) => {
|
|
407
|
+
delete this._initialized[key];
|
|
408
|
+
});
|
|
403
409
|
void this._onRemoveNode?.(id);
|
|
404
410
|
});
|
|
405
411
|
}
|
|
@@ -666,12 +672,11 @@ var GraphBuilder = class {
|
|
|
666
672
|
}
|
|
667
673
|
async _onInitialNode(nodeId) {
|
|
668
674
|
this._nodeChanged[nodeId] = this._nodeChanged[nodeId] ?? (0, import_signals_core2.signal)({});
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
const unsubscribe = (0, import_signals_core2.effect)(() => {
|
|
675
|
+
this._resolverSubscriptions.set(nodeId, (0, import_signals_core2.effect)(() => {
|
|
676
|
+
for (const { id, resolver } of Object.values(this._extensions)) {
|
|
677
|
+
if (!resolver) {
|
|
678
|
+
continue;
|
|
679
|
+
}
|
|
675
680
|
this._dispatcher.currentExtension = id;
|
|
676
681
|
this._dispatcher.stateIndex = 0;
|
|
677
682
|
BuilderInternal.currentDispatcher = this._dispatcher;
|
|
@@ -680,28 +685,26 @@ var GraphBuilder = class {
|
|
|
680
685
|
});
|
|
681
686
|
BuilderInternal.currentDispatcher = void 0;
|
|
682
687
|
if (node) {
|
|
683
|
-
resolved = true;
|
|
684
688
|
this.graph._addNodes([
|
|
685
689
|
node
|
|
686
690
|
]);
|
|
687
691
|
if (this._nodeChanged[node.id]) {
|
|
688
692
|
this._nodeChanged[node.id].value = {};
|
|
689
693
|
}
|
|
694
|
+
break;
|
|
690
695
|
}
|
|
691
|
-
});
|
|
692
|
-
if (resolved) {
|
|
693
|
-
this._resolverSubscriptions.get(nodeId)?.();
|
|
694
|
-
this._resolverSubscriptions.set(nodeId, unsubscribe);
|
|
695
|
-
break;
|
|
696
|
-
} else {
|
|
697
|
-
unsubscribe();
|
|
698
696
|
}
|
|
699
|
-
}
|
|
697
|
+
}));
|
|
700
698
|
}
|
|
701
699
|
async _onInitialNodes(node, nodesRelation, nodesType) {
|
|
702
700
|
this._nodeChanged[node.id] = this._nodeChanged[node.id] ?? (0, import_signals_core2.signal)({});
|
|
701
|
+
let first = true;
|
|
703
702
|
let previous = [];
|
|
704
703
|
this._connectorSubscriptions.set(node.id, (0, import_signals_core2.effect)(() => {
|
|
704
|
+
if (!first && !this._connectorSubscriptions.has(node.id)) {
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
first = false;
|
|
705
708
|
Object.keys(this._extensions);
|
|
706
709
|
this._nodeChanged[node.id].value;
|
|
707
710
|
const nodes = [];
|
|
@@ -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 // TODO(wittjosiah): Factor out helper.\n const key = `${node.id}-${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 /**\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 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 let resolved = false;\n for (const { id, resolver } of Object.values(this._extensions)) {\n if (resolved || !resolver) {\n continue;\n }\n\n const unsubscribe = effect(() => {\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 resolved = true;\n this.graph._addNodes([node]);\n if (this._nodeChanged[node.id]) {\n this._nodeChanged[node.id].value = {};\n }\n }\n });\n\n if (resolved) {\n this._resolverSubscriptions.get(nodeId)?.();\n this._resolverSubscriptions.set(nodeId, unsubscribe);\n break;\n } else {\n unsubscribe();\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 previous: string[] = [];\n this._connectorSubscriptions.set(\n node.id,\n effect(() => {\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", "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", "_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", "
|
|
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"]
|
|
7
7
|
}
|
package/dist/lib/node/meta.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"inputs":{"packages/sdk/app-graph/src/node.ts":{"bytes":5259,"imports":[],"format":"esm"},"packages/sdk/app-graph/src/graph.ts":{"bytes":
|
|
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 +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.
|
|
3
|
+
"version": "0.6.5-staging.097cf0c",
|
|
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",
|
|
@@ -9,12 +9,16 @@
|
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
11
|
"browser": "./dist/lib/browser/index.mjs",
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
"node": {
|
|
13
|
+
"default": "./dist/lib/node/index.cjs"
|
|
14
|
+
},
|
|
15
|
+
"types": "./dist/types/src/index.d.ts"
|
|
15
16
|
}
|
|
16
17
|
},
|
|
17
18
|
"types": "dist/types/src/index.d.ts",
|
|
19
|
+
"typesVersions": {
|
|
20
|
+
"*": {}
|
|
21
|
+
},
|
|
18
22
|
"files": [
|
|
19
23
|
"dist",
|
|
20
24
|
"src"
|
|
@@ -22,30 +26,30 @@
|
|
|
22
26
|
"dependencies": {
|
|
23
27
|
"@preact/signals-core": "^1.6.0",
|
|
24
28
|
"main-thread-scheduling": "^14.1.1",
|
|
25
|
-
"@dxos/echo-schema": "0.6.
|
|
26
|
-
"@dxos/
|
|
27
|
-
"@dxos/
|
|
28
|
-
"@dxos/
|
|
29
|
-
"@dxos/
|
|
30
|
-
"@dxos/
|
|
31
|
-
"@dxos/
|
|
29
|
+
"@dxos/echo-schema": "0.6.5-staging.097cf0c",
|
|
30
|
+
"@dxos/async": "0.6.5-staging.097cf0c",
|
|
31
|
+
"@dxos/invariant": "0.6.5-staging.097cf0c",
|
|
32
|
+
"@dxos/debug": "0.6.5-staging.097cf0c",
|
|
33
|
+
"@dxos/log": "0.6.5-staging.097cf0c",
|
|
34
|
+
"@dxos/echo-signals": "0.6.5-staging.097cf0c",
|
|
35
|
+
"@dxos/util": "0.6.5-staging.097cf0c"
|
|
32
36
|
},
|
|
33
37
|
"devDependencies": {
|
|
34
38
|
"@phosphor-icons/react": "^2.1.5",
|
|
35
39
|
"@types/react": "^18.0.21",
|
|
36
40
|
"@types/react-dom": "^18.0.6",
|
|
37
|
-
"react": "
|
|
38
|
-
"react-dom": "
|
|
41
|
+
"react": "~18.2.0",
|
|
42
|
+
"react-dom": "~18.2.0",
|
|
39
43
|
"vite": "^5.3.4",
|
|
40
|
-
"@dxos/
|
|
41
|
-
"@dxos/
|
|
42
|
-
"@dxos/react-ui
|
|
43
|
-
"@dxos/react-ui": "0.6.
|
|
44
|
-
"@dxos/storybook-utils": "0.6.
|
|
44
|
+
"@dxos/react-client": "0.6.5-staging.097cf0c",
|
|
45
|
+
"@dxos/random": "0.6.5-staging.097cf0c",
|
|
46
|
+
"@dxos/react-ui": "0.6.5-staging.097cf0c",
|
|
47
|
+
"@dxos/react-ui-theme": "0.6.5-staging.097cf0c",
|
|
48
|
+
"@dxos/storybook-utils": "0.6.5-staging.097cf0c"
|
|
45
49
|
},
|
|
46
50
|
"peerDependencies": {
|
|
47
|
-
"react": "^18.
|
|
48
|
-
"react-dom": "^18.
|
|
51
|
+
"react": "^18.0.0",
|
|
52
|
+
"react-dom": "^18.0.0"
|
|
49
53
|
},
|
|
50
54
|
"publishConfig": {
|
|
51
55
|
"access": "public"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { signal } from '@preact/signals-core';
|
|
5
|
+
import { batch, signal } from '@preact/signals-core';
|
|
6
6
|
import chai, { expect } from 'chai';
|
|
7
7
|
import chaiAsPromised from 'chai-as-promised';
|
|
8
8
|
|
|
@@ -174,6 +174,74 @@ describe('GraphBuilder', () => {
|
|
|
174
174
|
}
|
|
175
175
|
});
|
|
176
176
|
|
|
177
|
+
test('unsubscribes', async () => {
|
|
178
|
+
let count = 0;
|
|
179
|
+
const name = signal('default');
|
|
180
|
+
const sub = signal('default');
|
|
181
|
+
const builder = new GraphBuilder();
|
|
182
|
+
builder.addExtension([
|
|
183
|
+
createExtension({
|
|
184
|
+
id: 'root',
|
|
185
|
+
filter: (node): node is Node<null> => node.id === 'root',
|
|
186
|
+
connector: () =>
|
|
187
|
+
name.value === 'removed'
|
|
188
|
+
? []
|
|
189
|
+
: [{ id: EXAMPLE_ID, type: EXAMPLE_TYPE, data: name, properties: { label: name.value } }],
|
|
190
|
+
}),
|
|
191
|
+
createExtension({
|
|
192
|
+
id: 'connector',
|
|
193
|
+
filter: (node): node is Node<string> => node.id === EXAMPLE_ID,
|
|
194
|
+
connector: () => {
|
|
195
|
+
count++;
|
|
196
|
+
sub.value;
|
|
197
|
+
|
|
198
|
+
return [];
|
|
199
|
+
},
|
|
200
|
+
}),
|
|
201
|
+
]);
|
|
202
|
+
|
|
203
|
+
// Count should not increment until the node is expanded.
|
|
204
|
+
const graph = builder.graph;
|
|
205
|
+
await graph.expand(graph.root);
|
|
206
|
+
expect(count).to.equal(0);
|
|
207
|
+
|
|
208
|
+
// Count should increment when the node is expanded.
|
|
209
|
+
const [node] = graph.nodes(graph.root);
|
|
210
|
+
await graph.expand(node!);
|
|
211
|
+
expect(count).to.equal(1);
|
|
212
|
+
|
|
213
|
+
// Count should increment when the parent changes.
|
|
214
|
+
name.value = 'updated';
|
|
215
|
+
expect(count).to.equal(2);
|
|
216
|
+
|
|
217
|
+
// Count should increment when the signal changes.
|
|
218
|
+
sub.value = 'updated';
|
|
219
|
+
expect(count).to.equal(3);
|
|
220
|
+
|
|
221
|
+
// Count will still increment if the node is removed in a batch.
|
|
222
|
+
batch(() => {
|
|
223
|
+
name.value = 'removed';
|
|
224
|
+
sub.value = 'batch';
|
|
225
|
+
});
|
|
226
|
+
expect(count).to.equal(4);
|
|
227
|
+
|
|
228
|
+
// Count should not increment after the node is removed.
|
|
229
|
+
sub.value = 'removed';
|
|
230
|
+
expect(count).to.equal(4);
|
|
231
|
+
|
|
232
|
+
// Count will not increment when node is added back.
|
|
233
|
+
name.value = 'added';
|
|
234
|
+
expect(count).to.equal(4);
|
|
235
|
+
|
|
236
|
+
// Count should increment when the node is expanded again.
|
|
237
|
+
await graph.expand(node!);
|
|
238
|
+
expect(count).to.equal(5);
|
|
239
|
+
|
|
240
|
+
// Count should increment when signal changes again.
|
|
241
|
+
sub.value = 'added';
|
|
242
|
+
expect(count).to.equal(6);
|
|
243
|
+
});
|
|
244
|
+
|
|
177
245
|
test('filters by type', async () => {
|
|
178
246
|
const builder = new GraphBuilder();
|
|
179
247
|
builder.addExtension(
|
package/src/graph-builder.ts
CHANGED
|
@@ -265,43 +265,44 @@ export class GraphBuilder {
|
|
|
265
265
|
|
|
266
266
|
private async _onInitialNode(nodeId: string) {
|
|
267
267
|
this._nodeChanged[nodeId] = this._nodeChanged[nodeId] ?? signal({});
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
268
|
+
this._resolverSubscriptions.set(
|
|
269
|
+
nodeId,
|
|
270
|
+
effect(() => {
|
|
271
|
+
for (const { id, resolver } of Object.values(this._extensions)) {
|
|
272
|
+
if (!resolver) {
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
this._dispatcher.currentExtension = id;
|
|
276
|
+
this._dispatcher.stateIndex = 0;
|
|
277
|
+
BuilderInternal.currentDispatcher = this._dispatcher;
|
|
278
|
+
const node = resolver({ id: nodeId });
|
|
279
|
+
BuilderInternal.currentDispatcher = undefined;
|
|
280
|
+
if (node) {
|
|
281
|
+
this.graph._addNodes([node]);
|
|
282
|
+
if (this._nodeChanged[node.id]) {
|
|
283
|
+
this._nodeChanged[node.id].value = {};
|
|
284
|
+
}
|
|
285
|
+
break;
|
|
285
286
|
}
|
|
286
287
|
}
|
|
287
|
-
})
|
|
288
|
-
|
|
289
|
-
if (resolved) {
|
|
290
|
-
this._resolverSubscriptions.get(nodeId)?.();
|
|
291
|
-
this._resolverSubscriptions.set(nodeId, unsubscribe);
|
|
292
|
-
break;
|
|
293
|
-
} else {
|
|
294
|
-
unsubscribe();
|
|
295
|
-
}
|
|
296
|
-
}
|
|
288
|
+
}),
|
|
289
|
+
);
|
|
297
290
|
}
|
|
298
291
|
|
|
299
292
|
private async _onInitialNodes(node: Node, nodesRelation: Relation, nodesType?: string) {
|
|
300
293
|
this._nodeChanged[node.id] = this._nodeChanged[node.id] ?? signal({});
|
|
294
|
+
let first = true;
|
|
301
295
|
let previous: string[] = [];
|
|
302
296
|
this._connectorSubscriptions.set(
|
|
303
297
|
node.id,
|
|
304
298
|
effect(() => {
|
|
299
|
+
// TODO(wittjosiah): This is a workaround for a race between the node removal and the effect re-running.
|
|
300
|
+
// To cause this case to happen, remove a collection and then undo the removal.
|
|
301
|
+
if (!first && !this._connectorSubscriptions.has(node.id)) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
first = false;
|
|
305
|
+
|
|
305
306
|
// Subscribe to extensions being added.
|
|
306
307
|
Object.keys(this._extensions);
|
|
307
308
|
// Subscribe to connected node changes.
|
package/src/graph.test.ts
CHANGED
|
@@ -110,6 +110,37 @@ describe('Graph', () => {
|
|
|
110
110
|
expect(graph.nodes(root)).to.have.length(1);
|
|
111
111
|
});
|
|
112
112
|
|
|
113
|
+
test('re-add node', () => {
|
|
114
|
+
const graph = new Graph();
|
|
115
|
+
|
|
116
|
+
graph._addNodes([
|
|
117
|
+
{
|
|
118
|
+
id: ROOT_ID,
|
|
119
|
+
type: ROOT_TYPE,
|
|
120
|
+
nodes: [{ id: 'test1', type: 'test' }],
|
|
121
|
+
},
|
|
122
|
+
]);
|
|
123
|
+
|
|
124
|
+
expect(graph.root.id).to.equal('root');
|
|
125
|
+
expect(graph.nodes(graph.root)).to.have.length(1);
|
|
126
|
+
expect(graph.findNode('test1')?.id).to.equal('test1');
|
|
127
|
+
|
|
128
|
+
graph._removeNodes(['test1']);
|
|
129
|
+
expect(graph.findNode('test1')).to.be.undefined;
|
|
130
|
+
expect(graph.nodes(graph.root)).to.be.empty;
|
|
131
|
+
|
|
132
|
+
graph._addNodes([
|
|
133
|
+
{
|
|
134
|
+
id: ROOT_ID,
|
|
135
|
+
type: ROOT_TYPE,
|
|
136
|
+
nodes: [{ id: 'test1', type: 'test' }],
|
|
137
|
+
},
|
|
138
|
+
]);
|
|
139
|
+
expect(graph.root.id).to.equal('root');
|
|
140
|
+
expect(graph.nodes(graph.root)).to.have.length(1);
|
|
141
|
+
expect(graph.findNode('test1')?.id).to.equal('test1');
|
|
142
|
+
});
|
|
143
|
+
|
|
113
144
|
test('add edge', () => {
|
|
114
145
|
const graph = new Graph();
|
|
115
146
|
|
package/src/graph.ts
CHANGED
|
@@ -200,8 +200,7 @@ export class Graph {
|
|
|
200
200
|
}
|
|
201
201
|
|
|
202
202
|
async expand(node: Node, relation: Relation = 'outbound', type?: string) {
|
|
203
|
-
|
|
204
|
-
const key = `${node.id}-${relation}-${type}`;
|
|
203
|
+
const key = this._key(node, relation, type);
|
|
205
204
|
const initialized = this._initialized[key];
|
|
206
205
|
if (!initialized && this._onInitialNodes) {
|
|
207
206
|
await this._onInitialNodes(node, relation, type);
|
|
@@ -209,6 +208,10 @@ export class Graph {
|
|
|
209
208
|
}
|
|
210
209
|
}
|
|
211
210
|
|
|
211
|
+
private _key(node: Node, relation: Relation, type?: string) {
|
|
212
|
+
return `${node.id}-${relation}-${type}`;
|
|
213
|
+
}
|
|
214
|
+
|
|
212
215
|
/**
|
|
213
216
|
* Recursive depth-first traversal of the graph.
|
|
214
217
|
*
|
|
@@ -385,6 +388,11 @@ export class Graph {
|
|
|
385
388
|
|
|
386
389
|
// Remove node.
|
|
387
390
|
delete this._nodes[id];
|
|
391
|
+
Object.keys(this._initialized)
|
|
392
|
+
.filter((key) => key.startsWith(id))
|
|
393
|
+
.forEach((key) => {
|
|
394
|
+
delete this._initialized[key];
|
|
395
|
+
});
|
|
388
396
|
void this._onRemoveNode?.(id);
|
|
389
397
|
});
|
|
390
398
|
}
|