webloom-framework 0.4.1 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -1
- package/dist/advanced.d.ts +19 -7
- package/dist/advanced.js +4 -4
- package/dist/advanced.js.map +1 -1
- package/dist/{chunk-SX46RHDI.js → chunk-UZAO6ORB.js} +205 -41
- package/dist/chunk-UZAO6ORB.js.map +1 -0
- package/dist/{chunk-ANA6GBEI.js → chunk-YIIDRFHK.js} +553 -47
- package/dist/chunk-YIIDRFHK.js.map +1 -0
- package/dist/{chunk-HJKPKWI7.js → chunk-ZP5QYTXX.js} +19 -4
- package/dist/chunk-ZP5QYTXX.js.map +1 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +4 -4
- package/dist/{messageBus-CtrwkjrO.d.ts → messageBus-DigYfj74.d.ts} +1 -1
- package/dist/{messagePortServiceTransport-BYprNvQY.d.ts → messagePortServiceTransport-B9-24RK6.d.ts} +95 -4
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{runtimeTypes-DquUCHz-.d.ts → runtimeTypes-50LVQs0h.d.ts} +55 -2
- package/dist/{sharedWorkerHost-KI7TIGdX.d.ts → sharedWorkerHost-DikS18hA.d.ts} +88 -2
- package/dist/testing.d.ts +6 -6
- package/dist/testing.js +4 -4
- package/dist/{windowRuntime-BKkLPsAS.d.ts → windowRuntime-e1Tn6SnN.d.ts} +2 -2
- package/docs/api.md +28 -1
- package/docs/proposals/webloom-v4/requirements.md +1 -1
- package/docs/proposals/webloom-v4/verification.md +26 -11
- package/package.json +1 -1
- package/dist/chunk-ANA6GBEI.js.map +0 -1
- package/dist/chunk-HJKPKWI7.js.map +0 -1
- package/dist/chunk-SX46RHDI.js.map +0 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { createMessagePortRuntimeTransport, createCapabilityBridge, createPeerScopeView, createCapabilityPeerView, createMessagePortServiceProvider } from './chunk-
|
|
2
|
-
import { RuntimeInitializationError, normalizeRuntimeLimits, createRuntimeBudget, createRuntimeMessageCodec, capabilityKey, materializePluginDefinitions, createRuntimeUnitImplementationRegistry, createPluginHost, RUNTIME_SNAPSHOT_TYPE,
|
|
1
|
+
import { createInMemoryRuntimeLockManager, createRuntimeLock, RuntimeLockError, createRuntimeEndpointBinding, createMessagePortRuntimeTransport, createRuntimeEndpointSession, createCapabilityBridge, createPeerScopeView, createCapabilityPeerView, createMessagePortServiceProvider } from './chunk-YIIDRFHK.js';
|
|
2
|
+
import { RuntimeInitializationError, normalizeRuntimeLimits, createRuntimeBudget, createRuntimeMessageCodec, capabilityKey, materializePluginDefinitions, createRuntimeUnitImplementationRegistry, createPluginHost, RUNTIME_SNAPSHOT_TYPE, RUNTIME_PROTOCOL_VERSION, RUNTIME_ERROR_TYPE, cloneFrozenAttributes, WebLoomError, validateDto } from './chunk-ZP5QYTXX.js';
|
|
3
3
|
|
|
4
4
|
// src/runtime/sharedWorkerHost.ts
|
|
5
|
+
var testRuntimeLockManager = createInMemoryRuntimeLockManager();
|
|
5
6
|
function makeId(prefix) {
|
|
6
7
|
try {
|
|
7
8
|
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return `${prefix}:${crypto.randomUUID()}`;
|
|
@@ -12,7 +13,7 @@ function makeId(prefix) {
|
|
|
12
13
|
function message(error) {
|
|
13
14
|
return error instanceof Error ? error.message : String(error);
|
|
14
15
|
}
|
|
15
|
-
function startSharedWorkerAppInternal(options, injectedScope) {
|
|
16
|
+
function startSharedWorkerAppInternal(options, injectedScope, allowInjectedLockManager = false) {
|
|
16
17
|
if (!options || typeof options.id !== "string" || options.id.trim() === "") throw new TypeError("SharedWorker runtime id must be a non-empty string");
|
|
17
18
|
const scope = injectedScope ?? (globalThis.onconnect !== void 0 ? globalThis : void 0);
|
|
18
19
|
if (!scope) throw new RuntimeInitializationError({ phase: "validate", error: "startSharedWorkerApp must run in a SharedWorkerGlobalScope" });
|
|
@@ -23,6 +24,7 @@ function startSharedWorkerAppInternal(options, injectedScope) {
|
|
|
23
24
|
const runtimeCodec = createRuntimeMessageCodec();
|
|
24
25
|
const peerExposureAllowlist = options.peerExposureAllowlist === void 0 ? void 0 : new Set(options.peerExposureAllowlist.map((capability) => capabilityKey(capability)));
|
|
25
26
|
const listeners = /* @__PURE__ */ new Set();
|
|
27
|
+
const peerLifecycleListeners = /* @__PURE__ */ new Set();
|
|
26
28
|
const endpoints = /* @__PURE__ */ new Set();
|
|
27
29
|
let manifests = [];
|
|
28
30
|
let runtimeState = "starting";
|
|
@@ -31,11 +33,39 @@ function startSharedWorkerAppInternal(options, injectedScope) {
|
|
|
31
33
|
let accepting = true;
|
|
32
34
|
let host;
|
|
33
35
|
let disposePromise;
|
|
36
|
+
const runtimeLockOptions = options.runtimeLock === void 0 || allowInjectedLockManager ? options.runtimeLock : { messages: options.runtimeLock.messages };
|
|
37
|
+
const runtimeLock = createRuntimeLock(options.id, runtimeLockOptions);
|
|
38
|
+
let runtimeLockSettled = false;
|
|
39
|
+
let runtimeFailure;
|
|
40
|
+
const pendingPorts = [];
|
|
41
|
+
const emitPeerLifecycle = (event) => {
|
|
42
|
+
const frozen = Object.freeze({
|
|
43
|
+
...event,
|
|
44
|
+
binding: Object.freeze({ ...event.binding }),
|
|
45
|
+
...event.drain !== void 0 ? { drain: Object.freeze({ ...event.drain }) } : {}
|
|
46
|
+
});
|
|
47
|
+
for (const listener of [...peerLifecycleListeners]) {
|
|
48
|
+
try {
|
|
49
|
+
listener(frozen);
|
|
50
|
+
} catch {
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
34
54
|
const localSnapshot = () => {
|
|
35
55
|
const currentHost = host;
|
|
36
56
|
const units = currentHost ? currentHost.installed().flatMap((pluginId) => currentHost.state(pluginId).units.map((unit) => ({ pluginId: unit.pluginId, unitId: unit.unitId, runtime: unit.runtime, ...unit.instanceId !== void 0 ? { instanceId: unit.instanceId } : {}, state: unit.kind }))) : [];
|
|
37
57
|
const services = runtimeState === "ready" && host ? host.serviceReferences().map((service) => ({ kind: service.kind, capabilityId: service.capabilityId, contractVersion: service.contractVersion, serviceInstanceId: service.serviceInstanceId, attributes: cloneFrozenAttributes(service.attributes), ...service.grantId !== void 0 ? { grantId: service.grantId } : {}, ...service.authorizationRevision !== void 0 ? { authorizationRevision: service.authorizationRevision } : {} })) : [];
|
|
38
|
-
return Object.freeze({
|
|
58
|
+
return Object.freeze({
|
|
59
|
+
protocolVersion: RUNTIME_PROTOCOL_VERSION,
|
|
60
|
+
runtimeId: options.id,
|
|
61
|
+
runtimeKind: "shared-worker",
|
|
62
|
+
runtimeInstanceId,
|
|
63
|
+
revision,
|
|
64
|
+
state: runtimeState,
|
|
65
|
+
units: Object.freeze(units),
|
|
66
|
+
services: Object.freeze(services),
|
|
67
|
+
...runtimeFailure ? { error: runtimeFailure.message, errorCode: runtimeFailure.code } : {}
|
|
68
|
+
});
|
|
39
69
|
};
|
|
40
70
|
const emit = (snapshot = localSnapshot()) => {
|
|
41
71
|
for (const listener of [...listeners]) {
|
|
@@ -56,7 +86,7 @@ function startSharedWorkerAppInternal(options, injectedScope) {
|
|
|
56
86
|
const wireSnapshot = (endpoint, nextRevision = endpoint.revision, exposures = endpoint.exposures, base = localSnapshot()) => {
|
|
57
87
|
const services = [...exposures.values()].map((service) => ({ kind: service.kind, capabilityId: service.capabilityId, contractVersion: service.contractVersion, serviceInstanceId: service.serviceInstanceId, attributes: cloneFrozenAttributes(service.attributes), ...service.grantId !== void 0 ? { grantId: service.grantId } : {}, ...service.authorizationRevision !== void 0 ? { authorizationRevision: service.authorizationRevision } : {} }));
|
|
58
88
|
const state = base.state === "disconnected" ? "failed" : base.state;
|
|
59
|
-
return { type: RUNTIME_SNAPSHOT_TYPE, protocolVersion: base.protocolVersion, runtimeId: base.runtimeId, runtimeKind: base.runtimeKind, runtimeInstanceId: base.runtimeInstanceId, revision: nextRevision, state, units: projectedUnits(exposures), services: state === "ready" ? services : [] };
|
|
89
|
+
return { type: RUNTIME_SNAPSHOT_TYPE, protocolVersion: base.protocolVersion, runtimeId: base.runtimeId, runtimeKind: base.runtimeKind, runtimeInstanceId: base.runtimeInstanceId, revision: nextRevision, state, units: projectedUnits(exposures), services: state === "ready" ? services : [], binding: endpoint.binding };
|
|
60
90
|
};
|
|
61
91
|
const validateProjectedSnapshot = (endpoint, exposures) => {
|
|
62
92
|
if (exposures.size > limits.maxSnapshotServices) throw new WebLoomError("resource_limit_exceeded", "Runtime service exposure limit exceeded", "dispatch");
|
|
@@ -64,8 +94,8 @@ function startSharedWorkerAppInternal(options, injectedScope) {
|
|
|
64
94
|
runtimeCodec.encode(snapshot);
|
|
65
95
|
validateDto(snapshot, { limits: { maxDepth: limits.maxDtoDepth, maxNodes: limits.maxDtoNodes, maxEdges: limits.maxDtoEdges, maxBudgetBytes: limits.maxMessageBudgetBytes }, phase: "dispatch" });
|
|
66
96
|
};
|
|
67
|
-
const publish = (endpoint, exposures = endpoint.exposures, base) => {
|
|
68
|
-
if (endpoint.closed) return;
|
|
97
|
+
const publish = (endpoint, exposures = endpoint.exposures, base, allowClosed = false) => {
|
|
98
|
+
if (endpoint.closed && !allowClosed) return;
|
|
69
99
|
const nextRevision = endpoint.revision + 1;
|
|
70
100
|
const snapshot = wireSnapshot(endpoint, nextRevision, exposures, base);
|
|
71
101
|
endpoint.transport.send(snapshot);
|
|
@@ -76,6 +106,15 @@ function startSharedWorkerAppInternal(options, injectedScope) {
|
|
|
76
106
|
options.snapshotObserver?.(base);
|
|
77
107
|
for (const endpoint of endpoints) {
|
|
78
108
|
try {
|
|
109
|
+
if (runtimeFailure) {
|
|
110
|
+
endpoint.transport.send({
|
|
111
|
+
type: RUNTIME_ERROR_TYPE,
|
|
112
|
+
protocolVersion: RUNTIME_PROTOCOL_VERSION,
|
|
113
|
+
code: runtimeFailure.code,
|
|
114
|
+
message: runtimeFailure.message,
|
|
115
|
+
phase: runtimeFailure.phase
|
|
116
|
+
});
|
|
117
|
+
}
|
|
79
118
|
publish(endpoint, endpoint.exposures, base);
|
|
80
119
|
} catch {
|
|
81
120
|
closeEndpoint(endpoint, "Runtime snapshot publication failed");
|
|
@@ -87,12 +126,14 @@ function startSharedWorkerAppInternal(options, injectedScope) {
|
|
|
87
126
|
if (!host) throw new Error("SharedWorker Host is unavailable");
|
|
88
127
|
const peerScope = host.rootScope.child("peer", { attributes: { peerId: makeId("peer") } });
|
|
89
128
|
const transport = createMessagePortRuntimeTransport(port, { limits });
|
|
90
|
-
const
|
|
129
|
+
const binding = createRuntimeEndpointBinding(runtimeInstanceId);
|
|
130
|
+
const session = createRuntimeEndpointSession(binding);
|
|
131
|
+
const bridge = createCapabilityBridge({ transport, remoteRuntimeKind: "window-main", limits, budget: outboundBudget, binding, session });
|
|
91
132
|
const exposures = /* @__PURE__ */ new Map();
|
|
92
133
|
const exposurePolicies = /* @__PURE__ */ new Map();
|
|
93
134
|
const peerId = peerScope.identity.attributes.peerId ?? makeId("peer");
|
|
94
135
|
const peerScopeView = createPeerScopeView(peerScope);
|
|
95
|
-
const peerView = createCapabilityPeerView({ peerId, scope: peerScopeView, bridge, capabilityScope: peerScope });
|
|
136
|
+
const peerView = createCapabilityPeerView({ peerId, binding, scope: peerScopeView, bridge, capabilityScope: peerScope });
|
|
96
137
|
let endpointForDisconnect;
|
|
97
138
|
const exposeGroup = (entries, source = "dynamic") => {
|
|
98
139
|
if (peerScope.state !== "active") throw new WebLoomError("service_revoked", "Peer scope is not active", "dispatch", { capabilityId: entries[0]?.capability.id });
|
|
@@ -190,6 +231,10 @@ function startSharedWorkerAppInternal(options, injectedScope) {
|
|
|
190
231
|
const configuredExposureKeys = /* @__PURE__ */ new Set();
|
|
191
232
|
const peer = {
|
|
192
233
|
peerId,
|
|
234
|
+
binding,
|
|
235
|
+
get endpointState() {
|
|
236
|
+
return session.state;
|
|
237
|
+
},
|
|
193
238
|
get runtimeInstanceId() {
|
|
194
239
|
return bridge.runtimeInstanceId;
|
|
195
240
|
},
|
|
@@ -197,6 +242,12 @@ function startSharedWorkerAppInternal(options, injectedScope) {
|
|
|
197
242
|
scope: peerScope,
|
|
198
243
|
view: peerView,
|
|
199
244
|
capability: (capability) => bridge.getClient(capability, peerScope),
|
|
245
|
+
beginClose(reason = "Peer endpoint closing") {
|
|
246
|
+
session.beginClose(reason);
|
|
247
|
+
},
|
|
248
|
+
drain(timeoutMs) {
|
|
249
|
+
return bridge.drain(timeoutMs);
|
|
250
|
+
},
|
|
200
251
|
expose(capability, exposureOptions = {}) {
|
|
201
252
|
const result = exposeGroup([{ capability, options: exposureOptions }]);
|
|
202
253
|
configuredExposureKeys.add(capabilityKey(capability));
|
|
@@ -241,12 +292,14 @@ function startSharedWorkerAppInternal(options, injectedScope) {
|
|
|
241
292
|
transport,
|
|
242
293
|
peerScope,
|
|
243
294
|
peer: peerView,
|
|
295
|
+
binding,
|
|
296
|
+
session,
|
|
244
297
|
budget: inboundBudget,
|
|
245
298
|
limits,
|
|
246
299
|
services: () => [...exposures.values()],
|
|
247
300
|
peerForCall: (_call, reference) => {
|
|
248
301
|
const registration = host?.capabilities.registration({ kind: reference.kind, id: reference.capabilityId, version: reference.contractVersion });
|
|
249
|
-
return createCapabilityPeerView({ peerId, scope: peerScopeView, bridge, allowed: registration?.peerDependencies ?? [], capabilityScope: peerScope });
|
|
302
|
+
return createCapabilityPeerView({ peerId, binding, scope: peerScopeView, bridge, allowed: registration?.peerDependencies ?? [], capabilityScope: peerScope });
|
|
250
303
|
},
|
|
251
304
|
prepareRequest: (call) => {
|
|
252
305
|
if (!host) throw new WebLoomError("service_stale", "SharedWorker Host is unavailable", "dispatch");
|
|
@@ -268,7 +321,7 @@ function startSharedWorkerAppInternal(options, injectedScope) {
|
|
|
268
321
|
const policy = exposurePolicies.get(key);
|
|
269
322
|
if (!registration || !exposures.has(key)) throw new Error("Runtime service exposure is stale");
|
|
270
323
|
const handlerReference = reference;
|
|
271
|
-
const context = { signal, deadlineAt, ...call.operationId !== void 0 ? { operationId: call.operationId } : {}, reference: handlerReference, origin: "remote", peer: callPeer };
|
|
324
|
+
const context = { signal, deadlineAt, ...call.operationId !== void 0 ? { operationId: call.operationId } : {}, reference: handlerReference, binding: call.binding, origin: "remote", peer: callPeer };
|
|
272
325
|
if (policy?.authorize && !await policy.authorize(context, request)) throw new WebLoomError("permission_denied", "Peer capability authorization denied", "dispatch", { capabilityId: reference.capabilityId, serviceInstanceId: reference.serviceInstanceId });
|
|
273
326
|
if (exposures.get(key)?.serviceInstanceId !== handlerReference.serviceInstanceId) throw new WebLoomError("service_stale", "Runtime service exposure was replaced while authorization was pending", "dispatch", { serviceInstanceId: handlerReference.serviceInstanceId });
|
|
274
327
|
if (peerScope.state !== "active" || signal.aborted) throw new WebLoomError("service_revoked", "Peer scope was revoked", "dispose", { serviceInstanceId: reference.serviceInstanceId });
|
|
@@ -294,9 +347,11 @@ function startSharedWorkerAppInternal(options, injectedScope) {
|
|
|
294
347
|
return { value: parsed, transfer };
|
|
295
348
|
}
|
|
296
349
|
});
|
|
297
|
-
const endpoint = { port, scope: peerScope, transport, bridge, provider, exposures, installTopLevelExposures, closed: false, revision: 0 };
|
|
350
|
+
const endpoint = { port, scope: peerScope, binding, session, transport, bridge, provider, exposures, installTopLevelExposures, closed: false, revision: 0 };
|
|
298
351
|
endpointForDisconnect = endpoint;
|
|
299
352
|
endpoints.add(endpoint);
|
|
353
|
+
emitPeerLifecycle({ event: "active", peerId, binding, state: "active" });
|
|
354
|
+
session.onClosed(() => closeEndpoint(endpoint, "Runtime endpoint closed"));
|
|
300
355
|
try {
|
|
301
356
|
if (disconnectRequested !== void 0) closeEndpoint(endpoint, disconnectRequested);
|
|
302
357
|
installTopLevelExposures();
|
|
@@ -307,20 +362,71 @@ function startSharedWorkerAppInternal(options, injectedScope) {
|
|
|
307
362
|
}
|
|
308
363
|
return endpoint;
|
|
309
364
|
};
|
|
310
|
-
const
|
|
365
|
+
const beginCloseEndpoint = (endpoint, reason) => {
|
|
311
366
|
if (endpoint.closed) return;
|
|
312
367
|
endpoint.closed = true;
|
|
313
|
-
endpoint.scope.revoke(reason);
|
|
314
|
-
void endpoint.scope.dispose({ reason });
|
|
315
|
-
endpoint.provider.dispose();
|
|
316
|
-
endpoint.bridge.dispose(reason);
|
|
317
|
-
endpoint.transport.close?.();
|
|
318
368
|
endpoints.delete(endpoint);
|
|
369
|
+
endpoint.scope.revoke(reason);
|
|
370
|
+
endpoint.provider.beginClose(reason);
|
|
371
|
+
endpoint.bridge.beginClose(reason);
|
|
372
|
+
emitPeerLifecycle({ event: "closing", peerId: endpoint.scope.identity.attributes.peerId, binding: endpoint.binding, state: "closing" });
|
|
373
|
+
};
|
|
374
|
+
const closeEndpoint = (endpoint, reason) => {
|
|
375
|
+
if (endpoint.closePromise) return endpoint.closePromise;
|
|
376
|
+
beginCloseEndpoint(endpoint, reason);
|
|
377
|
+
endpoint.closePromise = (async () => {
|
|
378
|
+
let providerDrain;
|
|
379
|
+
let bridgeDrain;
|
|
380
|
+
try {
|
|
381
|
+
[providerDrain, bridgeDrain] = await Promise.all([endpoint.provider.drain(), endpoint.bridge.drain()]);
|
|
382
|
+
} catch {
|
|
383
|
+
providerDrain = { state: endpoint.session.state, drained: false, timedOut: true, pendingExecutions: endpoint.provider.executionCount() };
|
|
384
|
+
bridgeDrain = { state: endpoint.session.state, drained: false, timedOut: true, pendingExecutions: endpoint.bridge.pendingCallCount + endpoint.bridge.activeStreamCount };
|
|
385
|
+
}
|
|
386
|
+
try {
|
|
387
|
+
await endpoint.scope.dispose({ reason });
|
|
388
|
+
} catch {
|
|
389
|
+
}
|
|
390
|
+
endpoint.provider.dispose();
|
|
391
|
+
endpoint.bridge.dispose(reason);
|
|
392
|
+
endpoint.transport.close?.();
|
|
393
|
+
endpoint.session.close();
|
|
394
|
+
emitPeerLifecycle({ event: "closed", peerId: endpoint.scope.identity.attributes.peerId, binding: endpoint.binding, state: "closed", drain: bridgeDrain.drained && providerDrain.drained ? bridgeDrain : { ...bridgeDrain, drained: false, timedOut: bridgeDrain.timedOut || providerDrain.timedOut, pendingExecutions: Math.max(bridgeDrain.pendingExecutions, providerDrain.pendingExecutions) } });
|
|
395
|
+
})();
|
|
396
|
+
return endpoint.closePromise;
|
|
319
397
|
};
|
|
320
398
|
const sendTerminalSnapshot = (port) => {
|
|
321
399
|
try {
|
|
322
400
|
port.start();
|
|
323
|
-
|
|
401
|
+
const binding = createRuntimeEndpointBinding(runtimeInstanceId);
|
|
402
|
+
port.postMessage({ ...localSnapshot(), type: RUNTIME_SNAPSHOT_TYPE, binding });
|
|
403
|
+
setTimeout(() => {
|
|
404
|
+
try {
|
|
405
|
+
port.close();
|
|
406
|
+
} catch {
|
|
407
|
+
}
|
|
408
|
+
}, 0);
|
|
409
|
+
} catch {
|
|
410
|
+
try {
|
|
411
|
+
port.close();
|
|
412
|
+
} catch {
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
const sendRuntimeFailure = (port) => {
|
|
417
|
+
if (!runtimeFailure) {
|
|
418
|
+
sendTerminalSnapshot(port);
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
try {
|
|
422
|
+
port.start();
|
|
423
|
+
port.postMessage({
|
|
424
|
+
type: RUNTIME_ERROR_TYPE,
|
|
425
|
+
protocolVersion: RUNTIME_PROTOCOL_VERSION,
|
|
426
|
+
code: runtimeFailure.code,
|
|
427
|
+
message: runtimeFailure.message,
|
|
428
|
+
phase: runtimeFailure.phase
|
|
429
|
+
});
|
|
324
430
|
setTimeout(() => {
|
|
325
431
|
try {
|
|
326
432
|
port.close();
|
|
@@ -334,12 +440,46 @@ function startSharedWorkerAppInternal(options, injectedScope) {
|
|
|
334
440
|
}
|
|
335
441
|
}
|
|
336
442
|
};
|
|
443
|
+
const drainPendingPorts = () => {
|
|
444
|
+
const ports = pendingPorts.splice(0);
|
|
445
|
+
for (const port of ports) {
|
|
446
|
+
if (!accepting || disposed || endpoints.size >= limits.maxPeers) {
|
|
447
|
+
sendTerminalSnapshot(port);
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
450
|
+
if (runtimeFailure) {
|
|
451
|
+
sendRuntimeFailure(port);
|
|
452
|
+
continue;
|
|
453
|
+
}
|
|
454
|
+
try {
|
|
455
|
+
createEndpoint(port);
|
|
456
|
+
} catch {
|
|
457
|
+
try {
|
|
458
|
+
port.close();
|
|
459
|
+
} catch {
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
const failPendingPorts = () => {
|
|
465
|
+
const ports = pendingPorts.splice(0);
|
|
466
|
+
for (const port of ports) sendRuntimeFailure(port);
|
|
467
|
+
};
|
|
337
468
|
scope.onconnect = (event) => {
|
|
338
469
|
for (const port of event.ports ?? []) {
|
|
339
470
|
if (!accepting || disposed || endpoints.size >= limits.maxPeers) {
|
|
340
471
|
sendTerminalSnapshot(port);
|
|
341
472
|
continue;
|
|
342
473
|
}
|
|
474
|
+
if (!runtimeLockSettled) {
|
|
475
|
+
if (pendingPorts.length >= limits.maxPeers) sendTerminalSnapshot(port);
|
|
476
|
+
else pendingPorts.push(port);
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
if (runtimeFailure) {
|
|
480
|
+
sendRuntimeFailure(port);
|
|
481
|
+
continue;
|
|
482
|
+
}
|
|
343
483
|
try {
|
|
344
484
|
createEndpoint(port);
|
|
345
485
|
} catch {
|
|
@@ -350,11 +490,13 @@ function startSharedWorkerAppInternal(options, injectedScope) {
|
|
|
350
490
|
}
|
|
351
491
|
}
|
|
352
492
|
};
|
|
353
|
-
|
|
493
|
+
const ready = runtimeLock.acquired.then(async () => {
|
|
494
|
+
if (disposed) throw new Error("SharedWorker Runtime was disposed before the browser lock was acquired");
|
|
495
|
+
runtimeLockSettled = true;
|
|
354
496
|
const materialized = materializePluginDefinitions(options.plugins, "shared-worker");
|
|
355
497
|
manifests = materialized.map((item) => item.manifest);
|
|
356
498
|
const implementations = createRuntimeUnitImplementationRegistry(materialized.map((item) => ({ pluginId: item.manifest.id, unitId: item.unitId, setup: item.setup, capabilities: item.capabilities })));
|
|
357
|
-
const { id: _id, plugins: _plugins, expose: _expose, configurePeer: _configurePeer, ...hostOptions } = options;
|
|
499
|
+
const { id: _id, plugins: _plugins, expose: _expose, configurePeer: _configurePeer, runtimeLock: _runtimeLock, ...hostOptions } = options;
|
|
358
500
|
host = createPluginHost({ ...hostOptions, runtime: "shared-worker", runtimeId: options.id, runtimeInstanceId, runtimeUnitImplementationRegistry: implementations });
|
|
359
501
|
host.subscribe(() => {
|
|
360
502
|
if (runtimeState === "ready" && !disposed) {
|
|
@@ -362,30 +504,25 @@ function startSharedWorkerAppInternal(options, injectedScope) {
|
|
|
362
504
|
publishAll();
|
|
363
505
|
} else emit();
|
|
364
506
|
});
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
const failure = new RuntimeInitializationError({ phase: "validate", error: message(error) });
|
|
368
|
-
const failedReady = Promise.reject(failure);
|
|
369
|
-
void failedReady.catch(() => void 0);
|
|
370
|
-
const failedInspection = () => ({ runtimeId: options.id, runtimeKind: "shared-worker", runtimeInstanceId, version: 0, pluginCount: 0, peerCount: endpoints.size, pendingCallCount: 0, activeStreamCount: 0, plugins: [] });
|
|
371
|
-
return { runtimeKind: "shared-worker", runtimeId: options.id, runtimeInstanceId, ready: () => failedReady, reconcile: async () => failedReady, state: localSnapshot, subscribe(listener) {
|
|
372
|
-
listeners.add(listener);
|
|
373
|
-
listener(localSnapshot());
|
|
374
|
-
return () => listeners.delete(listener);
|
|
375
|
-
}, inspect: failedInspection, dispose: async () => ({ scopeId: `runtime:${runtimeInstanceId}`, state: "stopped", attempted: 0, released: 0, pending: [], errors: [], cleanupIncomplete: false }) };
|
|
376
|
-
}
|
|
377
|
-
const ready = host.registerAll(manifests).then(() => {
|
|
507
|
+
drainPendingPorts();
|
|
508
|
+
await host.registerAll(manifests);
|
|
378
509
|
for (const endpoint of endpoints) endpoint.installTopLevelExposures();
|
|
379
510
|
if (!disposed) {
|
|
380
511
|
runtimeState = "ready";
|
|
381
512
|
revision += 1;
|
|
382
513
|
publishAll();
|
|
383
514
|
}
|
|
384
|
-
}
|
|
515
|
+
}).catch((error) => {
|
|
385
516
|
if (!disposed) {
|
|
386
517
|
runtimeState = "failed";
|
|
518
|
+
const code = error instanceof RuntimeLockError ? error.code : error && typeof error === "object" && typeof error.code === "string" ? error.code : "runtime_initialization_failed";
|
|
519
|
+
runtimeFailure = { code, message: message(error), phase: error instanceof RuntimeLockError ? "wait" : "execute" };
|
|
520
|
+
runtimeLockSettled = true;
|
|
521
|
+
failPendingPorts();
|
|
387
522
|
publishAll();
|
|
388
523
|
}
|
|
524
|
+
void runtimeLock.release();
|
|
525
|
+
if (error instanceof RuntimeLockError) throw error;
|
|
389
526
|
throw new RuntimeInitializationError({ phase: "startup", error: message(error) });
|
|
390
527
|
});
|
|
391
528
|
void ready.catch(() => void 0);
|
|
@@ -402,17 +539,43 @@ function startSharedWorkerAppInternal(options, injectedScope) {
|
|
|
402
539
|
return () => listeners.delete(listener);
|
|
403
540
|
},
|
|
404
541
|
inspect: () => host ? { ...host.inspect(), peerCount: endpoints.size } : { runtimeId: options.id, runtimeKind: "shared-worker", runtimeInstanceId, version: 0, pluginCount: 0, peerCount: endpoints.size, pendingCallCount: 0, activeStreamCount: 0, plugins: [] },
|
|
542
|
+
activePeers: () => Object.freeze([...endpoints].filter((endpoint) => !endpoint.closed && endpoint.session.state === "active").map((endpoint) => Object.freeze({ event: "active", peerId: endpoint.scope.identity.attributes.peerId, binding: Object.freeze({ ...endpoint.binding }), state: "active" }))),
|
|
543
|
+
subscribePeerLifecycle(listener) {
|
|
544
|
+
peerLifecycleListeners.add(listener);
|
|
545
|
+
for (const endpoint of endpoints) if (!endpoint.closed && endpoint.session.state === "active") listener(Object.freeze({ event: "active", peerId: endpoint.scope.identity.attributes.peerId, binding: Object.freeze({ ...endpoint.binding }), state: "active" }));
|
|
546
|
+
return () => peerLifecycleListeners.delete(listener);
|
|
547
|
+
},
|
|
548
|
+
notifyPeerHandoff(peerId, handoffRevision) {
|
|
549
|
+
const endpoint = [...endpoints].find((candidate) => !candidate.closed && candidate.scope.identity.attributes.peerId === peerId);
|
|
550
|
+
if (!endpoint || endpoint.session.state !== "active") return false;
|
|
551
|
+
emitPeerLifecycle({ event: "handoff", peerId, binding: endpoint.binding, state: "active", ...handoffRevision !== void 0 ? { handoffRevision } : {} });
|
|
552
|
+
return true;
|
|
553
|
+
},
|
|
405
554
|
dispose(reason = "shared worker runtime disposed") {
|
|
406
555
|
if (disposePromise) return disposePromise;
|
|
407
556
|
accepting = false;
|
|
408
557
|
disposed = true;
|
|
558
|
+
runtimeLockSettled = true;
|
|
559
|
+
for (const port of pendingPorts.splice(0)) sendTerminalSnapshot(port);
|
|
409
560
|
runtimeState = "stopping";
|
|
561
|
+
const endpointsToClose = [...endpoints];
|
|
410
562
|
publishAll();
|
|
563
|
+
for (const endpoint of endpointsToClose) beginCloseEndpoint(endpoint, reason);
|
|
411
564
|
disposePromise = (async () => {
|
|
412
|
-
const result = host ?
|
|
565
|
+
const result = await (host ? host.dispose(reason) : Promise.resolve({ scopeId: `runtime:${runtimeInstanceId}`, state: "stopped", attempted: 0, released: 0, pending: [], errors: [], cleanupIncomplete: false }));
|
|
413
566
|
runtimeState = "disposed";
|
|
414
|
-
|
|
415
|
-
|
|
567
|
+
const terminal = localSnapshot();
|
|
568
|
+
options.snapshotObserver?.(terminal);
|
|
569
|
+
for (const endpoint of endpointsToClose) {
|
|
570
|
+
try {
|
|
571
|
+
publish(endpoint, endpoint.exposures, terminal, true);
|
|
572
|
+
} catch {
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
emit(terminal);
|
|
576
|
+
const endpointClosures = endpointsToClose.map((endpoint) => closeEndpoint(endpoint, reason));
|
|
577
|
+
await Promise.all(endpointClosures);
|
|
578
|
+
await runtimeLock.release();
|
|
416
579
|
return result;
|
|
417
580
|
})();
|
|
418
581
|
return disposePromise;
|
|
@@ -425,9 +588,10 @@ function startSharedWorkerApp(options) {
|
|
|
425
588
|
}
|
|
426
589
|
function startSharedWorkerAppForTesting(options) {
|
|
427
590
|
const { globalScope, ...runtimeOptions } = options;
|
|
428
|
-
|
|
591
|
+
const withTestLock = runtimeOptions.runtimeLock === void 0 ? { ...runtimeOptions, runtimeLock: { manager: testRuntimeLockManager } } : runtimeOptions;
|
|
592
|
+
return startSharedWorkerAppInternal(withTestLock, globalScope, true);
|
|
429
593
|
}
|
|
430
594
|
|
|
431
595
|
export { startSharedWorkerApp, startSharedWorkerAppForTesting };
|
|
432
|
-
//# sourceMappingURL=chunk-
|
|
433
|
-
//# sourceMappingURL=chunk-
|
|
596
|
+
//# sourceMappingURL=chunk-UZAO6ORB.js.map
|
|
597
|
+
//# sourceMappingURL=chunk-UZAO6ORB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime/sharedWorkerHost.ts"],"names":[],"mappings":"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","file":"chunk-UZAO6ORB.js","sourcesContent":["// SharedWorkerGlobalScope 内的 v4 Runtime。\n\nimport type { CapabilityPeer, RemoteCapability, ServiceReference } from \"../contracts/capability.js\";\nimport { capabilityKey } from \"../contracts/capability.js\";\nimport { WebLoomError, type LifecycleDisposeResult, type LifecycleScope, type RuntimeEndpointBinding, type RuntimeEndpointState, type RuntimeSnapshot } from \"../contracts/lifecycle.js\";\nimport { createRuntimeBudget, normalizeRuntimeLimits, validateDto, type RuntimeBudget, type RuntimeLimitsInput } from \"../transport/dto.js\";\nimport type { PluginManifest } from \"../contracts/plugin.js\";\nimport { createPluginHost, type CreatePluginHostOptions, type HostInspection, type PluginHost } from \"../host/createPluginHost.js\";\nimport { createRuntimeUnitImplementationRegistry } from \"../host/runtimeUnitImplementationRegistry.js\";\nimport { invokeCapabilityHandler } from \"../host/capabilityRegistry.js\";\nimport { materializePluginDefinitions, type RuntimePluginDefinition } from \"./pluginDefinitions.js\";\nimport { createCapabilityBridge } from \"../transport/serviceBridge.js\";\nimport { createMessagePortRuntimeTransport } from \"../transport/messagePortServiceTransport.js\";\nimport { createMessagePortServiceProvider } from \"../transport/messagePortServiceProvider.js\";\nimport { cloneFrozenAttributes } from \"../transport/dto.js\";\nimport { createRuntimeMessageCodec, RUNTIME_ERROR_TYPE, RUNTIME_PROTOCOL_VERSION, RUNTIME_SNAPSHOT_TYPE } from \"./runtimeProtocol.js\";\nimport { RuntimeInitializationError, type RuntimeStatusListener, type RuntimeStatusSnapshot } from \"./runtimeTypes.js\";\nimport { createCapabilityPeerView, createPeerScopeView } from \"./peerView.js\";\nimport { createRuntimeEndpointBinding, createRuntimeEndpointSession, type RuntimeEndpointSession } from \"./runtimeSession.js\";\nimport { createInMemoryRuntimeLockManager, createRuntimeLock, RuntimeLockError, type RuntimeLockOptions } from \"./runtimeLock.js\";\n\nexport interface SharedWorkerScopeLike {\n /** SharedWorker 连接事件。 */\n onconnect: ((event: { ports: MessagePort[] }) => void) | null;\n}\n\nexport interface PeerExposureOptions {\n /** 领域授权标识。 */\n readonly grantId?: string;\n /** 授权修订。 */\n readonly authorizationRevision?: number;\n /** 无环公开属性。 */\n readonly attributes?: Readonly<Record<string, unknown>>;\n /** 领域授权检查。 */\n readonly authorize?: (context: import(\"../contracts/capability.js\").HandlerCallContext, request: unknown) => boolean | Promise<boolean>;\n /** 领域 Scope。 */\n readonly scope?: LifecycleScope;\n}\n\nexport interface PeerController {\n /** peer 标识。 */\n readonly peerId: string;\n /** 当前物理 endpoint 的不可复用框架 binding。 */\n readonly binding: RuntimeEndpointBinding;\n /** 当前物理 endpoint 的关闭阶段。 */\n readonly endpointState: RuntimeEndpointState;\n /** 已观察到的页面 Runtime 实例;首个页面快照前为空。 */\n readonly runtimeInstanceId?: string;\n /** 对端 Window Runtime 类型。 */\n readonly runtime: \"window-main\";\n /** peer 子作用域。 */\n readonly scope: LifecycleScope;\n /** 传给普通 handler 的最小 PeerView。 */\n readonly view: CapabilityPeer;\n /** 获取页面暴露的 typed remote capability。 */\n capability<C extends RemoteCapability>(capability: C): import(\"../contracts/capability.js\").CapabilityClient<C>;\n /** 暴露 Worker 已注册的 capability。 */\n expose<C extends RemoteCapability>(capability: C, options?: PeerExposureOptions): { revoke(): void };\n /** 原子暴露一组 capability;任一项非法时不得部分开放。 */\n exposeGroup(entries: readonly { readonly capability: RemoteCapability; readonly options?: PeerExposureOptions }[]): { revoke(): void };\n /** 断开此 peer,不影响其它页面。 */\n disconnect(reason?: string): void;\n /** 同步停止新调用与暴露;后续由 drain/close 完成异步收尾。 */\n beginClose(reason?: string): void;\n /** 等待该 peer endpoint 的 bounded drain。 */\n drain(timeoutMs?: number): Promise<import(\"../contracts/lifecycle.js\").RuntimeDrainResult>;\n /** peer 诊断。 */\n inspect(): Readonly<Record<string, unknown>>;\n}\n\n/** 可信 Host 可观察的 peer 生命周期事件;不包含 owner/lease 等领域字段。 */\nexport interface PeerLifecycleEvent {\n /** active 建立、handoff 通知或关闭阶段。 */\n readonly event: \"active\" | \"handoff\" | \"closing\" | \"closed\";\n /** peer 物理连接的 opaque 标识。 */\n readonly peerId: string;\n /** 当前物理 endpoint 的框架 binding。 */\n readonly binding: RuntimeEndpointBinding;\n /** endpoint 的框架生命周期。 */\n readonly state: RuntimeEndpointState;\n /** closed 事件的真实 bounded drain 结果。 */\n readonly drain?: import(\"../contracts/lifecycle.js\").RuntimeDrainResult;\n /** 可信 Host 提供的 handoff 修订;WebLoom 不解释或选择 owner。 */\n readonly handoffRevision?: number;\n}\n\n/** 可信 Host 查询到的 active peer 只读投影。 */\nexport type ActivePeerSnapshot = Omit<PeerLifecycleEvent, \"event\" | \"drain\" | \"handoffRevision\"> & { readonly event: \"active\" };\n\nexport interface StartSharedWorkerAppOptions extends Omit<CreatePluginHostOptions, \"runtime\" | \"runtimeUnitImplementationRegistry\" | \"runtimeId\" | \"runtimeInstanceId\"> {\n /** Worker Runtime 逻辑标识。 */\n readonly id: string;\n /** Worker realm 的插件定义。 */\n readonly plugins: readonly RuntimePluginDefinition[];\n /** 对每个新 peer 顶层暴露的能力。 */\n readonly expose?: readonly RemoteCapability[];\n /** 同步配置 peer 级策略。 */\n readonly configurePeer?: (peer: PeerController) => void;\n /** configurePeer 可管理的显式 capability allowlist;未设置时不开放动态能力。 */\n readonly peerExposureAllowlist?: readonly RemoteCapability[];\n /** 可信 transport 配额;只能使用默认值或收紧。 */\n readonly limits?: RuntimeLimitsInput;\n /**\n * 浏览器唯一运行锁。锁名只由 runtime id 生成,不含构建号、版本号或\n * Worker URL;生产入口缺少 navigator.locks 时安全失败。manager 仅供\n * testing 入口注入,不能作为生产回退。\n */\n readonly runtimeLock?: RuntimeLockOptions;\n}\n\nexport interface StartSharedWorkerAppForTestingOptions extends StartSharedWorkerAppOptions {\n /** testing 入口注入的 SharedWorkerGlobalScope 替身。 */\n readonly globalScope: SharedWorkerScopeLike;\n /** 仅测试用:观察每次向所有 peer 广播前构建的公共快照。 */\n readonly snapshotObserver?: (snapshot: RuntimeStatusSnapshot) => void;\n}\n\nexport interface SharedWorkerApp {\n readonly runtimeKind: \"shared-worker\";\n readonly runtimeId: string;\n readonly runtimeInstanceId: string;\n ready(): Promise<void>;\n reconcile(): Promise<void>;\n state(): RuntimeStatusSnapshot;\n subscribe(listener: RuntimeStatusListener): () => void;\n inspect(): HostInspection;\n /** 只读查询当前仍处于 active 的物理 peer。 */\n activePeers(): readonly ActivePeerSnapshot[];\n /** 订阅 Host 可见的 peer active/closing/closed/handoff 事件。 */\n subscribePeerLifecycle(listener: (event: PeerLifecycleEvent) => void): () => void;\n /** 可信领域在完成自己的 owner/session 交接后报告 handoff;框架不选择 owner。 */\n notifyPeerHandoff(peerId: string, handoffRevision?: number): boolean;\n dispose(reason?: string): Promise<LifecycleDisposeResult>;\n}\n\ninterface Endpoint {\n readonly port: MessagePort;\n readonly scope: LifecycleScope;\n readonly binding: RuntimeEndpointBinding;\n readonly session: RuntimeEndpointSession;\n readonly transport: ReturnType<typeof createMessagePortRuntimeTransport>;\n readonly bridge: ReturnType<typeof createCapabilityBridge>;\n readonly provider: ReturnType<typeof createMessagePortServiceProvider>;\n readonly exposures: Map<string, ServiceReference>;\n readonly installTopLevelExposures: () => void;\n closed: boolean;\n revision: number;\n /** 已启动的 endpoint 收尾 Promise;保证 close 调用幂等且可等待。 */\n closePromise?: Promise<void>;\n}\n\n// testing 入口的进程内替身只用于没有浏览器 LockManager 的单测;生产入口\n// 永远不会把它作为 navigator.locks 的回退实现。\nconst testRuntimeLockManager = createInMemoryRuntimeLockManager();\n\nfunction makeId(prefix: string): string {\n try { if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") return `${prefix}:${crypto.randomUUID()}`; } catch { /* fallback */ }\n return `${prefix}:${Date.now().toString(36)}:${Math.random().toString(36).slice(2)}`;\n}\n\nfunction message(error: unknown): string { return error instanceof Error ? error.message : String(error); }\n\n/** 启动一个真实 SharedWorker Runtime;setup 异步完成前也会发布空 services 快照。 */\nfunction startSharedWorkerAppInternal(\n options: StartSharedWorkerAppOptions & Pick<StartSharedWorkerAppForTestingOptions, \"snapshotObserver\">,\n injectedScope?: SharedWorkerScopeLike,\n allowInjectedLockManager = false,\n): SharedWorkerApp {\n if (!options || typeof options.id !== \"string\" || options.id.trim() === \"\") throw new TypeError(\"SharedWorker runtime id must be a non-empty string\");\n const scope = injectedScope ?? ((globalThis as unknown as { onconnect?: unknown }).onconnect !== undefined ? globalThis as unknown as SharedWorkerScopeLike : undefined);\n if (!scope) throw new RuntimeInitializationError({ phase: \"validate\", error: \"startSharedWorkerApp must run in a SharedWorkerGlobalScope\" });\n const runtimeInstanceId = makeId(options.id);\n const limits = normalizeRuntimeLimits(options.limits);\n // One counter per direction is shared by every endpoint in this Runtime;\n // per-peer limits remain enforced inside each bridge/provider.\n const outboundBudget: RuntimeBudget = createRuntimeBudget(limits);\n const inboundBudget: RuntimeBudget = createRuntimeBudget(limits);\n const runtimeCodec = createRuntimeMessageCodec();\n const peerExposureAllowlist = options.peerExposureAllowlist === undefined\n ? undefined\n : new Set(options.peerExposureAllowlist.map((capability) => capabilityKey(capability)));\n const listeners = new Set<RuntimeStatusListener>();\n const peerLifecycleListeners = new Set<(event: PeerLifecycleEvent) => void>();\n const endpoints = new Set<Endpoint>();\n let manifests: readonly PluginManifest[] = [];\n let runtimeState: RuntimeSnapshot[\"state\"] = \"starting\";\n let revision = 0;\n let disposed = false;\n let accepting = true;\n let host: PluginHost | undefined;\n let disposePromise: Promise<LifecycleDisposeResult> | undefined;\n // 生产入口只接受浏览器 LockManager;传入的 manager 仅在 testing 入口\n // 生效,避免 Web Locks 不可用时悄悄退化成无锁或 localStorage 锁。\n const runtimeLockOptions = options.runtimeLock === undefined || allowInjectedLockManager\n ? options.runtimeLock\n : { messages: options.runtimeLock.messages };\n const runtimeLock = createRuntimeLock(options.id, runtimeLockOptions);\n let runtimeLockSettled = false;\n let runtimeFailure: { readonly code: string; readonly message: string; readonly phase: \"wait\" | \"validate\" | \"execute\" } | undefined;\n const pendingPorts: MessagePort[] = [];\n\n const emitPeerLifecycle = (event: PeerLifecycleEvent): void => {\n const frozen = Object.freeze({\n ...event,\n binding: Object.freeze({ ...event.binding }),\n ...(event.drain !== undefined ? { drain: Object.freeze({ ...event.drain }) } : {}),\n });\n for (const listener of [...peerLifecycleListeners]) {\n try { listener(frozen); } catch { /* observer isolation */ }\n }\n };\n\n const localSnapshot = (): RuntimeStatusSnapshot => {\n const currentHost = host;\n const units = currentHost ? currentHost.installed().flatMap((pluginId) => currentHost.state(pluginId).units.map((unit) => ({ pluginId: unit.pluginId, unitId: unit.unitId, runtime: unit.runtime, ...(unit.instanceId !== undefined ? { instanceId: unit.instanceId } : {}), state: unit.kind }))) : [];\n const services = runtimeState === \"ready\" && host ? host.serviceReferences().map((service) => ({ kind: service.kind, capabilityId: service.capabilityId, contractVersion: service.contractVersion, serviceInstanceId: service.serviceInstanceId, attributes: cloneFrozenAttributes(service.attributes), ...(service.grantId !== undefined ? { grantId: service.grantId } : {}), ...(service.authorizationRevision !== undefined ? { authorizationRevision: service.authorizationRevision } : {}) })) : [];\n return Object.freeze({\n protocolVersion: RUNTIME_PROTOCOL_VERSION,\n runtimeId: options.id,\n runtimeKind: \"shared-worker\",\n runtimeInstanceId,\n revision,\n state: runtimeState,\n units: Object.freeze(units),\n services: Object.freeze(services),\n ...(runtimeFailure ? { error: runtimeFailure.message, errorCode: runtimeFailure.code } : {}),\n });\n };\n const emit = (snapshot: RuntimeStatusSnapshot = localSnapshot()): void => { for (const listener of [...listeners]) { try { listener(snapshot); } catch { /* observer isolation */ } } };\n const projectedUnits = (exposures: ReadonlyMap<string, ServiceReference>): readonly RuntimeSnapshot[\"units\"][number][] => {\n if (!host || exposures.size === 0) return Object.freeze([]);\n // A peer may only learn about the provider units behind services explicitly\n // visible in its projection. The local Host snapshot remains complete for\n // trusted inspection; the wire projection must not be a hidden-provider\n // index.\n const owners = new Set(\n host.capabilities.registrations()\n .filter((registration) => exposures.has(capabilityKey(registration.capability)))\n .map((registration) => registration.ownerId),\n );\n if (owners.size === 0) return Object.freeze([]);\n return Object.freeze(host.installed().flatMap((pluginId) => host!.state(pluginId).units\n .filter((unit) => unit.instanceId !== undefined && owners.has(unit.instanceId))\n .map((unit) => ({ pluginId: unit.pluginId, unitId: unit.unitId, runtime: unit.runtime, ...(unit.instanceId !== undefined ? { instanceId: unit.instanceId } : {}), state: unit.kind }))));\n };\n const wireSnapshot = (endpoint: Endpoint, nextRevision = endpoint.revision, exposures: ReadonlyMap<string, ServiceReference> = endpoint.exposures, base = localSnapshot()): RuntimeSnapshot & { readonly type: typeof RUNTIME_SNAPSHOT_TYPE; readonly binding: RuntimeEndpointBinding } => {\n const services = [...exposures.values()].map((service) => ({ kind: service.kind, capabilityId: service.capabilityId, contractVersion: service.contractVersion, serviceInstanceId: service.serviceInstanceId, attributes: cloneFrozenAttributes(service.attributes), ...(service.grantId !== undefined ? { grantId: service.grantId } : {}), ...(service.authorizationRevision !== undefined ? { authorizationRevision: service.authorizationRevision } : {}) }));\n const state: RuntimeSnapshot[\"state\"] = base.state === \"disconnected\" ? \"failed\" : base.state;\n return { type: RUNTIME_SNAPSHOT_TYPE, protocolVersion: base.protocolVersion, runtimeId: base.runtimeId, runtimeKind: base.runtimeKind, runtimeInstanceId: base.runtimeInstanceId, revision: nextRevision, state, units: projectedUnits(exposures), services: state === \"ready\" ? services : [], binding: endpoint.binding };\n };\n const validateProjectedSnapshot = (endpoint: Endpoint, exposures: ReadonlyMap<string, ServiceReference>): void => {\n if (exposures.size > limits.maxSnapshotServices) throw new WebLoomError(\"resource_limit_exceeded\", \"Runtime service exposure limit exceeded\", \"dispatch\");\n const snapshot = wireSnapshot(endpoint, endpoint.revision + 1, exposures);\n runtimeCodec.encode(snapshot);\n validateDto(snapshot, { limits: { maxDepth: limits.maxDtoDepth, maxNodes: limits.maxDtoNodes, maxEdges: limits.maxDtoEdges, maxBudgetBytes: limits.maxMessageBudgetBytes }, phase: \"dispatch\" });\n };\n const publish = (endpoint: Endpoint, exposures = endpoint.exposures, base?: RuntimeStatusSnapshot, allowClosed = false): void => {\n if (endpoint.closed && !allowClosed) return;\n const nextRevision = endpoint.revision + 1;\n const snapshot = wireSnapshot(endpoint, nextRevision, exposures, base);\n endpoint.transport.send(snapshot);\n // postMessage performs structured-clone synchronously. Advance the\n // per-peer revision only after that operation has succeeded.\n endpoint.revision = nextRevision;\n };\n const publishAll = (): void => {\n const base = localSnapshot();\n options.snapshotObserver?.(base);\n for (const endpoint of endpoints) {\n try {\n if (runtimeFailure) {\n endpoint.transport.send({\n type: RUNTIME_ERROR_TYPE,\n protocolVersion: RUNTIME_PROTOCOL_VERSION,\n code: runtimeFailure.code,\n message: runtimeFailure.message,\n phase: runtimeFailure.phase,\n });\n }\n publish(endpoint, endpoint.exposures, base);\n } catch { closeEndpoint(endpoint, \"Runtime snapshot publication failed\"); }\n }\n emit(base);\n };\n\n const createEndpoint = (port: MessagePort): Endpoint => {\n if (!host) throw new Error(\"SharedWorker Host is unavailable\");\n const peerScope = host.rootScope.child(\"peer\", { attributes: { peerId: makeId(\"peer\") } });\n const transport = createMessagePortRuntimeTransport(port, { limits });\n const binding = createRuntimeEndpointBinding(runtimeInstanceId);\n const session = createRuntimeEndpointSession(binding);\n const bridge = createCapabilityBridge({ transport, remoteRuntimeKind: \"window-main\", limits, budget: outboundBudget, binding, session });\n const exposures = new Map<string, ServiceReference>();\n const exposurePolicies = new Map<string, PeerExposureOptions>();\n const peerId = peerScope.identity.attributes.peerId as string | undefined ?? makeId(\"peer\");\n const peerScopeView = createPeerScopeView(peerScope);\n const peerView: CapabilityPeer = createCapabilityPeerView({ peerId, binding, scope: peerScopeView, bridge, capabilityScope: peerScope });\n let endpointForDisconnect: Endpoint | undefined;\n const exposeGroup = (entries: readonly { readonly capability: RemoteCapability; readonly options?: PeerExposureOptions }[], source: \"dynamic\" | \"top-level\" = \"dynamic\"): { revoke(): void } => {\n if (peerScope.state !== \"active\") throw new WebLoomError(\"service_revoked\", \"Peer scope is not active\", \"dispatch\", { capabilityId: entries[0]?.capability.id });\n const prepared: { key: string; reference: ServiceReference; options: PeerExposureOptions }[] = [];\n const keys = new Set<string>();\n for (const entry of entries) {\n const capability = entry.capability;\n const exposureOptions = entry.options ?? {};\n const key = capabilityKey(capability);\n if (source === \"dynamic\" && (!peerExposureAllowlist || !peerExposureAllowlist.has(key))) {\n throw new WebLoomError(\"capability_unavailable\", \"Capability is outside the peer exposure allowlist\", \"dispatch\", { capabilityId: capability.id });\n }\n const registration = host?.capabilities.registration(capability);\n if (!registration || (capability.kind !== \"rpc\" && capability.kind !== \"stream\") || registration.capability.kind !== capability.kind) {\n throw new Error(`Capability \"${capability.id}\" is not a remote capability registered by this Host`);\n }\n if (keys.has(key) || exposures.has(key)) throw new Error(`Capability \"${capability.id}\" is already exposed to this peer`);\n keys.add(key);\n const reference: ServiceReference = Object.freeze({\n ...registration.reference,\n serviceInstanceId: makeId(`exposure:${peerId}:${capability.id}`),\n attributes: cloneFrozenAttributes(exposureOptions.attributes ?? registration.reference.attributes),\n ...(exposureOptions.grantId !== undefined ? { grantId: exposureOptions.grantId } : {}),\n ...(exposureOptions.authorizationRevision !== undefined ? { authorizationRevision: exposureOptions.authorizationRevision } : {}),\n });\n prepared.push({ key, reference, options: exposureOptions });\n }\n const projected = new Map(exposures);\n for (const item of prepared) projected.set(item.key, item.reference);\n if (endpointForDisconnect) validateProjectedSnapshot(endpointForDisconnect, projected);\n else if (projected.size > limits.maxSnapshotServices) throw new WebLoomError(\"resource_limit_exceeded\", \"Runtime service exposure limit exceeded\", \"dispatch\");\n\n let active = true;\n let committed = false;\n const removers: (() => void)[] = [];\n const removeExposure = (key: string): void => {\n if (!active || !committed || !exposures.delete(key)) return;\n exposurePolicies.delete(key);\n // If the peer scope itself is being revoked, the group callback below\n // performs one grouped removal/publication. Avoid exposing an\n // intermediate per-item revision during that synchronous fence.\n if (endpointForDisconnect && peerScope.state === \"active\") {\n try { publish(endpointForDisconnect); } catch { closeEndpoint(endpointForDisconnect, \"Runtime snapshot publication failed\"); }\n }\n };\n const removeGroup = (): void => {\n if (!active) return;\n active = false;\n let changed = false;\n for (const item of prepared) {\n changed = exposures.delete(item.key) || changed;\n exposurePolicies.delete(item.key);\n }\n for (const remove of removers.splice(0)) remove();\n if (changed && endpointForDisconnect) {\n try { publish(endpointForDisconnect); } catch { closeEndpoint(endpointForDisconnect, \"Runtime snapshot publication failed\"); }\n }\n };\n try {\n for (const item of prepared) {\n if (item.options.scope) {\n if (item.options.scope.state !== \"active\") throw new WebLoomError(\"service_revoked\", \"Capability exposure scope is not active\", \"dispatch\", { capabilityId: item.reference.capabilityId });\n removers.push(item.options.scope.onRevoke(() => removeExposure(item.key)));\n }\n }\n removers.push(peerScope.onRevoke(() => removeGroup()));\n } catch (error) {\n for (const remove of removers.splice(0)) remove();\n throw error;\n }\n\n // The projected snapshot is sent before the local maps are changed. A\n // synchronous postMessage failure therefore cannot leave a locally\n // committed service that the peer never observed. Map insertion itself\n // is then a non-throwing commit step and advances exactly one revision\n // for the complete group.\n try {\n if (prepared.length > 0 && endpointForDisconnect) publish(endpointForDisconnect, projected);\n } catch (error) {\n active = false;\n for (const remove of removers.splice(0)) remove();\n throw error;\n }\n if (peerScope.state !== \"active\" || prepared.some((item) => item.options.scope !== undefined && item.options.scope.state !== \"active\")) {\n active = false;\n for (const remove of removers.splice(0)) remove();\n throw new WebLoomError(\"service_revoked\", \"Capability exposure scope was revoked before commit\", \"dispose\", { capabilityId: prepared[0]?.reference.capabilityId });\n }\n for (const item of prepared) {\n exposures.set(item.key, item.reference);\n exposurePolicies.set(item.key, item.options);\n }\n committed = true;\n // Scope callbacks are registered above and only run after this task; the\n // explicit handle remains the first-class idempotent revocation path.\n return { revoke: removeGroup };\n };\n let disconnectRequested: string | undefined;\n const configuredExposureKeys = new Set<string>();\n const peer: PeerController = {\n peerId,\n binding,\n get endpointState() { return session.state; },\n get runtimeInstanceId() { return bridge.runtimeInstanceId; },\n runtime: \"window-main\",\n scope: peerScope,\n view: peerView,\n capability: (capability) => bridge.getClient(capability, peerScope),\n beginClose(reason = \"Peer endpoint closing\") { session.beginClose(reason); },\n drain(timeoutMs) { return bridge.drain(timeoutMs); },\n expose(capability, exposureOptions = {}) {\n const result = exposeGroup([{ capability, options: exposureOptions }]);\n configuredExposureKeys.add(capabilityKey(capability));\n return result;\n },\n exposeGroup(entries) {\n const result = exposeGroup(entries);\n for (const entry of entries) configuredExposureKeys.add(capabilityKey(entry.capability));\n return result;\n },\n disconnect(reason = \"Peer disconnected\") {\n if (endpointForDisconnect) closeEndpoint(endpointForDisconnect, reason);\n else { disconnectRequested = reason; peerScope.revoke(reason); }\n },\n inspect: () => Object.freeze({ peerId, scopeId: peerScope.identity.scopeId, state: peerScope.state, exposedServiceCount: exposures.size, pendingCallCount: bridge.pendingCallCount, activeStreamCount: bridge.activeStreamCount }),\n };\n const installTopLevelExposures = (): void => {\n const entries: { readonly capability: RemoteCapability }[] = [];\n for (const capability of options.expose ?? []) {\n const key = capabilityKey(capability);\n if (exposures.has(key)) {\n if (configuredExposureKeys.has(key)) throw new Error(`Capability \"${capability.id}\" is exposed by configurePeer and top-level expose`);\n continue;\n }\n if (!host?.capabilities.registration(capability)) continue;\n entries.push({ capability });\n }\n // This is an installation path, not a configurePeer-owned exposure. A\n // single projected snapshot keeps the whole top-level set atomic.\n if (entries.length > 0) exposeGroup(entries, \"top-level\");\n };\n try { options.configurePeer?.(peer); } catch (error) {\n peerScope.revoke(\"configurePeer failed\");\n bridge.dispose(\"configurePeer failed\");\n transport.close?.();\n throw error;\n }\n const provider = createMessagePortServiceProvider({\n transport,\n peerScope,\n peer: peerView,\n binding,\n session,\n budget: inboundBudget,\n limits,\n services: () => [...exposures.values()],\n peerForCall: (_call, reference) => {\n const registration = host?.capabilities.registration({ kind: reference.kind, id: reference.capabilityId, version: reference.contractVersion });\n return createCapabilityPeerView({ peerId, binding, scope: peerScopeView, bridge, allowed: registration?.peerDependencies ?? [], capabilityScope: peerScope });\n },\n prepareRequest: (call) => {\n if (!host) throw new WebLoomError(\"service_stale\", \"SharedWorker Host is unavailable\", \"dispatch\");\n const registration = host.capabilities.registration({ kind: call.mode === \"stream\" ? \"stream\" : \"rpc\", id: call.capabilityId, version: call.contractVersion });\n if (!registration || registration.capability.kind !== (call.mode === \"stream\" ? \"stream\" : \"rpc\")) throw new WebLoomError(\"service_stale\", \"Runtime service exposure is stale\", \"dispatch\");\n const parser = registration.capability as typeof registration.capability & { request: { parse(value: unknown): unknown }; transfer?: { request?: (value: unknown) => readonly Transferable[] } };\n let value: unknown;\n try { value = parser.request.parse(call.request); } catch { throw new WebLoomError(\"request_validation_failed\", \"Capability request failed validation\", \"receive\"); }\n return { value, transfer: parser.transfer?.request?.(value) };\n },\n handleCall: async ({ message: call, request, reference, signal, deadlineAt, peer: callPeer }) => {\n if (!host) throw new Error(\"SharedWorker Host is unavailable\");\n const registration = host.capabilities.registration({ kind: reference.kind, id: reference.capabilityId, version: reference.contractVersion });\n const key = capabilityKey({ kind: reference.kind, id: reference.capabilityId, version: reference.contractVersion });\n const policy = exposurePolicies.get(key);\n if (!registration || !exposures.has(key)) throw new Error(\"Runtime service exposure is stale\");\n const handlerReference = reference;\n const context = { signal, deadlineAt, ...(call.operationId !== undefined ? { operationId: call.operationId } : {}), reference: handlerReference, binding: call.binding, origin: \"remote\" as const, peer: callPeer };\n if (policy?.authorize && !(await policy.authorize(context, request))) throw new WebLoomError(\"permission_denied\", \"Peer capability authorization denied\", \"dispatch\", { capabilityId: reference.capabilityId, serviceInstanceId: reference.serviceInstanceId });\n if (exposures.get(key)?.serviceInstanceId !== handlerReference.serviceInstanceId) throw new WebLoomError(\"service_stale\", \"Runtime service exposure was replaced while authorization was pending\", \"dispatch\", { serviceInstanceId: handlerReference.serviceInstanceId });\n if (peerScope.state !== \"active\" || signal.aborted) throw new WebLoomError(\"service_revoked\", \"Peer scope was revoked\", \"dispose\", { serviceInstanceId: reference.serviceInstanceId });\n if (policy?.scope && policy.scope.state !== \"active\") throw new WebLoomError(\"service_revoked\", \"Peer capability authorization scope is revoked\", \"dispose\", { serviceInstanceId: reference.serviceInstanceId });\n const handler = registration.handler as ((value: unknown, context: import(\"../contracts/capability.js\").HandlerCallContext) => unknown | Promise<unknown>) | undefined;\n if (!handler) throw new WebLoomError(\"service_stale\", \"Runtime service handler is unavailable\", \"dispatch\");\n return handler(request, context);\n },\n prepareResult: (value, call) => {\n const registration = host?.capabilities.registration({ kind: \"rpc\", id: call.capabilityId, version: call.contractVersion });\n if (!registration || registration.capability.kind !== \"rpc\") throw new Error(\"RPC capability registration disappeared\");\n const rpc = registration.capability as typeof registration.capability & { response: { parse(value: unknown): unknown }; transfer?: { response?: (value: unknown) => readonly Transferable[] } };\n const parsed = rpc.response.parse(value);\n const transfer = (rpc.transfer?.response?.(parsed) ?? []);\n return { value: parsed, transfer };\n },\n prepareItem: (value, call) => {\n const registration = host?.capabilities.registration({ kind: \"stream\", id: call.capabilityId, version: call.contractVersion });\n if (!registration || registration.capability.kind !== \"stream\") throw new Error(\"stream capability registration disappeared\");\n const stream = registration.capability as typeof registration.capability & { item: { parse(value: unknown): unknown }; transfer?: { item?: (value: unknown) => readonly Transferable[] } };\n const parsed = stream.item.parse(value);\n const transfer = stream.transfer?.item?.(parsed) ?? [];\n return { value: parsed, transfer };\n },\n });\n const endpoint: Endpoint = { port, scope: peerScope, binding, session, transport, bridge, provider, exposures, installTopLevelExposures, closed: false, revision: 0 };\n endpointForDisconnect = endpoint;\n endpoints.add(endpoint);\n emitPeerLifecycle({ event: \"active\", peerId, binding, state: \"active\" });\n // A remote RuntimeHandle may close the physical endpoint directly. The\n // bridge/provider session can acknowledge that close, but the Worker\n // still owns the peer controller and its domain exposure until the\n // endpoint registry is revoked. Route every terminal session transition\n // through the same local endpoint teardown so configurePeer owners\n // observe the physical peer as closed as well.\n session.onClosed(() => closeEndpoint(endpoint, \"Runtime endpoint closed\"));\n try {\n if (disconnectRequested !== undefined) closeEndpoint(endpoint, disconnectRequested);\n installTopLevelExposures();\n // Window and Worker may both publish the first snapshot. Incoming snapshots\n // are consumed only by the bridge; no hello/handshake control message exists.\n publish(endpoint);\n } catch (error) {\n closeEndpoint(endpoint, \"SharedWorker endpoint initialization failed\");\n throw error;\n }\n return endpoint;\n };\n\n const beginCloseEndpoint = (endpoint: Endpoint, reason: string): void => {\n if (endpoint.closed) return;\n // The peer is removed from admission and all exposures are revoked before\n // any asynchronous drain or physical MessagePort close begins.\n endpoint.closed = true;\n endpoints.delete(endpoint);\n endpoint.scope.revoke(reason);\n endpoint.provider.beginClose(reason);\n endpoint.bridge.beginClose(reason);\n emitPeerLifecycle({ event: \"closing\", peerId: endpoint.scope.identity.attributes.peerId as string, binding: endpoint.binding, state: \"closing\" });\n };\n\n const closeEndpoint = (endpoint: Endpoint, reason: string): Promise<void> => {\n if (endpoint.closePromise) return endpoint.closePromise;\n beginCloseEndpoint(endpoint, reason);\n endpoint.closePromise = (async () => {\n let providerDrain;\n let bridgeDrain;\n try {\n // Both drains are started only after the synchronous admission fence\n // above. The public app.dispose() promise includes this handshake.\n [providerDrain, bridgeDrain] = await Promise.all([endpoint.provider.drain(), endpoint.bridge.drain()]);\n } catch {\n providerDrain = { state: endpoint.session.state, drained: false, timedOut: true, pendingExecutions: endpoint.provider.executionCount() };\n bridgeDrain = { state: endpoint.session.state, drained: false, timedOut: true, pendingExecutions: endpoint.bridge.pendingCallCount + endpoint.bridge.activeStreamCount };\n }\n try {\n await endpoint.scope.dispose({ reason });\n } catch {\n // The endpoint's transport must still be closed when a domain cleanup\n // callback fails; the close event reports the bounded drain result.\n }\n endpoint.provider.dispose();\n endpoint.bridge.dispose(reason);\n endpoint.transport.close?.();\n endpoint.session.close();\n emitPeerLifecycle({ event: \"closed\", peerId: endpoint.scope.identity.attributes.peerId as string, binding: endpoint.binding, state: \"closed\", drain: bridgeDrain.drained && providerDrain.drained ? bridgeDrain : { ...bridgeDrain, drained: false, timedOut: bridgeDrain.timedOut || providerDrain.timedOut, pendingExecutions: Math.max(bridgeDrain.pendingExecutions, providerDrain.pendingExecutions) } });\n })();\n return endpoint.closePromise;\n };\n const sendTerminalSnapshot = (port: MessagePort): void => {\n try {\n port.start();\n const binding = createRuntimeEndpointBinding(runtimeInstanceId);\n port.postMessage({ ...localSnapshot(), type: RUNTIME_SNAPSHOT_TYPE, binding });\n // Give the posted terminal snapshot a turn to cross the port before\n // closing a connection made after the Worker Runtime has stopped.\n setTimeout(() => { try { port.close(); } catch { /* noop */ } }, 0);\n } catch { try { port.close(); } catch { /* noop */ } }\n };\n const sendRuntimeFailure = (port: MessagePort): void => {\n if (!runtimeFailure) { sendTerminalSnapshot(port); return; }\n try {\n port.start();\n port.postMessage({\n type: RUNTIME_ERROR_TYPE,\n protocolVersion: RUNTIME_PROTOCOL_VERSION,\n code: runtimeFailure.code,\n message: runtimeFailure.message,\n phase: runtimeFailure.phase,\n });\n setTimeout(() => { try { port.close(); } catch { /* noop */ } }, 0);\n } catch { try { port.close(); } catch { /* noop */ } }\n };\n const drainPendingPorts = (): void => {\n const ports = pendingPorts.splice(0);\n for (const port of ports) {\n if (!accepting || disposed || endpoints.size >= limits.maxPeers) {\n sendTerminalSnapshot(port);\n continue;\n }\n if (runtimeFailure) {\n sendRuntimeFailure(port);\n continue;\n }\n try { createEndpoint(port); } catch { try { port.close(); } catch { /* noop */ } }\n }\n };\n const failPendingPorts = (): void => {\n const ports = pendingPorts.splice(0);\n for (const port of ports) sendRuntimeFailure(port);\n };\n scope.onconnect = (event) => {\n for (const port of event.ports ?? []) {\n if (!accepting || disposed || endpoints.size >= limits.maxPeers) { sendTerminalSnapshot(port); continue; }\n if (!runtimeLockSettled) {\n if (pendingPorts.length >= limits.maxPeers) sendTerminalSnapshot(port);\n else pendingPorts.push(port);\n continue;\n }\n if (runtimeFailure) { sendRuntimeFailure(port); continue; }\n try { createEndpoint(port); } catch { try { port.close(); } catch { /* noop */ } }\n }\n };\n\n const ready = runtimeLock.acquired.then(async () => {\n if (disposed) throw new Error(\"SharedWorker Runtime was disposed before the browser lock was acquired\");\n runtimeLockSettled = true;\n // 运行锁是最外层边界:拿到浏览器锁之前不物化插件、不创建 Host、\n // 不接受 peer。冲突 Worker 不会启动任何插件。\n const materialized = materializePluginDefinitions(options.plugins, \"shared-worker\");\n manifests = materialized.map((item) => item.manifest);\n const implementations = createRuntimeUnitImplementationRegistry(materialized.map((item) => ({ pluginId: item.manifest.id, unitId: item.unitId, setup: item.setup, capabilities: item.capabilities })));\n const { id: _id, plugins: _plugins, expose: _expose, configurePeer: _configurePeer, runtimeLock: _runtimeLock, ...hostOptions } = options;\n host = createPluginHost({ ...hostOptions, runtime: \"shared-worker\", runtimeId: options.id, runtimeInstanceId, runtimeUnitImplementationRegistry: implementations });\n host.subscribe(() => { if (runtimeState === \"ready\" && !disposed) { revision += 1; publishAll(); } else emit(); });\n drainPendingPorts();\n await host.registerAll(manifests);\n // A peer may have been connected while the Host was starting. Installing\n // the same top-level projection again is idempotent.\n for (const endpoint of endpoints) endpoint.installTopLevelExposures();\n if (!disposed) { runtimeState = \"ready\"; revision += 1; publishAll(); }\n }).catch((error) => {\n if (!disposed) {\n runtimeState = \"failed\";\n const code = error instanceof RuntimeLockError\n ? error.code\n : (error && typeof error === \"object\" && typeof (error as { code?: unknown }).code === \"string\" ? (error as { code: string }).code : \"runtime_initialization_failed\");\n runtimeFailure = { code, message: message(error), phase: error instanceof RuntimeLockError ? \"wait\" : \"execute\" };\n runtimeLockSettled = true;\n failPendingPorts();\n publishAll();\n }\n void runtimeLock.release();\n if (error instanceof RuntimeLockError) throw error;\n throw new RuntimeInitializationError({ phase: \"startup\", error: message(error) });\n });\n void ready.catch(() => undefined);\n const app: SharedWorkerApp = {\n runtimeKind: \"shared-worker\", runtimeId: options.id, runtimeInstanceId,\n ready: () => ready,\n reconcile: () => host?.reconcile() ?? Promise.resolve(),\n state: localSnapshot,\n subscribe(listener) { listeners.add(listener); listener(localSnapshot()); return () => listeners.delete(listener); },\n inspect: () => host ? { ...host.inspect(), peerCount: endpoints.size } : { runtimeId: options.id, runtimeKind: \"shared-worker\", runtimeInstanceId, version: 0, pluginCount: 0, peerCount: endpoints.size, pendingCallCount: 0, activeStreamCount: 0, plugins: [] },\n activePeers: () => Object.freeze([...endpoints].filter((endpoint) => !endpoint.closed && endpoint.session.state === \"active\").map((endpoint) => Object.freeze({ event: \"active\" as const, peerId: endpoint.scope.identity.attributes.peerId as string, binding: Object.freeze({ ...endpoint.binding }), state: \"active\" as const }))),\n subscribePeerLifecycle(listener) { peerLifecycleListeners.add(listener); for (const endpoint of endpoints) if (!endpoint.closed && endpoint.session.state === \"active\") listener(Object.freeze({ event: \"active\" as const, peerId: endpoint.scope.identity.attributes.peerId as string, binding: Object.freeze({ ...endpoint.binding }), state: \"active\" as const })); return () => peerLifecycleListeners.delete(listener); },\n notifyPeerHandoff(peerId, handoffRevision) {\n const endpoint = [...endpoints].find((candidate) => !candidate.closed && candidate.scope.identity.attributes.peerId === peerId);\n if (!endpoint || endpoint.session.state !== \"active\") return false;\n emitPeerLifecycle({ event: \"handoff\", peerId, binding: endpoint.binding, state: \"active\", ...(handoffRevision !== undefined ? { handoffRevision } : {}) });\n return true;\n },\n dispose(reason = \"shared worker runtime disposed\") {\n if (disposePromise) return disposePromise;\n accepting = false;\n disposed = true;\n runtimeLockSettled = true;\n for (const port of pendingPorts.splice(0)) sendTerminalSnapshot(port);\n runtimeState = \"stopping\";\n // Capture before publishing the terminal snapshot: a synchronous\n // postMessage failure during publishAll may itself close an endpoint.\n const endpointsToClose = [...endpoints];\n publishAll();\n // Fence every currently connected endpoint synchronously before the\n // first await. This closes admission and revokes peer capabilities while\n // the Host is still alive, then waits for each bounded close handshake.\n for (const endpoint of endpointsToClose) beginCloseEndpoint(endpoint, reason);\n disposePromise = (async () => {\n const result = await (host ? host.dispose(reason) : Promise.resolve({ scopeId: `runtime:${runtimeInstanceId}`, state: \"stopped\" as const, attempted: 0, released: 0, pending: [], errors: [], cleanupIncomplete: false }));\n runtimeState = \"disposed\";\n const terminal = localSnapshot();\n options.snapshotObserver?.(terminal);\n // Endpoint admission is already fenced, but its transport stays alive\n // long enough for every Window to observe the terminal disposed\n // snapshot before the bounded close handshake tears it down.\n for (const endpoint of endpointsToClose) {\n try { publish(endpoint, endpoint.exposures, terminal, true); } catch { /* close path still proceeds */ }\n }\n emit(terminal);\n const endpointClosures = endpointsToClose.map((endpoint) => closeEndpoint(endpoint, reason));\n await Promise.all(endpointClosures);\n await runtimeLock.release();\n return result;\n })();\n return disposePromise;\n },\n };\n return app;\n}\n\n/** 生产入口:只从真实 SharedWorkerGlobalScope 获取连接事件。 */\nexport function startSharedWorkerApp(options: StartSharedWorkerAppOptions): SharedWorkerApp {\n return startSharedWorkerAppInternal(options);\n}\n\n/** testing/advanced harness 入口;生产包的 startSharedWorkerApp 不接受 scope 注入。 */\nexport function startSharedWorkerAppForTesting(options: StartSharedWorkerAppForTestingOptions): SharedWorkerApp {\n const { globalScope, ...runtimeOptions } = options;\n // Node/MessageChannel 测试没有浏览器 navigator;默认使用显式的进程内\n // 测试替身。测试“缺少 Web Locks”时传入 runtimeLock: { manager: null }。\n const withTestLock = runtimeOptions.runtimeLock === undefined\n ? { ...runtimeOptions, runtimeLock: { manager: testRuntimeLockManager } }\n : runtimeOptions;\n return startSharedWorkerAppInternal(withTestLock, globalScope, true);\n}\n"]}
|