@dxos/app-graph 0.8.4-main.ead640a → 0.8.4-main.ef1bc66f44

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 (43) hide show
  1. package/dist/lib/browser/index.mjs +1105 -666
  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 +1104 -666
  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 +108 -66
  10. package/dist/types/src/graph-builder.d.ts.map +1 -1
  11. package/dist/types/src/graph.d.ts +182 -212
  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.map +1 -1
  22. package/dist/types/tsconfig.tsbuildinfo +1 -1
  23. package/package.json +35 -33
  24. package/src/atoms.ts +25 -0
  25. package/src/graph-builder.test.ts +520 -104
  26. package/src/graph-builder.ts +550 -255
  27. package/src/graph.test.ts +299 -106
  28. package/src/graph.ts +964 -394
  29. package/src/index.ts +9 -3
  30. package/src/node-matcher.test.ts +301 -0
  31. package/src/node-matcher.ts +284 -0
  32. package/src/node.ts +39 -6
  33. package/src/stories/EchoGraph.stories.tsx +105 -96
  34. package/src/stories/Tree.tsx +2 -2
  35. package/dist/types/src/experimental/graph-projections.test.d.ts +0 -25
  36. package/dist/types/src/experimental/graph-projections.test.d.ts.map +0 -1
  37. package/dist/types/src/signals-integration.test.d.ts +0 -2
  38. package/dist/types/src/signals-integration.test.d.ts.map +0 -1
  39. package/dist/types/src/testing.d.ts +0 -5
  40. package/dist/types/src/testing.d.ts.map +0 -1
  41. package/src/experimental/graph-projections.test.ts +0 -56
  42. package/src/signals-integration.test.ts +0 -218
  43. package/src/testing.ts +0 -20
@@ -1,35 +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
25
  // src/graph.ts
4
- import { Registry, Rx } from "@effect-rx/rx-react";
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";
5
55
  import * as Function from "effect/Function";
6
56
  import * as Option from "effect/Option";
57
+ import * as Pipeable from "effect/Pipeable";
7
58
  import * as Record from "effect/Record";
8
59
  import { Event, Trigger } from "@dxos/async";
9
60
  import { todo } from "@dxos/debug";
10
61
  import { invariant } from "@dxos/invariant";
11
62
  import { log } from "@dxos/log";
12
63
  import { isNonNullable } from "@dxos/util";
13
- function _define_property(obj, key, value) {
14
- if (key in obj) {
15
- Object.defineProperty(obj, key, {
16
- value,
17
- enumerable: true,
18
- configurable: true,
19
- writable: true
20
- });
21
- } else {
22
- obj[key] = value;
23
- }
24
- return obj;
25
- }
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
26
89
  var __dxlog_file = "/__w/dxos/dxos/packages/sdk/app-graph/src/graph.ts";
27
90
  var graphSymbol = Symbol("graph");
28
91
  var getGraph = (node) => {
29
92
  const graph = node[graphSymbol];
30
93
  invariant(graph, "Node is not associated with a graph.", {
31
94
  F: __dxlog_file,
32
- L: 27,
95
+ L: 32,
33
96
  S: void 0,
34
97
  A: [
35
98
  "graph",
@@ -38,603 +101,815 @@ var getGraph = (node) => {
38
101
  });
39
102
  return graph;
40
103
  };
41
- var ROOT_ID = "root";
42
- var ROOT_TYPE = "dxos.org/type/GraphRoot";
43
- var ACTION_TYPE = "dxos.org/type/GraphAction";
44
- var ACTION_GROUP_TYPE = "dxos.org/type/GraphActionGroup";
45
- var Graph = class {
46
- toJSON(id = ROOT_ID) {
47
- return this._registry.get(this._json(id));
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
+ ]
147
+ });
148
+ return node.value;
149
+ });
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
179
+ };
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 } = {}) {
199
+ this._registry = registry ?? Registry.make();
200
+ this._onInitialize = onInitialize;
201
+ this._onExpand = onExpand;
202
+ this._onRemoveNode = onRemoveNode;
203
+ if (nodes) {
204
+ nodes.forEach((node) => {
205
+ Record.set(this._initialNodes, node.id, this._constructNode(node));
206
+ });
207
+ }
208
+ if (edges) {
209
+ Object.entries(edges).forEach(([source, edges2]) => {
210
+ Record.set(this._initialEdges, source, edges2);
211
+ });
212
+ }
48
213
  }
