@stream44.studio/encapsulate 0.4.0-rc.24 → 0.4.0-rc.26

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.
package/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- encapsulate: Object encapsulation & mapping system with runtime kernel for TypeScript
3
+ encapsulate: Object encapsulation & mapping library with runtime kernel for TypeScript
4
4
 
5
5
  Copyright 2026 Christoph Dorn - https://Christoph.diy
6
6
 
package/README.md CHANGED
@@ -27,13 +27,23 @@ It is being used to underpin:
27
27
  <br/><br/>
28
28
  </p>
29
29
 
30
+ ### Why
31
+
32
+ When encoding a software system as a body (complete model), the body is structured through the declarative semantic schema and animated by functional processing in nodes.
33
+
34
+ We need a minimal abstraction to conveniently author graph processing nodes.
35
+
36
+ `encapsulate` provides such a primitive building block.
37
+
38
+ ![Source To Graph Isomorphism](./docs/SourceToGraphIsomorphism.svg)
39
+
40
+
30
41
  The CAPSULE Spine Contract
31
42
  ---
32
43
 
33
44
  The `encapsulate` library wraps TypeScript objects and binds reference trees for constructing executable component graphs.
34
45
 
35
- The binding rules are defined by **Spine Contracts**. The first *experimental* spine contract is the **Capsule Spine Contract**. It builds a model
36
- around **Capsules** which have certain properties.
46
+ The binding rules are defined by **Spine Contracts**. The first *experimental* spine contract is the **Capsule Spine Contract**. It builds a model around **Capsules** which have certain properties.
37
47
 
38
48
  The capsule spine contract is implemented here: [src/spine-contracts/CapsuleSpineContract.v0/](src/spine-contracts/CapsuleSpineContract.v0/)
39
49
 
