@lenne.tech/nest-server 11.31.1 → 11.31.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/.claude/rules/architecture.md +2 -0
  2. package/.claude/rules/configurable-features.md +2 -0
  3. package/CLAUDE.md +28 -1
  4. package/FRAMEWORK-API.md +4 -1
  5. package/dist/config.env.d.ts +4 -0
  6. package/dist/config.env.js +32 -2
  7. package/dist/config.env.js.map +1 -1
  8. package/dist/core/common/helpers/logging.helper.d.ts +1 -0
  9. package/dist/core/common/helpers/logging.helper.js +12 -0
  10. package/dist/core/common/helpers/logging.helper.js.map +1 -1
  11. package/dist/core/common/helpers/meta.helper.d.ts +1 -0
  12. package/dist/core/common/helpers/meta.helper.js +32 -1
  13. package/dist/core/common/helpers/meta.helper.js.map +1 -1
  14. package/dist/core/common/interfaces/server-options.interface.d.ts +9 -0
  15. package/dist/core/common/services/email.service.d.ts +3 -1
  16. package/dist/core/common/services/email.service.js +33 -2
  17. package/dist/core/common/services/email.service.js.map +1 -1
  18. package/dist/core/common/services/template.service.js +9 -4
  19. package/dist/core/common/services/template.service.js.map +1 -1
  20. package/dist/core/modules/ai/core-ai.controller.d.ts +1 -1
  21. package/dist/core/modules/ai/core-ai.controller.js +4 -5
  22. package/dist/core/modules/ai/core-ai.controller.js.map +1 -1
  23. package/dist/core/modules/ai/core-ai.resolver.d.ts +1 -1
  24. package/dist/core/modules/ai/core-ai.resolver.js +7 -6
  25. package/dist/core/modules/ai/core-ai.resolver.js.map +1 -1
  26. package/dist/core/modules/ai/models/core-ai-conversation.model.d.ts +6 -0
  27. package/dist/core/modules/ai/models/core-ai-conversation.model.js +13 -1
  28. package/dist/core/modules/ai/models/core-ai-conversation.model.js.map +1 -1
  29. package/dist/core/modules/ai/services/core-ai-conversation.service.d.ts +8 -2
  30. package/dist/core/modules/ai/services/core-ai-conversation.service.js +53 -2
  31. package/dist/core/modules/ai/services/core-ai-conversation.service.js.map +1 -1
  32. package/dist/core/modules/hub/core-hub-actions.controller.d.ts +22 -0
  33. package/dist/core/modules/hub/core-hub-actions.controller.js +141 -0
  34. package/dist/core/modules/hub/core-hub-actions.controller.js.map +1 -0
  35. package/dist/core/modules/hub/core-hub-html.service.d.ts +8 -0
  36. package/dist/core/modules/hub/core-hub-html.service.js +123 -0
  37. package/dist/core/modules/hub/core-hub-html.service.js.map +1 -0
  38. package/dist/core/modules/hub/core-hub.controller.d.ts +56 -0
  39. package/dist/core/modules/hub/core-hub.controller.js +398 -0
  40. package/dist/core/modules/hub/core-hub.controller.js.map +1 -0
  41. package/dist/core/modules/hub/core-hub.module.d.ts +17 -0
  42. package/dist/core/modules/hub/core-hub.module.js +109 -0
  43. package/dist/core/modules/hub/core-hub.module.js.map +1 -0
  44. package/dist/core/modules/hub/core-hub.service.d.ts +18 -0
  45. package/dist/core/modules/hub/core-hub.service.js +153 -0
  46. package/dist/core/modules/hub/core-hub.service.js.map +1 -0
  47. package/dist/core/modules/hub/helpers/hub-client-js.helper.d.ts +1 -0
  48. package/dist/core/modules/hub/helpers/hub-client-js.helper.js +755 -0
  49. package/dist/core/modules/hub/helpers/hub-client-js.helper.js.map +1 -0
  50. package/dist/core/modules/hub/helpers/hub-command-shape.helper.d.ts +1 -0
  51. package/dist/core/modules/hub/helpers/hub-command-shape.helper.js +33 -0
  52. package/dist/core/modules/hub/helpers/hub-command-shape.helper.js.map +1 -0
  53. package/dist/core/modules/hub/helpers/hub-mask.helper.d.ts +1 -0
  54. package/dist/core/modules/hub/helpers/hub-mask.helper.js +46 -0
  55. package/dist/core/modules/hub/helpers/hub-mask.helper.js.map +1 -0
  56. package/dist/core/modules/hub/helpers/hub-mermaid.helper.d.ts +10 -0
  57. package/dist/core/modules/hub/helpers/hub-mermaid.helper.js +35 -0
  58. package/dist/core/modules/hub/helpers/hub-mermaid.helper.js.map +1 -0
  59. package/dist/core/modules/hub/helpers/hub-shell.helper.d.ts +9 -0
  60. package/dist/core/modules/hub/helpers/hub-shell.helper.js +62 -0
  61. package/dist/core/modules/hub/helpers/hub-shell.helper.js.map +1 -0
  62. package/dist/core/modules/hub/hub-action-messages.d.ts +17 -0
  63. package/dist/core/modules/hub/hub-action-messages.js +21 -0
  64. package/dist/core/modules/hub/hub-action-messages.js.map +1 -0
  65. package/dist/core/modules/hub/hub-config.helper.d.ts +11 -0
  66. package/dist/core/modules/hub/hub-config.helper.js +164 -0
  67. package/dist/core/modules/hub/hub-config.helper.js.map +1 -0
  68. package/dist/core/modules/hub/hub-nav.d.ts +12 -0
  69. package/dist/core/modules/hub/hub-nav.js +43 -0
  70. package/dist/core/modules/hub/hub-nav.js.map +1 -0
  71. package/dist/core/modules/hub/hub-ring-buffer.d.ts +22 -0
  72. package/dist/core/modules/hub/hub-ring-buffer.js +59 -0
  73. package/dist/core/modules/hub/hub-ring-buffer.js.map +1 -0
  74. package/dist/core/modules/hub/hub.constants.d.ts +18 -0
  75. package/dist/core/modules/hub/hub.constants.js +22 -0
  76. package/dist/core/modules/hub/hub.constants.js.map +1 -0
  77. package/dist/core/modules/hub/index.d.ts +25 -0
  78. package/dist/core/modules/hub/index.js +42 -0
  79. package/dist/core/modules/hub/index.js.map +1 -0
  80. package/dist/core/modules/hub/interfaces/hub-config.interface.d.ts +115 -0
  81. package/dist/core/modules/hub/interfaces/hub-config.interface.js +3 -0
  82. package/dist/core/modules/hub/interfaces/hub-config.interface.js.map +1 -0
  83. package/dist/core/modules/hub/interfaces/hub-panels.interface.d.ts +231 -0
  84. package/dist/core/modules/hub/interfaces/hub-panels.interface.js +3 -0
  85. package/dist/core/modules/hub/interfaces/hub-panels.interface.js.map +1 -0
  86. package/dist/core/modules/hub/middleware/hub-trace.middleware.d.ts +8 -0
  87. package/dist/core/modules/hub/middleware/hub-trace.middleware.js +50 -0
  88. package/dist/core/modules/hub/middleware/hub-trace.middleware.js.map +1 -0
  89. package/dist/core/modules/hub/services/core-hub-actions.service.d.ts +48 -0
  90. package/dist/core/modules/hub/services/core-hub-actions.service.js +136 -0
  91. package/dist/core/modules/hub/services/core-hub-actions.service.js.map +1 -0
  92. package/dist/core/modules/hub/services/core-hub-db.service.d.ts +19 -0
  93. package/dist/core/modules/hub/services/core-hub-db.service.js +180 -0
  94. package/dist/core/modules/hub/services/core-hub-db.service.js.map +1 -0
  95. package/dist/core/modules/hub/services/core-hub-email.service.d.ts +24 -0
  96. package/dist/core/modules/hub/services/core-hub-email.service.js +148 -0
  97. package/dist/core/modules/hub/services/core-hub-email.service.js.map +1 -0
  98. package/dist/core/modules/hub/services/core-hub-mailbox.service.d.ts +20 -0
  99. package/dist/core/modules/hub/services/core-hub-mailbox.service.js +103 -0
  100. package/dist/core/modules/hub/services/core-hub-mailbox.service.js.map +1 -0
  101. package/dist/core/modules/hub/services/core-hub-migrations.service.d.ts +25 -0
  102. package/dist/core/modules/hub/services/core-hub-migrations.service.js +115 -0
  103. package/dist/core/modules/hub/services/core-hub-migrations.service.js.map +1 -0
  104. package/dist/core/modules/hub/services/core-hub-sources.service.d.ts +28 -0
  105. package/dist/core/modules/hub/services/core-hub-sources.service.js +187 -0
  106. package/dist/core/modules/hub/services/core-hub-sources.service.js.map +1 -0
  107. package/dist/core/modules/hub/services/hub-log-buffer.service.d.ts +24 -0
  108. package/dist/core/modules/hub/services/hub-log-buffer.service.js +210 -0
  109. package/dist/core/modules/hub/services/hub-log-buffer.service.js.map +1 -0
  110. package/dist/core/modules/hub/services/hub-query-profiler.service.d.ts +38 -0
  111. package/dist/core/modules/hub/services/hub-query-profiler.service.js +235 -0
  112. package/dist/core/modules/hub/services/hub-query-profiler.service.js.map +1 -0
  113. package/dist/core/modules/hub/services/hub-trace-buffer.service.d.ts +18 -0
  114. package/dist/core/modules/hub/services/hub-trace-buffer.service.js +123 -0
  115. package/dist/core/modules/hub/services/hub-trace-buffer.service.js.map +1 -0
  116. package/dist/core.module.js +42 -1
  117. package/dist/core.module.js.map +1 -1
  118. package/dist/index.d.ts +1 -0
  119. package/dist/index.js +1 -0
  120. package/dist/index.js.map +1 -1
  121. package/dist/tsconfig.build.tsbuildinfo +1 -1
  122. package/docs/REQUEST-LIFECYCLE.md +1 -0
  123. package/migration-guides/11.31.1-to-11.31.2.md +127 -0
  124. package/migration-guides/11.31.2-to-11.31.3.md +135 -0
  125. package/package.json +5 -4
  126. package/src/config.env.ts +75 -2
  127. package/src/core/common/helpers/logging.helper.spec.ts +61 -0
  128. package/src/core/common/helpers/logging.helper.ts +48 -0
  129. package/src/core/common/helpers/meta.helper.ts +46 -1
  130. package/src/core/common/interfaces/server-options.interface.ts +46 -0
  131. package/src/core/common/services/email.service.ts +33 -1
  132. package/src/core/common/services/template.service.ts +21 -16
  133. package/src/core/modules/ai/core-ai.controller.ts +12 -9
  134. package/src/core/modules/ai/core-ai.resolver.ts +14 -9
  135. package/src/core/modules/ai/models/core-ai-conversation.model.ts +18 -1
  136. package/src/core/modules/ai/services/core-ai-conversation.service.ts +110 -4
  137. package/src/core/modules/hub/INTEGRATION-CHECKLIST.md +64 -0
  138. package/src/core/modules/hub/README.md +159 -0
  139. package/src/core/modules/hub/core-hub-actions.controller.ts +137 -0
  140. package/src/core/modules/hub/core-hub-html.service.ts +135 -0
  141. package/src/core/modules/hub/core-hub.controller.ts +286 -0
  142. package/src/core/modules/hub/core-hub.module.spec.ts +108 -0
  143. package/src/core/modules/hub/core-hub.module.ts +159 -0
  144. package/src/core/modules/hub/core-hub.service.ts +169 -0
  145. package/src/core/modules/hub/helpers/hub-client-js.helper.ts +768 -0
  146. package/src/core/modules/hub/helpers/hub-command-shape.helper.spec.ts +48 -0
  147. package/src/core/modules/hub/helpers/hub-command-shape.helper.ts +47 -0
  148. package/src/core/modules/hub/helpers/hub-mask.helper.spec.ts +67 -0
  149. package/src/core/modules/hub/helpers/hub-mask.helper.ts +78 -0
  150. package/src/core/modules/hub/helpers/hub-mermaid.helper.spec.ts +54 -0
  151. package/src/core/modules/hub/helpers/hub-mermaid.helper.ts +62 -0
  152. package/src/core/modules/hub/helpers/hub-shell.helper.spec.ts +106 -0
  153. package/src/core/modules/hub/helpers/hub-shell.helper.ts +90 -0
  154. package/src/core/modules/hub/hub-action-messages.ts +47 -0
  155. package/src/core/modules/hub/hub-config.helper.spec.ts +108 -0
  156. package/src/core/modules/hub/hub-config.helper.ts +233 -0
  157. package/src/core/modules/hub/hub-nav.ts +66 -0
  158. package/src/core/modules/hub/hub-ring-buffer.spec.ts +95 -0
  159. package/src/core/modules/hub/hub-ring-buffer.ts +101 -0
  160. package/src/core/modules/hub/hub.constants.ts +84 -0
  161. package/src/core/modules/hub/index.ts +25 -0
  162. package/src/core/modules/hub/interfaces/hub-config.interface.ts +265 -0
  163. package/src/core/modules/hub/interfaces/hub-panels.interface.ts +186 -0
  164. package/src/core/modules/hub/middleware/hub-trace.middleware.ts +45 -0
  165. package/src/core/modules/hub/services/core-hub-actions.service.ts +133 -0
  166. package/src/core/modules/hub/services/core-hub-db.service.ts +185 -0
  167. package/src/core/modules/hub/services/core-hub-email.service.ts +158 -0
  168. package/src/core/modules/hub/services/core-hub-mailbox.service.spec.ts +116 -0
  169. package/src/core/modules/hub/services/core-hub-mailbox.service.ts +121 -0
  170. package/src/core/modules/hub/services/core-hub-migrations.service.ts +112 -0
  171. package/src/core/modules/hub/services/core-hub-sources.service.ts +194 -0
  172. package/src/core/modules/hub/services/hub-log-buffer.service.ts +252 -0
  173. package/src/core/modules/hub/services/hub-query-profiler.service.ts +274 -0
  174. package/src/core/modules/hub/services/hub-trace-buffer.service.spec.ts +112 -0
  175. package/src/core/modules/hub/services/hub-trace-buffer.service.ts +134 -0
  176. package/src/core.module.ts +61 -1
  177. package/src/index.ts +6 -0
