@dxos/app-graph 0.8.3 → 0.8.4-main.1068cf700f

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.
Files changed (47) hide show
  1. package/dist/lib/browser/index.mjs +1135 -616
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +1134 -616
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/atoms.d.ts +8 -0
  8. package/dist/types/src/atoms.d.ts.map +1 -0
  9. package/dist/types/src/graph-builder.d.ts +113 -60
  10. package/dist/types/src/graph-builder.d.ts.map +1 -1
  11. package/dist/types/src/graph.d.ts +183 -209
  12. package/dist/types/src/graph.d.ts.map +1 -1
  13. package/dist/types/src/index.d.ts +6 -3
  14. package/dist/types/src/index.d.ts.map +1 -1
  15. package/dist/types/src/node-matcher.d.ts +218 -0
  16. package/dist/types/src/node-matcher.d.ts.map +1 -0
  17. package/dist/types/src/node-matcher.test.d.ts +2 -0
  18. package/dist/types/src/node-matcher.test.d.ts.map +1 -0
  19. package/dist/types/src/node.d.ts +32 -3
  20. package/dist/types/src/node.d.ts.map +1 -1
  21. package/dist/types/src/stories/EchoGraph.stories.d.ts +6 -13
  22. package/dist/types/src/stories/EchoGraph.stories.d.ts.map +1 -1
  23. package/dist/types/tsconfig.tsbuildinfo +1 -1
  24. package/package.json +37 -37
  25. package/src/atoms.ts +25 -0
  26. package/src/graph-builder.test.ts +571 -97
  27. package/src/graph-builder.ts +600 -258
  28. package/src/graph.test.ts +300 -107
  29. package/src/graph.ts +971 -400
  30. package/src/index.ts +9 -3
  31. package/src/node-matcher.test.ts +301 -0
  32. package/src/node-matcher.ts +284 -0
  33. package/src/node.ts +40 -5
  34. package/src/stories/EchoGraph.stories.tsx +128 -233
  35. package/src/stories/Tree.tsx +2 -2
  36. package/dist/lib/node/index.cjs +0 -816
  37. package/dist/lib/node/index.cjs.map +0 -7
  38. package/dist/lib/node/meta.json +0 -1
  39. package/dist/types/src/experimental/graph-projections.test.d.ts +0 -25
  40. package/dist/types/src/experimental/graph-projections.test.d.ts.map +0 -1
  41. package/dist/types/src/signals-integration.test.d.ts +0 -2
  42. package/dist/types/src/signals-integration.test.d.ts.map +0 -1
  43. package/dist/types/src/testing.d.ts +0 -5
  44. package/dist/types/src/testing.d.ts.map +0 -1
  45. package/src/experimental/graph-projections.test.ts +0 -56
  46. package/src/signals-integration.test.ts +0 -218
  47. package/src/testing.ts +0 -20
@@ -1,20 +1,98 @@
1
1
  import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, { get: all[name], enumerable: true });
6
+ };
7
+
8
+ // src/atoms.ts
9
+ var atoms_exports = {};
10
+ __export(atoms_exports, {
11
+ fromObservable: () => fromObservable
12
+ });
13
+ import { Atom } from "@effect-atom/atom-react";
14
+ var observableFamily = Atom.family((observable) => {
15
+ return Atom.make((get2) => {
16
+ const subscription = observable.subscribe((value) => get2.setSelf(value));
17
+ get2.addFinalizer(() => subscription.unsubscribe());
18
+ return observable.get();
19
+ });
20
+ });
21
+ var fromObservable = (observable) => {
22
+ return observableFamily(observable);
23
+ };
2
24
 
3
- // packages/sdk/app-graph/src/graph.ts
4
- import { Registry, Rx } from "@effect-rx/rx-react";
5
- import { Option, pipe, Record } from "effect";
25
+ // src/graph.ts
26
+ var graph_exports = {};
27
+ __export(graph_exports, {
28
+ GraphKind: () => GraphKind,
29
+ GraphTypeId: () => GraphTypeId,
30
+ addEdge: () => addEdge,
31
+ addEdges: () => addEdges,
32
+ addNode: () => addNode,
33
+ addNodes: () => addNodes,
34
+ expand: () => expand,
35
+ getActions: () => getActions,
36
+ getConnections: () => getConnections,
37
+ getEdges: () => getEdges,
38
+ getGraph: () => getGraph,
39
+ getNode: () => getNode,
40
+ getNodeOrThrow: () => getNodeOrThrow,
41
+ getPath: () => getPath,
42
+ getRoot: () => getRoot,
43
+ initialize: () => initialize,
44
+ make: () => make,
45
+ removeEdge: () => removeEdge,
46
+ removeEdges: () => removeEdges,
47
+ removeNode: () => removeNode,
48
+ removeNodes: () => removeNodes,
49
+ sortEdges: () => sortEdges,
50
+ toJSON: () => toJSON,
51
+ traverse: () => traverse,
52
+ waitForPath: () => waitForPath
53
+ });
54
+ import { Atom as Atom2, Registry } from "@effect-atom/atom-react";
55
+ import * as Function from "effect/Function";
56
+ import * as Option from "effect/Option";
57
+ import * as Pipeable from "effect/Pipeable";
58
+ import * as Record from "effect/Record";
6
59
  import { Event, Trigger } from "@dxos/async";
7
60
  import { todo } from "@dxos/debug";
8
61
  import { invariant } from "@dxos/invariant";
9
62
  import { log } from "@dxos/log";
10
63
  import { isNonNullable } from "@dxos/util";
11
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/sdk/app-graph/src/graph.ts";
64
+
65
+ // src/node.ts
66
+ var node_exports = {};
67
+ __export(node_exports, {
68
+ ActionGroupType: () => ActionGroupType,
69
+ ActionType: () => ActionType,
70
+ RootId: () => RootId,
71
+ RootType: () => RootType,
72
+ actionGroupSymbol: () => actionGroupSymbol,
73
+ isAction: () => isAction,
74
+ isActionGroup: () => isActionGroup,
75
+ isActionLike: () => isActionLike,
76
+ isGraphNode: () => isGraphNode
77
+ });
78
+ var RootId = "root";
79
+ var RootType = "dxos.org/type/GraphRoot";
80
+ var ActionType = "dxos.org/type/GraphAction";
81
+ var ActionGroupType = "dxos.org/type/GraphActionGroup";
82
+ var isGraphNode = (data) => data && typeof data === "object" && "id" in data && "properties" in data && data.properties ? typeof data.properties === "object" && "data" in data : false;
83
+ var isAction = (data) => isGraphNode(data) ? typeof data.data === "function" && data.type === ActionType : false;
84
+ var actionGroupSymbol = Symbol("ActionGroup");
85
+ var isActionGroup = (data) => isGraphNode(data) ? data.data === actionGroupSymbol && data.type === ActionGroupType : false;
86
+ var isActionLike = (data) => isAction(data) || isActionGroup(data);
87
+
88
+ // src/graph.ts
89
+ var __dxlog_file = "/__w/dxos/dxos/packages/sdk/app-graph/src/graph.ts";
12
90
  var graphSymbol = Symbol("graph");