@@ -44,8 +54,6 @@ The capsule spine contract is implemented here: [src/spine-contracts/CapsuleSpin
44
54
  - [ ] Capsule Projectors
45
55
  - [ ] Load capsules from packs
46
56
 
47
- ![Capsule Spine Contract Overview](./src/spine-contracts/CapsuleSpineContract.v0/Overview.svg)
48
-
49
57
  Provenance
50
58
  ===
51
59
 
@@ -0,0 +1,100 @@
1
+ <mxfile host="65bd71144e">
2
+ <diagram name="Page-1" id="QeIE7gKKPfThrfCM8ygm">
3
+ <mxGraphModel dx="1145" dy="1728" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1100" pageHeight="850" math="0" shadow="0">
4
+ <root>
5
+ <mxCell id="0"/>
6
+ <mxCell id="1" parent="0"/>
7
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-29" value="" style="rounded=0;whiteSpace=wrap;html=1;movable=1;resizable=1;rotatable=1;deletable=1;editable=1;locked=0;connectable=1;" parent="1" vertex="1">
8
+ <mxGeometry x="10" y="-840" width="1070" height="480" as="geometry"/>
9
+ </mxCell>
10
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-33" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;strokeWidth=2;" parent="1" source="N3hJ6-WijfH2HfO5JL5S-28" target="N3hJ6-WijfH2HfO5JL5S-25" edge="1">
11
+ <mxGeometry relative="1" as="geometry"/>
12
+ </mxCell>
13
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-28" value="Source Code Module" style="rounded=0;whiteSpace=wrap;html=1;verticalAlign=top;dashed=1;" parent="1" vertex="1">
14
+ <mxGeometry x="30" y="-800" width="570" height="420" as="geometry"/>
15
+ </mxCell>
16
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-25" value="Semantic Graph Module" style="rounded=0;whiteSpace=wrap;html=1;dashed=1;verticalAlign=top;" parent="1" vertex="1">
17
+ <mxGeometry x="660" y="-800" width="390" height="420" as="geometry"/>
18
+ </mxCell>
19
+ <mxCell id="o5PIcx3FIGXJDux8oxUI-1" value="const &lt;font style=&quot;color: rgb(0, 102, 204);&quot;&gt;capsule&lt;/font&gt; = await Capsule({&lt;div&gt;&amp;nbsp; '&lt;font style=&quot;color: rgb(204, 102, 0);&quot;&gt;#@&amp;lt;org&amp;gt;/&amp;lt;project&amp;gt;/structs/StructA&lt;/font&gt;': {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; as:&amp;nbsp;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;'&lt;/span&gt;&lt;font style=&quot;color: rgb(153, 51, 255);&quot;&gt;&lt;span style=&quot;background-color: transparent;&quot;&gt;$#&lt;/span&gt;&lt;span style=&quot;background-color: transparent;&quot;&gt;@&amp;lt;org&amp;gt;/&amp;lt;project&amp;gt;/AspectX&lt;/span&gt;&lt;/font&gt;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; }&lt;/div&gt;&lt;div&gt;&amp;nbsp; '#'{&amp;nbsp;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &lt;font style=&quot;color: rgb(0, 153, 0);&quot;&gt;property1&lt;/font&gt;: 'val1',&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &lt;font style=&quot;color: rgb(204, 0, 102);&quot;&gt;mapping1&lt;/font&gt;: '&lt;span style=&quot;background-color: transparent;&quot;&gt;&lt;font style=&quot;color: rgb(204, 0, 102);&quot;&gt;@&amp;lt;org&amp;gt;/&amp;lt;project&amp;gt;/FeatureY&lt;/font&gt;&lt;/span&gt;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;',&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &lt;font style=&quot;color: rgb(0, 153, 0);&quot;&gt;method1&lt;/font&gt;: () =&amp;gt; {&lt;/div&gt;&lt;div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; this.&lt;span style=&quot;background-color: transparent;&quot;&gt;&lt;font style=&quot;color: light-dark(rgb(204, 0, 102), rgb(255, 255, 255));&quot;&gt;mapping1&lt;/font&gt;&lt;/span&gt;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;.featureMethod()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; this['&lt;font style=&quot;color: rgb(153, 51, 255);&quot;&gt;&lt;span style=&quot;background-color: transparent;&quot;&gt;$#&lt;/span&gt;&lt;span style=&quot;background-color: transparent;&quot;&gt;@&amp;lt;org&amp;gt;/&amp;lt;project&amp;gt;/AspectX&lt;/span&gt;&lt;/font&gt;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;.instanceMethod2()&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&amp;nbsp; }&lt;br&gt;}, {&lt;div&gt;&amp;nbsp; capsuleName: '&lt;font style=&quot;color: rgb(0, 102, 204);&quot;&gt;&lt;span style=&quot;background-color: transparent;&quot;&gt;@&amp;lt;org&amp;gt;/&amp;lt;project&amp;gt;/&lt;/span&gt;&lt;span style=&quot;background-color: transparent;&quot;&gt;MyCapsule&lt;/span&gt;&lt;/font&gt;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;'&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;})&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;&lt;font style=&quot;color: rgb(0, 102, 204);&quot;&gt;capsule&lt;/font&gt;.&lt;span style=&quot;background-color: transparent;&quot;&gt;&lt;font style=&quot;color: light-dark(rgb(0, 153, 0), rgb(255, 255, 255));&quot;&gt;property1&lt;/font&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;font style=&quot;color: rgb(0, 102, 204);&quot;&gt;capsule&lt;/font&gt;.&lt;span style=&quot;background-color: transparent;&quot;&gt;&lt;font style=&quot;color: light-dark(rgb(0, 153, 0), rgb(255, 255, 255));&quot;&gt;method1&lt;/font&gt;&lt;/span&gt;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;font style=&quot;color: rgb(0, 102, 204);&quot;&gt;capsule&lt;/font&gt;.&lt;span style=&quot;color: rgb(204, 0, 102); background-color: transparent;&quot;&gt;mapping1&lt;/span&gt;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;.featureMethod&lt;/span&gt;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;font style=&quot;color: rgb(0, 102, 204);&quot;&gt;capsule&lt;/font&gt;['&lt;font style=&quot;color: rgb(204, 102, 0);&quot;&gt;#@&amp;lt;org&amp;gt;/&amp;lt;project&amp;gt;/structs/StructA&lt;/font&gt;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;].protoMethod1&lt;/span&gt;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;font style=&quot;color: rgb(0, 102, 204);&quot;&gt;capsule&lt;/font&gt;['&lt;font style=&quot;color: rgb(153, 51, 255);&quot;&gt;&lt;span style=&quot;background-color: transparent;&quot;&gt;$#&lt;/span&gt;&lt;span style=&quot;background-color: transparent;&quot;&gt;@&amp;lt;org&amp;gt;/&amp;lt;project&amp;gt;/AspectX&lt;/span&gt;&lt;/font&gt;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;'&lt;/span&gt;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;].&lt;/span&gt;instanceMethod2&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;align=left;fontFamily=Courier New;fontStyle=1;fontSize=14;spacingLeft=10;fillColor=#FFFCF4;" parent="1" vertex="1">
20
+ <mxGeometry x="55" y="-765" width="520" height="370" as="geometry"/>
21
+ </mxCell>
22
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-26" value="" style="group;fillColor=default;" parent="1" connectable="0" vertex="1">
23
+ <mxGeometry x="685" y="-750" width="340" height="340" as="geometry"/>
24
+ </mxCell>
25
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-20" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fillColor=#FFFCF4;" parent="N3hJ6-WijfH2HfO5JL5S-26" vertex="1">
26
+ <mxGeometry width="340" height="340" as="geometry"/>
27
+ </mxCell>
28
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-9" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="N3hJ6-WijfH2HfO5JL5S-26" source="N3hJ6-WijfH2HfO5JL5S-1" target="N3hJ6-WijfH2HfO5JL5S-5" edge="1">
29
+ <mxGeometry relative="1" as="geometry"/>
30
+ </mxCell>
31
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-1" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" parent="N3hJ6-WijfH2HfO5JL5S-26" vertex="1">
32
+ <mxGeometry x="120" y="50" width="20" height="20" as="geometry"/>
33
+ </mxCell>
34
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-17" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="N3hJ6-WijfH2HfO5JL5S-26" source="N3hJ6-WijfH2HfO5JL5S-4" target="N3hJ6-WijfH2HfO5JL5S-16" edge="1">
35
+ <mxGeometry relative="1" as="geometry"/>
36
+ </mxCell>
37
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-4" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="N3hJ6-WijfH2HfO5JL5S-26" vertex="1">
38
+ <mxGeometry x="50" y="180" width="20" height="20" as="geometry"/>
39
+ </mxCell>
40
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-10" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="N3hJ6-WijfH2HfO5JL5S-26" source="N3hJ6-WijfH2HfO5JL5S-5" target="N3hJ6-WijfH2HfO5JL5S-7" edge="1">
41
+ <mxGeometry relative="1" as="geometry"/>
42
+ </mxCell>
43
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-11" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;entryX=0;entryY=0;entryDx=0;entryDy=0;" parent="N3hJ6-WijfH2HfO5JL5S-26" source="N3hJ6-WijfH2HfO5JL5S-5" target="N3hJ6-WijfH2HfO5JL5S-6" edge="1">
44
+ <mxGeometry relative="1" as="geometry">
45
+ <mxPoint x="220" y="250" as="targetPoint"/>
46
+ </mxGeometry>
47
+ </mxCell>
48
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-12" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="N3hJ6-WijfH2HfO5JL5S-26" source="N3hJ6-WijfH2HfO5JL5S-5" target="N3hJ6-WijfH2HfO5JL5S-8" edge="1">
49
+ <mxGeometry relative="1" as="geometry"/>
50
+ </mxCell>
51
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-13" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="N3hJ6-WijfH2HfO5JL5S-26" source="N3hJ6-WijfH2HfO5JL5S-5" target="N3hJ6-WijfH2HfO5JL5S-4" edge="1">
52
+ <mxGeometry relative="1" as="geometry"/>
53
+ </mxCell>
54
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-5" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="N3hJ6-WijfH2HfO5JL5S-26" vertex="1">
55
+ <mxGeometry x="170" y="140" width="20" height="20" as="geometry"/>
56
+ </mxCell>
57
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-6" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" parent="N3hJ6-WijfH2HfO5JL5S-26" vertex="1">
58
+ <mxGeometry x="230" y="250" width="20" height="20" as="geometry"/>
59
+ </mxCell>
60
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-7" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" parent="N3hJ6-WijfH2HfO5JL5S-26" vertex="1">
61
+ <mxGeometry x="280" y="140" width="20" height="20" as="geometry"/>
62
+ </mxCell>
63
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-8" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="N3hJ6-WijfH2HfO5JL5S-26" vertex="1">
64
+ <mxGeometry x="90" y="260" width="20" height="20" as="geometry"/>
65
+ </mxCell>
66
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-14" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="N3hJ6-WijfH2HfO5JL5S-26" source="N3hJ6-WijfH2HfO5JL5S-8" target="N3hJ6-WijfH2HfO5JL5S-6" edge="1">
67
+ <mxGeometry relative="1" as="geometry">
68
+ <mxPoint x="210" y="250" as="targetPoint"/>
69
+ </mxGeometry>
70
+ </mxCell>
71
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-18" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="N3hJ6-WijfH2HfO5JL5S-26" source="N3hJ6-WijfH2HfO5JL5S-15" target="N3hJ6-WijfH2HfO5JL5S-7" edge="1">
72
+ <mxGeometry relative="1" as="geometry"/>
73
+ </mxCell>
74
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-15" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="N3hJ6-WijfH2HfO5JL5S-26" vertex="1">
75
+ <mxGeometry x="220" y="80" width="20" height="20" as="geometry"/>
76
+ </mxCell>
77
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-16" value="" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" parent="N3hJ6-WijfH2HfO5JL5S-26" vertex="1">
78
+ <mxGeometry x="70" y="110" width="20" height="20" as="geometry"/>
79
+ </mxCell>
80
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-21" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.265;entryY=0.059;entryDx=0;entryDy=0;entryPerimeter=0;endArrow=none;endFill=0;dashed=1;strokeColor=#3399FF;" parent="N3hJ6-WijfH2HfO5JL5S-26" source="N3hJ6-WijfH2HfO5JL5S-1" target="N3hJ6-WijfH2HfO5JL5S-20" edge="1">
81
+ <mxGeometry relative="1" as="geometry"/>
82
+ </mxCell>
83
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-22" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.997;entryY=0.585;entryDx=0;entryDy=0;entryPerimeter=0;endArrow=none;endFill=0;dashed=1;strokeColor=#3399FF;" parent="N3hJ6-WijfH2HfO5JL5S-26" source="N3hJ6-WijfH2HfO5JL5S-6" target="N3hJ6-WijfH2HfO5JL5S-20" edge="1">
84
+ <mxGeometry relative="1" as="geometry"/>
85
+ </mxCell>
86
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-23" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.015;entryY=0.603;entryDx=0;entryDy=0;entryPerimeter=0;endArrow=none;endFill=0;dashed=1;strokeColor=#3399FF;" parent="N3hJ6-WijfH2HfO5JL5S-26" source="N3hJ6-WijfH2HfO5JL5S-4" target="N3hJ6-WijfH2HfO5JL5S-20" edge="1">
87
+ <mxGeometry relative="1" as="geometry">
88
+ <Array as="points"/>
89
+ </mxGeometry>
90
+ </mxCell>
91
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-31" value="(c) 2026 &lt;a href=&quot;https://christoph.diy&quot;&gt;Christoph.diy&lt;/a&gt;&amp;nbsp;CC BY" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=right;verticalAlign=middle;rounded=0;" parent="1" vertex="1">
92
+ <mxGeometry x="880" y="-840" width="185" height="30" as="geometry"/>
93
+ </mxCell>
94
+ <mxCell id="N3hJ6-WijfH2HfO5JL5S-32" value="Encapsulate: Source Code / Semantic Graph Isomorphism - v0.1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;rounded=0;" parent="1" vertex="1">
95
+ <mxGeometry x="360" y="-840" width="420" height="30" as="geometry"/>
96
+ </mxCell>
97
+ </root>
98
+ </mxGraphModel>
99
+ </diagram>
100
+ </mxfile>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1071px" height="481px" viewBox="-0.5 -0.5 1071 481" content="&lt;mxfile&gt;&lt;diagram name=&quot;Page-1&quot; id=&quot;QeIE7gKKPfThrfCM8ygm&quot;&gt;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&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><g><rect x="0" y="0" width="1070" height="480" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 598.24 250 L 641.76 250" fill="none" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 592.24 250 L 600.24 246 L 598.24 250 L 600.24 254 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/><path d="M 647.76 250 L 639.76 254 L 641.76 250 L 639.76 246 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-width="2" stroke-miterlimit="10" pointer-events="all"/><rect x="20" y="40" width="570" height="420" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 568px; height: 1px; padding-top: 47px; margin-left: 21px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Source Code Module</div></div></div></foreignObject><text x="305" y="59" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Source Code Module</text></switch></g><rect x="650" y="40" width="390" height="420" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 388px; height: 1px; padding-top: 47px; margin-left: 651px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Semantic Graph Module</div></div></div></foreignObject><text x="845" y="59" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">Semantic Graph Module</text></switch></g><rect x="45" y="75" width="520" height="370" fill="#fffcf4" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 508px; height: 1px; padding-top: 260px; margin-left: 57px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;"><div style="display: inline-block; font-size: 14px; font-family: &quot;Courier New&quot;; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; overflow-wrap: normal;">const <font style="color: rgb(0, 102, 204);">capsule</font> = await Capsule({<div>  '<font style="color: rgb(204, 102, 0);">#@&lt;org&gt;/&lt;project&gt;/structs/StructA</font>': {</div><div>    as: <span style="background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));">'</span><font style="color: rgb(153, 51, 255);"><span style="background-color: transparent;">$#</span><span style="background-color: transparent;">@&lt;org&gt;/&lt;project&gt;/AspectX</span></font><span style="background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));">'</span></div><div>  }</div><div>  '#'{ </div><div>    <font style="color: rgb(0, 153, 0);">property1</font>: 'val1',</div><div>    <font style="color: rgb(204, 0, 102);">mapping1</font>: '<span style="background-color: transparent;"><font style="color: rgb(204, 0, 102);">@&lt;org&gt;/&lt;project&gt;/FeatureY</font></span><span style="background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));">',</span></div><div>    <font style="color: rgb(0, 153, 0);">method1</font>: () =&gt; {</div><div><div>      this.<span style="background-color: transparent;"><font style="color: light-dark(rgb(204, 0, 102), rgb(255, 255, 255));">mapping1</font></span><span style="background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));">.featureMethod()</span></div></div><div>      this['<font style="color: rgb(153, 51, 255);"><span style="background-color: transparent;">$#</span><span style="background-color: transparent;">@&lt;org&gt;/&lt;project&gt;/AspectX</span></font><span style="background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));">'</span><span style="background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));">]</span><span style="background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));">.instanceMethod2()</span></div><div>    }</div><div>  }<br />}, {<div>  capsuleName: '<font style="color: rgb(0, 102, 204);"><span style="background-color: transparent;">@&lt;org&gt;/&lt;project&gt;/</span><span style="background-color: transparent;">MyCapsule</span></font><span style="background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));">'</span></div><div><div>})</div></div></div><div><br /></div><div><font style="color: rgb(0, 102, 204);">capsule</font>.<span style="background-color: transparent;"><font style="color: light-dark(rgb(0, 153, 0), rgb(255, 255, 255));">property1</font></span></div><div><font style="color: rgb(0, 102, 204);">capsule</font>.<span style="background-color: transparent;"><font style="color: light-dark(rgb(0, 153, 0), rgb(255, 255, 255));">method1</font></span><span style="background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));">()</span></div><div><div><font style="color: rgb(0, 102, 204);">capsule</font>.<span style="color: rgb(204, 0, 102); background-color: transparent;">mapping1</span><span style="background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));">.featureMethod</span><span style="background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));">()</span></div></div><div><div><div><font style="color: rgb(0, 102, 204);">capsule</font>['<font style="color: rgb(204, 102, 0);">#@&lt;org&gt;/&lt;project&gt;/structs/StructA</font><span style="background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));">'</span><span style="background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));">].protoMethod1</span><span style="background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));">()</span></div></div><div><font style="color: rgb(0, 102, 204);">capsule</font>['<font style="color: rgb(153, 51, 255);"><span style="background-color: transparent;">$#</span><span style="background-color: transparent;">@&lt;org&gt;/&lt;project&gt;/AspectX</span></font><span style="background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));">'</span><span style="background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));">].</span>instanceMethod2<span style="background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));">()</span></div></div></div></div></div></foreignObject><text x="57" y="264" fill="rgb(0, 0, 0)" font-family="Courier New" font-size="14px" font-weight="bold">const capsule = await Capsule({...</text></switch></g><rect x="675" y="90" width="340" height="340" fill="rgb(255, 255, 255)" stroke="none" pointer-events="all"/><ellipse cx="845" cy="260" rx="170" ry="170" fill="#fffcf4" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 809.86 158.74 L 850.14 231.26" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><ellipse cx="805" cy="150" rx="10" ry="10" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 737.73 270.38 L 752.25 219.62" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><ellipse cx="735" cy="280" rx="10" ry="10" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"/><path d="M 865 240 L 955 240" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 859.54 248.91 L 907.93 342.93" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 849.45 248.32 L 780.55 351.68" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 845.5 243.11 L 744.49 276.84" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><ellipse cx="855" cy="240" rx="10" ry="10" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"/><ellipse cx="915" cy="350" rx="10" ry="10" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><ellipse cx="965" cy="240" rx="10" ry="10" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><ellipse cx="775" cy="360" rx="10" ry="10" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"/><path d="M 784.98 359.31 L 905.03 350.71" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 912.07 187.07 L 957.93 232.93" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><ellipse cx="905" cy="180" rx="10" ry="10" fill="#dae8fc" stroke="#6c8ebf" pointer-events="all"/><ellipse cx="755" cy="210" rx="10" ry="10" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 797.93 142.93 L 765.1 110.06" fill="none" stroke="#3399ff" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 923.49 344.72 L 1013.98 288.9" fill="none" stroke="#3399ff" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 725.36 282.68 L 680.1 295.02" fill="none" stroke="#3399ff" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><rect x="870" y="0" width="185" height="30" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-end; width: 183px; height: 1px; padding-top: 15px; margin-left: 870px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: right;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">(c) 2026 <a href="https://christoph.diy">Christoph.diy</a> CC BY</div></div></div></foreignObject><text x="1053" y="19" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="end">(c) 2026 Christoph.diy CC BY</text></switch></g><rect x="350" y="0" width="420" height="30" fill="none" stroke="none" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 418px; height: 1px; padding-top: 15px; margin-left: 352px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: left;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Encapsulate: Source Code / Semantic Graph Isomorphism - v0.1</div></div></div></foreignObject><text x="352" y="19" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px">Encapsulate: Source Code / Semantic Graph Isomorphism - v0.1</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stream44.studio/encapsulate",
3
- "version": "0.4.0-rc.24",
3
+ "version": "0.4.0-rc.26",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -55,7 +55,8 @@ type TCapsuleMakeInstanceOptions = {
55
55
  moduleFilepath: string
56
56
  },
57
57
  parentCapsuleSourceUriLineRefInstanceId?: string,
58
- sit?: { capsuleInstances: Record<string, { capsuleName: string, capsuleSourceUriLineRef: string, parentCapsuleSourceUriLineRefInstanceId: string }> }
58
+ sit?: { capsuleInstances: Record<string, { capsuleName: string, capsuleSourceUriLineRef: string, parentCapsuleSourceUriLineRefInstanceId: string }> },
59
+ skipCache?: boolean
59
60
  }
