@spearwolf/shadow-objects 0.32.0 → 0.33.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 +64 -0
- package/README.md +49 -13
- package/bundle.js +7 -7
- package/package.json +2 -2
- package/src/elements/ShaeEntElement.d.ts +4 -4
- package/src/elements/ShaeEntElement.d.ts.map +1 -1
- package/src/elements/ShaeEntElement.js +4 -5
- package/src/elements/ShaeEntElement.js.map +2 -2
- package/src/elements/ShaePropElement.d.ts +5 -5
- package/src/elements/ShaePropElement.d.ts.map +1 -1
- package/src/elements/ShaePropElement.js +2 -2
- package/src/elements/ShaePropElement.js.map +2 -2
- package/src/elements/ShaeWorkerElement.d.ts.map +1 -1
- package/src/elements/ShaeWorkerElement.js +31 -6
- package/src/elements/ShaeWorkerElement.js.map +2 -2
- package/src/in-the-dark/Kernel.d.ts +5 -0
- package/src/in-the-dark/Kernel.d.ts.map +1 -1
- package/src/in-the-dark/Kernel.js +49 -24
- package/src/in-the-dark/Kernel.js.map +2 -2
- package/src/in-the-dark/Registry.d.ts +1 -1
- package/src/in-the-dark/Registry.d.ts.map +1 -1
- package/src/in-the-dark/Registry.js +24 -20
- package/src/in-the-dark/Registry.js.map +2 -2
- package/src/in-the-dark/ShadowObject.d.ts +1 -1
- package/src/in-the-dark/ShadowObject.d.ts.map +1 -1
- package/src/in-the-dark/ShadowObject.js +2 -2
- package/src/in-the-dark/ShadowObject.js.map +2 -2
- package/src/in-the-dark/SignalsPath.d.ts.map +1 -1
- package/src/in-the-dark/SignalsPath.js.map +2 -2
- package/src/in-the-dark/importModule.js +3 -3
- package/src/in-the-dark/importModule.js.map +2 -2
- package/src/types.d.ts +4 -4
- package/src/types.d.ts.map +1 -1
- package/src/utils/ConsoleLogger.d.ts.map +1 -1
- package/src/utils/ConsoleLogger.js +3 -2
- package/src/utils/ConsoleLogger.js.map +2 -2
- package/src/utils/FrameLoop.d.ts +1 -1
- package/src/utils/FrameLoop.d.ts.map +1 -1
- package/src/utils/FrameLoop.js +0 -2
- package/src/utils/FrameLoop.js.map +2 -2
- package/src/utils/attr-utils.d.ts.map +1 -1
- package/src/utils/attr-utils.js +1 -1
- package/src/utils/attr-utils.js.map +2 -2
- package/src/utils/generateUUID.d.ts +1 -1
- package/src/utils/generateUUID.d.ts.map +1 -1
- package/src/utils/props-utils.d.ts +1 -1
- package/src/utils/props-utils.d.ts.map +1 -1
- package/src/utils/waitForMessageOfType.d.ts +5 -1
- package/src/utils/waitForMessageOfType.d.ts.map +1 -1
- package/src/utils/waitForMessageOfType.js +12 -2
- package/src/utils/waitForMessageOfType.js.map +2 -2
- package/src/view/ComponentChanges.d.ts +4 -1
- package/src/view/ComponentChanges.d.ts.map +1 -1
- package/src/view/ComponentChanges.js +20 -6
- package/src/view/ComponentChanges.js.map +2 -2
- package/src/view/ComponentContext.d.ts +43 -1
- package/src/view/ComponentContext.d.ts.map +1 -1
- package/src/view/ComponentContext.js +123 -47
- package/src/view/ComponentContext.js.map +2 -2
- package/src/view/ComponentMemory.js +3 -1
- package/src/view/ComponentMemory.js.map +2 -2
- package/src/view/IShadowObjectEnvProxy.d.ts +6 -0
- package/src/view/IShadowObjectEnvProxy.d.ts.map +1 -1
- package/src/view/LocalShadowObjectEnv.d.ts +1 -1
- package/src/view/LocalShadowObjectEnv.d.ts.map +1 -1
- package/src/view/LocalShadowObjectEnv.js +11 -6
- package/src/view/LocalShadowObjectEnv.js.map +2 -2
- package/src/view/RemoteWorkerEnv.d.ts +42 -0
- package/src/view/RemoteWorkerEnv.d.ts.map +1 -1
- package/src/view/RemoteWorkerEnv.js +130 -18
- package/src/view/RemoteWorkerEnv.js.map +2 -2
- package/src/view/ShadowEnv.d.ts +25 -1
- package/src/view/ShadowEnv.d.ts.map +1 -1
- package/src/view/ShadowEnv.js +103 -29
- package/src/view/ShadowEnv.js.map +2 -2
- package/src/view/ViewComponent.d.ts +22 -1
- package/src/view/ViewComponent.d.ts.map +1 -1
- package/src/view/ViewComponent.js +66 -22
- package/src/view/ViewComponent.js.map +2 -2
- package/src/worker/MessageRouter.d.ts.map +1 -1
- package/src/worker/MessageRouter.js +7 -5
- package/src/worker/MessageRouter.js.map +2 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/view/LocalShadowObjectEnv.ts"],
|
|
4
|
-
"sourcesContent": ["import {on} from '@spearwolf/eventize';\nimport {MessageToView, ShadowObjectsExport} from '../constants.js';\nimport {importModule} from '../in-the-dark/importModule.js';\nimport {Kernel, type MessageToViewEvent} from '../in-the-dark/Kernel.js';\nimport
|
|
5
|
-
"mappings": "AAAA,SAAQ,UAAS;AACjB,SAAQ,eAAe,2BAA0B;AACjD,SAAQ,oBAAmB;AAC3B,SAAQ,cAAsC;
|
|
4
|
+
"sourcesContent": ["import {on} from '@spearwolf/eventize';\nimport {MessageToView, ShadowObjectsExport} from '../constants.js';\nimport {importModule} from '../in-the-dark/importModule.js';\nimport {Kernel, type MessageToViewEvent} from '../in-the-dark/Kernel.js';\nimport {Registry} from '../in-the-dark/Registry.js';\nimport type {ChangeTrailType, ShadowObjectsModule, SyncEvent} from '../types.js';\nimport {toUrlString} from '../utils/toUrlString.js';\nimport {cloneChangeTrail} from './cloneChangeTrail.js';\nimport type {IShadowObjectEnvProxy} from './IShadowObjectEnvProxy.js';\n\nexport class LocalShadowObjectEnv implements IShadowObjectEnvProxy {\n #importedModules: Set<ShadowObjectsModule> = new Set();\n readonly #usesDefaultRegistry: boolean;\n\n readonly kernel: Kernel;\n\n get registry(): Registry {\n return this.kernel.registry;\n }\n\n readonly isLocalEnv = true;\n\n disableStructuredClone = false;\n\n constructor(registry?: Registry) {\n this.kernel = new Kernel(registry);\n // The default registry is shared with every other environment in this thread and holds\n // everything `@ShadowObject` and `shadowObjects.define()` register without a registry of\n // their own, so `destroy()` must not clear it. This check only tells the default registry\n // apart from any other instance \u2014 a custom registry handed to more than one environment is\n // cleared by the first one of them to be destroyed, same as the default registry would be\n // without this guard.\n this.#usesDefaultRegistry = this.kernel.registry === Registry.get();\n\n on(this.kernel, MessageToView, (message: MessageToViewEvent) => {\n const onMessageToView = (this as IShadowObjectEnvProxy).onMessageToView;\n if (onMessageToView == null) return;\n\n const {type, uuid, traverseChildren} = message;\n const data = structuredClone(message.data, {transfer: message.transferables});\n // call() keeps the binding a plain method call would have given it: an outside\n // implementation of the proxy interface need not hand over a bound callback\n onMessageToView.call(this, {type, uuid, data, traverseChildren});\n });\n }\n\n start(): Promise<void> {\n return Promise.resolve();\n }\n\n applyChangeTrail(data: ChangeTrailType, _waitForConfirmation: boolean): Promise<void> {\n const syncData: SyncEvent = {changeTrail: this.disableStructuredClone ? data : cloneChangeTrail(data)};\n let result: Promise<void>;\n try {\n this.kernel.run(syncData);\n result = Promise.resolve();\n } catch (error) {\n result = Promise.reject(error);\n }\n return result;\n }\n\n async importScript(url: URL | string): Promise<void> {\n const module = await import(/* @vite-ignore */ toUrlString(url));\n if (module[ShadowObjectsExport]) {\n await this.importModule(module[ShadowObjectsExport]);\n }\n }\n\n async importModule(module: ShadowObjectsModule): Promise<void> {\n return importModule(this.kernel, module, this.#importedModules);\n }\n\n destroy(): void {\n this.kernel.destroy();\n if (!this.#usesDefaultRegistry) {\n this.registry.clear();\n }\n this.#importedModules.clear();\n }\n}"],
|
|
5
|
+
"mappings": "AAAA,SAAQ,UAAS;AACjB,SAAQ,eAAe,2BAA0B;AACjD,SAAQ,oBAAmB;AAC3B,SAAQ,cAAsC;AAC9C,SAAQ,gBAAe;AAEvB,SAAQ,mBAAkB;AAC1B,SAAQ,wBAAuB;AAGxB,MAAM,qBAAsD;AAAA,EAcjE,YAAY,UAAqB;AAbjC,4BAA6C,oBAAI,IAAI;AASrD,SAAS,aAAa;AAEtB,kCAAyB;AAGvB,SAAK,SAAS,IAAI,OAAO,QAAQ;AAOjC,SAAK,uBAAuB,KAAK,OAAO,aAAa,SAAS,IAAI;AAElE,OAAG,KAAK,QAAQ,eAAe,CAAC,YAAgC;AAC9D,YAAM,kBAAmB,KAA+B;AACxD,UAAI,mBAAmB,KAAM;AAE7B,YAAM,EAAC,MAAM,MAAM,iBAAgB,IAAI;AACvC,YAAM,OAAO,gBAAgB,QAAQ,MAAM,EAAC,UAAU,QAAQ,cAAa,CAAC;AAG5E,sBAAgB,KAAK,MAAM,EAAC,MAAM,MAAM,MAAM,iBAAgB,CAAC;AAAA,IACjE,CAAC;AAAA,EACH;AAAA,EAjCA;AAAA,EACS;AAAA,EAIT,IAAI,WAAqB;AACvB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA,EA4BA,QAAuB;AACrB,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EAEA,iBAAiB,MAAuB,sBAA8C;AACpF,UAAM,WAAsB,EAAC,aAAa,KAAK,yBAAyB,OAAO,iBAAiB,IAAI,EAAC;AACrG,QAAI;AACJ,QAAI;AACF,WAAK,OAAO,IAAI,QAAQ;AACxB,eAAS,QAAQ,QAAQ;AAAA,IAC3B,SAAS,OAAO;AACd,eAAS,QAAQ,OAAO,KAAK;AAAA,IAC/B;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,aAAa,KAAkC;AACnD,UAAM,SAAS,MAAM;AAAA;AAAA,MAA0B,YAAY,GAAG;AAAA;AAC9D,QAAI,OAAO,mBAAmB,GAAG;AAC/B,YAAM,KAAK,aAAa,OAAO,mBAAmB,CAAC;AAAA,IACrD;AAAA,EACF;AAAA,EAEA,MAAM,aAAa,QAA4C;AAC7D,WAAO,aAAa,KAAK,QAAQ,QAAQ,KAAK,gBAAgB;AAAA,EAChE;AAAA,EAEA,UAAgB;AACd,SAAK,OAAO,QAAQ;AACpB,QAAI,CAAC,KAAK,sBAAsB;AAC9B,WAAK,SAAS,MAAM;AAAA,IACtB;AACA,SAAK,iBAAiB,MAAM;AAAA,EAC9B;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,17 +1,59 @@
|
|
|
1
1
|
import type { ChangeTrailType } from '../types.js';
|
|
2
2
|
import { ConsoleLogger } from '../utils/ConsoleLogger.js';
|
|
3
3
|
import type { IShadowObjectEnvProxy } from './IShadowObjectEnvProxy.js';
|
|
4
|
+
/**
|
|
5
|
+
* The reason every pending and every later worker request is rejected with
|
|
6
|
+
* once the worker has failed.
|
|
7
|
+
*/
|
|
8
|
+
export declare class WorkerFailedError extends Error {
|
|
9
|
+
/** `'error'` when the worker itself threw, `'messageerror'` when it sent something that could not be deserialized. */
|
|
10
|
+
readonly type: 'error' | 'messageerror';
|
|
11
|
+
constructor(type: 'error' | 'messageerror', message: string, options?: ErrorOptions);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The reason a request is rejected with once the environment has been torn down
|
|
15
|
+
* with {@link RemoteWorkerEnv.destroy}. The worker is gone; no reply can arrive.
|
|
16
|
+
*/
|
|
17
|
+
export declare class WorkerDestroyedError extends Error {
|
|
18
|
+
constructor(message?: string);
|
|
19
|
+
}
|
|
20
|
+
/** What {@link RemoteWorkerEnv.WorkerFailed} carries. */
|
|
21
|
+
export interface WorkerFailedEvent {
|
|
22
|
+
/** the environment whose worker failed */
|
|
23
|
+
env: RemoteWorkerEnv;
|
|
24
|
+
/** what the worker reported */
|
|
25
|
+
type: 'error' | 'messageerror';
|
|
26
|
+
/** a readable description of the failure */
|
|
27
|
+
message: string;
|
|
28
|
+
/** the error every pending and every later request is rejected with */
|
|
29
|
+
reason: WorkerFailedError;
|
|
30
|
+
/** the worker event the failure was read from */
|
|
31
|
+
event: ErrorEvent | MessageEvent;
|
|
32
|
+
}
|
|
4
33
|
export declare class RemoteWorkerEnv implements IShadowObjectEnvProxy {
|
|
5
34
|
#private;
|
|
6
35
|
static WorkerLoaded: string;
|
|
36
|
+
static WorkerFailed: string;
|
|
7
37
|
readonly logger: ConsoleLogger;
|
|
8
38
|
get isDestroyed(): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Resolves once the worker is up.
|
|
41
|
+
*
|
|
42
|
+
* Every read hands out a promise that can reject, so a caller that only wants to
|
|
43
|
+
* kick the environment off and never awaits the result should still attach a
|
|
44
|
+
* `catch()` — otherwise a worker failure surfaces as an unhandled rejection.
|
|
45
|
+
*
|
|
46
|
+
* @throws {WorkerFailedError} if the worker fails before or after that happens
|
|
47
|
+
*/
|
|
9
48
|
get workerLoaded(): Promise<RemoteWorkerEnv>;
|
|
10
49
|
constructor();
|
|
11
50
|
start(): Promise<void>;
|
|
12
51
|
applyChangeTrail(changeTrail: ChangeTrailType, waitForConfirmation: boolean): Promise<void>;
|
|
13
52
|
importScript(url: URL | string): Promise<void>;
|
|
14
53
|
destroy(): void;
|
|
54
|
+
private onWorkerError;
|
|
55
|
+
private onWorkerMessageError;
|
|
56
|
+
private handleWorkerFailure;
|
|
15
57
|
private onMessageFromWorker;
|
|
16
58
|
private configureConsoleLogger;
|
|
17
59
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RemoteWorkerEnv.d.ts","sourceRoot":"","sources":["../../../src/view/RemoteWorkerEnv.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAA0B,eAAe,EAAyC,MAAM,aAAa,CAAC;AAClH,OAAO,EAAiB,aAAa,EAAC,MAAM,2BAA2B,CAAC;AAGxE,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,4BAA4B,CAAC;AAqBtE,qBAAa,eAAgB,YAAW,qBAAqB;;IAC3D,MAAM,CAAC,YAAY,SAAkB;
|
|
1
|
+
{"version":3,"file":"RemoteWorkerEnv.d.ts","sourceRoot":"","sources":["../../../src/view/RemoteWorkerEnv.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAA0B,eAAe,EAAyC,MAAM,aAAa,CAAC;AAClH,OAAO,EAAiB,aAAa,EAAC,MAAM,2BAA2B,CAAC;AAGxE,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,4BAA4B,CAAC;AAqBtE;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,sHAAsH;IACtH,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAAC;gBAE5B,IAAI,EAAE,OAAO,GAAG,cAAc,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;CAKpF;AAED;;;GAGG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,OAAO,SAA8C;CAIlE;AAED,yDAAyD;AACzD,MAAM,WAAW,iBAAiB;IAChC,0CAA0C;IAC1C,GAAG,EAAE,eAAe,CAAC;IACrB,+BAA+B;IAC/B,IAAI,EAAE,OAAO,GAAG,cAAc,CAAC;IAC/B,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,MAAM,EAAE,iBAAiB,CAAC;IAC1B,iDAAiD;IACjD,KAAK,EAAE,UAAU,GAAG,YAAY,CAAC;CAClC;AAED,qBAAa,eAAgB,YAAW,qBAAqB;;IAC3D,MAAM,CAAC,YAAY,SAAkB;IACrC,MAAM,CAAC,YAAY,SAAkB;IAYrC,QAAQ,CAAC,MAAM,gBAAwC;IAEvD,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED;;;;;;;;OAQG;IACH,IAAI,YAAY,IAAI,OAAO,CAAC,eAAe,CAAC,CA4B3C;;IAQK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAiE5B,gBAAgB,CAAC,WAAW,EAAE,eAAe,EAAE,mBAAmB,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAiC3F,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB9C,OAAO,IAAI,IAAI;IAef,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,mBAAmB;IAsC3B,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,sBAAsB;CAkB/B"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { emit,
|
|
1
|
+
import { emit, once, retain } from "@spearwolf/eventize";
|
|
2
2
|
import {
|
|
3
3
|
AppliedChangeTrail,
|
|
4
4
|
ChangeTrail,
|
|
@@ -33,78 +33,158 @@ const removeTransferables = (changeTrail) => {
|
|
|
33
33
|
}
|
|
34
34
|
return transferables;
|
|
35
35
|
};
|
|
36
|
+
class WorkerFailedError extends Error {
|
|
37
|
+
constructor(type, message, options) {
|
|
38
|
+
super(message, options);
|
|
39
|
+
this.name = "WorkerFailedError";
|
|
40
|
+
this.type = type;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
class WorkerDestroyedError extends Error {
|
|
44
|
+
constructor(message = "the worker environment has been destroyed") {
|
|
45
|
+
super(message);
|
|
46
|
+
this.name = "WorkerDestroyedError";
|
|
47
|
+
}
|
|
48
|
+
}
|
|
36
49
|
class RemoteWorkerEnv {
|
|
37
50
|
constructor() {
|
|
38
51
|
this.#isDestroyed = false;
|
|
39
52
|
this.#changeTrailSerial = 0;
|
|
53
|
+
/**
|
|
54
|
+
* Aborted exactly once, with the {@link WorkerFailedError} that describes the failure.
|
|
55
|
+
* It settles every request already waiting for a reply and turns away every later one.
|
|
56
|
+
*/
|
|
57
|
+
this.#workerFailure = new AbortController();
|
|
40
58
|
this.logger = new ConsoleLogger("RemoteWorkerEnv");
|
|
41
59
|
retain(this, RemoteWorkerEnv.WorkerLoaded);
|
|
60
|
+
retain(this, RemoteWorkerEnv.WorkerFailed);
|
|
42
61
|
}
|
|
43
62
|
static {
|
|
44
63
|
this.WorkerLoaded = "workerLoaded";
|
|
45
64
|
}
|
|
65
|
+
static {
|
|
66
|
+
this.WorkerFailed = "workerFailed";
|
|
67
|
+
}
|
|
46
68
|
#worker;
|
|
47
69
|
#isDestroyed;
|
|
48
70
|
#changeTrailSerial;
|
|
71
|
+
#workerFailure;
|
|
49
72
|
get isDestroyed() {
|
|
50
73
|
return this.#isDestroyed;
|
|
51
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Resolves once the worker is up.
|
|
77
|
+
*
|
|
78
|
+
* Every read hands out a promise that can reject, so a caller that only wants to
|
|
79
|
+
* kick the environment off and never awaits the result should still attach a
|
|
80
|
+
* `catch()` — otherwise a worker failure surfaces as an unhandled rejection.
|
|
81
|
+
*
|
|
82
|
+
* @throws {WorkerFailedError} if the worker fails before or after that happens
|
|
83
|
+
*/
|
|
52
84
|
get workerLoaded() {
|
|
53
|
-
|
|
85
|
+
const { signal } = this.#workerFailure;
|
|
86
|
+
if (signal.aborted) return Promise.reject(signal.reason);
|
|
87
|
+
return new Promise((resolve, reject) => {
|
|
88
|
+
let unsubscribeLoaded;
|
|
89
|
+
let settled = false;
|
|
90
|
+
const onFailure = () => {
|
|
91
|
+
if (settled) return;
|
|
92
|
+
settled = true;
|
|
93
|
+
unsubscribeLoaded?.();
|
|
94
|
+
reject(signal.reason);
|
|
95
|
+
};
|
|
96
|
+
unsubscribeLoaded = once(this, RemoteWorkerEnv.WorkerLoaded, (env) => {
|
|
97
|
+
if (settled) return;
|
|
98
|
+
settled = true;
|
|
99
|
+
signal.removeEventListener("abort", onFailure);
|
|
100
|
+
resolve(env);
|
|
101
|
+
});
|
|
102
|
+
if (settled) return;
|
|
103
|
+
signal.addEventListener("abort", onFailure, { once: true });
|
|
104
|
+
});
|
|
54
105
|
}
|
|
55
106
|
async start() {
|
|
107
|
+
const { signal } = this.#workerFailure;
|
|
108
|
+
if (signal.aborted) throw signal.reason;
|
|
109
|
+
if (this.#isDestroyed) throw new WorkerDestroyedError();
|
|
56
110
|
if (this.#worker) {
|
|
57
111
|
if (this.logger.isWarn) {
|
|
58
112
|
this.logger.warn("already started");
|
|
59
113
|
}
|
|
60
114
|
return this.workerLoaded.then(() => {
|
|
61
115
|
if (this.isDestroyed) {
|
|
62
|
-
throw
|
|
116
|
+
throw new WorkerDestroyedError();
|
|
63
117
|
}
|
|
64
|
-
return void 0;
|
|
65
118
|
});
|
|
66
119
|
}
|
|
67
120
|
const worker = this.#worker = createWorker();
|
|
121
|
+
worker.addEventListener("error", this.onWorkerError.bind(this));
|
|
122
|
+
worker.addEventListener("messageerror", this.onWorkerMessageError.bind(this));
|
|
68
123
|
this.configureConsoleLogger(worker);
|
|
69
124
|
try {
|
|
70
|
-
await waitForMessageOfType(worker, Loaded, WorkerLoadTimeout);
|
|
125
|
+
await waitForMessageOfType(worker, Loaded, WorkerLoadTimeout, void 0, signal);
|
|
71
126
|
if (this.isDestroyed) {
|
|
72
|
-
throw
|
|
127
|
+
throw new WorkerDestroyedError();
|
|
73
128
|
}
|
|
74
129
|
worker.addEventListener("message", this.onMessageFromWorker.bind(this));
|
|
75
130
|
queueMicrotask(() => {
|
|
76
131
|
emit(this, RemoteWorkerEnv.WorkerLoaded, this);
|
|
77
132
|
});
|
|
78
133
|
} catch (error) {
|
|
79
|
-
|
|
134
|
+
if (error !== signal.reason) {
|
|
135
|
+
this.logger.error("failed to start", error);
|
|
136
|
+
}
|
|
80
137
|
this.#worker = void 0;
|
|
138
|
+
if (!this.#isDestroyed) {
|
|
139
|
+
worker.terminate();
|
|
140
|
+
}
|
|
81
141
|
throw error;
|
|
82
142
|
}
|
|
83
143
|
}
|
|
84
144
|
applyChangeTrail(changeTrail, waitForConfirmation) {
|
|
145
|
+
const { signal } = this.#workerFailure;
|
|
146
|
+
if (signal.aborted) return Promise.reject(signal.reason);
|
|
147
|
+
const worker = this.#worker;
|
|
148
|
+
if (worker == null) return Promise.reject(new WorkerDestroyedError());
|
|
85
149
|
const transferables = removeTransferables(changeTrail);
|
|
86
150
|
const message = { type: ChangeTrail, changeTrail };
|
|
87
151
|
const serial = ++this.#changeTrailSerial;
|
|
88
152
|
if (waitForConfirmation) {
|
|
89
153
|
message.serial = serial;
|
|
90
154
|
}
|
|
91
|
-
|
|
155
|
+
worker.postMessage(message, transferables ?? []);
|
|
92
156
|
if (waitForConfirmation) {
|
|
93
|
-
return waitForMessageOfType(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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
|
+
);
|
|
97
167
|
} else {
|
|
98
168
|
return Promise.resolve();
|
|
99
169
|
}
|
|
100
170
|
}
|
|
101
171
|
importScript(url) {
|
|
172
|
+
const { signal } = this.#workerFailure;
|
|
173
|
+
if (signal.aborted) return Promise.reject(signal.reason);
|
|
174
|
+
const worker = this.#worker;
|
|
175
|
+
if (worker == null) return Promise.reject(new WorkerDestroyedError());
|
|
102
176
|
url = toUrlString(url);
|
|
103
|
-
|
|
104
|
-
return waitForMessageOfType(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
177
|
+
worker.postMessage({ type: Configure, importModule: url });
|
|
178
|
+
return waitForMessageOfType(
|
|
179
|
+
worker,
|
|
180
|
+
ImportedModule,
|
|
181
|
+
WorkerConfigureTimeout,
|
|
182
|
+
(data) => {
|
|
183
|
+
if (data.error) throw data.error;
|
|
184
|
+
return data.url === url;
|
|
185
|
+
},
|
|
186
|
+
signal
|
|
187
|
+
);
|
|
108
188
|
}
|
|
109
189
|
destroy() {
|
|
110
190
|
if (!this.#worker) return;
|
|
@@ -116,6 +196,36 @@ class RemoteWorkerEnv {
|
|
|
116
196
|
worker.terminate();
|
|
117
197
|
});
|
|
118
198
|
}
|
|
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
|
+
handleWorkerFailure(type, event, message) {
|
|
206
|
+
if (this.#isDestroyed) return;
|
|
207
|
+
this.#isDestroyed = true;
|
|
208
|
+
const reason = new WorkerFailedError(type, message, {
|
|
209
|
+
cause: type === "error" ? event.error ?? event : event
|
|
210
|
+
});
|
|
211
|
+
this.logger.error(message, event);
|
|
212
|
+
const worker = this.#worker;
|
|
213
|
+
this.#worker = void 0;
|
|
214
|
+
this.#workerFailure.abort(reason);
|
|
215
|
+
worker?.terminate();
|
|
216
|
+
try {
|
|
217
|
+
this.onProxyFailed?.(reason);
|
|
218
|
+
} catch (error) {
|
|
219
|
+
this.logger.error("the proxy-failed callback threw", error);
|
|
220
|
+
}
|
|
221
|
+
emit(this, RemoteWorkerEnv.WorkerFailed, {
|
|
222
|
+
env: this,
|
|
223
|
+
type,
|
|
224
|
+
message,
|
|
225
|
+
reason,
|
|
226
|
+
event
|
|
227
|
+
});
|
|
228
|
+
}
|
|
119
229
|
onMessageFromWorker(event) {
|
|
120
230
|
if (event.data?.type === MessageToView) {
|
|
121
231
|
this.onMessageToView?.(event.data.data);
|
|
@@ -141,6 +251,8 @@ class RemoteWorkerEnv {
|
|
|
141
251
|
}
|
|
142
252
|
}
|
|
143
253
|
export {
|
|
144
|
-
RemoteWorkerEnv
|
|
254
|
+
RemoteWorkerEnv,
|
|
255
|
+
WorkerDestroyedError,
|
|
256
|
+
WorkerFailedError
|
|
145
257
|
};
|
|
146
258
|
//# sourceMappingURL=RemoteWorkerEnv.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/view/RemoteWorkerEnv.ts"],
|
|
4
|
-
"sourcesContent": ["import {emit, onceAsync, retain} from '@spearwolf/eventize';\nimport {\n AppliedChangeTrail,\n ChangeTrail,\n Configure,\n Destroy,\n Destroyed,\n ImportedModule,\n Loaded,\n MessageToView,\n WorkerChangeTrailTimeout,\n WorkerConfigureTimeout,\n WorkerDestroyTimeout,\n WorkerLoadTimeout,\n} from '../constants.js';\nimport createWorker from '../create-worker.js';\nimport type {AppliedChangeTrailEvent, ChangeTrailType, ImportedModuleEvent, TransferablesType} from '../types.js';\nimport {CONSOLE_LOGGER, ConsoleLogger} from '../utils/ConsoleLogger.js';\nimport {toUrlString} from '../utils/toUrlString.js';\nimport {waitForMessageOfType} from '../utils/waitForMessageOfType.js';\nimport type {IShadowObjectEnvProxy} from './IShadowObjectEnvProxy.js';\n\nconst removeTransferables = (changeTrail: ChangeTrailType): TransferablesType | undefined => {\n let transferables: TransferablesType | undefined;\n\n if (changeTrail != null && Array.isArray(changeTrail)) {\n for (const changeItem of changeTrail) {\n if (changeItem.transferables) {\n if (!transferables) {\n transferables = changeItem.transferables;\n } else {\n transferables = [...transferables, ...changeItem.transferables];\n }\n delete changeItem.transferables;\n }\n }\n }\n\n return transferables;\n};\n\nexport class RemoteWorkerEnv implements IShadowObjectEnvProxy {\n static WorkerLoaded = 'workerLoaded';\n\n #worker?: Worker;\n #isDestroyed = false;\n #changeTrailSerial = 0;\n\n readonly logger = new ConsoleLogger('RemoteWorkerEnv');\n\n get isDestroyed(): boolean {\n return this.#isDestroyed;\n }\n\n get workerLoaded(): Promise<RemoteWorkerEnv> {\n return onceAsync<RemoteWorkerEnv>(this as RemoteWorkerEnv, RemoteWorkerEnv.WorkerLoaded);\n }\n\n constructor() {\n retain(this as RemoteWorkerEnv, RemoteWorkerEnv.WorkerLoaded);\n }\n\n async start(): Promise<void> {\n if (this.#worker) {\n if (this.logger.isWarn) {\n this.logger.warn('already started');\n }\n\n return this.workerLoaded.then((): void => {\n if (this.isDestroyed) {\n throw 'worker was destroyed';\n }\n return undefined;\n });\n }\n\n const worker = (this.#worker = createWorker());\n\n this.configureConsoleLogger(worker);\n\n try {\n await waitForMessageOfType(worker, Loaded, WorkerLoadTimeout);\n\n if (this.isDestroyed) {\n throw 'worker was destroyed';\n }\n\n worker.addEventListener('message', this.onMessageFromWorker.bind(this));\n\n queueMicrotask(() => {\n emit(this as RemoteWorkerEnv, RemoteWorkerEnv.WorkerLoaded, this);\n });\n } catch (error) {\n this.logger.error('failed to start', error);\n this.#worker = undefined;\n throw error;\n }\n }\n\n applyChangeTrail(changeTrail: ChangeTrailType, waitForConfirmation: boolean): Promise<void> {\n const transferables = removeTransferables(changeTrail);\n const message = {type: ChangeTrail, changeTrail} as any;\n\n const serial = ++this.#changeTrailSerial;\n if (waitForConfirmation) {\n message.serial = serial;\n }\n\n this.#worker.postMessage(message, transferables);\n\n if (waitForConfirmation) {\n return waitForMessageOfType(this.#worker, AppliedChangeTrail, WorkerChangeTrailTimeout, (data: AppliedChangeTrailEvent) => {\n if (data.error) throw data.error;\n return data.serial === serial;\n });\n } else {\n return Promise.resolve();\n }\n }\n\n importScript(url: URL | string): Promise<void> {\n url = toUrlString(url);\n this.#worker.postMessage({type: Configure, importModule: url});\n return waitForMessageOfType(this.#worker, ImportedModule, WorkerConfigureTimeout, (data: ImportedModuleEvent) => {\n if (data.error) throw data.error;\n return data.url === url;\n });\n }\n\n destroy(): void {\n if (!this.#worker) return;\n\n const worker = this.#worker;\n this.#worker = undefined;\n\n this.#isDestroyed = true;\n\n worker.postMessage({type: Destroy});\n\n waitForMessageOfType(worker, Destroyed, WorkerDestroyTimeout).finally(() => {\n worker.terminate();\n });\n }\n\n private onMessageFromWorker(event: MessageEvent) {\n if (event.data?.type === MessageToView) {\n (this as IShadowObjectEnvProxy).onMessageToView?.(event.data.data);\n } else if (this.logger.isDebug) {\n this.logger.debug('message from worker', event);\n }\n }\n\n private configureConsoleLogger(worker: Worker) {\n const workerConfigKey = `${CONSOLE_LOGGER}.RemoteWorkerEnv.workerConfig`;\n const workerConfig = JSON.parse(localStorage.getItem(workerConfigKey) ?? '{}');\n\n if (this.logger.isInfo) {\n this.logger.info('load console-logger worker config', {localStorageKey: workerConfigKey, workerConfig});\n }\n\n worker.postMessage({\n type: CONSOLE_LOGGER,\n config: {\n ...ConsoleLogger.sharedConfig,\n enable: this.logger.isEnabled,\n ...workerConfig,\n ...(ConsoleLogger.isEnabled ? {} : {enable: false}),\n },\n });\n }\n}"],
|
|
5
|
-
"mappings": "AAAA,SAAQ,MAAM,
|
|
4
|
+
"sourcesContent": ["import {emit, once, retain} from '@spearwolf/eventize';\nimport {\n AppliedChangeTrail,\n ChangeTrail,\n Configure,\n Destroy,\n Destroyed,\n ImportedModule,\n Loaded,\n MessageToView,\n WorkerChangeTrailTimeout,\n WorkerConfigureTimeout,\n WorkerDestroyTimeout,\n WorkerLoadTimeout,\n} from '../constants.js';\nimport createWorker from '../create-worker.js';\nimport type {AppliedChangeTrailEvent, ChangeTrailType, ImportedModuleEvent, TransferablesType} from '../types.js';\nimport {CONSOLE_LOGGER, ConsoleLogger} from '../utils/ConsoleLogger.js';\nimport {toUrlString} from '../utils/toUrlString.js';\nimport {waitForMessageOfType} from '../utils/waitForMessageOfType.js';\nimport type {IShadowObjectEnvProxy} from './IShadowObjectEnvProxy.js';\n\nconst removeTransferables = (changeTrail: ChangeTrailType): TransferablesType | undefined => {\n let transferables: TransferablesType | undefined;\n\n if (changeTrail != null && Array.isArray(changeTrail)) {\n for (const changeItem of changeTrail) {\n if (changeItem.transferables) {\n if (!transferables) {\n transferables = changeItem.transferables;\n } else {\n transferables = [...transferables, ...changeItem.transferables];\n }\n delete changeItem.transferables;\n }\n }\n }\n\n return transferables;\n};\n\n/**\n * The reason every pending and every later worker request is rejected with\n * once the worker has failed.\n */\nexport class WorkerFailedError extends Error {\n /** `'error'` when the worker itself threw, `'messageerror'` when it sent something that could not be deserialized. */\n readonly type: 'error' | 'messageerror';\n\n constructor(type: 'error' | 'messageerror', message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = 'WorkerFailedError';\n this.type = type;\n }\n}\n\n/**\n * The reason a request is rejected with once the environment has been torn down\n * with {@link RemoteWorkerEnv.destroy}. The worker is gone; no reply can arrive.\n */\nexport class WorkerDestroyedError extends Error {\n constructor(message = 'the worker environment has been destroyed') {\n super(message);\n this.name = 'WorkerDestroyedError';\n }\n}\n\n/** What {@link RemoteWorkerEnv.WorkerFailed} carries. */\nexport interface WorkerFailedEvent {\n /** the environment whose worker failed */\n env: RemoteWorkerEnv;\n /** what the worker reported */\n type: 'error' | 'messageerror';\n /** a readable description of the failure */\n message: string;\n /** the error every pending and every later request is rejected with */\n reason: WorkerFailedError;\n /** the worker event the failure was read from */\n event: ErrorEvent | MessageEvent;\n}\n\nexport class RemoteWorkerEnv implements IShadowObjectEnvProxy {\n static WorkerLoaded = 'workerLoaded';\n static WorkerFailed = 'workerFailed';\n\n #worker?: Worker;\n #isDestroyed = false;\n #changeTrailSerial = 0;\n\n /**\n * Aborted exactly once, with the {@link WorkerFailedError} that describes the failure.\n * It settles every request already waiting for a reply and turns away every later one.\n */\n readonly #workerFailure = new AbortController();\n\n readonly logger = new ConsoleLogger('RemoteWorkerEnv');\n\n get isDestroyed(): boolean {\n return this.#isDestroyed;\n }\n\n /**\n * Resolves once the worker is up.\n *\n * Every read hands out a promise that can reject, so a caller that only wants to\n * kick the environment off and never awaits the result should still attach a\n * `catch()` \u2014 otherwise a worker failure surfaces as an unhandled rejection.\n *\n * @throws {WorkerFailedError} if the worker fails before or after that happens\n */\n get workerLoaded(): Promise<RemoteWorkerEnv> {\n const {signal} = this.#workerFailure;\n if (signal.aborted) return Promise.reject(signal.reason);\n\n return new Promise<RemoteWorkerEnv>((resolve, reject) => {\n let unsubscribeLoaded: (() => void) | undefined;\n let settled = false;\n\n const onFailure = () => {\n if (settled) return;\n settled = true;\n unsubscribeLoaded?.();\n reject(signal.reason);\n };\n\n unsubscribeLoaded = once(this as RemoteWorkerEnv, RemoteWorkerEnv.WorkerLoaded, (env: RemoteWorkerEnv) => {\n if (settled) return;\n settled = true;\n signal.removeEventListener('abort', onFailure);\n resolve(env);\n });\n\n // a retained WorkerLoaded is replayed inside once(), before it returns \u2014\n // then there is nothing left to wait for and no abort listener to attach\n if (settled) return;\n\n signal.addEventListener('abort', onFailure, {once: true});\n });\n }\n\n constructor() {\n retain(this as RemoteWorkerEnv, RemoteWorkerEnv.WorkerLoaded);\n // a consumer that subscribes only after the failure still gets to hear about it\n retain(this as RemoteWorkerEnv, RemoteWorkerEnv.WorkerFailed);\n }\n\n async start(): Promise<void> {\n // both guards are needed, and in this order: a failure aborts the signal *and* marks the\n // environment destroyed, so asking about the teardown first would bury the more precise\n // reason \u2014 while a teardown leaves the signal untouched and would slip past it\n const {signal} = this.#workerFailure;\n if (signal.aborted) throw signal.reason;\n\n // a torn-down environment must not spawn a worker: nothing would ever reach it, and\n // nothing would ever shut it down again\n if (this.#isDestroyed) throw new WorkerDestroyedError();\n\n if (this.#worker) {\n if (this.logger.isWarn) {\n this.logger.warn('already started');\n }\n\n return this.workerLoaded.then((): void => {\n if (this.isDestroyed) {\n throw new WorkerDestroyedError();\n }\n });\n }\n\n const worker = (this.#worker = createWorker());\n\n // registered before the load handshake begins: a worker that dies while it is\n // still coming up must not leave the caller waiting for the load timeout\n worker.addEventListener('error', this.onWorkerError.bind(this));\n worker.addEventListener('messageerror', this.onWorkerMessageError.bind(this));\n\n this.configureConsoleLogger(worker);\n\n try {\n await waitForMessageOfType(worker, Loaded, WorkerLoadTimeout, undefined, signal);\n\n if (this.isDestroyed) {\n throw new WorkerDestroyedError();\n }\n\n worker.addEventListener('message', this.onMessageFromWorker.bind(this));\n\n queueMicrotask(() => {\n emit(this as RemoteWorkerEnv, RemoteWorkerEnv.WorkerLoaded, this);\n });\n } catch (error) {\n // the failure path reports with the worker event in hand; anything else is on us\n if (error !== signal.reason) {\n this.logger.error('failed to start', error);\n }\n\n this.#worker = undefined;\n\n // only a start that nobody else is unwinding owns this worker: the reference is gone,\n // nobody can reach it any more, and leaving it running would keep a thread open for an\n // environment that never started. A failure has already terminated it, and a teardown\n // in flight is waiting for its Destroyed reply \u2014 cutting that short here would leave\n // destroy() to sit out its timeout and skip the worker-side teardown entirely.\n if (!this.#isDestroyed) {\n worker.terminate();\n }\n\n throw error;\n }\n }\n\n applyChangeTrail(changeTrail: ChangeTrailType, waitForConfirmation: boolean): Promise<void> {\n const {signal} = this.#workerFailure;\n if (signal.aborted) return Promise.reject(signal.reason);\n\n const worker = this.#worker;\n if (worker == null) return Promise.reject(new WorkerDestroyedError());\n\n const transferables = removeTransferables(changeTrail);\n const message = {type: ChangeTrail, changeTrail} as any;\n\n const serial = ++this.#changeTrailSerial;\n if (waitForConfirmation) {\n message.serial = serial;\n }\n\n worker.postMessage(message, transferables ?? []);\n\n if (waitForConfirmation) {\n return waitForMessageOfType(\n worker,\n AppliedChangeTrail,\n WorkerChangeTrailTimeout,\n (data: AppliedChangeTrailEvent) => {\n if (data.error) throw data.error;\n return data.serial === serial;\n },\n signal,\n );\n } else {\n return Promise.resolve();\n }\n }\n\n importScript(url: URL | string): Promise<void> {\n const {signal} = this.#workerFailure;\n if (signal.aborted) return Promise.reject(signal.reason);\n\n const worker = this.#worker;\n if (worker == null) return Promise.reject(new WorkerDestroyedError());\n\n url = toUrlString(url);\n worker.postMessage({type: Configure, importModule: url});\n return waitForMessageOfType(\n worker,\n ImportedModule,\n WorkerConfigureTimeout,\n (data: ImportedModuleEvent) => {\n if (data.error) throw data.error;\n return data.url === url;\n },\n signal,\n );\n }\n\n destroy(): void {\n if (!this.#worker) return;\n\n const worker = this.#worker;\n this.#worker = undefined;\n\n this.#isDestroyed = true;\n\n worker.postMessage({type: Destroy});\n\n waitForMessageOfType(worker, Destroyed, WorkerDestroyTimeout).finally(() => {\n worker.terminate();\n });\n }\n\n private onWorkerError(event: ErrorEvent) {\n this.handleWorkerFailure('error', event, event.message || 'the worker reported an error');\n }\n\n private onWorkerMessageError(event: MessageEvent) {\n this.handleWorkerFailure('messageerror', event, 'the worker sent a message that could not be deserialized');\n }\n\n private handleWorkerFailure(type: 'error' | 'messageerror', event: ErrorEvent | MessageEvent, message: string): void {\n // a deliberate teardown, or a failure that was already reported: the first one wins\n if (this.#isDestroyed) return;\n\n this.#isDestroyed = true;\n\n const reason = new WorkerFailedError(type, message, {\n cause: type === 'error' ? ((event as ErrorEvent).error ?? event) : event,\n });\n\n this.logger.error(message, event);\n\n const worker = this.#worker;\n this.#worker = undefined;\n\n // settle everyone waiting for a reply before the worker goes away \u2014 it can no longer arrive\n this.#workerFailure.abort(reason);\n\n worker?.terminate();\n\n // the ShadowEnv is told first, so that the state it derives from this is already\n // settled when consumers hear about it. Whatever happens down that path stays\n // there \u2014 the public event is announced either way\n try {\n (this as IShadowObjectEnvProxy).onProxyFailed?.(reason);\n } catch (error) {\n this.logger.error('the proxy-failed callback threw', error);\n }\n\n emit(this as RemoteWorkerEnv, RemoteWorkerEnv.WorkerFailed, {\n env: this,\n type,\n message,\n reason,\n event,\n } as WorkerFailedEvent);\n }\n\n private onMessageFromWorker(event: MessageEvent) {\n if (event.data?.type === MessageToView) {\n (this as IShadowObjectEnvProxy).onMessageToView?.(event.data.data);\n } else if (this.logger.isDebug) {\n this.logger.debug('message from worker', event);\n }\n }\n\n private configureConsoleLogger(worker: Worker) {\n const workerConfigKey = `${CONSOLE_LOGGER}.RemoteWorkerEnv.workerConfig`;\n const workerConfig = JSON.parse(localStorage.getItem(workerConfigKey) ?? '{}');\n\n if (this.logger.isInfo) {\n this.logger.info('load console-logger worker config', {localStorageKey: workerConfigKey, workerConfig});\n }\n\n worker.postMessage({\n type: CONSOLE_LOGGER,\n config: {\n ...ConsoleLogger.sharedConfig,\n enable: this.logger.isEnabled,\n ...workerConfig,\n ...(ConsoleLogger.isEnabled ? {} : {enable: false}),\n },\n });\n }\n}"],
|
|
5
|
+
"mappings": "AAAA,SAAQ,MAAM,MAAM,cAAa;AACjC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,OAAO,kBAAkB;AAEzB,SAAQ,gBAAgB,qBAAoB;AAC5C,SAAQ,mBAAkB;AAC1B,SAAQ,4BAA2B;AAGnC,MAAM,sBAAsB,CAAC,gBAAgE;AAC3F,MAAI;AAEJ,MAAI,eAAe,QAAQ,MAAM,QAAQ,WAAW,GAAG;AACrD,eAAW,cAAc,aAAa;AACpC,UAAI,WAAW,eAAe;AAC5B,YAAI,CAAC,eAAe;AAClB,0BAAgB,WAAW;AAAA,QAC7B,OAAO;AACL,0BAAgB,CAAC,GAAG,eAAe,GAAG,WAAW,aAAa;AAAA,QAChE;AACA,eAAO,WAAW;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAMO,MAAM,0BAA0B,MAAM;AAAA,EAI3C,YAAY,MAAgC,SAAiB,SAAwB;AACnF,UAAM,SAAS,OAAO;AACtB,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AACF;AAMO,MAAM,6BAA6B,MAAM;AAAA,EAC9C,YAAY,UAAU,6CAA6C;AACjE,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAgBO,MAAM,gBAAiD;AAAA,EA2D5D,cAAc;AAtDd,wBAAe;AACf,8BAAqB;AAMrB;AAAA;AAAA;AAAA;AAAA,SAAS,iBAAiB,IAAI,gBAAgB;AAE9C,SAAS,SAAS,IAAI,cAAc,iBAAiB;AA8CnD,WAAO,MAAyB,gBAAgB,YAAY;AAE5D,WAAO,MAAyB,gBAAgB,YAAY;AAAA,EAC9D;AAAA,EA9DA;AAAA,SAAO,eAAe;AAAA;AAAA,EACtB;AAAA,SAAO,eAAe;AAAA;AAAA,EAEtB;AAAA,EACA;AAAA,EACA;AAAA,EAMS;AAAA,EAIT,IAAI,cAAuB;AACzB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,IAAI,eAAyC;AAC3C,UAAM,EAAC,OAAM,IAAI,KAAK;AACtB,QAAI,OAAO,QAAS,QAAO,QAAQ,OAAO,OAAO,MAAM;AAEvD,WAAO,IAAI,QAAyB,CAAC,SAAS,WAAW;AACvD,UAAI;AACJ,UAAI,UAAU;AAEd,YAAM,YAAY,MAAM;AACtB,YAAI,QAAS;AACb,kBAAU;AACV,4BAAoB;AACpB,eAAO,OAAO,MAAM;AAAA,MACtB;AAEA,0BAAoB,KAAK,MAAyB,gBAAgB,cAAc,CAAC,QAAyB;AACxG,YAAI,QAAS;AACb,kBAAU;AACV,eAAO,oBAAoB,SAAS,SAAS;AAC7C,gBAAQ,GAAG;AAAA,MACb,CAAC;AAID,UAAI,QAAS;AAEb,aAAO,iBAAiB,SAAS,WAAW,EAAC,MAAM,KAAI,CAAC;AAAA,IAC1D,CAAC;AAAA,EACH;AAAA,EAQA,MAAM,QAAuB;AAI3B,UAAM,EAAC,OAAM,IAAI,KAAK;AACtB,QAAI,OAAO,QAAS,OAAM,OAAO;AAIjC,QAAI,KAAK,aAAc,OAAM,IAAI,qBAAqB;AAEtD,QAAI,KAAK,SAAS;AAChB,UAAI,KAAK,OAAO,QAAQ;AACtB,aAAK,OAAO,KAAK,iBAAiB;AAAA,MACpC;AAEA,aAAO,KAAK,aAAa,KAAK,MAAY;AACxC,YAAI,KAAK,aAAa;AACpB,gBAAM,IAAI,qBAAqB;AAAA,QACjC;AAAA,MACF,CAAC;AAAA,IACH;AAEA,UAAM,SAAU,KAAK,UAAU,aAAa;AAI5C,WAAO,iBAAiB,SAAS,KAAK,cAAc,KAAK,IAAI,CAAC;AAC9D,WAAO,iBAAiB,gBAAgB,KAAK,qBAAqB,KAAK,IAAI,CAAC;AAE5E,SAAK,uBAAuB,MAAM;AAElC,QAAI;AACF,YAAM,qBAAqB,QAAQ,QAAQ,mBAAmB,QAAW,MAAM;AAE/E,UAAI,KAAK,aAAa;AACpB,cAAM,IAAI,qBAAqB;AAAA,MACjC;AAEA,aAAO,iBAAiB,WAAW,KAAK,oBAAoB,KAAK,IAAI,CAAC;AAEtE,qBAAe,MAAM;AACnB,aAAK,MAAyB,gBAAgB,cAAc,IAAI;AAAA,MAClE,CAAC;AAAA,IACH,SAAS,OAAO;AAEd,UAAI,UAAU,OAAO,QAAQ;AAC3B,aAAK,OAAO,MAAM,mBAAmB,KAAK;AAAA,MAC5C;AAEA,WAAK,UAAU;AAOf,UAAI,CAAC,KAAK,cAAc;AACtB,eAAO,UAAU;AAAA,MACnB;AAEA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,iBAAiB,aAA8B,qBAA6C;AAC1F,UAAM,EAAC,OAAM,IAAI,KAAK;AACtB,QAAI,OAAO,QAAS,QAAO,QAAQ,OAAO,OAAO,MAAM;AAEvD,UAAM,SAAS,KAAK;AACpB,QAAI,UAAU,KAAM,QAAO,QAAQ,OAAO,IAAI,qBAAqB,CAAC;AAEpE,UAAM,gBAAgB,oBAAoB,WAAW;AACrD,UAAM,UAAU,EAAC,MAAM,aAAa,YAAW;AAE/C,UAAM,SAAS,EAAE,KAAK;AACtB,QAAI,qBAAqB;AACvB,cAAQ,SAAS;AAAA,IACnB;AAEA,WAAO,YAAY,SAAS,iBAAiB,CAAC,CAAC;AAE/C,QAAI,qBAAqB;AACvB,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA,CAAC,SAAkC;AACjC,cAAI,KAAK,MAAO,OAAM,KAAK;AAC3B,iBAAO,KAAK,WAAW;AAAA,QACzB;AAAA,QACA;AAAA,MACF;AAAA,IACF,OAAO;AACL,aAAO,QAAQ,QAAQ;AAAA,IACzB;AAAA,EACF;AAAA,EAEA,aAAa,KAAkC;AAC7C,UAAM,EAAC,OAAM,IAAI,KAAK;AACtB,QAAI,OAAO,QAAS,QAAO,QAAQ,OAAO,OAAO,MAAM;AAEvD,UAAM,SAAS,KAAK;AACpB,QAAI,UAAU,KAAM,QAAO,QAAQ,OAAO,IAAI,qBAAqB,CAAC;AAEpE,UAAM,YAAY,GAAG;AACrB,WAAO,YAAY,EAAC,MAAM,WAAW,cAAc,IAAG,CAAC;AACvD,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA,CAAC,SAA8B;AAC7B,YAAI,KAAK,MAAO,OAAM,KAAK;AAC3B,eAAO,KAAK,QAAQ;AAAA,MACtB;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,UAAgB;AACd,QAAI,CAAC,KAAK,QAAS;AAEnB,UAAM,SAAS,KAAK;AACpB,SAAK,UAAU;AAEf,SAAK,eAAe;AAEpB,WAAO,YAAY,EAAC,MAAM,QAAO,CAAC;AAElC,yBAAqB,QAAQ,WAAW,oBAAoB,EAAE,QAAQ,MAAM;AAC1E,aAAO,UAAU;AAAA,IACnB,CAAC;AAAA,EACH;AAAA,EAEQ,cAAc,OAAmB;AACvC,SAAK,oBAAoB,SAAS,OAAO,MAAM,WAAW,8BAA8B;AAAA,EAC1F;AAAA,EAEQ,qBAAqB,OAAqB;AAChD,SAAK,oBAAoB,gBAAgB,OAAO,0DAA0D;AAAA,EAC5G;AAAA,EAEQ,oBAAoB,MAAgC,OAAkC,SAAuB;AAEnH,QAAI,KAAK,aAAc;AAEvB,SAAK,eAAe;AAEpB,UAAM,SAAS,IAAI,kBAAkB,MAAM,SAAS;AAAA,MAClD,OAAO,SAAS,UAAY,MAAqB,SAAS,QAAS;AAAA,IACrE,CAAC;AAED,SAAK,OAAO,MAAM,SAAS,KAAK;AAEhC,UAAM,SAAS,KAAK;AACpB,SAAK,UAAU;AAGf,SAAK,eAAe,MAAM,MAAM;AAEhC,YAAQ,UAAU;AAKlB,QAAI;AACF,MAAC,KAA+B,gBAAgB,MAAM;AAAA,IACxD,SAAS,OAAO;AACd,WAAK,OAAO,MAAM,mCAAmC,KAAK;AAAA,IAC5D;AAEA,SAAK,MAAyB,gBAAgB,cAAc;AAAA,MAC1D,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAsB;AAAA,EACxB;AAAA,EAEQ,oBAAoB,OAAqB;AAC/C,QAAI,MAAM,MAAM,SAAS,eAAe;AACtC,MAAC,KAA+B,kBAAkB,MAAM,KAAK,IAAI;AAAA,IACnE,WAAW,KAAK,OAAO,SAAS;AAC9B,WAAK,OAAO,MAAM,uBAAuB,KAAK;AAAA,IAChD;AAAA,EACF;AAAA,EAEQ,uBAAuB,QAAgB;AAC7C,UAAM,kBAAkB,GAAG,cAAc;AACzC,UAAM,eAAe,KAAK,MAAM,aAAa,QAAQ,eAAe,KAAK,IAAI;AAE7E,QAAI,KAAK,OAAO,QAAQ;AACtB,WAAK,OAAO,KAAK,qCAAqC,EAAC,iBAAiB,iBAAiB,aAAY,CAAC;AAAA,IACxG;AAEA,WAAO,YAAY;AAAA,MACjB,MAAM;AAAA,MACN,QAAQ;AAAA,QACN,GAAG,cAAc;AAAA,QACjB,QAAQ,KAAK,OAAO;AAAA,QACpB,GAAG;AAAA,QACH,GAAI,cAAc,YAAY,CAAC,IAAI,EAAC,QAAQ,MAAK;AAAA,MACnD;AAAA,IACF,CAAC;AAAA,EACH;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/src/view/ShadowEnv.d.ts
CHANGED
|
@@ -5,14 +5,22 @@ import type { IShadowObjectEnvProxy } from './IShadowObjectEnvProxy.js';
|
|
|
5
5
|
declare global {
|
|
6
6
|
var __shadowEnvs: Map<NamespaceType, ShadowEnv> | undefined;
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* The reason every pending {@link ShadowEnv.ready} and {@link ShadowEnv.syncWait} promise
|
|
10
|
+
* is rejected with when the environment is destroyed.
|
|
11
|
+
*/
|
|
12
|
+
export declare class ShadowEnvDestroyedError extends Error {
|
|
13
|
+
constructor(message?: string);
|
|
14
|
+
}
|
|
8
15
|
export declare class ShadowEnv {
|
|
9
16
|
#private;
|
|
10
17
|
static AfterSync: string;
|
|
11
18
|
static ContextLost: string;
|
|
12
19
|
static ContextCreated: string;
|
|
20
|
+
static ProxyFailed: string;
|
|
13
21
|
static get(ns: NamespaceType): ShadowEnv | undefined;
|
|
14
22
|
readonly logger: ConsoleLogger;
|
|
15
|
-
readonly ns$: import("@spearwolf/signalize").Signal<NamespaceType>;
|
|
23
|
+
readonly ns$: import("@spearwolf/signalize").Signal<NamespaceType | undefined>;
|
|
16
24
|
accessor viewReady: boolean;
|
|
17
25
|
accessor proxyReady: boolean;
|
|
18
26
|
get isDestroyed(): boolean;
|
|
@@ -22,9 +30,25 @@ export declare class ShadowEnv {
|
|
|
22
30
|
get envProxy(): IShadowObjectEnvProxy | undefined;
|
|
23
31
|
set envProxy(proxy: IShadowObjectEnvProxy | null | undefined);
|
|
24
32
|
get isReady(): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Resolves once the environment is ready.
|
|
35
|
+
*
|
|
36
|
+
* @throws {ShadowEnvDestroyedError} if the environment is destroyed before that happens
|
|
37
|
+
*/
|
|
25
38
|
readonly ready: () => Promise<ShadowEnv>;
|
|
26
39
|
sync(): void;
|
|
40
|
+
/**
|
|
41
|
+
* Like {@link ShadowEnv.sync}, but resolves with the change trail once the cycle completed.
|
|
42
|
+
*
|
|
43
|
+
* @throws {ShadowEnvDestroyedError} if the environment is destroyed before that happens
|
|
44
|
+
*/
|
|
27
45
|
syncWait(): Promise<ChangeTrailType>;
|
|
46
|
+
/**
|
|
47
|
+
* Tear the environment down: the proxy is destroyed, the namespace is released, all signals
|
|
48
|
+
* and listeners are removed, and every caller still waiting on {@link ShadowEnv.ready} or
|
|
49
|
+
* {@link ShadowEnv.syncWait} is rejected with a {@link ShadowEnvDestroyedError} instead of
|
|
50
|
+
* being left pending forever. Calling it more than once is a no-op.
|
|
51
|
+
*/
|
|
28
52
|
destroy(): void;
|
|
29
53
|
}
|
|
30
54
|
//# sourceMappingURL=ShadowEnv.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ShadowEnv.d.ts","sourceRoot":"","sources":["../../../src/view/ShadowEnv.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,eAAe,EAAE,aAAa,EAAC,MAAM,aAAa,CAAC;AAChE,OAAO,EAAC,aAAa,EAAC,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAC,gBAAgB,EAAC,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,4BAA4B,CAAC;AAEtE,OAAO,CAAC,MAAM,CAAC;IAEb,IAAI,YAAY,EAAE,GAAG,CAAC,aAAa,EAAE,SAAS,CAAC,GAAG,SAAS,CAAC;CAC7D;AAED,qBAAa,SAAS;;IACpB,MAAM,CAAC,SAAS,SAAe;IAC/B,MAAM,CAAC,WAAW,SAAiB;IACnC,MAAM,CAAC,cAAc,SAAoB;
|
|
1
|
+
{"version":3,"file":"ShadowEnv.d.ts","sourceRoot":"","sources":["../../../src/view/ShadowEnv.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,eAAe,EAAE,aAAa,EAAC,MAAM,aAAa,CAAC;AAChE,OAAO,EAAC,aAAa,EAAC,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAC,gBAAgB,EAAC,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,4BAA4B,CAAC;AAEtE,OAAO,CAAC,MAAM,CAAC;IAEb,IAAI,YAAY,EAAE,GAAG,CAAC,aAAa,EAAE,SAAS,CAAC,GAAG,SAAS,CAAC;CAC7D;AAED;;;GAGG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,OAAO,SAA8C;CAIlE;AAED,qBAAa,SAAS;;IACpB,MAAM,CAAC,SAAS,SAAe;IAC/B,MAAM,CAAC,WAAW,SAAiB;IACnC,MAAM,CAAC,cAAc,SAAoB;IACzC,MAAM,CAAC,WAAW,SAAiB;IAEnC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,aAAa,GAAG,SAAS,GAAG,SAAS;IAYpD,QAAQ,CAAC,MAAM,gBAAkC;IAEjD,QAAQ,CAAC,GAAG,mEAA6C;IAE/C,QAAQ,CAAC,SAAS,UAAS;IAC3B,QAAQ,CAAC,UAAU,UAAS;IAItC,IAAI,WAAW,YAEd;;IA2BD,IAAI,IAAI,IAAI,gBAAgB,GAAG,SAAS,CAEvC;IAED,IAAI,IAAI,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI,GAAG,SAAS,EAwBhD;IAED,IAAI,QAAQ,IAAI,qBAAqB,GAAG,SAAS,CAEhD;IAED,IAAI,QAAQ,CAAC,KAAK,EAAE,qBAAqB,GAAG,IAAI,GAAG,SAAS,EA0B3D;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAuBD;;;;OAIG;IACH,QAAQ,CAAC,KAAK,QAAa,OAAO,CAAC,SAAS,CAAC,CAI3C;IAEF,IAAI,IAAI,IAAI;IAWZ;;;;OAIG;IACH,QAAQ,IAAI,OAAO,CAAC,eAAe,CAAC;IAyBpC;;;;;OAKG;IACH,OAAO;CAwFR"}
|