49
- json(id = ROOT_ID) {
50
- return this._json(id);
214
+ json(id = RootId) {
215
+ return jsonImpl(this, id);
51
216
  }
52
217
  node(id) {
53
- return this._node(id);
218
+ return nodeImpl(this, id);
54
219
  }
55
220
  nodeOrThrow(id) {
56
- return this._nodeOrThrow(id);
221
+ return nodeOrThrowImpl(this, id);
57
222
  }
58
223
  connections(id, relation = "outbound") {
59
- return this._connections(`${id}$${relation}`);
224
+ return connectionsImpl(this, id, relation);
60
225
  }
61
226
  actions(id) {
62
- return this._actions(id);
227
+ return actionsImpl(this, id);
63
228
  }
64
229
  edges(id) {
65
- return this._edges(id);
230
+ return edgesImpl(this, id);
66
231
  }
67
- get root() {
68
- return this.getNodeOrThrow(ROOT_ID);
232
+ /** @internal */
233
+ _constructNode(node) {
234
+ return Option.some({
235
+ [graphSymbol]: this,
236
+ data: null,
237
+ properties: {},
238
+ ...node
239
+ });
69
240
  }
70
- getNode(id) {
71
- return this._registry.get(this.node(id));
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);
72
284
  }
73
- getNodeOrThrow(id) {
74
- return this._registry.get(this.nodeOrThrow(id));
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);
75
297
  }
76
- getConnections(id, relation = "outbound") {
77
- return this._registry.get(this.connections(id, relation));
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);
78
316
  }
79
- getActions(id) {
80
- return this._registry.get(this.actions(id));
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);
81
329
  }
82
- getEdges(id) {
83
- return this._registry.get(this.edges(id));
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);
84
342
  }
85
- async initialize(id) {
86
- const initialized = Record.get(this._initialized, id).pipe(Option.getOrElse(() => false));
87
- log("initialize", {
88
- id,
89
- initialized
90
- }, {
91
- F: __dxlog_file,
92
- L: 386,
93
- S: this,
94
- C: (f, a) => f(...a)
95
- });
96
- if (!initialized) {
97
- await this._onInitialize?.(id);
98
- Record.set(this._initialized, id, true);
99
- }
343
+ }
344
+ var traverseImpl = (graph, options, path = []) => {
345
+ const { visitor, source = RootId, relation = "outbound" } = options;
346
+ if (path.includes(source)) {
347
+ return;
100
348
  }
101
- expand(id, relation = "outbound") {
102
- const key = `${id}$${relation}`;
103
- const expanded = Record.get(this._expanded, key).pipe(Option.getOrElse(() => false));
104
- log("expand", {
105
- key,
106
- expanded
107
- }, {
108
- F: __dxlog_file,
109
- L: 396,
110
- S: this,
111
- C: (f, a) => f(...a)
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);
389
+ }
390
+ }
112
391
  });
113
- if (!expanded) {
114
- this._onExpand?.(id, relation);
115
- Record.set(this._expanded, key, true);
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);
116
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);
117
430
  }
118
- addNodes(nodes) {
119
- Rx.batch(() => {
120
- nodes.map((node) => this.addNode(node));
121
- });
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);
122
447
  }
