@spearwolf/shadow-objects 0.33.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 +350 -61
- package/README.md +66 -13
- package/bundle.js +6 -53
- package/package.json +15 -3
- package/src/ChangeTrailRefusedError.d.ts +27 -0
- package/src/ChangeTrailRefusedError.d.ts.map +1 -0
- package/src/ChangeTrailRefusedError.js +12 -0
- package/src/ChangeTrailRefusedError.js.map +7 -0
- package/src/EntityUuidInUseError.d.ts +19 -0
- package/src/EntityUuidInUseError.d.ts.map +1 -0
- package/src/EntityUuidInUseError.js +11 -0
- package/src/EntityUuidInUseError.js.map +7 -0
- package/src/WorkerTimeoutError.d.ts +26 -0
- package/src/WorkerTimeoutError.d.ts.map +1 -0
- package/src/WorkerTimeoutError.js +12 -0
- package/src/WorkerTimeoutError.js.map +7 -0
- package/src/bundle.d.ts +1 -1
- package/src/bundle.d.ts.map +1 -1
- package/src/bundle.js +1 -1
- package/src/bundle.js.map +2 -2
- package/src/constants.d.ts +13 -2
- package/src/constants.d.ts.map +1 -1
- package/src/constants.js +7 -1
- package/src/constants.js.map +2 -2
- package/src/create-worker.bundle.d.ts +1 -1
- package/src/create-worker.bundle.d.ts.map +1 -1
- package/src/create-worker.bundle.js.map +1 -1
- package/src/create-worker.d.ts +1 -1
- package/src/create-worker.d.ts.map +1 -1
- package/src/create-worker.js.map +1 -1
- package/src/elements/ShaeElement.d.ts +70 -2
- package/src/elements/ShaeElement.d.ts.map +1 -1
- package/src/elements/ShaeElement.js +129 -25
- package/src/elements/ShaeElement.js.map +3 -3
- package/src/elements/ShaeEntElement.d.ts +39 -1
- package/src/elements/ShaeEntElement.d.ts.map +1 -1
- package/src/elements/ShaeEntElement.js +397 -167
- package/src/elements/ShaeEntElement.js.map +2 -2
- package/src/elements/ShaeLifecycleElement.d.ts +71 -0
- package/src/elements/ShaeLifecycleElement.d.ts.map +1 -0
- package/src/elements/ShaeLifecycleElement.js +83 -0
- package/src/elements/ShaeLifecycleElement.js.map +7 -0
- package/src/elements/ShaePropElement.d.ts +61 -2
- package/src/elements/ShaePropElement.d.ts.map +1 -1
- package/src/elements/ShaePropElement.js +264 -219
- package/src/elements/ShaePropElement.js.map +2 -2
- package/src/elements/ShaeWorkerElement.d.ts +59 -5
- package/src/elements/ShaeWorkerElement.d.ts.map +1 -1
- package/src/elements/ShaeWorkerElement.js +271 -73
- package/src/elements/ShaeWorkerElement.js.map +2 -2
- package/src/elements/constants.d.ts +9 -0
- package/src/elements/constants.d.ts.map +1 -1
- package/src/elements/constants.js +18 -0
- package/src/elements/constants.js.map +2 -2
- package/src/elements/deferredTeardown.d.ts +24 -0
- package/src/elements/deferredTeardown.d.ts.map +1 -0
- package/src/elements/deferredTeardown.js +30 -0
- package/src/elements/deferredTeardown.js.map +7 -0
- package/src/elements/displayContentsRule.d.ts +25 -0
- package/src/elements/displayContentsRule.d.ts.map +1 -0
- package/src/elements/displayContentsRule.js +37 -0
- package/src/elements/displayContentsRule.js.map +7 -0
- package/src/elements/events.d.ts +10 -7
- package/src/elements/events.d.ts.map +1 -1
- package/src/elements/forwardCustomEvents.d.ts +19 -0
- package/src/elements/forwardCustomEvents.d.ts.map +1 -0
- package/src/elements/forwardCustomEvents.js +47 -0
- package/src/elements/forwardCustomEvents.js.map +7 -0
- package/src/elements/hostedSlots.d.ts +36 -0
- package/src/elements/hostedSlots.d.ts.map +1 -0
- package/src/elements/hostedSlots.js +118 -0
- package/src/elements/hostedSlots.js.map +7 -0
- package/src/elements/parentRemoval.d.ts +18 -0
- package/src/elements/parentRemoval.d.ts.map +1 -0
- package/src/elements/parentRemoval.js +60 -0
- package/src/elements/parentRemoval.js.map +7 -0
- package/src/elements/propValueConverters.d.ts +3 -0
- package/src/elements/propValueConverters.d.ts.map +1 -0
- package/src/elements/propValueConverters.js +54 -0
- package/src/elements/propValueConverters.js.map +7 -0
- package/src/elements/requestEntAncestor.d.ts +32 -0
- package/src/elements/requestEntAncestor.d.ts.map +1 -0
- package/src/elements/requestEntAncestor.js +16 -0
- package/src/elements/requestEntAncestor.js.map +7 -0
- package/src/elements.js.map +1 -1
- package/src/in-the-dark/Entity.d.ts +143 -3
- package/src/in-the-dark/Entity.d.ts.map +1 -1
- package/src/in-the-dark/Entity.js +330 -63
- package/src/in-the-dark/Entity.js.map +3 -3
- package/src/in-the-dark/Kernel.d.ts +98 -16
- package/src/in-the-dark/Kernel.d.ts.map +1 -1
- package/src/in-the-dark/Kernel.js +466 -379
- package/src/in-the-dark/Kernel.js.map +3 -3
- 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 +112 -14
- package/src/in-the-dark/Registry.js.map +2 -2
- package/src/in-the-dark/ShadowObject.d.ts.map +1 -1
- package/src/in-the-dark/ShadowObject.js +1 -0
- package/src/in-the-dark/ShadowObject.js.map +2 -2
- package/src/in-the-dark/ShadowObjectCreationScope.d.ts +133 -0
- package/src/in-the-dark/ShadowObjectCreationScope.d.ts.map +1 -0
- package/src/in-the-dark/ShadowObjectCreationScope.js +603 -0
- package/src/in-the-dark/ShadowObjectCreationScope.js.map +7 -0
- 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 +6 -2
- 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/in-the-dark/events.js.map +1 -1
- package/src/in-the-dark/importModule.d.ts +7 -0
- package/src/in-the-dark/importModule.d.ts.map +1 -1
- package/src/in-the-dark/importModule.js +5 -2
- package/src/in-the-dark/importModule.js.map +2 -2
- package/src/index.d.ts +9 -1
- package/src/index.d.ts.map +1 -1
- package/src/index.js +9 -1
- 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 +4 -0
- package/src/shadow-objects.d.ts.map +1 -1
- package/src/shadow-objects.js +6 -0
- package/src/shadow-objects.js.map +2 -2
- package/src/shadow-objects.worker.js +0 -1
- package/src/shadow-objects.worker.js.map +2 -2
- package/src/shae-ent.js.map +1 -1
- package/src/shae-prop.js +2 -2
- package/src/shae-prop.js.map +2 -2
- package/src/shae-worker.js.map +1 -1
- package/src/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 +185 -14
- package/src/types.d.ts.map +1 -1
- package/src/utils/ConsoleLogger.d.ts +45 -10
- package/src/utils/ConsoleLogger.d.ts.map +1 -1
- package/src/utils/ConsoleLogger.js +51 -26
- package/src/utils/ConsoleLogger.js.map +2 -2
- package/src/utils/FrameLoop.d.ts +42 -3
- package/src/utils/FrameLoop.d.ts.map +1 -1
- package/src/utils/FrameLoop.js +71 -10
- package/src/utils/FrameLoop.js.map +2 -2
- package/src/utils/MicrotaskCollector.d.ts +45 -0
- package/src/utils/MicrotaskCollector.d.ts.map +1 -0
- package/src/utils/MicrotaskCollector.js +33 -0
- package/src/utils/MicrotaskCollector.js.map +7 -0
- package/src/utils/MicrotaskGate.d.ts +17 -0
- package/src/utils/MicrotaskGate.d.ts.map +1 -0
- package/src/utils/MicrotaskGate.js +20 -0
- package/src/utils/MicrotaskGate.js.map +7 -0
- package/src/utils/array-utils.js.map +1 -1
- package/src/utils/attr-utils.d.ts +11 -0
- package/src/utils/attr-utils.d.ts.map +1 -1
- package/src/utils/attr-utils.js +5 -1
- package/src/utils/attr-utils.js.map +2 -2
- package/src/utils/constants.js.map +1 -1
- package/src/utils/generateUUID.d.ts +11 -0
- package/src/utils/generateUUID.d.ts.map +1 -1
- package/src/utils/generateUUID.js +31 -266
- package/src/utils/generateUUID.js.map +2 -2
- package/src/utils/props-utils.d.ts +3 -2
- package/src/utils/props-utils.d.ts.map +1 -1
- package/src/utils/props-utils.js +13 -24
- package/src/utils/props-utils.js.map +2 -2
- package/src/utils/runGuarded.d.ts +27 -0
- package/src/utils/runGuarded.d.ts.map +1 -0
- package/src/utils/runGuarded.js +11 -0
- package/src/utils/runGuarded.js.map +7 -0
- package/src/utils/toMaybe.d.ts.map +1 -1
- package/src/utils/toMaybe.js.map +1 -1
- package/src/utils/toNamespace.d.ts.map +1 -1
- package/src/utils/toNamespace.js.map +1 -1
- package/src/utils/toUrlString.d.ts +12 -0
- package/src/utils/toUrlString.d.ts.map +1 -1
- package/src/utils/toUrlString.js.map +2 -2
- package/src/utils/waitForMessageOfType.d.ts +12 -1
- package/src/utils/waitForMessageOfType.d.ts.map +1 -1
- package/src/utils/waitForMessageOfType.js +16 -1
- package/src/utils/waitForMessageOfType.js.map +2 -2
- package/src/view/ComponentChanges.d.ts +88 -1
- package/src/view/ComponentChanges.d.ts.map +1 -1
- package/src/view/ComponentChanges.js +243 -73
- package/src/view/ComponentChanges.js.map +2 -2
- package/src/view/ComponentContext.d.ts +206 -16
- package/src/view/ComponentContext.d.ts.map +1 -1
- package/src/view/ComponentContext.js +548 -91
- package/src/view/ComponentContext.js.map +2 -2
- package/src/view/ComponentMemory.d.ts +3 -3
- package/src/view/ComponentMemory.d.ts.map +1 -1
- package/src/view/ComponentMemory.js.map +1 -1
- package/src/view/IShadowObjectEnvProxy.d.ts +38 -3
- package/src/view/IShadowObjectEnvProxy.d.ts.map +1 -1
- package/src/view/LocalShadowObjectEnv.d.ts +8 -1
- package/src/view/LocalShadowObjectEnv.d.ts.map +1 -1
- package/src/view/LocalShadowObjectEnv.js +23 -7
- package/src/view/LocalShadowObjectEnv.js.map +2 -2
- package/src/view/RemoteWorkerEnv.d.ts +108 -5
- package/src/view/RemoteWorkerEnv.d.ts.map +1 -1
- package/src/view/RemoteWorkerEnv.js +244 -77
- package/src/view/RemoteWorkerEnv.js.map +2 -2
- package/src/view/ShadowEnv.d.ts +79 -2
- package/src/view/ShadowEnv.d.ts.map +1 -1
- package/src/view/ShadowEnv.js +323 -59
- package/src/view/ShadowEnv.js.map +3 -3
- package/src/view/ViewComponent.d.ts +78 -14
- package/src/view/ViewComponent.d.ts.map +1 -1
- package/src/view/ViewComponent.js +90 -14
- package/src/view/ViewComponent.js.map +2 -2
- package/src/view/cloneChangeTrail.js.map +2 -2
- package/src/worker/MessageRouter.d.ts +14 -0
- package/src/worker/MessageRouter.d.ts.map +1 -1
- package/src/worker/MessageRouter.js +98 -15
- package/src/worker/MessageRouter.js.map +2 -2
- package/src/worker/WorkerRuntime.d.ts +22 -1
- package/src/worker/WorkerRuntime.d.ts.map +1 -1
- package/src/worker/WorkerRuntime.js +60 -8
- package/src/worker/WorkerRuntime.js.map +2 -2
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { InspectRequest, KernelSnapshot } from '../inspect/types.js';
|
|
1
2
|
import type { ChangeTrailType } from '../types.js';
|
|
2
3
|
import { ConsoleLogger } from '../utils/ConsoleLogger.js';
|
|
3
4
|
import type { IShadowObjectEnvProxy } from './IShadowObjectEnvProxy.js';
|
|
@@ -17,6 +18,45 @@ export declare class WorkerFailedError extends Error {
|
|
|
17
18
|
export declare class WorkerDestroyedError extends Error {
|
|
18
19
|
constructor(message?: string);
|
|
19
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* The reason a request is rejected with when the worker reported a failure of its own -- a
|
|
23
|
+
* module that would not import, a change trail its Kernel refused. An error does not survive
|
|
24
|
+
* structured cloning as the object it is, so the two fields that do are rebuilt here, and
|
|
25
|
+
* `name` is the name the error called itself inside the worker: a caller reads it the same
|
|
26
|
+
* way it reads the name of an error a `LocalShadowObjectEnv` hands it. A name that is missing
|
|
27
|
+
* or empty names no class, and `Error` is what such a reason is called -- the same name a
|
|
28
|
+
* plain `new Error(message)` carries on the local side.
|
|
29
|
+
*
|
|
30
|
+
* What does not come across is the class and everything it added. `instanceof EntityUuidInUseError`
|
|
31
|
+
* is `false` here and there is no `uuid` field, whatever `name` says; `instanceof WorkerReportedError`
|
|
32
|
+
* is what tells such a reason apart from one raised on this side.
|
|
33
|
+
*/
|
|
34
|
+
export declare class WorkerReportedError extends Error {
|
|
35
|
+
constructor(name: string | undefined, message: string);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* How long a {@link RemoteWorkerEnv} waits for each of the five replies a worker owes it,
|
|
39
|
+
* in milliseconds.
|
|
40
|
+
*/
|
|
41
|
+
export interface WorkerTimeouts {
|
|
42
|
+
/** the `Loaded` handshake at the start */
|
|
43
|
+
loadTimeout: number;
|
|
44
|
+
/** the `ImportedModule` reply to an `importScript()` */
|
|
45
|
+
configureTimeout: number;
|
|
46
|
+
/** the `AppliedChangeTrail` confirmation of a change trail sent with `waitForConfirmation` */
|
|
47
|
+
changeTrailTimeout: number;
|
|
48
|
+
/** the `Inspected` answer to an `inspect()` */
|
|
49
|
+
inspectTimeout: number;
|
|
50
|
+
/** the `Destroyed` acknowledgement of a teardown */
|
|
51
|
+
destroyTimeout: number;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* What {@link RemoteWorkerEnv} takes. Every value left out keeps its default — the five
|
|
55
|
+
* `Worker*Timeout` constants. A value that is not a number of milliseconds from 1 to
|
|
56
|
+
* 2147483647 — close to 25 days, the longest delay a timer keeps — is reported through the
|
|
57
|
+
* logger and the default applies.
|
|
58
|
+
*/
|
|
59
|
+
export type RemoteWorkerEnvOptions = Partial<WorkerTimeouts>;
|
|
20
60
|
/** What {@link RemoteWorkerEnv.WorkerFailed} carries. */
|
|
21
61
|
export interface WorkerFailedEvent {
|
|
22
62
|
/** the environment whose worker failed */
|
|
@@ -34,7 +74,14 @@ export declare class RemoteWorkerEnv implements IShadowObjectEnvProxy {
|
|
|
34
74
|
#private;
|
|
35
75
|
static WorkerLoaded: string;
|
|
36
76
|
static WorkerFailed: string;
|
|
37
|
-
|
|
77
|
+
/** The logger this environment reports through. */
|
|
78
|
+
get logger(): ConsoleLogger;
|
|
79
|
+
/**
|
|
80
|
+
* The five timeouts this environment holds itself to, resolved once when it is built. The
|
|
81
|
+
* object is frozen and the slot holds no setter, so the constructor is the one way in --
|
|
82
|
+
* and `resolveTimeouts()` vets every value that goes through it.
|
|
83
|
+
*/
|
|
84
|
+
get timeouts(): Readonly<WorkerTimeouts>;
|
|
38
85
|
get isDestroyed(): boolean;
|
|
39
86
|
/**
|
|
40
87
|
* Resolves once the worker is up.
|
|
@@ -44,17 +91,73 @@ export declare class RemoteWorkerEnv implements IShadowObjectEnvProxy {
|
|
|
44
91
|
* `catch()` — otherwise a worker failure surfaces as an unhandled rejection.
|
|
45
92
|
*
|
|
46
93
|
* @throws {WorkerFailedError} if the worker fails before or after that happens
|
|
94
|
+
* @throws {WorkerDestroyedError} once the environment has been torn down — including every
|
|
95
|
+
* read after a load that had already succeeded, because there is no environment left to hand out
|
|
47
96
|
*/
|
|
48
97
|
get workerLoaded(): Promise<RemoteWorkerEnv>;
|
|
49
|
-
constructor();
|
|
98
|
+
constructor(options?: RemoteWorkerEnvOptions);
|
|
50
99
|
start(): Promise<void>;
|
|
51
100
|
applyChangeTrail(changeTrail: ChangeTrailType, waitForConfirmation: boolean): Promise<void>;
|
|
52
101
|
importScript(url: URL | string): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Asks the worker for a snapshot of its Kernel. The request travels as an `Inspect` message
|
|
104
|
+
* under a serial of its own, and the `Inspected` answer that carries the same serial settles
|
|
105
|
+
* the call: with the snapshot, or with a `WorkerReportedError` rebuilt from the failure the
|
|
106
|
+
* worker described. An answer that stays out past `inspectTimeout` rejects with a
|
|
107
|
+
* `WorkerTimeoutError`; a worker that failed or an environment that was torn down rejects right
|
|
108
|
+
* away, before or while the answer is awaited.
|
|
109
|
+
*
|
|
110
|
+
* The caller's `signal` ends the wait with its own reason. The worker is not told: an answer
|
|
111
|
+
* that arrives afterwards carries a serial nobody waits for any more and is discarded like any
|
|
112
|
+
* other unmatched message.
|
|
113
|
+
*
|
|
114
|
+
* The message runs through the same queue as the change trails, so the snapshot reflects every
|
|
115
|
+
* trail posted before this call and none posted after it.
|
|
116
|
+
*/
|
|
117
|
+
inspect(request?: InspectRequest, signal?: AbortSignal): Promise<KernelSnapshot>;
|
|
53
118
|
destroy(): void;
|
|
54
|
-
private onWorkerError;
|
|
55
|
-
private onWorkerMessageError;
|
|
119
|
+
private readonly onWorkerError;
|
|
120
|
+
private readonly onWorkerMessageError;
|
|
56
121
|
private handleWorkerFailure;
|
|
57
|
-
|
|
122
|
+
/**
|
|
123
|
+
* Announces the completed handshake to the consumers.
|
|
124
|
+
*
|
|
125
|
+
* `emitStrict()` rather than `emit()`, and the retain policy is what decides it. `workerLoaded`
|
|
126
|
+
* reads the retained value, and eventize writes that value only once the dispatch has run
|
|
127
|
+
* through: under the plain dispatch a single listener that throws would take the replay for
|
|
128
|
+
* every later subscriber with it, and every later read of `workerLoaded` would wait for a
|
|
129
|
+
* failure or a teardown instead of resolving. The guarded dispatch serves every listener and
|
|
130
|
+
* writes the retained value, because the event was delivered.
|
|
131
|
+
*
|
|
132
|
+
* What the listeners threw arrives here afterwards -- one of them unchanged, several as an
|
|
133
|
+
* `AggregateError` in dispatch order -- and is reported. It goes no further: this runs from a
|
|
134
|
+
* microtask, where a throw has no caller left to reach and would surface as an unhandled error.
|
|
135
|
+
*/
|
|
136
|
+
private announceLoaded;
|
|
137
|
+
/**
|
|
138
|
+
* Announces the failure to the consumers. The same guarded dispatch as
|
|
139
|
+
* {@link RemoteWorkerEnv.announceLoaded}, for the same reason: `WorkerFailed` is documented as
|
|
140
|
+
* retained, and a consumer that subscribes only after the failure has to be able to hear about
|
|
141
|
+
* it. Every listener is served, the retained value is written, and whatever was thrown is
|
|
142
|
+
* reported here and reaches no caller.
|
|
143
|
+
*/
|
|
144
|
+
private announceFailure;
|
|
145
|
+
private readonly onMessageFromWorker;
|
|
146
|
+
/**
|
|
147
|
+
* Takes every listener of this environment off a worker. Whoever registered them takes them
|
|
148
|
+
* off again -- between the teardown and the `terminate()` that ends it the worker stays
|
|
149
|
+
* alive, and through its listeners it keeps this environment and everything it references
|
|
150
|
+
* reachable for exactly that long.
|
|
151
|
+
*/
|
|
152
|
+
private stopListeningTo;
|
|
58
153
|
private configureConsoleLogger;
|
|
154
|
+
/**
|
|
155
|
+
* The console-logger config for the worker, read from the storage key this environment
|
|
156
|
+
* announces. The key is a diagnostic switch, set by hand and sharing its namespace with
|
|
157
|
+
* everything else on this origin, so its content decides nothing about whether the worker
|
|
158
|
+
* comes up: anything that is not a plain JSON object counts as no config at all, exactly
|
|
159
|
+
* like an absent key.
|
|
160
|
+
*/
|
|
161
|
+
private readWorkerConfig;
|
|
59
162
|
}
|
|
60
163
|
//# sourceMappingURL=RemoteWorkerEnv.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RemoteWorkerEnv.d.ts","sourceRoot":"","sources":["../../../src/view/RemoteWorkerEnv.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RemoteWorkerEnv.d.ts","sourceRoot":"","sources":["../../../src/view/RemoteWorkerEnv.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { emitStrict, once, retain } from "@spearwolf/eventize";
|
|
2
|
+
import { ChangeTrailRefusedError } from "../ChangeTrailRefusedError.js";
|
|
2
3
|
import {
|
|
3
4
|
AppliedChangeTrail,
|
|
4
5
|
ChangeTrail,
|
|
@@ -6,32 +7,35 @@ import {
|
|
|
6
7
|
Destroy,
|
|
7
8
|
Destroyed,
|
|
8
9
|
ImportedModule,
|
|
10
|
+
Inspect,
|
|
11
|
+
Inspected,
|
|
9
12
|
Loaded,
|
|
10
13
|
MessageToView,
|
|
11
14
|
WorkerChangeTrailTimeout,
|
|
12
15
|
WorkerConfigureTimeout,
|
|
13
16
|
WorkerDestroyTimeout,
|
|
17
|
+
WorkerInspectTimeout,
|
|
14
18
|
WorkerLoadTimeout
|
|
15
19
|
} from "../constants.js";
|
|
16
20
|
import createWorker from "../create-worker.js";
|
|
17
|
-
import { CONSOLE_LOGGER, ConsoleLogger } from "../utils/ConsoleLogger.js";
|
|
21
|
+
import { CONSOLE_LOGGER, ConsoleLogger, consoleLoggerConfigKey, loadConsoleLoggerConfig } from "../utils/ConsoleLogger.js";
|
|
18
22
|
import { toUrlString } from "../utils/toUrlString.js";
|
|
19
|
-
import { waitForMessageOfType } from "../utils/waitForMessageOfType.js";
|
|
20
|
-
const
|
|
23
|
+
import { isTimeout, MaxWorkerTimeout, waitForMessageOfType } from "../utils/waitForMessageOfType.js";
|
|
24
|
+
const splitTransferables = (changeTrail) => {
|
|
25
|
+
if (!Array.isArray(changeTrail)) return { changeTrail };
|
|
26
|
+
let outbound;
|
|
21
27
|
let transferables;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
delete changeItem.transferables;
|
|
31
|
-
}
|
|
28
|
+
for (let i = 0; i < changeTrail.length; i++) {
|
|
29
|
+
const changeItem = changeTrail[i];
|
|
30
|
+
if (changeItem?.transferables) {
|
|
31
|
+
transferables = transferables ? [...transferables, ...changeItem.transferables] : [...changeItem.transferables];
|
|
32
|
+
outbound ??= [...changeTrail];
|
|
33
|
+
const withoutTransferables = { ...changeItem };
|
|
34
|
+
delete withoutTransferables.transferables;
|
|
35
|
+
outbound[i] = withoutTransferables;
|
|
32
36
|
}
|
|
33
37
|
}
|
|
34
|
-
return transferables;
|
|
38
|
+
return { changeTrail: outbound ?? changeTrail, transferables };
|
|
35
39
|
};
|
|
36
40
|
class WorkerFailedError extends Error {
|
|
37
41
|
constructor(type, message, options) {
|
|
@@ -46,16 +50,61 @@ class WorkerDestroyedError extends Error {
|
|
|
46
50
|
this.name = "WorkerDestroyedError";
|
|
47
51
|
}
|
|
48
52
|
}
|
|
53
|
+
class WorkerReportedError extends Error {
|
|
54
|
+
constructor(name, message) {
|
|
55
|
+
super(message);
|
|
56
|
+
this.name = name || "Error";
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const DefaultWorkerTimeouts = {
|
|
60
|
+
loadTimeout: WorkerLoadTimeout,
|
|
61
|
+
configureTimeout: WorkerConfigureTimeout,
|
|
62
|
+
changeTrailTimeout: WorkerChangeTrailTimeout,
|
|
63
|
+
inspectTimeout: WorkerInspectTimeout,
|
|
64
|
+
destroyTimeout: WorkerDestroyTimeout
|
|
65
|
+
};
|
|
66
|
+
const resolveTimeouts = (options, logger) => {
|
|
67
|
+
const resolved = { ...DefaultWorkerTimeouts };
|
|
68
|
+
if (options == null) return resolved;
|
|
69
|
+
for (const key of Object.keys(DefaultWorkerTimeouts)) {
|
|
70
|
+
if (!Object.hasOwn(options, key)) continue;
|
|
71
|
+
const value = options[key];
|
|
72
|
+
if (value === void 0) continue;
|
|
73
|
+
if (isTimeout(value)) {
|
|
74
|
+
resolved[key] = value;
|
|
75
|
+
} else {
|
|
76
|
+
logger.error(`ignoring the ${key} option: expected a number of milliseconds from 1 to ${MaxWorkerTimeout}, got`, value);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return resolved;
|
|
80
|
+
};
|
|
49
81
|
class RemoteWorkerEnv {
|
|
50
|
-
constructor() {
|
|
82
|
+
constructor(options) {
|
|
51
83
|
this.#isDestroyed = false;
|
|
52
84
|
this.#changeTrailSerial = 0;
|
|
85
|
+
this.#inspectSerial = 0;
|
|
53
86
|
/**
|
|
54
|
-
* Aborted exactly once, with the {@link WorkerFailedError}
|
|
87
|
+
* Aborted exactly once, with the error that ends this environment: a {@link WorkerFailedError}
|
|
88
|
+
* when the worker broke down, a {@link WorkerDestroyedError} when it was torn down. Whichever
|
|
89
|
+
* comes first keeps the signal, so a teardown never buries the failure that provoked it.
|
|
55
90
|
* It settles every request already waiting for a reply and turns away every later one.
|
|
56
91
|
*/
|
|
57
92
|
this.#workerFailure = new AbortController();
|
|
58
|
-
this
|
|
93
|
+
this.#logger = new ConsoleLogger("RemoteWorkerEnv");
|
|
94
|
+
this.onWorkerError = (event) => {
|
|
95
|
+
this.handleWorkerFailure("error", event, event.message || "the worker reported an error");
|
|
96
|
+
};
|
|
97
|
+
this.onWorkerMessageError = (event) => {
|
|
98
|
+
this.handleWorkerFailure("messageerror", event, "the worker sent a message that could not be deserialized");
|
|
99
|
+
};
|
|
100
|
+
this.onMessageFromWorker = (event) => {
|
|
101
|
+
if (event.data?.type === MessageToView) {
|
|
102
|
+
this.onMessageToView?.(event.data.data);
|
|
103
|
+
} else {
|
|
104
|
+
this.logger.debug("message from worker", event);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
this.#timeouts = Object.freeze(resolveTimeouts(options, this.logger));
|
|
59
108
|
retain(this, RemoteWorkerEnv.WorkerLoaded);
|
|
60
109
|
retain(this, RemoteWorkerEnv.WorkerFailed);
|
|
61
110
|
}
|
|
@@ -68,7 +117,22 @@ class RemoteWorkerEnv {
|
|
|
68
117
|
#worker;
|
|
69
118
|
#isDestroyed;
|
|
70
119
|
#changeTrailSerial;
|
|
120
|
+
#inspectSerial;
|
|
71
121
|
#workerFailure;
|
|
122
|
+
#logger;
|
|
123
|
+
/** The logger this environment reports through. */
|
|
124
|
+
get logger() {
|
|
125
|
+
return this.#logger;
|
|
126
|
+
}
|
|
127
|
+
#timeouts;
|
|
128
|
+
/**
|
|
129
|
+
* The five timeouts this environment holds itself to, resolved once when it is built. The
|
|
130
|
+
* object is frozen and the slot holds no setter, so the constructor is the one way in --
|
|
131
|
+
* and `resolveTimeouts()` vets every value that goes through it.
|
|
132
|
+
*/
|
|
133
|
+
get timeouts() {
|
|
134
|
+
return this.#timeouts;
|
|
135
|
+
}
|
|
72
136
|
get isDestroyed() {
|
|
73
137
|
return this.#isDestroyed;
|
|
74
138
|
}
|
|
@@ -80,6 +144,8 @@ class RemoteWorkerEnv {
|
|
|
80
144
|
* `catch()` — otherwise a worker failure surfaces as an unhandled rejection.
|
|
81
145
|
*
|
|
82
146
|
* @throws {WorkerFailedError} if the worker fails before or after that happens
|
|
147
|
+
* @throws {WorkerDestroyedError} once the environment has been torn down — including every
|
|
148
|
+
* read after a load that had already succeeded, because there is no environment left to hand out
|
|
83
149
|
*/
|
|
84
150
|
get workerLoaded() {
|
|
85
151
|
const { signal } = this.#workerFailure;
|
|
@@ -106,11 +172,8 @@ class RemoteWorkerEnv {
|
|
|
106
172
|
async start() {
|
|
107
173
|
const { signal } = this.#workerFailure;
|
|
108
174
|
if (signal.aborted) throw signal.reason;
|
|
109
|
-
if (this.#isDestroyed) throw new WorkerDestroyedError();
|
|
110
175
|
if (this.#worker) {
|
|
111
|
-
|
|
112
|
-
this.logger.warn("already started");
|
|
113
|
-
}
|
|
176
|
+
this.logger.warn("already started");
|
|
114
177
|
return this.workerLoaded.then(() => {
|
|
115
178
|
if (this.isDestroyed) {
|
|
116
179
|
throw new WorkerDestroyedError();
|
|
@@ -118,22 +181,23 @@ class RemoteWorkerEnv {
|
|
|
118
181
|
});
|
|
119
182
|
}
|
|
120
183
|
const worker = this.#worker = createWorker();
|
|
121
|
-
worker.addEventListener("error", this.onWorkerError
|
|
122
|
-
worker.addEventListener("messageerror", this.onWorkerMessageError
|
|
184
|
+
worker.addEventListener("error", this.onWorkerError);
|
|
185
|
+
worker.addEventListener("messageerror", this.onWorkerMessageError);
|
|
123
186
|
this.configureConsoleLogger(worker);
|
|
124
187
|
try {
|
|
125
|
-
await waitForMessageOfType(worker, Loaded,
|
|
188
|
+
await waitForMessageOfType(worker, Loaded, this.timeouts.loadTimeout, void 0, signal);
|
|
126
189
|
if (this.isDestroyed) {
|
|
127
|
-
throw new WorkerDestroyedError();
|
|
190
|
+
throw signal.aborted ? signal.reason : new WorkerDestroyedError();
|
|
128
191
|
}
|
|
129
|
-
worker.addEventListener("message", this.onMessageFromWorker
|
|
192
|
+
worker.addEventListener("message", this.onMessageFromWorker);
|
|
130
193
|
queueMicrotask(() => {
|
|
131
|
-
|
|
194
|
+
this.announceLoaded();
|
|
132
195
|
});
|
|
133
196
|
} catch (error) {
|
|
134
197
|
if (error !== signal.reason) {
|
|
135
198
|
this.logger.error("failed to start", error);
|
|
136
199
|
}
|
|
200
|
+
this.stopListeningTo(worker);
|
|
137
201
|
this.#worker = void 0;
|
|
138
202
|
if (!this.#isDestroyed) {
|
|
139
203
|
worker.terminate();
|
|
@@ -146,27 +210,32 @@ class RemoteWorkerEnv {
|
|
|
146
210
|
if (signal.aborted) return Promise.reject(signal.reason);
|
|
147
211
|
const worker = this.#worker;
|
|
148
212
|
if (worker == null) return Promise.reject(new WorkerDestroyedError());
|
|
149
|
-
const transferables =
|
|
150
|
-
const message = { type: ChangeTrail, changeTrail };
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
message.serial = serial;
|
|
154
|
-
}
|
|
155
|
-
worker.postMessage(message, transferables ?? []);
|
|
156
|
-
if (waitForConfirmation) {
|
|
157
|
-
return waitForMessageOfType(
|
|
158
|
-
worker,
|
|
159
|
-
AppliedChangeTrail,
|
|
160
|
-
WorkerChangeTrailTimeout,
|
|
161
|
-
(data) => {
|
|
162
|
-
if (data.error) throw data.error;
|
|
163
|
-
return data.serial === serial;
|
|
164
|
-
},
|
|
165
|
-
signal
|
|
166
|
-
);
|
|
167
|
-
} else {
|
|
213
|
+
const { changeTrail: outbound, transferables } = splitTransferables(changeTrail);
|
|
214
|
+
const message = { type: ChangeTrail, changeTrail: outbound };
|
|
215
|
+
if (!waitForConfirmation) {
|
|
216
|
+
worker.postMessage(message, transferables ?? []);
|
|
168
217
|
return Promise.resolve();
|
|
169
218
|
}
|
|
219
|
+
const serial = ++this.#changeTrailSerial;
|
|
220
|
+
message.serial = serial;
|
|
221
|
+
worker.postMessage(message, transferables ?? []);
|
|
222
|
+
return waitForMessageOfType(
|
|
223
|
+
worker,
|
|
224
|
+
AppliedChangeTrail,
|
|
225
|
+
this.timeouts.changeTrailTimeout,
|
|
226
|
+
(data) => {
|
|
227
|
+
if (data.serial !== serial) return false;
|
|
228
|
+
if (data.error) {
|
|
229
|
+
const reason = new WorkerReportedError(data.errorName, data.error);
|
|
230
|
+
if (typeof data.appliedCount === "number") {
|
|
231
|
+
throw new ChangeTrailRefusedError(data.appliedCount, changeTrail.length, { cause: reason });
|
|
232
|
+
}
|
|
233
|
+
throw reason;
|
|
234
|
+
}
|
|
235
|
+
return true;
|
|
236
|
+
},
|
|
237
|
+
signal
|
|
238
|
+
);
|
|
170
239
|
}
|
|
171
240
|
importScript(url) {
|
|
172
241
|
const { signal } = this.#workerFailure;
|
|
@@ -178,30 +247,72 @@ class RemoteWorkerEnv {
|
|
|
178
247
|
return waitForMessageOfType(
|
|
179
248
|
worker,
|
|
180
249
|
ImportedModule,
|
|
181
|
-
|
|
250
|
+
this.timeouts.configureTimeout,
|
|
182
251
|
(data) => {
|
|
183
|
-
if (data.
|
|
184
|
-
|
|
252
|
+
if (data.url !== url) return false;
|
|
253
|
+
if (data.error) throw new WorkerReportedError(data.errorName, data.error);
|
|
254
|
+
return true;
|
|
185
255
|
},
|
|
186
256
|
signal
|
|
187
257
|
);
|
|
188
258
|
}
|
|
259
|
+
/**
|
|
260
|
+
* Asks the worker for a snapshot of its Kernel. The request travels as an `Inspect` message
|
|
261
|
+
* under a serial of its own, and the `Inspected` answer that carries the same serial settles
|
|
262
|
+
* the call: with the snapshot, or with a `WorkerReportedError` rebuilt from the failure the
|
|
263
|
+
* worker described. An answer that stays out past `inspectTimeout` rejects with a
|
|
264
|
+
* `WorkerTimeoutError`; a worker that failed or an environment that was torn down rejects right
|
|
265
|
+
* away, before or while the answer is awaited.
|
|
266
|
+
*
|
|
267
|
+
* The caller's `signal` ends the wait with its own reason. The worker is not told: an answer
|
|
268
|
+
* that arrives afterwards carries a serial nobody waits for any more and is discarded like any
|
|
269
|
+
* other unmatched message.
|
|
270
|
+
*
|
|
271
|
+
* The message runs through the same queue as the change trails, so the snapshot reflects every
|
|
272
|
+
* trail posted before this call and none posted after it.
|
|
273
|
+
*/
|
|
274
|
+
inspect(request = {}, signal) {
|
|
275
|
+
const { signal: failure } = this.#workerFailure;
|
|
276
|
+
if (failure.aborted) return Promise.reject(failure.reason);
|
|
277
|
+
if (signal?.aborted) return Promise.reject(signal.reason);
|
|
278
|
+
const worker = this.#worker;
|
|
279
|
+
if (worker == null) return Promise.reject(new WorkerDestroyedError());
|
|
280
|
+
const serial = ++this.#inspectSerial;
|
|
281
|
+
const message = { type: Inspect, serial, request };
|
|
282
|
+
worker.postMessage(message);
|
|
283
|
+
let snapshot;
|
|
284
|
+
return waitForMessageOfType(
|
|
285
|
+
worker,
|
|
286
|
+
Inspected,
|
|
287
|
+
this.timeouts.inspectTimeout,
|
|
288
|
+
(data) => {
|
|
289
|
+
if (data.serial !== serial) return false;
|
|
290
|
+
if (data.error) throw new WorkerReportedError(data.errorName, data.error);
|
|
291
|
+
snapshot = data.snapshot;
|
|
292
|
+
return true;
|
|
293
|
+
},
|
|
294
|
+
signal === void 0 ? failure : AbortSignal.any([failure, signal])
|
|
295
|
+
).then(() => {
|
|
296
|
+
if (snapshot === void 0) {
|
|
297
|
+
throw new WorkerReportedError(void 0, "the worker answered the inspection without a snapshot");
|
|
298
|
+
}
|
|
299
|
+
return snapshot;
|
|
300
|
+
});
|
|
301
|
+
}
|
|
189
302
|
destroy() {
|
|
190
|
-
|
|
303
|
+
this.#isDestroyed = true;
|
|
191
304
|
const worker = this.#worker;
|
|
192
305
|
this.#worker = void 0;
|
|
193
|
-
this.#
|
|
306
|
+
this.#workerFailure.abort(new WorkerDestroyedError());
|
|
307
|
+
if (worker == null) return;
|
|
308
|
+
this.stopListeningTo(worker);
|
|
194
309
|
worker.postMessage({ type: Destroy });
|
|
195
|
-
waitForMessageOfType(worker, Destroyed,
|
|
310
|
+
waitForMessageOfType(worker, Destroyed, this.timeouts.destroyTimeout).catch((error) => {
|
|
311
|
+
this.logger.warn("the worker did not acknowledge the teardown", error);
|
|
312
|
+
}).finally(() => {
|
|
196
313
|
worker.terminate();
|
|
197
314
|
});
|
|
198
315
|
}
|
|
199
|
-
onWorkerError(event) {
|
|
200
|
-
this.handleWorkerFailure("error", event, event.message || "the worker reported an error");
|
|
201
|
-
}
|
|
202
|
-
onWorkerMessageError(event) {
|
|
203
|
-
this.handleWorkerFailure("messageerror", event, "the worker sent a message that could not be deserialized");
|
|
204
|
-
}
|
|
205
316
|
handleWorkerFailure(type, event, message) {
|
|
206
317
|
if (this.#isDestroyed) return;
|
|
207
318
|
this.#isDestroyed = true;
|
|
@@ -211,6 +322,7 @@ class RemoteWorkerEnv {
|
|
|
211
322
|
this.logger.error(message, event);
|
|
212
323
|
const worker = this.#worker;
|
|
213
324
|
this.#worker = void 0;
|
|
325
|
+
if (worker != null) this.stopListeningTo(worker);
|
|
214
326
|
this.#workerFailure.abort(reason);
|
|
215
327
|
worker?.terminate();
|
|
216
328
|
try {
|
|
@@ -218,27 +330,59 @@ class RemoteWorkerEnv {
|
|
|
218
330
|
} catch (error) {
|
|
219
331
|
this.logger.error("the proxy-failed callback threw", error);
|
|
220
332
|
}
|
|
221
|
-
|
|
222
|
-
env: this,
|
|
223
|
-
type,
|
|
224
|
-
message,
|
|
225
|
-
reason,
|
|
226
|
-
event
|
|
227
|
-
});
|
|
333
|
+
this.announceFailure({ env: this, type, message, reason, event });
|
|
228
334
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
335
|
+
/**
|
|
336
|
+
* Announces the completed handshake to the consumers.
|
|
337
|
+
*
|
|
338
|
+
* `emitStrict()` rather than `emit()`, and the retain policy is what decides it. `workerLoaded`
|
|
339
|
+
* reads the retained value, and eventize writes that value only once the dispatch has run
|
|
340
|
+
* through: under the plain dispatch a single listener that throws would take the replay for
|
|
341
|
+
* every later subscriber with it, and every later read of `workerLoaded` would wait for a
|
|
342
|
+
* failure or a teardown instead of resolving. The guarded dispatch serves every listener and
|
|
343
|
+
* writes the retained value, because the event was delivered.
|
|
344
|
+
*
|
|
345
|
+
* What the listeners threw arrives here afterwards -- one of them unchanged, several as an
|
|
346
|
+
* `AggregateError` in dispatch order -- and is reported. It goes no further: this runs from a
|
|
347
|
+
* microtask, where a throw has no caller left to reach and would surface as an unhandled error.
|
|
348
|
+
*/
|
|
349
|
+
announceLoaded() {
|
|
350
|
+
try {
|
|
351
|
+
emitStrict(this, RemoteWorkerEnv.WorkerLoaded, this);
|
|
352
|
+
} catch (error) {
|
|
353
|
+
this.logger.error("a workerLoaded listener threw", error);
|
|
234
354
|
}
|
|
235
355
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
356
|
+
/**
|
|
357
|
+
* Announces the failure to the consumers. The same guarded dispatch as
|
|
358
|
+
* {@link RemoteWorkerEnv.announceLoaded}, for the same reason: `WorkerFailed` is documented as
|
|
359
|
+
* retained, and a consumer that subscribes only after the failure has to be able to hear about
|
|
360
|
+
* it. Every listener is served, the retained value is written, and whatever was thrown is
|
|
361
|
+
* reported here and reaches no caller.
|
|
362
|
+
*/
|
|
363
|
+
announceFailure(payload) {
|
|
364
|
+
try {
|
|
365
|
+
emitStrict(this, RemoteWorkerEnv.WorkerFailed, payload);
|
|
366
|
+
} catch (error) {
|
|
367
|
+
this.logger.error("a workerFailed listener threw", error);
|
|
241
368
|
}
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Takes every listener of this environment off a worker. Whoever registered them takes them
|
|
372
|
+
* off again -- between the teardown and the `terminate()` that ends it the worker stays
|
|
373
|
+
* alive, and through its listeners it keeps this environment and everything it references
|
|
374
|
+
* reachable for exactly that long.
|
|
375
|
+
*/
|
|
376
|
+
stopListeningTo(worker) {
|
|
377
|
+
worker.removeEventListener("error", this.onWorkerError);
|
|
378
|
+
worker.removeEventListener("messageerror", this.onWorkerMessageError);
|
|
379
|
+
worker.removeEventListener("message", this.onMessageFromWorker);
|
|
380
|
+
}
|
|
381
|
+
configureConsoleLogger(worker) {
|
|
382
|
+
const configKey = ["RemoteWorkerEnv", "workerConfig"];
|
|
383
|
+
const storageKey = consoleLoggerConfigKey(configKey);
|
|
384
|
+
const workerConfig = this.readWorkerConfig(configKey, storageKey);
|
|
385
|
+
this.logger.info("load console-logger worker config", { storageKey, workerConfig });
|
|
242
386
|
worker.postMessage({
|
|
243
387
|
type: CONSOLE_LOGGER,
|
|
244
388
|
config: {
|
|
@@ -249,10 +393,33 @@ class RemoteWorkerEnv {
|
|
|
249
393
|
}
|
|
250
394
|
});
|
|
251
395
|
}
|
|
396
|
+
/**
|
|
397
|
+
* The console-logger config for the worker, read from the storage key this environment
|
|
398
|
+
* announces. The key is a diagnostic switch, set by hand and sharing its namespace with
|
|
399
|
+
* everything else on this origin, so its content decides nothing about whether the worker
|
|
400
|
+
* comes up: anything that is not a plain JSON object counts as no config at all, exactly
|
|
401
|
+
* like an absent key.
|
|
402
|
+
*/
|
|
403
|
+
readWorkerConfig(configKey, storageKey) {
|
|
404
|
+
const stored = loadConsoleLoggerConfig(configKey, "{}");
|
|
405
|
+
let parsed;
|
|
406
|
+
try {
|
|
407
|
+
parsed = JSON.parse(stored);
|
|
408
|
+
} catch (error) {
|
|
409
|
+
this.logger.error(`ignoring the unreadable console-logger worker config at "${storageKey}"`, stored, error);
|
|
410
|
+
return {};
|
|
411
|
+
}
|
|
412
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
413
|
+
this.logger.error(`ignoring the console-logger worker config at "${storageKey}": expected a JSON object`, stored);
|
|
414
|
+
return {};
|
|
415
|
+
}
|
|
416
|
+
return parsed;
|
|
417
|
+
}
|
|
252
418
|
}
|
|
253
419
|
export {
|
|
254
420
|
RemoteWorkerEnv,
|
|
255
421
|
WorkerDestroyedError,
|
|
256
|
-
WorkerFailedError
|
|
422
|
+
WorkerFailedError,
|
|
423
|
+
WorkerReportedError
|
|
257
424
|
};
|
|
258
425
|
//# sourceMappingURL=RemoteWorkerEnv.js.map
|