@dxos/app-graph 0.8.4-main.84f28bd → 0.8.4-main.a4bbb77

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.
@@ -2,12 +2,25 @@ import { createRequire } from 'node:module';const require = createRequire(import
2
2
 
3
3
  // src/graph.ts
4
4
  import { Registry, Rx } from "@effect-rx/rx-react";
5
- import { Option, pipe, Record } from "effect";
5
+ import { Option, Record, pipe } from "effect";
6
6
  import { Event, Trigger } from "@dxos/async";
7
7
  import { todo } from "@dxos/debug";
8
8
  import { invariant } from "@dxos/invariant";
9
9
  import { log } from "@dxos/log";
10
10
  import { isNonNullable } from "@dxos/util";
11
+ function _define_property(obj, key, value) {
12
+ if (key in obj) {
13
+ Object.defineProperty(obj, key, {
14
+ value,
15
+ enumerable: true,
16
+ configurable: true,
17
+ writable: true
18
+ });
19
+ } else {
20
+ obj[key] = value;
21
+ }
22
+ return obj;
23
+ }
11
24
  var __dxlog_file = "/__w/dxos/dxos/packages/sdk/app-graph/src/graph.ts";
12
25
  var graphSymbol = Symbol("graph");
13
26
  var getGraph = (node) => {
@@ -28,103 +41,6 @@ var ROOT_TYPE = "dxos.org/type/GraphRoot";
28
41
  var ACTION_TYPE = "dxos.org/type/GraphAction";
29
42
  var ACTION_GROUP_TYPE = "dxos.org/type/GraphActionGroup";
30
43
  var Graph = class {
31
- constructor({ registry, nodes, edges, onExpand, onRemoveNode } = {}) {
32
- this.onNodeChanged = new Event();
33
- this._expanded = Record.empty();
34
- this._initialized = Record.empty();
35
- this._initialEdges = Record.empty();
36
- this._initialNodes = Record.fromEntries([
37
- [
38
- ROOT_ID,
39
- this._constructNode({
40
- id: ROOT_ID,
41
- type: ROOT_TYPE,
42
- data: null,
43
- properties: {}
44
- })
45
- ]
46
- ]);
47
- /** @internal */
48
- this._node = Rx.family((id) => {
49
- const initial = Option.flatten(Record.get(this._initialNodes, id));
50
- return Rx.make(initial).pipe(Rx.keepAlive, Rx.withLabel(`graph:node:${id}`));
51
- });
52
- this._nodeOrThrow = Rx.family((id) => {
53
- return Rx.make((get) => {
54
- const node = get(this._node(id));
55
- invariant(Option.isSome(node), `Node not available: ${id}`, {
56
- F: __dxlog_file,
57
- L: 253,
58
- S: this,
59
- A: [
60
- "Option.isSome(node)",
61
- "`Node not available: ${id}`"
62
- ]
63
- });
64
- return node.value;
65
- });
66
- });
67
- this._edges = Rx.family((id) => {
68
- const initial = Record.get(this._initialEdges, id).pipe(Option.getOrElse(() => ({
69
- inbound: [],
70
- outbound: []
71
- })));
72
- return Rx.make(initial).pipe(Rx.keepAlive, Rx.withLabel(`graph:edges:${id}`));
73
- });
74
- // NOTE: Currently the argument to the family needs to be referentially stable for the rx to be referentially stable.
75
- // TODO(wittjosiah): Rx feature request, support for something akin to `ComplexMap` to allow for complex arguments.
76
- this._connections = Rx.family((key) => {
77
- return Rx.make((get) => {
78
- const [id, relation] = key.split("$");
79
- const edges = get(this._edges(id));
80
- return edges[relation].map((id2) => get(this._node(id2))).filter(Option.isSome).map((o) => o.value);
81
- }).pipe(Rx.withLabel(`graph:connections:${key}`));
82
- });
83
- this._actions = Rx.family((id) => {
84
- return Rx.make((get) => {
85
- return get(this._connections(`${id}$outbound`)).filter((node) => node.type === ACTION_TYPE || node.type === ACTION_GROUP_TYPE);
86
- }).pipe(Rx.withLabel(`graph:actions:${id}`));
87
- });
88
- this._json = Rx.family((id) => {
89
- return Rx.make((get) => {
90
- const toJSON = (node, seen = []) => {
91
- const nodes = get(this.connections(node.id));
92
- const obj = {
93
- id: node.id.length > 32 ? `${node.id.slice(0, 32)}...` : node.id,
94
- type: node.type
95
- };
96
- if (node.properties.label) {
97
- obj.label = node.properties.label;
98
- }
99
- if (nodes.length) {
100
- obj.nodes = nodes.map((n) => {
101
- const nextSeen = [
102
- ...seen,
103
- node.id
104
- ];
105
- return nextSeen.includes(n.id) ? void 0 : toJSON(n, nextSeen);
106
- }).filter(isNonNullable);
107
- }
108
- return obj;
109
- };
110
- const root = get(this.nodeOrThrow(id));
111
- return toJSON(root);
112
- }).pipe(Rx.withLabel(`graph:json:${id}`));
113
- });
114
- this._registry = registry ?? Registry.make();
115
- this._onExpand = onExpand;
116
- this._onRemoveNode = onRemoveNode;
117
- if (nodes) {
118
- nodes.forEach((node) => {
119
- Record.set(this._initialNodes, node.id, this._constructNode(node));
120
- });
121
- }
122
- if (edges) {
123
- Object.entries(edges).forEach(([source, edges2]) => {
124
- Record.set(this._initialEdges, source, edges2);
125
- });
126
- }
127
- }
128
44
  toJSON(id = ROOT_ID) {
129
45
  return this._registry.get(this._json(id));
130
46
  }
@@ -164,15 +80,22 @@ var Graph = class {
164
80
  getEdges(id) {
165
81
  return this._registry.get(this.edges(id));
166
82
  }
167
- // TODO(wittjosiah): On initialize to restore state from cache.
168
- // async initialize(id: string) {
169
- // const initialized = Record.get(this._initialized, id).pipe(Option.getOrElse(() => false));
170
- // log('initialize', { id, initialized });
171
- // if (!initialized) {
172
- // await this._onInitialize?.(id);
173
- // Record.set(this._initialized, id, true);
174
- // }
175
- // }
83
+ async initialize(id) {
84
+ const initialized = Record.get(this._initialized, id).pipe(Option.getOrElse(() => false));
85
+ log("initialize", {
86
+ id,
87
+ initialized
88
+ }, {
89
+ F: __dxlog_file,
90
+ L: 384,
91
+ S: this,
92
+ C: (f, a) => f(...a)
93
+ });
94
+ if (!initialized) {
95
+ await this._onInitialize?.(id);
96
+ Record.set(this._initialized, id, true);
97
+ }
98
+ }
176
99
  expand(id, relation = "outbound") {
177
100
  const key = `${id}$${relation}`;
178
101
  const expanded = Record.get(this._expanded, key).pipe(Option.getOrElse(() => false));
@@ -181,7 +104,7 @@ var Graph = class {
181
104
  expanded
182
105
  }, {
183
106
  F: __dxlog_file,
184
- L: 395,
107
+ L: 394,
185
108
  S: this,
186
109
  C: (f, a) => f(...a)
187
110
  });
@@ -211,7 +134,7 @@ var Graph = class {
211
134
  propertiesChanged
212
135
  }, {
213
136
  F: __dxlog_file,
214
- L: 417,
137
+ L: 416,
215
138
  S: this,
216
139
  C: (f, a) => f(...a)
217
140
  });
@@ -223,7 +146,7 @@ var Graph = class {
223
146
  properties
224
147
  }, {
225
148
  F: __dxlog_file,
226
- L: 419,
149
+ L: 418,
227
150
  S: this,
228
151
  C: (f, a) => f(...a)
229
152
  });
@@ -251,7 +174,7 @@ var Graph = class {
251
174
  properties
252
175
  }, {
253
176
  F: __dxlog_file,
254
- L: 426,
177
+ L: 425,
255
178
  S: this,
256
179
  C: (f, a) => f(...a)
257
180
  });
@@ -322,7 +245,7 @@ var Graph = class {
322
245
  target: edgeArg.target
323
246
  }, {
324
247
  F: __dxlog_file,
325
- L: 481,
248
+ L: 480,
326
249
  S: this,
327
250
  C: (f, a) => f(...a)
328
251
  });