123
- addNode({ nodes, edges, ...nodeArg }) {
124
- const { id, type, data = null, properties = {} } = nodeArg;
125
- const nodeRx = this._node(id);
126
- const node = this._registry.get(nodeRx);
127
- Option.match(node, {
128
- onSome: (node2) => {
129
- const typeChanged = node2.type !== type;
130
- const dataChanged = node2.data !== data;
131
- const propertiesChanged = Object.keys(properties).some((key) => node2.properties[key] !== properties[key]);
132
- log("existing node", {
133
- id,
134
- typeChanged,
135
- dataChanged,
136
- propertiesChanged
137
- }, {
138
- F: __dxlog_file,
139
- L: 418,
140
- S: this,
141
- C: (f, a) => f(...a)
142
- });
143
- if (typeChanged || dataChanged || propertiesChanged) {
144
- log("updating node", {
145
- id,
146
- type,
147
- data,
148
- properties
149
- }, {
150
- F: __dxlog_file,
151
- L: 420,
152
- S: this,
153
- C: (f, a) => f(...a)
154
- });
155
- const newNode = Option.some({
156
- ...node2,
157
- type,
158
- data,
159
- properties: {
160
- ...node2.properties,
161
- ...properties
162
- }
163
- });
164
- this._registry.set(nodeRx, newNode);
165
- this.onNodeChanged.emit({
166
- id,
167
- node: newNode
168
- });
169
- }
170
- },
171
- onNone: () => {
172
- log("new node", {
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", {
173
554
  id,
174
555
  type,
175
556
  data,
176
557
  properties
177
558
  }, {
178
559
  F: __dxlog_file,
179
- L: 427,
180
- S: this,
560
+ L: 854,
561
+ S: void 0,
181
562
  C: (f, a) => f(...a)
182
563
  });
183
- const newNode = this._constructNode({
184
- id,
564
+ const newNode = Option.some({
565
+ ...existing,
566
+ ...rest,
185
567
  type,
186
568
  data,
187
- properties
569
+ properties: {
570
+ ...existing.properties,
571
+ ...properties
572
+ }
188
573
  });
189
- this._registry.set(nodeRx, newNode);
190
- this.onNodeChanged.emit({
574
+ internal._registry.set(nodeAtom, newNode);
575
+ graph.onNodeChanged.emit({
191
576
  id,
192
577
  node: newNode
193
578
  });
194
579
  }
195
- });
196
- if (nodes) {
197
- this.addNodes(nodes);
198
- const _edges = nodes.map((node2) => ({
199
- source: id,
200
- target: node2.id
201
- }));
202
- this.addEdges(_edges);
203
- }
204
- if (edges) {
205
- todo();
206
- }
207
- }
208
- removeNodes(ids, edges = false) {
209
- Rx.batch(() => {
210
- ids.map((id) => this.removeNode(id, edges));
211
- });
212
- }
213
- removeNode(id, edges = false) {
214
- const nodeRx = this._node(id);
215
- this._registry.set(nodeRx, Option.none());
216
- this.onNodeChanged.emit({
217
- id,
218
- node: Option.none()
219
- });
220
- if (edges) {
221
- const { inbound, outbound } = this._registry.get(this._edges(id));
222
- const edges2 = [
223
- ...inbound.map((source) => ({
224
- source,
225
- target: id
226
- })),
227
- ...outbound.map((target) => ({
228
- source: id,
229
- target
230
- }))
231
- ];
232
- this.removeEdges(edges2);
233
- }
234
- this._onRemoveNode?.(id);
235
- }
236
- addEdges(edges) {
237
- Rx.batch(() => {
238
- edges.map((edge) => this.addEdge(edge));
239
- });
240
- }
241
- addEdge(edgeArg) {
242
- const sourceRx = this._edges(edgeArg.source);
243
- const source = this._registry.get(sourceRx);
244
- if (!source.outbound.includes(edgeArg.target)) {
245
- log("add outbound edge", {
246
- source: edgeArg.source,
247
- target: edgeArg.target
580
+ },
581
+ onNone: () => {
582
+ log("new node", {
583
+ id,
584
+ type,
585
+ data,
586
+ properties
248
587
  }, {
249
588
  F: __dxlog_file,
250
- L: 482,
251
- S: this,
589
+ L: 867,
590
+ S: void 0,
252
591
  C: (f, a) => f(...a)
253
592
  });
254
- this._registry.set(sourceRx, {
255
- inbound: source.inbound,
256
- outbound: [
257
- ...source.outbound,
258
- edgeArg.target
259
- ]
260
- });
261
- }
262
- const targetRx = this._edges(edgeArg.target);
263
- const target = this._registry.get(targetRx);
264
- if (!target.inbound.includes(edgeArg.source)) {
265
- log("add inbound edge", {
266
- source: edgeArg.source,
267
- target: edgeArg.target
268
- }, {
269
- F: __dxlog_file,
270
- L: 489,
271
- S: this,
272
- C: (f, a) => f(...a)
593
+ const newNode = internal._constructNode({
594
+ id,
595
+ type,
596
+ data,
597
+ properties,
598
+ ...rest
273
599
  });
274
- this._registry.set(targetRx, {
275
- inbound: [
276
- ...target.inbound,
277
- edgeArg.source
278
- ],
279
- outbound: target.outbound
600
+ internal._registry.set(nodeAtom, newNode);
601
+ graph.onNodeChanged.emit({
602
+ id,
603
+ node: newNode
280
604
  });
281
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);
627
+ }
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);
282
697
  }
283
- removeEdges(edges, removeOrphans = false) {
284
- Rx.batch(() => {
285
- edges.map((edge) => this.removeEdge(edge, removeOrphans));
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
+ ]
286
719
  });
287
720
  }
288
- removeEdge(edgeArg, removeOrphans = false) {
289
- const sourceRx = this._edges(edgeArg.source);
290
- const source = this._registry.get(sourceRx);
291
- if (source.outbound.includes(edgeArg.target)) {
292
- this._registry.set(sourceRx, {
293
- inbound: source.inbound,
294
- outbound: source.outbound.filter((id) => id !== edgeArg.target)
295
- });
296
- }
297
- const targetRx = this._edges(edgeArg.target);
298
- const target = this._registry.get(targetRx);
299
- if (target.inbound.includes(edgeArg.source)) {
300
- this._registry.set(targetRx, {
301
- inbound: target.inbound.filter((id) => id !== edgeArg.source),
302
- outbound: target.outbound
303
- });
304
- }
305
- if (removeOrphans) {
306
- const source2 = this._registry.get(sourceRx);
307
- const target2 = this._registry.get(targetRx);
308
- if (source2.outbound.length === 0 && source2.inbound.length === 0 && edgeArg.source !== ROOT_ID) {
309
- this.removeNodes([
310
- edgeArg.source
311
- ]);
312
- }
313
- if (target2.outbound.length === 0 && target2.inbound.length === 0 && edgeArg.target !== ROOT_ID) {
314
- this.removeNodes([
315
- edgeArg.target
316
- ]);
317
- }
318
- }
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
+ });
319
740
  }
320
- sortEdges(id, relation, order) {
321
- const edgesRx = this._edges(id);
322
- const edges = this._registry.get(edgesRx);
323
- const unsorted = edges[relation].filter((id2) => !order.includes(id2)) ?? [];
324
- const sorted = order.filter((id2) => edges[relation].includes(id2)) ?? [];
325
- edges[relation].splice(0, edges[relation].length, ...[
326
- ...sorted,
327
- ...unsorted
328
- ]);
329
- 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);
330
750
  }
331
- traverse({ visitor, source = ROOT_ID, relation = "outbound" }, path = []) {
332
- if (path.includes(source)) {
333
- return;
334
- }
335
- const node = this.getNodeOrThrow(source);
336
- const shouldContinue = visitor(node, [
337
- ...path,
338
- source
339
- ]);
340
- if (shouldContinue === false) {
341
- return;
342
- }
343
- Object.values(this.getConnections(source, relation)).forEach((child) => this.traverse({
344
- source: child.id,
345
- relation,
346
- visitor
347
- }, [
348
- ...path,
349
- source
350
- ]));
351
- }
352
- getPath({ source = "root", target }) {
353
- return Function.pipe(this.getNode(source), Option.flatMap((node) => {
354
- let found = Option.none();
355
- this.traverse({
356
- source: node.id,
357
- visitor: (node2, path) => {
358
- if (Option.isSome(found)) {
359
- return false;
360
- }
361
- if (node2.id === target) {
362
- found = Option.some(path);
363
- }
364
- }
365
- });
366
- return found;
367
- }));
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);
368
768
  }
369
- async waitForPath(params, { timeout = 5e3, interval = 500 } = {}) {
370
- const path = this.getPath(params);
371
- if (Option.isSome(path)) {
372
- return path.value;
373
- }
374
- const trigger = new Trigger();
375
- const i = setInterval(() => {
376
- const path2 = this.getPath(params);
377
- if (Option.isSome(path2)) {
378
- trigger.wake(path2.value);
379
- }
380
- }, interval);
381
- return trigger.wait({
382
- timeout
383
- }).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
+ });
384
779
  }
385
- /** @internal */
386
- _constructNode(node) {
387
- return Option.some({
388
- [graphSymbol]: this,
389
- data: null,
390
- properties: {},
391
- ...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
392
786
  });
393
787
  }
394
- constructor({ registry, nodes, edges, onInitialize, onExpand, onRemoveNode } = {}) {
395
- _define_property(this, "onNodeChanged", new Event());
396
- _define_property(this, "_onExpand", void 0);
397
- _define_property(this, "_onInitialize", void 0);
398
- _define_property(this, "_onRemoveNode", void 0);
399
- _define_property(this, "_registry", void 0);
400
- _define_property(this, "_expanded", Record.empty());
401
- _define_property(this, "_initialized", Record.empty());
402
- _define_property(this, "_initialEdges", Record.empty());
403
- _define_property(this, "_initialNodes", Record.fromEntries([
404
- [
405
- ROOT_ID,
406
- this._constructNode({
407
- id: ROOT_ID,
408
- type: ROOT_TYPE,
409
- data: null,
410
- properties: {}
411
- })
412
- ]
413
- ]));
414
- _define_property(this, "_node", Rx.family((id) => {
415
- const initial = Option.flatten(Record.get(this._initialNodes, id));
416
- return Rx.make(initial).pipe(Rx.keepAlive, Rx.withLabel(`graph:node:${id}`));
417
- }));
418
- _define_property(this, "_nodeOrThrow", Rx.family((id) => {
419
- return Rx.make((get2) => {
420
- const node = get2(this._node(id));
421
- invariant(Option.isSome(node), `Node not available: ${id}`, {
422
- F: __dxlog_file,
423
- L: 254,
424
- S: this,
425
- A: [
426
- "Option.isSome(node)",
427
- "`Node not available: ${id}`"
428
- ]
429
- });
430
- return node.value;
431
- });
432
- }));
433
- _define_property(this, "_edges", Rx.family((id) => {
434
- const initial = Record.get(this._initialEdges, id).pipe(Option.getOrElse(() => ({
435
- inbound: [],
436
- outbound: []
437
- })));
438
- return Rx.make(initial).pipe(Rx.keepAlive, Rx.withLabel(`graph:edges:${id}`));
439
- }));
440
- _define_property(this, "_connections", Rx.family((key) => {
441
- return Rx.make((get2) => {
442
- const [id, relation] = key.split("$");
443
- const edges2 = get2(this._edges(id));
444
- return edges2[relation].map((id2) => get2(this._node(id2))).filter(Option.isSome).map((o) => o.value);
445
- }).pipe(Rx.withLabel(`graph:connections:${key}`));
446
- }));
447
- _define_property(this, "_actions", Rx.family((id) => {
448
- return Rx.make((get2) => {
449
- return get2(this._connections(`${id}$outbound`)).filter((node) => node.type === ACTION_TYPE || node.type === ACTION_GROUP_TYPE);
450
- }).pipe(Rx.withLabel(`graph:actions:${id}`));
451
- }));
452
- _define_property(this, "_json", Rx.family((id) => {
453
- return Rx.make((get2) => {
454
- const toJSON = (node, seen = []) => {
455
- const nodes2 = get2(this.connections(node.id));
456
- const obj = {
457
- id: node.id,
458
- type: node.type
459
- };
460
- if (node.properties.label) {
461
- obj.label = node.properties.label;
462
- }
463
- if (nodes2.length) {
464
- obj.nodes = nodes2.map((n) => {
465
- const nextSeen = [
466
- ...seen,
467
- node.id
468
- ];
469
- return nextSeen.includes(n.id) ? void 0 : toJSON(n, nextSeen);
470
- }).filter(isNonNullable);
471
- }
472
- return obj;
473
- };
474
- const root = get2(this.nodeOrThrow(id));
475
- return toJSON(root);
476
- }).pipe(Rx.withLabel(`graph:json:${id}`));
477
- }));
478
- this._registry = registry ?? Registry.make();
479
- this._onInitialize = onInitialize;
480
- this._onExpand = onExpand;
481
- this._onRemoveNode = onRemoveNode;
482
- if (nodes) {
483
- nodes.forEach((node) => {
484
- Record.set(this._initialNodes, node.id, this._constructNode(node));
485
- });
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
+ ]);
486
795
  }