13
91
  var getGraph = (node) => {
14
92
  const graph = node[graphSymbol];
15
93
  invariant(graph, "Node is not associated with a graph.", {
16
94
  F: __dxlog_file,
17
- L: 25,
95
+ L: 32,
18
96
  S: void 0,
19
97
  A: [
20
98
  "graph",
@@ -23,95 +101,103 @@ var getGraph = (node) => {
23
101
  });
24
102
  return graph;
25
103
  };
26
- var ROOT_ID = "root";
27
- var ROOT_TYPE = "dxos.org/type/GraphRoot";
28
- var ACTION_TYPE = "dxos.org/type/GraphAction";
29
- var ACTION_GROUP_TYPE = "dxos.org/type/GraphActionGroup";
30
- var Graph = class {
31
- constructor({ registry, nodes, edges, onExpand, onRemoveNode } = {}) {
32
- this.onNodeChanged = new Event();
33
- this._expanded = Record.empty();
34
- this._initialized = Record.empty();
35
- this._initialEdges = Record.empty();
36
- this._initialNodes = Record.fromEntries([
37
- [
38
- ROOT_ID,
39
- this._constructNode({
40
- id: ROOT_ID,
41
- type: ROOT_TYPE,
42
- data: null,
43
- properties: {}
44
- })
45
- ]
46
- ]);
47
- /** @internal */
48
- this._node = Rx.family((id) => {
49
- const initial = Option.flatten(Record.get(this._initialNodes, id));
50
- return Rx.make(initial).pipe(Rx.keepAlive, Rx.withLabel(`graph:node:${id}`));
51
- });
52
- this._nodeOrThrow = Rx.family((id) => {
53
- return Rx.make((get) => {
54
- const node = get(this._node(id));
55
- invariant(Option.isSome(node), `Node not available: ${id}`, {
56
- F: __dxlog_file,
57
- L: 253,
58
- S: this,
59
- A: [
60
- "Option.isSome(node)",
61
- "`Node not available: ${id}`"
62
- ]
63
- });
64
- return node.value;
104
+ var GraphTypeId = Symbol.for("@dxos/app-graph/Graph");
105
+ var GraphKind = Symbol.for("@dxos/app-graph/GraphKind");
106
+ var GraphImpl = class {
107
+ [GraphTypeId] = GraphTypeId;
108
+ [GraphKind] = "writable";
109
+ pipe() {
110
+ return Pipeable.pipeArguments(this, arguments);
111
+ }
112
+ onNodeChanged = new Event();
113
+ _onExpand;
114
+ _onInitialize;
115
+ _onRemoveNode;
116
+ _registry;
117
+ _expanded = Record.empty();
118
+ _initialized = Record.empty();
119
+ _initialEdges = Record.empty();
120
+ _initialNodes = Record.fromEntries([
121
+ [
122
+ RootId,
123
+ this._constructNode({
124
+ id: RootId,
125
+ type: RootType,
126
+ data: null,
127
+ properties: {}
128
+ })
129
+ ]
130
+ ]);
131
+ /** @internal */
132
+ _node = Atom2.family((id) => {
133
+ const initial = Option.flatten(Record.get(this._initialNodes, id));
134
+ return Atom2.make(initial).pipe(Atom2.keepAlive, Atom2.withLabel(`graph:node:${id}`));
135
+ });
136
+ _nodeOrThrow = Atom2.family((id) => {
137
+ return Atom2.make((get2) => {
138
+ const node = get2(this._node(id));
139
+ invariant(Option.isSome(node), `Node not available: ${id}`, {
140
+ F: __dxlog_file,
141
+ L: 174,
142
+ S: this,
143
+ A: [
144
+ "Option.isSome(node)",
145
+ "`Node not available: ${id}`"
146
+ ]
65
147
  });
148
+ return node.value;
66
149
  });
67
- this._edges = Rx.family((id) => {
68
- const initial = Record.get(this._initialEdges, id).pipe(Option.getOrElse(() => ({
69
- inbound: [],
70
- outbound: []
71
- })));
72
- return Rx.make(initial).pipe(Rx.keepAlive, Rx.withLabel(`graph:edges:${id}`));
73
- });
74
- // NOTE: Currently the argument to the family needs to be referentially stable for the rx to be referentially stable.
75
- // TODO(wittjosiah): Rx feature request, support for something akin to `ComplexMap` to allow for complex arguments.
76
- this._connections = Rx.family((key) => {
77
- return Rx.make((get) => {
78
- const [id, relation] = key.split("$");
79
- const edges = get(this._edges(id));
80
- return edges[relation].map((id2) => get(this._node(id2))).filter(Option.isSome).map((o) => o.value);
81
- }).pipe(Rx.withLabel(`graph:connections:${key}`));
82
- });
83
- this._actions = Rx.family((id) => {
84
- return Rx.make((get) => {
85
- return get(this._connections(`${id}$outbound`)).filter((node) => node.type === ACTION_TYPE || node.type === ACTION_GROUP_TYPE);
86
- }).pipe(Rx.withLabel(`graph:actions:${id}`));
87
- });
88
- this._json = Rx.family((id) => {
89
- return Rx.make((get) => {
90
- const toJSON = (node, seen = []) => {
91
- const nodes = get(this.connections(node.id));
92
- const obj = {
93
- id: node.id.length > 32 ? `${node.id.slice(0, 32)}...` : node.id,
94
- type: node.type
95
- };
96
- if (node.properties.label) {
97
- obj.label = node.properties.label;
98
- }
99
- if (nodes.length) {
100
- obj.nodes = nodes.map((n) => {
101
- const nextSeen = [
102
- ...seen,
103
- node.id
104
- ];
105
- return nextSeen.includes(n.id) ? void 0 : toJSON(n, nextSeen);
106
- }).filter(isNonNullable);
107
- }
108
- return obj;
150
+ });
151
+ _edges = Atom2.family((id) => {
152
+ const initial = Record.get(this._initialEdges, id).pipe(Option.getOrElse(() => ({
153
+ inbound: [],
154
+ outbound: []
155
+ })));
156
+ return Atom2.make(initial).pipe(Atom2.keepAlive, Atom2.withLabel(`graph:edges:${id}`));
157
+ });
158
+ // NOTE: Currently the argument to the family needs to be referentially stable for the atom to be referentially stable.
159
+ // TODO(wittjosiah): Atom feature request, support for something akin to `ComplexMap` to allow for complex arguments.
160
+ _connections = Atom2.family((key) => {
161
+ return Atom2.make((get2) => {
162
+ const [id, relation] = key.split("$");
163
+ const edges = get2(this._edges(id));
164
+ return edges[relation].map((id2) => get2(this._node(id2))).filter(Option.isSome).map((o) => o.value);
165
+ }).pipe(Atom2.withLabel(`graph:connections:${key}`));
166
+ });
167
+ _actions = Atom2.family((id) => {
168
+ return Atom2.make((get2) => {
169
+ return get2(this._connections(`${id}$outbound`)).filter((node) => node.type === ActionType || node.type === ActionGroupType);
170
+ }).pipe(Atom2.withLabel(`graph:actions:${id}`));
171
+ });
172
+ _json = Atom2.family((id) => {
173
+ return Atom2.make((get2) => {
174
+ const toJSON2 = (node, seen = []) => {
175
+ const nodes = get2(this._connections(`${node.id}$outbound`));
176
+ const obj = {
177
+ id: node.id,
178
+ type: node.type
109
179
  };
110
- const root = get(this.nodeOrThrow(id));
111
- return toJSON(root);
112
- }).pipe(Rx.withLabel(`graph:json:${id}`));
113
- });
180
+ if (node.properties.label) {
181
+ obj.label = node.properties.label;
182
+ }
183
+ if (nodes.length) {
184
+ obj.nodes = nodes.map((n) => {
185
+ const nextSeen = [
186
+ ...seen,
187
+ node.id
188
+ ];
189
+ return nextSeen.includes(n.id) ? void 0 : toJSON2(n, nextSeen);
190
+ }).filter(isNonNullable);
191
+ }
192
+ return obj;
193
+ };
194
+ const root = get2(this._nodeOrThrow(id));
195
+ return toJSON2(root);
196
+ }).pipe(Atom2.withLabel(`graph:json:${id}`));
197
+ });
198
+ constructor({ registry, nodes, edges, onInitialize, onExpand, onRemoveNode } = {}) {
114
199
  this._registry = registry ?? Registry.make();
200
+ this._onInitialize = onInitialize;
115
201
  this._onExpand = onExpand;
116
202
  this._onRemoveNode = onRemoveNode;
117
203
  if (nodes) {
@@ -125,500 +211,705 @@ var Graph = class {
125
211
  });
126
212
  }
127
213
  }
128
- toJSON(id = ROOT_ID) {
129
- return this._registry.get(this._json(id));
130
- }
131
- json(id = ROOT_ID) {
132
- return this._json(id);
214
+ json(id = RootId) {
215
+ return jsonImpl(this, id);
133
216
  }
134
217
  node(id) {
135
- return this._node(id);
218
+ return nodeImpl(this, id);
136
219
  }
137
220
  nodeOrThrow(id) {
138
- return this._nodeOrThrow(id);
221
+ return nodeOrThrowImpl(this, id);
139
222
  }
140
223
  connections(id, relation = "outbound") {
141
- return this._connections(`${id}$${relation}`);
224
+ return connectionsImpl(this, id, relation);
142
225
  }
143
226
  actions(id) {
144
- return this._actions(id);
227
+ return actionsImpl(this, id);
145
228
  }
146
229
  edges(id) {
147
- return this._edges(id);
148
- }
149
- get root() {
150
- return this.getNodeOrThrow(ROOT_ID);
151
- }
152
- getNode(id) {
153
- return this._registry.get(this.node(id));
154
- }
155
- getNodeOrThrow(id) {
156
- return this._registry.get(this.nodeOrThrow(id));
157
- }
158
- getConnections(id, relation = "outbound") {
159
- return this._registry.get(this.connections(id, relation));
160
- }
161
- getActions(id) {
162
- return this._registry.get(this.actions(id));
163
- }
164
- getEdges(id) {
165
- return this._registry.get(this.edges(id));
166
- }
167
- // TODO(wittjosiah): On initialize to restore state from cache.
168
- // async initialize(id: string) {
169
- // const initialized = Record.get(this._initialized, id).pipe(Option.getOrElse(() => false));
170
- // log('initialize', { id, initialized });
171
- // if (!initialized) {
172
- // await this._onInitialize?.(id);
173
- // Record.set(this._initialized, id, true);
174
- // }
175
- // }
176
- expand(id, relation = "outbound") {
177
- const key = `${id}$${relation}`;
178
- const expanded = Record.get(this._expanded, key).pipe(Option.getOrElse(() => false));
179
- log("expand", {
180
- key,
181
- expanded
182
- }, {
183
- F: __dxlog_file,
184
- L: 395,
185
- S: this,
186
- C: (f, a) => f(...a)
187
- });
188
- if (!expanded) {
189
- this._onExpand?.(id, relation);
190
- Record.set(this._expanded, key, true);
191
- }
230
+ return edgesImpl(this, id);
192
231
  }
193
- addNodes(nodes) {
194
- Rx.batch(() => {
195
- nodes.map((node) => this.addNode(node));
232
+ /** @internal */
233
+ _constructNode(node) {
234
+ return Option.some({
235
+ [graphSymbol]: this,
236
+ data: null,
237
+ properties: {},
238
+ ...node
196
239
  });
197
240
  }
198
- addNode({ nodes, edges, ...nodeArg }) {
199
- const { id, type, data = null, properties = {} } = nodeArg;
200
- const nodeRx = this._node(id);
201
- const node = this._registry.get(nodeRx);
202
- Option.match(node, {
203
- onSome: (node2) => {
204
- const typeChanged = node2.type !== type;
205
- const dataChanged = node2.data !== data;
206
- const propertiesChanged = Object.keys(properties).some((key) => node2.properties[key] !== properties[key]);
207
- log("existing node", {
208
- id,
209
- typeChanged,
210
- dataChanged,
211
- propertiesChanged
212
- }, {
213
- F: __dxlog_file,
214
- L: 417,
215
- S: this,
216
- C: (f, a) => f(...a)
217
- });
218
- if (typeChanged || dataChanged || propertiesChanged) {
219
- log("updating node", {
220
- id,
221
- type,
222
- data,
223
- properties
224
- }, {
225
- F: __dxlog_file,
226
- L: 419,
227
- S: this,
228
- C: (f, a) => f(...a)
229
- });
230
- const newNode = Option.some({
231
- ...node2,
232
- type,
233
- data,
234
- properties: {
235
- ...node2.properties,
236
- ...properties
237
- }
238
- });
239
- this._registry.set(nodeRx, newNode);
240
- this.onNodeChanged.emit({
241
- id,
242
- node: newNode
243
- });
241
+ };
242
+ var getInternal = (graph) => {
243
+ return graph;
244
+ };
245
+ var toJSON = (graph, id = RootId) => {
246
+ const internal = getInternal(graph);
247
+ return internal._registry.get(internal._json(id));
248
+ };
249
+ var jsonImpl = (graph, id = RootId) => {
250
+ const internal = getInternal(graph);
251
+ return internal._json(id);
252
+ };
253
+ var nodeImpl = (graph, id) => {
254
+ const internal = getInternal(graph);
255
+ return internal._node(id);
256
+ };
257
+ var nodeOrThrowImpl = (graph, id) => {
258
+ const internal = getInternal(graph);
259
+ return internal._nodeOrThrow(id);
260
+ };
261
+ var connectionsImpl = (graph, id, relation = "outbound") => {
262
+ const internal = getInternal(graph);
263
+ return internal._connections(`${id}$${relation}`);
264
+ };
265
+ var actionsImpl = (graph, id) => {
266
+ const internal = getInternal(graph);
267
+ return internal._actions(id);
268
+ };
269
+ var edgesImpl = (graph, id) => {
270
+ const internal = getInternal(graph);
271
+ return internal._edges(id);
272
+ };
273
+ var getNodeImpl = (graph, id) => {
274
+ const internal = getInternal(graph);
275
+ return internal._registry.get(nodeImpl(graph, id));
276
+ };
277
+ function getNode(graphOrId, id) {
278
+ if (typeof graphOrId === "string") {
279
+ const id2 = graphOrId;
280
+ return (graph) => getNodeImpl(graph, id2);
281
+ } else {
282
+ const graph = graphOrId;
283
+ return getNodeImpl(graph, id);
284
+ }
285
+ }
286
+ var getNodeOrThrowImpl = (graph, id) => {
287
+ const internal = getInternal(graph);
288
+ return internal._registry.get(nodeOrThrowImpl(graph, id));
289
+ };
290
+ function getNodeOrThrow(graphOrId, id) {
291
+ if (typeof graphOrId === "string") {
292
+ const id2 = graphOrId;
293
+ return (graph) => getNodeOrThrowImpl(graph, id2);
294
+ } else {
295
+ const graph = graphOrId;
296
+ return getNodeOrThrowImpl(graph, id);
297
+ }
298
+ }
299
+ function getRoot(graph) {
300
+ return getNodeOrThrowImpl(graph, RootId);
301
+ }
302
+ var getConnectionsImpl = (graph, id, relation = "outbound") => {
303
+ const internal = getInternal(graph);
304
+ return internal._registry.get(connectionsImpl(graph, id, relation));
305
+ };
306
+ function getConnections(graphOrId, idOrRelation, relation) {
307
+ if (typeof graphOrId === "string") {
308
+ const id = graphOrId;
309
+ const rel = (typeof idOrRelation === "string" ? "outbound" : idOrRelation) ?? "outbound";
310
+ return (graph) => getConnectionsImpl(graph, id, rel);
311
+ } else {
312
+ const graph = graphOrId;
313
+ const id = idOrRelation;
314
+ const rel = relation ?? "outbound";
315
+ return getConnectionsImpl(graph, id, rel);
316
+ }
317
+ }
318
+ var getActionsImpl = (graph, id) => {
319
+ const internal = getInternal(graph);
320
+ return internal._registry.get(actionsImpl(graph, id));
321
+ };
322
+ function getActions(graphOrId, id) {
323
+ if (typeof graphOrId === "string") {
324
+ const id2 = graphOrId;
325
+ return (graph) => getActionsImpl(graph, id2);
326
+ } else {
327
+ const graph = graphOrId;
328
+ return getActionsImpl(graph, id);
329
+ }
330
+ }
331
+ var getEdgesImpl = (graph, id) => {
332
+ const internal = getInternal(graph);
333
+ return internal._registry.get(edgesImpl(graph, id));
334
+ };
335
+ function getEdges(graphOrId, id) {
336
+ if (typeof graphOrId === "string") {
337
+ const id2 = graphOrId;
338
+ return (graph) => getEdgesImpl(graph, id2);
339
+ } else {
340
+ const graph = graphOrId;
341
+ return getEdgesImpl(graph, id);
342
+ }
343
+ }
344
+ var traverseImpl = (graph, options, path = []) => {
345
+ const { visitor, source = RootId, relation = "outbound" } = options;
346
+ if (path.includes(source)) {
347
+ return;
348
+ }
349
+ const node = getNodeOrThrow(graph, source);
350
+ const shouldContinue = visitor(node, [
351
+ ...path,
352
+ source
353
+ ]);
354
+ if (shouldContinue === false) {
355
+ return;
356
+ }
357
+ Object.values(getConnections(graph, source, relation)).forEach((child) => traverseImpl(graph, {
358
+ source: child.id,
359
+ relation,
360
+ visitor
361
+ }, [
362
+ ...path,
363
+ source
364
+ ]));
365
+ };
366
+ function traverse(graphOrOptions, optionsOrPath, path) {
367
+ if (typeof graphOrOptions === "object" && "visitor" in graphOrOptions) {
368
+ const options = graphOrOptions;
369
+ const pathArg = Array.isArray(optionsOrPath) ? optionsOrPath : void 0;
370
+ return (graph) => traverseImpl(graph, options, pathArg);
371
+ } else {
372
+ const graph = graphOrOptions;
373
+ const options = optionsOrPath;
374
+ const pathArg = path ?? (Array.isArray(optionsOrPath) ? optionsOrPath : void 0);
375
+ return traverseImpl(graph, options, pathArg);
376
+ }
377
+ }
378
+ var getPathImpl = (graph, params) => {
379
+ return Function.pipe(getNode(graph, params.source ?? "root"), Option.flatMap((node) => {
380
+ let found = Option.none();
381
+ traverseImpl(graph, {
382
+ source: node.id,
383
+ visitor: (node2, path) => {
384
+ if (Option.isSome(found)) {
385
+ return false;
386
+ }
387
+ if (node2.id === params.target) {
388
+ found = Option.some(path);
244
389
  }
245
- },
246
- onNone: () => {
247
- log("new node", {
390
+ }
391
+ });
392
+ return found;
393
+ }));
394
+ };
395
+ function getPath(graphOrParams, params) {
396
+ if (params === void 0 && typeof graphOrParams === "object" && "target" in graphOrParams) {
397
+ const params2 = graphOrParams;
398
+ return (graph) => getPathImpl(graph, params2);
399
+ } else {
400
+ const graph = graphOrParams;
401
+ return getPathImpl(graph, params);
402
+ }
403
+ }
404
+ var waitForPathImpl = (graph, params, options) => {
405
+ const { timeout = 5e3, interval = 500 } = options ?? {};
406
+ const path = getPathImpl(graph, params);
407
+ if (Option.isSome(path)) {
408
+ return Promise.resolve(path.value);
409
+ }
410
+ const trigger = new Trigger();
411
+ const i = setInterval(() => {
412
+ const path2 = getPathImpl(graph, params);
413
+ if (Option.isSome(path2)) {
414
+ trigger.wake(path2.value);
415
+ }
416
+ }, interval);
417
+ return trigger.wait({
418
+ timeout
419
+ }).finally(() => clearInterval(i));
420
+ };
421
+ function waitForPath(graphOrParams, paramsOrOptions, options) {
422
+ if (typeof graphOrParams === "object" && "target" in graphOrParams) {
423
+ const params = graphOrParams;
424
+ const opts = typeof paramsOrOptions === "object" && !("target" in paramsOrOptions) ? paramsOrOptions : void 0;
425
+ return (graph) => waitForPathImpl(graph, params, opts);
426
+ } else {
427
+ const graph = graphOrParams;
428
+ const params = paramsOrOptions;
429
+ return waitForPathImpl(graph, params, options);
430
+ }
431
+ }
432
+ var initializeImpl = async (graph, id) => {
433
+ const internal = getInternal(graph);
434
+ const initialized = Record.get(internal._initialized, id).pipe(Option.getOrElse(() => false));
435
+ log("initialize", {
436
+ id,
437
+ initialized
438
+ }, {
439
+ F: __dxlog_file,
440
+ L: 661,
441
+ S: void 0,
442
+ C: (f, a) => f(...a)
443
+ });
444
+ if (!initialized) {
445
+ await internal._onInitialize?.(id);
446
+ Record.set(internal._initialized, id, true);
447
+ }
448
+ return graph;
449
+ };
450
+ function initialize(graphOrId, id) {
451
+ if (typeof graphOrId === "string") {
452
+ const id2 = graphOrId;
453
+ return (graph) => initializeImpl(graph, id2);
454
+ } else {
455
+ const graph = graphOrId;
456
+ return initializeImpl(graph, id);
457
+ }
458
+ }
459
+ var expandImpl = (graph, id, relation = "outbound") => {
460
+ const internal = getInternal(graph);
461
+ const key = `${id}$${relation}`;
462
+ const expanded = Record.get(internal._expanded, key).pipe(Option.getOrElse(() => false));
463
+ log("expand", {
464
+ key,
465
+ expanded
466
+ }, {
467
+ F: __dxlog_file,
468
+ L: 702,
469
+ S: void 0,
470
+ C: (f, a) => f(...a)
471
+ });
472
+ if (!expanded) {
473
+ internal._onExpand?.(id, relation);
474
+ Record.set(internal._expanded, key, true);
475
+ }
476
+ return graph;
477
+ };
478
+ function expand(graphOrId, idOrRelation, relation) {
479
+ if (typeof graphOrId === "string") {
480
+ const id = graphOrId;
481
+ const rel = (typeof idOrRelation === "string" ? "outbound" : idOrRelation) ?? "outbound";
482
+ return (graph) => expandImpl(graph, id, rel);
483
+ } else {
484
+ const graph = graphOrId;
485
+ const id = idOrRelation;
486
+ const rel = relation ?? "outbound";
487
+ return expandImpl(graph, id, rel);
488
+ }
489
+ }
490
+ var sortEdgesImpl = (graph, id, relation, order) => {
491
+ const internal = getInternal(graph);
492
+ const edgesAtom = internal._edges(id);
493
+ const edges = internal._registry.get(edgesAtom);
494
+ const unsorted = edges[relation].filter((id2) => !order.includes(id2)) ?? [];
495
+ const sorted = order.filter((id2) => edges[relation].includes(id2)) ?? [];
496
+ edges[relation].splice(0, edges[relation].length, ...[
497
+ ...sorted,
498
+ ...unsorted
499
+ ]);
500
+ internal._registry.set(edgesAtom, edges);
501
+ return graph;
502
+ };
503
+ function sortEdges(graphOrId, idOrRelation, relationOrOrder, order) {
504
+ if (typeof graphOrId === "string") {
505
+ const id = graphOrId;
506
+ const relation = idOrRelation;
507
+ const order2 = relationOrOrder;
508
+ return (graph) => sortEdgesImpl(graph, id, relation, order2);
509
+ } else {
510
+ const graph = graphOrId;
511
+ const id = idOrRelation;
512
+ const relation = relationOrOrder;
513
+ return sortEdgesImpl(graph, id, relation, order);
514
+ }
515
+ }
516
+ var addNodesImpl = (graph, nodes) => {
517
+ Atom2.batch(() => {
518
+ nodes.map((node) => addNodeImpl(graph, node));
519
+ });
520
+ return graph;
521
+ };
522
+ function addNodes(graphOrNodes, nodes) {
523
+ if (nodes === void 0) {
524
+ const nodes2 = graphOrNodes;
525
+ return (graph) => addNodesImpl(graph, nodes2);
526
+ } else {
527
+ const graph = graphOrNodes;
528
+ return addNodesImpl(graph, nodes);
529
+ }
530
+ }
531
+ var addNodeImpl = (graph, nodeArg) => {
532
+ const internal = getInternal(graph);
533
+ const { nodes, edges, id, type, data = null, properties = {}, ...rest } = nodeArg;
534
+ const nodeAtom = internal._node(id);
535
+ const existingNode = internal._registry.get(nodeAtom);
536
+ Option.match(existingNode, {
537
+ onSome: (existing) => {
538
+ const typeChanged = existing.type !== type;
539
+ const dataChanged = existing.data !== data;
540
+ const propertiesChanged = Object.keys(properties).some((key) => existing.properties[key] !== properties[key]);
541
+ log("existing node", {
542
+ id,
543
+ typeChanged,
544
+ dataChanged,
545
+ propertiesChanged
546
+ }, {
547
+ F: __dxlog_file,
548
+ L: 847,
549
+ S: void 0,
550
+ C: (f, a) => f(...a)
551
+ });
552
+ if (typeChanged || dataChanged || propertiesChanged) {
553
+ log("updating node", {
248
554
  id,
249
555
  type,
250
556
  data,
251
557
  properties
252
558
  }, {
253
559
  F: __dxlog_file,
254
- L: 426,
255
- S: this,
560
+ L: 854,
561
+ S: void 0,
256
562
  C: (f, a) => f(...a)
257
563
  });
258
- const newNode = this._constructNode({
259
- id,
564
+ const newNode = Option.some({
565
+ ...existing,
566
+ ...rest,
260
567
  type,
261
568
  data,
262
- properties
569
+ properties: {
570
+ ...existing.properties,
571
+ ...properties
572
+ }
263
573
  });
264
- this._registry.set(nodeRx, newNode);
265
- this.onNodeChanged.emit({
574
+ internal._registry.set(nodeAtom, newNode);
575
+ graph.onNodeChanged.emit({
266
576
  id,
267
577
  node: newNode
268
578
  });
269
579
  }
270
- });
271
- if (nodes) {
272
- this.addNodes(nodes);
273
- const _edges = nodes.map((node2) => ({
274
- source: id,
275
- target: node2.id
276
- }));
277
- this.addEdges(_edges);
278
- }
279
- if (edges) {
280
- todo();
281
- }
282
- }
283
- removeNodes(ids, edges = false) {
284
- Rx.batch(() => {
285
- ids.map((id) => this.removeNode(id, edges));
286
- });
287
- }
288
- removeNode(id, edges = false) {
289
- const nodeRx = this._node(id);
290
- this._registry.set(nodeRx, Option.none());
291
- this.onNodeChanged.emit({
292
- id,
293
- node: Option.none()
294
- });
295
- if (edges) {
296
- const { inbound, outbound } = this._registry.get(this._edges(id));
297
- const edges2 = [
298
- ...inbound.map((source) => ({
299
- source,
300
- target: id
301
- })),
302
- ...outbound.map((target) => ({
303
- source: id,
304
- target
305
- }))
306
- ];
307
- this.removeEdges(edges2);
308
- }
309
- this._onRemoveNode?.(id);
310
- }
311
- addEdges(edges) {
312
- Rx.batch(() => {
313
- edges.map((edge) => this.addEdge(edge));
314
- });
315
- }
316
- addEdge(edgeArg) {
317
- const sourceRx = this._edges(edgeArg.source);
318
- const source = this._registry.get(sourceRx);
319
- if (!source.outbound.includes(edgeArg.target)) {
320
- log("add outbound edge", {
321
- source: edgeArg.source,
322
- target: edgeArg.target
580
+ },
581
+ onNone: () => {
582
+ log("new node", {
583
+ id,
584
+ type,
585
+ data,
586
+ properties
323
587
  }, {
324
588
  F: __dxlog_file,
325
- L: 481,
326
- S: this,
589
+ L: 867,
590
+ S: void 0,
327
591
  C: (f, a) => f(...a)
328
592
  });
329
- this._registry.set(sourceRx, {
330
- inbound: source.inbound,
331
- outbound: [
332
- ...source.outbound,
333
- edgeArg.target
334
- ]
335
- });
336
- }
337
- const targetRx = this._edges(edgeArg.target);
338
- const target = this._registry.get(targetRx);
339
- if (!target.inbound.includes(edgeArg.source)) {
340
- log("add inbound edge", {
341
- source: edgeArg.source,
342
- target: edgeArg.target
343
- }, {
344
- F: __dxlog_file,
345
- L: 488,
346
- S: this,
347
- C: (f, a) => f(...a)
593
+ const newNode = internal._constructNode({
594
+ id,
595
+ type,
596
+ data,
597
+ properties,
598
+ ...rest
348
599
  });
349
- this._registry.set(targetRx, {
350
- inbound: [
351
- ...target.inbound,
352
- edgeArg.source
353
- ],
354
- outbound: target.outbound
600
+ internal._registry.set(nodeAtom, newNode);
601
+ graph.onNodeChanged.emit({
602
+ id,
603
+ node: newNode
355
604
  });
356
605
  }
606
+ });
607
+ if (nodes) {
608
+ addNodesImpl(graph, nodes);
609
+ const _edges = nodes.map((node) => ({
610
+ source: id,
611
+ target: node.id
612
+ }));
613
+ addEdgesImpl(graph, _edges);
614
+ }
615
+ if (edges) {
616
+ todo();
617
+ }
618
+ return graph;
619
+ };
620
+ function addNode(graphOrNodeArg, nodeArg) {
621
+ if (nodeArg === void 0) {
622
+ const nodeArg2 = graphOrNodeArg;
623
+ return (graph) => addNodeImpl(graph, nodeArg2);
624
+ } else {
625
+ const graph = graphOrNodeArg;
626
+ return addNodeImpl(graph, nodeArg);
357
627
  }
358
- removeEdges(edges, removeOrphans = false) {
359
- Rx.batch(() => {
360
- edges.map((edge) => this.removeEdge(edge, removeOrphans));
628
+ }
629
+ var removeNodesImpl = (graph, ids, edges = false) => {
630
+ Atom2.batch(() => {
631
+ ids.map((id) => removeNodeImpl(graph, id, edges));
632
+ });
633
+ return graph;
634
+ };
635
+ function removeNodes(graphOrIds, idsOrEdges, edges) {
636
+ if (Array.isArray(graphOrIds)) {
637
+ const ids = graphOrIds;
638
+ const edgesArg = typeof idsOrEdges === "boolean" ? idsOrEdges : false;
639
+ return (graph) => removeNodesImpl(graph, ids, edgesArg);
640
+ } else {
641
+ const graph = graphOrIds;
642
+ const ids = idsOrEdges;
643
+ const edgesArg = edges ?? false;
644
+ return removeNodesImpl(graph, ids, edgesArg);
645
+ }
646
+ }
647
+ var removeNodeImpl = (graph, id, edges = false) => {
648
+ const internal = getInternal(graph);
649
+ const nodeAtom = internal._node(id);
650
+ internal._registry.set(nodeAtom, Option.none());
651
+ graph.onNodeChanged.emit({
652
+ id,
653
+ node: Option.none()
654
+ });
655
+ if (edges) {
656
+ const { inbound, outbound } = internal._registry.get(internal._edges(id));
657
+ const edgesToRemove = [
658
+ ...inbound.map((source) => ({
659
+ source,
660
+ target: id
661
+ })),
662
+ ...outbound.map((target) => ({
663
+ source: id,
664
+ target
665
+ }))
666
+ ];
667
+ removeEdgesImpl(graph, edgesToRemove);
668
+ }
669
+ internal._onRemoveNode?.(id);
670
+ return graph;
671
+ };
672
+ function removeNode(graphOrId, idOrEdges, edges) {
673
+ if (typeof graphOrId === "string") {
674
+ const id = graphOrId;
675
+ const edgesArg = typeof idOrEdges === "boolean" ? idOrEdges : false;
676
+ return (graph) => removeNodeImpl(graph, id, edgesArg);
677
+ } else {
678
+ const graph = graphOrId;
679
+ const id = idOrEdges;
680
+ const edgesArg = edges ?? false;
681
+ return removeNodeImpl(graph, id, edgesArg);
682
+ }
683
+ }
684
+ var addEdgesImpl = (graph, edges) => {
685
+ Atom2.batch(() => {
686
+ edges.map((edge) => addEdgeImpl(graph, edge));
687
+ });
688
+ return graph;
689
+ };
690
+ function addEdges(graphOrEdges, edges) {
691
+ if (edges === void 0) {
692
+ const edges2 = graphOrEdges;
693
+ return (graph) => addEdgesImpl(graph, edges2);
694
+ } else {
695
+ const graph = graphOrEdges;
696
+ return addEdgesImpl(graph, edges);
697
+ }
698
+ }
699
+ var addEdgeImpl = (graph, edgeArg) => {
700
+ const internal = getInternal(graph);
701
+ const sourceAtom = internal._edges(edgeArg.source);
702
+ const source = internal._registry.get(sourceAtom);
703
+ if (!source.outbound.includes(edgeArg.target)) {
704
+ log("add outbound edge", {
705
+ source: edgeArg.source,
706
+ target: edgeArg.target
707
+ }, {
708
+ F: __dxlog_file,
709
+ L: 1026,
710
+ S: void 0,
711
+ C: (f, a) => f(...a)
712
+ });
713
+ internal._registry.set(sourceAtom, {
714
+ inbound: source.inbound,
715
+ outbound: [
716
+ ...source.outbound,
717
+ edgeArg.target
718
+ ]
361
719
  });
362
720
  }
363
- removeEdge(edgeArg, removeOrphans = false) {
364
- const sourceRx = this._edges(edgeArg.source);
365
- const source = this._registry.get(sourceRx);
366
- if (source.outbound.includes(edgeArg.target)) {
367
- this._registry.set(sourceRx, {
368
- inbound: source.inbound,
369
- outbound: source.outbound.filter((id) => id !== edgeArg.target)
370
- });
371
- }
372
- const targetRx = this._edges(edgeArg.target);
373
- const target = this._registry.get(targetRx);
374
- if (target.inbound.includes(edgeArg.source)) {
375
- this._registry.set(targetRx, {
376
- inbound: target.inbound.filter((id) => id !== edgeArg.source),
377
- outbound: target.outbound
378
- });
379
- }
380
- if (removeOrphans) {
381
- const source2 = this._registry.get(sourceRx);
382
- const target2 = this._registry.get(targetRx);
383
- if (source2.outbound.length === 0 && source2.inbound.length === 0 && edgeArg.source !== ROOT_ID) {
384
- this.removeNodes([
385
- edgeArg.source
386
- ]);
387
- }
388
- if (target2.outbound.length === 0 && target2.inbound.length === 0 && edgeArg.target !== ROOT_ID) {
389
- this.removeNodes([
390
- edgeArg.target
391
- ]);
392
- }
393
- }
721
+ const targetAtom = internal._edges(edgeArg.target);
722
+ const target = internal._registry.get(targetAtom);
723
+ if (!target.inbound.includes(edgeArg.source)) {
724
+ log("add inbound edge", {
725
+ source: edgeArg.source,
726
+ target: edgeArg.target
727
+ }, {
728
+ F: __dxlog_file,
729
+ L: 1039,
730
+ S: void 0,
731
+ C: (f, a) => f(...a)
732
+ });
733
+ internal._registry.set(targetAtom, {
734
+ inbound: [
735
+ ...target.inbound,
736
+ edgeArg.source
737
+ ],
738
+ outbound: target.outbound
739
+ });
394
740
  }
395
- sortEdges(id, relation, order) {
396
- const edgesRx = this._edges(id);
397
- const edges = this._registry.get(edgesRx);
398
- const unsorted = edges[relation].filter((id2) => !order.includes(id2)) ?? [];
399
- const sorted = order.filter((id2) => edges[relation].includes(id2)) ?? [];
400
- edges[relation].splice(0, edges[relation].length, ...[
401
- ...sorted,
402
- ...unsorted
403
- ]);
404
- this._registry.set(edgesRx, edges);
741
+ return graph;
742
+ };
743
+ function addEdge(graphOrEdgeArg, edgeArg) {
744
+ if (edgeArg === void 0) {
745
+ const edgeArg2 = graphOrEdgeArg;
746
+ return (graph) => addEdgeImpl(graph, edgeArg2);
747
+ } else {
748
+ const graph = graphOrEdgeArg;
749
+ return addEdgeImpl(graph, edgeArg);
405
750
  }
406
- traverse({ visitor, source = ROOT_ID, relation = "outbound" }, path = []) {
407
- if (path.includes(source)) {
408
- return;
409
- }
410
- const node = this.getNodeOrThrow(source);
411
- const shouldContinue = visitor(node, [
412
- ...path,
413
- source
414
- ]);
415
- if (shouldContinue === false) {
416
- return;
417
- }
418
- Object.values(this.getConnections(source, relation)).forEach((child) => this.traverse({
419
- source: child.id,
420
- relation,
421
- visitor
422
- }, [
423
- ...path,
424
- source
425
- ]));
426
- }
427
- getPath({ source = "root", target }) {
428
- return pipe(this.getNode(source), Option.flatMap((node) => {
429
- let found = Option.none();
430
- this.traverse({
431
- source: node.id,
432
- visitor: (node2, path) => {
433
- if (Option.isSome(found)) {
434
- return false;
435
- }
436
- if (node2.id === target) {
437
- found = Option.some(path);
438
- }
439
- }
440
- });
441
- return found;
442
- }));
751
+ }
752
+ var removeEdgesImpl = (graph, edges, removeOrphans = false) => {
753
+ Atom2.batch(() => {
754
+ edges.map((edge) => removeEdgeImpl(graph, edge, removeOrphans));
755
+ });
756
+ return graph;
757
+ };
758
+ function removeEdges(graphOrEdges, edgesOrRemoveOrphans, removeOrphans) {
759
+ if (Array.isArray(graphOrEdges)) {
760
+ const edges = graphOrEdges;
761
+ const removeOrphansArg = typeof edgesOrRemoveOrphans === "boolean" ? edgesOrRemoveOrphans : false;
762
+ return (graph) => removeEdgesImpl(graph, edges, removeOrphansArg);
763
+ } else {
764
+ const graph = graphOrEdges;
765
+ const edges = edgesOrRemoveOrphans;
766
+ const removeOrphansArg = removeOrphans ?? false;
767
+ return removeEdgesImpl(graph, edges, removeOrphansArg);
443
768
  }
444
- async waitForPath(params, { timeout = 5e3, interval = 500 } = {}) {
445
- const path = this.getPath(params);
446
- if (Option.isSome(path)) {
447
- return path.value;
448
- }
449
- const trigger = new Trigger();
450
- const i = setInterval(() => {
451
- const path2 = this.getPath(params);
452
- if (Option.isSome(path2)) {
453
- trigger.wake(path2.value);
454
- }
455
- }, interval);
456
- return trigger.wait({
457
- timeout
458
- }).finally(() => clearInterval(i));
769
+ }
770
+ var removeEdgeImpl = (graph, edgeArg, removeOrphans = false) => {
771
+ const internal = getInternal(graph);
772
+ const sourceAtom = internal._edges(edgeArg.source);
773
+ const source = internal._registry.get(sourceAtom);
774
+ if (source.outbound.includes(edgeArg.target)) {
775
+ internal._registry.set(sourceAtom, {
776
+ inbound: source.inbound,
777
+ outbound: source.outbound.filter((id) => id !== edgeArg.target)
778
+ });
459
779
  }
460
- /** @internal */
461
- _constructNode(node) {
462
- return Option.some({
463
- [graphSymbol]: this,
464
- data: null,
465
- properties: {},
466
- ...node
780
+ const targetAtom = internal._edges(edgeArg.target);
781
+ const target = internal._registry.get(targetAtom);
782
+ if (target.inbound.includes(edgeArg.source)) {
783
+ internal._registry.set(targetAtom, {
784
+ inbound: target.inbound.filter((id) => id !== edgeArg.source),
785
+ outbound: target.outbound
467
786
  });
468
787
  }
788
+ if (removeOrphans) {
789
+ const source2 = internal._registry.get(sourceAtom);
790
+ const target2 = internal._registry.get(targetAtom);
791
+ if (source2.outbound.length === 0 && source2.inbound.length === 0 && edgeArg.source !== RootId) {
792
+ removeNodesImpl(graph, [
793
+ edgeArg.source
794
+ ]);
795
+ }
796
+ if (target2.outbound.length === 0 && target2.inbound.length === 0 && edgeArg.target !== RootId) {
797
+ removeNodesImpl(graph, [
798
+ edgeArg.target
799
+ ]);
800
+ }
801
+ }
802
+ return graph;
803
+ };
804
+ function removeEdge(graphOrEdgeArg, edgeArgOrRemoveOrphans, removeOrphans) {
805
+ if (edgeArgOrRemoveOrphans === void 0 || typeof edgeArgOrRemoveOrphans === "boolean" || "source" in graphOrEdgeArg) {
806
+ const edgeArg = graphOrEdgeArg;
807
+ const removeOrphansArg = typeof edgeArgOrRemoveOrphans === "boolean" ? edgeArgOrRemoveOrphans : false;
808
+ return (graph) => removeEdgeImpl(graph, edgeArg, removeOrphansArg);
809
+ } else {
810
+ const graph = graphOrEdgeArg;
811
+ const edgeArg = edgeArgOrRemoveOrphans;
812
+ const removeOrphansArg = removeOrphans ?? false;
813
+ return removeEdgeImpl(graph, edgeArg, removeOrphansArg);
814
+ }
815
+ }
816
+ var make = (params) => {
817
+ return new GraphImpl(params);
469
818
  };
470
819
 
471
- // packages/sdk/app-graph/src/graph-builder.ts
472
- import { Registry as Registry2, Rx as Rx2 } from "@effect-rx/rx-react";
473
- import { effect } from "@preact/signals-core";
474
- import { Array, pipe as pipe2, Record as Record2 } from "effect";
820
+ // src/graph-builder.ts
821
+ var graph_builder_exports = {};
822
+ __export(graph_builder_exports, {
823
+ GraphBuilderTypeId: () => GraphBuilderTypeId,
824
+ addExtension: () => addExtension,
825
+ createConnector: () => createConnector,
826
+ createExtension: () => createExtension,
827
+ createExtensionRaw: () => createExtensionRaw,
828
+ createTypeExtension: () => createTypeExtension,
829
+ destroy: () => destroy,
830
+ explore: () => explore,
831
+ flattenExtensions: () => flattenExtensions,
832
+ from: () => from,
833
+ make: () => make2,
834
+ removeExtension: () => removeExtension
835
+ });
836
+ import { Atom as Atom3, Registry as Registry2 } from "@effect-atom/atom-react";
837
+ import * as Array2 from "effect/Array";
838
+ import * as Effect from "effect/Effect";
839
+ import * as Function2 from "effect/Function";
840
+ import * as Option3 from "effect/Option";
841
+ import * as Pipeable2 from "effect/Pipeable";
842
+ import * as Record2 from "effect/Record";
475
843
  import { log as log2 } from "@dxos/log";
476
844
  import { byPosition, getDebugName, isNode, isNonNullable as isNonNullable2 } from "@dxos/util";
477
845
 
478
- // packages/sdk/app-graph/src/node.ts
479
- var isGraphNode = (data) => data && typeof data === "object" && "id" in data && "properties" in data && data.properties ? typeof data.properties === "object" && "data" in data : false;
480
- var isAction = (data) => isGraphNode(data) ? typeof data.data === "function" : false;
481
- var actionGroupSymbol = Symbol("ActionGroup");
482
- var isActionGroup = (data) => isGraphNode(data) ? data.data === actionGroupSymbol : false;
483
- var isActionLike = (data) => isAction(data) || isActionGroup(data);
484
-
485
- // packages/sdk/app-graph/src/graph-builder.ts
486
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/sdk/app-graph/src/graph-builder.ts";
487
- var createExtension = (extension) => {
488
- const { id, position = "static", relation = "outbound", connector: _connector, actions: _actions, actionGroups: _actionGroups } = extension;
489
- const getId = (key) => `${id}/${key}`;
490
- const connector = _connector && Rx2.family((node) => _connector(node).pipe(Rx2.withLabel(`graph-builder:_connector:${id}`)));
491
- const actionGroups = _actionGroups && Rx2.family((node) => _actionGroups(node).pipe(Rx2.withLabel(`graph-builder:_actionGroups:${id}`)));
492
- const actions = _actions && Rx2.family((node) => _actions(node).pipe(Rx2.withLabel(`graph-builder:_actions:${id}`)));
493
- return [
494
- // resolver ? { id: getId('resolver'), position, resolver } : undefined,
495
- connector ? {
496
- id: getId("connector"),
497
- position,
498
- relation,
499
- connector: Rx2.family((node) => Rx2.make((get) => {
500
- try {
501
- return get(connector(node));
502
- } catch {
503
- log2.warn("Error in connector", {
504
- id: getId("connector"),
505
- node
506
- }, {
507
- F: __dxlog_file2,
508
- L: 101,
509
- S: void 0,
510
- C: (f, a) => f(...a)
511
- });
512
- return [];
513
- }
514
- }).pipe(Rx2.withLabel(`graph-builder:connector:${id}`)))
515
- } : void 0,
516
- actionGroups ? {
517
- id: getId("actionGroups"),
518
- position,
519
- relation: "outbound",
520
- connector: Rx2.family((node) => Rx2.make((get) => {
521
- try {
522
- return get(actionGroups(node)).map((arg) => ({
523
- ...arg,
524
- data: actionGroupSymbol,
525
- type: ACTION_GROUP_TYPE
526
- }));
527
- } catch {
528
- log2.warn("Error in actionGroups", {
529
- id: getId("actionGroups"),
530
- node
531
- }, {
532
- F: __dxlog_file2,
533
- L: 122,
534
- S: void 0,
535
- C: (f, a) => f(...a)
536
- });
537
- return [];
538
- }
539
- }).pipe(Rx2.withLabel(`graph-builder:connector:actionGroups:${id}`)))
540
- } : void 0,
541
- actions ? {
542
- id: getId("actions"),
543
- position,
544
- relation: "outbound",
545
- connector: Rx2.family((node) => Rx2.make((get) => {
546
- try {
547
- return get(actions(node)).map((arg) => ({
548
- ...arg,
549
- type: ACTION_TYPE
550
- }));
551
- } catch {
552
- log2.warn("Error in actions", {
553
- id: getId("actions"),
554
- node
555
- }, {
556
- F: __dxlog_file2,
557
- L: 139,
558
- S: void 0,
559
- C: (f, a) => f(...a)
560
- });
561
- return [];
562
- }
563
- }).pipe(Rx2.withLabel(`graph-builder:connector:actions:${id}`)))
564
- } : void 0
565
- ].filter(isNonNullable2);
846
+ // src/node-matcher.ts
847
+ var node_matcher_exports = {};
848
+ __export(node_matcher_exports, {
849
+ whenAll: () => whenAll,
850
+ whenAny: () => whenAny,
851
+ whenEchoObject: () => whenEchoObject,
852
+ whenEchoObjectMatches: () => whenEchoObjectMatches,
853
+ whenEchoType: () => whenEchoType,
854
+ whenEchoTypeMatches: () => whenEchoTypeMatches,
855
+ whenId: () => whenId,
856
+ whenNodeType: () => whenNodeType,
857
+ whenNot: () => whenNot,
858
+ whenRoot: () => whenRoot
859
+ });
860
+ import * as Option2 from "effect/Option";
861
+ import { Obj } from "@dxos/echo";
862
+ var whenRoot = (node) => node.id === RootId ? Option2.some(node) : Option2.none();
863
+ var whenId = (id) => (node) => node.id === id ? Option2.some(node) : Option2.none();
864
+ var whenNodeType = (type) => (node) => node.type === type ? Option2.some(node) : Option2.none();
865
+ var whenEchoType = (type) => (node) => Obj.instanceOf(type, node.data) ? Option2.some(node.data) : Option2.none();
866
+ var whenEchoObject = (node) => Obj.isObject(node.data) ? Option2.some(node.data) : Option2.none();
867
+ var whenAll = (...matchers) => (node) => {
868
+ for (const matcher of matchers) {
869
+ const result = matcher(node);
870
+ if (Option2.isNone(result)) {
871
+ return Option2.none();
872
+ }
873
+ }
874
+ return Option2.some(node);
566
875
  };
567
- var flattenExtensions = (extension, acc = []) => {
568
- if (Array.isArray(extension)) {
569
- return [
570
- ...acc,
571
- ...extension.flatMap((ext) => flattenExtensions(ext, acc))
572
- ];
573
- } else {
574
- return [
575
- ...acc,
576
- extension
577
- ];
876
+ var whenAny = (...matchers) => (node) => {
877
+ for (const matcher of matchers) {
878
+ const result = matcher(node);
879
+ if (Option2.isSome(result)) {
880
+ return Option2.some(node);
881
+ }
578
882
  }
883
+ return Option2.none();
579
884
  };
580
- var GraphBuilder = class _GraphBuilder {
885
+ var whenEchoTypeMatches = (type) => (node) => Obj.instanceOf(type, node.data) ? Option2.some(node) : Option2.none();
886
+ var whenEchoObjectMatches = (node) => Obj.isObject(node.data) ? Option2.some(node) : Option2.none();
887
+ var whenNot = (matcher) => (node) => Option2.isNone(matcher(node)) ? Option2.some(node) : Option2.none();
888
+
889
+ // src/graph-builder.ts
890
+ var __dxlog_file2 = "/__w/dxos/dxos/packages/sdk/app-graph/src/graph-builder.ts";
891
+ var GraphBuilderTypeId = Symbol.for("@dxos/app-graph/GraphBuilder");
892
+ var GraphBuilderImpl = class {
893
+ [GraphBuilderTypeId] = GraphBuilderTypeId;
894
+ pipe() {
895
+ return Pipeable2.pipeArguments(this, arguments);
896
+ }
897
+ // TODO(wittjosiah): Use Context.
898
+ _subscriptions = /* @__PURE__ */ new Map();
899
+ _extensions = Atom3.make(Record2.empty()).pipe(Atom3.keepAlive, Atom3.withLabel("graph-builder:extensions"));
900
+ _initialized = {};
901
+ _registry;
902
+ _graph;
581
903
  constructor({ registry, ...params } = {}) {
582
- // TODO(wittjosiah): Use Context.
583
- this._connectorSubscriptions = /* @__PURE__ */ new Map();
584
- this._extensions = Rx2.make(Record2.empty()).pipe(Rx2.keepAlive, Rx2.withLabel("graph-builder:extensions"));
585
- this._connectors = Rx2.family((key) => {
586
- return Rx2.make((get) => {
587
- const [id, relation] = key.split("+");
588
- const node = this._graph.node(id);
589
- return pipe2(
590
- get(this._extensions),
591
- Record2.values,
592
- // TODO(wittjosiah): Sort on write rather than read.
593
- Array.sortBy(byPosition),
594
- Array.filter(({ relation: _relation = "outbound" }) => _relation === relation),
595
- Array.map(({ connector }) => connector?.(node)),
596
- Array.filter(isNonNullable2),
597
- Array.flatMap((result) => get(result))
598
- );
599
- }).pipe(Rx2.withLabel(`graph-builder:connectors:${key}`));
600
- });
601
904
  this._registry = registry ?? Registry2.make();
602
- this._graph = new Graph({
905
+ const graph = make({
603
906
  ...params,
604
907
  registry: this._registry,
605
908
  onExpand: (id, relation) => this._onExpand(id, relation),
606
- // onInitialize: (id) => this._onInitialize(id),
909
+ onInitialize: (id) => this._onInitialize(id),
607
910
  onRemoveNode: (id) => this._onRemoveNode(id)
608
911
  });
609
- }
610
- static from(pickle, registry) {
611
- if (!pickle) {
612
- return new _GraphBuilder({
613
- registry
614
- });
615
- }
616
- const { nodes, edges } = JSON.parse(pickle);
617
- return new _GraphBuilder({
618
- nodes,
619
- edges,
620
- registry
621
- });
912
+ this._graph = graph;
622
913
  }
623
914
  get graph() {
624
915
  return this._graph;
@@ -626,56 +917,27 @@ var GraphBuilder = class _GraphBuilder {
626
917
  get extensions() {
627
918
  return this._extensions;
628
919
  }
629
- addExtension(extensions) {
630
- flattenExtensions(extensions).forEach((extension) => {
631
- const extensions2 = this._registry.get(this._extensions);
632
- this._registry.set(this._extensions, Record2.set(extensions2, extension.id, extension));
920
+ _resolvers = Atom3.family((id) => {
921
+ return Atom3.make((get2) => {
922
+ return Function2.pipe(get2(this._extensions), Record2.values, Array2.sortBy(byPosition), Array2.map(({ resolver }) => resolver), Array2.filter(isNonNullable2), Array2.map((resolver) => get2(resolver(id))), Array2.filter(isNonNullable2), Array2.head);
633
923
  });
634
- return this;
635
- }
636
- removeExtension(id) {
637
- const extensions = this._registry.get(this._extensions);
638
- this._registry.set(this._extensions, Record2.remove(extensions, id));
639
- return this;
640
- }
641
- async explore({ registry = Registry2.make(), source = ROOT_ID, relation = "outbound", visitor }, path = []) {
642
- if (path.includes(source)) {
643
- return;
644
- }
645
- if (!isNode()) {
646
- const { yieldOrContinue } = await import("main-thread-scheduling");
647
- await yieldOrContinue("idle");
648
- }
649
- const node = registry.get(this._graph.nodeOrThrow(source));
650
- const shouldContinue = await visitor(node, [
651
- ...path,
652
- node.id
653
- ]);
654
- if (shouldContinue === false) {
655
- return;
656
- }
657
- const nodes = Object.values(this._registry.get(this._extensions)).filter((extension) => relation === (extension.relation ?? "outbound")).map((extension) => extension.connector).filter(isNonNullable2).flatMap((connector) => registry.get(connector(this._graph.node(source))));
658
- await Promise.all(nodes.map((nodeArg) => {
659
- registry.set(this._graph._node(nodeArg.id), this._graph._constructNode(nodeArg));
660
- return this.explore({
661
- registry,
662
- source: nodeArg.id,
663
- relation,
664
- visitor
665
- }, [
666
- ...path,
667
- node.id
668
- ]);
669
- }));
670
- if (registry !== this._registry) {
671
- registry.reset();
672
- registry.dispose();
673
- }
674
- }
675
- destroy() {
676
- this._connectorSubscriptions.forEach((unsubscribe) => unsubscribe());
677
- this._connectorSubscriptions.clear();
678
- }
924
+ });
925
+ _connectors = Atom3.family((key) => {
926
+ return Atom3.make((get2) => {
927
+ const [id, relation] = key.split("+");
928
+ const node = this._graph.node(id);
929
+ return Function2.pipe(
930
+ get2(this._extensions),
931
+ Record2.values,
932
+ // TODO(wittjosiah): Sort on write rather than read.
933
+ Array2.sortBy(byPosition),
934
+ Array2.filter(({ relation: _relation = "outbound" }) => _relation === relation),
935
+ Array2.map(({ connector }) => connector?.(node)),
936
+ Array2.filter(isNonNullable2),
937
+ Array2.flatMap((result) => get2(result))
938
+ );
939
+ }).pipe(Atom3.withLabel(`graph-builder:connectors:${key}`));
940
+ });
679
941
  _onExpand(id, relation) {
680
942
  log2("onExpand", {
681
943
  id,
@@ -683,7 +945,7 @@ var GraphBuilder = class _GraphBuilder {
683
945
  registry: getDebugName(this._registry)
684
946
  }, {
685
947
  F: __dxlog_file2,
686
- L: 301,
948
+ L: 176,
687
949
  S: this,
688
950
  C: (f, a) => f(...a)
689
951
  });
@@ -700,25 +962,25 @@ var GraphBuilder = class _GraphBuilder {
700
962
  removed
701
963
  }, {
702
964
  F: __dxlog_file2,
703
- L: 312,
965
+ L: 187,
704
966
  S: this,
705
967
  C: (f, a) => f(...a)
706
968
  });
707
969
  const update = () => {
708
- Rx2.batch(() => {
709
- this._graph.removeEdges(removed.map((target) => ({
970
+ Atom3.batch(() => {
971
+ removeEdges(this._graph, removed.map((target) => ({
710
972
  source: id,
711
973
  target
712
974
  })), true);
713
- this._graph.addNodes(nodes);
714
- this._graph.addEdges(nodes.map((node) => relation === "outbound" ? {
975
+ addNodes(this._graph, nodes);
976
+ addEdges(this._graph, nodes.map((node) => relation === "outbound" ? {
715
977
  source: id,
716
978
  target: node.id
717
979
  } : {
718
980
  source: node.id,
719
981
  target: id
720
982
  }));
721
- this._graph.sortEdges(id, relation, nodes.map(({ id: id2 }) => id2));
983
+ sortEdges(this._graph, id, relation, nodes.map(({ id: id2 }) => id2));
722
984
  });
723
985
  };
724
986
  if (typeof requestAnimationFrame === "function") {
@@ -729,52 +991,308 @@ var GraphBuilder = class _GraphBuilder {
729
991
  }, {
730
992
  immediate: true
731
993
  });
732
- this._connectorSubscriptions.set(id, cancel);
994
+ this._subscriptions.set(id, cancel);
995
+ }
996
+ // TODO(wittjosiah): If the same node is added by a connector, the resolver should probably cancel itself?
997
+ async _onInitialize(id) {
998
+ log2("onInitialize", {
999
+ id
1000
+ }, {
1001
+ F: __dxlog_file2,
1002
+ L: 227,
1003
+ S: this,
1004
+ C: (f, a) => f(...a)
1005
+ });
1006
+ const resolver = this._resolvers(id);
1007
+ const cancel = this._registry.subscribe(resolver, (node) => {
1008
+ const trigger = this._initialized[id];
1009
+ Option3.match(node, {
1010
+ onSome: (node2) => {
1011
+ addNodes(this._graph, [
1012
+ node2
1013
+ ]);
1014
+ trigger?.wake();
1015
+ },
1016
+ onNone: () => {
1017
+ trigger?.wake();
1018
+ removeNodes(this._graph, [
1019
+ id
1020
+ ]);
1021
+ }
1022
+ });
1023
+ }, {
1024
+ immediate: true
1025
+ });
1026
+ this._subscriptions.set(id, cancel);
733
1027
  }
734
- // TODO(wittjosiah): On initialize to restore state from cache.
735
- // private async _onInitialize(id: string) {
736
- // log('onInitialize', { id });
737
- // }
738
1028
  _onRemoveNode(id) {
739
- this._connectorSubscriptions.get(id)?.();
740
- this._connectorSubscriptions.delete(id);
1029
+ this._subscriptions.get(id)?.();
1030
+ this._subscriptions.delete(id);
741
1031
  }
742
1032
  };
743
- var rxFromSignal = (cb) => {
744
- return Rx2.make((get) => {
745
- const dispose = effect(() => {
746
- get.setSelf(cb());
1033
+ var make2 = (params) => {
1034
+ return new GraphBuilderImpl(params);
1035
+ };
1036
+ var from = (pickle, registry) => {
1037
+ if (!pickle) {
1038
+ return make2({
1039
+ registry
747
1040
  });
748
- get.addFinalizer(() => dispose());
749
- return cb();
1041
+ }
1042
+ const { nodes, edges } = JSON.parse(pickle);
1043
+ return make2({
1044
+ nodes,
1045
+ edges,
1046
+ registry
750
1047
  });
751
1048
  };
752
- var observableFamily = Rx2.family((observable) => {
753
- return Rx2.make((get) => {
754
- const subscription = observable.subscribe((value) => get.setSelf(value));
755
- get.addFinalizer(() => subscription.unsubscribe());
756
- return observable.get();
1049
+ var addExtensionImpl = (builder, extensions) => {
1050
+ const internal = builder;
1051
+ flattenExtensions(extensions).forEach((extension) => {
1052
+ const extensions2 = internal._registry.get(internal._extensions);
1053
+ internal._registry.set(internal._extensions, Record2.set(extensions2, extension.id, extension));
1054
+ });
1055
+ return builder;
1056
+ };
1057
+ function addExtension(builderOrExtensions, extensions) {
1058
+ if (extensions === void 0) {
1059
+ const extensions2 = builderOrExtensions;
1060
+ return (builder) => addExtensionImpl(builder, extensions2);
1061
+ } else {
1062
+ const builder = builderOrExtensions;
1063
+ return addExtensionImpl(builder, extensions);
1064
+ }
1065
+ }
1066
+ var removeExtensionImpl = (builder, id) => {
1067
+ const internal = builder;
1068
+ const extensions = internal._registry.get(internal._extensions);
1069
+ internal._registry.set(internal._extensions, Record2.remove(extensions, id));
1070
+ return builder;
1071
+ };
1072
+ function removeExtension(builderOrId, id) {
1073
+ if (typeof builderOrId === "string") {
1074
+ const id2 = builderOrId;
1075
+ return (builder) => removeExtensionImpl(builder, id2);
1076
+ } else {
1077
+ const builder = builderOrId;
1078
+ return removeExtensionImpl(builder, id);
1079
+ }
1080
+ }
1081
+ var exploreImpl = async (builder, options, path = []) => {
1082
+ const internal = builder;
1083
+ const { registry = Registry2.make(), source = RootId, relation = "outbound", visitor } = options;
1084
+ if (path.includes(source)) {
1085
+ return;
1086
+ }
1087
+ if (!isNode()) {
1088
+ const { yieldOrContinue } = await import("main-thread-scheduling");
1089
+ await yieldOrContinue("idle");
1090
+ }
1091
+ const node = registry.get(internal._graph.nodeOrThrow(source));
1092
+ const shouldContinue = await visitor(node, [
1093
+ ...path,
1094
+ node.id
1095
+ ]);
1096
+ if (shouldContinue === false) {
1097
+ return;
1098
+ }
1099
+ const nodes = Object.values(internal._registry.get(internal._extensions)).filter((extension) => relation === (extension.relation ?? "outbound")).map((extension) => extension.connector).filter(isNonNullable2).flatMap((connector) => registry.get(connector(internal._graph.node(source))));
1100
+ await Promise.all(nodes.map((nodeArg) => {
1101
+ registry.set(internal._graph._node(nodeArg.id), internal._graph._constructNode(nodeArg));
1102
+ return exploreImpl(builder, {
1103
+ registry,
1104
+ source: nodeArg.id,
1105
+ relation,
1106
+ visitor
1107
+ }, [
1108
+ ...path,
1109
+ node.id
1110
+ ]);
1111
+ }));
1112
+ if (registry !== internal._registry) {
1113
+ registry.reset();
1114
+ registry.dispose();
1115
+ }
1116
+ };
1117
+ function explore(builderOrOptions, optionsOrPath, path) {
1118
+ if (typeof builderOrOptions === "object" && "visitor" in builderOrOptions) {
1119
+ const options = builderOrOptions;
1120
+ const path2 = Array2.isArray(optionsOrPath) ? optionsOrPath : void 0;
1121
+ return (builder) => exploreImpl(builder, options, path2);
1122
+ } else {
1123
+ const builder = builderOrOptions;
1124
+ const options = optionsOrPath;
1125
+ const pathArg = path ?? (Array2.isArray(optionsOrPath) ? optionsOrPath : void 0);
1126
+ return exploreImpl(builder, options, pathArg);
1127
+ }
1128
+ }
1129
+ var destroyImpl = (builder) => {
1130
+ const internal = builder;
1131
+ internal._subscriptions.forEach((unsubscribe) => unsubscribe());
1132
+ internal._subscriptions.clear();
1133
+ };
1134
+ function destroy(builder) {
1135
+ if (builder === void 0) {
1136
+ return (builder2) => destroyImpl(builder2);
1137
+ } else {
1138
+ return destroyImpl(builder);
1139
+ }
1140
+ }
1141
+ var createExtensionRaw = (extension) => {
1142
+ const { id, position = "static", relation = "outbound", resolver: _resolver, connector: _connector, actions: _actions, actionGroups: _actionGroups } = extension;
1143
+ const getId = (key) => `${id}/${key}`;
1144
+ const resolver = _resolver && Atom3.family((id2) => _resolver(id2).pipe(Atom3.withLabel(`graph-builder:_resolver:${id2}`)));
1145
+ const connector = _connector && Atom3.family((node) => _connector(node).pipe(Atom3.withLabel(`graph-builder:_connector:${id}`)));
1146
+ const actionGroups = _actionGroups && Atom3.family((node) => _actionGroups(node).pipe(Atom3.withLabel(`graph-builder:_actionGroups:${id}`)));
1147
+ const actions = _actions && Atom3.family((node) => _actions(node).pipe(Atom3.withLabel(`graph-builder:_actions:${id}`)));
1148
+ return [
1149
+ resolver ? {
1150
+ id: getId("resolver"),
1151
+ position,
1152
+ resolver
1153
+ } : void 0,
1154
+ connector ? {
1155
+ id: getId("connector"),
1156
+ position,
1157
+ relation,
1158
+ connector: Atom3.family((node) => Atom3.make((get2) => {
1159
+ try {
1160
+ return get2(connector(node));
1161
+ } catch (error) {
1162
+ log2.warn("Error in connector", {
1163
+ id: getId("connector"),
1164
+ node,
1165
+ error
1166
+ }, {
1167
+ F: __dxlog_file2,
1168
+ L: 509,
1169
+ S: void 0,
1170
+ C: (f, a) => f(...a)
1171
+ });
1172
+ return [];
1173
+ }
1174
+ }).pipe(Atom3.withLabel(`graph-builder:connector:${id}`)))
1175
+ } : void 0,
1176
+ actionGroups ? {
1177
+ id: getId("actionGroups"),
1178
+ position,
1179
+ relation: "outbound",
1180
+ connector: Atom3.family((node) => Atom3.make((get2) => {
1181
+ try {
1182
+ return get2(actionGroups(node)).map((arg) => ({
1183
+ ...arg,
1184
+ data: actionGroupSymbol,
1185
+ type: ActionGroupType
1186
+ }));
1187
+ } catch (error) {
1188
+ log2.warn("Error in actionGroups", {
1189
+ id: getId("actionGroups"),
1190
+ node,
1191
+ error
1192
+ }, {
1193
+ F: __dxlog_file2,
1194
+ L: 530,
1195
+ S: void 0,
1196
+ C: (f, a) => f(...a)
1197
+ });
1198
+ return [];
1199
+ }
1200
+ }).pipe(Atom3.withLabel(`graph-builder:connector:actionGroups:${id}`)))
1201
+ } : void 0,
1202
+ actions ? {
1203
+ id: getId("actions"),
1204
+ position,
1205
+ relation: "outbound",
1206
+ connector: Atom3.family((node) => Atom3.make((get2) => {
1207
+ try {
1208
+ return get2(actions(node)).map((arg) => ({
1209
+ ...arg,
1210
+ type: ActionType
1211
+ }));
1212
+ } catch (error) {
1213
+ log2.warn("Error in actions", {
1214
+ id: getId("actions"),
1215
+ node,
1216
+ error
1217
+ }, {
1218
+ F: __dxlog_file2,
1219
+ L: 547,
1220
+ S: void 0,
1221
+ C: (f, a) => f(...a)
1222
+ });
1223
+ return [];
1224
+ }
1225
+ }).pipe(Atom3.withLabel(`graph-builder:connector:actions:${id}`)))
1226
+ } : void 0
1227
+ ].filter(isNonNullable2);
1228
+ };
1229
+ var runEffectSyncWithFallback = (effect, context2, extensionId, fallback) => {
1230
+ return Effect.runSync(effect.pipe(Effect.provide(context2), Effect.catchAll((error) => {
1231
+ log2.warn("Extension failed", {
1232
+ extension: extensionId,
1233
+ error
1234
+ }, {
1235
+ F: __dxlog_file2,
1236
+ L: 590,
1237
+ S: void 0,
1238
+ C: (f, a) => f(...a)
1239
+ });
1240
+ return Effect.succeed(fallback);
1241
+ })));
1242
+ };
1243
+ var createExtension = (options) => Effect.map(Effect.context(), (context2) => {
1244
+ const { id, match: match3, actions, connector, resolver, relation, position } = options;
1245
+ const connectorExtension = connector ? createConnectorWithRuntime(id, match3, connector, context2) : void 0;
1246
+ const actionsExtension = actions ? (node) => Atom3.make((get2) => Function2.pipe(get2(node), Option3.flatMap(match3), Option3.map((matched) => runEffectSyncWithFallback(actions(matched, get2), context2, id, []).map((action) => ({
1247
+ ...action,
1248
+ // Attach captured context for action execution.
1249
+ _actionContext: context2
1250
+ }))), Option3.getOrElse(() => []))) : void 0;
1251
+ const resolverExtension = resolver ? (nodeId) => Atom3.make((get2) => runEffectSyncWithFallback(resolver(nodeId, get2), context2, id, null) ?? null) : void 0;
1252
+ return createExtensionRaw({
1253
+ id,
1254
+ relation,
1255
+ position,
1256
+ connector: connectorExtension,
1257
+ actions: actionsExtension,
1258
+ resolver: resolverExtension
757
1259
  });
758
1260
  });
759
- var rxFromObservable = (observable) => {
760
- return observableFamily(observable);
1261
+ var createConnector = (matcher, factory) => {
1262
+ return (node) => Atom3.make((get2) => Function2.pipe(get2(node), Option3.flatMap(matcher), Option3.map((data) => factory(data, get2)), Option3.getOrElse(() => [])));
1263
+ };
1264
+ var createConnectorWithRuntime = (extensionId, matcher, factory, context2) => {
1265
+ return (node) => Atom3.make((get2) => Function2.pipe(get2(node), Option3.flatMap(matcher), Option3.map((data) => runEffectSyncWithFallback(factory(data, get2), context2, extensionId, [])), Option3.getOrElse(() => [])));
1266
+ };
1267
+ var createTypeExtension = (options) => {
1268
+ const { id, type, actions, connector, relation, position } = options;
1269
+ return createExtension({
1270
+ id,
1271
+ match: whenEchoType(type),
1272
+ actions,
1273
+ connector,
1274
+ relation,
1275
+ position
1276
+ });
1277
+ };
1278
+ var flattenExtensions = (extension, acc = []) => {
1279
+ if (Array2.isArray(extension)) {
1280
+ return [
1281
+ ...acc,
1282
+ ...extension.flatMap((ext) => flattenExtensions(ext, acc))
1283
+ ];
1284
+ } else {
1285
+ return [
1286
+ ...acc,
1287
+ extension
1288
+ ];
1289
+ }
761
1290
  };
762
1291
  export {
763
- ACTION_GROUP_TYPE,
764
- ACTION_TYPE,
765
- Graph,
766
- GraphBuilder,
767
- ROOT_ID,
768
- ROOT_TYPE,
769
- actionGroupSymbol,
770
- createExtension,
771
- flattenExtensions,
772
- getGraph,
773
- isAction,
774
- isActionGroup,
775
- isActionLike,
776
- isGraphNode,
777
- rxFromObservable,
778
- rxFromSignal
1292
+ atoms_exports as CreateAtom,
1293
+ graph_exports as Graph,
1294
+ graph_builder_exports as GraphBuilder,
1295
+ node_exports as Node,
1296
+ node_matcher_exports as NodeMatcher
779
1297
  };
780
1298
  //# sourceMappingURL=index.mjs.map