60
61
 
61
62
  type TCapsule = {
@@ -554,13 +555,15 @@ async function encapsulate(definition: TCapsuleDefinition, options: TCapsuleOpti
554
555
  encapsulateOptions,
555
556
  cst,
556
557
  crt: crts?.[capsuleSourceLineRef],
557
- makeInstance: async ({ overrides = {}, options = {}, runtimeSpineContracts, sharedSelf, rootCapsule, parentCapsuleSourceUriLineRefInstanceId, sit }: TCapsuleMakeInstanceOptions = {}) => {
558
+ makeInstance: async ({ overrides = {}, options = {}, runtimeSpineContracts, sharedSelf, rootCapsule, parentCapsuleSourceUriLineRefInstanceId, sit, skipCache }: TCapsuleMakeInstanceOptions = {}) => {
558
559
 
559
560
  // Create cache key based on parameters
560
561
  // When sharedSelf is provided, we must NOT cache because each extending capsule
561
562
  // needs its own instance with its own 'this' context (sharedSelf).
562
563
  // This is critical for the pattern where multiple structs extend the same parent.
563
- const cacheKey = sharedSelf ? null : JSON.stringify({
564
+ // When skipCache is true (property contract delegates like structs/Capsule),
565
+ // each parent capsule must get its own unique instance.
566
+ const cacheKey = (sharedSelf || skipCache) ? null : JSON.stringify({
564
567
  overrides,
565
568
  options,
566
569
  hasRuntimeContracts: !!runtimeSpineContracts
@@ -149,9 +149,11 @@ class MembraneContractCapsuleInstanceFactory extends ContractCapsuleInstanceFact
149
149
 
150
150
  // Check for existing instance in registry - reuse if available (regardless of options)
151
151
  // Pre-registration with null allows parent capsules to "claim" a slot before child capsules process
152
+ // Property contract delegates (structs) always get a fresh instance per parent capsule
152
153
  const capsuleName = mappedCapsule.encapsulateOptions?.capsuleName
154
+ const isCapsuleStruct = property.definition.propertyContractDelegate === '#@stream44.studio/encapsulate/structs/Capsule'
153
155
 
154
- if (capsuleName && this.instanceRegistry) {
156
+ if (capsuleName && this.instanceRegistry && !isCapsuleStruct) {
155
157
  if (this.instanceRegistry.has(capsuleName)) {
156
158
  const existingEntry = this.instanceRegistry.get(capsuleName)
157
159
 
@@ -275,12 +277,16 @@ class MembraneContractCapsuleInstanceFactory extends ContractCapsuleInstanceFact
275
277
  overrides: mappedOverrides,
276
278
  options: ownMappingOptions,
277
279
  runtimeSpineContracts: this.runtimeSpineContracts,
278
- rootCapsule: this.capsuleInstance?.rootCapsule
280
+ rootCapsule: this.capsuleInstance?.rootCapsule,
281
+ parentCapsuleSourceUriLineRefInstanceId: this.capsuleInstance?.capsuleSourceUriLineRefInstanceId,
282
+ sit: this.capsuleInstance?.sit,
283
+ skipCache: isCapsuleStruct
279
284
  })
280
285
 
281
286
  // Register the instance (replaces null pre-registration marker)
282
287
  // Always register to make instance available for child capsules with deferred proxies
283
- if (capsuleName && this.instanceRegistry) {
288
+ // Property contract delegates skip registry (each parent gets its own instance)
289
+ if (capsuleName && this.instanceRegistry && !isCapsuleStruct) {
284
290
  this.instanceRegistry.set(capsuleName, mappedCapsuleInstance)
285
291
  }
286
292
 
@@ -206,9 +206,11 @@ export class ContractCapsuleInstanceFactory {
206
206
 
207
207
  // Check for existing instance in registry - reuse if available when no options
208
208
  // Pre-registration with null allows parent capsules to "claim" a slot before child capsules process
209
+ // Property contract delegates (structs) always get a fresh instance per parent capsule
209
210
  const capsuleName = mappedCapsule.encapsulateOptions?.capsuleName
211
+ const isCapsuleStruct = property.definition.propertyContractDelegate === '#@stream44.studio/encapsulate/structs/Capsule'
210
212
 
211
- if (capsuleName && this.instanceRegistry) {
213
+ if (capsuleName && this.instanceRegistry && !isCapsuleStruct) {
212
214
  if (this.instanceRegistry.has(capsuleName)) {
213
215
  const existingEntry = this.instanceRegistry.get(capsuleName)
214
216
 
@@ -315,12 +317,14 @@ export class ContractCapsuleInstanceFactory {
315
317
  runtimeSpineContracts: this.runtimeSpineContracts,
316
318
  rootCapsule: this.capsuleInstance?.rootCapsule,
317
319
  parentCapsuleSourceUriLineRefInstanceId: this.capsuleInstance?.capsuleSourceUriLineRefInstanceId,
318
- sit: this.capsuleInstance?.sit
320
+ sit: this.capsuleInstance?.sit,
321
+ skipCache: isCapsuleStruct
319
322
  })
320
323
 
321
324
  // Register the instance (replaces null pre-registration marker)
322
325
  // Always register to make instance available for child capsules with deferred proxies
323
- if (capsuleName && this.instanceRegistry) {
326
+ // Property contract delegates skip registry (each parent gets its own instance)
327
+ if (capsuleName && this.instanceRegistry && !isCapsuleStruct) {
324
328
  this.instanceRegistry.set(capsuleName, mappedInstance)
325
329
  }
326
330
 
@@ -642,33 +642,28 @@ export async function CapsuleSpineFactory({
642
642
  const rootInstance = await capsule.makeInstance()
643
643
  const capsuleInstances: Record<string, { capsuleName: string, capsuleSourceUriLineRef: string, parentCapsuleSourceUriLineRefInstanceId: string }> = {}
644
644
 
645
- // If the root instance has a sit with pre-populated capsuleInstances, use it directly
646
- if (rootInstance.sit?.capsuleInstances && Object.keys(rootInstance.sit.capsuleInstances).length > 0) {
647
- Object.assign(capsuleInstances, rootInstance.sit.capsuleInstances)
648
- } else {
649
- // Iterative stack-based collection from instance tree
650
- const stack: Array<{ instance: any, parentId: string }> = [{ instance: rootInstance, parentId: '' }]
651
- const visited = new Set<string>()
652
- while (stack.length > 0) {
653
- const { instance, parentId } = stack.pop()!
654
- if (!instance?.capsuleSourceUriLineRefInstanceId) continue
655
- const id = instance.capsuleSourceUriLineRefInstanceId
656
- if (visited.has(id)) continue
657
- visited.add(id)
658
-
659
- capsuleInstances[id] = {
660
- capsuleName: instance.capsuleName || '',
661
- capsuleSourceUriLineRef: instance.capsuleSourceUriLineRef || '',
662
- parentCapsuleSourceUriLineRefInstanceId: parentId
663
- }
645
+ // Iterative stack-based collection from instance tree
646
+ const stack: Array<{ instance: any, parentId: string }> = [{ instance: rootInstance, parentId: '' }]
647
+ const visited = new Set<string>()
648
+ while (stack.length > 0) {
649
+ const { instance, parentId } = stack.pop()!
650
+ if (!instance?.capsuleSourceUriLineRefInstanceId) continue
651
+ const id = instance.capsuleSourceUriLineRefInstanceId
652
+ if (visited.has(id)) continue
653
+ visited.add(id)
654
+
655
+ capsuleInstances[id] = {
656
+ capsuleName: instance.capsuleName || '',
657
+ capsuleSourceUriLineRef: instance.capsuleSourceUriLineRef || '',
658
+ parentCapsuleSourceUriLineRefInstanceId: parentId
659
+ }
664
660
 
665
- if (instance.extendedCapsuleInstance) {
666
- stack.push({ instance: instance.extendedCapsuleInstance, parentId: id })
667
- }
668
- if (instance.mappedCapsuleInstances) {
669
- for (const mapped of instance.mappedCapsuleInstances) {
670
- stack.push({ instance: mapped, parentId: id })
671
- }
661
+ if (instance.extendedCapsuleInstance) {
662
+ stack.push({ instance: instance.extendedCapsuleInstance, parentId: id })
663
+ }
664
+ if (instance.mappedCapsuleInstances) {
665
+ for (const mapped of instance.mappedCapsuleInstances) {
666
+ stack.push({ instance: mapped, parentId: id })
672
667
  }
673
668
  }
674
669
  }