@@ -342,7 +265,7 @@ var Graph = class {
342
265
  target: edgeArg.target
343
266
  }, {
344
267
  F: __dxlog_file,
345
- L: 488,
268
+ L: 487,
346
269
  S: this,
347
270
  C: (f, a) => f(...a)
348
271
  });
@@ -466,32 +389,149 @@ var Graph = class {
466
389
  ...node
467
390
  });
468
391
  }
392
+ constructor({ registry, nodes, edges, onInitialize, onExpand, onRemoveNode } = {}) {
393
+ _define_property(this, "onNodeChanged", new Event());
394
+ _define_property(this, "_onExpand", void 0);
395
+ _define_property(this, "_onInitialize", void 0);
396
+ _define_property(this, "_onRemoveNode", void 0);
397
+ _define_property(this, "_registry", void 0);
398
+ _define_property(this, "_expanded", Record.empty());
399
+ _define_property(this, "_initialized", Record.empty());
400
+ _define_property(this, "_initialEdges", Record.empty());
401
+ _define_property(this, "_initialNodes", Record.fromEntries([
402
+ [
403
+ ROOT_ID,
404
+ this._constructNode({
405
+ id: ROOT_ID,
406
+ type: ROOT_TYPE,
407
+ data: null,
408
+ properties: {}
409
+ })
410
+ ]
411
+ ]));
412
+ _define_property(this, "_node", Rx.family((id) => {
413
+ const initial = Option.flatten(Record.get(this._initialNodes, id));
414
+ return Rx.make(initial).pipe(Rx.keepAlive, Rx.withLabel(`graph:node:${id}`));
415
+ }));
416
+ _define_property(this, "_nodeOrThrow", Rx.family((id) => {
417
+ return Rx.make((get) => {
418
+ const node = get(this._node(id));
419
+ invariant(Option.isSome(node), `Node not available: ${id}`, {
420
+ F: __dxlog_file,
421
+ L: 252,
422
+ S: this,
423
+ A: [
424
+ "Option.isSome(node)",
425
+ "`Node not available: ${id}`"
426
+ ]
427
+ });
428
+ return node.value;
429
+ });
430
+ }));
431
+ _define_property(this, "_edges", Rx.family((id) => {
432
+ const initial = Record.get(this._initialEdges, id).pipe(Option.getOrElse(() => ({
433
+ inbound: [],
434
+ outbound: []
435
+ })));
436
+ return Rx.make(initial).pipe(Rx.keepAlive, Rx.withLabel(`graph:edges:${id}`));
437
+ }));
438
+ _define_property(this, "_connections", Rx.family((key) => {
439
+ return Rx.make((get) => {
440
+ const [id, relation] = key.split("$");
441
+ const edges2 = get(this._edges(id));
442
+ return edges2[relation].map((id2) => get(this._node(id2))).filter(Option.isSome).map((o) => o.value);
443
+ }).pipe(Rx.withLabel(`graph:connections:${key}`));
444
+ }));
445
+ _define_property(this, "_actions", Rx.family((id) => {
446
+ return Rx.make((get) => {
447
+ return get(this._connections(`${id}$outbound`)).filter((node) => node.type === ACTION_TYPE || node.type === ACTION_GROUP_TYPE);
448
+ }).pipe(Rx.withLabel(`graph:actions:${id}`));
449
+ }));
450
+ _define_property(this, "_json", Rx.family((id) => {
451
+ return Rx.make((get) => {
452
+ const toJSON = (node, seen = []) => {
453
+ const nodes2 = get(this.connections(node.id));
454
+ const obj = {
455
+ id: node.id.length > 32 ? `${node.id.slice(0, 32)}...` : node.id,
456
+ type: node.type
457
+ };
458
+ if (node.properties.label) {
459
+ obj.label = node.properties.label;
460
+ }
461
+ if (nodes2.length) {
462
+ obj.nodes = nodes2.map((n) => {
463
+ const nextSeen = [
464
+ ...seen,
465
+ node.id
466
+ ];
467
+ return nextSeen.includes(n.id) ? void 0 : toJSON(n, nextSeen);
468
+ }).filter(isNonNullable);
469
+ }
470
+ return obj;
471
+ };
472
+ const root = get(this.nodeOrThrow(id));
473
+ return toJSON(root);
474
+ }).pipe(Rx.withLabel(`graph:json:${id}`));
475
+ }));
476
+ this._registry = registry ?? Registry.make();
477
+ this._onInitialize = onInitialize;
478
+ this._onExpand = onExpand;
479
+ this._onRemoveNode = onRemoveNode;
480
+ if (nodes) {
481
+ nodes.forEach((node) => {
482
+ Record.set(this._initialNodes, node.id, this._constructNode(node));
483
+ });
484
+ }
485
+ if (edges) {
486
+ Object.entries(edges).forEach(([source, edges2]) => {
487
+ Record.set(this._initialEdges, source, edges2);
488
+ });
489
+ }
490
+ }
469
491
  };
