@dxos/app-graph 0.8.4-main.f9ba587 → 0.8.4-main.fffef41

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.
@@ -1,6 +1,8 @@
1
1
  // src/graph.ts
2
- import { Registry, Rx } from "@effect-rx/rx-react";
3
- import { Option, pipe, Record } from "effect";
2
+ import { Atom, Registry } from "@effect-atom/atom-react";
3
+ import * as Function from "effect/Function";
4
+ import * as Option from "effect/Option";
5
+ import * as Record from "effect/Record";
4
6
  import { Event, Trigger } from "@dxos/async";
5
7
  import { todo } from "@dxos/debug";
6
8
  import { invariant } from "@dxos/invariant";
@@ -12,7 +14,7 @@ var getGraph = (node) => {
12
14
  const graph = node[graphSymbol];
13
15
  invariant(graph, "Node is not associated with a graph.", {
14
16
  F: __dxlog_file,
15
- L: 25,
17
+ L: 29,
16
18
  S: void 0,
17
19
  A: [
18
20
  "graph",
@@ -26,90 +28,95 @@ var ROOT_TYPE = "dxos.org/type/GraphRoot";
26
28
  var ACTION_TYPE = "dxos.org/type/GraphAction";
27
29
  var ACTION_GROUP_TYPE = "dxos.org/type/GraphActionGroup";
28
30
  var Graph = class {
29
- constructor({ registry, nodes, edges, onExpand, onRemoveNode } = {}) {
30
- this.onNodeChanged = new Event();
31
- this._expanded = Record.empty();
32
- this._initialized = Record.empty();
33
- this._initialEdges = Record.empty();
34
- this._initialNodes = Record.fromEntries([
35
- [
36
- ROOT_ID,
37
- this._constructNode({
38
- id: ROOT_ID,
39
- type: ROOT_TYPE,
40
- data: null,
41
- properties: {}
42
- })
43
- ]
44
- ]);
45
- /** @internal */
46
- this._node = Rx.family((id) => {
47
- const initial = Option.flatten(Record.get(this._initialNodes, id));
48
- return Rx.make(initial).pipe(Rx.keepAlive, Rx.withLabel(`graph:node:${id}`));
49
- });
50
- this._nodeOrThrow = Rx.family((id) => {
51
- return Rx.make((get) => {
52
- const node = get(this._node(id));
53
- invariant(Option.isSome(node), `Node not available: ${id}`, {
54
- F: __dxlog_file,
55
- L: 253,
56
- S: this,
57
- A: [
58
- "Option.isSome(node)",
59
- "`Node not available: ${id}`"
60
- ]
61
- });
62
- return node.value;
31
+ onNodeChanged = new Event();
32
+ _onExpand;
33
+ _onInitialize;
34
+ _onRemoveNode;
35
+ _registry;
36
+ _expanded = Record.empty();
37
+ _initialized = Record.empty();
38
+ _initialEdges = Record.empty();
39
+ _initialNodes = Record.fromEntries([
40
+ [
41
+ ROOT_ID,
42
+ this._constructNode({
43
+ id: ROOT_ID,
44
+ type: ROOT_TYPE,
45
+ data: null,
46
+ properties: {}
47
+ })
48
+ ]
49
+ ]);
50
+ /** @internal */
51
+ _node = Atom.family((id) => {
52
+ const initial = Option.flatten(Record.get(this._initialNodes, id));
53
+ return Atom.make(initial).pipe(Atom.keepAlive, Atom.withLabel(`graph:node:${id}`));
54
+ });
55
+ _nodeOrThrow = Atom.family((id) => {
56
+ return Atom.make((get2) => {
57
+ const node = get2(this._node(id));
58
+ invariant(Option.isSome(node), `Node not available: ${id}`, {
59
+ F: __dxlog_file,
60
+ L: 267,
61
+ S: this,
62
+ A: [
63
+ "Option.isSome(node)",
64
+ "`Node not available: ${id}`"
65
+ ]
63
66
  });
67
+ return node.value;
64
68
  });
65
- this._edges = Rx.family((id) => {
66
- const initial = Record.get(this._initialEdges, id).pipe(Option.getOrElse(() => ({
67
- inbound: [],
68
- outbound: []
69
- })));
70
- return Rx.make(initial).pipe(Rx.keepAlive, Rx.withLabel(`graph:edges:${id}`));
71
- });
72
- // NOTE: Currently the argument to the family needs to be referentially stable for the rx to be referentially stable.
73
- // TODO(wittjosiah): Rx feature request, support for something akin to `ComplexMap` to allow for complex arguments.
74
- this._connections = Rx.family((key) => {
75
- return Rx.make((get) => {
76
- const [id, relation] = key.split("$");
77
- const edges = get(this._edges(id));
78
- return edges[relation].map((id2) => get(this._node(id2))).filter(Option.isSome).map((o) => o.value);
79
- }).pipe(Rx.withLabel(`graph:connections:${key}`));
80
- });
81
- this._actions = Rx.family((id) => {
82
- return Rx.make((get) => {
83
- return get(this._connections(`${id}$outbound`)).filter((node) => node.type === ACTION_TYPE || node.type === ACTION_GROUP_TYPE);
84
- }).pipe(Rx.withLabel(`graph:actions:${id}`));
85
- });
86
- this._json = Rx.family((id) => {
87
- return Rx.make((get) => {
88
- const toJSON = (node, seen = []) => {
89
- const nodes = get(this.connections(node.id));
90
- const obj = {
91
- id: node.id.length > 32 ? `${node.id.slice(0, 32)}...` : node.id,
92
- type: node.type
93
- };
94
- if (node.properties.label) {
95
- obj.label = node.properties.label;
96
- }
97
- if (nodes.length) {
98
- obj.nodes = nodes.map((n) => {
99
- const nextSeen = [
100
- ...seen,
101
- node.id
102
- ];
103
- return nextSeen.includes(n.id) ? void 0 : toJSON(n, nextSeen);
104
- }).filter(isNonNullable);
105
- }
106
- return obj;
69
+ });
70
+ _edges = Atom.family((id) => {
71
+ const initial = Record.get(this._initialEdges, id).pipe(Option.getOrElse(() => ({
72
+ inbound: [],
73
+ outbound: []
74
+ })));
75
+ return Atom.make(initial).pipe(Atom.keepAlive, Atom.withLabel(`graph:edges:${id}`));
76
+ });
77
+ // NOTE: Currently the argument to the family needs to be referentially stable for the atom to be referentially stable.
78
+ // TODO(wittjosiah): Atom feature request, support for something akin to `ComplexMap` to allow for complex arguments.
79
+ _connections = Atom.family((key) => {
80
+ return Atom.make((get2) => {
81
+ const [id, relation] = key.split("$");
82
+ const edges = get2(this._edges(id));
83
+ return edges[relation].map((id2) => get2(this._node(id2))).filter(Option.isSome).map((o) => o.value);
84
+ }).pipe(Atom.withLabel(`graph:connections:${key}`));
85
+ });
86
+ _actions = Atom.family((id) => {
87
+ return Atom.make((get2) => {
88
+ return get2(this._connections(`${id}$outbound`)).filter((node) => node.type === ACTION_TYPE || node.type === ACTION_GROUP_TYPE);
89
+ }).pipe(Atom.withLabel(`graph:actions:${id}`));
90
+ });
91
+ _json = Atom.family((id) => {
92
+ return Atom.make((get2) => {
93
+ const toJSON = (node, seen = []) => {
94
+ const nodes = get2(this.connections(node.id));
95
+ const obj = {
96
+ id: node.id,
97
+ type: node.type
107
98
  };
108
- const root = get(this.nodeOrThrow(id));
109
- return toJSON(root);
110
- }).pipe(Rx.withLabel(`graph:json:${id}`));
111
- });
99
+ if (node.properties.label) {
100
+ obj.label = node.properties.label;
101
+ }
102
+ if (nodes.length) {
103
+ obj.nodes = nodes.map((n) => {
104
+ const nextSeen = [
105
+ ...seen,
106
+ node.id
107
+ ];
108
+ return nextSeen.includes(n.id) ? void 0 : toJSON(n, nextSeen);
109
+ }).filter(isNonNullable);
110
+ }
111
+ return obj;
112
+ };
113
+ const root = get2(this.nodeOrThrow(id));
114
+ return toJSON(root);
115
+ }).pipe(Atom.withLabel(`graph:json:${id}`));
116
+ });
117
+ constructor({ registry, nodes, edges, onInitialize, onExpand, onRemoveNode } = {}) {
112
118
  this._registry = registry ?? Registry.make();
119
+ this._onInitialize = onInitialize;
113
120
  this._onExpand = onExpand;
114
121
  this._onRemoveNode = onRemoveNode;
115
122
  if (nodes) {
@@ -162,15 +169,22 @@ var Graph = class {
162
169
  getEdges(id) {
163
170
  return this._registry.get(this.edges(id));
164
171
  }
165
- // TODO(wittjosiah): On initialize to restore state from cache.
166
- // async initialize(id: string) {
167
- // const initialized = Record.get(this._initialized, id).pipe(Option.getOrElse(() => false));
168
- // log('initialize', { id, initialized });
169
- // if (!initialized) {
170
- // await this._onInitialize?.(id);
171
- // Record.set(this._initialized, id, true);
172
- // }
173
- // }
172
+ async initialize(id) {
173
+ const initialized = Record.get(this._initialized, id).pipe(Option.getOrElse(() => false));
174
+ log("initialize", {
175
+ id,
176
+ initialized
177
+ }, {
178
+ F: __dxlog_file,
179
+ L: 399,
180
+ S: this,
181
+ C: (f, a) => f(...a)
182
+ });
183
+ if (!initialized) {
184
+ await this._onInitialize?.(id);
185
+ Record.set(this._initialized, id, true);
186
+ }
187
+ }
174
188
  expand(id, relation = "outbound") {
175
189
  const key = `${id}$${relation}`;
176
190
  const expanded = Record.get(this._expanded, key).pipe(Option.getOrElse(() => false));
@@ -179,7 +193,7 @@ var Graph = class {
179
193
  expanded
180
194
  }, {
181
195
  F: __dxlog_file,
182
- L: 395,
196
+ L: 409,
183
197
  S: this,
184
198
  C: (f, a) => f(...a)
185
199
  });
@@ -189,14 +203,14 @@ var Graph = class {
189
203
  }
190
204
  }
191
205
  addNodes(nodes) {
192
- Rx.batch(() => {
206
+ Atom.batch(() => {
193
207
  nodes.map((node) => this.addNode(node));
194
208
  });
195
209
  }
196
210
  addNode({ nodes, edges, ...nodeArg }) {
197
211
  const { id, type, data = null, properties = {} } = nodeArg;
198
- const nodeRx = this._node(id);
199
- const node = this._registry.get(nodeRx);
212
+ const nodeAtom = this._node(id);
213
+ const node = this._registry.get(nodeAtom);
200
214
  Option.match(node, {
201
215
  onSome: (node2) => {
202
216
  const typeChanged = node2.type !== type;
@@ -209,7 +223,7 @@ var Graph = class {
209
223
  propertiesChanged
210
224
  }, {
211
225
  F: __dxlog_file,
212
- L: 417,
226
+ L: 431,
213
227
  S: this,
214
228
  C: (f, a) => f(...a)
215
229
  });
@@ -221,7 +235,7 @@ var Graph = class {
221
235
  properties
222
236
  }, {
223
237
  F: __dxlog_file,
224
- L: 419,
238
+ L: 438,
225
239
  S: this,
226
240
  C: (f, a) => f(...a)
227
241
  });
@@ -234,7 +248,7 @@ var Graph = class {
234
248
  ...properties
235
249
  }
236
250
  });
237
- this._registry.set(nodeRx, newNode);
251
+ this._registry.set(nodeAtom, newNode);
238
252
  this.onNodeChanged.emit({
239
253
  id,
240
254
  node: newNode
@@ -249,7 +263,7 @@ var Graph = class {
249
263
  properties
250
264
  }, {
251
265
  F: __dxlog_file,
252
- L: 426,
266
+ L: 450,
253
267
  S: this,
254
268
  C: (f, a) => f(...a)
255
269
  });
@@ -259,7 +273,7 @@ var Graph = class {
259
273
  data,
260
274
  properties
261
275
  });
262
- this._registry.set(nodeRx, newNode);
276
+ this._registry.set(nodeAtom, newNode);
263
277
  this.onNodeChanged.emit({
264
278
  id,
265
279
  node: newNode
@@ -279,13 +293,13 @@ var Graph = class {
279
293
  }
280
294
  }
281
295
  removeNodes(ids, edges = false) {
282
- Rx.batch(() => {
296
+ Atom.batch(() => {
283
297
  ids.map((id) => this.removeNode(id, edges));
284
298
  });
285
299
  }
286
300
  removeNode(id, edges = false) {
287
- const nodeRx = this._node(id);
288
- this._registry.set(nodeRx, Option.none());
301
+ const nodeAtom = this._node(id);
302
+ this._registry.set(nodeAtom, Option.none());
289
303
  this.onNodeChanged.emit({
290
304
  id,
291
305
  node: Option.none()
@@ -307,24 +321,24 @@ var Graph = class {
307
321
  this._onRemoveNode?.(id);
308
322
  }
309
323
  addEdges(edges) {
310
- Rx.batch(() => {
324
+ Atom.batch(() => {
311
325
  edges.map((edge) => this.addEdge(edge));
312
326
  });
313
327
  }
314
328
  addEdge(edgeArg) {
315
- const sourceRx = this._edges(edgeArg.source);
316
- const source = this._registry.get(sourceRx);
329
+ const sourceAtom = this._edges(edgeArg.source);
330
+ const source = this._registry.get(sourceAtom);
317
331
  if (!source.outbound.includes(edgeArg.target)) {
318
332
  log("add outbound edge", {
319
333
  source: edgeArg.source,
320
334
  target: edgeArg.target
321
335
  }, {
322
336
  F: __dxlog_file,
323
- L: 481,
337
+ L: 505,
324
338
  S: this,
325
339
  C: (f, a) => f(...a)
326
340
  });
327
- this._registry.set(sourceRx, {
341
+ this._registry.set(sourceAtom, {
328
342
  inbound: source.inbound,
329
343
  outbound: [
330
344
  ...source.outbound,
@@ -332,19 +346,19 @@ var Graph = class {
332
346
  ]
333
347
  });
334
348
  }
335
- const targetRx = this._edges(edgeArg.target);
336
- const target = this._registry.get(targetRx);
349
+ const targetAtom = this._edges(edgeArg.target);
350
+ const target = this._registry.get(targetAtom);
337
351
  if (!target.inbound.includes(edgeArg.source)) {
338
352
  log("add inbound edge", {
339
353
  source: edgeArg.source,
340
354
  target: edgeArg.target
341
355
  }, {
342
356
  F: __dxlog_file,
343
- L: 488,
357
+ L: 518,
344
358
  S: this,
345
359
  C: (f, a) => f(...a)
346
360
  });
347
- this._registry.set(targetRx, {
361
+ this._registry.set(targetAtom, {
348
362
  inbound: [
349
363
  ...target.inbound,
350
364
  edgeArg.source
@@ -354,30 +368,30 @@ var Graph = class {
354
368
  }
355
369
  }
356
370
  removeEdges(edges, removeOrphans = false) {
357
- Rx.batch(() => {
371
+ Atom.batch(() => {
358
372
  edges.map((edge) => this.removeEdge(edge, removeOrphans));
359
373
  });
360
374
  }
361
375
  removeEdge(edgeArg, removeOrphans = false) {
362
- const sourceRx = this._edges(edgeArg.source);
363
- const source = this._registry.get(sourceRx);
376
+ const sourceAtom = this._edges(edgeArg.source);
377
+ const source = this._registry.get(sourceAtom);
364
378
  if (source.outbound.includes(edgeArg.target)) {
365
- this._registry.set(sourceRx, {
379
+ this._registry.set(sourceAtom, {
366
380
  inbound: source.inbound,
367
381
  outbound: source.outbound.filter((id) => id !== edgeArg.target)
368
382
  });
369
383
  }
370
- const targetRx = this._edges(edgeArg.target);
371
- const target = this._registry.get(targetRx);
384
+ const targetAtom = this._edges(edgeArg.target);
385
+ const target = this._registry.get(targetAtom);
372
386
  if (target.inbound.includes(edgeArg.source)) {
373
- this._registry.set(targetRx, {
387
+ this._registry.set(targetAtom, {
374
388
  inbound: target.inbound.filter((id) => id !== edgeArg.source),
375
389
  outbound: target.outbound
376
390
  });
377
391
  }
378
392
  if (removeOrphans) {
379
- const source2 = this._registry.get(sourceRx);
380
- const target2 = this._registry.get(targetRx);
393
+ const source2 = this._registry.get(sourceAtom);
394
+ const target2 = this._registry.get(targetAtom);
381
395
  if (source2.outbound.length === 0 && source2.inbound.length === 0 && edgeArg.source !== ROOT_ID) {
382
396
  this.removeNodes([
383
397
  edgeArg.source
@@ -391,15 +405,15 @@ var Graph = class {
391
405
  }
392
406
  }
393
407
  sortEdges(id, relation, order) {
394
- const edgesRx = this._edges(id);
395
- const edges = this._registry.get(edgesRx);
408
+ const edgesAtom = this._edges(id);
409
+ const edges = this._registry.get(edgesAtom);
396
410
  const unsorted = edges[relation].filter((id2) => !order.includes(id2)) ?? [];
397
411
  const sorted = order.filter((id2) => edges[relation].includes(id2)) ?? [];
398
412
  edges[relation].splice(0, edges[relation].length, ...[
399
413
  ...sorted,
400
414
  ...unsorted
401
415
  ]);
402
- this._registry.set(edgesRx, edges);
416
+ this._registry.set(edgesAtom, edges);
403
417
  }
404
418
  traverse({ visitor, source = ROOT_ID, relation = "outbound" }, path = []) {
405
419
  if (path.includes(source)) {
@@ -423,7 +437,7 @@ var Graph = class {
423
437
  ]));
424
438
  }
425
439
  getPath({ source = "root", target }) {
426
- return pipe(this.getNode(source), Option.flatMap((node) => {
440
+ return Function.pipe(this.getNode(source), Option.flatMap((node) => {
427
441
  let found = Option.none();
428
442
  this.traverse({
429
443
  source: node.id,
@@ -467,57 +481,65 @@ var Graph = class {
467
481
  };
468
482
 
469
483
  // src/graph-builder.ts
470
- import { Registry as Registry2, Rx as Rx2 } from "@effect-rx/rx-react";
484
+ import { Atom as Atom2, Registry as Registry2 } from "@effect-atom/atom-react";
471
485
  import { effect } from "@preact/signals-core";
472
- import { Array, pipe as pipe2, Record as Record2 } from "effect";
486
+ import * as Array from "effect/Array";
487
+ import * as Function2 from "effect/Function";
488
+ import * as Option2 from "effect/Option";
489
+ import * as Record2 from "effect/Record";
473
490
  import { log as log2 } from "@dxos/log";
474
491
  import { byPosition, getDebugName, isNode, isNonNullable as isNonNullable2 } from "@dxos/util";
475
492
 
476
493
  // src/node.ts
477
494
  var isGraphNode = (data) => data && typeof data === "object" && "id" in data && "properties" in data && data.properties ? typeof data.properties === "object" && "data" in data : false;
478
- var isAction = (data) => isGraphNode(data) ? typeof data.data === "function" : false;
495
+ var isAction = (data) => isGraphNode(data) ? typeof data.data === "function" && data.type === ACTION_TYPE : false;
479
496
  var actionGroupSymbol = Symbol("ActionGroup");
480
- var isActionGroup = (data) => isGraphNode(data) ? data.data === actionGroupSymbol : false;
497
+ var isActionGroup = (data) => isGraphNode(data) ? data.data === actionGroupSymbol && data.type === ACTION_GROUP_TYPE : false;
481
498
  var isActionLike = (data) => isAction(data) || isActionGroup(data);
482
499
 
483
500
  // src/graph-builder.ts
484
501
  var __dxlog_file2 = "/__w/dxos/dxos/packages/sdk/app-graph/src/graph-builder.ts";
485
502
  var createExtension = (extension) => {
486
- const { id, position = "static", relation = "outbound", connector: _connector, actions: _actions, actionGroups: _actionGroups } = extension;
503
+ const { id, position = "static", relation = "outbound", resolver: _resolver, connector: _connector, actions: _actions, actionGroups: _actionGroups } = extension;
487
504
  const getId = (key) => `${id}/${key}`;
488
- const connector = _connector && Rx2.family((node) => _connector(node).pipe(Rx2.withLabel(`graph-builder:_connector:${id}`)));
489
- const actionGroups = _actionGroups && Rx2.family((node) => _actionGroups(node).pipe(Rx2.withLabel(`graph-builder:_actionGroups:${id}`)));
490
- const actions = _actions && Rx2.family((node) => _actions(node).pipe(Rx2.withLabel(`graph-builder:_actions:${id}`)));
505
+ const resolver = _resolver && Atom2.family((id2) => _resolver(id2).pipe(Atom2.withLabel(`graph-builder:_resolver:${id2}`)));
506
+ const connector = _connector && Atom2.family((node) => _connector(node).pipe(Atom2.withLabel(`graph-builder:_connector:${id}`)));
507
+ const actionGroups = _actionGroups && Atom2.family((node) => _actionGroups(node).pipe(Atom2.withLabel(`graph-builder:_actionGroups:${id}`)));
508
+ const actions = _actions && Atom2.family((node) => _actions(node).pipe(Atom2.withLabel(`graph-builder:_actions:${id}`)));
491
509
  return [
492
- // resolver ? { id: getId('resolver'), position, resolver } : undefined,
510
+ resolver ? {
511
+ id: getId("resolver"),
512
+ position,
513
+ resolver
514
+ } : void 0,
493
515
  connector ? {
494
516
  id: getId("connector"),
495
517
  position,
496
518
  relation,
497
- connector: Rx2.family((node) => Rx2.make((get) => {
519
+ connector: Atom2.family((node) => Atom2.make((get2) => {
498
520
  try {
499
- return get(connector(node));
521
+ return get2(connector(node));
500
522
  } catch {
501
523
  log2.warn("Error in connector", {
502
524
  id: getId("connector"),
503
525
  node
504
526
  }, {
505
527
  F: __dxlog_file2,
506
- L: 101,
528
+ L: 114,
507
529
  S: void 0,
508
530
  C: (f, a) => f(...a)
509
531
  });
510
532
  return [];
511
533
  }
512
- }).pipe(Rx2.withLabel(`graph-builder:connector:${id}`)))
534
+ }).pipe(Atom2.withLabel(`graph-builder:connector:${id}`)))
513
535
  } : void 0,
514
536
  actionGroups ? {
515
537
  id: getId("actionGroups"),
516
538
  position,
517
539
  relation: "outbound",
518
- connector: Rx2.family((node) => Rx2.make((get) => {
540
+ connector: Atom2.family((node) => Atom2.make((get2) => {
519
541
  try {
520
- return get(actionGroups(node)).map((arg) => ({
542
+ return get2(actionGroups(node)).map((arg) => ({
521
543
  ...arg,
522
544
  data: actionGroupSymbol,
523
545
  type: ACTION_GROUP_TYPE
@@ -528,21 +550,21 @@ var createExtension = (extension) => {
528
550
  node
529
551
  }, {
530
552
  F: __dxlog_file2,
531
- L: 122,
553
+ L: 135,
532
554
  S: void 0,
533
555
  C: (f, a) => f(...a)
534
556
  });
535
557
  return [];
536
558
  }
537
- }).pipe(Rx2.withLabel(`graph-builder:connector:actionGroups:${id}`)))
559
+ }).pipe(Atom2.withLabel(`graph-builder:connector:actionGroups:${id}`)))
538
560
  } : void 0,
539
561
  actions ? {
540
562
  id: getId("actions"),
541
563
  position,
542
564
  relation: "outbound",
543
- connector: Rx2.family((node) => Rx2.make((get) => {
565
+ connector: Atom2.family((node) => Atom2.make((get2) => {
544
566
  try {
545
- return get(actions(node)).map((arg) => ({
567
+ return get2(actions(node)).map((arg) => ({
546
568
  ...arg,
547
569
  type: ACTION_TYPE
548
570
  }));
@@ -552,13 +574,13 @@ var createExtension = (extension) => {
552
574
  node
553
575
  }, {
554
576
  F: __dxlog_file2,
555
- L: 139,
577
+ L: 152,
556
578
  S: void 0,
557
579
  C: (f, a) => f(...a)
558
580
  });
559
581
  return [];
560
582
  }
561
- }).pipe(Rx2.withLabel(`graph-builder:connector:actions:${id}`)))
583
+ }).pipe(Atom2.withLabel(`graph-builder:connector:actions:${id}`)))
562
584
  } : void 0
563
585
  ].filter(isNonNullable2);
564
586
  };
@@ -576,32 +598,19 @@ var flattenExtensions = (extension, acc = []) => {
576
598
  }
577
599
  };
578
600
  var GraphBuilder = class _GraphBuilder {
601
+ // TODO(wittjosiah): Use Context.
602
+ _subscriptions = /* @__PURE__ */ new Map();
603
+ _extensions = Atom2.make(Record2.empty()).pipe(Atom2.keepAlive, Atom2.withLabel("graph-builder:extensions"));
604
+ _initialized = {};
605
+ _registry;
606
+ _graph;
579
607
  constructor({ registry, ...params } = {}) {
580
- // TODO(wittjosiah): Use Context.
581
- this._connectorSubscriptions = /* @__PURE__ */ new Map();
582
- this._extensions = Rx2.make(Record2.empty()).pipe(Rx2.keepAlive, Rx2.withLabel("graph-builder:extensions"));
583
- this._connectors = Rx2.family((key) => {
584
- return Rx2.make((get) => {
585
- const [id, relation] = key.split("+");
586
- const node = this._graph.node(id);
587
- return pipe2(
588
- get(this._extensions),
589
- Record2.values,
590
- // TODO(wittjosiah): Sort on write rather than read.
591
- Array.sortBy(byPosition),
592
- Array.filter(({ relation: _relation = "outbound" }) => _relation === relation),
593
- Array.map(({ connector }) => connector?.(node)),
594
- Array.filter(isNonNullable2),
595
- Array.flatMap((result) => get(result))
596
- );
597
- }).pipe(Rx2.withLabel(`graph-builder:connectors:${key}`));
598
- });
599
608
  this._registry = registry ?? Registry2.make();
600
609
  this._graph = new Graph({
601
610
  ...params,
602
611
  registry: this._registry,
603
612
  onExpand: (id, relation) => this._onExpand(id, relation),
604
- // onInitialize: (id) => this._onInitialize(id),
613
+ onInitialize: (id) => this._onInitialize(id),
605
614
  onRemoveNode: (id) => this._onRemoveNode(id)
606
615
  });
607
616
  }
@@ -671,9 +680,30 @@ var GraphBuilder = class _GraphBuilder {
671
680
  }
672
681
  }
673
682
  destroy() {
674
- this._connectorSubscriptions.forEach((unsubscribe) => unsubscribe());
675
- this._connectorSubscriptions.clear();
683
+ this._subscriptions.forEach((unsubscribe) => unsubscribe());
684
+ this._subscriptions.clear();
676
685
  }
686
+ _resolvers = Atom2.family((id) => {
687
+ return Atom2.make((get2) => {
688
+ 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);
689
+ });
690
+ });
691
+ _connectors = Atom2.family((key) => {
692
+ return Atom2.make((get2) => {
693
+ const [id, relation] = key.split("+");
694
+ const node = this._graph.node(id);
695
+ return Function2.pipe(
696
+ get2(this._extensions),
697
+ Record2.values,
698
+ // TODO(wittjosiah): Sort on write rather than read.
699
+ Array.sortBy(byPosition),
700
+ Array.filter(({ relation: _relation = "outbound" }) => _relation === relation),
701
+ Array.map(({ connector }) => connector?.(node)),
702
+ Array.filter(isNonNullable2),
703
+ Array.flatMap((result) => get2(result))
704
+ );
705
+ }).pipe(Atom2.withLabel(`graph-builder:connectors:${key}`));
706
+ });
677
707
  _onExpand(id, relation) {
678
708
  log2("onExpand", {
679
709
  id,
@@ -681,7 +711,7 @@ var GraphBuilder = class _GraphBuilder {
681
711
  registry: getDebugName(this._registry)
682
712
  }, {
683
713
  F: __dxlog_file2,
684
- L: 301,
714
+ L: 329,
685
715
  S: this,
686
716
  C: (f, a) => f(...a)
687
717
  });
@@ -698,12 +728,12 @@ var GraphBuilder = class _GraphBuilder {
698
728
  removed
699
729
  }, {
700
730
  F: __dxlog_file2,
701
- L: 312,
731
+ L: 340,
702
732
  S: this,
703
733
  C: (f, a) => f(...a)
704
734
  });
705
735
  const update = () => {
706
- Rx2.batch(() => {
736
+ Atom2.batch(() => {
707
737
  this._graph.removeEdges(removed.map((target) => ({
708
738
  source: id,
709
739
  target
@@ -727,34 +757,62 @@ var GraphBuilder = class _GraphBuilder {
727
757
  }, {
728
758
  immediate: true
729
759
  });
730
- this._connectorSubscriptions.set(id, cancel);
760
+ this._subscriptions.set(id, cancel);
761
+ }
762
+ // TODO(wittjosiah): If the same node is added by a connector, the resolver should probably cancel itself?
763
+ async _onInitialize(id) {
764
+ log2("onInitialize", {
765
+ id
766
+ }, {
767
+ F: __dxlog_file2,
768
+ L: 377,
769
+ S: this,
770
+ C: (f, a) => f(...a)
771
+ });
772
+ const resolver = this._resolvers(id);
773
+ const cancel = this._registry.subscribe(resolver, (node) => {
774
+ const trigger = this._initialized[id];
775
+ Option2.match(node, {
776
+ onSome: (node2) => {
777
+ this._graph.addNodes([
778
+ node2
779
+ ]);
780
+ trigger?.wake();
781
+ },
782
+ onNone: () => {
783
+ trigger?.wake();
784
+ this._graph.removeNodes([
785
+ id
786
+ ]);
787
+ }
788
+ });
789
+ }, {
790
+ immediate: true
791
+ });
792
+ this._subscriptions.set(id, cancel);
731
793
  }
732
- // TODO(wittjosiah): On initialize to restore state from cache.
733
- // private async _onInitialize(id: string) {
734
- // log('onInitialize', { id });
735
- // }
736
794
  _onRemoveNode(id) {
737
- this._connectorSubscriptions.get(id)?.();
738
- this._connectorSubscriptions.delete(id);
795
+ this._subscriptions.get(id)?.();
796
+ this._subscriptions.delete(id);
739
797
  }
740
798
  };
741
- var rxFromSignal = (cb) => {
742
- return Rx2.make((get) => {
799
+ var atomFromSignal = (cb) => {
800
+ return Atom2.make((get2) => {
743
801
  const dispose = effect(() => {
744
- get.setSelf(cb());
802
+ get2.setSelf(cb());
745
803
  });
746
- get.addFinalizer(() => dispose());
804
+ get2.addFinalizer(() => dispose());
747
805
  return cb();
748
806
  });
749
807
  };
750
- var observableFamily = Rx2.family((observable) => {
751
- return Rx2.make((get) => {
752
- const subscription = observable.subscribe((value) => get.setSelf(value));
753
- get.addFinalizer(() => subscription.unsubscribe());
808
+ var observableFamily = Atom2.family((observable) => {
809
+ return Atom2.make((get2) => {
810
+ const subscription = observable.subscribe((value) => get2.setSelf(value));
811
+ get2.addFinalizer(() => subscription.unsubscribe());
754
812
  return observable.get();
755
813
  });
756
814
  });
757
- var rxFromObservable = (observable) => {
815
+ var atomFromObservable = (observable) => {
758
816
  return observableFamily(observable);
759
817
  };
760
818
  export {
@@ -765,14 +823,14 @@ export {
765
823
  ROOT_ID,
766
824
  ROOT_TYPE,
767
825
  actionGroupSymbol,
826
+ atomFromObservable,
827
+ atomFromSignal,
768
828
  createExtension,
769
829
  flattenExtensions,
770
830
  getGraph,
771
831
  isAction,
772
832
  isActionGroup,
773
833
  isActionLike,
774
- isGraphNode,
775
- rxFromObservable,
776
- rxFromSignal
834
+ isGraphNode
777
835
  };
778
836
  //# sourceMappingURL=index.mjs.map