487
- if (edges) {
488
- Object.entries(edges).forEach(([source, edges2]) => {
489
- Record.set(this._initialEdges, source, edges2);
490
- });
796
+ if (target2.outbound.length === 0 && target2.inbound.length === 0 && edgeArg.target !== RootId) {
797
+ removeNodesImpl(graph, [
798
+ edgeArg.target
799
+ ]);
491
800
  }
492
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);
493
818
  };
494
819
 
495
820
  // src/graph-builder.ts
496
- import { Registry as Registry2, Rx as Rx2 } from "@effect-rx/rx-react";
497
- import { effect } from "@preact/signals-core";
498
- import * as Array from "effect/Array";
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";
499
839
  import * as Function2 from "effect/Function";
500
- import * as Option2 from "effect/Option";
840
+ import * as Option3 from "effect/Option";
841
+ import * as Pipeable2 from "effect/Pipeable";
501
842
  import * as Record2 from "effect/Record";
502
843
  import { log as log2 } from "@dxos/log";
503
844
  import { byPosition, getDebugName, isNode, isNonNullable as isNonNullable2 } from "@dxos/util";
504
845
 
505
- // src/node.ts
506
- var isGraphNode = (data) => data && typeof data === "object" && "id" in data && "properties" in data && data.properties ? typeof data.properties === "object" && "data" in data : false;
507
- var isAction = (data) => isGraphNode(data) ? typeof data.data === "function" && data.type === ACTION_TYPE : false;
508
- var actionGroupSymbol = Symbol("ActionGroup");
509
- var isActionGroup = (data) => isGraphNode(data) ? data.data === actionGroupSymbol && data.type === ACTION_GROUP_TYPE : false;
510
- var isActionLike = (data) => isAction(data) || isActionGroup(data);
511
-
512
- // src/graph-builder.ts
513
- function _define_property2(obj, key, value) {
514
- if (key in obj) {
515
- Object.defineProperty(obj, key, {
516
- value,
517
- enumerable: true,
518
- configurable: true,
519
- writable: true
520
- });
521
- } else {
522
- obj[key] = value;
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
+ }
523
873
  }
