@dxos/app-graph 0.8.4-main.1da679c → 0.8.4-main.21d9917

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