@dxos/app-graph 0.8.4-main.c85a9c8dae → 0.8.4-main.d05539e30a

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 (55) hide show
  1. package/LICENSE +102 -5
  2. package/README.md +1 -1
  3. package/dist/lib/{browser/index.mjs → neutral/chunk-32XXJE6M.mjs} +304 -349
  4. package/dist/lib/neutral/chunk-32XXJE6M.mjs.map +7 -0
  5. package/dist/lib/neutral/chunk-J5LGTIGS.mjs +10 -0
  6. package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +7 -0
  7. package/dist/lib/neutral/index.mjs +40 -0
  8. package/dist/lib/neutral/index.mjs.map +7 -0
  9. package/dist/lib/neutral/meta.json +1 -0
  10. package/dist/lib/neutral/scheduler.mjs +15 -0
  11. package/dist/lib/neutral/scheduler.mjs.map +7 -0
  12. package/dist/lib/neutral/testing/index.mjs +40 -0
  13. package/dist/lib/neutral/testing/index.mjs.map +7 -0
  14. package/dist/types/src/atoms.d.ts.map +1 -1
  15. package/dist/types/src/graph-builder.d.ts +3 -3
  16. package/dist/types/src/graph-builder.d.ts.map +1 -1
  17. package/dist/types/src/graph.d.ts +2 -2
  18. package/dist/types/src/graph.d.ts.map +1 -1
  19. package/dist/types/src/index.d.ts +1 -0
  20. package/dist/types/src/index.d.ts.map +1 -1
  21. package/dist/types/src/node-matcher.d.ts +44 -18
  22. package/dist/types/src/node-matcher.d.ts.map +1 -1
  23. package/dist/types/src/node.d.ts +11 -3
  24. package/dist/types/src/node.d.ts.map +1 -1
  25. package/dist/types/src/scheduler.browser.d.ts +2 -0
  26. package/dist/types/src/scheduler.browser.d.ts.map +1 -0
  27. package/dist/types/src/scheduler.d.ts +8 -0
  28. package/dist/types/src/scheduler.d.ts.map +1 -0
  29. package/dist/types/src/stories/EchoGraph.stories.d.ts.map +1 -1
  30. package/dist/types/src/testing/index.d.ts +2 -0
  31. package/dist/types/src/testing/index.d.ts.map +1 -0
  32. package/dist/types/src/testing/setup-graph-builder.d.ts +31 -0
  33. package/dist/types/src/testing/setup-graph-builder.d.ts.map +1 -0
  34. package/dist/types/src/util.d.ts +26 -10
  35. package/dist/types/src/util.d.ts.map +1 -1
  36. package/dist/types/tsconfig.tsbuildinfo +1 -1
  37. package/package.json +38 -27
  38. package/src/graph-builder.test.ts +536 -34
  39. package/src/graph-builder.ts +87 -24
  40. package/src/graph.test.ts +21 -1
  41. package/src/graph.ts +32 -21
  42. package/src/index.ts +1 -0
  43. package/src/node-matcher.ts +59 -27
  44. package/src/node.ts +32 -3
  45. package/src/scheduler.browser.ts +5 -0
  46. package/src/scheduler.ts +17 -0
  47. package/src/stories/EchoGraph.stories.tsx +13 -15
  48. package/src/testing/index.ts +5 -0
  49. package/src/testing/setup-graph-builder.ts +41 -0
  50. package/src/util.ts +59 -13
  51. package/dist/lib/browser/index.mjs.map +0 -7
  52. package/dist/lib/browser/meta.json +0 -1
  53. package/dist/lib/node-esm/index.mjs +0 -1523
  54. package/dist/lib/node-esm/index.mjs.map +0 -7
  55. package/dist/lib/node-esm/meta.json +0 -1
@@ -1,67 +1,6 @@
1
- var __defProp = Object.defineProperty;
2
- var __export = (target, all) => {
3
- for (var name in all)
4
- __defProp(target, name, { get: all[name], enumerable: true });
5
- };
6
-
7
- // src/atoms.ts
8
- var atoms_exports = {};
9
- __export(atoms_exports, {
10
- fromObservable: () => fromObservable
11
- });
12
- import { Atom } from "@effect-atom/atom-react";
13
- var observableFamily = Atom.family((observable) => {
14
- return Atom.make((get2) => {
15
- const subscription = observable.subscribe((value) => get2.setSelf(value));
16
- get2.addFinalizer(() => subscription.unsubscribe());
17
- return observable.get();
18
- });
19
- });
20
- var fromObservable = (observable) => {
21
- return observableFamily(observable);
22
- };
23
-
24
- // src/graph.ts
25
- var graph_exports = {};
26
- __export(graph_exports, {
27
- GraphKind: () => GraphKind,
28
- GraphTypeId: () => GraphTypeId,
29
- addEdge: () => addEdge,
30
- addEdges: () => addEdges,
31
- addNode: () => addNode,
32
- addNodes: () => addNodes,
33
- expand: () => expand,
34
- getActions: () => getActions,
35
- getConnections: () => getConnections,
36
- getEdges: () => getEdges,
37
- getGraph: () => getGraph,
38
- getNode: () => getNode,
39
- getNodeOrThrow: () => getNodeOrThrow,
40
- getPath: () => getPath,
41
- getRoot: () => getRoot,
42
- initialize: () => initialize,
43
- make: () => make,
44
- relationFromKey: () => relationFromKey,
45
- relationKey: () => relationKey,
46
- removeEdge: () => removeEdge,
47
- removeEdges: () => removeEdges,
48
- removeNode: () => removeNode,
49
- removeNodes: () => removeNodes,
50
- sortEdges: () => sortEdges,
51
- toJSON: () => toJSON,
52
- traverse: () => traverse,
53
- waitForPath: () => waitForPath
54
- });
55
- import { Atom as Atom2, Registry } from "@effect-atom/atom-react";
56
- import * as Function from "effect/Function";
57
- import * as Option from "effect/Option";
58
- import * as Pipeable from "effect/Pipeable";
59
- import * as Record from "effect/Record";
60
- import { Event, Trigger } from "@dxos/async";
61
- import { todo } from "@dxos/debug";
62
- import { invariant } from "@dxos/invariant";
63
- import { log } from "@dxos/log";
64
- import { isNonNullable } from "@dxos/util";
1
+ import {
2
+ __export
3
+ } from "./chunk-J5LGTIGS.mjs";
65
4
 
66
5
  // src/node.ts
67
6
  var node_exports = {};
@@ -77,12 +16,15 @@ __export(node_exports, {
77
16
  isActionGroup: () => isActionGroup,
78
17
  isActionLike: () => isActionLike,
79
18
  isGraphNode: () => isGraphNode,
19
+ make: () => make,
20
+ makeAction: () => makeAction,
21
+ makeActionGroup: () => makeActionGroup,
80
22
  relation: () => relation
81
23
  });
82
24
  var RootId = "root";