@@ -0,0 +1,159 @@
1
+ import { DynamicModule, MiddlewareConsumer, Module, NestModule, Provider, Type } from '@nestjs/common';
2
+ import { PATH_METADATA } from '@nestjs/common/constants';
3
+
4
+ import { CoreHubActionsController } from './core-hub-actions.controller';
5
+ import { CoreHubHtmlService } from './core-hub-html.service';
6
+ import { CoreHubController } from './core-hub.controller';
7
+ import { CoreHubService } from './core-hub.service';
8
+ import { HUB_CONFIG, HUB_EMAIL_CAPTURE } from './hub.constants';
9
+ import { HubConfigContext, isReachableEnv, normalizeHubConfig } from './hub-config.helper';
10
+ import { HubTraceMiddleware } from './middleware/hub-trace.middleware';
11
+ import { CoreHubActionsService } from './services/core-hub-actions.service';
12
+ import { CoreHubDbService } from './services/core-hub-db.service';
13
+ import { CoreHubEmailService } from './services/core-hub-email.service';
14
+ import { CoreHubMailboxService } from './services/core-hub-mailbox.service';
15
+ import { CoreHubMigrationsService } from './services/core-hub-migrations.service';
16
+ import { CoreHubSourcesService } from './services/core-hub-sources.service';
17
+ import { HubLogBufferService } from './services/hub-log-buffer.service';
18
+ import { HubQueryProfilerService } from './services/hub-query-profiler.service';
19
+ import { HubTraceBufferService } from './services/hub-trace-buffer.service';
20
+ import { IHubConfig } from './interfaces/hub-config.interface';
21
+
22
+ /** Options passed by `CoreModule.forRoot()` when it registers the Hub. */
23
+ export interface CoreHubModuleOptions {
24
+ /** Override the actions controller (must extend `CoreHubActionsController`). */
25
+ actionsController?: Type<any>;
26
+ /** Override the actions service (must extend `CoreHubActionsService`). */
27
+ actionsService?: Type<any>;
28
+ /** Raw hub config from `IServerOptions.hub`. */
29
+ config: boolean | IHubConfig;
30
+ /** Override the page/sidecar controller (must extend `CoreHubController`). */
31
+ controller?: Type<any>;
32
+ /** Environment-derived defaults (env name, version, GraphQL/permissions link resolution). */
33
+ ctx: HubConfigContext;
34
+ /** Override the HTML shell service (must extend `CoreHubHtmlService`). */
35
+ htmlService?: Type<any>;
36
+ /** Override the aggregator service (must extend `CoreHubService`). */
37
+ service?: Type<any>;
38
+ }
39
+
40
+ /**
41
+ * The Hub admin area (operator cockpit).
42
+ *
43
+ * Registered by `CoreModule.forRoot()` when `IServerOptions.hub` is enabled. The controller path and
44
+ * required roles are assigned to the controller class at runtime (via `Reflect.defineMetadata`)
45
+ * because they come from configuration — the same pattern the permissions module uses.
46
+ */
47
+ @Module({})
48
+ export class CoreHubModule implements NestModule {
49
+ // Write-once-per-forRoot (same accepted pattern as CoreModule.graphQlEnabled). Read by configure()
50
+ // to decide whether to bind the trace middleware. The last forRoot wins in multi-app processes.
51
+ private static traceEnabled = false;
52
+
53
+ configure(consumer: MiddlewareConsumer): void {
54
+ if (CoreHubModule.traceEnabled) {
55
+ // Bind before RequestContextMiddleware so timing starts early; the trace path never reads
56
+ // RequestContext (it uses req.user directly), so ordering is a non-issue.
57
+ consumer.apply(HubTraceMiddleware).forRoutes('*');
58
+ }
59
+ }
60
+
61
+ static forRoot(options: CoreHubModuleOptions): DynamicModule {
62
+ const resolved = normalizeHubConfig(options.config, options.ctx);
63
+ CoreHubModule.traceEnabled = resolved.collectors.traces !== false;
64
+
65
+ // Guard: capture mode silently suppresses outgoing mail — forbid it in production/staging so a
66
+ // misconfiguration cannot make password-reset, 2FA and verification mail vanish (mirrors the
67
+ // JSONTransport guard in EmailService).
68
+ if (resolved.mailbox !== false && resolved.mailbox.mode === 'capture' && isReachableEnv(resolved.env)) {
69
+ throw new Error(
70
+ `Hub mailbox mode 'capture' is not permitted in a reachable environment (${resolved.env}): it ` +
71
+ "suppresses all outgoing mail. Use mode 'copy' (send + record) or disable the mailbox.",
72
+ );
73
+ }
74
+
75
+ // Guard: a PUBLIC Hub (roles: false → no auth check whatsoever) in a reachable environment exposes
76
+ // the config viewer, logs and DESTRUCTIVE admin actions (migrations, file delete, cron control) to
77
+ // ANY unauthenticated request. Forbid it in production/staging unless the operator has EXPLICITLY
78
+ // acknowledged it via `allowPublicAccessInProduction` (only sane behind a fully-controlled network
79
+ // boundary). This mirrors the mailbox-capture guard above and closes the single most dangerous
80
+ // Hub misconfiguration (e.g. a `roles: false` copied from a local config).
81
+ if (resolved.roles === false && isReachableEnv(resolved.env) && !resolved.allowPublicAccessInProduction) {
82
+ throw new Error(
83
+ `Hub 'roles: false' (no auth check) is not permitted in a reachable environment (${resolved.env}): ` +
84
+ 'it exposes the config viewer, logs and destructive admin actions to unauthenticated requests. ' +
85
+ 'Keep the default ADMIN gate (omit `roles`), or — ONLY behind a fully-controlled network ' +
86
+ 'boundary — set hub.allowPublicAccessInProduction: true to acknowledge the risk.',
87
+ );
88
+ }
89
+
90
+ const ControllerClass = options.controller || CoreHubController;
91
+ const ActionsControllerClass = options.actionsController || CoreHubActionsController;
92
+
93
+ // Runtime path + roles metadata (see permissions module), applied to BOTH controllers. Written
94
+ // UNCONDITIONALLY so a second forRoot on the same class fully overrides the first — otherwise
95
+ // stale metadata leaks across app instances that share the class (a real hazard in multi-app
96
+ // tests). `roles: false` clears the metadata, which the guards read as "public" — a deliberate,
97
+ // dangerous opt-out (documented in IHubConfig.roles).
98
+ for (const Ctrl of resolved.actions ? [ControllerClass, ActionsControllerClass] : [ControllerClass]) {
99
+ Reflect.defineMetadata(PATH_METADATA, resolved.path, Ctrl);
100
+ if (resolved.roles === false) {
101
+ Reflect.deleteMetadata('roles', Ctrl);
102
+ } else {
103
+ Reflect.defineMetadata('roles', resolved.roles, Ctrl);
104
+ }
105
+ }
106
+
107
+ const providers: Provider[] = [
108
+ { provide: HUB_CONFIG, useValue: resolved },
109
+ { provide: CoreHubService, useClass: options.service || CoreHubService },
110
+ { provide: CoreHubHtmlService, useClass: options.htmlService || CoreHubHtmlService },
111
+ CoreHubDbService,
112
+ CoreHubEmailService,
113
+ CoreHubMigrationsService,
114
+ CoreHubSourcesService,
115
+ // Collectors are always provided; each is inert when its own config slice is disabled, so the
116
+ // sidecar can answer `{ enabled: false }` rather than 404.
117
+ HubLogBufferService,
118
+ HubQueryProfilerService,
119
+ HubTraceBufferService,
120
+ HubTraceMiddleware,
121
+ ];
122
+
123
+ // Actions controller/service only when actions are enabled (disabling removes the routes → 404).
124
+ const controllers: Type<any>[] = [ControllerClass];
125
+ if (resolved.actions) {
126
+ controllers.push(ActionsControllerClass);
127
+ providers.push({ provide: CoreHubActionsService, useClass: options.actionsService || CoreHubActionsService });
128
+ }
129
+
130
+ // When the mailbox is enabled, provide it AND bind it to the EMAIL_CAPTURE token so EmailService
131
+ // (which injects the token optionally) starts capturing. The module must be global for the token
132
+ // to reach EmailService, which lives in a different module.
133
+ const global = resolved.mailbox !== false;
134
+ if (global) {
135
+ providers.push(CoreHubMailboxService);
136
+ providers.push({ provide: HUB_EMAIL_CAPTURE, useExisting: CoreHubMailboxService });
137
+ }
138
+
139
+ return {
140
+ controllers,
141
+ exports: [
142
+ CoreHubService,
143
+ CoreHubHtmlService,
144
+ CoreHubDbService,
145
+ CoreHubEmailService,
146
+ CoreHubMigrationsService,
147
+ CoreHubSourcesService,
148
+ HubLogBufferService,
149
+ HubQueryProfilerService,
150
+ HubTraceBufferService,
151
+ HUB_CONFIG,
152
+ ...(global ? [CoreHubMailboxService, HUB_EMAIL_CAPTURE] : []),
153
+ ],
154
+ global,
155
+ module: CoreHubModule,
156
+ providers,
157
+ };
158
+ }
159
+ }
@@ -0,0 +1,169 @@
1
+ import { Inject, Injectable, Optional } from '@nestjs/common';
2
+ import { InjectConnection } from '@nestjs/mongoose';
3
+ import { Connection } from 'mongoose';
4
+
5
+ import { getBuildInfo } from '../../common/helpers/meta.helper';
6
+ import { ConfigService } from '../../common/services/config.service';
7
+
8
+ import { HUB_CONFIG } from './hub.constants';
9
+ import { HUB_PANEL_GROUPS, HUB_PANELS } from './hub-nav';
10
+ import { maskConfigDeep } from './helpers/hub-mask.helper';
11
+ import { CoreHubSourcesService } from './services/core-hub-sources.service';
12
+ import { HubDashboardData, HubDiagnosticsData, HubSessionData } from './interfaces/hub-panels.interface';
13
+ import { ResolvedHubConfig } from './interfaces/hub-config.interface';
14
+
15
+ /**
16
+ * Framework-default secret field names (see CheckSecurityInterceptor). Union with the pattern-based
17
+ * masking in {@link maskConfigDeep} and the project's `security.secretFields`.
18
+ */
19
+ const FRAMEWORK_SECRET_FIELDS = [
20
+ 'password',
21
+ 'verificationToken',
22
+ 'passwordResetToken',
23
+ 'refreshTokens',
24
+ 'tempTokens',
25
+ 'apiKeyEncrypted',
26
+ ];
27
+
28
+ const MONGO_STATES: Record<number, string> = {
29
+ 0: 'disconnected',
30
+ 1: 'connected',
31
+ 2: 'connecting',
32
+ 3: 'disconnecting',
33
+ 99: 'uninitialized',
34
+ };
35
+
36
+ /**
37
+ * Aggregator for the Hub's own data (dashboard + diagnostics + the feature matrix). Panel-specific
38
+ * data lives in the focused services (`CoreHubDbService`, `CoreHubMigrationsService`, …).
39
+ *
40
+ * Overridable via `overrides.hub.service`.
41
+ */
42
+ @Injectable()
43
+ export class CoreHubService {
44
+ constructor(
45
+ @Inject(HUB_CONFIG) protected readonly config: ResolvedHubConfig,
46
+ protected readonly configService: ConfigService,
47
+ protected readonly sources: CoreHubSourcesService,
48
+ @Optional() @InjectConnection() protected readonly connection?: Connection,
49
+ ) {}
50
+
51
+ /** Data for the dashboard panel. */
52
+ getDashboard(): HubDashboardData {
53
+ const mem = process.memoryUsage();
54
+ const build = getBuildInfo({ env: this.config.env, version: this.config.version });
55
+ const readyState = this.connection?.readyState ?? 0;
56
+
57
+ return {
58
+ build: { commit: build.commit, env: this.config.env, version: this.config.version },
59
+ features: this.featureMatrix(),
60
+ links: { ...this.config.links },
61
+ memory: { heapTotal: mem.heapTotal, heapUsed: mem.heapUsed, rss: mem.rss },
62
+ mongo: { readyState, state: MONGO_STATES[readyState] ?? 'unknown' },
63
+ time: new Date().toISOString(),
64
+ uptimeSeconds: Math.round(process.uptime()),
65
+ };
66
+ }
67
+
68
+ /** Data for the diagnostics panel. `buffers` is filled once the collectors are wired (Phase 6). */
69
+ getDiagnostics(buffers: HubDiagnosticsData['buffers'] = {}): HubDiagnosticsData {
70
+ const mem = process.memoryUsage();
71
+ const cpu = process.cpuUsage();
72
+
73
+ return {
74
+ arch: process.arch,
75
+ buffers,
76
+ cpuUsage: { system: cpu.system, user: cpu.user },
77
+ env: this.config.env,
78
+ memory: {
79
+ arrayBuffers: mem.arrayBuffers,
80
+ external: mem.external,
81
+ heapTotal: mem.heapTotal,
82
+ heapUsed: mem.heapUsed,
83
+ rss: mem.rss,
84
+ },
85
+ nodeVersion: process.version,
86
+ pid: process.pid,
87
+ platform: process.platform,
88
+ time: new Date().toISOString(),
89
+ uptimeSeconds: Math.round(process.uptime()),
90
+ };
91
+ }
92
+
93
+ /**
94
+ * The full server config with all secrets masked. Deep-cloned first (never mutate the live config),
95
+ * then masked by key heuristics + the framework/project secret-field lists.
96
+ */
97
+ getConfigMasked(): Record<string, unknown> {
98
+ const raw = this.configService.configFastButReadOnly as Record<string, unknown>;
99
+ const projectSecretFields = this.configService.get<string[]>('security.secretFields', []) ?? [];
100
+ return maskConfigDeep(raw, [...FRAMEWORK_SECRET_FIELDS, ...projectSecretFields]);
101
+ }
102
+
103
+ /** The resolved Hub config (for controller/actions/gating decisions). */
104
+ getResolvedConfig(): ResolvedHubConfig {
105
+ return this.config;
106
+ }
107
+
108
+ /**
109
+ * Cockpit-chrome data the client needs to build the navigation AFTER a successful ADMIN auth check.
110
+ * Served ADMIN-gated via `GET /{hub}/session.json`. Because it sits behind the roles guard, the
111
+ * public shell can carry NO nav/env/links — an unauthenticated request reveals nothing of the Hub.
112
+ */
113
+ getSessionPayload(): HubSessionData {
114
+ // Availability of the optional-source panels, so the client can grey out + disable dead nav
115
+ // entries. `mailbox` depends on config (its service is only provided when enabled); everything not
116
+ // covered is intrinsic to the Hub and always available.
117
+ const sourceAvailability = this.sources.getPanelAvailability();
118
+ const isAvailable = (id: string): boolean => {
119
+ if (id === 'mailbox') {
120
+ return this.config.mailbox !== false;
121
+ }
122
+ return sourceAvailability[id] ?? true;
123
+ };
124
+
125
+ return {
126
+ authenticated: true,
127
+ env: this.config.env,
128
+ links: { ...this.config.links },
129
+ logoutEndpoint: this.config.logoutEndpoint,
130
+ panelGroups: [...HUB_PANEL_GROUPS],
131
+ panels: HUB_PANELS.map((panel) => ({
132
+ available: isAvailable(panel.id),
133
+ group: panel.group,
134
+ id: panel.id,
135
+ optional: !!panel.optional,
136
+ path: panel.path,
137
+ title: panel.title,
138
+ })),
139
+ version: this.config.version,
140
+ };
141
+ }
142
+
143
+ /** Which optional framework features are active, for the dashboard feature matrix. */
144
+ protected featureMatrix(): Record<string, boolean> {
145
+ const has = (key: string): boolean => {
146
+ const value = this.configService.get(key);
147
+ if (value === undefined || value === null || value === false) {
148
+ return false;
149
+ }
150
+ if (typeof value === 'object') {
151
+ return (value as { enabled?: boolean }).enabled !== false;
152
+ }
153
+ return true;
154
+ };
155
+
156
+ return {
157
+ ai: has('ai'),
158
+ // Runtime check: BetterAuth can be active via BetterAuthModule.forRoot() without an obvious
159
+ // config flag, so config-sniffing is unreliable — ask whether it is actually wired in.
160
+ betterAuth: this.sources.isBetterAuthActive(),
161
+ cookies: this.configService.get('cookies') !== false,
162
+ graphQl: this.configService.get('graphQl') !== false,
163
+ healthCheck: has('healthCheck'),
164
+ multiTenancy: has('multiTenancy'),
165
+ permissions: has('permissions'),
166
+ tus: has('tus'),
167
+ };
168
+ }
169
+ }