@spearwolf/shadow-objects 0.34.0 → 0.35.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 +30 -0
- package/README.md +11 -2
- package/bundle.js +4 -2
- package/package.json +9 -1
- package/src/WorkerTimeoutError.d.ts +4 -3
- package/src/WorkerTimeoutError.d.ts.map +1 -1
- package/src/WorkerTimeoutError.js.map +2 -2
- package/src/constants.d.ts +8 -4
- package/src/constants.d.ts.map +1 -1
- package/src/constants.js +6 -0
- package/src/constants.js.map +2 -2
- package/src/elements/ShaePropElement.d.ts +15 -6
- package/src/elements/ShaePropElement.d.ts.map +1 -1
- package/src/elements/ShaePropElement.js +31 -7
- package/src/elements/ShaePropElement.js.map +2 -2
- package/src/elements/ShaeWorkerElement.d.ts +10 -0
- package/src/elements/ShaeWorkerElement.d.ts.map +1 -1
- package/src/elements/ShaeWorkerElement.js +69 -2
- package/src/elements/ShaeWorkerElement.js.map +2 -2
- package/src/elements/constants.d.ts +3 -0
- package/src/elements/constants.d.ts.map +1 -1
- package/src/elements/constants.js +6 -0
- package/src/elements/constants.js.map +2 -2
- package/src/in-the-dark/Entity.d.ts +30 -0
- package/src/in-the-dark/Entity.d.ts.map +1 -1
- package/src/in-the-dark/Entity.js +38 -0
- package/src/in-the-dark/Entity.js.map +2 -2
- package/src/in-the-dark/Kernel.d.ts +24 -1
- package/src/in-the-dark/Kernel.d.ts.map +1 -1
- package/src/in-the-dark/Kernel.js +56 -1
- package/src/in-the-dark/Kernel.js.map +2 -2
- package/src/in-the-dark/Registry.d.ts +7 -1
- package/src/in-the-dark/Registry.d.ts.map +1 -1
- package/src/in-the-dark/Registry.js +29 -0
- package/src/in-the-dark/Registry.js.map +2 -2
- package/src/in-the-dark/ShadowObjectCreationScope.d.ts +8 -1
- package/src/in-the-dark/ShadowObjectCreationScope.d.ts.map +1 -1
- package/src/in-the-dark/ShadowObjectCreationScope.js +23 -16
- package/src/in-the-dark/ShadowObjectCreationScope.js.map +2 -2
- package/src/in-the-dark/SignalsPath.d.ts +2 -0
- package/src/in-the-dark/SignalsPath.d.ts.map +1 -1
- package/src/in-the-dark/SignalsPath.js +4 -0
- package/src/in-the-dark/SignalsPath.js.map +2 -2
- package/src/in-the-dark/displayName.d.ts +4 -0
- package/src/in-the-dark/displayName.d.ts.map +1 -0
- package/src/in-the-dark/displayName.js +5 -0
- package/src/in-the-dark/displayName.js.map +7 -0
- package/src/index.d.ts +2 -0
- package/src/index.d.ts.map +1 -1
- package/src/index.js +4 -0
- package/src/index.js.map +2 -2
- package/src/inspect/createKernelSnapshot.d.ts +17 -0
- package/src/inspect/createKernelSnapshot.d.ts.map +1 -0
- package/src/inspect/createKernelSnapshot.js +247 -0
- package/src/inspect/createKernelSnapshot.js.map +7 -0
- package/src/inspect/createViewSnapshot.d.ts +10 -0
- package/src/inspect/createViewSnapshot.d.ts.map +1 -0
- package/src/inspect/createViewSnapshot.js +143 -0
- package/src/inspect/createViewSnapshot.js.map +7 -0
- package/src/inspect/normalizeInspectRequest.d.ts +32 -0
- package/src/inspect/normalizeInspectRequest.d.ts.map +1 -0
- package/src/inspect/normalizeInspectRequest.js +55 -0
- package/src/inspect/normalizeInspectRequest.js.map +7 -0
- package/src/inspect/serializeValue.d.ts +13 -0
- package/src/inspect/serializeValue.d.ts.map +1 -0
- package/src/inspect/serializeValue.js +149 -0
- package/src/inspect/serializeValue.js.map +7 -0
- package/src/inspect/types.d.ts +260 -0
- package/src/inspect/types.d.ts.map +1 -0
- package/src/inspect/types.js +1 -0
- package/src/inspect/types.js.map +7 -0
- package/src/model-context/ModelContextLike.d.ts +59 -0
- package/src/model-context/ModelContextLike.d.ts.map +1 -0
- package/src/model-context/ModelContextLike.js +15 -0
- package/src/model-context/ModelContextLike.js.map +7 -0
- package/src/model-context/exposeShadowEnvsToModelContext.d.ts +48 -0
- package/src/model-context/exposeShadowEnvsToModelContext.d.ts.map +1 -0
- package/src/model-context/exposeShadowEnvsToModelContext.js +39 -0
- package/src/model-context/exposeShadowEnvsToModelContext.js.map +7 -0
- package/src/model-context/redactProps.d.ts +14 -0
- package/src/model-context/redactProps.d.ts.map +1 -0
- package/src/model-context/redactProps.js +22 -0
- package/src/model-context/redactProps.js.map +7 -0
- package/src/model-context/sharedExposure.d.ts +32 -0
- package/src/model-context/sharedExposure.d.ts.map +1 -0
- package/src/model-context/sharedExposure.js +108 -0
- package/src/model-context/sharedExposure.js.map +7 -0
- package/src/model-context/toolSupport.d.ts +72 -0
- package/src/model-context/toolSupport.d.ts.map +1 -0
- package/src/model-context/toolSupport.js +145 -0
- package/src/model-context/toolSupport.js.map +7 -0
- package/src/model-context/tools/findEntities.d.ts +15 -0
- package/src/model-context/tools/findEntities.d.ts.map +1 -0
- package/src/model-context/tools/findEntities.js +71 -0
- package/src/model-context/tools/findEntities.js.map +7 -0
- package/src/model-context/tools/getEntity.d.ts +16 -0
- package/src/model-context/tools/getEntity.d.ts.map +1 -0
- package/src/model-context/tools/getEntity.js +65 -0
- package/src/model-context/tools/getEntity.js.map +7 -0
- package/src/model-context/tools/getEntityTree.d.ts +4 -0
- package/src/model-context/tools/getEntityTree.d.ts.map +1 -0
- package/src/model-context/tools/getEntityTree.js +58 -0
- package/src/model-context/tools/getEntityTree.js.map +7 -0
- package/src/model-context/tools/getRegistry.d.ts +14 -0
- package/src/model-context/tools/getRegistry.d.ts.map +1 -0
- package/src/model-context/tools/getRegistry.js +39 -0
- package/src/model-context/tools/getRegistry.js.map +7 -0
- package/src/model-context/tools/index.d.ts +9 -0
- package/src/model-context/tools/index.d.ts.map +1 -0
- package/src/model-context/tools/index.js +16 -0
- package/src/model-context/tools/index.js.map +7 -0
- package/src/model-context/tools/listEnvs.d.ts +33 -0
- package/src/model-context/tools/listEnvs.d.ts.map +1 -0
- package/src/model-context/tools/listEnvs.js +37 -0
- package/src/model-context/tools/listEnvs.js.map +7 -0
- package/src/model-context.d.ts +13 -0
- package/src/model-context.d.ts.map +1 -0
- package/src/model-context.js +15 -0
- package/src/model-context.js.map +7 -0
- package/src/shadow-objects.d.ts +2 -0
- package/src/shadow-objects.d.ts.map +1 -1
- package/src/shadow-objects.js +4 -0
- package/src/shadow-objects.js.map +2 -2
- package/src/testing/TestEntity.d.ts +79 -0
- package/src/testing/TestEntity.d.ts.map +1 -0
- package/src/testing/TestEntity.js +135 -0
- package/src/testing/TestEntity.js.map +7 -0
- package/src/testing/createTestKernel.d.ts +11 -0
- package/src/testing/createTestKernel.d.ts.map +1 -0
- package/src/testing/createTestKernel.js +132 -0
- package/src/testing/createTestKernel.js.map +7 -0
- package/src/testing/mountShadowObject.d.ts +21 -0
- package/src/testing/mountShadowObject.d.ts.map +1 -0
- package/src/testing/mountShadowObject.js +72 -0
- package/src/testing/mountShadowObject.js.map +7 -0
- package/src/testing/recordKernelErrors.d.ts +21 -0
- package/src/testing/recordKernelErrors.d.ts.map +1 -0
- package/src/testing/recordKernelErrors.js +39 -0
- package/src/testing/recordKernelErrors.js.map +7 -0
- package/src/testing/settle.d.ts +15 -0
- package/src/testing/settle.d.ts.map +1 -0
- package/src/testing/settle.js +19 -0
- package/src/testing/settle.js.map +7 -0
- package/src/testing/types.d.ts +119 -0
- package/src/testing/types.d.ts.map +1 -0
- package/src/testing/types.js +1 -0
- package/src/testing/types.js.map +7 -0
- package/src/testing.d.ts +14 -0
- package/src/testing.d.ts.map +1 -0
- package/src/testing.js +11 -0
- package/src/testing.js.map +7 -0
- package/src/types.d.ts +150 -10
- package/src/types.d.ts.map +1 -1
- package/src/utils/attr-utils.d.ts +5 -0
- package/src/utils/attr-utils.d.ts.map +1 -1
- package/src/utils/attr-utils.js +2 -0
- package/src/utils/attr-utils.js.map +2 -2
- package/src/view/IShadowObjectEnvProxy.d.ts +9 -0
- package/src/view/IShadowObjectEnvProxy.d.ts.map +1 -1
- package/src/view/LocalShadowObjectEnv.d.ts +7 -0
- package/src/view/LocalShadowObjectEnv.d.ts.map +1 -1
- package/src/view/LocalShadowObjectEnv.js +15 -1
- package/src/view/LocalShadowObjectEnv.js.map +2 -2
- package/src/view/RemoteWorkerEnv.d.ts +22 -3
- package/src/view/RemoteWorkerEnv.d.ts.map +1 -1
- package/src/view/RemoteWorkerEnv.js +50 -1
- package/src/view/RemoteWorkerEnv.js.map +2 -2
- package/src/view/ShadowEnv.d.ts +30 -0
- package/src/view/ShadowEnv.d.ts.map +1 -1
- package/src/view/ShadowEnv.js +101 -0
- package/src/view/ShadowEnv.js.map +3 -3
- package/src/worker/MessageRouter.d.ts.map +1 -1
- package/src/worker/MessageRouter.js +23 -0
- package/src/worker/MessageRouter.js.map +2 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/elements/ShaeWorkerElement.ts"],
|
|
4
|
-
"sourcesContent": ["import {on} from '@spearwolf/eventize';\nimport {batch, createEffect, createSignal, destroySignal, Effect, hibernate} from '@spearwolf/signalize';\nimport {readBooleanAttribute, readNumberAttribute} from '../utils/attr-utils.js';\nimport {ConsoleLogger} from '../utils/ConsoleLogger.js';\nimport {FrameLoop} from '../utils/FrameLoop.js';\nimport {ComponentContext} from '../view/ComponentContext.js';\nimport {LocalShadowObjectEnv} from '../view/LocalShadowObjectEnv.js';\nimport {RemoteWorkerEnv, type RemoteWorkerEnvOptions} from '../view/RemoteWorkerEnv.js';\nimport {ShadowEnv, ShadowEnvDestroyedError} from '../view/ShadowEnv.js';\nimport {\n ATTR_AUTO_SYNC,\n ATTR_CHANGE_TRAIL_TIMEOUT,\n ATTR_CONFIGURE_TIMEOUT,\n ATTR_DESTROY_TIMEOUT,\n ATTR_LOAD_TIMEOUT,\n ATTR_LOCAL,\n ATTR_NO_AUTOSTART,\n ATTR_NO_STRUCTURED_CLONE,\n ATTR_SRC,\n} from './constants.js';\nimport {ensureDisplayContentsRule} from './displayContentsRule.js';\nimport {ShaeElement} from './ShaeElement.js';\n\nconst WorkerTimeoutAttributes: [keyof RemoteWorkerEnvOptions, string][] = [\n ['loadTimeout', ATTR_LOAD_TIMEOUT],\n ['configureTimeout', ATTR_CONFIGURE_TIMEOUT],\n ['changeTrailTimeout', ATTR_CHANGE_TRAIL_TIMEOUT],\n ['destroyTimeout', ATTR_DESTROY_TIMEOUT],\n];\n\n/**\n * The one place the `auto-sync` spelling rule lives: a string is trimmed and lower-cased,\n * and anything else is read as a flag \u2014 a truthy value asks for the frame default, a falsy\n * one for no syncing at all. Every write into `autoSync$` this element makes goes through\n * here, so the canonical spelling does not depend on which write ran first.\n */\nfunction normaliseAutoSync(value: unknown): string {\n if (typeof value !== 'string') {\n return value ? ShaeWorkerElement.DefaultAutoSync : 'no';\n }\n return value.trim().toLowerCase();\n}\n\nexport class ShaeWorkerElement extends ShaeElement {\n static override observedAttributes = [\n ...ShaeElement.observedAttributes,\n ATTR_LOCAL,\n ATTR_SRC,\n ATTR_NO_STRUCTURED_CLONE,\n ATTR_AUTO_SYNC,\n ];\n\n static DefaultAutoSync = 'frame';\n\n readonly isShaeWorkerElement = true;\n\n readonly shadowEnv = new ShadowEnv();\n\n readonly #logger = new ConsoleLogger('ShaeWorkerElement');\n\n /** The logger this element reports through. */\n get logger(): ConsoleLogger {\n return this.#logger;\n }\n\n autostart = true;\n\n isConnected$ = createSignal(false);\n autoSync$ = createSignal(ShaeWorkerElement.DefaultAutoSync);\n src$ = createSignal('');\n\n #started = false;\n\n #autoSync?: Effect;\n #importScript?: Effect;\n\n /**\n * Points the environment at the namespace this element names.\n *\n * It hangs on `ns$`, which belongs to the base class and outlives this element's teardown, so\n * the handle is kept and released by hand \u2014 a listener left on a living signal is a listener the\n * global signal queue goes on holding, and with it this element.\n */\n #envViewBinding?: (() => void) | undefined;\n\n /**\n * Take the subscriptions up. Runs exactly once for this element, on the first connect.\n *\n * The return that `restore()` stands for on `<shae-ent>` and `<shae-prop>` does not exist here:\n * `connectedCallback` turns a torn-down `<shae-worker>` away, so nothing ever calls this a second\n * time.\n *\n * One path runs ahead of it, and it is the only one: `start()` is public, and an element started\n * by hand while it is out of the document builds its environment before anything below is\n * listening. Two things are lost there and stay lost, because both are moments rather than\n * values, and there is no honest way to replay a moment that has passed:\n *\n * - the `contextcreated` \u2014 and, should the environment lose its connection first, the\n * `contextlost` \u2014 DOM event for that environment. `ShadowEnv.ContextCreated` fires once, with\n * nobody on the element listening for it; re-dispatching it from here would announce as new an\n * environment that has been up for a while.\n * - the namespace the environment points at, where `ns` changed between that `start()` and the\n * first connect. `start()` resolves the view once with `??=`, the binding below only reacts to\n * *changes*, and the change already happened. `shadowEnv.view` then names the context of the\n * namespace the element carried when it was started. A write of `ns` after the first connect\n * moves it, as it always does.\n *\n * A `<shae-worker>` that connects before it starts \u2014 the ordinary way, and the only way the\n * declarative form has \u2014 meets neither. The import of `src` is the one case of this shape that\n * *is* caught up, at the end of this method, because a pending import is a value and not a\n * moment.\n */\n protected override restore(): void {\n super.restore();\n\n this.#envViewBinding = this.ns$.onChange((ns) => {\n this.shadowEnv.view = ComponentContext.get(ns);\n });\n\n on(this.shadowEnv, ShadowEnv.ContextCreated, () => {\n this.#importScript?.run();\n this.dispatchEvent(\n new CustomEvent(ShadowEnv.ContextCreated.toLowerCase(), {\n bubbles: false,\n detail: {shadowEnv: this.shadowEnv},\n }),\n );\n });\n\n on(this.shadowEnv, ShadowEnv.ContextLost, () => {\n this.dispatchEvent(\n new CustomEvent(ShadowEnv.ContextLost.toLowerCase(), {\n bubbles: false,\n detail: {shadowEnv: this.shadowEnv},\n }),\n );\n });\n\n on(this.shadowEnv, ShadowEnv.ProxyFailed, (reason: unknown) => {\n this.dispatchEvent(\n new CustomEvent(ShadowEnv.ProxyFailed.toLowerCase(), {\n bubbles: false,\n detail: {shadowEnv: this.shadowEnv, reason},\n }),\n );\n });\n\n on(this.shadowEnv, ShadowEnv.SyncFailed, (reason: unknown, changeTrail: unknown) => {\n this.dispatchEvent(\n new CustomEvent(ShadowEnv.SyncFailed.toLowerCase(), {\n bubbles: false,\n detail: {shadowEnv: this.shadowEnv, reason, changeTrail},\n }),\n );\n });\n\n this.autoSync$.onChange((sVal) => this.#reflectAutoSync(sVal));\n\n // the catch-up half of `restore()`: the signal carries the canonical spelling, and this is\n // what puts it on the attribute \u2014 `auto-sync=\"YES\"` is what an author writes, `auto-sync=\"yes\"`\n // is what the element syncs on, and a reader of the DOM sees the second\n this.#reflectAutoSync(this.autoSync$.value);\n\n // no catch-up for the namespace binding, and that is deliberate: the environment gets its view\n // from `start()`, which resolves the namespace at the one moment it needs it. Resolving it here\n // would build a `ComponentContext` for every `<shae-worker>` that has merely been connected,\n // and a context that exists is a context entities join\n this.#createAutoSyncEffect();\n this.#createImportScriptEffect();\n\n // a `src` that arrived while the environment was already up \u2014 only reachable through a\n // `start()` made by hand on an element outside the document \u2014 has nothing that would import it:\n // the effect is built without an autorun, and both callers that run it were registered a few\n // lines above. The same test `attributeChangedCallback` makes for `src`\n if (this.shadowEnv.isReady) {\n this.#importScript?.run();\n }\n }\n\n #reflectAutoSync(sVal: string): void {\n this.reflectAttribute(ATTR_AUTO_SYNC, () => {\n const hasAttr = this.hasAttribute(ATTR_AUTO_SYNC);\n const attrVal = hasAttr ? this.getAttribute(ATTR_AUTO_SYNC) : undefined;\n\n if (sVal === ShaeWorkerElement.DefaultAutoSync) {\n if (hasAttr && attrVal !== sVal) {\n this.setAttribute(ATTR_AUTO_SYNC, sVal);\n }\n } else if (attrVal !== sVal) {\n this.setAttribute(ATTR_AUTO_SYNC, sVal);\n }\n });\n }\n\n #createImportScriptEffect() {\n this.#importScript = createEffect(\n () => {\n const src = this.src$.get();\n if (src) {\n this.importScript(src).catch(this.#onUnobservedRejection);\n }\n },\n {autorun: false},\n );\n }\n\n /**\n * Both {@link ShaeWorkerElement.start} and {@link ShaeWorkerElement.importScript} await\n * {@link ShadowEnv.ready}, which rejects once the environment is destroyed \u2014 the normal\n * outcome for an element that connects and disconnects within the same task. Nothing in the\n * element waits on those promises, so the rejection has to end here instead of surfacing as\n * an unhandled rejection in the browser or as a hard failure in a test runner.\n */\n #onUnobservedRejection = (error: unknown) => {\n if (error instanceof ShadowEnvDestroyedError) return;\n this.logger.error('shadowEnv failed', error);\n };\n\n get shouldAutostart(): boolean {\n return this.autostart && !readBooleanAttribute(this, ATTR_NO_AUTOSTART);\n }\n\n get autoSync() {\n return this.autoSync$.value;\n }\n\n set autoSync(val: string | boolean | number) {\n this.autoSync$.set(normaliseAutoSync(val));\n }\n\n get frameLoop(): FrameLoop {\n return FrameLoop.get();\n }\n\n /**\n * The frameLoop (if activated) calls this method on every frame\n */\n [FrameLoop.OnFrame]() {\n this.syncShadowObjects();\n }\n\n async importScript(src: URL | string): Promise<ShaeWorkerElement> {\n if (!src) {\n throw new Error('src is blank');\n }\n const shadowEnv = await this.shadowEnv.ready();\n this.logger.info('shadowEnv importScript:', src, {shadowEnv});\n // ready() only vouches for the proxy at the moment it resolves; a teardown can slip in\n // between that microtask and this line\n const envProxy = shadowEnv.envProxy;\n if (envProxy == null) {\n throw new ShadowEnvDestroyedError();\n }\n\n await envProxy.importScript(src);\n return this;\n }\n\n override connectedCallback() {\n // the whole body outside any reactive context of the caller \u2014 same reason as in\n // `ShaeLifecycleElement.connectedCallback`, and the frames nest without trouble\n hibernate(() => {\n // this element does not come back, and the refusal has to stand in front of `super`: the base\n // takes an element's subscriptions up there, and for a torn-down one there is nothing to take\n // up \u2014 the teardown took the environment with it, and an environment cannot be rebuilt around\n // a proxy that is gone. A `<shae-worker>` that is needed again is a new one.\n //\n // How the element renders is a separate question from whether it still listens, so the rule\n // is installed before the refusal returns\n if (this.isDestroyed) {\n ensureDisplayContentsRule(this.getRootNode(), this.localName);\n return;\n }\n\n super.connectedCallback();\n\n batch(() => {\n const autoSync = this.getAttribute(ATTR_AUTO_SYNC);\n if (autoSync != null) {\n this.autoSync = autoSync;\n }\n this.isConnected$.set(true);\n });\n if (this.shouldAutostart) {\n this.start().catch(this.#onUnobservedRejection);\n }\n });\n }\n\n override disconnectedCallback() {\n this.isConnected$.set(false);\n super.disconnectedCallback();\n }\n\n override attributeChangedCallback(name: string) {\n // the signals of this class are destroyed, so an attribute write would land in a value that\n // notifies nobody \u2014 and there is no return that would ever read it back\n if (this.isDestroyed) return;\n\n super.attributeChangedCallback(name);\n\n if (name === ATTR_LOCAL) {\n this.#refuseLocalChange();\n }\n\n if (name === ATTR_NO_STRUCTURED_CLONE) {\n this.#disableStructuredClone();\n }\n\n if (name === ATTR_AUTO_SYNC) {\n this.autoSync = this.getAttribute(ATTR_AUTO_SYNC) ?? true;\n }\n\n if (name === ATTR_SRC) {\n const src = (this.getAttribute(ATTR_SRC) || '').trim();\n this.src$.set(src);\n if (this.shadowEnv.isReady) {\n this.#importScript?.run();\n }\n }\n }\n\n /**\n * The timeout attributes, read at the one moment they are needed: when the worker environment\n * is built. An attribute that is not there is left out, so the environment keeps its default,\n * and a value the environment does not accept is reported there. They are not observed \u2014\n * setting one afterwards changes nothing about an environment that already exists, and a\n * `local` element builds no worker environment at all, so they do nothing there.\n */\n #readWorkerTimeouts(): RemoteWorkerEnvOptions {\n const options: RemoteWorkerEnvOptions = {};\n\n for (const [key, attr] of WorkerTimeoutAttributes) {\n const value = readNumberAttribute(this, attr);\n if (value !== undefined) options[key] = value;\n }\n\n return options;\n }\n\n start(): Promise<ShadowEnv> {\n if (!this.#started) {\n this.shadowEnv.view ??= ComponentContext.get(this.ns);\n\n if (this.shadowEnv.envProxy == null) {\n const envProxy = readBooleanAttribute(this, ATTR_LOCAL)\n ? new LocalShadowObjectEnv()\n : new RemoteWorkerEnv(this.#readWorkerTimeouts());\n this.shadowEnv.envProxy = envProxy;\n this.#disableStructuredClone();\n }\n\n this.#started = true;\n }\n\n return this.shadowEnv.ready();\n }\n\n /**\n * Tear this element down \u2014 for good.\n *\n * The effects and signals below belong to the element alone, so the element is what decides\n * whether they have already been released; the guard for that sits in\n * `ShaeLifecycleElement.destroy()`, which has already set the flag by the time this runs. Here\n * that matters more than anywhere else: `shadowEnv.destroy()` dispatches a `contextlost`\n * `CustomEvent` on this element on its way out, and a listener on it that reaches back into\n * `destroy()` finds the flag down and turns around instead of tearing the same environment down\n * a second time.\n *\n * Unlike `<shae-ent>` and `<shae-prop>`, this teardown is final: it destroys the signals and\n * takes the environment down with them, and neither comes back. `connectedCallback` turns a\n * returning element away rather than handing it a half of what it had, which is what makes\n * {@link ShaeWorkerElement.restore} a method that runs once and never again.\n */\n protected override teardown() {\n this.#envViewBinding?.();\n this.#envViewBinding = undefined;\n\n this.#autoSync?.destroy();\n this.#importScript?.destroy();\n destroySignal(this.isConnected$, this.autoSync$, this.src$);\n this.shadowEnv.envProxy = undefined;\n this.shadowEnv.destroy();\n\n super.teardown();\n }\n\n #createAutoSyncEffect() {\n this.#autoSync = createEffect(() => {\n if (this.isConnected$.get()) {\n const autoSync = normaliseAutoSync(this.autoSync$.get() || ShaeWorkerElement.DefaultAutoSync);\n let delay;\n\n if (['true', 'yes', 'on', 'frame', 'auto-sync'].includes(autoSync)) {\n this.logger.debug('auto-sync', autoSync, this);\n this.frameLoop.start(this);\n return () => {\n this.frameLoop.stop(this);\n };\n } else if (autoSync.endsWith('fps')) {\n const fps = parseInt(autoSync, 10);\n if (fps > 0) {\n delay = Math.floor(1000 / fps);\n } else {\n this.logger.warn(`invalid auto-sync value: ${autoSync}`);\n }\n } else {\n delay = parseInt(autoSync, 10);\n if (isNaN(delay)) {\n delay = undefined;\n if (!['false', 'no', 'off'].includes(autoSync)) {\n this.logger.error(`invalid auto-sync value: ${autoSync}`);\n }\n }\n }\n\n if (delay !== undefined && delay > 0) {\n this.logger.debug('auto-sync interval (ms)', delay, this);\n const id = setInterval(() => {\n this.syncShadowObjects();\n }, delay);\n return () => {\n clearInterval(id);\n };\n } else {\n this.logger.debug('auto-sync off', this);\n }\n }\n }, [this.autoSync$, this.isConnected$]);\n }\n\n #disableStructuredClone() {\n const env = this.shadowEnv.envProxy as LocalShadowObjectEnv;\n if (env?.isLocalEnv) {\n env.disableStructuredClone = this.hasAttribute(ATTR_NO_STRUCTURED_CLONE);\n }\n }\n\n /**\n * `local` picks the environment kind once, at `start()`. The proxy, its kernel and its\n * entities all belong to the side they were built on, and there is no way to move them onto\n * the other one afterwards \u2014 a later write to this attribute is refused, not carried out.\n *\n * A throw from this reaction would not reach the caller of `setAttribute` either way: per spec,\n * a Custom Element reaction reports its own exceptions to the global `error` event instead of\n * propagating them synchronously, so a `try`/`catch` around the write would catch nothing. The\n * refusal writes the attribute back through `reflectAttribute`, the one path this element uses\n * to write its own attributes from inside, and reports the refusal separately through the\n * `ConsoleLogger`. `logger.error` and not `logger.warn`: `logger.error` always prints, where\n * `logger.warn` is gated behind `isWarn`, which is off outside `localhost`, and a refusal that\n * goes silent there is exactly what this call needs to avoid.\n *\n * The write back re-enters `attributeChangedCallback` once, where the attribute now matches\n * the effective state and the check below returns before logging again. On an element built\n * and started by hand while it was never in the document, that write is parked until the first\n * connect (see `reflectAttribute`), while the log line above runs immediately.\n */\n #refuseLocalChange(): void {\n const envProxy = this.shadowEnv.envProxy;\n if (envProxy == null) return;\n\n const isLocalEnv = Boolean((envProxy as LocalShadowObjectEnv).isLocalEnv);\n if (readBooleanAttribute(this, ATTR_LOCAL) === isLocalEnv) return;\n\n this.logger.error(\n `the \"local\" attribute cannot change once the shadowEnv is built; it is reset to ${\n isLocalEnv ? 'the bare \"local\" form' : 'its absence'\n } \u2014 build a new <shae-worker> element to switch environments`,\n );\n\n this.reflectAttribute(ATTR_LOCAL, () => {\n if (isLocalEnv) {\n this.setAttribute(ATTR_LOCAL, '');\n } else {\n this.removeAttribute(ATTR_LOCAL);\n }\n });\n }\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAQ,UAAS;AACjB,SAAQ,OAAO,cAAc,cAAc,eAAe,QAAQ,iBAAgB;
|
|
4
|
+
"sourcesContent": ["import {on} from '@spearwolf/eventize';\nimport {batch, createEffect, createSignal, destroySignal, Effect, hibernate} from '@spearwolf/signalize';\nimport type {ExposeHandle} from '../model-context/exposeShadowEnvsToModelContext.js';\nimport {readBooleanAttribute, readListAttribute, readNumberAttribute} from '../utils/attr-utils.js';\nimport {ConsoleLogger} from '../utils/ConsoleLogger.js';\nimport {FrameLoop} from '../utils/FrameLoop.js';\nimport {ComponentContext} from '../view/ComponentContext.js';\nimport {LocalShadowObjectEnv} from '../view/LocalShadowObjectEnv.js';\nimport {RemoteWorkerEnv, type RemoteWorkerEnvOptions} from '../view/RemoteWorkerEnv.js';\nimport {ShadowEnv, ShadowEnvDestroyedError} from '../view/ShadowEnv.js';\nimport {\n ATTR_AUTO_SYNC,\n ATTR_CHANGE_TRAIL_TIMEOUT,\n ATTR_CONFIGURE_TIMEOUT,\n ATTR_DESTROY_TIMEOUT,\n ATTR_EXPOSE_TO_MODEL_CONTEXT,\n ATTR_INSPECT_TIMEOUT,\n ATTR_LOAD_TIMEOUT,\n ATTR_LOCAL,\n ATTR_NO_AUTOSTART,\n ATTR_NO_STRUCTURED_CLONE,\n ATTR_REDACT_PROPS,\n ATTR_SRC,\n} from './constants.js';\nimport {ensureDisplayContentsRule} from './displayContentsRule.js';\nimport {ShaeElement} from './ShaeElement.js';\n\nconst WorkerTimeoutAttributes: [keyof RemoteWorkerEnvOptions, string][] = [\n ['loadTimeout', ATTR_LOAD_TIMEOUT],\n ['configureTimeout', ATTR_CONFIGURE_TIMEOUT],\n ['changeTrailTimeout', ATTR_CHANGE_TRAIL_TIMEOUT],\n ['inspectTimeout', ATTR_INSPECT_TIMEOUT],\n ['destroyTimeout', ATTR_DESTROY_TIMEOUT],\n];\n\n/**\n * The one place the `auto-sync` spelling rule lives: a string is trimmed and lower-cased,\n * and anything else is read as a flag \u2014 a truthy value asks for the frame default, a falsy\n * one for no syncing at all. Every write into `autoSync$` this element makes goes through\n * here, so the canonical spelling does not depend on which write ran first.\n */\nfunction normaliseAutoSync(value: unknown): string {\n if (typeof value !== 'string') {\n return value ? ShaeWorkerElement.DefaultAutoSync : 'no';\n }\n return value.trim().toLowerCase();\n}\n\n/** One element's share of the page's model-context registration: the signal that ends it, the handle it resolves to. */\ninterface ModelContextExposure {\n controller: AbortController;\n handle: Promise<ExposeHandle>;\n}\n\nexport class ShaeWorkerElement extends ShaeElement {\n static override observedAttributes = [\n ...ShaeElement.observedAttributes,\n ATTR_LOCAL,\n ATTR_SRC,\n ATTR_NO_STRUCTURED_CLONE,\n ATTR_AUTO_SYNC,\n ATTR_EXPOSE_TO_MODEL_CONTEXT,\n ];\n\n static DefaultAutoSync = 'frame';\n\n readonly isShaeWorkerElement = true;\n\n readonly shadowEnv = new ShadowEnv();\n\n readonly #logger = new ConsoleLogger('ShaeWorkerElement');\n\n /** The logger this element reports through. */\n get logger(): ConsoleLogger {\n return this.#logger;\n }\n\n autostart = true;\n\n isConnected$ = createSignal(false);\n autoSync$ = createSignal(ShaeWorkerElement.DefaultAutoSync);\n src$ = createSignal('');\n\n #started = false;\n\n #autoSync?: Effect;\n #importScript?: Effect;\n\n #modelContextExposure?: ModelContextExposure | undefined;\n\n /** The `redact-props` attribute as a list of property names, read as it stands right now. */\n get redactProps(): string[] {\n return readListAttribute(this, ATTR_REDACT_PROPS);\n }\n\n /**\n * This element's share of the page's model-context registration, while it has one: a promise\n * of the `ExposeHandle`, resolving once the tools are on the platform (`available: false` where\n * there is none) and rejecting with what `registerTool()` rejected with. `undefined` without\n * the `expose-to-model-context` attribute, before the first connect, and after a teardown.\n */\n get modelContextExposure(): Promise<ExposeHandle> | undefined {\n return this.#modelContextExposure?.handle;\n }\n\n /**\n * Points the environment at the namespace this element names.\n *\n * It hangs on `ns$`, which belongs to the base class and outlives this element's teardown, so\n * the handle is kept and released by hand \u2014 a listener left on a living signal is a listener the\n * global signal queue goes on holding, and with it this element.\n */\n #envViewBinding?: (() => void) | undefined;\n\n /**\n * Take the subscriptions up. Runs exactly once for this element, on the first connect.\n *\n * The return that `restore()` stands for on `<shae-ent>` and `<shae-prop>` does not exist here:\n * `connectedCallback` turns a torn-down `<shae-worker>` away, so nothing ever calls this a second\n * time.\n *\n * One path runs ahead of it, and it is the only one: `start()` is public, and an element started\n * by hand while it is out of the document builds its environment before anything below is\n * listening. Two things are lost there and stay lost, because both are moments rather than\n * values, and there is no honest way to replay a moment that has passed:\n *\n * - the `contextcreated` \u2014 and, should the environment lose its connection first, the\n * `contextlost` \u2014 DOM event for that environment. `ShadowEnv.ContextCreated` fires once, with\n * nobody on the element listening for it; re-dispatching it from here would announce as new an\n * environment that has been up for a while.\n * - the namespace the environment points at, where `ns` changed between that `start()` and the\n * first connect. `start()` resolves the view once with `??=`, the binding below only reacts to\n * *changes*, and the change already happened. `shadowEnv.view` then names the context of the\n * namespace the element carried when it was started. A write of `ns` after the first connect\n * moves it, as it always does.\n *\n * A `<shae-worker>` that connects before it starts \u2014 the ordinary way, and the only way the\n * declarative form has \u2014 meets neither. The import of `src` is the one case of this shape that\n * *is* caught up, at the end of this method, because a pending import is a value and not a\n * moment.\n */\n protected override restore(): void {\n super.restore();\n\n this.#envViewBinding = this.ns$.onChange((ns) => {\n this.shadowEnv.view = ComponentContext.get(ns);\n });\n\n on(this.shadowEnv, ShadowEnv.ContextCreated, () => {\n this.#importScript?.run();\n this.dispatchEvent(\n new CustomEvent(ShadowEnv.ContextCreated.toLowerCase(), {\n bubbles: false,\n detail: {shadowEnv: this.shadowEnv},\n }),\n );\n });\n\n on(this.shadowEnv, ShadowEnv.ContextLost, () => {\n this.dispatchEvent(\n new CustomEvent(ShadowEnv.ContextLost.toLowerCase(), {\n bubbles: false,\n detail: {shadowEnv: this.shadowEnv},\n }),\n );\n });\n\n on(this.shadowEnv, ShadowEnv.ProxyFailed, (reason: unknown) => {\n this.dispatchEvent(\n new CustomEvent(ShadowEnv.ProxyFailed.toLowerCase(), {\n bubbles: false,\n detail: {shadowEnv: this.shadowEnv, reason},\n }),\n );\n });\n\n on(this.shadowEnv, ShadowEnv.SyncFailed, (reason: unknown, changeTrail: unknown) => {\n this.dispatchEvent(\n new CustomEvent(ShadowEnv.SyncFailed.toLowerCase(), {\n bubbles: false,\n detail: {shadowEnv: this.shadowEnv, reason, changeTrail},\n }),\n );\n });\n\n this.autoSync$.onChange((sVal) => this.#reflectAutoSync(sVal));\n\n // the catch-up half of `restore()`: the signal carries the canonical spelling, and this is\n // what puts it on the attribute \u2014 `auto-sync=\"YES\"` is what an author writes, `auto-sync=\"yes\"`\n // is what the element syncs on, and a reader of the DOM sees the second\n this.#reflectAutoSync(this.autoSync$.value);\n\n // no catch-up for the namespace binding, and that is deliberate: the environment gets its view\n // from `start()`, which resolves the namespace at the one moment it needs it. Resolving it here\n // would build a `ComponentContext` for every `<shae-worker>` that has merely been connected,\n // and a context that exists is a context entities join\n this.#createAutoSyncEffect();\n this.#createImportScriptEffect();\n\n // a `src` that arrived while the environment was already up \u2014 only reachable through a\n // `start()` made by hand on an element outside the document \u2014 has nothing that would import it:\n // the effect is built without an autorun, and both callers that run it were registered a few\n // lines above. The same test `attributeChangedCallback` makes for `src`\n if (this.shadowEnv.isReady) {\n this.#importScript?.run();\n }\n }\n\n #reflectAutoSync(sVal: string): void {\n this.reflectAttribute(ATTR_AUTO_SYNC, () => {\n const hasAttr = this.hasAttribute(ATTR_AUTO_SYNC);\n const attrVal = hasAttr ? this.getAttribute(ATTR_AUTO_SYNC) : undefined;\n\n if (sVal === ShaeWorkerElement.DefaultAutoSync) {\n if (hasAttr && attrVal !== sVal) {\n this.setAttribute(ATTR_AUTO_SYNC, sVal);\n }\n } else if (attrVal !== sVal) {\n this.setAttribute(ATTR_AUTO_SYNC, sVal);\n }\n });\n }\n\n #createImportScriptEffect() {\n this.#importScript = createEffect(\n () => {\n const src = this.src$.get();\n if (src) {\n this.importScript(src).catch(this.#onUnobservedRejection);\n }\n },\n {autorun: false},\n );\n }\n\n /**\n * Both {@link ShaeWorkerElement.start} and {@link ShaeWorkerElement.importScript} await\n * {@link ShadowEnv.ready}, which rejects once the environment is destroyed \u2014 the normal\n * outcome for an element that connects and disconnects within the same task. Nothing in the\n * element waits on those promises, so the rejection has to end here instead of surfacing as\n * an unhandled rejection in the browser or as a hard failure in a test runner.\n */\n #onUnobservedRejection = (error: unknown) => {\n if (error instanceof ShadowEnvDestroyedError) return;\n this.logger.error('shadowEnv failed', error);\n };\n\n get shouldAutostart(): boolean {\n return this.autostart && !readBooleanAttribute(this, ATTR_NO_AUTOSTART);\n }\n\n get autoSync() {\n return this.autoSync$.value;\n }\n\n set autoSync(val: string | boolean | number) {\n this.autoSync$.set(normaliseAutoSync(val));\n }\n\n get frameLoop(): FrameLoop {\n return FrameLoop.get();\n }\n\n /**\n * The frameLoop (if activated) calls this method on every frame\n */\n [FrameLoop.OnFrame]() {\n this.syncShadowObjects();\n }\n\n async importScript(src: URL | string): Promise<ShaeWorkerElement> {\n if (!src) {\n throw new Error('src is blank');\n }\n const shadowEnv = await this.shadowEnv.ready();\n this.logger.info('shadowEnv importScript:', src, {shadowEnv});\n // ready() only vouches for the proxy at the moment it resolves; a teardown can slip in\n // between that microtask and this line\n const envProxy = shadowEnv.envProxy;\n if (envProxy == null) {\n throw new ShadowEnvDestroyedError();\n }\n\n await envProxy.importScript(src);\n return this;\n }\n\n override connectedCallback() {\n // the whole body outside any reactive context of the caller \u2014 same reason as in\n // `ShaeLifecycleElement.connectedCallback`, and the frames nest without trouble\n hibernate(() => {\n // this element does not come back, and the refusal has to stand in front of `super`: the base\n // takes an element's subscriptions up there, and for a torn-down one there is nothing to take\n // up \u2014 the teardown took the environment with it, and an environment cannot be rebuilt around\n // a proxy that is gone. A `<shae-worker>` that is needed again is a new one.\n //\n // How the element renders is a separate question from whether it still listens, so the rule\n // is installed before the refusal returns\n if (this.isDestroyed) {\n ensureDisplayContentsRule(this.getRootNode(), this.localName);\n return;\n }\n\n super.connectedCallback();\n\n batch(() => {\n const autoSync = this.getAttribute(ATTR_AUTO_SYNC);\n if (autoSync != null) {\n this.autoSync = autoSync;\n }\n this.isConnected$.set(true);\n });\n if (this.shouldAutostart) {\n this.start().catch(this.#onUnobservedRejection);\n }\n this.#syncModelContextExposure();\n });\n }\n\n override disconnectedCallback() {\n this.isConnected$.set(false);\n super.disconnectedCallback();\n }\n\n override attributeChangedCallback(name: string) {\n // the signals of this class are destroyed, so an attribute write would land in a value that\n // notifies nobody \u2014 and there is no return that would ever read it back\n if (this.isDestroyed) return;\n\n super.attributeChangedCallback(name);\n\n if (name === ATTR_LOCAL) {\n this.#refuseLocalChange();\n }\n\n if (name === ATTR_NO_STRUCTURED_CLONE) {\n this.#disableStructuredClone();\n }\n\n if (name === ATTR_AUTO_SYNC) {\n this.autoSync = this.getAttribute(ATTR_AUTO_SYNC) ?? true;\n }\n\n if (name === ATTR_SRC) {\n const src = (this.getAttribute(ATTR_SRC) || '').trim();\n this.src$.set(src);\n if (this.shadowEnv.isReady) {\n this.#importScript?.run();\n }\n }\n\n if (name === ATTR_EXPOSE_TO_MODEL_CONTEXT) {\n this.#syncModelContextExposure();\n }\n }\n\n /**\n * The timeout attributes, read at the one moment they are needed: when the worker environment\n * is built. An attribute that is not there is left out, so the environment keeps its default,\n * and a value the environment does not accept is reported there. They are not observed \u2014\n * setting one afterwards changes nothing about an environment that already exists, and a\n * `local` element builds no worker environment at all, so they do nothing there.\n */\n #readWorkerTimeouts(): RemoteWorkerEnvOptions {\n const options: RemoteWorkerEnvOptions = {};\n\n for (const [key, attr] of WorkerTimeoutAttributes) {\n const value = readNumberAttribute(this, attr);\n if (value !== undefined) options[key] = value;\n }\n\n return options;\n }\n\n start(): Promise<ShadowEnv> {\n if (!this.#started) {\n this.shadowEnv.view ??= ComponentContext.get(this.ns);\n\n if (this.shadowEnv.envProxy == null) {\n const envProxy = readBooleanAttribute(this, ATTR_LOCAL)\n ? new LocalShadowObjectEnv()\n : new RemoteWorkerEnv(this.#readWorkerTimeouts());\n this.shadowEnv.envProxy = envProxy;\n this.#disableStructuredClone();\n }\n\n this.#started = true;\n }\n\n return this.shadowEnv.ready();\n }\n\n /**\n * Tear this element down \u2014 for good.\n *\n * The effects and signals below belong to the element alone, so the element is what decides\n * whether they have already been released; the guard for that sits in\n * `ShaeLifecycleElement.destroy()`, which has already set the flag by the time this runs. Here\n * that matters more than anywhere else: `shadowEnv.destroy()` dispatches a `contextlost`\n * `CustomEvent` on this element on its way out, and a listener on it that reaches back into\n * `destroy()` finds the flag down and turns around instead of tearing the same environment down\n * a second time.\n *\n * Unlike `<shae-ent>` and `<shae-prop>`, this teardown is final: it destroys the signals and\n * takes the environment down with them, and neither comes back. `connectedCallback` turns a\n * returning element away rather than handing it a half of what it had, which is what makes\n * {@link ShaeWorkerElement.restore} a method that runs once and never again.\n */\n protected override teardown() {\n this.#leaveModelContextExposure();\n\n this.#envViewBinding?.();\n this.#envViewBinding = undefined;\n\n this.#autoSync?.destroy();\n this.#importScript?.destroy();\n destroySignal(this.isConnected$, this.autoSync$, this.src$);\n this.shadowEnv.envProxy = undefined;\n this.shadowEnv.destroy();\n\n super.teardown();\n }\n\n #createAutoSyncEffect() {\n this.#autoSync = createEffect(() => {\n if (this.isConnected$.get()) {\n const autoSync = normaliseAutoSync(this.autoSync$.get() || ShaeWorkerElement.DefaultAutoSync);\n let delay;\n\n if (['true', 'yes', 'on', 'frame', 'auto-sync'].includes(autoSync)) {\n this.logger.debug('auto-sync', autoSync, this);\n this.frameLoop.start(this);\n return () => {\n this.frameLoop.stop(this);\n };\n } else if (autoSync.endsWith('fps')) {\n const fps = parseInt(autoSync, 10);\n if (fps > 0) {\n delay = Math.floor(1000 / fps);\n } else {\n this.logger.warn(`invalid auto-sync value: ${autoSync}`);\n }\n } else {\n delay = parseInt(autoSync, 10);\n if (isNaN(delay)) {\n delay = undefined;\n if (!['false', 'no', 'off'].includes(autoSync)) {\n this.logger.error(`invalid auto-sync value: ${autoSync}`);\n }\n }\n }\n\n if (delay !== undefined && delay > 0) {\n this.logger.debug('auto-sync interval (ms)', delay, this);\n const id = setInterval(() => {\n this.syncShadowObjects();\n }, delay);\n return () => {\n clearInterval(id);\n };\n } else {\n this.logger.debug('auto-sync off', this);\n }\n }\n }, [this.autoSync$, this.isConnected$]);\n }\n\n #disableStructuredClone() {\n const env = this.shadowEnv.envProxy as LocalShadowObjectEnv;\n if (env?.isLocalEnv) {\n env.disableStructuredClone = this.hasAttribute(ATTR_NO_STRUCTURED_CLONE);\n }\n }\n\n /**\n * `local` picks the environment kind once, at `start()`. The proxy, its kernel and its\n * entities all belong to the side they were built on, and there is no way to move them onto\n * the other one afterwards \u2014 a later write to this attribute is refused, not carried out.\n *\n * A throw from this reaction would not reach the caller of `setAttribute` either way: per spec,\n * a Custom Element reaction reports its own exceptions to the global `error` event instead of\n * propagating them synchronously, so a `try`/`catch` around the write would catch nothing. The\n * refusal writes the attribute back through `reflectAttribute`, the one path this element uses\n * to write its own attributes from inside, and reports the refusal separately through the\n * `ConsoleLogger`. `logger.error` and not `logger.warn`: `logger.error` always prints, where\n * `logger.warn` is gated behind `isWarn`, which is off outside `localhost`, and a refusal that\n * goes silent there is exactly what this call needs to avoid.\n *\n * The write back re-enters `attributeChangedCallback` once, where the attribute now matches\n * the effective state and the check below returns before logging again. On an element built\n * and started by hand while it was never in the document, that write is parked until the first\n * connect (see `reflectAttribute`), while the log line above runs immediately.\n */\n #refuseLocalChange(): void {\n const envProxy = this.shadowEnv.envProxy;\n if (envProxy == null) return;\n\n const isLocalEnv = Boolean((envProxy as LocalShadowObjectEnv).isLocalEnv);\n if (readBooleanAttribute(this, ATTR_LOCAL) === isLocalEnv) return;\n\n this.logger.error(\n `the \"local\" attribute cannot change once the shadowEnv is built; it is reset to ${\n isLocalEnv ? 'the bare \"local\" form' : 'its absence'\n } \u2014 build a new <shae-worker> element to switch environments`,\n );\n\n this.reflectAttribute(ATTR_LOCAL, () => {\n if (isLocalEnv) {\n this.setAttribute(ATTR_LOCAL, '');\n } else {\n this.removeAttribute(ATTR_LOCAL);\n }\n });\n }\n /**\n * Joins or leaves the page's model-context registration, whichever the attribute and the\n * element's state ask for. The attribute is a truthy attribute like `local`; the join waits\n * for a connect, because an element that is never connected has no environment to expose, and\n * it ends with the teardown. `redact-props` is not watched: the share reads it at every call.\n */\n #syncModelContextExposure(): void {\n const wanted = !this.isDestroyed && this.isConnected && readBooleanAttribute(this, ATTR_EXPOSE_TO_MODEL_CONTEXT);\n if (wanted) {\n this.#joinModelContextExposure();\n } else {\n this.#leaveModelContextExposure();\n }\n }\n\n /**\n * The share is an ordinary call of `exposeShadowEnvsToModelContext()` with two live rules:\n * this element's namespace, and the names its `redact-props` attribute carries at the moment\n * a tool asks. The function comes in through a dynamic import, and that is the whole reason\n * this element can carry the attribute at all -- a static import would pull the model-context\n * layer into every consumer of `<shae-worker>`, and the layer is meant to stay out of\n * `index.ts` and the worker bundle. The single-file bundle inlines the import; the lib layout\n * keeps the modules apart. A leave before the import is back aborts the signal the call is\n * made with, and the function registers nothing for an aborted signal.\n */\n #joinModelContextExposure(): void {\n if (this.#modelContextExposure !== undefined) return;\n\n const controller = new AbortController();\n const handle = import('../model-context/exposeShadowEnvsToModelContext.js').then(({exposeShadowEnvsToModelContext}) =>\n exposeShadowEnvsToModelContext({\n signal: controller.signal,\n namespaces: (ns) => ns === this.ns,\n redactProps: (name) => this.redactProps.includes(name),\n }),\n );\n this.#modelContextExposure = {controller, handle};\n\n // the rejection reaches whoever awaits `modelContextExposure` as well; this makes sure it is heard when nobody does\n handle.catch((error) => this.logger.error('expose-to-model-context: registering the tools failed', error));\n }\n\n #leaveModelContextExposure(): void {\n const exposure = this.#modelContextExposure;\n if (exposure === undefined) return;\n this.#modelContextExposure = undefined;\n exposure.controller.abort();\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -16,7 +16,10 @@ export declare const ATTR_SRC = "src";
|
|
|
16
16
|
export declare const ATTR_LOAD_TIMEOUT = "load-timeout";
|
|
17
17
|
export declare const ATTR_CONFIGURE_TIMEOUT = "configure-timeout";
|
|
18
18
|
export declare const ATTR_CHANGE_TRAIL_TIMEOUT = "change-trail-timeout";
|
|
19
|
+
export declare const ATTR_INSPECT_TIMEOUT = "inspect-timeout";
|
|
19
20
|
export declare const ATTR_DESTROY_TIMEOUT = "destroy-timeout";
|
|
21
|
+
export declare const ATTR_EXPOSE_TO_MODEL_CONTEXT = "expose-to-model-context";
|
|
22
|
+
export declare const ATTR_REDACT_PROPS = "redact-props";
|
|
20
23
|
export declare const ATTR_NAME = "name";
|
|
21
24
|
export declare const ATTR_VALUE = "value";
|
|
22
25
|
export declare const ATTR_TYPE = "type";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/elements/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,yBAAyB,yBAAyB,CAAC;AAChE,eAAO,MAAM,2BAA2B,2BAA2B,CAAC;AACpE,eAAO,MAAM,yBAAyB,yBAAyB,CAAC;AAEhE,eAAO,MAAM,WAAW,gBAAgB,CAAC;AACzC,eAAO,MAAM,QAAQ,aAAa,CAAC;AACnC,eAAO,MAAM,SAAS,cAAc,CAAC;AAGrC,eAAO,MAAM,UAAU,UAAU,CAAC;AAClC,eAAO,MAAM,0BAA0B,0BAA0B,CAAC;AAClE,eAAO,MAAM,kBAAkB,kBAAkB,CAAC;AAGlD,eAAO,MAAM,OAAO,OAAO,CAAC;AAG5B,eAAO,MAAM,UAAU,UAAU,CAAC;AAClC,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAChD,eAAO,MAAM,wBAAwB,wBAAwB,CAAC;AAC9D,eAAO,MAAM,cAAc,cAAc,CAAC;AAC1C,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAC9B,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAChD,eAAO,MAAM,sBAAsB,sBAAsB,CAAC;AAC1D,eAAO,MAAM,yBAAyB,yBAAyB,CAAC;AAChE,eAAO,MAAM,oBAAoB,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/elements/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,yBAAyB,yBAAyB,CAAC;AAChE,eAAO,MAAM,2BAA2B,2BAA2B,CAAC;AACpE,eAAO,MAAM,yBAAyB,yBAAyB,CAAC;AAEhE,eAAO,MAAM,WAAW,gBAAgB,CAAC;AACzC,eAAO,MAAM,QAAQ,aAAa,CAAC;AACnC,eAAO,MAAM,SAAS,cAAc,CAAC;AAGrC,eAAO,MAAM,UAAU,UAAU,CAAC;AAClC,eAAO,MAAM,0BAA0B,0BAA0B,CAAC;AAClE,eAAO,MAAM,kBAAkB,kBAAkB,CAAC;AAGlD,eAAO,MAAM,OAAO,OAAO,CAAC;AAG5B,eAAO,MAAM,UAAU,UAAU,CAAC;AAClC,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAChD,eAAO,MAAM,wBAAwB,wBAAwB,CAAC;AAC9D,eAAO,MAAM,cAAc,cAAc,CAAC;AAC1C,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAC9B,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAChD,eAAO,MAAM,sBAAsB,sBAAsB,CAAC;AAC1D,eAAO,MAAM,yBAAyB,yBAAyB,CAAC;AAChE,eAAO,MAAM,oBAAoB,oBAAoB,CAAC;AACtD,eAAO,MAAM,oBAAoB,oBAAoB,CAAC;AACtD,eAAO,MAAM,4BAA4B,4BAA4B,CAAC;AACtE,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAGhD,eAAO,MAAM,SAAS,SAAS,CAAC;AAChC,eAAO,MAAM,UAAU,UAAU,CAAC;AAClC,eAAO,MAAM,SAAS,SAAS,CAAC;AAChC,eAAO,MAAM,YAAY,YAAY,CAAC"}
|
|
@@ -16,7 +16,10 @@ const ATTR_SRC = "src";
|
|
|
16
16
|
const ATTR_LOAD_TIMEOUT = "load-timeout";
|
|
17
17
|
const ATTR_CONFIGURE_TIMEOUT = "configure-timeout";
|
|
18
18
|
const ATTR_CHANGE_TRAIL_TIMEOUT = "change-trail-timeout";
|
|
19
|
+
const ATTR_INSPECT_TIMEOUT = "inspect-timeout";
|
|
19
20
|
const ATTR_DESTROY_TIMEOUT = "destroy-timeout";
|
|
21
|
+
const ATTR_EXPOSE_TO_MODEL_CONTEXT = "expose-to-model-context";
|
|
22
|
+
const ATTR_REDACT_PROPS = "redact-props";
|
|
20
23
|
const ATTR_NAME = "name";
|
|
21
24
|
const ATTR_VALUE = "value";
|
|
22
25
|
const ATTR_TYPE = "type";
|
|
@@ -27,7 +30,9 @@ export {
|
|
|
27
30
|
ATTR_CHANGE_TRAIL_TIMEOUT,
|
|
28
31
|
ATTR_CONFIGURE_TIMEOUT,
|
|
29
32
|
ATTR_DESTROY_TIMEOUT,
|
|
33
|
+
ATTR_EXPOSE_TO_MODEL_CONTEXT,
|
|
30
34
|
ATTR_FORWARD_CUSTOM_EVENTS,
|
|
35
|
+
ATTR_INSPECT_TIMEOUT,
|
|
31
36
|
ATTR_LOAD_TIMEOUT,
|
|
32
37
|
ATTR_LOCAL,
|
|
33
38
|
ATTR_NAME,
|
|
@@ -35,6 +40,7 @@ export {
|
|
|
35
40
|
ATTR_NO_STRUCTURED_CLONE,
|
|
36
41
|
ATTR_NO_TRIM,
|
|
37
42
|
ATTR_NS,
|
|
43
|
+
ATTR_REDACT_PROPS,
|
|
38
44
|
ATTR_SRC,
|
|
39
45
|
ATTR_TOKEN,
|
|
40
46
|
ATTR_TYPE,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/elements/constants.ts"],
|
|
4
|
-
"sourcesContent": ["export const RequestEntParentEventName = 'shaeRequestEntParent';\nexport const ReRequestEntParentEventName = 'shaeReRequestEntParent';\nexport const ReRequestEntHostEventName = 'shaeReRequestEntHost';\n\nexport const SHAE_WORKER = 'shae-worker';\nexport const SHAE_ENT = 'shae-ent';\nexport const SHAE_PROP = 'shae-prop';\n\n// <shae-ent> attributes\nexport const ATTR_TOKEN = 'token';\nexport const ATTR_FORWARD_CUSTOM_EVENTS = 'forward-custom-events';\nexport const ATTR_AUTO_DESTRUCT = 'auto-destruct';\n\n// <shae-ent> + <shae-worker> attributes\nexport const ATTR_NS = 'ns';\n\n// <shae-worker> attributes\nexport const ATTR_LOCAL = 'local';\nexport const ATTR_NO_AUTOSTART = 'no-autostart';\nexport const ATTR_NO_STRUCTURED_CLONE = 'no-structured-clone';\nexport const ATTR_AUTO_SYNC = 'auto-sync';\nexport const ATTR_SRC = 'src';\nexport const ATTR_LOAD_TIMEOUT = 'load-timeout';\nexport const ATTR_CONFIGURE_TIMEOUT = 'configure-timeout';\nexport const ATTR_CHANGE_TRAIL_TIMEOUT = 'change-trail-timeout';\nexport const ATTR_DESTROY_TIMEOUT = 'destroy-timeout';\n\n// <shae-prop> attributes\nexport const ATTR_NAME = 'name';\nexport const ATTR_VALUE = 'value';\nexport const ATTR_TYPE = 'type';\nexport const ATTR_NO_TRIM = 'no-trim';\n"],
|
|
5
|
-
"mappings": "AAAO,MAAM,4BAA4B;AAClC,MAAM,8BAA8B;AACpC,MAAM,4BAA4B;AAElC,MAAM,cAAc;AACpB,MAAM,WAAW;AACjB,MAAM,YAAY;AAGlB,MAAM,aAAa;AACnB,MAAM,6BAA6B;AACnC,MAAM,qBAAqB;AAG3B,MAAM,UAAU;AAGhB,MAAM,aAAa;AACnB,MAAM,oBAAoB;AAC1B,MAAM,2BAA2B;AACjC,MAAM,iBAAiB;AACvB,MAAM,WAAW;AACjB,MAAM,oBAAoB;AAC1B,MAAM,yBAAyB;AAC/B,MAAM,4BAA4B;AAClC,MAAM,uBAAuB;
|
|
4
|
+
"sourcesContent": ["export const RequestEntParentEventName = 'shaeRequestEntParent';\nexport const ReRequestEntParentEventName = 'shaeReRequestEntParent';\nexport const ReRequestEntHostEventName = 'shaeReRequestEntHost';\n\nexport const SHAE_WORKER = 'shae-worker';\nexport const SHAE_ENT = 'shae-ent';\nexport const SHAE_PROP = 'shae-prop';\n\n// <shae-ent> attributes\nexport const ATTR_TOKEN = 'token';\nexport const ATTR_FORWARD_CUSTOM_EVENTS = 'forward-custom-events';\nexport const ATTR_AUTO_DESTRUCT = 'auto-destruct';\n\n// <shae-ent> + <shae-worker> attributes\nexport const ATTR_NS = 'ns';\n\n// <shae-worker> attributes\nexport const ATTR_LOCAL = 'local';\nexport const ATTR_NO_AUTOSTART = 'no-autostart';\nexport const ATTR_NO_STRUCTURED_CLONE = 'no-structured-clone';\nexport const ATTR_AUTO_SYNC = 'auto-sync';\nexport const ATTR_SRC = 'src';\nexport const ATTR_LOAD_TIMEOUT = 'load-timeout';\nexport const ATTR_CONFIGURE_TIMEOUT = 'configure-timeout';\nexport const ATTR_CHANGE_TRAIL_TIMEOUT = 'change-trail-timeout';\nexport const ATTR_INSPECT_TIMEOUT = 'inspect-timeout';\nexport const ATTR_DESTROY_TIMEOUT = 'destroy-timeout';\nexport const ATTR_EXPOSE_TO_MODEL_CONTEXT = 'expose-to-model-context';\nexport const ATTR_REDACT_PROPS = 'redact-props';\n\n// <shae-prop> attributes\nexport const ATTR_NAME = 'name';\nexport const ATTR_VALUE = 'value';\nexport const ATTR_TYPE = 'type';\nexport const ATTR_NO_TRIM = 'no-trim';\n"],
|
|
5
|
+
"mappings": "AAAO,MAAM,4BAA4B;AAClC,MAAM,8BAA8B;AACpC,MAAM,4BAA4B;AAElC,MAAM,cAAc;AACpB,MAAM,WAAW;AACjB,MAAM,YAAY;AAGlB,MAAM,aAAa;AACnB,MAAM,6BAA6B;AACnC,MAAM,qBAAqB;AAG3B,MAAM,UAAU;AAGhB,MAAM,aAAa;AACnB,MAAM,oBAAoB;AAC1B,MAAM,2BAA2B;AACjC,MAAM,iBAAiB;AACvB,MAAM,WAAW;AACjB,MAAM,oBAAoB;AAC1B,MAAM,yBAAyB;AAC/B,MAAM,4BAA4B;AAClC,MAAM,uBAAuB;AAC7B,MAAM,uBAAuB;AAC7B,MAAM,+BAA+B;AACrC,MAAM,oBAAoB;AAG1B,MAAM,YAAY;AAClB,MAAM,aAAa;AACnB,MAAM,YAAY;AAClB,MAAM,eAAe;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -130,6 +130,36 @@ export declare class Entity {
|
|
|
130
130
|
clearTruthyPropsCache(): void;
|
|
131
131
|
truthyProps(): Set<string> | undefined;
|
|
132
132
|
hasContext(name: ContextNameType): boolean;
|
|
133
|
+
/** The names of the Entity Contexts this entity holds, used or provided. Reads only, creates none. */
|
|
134
|
+
contextNames(): ContextNameType[];
|
|
135
|
+
/**
|
|
136
|
+
* The three values behind one Entity Context of this entity: what its own providers wrote, what it
|
|
137
|
+
* inherits from the parent (or from the global chain at a root), and what `useContext(name)` reads.
|
|
138
|
+
* `hasProviders` says whether a provider feed is attached -- a value written straight into the
|
|
139
|
+
* signal from `provideContext()` counts as provided but not as a provider.
|
|
140
|
+
*
|
|
141
|
+
* `undefined` when the entity holds no context of that name; asking does not create one. The
|
|
142
|
+
* reads are plain `.value` reads and track nothing, so a call from inside an effect does not
|
|
143
|
+
* subscribe that effect to the context.
|
|
144
|
+
*/
|
|
145
|
+
describeContext(name: ContextNameType): {
|
|
146
|
+
provided: unknown;
|
|
147
|
+
inherited: unknown;
|
|
148
|
+
effective: unknown;
|
|
149
|
+
hasProviders: boolean;
|
|
150
|
+
} | undefined;
|
|
151
|
+
/** The names of the global Entity Contexts this entity contributes to. Reads only, creates none. */
|
|
152
|
+
globalContextNames(): ContextNameType[];
|
|
153
|
+
/**
|
|
154
|
+
* What this entity contributes to the kernel-wide chain of one global Entity Context: the value
|
|
155
|
+
* and the very signal that stands in the chain, so a caller holding the chain can find this entity
|
|
156
|
+
* in it by identity. `undefined` when the entity contributes nothing under that name.
|
|
157
|
+
*/
|
|
158
|
+
describeGlobalContext(name: ContextNameType): {
|
|
159
|
+
value: unknown;
|
|
160
|
+
signal: Signal<unknown>;
|
|
161
|
+
hasProviders: boolean;
|
|
162
|
+
} | undefined;
|
|
133
163
|
useContext<T = unknown>(name: ContextNameType): SignalReader<T>;
|
|
134
164
|
useParentContext<T = unknown>(name: ContextNameType): SignalReader<T>;
|
|
135
165
|
provideContext<T = unknown>(name: ContextNameType): Signal<T>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Entity.d.ts","sourceRoot":"","sources":["../../../src/in-the-dark/Entity.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Entity.d.ts","sourceRoot":"","sources":["../../../src/in-the-dark/Entity.ts"],"names":[],"mappings":"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"}
|
|
@@ -402,6 +402,44 @@ class Entity {
|
|
|
402
402
|
hasContext(name) {
|
|
403
403
|
return this.#context.has(name);
|
|
404
404
|
}
|
|
405
|
+
/** The names of the Entity Contexts this entity holds, used or provided. Reads only, creates none. */
|
|
406
|
+
contextNames() {
|
|
407
|
+
return Array.from(this.#context.keys());
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* The three values behind one Entity Context of this entity: what its own providers wrote, what it
|
|
411
|
+
* inherits from the parent (or from the global chain at a root), and what `useContext(name)` reads.
|
|
412
|
+
* `hasProviders` says whether a provider feed is attached -- a value written straight into the
|
|
413
|
+
* signal from `provideContext()` counts as provided but not as a provider.
|
|
414
|
+
*
|
|
415
|
+
* `undefined` when the entity holds no context of that name; asking does not create one. The
|
|
416
|
+
* reads are plain `.value` reads and track nothing, so a call from inside an effect does not
|
|
417
|
+
* subscribe that effect to the context.
|
|
418
|
+
*/
|
|
419
|
+
describeContext(name) {
|
|
420
|
+
const ctx = this.#context.get(name);
|
|
421
|
+
if (ctx === void 0) return void 0;
|
|
422
|
+
return {
|
|
423
|
+
provided: ctx.provide.value,
|
|
424
|
+
inherited: ctx.inherited.value,
|
|
425
|
+
effective: ctx.context.value,
|
|
426
|
+
hasProviders: ctx.providerFeeds.size > 0
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
/** The names of the global Entity Contexts this entity contributes to. Reads only, creates none. */
|
|
430
|
+
globalContextNames() {
|
|
431
|
+
return Array.from(this.#rootContexts.keys());
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* What this entity contributes to the kernel-wide chain of one global Entity Context: the value
|
|
435
|
+
* and the very signal that stands in the chain, so a caller holding the chain can find this entity
|
|
436
|
+
* in it by identity. `undefined` when the entity contributes nothing under that name.
|
|
437
|
+
*/
|
|
438
|
+
describeGlobalContext(name) {
|
|
439
|
+
const rootCtx = this.#rootContexts.get(name);
|
|
440
|
+
if (rootCtx === void 0) return void 0;
|
|
441
|
+
return { value: rootCtx.signal.value, signal: rootCtx.signal, hasProviders: rootCtx.providerFeeds.size > 0 };
|
|
442
|
+
}
|
|
405
443
|
useContext(name) {
|
|
406
444
|
return this.#findOrCreateContext(name).context.get;
|
|
407
445
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/in-the-dark/Entity.ts"],
|
|
4
|
-
"sourcesContent": ["import {emitStrict, off, on, once, Priority} from '@spearwolf/eventize';\nimport {\n batch,\n createSignal,\n link,\n Signal,\n SignalAutoMap,\n type SignalLink,\n type SignalReader,\n type SignalWriter,\n type SignalWriterParams,\n value,\n} from '@spearwolf/signalize';\nimport type {ComponentPropertiesType, IComponentEvent} from '../types.js';\nimport {MicrotaskCollector} from '../utils/MicrotaskCollector.js';\nimport {runGuarded} from '../utils/runGuarded.js';\nimport {onDestroy, onViewEvent} from './events.js';\nimport {Kernel} from './Kernel.js';\nimport {SignalsPath} from './SignalsPath.js';\n\ntype ContextNameType = string | symbol;\n\ninterface IContextValue {\n name: ContextNameType;\n inherited: Signal<unknown>;\n provide: Signal<unknown>;\n context: Signal<unknown>;\n valuePath: SignalsPath;\n\n /**\n * The links that feed `provide`, one per provider of this name on this entity. They all write\n * into that one signal, so the value standing there is the one written last -- and the set is\n * what makes it possible to ask a provider that is still here for its value once another one\n * lets go. See {@link Entity.attachContextProvider}.\n */\n providerFeeds: Set<SignalLink<any>>;\n\n unsubscribePathValue: () => void;\n unsubscribeFromParent?: (() => void) | undefined;\n}\n\ninterface IRootContextValue {\n signal: Signal<any>;\n\n /** The links that feed `signal`, exactly as {@link IContextValue.providerFeeds} feeds `provide`. */\n providerFeeds: Set<SignalLink<any>>;\n\n /** Takes the entity's signal back out of the kernel-wide chain of this name. */\n cleanup: () => void;\n}\n\n/** One context value an entity has waiting for its readers in the current round. */\ninterface IDeferredContextValue {\n value: unknown;\n name: ContextNameType;\n uuid: string;\n}\n\n/**\n * The context values waiting to reach their readers, one collector per kernel.\n *\n * Per kernel rather than per module for two reasons that are the same one: a write below can fail,\n * and what it is reported to is a logger, of which there is one per kernel; and an application\n * running two shadow environments in one realm would otherwise hand the values of one to a round\n * the other started. The kernel is the key, so a collector reaches no further than the kernel it\n * belongs to and needs no teardown of its own -- every round empties it, and the last one is\n * emptied by the kernel going out of reach.\n */\nconst contextValueCollectors = new WeakMap<Kernel, MicrotaskCollector<Signal<unknown>, IDeferredContextValue>>();\n\nconst collectorOf = (kernel: Kernel): MicrotaskCollector<Signal<unknown>, IDeferredContextValue> => {\n let collector = contextValueCollectors.get(kernel);\n if (collector == null) {\n collector = new MicrotaskCollector<Signal<unknown>, IDeferredContextValue>((contextValues) => {\n for (const [contextSignal, entry] of contextValues) {\n // one hand-over is one context value: `set()` runs the effects that read it synchronously\n // and throws what one of them threw\n runGuarded(\n kernel.logger,\n () => contextSignal.set(entry.value),\n `an effect of a context value failed (${String(entry.name)}):`,\n entry.uuid,\n );\n }\n });\n contextValueCollectors.set(kernel, collector);\n }\n return collector;\n};\n\n/**\n * Collects the context values written in one task and hands them to their readers a microtask\n * later, one at a time. A second value for the same signal replaces the one waiting, so a name\n * written twice in a task reaches its readers once, with the value that stood at the end of it.\n */\nconst deferContextValueUpdate = (kernel: Kernel, signal: Signal<unknown>, val: unknown, name: ContextNameType, uuid: string) => {\n collectorOf(kernel).add(signal, {value: val, name, uuid});\n};\n\n/**\n * An entity has a parent and children, replicating the hierarchy of view-components.\n *\n * A signal is created for each view-component property.\n *\n * Shadow-objects can use the signal properties via the entity.\n */\nexport class Entity {\n #kernel: Kernel;\n #uuid: string;\n\n #props = new SignalAutoMap();\n #context: Map<ContextNameType, IContextValue> = new Map();\n\n #rootContexts: Map<ContextNameType, IRootContextValue> = new Map();\n\n // There is one place the parent is kept: `parentUuid` answers from `#parent.uuid`, so a half-set\n // link -- a uuid with no matching entity, or an entity with no uuid to show for it -- has no field\n // left to hold it in.\n #parent?: Entity | undefined;\n\n #childrenUuids: Set<string> = new Set();\n #children: Entity[] = [];\n\n #order = 0;\n\n #isReleased = false;\n\n get kernel(): Kernel {\n return this.#kernel;\n }\n\n get uuid(): string {\n return this.#uuid;\n }\n\n get order(): number {\n return this.#order;\n }\n\n set order(value: number) {\n if (this.#order !== value) {\n this.#order = value;\n if (this.#parent) {\n this.#parent.resortChildren();\n }\n // The place among the siblings is part of the traversal order the kernel caches.\n this.#kernel.noteEntityTreeChange(this.#uuid);\n }\n }\n\n get parentUuid(): string | undefined {\n return this.#parent?.uuid;\n }\n\n set parentUuid(parentUuid: string | undefined) {\n if (this.#parent?.uuid !== parentUuid) {\n // Resolve the new parent FIRST so an unknown-uuid throw doesn't orphan us mid-mutation.\n const nextParent = parentUuid ? this.#kernel.getEntity(parentUuid) : undefined;\n\n if (nextParent != null) {\n this.assertAttachableTo(nextParent);\n }\n\n // A parent that follows right away binds the contexts itself, so the detachment skips it. The\n // entity keeps reading the parent it leaves until the one it joins takes over.\n this.#detachFromParent(nextParent == null);\n\n this.#parent = nextParent;\n\n if (this.#parent) {\n this.#parent.addChild(this);\n }\n\n this.#updateAutoDestructionSubscription();\n\n // The link is written; the kernel writes down where the entity stands now. This is the route\n // a shadow-object takes when it moves an entity without going through `Kernel.setParent()`,\n // and the report is the only thing the two share -- the `onParentChanged` notification stays\n // with `setParent()`.\n this.#kernel.noteEntityTreeChange(this.#uuid);\n }\n }\n\n get parent(): Entity | undefined {\n return this.#parent;\n }\n\n set parent(parent: Entity | undefined) {\n this.parentUuid = parent?.uuid;\n }\n\n // Reads the same field `parent` and `parentUuid` do, so `Kernel.noteEntityTreeChange()` -- which\n // reads `hasParent` to decide whether the uuid belongs in the root set -- sees what they see.\n get hasParent(): boolean {\n return !!this.#parent;\n }\n\n get children(): readonly Entity[] {\n return this.#children;\n }\n\n constructor(kernel: Kernel, uuid: string) {\n this.#kernel = kernel;\n this.#uuid = uuid;\n }\n\n traverse(callback: (entity: Entity) => void) {\n this.#traverse(callback, new Set());\n }\n\n // The visited set guards the one traversal an outside shadow object drives, over a tree it did not\n // build. `addChild()` writes a children list without touching the parent link, so no ancestor check\n // can cover it.\n #traverse(callback: (entity: Entity) => void, visited: Set<Entity>) {\n if (visited.has(this)) return;\n visited.add(this);\n\n callback(this);\n\n for (const child of this.#children) {\n child.#traverse(callback, visited);\n }\n }\n\n /**\n * Releases everything the entity holds: its properties, its subscriptions, its contexts and its place\n * in the entity tree.\n *\n * It runs once, whichever way it is reached. The kernel reaches it directly, right behind the\n * destruction notification it sends on the entity, so that every listener on that notification has\n * had its turn first -- down to `Priority.Min`, which is nobody's but the caller's. The entity is\n * not a listener on its own notification: registering it in the constructor would put it ahead of\n * anything registered at the same priority, because eventize breaks a tie by order of registration,\n * and the bulk `off(this)` below would then take the listeners still waiting in that delivery with\n * it. The flag makes a second call cost nothing and keeps every step below written for a\n * single run: `kernel.getEntity()` hands the entity to anyone, and this method is as reachable as\n * the rest of it.\n *\n * The flag is raised before the first step rather than after the last, because that is what a release\n * running twice would cost: the steps below are written for one pass, not for a repeat.\n *\n * Every step below runs behind a guard of its own, the way `ShadowObjectCreationScope.tearDown()`\n * gives each of its steps one: a step that throws is reported through the kernel's logger, named by\n * the step and by the uuid of this entity, and costs only itself -- the steps behind it still run.\n * The method therefore never throws to its own caller. The plain resets at the end -- clearing a\n * collection, overwriting a field -- cannot throw and run unguarded, exactly as `tearDown()` empties\n * its own sets at the end.\n */\n [onDestroy]() {\n if (this.#isReleased) return;\n this.#isReleased = true;\n\n // `SignalAutoMap.clear()` destroys every property signal and only then re-raises whatever a\n // dependent effect's cleanup threw along the way, so it belongs behind a guard of its own like\n // every other step here -- it is not the plain reset it looks like.\n this.#runGuarded('properties', () => this.#props.clear());\n this.#runGuarded('listeners', () => off(this));\n this.#runGuarded('auto-destruction subscription', () => this.#autoDestructionSubscription?.());\n\n for (const rootCtx of this.#rootContexts.values()) {\n this.#runGuarded('global context cleanup', () => rootCtx.cleanup());\n this.#runGuarded('global context signal', () => rootCtx.signal.destroy());\n }\n\n for (const ctx of this.#context.values()) {\n this.#runGuarded('context value reset', () => ctx.context.set(undefined));\n this.#runGuarded('context value subscription', () => ctx.unsubscribePathValue());\n this.#runGuarded('context parent subscription', () => ctx.unsubscribeFromParent?.());\n this.#runGuarded('context value path', () => ctx.valuePath.dispose());\n this.#runGuarded('inherited context signal', () => ctx.inherited.destroy());\n this.#runGuarded('provided context signal', () => ctx.provide.destroy());\n this.#runGuarded('context signal', () => ctx.context.destroy());\n }\n\n this.#rootContexts.clear();\n this.#context.clear();\n\n this.#parent = undefined;\n\n this.#childrenUuids.clear();\n this.#children.length = 0;\n }\n\n /**\n * Isolates one release step from the ones around it: a step that throws is reported through the\n * kernel's logger and does not stop `[onDestroy]()` from reaching the steps that follow. The\n * report goes out through the shared `runGuarded()`; what this wrapper adds is the label of the\n * step and the uuid of the entity it belongs to.\n */\n #runGuarded(step: string, run: () => void): void {\n runGuarded(this.#kernel.logger, run, `entity teardown step failed (${step}):`, this.#uuid);\n }\n\n /**\n * Refuses a parent that would close the entity tree into a ring: the entity itself, or an entity that\n * already sits below it. The walk follows the parent chain upwards, which is a chain exactly because\n * this guard keeps it one.\n *\n * `Kernel.setParent()` calls it before it detaches, and the `parentUuid` setter before it resolves the\n * link, so a refused attachment leaves the entity where it was instead of orphaned halfway through.\n * `ViewComponent.addChild()` guards the same thing on the view side.\n */\n assertAttachableTo(nextParent: Entity) {\n for (let e: Entity | undefined = nextParent; e != null; e = e.parent) {\n if (e === this) {\n throw new Error(\n `entity \"${nextParent.uuid}\" cannot become the parent of \"${this.uuid}\": it is the entity itself or one of its descendants`,\n );\n }\n }\n }\n\n /**\n * Puts `child` into the children list, at its place among the siblings.\n *\n * Nothing here notifies. Neither this method nor {@link Entity.removeChild} nor a detachment\n * sends anything to a listener on the entity -- the one notification over a moved entity is\n * `onParentChanged`, and `Kernel.setParent()` is the call that sends it.\n */\n addChild(child: Entity) {\n if (this.#childrenUuids.has(child.uuid)) {\n throw new Error(`child with uuid: ${child.uuid} already exists! parentUuid: ${this.uuid}`);\n }\n\n this.#childrenUuids.add(child.uuid);\n this.#insertChildInOrder(child);\n\n // the child may have created its contexts while it was still unattached: they hang on the root\n // of the entity context tree until something binds them to the parent they now have\n for (const [, ctx] of child.#context) {\n child.#subscribeToParent(ctx);\n }\n }\n\n /**\n * Puts a child at its place among the siblings, so building a subtree costs one insertion per\n * child. The scan runs from the end because children usually arrive with an equal or rising\n * `order`, which makes the common case a plain append. A child lands behind every sibling that\n * shares its `order` -- the same place a stable sort would give it.\n *\n * The result only matches a full sort while `#children` is already sorted when the insertion\n * starts, so name what keeps it that way: the insertion here preserves the order, `removeChild()`\n * cuts an element out with `splice`, the destroy handler empties the list, and the `order` setter\n * re-sorts through the parent. That last one is the condition worth stating, because it needs the\n * child to know its parent -- the parent link has to be established. Every way an entity is\n * attached inside this class goes through the `parentUuid` setter, which sets the parent before it\n * calls `addChild()`. A caller that reaches for `addChild()` on its own leaves the child without a\n * parent link, and a later `order` on such a child never reaches this list.\n */\n #insertChildInOrder(child: Entity) {\n let i = this.#children.length;\n while (i > 0 && child.order < this.#children[i - 1]!.order) i--;\n this.#children.splice(i, 0, child);\n }\n\n resortChildren() {\n this.#children.sort((a, b) => a.order - b.order);\n }\n\n removeChild(child: Entity) {\n // The identity decides here, not the uuid: `indexOf` answers -1 for an entity this list\n // does not hold, and a `splice(-1, 1)` on that answer would cut the last child out\n // instead of none. The ordered uuid lists of `ComponentContext` carry the same guard where\n // they cut a uuid out.\n const idx = this.#children.indexOf(child);\n if (idx !== -1) {\n this.#childrenUuids.delete(child.uuid);\n this.#children.splice(idx, 1);\n }\n }\n\n /**\n * @param rebindContexts bind every context back to the root of the entity context tree. An entity\n * that carries a context out of a subtree keeps following the value it can still see, rather\n * than freezing on the last one the former parent held. Only a caller that attaches the entity\n * to the next parent in the same breath passes `false` -- that parent binds the contexts itself,\n * and the detour over the root would be visible to `useParentContext()`, which hands out the\n * inherited value without the microtask collector `useContext()` has in front of it.\n */\n removeFromParent(rebindContexts = true) {\n this.#detachFromParent(rebindContexts);\n }\n\n #detachFromParent(rebindContexts: boolean) {\n // The field `parent` and `parentUuid` both answer from: clearing it here clears what either\n // getter would report, with nothing left over for a second check to find.\n if (this.#parent) {\n this.#parent.removeChild(this);\n\n this.#parent = undefined;\n\n if (rebindContexts) {\n for (const [, ctx] of this.#context) {\n this.#subscribeToParent(ctx);\n }\n }\n\n this.#unsubscribeAutoDestruction();\n\n // Detached is a place too: an entity with no parent is a root, and the root set is where\n // every traversal starts.\n this.#kernel.noteEntityTreeChange(this.#uuid);\n }\n }\n\n #autoDestructionEnabled = false;\n #autoDestructionSubscription?: (() => void) | undefined;\n\n get autoDestructionOnParentRemoval(): boolean {\n return this.#autoDestructionEnabled;\n }\n\n set autoDestructionOnParentRemoval(autoDestruct: boolean) {\n if (this.#autoDestructionEnabled === autoDestruct) return;\n this.#autoDestructionEnabled = autoDestruct;\n this.#updateAutoDestructionSubscription();\n }\n\n #unsubscribeAutoDestruction() {\n if (this.#autoDestructionSubscription) {\n this.#autoDestructionSubscription();\n this.#autoDestructionSubscription = undefined;\n }\n }\n\n #updateAutoDestructionSubscription() {\n this.#unsubscribeAutoDestruction();\n if (this.#autoDestructionEnabled && this.#parent) {\n this.#autoDestructionSubscription = once(this.#parent, onDestroy, Priority.Max, () => {\n this.#autoDestructionSubscription = undefined;\n this.#kernel.destroyEntity(this.#uuid);\n });\n }\n }\n\n /**\n * Binds every context of this entity to its current position in the entity tree -- to the parent\n * if there is one, to the root otherwise. `addChild()` and `removeFromParent()` each do this for\n * the entity they move, so a caller needs this only when it changed the position by other means\n * or wants the binding re-established without knowing which of the two ran.\n *\n * Moving an entity through the kernel is not such a case: both directions bring their own binding,\n * and a third one would reach every `useParentContext()` reader as another change.\n */\n reSubscribeToParentContexts() {\n for (const [, ctx] of this.#context) {\n this.#subscribeToParent(ctx);\n }\n }\n\n dispatchMessageToView(type: string, data?: unknown, transferables?: Transferable[], traverseChildren = false) {\n this.#kernel.dispatchMessageToView({uuid: this.#uuid, type, data, transferables, traverseChildren});\n }\n\n /**\n * Hands the events the view sent to whoever listens on this entity, one delivery per event.\n *\n * Each delivery is guarded, and the reason is where this call sits: the kernel makes it from\n * inside a change trail, on a path that builds. Unguarded, a single shadow-object that cannot cope\n * with a single view event would leave through `Kernel.run()` and refuse the whole trail -- the\n * same argument that puts a guard around the `onParentChanged` notification, which is a delivery\n * on a building path as well. The guard is per event, so one that fails costs neither the events\n * behind it nor the caller anything; `emitStrict()` inside it makes the same promise one level\n * down, to the listeners of one event.\n */\n dispatchViewEvents(events: IComponentEvent[]) {\n for (const {type, data} of events) {\n runGuarded(\n this.#kernel.logger,\n // the concrete class is needed here: eventize cannot reduce its emitter conditional\n // (`NonTypedEmitter<this>`) over the polymorphic `this` type, and no overload then matches\n () => emitStrict(this as Entity, onViewEvent, type, data),\n 'entity view event delivery failed:',\n type,\n this.#uuid,\n );\n }\n }\n\n dispatchViewEvent(type: string, data: unknown) {\n this.dispatchViewEvents([{type, data}]);\n }\n\n #getPropSignal<T = unknown>(key: string): Signal<T> {\n return this.#props.get<T>(key);\n }\n\n getPropertyReader<T = unknown>(key: string): SignalReader<T> {\n return this.#getPropSignal<T>(key).get;\n }\n\n /**\n * A write head for one property. Every write through it drops the cache behind\n * `truthyProps()`: that cache answers `Kernel.#updateShadowObjects()`, which picks the shadow\n * objects of this entity along the property routes of the registry, and a write the cache does\n * not see routes the entity to a state it no longer has.\n *\n * What comes back is a function of the entity, not the `set` of the signal behind the property.\n * The signalize helpers that take a signal-like -- `isSignal()`, `destroySignal()`, `touch()` --\n * do not recognise it; `getPropertyReader()` hands out the signal's own reader for that.\n *\n * A fresh closure is handed out on every call rather than one cached per key: `SignalAutoMap`\n * hands out \"a fresh, live\" signal for a key whose signal was destroyed from the outside, so a\n * writer cached against the signal captured on an earlier call could end up closing over a corpse.\n * The call sites this feeds -- `setProperty()` from a change-trail application, at most once per\n * property that actually changed -- do not turn this into a hot path.\n */\n getPropertyWriter<T = unknown>(key: string): SignalWriter<T> {\n const signal = this.#getPropSignal<T>(key);\n return (value: unknown, params?: SignalWriterParams<T>) => {\n this.clearTruthyPropsCache();\n signal.set(value as T, params);\n };\n }\n\n setProperties(properties: ComponentPropertiesType) {\n batch(() => {\n // an entry that names only the key sets the property to `undefined` \u2014 the key is there, the value is not\n for (const [key, val] of properties) {\n this.setProperty(key, val);\n }\n });\n }\n\n setProperty(key: string, value: unknown) {\n this.getPropertyWriter(key)(value);\n }\n\n getProperty<T = unknown>(key: string): T {\n return value(this.getPropertyReader<T>(key));\n }\n\n propKeys(): string[] {\n return Array.from(this.#props.keys()) as string[];\n }\n\n propEntries(): [string, unknown][] {\n return Array.from(this.#props.entries()).map(([key, sig]) => [key, sig.value]) as [string, unknown][];\n }\n\n #truthyPropsCache: Set<string> | undefined;\n\n clearTruthyPropsCache() {\n this.#truthyPropsCache = undefined;\n }\n\n truthyProps(): Set<string> | undefined {\n if (this.#truthyPropsCache) {\n return this.#truthyPropsCache.size ? this.#truthyPropsCache : undefined;\n }\n const truthyProps = new Set<string>();\n for (const [key, sig] of this.#props.entries()) {\n if (typeof key === 'string') {\n const val = sig.value;\n if (val != null && val !== false && val !== '') {\n truthyProps.add(key);\n }\n }\n }\n this.#truthyPropsCache = truthyProps;\n return truthyProps.size ? truthyProps : undefined;\n }\n\n hasContext(name: ContextNameType): boolean {\n return this.#context.has(name);\n }\n\n useContext<T = unknown>(name: ContextNameType): SignalReader<T> {\n return this.#findOrCreateContext(name).context.get as SignalReader<T>;\n }\n\n useParentContext<T = unknown>(name: ContextNameType): SignalReader<T> {\n return this.#findOrCreateContext(name).inherited.get as SignalReader<T>;\n }\n\n provideContext<T = unknown>(name: ContextNameType): Signal<T> {\n return this.#findOrCreateContext(name).provide as Signal<T>;\n }\n\n provideGlobalContext<T = unknown>(name: ContextNameType): Signal<T> {\n // The signal behind it is created without an initial value \u2014 a context signal does start out\n // empty and holds no `T` until a provider writes one. The cast keeps the same contract\n // `provideContext()` hands out; callers see the `undefined` through `Maybe<T>` in the\n // shadow-object API.\n return this.#findOrCreateGlobalContext(name).signal as Signal<T>;\n }\n\n /**\n * Attaches a provider signal to the context of `name` on this entity and answers with the release\n * that detaches it again.\n *\n * Every provider of one name writes into the single signal that `provideContext()` hands out, so\n * what a consumer reads is what was written last. The release therefore does two things: it cuts\n * this feed, and it then lets a provider that is still attached write its value once more. Without\n * that second step the context would keep whatever the departure left standing -- the `undefined`\n * of a clearing provider, or the last value of one that opted out of it -- even though this entity\n * still has a provider of the name that says otherwise.\n *\n * A value written straight into the signal from `provideContext()` is not a feed and is therefore\n * overwritten by the next release. Feeding a value in through this method is what makes it survive\n * one.\n */\n attachContextProvider(name: ContextNameType, provider: Signal<any>): () => void {\n const ctx = this.#findOrCreateContext(name);\n return Entity.#attachProviderFeed(provider, ctx.provide, ctx.providerFeeds);\n }\n\n /**\n * The counterpart of {@link Entity.attachContextProvider} for the global context of `name`.\n *\n * Within one entity the situation is the same one: every provider feeds the single signal this\n * entity contributes to the kernel-wide chain of that name, and a release hands the name back to a\n * provider that stays. Across entities the chain decides on its own -- it resolves to the first\n * entry that holds something, so an entity whose signal falls empty lets the next one through.\n */\n attachGlobalContextProvider(name: ContextNameType, provider: Signal<any>): () => void {\n const rootCtx = this.#findOrCreateGlobalContext(name);\n return Entity.#attachProviderFeed(provider, rootCtx.signal, rootCtx.providerFeeds);\n }\n\n static #attachProviderFeed(provider: Signal<any>, target: Signal<any>, feeds: Set<SignalLink<any>>): () => void {\n const feed = link(provider, target);\n feeds.add(feed);\n\n return () => {\n // A release called a second time finds nothing of its own left and leaves the context to\n // whoever holds it by then.\n if (!feeds.delete(feed)) return;\n feed.destroy();\n Entity.#handOverToRemainingProvider(feeds);\n };\n }\n\n /**\n * Lets the provider that stays write its value into the context signal again.\n *\n * The set iterates in the order the providers were attached and the loop keeps the last hit, so the\n * winner is the one attached last that still holds a value. Attachment order is the order in which the\n * providers took the name: attaching feeds the value straight through, so a later attachment writes\n * over an earlier one, and the hand-over falls back on that order instead of inventing one of its own.\n * It is not the order of the writes -- a provider that writes to its signal after attaching carries\n * the name until the next departure, and the hand-over does not restore that write, because what this\n * entity keeps on file is its providers and not the sequence in which they wrote. Providers holding\n * nothing are passed over -- by the same `!= null` rule with which `SignalsPath` resolves a context\n * chain, and for the same reason: a provider without a value has nothing to say about the name, and\n * electing it would clear a name that is still being provided.\n *\n * A feed whose link is destroyed is passed over as well. A shadow-object owns the signal it was\n * handed and may end it early, which destroys the link without the release ever having run: such a\n * feed still reports a value through its source while its writes go nowhere, so electing it would\n * leave the write of the departure standing, silently and over a provider that is alive.\n *\n * `touch()` is what makes the winner write, because `SignalLink.write()` is protected: touching is\n * the only public way to push the current value of a source through its link again, and the source\n * of a provider that merely stays has no reason to change.\n *\n * Where no remaining feed qualifies, nothing is written: then what the departure left stands,\n * which is the `undefined` of a clearing provider or the last value of one that opted out.\n */\n static #handOverToRemainingProvider(feeds: Set<SignalLink<any>>): void {\n let winner: SignalLink<any> | undefined;\n for (const feed of feeds) {\n if (!feed.isDestroyed && feed.source.value != null) winner = feed;\n }\n winner?.touch();\n }\n\n #findOrCreateGlobalContext(name: ContextNameType): IRootContextValue {\n if (this.#rootContexts.has(name)) {\n return this.#rootContexts.get(name)!;\n }\n const rootCtx = this.#kernel.findOrCreateRootContext(name);\n const signal = createSignal() as Signal<any>;\n const cleanup = rootCtx.add(signal);\n const ctx: IRootContextValue = {cleanup, signal, providerFeeds: new Set()};\n this.#rootContexts.set(name, ctx);\n return ctx;\n }\n\n #findOrCreateContext(name: ContextNameType): IContextValue {\n if (this.#context.has(name)) {\n return this.#context.get(name)!;\n }\n\n const inherited = createSignal();\n const provide = createSignal();\n const context = createSignal();\n\n const valuePath = new SignalsPath([provide, inherited]);\n\n const unsubscribePathValue = on(valuePath, SignalsPath.Value, (val) => {\n deferContextValueUpdate(this.#kernel, context, val, name, this.#uuid);\n });\n\n const ctx: IContextValue = {name, inherited, provide, context, valuePath, providerFeeds: new Set(), unsubscribePathValue};\n this.#context.set(name, ctx);\n\n this.#subscribeToParent(ctx);\n\n return ctx;\n }\n\n #subscribeToParent(ctx: IContextValue) {\n ctx.unsubscribeFromParent?.();\n ctx.unsubscribeFromParent = undefined;\n if (this.parent) {\n const parentCtx = this.parent.#findOrCreateContext(ctx.name);\n const linkToParent = link(parentCtx.context, ctx.inherited);\n ctx.unsubscribeFromParent = linkToParent.destroy.bind(linkToParent);\n } else {\n const rootCtx = this.#kernel.findOrCreateRootContext(ctx.name);\n const linkToRoot = link(rootCtx.value$, ctx.inherited);\n ctx.unsubscribeFromParent = linkToRoot.destroy.bind(linkToRoot);\n }\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import {emitStrict, off, on, once, Priority} from '@spearwolf/eventize';\nimport {\n batch,\n createSignal,\n link,\n Signal,\n SignalAutoMap,\n type SignalLink,\n type SignalReader,\n type SignalWriter,\n type SignalWriterParams,\n value,\n} from '@spearwolf/signalize';\nimport type {ComponentPropertiesType, IComponentEvent} from '../types.js';\nimport {MicrotaskCollector} from '../utils/MicrotaskCollector.js';\nimport {runGuarded} from '../utils/runGuarded.js';\nimport {onDestroy, onViewEvent} from './events.js';\nimport {Kernel} from './Kernel.js';\nimport {SignalsPath} from './SignalsPath.js';\n\ntype ContextNameType = string | symbol;\n\ninterface IContextValue {\n name: ContextNameType;\n inherited: Signal<unknown>;\n provide: Signal<unknown>;\n context: Signal<unknown>;\n valuePath: SignalsPath;\n\n /**\n * The links that feed `provide`, one per provider of this name on this entity. They all write\n * into that one signal, so the value standing there is the one written last -- and the set is\n * what makes it possible to ask a provider that is still here for its value once another one\n * lets go. See {@link Entity.attachContextProvider}.\n */\n providerFeeds: Set<SignalLink<any>>;\n\n unsubscribePathValue: () => void;\n unsubscribeFromParent?: (() => void) | undefined;\n}\n\ninterface IRootContextValue {\n signal: Signal<any>;\n\n /** The links that feed `signal`, exactly as {@link IContextValue.providerFeeds} feeds `provide`. */\n providerFeeds: Set<SignalLink<any>>;\n\n /** Takes the entity's signal back out of the kernel-wide chain of this name. */\n cleanup: () => void;\n}\n\n/** One context value an entity has waiting for its readers in the current round. */\ninterface IDeferredContextValue {\n value: unknown;\n name: ContextNameType;\n uuid: string;\n}\n\n/**\n * The context values waiting to reach their readers, one collector per kernel.\n *\n * Per kernel rather than per module for two reasons that are the same one: a write below can fail,\n * and what it is reported to is a logger, of which there is one per kernel; and an application\n * running two shadow environments in one realm would otherwise hand the values of one to a round\n * the other started. The kernel is the key, so a collector reaches no further than the kernel it\n * belongs to and needs no teardown of its own -- every round empties it, and the last one is\n * emptied by the kernel going out of reach.\n */\nconst contextValueCollectors = new WeakMap<Kernel, MicrotaskCollector<Signal<unknown>, IDeferredContextValue>>();\n\nconst collectorOf = (kernel: Kernel): MicrotaskCollector<Signal<unknown>, IDeferredContextValue> => {\n let collector = contextValueCollectors.get(kernel);\n if (collector == null) {\n collector = new MicrotaskCollector<Signal<unknown>, IDeferredContextValue>((contextValues) => {\n for (const [contextSignal, entry] of contextValues) {\n // one hand-over is one context value: `set()` runs the effects that read it synchronously\n // and throws what one of them threw\n runGuarded(\n kernel.logger,\n () => contextSignal.set(entry.value),\n `an effect of a context value failed (${String(entry.name)}):`,\n entry.uuid,\n );\n }\n });\n contextValueCollectors.set(kernel, collector);\n }\n return collector;\n};\n\n/**\n * Collects the context values written in one task and hands them to their readers a microtask\n * later, one at a time. A second value for the same signal replaces the one waiting, so a name\n * written twice in a task reaches its readers once, with the value that stood at the end of it.\n */\nconst deferContextValueUpdate = (kernel: Kernel, signal: Signal<unknown>, val: unknown, name: ContextNameType, uuid: string) => {\n collectorOf(kernel).add(signal, {value: val, name, uuid});\n};\n\n/**\n * An entity has a parent and children, replicating the hierarchy of view-components.\n *\n * A signal is created for each view-component property.\n *\n * Shadow-objects can use the signal properties via the entity.\n */\nexport class Entity {\n #kernel: Kernel;\n #uuid: string;\n\n #props = new SignalAutoMap();\n #context: Map<ContextNameType, IContextValue> = new Map();\n\n #rootContexts: Map<ContextNameType, IRootContextValue> = new Map();\n\n // There is one place the parent is kept: `parentUuid` answers from `#parent.uuid`, so a half-set\n // link -- a uuid with no matching entity, or an entity with no uuid to show for it -- has no field\n // left to hold it in.\n #parent?: Entity | undefined;\n\n #childrenUuids: Set<string> = new Set();\n #children: Entity[] = [];\n\n #order = 0;\n\n #isReleased = false;\n\n get kernel(): Kernel {\n return this.#kernel;\n }\n\n get uuid(): string {\n return this.#uuid;\n }\n\n get order(): number {\n return this.#order;\n }\n\n set order(value: number) {\n if (this.#order !== value) {\n this.#order = value;\n if (this.#parent) {\n this.#parent.resortChildren();\n }\n // The place among the siblings is part of the traversal order the kernel caches.\n this.#kernel.noteEntityTreeChange(this.#uuid);\n }\n }\n\n get parentUuid(): string | undefined {\n return this.#parent?.uuid;\n }\n\n set parentUuid(parentUuid: string | undefined) {\n if (this.#parent?.uuid !== parentUuid) {\n // Resolve the new parent FIRST so an unknown-uuid throw doesn't orphan us mid-mutation.\n const nextParent = parentUuid ? this.#kernel.getEntity(parentUuid) : undefined;\n\n if (nextParent != null) {\n this.assertAttachableTo(nextParent);\n }\n\n // A parent that follows right away binds the contexts itself, so the detachment skips it. The\n // entity keeps reading the parent it leaves until the one it joins takes over.\n this.#detachFromParent(nextParent == null);\n\n this.#parent = nextParent;\n\n if (this.#parent) {\n this.#parent.addChild(this);\n }\n\n this.#updateAutoDestructionSubscription();\n\n // The link is written; the kernel writes down where the entity stands now. This is the route\n // a shadow-object takes when it moves an entity without going through `Kernel.setParent()`,\n // and the report is the only thing the two share -- the `onParentChanged` notification stays\n // with `setParent()`.\n this.#kernel.noteEntityTreeChange(this.#uuid);\n }\n }\n\n get parent(): Entity | undefined {\n return this.#parent;\n }\n\n set parent(parent: Entity | undefined) {\n this.parentUuid = parent?.uuid;\n }\n\n // Reads the same field `parent` and `parentUuid` do, so `Kernel.noteEntityTreeChange()` -- which\n // reads `hasParent` to decide whether the uuid belongs in the root set -- sees what they see.\n get hasParent(): boolean {\n return !!this.#parent;\n }\n\n get children(): readonly Entity[] {\n return this.#children;\n }\n\n constructor(kernel: Kernel, uuid: string) {\n this.#kernel = kernel;\n this.#uuid = uuid;\n }\n\n traverse(callback: (entity: Entity) => void) {\n this.#traverse(callback, new Set());\n }\n\n // The visited set guards the one traversal an outside shadow object drives, over a tree it did not\n // build. `addChild()` writes a children list without touching the parent link, so no ancestor check\n // can cover it.\n #traverse(callback: (entity: Entity) => void, visited: Set<Entity>) {\n if (visited.has(this)) return;\n visited.add(this);\n\n callback(this);\n\n for (const child of this.#children) {\n child.#traverse(callback, visited);\n }\n }\n\n /**\n * Releases everything the entity holds: its properties, its subscriptions, its contexts and its place\n * in the entity tree.\n *\n * It runs once, whichever way it is reached. The kernel reaches it directly, right behind the\n * destruction notification it sends on the entity, so that every listener on that notification has\n * had its turn first -- down to `Priority.Min`, which is nobody's but the caller's. The entity is\n * not a listener on its own notification: registering it in the constructor would put it ahead of\n * anything registered at the same priority, because eventize breaks a tie by order of registration,\n * and the bulk `off(this)` below would then take the listeners still waiting in that delivery with\n * it. The flag makes a second call cost nothing and keeps every step below written for a\n * single run: `kernel.getEntity()` hands the entity to anyone, and this method is as reachable as\n * the rest of it.\n *\n * The flag is raised before the first step rather than after the last, because that is what a release\n * running twice would cost: the steps below are written for one pass, not for a repeat.\n *\n * Every step below runs behind a guard of its own, the way `ShadowObjectCreationScope.tearDown()`\n * gives each of its steps one: a step that throws is reported through the kernel's logger, named by\n * the step and by the uuid of this entity, and costs only itself -- the steps behind it still run.\n * The method therefore never throws to its own caller. The plain resets at the end -- clearing a\n * collection, overwriting a field -- cannot throw and run unguarded, exactly as `tearDown()` empties\n * its own sets at the end.\n */\n [onDestroy]() {\n if (this.#isReleased) return;\n this.#isReleased = true;\n\n // `SignalAutoMap.clear()` destroys every property signal and only then re-raises whatever a\n // dependent effect's cleanup threw along the way, so it belongs behind a guard of its own like\n // every other step here -- it is not the plain reset it looks like.\n this.#runGuarded('properties', () => this.#props.clear());\n this.#runGuarded('listeners', () => off(this));\n this.#runGuarded('auto-destruction subscription', () => this.#autoDestructionSubscription?.());\n\n for (const rootCtx of this.#rootContexts.values()) {\n this.#runGuarded('global context cleanup', () => rootCtx.cleanup());\n this.#runGuarded('global context signal', () => rootCtx.signal.destroy());\n }\n\n for (const ctx of this.#context.values()) {\n this.#runGuarded('context value reset', () => ctx.context.set(undefined));\n this.#runGuarded('context value subscription', () => ctx.unsubscribePathValue());\n this.#runGuarded('context parent subscription', () => ctx.unsubscribeFromParent?.());\n this.#runGuarded('context value path', () => ctx.valuePath.dispose());\n this.#runGuarded('inherited context signal', () => ctx.inherited.destroy());\n this.#runGuarded('provided context signal', () => ctx.provide.destroy());\n this.#runGuarded('context signal', () => ctx.context.destroy());\n }\n\n this.#rootContexts.clear();\n this.#context.clear();\n\n this.#parent = undefined;\n\n this.#childrenUuids.clear();\n this.#children.length = 0;\n }\n\n /**\n * Isolates one release step from the ones around it: a step that throws is reported through the\n * kernel's logger and does not stop `[onDestroy]()` from reaching the steps that follow. The\n * report goes out through the shared `runGuarded()`; what this wrapper adds is the label of the\n * step and the uuid of the entity it belongs to.\n */\n #runGuarded(step: string, run: () => void): void {\n runGuarded(this.#kernel.logger, run, `entity teardown step failed (${step}):`, this.#uuid);\n }\n\n /**\n * Refuses a parent that would close the entity tree into a ring: the entity itself, or an entity that\n * already sits below it. The walk follows the parent chain upwards, which is a chain exactly because\n * this guard keeps it one.\n *\n * `Kernel.setParent()` calls it before it detaches, and the `parentUuid` setter before it resolves the\n * link, so a refused attachment leaves the entity where it was instead of orphaned halfway through.\n * `ViewComponent.addChild()` guards the same thing on the view side.\n */\n assertAttachableTo(nextParent: Entity) {\n for (let e: Entity | undefined = nextParent; e != null; e = e.parent) {\n if (e === this) {\n throw new Error(\n `entity \"${nextParent.uuid}\" cannot become the parent of \"${this.uuid}\": it is the entity itself or one of its descendants`,\n );\n }\n }\n }\n\n /**\n * Puts `child` into the children list, at its place among the siblings.\n *\n * Nothing here notifies. Neither this method nor {@link Entity.removeChild} nor a detachment\n * sends anything to a listener on the entity -- the one notification over a moved entity is\n * `onParentChanged`, and `Kernel.setParent()` is the call that sends it.\n */\n addChild(child: Entity) {\n if (this.#childrenUuids.has(child.uuid)) {\n throw new Error(`child with uuid: ${child.uuid} already exists! parentUuid: ${this.uuid}`);\n }\n\n this.#childrenUuids.add(child.uuid);\n this.#insertChildInOrder(child);\n\n // the child may have created its contexts while it was still unattached: they hang on the root\n // of the entity context tree until something binds them to the parent they now have\n for (const [, ctx] of child.#context) {\n child.#subscribeToParent(ctx);\n }\n }\n\n /**\n * Puts a child at its place among the siblings, so building a subtree costs one insertion per\n * child. The scan runs from the end because children usually arrive with an equal or rising\n * `order`, which makes the common case a plain append. A child lands behind every sibling that\n * shares its `order` -- the same place a stable sort would give it.\n *\n * The result only matches a full sort while `#children` is already sorted when the insertion\n * starts, so name what keeps it that way: the insertion here preserves the order, `removeChild()`\n * cuts an element out with `splice`, the destroy handler empties the list, and the `order` setter\n * re-sorts through the parent. That last one is the condition worth stating, because it needs the\n * child to know its parent -- the parent link has to be established. Every way an entity is\n * attached inside this class goes through the `parentUuid` setter, which sets the parent before it\n * calls `addChild()`. A caller that reaches for `addChild()` on its own leaves the child without a\n * parent link, and a later `order` on such a child never reaches this list.\n */\n #insertChildInOrder(child: Entity) {\n let i = this.#children.length;\n while (i > 0 && child.order < this.#children[i - 1]!.order) i--;\n this.#children.splice(i, 0, child);\n }\n\n resortChildren() {\n this.#children.sort((a, b) => a.order - b.order);\n }\n\n removeChild(child: Entity) {\n // The identity decides here, not the uuid: `indexOf` answers -1 for an entity this list\n // does not hold, and a `splice(-1, 1)` on that answer would cut the last child out\n // instead of none. The ordered uuid lists of `ComponentContext` carry the same guard where\n // they cut a uuid out.\n const idx = this.#children.indexOf(child);\n if (idx !== -1) {\n this.#childrenUuids.delete(child.uuid);\n this.#children.splice(idx, 1);\n }\n }\n\n /**\n * @param rebindContexts bind every context back to the root of the entity context tree. An entity\n * that carries a context out of a subtree keeps following the value it can still see, rather\n * than freezing on the last one the former parent held. Only a caller that attaches the entity\n * to the next parent in the same breath passes `false` -- that parent binds the contexts itself,\n * and the detour over the root would be visible to `useParentContext()`, which hands out the\n * inherited value without the microtask collector `useContext()` has in front of it.\n */\n removeFromParent(rebindContexts = true) {\n this.#detachFromParent(rebindContexts);\n }\n\n #detachFromParent(rebindContexts: boolean) {\n // The field `parent` and `parentUuid` both answer from: clearing it here clears what either\n // getter would report, with nothing left over for a second check to find.\n if (this.#parent) {\n this.#parent.removeChild(this);\n\n this.#parent = undefined;\n\n if (rebindContexts) {\n for (const [, ctx] of this.#context) {\n this.#subscribeToParent(ctx);\n }\n }\n\n this.#unsubscribeAutoDestruction();\n\n // Detached is a place too: an entity with no parent is a root, and the root set is where\n // every traversal starts.\n this.#kernel.noteEntityTreeChange(this.#uuid);\n }\n }\n\n #autoDestructionEnabled = false;\n #autoDestructionSubscription?: (() => void) | undefined;\n\n get autoDestructionOnParentRemoval(): boolean {\n return this.#autoDestructionEnabled;\n }\n\n set autoDestructionOnParentRemoval(autoDestruct: boolean) {\n if (this.#autoDestructionEnabled === autoDestruct) return;\n this.#autoDestructionEnabled = autoDestruct;\n this.#updateAutoDestructionSubscription();\n }\n\n #unsubscribeAutoDestruction() {\n if (this.#autoDestructionSubscription) {\n this.#autoDestructionSubscription();\n this.#autoDestructionSubscription = undefined;\n }\n }\n\n #updateAutoDestructionSubscription() {\n this.#unsubscribeAutoDestruction();\n if (this.#autoDestructionEnabled && this.#parent) {\n this.#autoDestructionSubscription = once(this.#parent, onDestroy, Priority.Max, () => {\n this.#autoDestructionSubscription = undefined;\n this.#kernel.destroyEntity(this.#uuid);\n });\n }\n }\n\n /**\n * Binds every context of this entity to its current position in the entity tree -- to the parent\n * if there is one, to the root otherwise. `addChild()` and `removeFromParent()` each do this for\n * the entity they move, so a caller needs this only when it changed the position by other means\n * or wants the binding re-established without knowing which of the two ran.\n *\n * Moving an entity through the kernel is not such a case: both directions bring their own binding,\n * and a third one would reach every `useParentContext()` reader as another change.\n */\n reSubscribeToParentContexts() {\n for (const [, ctx] of this.#context) {\n this.#subscribeToParent(ctx);\n }\n }\n\n dispatchMessageToView(type: string, data?: unknown, transferables?: Transferable[], traverseChildren = false) {\n this.#kernel.dispatchMessageToView({uuid: this.#uuid, type, data, transferables, traverseChildren});\n }\n\n /**\n * Hands the events the view sent to whoever listens on this entity, one delivery per event.\n *\n * Each delivery is guarded, and the reason is where this call sits: the kernel makes it from\n * inside a change trail, on a path that builds. Unguarded, a single shadow-object that cannot cope\n * with a single view event would leave through `Kernel.run()` and refuse the whole trail -- the\n * same argument that puts a guard around the `onParentChanged` notification, which is a delivery\n * on a building path as well. The guard is per event, so one that fails costs neither the events\n * behind it nor the caller anything; `emitStrict()` inside it makes the same promise one level\n * down, to the listeners of one event.\n */\n dispatchViewEvents(events: IComponentEvent[]) {\n for (const {type, data} of events) {\n runGuarded(\n this.#kernel.logger,\n // the concrete class is needed here: eventize cannot reduce its emitter conditional\n // (`NonTypedEmitter<this>`) over the polymorphic `this` type, and no overload then matches\n () => emitStrict(this as Entity, onViewEvent, type, data),\n 'entity view event delivery failed:',\n type,\n this.#uuid,\n );\n }\n }\n\n dispatchViewEvent(type: string, data: unknown) {\n this.dispatchViewEvents([{type, data}]);\n }\n\n #getPropSignal<T = unknown>(key: string): Signal<T> {\n return this.#props.get<T>(key);\n }\n\n getPropertyReader<T = unknown>(key: string): SignalReader<T> {\n return this.#getPropSignal<T>(key).get;\n }\n\n /**\n * A write head for one property. Every write through it drops the cache behind\n * `truthyProps()`: that cache answers `Kernel.#updateShadowObjects()`, which picks the shadow\n * objects of this entity along the property routes of the registry, and a write the cache does\n * not see routes the entity to a state it no longer has.\n *\n * What comes back is a function of the entity, not the `set` of the signal behind the property.\n * The signalize helpers that take a signal-like -- `isSignal()`, `destroySignal()`, `touch()` --\n * do not recognise it; `getPropertyReader()` hands out the signal's own reader for that.\n *\n * A fresh closure is handed out on every call rather than one cached per key: `SignalAutoMap`\n * hands out \"a fresh, live\" signal for a key whose signal was destroyed from the outside, so a\n * writer cached against the signal captured on an earlier call could end up closing over a corpse.\n * The call sites this feeds -- `setProperty()` from a change-trail application, at most once per\n * property that actually changed -- do not turn this into a hot path.\n */\n getPropertyWriter<T = unknown>(key: string): SignalWriter<T> {\n const signal = this.#getPropSignal<T>(key);\n return (value: unknown, params?: SignalWriterParams<T>) => {\n this.clearTruthyPropsCache();\n signal.set(value as T, params);\n };\n }\n\n setProperties(properties: ComponentPropertiesType) {\n batch(() => {\n // an entry that names only the key sets the property to `undefined` \u2014 the key is there, the value is not\n for (const [key, val] of properties) {\n this.setProperty(key, val);\n }\n });\n }\n\n setProperty(key: string, value: unknown) {\n this.getPropertyWriter(key)(value);\n }\n\n getProperty<T = unknown>(key: string): T {\n return value(this.getPropertyReader<T>(key));\n }\n\n propKeys(): string[] {\n return Array.from(this.#props.keys()) as string[];\n }\n\n propEntries(): [string, unknown][] {\n return Array.from(this.#props.entries()).map(([key, sig]) => [key, sig.value]) as [string, unknown][];\n }\n\n #truthyPropsCache: Set<string> | undefined;\n\n clearTruthyPropsCache() {\n this.#truthyPropsCache = undefined;\n }\n\n truthyProps(): Set<string> | undefined {\n if (this.#truthyPropsCache) {\n return this.#truthyPropsCache.size ? this.#truthyPropsCache : undefined;\n }\n const truthyProps = new Set<string>();\n for (const [key, sig] of this.#props.entries()) {\n if (typeof key === 'string') {\n const val = sig.value;\n if (val != null && val !== false && val !== '') {\n truthyProps.add(key);\n }\n }\n }\n this.#truthyPropsCache = truthyProps;\n return truthyProps.size ? truthyProps : undefined;\n }\n\n hasContext(name: ContextNameType): boolean {\n return this.#context.has(name);\n }\n\n /** The names of the Entity Contexts this entity holds, used or provided. Reads only, creates none. */\n contextNames(): ContextNameType[] {\n return Array.from(this.#context.keys());\n }\n\n /**\n * The three values behind one Entity Context of this entity: what its own providers wrote, what it\n * inherits from the parent (or from the global chain at a root), and what `useContext(name)` reads.\n * `hasProviders` says whether a provider feed is attached -- a value written straight into the\n * signal from `provideContext()` counts as provided but not as a provider.\n *\n * `undefined` when the entity holds no context of that name; asking does not create one. The\n * reads are plain `.value` reads and track nothing, so a call from inside an effect does not\n * subscribe that effect to the context.\n */\n describeContext(\n name: ContextNameType,\n ): {provided: unknown; inherited: unknown; effective: unknown; hasProviders: boolean} | undefined {\n const ctx = this.#context.get(name);\n if (ctx === undefined) return undefined;\n return {\n provided: ctx.provide.value,\n inherited: ctx.inherited.value,\n effective: ctx.context.value,\n hasProviders: ctx.providerFeeds.size > 0,\n };\n }\n\n /** The names of the global Entity Contexts this entity contributes to. Reads only, creates none. */\n globalContextNames(): ContextNameType[] {\n return Array.from(this.#rootContexts.keys());\n }\n\n /**\n * What this entity contributes to the kernel-wide chain of one global Entity Context: the value\n * and the very signal that stands in the chain, so a caller holding the chain can find this entity\n * in it by identity. `undefined` when the entity contributes nothing under that name.\n */\n describeGlobalContext(name: ContextNameType): {value: unknown; signal: Signal<unknown>; hasProviders: boolean} | undefined {\n const rootCtx = this.#rootContexts.get(name);\n if (rootCtx === undefined) return undefined;\n return {value: rootCtx.signal.value, signal: rootCtx.signal, hasProviders: rootCtx.providerFeeds.size > 0};\n }\n\n useContext<T = unknown>(name: ContextNameType): SignalReader<T> {\n return this.#findOrCreateContext(name).context.get as SignalReader<T>;\n }\n\n useParentContext<T = unknown>(name: ContextNameType): SignalReader<T> {\n return this.#findOrCreateContext(name).inherited.get as SignalReader<T>;\n }\n\n provideContext<T = unknown>(name: ContextNameType): Signal<T> {\n return this.#findOrCreateContext(name).provide as Signal<T>;\n }\n\n provideGlobalContext<T = unknown>(name: ContextNameType): Signal<T> {\n // The signal behind it is created without an initial value \u2014 a context signal does start out\n // empty and holds no `T` until a provider writes one. The cast keeps the same contract\n // `provideContext()` hands out; callers see the `undefined` through `Maybe<T>` in the\n // shadow-object API.\n return this.#findOrCreateGlobalContext(name).signal as Signal<T>;\n }\n\n /**\n * Attaches a provider signal to the context of `name` on this entity and answers with the release\n * that detaches it again.\n *\n * Every provider of one name writes into the single signal that `provideContext()` hands out, so\n * what a consumer reads is what was written last. The release therefore does two things: it cuts\n * this feed, and it then lets a provider that is still attached write its value once more. Without\n * that second step the context would keep whatever the departure left standing -- the `undefined`\n * of a clearing provider, or the last value of one that opted out of it -- even though this entity\n * still has a provider of the name that says otherwise.\n *\n * A value written straight into the signal from `provideContext()` is not a feed and is therefore\n * overwritten by the next release. Feeding a value in through this method is what makes it survive\n * one.\n */\n attachContextProvider(name: ContextNameType, provider: Signal<any>): () => void {\n const ctx = this.#findOrCreateContext(name);\n return Entity.#attachProviderFeed(provider, ctx.provide, ctx.providerFeeds);\n }\n\n /**\n * The counterpart of {@link Entity.attachContextProvider} for the global context of `name`.\n *\n * Within one entity the situation is the same one: every provider feeds the single signal this\n * entity contributes to the kernel-wide chain of that name, and a release hands the name back to a\n * provider that stays. Across entities the chain decides on its own -- it resolves to the first\n * entry that holds something, so an entity whose signal falls empty lets the next one through.\n */\n attachGlobalContextProvider(name: ContextNameType, provider: Signal<any>): () => void {\n const rootCtx = this.#findOrCreateGlobalContext(name);\n return Entity.#attachProviderFeed(provider, rootCtx.signal, rootCtx.providerFeeds);\n }\n\n static #attachProviderFeed(provider: Signal<any>, target: Signal<any>, feeds: Set<SignalLink<any>>): () => void {\n const feed = link(provider, target);\n feeds.add(feed);\n\n return () => {\n // A release called a second time finds nothing of its own left and leaves the context to\n // whoever holds it by then.\n if (!feeds.delete(feed)) return;\n feed.destroy();\n Entity.#handOverToRemainingProvider(feeds);\n };\n }\n\n /**\n * Lets the provider that stays write its value into the context signal again.\n *\n * The set iterates in the order the providers were attached and the loop keeps the last hit, so the\n * winner is the one attached last that still holds a value. Attachment order is the order in which the\n * providers took the name: attaching feeds the value straight through, so a later attachment writes\n * over an earlier one, and the hand-over falls back on that order instead of inventing one of its own.\n * It is not the order of the writes -- a provider that writes to its signal after attaching carries\n * the name until the next departure, and the hand-over does not restore that write, because what this\n * entity keeps on file is its providers and not the sequence in which they wrote. Providers holding\n * nothing are passed over -- by the same `!= null` rule with which `SignalsPath` resolves a context\n * chain, and for the same reason: a provider without a value has nothing to say about the name, and\n * electing it would clear a name that is still being provided.\n *\n * A feed whose link is destroyed is passed over as well. A shadow-object owns the signal it was\n * handed and may end it early, which destroys the link without the release ever having run: such a\n * feed still reports a value through its source while its writes go nowhere, so electing it would\n * leave the write of the departure standing, silently and over a provider that is alive.\n *\n * `touch()` is what makes the winner write, because `SignalLink.write()` is protected: touching is\n * the only public way to push the current value of a source through its link again, and the source\n * of a provider that merely stays has no reason to change.\n *\n * Where no remaining feed qualifies, nothing is written: then what the departure left stands,\n * which is the `undefined` of a clearing provider or the last value of one that opted out.\n */\n static #handOverToRemainingProvider(feeds: Set<SignalLink<any>>): void {\n let winner: SignalLink<any> | undefined;\n for (const feed of feeds) {\n if (!feed.isDestroyed && feed.source.value != null) winner = feed;\n }\n winner?.touch();\n }\n\n #findOrCreateGlobalContext(name: ContextNameType): IRootContextValue {\n if (this.#rootContexts.has(name)) {\n return this.#rootContexts.get(name)!;\n }\n const rootCtx = this.#kernel.findOrCreateRootContext(name);\n const signal = createSignal() as Signal<any>;\n const cleanup = rootCtx.add(signal);\n const ctx: IRootContextValue = {cleanup, signal, providerFeeds: new Set()};\n this.#rootContexts.set(name, ctx);\n return ctx;\n }\n\n #findOrCreateContext(name: ContextNameType): IContextValue {\n if (this.#context.has(name)) {\n return this.#context.get(name)!;\n }\n\n const inherited = createSignal();\n const provide = createSignal();\n const context = createSignal();\n\n const valuePath = new SignalsPath([provide, inherited]);\n\n const unsubscribePathValue = on(valuePath, SignalsPath.Value, (val) => {\n deferContextValueUpdate(this.#kernel, context, val, name, this.#uuid);\n });\n\n const ctx: IContextValue = {name, inherited, provide, context, valuePath, providerFeeds: new Set(), unsubscribePathValue};\n this.#context.set(name, ctx);\n\n this.#subscribeToParent(ctx);\n\n return ctx;\n }\n\n #subscribeToParent(ctx: IContextValue) {\n ctx.unsubscribeFromParent?.();\n ctx.unsubscribeFromParent = undefined;\n if (this.parent) {\n const parentCtx = this.parent.#findOrCreateContext(ctx.name);\n const linkToParent = link(parentCtx.context, ctx.inherited);\n ctx.unsubscribeFromParent = linkToParent.destroy.bind(linkToParent);\n } else {\n const rootCtx = this.#kernel.findOrCreateRootContext(ctx.name);\n const linkToRoot = link(rootCtx.value$, ctx.inherited);\n ctx.unsubscribeFromParent = linkToRoot.destroy.bind(linkToRoot);\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["value"]
|
|
7
7
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { type SignalLike } from '@spearwolf/signalize';
|
|
2
|
+
import type { ComponentPropertiesType, IComponentEvent, ShadowObjectDescription, ShadowObjectType, SyncEvent } from '../types.js';
|
|
2
3
|
import { ConsoleLogger } from '../utils/ConsoleLogger.js';
|
|
3
4
|
import { Entity } from './Entity.js';
|
|
4
5
|
import { Registry } from './Registry.js';
|
|
@@ -46,6 +47,8 @@ export declare class Kernel {
|
|
|
46
47
|
*/
|
|
47
48
|
findEntity(uuid: string): Entity | undefined;
|
|
48
49
|
hasEntity(uuid: string): boolean;
|
|
50
|
+
/** The token of the entity behind `uuid`, or `undefined` when the kernel does not hold one. */
|
|
51
|
+
tokenOf(uuid: string): string | undefined;
|
|
49
52
|
/**
|
|
50
53
|
* @returns all entities in breadth-first order
|
|
51
54
|
*
|
|
@@ -121,7 +124,27 @@ export declare class Kernel {
|
|
|
121
124
|
changeToken(uuid: string, token: string): void;
|
|
122
125
|
dispatchMessageToView(message: MessageToViewEvent): void;
|
|
123
126
|
findShadowObjects(uuid: string): ShadowObjectType[];
|
|
127
|
+
/**
|
|
128
|
+
* One description per Shadow Object of the entity, in the order `findShadowObjects()` lists them:
|
|
129
|
+
* what the creation scope knows (display name, the five name lists), the tokens the constructor is
|
|
130
|
+
* defined under in this kernel's registry, and which of the four lifecycle hooks the instance
|
|
131
|
+
* implements. `[]` for a uuid the kernel does not hold. Reads only; a scope that is already gone
|
|
132
|
+
* contributes its display name and empty lists.
|
|
133
|
+
*/
|
|
134
|
+
describeShadowObjects(uuid: string): ShadowObjectDescription[];
|
|
124
135
|
findOrCreateRootContext(name: string | symbol): SignalsPath;
|
|
136
|
+
/** The names of the kernel-wide context chains -- every name a root entity uses or any entity provides globally. */
|
|
137
|
+
rootContextNames(): (string | symbol)[];
|
|
138
|
+
/**
|
|
139
|
+
* One kernel-wide context chain: what it resolves to, and its members in chain order. The members
|
|
140
|
+
* are the signals the entities contributed -- `Entity.describeGlobalContext()` hands out the same
|
|
141
|
+
* objects, so a caller can match them by identity. `undefined` for a name the kernel holds no
|
|
142
|
+
* chain for; asking does not create one.
|
|
143
|
+
*/
|
|
144
|
+
describeRootContext(name: string | symbol): {
|
|
145
|
+
value: unknown;
|
|
146
|
+
signals: readonly SignalLike<any>[];
|
|
147
|
+
} | undefined;
|
|
125
148
|
destroy(): void;
|
|
126
149
|
}
|
|
127
150
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Kernel.d.ts","sourceRoot":"","sources":["../../../src/in-the-dark/Kernel.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Kernel.d.ts","sourceRoot":"","sources":["../../../src/in-the-dark/Kernel.ts"],"names":[],"mappings":"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"}
|