83
- var RootType = "dxos.org/type/GraphRoot";
84
- var ActionType = "dxos.org/type/GraphAction";
85
- var ActionGroupType = "dxos.org/type/GraphActionGroup";
25
+ var RootType = "org.dxos.type.graphRoot";
26
+ var ActionType = "org.dxos.type.graphAction";
27
+ var ActionGroupType = "org.dxos.type.graphActionGroup";
86
28
  var relation = (kind, direction = "outbound") => ({
87
29
  kind,
88
30
  direction
@@ -94,16 +36,35 @@ var isAction = (data) => isGraphNode(data) ? typeof data.data === "function" &&
94
36
  var actionGroupSymbol = /* @__PURE__ */ Symbol("ActionGroup");
95
37
  var isActionGroup = (data) => isGraphNode(data) ? data.data === actionGroupSymbol && data.type === ActionGroupType : false;
96
38
  var isActionLike = (data) => isAction(data) || isActionGroup(data);
39
+ var make = (arg) => arg;
40
+ var makeAction = (arg) => ({
41
+ ...arg,
42
+ type: ActionType
43
+ });
44
+ var makeActionGroup = (arg) => ({
45
+ ...arg,
46
+ type: ActionGroupType,
47
+ data: actionGroupSymbol
48
+ });
97
49
 
98
50
  // src/util.ts
99
- var Separators = {
100
- primary: "",
101
- secondary: ""
102
- };
51
+ import { invariant } from "@dxos/invariant";
52
+ var __dxlog_file = "/__w/dxos/dxos/packages/sdk/app-graph/src/util.ts";
53
+ var PRIMARY = "";
54
+ var SECONDARY = "";
55
+ var PATH = "/";
56
+ var primaryKey = (...parts) => parts.join(PRIMARY);
57
+ var primaryParts = (key) => key.split(PRIMARY);
58
+ var secondaryKey = (...parts) => parts.join(SECONDARY);
59
+ var secondaryParts = (key) => key.split(SECONDARY);
103
60
  var normalizeRelation = (relation2) => relation2 == null ? childRelation() : typeof relation2 === "string" ? relation(relation2) : relation2;
104
61
  var shallowEqual = (a, b) => {
105
- if (a === b) return true;
106
- if (a == null || b == null || typeof a !== "object" || typeof b !== "object") return false;
62
+ if (a === b) {
63
+ return true;
64
+ }
65
+ if (a == null || b == null || typeof a !== "object" || typeof b !== "object") {
66
+ return false;
67
+ }
107
68
  const keysA = Object.keys(a);
108
69
  const keysB = Object.keys(b);
109
70
  if (keysA.length !== keysB.length) {
@@ -117,24 +78,70 @@ var nodeArgsUnchanged = (prev, next) => {
117
78
  }
118
79
  return prev.every((prevNode, idx) => {
119
80
  const nextNode = next[idx];
120
- return prevNode.id === nextNode.id && prevNode.type === nextNode.type && shallowEqual(prevNode.data, nextNode.data) && shallowEqual(prevNode.properties, nextNode.properties);
81
+ return prevNode.id === nextNode.id && prevNode.type === nextNode.type && shallowEqual(prevNode.data, nextNode.data) && shallowEqual(prevNode.properties, nextNode.properties) && nodeArgsUnchanged(prevNode.nodes ?? [], nextNode.nodes ?? []);
121
82
  });
122
83
  };
84
+ var qualifyId = (parentId, ...segmentIds) => [
85
+ parentId,
86
+ ...segmentIds
87
+ ].join(PATH);
88
+ var validateSegmentId = (id) => {
89
+ invariant(!id.includes(PATH), `Node segment ID must not contain '${PATH}': ${id}`, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 56, S: void 0, A: ["!id.includes(PATH)", "`Node segment ID must not contain '${PATH}': ${id}`"] });
90
+ };
91
+ var getParentId = (qualifiedId) => {
92
+ const lastSlash = qualifiedId.lastIndexOf(PATH);
93
+ return lastSlash > 0 ? qualifiedId.slice(0, lastSlash) : void 0;
94
+ };
95
+ var getSegmentId = (qualifiedId) => {
96
+ return qualifiedId.split(PATH).pop() ?? qualifiedId;
97
+ };
123
98
 
124
99
  // src/graph.ts
125
- var __dxlog_file = "/__w/dxos/dxos/packages/sdk/app-graph/src/graph.ts";
100
+ var graph_exports = {};
101
+ __export(graph_exports, {
102
+ GraphKind: () => GraphKind,
103
+ GraphTypeId: () => GraphTypeId,
104
+ addEdge: () => addEdge,
105
+ addEdges: () => addEdges,
106
+ addNode: () => addNode,
107
+ addNodes: () => addNodes,
108
+ expand: () => expand,
109
+ getActions: () => getActions,
110
+ getConnections: () => getConnections,
111
+ getEdges: () => getEdges,
112
+ getGraph: () => getGraph,
113
+ getNode: () => getNode,
114
+ getNodeOrThrow: () => getNodeOrThrow,
115
+ getPath: () => getPath,
116
+ getRoot: () => getRoot,
117
+ initialize: () => initialize,
118
+ make: () => make2,
119
+ relationFromKey: () => relationFromKey,
120
+ relationKey: () => relationKey,
121
+ removeEdge: () => removeEdge,
122
+ removeEdges: () => removeEdges,
123
+ removeNode: () => removeNode,
124
+ removeNodes: () => removeNodes,
125
+ sortEdges: () => sortEdges,
126
+ toJSON: () => toJSON,
127
+ traverse: () => traverse,
128
+ waitForPath: () => waitForPath
129
+ });
130
+ import { Atom, Registry } from "@effect-atom/atom-react";
131
+ import * as Function from "effect/Function";
132
+ import * as Option from "effect/Option";
133
+ import * as Pipeable from "effect/Pipeable";
134
+ import * as Record from "effect/Record";
135
+ import { Event, Trigger } from "@dxos/async";
136
+ import { todo } from "@dxos/debug";
137
+ import { invariant as invariant2 } from "@dxos/invariant";
138
+ import { log } from "@dxos/log";
139
+ import { isNonNullable } from "@dxos/util";
140
+ var __dxlog_file2 = "/__w/dxos/dxos/packages/sdk/app-graph/src/graph.ts";
126
141
  var graphSymbol = /* @__PURE__ */ Symbol("graph");
127
142
  var getGraph = (node) => {
128
143
  const graph = node[graphSymbol];
129
- invariant(graph, "Node is not associated with a graph.", {
130
- F: __dxlog_file,
131
- L: 33,
132
- S: void 0,
133
- A: [
134
- "graph",
135
- "'Node is not associated with a graph.'"
136
- ]
137
- });
144
+ invariant2(graph, "Node is not associated with a graph.", { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 21, S: void 0, A: ["graph", "'Node is not associated with a graph.'"] });
138
145
  return graph;
139
146
  };
140
147
  var GraphTypeId = /* @__PURE__ */ Symbol.for("@dxos/app-graph/Graph");
@@ -166,45 +173,44 @@ var GraphImpl = class {
166
173
  ]
167
174
  ]);
168
175
  /** @internal */
