@dxos/app-graph 0.8.4-main.422d1c7879 → 0.8.4-main.4668b7de9b

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 (47) hide show
  1. package/LICENSE +102 -5
  2. package/README.md +1 -1
  3. package/dist/lib/{browser/chunk-W47H2NND.mjs → neutral/chunk-7BYCDV55.mjs} +57 -177
  4. package/dist/lib/neutral/chunk-7BYCDV55.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/{browser → neutral}/index.mjs +4 -2
  8. package/dist/lib/{browser → neutral}/index.mjs.map +2 -2
  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/{browser → neutral}/testing/index.mjs +2 -1
  13. package/dist/types/src/atoms.d.ts.map +1 -1
  14. package/dist/types/src/graph-builder.d.ts +5 -6
  15. package/dist/types/src/graph-builder.d.ts.map +1 -1
  16. package/dist/types/src/graph.d.ts.map +1 -1
  17. package/dist/types/src/node-matcher.d.ts +11 -12
  18. package/dist/types/src/node-matcher.d.ts.map +1 -1
  19. package/dist/types/src/node.d.ts +2 -2
  20. package/dist/types/src/node.d.ts.map +1 -1
  21. package/dist/types/src/scheduler.browser.d.ts +2 -0
  22. package/dist/types/src/scheduler.browser.d.ts.map +1 -0
  23. package/dist/types/src/scheduler.d.ts +8 -0
  24. package/dist/types/src/scheduler.d.ts.map +1 -0
  25. package/dist/types/src/stories/EchoGraph.stories.d.ts.map +1 -1
  26. package/dist/types/src/testing/setup-graph-builder.d.ts.map +1 -1
  27. package/dist/types/src/util.d.ts +1 -0
  28. package/dist/types/src/util.d.ts.map +1 -1
  29. package/dist/types/tsconfig.tsbuildinfo +1 -1
  30. package/package.json +32 -24
  31. package/src/graph-builder.test.ts +147 -21
  32. package/src/graph-builder.ts +45 -11
  33. package/src/node-matcher.ts +14 -15
  34. package/src/scheduler.browser.ts +5 -0
  35. package/src/scheduler.ts +17 -0
  36. package/src/stories/EchoGraph.stories.tsx +5 -5
  37. package/src/util.ts +9 -3
  38. package/dist/lib/browser/chunk-W47H2NND.mjs.map +0 -7
  39. package/dist/lib/browser/meta.json +0 -1
  40. package/dist/lib/browser/testing/index.mjs.map +0 -7
  41. package/dist/lib/node-esm/chunk-LYZWNJ7J.mjs +0 -1605
  42. package/dist/lib/node-esm/chunk-LYZWNJ7J.mjs.map +0 -7
  43. package/dist/lib/node-esm/index.mjs +0 -39
  44. package/dist/lib/node-esm/index.mjs.map +0 -7
  45. package/dist/lib/node-esm/meta.json +0 -1
  46. package/dist/lib/node-esm/testing/index.mjs +0 -40
  47. /package/dist/lib/{node-esm → neutral}/testing/index.mjs.map +0 -0
package/LICENSE CHANGED
@@ -1,8 +1,105 @@
1
- MIT License
2
- Copyright (c) 2022 DXOS
1
+ # Functional Source License, Version 1.1, ALv2 Future License
3
2
 
4
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
3
+ ## Abbreviation
5
4
 
6
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
5
+ FSL-1.1-Apache-2.0
7
6
 
