@dxos/app-graph 0.8.4-main.b97322e → 0.8.4-main.dedc0f3

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