@stream44.studio/encapsulate 0.4.0-rc.26 → 0.4.0-rc.28
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/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<td><a href="https://Stream44.Studio"><img src=".o/stream44.studio/assets/Icon-v1.svg" width="42" height="42"></a></td>
|
|
4
4
|
<td><strong><a href="https://Stream44.Studio">Stream44 Studio</a></strong><br/>Open Development Project</td>
|
|
5
5
|
<td>Preview release for community feedback.<br/>Get in touch on <a href="https://discord.gg/9eBcQXEJAN">discord</a>.</td>
|
|
6
|
-
<td>Hand
|
|
6
|
+
<td>Designed by Hand<br/><b>AI assisted Code</a></td>
|
|
7
7
|
</tr>
|
|
8
8
|
</table>
|
|
9
9
|
|
package/package.json
CHANGED
|
@@ -417,6 +417,7 @@ class MembraneContractCapsuleInstanceFactory extends ContractCapsuleInstanceFact
|
|
|
417
417
|
const event: any = {
|
|
418
418
|
event: 'get',
|
|
419
419
|
eventIndex: this.incrementEventIndex(),
|
|
420
|
+
membrane: 'external',
|
|
420
421
|
target: {
|
|
421
422
|
capsuleSourceLineRef: this.encapsulateOptions.capsuleSourceLineRef,
|
|
422
423
|
spineContractCapsuleInstanceId: this.id,
|
|
@@ -445,6 +446,7 @@ class MembraneContractCapsuleInstanceFactory extends ContractCapsuleInstanceFact
|
|
|
445
446
|
const event: any = {
|
|
446
447
|
event: 'set',
|
|
447
448
|
eventIndex: this.incrementEventIndex(),
|
|
449
|
+
membrane: 'external',
|
|
448
450
|
target: {
|
|
449
451
|
capsuleSourceLineRef: this.encapsulateOptions.capsuleSourceLineRef,
|
|
450
452
|
spineContractCapsuleInstanceId: this.id,
|
|
@@ -511,6 +513,7 @@ class MembraneContractCapsuleInstanceFactory extends ContractCapsuleInstanceFact
|
|
|
511
513
|
const callEvent: any = {
|
|
512
514
|
event: 'call',
|
|
513
515
|
eventIndex: this.incrementEventIndex(),
|
|
516
|
+
membrane: 'external',
|
|
514
517
|
target: {
|
|
515
518
|
capsuleSourceLineRef: this.encapsulateOptions.capsuleSourceLineRef,
|
|
516
519
|
spineContractCapsuleInstanceId: this.id,
|
|
@@ -536,6 +539,7 @@ class MembraneContractCapsuleInstanceFactory extends ContractCapsuleInstanceFact
|
|
|
536
539
|
const resultEvent: any = {
|
|
537
540
|
event: 'call-result',
|
|
538
541
|
eventIndex: this.incrementEventIndex(),
|
|
542
|
+
membrane: 'external',
|
|
539
543
|
callEventIndex: callEvent.eventIndex,
|
|
540
544
|
target: {
|
|
541
545
|
spineContractCapsuleInstanceId: this.id,
|
|
@@ -552,6 +556,7 @@ class MembraneContractCapsuleInstanceFactory extends ContractCapsuleInstanceFact
|
|
|
552
556
|
const callEvent: any = {
|
|
553
557
|
event: 'call',
|
|
554
558
|
eventIndex: this.incrementEventIndex(),
|
|
559
|
+
membrane: 'external',
|
|
555
560
|
target: {
|
|
556
561
|
capsuleSourceLineRef: this.encapsulateOptions.capsuleSourceLineRef,
|
|
557
562
|
spineContractCapsuleInstanceId: this.id,
|
|
@@ -588,6 +593,7 @@ class MembraneContractCapsuleInstanceFactory extends ContractCapsuleInstanceFact
|
|
|
588
593
|
const resultEvent: any = {
|
|
589
594
|
event: 'call-result',
|
|
590
595
|
eventIndex: this.incrementEventIndex(),
|
|
596
|
+
membrane: 'external',
|
|
591
597
|
callEventIndex: callEvent.eventIndex,
|
|
592
598
|
target: {
|
|
593
599
|
spineContractCapsuleInstanceId: this.id,
|
|
@@ -637,6 +643,7 @@ class MembraneContractCapsuleInstanceFactory extends ContractCapsuleInstanceFact
|
|
|
637
643
|
const event: any = {
|
|
638
644
|
event: 'get',
|
|
639
645
|
eventIndex: this.incrementEventIndex(),
|
|
646
|
+
membrane: 'external',
|
|
640
647
|
target: {
|
|
641
648
|
capsuleSourceLineRef: this.encapsulateOptions.capsuleSourceLineRef,
|
|
642
649
|
spineContractCapsuleInstanceId: this.id,
|
|
@@ -673,6 +680,7 @@ class MembraneContractCapsuleInstanceFactory extends ContractCapsuleInstanceFact
|
|
|
673
680
|
const event: any = {
|
|
674
681
|
event: 'get',
|
|
675
682
|
eventIndex: this.incrementEventIndex(),
|
|
683
|
+
membrane: 'external',
|
|
676
684
|
target: {
|
|
677
685
|
capsuleSourceLineRef: this.encapsulateOptions.capsuleSourceLineRef,
|
|
678
686
|
spineContractCapsuleInstanceId: this.id,
|
|
@@ -718,6 +726,134 @@ class MembraneContractCapsuleInstanceFactory extends ContractCapsuleInstanceFact
|
|
|
718
726
|
}
|
|
719
727
|
}
|
|
720
728
|
|
|
729
|
+
protected override createSelfProxy() {
|
|
730
|
+
const extendedApi = this.extendedCapsuleInstance?.api
|
|
731
|
+
const ownSelf = this.ownSelf
|
|
732
|
+
const factory = this
|
|
733
|
+
return new Proxy(this.self, {
|
|
734
|
+
get: (target: any, prop: string | symbol) => {
|
|
735
|
+
if (typeof prop === 'symbol') return target[prop]
|
|
736
|
+
|
|
737
|
+
// 'self' property returns ownSelf (only this capsule's own properties)
|
|
738
|
+
if (prop === 'self' && ownSelf) {
|
|
739
|
+
return ownSelf
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
// Determine the value source and get the value
|
|
743
|
+
let value: any
|
|
744
|
+
let source: 'self' | 'encapsulatedApi' | 'childApi' | 'extendedApi' | undefined
|
|
745
|
+
|
|
746
|
+
if (prop in target) {
|
|
747
|
+
value = target[prop]
|
|
748
|
+
source = 'self'
|
|
749
|
+
} else if (prop in factory.encapsulatedApi) {
|
|
750
|
+
value = factory.encapsulatedApi[prop]
|
|
751
|
+
source = 'encapsulatedApi'
|
|
752
|
+
} else if (factory.childEncapsulatedApis) {
|
|
753
|
+
for (const childApi of factory.childEncapsulatedApis) {
|
|
754
|
+
if (prop in childApi) {
|
|
755
|
+
value = childApi[prop]
|
|
756
|
+
source = 'childApi'
|
|
757
|
+
break
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
if (source === undefined && extendedApi && prop in extendedApi) {
|
|
763
|
+
value = extendedApi[prop]
|
|
764
|
+
source = 'extendedApi'
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
// Only emit internal events if we're inside a function/getter execution (caller context is set)
|
|
768
|
+
// and the property is not a function (we don't want to emit get events for function references)
|
|
769
|
+
if (source && typeof value !== 'function' && this.getCurrentCallerContext()) {
|
|
770
|
+
const event: any = {
|
|
771
|
+
event: 'get',
|
|
772
|
+
eventIndex: this.incrementEventIndex(),
|
|
773
|
+
membrane: 'internal',
|
|
774
|
+
target: {
|
|
775
|
+
capsuleSourceLineRef: this.encapsulateOptions.capsuleSourceLineRef,
|
|
776
|
+
spineContractCapsuleInstanceId: this.id,
|
|
777
|
+
prop: prop as string,
|
|
778
|
+
},
|
|
779
|
+
value
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
if (this.capsuleSourceNameRef) {
|
|
783
|
+
event.target.capsuleSourceNameRef = this.capsuleSourceNameRef
|
|
784
|
+
}
|
|
785
|
+
if (this.capsuleSourceNameRefHash) {
|
|
786
|
+
event.target.capsuleSourceNameRefHash = this.capsuleSourceNameRefHash
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
this.addCallerContextToEvent(event)
|
|
790
|
+
this.onMembraneEvent?.(event)
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
return value
|
|
794
|
+
},
|
|
795
|
+
ownKeys: (target: any) => {
|
|
796
|
+
const keys = new Set<string>(Object.keys(target))
|
|
797
|
+
for (const k of Object.keys(factory.encapsulatedApi)) keys.add(k)
|
|
798
|
+
if (factory.childEncapsulatedApis) {
|
|
799
|
+
for (const childApi of factory.childEncapsulatedApis) {
|
|
800
|
+
for (const k of Object.keys(childApi)) keys.add(k)
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
if (extendedApi) {
|
|
804
|
+
for (const k of Object.keys(extendedApi)) keys.add(k)
|
|
805
|
+
}
|
|
806
|
+
return [...keys]
|
|
807
|
+
},
|
|
808
|
+
set: (target: any, prop: string | symbol, value: any) => {
|
|
809
|
+
if (typeof prop === 'symbol') {
|
|
810
|
+
target[prop] = value
|
|
811
|
+
return true
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
// Emit internal set event if we're inside a function/getter execution
|
|
815
|
+
if (this.getCurrentCallerContext()) {
|
|
816
|
+
const event: any = {
|
|
817
|
+
event: 'set',
|
|
818
|
+
eventIndex: this.incrementEventIndex(),
|
|
819
|
+
membrane: 'internal',
|
|
820
|
+
target: {
|
|
821
|
+
capsuleSourceLineRef: this.encapsulateOptions.capsuleSourceLineRef,
|
|
822
|
+
spineContractCapsuleInstanceId: this.id,
|
|
823
|
+
prop: prop as string,
|
|
824
|
+
},
|
|
825
|
+
value
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
if (this.capsuleSourceNameRef) {
|
|
829
|
+
event.target.capsuleSourceNameRef = this.capsuleSourceNameRef
|
|
830
|
+
}
|
|
831
|
+
if (this.capsuleSourceNameRefHash) {
|
|
832
|
+
event.target.capsuleSourceNameRefHash = this.capsuleSourceNameRefHash
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
this.addCallerContextToEvent(event)
|
|
836
|
+
this.onMembraneEvent?.(event)
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
target[prop] = value
|
|
840
|
+
return true
|
|
841
|
+
},
|
|
842
|
+
getOwnPropertyDescriptor: (target: any, prop: string | symbol) => {
|
|
843
|
+
if (typeof prop === 'symbol') return Object.getOwnPropertyDescriptor(target, prop)
|
|
844
|
+
if (prop in target) return Object.getOwnPropertyDescriptor(target, prop)
|
|
845
|
+
if (prop in factory.encapsulatedApi) return { configurable: true, enumerable: true, writable: true, value: factory.encapsulatedApi[prop as string] }
|
|
846
|
+
if (factory.childEncapsulatedApis) {
|
|
847
|
+
for (const childApi of factory.childEncapsulatedApis) {
|
|
848
|
+
if (prop in childApi) return { configurable: true, enumerable: true, writable: true, value: childApi[prop as string] }
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
if (extendedApi && prop in extendedApi) return { configurable: true, enumerable: true, writable: true, value: extendedApi[prop as string] }
|
|
852
|
+
return undefined
|
|
853
|
+
}
|
|
854
|
+
})
|
|
855
|
+
}
|
|
856
|
+
|
|
721
857
|
private addCallerContextToEvent(event: any): void {
|
|
722
858
|
const callerCtx = this.getCurrentCallerContext()
|
|
723
859
|
if (callerCtx) {
|
|
@@ -782,6 +918,20 @@ export function CapsuleSpineContract({
|
|
|
782
918
|
let currentCallerContext: CallerContext | undefined = undefined
|
|
783
919
|
const instanceRegistry: CapsuleInstanceRegistry = new Map()
|
|
784
920
|
|
|
921
|
+
// Re-entrancy guard: suppress event emission while inside an onMembraneEvent callback.
|
|
922
|
+
// This prevents consumers (e.g. JSON.stringify on event.value) from triggering proxy getters
|
|
923
|
+
// that would cause spurious recursive membrane events with wrong caller context and ordering.
|
|
924
|
+
let isEmittingEvent = false
|
|
925
|
+
const guardedOnMembraneEvent = onMembraneEvent ? (event: any) => {
|
|
926
|
+
if (isEmittingEvent) return
|
|
927
|
+
isEmittingEvent = true
|
|
928
|
+
try {
|
|
929
|
+
onMembraneEvent(event)
|
|
930
|
+
} finally {
|
|
931
|
+
isEmittingEvent = false
|
|
932
|
+
}
|
|
933
|
+
} : undefined
|
|
934
|
+
|
|
785
935
|
return {
|
|
786
936
|
'#': CapsuleSpineContract['#'],
|
|
787
937
|
instanceRegistry,
|
|
@@ -796,7 +946,7 @@ export function CapsuleSpineContract({
|
|
|
796
946
|
freezeCapsule,
|
|
797
947
|
resolve,
|
|
798
948
|
importCapsule,
|
|
799
|
-
onMembraneEvent,
|
|
949
|
+
onMembraneEvent: guardedOnMembraneEvent,
|
|
800
950
|
enableCallerStackInference,
|
|
801
951
|
encapsulateOptions,
|
|
802
952
|
getEventIndex: () => eventIndex,
|