470
492
 
471
493
  // src/graph-builder.ts
472
494
  import { Registry as Registry2, Rx as Rx2 } from "@effect-rx/rx-react";
473
495
  import { effect } from "@preact/signals-core";
474
- import { Array, pipe as pipe2, Record as Record2 } from "effect";
496
+ import { Array, Option as Option2, Record as Record2, pipe as pipe2 } from "effect";
475
497
  import { log as log2 } from "@dxos/log";
476
498
  import { byPosition, getDebugName, isNode, isNonNullable as isNonNullable2 } from "@dxos/util";
477
499
 
478
500
  // src/node.ts
479
501
  var isGraphNode = (data) => data && typeof data === "object" && "id" in data && "properties" in data && data.properties ? typeof data.properties === "object" && "data" in data : false;
480
- var isAction = (data) => isGraphNode(data) ? typeof data.data === "function" : false;
502
+ var isAction = (data) => isGraphNode(data) ? typeof data.data === "function" && data.type === ACTION_TYPE : false;
481
503
  var actionGroupSymbol = Symbol("ActionGroup");
482
- var isActionGroup = (data) => isGraphNode(data) ? data.data === actionGroupSymbol : false;
504
+ var isActionGroup = (data) => isGraphNode(data) ? data.data === actionGroupSymbol && data.type === ACTION_GROUP_TYPE : false;
483
505
  var isActionLike = (data) => isAction(data) || isActionGroup(data);