8
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
7
+ ## Notice
8
+
9
+ Copyright 2026 DXOS
10
+
11
+ ## Terms and Conditions
12
+
13
+ ### Licensor ("We")
14
+
15
+ The party offering the Software under these Terms and Conditions.
16
+
17
+ ### The Software
18
+
19
+ The "Software" is each version of the software that we make available under
20
+ these Terms and Conditions, as indicated by our inclusion of these Terms and
21
+ Conditions with the Software.
22
+
23
+ ### License Grant
24
+
25
+ Subject to your compliance with this License Grant and the Patents,
26
+ Redistribution and Trademark clauses below, we hereby grant you the right to
27
+ use, copy, modify, create derivative works, publicly perform, publicly display
28
+ and redistribute the Software for any Permitted Purpose identified below.
29
+
30
+ ### Permitted Purpose
31
+
32
+ A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
33
+ means making the Software available to others in a commercial product or
34
+ service that:
35
+
36
+ 1. substitutes for the Software;
37
+
38
+ 2. substitutes for any other product or service we offer using the Software
39
+ that exists as of the date we make the Software available; or
40
+
41
+ 3. offers the same or substantially similar functionality as the Software.
42
+
43
+ Permitted Purposes specifically include using the Software:
44
+
45
+ 1. for your internal use and access;
46
+
47
+ 2. for non-commercial education;
48
+
49
+ 3. for non-commercial research; and
50
+
51
+ 4. in connection with professional services that you provide to a licensee
52
+ using the Software in accordance with these Terms and Conditions.
53
+
54
+ ### Patents
55
+
56
+ To the extent your use for a Permitted Purpose would necessarily infringe our
57
+ patents, the license grant above includes a license under our patents. If you
58
+ make a claim against any party that the Software infringes or contributes to
59
+ the infringement of any patent, then your patent license to the Software ends
60
+ immediately.
61
+
62
+ ### Redistribution
63
+
64
+ The Terms and Conditions apply to all copies, modifications and derivatives of
65
+ the Software.
66
+
67
+ If you redistribute any copies, modifications or derivatives of the Software,
68
+ you must include a copy of or a link to these Terms and Conditions and not
69
+ remove any copyright notices provided in or with the Software.
70
+
71
+ ### Disclaimer
72
+
73
+ THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
74
+ IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
75
+ PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
76
+
77
+ IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
78
+ SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
79
+ EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
80
+
81
+ ### Trademarks
82
+
83
+ Except for displaying the License Details and identifying us as the origin of
84
+ the Software, you have no right under these Terms and Conditions to use our
85
+ trademarks, trade names, service marks or product names.
86
+
87
+ ## Grant of Future License
88
+
89
+ We hereby irrevocably grant you an additional license to use the Software under
90
+ the Apache License, Version 2.0 that is effective on the second anniversary of
91
+ the date we make the Software available. On or after that date, you may use the
92
+ Software under the Apache License, Version 2.0, in which case the following
93
+ will apply:
94
+
95
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use
96
+ this file except in compliance with the License.
97
+
98
+ You may obtain a copy of the License at
99
+
100
+ http://www.apache.org/licenses/LICENSE-2.0
101
+
102
+ Unless required by applicable law or agreed to in writing, software distributed
103
+ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
104
+ CONDITIONS OF ANY KIND, either express or implied. See the License for the
105
+ specific language governing permissions and limitations under the License.
package/README.md CHANGED
@@ -10,4 +10,4 @@
10
10
 
11
11
  Your ideas, issues, and code are most welcome. Please take a look at our [community code of conduct](https://github.com/dxos/dxos/blob/main/CODE_OF_CONDUCT.md), the [issue guide](https://github.com/dxos/dxos/blob/main/CONTRIBUTING.md#submitting-issues), and the [PR contribution guide](https://github.com/dxos/dxos/blob/main/CONTRIBUTING.md#submitting-prs).
12
12
 
13
- License: [MIT](./LICENSE) Copyright 2023 © DXOS
13
+ License: [FSL-1.1-Apache-2.0](./LICENSE) Copyright 2023 © DXOS
@@ -1,8 +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
- };
1
+ import {
2
+ __export
3
+ } from "./chunk-J5LGTIGS.mjs";
6
4
 
7
5
  // src/node.ts
8
6
  var node_exports = {};
@@ -61,8 +59,12 @@ var secondaryKey = (...parts) => parts.join(SECONDARY);
61
59
  var secondaryParts = (key) => key.split(SECONDARY);
62
60
  var normalizeRelation = (relation2) => relation2 == null ? childRelation() : typeof relation2 === "string" ? relation(relation2) : relation2;
