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
|
@@ -1,537 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ThreadForge Plugin System
|
|
3
|
-
*
|
|
4
|
-
* Plugins add infrastructure to your app without boilerplate.
|
|
5
|
-
* They handle connection management, health checks, nginx routing,
|
|
6
|
-
* graceful shutdown, and inject clients into every service.
|
|
7
|
-
*
|
|
8
|
-
* ═══════════════════════════════════════════════════════════════
|
|
9
|
-
* USAGE
|
|
10
|
-
* ═══════════════════════════════════════════════════════════════
|
|
11
|
-
*
|
|
12
|
-
* // forge.config.ts
|
|
13
|
-
* import { defineServices } from 'threadforge';
|
|
14
|
-
* import { redis, postgres, s3 } from 'threadforge/plugins';
|
|
15
|
-
*
|
|
16
|
-
* export default defineServices({
|
|
17
|
-
* plugins: [
|
|
18
|
-
* redis({ url: 'redis://localhost:6379' }),
|
|
19
|
-
* postgres({ url: 'postgres://user:pass@localhost:5432/mydb' }),
|
|
20
|
-
* s3({ bucket: 'my-uploads', region: 'us-east-1' }),
|
|
21
|
-
* ],
|
|
22
|
-
*
|
|
23
|
-
* users: {
|
|
24
|
-
* entry: './services/users.ts',
|
|
25
|
-
* port: 3001,
|
|
26
|
-
* plugins: ['redis', 'postgres'], // opt-in per service
|
|
27
|
-
* },
|
|
28
|
-
*
|
|
29
|
-
* uploads: {
|
|
30
|
-
* entry: './services/uploads.ts',
|
|
31
|
-
* port: 3002,
|
|
32
|
-
* plugins: ['s3'],
|
|
33
|
-
* },
|
|
34
|
-
* });
|
|
35
|
-
*
|
|
36
|
-
* In your service:
|
|
37
|
-
*
|
|
38
|
-
* @Prefix('/api/users')
|
|
39
|
-
* class UserService extends Service {
|
|
40
|
-
* async onStart(ctx) {
|
|
41
|
-
* // Injected by plugins — ready to use, connection managed
|
|
42
|
-
* const cached = await this.redis.get('user:123');
|
|
43
|
-
* const rows = await this.pg.query('SELECT * FROM users WHERE id = $1', [123]);
|
|
44
|
-
* }
|
|
45
|
-
* }
|
|
46
|
-
*
|
|
47
|
-
* ═══════════════════════════════════════════════════════════════
|
|
48
|
-
* PLUGIN LIFECYCLE
|
|
49
|
-
* ═══════════════════════════════════════════════════════════════
|
|
50
|
-
*
|
|
51
|
-
* forge start
|
|
52
|
-
* │
|
|
53
|
-
* ▼ Supervisor reads config, finds plugins
|
|
54
|
-
* │
|
|
55
|
-
* ▼ plugin.validate() — check config, throw if bad
|
|
56
|
-
* ▼ plugin.env() — env vars for workers (connection strings)
|
|
57
|
-
* ▼ plugin.nginx() — nginx location blocks (admin UIs, proxying)
|
|
58
|
-
* │
|
|
59
|
-
* ▼ Workers fork
|
|
60
|
-
* │
|
|
61
|
-
* ▼ plugin.connect() — create client, connect, return instance
|
|
62
|
-
* ▼ service.redis = client — injected onto service instance
|
|
63
|
-
* ▼ service.onStart(ctx) — your code runs, clients ready
|
|
64
|
-
* │
|
|
65
|
-
* ▼ plugin.healthCheck() — called by /health endpoint
|
|
66
|
-
* │
|
|
67
|
-
* ▼ shutdown
|
|
68
|
-
* ▼ plugin.disconnect() — close connections, drain pools
|
|
69
|
-
*
|
|
70
|
-
* ═══════════════════════════════════════════════════════════════
|
|
71
|
-
* WRITING A PLUGIN
|
|
72
|
-
* ═══════════════════════════════════════════════════════════════
|
|
73
|
-
*
|
|
74
|
-
* export function myPlugin(options) {
|
|
75
|
-
* return {
|
|
76
|
-
* name: 'myPlugin',
|
|
77
|
-
* version: '1.0.0',
|
|
78
|
-
*
|
|
79
|
-
* // What property name to inject on the service (this.myPlugin)
|
|
80
|
-
* inject: 'myPlugin',
|
|
81
|
-
*
|
|
82
|
-
* // Validate config before startup (fail fast)
|
|
83
|
-
* validate() { ... },
|
|
84
|
-
*
|
|
85
|
-
* // Env vars to pass to workers
|
|
86
|
-
* env() { return { MY_PLUGIN_URL: options.url }; },
|
|
87
|
-
*
|
|
88
|
-
* // Create and return the client (called once per worker)
|
|
89
|
-
* async connect(ctx) {
|
|
90
|
-
* const client = new MyClient(options.url);
|
|
91
|
-
* await client.connect();
|
|
92
|
-
* return client;
|
|
93
|
-
* },
|
|
94
|
-
*
|
|
95
|
-
* // Health check (called by GET /health)
|
|
96
|
-
* async healthCheck(client) {
|
|
97
|
-
* await client.ping();
|
|
98
|
-
* return { status: 'ok' };
|
|
99
|
-
* },
|
|
100
|
-
*
|
|
101
|
-
* // Clean shutdown
|
|
102
|
-
* async disconnect(client) {
|
|
103
|
-
* await client.quit();
|
|
104
|
-
* },
|
|
105
|
-
*
|
|
106
|
-
* // Nginx config blocks (optional)
|
|
107
|
-
* nginx() {
|
|
108
|
-
* return {
|
|
109
|
-
* upstreams: [{ name: 'myPlugin', host: 'localhost', port: 8080 }],
|
|
110
|
-
* locations: [{ path: '/admin/myplugin', proxy_pass: 'myPlugin' }],
|
|
111
|
-
* };
|
|
112
|
-
* },
|
|
113
|
-
*
|
|
114
|
-
* // Prometheus metrics (optional)
|
|
115
|
-
* metrics(client) {
|
|
116
|
-
* return { pool_size: client.pool.totalCount };
|
|
117
|
-
* },
|
|
118
|
-
* };
|
|
119
|
-
* }
|
|
120
|
-
*/
|
|
121
|
-
|
|
122
|
-
// ─── Plugin Interface ──────────────────────────────────────
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* @typedef {Object} ForgePlugin
|
|
126
|
-
* @property {string} name - Unique plugin name
|
|
127
|
-
* @property {string} [version] - Plugin version
|
|
128
|
-
* @property {string} inject - Property name on service (this.redis, this.pg, etc.)
|
|
129
|
-
* @property {Function} [validate] - Validate config, throw on error
|
|
130
|
-
* @property {Function} [env] - Return env vars for workers: () => Record<string, string>
|
|
131
|
-
* @property {Function} connect - Create client: (ctx: ForgeContext) => Promise<any>
|
|
132
|
-
* @property {Function} [healthCheck] - Check health: (client: any) => Promise<{status: string}>
|
|
133
|
-
* @property {Function} [disconnect] - Close connections: (client: any) => Promise<void>
|
|
134
|
-
* @property {Function} [nginx] - Nginx config: () => { upstreams?, locations? }
|
|
135
|
-
* @property {Function} [metrics] - Prometheus metrics: (client: any) => Record<string, number>
|
|
136
|
-
* @property {Function} [middleware] - HTTP middleware: (client: any) => (req, res, next) => void
|
|
137
|
-
* @property {Function} [onWsUpgrade] - WebSocket upgrade hook: (client, ctx) => Promise<boolean|{allow:boolean,statusCode?:number,reason?:string}>
|
|
138
|
-
* @property {Function} [onWsConnect] - WebSocket connect hook: (client, ctx) => Promise<void>
|
|
139
|
-
* @property {Function} [onWsMessage] - WebSocket message hook: (client, ctx) => Promise<void>
|
|
140
|
-
* @property {Function} [onWsClose] - WebSocket close hook: (client, ctx) => Promise<void>
|
|
141
|
-
*/
|
|
142
|
-
|
|
143
|
-
// ─── Timeout Helper ────────────────────────────────────────
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Race a promise against a timeout. Resolves/rejects with the promise
|
|
147
|
-
* result if it finishes first, otherwise rejects with a timeout error.
|
|
148
|
-
*/
|
|
149
|
-
function withTimeout(promise, ms, label) {
|
|
150
|
-
return new Promise((resolve, reject) => {
|
|
151
|
-
const timer = setTimeout(() => {
|
|
152
|
-
reject(new Error(`${label} timed out after ${ms}ms`));
|
|
153
|
-
}, ms);
|
|
154
|
-
promise.then(
|
|
155
|
-
(val) => {
|
|
156
|
-
clearTimeout(timer);
|
|
157
|
-
resolve(val);
|
|
158
|
-
},
|
|
159
|
-
(err) => {
|
|
160
|
-
clearTimeout(timer);
|
|
161
|
-
reject(err);
|
|
162
|
-
},
|
|
163
|
-
);
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Default timeouts (ms)
|
|
168
|
-
const CONNECT_TIMEOUT = 10_000;
|
|
169
|
-
const HEALTH_TIMEOUT = 5_000;
|
|
170
|
-
const DISCONNECT_TIMEOUT = 5_000;
|
|
171
|
-
|
|
172
|
-
// ─── Plugin Manager ────────────────────────────────────────
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Manages plugin lifecycle across the supervisor and workers.
|
|
176
|
-
*/
|
|
177
|
-
export class PluginManager {
|
|
178
|
-
constructor(options = {}) {
|
|
179
|
-
/** @type {Map<string, ForgePlugin>} */
|
|
180
|
-
this.plugins = new Map();
|
|
181
|
-
|
|
182
|
-
/** @type {Map<string, any>} plugin name → connected client */
|
|
183
|
-
this.clients = new Map();
|
|
184
|
-
|
|
185
|
-
/** @type {Map<string, Promise>} plugin name → in-flight connect promise (C-PLUGIN-2) */
|
|
186
|
-
this._connecting = new Map();
|
|
187
|
-
|
|
188
|
-
this._logger = options.logger ?? {
|
|
189
|
-
info: (...args) => console.log('[PluginManager]', ...args),
|
|
190
|
-
warn: (...args) => console.warn('[PluginManager]', ...args),
|
|
191
|
-
error: (...args) => console.error('[PluginManager]', ...args),
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Register plugins from config.
|
|
197
|
-
*/
|
|
198
|
-
register(plugins) {
|
|
199
|
-
if (!plugins || !Array.isArray(plugins)) return;
|
|
200
|
-
|
|
201
|
-
// Build set of existing inject names
|
|
202
|
-
const injectNames = new Set();
|
|
203
|
-
for (const [, p] of this.plugins) {
|
|
204
|
-
if (p.inject) injectNames.add(p.inject);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
for (const plugin of plugins) {
|
|
208
|
-
if (!plugin.name) throw new Error("Plugin must have a name");
|
|
209
|
-
if (!plugin.inject) throw new Error(`Plugin "${plugin.name}" must have an inject property`);
|
|
210
|
-
if (!plugin.connect) throw new Error(`Plugin "${plugin.name}" must have a connect() method`);
|
|
211
|
-
for (const optionalFn of [
|
|
212
|
-
"validate",
|
|
213
|
-
"env",
|
|
214
|
-
"healthCheck",
|
|
215
|
-
"disconnect",
|
|
216
|
-
"nginx",
|
|
217
|
-
"metrics",
|
|
218
|
-
"middleware",
|
|
219
|
-
"onWsUpgrade",
|
|
220
|
-
"onWsConnect",
|
|
221
|
-
"onWsMessage",
|
|
222
|
-
"onWsClose",
|
|
223
|
-
]) {
|
|
224
|
-
if (plugin[optionalFn] !== undefined && typeof plugin[optionalFn] !== "function") {
|
|
225
|
-
throw new Error(`Plugin "${plugin.name}" optional hook "${optionalFn}" must be a function`);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
if (this.plugins.has(plugin.name)) {
|
|
230
|
-
throw new Error(`Duplicate plugin: "${plugin.name}"`);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
if (injectNames.has(plugin.inject)) {
|
|
234
|
-
throw new Error(`Duplicate plugin inject name: "${plugin.inject}"`);
|
|
235
|
-
}
|
|
236
|
-
injectNames.add(plugin.inject);
|
|
237
|
-
|
|
238
|
-
this.plugins.set(plugin.name, plugin);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* Validate all plugins (called by Supervisor before forking).
|
|
244
|
-
* Throws on first error.
|
|
245
|
-
*/
|
|
246
|
-
validate() {
|
|
247
|
-
for (const [name, plugin] of this.plugins) {
|
|
248
|
-
if (plugin.validate) {
|
|
249
|
-
try {
|
|
250
|
-
plugin.validate();
|
|
251
|
-
} catch (err) {
|
|
252
|
-
throw new Error(`Plugin "${name}" validation failed: ${err.message}`);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* Collect env vars from all plugins (supervisor passes to workers).
|
|
260
|
-
*/
|
|
261
|
-
env() {
|
|
262
|
-
const merged = {};
|
|
263
|
-
for (const [, plugin] of this.plugins) {
|
|
264
|
-
if (plugin.env) {
|
|
265
|
-
const pluginEnv = plugin.env();
|
|
266
|
-
for (const key of Object.keys(pluginEnv)) {
|
|
267
|
-
if (merged[key] !== undefined) {
|
|
268
|
-
throw new Error(`Plugin env var conflict: "${key}" is set by multiple plugins`);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
Object.assign(merged, pluginEnv);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
return merged;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Connect all plugins for a specific service.
|
|
279
|
-
* Only connects plugins the service opts into.
|
|
280
|
-
*
|
|
281
|
-
* @param {string[]} servicePlugins - Plugin names this service uses
|
|
282
|
-
* @param {any} ctx - ForgeContext
|
|
283
|
-
* @returns {Promise<Map<string, any>>} inject name → client
|
|
284
|
-
*/
|
|
285
|
-
async connectForService(servicePlugins, ctx) {
|
|
286
|
-
const clients = new Map();
|
|
287
|
-
|
|
288
|
-
// If service doesn't specify plugins, connect ALL registered plugins
|
|
289
|
-
const pluginNames = servicePlugins ?? [...this.plugins.keys()];
|
|
290
|
-
|
|
291
|
-
// H-PLUGIN-2: Connect independent plugins in parallel for faster startup.
|
|
292
|
-
// Separate into cached/in-flight (resolved immediately) and fresh (connected concurrently).
|
|
293
|
-
const pendingConnects = []; // Array of { name, plugin, promise }
|
|
294
|
-
|
|
295
|
-
for (const name of pluginNames) {
|
|
296
|
-
const plugin = this.plugins.get(name);
|
|
297
|
-
if (!plugin) {
|
|
298
|
-
ctx.logger.warn(`Plugin "${name}" not registered, skipping`);
|
|
299
|
-
continue;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// Reuse existing connection if already connected in this worker
|
|
303
|
-
if (this.clients.has(name)) {
|
|
304
|
-
const cached = this.clients.get(name);
|
|
305
|
-
if (cached !== null && typeof cached === 'object' && cached._pluginError === true) {
|
|
306
|
-
const attempts = cached.attempts ?? 0;
|
|
307
|
-
const retryAfterMs = Math.min(5000 * 2 ** attempts, 30000);
|
|
308
|
-
if (Date.now() - cached.timestamp < retryAfterMs) {
|
|
309
|
-
const errMsg = cached.errorMessage;
|
|
310
|
-
const errorProxy = new Proxy({}, {
|
|
311
|
-
get(_, prop) {
|
|
312
|
-
if (prop === 'then') return undefined;
|
|
313
|
-
throw new Error(`Plugin "${name}" is unavailable (connection failed: ${errMsg})`);
|
|
314
|
-
}
|
|
315
|
-
});
|
|
316
|
-
clients.set(plugin.inject, errorProxy);
|
|
317
|
-
continue;
|
|
318
|
-
}
|
|
319
|
-
this.clients.delete(name);
|
|
320
|
-
} else if (cached !== null && !(typeof cached === 'object' && cached._pluginError === true)) {
|
|
321
|
-
clients.set(plugin.inject, cached);
|
|
322
|
-
continue;
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// C-PLUGIN-2: Prevent double-connect — join in-flight connection
|
|
327
|
-
if (this._connecting.has(name)) {
|
|
328
|
-
pendingConnects.push({ name, plugin, promise: this._connecting.get(name), isJoin: true });
|
|
329
|
-
continue;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// Fresh connection — launch now, await later (parallel)
|
|
333
|
-
const connectPromise = (async () => {
|
|
334
|
-
const startTime = performance.now();
|
|
335
|
-
const client = await withTimeout(plugin.connect(ctx), CONNECT_TIMEOUT, `Plugin "${name}" connect`);
|
|
336
|
-
const duration = performance.now() - startTime;
|
|
337
|
-
ctx.metrics?.histogram?.('forge_plugin_connect_duration_ms', duration, { plugin: name, status: 'success' });
|
|
338
|
-
return client;
|
|
339
|
-
})();
|
|
340
|
-
this._connecting.set(name, connectPromise);
|
|
341
|
-
pendingConnects.push({ name, plugin, promise: connectPromise, isJoin: false });
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
// Await all pending connections concurrently
|
|
345
|
-
const results = await Promise.allSettled(pendingConnects.map(p => p.promise));
|
|
346
|
-
for (let i = 0; i < pendingConnects.length; i++) {
|
|
347
|
-
const { name, plugin, isJoin } = pendingConnects[i];
|
|
348
|
-
const result = results[i];
|
|
349
|
-
|
|
350
|
-
if (result.status === 'fulfilled') {
|
|
351
|
-
const client = result.value;
|
|
352
|
-
if (!isJoin) {
|
|
353
|
-
this.clients.set(name, client);
|
|
354
|
-
ctx.logger.info(`Plugin connected: ${name}`, { inject: `this.${plugin.inject}` });
|
|
355
|
-
}
|
|
356
|
-
clients.set(plugin.inject, client);
|
|
357
|
-
} else {
|
|
358
|
-
const err = result.reason;
|
|
359
|
-
if (!isJoin) {
|
|
360
|
-
ctx.metrics?.increment?.('forge_plugin_connect_failures_total', { plugin: name });
|
|
361
|
-
ctx.logger.warn(`Plugin "${name}" connect failed (degraded mode): ${err.message}`);
|
|
362
|
-
const prevCached = this.clients.get(name);
|
|
363
|
-
const attempts = (prevCached?._pluginError ? (prevCached.attempts ?? 0) : 0) + 1;
|
|
364
|
-
this.clients.set(name, { _pluginError: true, timestamp: Date.now(), errorMessage: err.message, attempts });
|
|
365
|
-
}
|
|
366
|
-
const pluginName = name;
|
|
367
|
-
const errMsg = err.message;
|
|
368
|
-
const errorProxy = new Proxy({}, {
|
|
369
|
-
get(_, prop) {
|
|
370
|
-
if (prop === Symbol.toPrimitive || prop === "then" || prop === Symbol.iterator) return undefined;
|
|
371
|
-
throw new Error(`Plugin "${pluginName}" is unavailable (connect failed: ${errMsg}). Check your ${pluginName} configuration.`);
|
|
372
|
-
},
|
|
373
|
-
});
|
|
374
|
-
clients.set(plugin.inject, errorProxy);
|
|
375
|
-
}
|
|
376
|
-
if (!isJoin) this._connecting.delete(name);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
return clients;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* Run health checks for all connected plugins.
|
|
384
|
-
*/
|
|
385
|
-
async healthCheck() {
|
|
386
|
-
const results = {};
|
|
387
|
-
|
|
388
|
-
for (const [name, plugin] of this.plugins) {
|
|
389
|
-
const client = this.clients.get(name);
|
|
390
|
-
|
|
391
|
-
if (!client || (typeof client === 'object' && client._pluginError === true)) {
|
|
392
|
-
results[name] = this.clients.has(name)
|
|
393
|
-
? { status: "error", error: "Plugin failed to connect" }
|
|
394
|
-
: { status: "not-checked" };
|
|
395
|
-
continue;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
if (!plugin.healthCheck) {
|
|
399
|
-
results[name] = { status: "unknown" };
|
|
400
|
-
continue;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
try {
|
|
404
|
-
results[name] = await withTimeout(plugin.healthCheck(client), HEALTH_TIMEOUT, `Plugin "${name}" healthCheck`);
|
|
405
|
-
} catch (err) {
|
|
406
|
-
results[name] = { status: "error", error: err.message };
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
return results;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
/**
|
|
414
|
-
* Collect Prometheus metrics from all plugins.
|
|
415
|
-
*/
|
|
416
|
-
collectMetrics(metricsCollector) {
|
|
417
|
-
for (const [name, plugin] of this.plugins) {
|
|
418
|
-
const client = this.clients.get(name);
|
|
419
|
-
if (!client || !plugin.metrics) continue;
|
|
420
|
-
|
|
421
|
-
try {
|
|
422
|
-
const pluginMetrics = plugin.metrics(client);
|
|
423
|
-
for (const [key, value] of Object.entries(pluginMetrics)) {
|
|
424
|
-
metricsCollector.gauge(`forge_plugin_${name}_${key}`, value);
|
|
425
|
-
}
|
|
426
|
-
} catch (err) {
|
|
427
|
-
this._logger?.warn?.(`Plugin metrics collection failed`, { error: err.message });
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
/**
|
|
433
|
-
* Disconnect all plugins (graceful shutdown).
|
|
434
|
-
*/
|
|
435
|
-
async disconnectAll(logger) {
|
|
436
|
-
const errors = [];
|
|
437
|
-
|
|
438
|
-
for (const [name, plugin] of this.plugins) {
|
|
439
|
-
const client = this.clients.get(name);
|
|
440
|
-
if (!client || (typeof client === 'object' && client._pluginError === true)) {
|
|
441
|
-
this.clients.delete(name);
|
|
442
|
-
continue;
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
try {
|
|
446
|
-
if (plugin.disconnect) {
|
|
447
|
-
await withTimeout(plugin.disconnect(client), DISCONNECT_TIMEOUT, `Plugin "${name}" disconnect`);
|
|
448
|
-
}
|
|
449
|
-
logger?.info(`Plugin disconnected: ${name}`);
|
|
450
|
-
} catch (err) {
|
|
451
|
-
errors.push({ name, error: err.message });
|
|
452
|
-
logger?.error(`Plugin "${name}" disconnect failed: ${err.message}`);
|
|
453
|
-
// Force cleanup as best effort
|
|
454
|
-
try {
|
|
455
|
-
if (typeof client.end === 'function') await client.end().catch(() => {});
|
|
456
|
-
else if (typeof client.quit === 'function') await client.quit().catch(() => {});
|
|
457
|
-
else if (typeof client.destroy === 'function') client.destroy();
|
|
458
|
-
} catch {}
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
this.clients.delete(name);
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
return errors;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
/**
|
|
468
|
-
* Get nginx config blocks from all plugins.
|
|
469
|
-
*/
|
|
470
|
-
nginxBlocks() {
|
|
471
|
-
const blocks = { upstreams: [], locations: [] };
|
|
472
|
-
|
|
473
|
-
for (const [, plugin] of this.plugins) {
|
|
474
|
-
if (!plugin.nginx) continue;
|
|
475
|
-
const nginx = plugin.nginx();
|
|
476
|
-
if (nginx.upstreams) blocks.upstreams.push(...nginx.upstreams);
|
|
477
|
-
if (nginx.locations) blocks.locations.push(...nginx.locations);
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
return blocks;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
/**
|
|
484
|
-
* Get middleware from all plugins (for service HTTP server).
|
|
485
|
-
*/
|
|
486
|
-
getMiddleware(servicePlugins) {
|
|
487
|
-
const middleware = [];
|
|
488
|
-
const names = servicePlugins ?? [...this.plugins.keys()];
|
|
489
|
-
|
|
490
|
-
for (const name of names) {
|
|
491
|
-
const plugin = this.plugins.get(name);
|
|
492
|
-
const client = this.clients.get(name);
|
|
493
|
-
if (!plugin?.middleware || !client) continue;
|
|
494
|
-
middleware.push(plugin.middleware(client));
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
return middleware;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
/**
|
|
501
|
-
* Get websocket lifecycle hooks from all plugins for a service.
|
|
502
|
-
*
|
|
503
|
-
* @param {string[] | null | undefined} servicePlugins
|
|
504
|
-
* @returns {Array<{name: string, onWsUpgrade?: Function, onWsConnect?: Function, onWsMessage?: Function, onWsClose?: Function}>}
|
|
505
|
-
*/
|
|
506
|
-
getWebSocketHooks(servicePlugins) {
|
|
507
|
-
const hooks = [];
|
|
508
|
-
const names = servicePlugins ?? [...this.plugins.keys()];
|
|
509
|
-
|
|
510
|
-
for (const name of names) {
|
|
511
|
-
const plugin = this.plugins.get(name);
|
|
512
|
-
const client = this.clients.get(name);
|
|
513
|
-
|
|
514
|
-
if (!plugin || !client) continue;
|
|
515
|
-
if (typeof client === "object" && client._pluginError === true) continue;
|
|
516
|
-
if (!plugin.onWsUpgrade && !plugin.onWsConnect && !plugin.onWsMessage && !plugin.onWsClose) continue;
|
|
517
|
-
|
|
518
|
-
hooks.push({
|
|
519
|
-
name,
|
|
520
|
-
onWsUpgrade: plugin.onWsUpgrade
|
|
521
|
-
? (ctx) => plugin.onWsUpgrade(client, ctx)
|
|
522
|
-
: undefined,
|
|
523
|
-
onWsConnect: plugin.onWsConnect
|
|
524
|
-
? (ctx) => plugin.onWsConnect(client, ctx)
|
|
525
|
-
: undefined,
|
|
526
|
-
onWsMessage: plugin.onWsMessage
|
|
527
|
-
? (ctx) => plugin.onWsMessage(client, ctx)
|
|
528
|
-
: undefined,
|
|
529
|
-
onWsClose: plugin.onWsClose
|
|
530
|
-
? (ctx) => plugin.onWsClose(client, ctx)
|
|
531
|
-
: undefined,
|
|
532
|
-
});
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
return hooks;
|
|
536
|
-
}
|
|
537
|
-
}
|