524
- return obj;
525
- }
526
- var __dxlog_file2 = "/__w/dxos/dxos/packages/sdk/app-graph/src/graph-builder.ts";
527
- var createExtension = (extension) => {
528
- const { id, position = "static", relation = "outbound", resolver: _resolver, connector: _connector, actions: _actions, actionGroups: _actionGroups } = extension;
529
- const getId = (key) => `${id}/${key}`;
530
- const resolver = _resolver && Rx2.family((id2) => _resolver(id2).pipe(Rx2.withLabel(`graph-builder:_resolver:${id2}`)));
531
- const connector = _connector && Rx2.family((node) => _connector(node).pipe(Rx2.withLabel(`graph-builder:_connector:${id}`)));
532
- const actionGroups = _actionGroups && Rx2.family((node) => _actionGroups(node).pipe(Rx2.withLabel(`graph-builder:_actionGroups:${id}`)));
533
- const actions = _actions && Rx2.family((node) => _actions(node).pipe(Rx2.withLabel(`graph-builder:_actions:${id}`)));
534
- return [
535
- resolver ? {
536
- id: getId("resolver"),
537
- position,
538
- resolver
539
- } : void 0,
540
- connector ? {
541
- id: getId("connector"),
542
- position,
543
- relation,
544
- connector: Rx2.family((node) => Rx2.make((get2) => {
545
- try {
546
- return get2(connector(node));
547
- } catch {
548
- log2.warn("Error in connector", {
549
- id: getId("connector"),
550
- node
551
- }, {
552
- F: __dxlog_file2,
553
- L: 112,
554
- S: void 0,
555
- C: (f, a) => f(...a)
556
- });
557
- return [];
558
- }
559
- }).pipe(Rx2.withLabel(`graph-builder:connector:${id}`)))
560
- } : void 0,
561
- actionGroups ? {
562
- id: getId("actionGroups"),
563
- position,
564
- relation: "outbound",
565
- connector: Rx2.family((node) => Rx2.make((get2) => {
566
- try {
567
- return get2(actionGroups(node)).map((arg) => ({
568
- ...arg,
569
- data: actionGroupSymbol,
570
- type: ACTION_GROUP_TYPE
571
- }));
572
- } catch {
573
- log2.warn("Error in actionGroups", {
574
- id: getId("actionGroups"),
575
- node
576
- }, {
577
- F: __dxlog_file2,
578
- L: 133,
579
- S: void 0,
580
- C: (f, a) => f(...a)
581
- });
582
- return [];
583
- }
584
- }).pipe(Rx2.withLabel(`graph-builder:connector:actionGroups:${id}`)))
585
- } : void 0,
586
- actions ? {
587
- id: getId("actions"),
588
- position,
589
- relation: "outbound",
590
- connector: Rx2.family((node) => Rx2.make((get2) => {
591
- try {
592
- return get2(actions(node)).map((arg) => ({
593
- ...arg,
594
- type: ACTION_TYPE
595
- }));
596
- } catch {
597
- log2.warn("Error in actions", {
598
- id: getId("actions"),
599
- node
600
- }, {
601
- F: __dxlog_file2,
602
- L: 150,
603
- S: void 0,
604
- C: (f, a) => f(...a)
605
- });
606
- return [];
607
- }
608
- }).pipe(Rx2.withLabel(`graph-builder:connector:actions:${id}`)))
609
- } : void 0
610
- ].filter(isNonNullable2);
874
+ return Option2.some(node);
611
875
  };
