@overlordai/server 1.0.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/database/migrations/001-init-schema.sql +226 -0
- package/database/migrations/002-add-indexes.sql +17 -0
- package/database/migrations/003-add-settings-table.sql +4 -0
- package/database/migrations/004-add-developer-id-index.sql +5 -0
- package/dist/adapters/adapter.interface.d.ts +41 -0
- package/dist/adapters/adapter.interface.d.ts.map +1 -0
- package/dist/adapters/adapter.interface.js +6 -0
- package/dist/adapters/adapter.interface.js.map +1 -0
- package/dist/adapters/adapter.module.d.ts +3 -0
- package/dist/adapters/adapter.module.d.ts.map +1 -0
- package/dist/adapters/adapter.module.js +54 -0
- package/dist/adapters/adapter.module.js.map +1 -0
- package/dist/adapters/adapter.registry.d.ts +19 -0
- package/dist/adapters/adapter.registry.d.ts.map +1 -0
- package/dist/adapters/adapter.registry.js +51 -0
- package/dist/adapters/adapter.registry.js.map +1 -0
- package/dist/adapters/lark/lark-card.builder.d.ts +48 -0
- package/dist/adapters/lark/lark-card.builder.d.ts.map +1 -0
- package/dist/adapters/lark/lark-card.builder.js +259 -0
- package/dist/adapters/lark/lark-card.builder.js.map +1 -0
- package/dist/adapters/lark/lark-message.parser.d.ts +51 -0
- package/dist/adapters/lark/lark-message.parser.d.ts.map +1 -0
- package/dist/adapters/lark/lark-message.parser.js +189 -0
- package/dist/adapters/lark/lark-message.parser.js.map +1 -0
- package/dist/adapters/lark/lark-signature.d.ts +13 -0
- package/dist/adapters/lark/lark-signature.d.ts.map +1 -0
- package/dist/adapters/lark/lark-signature.js +58 -0
- package/dist/adapters/lark/lark-signature.js.map +1 -0
- package/dist/adapters/lark/lark.adapter.d.ts +65 -0
- package/dist/adapters/lark/lark.adapter.d.ts.map +1 -0
- package/dist/adapters/lark/lark.adapter.js +565 -0
- package/dist/adapters/lark/lark.adapter.js.map +1 -0
- package/dist/adapters/lark/lark.controller.d.ts +21 -0
- package/dist/adapters/lark/lark.controller.d.ts.map +1 -0
- package/dist/adapters/lark/lark.controller.js +120 -0
- package/dist/adapters/lark/lark.controller.js.map +1 -0
- package/dist/adapters/slack/slack.adapter.d.ts +19 -0
- package/dist/adapters/slack/slack.adapter.d.ts.map +1 -0
- package/dist/adapters/slack/slack.adapter.js +42 -0
- package/dist/adapters/slack/slack.adapter.js.map +1 -0
- package/dist/app.module.d.ts +5 -0
- package/dist/app.module.d.ts.map +1 -0
- package/dist/app.module.js +48 -0
- package/dist/app.module.js.map +1 -0
- package/dist/auth/auth.controller.d.ts +15 -0
- package/dist/auth/auth.controller.d.ts.map +1 -0
- package/dist/auth/auth.controller.js +67 -0
- package/dist/auth/auth.controller.js.map +1 -0
- package/dist/auth/auth.module.d.ts +3 -0
- package/dist/auth/auth.module.d.ts.map +1 -0
- package/dist/auth/auth.module.js +46 -0
- package/dist/auth/auth.module.js.map +1 -0
- package/dist/auth/auth.service.d.ts +62 -0
- package/dist/auth/auth.service.d.ts.map +1 -0
- package/dist/auth/auth.service.js +307 -0
- package/dist/auth/auth.service.js.map +1 -0
- package/dist/auth/decorators/allow-totp-setup.decorator.d.ts +3 -0
- package/dist/auth/decorators/allow-totp-setup.decorator.d.ts.map +1 -0
- package/dist/auth/decorators/allow-totp-setup.decorator.js +8 -0
- package/dist/auth/decorators/allow-totp-setup.decorator.js.map +1 -0
- package/dist/auth/decorators/project-roles.decorator.d.ts +4 -0
- package/dist/auth/decorators/project-roles.decorator.d.ts.map +1 -0
- package/dist/auth/decorators/project-roles.decorator.js +8 -0
- package/dist/auth/decorators/project-roles.decorator.js.map +1 -0
- package/dist/auth/decorators/roles.decorator.d.ts +4 -0
- package/dist/auth/decorators/roles.decorator.d.ts.map +1 -0
- package/dist/auth/decorators/roles.decorator.js +8 -0
- package/dist/auth/decorators/roles.decorator.js.map +1 -0
- package/dist/auth/extract-user.middleware.d.ts +21 -0
- package/dist/auth/extract-user.middleware.d.ts.map +1 -0
- package/dist/auth/extract-user.middleware.js +57 -0
- package/dist/auth/extract-user.middleware.js.map +1 -0
- package/dist/auth/guards/jwt-auth.guard.d.ts +14 -0
- package/dist/auth/guards/jwt-auth.guard.d.ts.map +1 -0
- package/dist/auth/guards/jwt-auth.guard.js +139 -0
- package/dist/auth/guards/jwt-auth.guard.js.map +1 -0
- package/dist/auth/guards/project-role.guard.d.ts +10 -0
- package/dist/auth/guards/project-role.guard.d.ts.map +1 -0
- package/dist/auth/guards/project-role.guard.js +72 -0
- package/dist/auth/guards/project-role.guard.js.map +1 -0
- package/dist/auth/guards/roles.guard.d.ts +8 -0
- package/dist/auth/guards/roles.guard.d.ts.map +1 -0
- package/dist/auth/guards/roles.guard.js +56 -0
- package/dist/auth/guards/roles.guard.js.map +1 -0
- package/dist/auth/jwt.strategy.d.ts +23 -0
- package/dist/auth/jwt.strategy.d.ts.map +1 -0
- package/dist/auth/jwt.strategy.js +49 -0
- package/dist/auth/jwt.strategy.js.map +1 -0
- package/dist/common/crypto.service.d.ts +31 -0
- package/dist/common/crypto.service.d.ts.map +1 -0
- package/dist/common/crypto.service.js +120 -0
- package/dist/common/crypto.service.js.map +1 -0
- package/dist/common/error-filter.d.ts +6 -0
- package/dist/common/error-filter.d.ts.map +1 -0
- package/dist/common/error-filter.js +78 -0
- package/dist/common/error-filter.js.map +1 -0
- package/dist/common/health.controller.d.ts +13 -0
- package/dist/common/health.controller.d.ts.map +1 -0
- package/dist/common/health.controller.js +75 -0
- package/dist/common/health.controller.js.map +1 -0
- package/dist/common/logger.service.d.ts +11 -0
- package/dist/common/logger.service.d.ts.map +1 -0
- package/dist/common/logger.service.js +48 -0
- package/dist/common/logger.service.js.map +1 -0
- package/dist/common/pagination.d.ts +18 -0
- package/dist/common/pagination.d.ts.map +1 -0
- package/dist/common/pagination.js +39 -0
- package/dist/common/pagination.js.map +1 -0
- package/dist/common/rate-limit.guard.d.ts +48 -0
- package/dist/common/rate-limit.guard.d.ts.map +1 -0
- package/dist/common/rate-limit.guard.js +129 -0
- package/dist/common/rate-limit.guard.js.map +1 -0
- package/dist/common/sensitive-filter.d.ts +7 -0
- package/dist/common/sensitive-filter.d.ts.map +1 -0
- package/dist/common/sensitive-filter.js +20 -0
- package/dist/common/sensitive-filter.js.map +1 -0
- package/dist/database/database.module.d.ts +3 -0
- package/dist/database/database.module.d.ts.map +1 -0
- package/dist/database/database.module.js +22 -0
- package/dist/database/database.module.js.map +1 -0
- package/dist/database/database.service.d.ts +13 -0
- package/dist/database/database.service.d.ts.map +1 -0
- package/dist/database/database.service.js +107 -0
- package/dist/database/database.service.js.map +1 -0
- package/dist/database/migration-runner.d.ts +5 -0
- package/dist/database/migration-runner.d.ts.map +1 -0
- package/dist/database/migration-runner.js +86 -0
- package/dist/database/migration-runner.js.map +1 -0
- package/dist/database/repositories/audit-log.repository.d.ts +29 -0
- package/dist/database/repositories/audit-log.repository.d.ts.map +1 -0
- package/dist/database/repositories/audit-log.repository.js +80 -0
- package/dist/database/repositories/audit-log.repository.js.map +1 -0
- package/dist/database/repositories/bot.repository.d.ts +67 -0
- package/dist/database/repositories/bot.repository.d.ts.map +1 -0
- package/dist/database/repositories/bot.repository.js +133 -0
- package/dist/database/repositories/bot.repository.js.map +1 -0
- package/dist/database/repositories/developer-token.repository.d.ts +40 -0
- package/dist/database/repositories/developer-token.repository.d.ts.map +1 -0
- package/dist/database/repositories/developer-token.repository.js +84 -0
- package/dist/database/repositories/developer-token.repository.js.map +1 -0
- package/dist/database/repositories/developer.repository.d.ts +25 -0
- package/dist/database/repositories/developer.repository.d.ts.map +1 -0
- package/dist/database/repositories/developer.repository.js +139 -0
- package/dist/database/repositories/developer.repository.js.map +1 -0
- package/dist/database/repositories/machine.repository.d.ts +39 -0
- package/dist/database/repositories/machine.repository.d.ts.map +1 -0
- package/dist/database/repositories/machine.repository.js +176 -0
- package/dist/database/repositories/machine.repository.js.map +1 -0
- package/dist/database/repositories/notification.repository.d.ts +19 -0
- package/dist/database/repositories/notification.repository.d.ts.map +1 -0
- package/dist/database/repositories/notification.repository.js +94 -0
- package/dist/database/repositories/notification.repository.js.map +1 -0
- package/dist/database/repositories/project-member.repository.d.ts +30 -0
- package/dist/database/repositories/project-member.repository.d.ts.map +1 -0
- package/dist/database/repositories/project-member.repository.js +75 -0
- package/dist/database/repositories/project-member.repository.js.map +1 -0
- package/dist/database/repositories/project.repository.d.ts +24 -0
- package/dist/database/repositories/project.repository.d.ts.map +1 -0
- package/dist/database/repositories/project.repository.js +154 -0
- package/dist/database/repositories/project.repository.js.map +1 -0
- package/dist/database/repositories/session.repository.d.ts +19 -0
- package/dist/database/repositories/session.repository.d.ts.map +1 -0
- package/dist/database/repositories/session.repository.js +117 -0
- package/dist/database/repositories/session.repository.js.map +1 -0
- package/dist/database/repositories/task.repository.d.ts +37 -0
- package/dist/database/repositories/task.repository.d.ts.map +1 -0
- package/dist/database/repositories/task.repository.js +229 -0
- package/dist/database/repositories/task.repository.js.map +1 -0
- package/dist/database/repositories/worker-token.repository.d.ts +20 -0
- package/dist/database/repositories/worker-token.repository.d.ts.map +1 -0
- package/dist/database/repositories/worker-token.repository.js +94 -0
- package/dist/database/repositories/worker-token.repository.js.map +1 -0
- package/dist/database/repositories/workspace.repository.d.ts +19 -0
- package/dist/database/repositories/workspace.repository.d.ts.map +1 -0
- package/dist/database/repositories/workspace.repository.js +82 -0
- package/dist/database/repositories/workspace.repository.js.map +1 -0
- package/dist/dispatcher/capability.service.d.ts +50 -0
- package/dist/dispatcher/capability.service.d.ts.map +1 -0
- package/dist/dispatcher/capability.service.js +159 -0
- package/dist/dispatcher/capability.service.js.map +1 -0
- package/dist/dispatcher/cleanup.service.d.ts +23 -0
- package/dist/dispatcher/cleanup.service.d.ts.map +1 -0
- package/dist/dispatcher/cleanup.service.js +107 -0
- package/dist/dispatcher/cleanup.service.js.map +1 -0
- package/dist/dispatcher/dedup.service.d.ts +48 -0
- package/dist/dispatcher/dedup.service.d.ts.map +1 -0
- package/dist/dispatcher/dedup.service.js +189 -0
- package/dist/dispatcher/dedup.service.js.map +1 -0
- package/dist/dispatcher/dispatcher.module.d.ts +3 -0
- package/dist/dispatcher/dispatcher.module.d.ts.map +1 -0
- package/dist/dispatcher/dispatcher.module.js +76 -0
- package/dist/dispatcher/dispatcher.module.js.map +1 -0
- package/dist/dispatcher/dispatcher.service.d.ts +134 -0
- package/dist/dispatcher/dispatcher.service.d.ts.map +1 -0
- package/dist/dispatcher/dispatcher.service.js +1034 -0
- package/dist/dispatcher/dispatcher.service.js.map +1 -0
- package/dist/dispatcher/heartbeat.service.d.ts +50 -0
- package/dist/dispatcher/heartbeat.service.d.ts.map +1 -0
- package/dist/dispatcher/heartbeat.service.js +154 -0
- package/dist/dispatcher/heartbeat.service.js.map +1 -0
- package/dist/dispatcher/machine-selector.d.ts +18 -0
- package/dist/dispatcher/machine-selector.d.ts.map +1 -0
- package/dist/dispatcher/machine-selector.js +144 -0
- package/dist/dispatcher/machine-selector.js.map +1 -0
- package/dist/dispatcher/pty-relay.service.d.ts +75 -0
- package/dist/dispatcher/pty-relay.service.d.ts.map +1 -0
- package/dist/dispatcher/pty-relay.service.js +404 -0
- package/dist/dispatcher/pty-relay.service.js.map +1 -0
- package/dist/dispatcher/reconciler.d.ts +39 -0
- package/dist/dispatcher/reconciler.d.ts.map +1 -0
- package/dist/dispatcher/reconciler.js +556 -0
- package/dist/dispatcher/reconciler.js.map +1 -0
- package/dist/dispatcher/scheduler.service.d.ts +50 -0
- package/dist/dispatcher/scheduler.service.d.ts.map +1 -0
- package/dist/dispatcher/scheduler.service.js +287 -0
- package/dist/dispatcher/scheduler.service.js.map +1 -0
- package/dist/dispatcher/state-machine.d.ts +16 -0
- package/dist/dispatcher/state-machine.d.ts.map +1 -0
- package/dist/dispatcher/state-machine.js +77 -0
- package/dist/dispatcher/state-machine.js.map +1 -0
- package/dist/dispatcher/task-log-batcher.d.ts +50 -0
- package/dist/dispatcher/task-log-batcher.d.ts.map +1 -0
- package/dist/dispatcher/task-log-batcher.js +184 -0
- package/dist/dispatcher/task-log-batcher.js.map +1 -0
- package/dist/dispatcher/worker-connection.manager.d.ts +49 -0
- package/dist/dispatcher/worker-connection.manager.d.ts.map +1 -0
- package/dist/dispatcher/worker-connection.manager.js +128 -0
- package/dist/dispatcher/worker-connection.manager.js.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +85 -0
- package/dist/main.js.map +1 -0
- package/dist/notifier/debouncer.d.ts +39 -0
- package/dist/notifier/debouncer.d.ts.map +1 -0
- package/dist/notifier/debouncer.js +123 -0
- package/dist/notifier/debouncer.js.map +1 -0
- package/dist/notifier/notification-consumer.d.ts +88 -0
- package/dist/notifier/notification-consumer.d.ts.map +1 -0
- package/dist/notifier/notification-consumer.js +186 -0
- package/dist/notifier/notification-consumer.js.map +1 -0
- package/dist/notifier/notifier.module.d.ts +9 -0
- package/dist/notifier/notifier.module.d.ts.map +1 -0
- package/dist/notifier/notifier.module.js +58 -0
- package/dist/notifier/notifier.module.js.map +1 -0
- package/dist/notifier/notifier.service.d.ts +40 -0
- package/dist/notifier/notifier.service.d.ts.map +1 -0
- package/dist/notifier/notifier.service.js +191 -0
- package/dist/notifier/notifier.service.js.map +1 -0
- package/dist/notifier/template.service.d.ts +42 -0
- package/dist/notifier/template.service.d.ts.map +1 -0
- package/dist/notifier/template.service.js +201 -0
- package/dist/notifier/template.service.js.map +1 -0
- package/dist/redis/redis.module.d.ts +3 -0
- package/dist/redis/redis.module.d.ts.map +1 -0
- package/dist/redis/redis.module.js +22 -0
- package/dist/redis/redis.module.js.map +1 -0
- package/dist/redis/redis.service.d.ts +19 -0
- package/dist/redis/redis.service.d.ts.map +1 -0
- package/dist/redis/redis.service.js +69 -0
- package/dist/redis/redis.service.js.map +1 -0
- package/dist/web/admin/admin-audit.controller.d.ts +7 -0
- package/dist/web/admin/admin-audit.controller.d.ts.map +1 -0
- package/dist/web/admin/admin-audit.controller.js +53 -0
- package/dist/web/admin/admin-audit.controller.js.map +1 -0
- package/dist/web/admin/admin-bot.controller.d.ts +79 -0
- package/dist/web/admin/admin-bot.controller.d.ts.map +1 -0
- package/dist/web/admin/admin-bot.controller.js +193 -0
- package/dist/web/admin/admin-bot.controller.js.map +1 -0
- package/dist/web/admin/admin-developer.controller.d.ts +52 -0
- package/dist/web/admin/admin-developer.controller.d.ts.map +1 -0
- package/dist/web/admin/admin-developer.controller.js +160 -0
- package/dist/web/admin/admin-developer.controller.js.map +1 -0
- package/dist/web/admin/admin-machine.controller.d.ts +64 -0
- package/dist/web/admin/admin-machine.controller.d.ts.map +1 -0
- package/dist/web/admin/admin-machine.controller.js +111 -0
- package/dist/web/admin/admin-machine.controller.js.map +1 -0
- package/dist/web/admin/admin-project.controller.d.ts +45 -0
- package/dist/web/admin/admin-project.controller.d.ts.map +1 -0
- package/dist/web/admin/admin-project.controller.js +207 -0
- package/dist/web/admin/admin-project.controller.js.map +1 -0
- package/dist/web/admin/admin-settings.controller.d.ts +18 -0
- package/dist/web/admin/admin-settings.controller.d.ts.map +1 -0
- package/dist/web/admin/admin-settings.controller.js +93 -0
- package/dist/web/admin/admin-settings.controller.js.map +1 -0
- package/dist/web/admin/admin-token.controller.d.ts +45 -0
- package/dist/web/admin/admin-token.controller.d.ts.map +1 -0
- package/dist/web/admin/admin-token.controller.js +182 -0
- package/dist/web/admin/admin-token.controller.js.map +1 -0
- package/dist/web/dashboard.controller.d.ts +16 -0
- package/dist/web/dashboard.controller.d.ts.map +1 -0
- package/dist/web/dashboard.controller.js +78 -0
- package/dist/web/dashboard.controller.js.map +1 -0
- package/dist/web/dashboard.service.d.ts +39 -0
- package/dist/web/dashboard.service.d.ts.map +1 -0
- package/dist/web/dashboard.service.js +234 -0
- package/dist/web/dashboard.service.js.map +1 -0
- package/dist/web/interaction.service.d.ts +42 -0
- package/dist/web/interaction.service.d.ts.map +1 -0
- package/dist/web/interaction.service.js +102 -0
- package/dist/web/interaction.service.js.map +1 -0
- package/dist/web/machine.controller.d.ts +102 -0
- package/dist/web/machine.controller.d.ts.map +1 -0
- package/dist/web/machine.controller.js +121 -0
- package/dist/web/machine.controller.js.map +1 -0
- package/dist/web/notification.controller.d.ts +22 -0
- package/dist/web/notification.controller.d.ts.map +1 -0
- package/dist/web/notification.controller.js +70 -0
- package/dist/web/notification.controller.js.map +1 -0
- package/dist/web/profile.controller.d.ts +70 -0
- package/dist/web/profile.controller.d.ts.map +1 -0
- package/dist/web/profile.controller.js +262 -0
- package/dist/web/profile.controller.js.map +1 -0
- package/dist/web/project.controller.d.ts +8 -0
- package/dist/web/project.controller.d.ts.map +1 -0
- package/dist/web/project.controller.js +54 -0
- package/dist/web/project.controller.js.map +1 -0
- package/dist/web/pty.gateway.d.ts +32 -0
- package/dist/web/pty.gateway.d.ts.map +1 -0
- package/dist/web/pty.gateway.js +358 -0
- package/dist/web/pty.gateway.js.map +1 -0
- package/dist/web/search.service.d.ts +34 -0
- package/dist/web/search.service.d.ts.map +1 -0
- package/dist/web/search.service.js +106 -0
- package/dist/web/search.service.js.map +1 -0
- package/dist/web/task.controller.d.ts +54 -0
- package/dist/web/task.controller.d.ts.map +1 -0
- package/dist/web/task.controller.js +266 -0
- package/dist/web/task.controller.js.map +1 -0
- package/dist/web/web.module.d.ts +3 -0
- package/dist/web/web.module.d.ts.map +1 -0
- package/dist/web/web.module.js +97 -0
- package/dist/web/web.module.js.map +1 -0
- package/dist/web/worker-channel.gateway.d.ts +45 -0
- package/dist/web/worker-channel.gateway.d.ts.map +1 -0
- package/dist/web/worker-channel.gateway.js +283 -0
- package/dist/web/worker-channel.gateway.js.map +1 -0
- package/dist/web/worker.controller.d.ts +14 -0
- package/dist/web/worker.controller.d.ts.map +1 -0
- package/dist/web/worker.controller.js +73 -0
- package/dist/web/worker.controller.js.map +1 -0
- package/dist/web/workspace.controller.d.ts +109 -0
- package/dist/web/workspace.controller.d.ts.map +1 -0
- package/dist/web/workspace.controller.js +386 -0
- package/dist/web/workspace.controller.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { WebSocket } from 'ws';
|
|
2
|
+
import type { DispatcherDownFrame } from '@overlordai/protocol';
|
|
3
|
+
export declare class WorkerConnectionManager {
|
|
4
|
+
private readonly logger;
|
|
5
|
+
private readonly connections;
|
|
6
|
+
private readonly pendingAcks;
|
|
7
|
+
/**
|
|
8
|
+
* Register a WebSocket connection for a given machine.
|
|
9
|
+
* If a previous connection exists, it is forcibly closed.
|
|
10
|
+
*/
|
|
11
|
+
register(machineId: string, ws: WebSocket): void;
|
|
12
|
+
/**
|
|
13
|
+
* Unregister the connection for a given machine.
|
|
14
|
+
*/
|
|
15
|
+
unregister(machineId: string): void;
|
|
16
|
+
/**
|
|
17
|
+
* Send a frame to a specific machine. The frame is JSON-serialized before sending.
|
|
18
|
+
* Returns true if the message was sent, false if the machine is not connected.
|
|
19
|
+
*/
|
|
20
|
+
send(machineId: string, frame: DispatcherDownFrame): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Send a frame that has a msgId and wait for the worker to acknowledge it.
|
|
23
|
+
* Resolves with the ack payload, or rejects on timeout.
|
|
24
|
+
*/
|
|
25
|
+
sendWithAck(machineId: string, frame: DispatcherDownFrame & {
|
|
26
|
+
msgId: string;
|
|
27
|
+
}, timeoutMs: number): Promise<Record<string, unknown> | undefined>;
|
|
28
|
+
/**
|
|
29
|
+
* Handle an incoming ack frame from a worker. Resolves the matching pending promise.
|
|
30
|
+
*/
|
|
31
|
+
handleAck(msgId: string, payload?: Record<string, unknown>): void;
|
|
32
|
+
/**
|
|
33
|
+
* Broadcast a frame to all connected machines.
|
|
34
|
+
*/
|
|
35
|
+
broadcast(frame: DispatcherDownFrame): void;
|
|
36
|
+
/**
|
|
37
|
+
* Check whether a machine is currently connected with an open WebSocket.
|
|
38
|
+
*/
|
|
39
|
+
isConnected(machineId: string): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Return the raw WebSocket for a machine, or undefined if not connected.
|
|
42
|
+
*/
|
|
43
|
+
getConnection(machineId: string): WebSocket | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* Generate a unique message ID for use in frames that require ack.
|
|
46
|
+
*/
|
|
47
|
+
generateMsgId(): string;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=worker-connection.manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-connection.manager.d.ts","sourceRoot":"","sources":["../../src/dispatcher/worker-connection.manager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAE/B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAQhE,qBACa,uBAAuB;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4C;IACnE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAgC;IAC5D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAiC;IAE7D;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,GAAG,IAAI;IAYhD;;OAEG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAKnC;;;OAGG;IACH,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,mBAAmB,GAAG,OAAO;IAqB5D;;;OAGG;IACH,WAAW,CACT,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,mBAAmB,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,EAC9C,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IA2B/C;;OAEG;IACH,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAWjE;;OAEG;IACH,SAAS,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI;IAgB3C;;OAEG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAKvC;;OAEG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAIvD;;OAEG;IACH,aAAa,IAAI,MAAM;CAGxB"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var WorkerConnectionManager_1;
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.WorkerConnectionManager = void 0;
|
|
11
|
+
const common_1 = require("@nestjs/common");
|
|
12
|
+
const ws_1 = require("ws");
|
|
13
|
+
const uuid_1 = require("uuid");
|
|
14
|
+
let WorkerConnectionManager = WorkerConnectionManager_1 = class WorkerConnectionManager {
|
|
15
|
+
logger = new common_1.Logger(WorkerConnectionManager_1.name);
|
|
16
|
+
connections = new Map();
|
|
17
|
+
pendingAcks = new Map();
|
|
18
|
+
/**
|
|
19
|
+
* Register a WebSocket connection for a given machine.
|
|
20
|
+
* If a previous connection exists, it is forcibly closed.
|
|
21
|
+
*/
|
|
22
|
+
register(machineId, ws) {
|
|
23
|
+
const existing = this.connections.get(machineId);
|
|
24
|
+
if (existing && existing.readyState === ws_1.WebSocket.OPEN) {
|
|
25
|
+
this.logger.warn(`Replacing existing connection for machine ${machineId}`);
|
|
26
|
+
existing.close(1000, 'Replaced by new connection');
|
|
27
|
+
}
|
|
28
|
+
this.connections.set(machineId, ws);
|
|
29
|
+
this.logger.log(`Machine ${machineId} connected`);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Unregister the connection for a given machine.
|
|
33
|
+
*/
|
|
34
|
+
unregister(machineId) {
|
|
35
|
+
this.connections.delete(machineId);
|
|
36
|
+
this.logger.log(`Machine ${machineId} disconnected`);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Send a frame to a specific machine. The frame is JSON-serialized before sending.
|
|
40
|
+
* Returns true if the message was sent, false if the machine is not connected.
|
|
41
|
+
*/
|
|
42
|
+
send(machineId, frame) {
|
|
43
|
+
const ws = this.connections.get(machineId);
|
|
44
|
+
if (!ws || ws.readyState !== ws_1.WebSocket.OPEN) {
|
|
45
|
+
this.logger.warn(`Cannot send to machine ${machineId}: not connected`);
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
ws.send(JSON.stringify(frame));
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
this.logger.error(`Failed to send frame to machine ${machineId}`, err instanceof Error ? err.stack : String(err));
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Send a frame that has a msgId and wait for the worker to acknowledge it.
|
|
59
|
+
* Resolves with the ack payload, or rejects on timeout.
|
|
60
|
+
*/
|
|
61
|
+
sendWithAck(machineId, frame, timeoutMs) {
|
|
62
|
+
return new Promise((resolve, reject) => {
|
|
63
|
+
const sent = this.send(machineId, frame);
|
|
64
|
+
if (!sent) {
|
|
65
|
+
reject(new Error(`Machine ${machineId} is not connected; cannot send frame`));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const timer = setTimeout(() => {
|
|
69
|
+
this.pendingAcks.delete(frame.msgId);
|
|
70
|
+
reject(new Error(`Ack timeout for msgId ${frame.msgId} on machine ${machineId} after ${timeoutMs}ms`));
|
|
71
|
+
}, timeoutMs);
|
|
72
|
+
this.pendingAcks.set(frame.msgId, { resolve, reject, timer });
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Handle an incoming ack frame from a worker. Resolves the matching pending promise.
|
|
77
|
+
*/
|
|
78
|
+
handleAck(msgId, payload) {
|
|
79
|
+
const pending = this.pendingAcks.get(msgId);
|
|
80
|
+
if (!pending) {
|
|
81
|
+
this.logger.debug(`No pending ack for msgId ${msgId}`);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
clearTimeout(pending.timer);
|
|
85
|
+
this.pendingAcks.delete(msgId);
|
|
86
|
+
pending.resolve(payload);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Broadcast a frame to all connected machines.
|
|
90
|
+
*/
|
|
91
|
+
broadcast(frame) {
|
|
92
|
+
const serialized = JSON.stringify(frame);
|
|
93
|
+
for (const [machineId, ws] of this.connections) {
|
|
94
|
+
if (ws.readyState === ws_1.WebSocket.OPEN) {
|
|
95
|
+
try {
|
|
96
|
+
ws.send(serialized);
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
this.logger.error(`Failed to broadcast to machine ${machineId}`, err instanceof Error ? err.stack : String(err));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Check whether a machine is currently connected with an open WebSocket.
|
|
106
|
+
*/
|
|
107
|
+
isConnected(machineId) {
|
|
108
|
+
const ws = this.connections.get(machineId);
|
|
109
|
+
return ws !== undefined && ws.readyState === ws_1.WebSocket.OPEN;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Return the raw WebSocket for a machine, or undefined if not connected.
|
|
113
|
+
*/
|
|
114
|
+
getConnection(machineId) {
|
|
115
|
+
return this.connections.get(machineId);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Generate a unique message ID for use in frames that require ack.
|
|
119
|
+
*/
|
|
120
|
+
generateMsgId() {
|
|
121
|
+
return (0, uuid_1.v4)();
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
exports.WorkerConnectionManager = WorkerConnectionManager;
|
|
125
|
+
exports.WorkerConnectionManager = WorkerConnectionManager = WorkerConnectionManager_1 = __decorate([
|
|
126
|
+
(0, common_1.Injectable)()
|
|
127
|
+
], WorkerConnectionManager);
|
|
128
|
+
//# sourceMappingURL=worker-connection.manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-connection.manager.js","sourceRoot":"","sources":["../../src/dispatcher/worker-connection.manager.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAAoD;AACpD,2BAA+B;AAC/B,+BAAoC;AAU7B,IAAM,uBAAuB,+BAA7B,MAAM,uBAAuB;IACjB,MAAM,GAAG,IAAI,eAAM,CAAC,yBAAuB,CAAC,IAAI,CAAC,CAAC;IAClD,WAAW,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC3C,WAAW,GAAG,IAAI,GAAG,EAAsB,CAAC;IAE7D;;;OAGG;IACH,QAAQ,CAAC,SAAiB,EAAE,EAAa;QACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACjD,IAAI,QAAQ,IAAI,QAAQ,CAAC,UAAU,KAAK,cAAS,CAAC,IAAI,EAAE,CAAC;YACvD,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,6CAA6C,SAAS,EAAE,CACzD,CAAC;YACF,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,4BAA4B,CAAC,CAAC;QACrD,CAAC;QACD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QACpC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,SAAS,YAAY,CAAC,CAAC;IACpD,CAAC;IAED;;OAEG;IACH,UAAU,CAAC,SAAiB;QAC1B,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACnC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,SAAS,eAAe,CAAC,CAAC;IACvD,CAAC;IAED;;;OAGG;IACH,IAAI,CAAC,SAAiB,EAAE,KAA0B;QAChD,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC3C,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,UAAU,KAAK,cAAS,CAAC,IAAI,EAAE,CAAC;YAC5C,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,0BAA0B,SAAS,iBAAiB,CACrD,CAAC;YACF,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,CAAC;YACH,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;YAC/B,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,mCAAmC,SAAS,EAAE,EAC9C,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAC/C,CAAC;YACF,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,WAAW,CACT,SAAiB,EACjB,KAA8C,EAC9C,SAAiB;QAEjB,OAAO,IAAI,OAAO,CAChB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAClB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;YACzC,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,MAAM,CACJ,IAAI,KAAK,CACP,WAAW,SAAS,sCAAsC,CAC3D,CACF,CAAC;gBACF,OAAO;YACT,CAAC;YAED,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC5B,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBACrC,MAAM,CACJ,IAAI,KAAK,CACP,yBAAyB,KAAK,CAAC,KAAK,eAAe,SAAS,UAAU,SAAS,IAAI,CACpF,CACF,CAAC;YACJ,CAAC,EAAE,SAAS,CAAC,CAAC;YAEd,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QAChE,CAAC,CACF,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,SAAS,CAAC,KAAa,EAAE,OAAiC;QACxD,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,KAAK,EAAE,CAAC,CAAC;YACvD,OAAO;QACT,CAAC;QACD,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC5B,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC/B,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,SAAS,CAAC,KAA0B;QAClC,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACzC,KAAK,MAAM,CAAC,SAAS,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YAC/C,IAAI,EAAE,CAAC,UAAU,KAAK,cAAS,CAAC,IAAI,EAAE,CAAC;gBACrC,IAAI,CAAC;oBACH,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBACtB,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,kCAAkC,SAAS,EAAE,EAC7C,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAC/C,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,WAAW,CAAC,SAAiB;QAC3B,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC3C,OAAO,EAAE,KAAK,SAAS,IAAI,EAAE,CAAC,UAAU,KAAK,cAAS,CAAC,IAAI,CAAC;IAC9D,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,SAAiB;QAC7B,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACzC,CAAC;IAED;;OAEG;IACH,aAAa;QACX,OAAO,IAAA,SAAM,GAAE,CAAC;IAClB,CAAC;CACF,CAAA;AA/IY,0DAAuB;kCAAvB,uBAAuB;IADnC,IAAA,mBAAU,GAAE;GACA,uBAAuB,CA+InC"}
|
package/dist/main.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC"}
|
package/dist/main.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
require("reflect-metadata");
|
|
5
|
+
const core_1 = require("@nestjs/core");
|
|
6
|
+
const platform_ws_1 = require("@nestjs/platform-ws");
|
|
7
|
+
const app_module_1 = require("./app.module");
|
|
8
|
+
const express_1 = require("express");
|
|
9
|
+
const path_1 = require("path");
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
const error_filter_1 = require("./common/error-filter");
|
|
12
|
+
async function bootstrap() {
|
|
13
|
+
const logger = new common_1.Logger('Bootstrap');
|
|
14
|
+
const app = await core_1.NestFactory.create(app_module_1.AppModule, { rawBody: true });
|
|
15
|
+
// CORS — configurable origin, defaults to allow all
|
|
16
|
+
const corsOrigin = process.env.CORS_ORIGIN || '*';
|
|
17
|
+
app.enableCors({
|
|
18
|
+
origin: corsOrigin,
|
|
19
|
+
credentials: corsOrigin !== '*',
|
|
20
|
+
});
|
|
21
|
+
// Body parser with 1MB limit
|
|
22
|
+
app.use((0, express_1.json)({ limit: '1mb' }));
|
|
23
|
+
// Static file serving from public/ directory
|
|
24
|
+
app.useStaticAssets((0, path_1.join)(__dirname, '..', 'public'));
|
|
25
|
+
// Global exception filter
|
|
26
|
+
app.useGlobalFilters(new error_filter_1.GlobalExceptionFilter());
|
|
27
|
+
// WebSocket adapter
|
|
28
|
+
app.useWebSocketAdapter(new platform_ws_1.WsAdapter(app));
|
|
29
|
+
// NOTE: Do NOT call app.enableShutdownHooks() here.
|
|
30
|
+
// The custom SIGTERM/SIGINT handlers below already call app.close(),
|
|
31
|
+
// which triggers NestJS lifecycle hooks. Enabling shutdown hooks would
|
|
32
|
+
// register a second set of signal handlers, causing double teardown.
|
|
33
|
+
const port = process.env.PORT || 9000;
|
|
34
|
+
// --- Graceful shutdown ---
|
|
35
|
+
let isShuttingDown = false;
|
|
36
|
+
// Step 1: Reject new requests during shutdown
|
|
37
|
+
app.use((_req, res, next) => {
|
|
38
|
+
if (isShuttingDown) {
|
|
39
|
+
res.status(503).json({ error: 'server_shutting_down' });
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
next();
|
|
43
|
+
});
|
|
44
|
+
const shutdown = async (signal) => {
|
|
45
|
+
if (isShuttingDown)
|
|
46
|
+
return;
|
|
47
|
+
isShuttingDown = true;
|
|
48
|
+
logger.warn(`Received ${signal}, starting graceful shutdown...`);
|
|
49
|
+
// Step 8: Overall 30-second forced exit timeout
|
|
50
|
+
const forceExitTimer = setTimeout(() => {
|
|
51
|
+
logger.error('Graceful shutdown timed out after 30s, forcing exit');
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}, 30_000);
|
|
54
|
+
forceExitTimer.unref();
|
|
55
|
+
try {
|
|
56
|
+
// All cleanup is handled by NestJS lifecycle hooks (onModuleDestroy):
|
|
57
|
+
// - SchedulerService: stops BullMQ poller and closes queue/worker
|
|
58
|
+
// - CleanupService: closes BullMQ queue/worker
|
|
59
|
+
// - TaskLogBatcher: flushes pending logs
|
|
60
|
+
// - HeartbeatService: flushes pending heartbeats
|
|
61
|
+
// - NotificationConsumer: closes BullMQ worker
|
|
62
|
+
// - DashboardService: clears refresh timer
|
|
63
|
+
// - DatabaseService: WAL checkpoint + close
|
|
64
|
+
// - RedisService: disconnect
|
|
65
|
+
//
|
|
66
|
+
// Do NOT manually flush/close services here — that causes double teardown
|
|
67
|
+
// because app.close() triggers the same onModuleDestroy hooks.
|
|
68
|
+
await app.close();
|
|
69
|
+
logger.log('Graceful shutdown complete');
|
|
70
|
+
clearTimeout(forceExitTimer);
|
|
71
|
+
process.exit(0);
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
logger.error('Error during graceful shutdown', err);
|
|
75
|
+
clearTimeout(forceExitTimer);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
80
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
81
|
+
await app.listen(port);
|
|
82
|
+
logger.log(`Overlord server listening on port ${port}`);
|
|
83
|
+
}
|
|
84
|
+
bootstrap();
|
|
85
|
+
//# sourceMappingURL=main.js.map
|
package/dist/main.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { OnModuleDestroy } from '@nestjs/common';
|
|
2
|
+
import type { Task } from '@overlordai/protocol';
|
|
3
|
+
/** Payload that accumulates during the debounce/merge window. */
|
|
4
|
+
export interface DebouncedNotification {
|
|
5
|
+
taskId: number;
|
|
6
|
+
task: Task;
|
|
7
|
+
eventType: string;
|
|
8
|
+
/** Latest status snapshot. */
|
|
9
|
+
latestStatus: string;
|
|
10
|
+
/** Accumulated stage transitions. */
|
|
11
|
+
stageChanges: string[];
|
|
12
|
+
/** Extra data from the most recent event. */
|
|
13
|
+
extra: Record<string, unknown>;
|
|
14
|
+
}
|
|
15
|
+
export type FlushCallback = (notification: DebouncedNotification) => void;
|
|
16
|
+
export declare class NotificationDebouncer implements OnModuleDestroy {
|
|
17
|
+
private readonly logger;
|
|
18
|
+
private readonly pending;
|
|
19
|
+
private flushCallback;
|
|
20
|
+
/**
|
|
21
|
+
* Register the callback that fires when a debounced notification is ready.
|
|
22
|
+
*/
|
|
23
|
+
onFlush(callback: FlushCallback): void;
|
|
24
|
+
/**
|
|
25
|
+
* Submit a notification event. Events for the same task within the debounce
|
|
26
|
+
* window are merged; the timer resets on each new event.
|
|
27
|
+
*
|
|
28
|
+
* @returns The dedup jobId (`${taskId}_${eventType}_${timeBucket}`) for BullMQ dedup.
|
|
29
|
+
*/
|
|
30
|
+
submit(task: Task, eventType: string, extra?: Record<string, unknown>): string;
|
|
31
|
+
/** Flush all pending entries immediately (used on shutdown). */
|
|
32
|
+
flushAll(): void;
|
|
33
|
+
onModuleDestroy(): void;
|
|
34
|
+
/** Check if a notification for this task+event is currently pending. */
|
|
35
|
+
isPending(taskId: number, eventType: string): boolean;
|
|
36
|
+
private createTimer;
|
|
37
|
+
private flushEntry;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=debouncer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debouncer.d.ts","sourceRoot":"","sources":["../../src/notifier/debouncer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAEjD,iEAAiE;AACjE,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,IAAI,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,8BAA8B;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,YAAY,EAAE,qBAAqB,KAAK,IAAI,CAAC;AAgB1E,qBACa,qBAAsB,YAAW,eAAe;IAC3D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;IACjE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmC;IAC3D,OAAO,CAAC,aAAa,CAA8B;IAEnD;;OAEG;IACH,OAAO,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI;IAItC;;;;;OAKG;IACH,MAAM,CACJ,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAClC,MAAM;IAsET,gEAAgE;IAChE,QAAQ,IAAI,IAAI;IAUhB,eAAe,IAAI,IAAI;IAIvB,wEAAwE;IACxE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;IAIrD,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,UAAU;CAgBnB"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var NotificationDebouncer_1;
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.NotificationDebouncer = void 0;
|
|
11
|
+
const common_1 = require("@nestjs/common");
|
|
12
|
+
/** Debounce delay before flushing (10 seconds). */
|
|
13
|
+
const DEBOUNCE_DELAY_MS = 10_000;
|
|
14
|
+
/** Merge window duration (1 minute). */
|
|
15
|
+
const MERGE_WINDOW_MS = 60_000;
|
|
16
|
+
let NotificationDebouncer = NotificationDebouncer_1 = class NotificationDebouncer {
|
|
17
|
+
logger = new common_1.Logger(NotificationDebouncer_1.name);
|
|
18
|
+
pending = new Map();
|
|
19
|
+
flushCallback = null;
|
|
20
|
+
/**
|
|
21
|
+
* Register the callback that fires when a debounced notification is ready.
|
|
22
|
+
*/
|
|
23
|
+
onFlush(callback) {
|
|
24
|
+
this.flushCallback = callback;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Submit a notification event. Events for the same task within the debounce
|
|
28
|
+
* window are merged; the timer resets on each new event.
|
|
29
|
+
*
|
|
30
|
+
* @returns The dedup jobId (`${taskId}_${eventType}_${timeBucket}`) for BullMQ dedup.
|
|
31
|
+
*/
|
|
32
|
+
submit(task, eventType, extra = {}) {
|
|
33
|
+
const currentBucket = Math.floor(Date.now() / MERGE_WINDOW_MS);
|
|
34
|
+
const notificationKey = `${task.id}_${eventType}`;
|
|
35
|
+
const jobId = `${notificationKey}_${currentBucket}`;
|
|
36
|
+
const existing = this.pending.get(notificationKey);
|
|
37
|
+
if (existing) {
|
|
38
|
+
// Within the same merge window — merge events.
|
|
39
|
+
if (existing.timeBucket === currentBucket) {
|
|
40
|
+
clearTimeout(existing.timer);
|
|
41
|
+
// Merge: keep latest status, accumulate stage changes.
|
|
42
|
+
existing.notification.task = task;
|
|
43
|
+
existing.notification.latestStatus = task.status;
|
|
44
|
+
existing.notification.extra = { ...existing.notification.extra, ...extra };
|
|
45
|
+
if (extra.toStage && typeof extra.toStage === 'string') {
|
|
46
|
+
if (!existing.notification.stageChanges.includes(extra.toStage)) {
|
|
47
|
+
existing.notification.stageChanges.push(extra.toStage);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
existing.timer = this.createTimer(notificationKey);
|
|
51
|
+
this.logger.debug(`Merged notification for task ${task.id} event=${eventType} bucket=${currentBucket}`);
|
|
52
|
+
return jobId;
|
|
53
|
+
}
|
|
54
|
+
// Different time bucket — flush the old one immediately and start fresh.
|
|
55
|
+
clearTimeout(existing.timer);
|
|
56
|
+
this.flushEntry(notificationKey);
|
|
57
|
+
}
|
|
58
|
+
// Create a new pending entry.
|
|
59
|
+
const stageChanges = [];
|
|
60
|
+
if (extra.toStage && typeof extra.toStage === 'string') {
|
|
61
|
+
stageChanges.push(extra.toStage);
|
|
62
|
+
}
|
|
63
|
+
if (extra.stage && typeof extra.stage === 'string' && stageChanges.length === 0) {
|
|
64
|
+
stageChanges.push(extra.stage);
|
|
65
|
+
}
|
|
66
|
+
const entry = {
|
|
67
|
+
notification: {
|
|
68
|
+
taskId: task.id,
|
|
69
|
+
task,
|
|
70
|
+
eventType,
|
|
71
|
+
latestStatus: task.status,
|
|
72
|
+
stageChanges,
|
|
73
|
+
extra,
|
|
74
|
+
},
|
|
75
|
+
timer: this.createTimer(notificationKey),
|
|
76
|
+
timeBucket: currentBucket,
|
|
77
|
+
};
|
|
78
|
+
this.pending.set(notificationKey, entry);
|
|
79
|
+
this.logger.debug(`Debounce started for task ${task.id} event=${eventType} bucket=${currentBucket}`);
|
|
80
|
+
return jobId;
|
|
81
|
+
}
|
|
82
|
+
/** Flush all pending entries immediately (used on shutdown). */
|
|
83
|
+
flushAll() {
|
|
84
|
+
for (const key of [...this.pending.keys()]) {
|
|
85
|
+
const entry = this.pending.get(key);
|
|
86
|
+
if (entry) {
|
|
87
|
+
clearTimeout(entry.timer);
|
|
88
|
+
}
|
|
89
|
+
this.flushEntry(key);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
onModuleDestroy() {
|
|
93
|
+
this.flushAll();
|
|
94
|
+
}
|
|
95
|
+
/** Check if a notification for this task+event is currently pending. */
|
|
96
|
+
isPending(taskId, eventType) {
|
|
97
|
+
return this.pending.has(`${taskId}_${eventType}`);
|
|
98
|
+
}
|
|
99
|
+
createTimer(key) {
|
|
100
|
+
return setTimeout(() => {
|
|
101
|
+
this.flushEntry(key);
|
|
102
|
+
}, DEBOUNCE_DELAY_MS);
|
|
103
|
+
}
|
|
104
|
+
flushEntry(key) {
|
|
105
|
+
const entry = this.pending.get(key);
|
|
106
|
+
if (!entry)
|
|
107
|
+
return;
|
|
108
|
+
this.pending.delete(key);
|
|
109
|
+
if (this.flushCallback) {
|
|
110
|
+
try {
|
|
111
|
+
this.flushCallback(entry.notification);
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
this.logger.error(`Flush callback error for key=${key}: ${err instanceof Error ? err.message : String(err)}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
exports.NotificationDebouncer = NotificationDebouncer;
|
|
120
|
+
exports.NotificationDebouncer = NotificationDebouncer = NotificationDebouncer_1 = __decorate([
|
|
121
|
+
(0, common_1.Injectable)()
|
|
122
|
+
], NotificationDebouncer);
|
|
123
|
+
//# sourceMappingURL=debouncer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debouncer.js","sourceRoot":"","sources":["../../src/notifier/debouncer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { OnModuleInit, OnModuleDestroy } from '@nestjs/common';
|
|
2
|
+
import type { Task } from '@overlordai/protocol';
|
|
3
|
+
import { NotificationRepository } from '../database/repositories/notification.repository';
|
|
4
|
+
import { TaskRepository } from '../database/repositories/task.repository';
|
|
5
|
+
import { TaskLogBatcher } from '../dispatcher/task-log-batcher';
|
|
6
|
+
import { TemplateService } from './template.service';
|
|
7
|
+
/** Name of the BullMQ notification queue. */
|
|
8
|
+
export declare const NOTIFICATION_QUEUE_NAME = "notification";
|
|
9
|
+
/** Payload shape for notification jobs. */
|
|
10
|
+
export interface NotificationJobData {
|
|
11
|
+
taskId: number;
|
|
12
|
+
eventType: string;
|
|
13
|
+
/** Source platform from the task (lark, slack, web, etc.). */
|
|
14
|
+
sourcePlatform: string | null;
|
|
15
|
+
/** Chat ID for platform message delivery. */
|
|
16
|
+
sourceChatId: string | null;
|
|
17
|
+
/** App ID used for platform adapter lookup. */
|
|
18
|
+
sourceAppId: string | null;
|
|
19
|
+
/** Existing notification message ID for in-place updates. */
|
|
20
|
+
notificationMsgId: string | null;
|
|
21
|
+
/** Snapshot of the task at notification time. */
|
|
22
|
+
task: Task;
|
|
23
|
+
/** Extra event-specific data. */
|
|
24
|
+
extra: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Interface for platform message adapters.
|
|
28
|
+
* Mirrors the adapter spec (IMessageAdapter) but only the parts we need.
|
|
29
|
+
*/
|
|
30
|
+
export interface IMessageAdapter {
|
|
31
|
+
platform: string;
|
|
32
|
+
sendMessage(chatId: string, content: {
|
|
33
|
+
type: 'text' | 'card';
|
|
34
|
+
text?: string;
|
|
35
|
+
card?: unknown;
|
|
36
|
+
}): Promise<string>;
|
|
37
|
+
updateMessage(msgId: string, content: {
|
|
38
|
+
type: 'text' | 'card';
|
|
39
|
+
text?: string;
|
|
40
|
+
card?: unknown;
|
|
41
|
+
}): Promise<void>;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Interface for the adapter registry.
|
|
45
|
+
* The real AdapterRegistry lives in the adapters module; we depend on an
|
|
46
|
+
* injectable token so the notifier module remains decoupled.
|
|
47
|
+
*/
|
|
48
|
+
export interface IAdapterRegistry {
|
|
49
|
+
getAdapter(platform: string): IMessageAdapter | null;
|
|
50
|
+
}
|
|
51
|
+
/** DI token for the adapter registry. */
|
|
52
|
+
export declare const ADAPTER_REGISTRY_TOKEN = "ADAPTER_REGISTRY";
|
|
53
|
+
export declare class NotificationConsumer implements OnModuleInit, OnModuleDestroy {
|
|
54
|
+
private readonly notificationRepo;
|
|
55
|
+
private readonly taskRepo;
|
|
56
|
+
private readonly taskLogBatcher;
|
|
57
|
+
private readonly templateService;
|
|
58
|
+
private readonly logger;
|
|
59
|
+
private worker;
|
|
60
|
+
/**
|
|
61
|
+
* Adapter registry is optional — if the adapters module is not yet loaded,
|
|
62
|
+
* platform notifications gracefully fall back to web (in-app) only.
|
|
63
|
+
*/
|
|
64
|
+
private adapterRegistry;
|
|
65
|
+
constructor(notificationRepo: NotificationRepository, taskRepo: TaskRepository, taskLogBatcher: TaskLogBatcher, templateService: TemplateService);
|
|
66
|
+
/** Allow the module to inject the adapter registry after construction. */
|
|
67
|
+
setAdapterRegistry(registry: IAdapterRegistry): void;
|
|
68
|
+
onModuleInit(): Promise<void>;
|
|
69
|
+
onModuleDestroy(): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Process a single notification job.
|
|
72
|
+
*/
|
|
73
|
+
private process;
|
|
74
|
+
/**
|
|
75
|
+
* Write an in-app (web) notification to the notifications table.
|
|
76
|
+
*/
|
|
77
|
+
private handleWebNotification;
|
|
78
|
+
/**
|
|
79
|
+
* Build the notification content from template service.
|
|
80
|
+
*/
|
|
81
|
+
private buildContent;
|
|
82
|
+
/**
|
|
83
|
+
* Persist the notification message ID on the task so subsequent
|
|
84
|
+
* notifications can update the same message in-place.
|
|
85
|
+
*/
|
|
86
|
+
private storeNotificationMsgId;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=notification-consumer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification-consumer.d.ts","sourceRoot":"","sources":["../../src/notifier/notification-consumer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGnF,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,kDAAkD,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,MAAM,0CAA0C,CAAC;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,6CAA6C;AAC7C,eAAO,MAAM,uBAAuB,iBAAiB,CAAC;AAEtD,2CAA2C;AAC3C,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,6CAA6C;IAC7C,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,+CAA+C;IAC/C,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,6DAA6D;IAC7D,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,iDAAiD;IACjD,IAAI,EAAE,IAAI,CAAC;IACX,iCAAiC;IACjC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CACT,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,GAChE,OAAO,CAAC,MAAM,CAAC,CAAC;IACnB,aAAa,CACX,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,GAChE,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAAC;CACtD;AAED,yCAAyC;AACzC,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AAEzD,qBACa,oBAAqB,YAAW,YAAY,EAAE,eAAe;IAWtE,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAblC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyC;IAChE,OAAO,CAAC,MAAM,CAAc;IAE5B;;;OAGG;IACH,OAAO,CAAC,eAAe,CAAiC;gBAGrC,gBAAgB,EAAE,sBAAsB,EACxC,QAAQ,EAAE,cAAc,EACxB,cAAc,EAAE,cAAc,EAC9B,eAAe,EAAE,eAAe;IAGnD,0EAA0E;IAC1E,kBAAkB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI;IAI9C,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAgC7B,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAMtC;;OAEG;YACW,OAAO;IA8ErB;;OAEG;YACW,qBAAqB;IA0BnC;;OAEG;IACH,OAAO,CAAC,YAAY;IA4BpB;;;OAGG;IACH,OAAO,CAAC,sBAAsB;CAiB/B"}
|