169
- _node = Atom2.family((id) => {
176
+ _node = Atom.family((id) => {
170
177
  const initial = Option.flatten(Record.get(this._initialNodes, id));
171
- return Atom2.make(initial).pipe(Atom2.keepAlive, Atom2.withLabel(`graph:node:${id}`));
178
+ return Atom.make(initial).pipe(Atom.keepAlive, Atom.withLabel(`graph:node:${id}`));
172
179
  });
173
- _nodeOrThrow = Atom2.family((id) => {
174
- return Atom2.make((get2) => {
180
+ _nodeOrThrow = Atom.family((id) => {
181
+ return Atom.make((get2) => {
175
182
  const node = get2(this._node(id));
176
- invariant(Option.isSome(node), `Node not available: ${id}`, {
177
- F: __dxlog_file,
178
- L: 172,
179
- S: this,
180
- A: [
181
- "Option.isSome(node)",
182
- "`Node not available: ${id}`"
183
- ]
184
- });
183
+ invariant2(Option.isSome(node), `Node not available: ${id}`, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 67, S: this, A: ["Option.isSome(node)", "`Node not available: ${id}`"] });
185
184
  return node.value;
186
185
  });
187
186
  });
188
- _edges = Atom2.family((id) => {
187
+ _edges = Atom.family((id) => {
189
188
  const initial = Record.get(this._initialEdges, id).pipe(Option.getOrElse(() => ({})));
190
- return Atom2.make(initial).pipe(Atom2.keepAlive, Atom2.withLabel(`graph:edges:${id}`));
189
+ return Atom.make(initial).pipe(Atom.keepAlive, Atom.withLabel(`graph:edges:${id}`));
191
190
  });
192
191
  // NOTE: Currently the argument to the family needs to be referentially stable for the atom to be referentially stable.
193
192
  // TODO(wittjosiah): Atom feature request, support for something akin to `ComplexMap` to allow for complex arguments.
194
- _connections = Atom2.family((key) => {
195
- return Atom2.make((get2) => {
193
+ _connections = Atom.family((key) => {
194
+ return Atom.make((get2) => {
195
+ const parts = key ? primaryParts(key) : [];
196
+ if (parts.length < 2 || !parts[0]) {
197
+ return [];
198
+ }
196
199
  const { id, relation: relation2 } = relationFromConnectionKey(key);
197
200
  const edges = get2(this._edges(id));
198
201
  return (edges[relationKey(relation2)] ?? []).map((id2) => get2(this._node(id2))).filter(Option.isSome).map((o) => o.value);
199
- }).pipe(Atom2.withLabel(`graph:connections:${key}`));
202
+ }).pipe(Atom.withLabel(`graph:connections:${key}`));
200
203
  });
201
- _actions = Atom2.family((id) => {
202
- return Atom2.make((get2) => {
204
+ _actions = Atom.family((id) => {
205
+ return Atom.make((get2) => {
206
+ if (!id) {
207
+ return [];
208
+ }
203
209
  return get2(this._connections(connectionKey(id, actionRelation())));
204
- }).pipe(Atom2.withLabel(`graph:actions:${id}`));
210
+ }).pipe(Atom.withLabel(`graph:actions:${id}`));
205
211
  });
206
- _json = Atom2.family((id) => {
207
- return Atom2.make((get2) => {
212
+ _json = Atom.family((id) => {
213
+ return Atom.make((get2) => {
208
214
  const toJSON2 = (node, seen = []) => {
209
215
  const nodes = get2(this._connections(connectionKey(node.id, "child")));
210
216
  const obj = {
@@ -227,7 +233,7 @@ var GraphImpl = class {
227
233
  };
228
234
  const root = get2(this._nodeOrThrow(id));
229
235
  return toJSON2(root);
230
- }).pipe(Atom2.withLabel(`graph:json:${id}`));
236
+ }).pipe(Atom.withLabel(`graph:json:${id}`));
231
237
  });
232
238
  constructor({ registry, nodes, edges, onInitialize, onExpand, onRemoveNode } = {}) {
233
239
  this._registry = registry ?? Registry.make();
@@ -345,15 +351,7 @@ function getConnections(graphOrId, idOrRelation, relation2) {
345
351
  } else {
346
352
  const graph = graphOrId;
347
353
  const id = idOrRelation;
348
- invariant(relation2 !== void 0, "Relation is required.", {
349
- F: __dxlog_file,
350
- L: 440,
351
- S: this,
352
- A: [
353
- "relation !== undefined",
354
- "'Relation is required.'"
355
- ]
356
- });
354
+ invariant2(relation2 !== void 0, "Relation is required.", { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 272, S: this, A: ["relation !== undefined", "'Relation is required.'"] });
357
355
  const rel = relation2;
358
356
  return getConnectionsImpl(graph, id, rel);
359
357
  }
@@ -397,14 +395,25 @@ var traverseImpl = (graph, options, path = []) => {
397
395
  if (shouldContinue === false) {
398
396
  return;
399
397
  }
400
- Object.values(getConnections(graph, source, relation2)).forEach((child) => traverseImpl(graph, {
401
- source: child.id,
402
- relation: relation2,
403
- visitor
404
- }, [
405
- ...path,
406
- source
407
- ]));
398
+ const relations = Array.isArray(relation2) ? relation2 : [
399
+ relation2
400
+ ];
401
+ const seen = /* @__PURE__ */ new Set();
402
+ for (const rel of relations) {
403
+ for (const connected of getConnections(graph, source, rel)) {
404
+ if (!seen.has(connected.id)) {
405
+ seen.add(connected.id);
406
+ traverseImpl(graph, {
407
+ source: connected.id,
408
+ relation: relation2,
409
+ visitor
410
+ }, [
411
+ ...path,
412
+ source
413
+ ]);
414
+ }
415
+ }
416
+ }
408
417
  };
409
418
  function traverse(graphOrOptions, optionsOrPath, path) {
410
419
  if (typeof graphOrOptions === "object" && "visitor" in graphOrOptions) {
@@ -479,12 +488,7 @@ var initializeImpl = async (graph, id) => {
479
488
  log("initialize", {
480
489
  id,
481
490
  initialized
482
- }, {
483
- F: __dxlog_file,
484
- L: 655,
485
- S: void 0,
486
- C: (f, a) => f(...a)
487
- });
491
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 431, S: void 0 });
488
492
  if (!initialized) {
489
493
  Record.set(internal._initialized, id, true);
490
494
  await internal._onInitialize?.(id);
@@ -503,31 +507,21 @@ function initialize(graphOrId, id) {
503
507
  var expandImpl = (graph, id, relation2) => {
504
508
  const internal = getInternal(graph);
505
509
  const normalizedRelation = normalizeRelation(relation2);
506
- const key = `${id}${Separators.primary}${relationKey(normalizedRelation)}`;
510
+ const key = primaryKey(id, relationKey(normalizedRelation));
507
511
  const nodeOpt = internal._registry.get(internal._node(id));
508
512
  if (Option.isNone(nodeOpt)) {
509
513
  internal._pendingExpands.add(key);
510
514
  log("expand", {
511
515
  key,
512
516
  deferred: true
513
- }, {
514
- F: __dxlog_file,
515
- L: 701,
516
- S: void 0,
517
- C: (f, a) => f(...a)
518
- });
517
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 463, S: void 0 });
519
518
  return graph;
520
519
  }
521
520
  const expanded = Record.get(internal._expanded, key).pipe(Option.getOrElse(() => false));
522
521
  log("expand", {
523
522
  key,
524
523
  expanded
525
- }, {
526
- F: __dxlog_file,
527
- L: 706,
528
- S: void 0,
529
- C: (f, a) => f(...a)
530
- });
524
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 470, S: void 0 });
531
525
  if (!expanded) {
532
526
  Record.set(internal._expanded, key, true);
533
527
  internal._onExpand?.(id, normalizedRelation);
@@ -542,15 +536,7 @@ function expand(graphOrId, idOrRelation, relation2) {
542
536
  } else {
543
537
  const graph = graphOrId;
544
538
  const id = idOrRelation;
545
- invariant(relation2 !== void 0, "Relation is required.", {
546
- F: __dxlog_file,
547
- L: 742,
548
- S: this,
549
- A: [
550
- "relation !== undefined",
551
- "'Relation is required.'"
552
- ]
553
- });
539
+ invariant2(relation2 !== void 0, "Relation is required.", { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 490, S: this, A: ["relation !== undefined", "'Relation is required.'"] });
554
540
  const rel = relation2;
555
541
  return expandImpl(graph, id, rel);
556
542
  }
@@ -590,7 +576,7 @@ function sortEdges(graphOrId, idOrRelation, relationOrOrder, order) {
590
576
  }
591
577
  }
592
578
  var addNodesImpl = (graph, nodes) => {
593
- Atom2.batch(() => {
579
+ Atom.batch(() => {
594
580
  nodes.map((node) => addNodeImpl(graph, node));
595
581
  });
596
582
  return graph;
@@ -619,24 +605,14 @@ var addNodeImpl = (graph, nodeArg) => {
619
605
  typeChanged,
620
606
  dataChanged,
621
607
  propertiesChanged
622
- }, {
623
- F: __dxlog_file,
624
- L: 864,
625
- S: void 0,
626
- C: (f, a) => f(...a)
627
- });
608
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 565, S: void 0 });
628
609
  if (typeChanged || dataChanged || propertiesChanged) {
629
610
  log("updating node", {
630
611
  id,
631
612
  type,
632
613
  data,
633
614
  properties
634
- }, {
635
- F: __dxlog_file,
636
- L: 871,
637
- S: void 0,
638
- C: (f, a) => f(...a)
639
- });
615
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 572, S: void 0 });
640
616
  const newNode = Option.some({
641
617
  ...existing,
642
618
  ...rest,
@@ -660,12 +636,7 @@ var addNodeImpl = (graph, nodeArg) => {
660
636
  type,
661
637
  data,
662
638
  properties
663
- }, {
664
- F: __dxlog_file,
665
- L: 884,
666
- S: void 0,
667
- C: (f, a) => f(...a)
668
- });
639
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 596, S: void 0 });
669
640
  const newNode = internal._constructNode({
670
641
  id,
671
642
  type,
@@ -678,13 +649,12 @@ var addNodeImpl = (graph, nodeArg) => {
678
649
  id,
679
650
  node: newNode
680
651
  });
681
- const prefix = `${id}${Separators.primary}`;
682
652
  const toApply = [
683
653
  ...internal._pendingExpands
684
- ].filter((k) => k.startsWith(prefix));
654
+ ].filter((k) => primaryParts(k)[0] === id);
685
655
  for (const pendingKey of toApply) {
686
656
  internal._pendingExpands.delete(pendingKey);
687
- const relation2 = relationFromKey(pendingKey.slice(prefix.length));
657
+ const relation2 = relationFromKey(primaryParts(pendingKey)[1]);
688
658
  Record.set(internal._expanded, pendingKey, true);
689
659
  internal._onExpand?.(id, relation2);
690
660
  }
@@ -714,7 +684,7 @@ function addNode(graphOrNodeArg, nodeArg) {
714
684
  }
715
685
  }
716
686
  var removeNodesImpl = (graph, ids, edges = false) => {
717
- Atom2.batch(() => {
687
+ Atom.batch(() => {
718
688
  ids.map((id) => removeNodeImpl(graph, id, edges));
719
689
  });
720
690
  return graph;
@@ -779,7 +749,7 @@ function removeNode(graphOrId, idOrEdges, edges) {
779
749
  }
780
750
  }
781
751
  var addEdgesImpl = (graph, edges) => {
782
- Atom2.batch(() => {
752
+ Atom.batch(() => {
783
753
  edges.map((edge) => addEdgeImpl(graph, edge));
784
754
  });
785
755
  return graph;
@@ -807,12 +777,7 @@ var addEdgeImpl = (graph, edgeArg) => {
807
777
  source: edgeArg.source,
808
778
  target: edgeArg.target,
809
779
  relation: relationId
810
- }, {
811
- F: __dxlog_file,
812
- L: 1068,
813
- S: void 0,
814
- C: (f, a) => f(...a)
815
- });
780
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 758, S: void 0 });
816
781
  internal._registry.set(sourceAtom, {
817
782
  ...source,
818
783
  [relationId]: [
@@ -829,12 +794,7 @@ var addEdgeImpl = (graph, edgeArg) => {
829
794
  source: edgeArg.source,
830
795
  target: edgeArg.target,
831
796
  relation: inverseId
832
- }, {
833
- F: __dxlog_file,
834
- L: 1076,
835
- S: void 0,
836
- C: (f, a) => f(...a)
837
- });
797
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 775, S: void 0 });
838
798
  internal._registry.set(targetAtom, {
839
799
  ...target,
840
800
  [inverseId]: [
@@ -855,7 +815,7 @@ function addEdge(graphOrEdgeArg, edgeArg) {
855
815
  }
856
816
  }
857
817
  var removeEdgesImpl = (graph, edges, removeOrphans = false) => {
858
- Atom2.batch(() => {
818
+ Atom.batch(() => {
859
819
  edges.map((edge) => removeEdgeImpl(graph, edge, removeOrphans));
860
820
  });
861
821
  return graph;
@@ -925,51 +885,24 @@ function removeEdge(graphOrEdgeArg, edgeArgOrRemoveOrphans, removeOrphans) {
925
885
  return removeEdgeImpl(graph, edgeArg, removeOrphansArg);
926
886
  }
927
887
  }
928
- var make = (params) => {
888
+ var make2 = (params) => {
929
889
  return new GraphImpl(params);
930
890
  };
931
891
  var relationKey = (relation2) => {
932
892
  const normalized = normalizeRelation(relation2);
933
- return `${normalized.kind}${Separators.secondary}${normalized.direction}`;
893
+ return secondaryKey(normalized.kind, normalized.direction);
934
894
  };
935
895
  var relationFromKey = (encoded) => {
936
- const separatorIndex = encoded.lastIndexOf(Separators.secondary);
937
- invariant(separatorIndex > 0 && separatorIndex < encoded.length - 1, `Invalid relation key: ${encoded}`, {
938
- F: __dxlog_file,
939
- L: 1221,
940
- S: void 0,
941
- A: [
942
- "separatorIndex > 0 && separatorIndex < encoded.length - 1",
943
- "`Invalid relation key: ${encoded}`"
944
- ]
945
- });
946
- const kind = encoded.slice(0, separatorIndex);
947
- const directionRaw = encoded.slice(separatorIndex + 1);
948
- invariant(directionRaw === "outbound" || directionRaw === "inbound", `Invalid relation direction: ${directionRaw}`, {
949
- F: __dxlog_file,
950
- L: 1224,
951
- S: void 0,
952
- A: [
953
- "directionRaw === 'outbound' || directionRaw === 'inbound'",
954
- "`Invalid relation direction: ${directionRaw}`"
955
- ]
956
- });
896
+ const parts = secondaryParts(encoded);
897
+ invariant2(parts.length === 2 && parts[0].length > 0 && parts[1].length > 0, `Invalid relation key: ${encoded}`, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 894, S: void 0, A: ["parts.length === 2 && parts[0].length > 0 && parts[1].length > 0", "`Invalid relation key: ${encoded}`"] });
898
+ const [kind, directionRaw] = parts;
899
+ invariant2(directionRaw === "outbound" || directionRaw === "inbound", `Invalid relation direction: ${directionRaw}`, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 896, S: void 0, A: ["directionRaw === 'outbound' || directionRaw === 'inbound'", "`Invalid relation direction: ${directionRaw}`"] });
957
900
  return relation(kind, directionRaw);
958
901
  };
959
- var connectionKey = (id, relation2) => `${id}${Separators.primary}${relationKey(relation2)}`;
902
+ var connectionKey = (id, relation2) => primaryKey(id, relationKey(relation2));
960
903
  var relationFromConnectionKey = (key) => {
961
- const separatorIndex = key.indexOf(Separators.primary);
962
- invariant(separatorIndex > 0 && separatorIndex < key.length - 1, `Invalid connection key: ${key}`, {
963
- F: __dxlog_file,
964
- L: 1233,
965
- S: void 0,
966
- A: [
967
- "separatorIndex > 0 && separatorIndex < key.length - 1",
968
- "`Invalid connection key: ${key}`"
969
- ]
970
- });
971
- const id = key.slice(0, separatorIndex);
972
- const encodedRelation = key.slice(separatorIndex + 1);
904
+ const [id, encodedRelation] = primaryParts(key);
905
+ invariant2(id && encodedRelation, `Invalid connection key: ${key}`, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 902, S: void 0, A: ["id && encodedRelation", "`Invalid connection key: ${key}`"] });
973
906
  return {
974
907
  id,
975
908
  relation: relationFromKey(encodedRelation)
@@ -980,34 +913,6 @@ var inverseRelation = (relation2) => {
980
913
  return relation(normalized.kind, normalized.direction === "outbound" ? "inbound" : "outbound");
981
914
  };
982
915
 
983
- // src/graph-builder.ts
984
- var graph_builder_exports = {};
985
- __export(graph_builder_exports, {
986
- GraphBuilderTypeId: () => GraphBuilderTypeId,
987
- addExtension: () => addExtension,
988
- createConnector: () => createConnector,
989
- createExtension: () => createExtension,
990
- createExtensionRaw: () => createExtensionRaw,
991
- createTypeExtension: () => createTypeExtension,
992
- destroy: () => destroy,
993
- explore: () => explore,
994
- flattenExtensions: () => flattenExtensions,
995
- flush: () => flush,
996
- from: () => from,
997
- make: () => make2,
998
- removeExtension: () => removeExtension
999
- });
1000
- import { Atom as Atom3, Registry as Registry2 } from "@effect-atom/atom-react";
1001
- import * as Array2 from "effect/Array";
1002
- import * as Effect from "effect/Effect";
1003
- import * as Function2 from "effect/Function";
1004
- import * as Option3 from "effect/Option";
1005
- import * as Pipeable2 from "effect/Pipeable";
1006
- import * as Record2 from "effect/Record";
1007
- import { scheduleTask, yieldOrContinue } from "main-thread-scheduling";
1008
- import { log as log2 } from "@dxos/log";
1009
- import { byPosition, getDebugName, isNonNullable as isNonNullable2 } from "@dxos/util";
1010
-
1011
916
  // src/node-matcher.ts
1012
917
  var node_matcher_exports = {};
1013
918
  __export(node_matcher_exports, {
@@ -1030,17 +935,23 @@ var whenNodeType = (type) => (node) => node.type === type ? Option2.some(node) :
1030
935
  var whenEchoType = (type) => (node) => Obj.instanceOf(type, node.data) ? Option2.some(node.data) : Option2.none();
1031
936
  var whenEchoObject = (node) => Obj.isObject(node.data) ? Option2.some(node.data) : Option2.none();
1032
937
  var whenAll = (...matchers) => (node) => {
938
+ let first = Option2.none();
1033
939
  for (const candidate of matchers) {
1034
- if (Option2.isNone(candidate(node))) {
940
+ const result = candidate(node);
941
+ if (Option2.isNone(result)) {
1035
942
  return Option2.none();
1036
943
  }
944
+ if (Option2.isNone(first)) {
945
+ first = result;
946
+ }
1037
947
  }
1038
- return Option2.some(node);
948
+ return first;
1039
949
  };
1040
950
  var whenAny = (...matchers) => (node) => {
1041
951
  for (const candidate of matchers) {
1042
- if (Option2.isSome(candidate(node))) {
1043
- return Option2.some(node);
952
+ const result = candidate(node);
953
+ if (Option2.isSome(result)) {
954
+ return result;
1044
955
  }
1045
956
  }
1046
957
  return Option2.none();
@@ -1050,7 +961,33 @@ var whenEchoObjectMatches = (node) => Obj.isObject(node.data) ? Option2.some(nod
1050
961
  var whenNot = (matcher) => (node) => Option2.isNone(matcher(node)) ? Option2.some(node) : Option2.none();
1051
962
 
1052
963
  // src/graph-builder.ts
1053
- var __dxlog_file2 = "/__w/dxos/dxos/packages/sdk/app-graph/src/graph-builder.ts";
964
+ var graph_builder_exports = {};
965
+ __export(graph_builder_exports, {
966
+ GraphBuilderTypeId: () => GraphBuilderTypeId,
967
+ addExtension: () => addExtension,
968
+ createConnector: () => createConnector,
969
+ createExtension: () => createExtension,
970
+ createExtensionRaw: () => createExtensionRaw,
971
+ createTypeExtension: () => createTypeExtension,
972
+ destroy: () => destroy,
973
+ explore: () => explore,
974
+ flattenExtensions: () => flattenExtensions,
975
+ flush: () => flush,
976
+ from: () => from,
977
+ make: () => make3,
978
+ removeExtension: () => removeExtension
979
+ });
980
+ import { Atom as Atom2, Registry as Registry2 } from "@effect-atom/atom-react";
981
+ import * as Array2 from "effect/Array";
982
+ import * as Effect from "effect/Effect";
983
+ import * as Function2 from "effect/Function";
984
+ import * as Option3 from "effect/Option";
985
+ import * as Pipeable2 from "effect/Pipeable";
986
+ import * as Record2 from "effect/Record";
987
+ import { log as log2 } from "@dxos/log";
988
+ import { byPosition, getDebugName, isNonNullable as isNonNullable2 } from "@dxos/util";
989
+ import { scheduleTask, yieldOrContinue } from "#scheduler";
990
+ var __dxlog_file3 = "/__w/dxos/dxos/packages/sdk/app-graph/src/graph-builder.ts";
1054
991
  var GraphBuilderTypeId = /* @__PURE__ */ Symbol.for("@dxos/app-graph/GraphBuilder");
1055
992
  var GraphBuilderImpl = class {
1056
993
  [GraphBuilderTypeId] = GraphBuilderTypeId;
@@ -1058,19 +995,31 @@ var GraphBuilderImpl = class {
1058
995
  return Pipeable2.pipeArguments(this, arguments);
1059
996
  }
1060
997
  // TODO(wittjosiah): Use Context.
998
+ /** Active subscriptions keyed by composite ID, cleaned up on node removal. */
1061
999
  _subscriptions = /* @__PURE__ */ new Map();
1000
+ /** Connector updates pending flush, keyed by connector key. */
1062
1001
  _dirtyConnectors = /* @__PURE__ */ new Map();
1002
+ /** Last-flushed node IDs per connector key, used for edge removal on update. */
1063
1003
  _connectorPrevious = /* @__PURE__ */ new Map();
1004
+ /** All inline-descendant IDs per connector key, used to remove stale inline nodes on update. */
1005
+ _connectorPreviousInlineIds = /* @__PURE__ */ new Map();
1006
+ /** Last-flushed node args per connector key, used for change detection. */
1064
1007
  _connectorPreviousArgs = /* @__PURE__ */ new Map();
1008
+ /** Whether a dirty-flush task is already scheduled. */
1065
1009
  _flushScheduled = false;
1010
+ /** Resolves when the current flush completes. */
1066
1011
  _flushPromise = Promise.resolve();
1067
- _extensions = Atom3.make(Record2.empty()).pipe(Atom3.keepAlive, Atom3.withLabel("graph-builder:extensions"));
1012
+ /** Registered builder extensions keyed by extension ID. */
1013
+ _extensions = Atom2.make(Record2.empty()).pipe(Atom2.keepAlive, Atom2.withLabel("graph-builder:extensions"));
1014
+ /** Triggers signalling that a node's resolver has fired at least once. */
1068
1015
  _initialized = {};
1016
+ /** Shared atom registry for reactive subscriptions. */
1069
1017
  _registry;
1018
+ /** Backing graph with internal accessors for node atoms and construction. */
1070
1019
  _graph;
1071
1020
  constructor({ registry, ...params } = {}) {
1072
1021
  this._registry = registry ?? Registry2.make();
1073
- const graph = make({
1022
+ const graph = make2({
1074
1023
  ...params,
1075
1024
  registry: this._registry,
1076
1025
  onExpand: (id, relation2) => this._onExpand(id, relation2),
@@ -1092,6 +1041,11 @@ var GraphBuilderImpl = class {
1092
1041
  const removed = previous.filter((pid) => !ids.includes(pid));
1093
1042
  this._connectorPrevious.set(key, ids);
1094
1043
  this._connectorPreviousArgs.set(key, nodes);
1044
+ const currentInlineIds = collectAllInlineIds(nodes);
1045
+ const previousInlineIds = this._connectorPreviousInlineIds.get(key) ?? [];
1046
+ const staleInlineIds = previousInlineIds.filter((pid) => !currentInlineIds.includes(pid));
1047
+ this._connectorPreviousInlineIds.set(key, currentInlineIds);
1048
+ removeNodes(this._graph, staleInlineIds, true);
1095
1049
  removeEdges(this._graph, removed.map((target) => ({
1096
1050
  source: id,
1097
1051
  target,
@@ -1120,7 +1074,7 @@ var GraphBuilderImpl = class {
1120
1074
  ...this._dirtyConnectors.entries()
1121
1075
  ];
1122
1076
  this._dirtyConnectors.clear();
1123
- Atom3.batch(() => {
1077
+ Atom2.batch(() => {
1124
1078
  for (const [key, { nodes, previous }] of entries) {
1125
1079
  this._applyConnectorUpdate(key, nodes, previous);
1126
1080
  }
@@ -1131,13 +1085,13 @@ var GraphBuilderImpl = class {
1131
1085
  });
1132
1086
  }
1133
1087
  }
1134
- _resolvers = Atom3.family((id) => {
1135
- return Atom3.make((get2) => {
1088
+ _resolvers = Atom2.family((id) => {
1089
+ return Atom2.make((get2) => {
1136
1090
  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);
1137
1091
  });
1138
1092
  });
1139
- _connectors = Atom3.family((key) => {
1140
- return Atom3.make((get2) => {
1093
+ _connectors = Atom2.family((key) => {
1094
+ return Atom2.make((get2) => {
1141
1095
  const { id, relation: relation2 } = relationFromConnectorKey(key);
1142
1096
  const node = this._graph.node(id);
1143
1097
  const sourceNode = Option3.getOrElse(get2(node), () => void 0);
@@ -1151,19 +1105,14 @@ var GraphBuilderImpl = class {
1151
1105
  nodes.push(...result);
1152
1106
  }
1153
1107
  return nodes;
1154
- }).pipe(Atom3.withLabel(`graph-builder:connectors:${key}`));
1108
+ }).pipe(Atom2.withLabel(`graph-builder:connectors:${key}`));
1155
1109
  });
1156
1110
  _onExpand(id, relation2) {
1157
1111
  log2("onExpand", {
1158
1112
  id,
1159
1113
  relation: relation2,
1160
1114
  registry: getDebugName(this._registry)
1161
- }, {
1162
- F: __dxlog_file2,
1163
- L: 251,
1164
- S: this,
1165
- C: (f, a) => f(...a)
1166
- });
1115
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 136, S: this });
1167
1116
  this._expandRelation(id, relation2);
1168
1117
  if (relation2.kind === "child" && relation2.direction === "outbound") {
1169
1118
  expand(this._graph, id, "action");
@@ -1172,7 +1121,8 @@ var GraphBuilderImpl = class {
1172
1121
  _expandRelation(id, relation2) {
1173
1122
  const key = connectorKey(id, relation2);
1174
1123
  const connectors = this._connectors(key);
1175
- const cancel = this._registry.subscribe(connectors, (nodes) => {
1124
+ const cancel = this._registry.subscribe(connectors, (rawNodes) => {
1125
+ const nodes = qualifyNodeArgs(id)(rawNodes);
1176
1126
  const previous = this._connectorPrevious.get(key) ?? [];
1177
1127
  const ids = nodes.map((n) => n.id);
1178
1128
  if (ids.length === previous.length && ids.every((nodeId, idx) => nodeId === previous[idx])) {
@@ -1185,12 +1135,7 @@ var GraphBuilderImpl = class {
1185
1135
  id,
1186
1136
  relation: relation2,
1187
1137
  ids
1188
- }, {
1189
- F: __dxlog_file2,
1190
- L: 277,
1191
- S: this,
1192
- C: (f, a) => f(...a)
1193
- });
1138
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 160, S: this });
1194
1139
  this._dirtyConnectors.set(key, {
1195
1140
  nodes,
1196
1141
  previous
@@ -1201,31 +1146,42 @@ var GraphBuilderImpl = class {
1201
1146
  });
1202
1147
  this._subscriptions.set(subscriptionKey(id, "expand", key), cancel);
1203
1148
  }
1204
- // TODO(wittjosiah): If the same node is added by a connector, the resolver should probably cancel itself?
1205
1149
  async _onInitialize(id) {
1206
1150
  log2("onInitialize", {
1207
1151
  id
1208
- }, {
1209
- F: __dxlog_file2,
1210
- L: 289,
1211
- S: this,
1212
- C: (f, a) => f(...a)
1213
- });
1152
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 176, S: this });
1214
1153
  const resolver = this._resolvers(id);
1215
1154
  const cancel = this._registry.subscribe(resolver, (node) => {
1216
1155
  const trigger = this._initialized[id];
1156
+ const connectorOwned = [
1157
+ ...this._connectorPrevious.values()
1158
+ ].some((ids) => ids.includes(id));
1217
1159
  Option3.match(node, {
1218
1160
  onSome: (node2) => {
1219
- addNodes(this._graph, [
1220
- node2
1221
- ]);
1161
+ if (!connectorOwned) {
1162
+ addNodes(this._graph, [
1163
+ node2
1164
+ ]);
1165
+ const parentId = getParentId(id);
1166
+ if (parentId) {
1167
+ addEdges(this._graph, [
1168
+ {
1169
+ source: parentId,
1170
+ target: id,
1171
+ relation: "child"
1172
+ }
1173
+ ]);
1174
+ }
1175
+ }
1222
1176
  trigger?.wake();
1223
1177
  },
1224
1178
  onNone: () => {
1225
1179
  trigger?.wake();
1226
- removeNodes(this._graph, [
1227
- id
1228
- ]);
1180
+ if (!connectorOwned) {
1181
+ removeNodes(this._graph, [
1182
+ id
1183
+ ]);
1184
+ }
1229
1185
  }
1230
1186
  });
1231
1187
  }, {
@@ -1234,26 +1190,25 @@ var GraphBuilderImpl = class {
1234
1190
  this._subscriptions.set(subscriptionKey(id, "init"), cancel);
1235
1191
  }
1236
1192
  _onRemoveNode(id) {
1237
- const prefix = `${id}${Separators.primary}`;
1238
1193
  for (const [key, cleanup] of this._subscriptions) {
1239
- if (key.startsWith(prefix)) {
1194
+ if (primaryParts(key)[0] === id) {
1240
1195
  cleanup();
1241
1196
  this._subscriptions.delete(key);
1242
1197
  }
1243
1198
  }
1244
1199
  }
1245
1200
  };
1246
- var make2 = (params) => {
1201
+ var make3 = (params) => {
1247
1202
  return new GraphBuilderImpl(params);
1248
1203
  };
1249
1204
  var from = (pickle, registry) => {
1250
1205
  if (!pickle) {
1251
- return make2({
1206
+ return make3({
1252
1207
  registry
1253
1208
  });
1254
1209
  }
1255
1210
  const { nodes, edges } = JSON.parse(pickle);
1256
- return make2({
1211
+ return make3({
1257
1212
  nodes,
1258
1213
  edges,
1259
1214
  registry
@@ -1306,7 +1261,7 @@ var exploreImpl = async (builder, options, path = []) => {
1306
1261
  if (shouldContinue === false) {
1307
1262
  return;
1308
1263
  }
1309
- const nodes = Object.values(internal._registry.get(internal._extensions)).filter((extension) => relationKey(extension.relation ?? "child") === relationKey(relation2)).map((extension) => extension.connector).filter(isNonNullable2).flatMap((connector) => registry.get(connector(internal._graph.node(source))));
1264
+ const nodes = Function2.pipe(internal._registry.get(internal._extensions), Record2.values, Array2.map((extension) => extension.connector), Array2.filter(isNonNullable2), Array2.flatMap((connector) => registry.get(connector(internal._graph.node(source)))), qualifyNodeArgs(source));
1310
1265
  await Promise.all(nodes.map((nodeArg) => {
1311
1266
  registry.set(internal._graph._node(nodeArg.id), internal._graph._constructNode(nodeArg));
1312
1267
  return exploreImpl(builder, {
@@ -1352,13 +1307,13 @@ var flush = (builder) => {
1352
1307
  return builder._flushPromise;
1353
1308
  };
1354
1309
  var createExtensionRaw = (extension) => {
1355
- const { id, position = "static", relation: relation2 = "child", resolver: _resolver, connector: _connector, actions: _actions, actionGroups: _actionGroups } = extension;
1310
+ const { id, position, relation: relation2 = "child", resolver: _resolver, connector: _connector, actions: _actions, actionGroups: _actionGroups } = extension;
1356
1311
  const normalizedRelation = normalizeRelation(relation2);
1357
1312
  const getId = (key) => `${id}/${key}`;
1358
- const resolver = _resolver && Atom3.family((id2) => _resolver(id2).pipe(Atom3.withLabel(`graph-builder:_resolver:${id2}`)));
1359
- const connector = _connector && Atom3.family((node) => _connector(node).pipe(Atom3.withLabel(`graph-builder:_connector:${id}`)));
1360
- const actionGroups = _actionGroups && Atom3.family((node) => _actionGroups(node).pipe(Atom3.withLabel(`graph-builder:_actionGroups:${id}`)));
1361
- const actions = _actions && Atom3.family((node) => _actions(node).pipe(Atom3.withLabel(`graph-builder:_actions:${id}`)));
1313
+ const resolver = _resolver && Atom2.family((id2) => _resolver(id2).pipe(Atom2.withLabel(`graph-builder:_resolver:${id2}`)));
1314
+ const connector = _connector && Atom2.family((node) => _connector(node).pipe(Atom2.withLabel(`graph-builder:_connector:${id}`)));
1315
+ const actionGroups = _actionGroups && Atom2.family((node) => _actionGroups(node).pipe(Atom2.withLabel(`graph-builder:_actionGroups:${id}`)));
1316
+ const actions = _actions && Atom2.family((node) => _actions(node).pipe(Atom2.withLabel(`graph-builder:_actions:${id}`)));
1362
1317
  return [
1363
1318
  resolver ? {
1364
1319
  id: getId("resolver"),
@@ -1369,7 +1324,7 @@ var createExtensionRaw = (extension) => {
1369
1324
  id: getId("connector"),
1370
1325
  position,
1371
1326
  relation: normalizedRelation,
1372
- connector: Atom3.family((node) => Atom3.make((get2) => {
1327
+ connector: Atom2.family((node) => Atom2.make((get2) => {
1373
1328
  try {
1374
1329
  return get2(connector(node));
1375
1330
  } catch (error) {
@@ -1377,21 +1332,16 @@ var createExtensionRaw = (extension) => {
1377
1332
  id: getId("connector"),
1378
1333
  node,
1379
1334
  error
1380
- }, {
1381
- F: __dxlog_file2,
1382
- L: 579,
1383
- S: void 0,
1384
- C: (f, a) => f(...a)
1385
- });
1335
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 383, S: void 0 });
1386
1336
  return [];
1387
1337
  }
1388
- }).pipe(Atom3.withLabel(`graph-builder:connector:${id}`)))
1338
+ }).pipe(Atom2.withLabel(`graph-builder:connector:${id}`)))
1389
1339
  } : void 0,
1390
1340
  actionGroups ? {
1391
1341
  id: getId("actionGroups"),
1392
1342
  position,
1393
1343
  relation: actionRelation(),
1394
- connector: Atom3.family((node) => Atom3.make((get2) => {
1344
+ connector: Atom2.family((node) => Atom2.make((get2) => {
1395
1345
  try {
1396
1346
  return get2(actionGroups(node)).map((arg) => ({
1397
1347
  ...arg,
@@ -1403,21 +1353,16 @@ var createExtensionRaw = (extension) => {
1403
1353
  id: getId("actionGroups"),
1404
1354
  node,
1405
1355
  error
1406
- }, {
1407
- F: __dxlog_file2,
1408
- L: 600,
1409
- S: void 0,
1410
- C: (f, a) => f(...a)
1411
- });
1356
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 404, S: void 0 });
1412
1357
  return [];
1413
1358
  }
1414
- }).pipe(Atom3.withLabel(`graph-builder:connector:actionGroups:${id}`)))
1359
+ }).pipe(Atom2.withLabel(`graph-builder:connector:actionGroups:${id}`)))
1415
1360
  } : void 0,
1416
1361
  actions ? {
1417
1362
  id: getId("actions"),
1418
1363
  position,
1419
1364
  relation: actionRelation(),
1420
- connector: Atom3.family((node) => Atom3.make((get2) => {
1365
+ connector: Atom2.family((node) => Atom2.make((get2) => {
1421
1366
  try {
1422
1367
  return get2(actions(node)).map((arg) => ({
1423
1368
  ...arg,
@@ -1428,15 +1373,10 @@ var createExtensionRaw = (extension) => {
1428
1373
  id: getId("actions"),
1429
1374
  node,
1430
1375
  error
1431
- }, {
1432
- F: __dxlog_file2,
1433
- L: 617,
1434
- S: void 0,
1435
- C: (f, a) => f(...a)
1436
- });
1376
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 424, S: void 0 });
1437
1377
  return [];
1438
1378
  }
1439
- }).pipe(Atom3.withLabel(`graph-builder:connector:actions:${id}`)))
1379
+ }).pipe(Atom2.withLabel(`graph-builder:connector:actions:${id}`)))
1440
1380
  } : void 0
1441
1381
  ].filter(isNonNullable2);
1442
1382
  };
@@ -1445,24 +1385,19 @@ var runEffectSyncWithFallback = (effect, context2, extensionId, fallback) => {
1445
1385
  log2.warn("Extension failed", {
1446
1386
  extension: extensionId,
1447
1387
  error
1448
- }, {
1449
- F: __dxlog_file2,
1450
- L: 660,
1451
- S: void 0,
1452
- C: (f, a) => f(...a)
1453
- });
1388
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 441, S: void 0 });
1454
1389
  return Effect.succeed(fallback);
1455
1390
  })));
1456
1391
  };
1457
1392
  var createExtension = (options) => Effect.map(Effect.context(), (context2) => {
1458
1393
  const { id, match: match3, actions, connector, resolver, relation: relation2, position } = options;
1459
1394
  const connectorExtension = connector ? createConnectorWithRuntime(id, match3, connector, context2) : void 0;
1460
- 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) => ({
1395
+ const actionsExtension = actions ? (node) => Atom2.make((get2) => Function2.pipe(get2(node), Option3.flatMap(match3), Option3.map((matched) => runEffectSyncWithFallback(actions(matched, get2), context2, id, []).map((action) => ({
1461
1396
  ...action,
1462
1397
  // Attach captured context for action execution.
1463
1398
  _actionContext: context2
1464
1399
  }))), Option3.getOrElse(() => []))) : void 0;
1465
- const resolverExtension = resolver ? (nodeId) => Atom3.make((get2) => runEffectSyncWithFallback(resolver(nodeId, get2), context2, id, null) ?? null) : void 0;
1400
+ const resolverExtension = resolver ? (nodeId) => Atom2.make((get2) => runEffectSyncWithFallback(resolver(nodeId, get2), context2, id, null) ?? null) : void 0;
1466
1401
  return createExtensionRaw({
1467
1402
  id,
1468
1403
  relation: relation2,
@@ -1473,10 +1408,10 @@ var createExtension = (options) => Effect.map(Effect.context(), (context2) => {
1473
1408
  });
1474
1409
  });
1475
1410
  var createConnector = (matcher, factory) => {
1476
- return (node) => Atom3.make((get2) => Function2.pipe(get2(node), Option3.flatMap(matcher), Option3.map((data) => factory(data, get2)), Option3.getOrElse(() => [])));
1411
+ return (node) => Atom2.make((get2) => Function2.pipe(get2(node), Option3.flatMap(matcher), Option3.map((data) => factory(data, get2)), Option3.getOrElse(() => [])));
1477
1412
  };
1478
1413
  var createConnectorWithRuntime = (extensionId, matcher, factory, context2) => {
1479
- return (node) => Atom3.make((get2) => Function2.pipe(get2(node), Option3.flatMap(matcher), Option3.map((data) => runEffectSyncWithFallback(factory(data, get2), context2, extensionId, [])), Option3.getOrElse(() => [])));
1414
+ return (node) => Atom2.make((get2) => Function2.pipe(get2(node), Option3.flatMap(matcher), Option3.map((data) => runEffectSyncWithFallback(factory(data, get2), context2, extensionId, [])), Option3.getOrElse(() => [])));
1480
1415
  };
1481
1416
  var createTypeExtension = (options) => {
1482
1417
  const { id, type, actions, connector, relation: relation2, position } = options;
@@ -1489,16 +1424,28 @@ var createTypeExtension = (options) => {
1489
1424
  position
1490
1425
  });
1491
1426
  };
1492
- var connectorKey = (id, relation2) => `${id}${Separators.primary}${relationKey(relation2)}`;
1427
+ var qualifyNodeArgs = (parentId) => (nodes) => nodes.map((node) => {
1428
+ validateSegmentId(node.id);
1429
+ const qualified = qualifyId(parentId, node.id);
1430
+ return {
1431
+ ...node,
1432
+ id: qualified,
1433
+ nodes: node.nodes ? qualifyNodeArgs(qualified)(node.nodes) : void 0
1434
+ };
1435
+ });
1436
+ var collectAllInlineIds = (nodes) => nodes.flatMap((node) => node.nodes ? [
1437
+ ...node.nodes.map((child) => child.id),
1438
+ ...collectAllInlineIds(node.nodes)
1439
+ ] : []);
1440
+ var connectorKey = (id, relation2) => primaryKey(id, relationKey(relation2));
1493
1441
  var relationFromConnectorKey = (key) => {
1494
- const separatorIndex = key.indexOf(Separators.primary);
1495
- const id = key.slice(0, separatorIndex);
1442
+ const [id, encodedRelation] = primaryParts(key);
1496
1443
  return {
1497
1444
  id,
1498
- relation: relationFromKey(key.slice(separatorIndex + 1))
1445
+ relation: relationFromKey(encodedRelation)
1499
1446
  };
1500
1447
  };
1501
- var subscriptionKey = (id, kind, detail) => detail != null ? `${id}${Separators.primary}${kind}${Separators.primary}${detail}` : `${id}${Separators.primary}${kind}`;
1448
+ var subscriptionKey = (id, kind, detail) => detail != null ? primaryKey(id, kind, detail) : primaryKey(id, kind);
1502
1449
  var flattenExtensions = (extension, acc = []) => {
1503
1450
  if (Array2.isArray(extension)) {
1504
1451
  return [
@@ -1512,11 +1459,19 @@ var flattenExtensions = (extension, acc = []) => {
1512
1459
  ];
1513
1460
  }
1514
1461
  };
1462
+
1515
1463
  export {
1516
- atoms_exports as CreateAtom,
1517
- graph_exports as Graph,
1518
- graph_builder_exports as GraphBuilder,
1519
- node_exports as Node,
1520
- node_matcher_exports as NodeMatcher
1464
+ node_exports,
1465
+ qualifyId,
1466
+ getParentId,
1467
+ getSegmentId,
1468
+ getNode,
1469
+ expand,
1470
+ graph_exports,
1471
+ node_matcher_exports,
1472
+ make3 as make,
1473
+ addExtension,
1474
+ flush,
1475
+ graph_builder_exports
1521
1476
  };
1522
- //# sourceMappingURL=index.mjs.map
1477
+ //# sourceMappingURL=chunk-32XXJE6M.mjs.map