63
61
  var shallowEqual = (a, b) => {
64
- if (a === b) return true;
65
- 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
+ }
66
68
  const keysA = Object.keys(a);
67
69
  const keysB = Object.keys(b);
68
70
  if (keysA.length !== keysB.length) {
@@ -76,7 +78,7 @@ var nodeArgsUnchanged = (prev, next) => {
76
78
  }
77
79
  return prev.every((prevNode, idx) => {
78
80
  const nextNode = next[idx];
79
- 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 ?? []);
80
82
  });
81
83
  };
82
84
  var qualifyId = (parentId, ...segmentIds) => [
@@ -84,15 +86,7 @@ var qualifyId = (parentId, ...segmentIds) => [
84
86
  ...segmentIds
85
87
  ].join(PATH);
86
88
  var validateSegmentId = (id) => {
87
- invariant(!id.includes(PATH), `Node segment ID must not contain '${PATH}': ${id}`, {
88
- F: __dxlog_file,
89
- L: 78,
90
- S: void 0,
91
- A: [
92
- "!id.includes(PATH)",
93
- "`Node segment ID must not contain '${PATH}': ${id}`"
94
- ]
95
- });
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}`"] });
96
90
  };
97
91
  var getParentId = (qualifiedId) => {
98
92
  const lastSlash = qualifiedId.lastIndexOf(PATH);
@@ -147,15 +141,7 @@ var __dxlog_file2 = "/__w/dxos/dxos/packages/sdk/app-graph/src/graph.ts";
147
141
  var graphSymbol = /* @__PURE__ */ Symbol("graph");
148
142
  var getGraph = (node) => {
149
143
  const graph = node[graphSymbol];
150
- invariant2(graph, "Node is not associated with a graph.", {
151
- F: __dxlog_file2,
152
- L: 33,
153
- S: void 0,
154
- A: [
155
- "graph",
156
- "'Node is not associated with a graph.'"
157
- ]
158
- });
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.'"] });
159
145
  return graph;
160
146
  };
161
147
  var GraphTypeId = /* @__PURE__ */ Symbol.for("@dxos/app-graph/Graph");
@@ -194,15 +180,7 @@ var GraphImpl = class {
194
180
  _nodeOrThrow = Atom.family((id) => {
195
181
  return Atom.make((get2) => {
196
182
  const node = get2(this._node(id));
197
- invariant2(Option.isSome(node), `Node not available: ${id}`, {
198
- F: __dxlog_file2,
199
- L: 172,
200
- S: this,
201
- A: [
202
- "Option.isSome(node)",
203
- "`Node not available: ${id}`"
204
- ]
205
- });
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}`"] });
206
184
  return node.value;
207
185
  });
208
186
  });
@@ -373,15 +351,7 @@ function getConnections(graphOrId, idOrRelation, relation2) {
373
351
  } else {
374
352
  const graph = graphOrId;
375
353
  const id = idOrRelation;
376
- invariant2(relation2 !== void 0, "Relation is required.", {
377
- F: __dxlog_file2,
378
- L: 449,
379
- S: this,
380
- A: [
381
- "relation !== undefined",
382
- "'Relation is required.'"
383
- ]
384
- });
354
+ invariant2(relation2 !== void 0, "Relation is required.", { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 272, S: this, A: ["relation !== undefined", "'Relation is required.'"] });
385
355
  const rel = relation2;
386
356
  return getConnectionsImpl(graph, id, rel);
387
357
  }
@@ -518,12 +488,7 @@ var initializeImpl = async (graph, id) => {
518
488
  log("initialize", {
519
489
  id,
520
490
  initialized
521
- }, {
522
- F: __dxlog_file2,
523
- L: 671,
524
- S: void 0,
525
- C: (f, a) => f(...a)
526
- });
491
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 431, S: void 0 });
527
492
  if (!initialized) {
528
493
  Record.set(internal._initialized, id, true);
529
494
  await internal._onInitialize?.(id);
@@ -549,24 +514,14 @@ var expandImpl = (graph, id, relation2) => {
549
514
  log("expand", {
550
515
  key,
551
516
  deferred: true
552
- }, {
553
- F: __dxlog_file2,
554
- L: 717,
555
- S: void 0,
556
- C: (f, a) => f(...a)
557
- });
517
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 463, S: void 0 });
558
518
  return graph;