612
- var flattenExtensions = (extension, acc = []) => {
613
- if (Array.isArray(extension)) {
614
- return [
615
- ...acc,
616
- ...extension.flatMap((ext) => flattenExtensions(ext, acc))
617
- ];
618
- } else {
619
- return [
620
- ...acc,
621
- extension
622
- ];
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
+ }
623
882
  }
883
+ return Option2.none();
624
884
  };
625
- var GraphBuilder = class _GraphBuilder {
626
- static from(pickle, registry) {
627
- if (!pickle) {
628
- return new _GraphBuilder({
629
- registry
630
- });
631
- }
632
- const { nodes, edges } = JSON.parse(pickle);
633
- return new _GraphBuilder({
634
- nodes,
635
- edges,
636
- registry
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;
903
+ constructor({ registry, ...params } = {}) {
904
+ this._registry = registry ?? Registry2.make();
905
+ const graph = make({
906
+ ...params,
907
+ registry: this._registry,
908
+ onExpand: (id, relation) => this._onExpand(id, relation),
909
+ onInitialize: (id) => this._onInitialize(id),
910
+ onRemoveNode: (id) => this._onRemoveNode(id)
637
911
  });
912
+ this._graph = graph;
638
913
  }
639
914
  get graph() {
640
915
  return this._graph;
@@ -642,56 +917,27 @@ var GraphBuilder = class _GraphBuilder {
642
917
  get extensions() {
643
918
  return this._extensions;
644
919
  }
645
- addExtension(extensions) {
646
- flattenExtensions(extensions).forEach((extension) => {
647
- const extensions2 = this._registry.get(this._extensions);
648
- 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);
649
923
  });
650
- return this;
651
- }
652
- removeExtension(id) {
653
- const extensions = this._registry.get(this._extensions);
654
- this._registry.set(this._extensions, Record2.remove(extensions, id));
655
- return this;
656
- }
657
- async explore({ registry = Registry2.make(), source = ROOT_ID, relation = "outbound", visitor }, path = []) {
658
- if (path.includes(source)) {
659
- return;
660
- }
661
- if (!isNode()) {
662
- const { yieldOrContinue } = await import("main-thread-scheduling");
663
- await yieldOrContinue("idle");
664
- }
665
- const node = registry.get(this._graph.nodeOrThrow(source));
666
- const shouldContinue = await visitor(node, [
667
- ...path,
668
- node.id
669
- ]);
670
- if (shouldContinue === false) {
671
- return;
672
- }
673
- 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))));
674
- await Promise.all(nodes.map((nodeArg) => {
675
- registry.set(this._graph._node(nodeArg.id), this._graph._constructNode(nodeArg));
676
- return this.explore({
677
- registry,
678
- source: nodeArg.id,
679
- relation,
680
- visitor
681
- }, [
682
- ...path,
683
- node.id
684
- ]);
685
- }));
686
- if (registry !== this._registry) {
687
- registry.reset();
688
- registry.dispose();
689
- }
690
- }
691
- destroy() {
692
- this._subscriptions.forEach((unsubscribe) => unsubscribe());
693
- this._subscriptions.clear();
694
- }
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
+ });
695
941
  _onExpand(id, relation) {
696
942
  log2("onExpand", {
697
943
  id,
@@ -699,7 +945,7 @@ var GraphBuilder = class _GraphBuilder {
699
945
  registry: getDebugName(this._registry)
700
946
  }, {
701
947
  F: __dxlog_file2,
702
- L: 327,
948
+ L: 176,
703
949
  S: this,
704
950
  C: (f, a) => f(...a)
705
951
  });
@@ -716,25 +962,25 @@ var GraphBuilder = class _GraphBuilder {
716
962
  removed
717
963
  }, {
718
964
  F: __dxlog_file2,
719
- L: 338,
965
+ L: 187,
720
966
  S: this,
721
967
  C: (f, a) => f(...a)
722
968
  });
723
969
  const update = () => {
724
- Rx2.batch(() => {
725
- this._graph.removeEdges(removed.map((target) => ({
970
+ Atom3.batch(() => {
971
+ removeEdges(this._graph, removed.map((target) => ({
726
972
  source: id,
727
973
  target
728
974
  })), true);
729
- this._graph.addNodes(nodes);
730
- this._graph.addEdges(nodes.map((node) => relation === "outbound" ? {
975
+ addNodes(this._graph, nodes);
976
+ addEdges(this._graph, nodes.map((node) => relation === "outbound" ? {
731
977
  source: id,
732
978
  target: node.id
733
979
  } : {
734
980
  source: node.id,
735
981
  target: id
736
982
  }));
737
- this._graph.sortEdges(id, relation, nodes.map(({ id: id2 }) => id2));
983
+ sortEdges(this._graph, id, relation, nodes.map(({ id: id2 }) => id2));
738
984
  });
739
985
  };
740
986
  if (typeof requestAnimationFrame === "function") {
@@ -753,23 +999,23 @@ var GraphBuilder = class _GraphBuilder {
753
999
  id
754
1000
  }, {
755
1001
  F: __dxlog_file2,
756
- L: 375,
1002
+ L: 227,
757
1003
  S: this,
758
1004
  C: (f, a) => f(...a)
759
1005
  });
760
1006
  const resolver = this._resolvers(id);
761
1007
  const cancel = this._registry.subscribe(resolver, (node) => {
762
1008
  const trigger = this._initialized[id];
763
- Option2.match(node, {
1009
+ Option3.match(node, {
764
1010
  onSome: (node2) => {
765
- this._graph.addNodes([
1011
+ addNodes(this._graph, [
766
1012
  node2
767
1013
  ]);
768
1014
  trigger?.wake();
769
1015
  },
770
1016
  onNone: () => {
771
1017
  trigger?.wake();
772
- this._graph.removeNodes([
1018
+ removeNodes(this._graph, [
773
1019
  id
774
1020
  ]);
775
1021
  }
@@ -783,78 +1029,270 @@ var GraphBuilder = class _GraphBuilder {
783
1029
  this._subscriptions.get(id)?.();
784
1030
  this._subscriptions.delete(id);
785
1031
  }
786
- constructor({ registry, ...params } = {}) {
787
- _define_property2(this, "_subscriptions", /* @__PURE__ */ new Map());
788
- _define_property2(this, "_extensions", Rx2.make(Record2.empty()).pipe(Rx2.keepAlive, Rx2.withLabel("graph-builder:extensions")));
789
- _define_property2(this, "_initialized", {});
790
- _define_property2(this, "_registry", void 0);
791
- _define_property2(this, "_graph", void 0);
792
- _define_property2(this, "_resolvers", Rx2.family((id) => {
793
- return Rx2.make((get2) => {
794
- return Function2.pipe(get2(this._extensions), Record2.values, Array.sortBy(byPosition), Array.map(({ resolver }) => resolver), Array.filter(isNonNullable2), Array.map((resolver) => get2(resolver(id))), Array.filter(isNonNullable2), Array.head);
795
- });
796
- }));
797
- _define_property2(this, "_connectors", Rx2.family((key) => {
798
- return Rx2.make((get2) => {
799
- const [id, relation] = key.split("+");
800
- const node = this._graph.node(id);
801
- return Function2.pipe(
802
- get2(this._extensions),
803
- Record2.values,
804
- // TODO(wittjosiah): Sort on write rather than read.
805
- Array.sortBy(byPosition),
806
- Array.filter(({ relation: _relation = "outbound" }) => _relation === relation),
807
- Array.map(({ connector }) => connector?.(node)),
808
- Array.filter(isNonNullable2),
809
- Array.flatMap((result) => get2(result))
810
- );
811
- }).pipe(Rx2.withLabel(`graph-builder:connectors:${key}`));
812
- }));
813
- this._registry = registry ?? Registry2.make();
814
- this._graph = new Graph({
815
- ...params,
816
- registry: this._registry,
817
- onExpand: (id, relation) => this._onExpand(id, relation),
818
- onInitialize: (id) => this._onInitialize(id),
819
- onRemoveNode: (id) => this._onRemoveNode(id)
1032
+ };
1033
+ var make2 = (params) => {
1034
+ return new GraphBuilderImpl(params);
1035
+ };
1036
+ var from = (pickle, registry) => {
1037
+ if (!pickle) {
1038
+ return make2({
1039
+ registry
820
1040
  });
821
1041
  }
1042
+ const { nodes, edges } = JSON.parse(pickle);
1043
+ return make2({
1044
+ nodes,
1045
+ edges,
1046
+ registry
1047
+ });
822
1048
  };
823
- var rxFromSignal = (cb) => {
824
- return Rx2.make((get2) => {
825
- const dispose = effect(() => {
826
- get2.setSelf(cb());
827
- });
828
- get2.addFinalizer(() => dispose());
829
- return cb();
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));
830
1054
  });
1055
+ return builder;
831
1056
  };
832
- var observableFamily = Rx2.family((observable) => {
833
- return Rx2.make((get2) => {
834
- const subscription = observable.subscribe((value) => get2.setSelf(value));
835
- get2.addFinalizer(() => subscription.unsubscribe());
836
- return observable.get();
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
837
1259
  });
838
1260
  });
839
- var rxFromObservable = (observable) => {
840
- 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
+ }
841
1290
  };
842
1291
  export {
843
- ACTION_GROUP_TYPE,
844
- ACTION_TYPE,
845
- Graph,
846
- GraphBuilder,
847
- ROOT_ID,
848
- ROOT_TYPE,
849
- actionGroupSymbol,
850
- createExtension,
851
- flattenExtensions,
852
- getGraph,
853
- isAction,
854
- isActionGroup,
855
- isActionLike,
856
- isGraphNode,
857
- rxFromObservable,
858
- 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
859
1297
  };
860
1298
  //# sourceMappingURL=index.mjs.map