@spearwolf/shadow-objects 0.33.0 → 0.34.0
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/CHANGELOG.md +320 -61
- package/README.md +57 -13
- package/bundle.js +5 -54
- package/package.json +7 -3
- package/src/ChangeTrailRefusedError.d.ts +27 -0
- package/src/ChangeTrailRefusedError.d.ts.map +1 -0
- package/src/ChangeTrailRefusedError.js +12 -0
- package/src/ChangeTrailRefusedError.js.map +7 -0
- package/src/EntityUuidInUseError.d.ts +19 -0
- package/src/EntityUuidInUseError.d.ts.map +1 -0
- package/src/EntityUuidInUseError.js +11 -0
- package/src/EntityUuidInUseError.js.map +7 -0
- package/src/WorkerTimeoutError.d.ts +25 -0
- package/src/WorkerTimeoutError.d.ts.map +1 -0
- package/src/WorkerTimeoutError.js +12 -0
- package/src/WorkerTimeoutError.js.map +7 -0
- package/src/bundle.d.ts +1 -1
- package/src/bundle.d.ts.map +1 -1
- package/src/bundle.js +1 -1
- package/src/bundle.js.map +2 -2
- package/src/constants.d.ts +9 -2
- package/src/constants.d.ts.map +1 -1
- package/src/constants.js +1 -1
- package/src/constants.js.map +2 -2
- package/src/create-worker.bundle.d.ts +1 -1
- package/src/create-worker.bundle.d.ts.map +1 -1
- package/src/create-worker.bundle.js.map +1 -1
- package/src/create-worker.d.ts +1 -1
- package/src/create-worker.d.ts.map +1 -1
- package/src/create-worker.js.map +1 -1
- package/src/elements/ShaeElement.d.ts +70 -2
- package/src/elements/ShaeElement.d.ts.map +1 -1
- package/src/elements/ShaeElement.js +129 -25
- package/src/elements/ShaeElement.js.map +3 -3
- package/src/elements/ShaeEntElement.d.ts +39 -1
- package/src/elements/ShaeEntElement.d.ts.map +1 -1
- package/src/elements/ShaeEntElement.js +397 -167
- package/src/elements/ShaeEntElement.js.map +2 -2
- package/src/elements/ShaeLifecycleElement.d.ts +71 -0
- package/src/elements/ShaeLifecycleElement.d.ts.map +1 -0
- package/src/elements/ShaeLifecycleElement.js +83 -0
- package/src/elements/ShaeLifecycleElement.js.map +7 -0
- package/src/elements/ShaePropElement.d.ts +52 -2
- package/src/elements/ShaePropElement.d.ts.map +1 -1
- package/src/elements/ShaePropElement.js +240 -219
- package/src/elements/ShaePropElement.js.map +2 -2
- package/src/elements/ShaeWorkerElement.d.ts +49 -5
- package/src/elements/ShaeWorkerElement.d.ts.map +1 -1
- package/src/elements/ShaeWorkerElement.js +204 -73
- package/src/elements/ShaeWorkerElement.js.map +2 -2
- package/src/elements/constants.d.ts +6 -0
- package/src/elements/constants.d.ts.map +1 -1
- package/src/elements/constants.js +12 -0
- package/src/elements/constants.js.map +2 -2
- package/src/elements/deferredTeardown.d.ts +24 -0
- package/src/elements/deferredTeardown.d.ts.map +1 -0
- package/src/elements/deferredTeardown.js +30 -0
- package/src/elements/deferredTeardown.js.map +7 -0
- package/src/elements/displayContentsRule.d.ts +25 -0
- package/src/elements/displayContentsRule.d.ts.map +1 -0
- package/src/elements/displayContentsRule.js +37 -0
- package/src/elements/displayContentsRule.js.map +7 -0
- package/src/elements/events.d.ts +10 -7
- package/src/elements/events.d.ts.map +1 -1
- package/src/elements/forwardCustomEvents.d.ts +19 -0
- package/src/elements/forwardCustomEvents.d.ts.map +1 -0
- package/src/elements/forwardCustomEvents.js +47 -0
- package/src/elements/forwardCustomEvents.js.map +7 -0
- package/src/elements/hostedSlots.d.ts +36 -0
- package/src/elements/hostedSlots.d.ts.map +1 -0
- package/src/elements/hostedSlots.js +118 -0
- package/src/elements/hostedSlots.js.map +7 -0
- package/src/elements/parentRemoval.d.ts +18 -0
- package/src/elements/parentRemoval.d.ts.map +1 -0
- package/src/elements/parentRemoval.js +60 -0
- package/src/elements/parentRemoval.js.map +7 -0
- package/src/elements/propValueConverters.d.ts +3 -0
- package/src/elements/propValueConverters.d.ts.map +1 -0
- package/src/elements/propValueConverters.js +54 -0
- package/src/elements/propValueConverters.js.map +7 -0
- package/src/elements/requestEntAncestor.d.ts +32 -0
- package/src/elements/requestEntAncestor.d.ts.map +1 -0
- package/src/elements/requestEntAncestor.js +16 -0
- package/src/elements/requestEntAncestor.js.map +7 -0
- package/src/elements.js.map +1 -1
- package/src/in-the-dark/Entity.d.ts +113 -3
- package/src/in-the-dark/Entity.d.ts.map +1 -1
- package/src/in-the-dark/Entity.js +292 -63
- package/src/in-the-dark/Entity.js.map +3 -3
- package/src/in-the-dark/Kernel.d.ts +76 -17
- package/src/in-the-dark/Kernel.d.ts.map +1 -1
- package/src/in-the-dark/Kernel.js +410 -378
- package/src/in-the-dark/Kernel.js.map +3 -3
- package/src/in-the-dark/Registry.d.ts.map +1 -1
- package/src/in-the-dark/Registry.js +83 -14
- package/src/in-the-dark/Registry.js.map +2 -2
- package/src/in-the-dark/ShadowObject.d.ts.map +1 -1
- package/src/in-the-dark/ShadowObject.js +1 -0
- package/src/in-the-dark/ShadowObject.js.map +2 -2
- package/src/in-the-dark/ShadowObjectCreationScope.d.ts +126 -0
- package/src/in-the-dark/ShadowObjectCreationScope.d.ts.map +1 -0
- package/src/in-the-dark/ShadowObjectCreationScope.js +596 -0
- package/src/in-the-dark/ShadowObjectCreationScope.js.map +7 -0
- package/src/in-the-dark/SignalsPath.d.ts.map +1 -1
- package/src/in-the-dark/SignalsPath.js +2 -2
- package/src/in-the-dark/SignalsPath.js.map +2 -2
- package/src/in-the-dark/events.js.map +1 -1
- package/src/in-the-dark/importModule.d.ts +7 -0
- package/src/in-the-dark/importModule.d.ts.map +1 -1
- package/src/in-the-dark/importModule.js +5 -2
- package/src/in-the-dark/importModule.js.map +2 -2
- package/src/index.d.ts +7 -1
- package/src/index.d.ts.map +1 -1
- package/src/index.js +5 -1
- package/src/index.js.map +2 -2
- package/src/shadow-objects.d.ts +2 -0
- package/src/shadow-objects.d.ts.map +1 -1
- package/src/shadow-objects.js +2 -0
- package/src/shadow-objects.js.map +2 -2
- package/src/shadow-objects.worker.js +0 -1
- package/src/shadow-objects.worker.js.map +2 -2
- package/src/shae-ent.js.map +1 -1
- package/src/shae-prop.js +2 -2
- package/src/shae-prop.js.map +2 -2
- package/src/shae-worker.js.map +1 -1
- package/src/types.d.ts +35 -4
- package/src/types.d.ts.map +1 -1
- package/src/utils/ConsoleLogger.d.ts +45 -10
- package/src/utils/ConsoleLogger.d.ts.map +1 -1
- package/src/utils/ConsoleLogger.js +51 -26
- package/src/utils/ConsoleLogger.js.map +2 -2
- package/src/utils/FrameLoop.d.ts +42 -3
- package/src/utils/FrameLoop.d.ts.map +1 -1
- package/src/utils/FrameLoop.js +71 -10
- package/src/utils/FrameLoop.js.map +2 -2
- package/src/utils/MicrotaskCollector.d.ts +45 -0
- package/src/utils/MicrotaskCollector.d.ts.map +1 -0
- package/src/utils/MicrotaskCollector.js +33 -0
- package/src/utils/MicrotaskCollector.js.map +7 -0
- package/src/utils/MicrotaskGate.d.ts +17 -0
- package/src/utils/MicrotaskGate.d.ts.map +1 -0
- package/src/utils/MicrotaskGate.js +20 -0
- package/src/utils/MicrotaskGate.js.map +7 -0
- package/src/utils/array-utils.js.map +1 -1
- package/src/utils/attr-utils.d.ts +6 -0
- package/src/utils/attr-utils.d.ts.map +1 -1
- package/src/utils/attr-utils.js +3 -1
- package/src/utils/attr-utils.js.map +2 -2
- package/src/utils/constants.js.map +1 -1
- package/src/utils/generateUUID.d.ts +11 -0
- package/src/utils/generateUUID.d.ts.map +1 -1
- package/src/utils/generateUUID.js +31 -266
- package/src/utils/generateUUID.js.map +2 -2
- package/src/utils/props-utils.d.ts +3 -2
- package/src/utils/props-utils.d.ts.map +1 -1
- package/src/utils/props-utils.js +13 -24
- package/src/utils/props-utils.js.map +2 -2
- package/src/utils/runGuarded.d.ts +27 -0
- package/src/utils/runGuarded.d.ts.map +1 -0
- package/src/utils/runGuarded.js +11 -0
- package/src/utils/runGuarded.js.map +7 -0
- package/src/utils/toMaybe.d.ts.map +1 -1
- package/src/utils/toMaybe.js.map +1 -1
- package/src/utils/toNamespace.d.ts.map +1 -1
- package/src/utils/toNamespace.js.map +1 -1
- package/src/utils/toUrlString.d.ts +12 -0
- package/src/utils/toUrlString.d.ts.map +1 -1
- package/src/utils/toUrlString.js.map +2 -2
- package/src/utils/waitForMessageOfType.d.ts +12 -1
- package/src/utils/waitForMessageOfType.d.ts.map +1 -1
- package/src/utils/waitForMessageOfType.js +16 -1
- package/src/utils/waitForMessageOfType.js.map +2 -2
- package/src/view/ComponentChanges.d.ts +88 -1
- package/src/view/ComponentChanges.d.ts.map +1 -1
- package/src/view/ComponentChanges.js +243 -73
- package/src/view/ComponentChanges.js.map +2 -2
- package/src/view/ComponentContext.d.ts +206 -16
- package/src/view/ComponentContext.d.ts.map +1 -1
- package/src/view/ComponentContext.js +548 -91
- package/src/view/ComponentContext.js.map +2 -2
- package/src/view/ComponentMemory.d.ts +3 -3
- package/src/view/ComponentMemory.d.ts.map +1 -1
- package/src/view/ComponentMemory.js.map +1 -1
- package/src/view/IShadowObjectEnvProxy.d.ts +29 -3
- package/src/view/IShadowObjectEnvProxy.d.ts.map +1 -1
- package/src/view/LocalShadowObjectEnv.d.ts +1 -1
- package/src/view/LocalShadowObjectEnv.d.ts.map +1 -1
- package/src/view/LocalShadowObjectEnv.js +8 -6
- package/src/view/LocalShadowObjectEnv.js.map +2 -2
- package/src/view/RemoteWorkerEnv.d.ts +89 -5
- package/src/view/RemoteWorkerEnv.d.ts.map +1 -1
- package/src/view/RemoteWorkerEnv.js +195 -77
- package/src/view/RemoteWorkerEnv.js.map +2 -2
- package/src/view/ShadowEnv.d.ts +49 -2
- package/src/view/ShadowEnv.d.ts.map +1 -1
- package/src/view/ShadowEnv.js +223 -60
- package/src/view/ShadowEnv.js.map +2 -2
- package/src/view/ViewComponent.d.ts +78 -14
- package/src/view/ViewComponent.d.ts.map +1 -1
- package/src/view/ViewComponent.js +90 -14
- package/src/view/ViewComponent.js.map +2 -2
- package/src/view/cloneChangeTrail.js.map +2 -2
- package/src/worker/MessageRouter.d.ts +14 -0
- package/src/worker/MessageRouter.d.ts.map +1 -1
- package/src/worker/MessageRouter.js +75 -15
- package/src/worker/MessageRouter.js.map +2 -2
- package/src/worker/WorkerRuntime.d.ts +22 -1
- package/src/worker/WorkerRuntime.d.ts.map +1 -1
- package/src/worker/WorkerRuntime.js +60 -8
- package/src/worker/WorkerRuntime.js.map +2 -2
|
@@ -0,0 +1,596 @@
|
|
|
1
|
+
import { emit, on, once, Priority } from "@spearwolf/eventize";
|
|
2
|
+
import {
|
|
3
|
+
createEffect,
|
|
4
|
+
createMemo,
|
|
5
|
+
createSignal,
|
|
6
|
+
destroySignal,
|
|
7
|
+
isSignal,
|
|
8
|
+
link
|
|
9
|
+
} from "@spearwolf/signalize";
|
|
10
|
+
import { runGuarded } from "../utils/runGuarded.js";
|
|
11
|
+
import { toMaybe } from "../utils/toMaybe.js";
|
|
12
|
+
import { onDestroy, onViewEvent } from "./events.js";
|
|
13
|
+
const inertSignal = () => {
|
|
14
|
+
const sig = createSignal(void 0);
|
|
15
|
+
destroySignal(sig);
|
|
16
|
+
return sig;
|
|
17
|
+
};
|
|
18
|
+
const inertEffect = () => {
|
|
19
|
+
const effect = createEffect(() => {
|
|
20
|
+
}, { autorun: false });
|
|
21
|
+
effect.destroy();
|
|
22
|
+
return effect;
|
|
23
|
+
};
|
|
24
|
+
const noSubscription = () => {
|
|
25
|
+
};
|
|
26
|
+
class ShadowObjectCreationScope {
|
|
27
|
+
#entity;
|
|
28
|
+
#logger;
|
|
29
|
+
#displayName;
|
|
30
|
+
// The kernel's list of member names whose deprecation report has already been made. Shared by
|
|
31
|
+
// every scope of one kernel, which is what makes the report fall once per kernel and name.
|
|
32
|
+
#shownDeprecations;
|
|
33
|
+
// The cleanup callbacks of the shadow-object itself, registered through `onDestroy()`.
|
|
34
|
+
#unsubscribePrimary = /* @__PURE__ */ new Set();
|
|
35
|
+
// The cleanup callbacks the creation API registered on its own behalf. A `Set` iterating in
|
|
36
|
+
// insertion order: which cleanup runs before which is observable behaviour.
|
|
37
|
+
#unsubscribeSecondary = /* @__PURE__ */ new Set();
|
|
38
|
+
// The releases of the provider feeds, one per context name this shadow-object provides. The
|
|
39
|
+
// entity hands each of them out when the provider is attached to it, and they fall after every
|
|
40
|
+
// other cleanup callback, so a write the teardown still makes -- the `undefined` of a
|
|
41
|
+
// `clearOnDestroy`, or one from an `onDestroy` callback -- reaches the entity-side signal instead
|
|
42
|
+
// of stopping at the provider. Where the entity lives on, that is what makes the write count: the
|
|
43
|
+
// entity hands it on to its own context signal one microtask later, and from there to its readers
|
|
44
|
+
// and to the entities below it. The order matters in the other direction as well, because a
|
|
45
|
+
// release also lets a provider that stays on the entity write its value once more, and that
|
|
46
|
+
// hand-over may only happen once the write of the leaving provider is through.
|
|
47
|
+
//
|
|
48
|
+
// Where the entity is destroyed, the two kinds of target part ways. The signal behind
|
|
49
|
+
// `provideContext()` takes the write and keeps it: the microtask that would hand it on falls
|
|
50
|
+
// after the entity has cleared and destroyed its context signals, and the children that outlive
|
|
51
|
+
// it were re-bound before the teardown even began. The signal behind `provideGlobalContext()`
|
|
52
|
+
// stays a member of the kernel-wide chain of its name until the entity's own destruction runs at
|
|
53
|
+
// `Priority.Min`, so the write does travel on to the inherited signals of other entities -- with
|
|
54
|
+
// no observable difference, because the entity takes its signal out of that chain in the same run,
|
|
55
|
+
// and what the chain resolves to without it is what those readers were going to see anyway: the
|
|
56
|
+
// contribution of the next entity that holds the name, or nothing where there is none. The
|
|
57
|
+
// ordering is kept for the paths on which it is observable.
|
|
58
|
+
#unsubscribeContextFeeds = /* @__PURE__ */ new Set();
|
|
59
|
+
#contextReaders = /* @__PURE__ */ new Map();
|
|
60
|
+
#contextReaderCompares = /* @__PURE__ */ new Map();
|
|
61
|
+
#contextParentReaders = /* @__PURE__ */ new Map();
|
|
62
|
+
#contextParentReaderCompares = /* @__PURE__ */ new Map();
|
|
63
|
+
#contextProviders = /* @__PURE__ */ new Map();
|
|
64
|
+
#contextRootProviders = /* @__PURE__ */ new Map();
|
|
65
|
+
// The provider signals that already have their `clearOnDestroy` write registered in
|
|
66
|
+
// `#unsubscribeSecondary`. Keyed by the signal itself rather than by name, because a
|
|
67
|
+
// `provideContext(name)` and a `provideGlobalContext(name)` call can share one name while landing
|
|
68
|
+
// in two different maps above -- a name-keyed set would conflate the two providers.
|
|
69
|
+
#clearOnDestroyRegistered = /* @__PURE__ */ new Set();
|
|
70
|
+
#propertyReaders = /* @__PURE__ */ new Map();
|
|
71
|
+
#propertyCompares = /* @__PURE__ */ new Map();
|
|
72
|
+
#shadowObject;
|
|
73
|
+
#releaseScope;
|
|
74
|
+
#forgetShadowObject;
|
|
75
|
+
#unsubscribeFromEntityDestroy;
|
|
76
|
+
#isTornDown = false;
|
|
77
|
+
// Armed at the *end* of `tearDown()`, not at its start, and the difference is the whole point:
|
|
78
|
+
// the teardown runs the shadow-object's own cleanup callbacks, and those are allowed the creation
|
|
79
|
+
// API -- a goodbye to the view, a last write. What they register there is still swept up by the
|
|
80
|
+
// steps behind them. What arrives after the teardown has returned is not, which is what this
|
|
81
|
+
// closes.
|
|
82
|
+
#isCreationApiClosed = false;
|
|
83
|
+
// The member names whose late call has already been reported, at most as many as the API has
|
|
84
|
+
// members. Lazy, because a scope that is used correctly never allocates it.
|
|
85
|
+
#lateCallsReported;
|
|
86
|
+
/**
|
|
87
|
+
* The name the kernel gave this scope, taken from the constructor it belongs to rather than from
|
|
88
|
+
* the shadow-object that came out of it. The two agree for most forms -- a class and a function
|
|
89
|
+
* that returns nothing both leave their own name on the instance's `constructor` -- but not for a
|
|
90
|
+
* function that returns an object literal: `new` hands that literal back, and it reports `Object`.
|
|
91
|
+
* Reports about the shadow-object are keyed by this name, so the kernel reads it here instead of
|
|
92
|
+
* asking the instance.
|
|
93
|
+
*/
|
|
94
|
+
get displayName() {
|
|
95
|
+
return this.#displayName;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* The four teardown handles, read without waiting on a garbage collector: a test can check that
|
|
99
|
+
* `tearDown()` let go of them by comparing this before and after, rather than by proving the
|
|
100
|
+
* absence of a reference through a `WeakRef`.
|
|
101
|
+
*
|
|
102
|
+
* @internal
|
|
103
|
+
*/
|
|
104
|
+
get debugHandles() {
|
|
105
|
+
return {
|
|
106
|
+
shadowObject: this.#shadowObject,
|
|
107
|
+
releaseScope: this.#releaseScope,
|
|
108
|
+
forgetShadowObject: this.#forgetShadowObject,
|
|
109
|
+
unsubscribeFromEntityDestroy: this.#unsubscribeFromEntityDestroy
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* How many cleanup callbacks the scope is holding, one count per set, read without waiting on a
|
|
114
|
+
* garbage collector: a test can subscribe and unsubscribe n times and see that the scope let go
|
|
115
|
+
* of each handle as it went, rather than inferring it from what a collector happened to do.
|
|
116
|
+
*
|
|
117
|
+
* @internal
|
|
118
|
+
*/
|
|
119
|
+
get debugCleanupCounts() {
|
|
120
|
+
return {
|
|
121
|
+
primary: this.#unsubscribePrimary.size,
|
|
122
|
+
secondary: this.#unsubscribeSecondary.size,
|
|
123
|
+
contextFeeds: this.#unsubscribeContextFeeds.size
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
constructor(entity, logger, displayName, shownDeprecations) {
|
|
127
|
+
this.#entity = entity;
|
|
128
|
+
this.#logger = logger;
|
|
129
|
+
this.#displayName = displayName;
|
|
130
|
+
this.#shownDeprecations = shownDeprecations;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* The object that goes into `new construct(…)`.
|
|
134
|
+
*
|
|
135
|
+
* Every member is a bound function, because a shadow-object constructor is expected to destructure the
|
|
136
|
+
* API in its parameter list — a member that took its receiver from the call site would lose it there.
|
|
137
|
+
*/
|
|
138
|
+
createAPI() {
|
|
139
|
+
return {
|
|
140
|
+
entity: this.#entity,
|
|
141
|
+
provideContext: this.provideContext.bind(this),
|
|
142
|
+
provideGlobalContext: this.provideGlobalContext.bind(this),
|
|
143
|
+
useContext: this.useContext.bind(this),
|
|
144
|
+
useParentContext: this.useParentContext.bind(this),
|
|
145
|
+
dispatchMessageToView: this.dispatchMessageToView.bind(this),
|
|
146
|
+
useProperty: this.useProperty.bind(this),
|
|
147
|
+
useProperties: this.useProperties.bind(this),
|
|
148
|
+
createResource: this.createResource.bind(this),
|
|
149
|
+
createEffect: this.createEffect.bind(this),
|
|
150
|
+
createSignal: this.createSignal.bind(this),
|
|
151
|
+
createMemo: this.createMemo.bind(this),
|
|
152
|
+
on: this.on.bind(this),
|
|
153
|
+
once: this.once.bind(this),
|
|
154
|
+
emit: this.emit.bind(this),
|
|
155
|
+
onViewEvent: this.onViewEvent.bind(this),
|
|
156
|
+
onDestroy: this.onDestroy.bind(this)
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Binds the scope to the shadow-object it made the API for and subscribes to the destruction of the entity.
|
|
161
|
+
*
|
|
162
|
+
* A shadow-object reaches its end on two independent paths: the entity is destroyed, or the shadow-object
|
|
163
|
+
* leaves the constructor set of a still living entity (token or route change). Both run the same teardown,
|
|
164
|
+
* and each path reaches it through a handle of its own.
|
|
165
|
+
*
|
|
166
|
+
* The kernel keeps two releases rather than one, because they belong to opposite ends of the teardown:
|
|
167
|
+
* `releaseScope` runs at its start, `forgetShadowObject` at its end.
|
|
168
|
+
*
|
|
169
|
+
* One scope serves one shadow-object, once: the call is part of the contract, and both ways of breaking
|
|
170
|
+
* it are refused below.
|
|
171
|
+
*/
|
|
172
|
+
bindTo(shadowObject, releaseScope, forgetShadowObject) {
|
|
173
|
+
if (this.#isTornDown) {
|
|
174
|
+
throw new Error(`the creation scope of "${this.#displayName}" has torn down and cannot be bound`);
|
|
175
|
+
}
|
|
176
|
+
if (this.#shadowObject !== void 0) {
|
|
177
|
+
throw new Error(`the creation scope of "${this.#displayName}" is already bound to a shadow-object`);
|
|
178
|
+
}
|
|
179
|
+
this.#shadowObject = shadowObject;
|
|
180
|
+
this.#releaseScope = releaseScope;
|
|
181
|
+
this.#forgetShadowObject = forgetShadowObject;
|
|
182
|
+
this.#logger.info("create shadow-object", this.#displayName, { shadowObject, entity: this.#entity });
|
|
183
|
+
this.#unsubscribeFromEntityDestroy = once(this.#entity, onDestroy, Priority.Low, () => {
|
|
184
|
+
this.tearDown();
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Runs once, whichever path reaches it first.
|
|
189
|
+
*
|
|
190
|
+
* Three lead here. Two belong to a shadow-object that lived: its entity is destroyed, or it leaves the
|
|
191
|
+
* constructor set of an entity that stays. On the third, the kernel calls this directly on a scope that
|
|
192
|
+
* `bindTo()` never saw, because the constructor threw -- there is no shadow-object then, and three of the
|
|
193
|
+
* handles below are still unset (`#releaseScope` and `#unsubscribeFromEntityDestroy` at the start,
|
|
194
|
+
* `#forgetShadowObject` at the end), which is why all three are called optionally.
|
|
195
|
+
*
|
|
196
|
+
* The provider feeds are released after everything else, so that a write made on the way out reaches the
|
|
197
|
+
* entity-side signal rather than stopping at the provider, and so that the entity hands the context over to
|
|
198
|
+
* a provider that stays only once that write is through.
|
|
199
|
+
*
|
|
200
|
+
* The flag makes the teardown a one-time act: a destroy callback reaching back into the kernel finds no
|
|
201
|
+
* way to start it a second time. Releasing both handles right after ends the retention in both directions
|
|
202
|
+
* -- the kernel's map points from the shadow-object to this scope, the subscription points from the entity
|
|
203
|
+
* to the same scope.
|
|
204
|
+
*
|
|
205
|
+
* The kernel is told to forget the shadow-object at the very end, so a destroy callback that reaches back
|
|
206
|
+
* into the kernel still finds its shadow-object listed among the ones the constructor created. Once that
|
|
207
|
+
* call is through, the four handles above are let go of as well -- the shadow-object, both kernel releases
|
|
208
|
+
* and the entity subscription -- so a scope past this point holds none of the four through these fields.
|
|
209
|
+
*
|
|
210
|
+
* Every step below runs behind its own guard, so a callback or signal teardown that throws does not stop
|
|
211
|
+
* the ones after it: the remaining callbacks, the remaining signal releases, and the provider feed
|
|
212
|
+
* hand-over all still happen. A caught error goes to the logger by displayName and the label of the step
|
|
213
|
+
* that failed, and is not re-thrown -- neither `changeToken()` nor `destroyEntity()` deliver it to their
|
|
214
|
+
* caller, nor does it stop the destroy notification the entity is still delivering to whatever comes after
|
|
215
|
+
* this shadow-object in the same run.
|
|
216
|
+
*
|
|
217
|
+
* The creation API is closed as the very last step, after everything above has run. Until then it
|
|
218
|
+
* is open, because the cleanup callbacks of the shadow-object run inside this method and are
|
|
219
|
+
* entitled to it -- a last message to the view, a last write to a context. What such a callback
|
|
220
|
+
* registers is still reached by the steps behind it. The two sets of cleanup callbacks are run
|
|
221
|
+
* in rounds until neither has anything left, so a callback that another one registers is reached
|
|
222
|
+
* whichever of the two it lands in. The context feed releases follow all of them. What arrives
|
|
223
|
+
* once this method has returned is not, and is turned away by `#refuseAfterTearDown()`.
|
|
224
|
+
*/
|
|
225
|
+
tearDown() {
|
|
226
|
+
if (this.#isTornDown) return;
|
|
227
|
+
this.#isTornDown = true;
|
|
228
|
+
this.#runGuarded("scope release", () => this.#releaseScope?.());
|
|
229
|
+
this.#runGuarded("entity destroy subscription", () => this.#unsubscribeFromEntityDestroy?.());
|
|
230
|
+
if (this.#shadowObject !== void 0) {
|
|
231
|
+
this.#logger.info("destroy shadow-object", this.#displayName, { shadowObject: this.#shadowObject, entity: this.#entity });
|
|
232
|
+
}
|
|
233
|
+
const alreadyRun = /* @__PURE__ */ new Set();
|
|
234
|
+
const runCleanups = (callbacks, step) => {
|
|
235
|
+
let ranAny = false;
|
|
236
|
+
for (const callback of callbacks) {
|
|
237
|
+
if (alreadyRun.has(callback)) continue;
|
|
238
|
+
alreadyRun.add(callback);
|
|
239
|
+
ranAny = true;
|
|
240
|
+
this.#runGuarded(step, callback);
|
|
241
|
+
}
|
|
242
|
+
return ranAny;
|
|
243
|
+
};
|
|
244
|
+
let ranAnything = true;
|
|
245
|
+
while (ranAnything) {
|
|
246
|
+
const ranPrimary = runCleanups(this.#unsubscribePrimary, "onDestroy callback");
|
|
247
|
+
const ranSecondary = runCleanups(this.#unsubscribeSecondary, "creation-api cleanup");
|
|
248
|
+
ranAnything = ranPrimary || ranSecondary;
|
|
249
|
+
}
|
|
250
|
+
for (const callback of this.#unsubscribeContextFeeds) {
|
|
251
|
+
this.#runGuarded("context feed release", callback);
|
|
252
|
+
}
|
|
253
|
+
for (const sig of this.#contextReaders.values()) {
|
|
254
|
+
this.#runGuarded("context reader", () => destroySignal(sig));
|
|
255
|
+
}
|
|
256
|
+
for (const sig of this.#contextParentReaders.values()) {
|
|
257
|
+
this.#runGuarded("parent context reader", () => destroySignal(sig));
|
|
258
|
+
}
|
|
259
|
+
for (const sig of this.#propertyReaders.values()) {
|
|
260
|
+
this.#runGuarded("property reader", () => destroySignal(sig));
|
|
261
|
+
}
|
|
262
|
+
for (const sig of this.#contextProviders.values()) {
|
|
263
|
+
this.#runGuarded("context provider", () => destroySignal(sig));
|
|
264
|
+
}
|
|
265
|
+
for (const sig of this.#contextRootProviders.values()) {
|
|
266
|
+
this.#runGuarded("global context provider", () => destroySignal(sig));
|
|
267
|
+
}
|
|
268
|
+
this.#unsubscribePrimary.clear();
|
|
269
|
+
this.#unsubscribeSecondary.clear();
|
|
270
|
+
this.#unsubscribeContextFeeds.clear();
|
|
271
|
+
this.#contextReaders.clear();
|
|
272
|
+
this.#contextReaderCompares.clear();
|
|
273
|
+
this.#contextParentReaders.clear();
|
|
274
|
+
this.#contextParentReaderCompares.clear();
|
|
275
|
+
this.#propertyReaders.clear();
|
|
276
|
+
this.#propertyCompares.clear();
|
|
277
|
+
this.#contextProviders.clear();
|
|
278
|
+
this.#contextRootProviders.clear();
|
|
279
|
+
this.#clearOnDestroyRegistered.clear();
|
|
280
|
+
this.#runGuarded("forget shadow-object", () => this.#forgetShadowObject?.());
|
|
281
|
+
this.#shadowObject = void 0;
|
|
282
|
+
this.#releaseScope = void 0;
|
|
283
|
+
this.#forgetShadowObject = void 0;
|
|
284
|
+
this.#unsubscribeFromEntityDestroy = void 0;
|
|
285
|
+
this.#isCreationApiClosed = true;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Isolates one teardown step from the ones around it: a step that throws is reported through the
|
|
289
|
+
* logger -- ungated, so the report stays visible outside localhost -- and does not stop `tearDown()`
|
|
290
|
+
* from reaching the steps that follow. The report goes out through the shared `runGuarded()`;
|
|
291
|
+
* what this wrapper adds is the label of the step and the display name it belongs to.
|
|
292
|
+
*/
|
|
293
|
+
#runGuarded(step, run) {
|
|
294
|
+
runGuarded(this.#logger, run, `shadow-object teardown failed (${step}):`, this.#displayName);
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Books an `on()` or `once()` subscription into the cleanup set and hands back a handle that takes
|
|
298
|
+
* it out again. Unsubscribing releases the callback there and then rather than at the teardown, so
|
|
299
|
+
* a shadow-object that subscribes and unsubscribes over the whole life of its entity holds one
|
|
300
|
+
* handle at a time instead of one per call. The target makes no difference to that: a subscription
|
|
301
|
+
* on the entity ends the same way one on any other object does.
|
|
302
|
+
*/
|
|
303
|
+
#trackSubscription(unsubscribe) {
|
|
304
|
+
this.#unsubscribeSecondary.add(unsubscribe);
|
|
305
|
+
return Object.assign(() => {
|
|
306
|
+
this.#unsubscribeSecondary.delete(unsubscribe);
|
|
307
|
+
unsubscribe();
|
|
308
|
+
}, unsubscribe);
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* The body the three cached readers share: one reader per name, created on the first call and fed
|
|
312
|
+
* from the entity-side source, plus a warning when a later call brings a different {compare}
|
|
313
|
+
* function than the one the reader was created with.
|
|
314
|
+
*
|
|
315
|
+
* `linkSource` is a thunk because the source may only be read when a reader is actually created.
|
|
316
|
+
*/
|
|
317
|
+
#cachedReader(name, readers, compares, linkSource, opts, apiName, subject) {
|
|
318
|
+
let reader = readers.get(name);
|
|
319
|
+
if (reader === void 0) {
|
|
320
|
+
reader = createSignal(void 0, opts).get;
|
|
321
|
+
readers.set(name, reader);
|
|
322
|
+
compares.set(name, opts?.compare);
|
|
323
|
+
const ln = link(linkSource(), reader);
|
|
324
|
+
this.#unsubscribeSecondary.add(ln.destroy.bind(ln));
|
|
325
|
+
} else if (opts?.compare != null && compares.get(name) !== opts.compare) {
|
|
326
|
+
this.#logger.error(
|
|
327
|
+
`[shadow-objects] ${apiName}("${String(name)}"): the cached signal already exists with a different (or no) {compare} function \u2014 the new options are ignored. Pass options only on the first call per ${subject}.`
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
return reader;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Reports the deprecated call form in which a bare compare function stands where the options
|
|
334
|
+
* object belongs, at most once per kernel and member name.
|
|
335
|
+
*
|
|
336
|
+
* Through `error` rather than `warn`: this names a mistake in the calling code, and its author
|
|
337
|
+
* has to see it wherever the application runs. `logger.warn` is asked `isWarn` first, and the
|
|
338
|
+
* shared `enable` behind that getter is off anywhere but `localhost` -- a deprecation notice
|
|
339
|
+
* that goes silent everywhere the code actually ships is no notice at all. See the table of
|
|
340
|
+
* call against getter under "Console Logger" in `docs/api-reference.md`.
|
|
341
|
+
*
|
|
342
|
+
* One line per kernel and member name: a shadow-object calling a deprecated member inside a
|
|
343
|
+
* loop would otherwise fill the console.
|
|
344
|
+
*/
|
|
345
|
+
#reportDeprecatedIsEqualOption(options, apiName) {
|
|
346
|
+
if (typeof options !== "function" || this.#shownDeprecations.has(apiName)) return;
|
|
347
|
+
this.#logger.error(
|
|
348
|
+
`[shadow-objects] Deprecation Warning: The "isEqual" option of "${apiName}()" is now passed as {compare} argument. Please update your code accordingly.`
|
|
349
|
+
);
|
|
350
|
+
this.#shownDeprecations.add(apiName);
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Answers whether the creation API still has anything to give, and reports it where it has not.
|
|
354
|
+
*
|
|
355
|
+
* Past the teardown the scope has released what it held and cleared what it tracked. A call
|
|
356
|
+
* arriving now would fill those maps again with entries no second teardown ever reaches -- the
|
|
357
|
+
* teardown runs once, and it has run. Such a call is therefore turned away rather than served.
|
|
358
|
+
*
|
|
359
|
+
* Turned away quietly: the callers that arrive late are the ones with nobody to catch a throw --
|
|
360
|
+
* a timer, a continuation behind an `await`, a callback of some other object that outlived this
|
|
361
|
+
* one. It is reported instead, through `error` for the same reason the deprecation report above
|
|
362
|
+
* uses it: this names a mistake in the calling code, and its author has to see it wherever the
|
|
363
|
+
* application runs. Once per member name and scope, because a stale timer comes back on its next
|
|
364
|
+
* tick and a line per tick would bury the first one.
|
|
365
|
+
*/
|
|
366
|
+
#refuseAfterTearDown(apiName) {
|
|
367
|
+
if (!this.#isCreationApiClosed) return false;
|
|
368
|
+
if (!this.#lateCallsReported?.has(apiName)) {
|
|
369
|
+
(this.#lateCallsReported ??= /* @__PURE__ */ new Set()).add(apiName);
|
|
370
|
+
this.#logger.error(
|
|
371
|
+
`[shadow-objects] ${apiName}(): the creation scope of "${this.#displayName}" has torn down \u2014 the call does nothing. Something is still holding the creation API past the end of its shadow-object.`
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
return true;
|
|
375
|
+
}
|
|
376
|
+
useProperty(name, options) {
|
|
377
|
+
if (this.#refuseAfterTearDown("useProperty")) return inertSignal().get;
|
|
378
|
+
this.#reportDeprecatedIsEqualOption(options, "useProperty");
|
|
379
|
+
const opts = typeof options === "function" ? { compare: options } : options;
|
|
380
|
+
return this.#cachedReader(
|
|
381
|
+
name,
|
|
382
|
+
this.#propertyReaders,
|
|
383
|
+
this.#propertyCompares,
|
|
384
|
+
() => this.#entity.getPropertyReader(name),
|
|
385
|
+
opts,
|
|
386
|
+
"useProperty",
|
|
387
|
+
"property"
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
useProperties(props) {
|
|
391
|
+
const result = {};
|
|
392
|
+
for (const key in props) {
|
|
393
|
+
if (Object.hasOwn(props, key)) {
|
|
394
|
+
result[key] = this.useProperty(props[key]);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return result;
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* The body the two context providers share: one provider signal per name, created on the first
|
|
401
|
+
* call, attached to the entity-side context signal, and cleared on teardown unless the caller
|
|
402
|
+
* opted out -- a clearing that finds the way to the entity side still open. A source signal handed
|
|
403
|
+
* in instead of an initial value feeds the provider through a link of its own.
|
|
404
|
+
*
|
|
405
|
+
* The entity keeps every provider of a name together and answers the attachment with the release
|
|
406
|
+
* that detaches this one again. Releasing it does more than cut the feed: the entity then lets a
|
|
407
|
+
* provider that stays write its value once more, so the name ends up with a value that is actually
|
|
408
|
+
* still being provided rather than with what this shadow-object left behind on its way out.
|
|
409
|
+
*
|
|
410
|
+
* `attachToEntity` is called inside the creation branch only, so the entity-side signal is
|
|
411
|
+
* requested when a provider is actually created. The `clearOnDestroy` check sits outside that
|
|
412
|
+
* branch: every call is allowed to ask for the clearing, not only the one that created the signal.
|
|
413
|
+
* The request is booked once per provider, though -- a repeated ask does not queue a second write,
|
|
414
|
+
* and once a provider has one on file, an opt-out on a later call does not take it back.
|
|
415
|
+
*/
|
|
416
|
+
#provideContextSignal(name, providers, attachToEntity, sourceOrInitialValue, opts) {
|
|
417
|
+
let ctxProvider = providers.get(name);
|
|
418
|
+
if (ctxProvider == null) {
|
|
419
|
+
const isSig = isSignal(sourceOrInitialValue);
|
|
420
|
+
const initialValue = isSig ? void 0 : toMaybe(sourceOrInitialValue);
|
|
421
|
+
ctxProvider = createSignal(initialValue, opts?.compare ? { compare: opts.compare } : void 0);
|
|
422
|
+
if (isSig) {
|
|
423
|
+
const ln = link(sourceOrInitialValue, ctxProvider);
|
|
424
|
+
this.#unsubscribeSecondary.add(ln.destroy.bind(ln));
|
|
425
|
+
}
|
|
426
|
+
this.#unsubscribeContextFeeds.add(attachToEntity(ctxProvider));
|
|
427
|
+
providers.set(name, ctxProvider);
|
|
428
|
+
}
|
|
429
|
+
if ((opts?.clearOnDestroy ?? true) && !this.#clearOnDestroyRegistered.has(ctxProvider)) {
|
|
430
|
+
this.#clearOnDestroyRegistered.add(ctxProvider);
|
|
431
|
+
this.#unsubscribeSecondary.add(() => {
|
|
432
|
+
ctxProvider.set(void 0);
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
return ctxProvider;
|
|
436
|
+
}
|
|
437
|
+
provideContext(name, sourceOrInitialValue, options) {
|
|
438
|
+
if (this.#refuseAfterTearDown("provideContext")) return inertSignal();
|
|
439
|
+
this.#reportDeprecatedIsEqualOption(options, "provideContext");
|
|
440
|
+
const opts = typeof options === "function" ? { compare: options } : options;
|
|
441
|
+
return this.#provideContextSignal(
|
|
442
|
+
name,
|
|
443
|
+
this.#contextProviders,
|
|
444
|
+
(provider) => this.#entity.attachContextProvider(name, provider),
|
|
445
|
+
sourceOrInitialValue,
|
|
446
|
+
opts
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
provideGlobalContext(name, sourceOrInitialValue, options) {
|
|
450
|
+
if (this.#refuseAfterTearDown("provideGlobalContext")) return inertSignal();
|
|
451
|
+
this.#reportDeprecatedIsEqualOption(options, "provideGlobalContext");
|
|
452
|
+
const opts = typeof options === "function" ? { compare: options } : options;
|
|
453
|
+
return this.#provideContextSignal(
|
|
454
|
+
name,
|
|
455
|
+
this.#contextRootProviders,
|
|
456
|
+
(provider) => this.#entity.attachGlobalContextProvider(name, provider),
|
|
457
|
+
sourceOrInitialValue,
|
|
458
|
+
opts
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
useContext(name, options) {
|
|
462
|
+
if (this.#refuseAfterTearDown("useContext")) return inertSignal().get;
|
|
463
|
+
this.#reportDeprecatedIsEqualOption(options, "useContext");
|
|
464
|
+
const opts = typeof options === "function" ? { compare: options } : options;
|
|
465
|
+
return this.#cachedReader(
|
|
466
|
+
name,
|
|
467
|
+
this.#contextReaders,
|
|
468
|
+
this.#contextReaderCompares,
|
|
469
|
+
() => this.#entity.useContext(name),
|
|
470
|
+
opts,
|
|
471
|
+
"useContext",
|
|
472
|
+
"context"
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
useParentContext(name, options) {
|
|
476
|
+
if (this.#refuseAfterTearDown("useParentContext")) return inertSignal().get;
|
|
477
|
+
this.#reportDeprecatedIsEqualOption(options, "useParentContext");
|
|
478
|
+
const opts = typeof options === "function" ? { compare: options } : options;
|
|
479
|
+
return this.#cachedReader(
|
|
480
|
+
name,
|
|
481
|
+
this.#contextParentReaders,
|
|
482
|
+
this.#contextParentReaderCompares,
|
|
483
|
+
() => this.#entity.useParentContext(name),
|
|
484
|
+
opts,
|
|
485
|
+
"useParentContext",
|
|
486
|
+
"parent context"
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
createSignal(...args) {
|
|
490
|
+
if (this.#refuseAfterTearDown("createSignal")) return inertSignal();
|
|
491
|
+
const sig = createSignal(...args);
|
|
492
|
+
this.#unsubscribeSecondary.add(() => {
|
|
493
|
+
destroySignal(sig);
|
|
494
|
+
});
|
|
495
|
+
return sig;
|
|
496
|
+
}
|
|
497
|
+
createEffect(...args) {
|
|
498
|
+
if (this.#refuseAfterTearDown("createEffect")) return inertEffect();
|
|
499
|
+
const effect = createEffect(...args);
|
|
500
|
+
this.#unsubscribeSecondary.add(effect.destroy);
|
|
501
|
+
return effect;
|
|
502
|
+
}
|
|
503
|
+
createMemo(...args) {
|
|
504
|
+
if (this.#refuseAfterTearDown("createMemo")) return inertSignal().get;
|
|
505
|
+
const sig = createMemo(...args);
|
|
506
|
+
this.#unsubscribeSecondary.add(() => {
|
|
507
|
+
destroySignal(sig);
|
|
508
|
+
});
|
|
509
|
+
return sig;
|
|
510
|
+
}
|
|
511
|
+
createResource(factory, cleanup) {
|
|
512
|
+
if (this.#refuseAfterTearDown("createResource")) return inertSignal();
|
|
513
|
+
const resourceSignal = createSignal();
|
|
514
|
+
const effect = createEffect(() => {
|
|
515
|
+
const resource = toMaybe(factory());
|
|
516
|
+
resourceSignal.set(resource);
|
|
517
|
+
if (resource !== void 0 && cleanup) {
|
|
518
|
+
return () => {
|
|
519
|
+
cleanup(resource);
|
|
520
|
+
resourceSignal.set(void 0);
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
return () => {
|
|
524
|
+
resourceSignal.set(void 0);
|
|
525
|
+
};
|
|
526
|
+
});
|
|
527
|
+
this.#unsubscribeSecondary.add(() => {
|
|
528
|
+
try {
|
|
529
|
+
effect.destroy();
|
|
530
|
+
} finally {
|
|
531
|
+
resourceSignal.set(void 0);
|
|
532
|
+
destroySignal(resourceSignal);
|
|
533
|
+
}
|
|
534
|
+
});
|
|
535
|
+
return resourceSignal;
|
|
536
|
+
}
|
|
537
|
+
on(...args) {
|
|
538
|
+
if (this.#refuseAfterTearDown("on")) return noSubscription;
|
|
539
|
+
const [firstArg] = args;
|
|
540
|
+
const unsubscribe = typeof firstArg === "string" || typeof firstArg === "symbol" || Array.isArray(firstArg) ? (
|
|
541
|
+
// @ts-ignore
|
|
542
|
+
on(this.#entity, ...args)
|
|
543
|
+
) : (
|
|
544
|
+
// @ts-ignore
|
|
545
|
+
on(...args)
|
|
546
|
+
);
|
|
547
|
+
return this.#trackSubscription(unsubscribe);
|
|
548
|
+
}
|
|
549
|
+
once(...args) {
|
|
550
|
+
if (this.#refuseAfterTearDown("once")) return noSubscription;
|
|
551
|
+
const [firstArg] = args;
|
|
552
|
+
const unsubscribe = typeof firstArg === "string" || typeof firstArg === "symbol" || Array.isArray(firstArg) ? (
|
|
553
|
+
// @ts-ignore
|
|
554
|
+
once(this.#entity, ...args)
|
|
555
|
+
) : (
|
|
556
|
+
// @ts-ignore
|
|
557
|
+
once(...args)
|
|
558
|
+
);
|
|
559
|
+
return this.#trackSubscription(unsubscribe);
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* The plain `emit()`, deliberately, where every notification the framework sends out of its own
|
|
563
|
+
* accord runs on the guarded dispatch. This one is outbound and belongs to the Shadow Object: it
|
|
564
|
+
* owns the listeners, a throw from one of them is its own bug, and letting it surface where it
|
|
565
|
+
* happened is the fastest way to find it. A listener that needs a policy of its own carries a
|
|
566
|
+
* `try`/`catch` in its own body, which is where that decision belongs.
|
|
567
|
+
*/
|
|
568
|
+
emit(...args) {
|
|
569
|
+
if (this.#refuseAfterTearDown("emit")) return;
|
|
570
|
+
const [firstArg] = args;
|
|
571
|
+
if (typeof firstArg === "string" || typeof firstArg === "symbol" || Array.isArray(firstArg)) {
|
|
572
|
+
emit(this.#entity, ...args);
|
|
573
|
+
} else {
|
|
574
|
+
emit(...args);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
onViewEvent(callback) {
|
|
578
|
+
if (this.#refuseAfterTearDown("onViewEvent")) return;
|
|
579
|
+
const unsub = on(this.#entity, onViewEvent, (type, data) => {
|
|
580
|
+
callback(type, data);
|
|
581
|
+
});
|
|
582
|
+
this.#unsubscribeSecondary.add(unsub);
|
|
583
|
+
}
|
|
584
|
+
onDestroy(callback) {
|
|
585
|
+
if (this.#refuseAfterTearDown("onDestroy")) return;
|
|
586
|
+
this.#unsubscribePrimary.add(callback);
|
|
587
|
+
}
|
|
588
|
+
dispatchMessageToView(type, data, transferables, traverseChildren = false) {
|
|
589
|
+
if (this.#refuseAfterTearDown("dispatchMessageToView")) return;
|
|
590
|
+
this.#entity.dispatchMessageToView(type, data, transferables, traverseChildren);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
export {
|
|
594
|
+
ShadowObjectCreationScope
|
|
595
|
+
};
|
|
596
|
+
//# sourceMappingURL=ShadowObjectCreationScope.js.map
|