484
506
 
485
507
  // src/graph-builder.ts
508
+ function _define_property2(obj, key, value) {
509
+ if (key in obj) {
510
+ Object.defineProperty(obj, key, {
511
+ value,
512
+ enumerable: true,
513
+ configurable: true,
514
+ writable: true
515
+ });
516
+ } else {
517
+ obj[key] = value;
518
+ }
519
+ return obj;
520
+ }
486
521
  var __dxlog_file2 = "/__w/dxos/dxos/packages/sdk/app-graph/src/graph-builder.ts";
487
522
  var createExtension = (extension) => {
488
- const { id, position = "static", relation = "outbound", connector: _connector, actions: _actions, actionGroups: _actionGroups } = extension;
523
+ const { id, position = "static", relation = "outbound", resolver: _resolver, connector: _connector, actions: _actions, actionGroups: _actionGroups } = extension;
489
524
  const getId = (key) => `${id}/${key}`;
525
+ const resolver = _resolver && Rx2.family((id2) => _resolver(id2).pipe(Rx2.withLabel(`graph-builder:_resolver:${id2}`)));
490
526
  const connector = _connector && Rx2.family((node) => _connector(node).pipe(Rx2.withLabel(`graph-builder:_connector:${id}`)));
491
527
  const actionGroups = _actionGroups && Rx2.family((node) => _actionGroups(node).pipe(Rx2.withLabel(`graph-builder:_actionGroups:${id}`)));
492
528
  const actions = _actions && Rx2.family((node) => _actions(node).pipe(Rx2.withLabel(`graph-builder:_actions:${id}`)));
493
529
  return [
494
- // resolver ? { id: getId('resolver'), position, resolver } : undefined,
530
+ resolver ? {
531
+ id: getId("resolver"),
532
+ position,
533
+ resolver
534
+ } : void 0,
495
535
  connector ? {
496
536
  id: getId("connector"),
497
537
  position,
@@ -505,7 +545,7 @@ var createExtension = (extension) => {
505
545
  node
506
546
  }, {
507
547
  F: __dxlog_file2,
508
- L: 101,
548
+ L: 109,
509
549
  S: void 0,
510
550
  C: (f, a) => f(...a)
511
551
  });
@@ -530,7 +570,7 @@ var createExtension = (extension) => {
530
570
  node
531
571
  }, {
532
572
  F: __dxlog_file2,
533
- L: 122,
573
+ L: 130,
534
574
  S: void 0,
535
575
  C: (f, a) => f(...a)
536
576
  });
@@ -554,7 +594,7 @@ var createExtension = (extension) => {
554
594
  node
555
595
  }, {
556
596
  F: __dxlog_file2,
557
- L: 139,
597
+ L: 147,
558
598
  S: void 0,
559
599
  C: (f, a) => f(...a)
560
600
  });