559
519
  }
560
520
  const expanded = Record.get(internal._expanded, key).pipe(Option.getOrElse(() => false));
561
521
  log("expand", {
562
522
  key,
563
523
  expanded
564
- }, {
565
- F: __dxlog_file2,
566
- L: 722,
567
- S: void 0,
568
- C: (f, a) => f(...a)
569
- });
524
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 470, S: void 0 });
570
525
  if (!expanded) {
571
526
  Record.set(internal._expanded, key, true);
572
527
  internal._onExpand?.(id, normalizedRelation);
@@ -581,15 +536,7 @@ function expand(graphOrId, idOrRelation, relation2) {
581
536
  } else {
582
537
  const graph = graphOrId;
583
538
  const id = idOrRelation;
584
- invariant2(relation2 !== void 0, "Relation is required.", {
585
- F: __dxlog_file2,
586
- L: 758,
587
- S: this,
588
- A: [
589
- "relation !== undefined",
590
- "'Relation is required.'"
591
- ]
592
- });
539
+ invariant2(relation2 !== void 0, "Relation is required.", { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 490, S: this, A: ["relation !== undefined", "'Relation is required.'"] });
593
540
  const rel = relation2;
594
541
  return expandImpl(graph, id, rel);
595
542
  }
@@ -658,24 +605,14 @@ var addNodeImpl = (graph, nodeArg) => {
658
605
  typeChanged,
659
606
  dataChanged,
660
607
  propertiesChanged
661
- }, {
662
- F: __dxlog_file2,
663
- L: 880,
664
- S: void 0,
665
- C: (f, a) => f(...a)
666
- });
608
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 565, S: void 0 });
667
609
  if (typeChanged || dataChanged || propertiesChanged) {
668
610
  log("updating node", {
669
611
  id,
670
612
  type,
671
613
  data,
672
614
  properties
673
- }, {
674
- F: __dxlog_file2,
675
- L: 887,
676
- S: void 0,
677
- C: (f, a) => f(...a)
678
- });
615
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 572, S: void 0 });
679
616
  const newNode = Option.some({
680
617
  ...existing,
681
618
  ...rest,
@@ -699,12 +636,7 @@ var addNodeImpl = (graph, nodeArg) => {
699
636
  type,
700
637
  data,
701
638
  properties
702
- }, {
703
- F: __dxlog_file2,
704
- L: 900,
705
- S: void 0,
706
- C: (f, a) => f(...a)
707
- });
639
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 596, S: void 0 });
708
640
  const newNode = internal._constructNode({
709
641
  id,
710
642
  type,
@@ -845,12 +777,7 @@ var addEdgeImpl = (graph, edgeArg) => {
845
777
  source: edgeArg.source,
846
778
  target: edgeArg.target,
847
779
  relation: relationId
848
- }, {
849
- F: __dxlog_file2,
850
- L: 1083,
851
- S: void 0,
852
- C: (f, a) => f(...a)
853
- });
780
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 758, S: void 0 });
854
781
  internal._registry.set(sourceAtom, {
855
782
  ...source,
856
783
  [relationId]: [
@@ -867,12 +794,7 @@ var addEdgeImpl = (graph, edgeArg) => {
867
794
  source: edgeArg.source,
868
795
  target: edgeArg.target,
869
796
  relation: inverseId
870
- }, {
871
- F: __dxlog_file2,
872
- L: 1091,
873
- S: void 0,
874
- C: (f, a) => f(...a)
875
- });
797
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 775, S: void 0 });
876
798
  internal._registry.set(targetAtom, {
877
799
  ...target,
878
800
  [inverseId]: [
@@ -972,39 +894,15 @@ var relationKey = (relation2) => {
972
894
  };
973
895
  var relationFromKey = (encoded) => {
974
896
  const parts = secondaryParts(encoded);
975
- invariant2(parts.length === 2 && parts[0].length > 0 && parts[1].length > 0, `Invalid relation key: ${encoded}`, {
976
- F: __dxlog_file2,
977
- L: 1236,
978
- S: void 0,
979
- A: [
980
- "parts.length === 2 && parts[0].length > 0 && parts[1].length > 0",
981
- "`Invalid relation key: ${encoded}`"
982
- ]
983
- });
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}`"] });
984
898
  const [kind, directionRaw] = parts;
985
- invariant2(directionRaw === "outbound" || directionRaw === "inbound", `Invalid relation direction: ${directionRaw}`, {
986
- F: __dxlog_file2,
987
- L: 1238,
988
- S: void 0,
989
- A: [
990
- "directionRaw === 'outbound' || directionRaw === 'inbound'",
991
- "`Invalid relation direction: ${directionRaw}`"
992
- ]
993
- });
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}`"] });
994
900
  return relation(kind, directionRaw);
995
901
  };
996
902
  var connectionKey = (id, relation2) => primaryKey(id, relationKey(relation2));
997
903
  var relationFromConnectionKey = (key) => {
998
904
  const [id, encodedRelation] = primaryParts(key);
999
- invariant2(id && encodedRelation, `Invalid connection key: ${key}`, {
1000
- F: __dxlog_file2,
1001
- L: 1246,
1002
- S: void 0,
1003
- A: [
1004
- "id && encodedRelation",
1005
- "`Invalid connection key: ${key}`"
1006
- ]
1007
- });
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}`"] });
1008
906
  return {
1009
907
  id,
1010
908
  relation: relationFromKey(encodedRelation)
@@ -1030,11 +928,11 @@ __export(node_matcher_exports, {
1030
928
  whenRoot: () => whenRoot
1031
929
  });
1032
930
  import * as Option2 from "effect/Option";
1033
- import { Obj } from "@dxos/echo";
931
+ import { Entity, Obj } from "@dxos/echo";
1034
932
  var whenRoot = (node) => node.id === RootId ? Option2.some(node) : Option2.none();
1035
933
  var whenId = (id) => (node) => node.id === id ? Option2.some(node) : Option2.none();
1036
934
  var whenNodeType = (type) => (node) => node.type === type ? Option2.some(node) : Option2.none();
1037
- var whenEchoType = (type) => (node) => Obj.instanceOf(type, node.data) ? Option2.some(node.data) : Option2.none();
935
+ var whenEchoType = (type) => (node) => Entity.instanceOf(type, node.data) ? Option2.some(node.data) : Option2.none();
1038
936
  var whenEchoObject = (node) => Obj.isObject(node.data) ? Option2.some(node.data) : Option2.none();
1039
937
  var whenAll = (...matchers) => (node) => {
1040
938
  let first = Option2.none();
@@ -1058,7 +956,7 @@ var whenAny = (...matchers) => (node) => {
1058
956
  }
1059
957
  return Option2.none();
1060
958
  };
1061
- var whenEchoTypeMatches = (type) => (node) => Obj.instanceOf(type, node.data) ? Option2.some(node) : Option2.none();
959
+ var whenEchoTypeMatches = (type) => (node) => Entity.instanceOf(type, node.data) ? Option2.some(node) : Option2.none();
1062
960
  var whenEchoObjectMatches = (node) => Obj.isObject(node.data) ? Option2.some(node) : Option2.none();
1063
961
  var whenNot = (matcher) => (node) => Option2.isNone(matcher(node)) ? Option2.some(node) : Option2.none();
1064
962
 
@@ -1086,9 +984,9 @@ import * as Function2 from "effect/Function";
1086
984
  import * as Option3 from "effect/Option";
1087
985
  import * as Pipeable2 from "effect/Pipeable";
1088
986
  import * as Record2 from "effect/Record";
1089
- import { scheduleTask, yieldOrContinue } from "main-thread-scheduling";
1090
987
  import { log as log2 } from "@dxos/log";
1091
988
  import { byPosition, getDebugName, isNonNullable as isNonNullable2 } from "@dxos/util";
989
+ import { scheduleTask, yieldOrContinue } from "#scheduler";
1092
990
  var __dxlog_file3 = "/__w/dxos/dxos/packages/sdk/app-graph/src/graph-builder.ts";
1093
991
  var GraphBuilderTypeId = /* @__PURE__ */ Symbol.for("@dxos/app-graph/GraphBuilder");
1094
992
  var GraphBuilderImpl = class {
@@ -1103,6 +1001,8 @@ var GraphBuilderImpl = class {
1103
1001
  _dirtyConnectors = /* @__PURE__ */ new Map();
1104
1002
  /** Last-flushed node IDs per connector key, used for edge removal on update. */
1105
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();
1106
1006
  /** Last-flushed node args per connector key, used for change detection. */
1107
1007
  _connectorPreviousArgs = /* @__PURE__ */ new Map();
1108
1008
  /** Whether a dirty-flush task is already scheduled. */
@@ -1141,6 +1041,11 @@ var GraphBuilderImpl = class {
1141
1041
  const removed = previous.filter((pid) => !ids.includes(pid));
1142
1042
  this._connectorPrevious.set(key, ids);
1143
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);
1144
1049
  removeEdges(this._graph, removed.map((target) => ({
1145
1050
  source: id,
1146
1051
  target,
@@ -1207,12 +1112,7 @@ var GraphBuilderImpl = class {
1207
1112
  id,
1208
1113
  relation: relation2,
1209
1114
  registry: getDebugName(this._registry)
1210
- }, {
1211
- F: __dxlog_file3,
1212
- L: 269,
1213
- S: this,
1214
- C: (f, a) => f(...a)
1215
- });
1115
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 136, S: this });
1216
1116
  this._expandRelation(id, relation2);
1217
1117
  if (relation2.kind === "child" && relation2.direction === "outbound") {
1218
1118
  expand(this._graph, id, "action");
@@ -1235,12 +1135,7 @@ var GraphBuilderImpl = class {
1235
1135
  id,
1236
1136
  relation: relation2,
1237
1137
  ids
1238
- }, {
1239
- F: __dxlog_file3,
1240
- L: 296,
1241
- S: this,
1242
- C: (f, a) => f(...a)
1243
- });
1138
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 160, S: this });
1244
1139
  this._dirtyConnectors.set(key, {
1245
1140
  nodes,
1246
1141
  previous
@@ -1254,12 +1149,7 @@ var GraphBuilderImpl = class {
1254
1149
  async _onInitialize(id) {
1255
1150
  log2("onInitialize", {
1256
1151
  id
1257
- }, {
1258
- F: __dxlog_file3,
1259
- L: 307,
1260
- S: this,
1261
- C: (f, a) => f(...a)
1262
- });
1152
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 176, S: this });
1263
1153
  const resolver = this._resolvers(id);
1264
1154
  const cancel = this._registry.subscribe(resolver, (node) => {
1265
1155
  const trigger = this._initialized[id];
@@ -1416,8 +1306,15 @@ function destroy(builder) {
1416
1306
  var flush = (builder) => {
1417
1307
  return builder._flushPromise;
1418
1308
  };
1309
+ var validateLocalId = (id) => {
1310
+ const finalSegment = id.split(".").pop();
1311
+ if (!/^[a-zA-Z][a-zA-Z0-9]*$/.test(finalSegment)) {
1312
+ throw new Error(`Invalid extension id: "${id}". The final segment "${finalSegment}" must be camelCase (letters and digits only, starting with a letter \u2014 no hyphens or underscores).`);
1313
+ }
1314
+ };
1419
1315
  var createExtensionRaw = (extension) => {
1420
- const { id, position = "static", relation: relation2 = "child", resolver: _resolver, connector: _connector, actions: _actions, actionGroups: _actionGroups } = extension;
1316
+ const { id, position, relation: relation2 = "child", resolver: _resolver, connector: _connector, actions: _actions, actionGroups: _actionGroups } = extension;
1317
+ validateLocalId(id);
1421
1318
  const normalizedRelation = normalizeRelation(relation2);
1422
1319
  const getId = (key) => `${id}/${key}`;
1423
1320
  const resolver = _resolver && Atom2.family((id2) => _resolver(id2).pipe(Atom2.withLabel(`graph-builder:_resolver:${id2}`)));
@@ -1442,12 +1339,7 @@ var createExtensionRaw = (extension) => {
1442
1339
  id: getId("connector"),
1443
1340
  node,
1444
1341
  error
1445
- }, {
1446
- F: __dxlog_file3,
1447
- L: 609,
1448
- S: void 0,
1449
- C: (f, a) => f(...a)
1450
- });
1342
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 398, S: void 0 });
1451
1343
  return [];
1452
1344
  }
1453
1345
  }).pipe(Atom2.withLabel(`graph-builder:connector:${id}`)))
@@ -1468,12 +1360,7 @@ var createExtensionRaw = (extension) => {
1468
1360
  id: getId("actionGroups"),
1469
1361
  node,
1470
1362
  error
1471
- }, {
1472
- F: __dxlog_file3,
1473
- L: 630,
1474
- S: void 0,
1475
- C: (f, a) => f(...a)
1476
- });
1363
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 419, S: void 0 });
1477
1364
  return [];
1478
1365
  }
1479
1366
  }).pipe(Atom2.withLabel(`graph-builder:connector:actionGroups:${id}`)))
@@ -1493,12 +1380,7 @@ var createExtensionRaw = (extension) => {
1493
1380
  id: getId("actions"),
1494
1381
  node,
1495
1382
  error
1496
- }, {
1497
- F: __dxlog_file3,
1498
- L: 647,
1499
- S: void 0,
1500
- C: (f, a) => f(...a)
1501
- });
1383
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 439, S: void 0 });
1502
1384
  return [];
1503
1385
  }
1504
1386
  }).pipe(Atom2.withLabel(`graph-builder:connector:actions:${id}`)))
@@ -1510,12 +1392,7 @@ var runEffectSyncWithFallback = (effect, context2, extensionId, fallback) => {
1510
1392
  log2.warn("Extension failed", {
1511
1393
  extension: extensionId,
1512
1394
  error
1513
- }, {
1514
- F: __dxlog_file3,
1515
- L: 690,
1516
- S: void 0,
1517
- C: (f, a) => f(...a)
1518
- });
1395
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 456, S: void 0 });
1519
1396
  return Effect.succeed(fallback);
1520
1397
  })));
1521
1398
  };
@@ -1563,6 +1440,10 @@ var qualifyNodeArgs = (parentId) => (nodes) => nodes.map((node) => {
1563
1440
  nodes: node.nodes ? qualifyNodeArgs(qualified)(node.nodes) : void 0
1564
1441
  };
1565
1442
  });
1443
+ var collectAllInlineIds = (nodes) => nodes.flatMap((node) => node.nodes ? [
1444
+ ...node.nodes.map((child) => child.id),
1445
+ ...collectAllInlineIds(node.nodes)
1446
+ ] : []);
1566
1447
  var connectorKey = (id, relation2) => primaryKey(id, relationKey(relation2));
1567
1448
  var relationFromConnectorKey = (key) => {
1568
1449
  const [id, encodedRelation] = primaryParts(key);
@@ -1587,7 +1468,6 @@ var flattenExtensions = (extension, acc = []) => {
1587
1468
  };
1588
1469
 
1589
1470
  export {
1590
- __export,
1591
1471
  node_exports,
1592
1472
  qualifyId,
1593
1473
  getParentId,
@@ -1601,4 +1481,4 @@ export {
1601
1481
  flush,
1602
1482
  graph_builder_exports
1603
1483
  };
1604
- //# sourceMappingURL=chunk-W47H2NND.mjs.map
1484
+ //# sourceMappingURL=chunk-7BYCDV55.mjs.map