threadforge 0.1.1 → 0.2.1
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 +52 -20
- package/bin/forge.js +2 -1058
- package/bin/host-commands.d.ts +2 -0
- package/bin/host-commands.d.ts.map +1 -0
- package/bin/host-commands.js +7 -8
- package/bin/platform-commands.d.ts +2 -0
- package/bin/platform-commands.d.ts.map +1 -0
- package/bin/platform-commands.js +118 -36
- package/dist/cli/base-command.d.ts +12 -0
- package/dist/cli/base-command.d.ts.map +1 -0
- package/dist/cli/base-command.js +25 -0
- package/dist/cli/base-command.js.map +1 -0
- package/dist/cli/commands/build.d.ts +10 -0
- package/dist/cli/commands/build.d.ts.map +1 -0
- package/dist/cli/commands/build.js +110 -0
- package/dist/cli/commands/build.js.map +1 -0
- package/dist/cli/commands/deploy.d.ts +12 -0
- package/dist/cli/commands/deploy.d.ts.map +1 -0
- package/dist/cli/commands/deploy.js +143 -0
- package/dist/cli/commands/deploy.js.map +1 -0
- package/dist/cli/commands/dev.d.ts +10 -0
- package/dist/cli/commands/dev.d.ts.map +1 -0
- package/dist/cli/commands/dev.js +138 -0
- package/dist/cli/commands/dev.js.map +1 -0
- package/dist/cli/commands/generate.d.ts +10 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/generate.js +76 -0
- package/dist/cli/commands/generate.js.map +1 -0
- package/dist/cli/commands/host.d.ts +8 -0
- package/dist/cli/commands/host.d.ts.map +1 -0
- package/dist/cli/commands/host.js +20 -0
- package/dist/cli/commands/host.js.map +1 -0
- package/dist/cli/commands/init.d.ts +16 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +246 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/platform.d.ts +8 -0
- package/dist/cli/commands/platform.d.ts.map +1 -0
- package/dist/cli/commands/platform.js +20 -0
- package/dist/cli/commands/platform.js.map +1 -0
- package/dist/cli/commands/restart.d.ts +8 -0
- package/dist/cli/commands/restart.d.ts.map +1 -0
- package/dist/cli/commands/restart.js +13 -0
- package/dist/cli/commands/restart.js.map +1 -0
- package/dist/cli/commands/scaffold/frontend.d.ts +10 -0
- package/dist/cli/commands/scaffold/frontend.d.ts.map +1 -0
- package/dist/cli/commands/scaffold/frontend.js +130 -0
- package/dist/cli/commands/scaffold/frontend.js.map +1 -0
- package/dist/cli/commands/scaffold/react.d.ts +7 -0
- package/dist/cli/commands/scaffold/react.d.ts.map +1 -0
- package/dist/cli/commands/scaffold/react.js +12 -0
- package/dist/cli/commands/scaffold/react.js.map +1 -0
- package/dist/cli/commands/scale.d.ts +8 -0
- package/dist/cli/commands/scale.d.ts.map +1 -0
- package/dist/cli/commands/scale.js +13 -0
- package/dist/cli/commands/scale.js.map +1 -0
- package/dist/cli/commands/start.d.ts +10 -0
- package/dist/cli/commands/start.d.ts.map +1 -0
- package/dist/cli/commands/start.js +71 -0
- package/dist/cli/commands/start.js.map +1 -0
- package/dist/cli/commands/status.d.ts +11 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +60 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/stop.d.ts +10 -0
- package/dist/cli/commands/stop.d.ts.map +1 -0
- package/dist/cli/commands/stop.js +89 -0
- package/dist/cli/commands/stop.js.map +1 -0
- package/dist/cli/util/config-discovery.d.ts +8 -0
- package/dist/cli/util/config-discovery.d.ts.map +1 -0
- package/dist/cli/util/config-discovery.js +70 -0
- package/dist/cli/util/config-discovery.js.map +1 -0
- package/dist/cli/util/config-patcher.d.ts +17 -0
- package/dist/cli/util/config-patcher.d.ts.map +1 -0
- package/dist/cli/util/config-patcher.js +439 -0
- package/dist/cli/util/config-patcher.js.map +1 -0
- package/dist/cli/util/frontend-dev.d.ts +8 -0
- package/dist/cli/util/frontend-dev.d.ts.map +1 -0
- package/dist/cli/util/frontend-dev.js +117 -0
- package/dist/cli/util/frontend-dev.js.map +1 -0
- package/dist/cli/util/process.d.ts +5 -0
- package/dist/cli/util/process.d.ts.map +1 -0
- package/dist/cli/util/process.js +17 -0
- package/dist/cli/util/process.js.map +1 -0
- package/dist/cli/util/templates.d.ts +10 -0
- package/dist/cli/util/templates.d.ts.map +1 -0
- package/dist/cli/util/templates.js +157 -0
- package/dist/cli/util/templates.js.map +1 -0
- package/dist/core/AlertSink.d.ts +83 -0
- package/dist/core/AlertSink.d.ts.map +1 -0
- package/dist/core/AlertSink.js +126 -0
- package/dist/core/AlertSink.js.map +1 -0
- package/dist/core/DirectMessageBus.d.ts +88 -0
- package/dist/core/DirectMessageBus.d.ts.map +1 -0
- package/dist/core/DirectMessageBus.js +352 -0
- package/dist/core/DirectMessageBus.js.map +1 -0
- package/dist/core/EndpointResolver.d.ts +111 -0
- package/dist/core/EndpointResolver.d.ts.map +1 -0
- package/dist/core/EndpointResolver.js +336 -0
- package/dist/core/EndpointResolver.js.map +1 -0
- package/dist/core/ForgeContext.d.ts +221 -0
- package/dist/core/ForgeContext.d.ts.map +1 -0
- package/dist/core/ForgeContext.js +1169 -0
- package/dist/core/ForgeContext.js.map +1 -0
- package/dist/core/ForgeEndpoints.d.ts +71 -0
- package/dist/core/ForgeEndpoints.d.ts.map +1 -0
- package/dist/core/ForgeEndpoints.js +442 -0
- package/dist/core/ForgeEndpoints.js.map +1 -0
- package/dist/core/ForgeHost.d.ts +82 -0
- package/dist/core/ForgeHost.d.ts.map +1 -0
- package/dist/core/ForgeHost.js +107 -0
- package/dist/core/ForgeHost.js.map +1 -0
- package/dist/core/ForgePlatform.d.ts +96 -0
- package/dist/core/ForgePlatform.d.ts.map +1 -0
- package/dist/core/ForgePlatform.js +136 -0
- package/dist/core/ForgePlatform.js.map +1 -0
- package/dist/core/ForgeWebSocket.d.ts +56 -0
- package/dist/core/ForgeWebSocket.d.ts.map +1 -0
- package/dist/core/ForgeWebSocket.js +415 -0
- package/dist/core/ForgeWebSocket.js.map +1 -0
- package/dist/core/Ingress.d.ts +329 -0
- package/dist/core/Ingress.d.ts.map +1 -0
- package/dist/core/Ingress.js +694 -0
- package/dist/core/Ingress.js.map +1 -0
- package/dist/core/Interceptors.d.ts +134 -0
- package/dist/core/Interceptors.d.ts.map +1 -0
- package/dist/core/Interceptors.js +416 -0
- package/dist/core/Interceptors.js.map +1 -0
- package/dist/core/Logger.d.ts +20 -0
- package/dist/core/Logger.d.ts.map +1 -0
- package/dist/core/Logger.js +77 -0
- package/dist/core/Logger.js.map +1 -0
- package/dist/core/MessageBus.d.ts +15 -0
- package/dist/core/MessageBus.d.ts.map +1 -0
- package/dist/core/MessageBus.js +18 -0
- package/dist/core/MessageBus.js.map +1 -0
- package/dist/core/Prometheus.d.ts +80 -0
- package/dist/core/Prometheus.d.ts.map +1 -0
- package/dist/core/Prometheus.js +332 -0
- package/dist/core/Prometheus.js.map +1 -0
- package/dist/core/RequestContext.d.ts +214 -0
- package/dist/core/RequestContext.d.ts.map +1 -0
- package/dist/core/RequestContext.js +556 -0
- package/dist/core/RequestContext.js.map +1 -0
- package/dist/core/Router.d.ts +45 -0
- package/dist/core/Router.d.ts.map +1 -0
- package/dist/core/Router.js +285 -0
- package/dist/core/Router.js.map +1 -0
- package/dist/core/RoutingStrategy.d.ts +116 -0
- package/dist/core/RoutingStrategy.d.ts.map +1 -0
- package/dist/core/RoutingStrategy.js +306 -0
- package/dist/core/RoutingStrategy.js.map +1 -0
- package/dist/core/RpcConfig.d.ts +72 -0
- package/dist/core/RpcConfig.d.ts.map +1 -0
- package/dist/core/RpcConfig.js +127 -0
- package/dist/core/RpcConfig.js.map +1 -0
- package/dist/core/SignatureCache.d.ts +81 -0
- package/dist/core/SignatureCache.d.ts.map +1 -0
- package/dist/core/SignatureCache.js +172 -0
- package/dist/core/SignatureCache.js.map +1 -0
- package/dist/core/StaticFileServer.d.ts +34 -0
- package/dist/core/StaticFileServer.d.ts.map +1 -0
- package/dist/core/StaticFileServer.js +497 -0
- package/dist/core/StaticFileServer.js.map +1 -0
- package/dist/core/Supervisor.d.ts +198 -0
- package/dist/core/Supervisor.d.ts.map +1 -0
- package/dist/core/Supervisor.js +1418 -0
- package/dist/core/Supervisor.js.map +1 -0
- package/dist/core/ThreadAllocator.d.ts +52 -0
- package/dist/core/ThreadAllocator.d.ts.map +1 -0
- package/dist/core/ThreadAllocator.js +174 -0
- package/dist/core/ThreadAllocator.js.map +1 -0
- package/dist/core/WorkerChannelManager.d.ts +130 -0
- package/dist/core/WorkerChannelManager.d.ts.map +1 -0
- package/dist/core/WorkerChannelManager.js +956 -0
- package/dist/core/WorkerChannelManager.js.map +1 -0
- package/dist/core/config-enums.d.ts +41 -0
- package/dist/core/config-enums.d.ts.map +1 -0
- package/dist/core/config-enums.js +59 -0
- package/dist/core/config-enums.js.map +1 -0
- package/dist/core/config.d.ts +159 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +694 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/host-config.d.ts +146 -0
- package/dist/core/host-config.d.ts.map +1 -0
- package/dist/core/host-config.js +312 -0
- package/dist/core/host-config.js.map +1 -0
- package/dist/core/ipc-errors.d.ts +27 -0
- package/dist/core/ipc-errors.d.ts.map +1 -0
- package/dist/core/ipc-errors.js +36 -0
- package/dist/core/ipc-errors.js.map +1 -0
- package/dist/core/network-utils.d.ts +35 -0
- package/dist/core/network-utils.d.ts.map +1 -0
- package/dist/core/network-utils.js +145 -0
- package/dist/core/network-utils.js.map +1 -0
- package/dist/core/platform-config.d.ts +142 -0
- package/dist/core/platform-config.d.ts.map +1 -0
- package/dist/core/platform-config.js +299 -0
- package/dist/core/platform-config.js.map +1 -0
- package/dist/decorators/ServiceProxy.d.ts +175 -0
- package/dist/decorators/ServiceProxy.d.ts.map +1 -0
- package/dist/decorators/ServiceProxy.js +969 -0
- package/dist/decorators/ServiceProxy.js.map +1 -0
- package/dist/decorators/index.d.ts +146 -0
- package/dist/decorators/index.d.ts.map +1 -0
- package/dist/decorators/index.js +545 -0
- package/dist/decorators/index.js.map +1 -0
- package/dist/deploy/NginxGenerator.d.ts +165 -0
- package/dist/deploy/NginxGenerator.d.ts.map +1 -0
- package/dist/deploy/NginxGenerator.js +781 -0
- package/dist/deploy/NginxGenerator.js.map +1 -0
- package/dist/deploy/PlatformManifestGenerator.d.ts +43 -0
- package/dist/deploy/PlatformManifestGenerator.d.ts.map +1 -0
- package/dist/deploy/PlatformManifestGenerator.js +80 -0
- package/dist/deploy/PlatformManifestGenerator.js.map +1 -0
- package/dist/deploy/RouteManifestGenerator.d.ts +42 -0
- package/dist/deploy/RouteManifestGenerator.d.ts.map +1 -0
- package/dist/deploy/RouteManifestGenerator.js +105 -0
- package/dist/deploy/RouteManifestGenerator.js.map +1 -0
- package/dist/deploy/index.d.ts +210 -0
- package/dist/deploy/index.d.ts.map +1 -0
- package/dist/deploy/index.js +918 -0
- package/dist/deploy/index.js.map +1 -0
- package/dist/frontend/FrontendDevLifecycle.d.ts +26 -0
- package/dist/frontend/FrontendDevLifecycle.d.ts.map +1 -0
- package/dist/frontend/FrontendDevLifecycle.js +60 -0
- package/dist/frontend/FrontendDevLifecycle.js.map +1 -0
- package/dist/frontend/FrontendPluginOrchestrator.d.ts +64 -0
- package/dist/frontend/FrontendPluginOrchestrator.d.ts.map +1 -0
- package/dist/frontend/FrontendPluginOrchestrator.js +167 -0
- package/dist/frontend/FrontendPluginOrchestrator.js.map +1 -0
- package/dist/frontend/SiteResolver.d.ts +33 -0
- package/dist/frontend/SiteResolver.d.ts.map +1 -0
- package/dist/frontend/SiteResolver.js +53 -0
- package/dist/frontend/SiteResolver.js.map +1 -0
- package/dist/frontend/StaticMountRegistry.d.ts +36 -0
- package/dist/frontend/StaticMountRegistry.d.ts.map +1 -0
- package/dist/frontend/StaticMountRegistry.js +94 -0
- package/dist/frontend/StaticMountRegistry.js.map +1 -0
- package/dist/frontend/index.d.ts +7 -0
- package/dist/frontend/index.d.ts.map +1 -0
- package/{src → dist}/frontend/index.js +4 -2
- package/dist/frontend/index.js.map +1 -0
- package/dist/frontend/pathUtils.d.ts +8 -0
- package/dist/frontend/pathUtils.d.ts.map +1 -0
- package/dist/frontend/pathUtils.js +17 -0
- package/dist/frontend/pathUtils.js.map +1 -0
- package/dist/frontend/plugins/index.d.ts +2 -0
- package/dist/frontend/plugins/index.d.ts.map +1 -0
- package/{src → dist}/frontend/plugins/index.js +1 -1
- package/dist/frontend/plugins/index.js.map +1 -0
- package/dist/frontend/plugins/viteFrontend.d.ts +51 -0
- package/dist/frontend/plugins/viteFrontend.d.ts.map +1 -0
- package/dist/frontend/plugins/viteFrontend.js +134 -0
- package/dist/frontend/plugins/viteFrontend.js.map +1 -0
- package/dist/frontend/types.d.ts +25 -0
- package/dist/frontend/types.d.ts.map +1 -0
- package/dist/frontend/types.js +2 -0
- package/dist/frontend/types.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/internals.d.ts +21 -0
- package/dist/internals.d.ts.map +1 -0
- package/{src → dist}/internals.js +12 -14
- package/dist/internals.js.map +1 -0
- package/dist/plugins/PluginManager.d.ts +209 -0
- package/dist/plugins/PluginManager.d.ts.map +1 -0
- package/dist/plugins/PluginManager.js +365 -0
- package/dist/plugins/PluginManager.js.map +1 -0
- package/dist/plugins/ScopedPostgres.d.ts +78 -0
- package/dist/plugins/ScopedPostgres.d.ts.map +1 -0
- package/dist/plugins/ScopedPostgres.js +190 -0
- package/dist/plugins/ScopedPostgres.js.map +1 -0
- package/dist/plugins/ScopedRedis.d.ts +88 -0
- package/dist/plugins/ScopedRedis.d.ts.map +1 -0
- package/dist/plugins/ScopedRedis.js +169 -0
- package/dist/plugins/ScopedRedis.js.map +1 -0
- package/dist/plugins/index.d.ts +289 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +1942 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/types.d.ts +59 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +2 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/registry/ServiceRegistry.d.ts +305 -0
- package/dist/registry/ServiceRegistry.d.ts.map +1 -0
- package/dist/registry/ServiceRegistry.js +735 -0
- package/dist/registry/ServiceRegistry.js.map +1 -0
- package/dist/scaling/ScaleAdvisor.d.ts +214 -0
- package/dist/scaling/ScaleAdvisor.d.ts.map +1 -0
- package/dist/scaling/ScaleAdvisor.js +526 -0
- package/dist/scaling/ScaleAdvisor.js.map +1 -0
- package/dist/services/Service.d.ts +164 -0
- package/dist/services/Service.d.ts.map +1 -0
- package/dist/services/Service.js +106 -0
- package/dist/services/Service.js.map +1 -0
- package/dist/services/worker-bootstrap.d.ts +15 -0
- package/dist/services/worker-bootstrap.d.ts.map +1 -0
- package/dist/services/worker-bootstrap.js +744 -0
- package/dist/services/worker-bootstrap.js.map +1 -0
- package/dist/templates/auth-service.d.ts +42 -0
- package/dist/templates/auth-service.d.ts.map +1 -0
- package/dist/templates/auth-service.js +54 -0
- package/dist/templates/auth-service.js.map +1 -0
- package/dist/templates/identity-service.d.ts +50 -0
- package/dist/templates/identity-service.d.ts.map +1 -0
- package/dist/templates/identity-service.js +62 -0
- package/dist/templates/identity-service.js.map +1 -0
- package/dist/types/contract.d.ts +120 -0
- package/dist/types/contract.d.ts.map +1 -0
- package/dist/types/contract.js +69 -0
- package/dist/types/contract.js.map +1 -0
- package/package.json +78 -20
- package/src/core/DirectMessageBus.js +0 -364
- package/src/core/EndpointResolver.js +0 -259
- package/src/core/ForgeContext.js +0 -2236
- package/src/core/ForgeHost.js +0 -122
- package/src/core/ForgePlatform.js +0 -145
- package/src/core/Ingress.js +0 -768
- package/src/core/Interceptors.js +0 -420
- package/src/core/MessageBus.js +0 -321
- package/src/core/Prometheus.js +0 -305
- package/src/core/RequestContext.js +0 -413
- package/src/core/RoutingStrategy.js +0 -330
- package/src/core/Supervisor.js +0 -1349
- package/src/core/ThreadAllocator.js +0 -196
- package/src/core/WorkerChannelManager.js +0 -879
- package/src/core/config.js +0 -637
- package/src/core/host-config.js +0 -311
- package/src/core/network-utils.js +0 -166
- package/src/core/platform-config.js +0 -308
- package/src/decorators/ServiceProxy.js +0 -904
- package/src/decorators/index.js +0 -571
- package/src/deploy/NginxGenerator.js +0 -865
- package/src/deploy/PlatformManifestGenerator.js +0 -96
- package/src/deploy/RouteManifestGenerator.js +0 -112
- package/src/deploy/index.js +0 -984
- package/src/frontend/FrontendDevLifecycle.js +0 -65
- package/src/frontend/FrontendPluginOrchestrator.js +0 -187
- package/src/frontend/SiteResolver.js +0 -63
- package/src/frontend/StaticMountRegistry.js +0 -90
- package/src/frontend/plugins/viteFrontend.js +0 -79
- package/src/frontend/types.js +0 -35
- package/src/index.js +0 -58
- package/src/plugins/PluginManager.js +0 -537
- package/src/plugins/ScopedPostgres.js +0 -192
- package/src/plugins/ScopedRedis.js +0 -142
- package/src/plugins/index.js +0 -1756
- package/src/registry/ServiceRegistry.js +0 -797
- package/src/scaling/ScaleAdvisor.js +0 -442
- package/src/services/Service.js +0 -195
- package/src/services/worker-bootstrap.js +0 -679
- package/src/templates/auth-service.js +0 -65
- package/src/templates/identity-service.js +0 -75
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import { EventEmitter } from "node:events";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { isExpectedIpcError } from "./ipc-errors.js";
|
|
7
|
+
const EXIT_SOCKET_DIRS = new Set();
|
|
8
|
+
let EXIT_CLEANUP_INSTALLED = false;
|
|
9
|
+
function cleanupSocketDir(socketDir) {
|
|
10
|
+
try {
|
|
11
|
+
if (fs.existsSync(socketDir)) {
|
|
12
|
+
for (const f of fs.readdirSync(socketDir)) {
|
|
13
|
+
try {
|
|
14
|
+
fs.unlinkSync(path.join(socketDir, f));
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
/* ignore: cleanup — socket file may already be removed */
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
fs.rmdirSync(socketDir);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
/* ignore: cleanup — directory may already be removed or non-empty */
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
/* ignore: cleanup — best-effort removal of socket directory */
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function installExitCleanupHook() {
|
|
33
|
+
if (EXIT_CLEANUP_INSTALLED)
|
|
34
|
+
return;
|
|
35
|
+
EXIT_CLEANUP_INSTALLED = true;
|
|
36
|
+
process.once("exit", () => {
|
|
37
|
+
for (const socketDir of EXIT_SOCKET_DIRS) {
|
|
38
|
+
cleanupSocketDir(socketDir);
|
|
39
|
+
}
|
|
40
|
+
EXIT_SOCKET_DIRS.clear();
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function isWorkerSendable(worker) {
|
|
44
|
+
if (!worker)
|
|
45
|
+
return false;
|
|
46
|
+
if (typeof worker.isDead === "function" && worker.isDead())
|
|
47
|
+
return false;
|
|
48
|
+
if (typeof worker.isConnected === "function" && !worker.isConnected())
|
|
49
|
+
return false;
|
|
50
|
+
if (worker.process?.connected === false)
|
|
51
|
+
return false;
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* DirectMessageBus — Unix Domain Socket Mesh (Supervisor Side)
|
|
56
|
+
*
|
|
57
|
+
* The fundamental problem: cluster.Worker.send() can only transfer
|
|
58
|
+
* sockets/servers, not MessagePort objects. So we can't use MessageChannel
|
|
59
|
+
* for direct worker-to-worker communication in cluster mode.
|
|
60
|
+
*
|
|
61
|
+
* Solution: Each worker opens a Unix domain socket server. Workers connect
|
|
62
|
+
* directly to each other via these sockets. The supervisor only tells
|
|
63
|
+
* workers WHERE to connect (socket paths), then gets out of the way.
|
|
64
|
+
*
|
|
65
|
+
* Architecture:
|
|
66
|
+
*
|
|
67
|
+
* SETUP (supervisor involved briefly):
|
|
68
|
+
* 1. Each worker starts a UDS server at /tmp/forge-{pid}/{service}-{worker}.sock
|
|
69
|
+
* 2. Worker reports its socket path to supervisor via IPC
|
|
70
|
+
* 3. Supervisor broadcasts the full socket registry to all workers
|
|
71
|
+
* 4. Workers establish direct connections to each other
|
|
72
|
+
*
|
|
73
|
+
* RUNTIME (supervisor NOT involved in message routing):
|
|
74
|
+
* Worker A ──UDS──► Worker B (direct, length-prefixed JSON)
|
|
75
|
+
* Worker B ──UDS──► Worker A
|
|
76
|
+
*
|
|
77
|
+
* Supervisor only handles:
|
|
78
|
+
* - Socket path registry distribution (one-time + on new workers)
|
|
79
|
+
* - Health checks (periodic pull, not per-message)
|
|
80
|
+
* - Worker lifecycle (restart, scale)
|
|
81
|
+
*/
|
|
82
|
+
export class DirectMessageBus extends EventEmitter {
|
|
83
|
+
workers;
|
|
84
|
+
socketRegistry;
|
|
85
|
+
_registeredWorkerIds;
|
|
86
|
+
_workerErrorHandlers;
|
|
87
|
+
_connections;
|
|
88
|
+
_socketDir;
|
|
89
|
+
_broadcastTimer;
|
|
90
|
+
constructor() {
|
|
91
|
+
super();
|
|
92
|
+
this.workers = new Map();
|
|
93
|
+
this.socketRegistry = new Map();
|
|
94
|
+
this._registeredWorkerIds = new Set();
|
|
95
|
+
this._workerErrorHandlers = new WeakMap();
|
|
96
|
+
this._connections = new Map();
|
|
97
|
+
// S-IPC-2: Random suffix prevents socket path prediction
|
|
98
|
+
this._socketDir = path.join(os.tmpdir(), `forge-${process.pid}-${crypto.randomBytes(4).toString("hex")}`);
|
|
99
|
+
this._broadcastTimer = null;
|
|
100
|
+
try {
|
|
101
|
+
fs.mkdirSync(this._socketDir, { recursive: true });
|
|
102
|
+
}
|
|
103
|
+
catch (e) {
|
|
104
|
+
if (e.code !== "EEXIST")
|
|
105
|
+
console.error("[DirectMessageBus] mkdirSync failed:", e.message);
|
|
106
|
+
}
|
|
107
|
+
EXIT_SOCKET_DIRS.add(this._socketDir);
|
|
108
|
+
installExitCleanupHook();
|
|
109
|
+
}
|
|
110
|
+
get socketDir() {
|
|
111
|
+
return this._socketDir;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Register a worker. Tell it to start a UDS server, then
|
|
115
|
+
* broadcast the updated registry to all workers.
|
|
116
|
+
*/
|
|
117
|
+
registerWorker(serviceName, worker, mode = "cluster") {
|
|
118
|
+
if (!this.workers.has(serviceName)) {
|
|
119
|
+
this.workers.set(serviceName, []);
|
|
120
|
+
}
|
|
121
|
+
const workerId = mode === "cluster" ? worker.id : worker.threadId;
|
|
122
|
+
const entry = {
|
|
123
|
+
id: workerId,
|
|
124
|
+
worker,
|
|
125
|
+
mode,
|
|
126
|
+
socketPath: null,
|
|
127
|
+
};
|
|
128
|
+
this.workers.get(serviceName).push(entry);
|
|
129
|
+
// Attach one shared error listener per worker so late IPC channel errors
|
|
130
|
+
// during churn don't surface as unhandled EventEmitter errors.
|
|
131
|
+
if (!this._workerErrorHandlers.has(worker)) {
|
|
132
|
+
const errorHandler = (err) => {
|
|
133
|
+
if (!isExpectedIpcError(err)) {
|
|
134
|
+
console.error("[DirectMessageBus] Worker error:", err?.message ?? err);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
this._workerErrorHandlers.set(worker, errorHandler);
|
|
138
|
+
worker.on("error", errorHandler);
|
|
139
|
+
}
|
|
140
|
+
entry._errorHandler = this._workerErrorHandlers.get(worker);
|
|
141
|
+
// Prevent duplicate message listener registration
|
|
142
|
+
// If workerId is already registered (e.g., crashed worker's ID reused), clean up stale listeners
|
|
143
|
+
if (this._registeredWorkerIds.has(workerId)) {
|
|
144
|
+
// Find and clean up stale entry with this workerId across all services
|
|
145
|
+
for (const [svcName, entries] of this.workers) {
|
|
146
|
+
const staleIdx = entries.findIndex((e) => e.id === workerId && e.worker !== worker);
|
|
147
|
+
if (staleIdx !== -1) {
|
|
148
|
+
const stale = entries[staleIdx];
|
|
149
|
+
if (stale._messageHandler)
|
|
150
|
+
stale.worker.off("message", stale._messageHandler);
|
|
151
|
+
if (stale.socketPath) {
|
|
152
|
+
try {
|
|
153
|
+
fs.unlinkSync(stale.socketPath);
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
/* ignore: cleanup — stale socket may already be removed */
|
|
157
|
+
}
|
|
158
|
+
this.socketRegistry.delete(`${svcName}:${workerId}`);
|
|
159
|
+
}
|
|
160
|
+
entries.splice(staleIdx, 1);
|
|
161
|
+
if (entries.length === 0)
|
|
162
|
+
this.workers.delete(svcName);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
this._registeredWorkerIds.delete(workerId);
|
|
166
|
+
}
|
|
167
|
+
this._registeredWorkerIds.add(workerId);
|
|
168
|
+
// Listen for supervisor-level IPC from this worker
|
|
169
|
+
const messageHandler = (msg) => {
|
|
170
|
+
const forgeMsg = msg;
|
|
171
|
+
if (!forgeMsg || !forgeMsg.type)
|
|
172
|
+
return;
|
|
173
|
+
switch (forgeMsg.type) {
|
|
174
|
+
case "forge:socket-ready":
|
|
175
|
+
// In colocated groups a worker may host multiple services, each with its
|
|
176
|
+
// own socket. Ignore ready messages for sibling services on this entry.
|
|
177
|
+
if (forgeMsg.serviceName && forgeMsg.serviceName !== serviceName)
|
|
178
|
+
break;
|
|
179
|
+
entry.socketPath = forgeMsg.socketPath;
|
|
180
|
+
this.socketRegistry.set(`${serviceName}:${forgeMsg.workerId}`, forgeMsg.socketPath);
|
|
181
|
+
this._scheduleBroadcast();
|
|
182
|
+
break;
|
|
183
|
+
case "forge:worker-ready":
|
|
184
|
+
this._sendInitSocket(worker, serviceName, entry.id);
|
|
185
|
+
this._sendRegistryTo(worker);
|
|
186
|
+
break;
|
|
187
|
+
case "forge:channel-ready": {
|
|
188
|
+
// CR-IPC-9: Track established connections
|
|
189
|
+
const workerKey = `${serviceName}:${entry.id}`;
|
|
190
|
+
if (!this._connections.has(workerKey)) {
|
|
191
|
+
this._connections.set(workerKey, new Set());
|
|
192
|
+
}
|
|
193
|
+
if (forgeMsg.peerKey) {
|
|
194
|
+
this._connections.get(workerKey).add(forgeMsg.peerKey);
|
|
195
|
+
}
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
case "forge:metric":
|
|
199
|
+
case "forge:log":
|
|
200
|
+
case "forge:health-response": {
|
|
201
|
+
const eventName = forgeMsg.type.replace("forge:", "");
|
|
202
|
+
this.emit(eventName, { service: serviceName, ...forgeMsg });
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
entry._messageHandler = messageHandler;
|
|
208
|
+
worker.on("message", messageHandler);
|
|
209
|
+
// Tell the new worker to start its UDS server
|
|
210
|
+
this._sendInitSocket(worker, serviceName, entry.id);
|
|
211
|
+
this._sendRegistryTo(worker);
|
|
212
|
+
}
|
|
213
|
+
_scheduleBroadcast() {
|
|
214
|
+
// CR-IPC-5: Don't cancel existing timer — let the first registration broadcast on schedule
|
|
215
|
+
if (this._broadcastTimer)
|
|
216
|
+
return;
|
|
217
|
+
this._broadcastTimer = setTimeout(() => {
|
|
218
|
+
this._broadcastTimer = null;
|
|
219
|
+
this._broadcastRegistry();
|
|
220
|
+
}, 50 + Math.floor(Math.random() * 50));
|
|
221
|
+
// SUP-M3: Don't keep the process alive during shutdown
|
|
222
|
+
this._broadcastTimer.unref();
|
|
223
|
+
}
|
|
224
|
+
_sendInitSocket(worker, serviceName, workerId) {
|
|
225
|
+
if (!isWorkerSendable(worker))
|
|
226
|
+
return;
|
|
227
|
+
try {
|
|
228
|
+
worker.send({
|
|
229
|
+
type: "forge:init-socket",
|
|
230
|
+
socketDir: this._socketDir,
|
|
231
|
+
serviceName,
|
|
232
|
+
workerId,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
catch (e) {
|
|
236
|
+
if (!isExpectedIpcError(e)) {
|
|
237
|
+
console.error("[DirectMessageBus] Failed to send init-socket:", e.message);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
_sendRegistryTo(worker) {
|
|
242
|
+
if (!isWorkerSendable(worker))
|
|
243
|
+
return;
|
|
244
|
+
try {
|
|
245
|
+
const msg = {
|
|
246
|
+
type: "forge:socket-registry",
|
|
247
|
+
registry: Object.fromEntries(this.socketRegistry),
|
|
248
|
+
};
|
|
249
|
+
// S-IPC-1: Include cluster secret for handshake authentication
|
|
250
|
+
const secret = process.env.FORGE_CLUSTER_SECRET;
|
|
251
|
+
if (secret) {
|
|
252
|
+
msg.secret = secret;
|
|
253
|
+
}
|
|
254
|
+
worker.send(msg);
|
|
255
|
+
}
|
|
256
|
+
catch (e) {
|
|
257
|
+
if (!isExpectedIpcError(e)) {
|
|
258
|
+
console.error("[DirectMessageBus] Failed to send registry:", e.message);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
_broadcastRegistry() {
|
|
263
|
+
for (const [, workers] of this.workers) {
|
|
264
|
+
for (const entry of workers) {
|
|
265
|
+
this._sendRegistryTo(entry.worker);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
unregisterWorker(serviceName, workerId, options = {}) {
|
|
270
|
+
const workers = this.workers.get(serviceName);
|
|
271
|
+
if (!workers)
|
|
272
|
+
return;
|
|
273
|
+
const idx = workers.findIndex((w) => w.id === workerId);
|
|
274
|
+
if (idx === -1)
|
|
275
|
+
return;
|
|
276
|
+
const entry = workers[idx];
|
|
277
|
+
if (entry._messageHandler) {
|
|
278
|
+
entry.worker.off("message", entry._messageHandler);
|
|
279
|
+
}
|
|
280
|
+
if (entry.socketPath) {
|
|
281
|
+
try {
|
|
282
|
+
fs.unlinkSync(entry.socketPath);
|
|
283
|
+
}
|
|
284
|
+
catch (e) {
|
|
285
|
+
if (e.code !== "ENOENT")
|
|
286
|
+
console.error("[DirectMessageBus] unlink failed:", e.message);
|
|
287
|
+
}
|
|
288
|
+
this.socketRegistry.delete(`${serviceName}:${workerId}`);
|
|
289
|
+
}
|
|
290
|
+
workers.splice(idx, 1);
|
|
291
|
+
// Clean up the registered worker ID tracking
|
|
292
|
+
this._registeredWorkerIds.delete(workerId);
|
|
293
|
+
if (workers.length === 0) {
|
|
294
|
+
this.workers.delete(serviceName);
|
|
295
|
+
}
|
|
296
|
+
if (!options.suppressBroadcast && this.workers.size > 0) {
|
|
297
|
+
this._broadcastRegistry();
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
unregisterService(serviceName) {
|
|
301
|
+
const workers = [...(this.workers.get(serviceName) ?? [])];
|
|
302
|
+
for (const w of workers) {
|
|
303
|
+
this.unregisterWorker(serviceName, w.id);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
requestHealthChecks() {
|
|
307
|
+
for (const [, workers] of this.workers) {
|
|
308
|
+
for (const entry of workers) {
|
|
309
|
+
if (!isWorkerSendable(entry.worker))
|
|
310
|
+
continue;
|
|
311
|
+
try {
|
|
312
|
+
entry.worker.send({ type: "forge:health-check", timestamp: Date.now() });
|
|
313
|
+
}
|
|
314
|
+
catch (err) {
|
|
315
|
+
if (!isExpectedIpcError(err)) {
|
|
316
|
+
console.error("[DirectMessageBus] Failed to send health-check:", err.message);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
stats() {
|
|
323
|
+
const result = {};
|
|
324
|
+
for (const [name, workers] of this.workers) {
|
|
325
|
+
result[name] = {
|
|
326
|
+
workerCount: workers.length,
|
|
327
|
+
ids: workers.map((w) => w.id),
|
|
328
|
+
directSockets: workers.filter((w) => w.socketPath).length,
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
return result;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* CR-IPC-9: Get the connection matrix for debugging.
|
|
335
|
+
*/
|
|
336
|
+
getConnectionMatrix() {
|
|
337
|
+
const result = {};
|
|
338
|
+
for (const [key, peers] of this._connections) {
|
|
339
|
+
result[key] = [...peers];
|
|
340
|
+
}
|
|
341
|
+
return result;
|
|
342
|
+
}
|
|
343
|
+
cleanup() {
|
|
344
|
+
if (this._broadcastTimer) {
|
|
345
|
+
clearTimeout(this._broadcastTimer);
|
|
346
|
+
this._broadcastTimer = null;
|
|
347
|
+
}
|
|
348
|
+
cleanupSocketDir(this._socketDir);
|
|
349
|
+
EXIT_SOCKET_DIRS.delete(this._socketDir);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
//# sourceMappingURL=DirectMessageBus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DirectMessageBus.js","sourceRoot":"","sources":["../../src/core/DirectMessageBus.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
interface Endpoint {
|
|
2
|
+
host: string;
|
|
3
|
+
port: number;
|
|
4
|
+
remote: boolean;
|
|
5
|
+
}
|
|
6
|
+
interface EndpointInput {
|
|
7
|
+
host: string;
|
|
8
|
+
port: number;
|
|
9
|
+
remote?: boolean;
|
|
10
|
+
}
|
|
11
|
+
interface WrappedEntry {
|
|
12
|
+
key: string;
|
|
13
|
+
host: string;
|
|
14
|
+
port: number;
|
|
15
|
+
remote: boolean;
|
|
16
|
+
}
|
|
17
|
+
interface RoutingStrategy {
|
|
18
|
+
pick(entries: WrappedEntry[], callContext?: unknown): WrappedEntry | WrappedEntry[] | null;
|
|
19
|
+
acquire?(endpointKey: string): void;
|
|
20
|
+
release?(endpointKey: string): void;
|
|
21
|
+
}
|
|
22
|
+
export declare class EndpointResolver {
|
|
23
|
+
private _endpoints;
|
|
24
|
+
private _counters;
|
|
25
|
+
private _strategies;
|
|
26
|
+
private _wrappedCache;
|
|
27
|
+
private _healthStatus;
|
|
28
|
+
private _failureCounts;
|
|
29
|
+
private _failureThreshold;
|
|
30
|
+
constructor();
|
|
31
|
+
/**
|
|
32
|
+
* Set a routing strategy for a specific service.
|
|
33
|
+
* When set, resolve() delegates to the strategy's pick() method
|
|
34
|
+
* instead of using built-in round-robin.
|
|
35
|
+
*
|
|
36
|
+
* The strategy must implement pick(entries, callContext) where entries
|
|
37
|
+
* are wrapped as { key: "host:port", host, port, remote }.
|
|
38
|
+
*/
|
|
39
|
+
setStrategy(serviceName: string, strategy: RoutingStrategy): void;
|
|
40
|
+
/**
|
|
41
|
+
* Create an EndpointResolver from environment variables.
|
|
42
|
+
*
|
|
43
|
+
* Parses FORGE_SERVICE_ENDPOINTS first (full endpoint map with host/port/remote).
|
|
44
|
+
* Falls back to FORGE_SERVICE_PORTS (localhost-only port map) when endpoints
|
|
45
|
+
* aren't available.
|
|
46
|
+
*/
|
|
47
|
+
static fromEnv(): EndpointResolver;
|
|
48
|
+
/**
|
|
49
|
+
* Resolve an endpoint for a service.
|
|
50
|
+
* Delegates to a configured RoutingStrategy when available,
|
|
51
|
+
* otherwise round-robins across instances.
|
|
52
|
+
*/
|
|
53
|
+
resolve(serviceName: string, callContext?: unknown): Endpoint | Endpoint[] | null;
|
|
54
|
+
/**
|
|
55
|
+
* Get all endpoints for a service (used for broadcast/event delivery).
|
|
56
|
+
*/
|
|
57
|
+
all(serviceName: string): Endpoint[];
|
|
58
|
+
/**
|
|
59
|
+
* Add or update an endpoint for a service.
|
|
60
|
+
* Used by dynamic registry discovery.
|
|
61
|
+
*/
|
|
62
|
+
set(serviceName: string, endpoint: EndpointInput): void;
|
|
63
|
+
/**
|
|
64
|
+
* Remove a specific instance of a service.
|
|
65
|
+
* Used when a remote node goes down.
|
|
66
|
+
*/
|
|
67
|
+
remove(serviceName: string, host: string, port: number): void;
|
|
68
|
+
/**
|
|
69
|
+
* COR-C1: Acquire a pending slot for a resolved endpoint.
|
|
70
|
+
* Delegates to the service's routing strategy if it supports acquire().
|
|
71
|
+
* Must be paired with releaseEndpoint() in a finally block.
|
|
72
|
+
*/
|
|
73
|
+
acquireEndpoint(serviceName: string, endpointKey: string): void;
|
|
74
|
+
/**
|
|
75
|
+
* COR-C1: Release a pending slot for a resolved endpoint.
|
|
76
|
+
* Delegates to the service's routing strategy if it supports release().
|
|
77
|
+
*/
|
|
78
|
+
releaseEndpoint(serviceName: string, endpointKey: string): void;
|
|
79
|
+
/**
|
|
80
|
+
* REG-H2: Update health status for a specific endpoint.
|
|
81
|
+
* Called when the Supervisor pushes health updates or on connection failure feedback.
|
|
82
|
+
*/
|
|
83
|
+
setHealthStatus(host: string, port: number, status: 'healthy' | 'degraded' | 'unhealthy' | 'draining'): void;
|
|
84
|
+
/**
|
|
85
|
+
* REG-H2: Get the health status of a specific endpoint.
|
|
86
|
+
*/
|
|
87
|
+
getHealthStatus(host: string, port: number): string;
|
|
88
|
+
/**
|
|
89
|
+
* REG-M2: Record a connection failure for an endpoint.
|
|
90
|
+
* After _failureThreshold consecutive failures, the endpoint is marked unhealthy.
|
|
91
|
+
* Returns the current consecutive failure count.
|
|
92
|
+
*/
|
|
93
|
+
recordFailure(host: string, port: number): number;
|
|
94
|
+
/**
|
|
95
|
+
* REG-M2: Record a successful connection to an endpoint.
|
|
96
|
+
* Resets the consecutive failure counter and marks the endpoint healthy.
|
|
97
|
+
*/
|
|
98
|
+
recordSuccess(host: string, port: number): void;
|
|
99
|
+
/**
|
|
100
|
+
* Check if a service has any known endpoints.
|
|
101
|
+
*/
|
|
102
|
+
has(serviceName: string): boolean;
|
|
103
|
+
/**
|
|
104
|
+
* REG-H1: Apply a full endpoint map update (pushed from Supervisor).
|
|
105
|
+
* Merges new/updated endpoints and removes stale ones not present in the update.
|
|
106
|
+
* Only updates remote endpoints to avoid overwriting local colocated/UDS entries.
|
|
107
|
+
*/
|
|
108
|
+
applyEndpointUpdate(endpointMap: Record<string, unknown>): void;
|
|
109
|
+
}
|
|
110
|
+
export {};
|
|
111
|
+
//# sourceMappingURL=EndpointResolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EndpointResolver.d.ts","sourceRoot":"","sources":["../../src/core/EndpointResolver.ts"],"names":[],"mappings":"AAaA,UAAU,QAAQ;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,UAAU,YAAY;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,UAAU,eAAe;IACvB,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,WAAW,CAAC,EAAE,OAAO,GAAG,YAAY,GAAG,YAAY,EAAE,GAAG,IAAI,CAAC;IAC3F,OAAO,CAAC,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,OAAO,CAAC,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAWD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,WAAW,CAA+B;IAElD,OAAO,CAAC,aAAa,CAA8B;IAEnD,OAAO,CAAC,aAAa,CAAiE;IAEtF,OAAO,CAAC,cAAc,CAAsB;IAE5C,OAAO,CAAC,iBAAiB,CAAS;;IAYlC;;;;;;;OAOG;IACH,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,IAAI;IAOjE;;;;;;OAMG;IACH,MAAM,CAAC,OAAO,IAAI,gBAAgB;IAkDlC;;;;OAIG;IACH,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,EAAE,GAAG,IAAI;IAoDjF;;OAEG;IACH,GAAG,CAAC,WAAW,EAAE,MAAM,GAAG,QAAQ,EAAE;IAIpC;;;OAGG;IACH,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI;IAuBvD;;;OAGG;IACH,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAiB7D;;;;OAIG;IACH,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAO/D;;;OAGG;IACH,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAO/D;;;OAGG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,WAAW,GAAG,UAAU,GAAG,IAAI;IAW5G;;OAEG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAInD;;;;OAIG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAWjD;;;OAGG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAW/C;;OAEG;IACH,GAAG,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IAKjC;;;;OAIG;IACH,mBAAmB,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;CA+BhE"}
|