@@ -578,35 +618,6 @@ var flattenExtensions = (extension, acc = []) => {
578
618
  }
579
619
  };
580
620
  var GraphBuilder = class _GraphBuilder {
581
- constructor({ registry, ...params } = {}) {
582
- // TODO(wittjosiah): Use Context.
583
- this._connectorSubscriptions = /* @__PURE__ */ new Map();
584
- this._extensions = Rx2.make(Record2.empty()).pipe(Rx2.keepAlive, Rx2.withLabel("graph-builder:extensions"));
585
- this._connectors = Rx2.family((key) => {
586
- return Rx2.make((get) => {
587
- const [id, relation] = key.split("+");
588
- const node = this._graph.node(id);
589
- return pipe2(
590
- get(this._extensions),
591
- Record2.values,
592
- // TODO(wittjosiah): Sort on write rather than read.
593
- Array.sortBy(byPosition),
594
- Array.filter(({ relation: _relation = "outbound" }) => _relation === relation),
595
- Array.map(({ connector }) => connector?.(node)),
596
- Array.filter(isNonNullable2),
597
- Array.flatMap((result) => get(result))
598
- );
599
- }).pipe(Rx2.withLabel(`graph-builder:connectors:${key}`));
600
- });
601
- this._registry = registry ?? Registry2.make();
602
- this._graph = new Graph({
603
- ...params,
604
- registry: this._registry,
605
- onExpand: (id, relation) => this._onExpand(id, relation),
606
- // onInitialize: (id) => this._onInitialize(id),
607
- onRemoveNode: (id) => this._onRemoveNode(id)
608
- });
609
- }
610
621
  static from(pickle, registry) {
611
622
  if (!pickle) {
612
623
  return new _GraphBuilder({
@@ -673,8 +684,8 @@ var GraphBuilder = class _GraphBuilder {
673
684
  }
674
685
  }
675
686
  destroy() {
676
- this._connectorSubscriptions.forEach((unsubscribe) => unsubscribe());
677
- this._connectorSubscriptions.clear();
687
+ this._subscriptions.forEach((unsubscribe) => unsubscribe());
688
+ this._subscriptions.clear();
678
689
  }
679
690
  _onExpand(id, relation) {
680
691
  log2("onExpand", {
@@ -683,7 +694,7 @@ var GraphBuilder = class _GraphBuilder {
683
694
  registry: getDebugName(this._registry)
684
695
  }, {
685
696
  F: __dxlog_file2,
686
- L: 301,
697
+ L: 324,
687
698
  S: this,
688
699
  C: (f, a) => f(...a)
689
700
  });
@@ -700,7 +711,7 @@ var GraphBuilder = class _GraphBuilder {
700
711
  removed
701
712
  }, {
702
713
  F: __dxlog_file2,
703
- L: 312,
714
+ L: 335,
704
715
  S: this,
705
716
  C: (f, a) => f(...a)
706
717
  });
@@ -729,15 +740,79 @@ var GraphBuilder = class _GraphBuilder {
729
740
  }, {
730
741
  immediate: true
731
742
  });
732
- this._connectorSubscriptions.set(id, cancel);
743
+ this._subscriptions.set(id, cancel);
744
+ }
745
+ // TODO(wittjosiah): If the same node is added by a connector, the resolver should probably cancel itself?
746
+ async _onInitialize(id) {
747
+ log2("onInitialize", {
748
+ id
749
+ }, {
750
+ F: __dxlog_file2,
751
+ L: 372,
752
+ S: this,
753
+ C: (f, a) => f(...a)
754
+ });
755
+ const resolver = this._resolvers(id);
756
+ const cancel = this._registry.subscribe(resolver, (node) => {
757
+ const trigger = this._initialized[id];
758
+ Option2.match(node, {
759
+ onSome: (node2) => {
760
+ this._graph.addNodes([
761
+ node2
762
+ ]);
763
+ trigger?.wake();
764
+ },
765
+ onNone: () => {
766
+ trigger?.wake();
767
+ this._graph.removeNodes([
768
+ id
769
+ ]);
770
+ }
771
+ });
772
+ }, {
773
+ immediate: true
774
+ });
775
+ this._subscriptions.set(id, cancel);
733
776
  }
734
- // TODO(wittjosiah): On initialize to restore state from cache.
735
- // private async _onInitialize(id: string) {
736
- // log('onInitialize', { id });
737
- // }
738
777
  _onRemoveNode(id) {
739
- this._connectorSubscriptions.get(id)?.();
740
- this._connectorSubscriptions.delete(id);
778
+ this._subscriptions.get(id)?.();
779
+ this._subscriptions.delete(id);
780
+ }
781
+ constructor({ registry, ...params } = {}) {
782
+ _define_property2(this, "_subscriptions", /* @__PURE__ */ new Map());
783
+ _define_property2(this, "_extensions", Rx2.make(Record2.empty()).pipe(Rx2.keepAlive, Rx2.withLabel("graph-builder:extensions")));
784
+ _define_property2(this, "_initialized", {});
785
+ _define_property2(this, "_registry", void 0);
786
+ _define_property2(this, "_graph", void 0);
787
+ _define_property2(this, "_resolvers", Rx2.family((id) => {
788
+ return Rx2.make((get) => {
789
+ return pipe2(get(this._extensions), Record2.values, Array.sortBy(byPosition), Array.map(({ resolver }) => resolver), Array.filter(isNonNullable2), Array.map((resolver) => get(resolver(id))), Array.filter(isNonNullable2), Array.head);
790
+ });
791
+ }));
792
+ _define_property2(this, "_connectors", Rx2.family((key) => {
793
+ return Rx2.make((get) => {
794
+ const [id, relation] = key.split("+");
795
+ const node = this._graph.node(id);
796
+ return pipe2(
797
+ get(this._extensions),
798
+ Record2.values,
799
+ // TODO(wittjosiah): Sort on write rather than read.
800
+ Array.sortBy(byPosition),
801
+ Array.filter(({ relation: _relation = "outbound" }) => _relation === relation),
802
+ Array.map(({ connector }) => connector?.(node)),
803
+ Array.filter(isNonNullable2),
804
+ Array.flatMap((result) => get(result))
805
+ );
806
+ }).pipe(Rx2.withLabel(`graph-builder:connectors:${key}`));
807
+ }));
808
+ this._registry = registry ?? Registry2.make();
809
+ this._graph = new Graph({
810
+ ...params,
811
+ registry: this._registry,
812
+ onExpand: (id, relation) => this._onExpand(id, relation),
813
+ onInitialize: (id) => this._onInitialize(id),
814
+ onRemoveNode: (id) => this._onRemoveNode(id)
815
+ });
741
816
  }
742
817
  };
743
818
  var rxFromSignal = (cb) => {