@codemation/host 0.2.5 → 0.3.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.
Files changed (123) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/dist/{AppConfigFactory-CqKWXqOm.js → AppConfigFactory-BPp02HMv.js} +82 -5
  3. package/dist/{AppConfigFactory-CqKWXqOm.js.map → AppConfigFactory-BPp02HMv.js.map} +1 -1
  4. package/dist/{AppConfigFactory-CK28UPK0.d.ts → AppConfigFactory-Dq7ttwQ_.d.ts} +6001 -144
  5. package/dist/{AppContainerFactory-CcSGFNLW.js → AppContainerFactory-DL_qZ80U.js} +2665 -264
  6. package/dist/AppContainerFactory-DL_qZ80U.js.map +1 -0
  7. package/dist/{CodemationAppContext-KqDoeHqN.d.ts → CodemationAppContext-P7P-xZhQ.d.ts} +2 -2
  8. package/dist/{CodemationAuthoring.types-BP6Inucu.d.ts → CodemationAuthoring.types-OMYu7vKP.d.ts} +3 -3
  9. package/dist/{CodemationConfigNormalizer-DIAE0VHw.d.ts → CodemationConfigNormalizer-BCtBrJDe.d.ts} +2 -2
  10. package/dist/{CodemationConsumerConfigLoader-nj9kTmfJ.d.ts → CodemationConsumerConfigLoader-evvw4b_a.d.ts} +2 -2
  11. package/dist/CodemationPluginListMerger-PSTtEQjC.d.ts +674 -0
  12. package/dist/{CredentialServices-BFQD_VN1.d.ts → CredentialServices-0Hk8RFY1.d.ts} +3 -3
  13. package/dist/{CredentialServices-BPKUF8Xs.js → CredentialServices-BNBMFOPt.js} +6 -1
  14. package/dist/CredentialServices-BNBMFOPt.js.map +1 -0
  15. package/dist/{PublicFrontendBootstrapFactory-DTA1iDo0.d.ts → PublicFrontendBootstrapFactory-D0_ds7nS.d.ts} +2 -2
  16. package/dist/authoring.d.ts +3 -3
  17. package/dist/consumer.d.ts +4 -4
  18. package/dist/credentials.d.ts +3 -3
  19. package/dist/credentials.js +1 -1
  20. package/dist/devServerSidecar.d.ts +1 -1
  21. package/dist/{index-Dd6BrWyH.d.ts → index-CeS2saCe.d.ts} +105 -2
  22. package/dist/index.d.ts +12 -11
  23. package/dist/index.js +5 -5
  24. package/dist/nextServer.d.ts +8 -58
  25. package/dist/nextServer.js +6 -100
  26. package/dist/{persistenceServer-DKbFDxoS.js → persistenceServer-CA0_q0D7.js} +2 -2
  27. package/dist/{persistenceServer-DKbFDxoS.js.map → persistenceServer-CA0_q0D7.js.map} +1 -1
  28. package/dist/{persistenceServer-Y-u7lV7f.d.ts → persistenceServer-CJeu1STC.d.ts} +2 -2
  29. package/dist/persistenceServer.d.ts +5 -5
  30. package/dist/persistenceServer.js +2 -2
  31. package/dist/{server-axppTMgo.d.ts → server-Clvg5x1w.d.ts} +11 -5
  32. package/dist/{server-CFpgKuVE.js → server-DteBORJX.js} +4 -4
  33. package/dist/{server-CFpgKuVE.js.map → server-DteBORJX.js.map} +1 -1
  34. package/dist/server.d.ts +8 -8
  35. package/dist/server.js +5 -5
  36. package/package.json +6 -5
  37. package/prisma/migrations/20260414120000_telemetry_foundation/migration.sql +112 -0
  38. package/prisma/migrations/20260414153000_telemetry_retention_metrics_refactor/migration.sql +239 -0
  39. package/prisma/migrations.sqlite/20260414120000_telemetry_foundation/migration.sql +103 -0
  40. package/prisma/migrations.sqlite/20260414153000_telemetry_retention_metrics_refactor/migration.sql +540 -0
  41. package/prisma/schema.postgresql.prisma +100 -1
  42. package/prisma/schema.sqlite.prisma +100 -1
  43. package/scripts/generate-prisma-clients.mjs +89 -1
  44. package/src/application/contracts/TelemetryDashboardContracts.ts +113 -0
  45. package/src/application/contracts/TelemetryRunTraceContracts.ts +13 -0
  46. package/src/application/cost/FrameworkCostCatalogEntries.ts +126 -0
  47. package/src/application/queries/GetTelemetryDashboardDimensionsQuery.ts +11 -0
  48. package/src/application/queries/GetTelemetryDashboardDimensionsQueryHandler.ts +20 -0
  49. package/src/application/queries/GetTelemetryDashboardRunsQuery.ts +11 -0
  50. package/src/application/queries/GetTelemetryDashboardRunsQueryHandler.ts +20 -0
  51. package/src/application/queries/GetTelemetryDashboardSummaryQuery.ts +11 -0
  52. package/src/application/queries/GetTelemetryDashboardSummaryQueryHandler.ts +29 -0
  53. package/src/application/queries/GetTelemetryDashboardTimeseriesQuery.ts +11 -0
  54. package/src/application/queries/GetTelemetryDashboardTimeseriesQueryHandler.ts +36 -0
  55. package/src/application/queries/GetTelemetryRunTraceQuery.ts +8 -0
  56. package/src/application/queries/GetTelemetryRunTraceQueryHandler.ts +20 -0
  57. package/src/application/queries/WorkflowQueryHandlers.ts +5 -0
  58. package/src/application/runs/WorkflowRunRetentionPruneScheduler.ts +71 -26
  59. package/src/application/telemetry/CompositeTelemetryExporter.ts +13 -0
  60. package/src/application/telemetry/LazyExecutionTelemetryFactory.ts +21 -0
  61. package/src/application/telemetry/NoOpTelemetryExporter.ts +7 -0
  62. package/src/application/telemetry/OtelExecutionTelemetry.types.ts +41 -0
  63. package/src/application/telemetry/OtelExecutionTelemetryFactory.ts +56 -0
  64. package/src/application/telemetry/OtelIdentityFactory.ts +41 -0
  65. package/src/application/telemetry/RunEventBusTelemetryReporter.ts +188 -0
  66. package/src/application/telemetry/StoredExecutionTelemetry.ts +56 -0
  67. package/src/application/telemetry/StoredNodeExecutionTelemetry.ts +35 -0
  68. package/src/application/telemetry/StoredTelemetrySpanScope.ts +188 -0
  69. package/src/application/telemetry/TelemetryEnricherChain.ts +85 -0
  70. package/src/application/telemetry/TelemetryPrivacyPolicy.ts +19 -0
  71. package/src/application/telemetry/TelemetryQueryService.ts +815 -0
  72. package/src/application/telemetry/TelemetryRetentionTimestampFactory.ts +40 -0
  73. package/src/applicationTokens.ts +18 -0
  74. package/src/bootstrap/AppContainerFactory.ts +183 -64
  75. package/src/bootstrap/AppContainerLifecycle.ts +8 -0
  76. package/src/bootstrap/CodemationContainerRegistrationRegistrar.ts +1 -3
  77. package/src/bootstrap/runtime/FrontendRuntime.ts +8 -0
  78. package/src/bootstrap/runtime/WorkerRuntime.ts +8 -0
  79. package/src/domain/runs/WorkflowRunRepository.ts +3 -1
  80. package/src/domain/telemetry/TelemetryContracts.ts +197 -0
  81. package/src/infrastructure/config/CodemationPluginRegistrar.ts +2 -6
  82. package/src/infrastructure/di/HandlesDomainEventRegistry.ts +5 -7
  83. package/src/infrastructure/persistence/InMemoryRunTraceContextRepository.ts +56 -0
  84. package/src/infrastructure/persistence/InMemoryTelemetryArtifactStore.ts +56 -0
  85. package/src/infrastructure/persistence/InMemoryTelemetryMetricPointStore.ts +97 -0
  86. package/src/infrastructure/persistence/InMemoryTelemetrySpanStore.ts +113 -0
  87. package/src/infrastructure/persistence/InMemoryWorkflowRunRepository.ts +4 -2
  88. package/src/infrastructure/persistence/PrismaRunTraceContextRepository.ts +92 -0
  89. package/src/infrastructure/persistence/PrismaTelemetryArtifactStore.ts +125 -0
  90. package/src/infrastructure/persistence/PrismaTelemetryMetricPointStore.ts +134 -0
  91. package/src/infrastructure/persistence/PrismaTelemetrySpanStore.ts +166 -0
  92. package/src/infrastructure/persistence/PrismaWorkflowRunRepository.ts +20 -7
  93. package/src/infrastructure/persistence/generated/prisma-postgresql-client/edge.js +85 -4
  94. package/src/infrastructure/persistence/generated/prisma-postgresql-client/index-browser.js +81 -0
  95. package/src/infrastructure/persistence/generated/prisma-postgresql-client/index.d.ts +6488 -102
  96. package/src/infrastructure/persistence/generated/prisma-postgresql-client/index.js +85 -4
  97. package/src/infrastructure/persistence/generated/prisma-postgresql-client/package.json +1 -1
  98. package/src/infrastructure/persistence/generated/prisma-postgresql-client/schema.prisma +100 -0
  99. package/src/infrastructure/persistence/generated/prisma-sqlite-client/edge.js +85 -4
  100. package/src/infrastructure/persistence/generated/prisma-sqlite-client/index-browser.js +81 -0
  101. package/src/infrastructure/persistence/generated/prisma-sqlite-client/index.d.ts +6476 -98
  102. package/src/infrastructure/persistence/generated/prisma-sqlite-client/index.js +85 -4
  103. package/src/infrastructure/persistence/generated/prisma-sqlite-client/package.json +1 -1
  104. package/src/infrastructure/persistence/generated/prisma-sqlite-client/schema.prisma +100 -0
  105. package/src/presentation/http/ApiPaths.ts +22 -0
  106. package/src/presentation/http/hono/registrars/AuthHonoApiRouteRegistrar.ts +1 -3
  107. package/src/presentation/http/hono/registrars/BinaryHonoApiRouteRegistrar.ts +1 -3
  108. package/src/presentation/http/hono/registrars/BootstrapHonoApiRouteRegistrar.ts +1 -3
  109. package/src/presentation/http/hono/registrars/CredentialHonoApiRouteRegistrar.ts +1 -3
  110. package/src/presentation/http/hono/registrars/DevHonoApiRouteRegistrar.ts +1 -3
  111. package/src/presentation/http/hono/registrars/OAuth2HonoApiRouteRegistrar.ts +1 -3
  112. package/src/presentation/http/hono/registrars/RunHonoApiRouteRegistrar.ts +1 -3
  113. package/src/presentation/http/hono/registrars/TelemetryHonoApiRouteRegistrar.ts +17 -0
  114. package/src/presentation/http/hono/registrars/UserHonoApiRouteRegistrar.ts +1 -3
  115. package/src/presentation/http/hono/registrars/WebhookHonoApiRouteRegistrar.ts +1 -3
  116. package/src/presentation/http/hono/registrars/WhitelabelHonoApiRouteRegistrar.ts +1 -3
  117. package/src/presentation/http/hono/registrars/WorkflowHonoApiRouteRegistrar.ts +1 -3
  118. package/src/presentation/http/routeHandlers/TelemetryDashboardRequestError.ts +1 -0
  119. package/src/presentation/http/routeHandlers/TelemetryHttpRouteHandler.ts +181 -0
  120. package/dist/AppContainerFactory-CcSGFNLW.js.map +0 -1
  121. package/dist/CodemationPluginListMerger-QvUa2SIt.d.ts +0 -357
  122. package/dist/CredentialServices-BPKUF8Xs.js.map +0 -1
  123. package/dist/nextServer.js.map +0 -1
@@ -0,0 +1,40 @@
1
+ import type { PersistedRunPolicySnapshot } from "@codemation/core";
2
+ import { injectable } from "@codemation/core";
3
+
4
+ @injectable()
5
+ export class TelemetryRetentionTimestampFactory {
6
+ createSpanExpiry(policySnapshot: PersistedRunPolicySnapshot | undefined, observedAt: Date): string | undefined {
7
+ return this.createExpiry(policySnapshot?.telemetrySpanRetentionSeconds, observedAt);
8
+ }
9
+
10
+ createArtifactExpiry(policySnapshot: PersistedRunPolicySnapshot | undefined, observedAt: Date): string | undefined {
11
+ return this.createExpiry(policySnapshot?.telemetryArtifactRetentionSeconds, observedAt);
12
+ }
13
+
14
+ createMetricExpiry(policySnapshot: PersistedRunPolicySnapshot | undefined, observedAt: Date): string | undefined {
15
+ return this.createExpiry(policySnapshot?.telemetryMetricRetentionSeconds, observedAt);
16
+ }
17
+
18
+ createTraceContextExpiry(
19
+ policySnapshot: PersistedRunPolicySnapshot | undefined,
20
+ observedAt: Date,
21
+ ): string | undefined {
22
+ const candidates = [
23
+ policySnapshot?.telemetrySpanRetentionSeconds,
24
+ policySnapshot?.telemetryArtifactRetentionSeconds,
25
+ policySnapshot?.telemetryMetricRetentionSeconds,
26
+ ].filter((value): value is number => typeof value === "number" && value > 0);
27
+ if (candidates.length === 0) {
28
+ return undefined;
29
+ }
30
+ const maxSeconds = Math.max(...candidates);
31
+ return this.createExpiry(maxSeconds, observedAt);
32
+ }
33
+
34
+ private createExpiry(retentionSeconds: number | undefined, observedAt: Date): string | undefined {
35
+ if (!retentionSeconds || retentionSeconds <= 0) {
36
+ return undefined;
37
+ }
38
+ return new Date(observedAt.getTime() + retentionSeconds * 1000).toISOString();
39
+ }
40
+ }
@@ -12,6 +12,13 @@ import type { QueryHandler } from "./application/bus/QueryHandler";
12
12
  import type { Logger, LoggerFactory } from "./application/logging/Logger";
13
13
  import type { WorkflowWebsocketPublisher } from "./application/websocket/WorkflowWebsocketPublisher";
14
14
  import type { CredentialStore } from "./domain/credentials/CredentialServices";
15
+ import type {
16
+ RunTraceContextRepository,
17
+ TelemetryArtifactStore,
18
+ TelemetryExporter,
19
+ TelemetryMetricPointStore,
20
+ TelemetrySpanStore,
21
+ } from "./domain/telemetry/TelemetryContracts";
15
22
  import type { WorkflowRunRepository } from "./domain/runs/WorkflowRunRepository";
16
23
  import type { WorkflowDebuggerOverlayRepository } from "./domain/workflows/WorkflowDebuggerOverlayRepository";
17
24
  import type { WorkflowDefinitionRepository } from "./domain/workflows/WorkflowDefinitionRepository";
@@ -66,6 +73,17 @@ export const ApplicationTokens = {
66
73
  */
67
74
  PerformanceDiagnosticsLogger: Symbol.for("codemation.application.PerformanceDiagnosticsLogger") as TypeToken<Logger>,
68
75
  CredentialStore: Symbol.for("codemation.application.CredentialStore") as TypeToken<CredentialStore>,
76
+ RunTraceContextRepository: Symbol.for(
77
+ "codemation.application.RunTraceContextRepository",
78
+ ) as TypeToken<RunTraceContextRepository>,
79
+ TelemetrySpanStore: Symbol.for("codemation.application.TelemetrySpanStore") as TypeToken<TelemetrySpanStore>,
80
+ TelemetryArtifactStore: Symbol.for(
81
+ "codemation.application.TelemetryArtifactStore",
82
+ ) as TypeToken<TelemetryArtifactStore>,
83
+ TelemetryMetricPointStore: Symbol.for(
84
+ "codemation.application.TelemetryMetricPointStore",
85
+ ) as TypeToken<TelemetryMetricPointStore>,
86
+ TelemetryExporter: Symbol.for("codemation.application.TelemetryExporter") as TypeToken<TelemetryExporter>,
69
87
  PrismaClient: Symbol.for("codemation.application.PrismaClient") as TypeToken<PrismaDatabaseClient>,
70
88
  SessionVerifier: Symbol.for("codemation.application.SessionVerifier") as TypeToken<SessionVerifier>,
71
89
  Clock: Symbol.for("codemation.application.Clock") as TypeToken<Clock>,
@@ -9,8 +9,10 @@ import {
9
9
  SystemClock,
10
10
  container as tsyringeContainer,
11
11
  type WorkflowDefinition,
12
+ type WorkflowPolicyRuntimeDefaults,
12
13
  } from "@codemation/core";
13
14
  import {
15
+ CatalogBackedCostTrackingTelemetryFactory,
14
16
  ConfigDrivenOffloadPolicy,
15
17
  DefaultDrivingScheduler,
16
18
  DefaultExecutionContextFactory,
@@ -18,6 +20,7 @@ import {
18
20
  InMemoryRunDataFactory,
19
21
  InlineDrivingScheduler,
20
22
  PersistedWorkflowTokenRegistry,
23
+ StaticCostCatalog,
21
24
  WorkflowRepositoryWebhookTriggerMatcher,
22
25
  } from "@codemation/core/bootstrap";
23
26
  import { AIAgentConnectionWorkflowExpander, ConnectionCredentialNodeConfigFactory } from "@codemation/core-nodes";
@@ -60,6 +63,11 @@ import {
60
63
  } from "../application/queries/UserAccountQueryHandlers";
61
64
  import {
62
65
  GetRunBinaryAttachmentQueryHandler,
66
+ GetTelemetryDashboardDimensionsQueryHandler,
67
+ GetTelemetryDashboardRunsQueryHandler,
68
+ GetTelemetryRunTraceQueryHandler,
69
+ GetTelemetryDashboardSummaryQueryHandler,
70
+ GetTelemetryDashboardTimeseriesQueryHandler,
63
71
  GetRunStateQueryHandler,
64
72
  GetWorkflowDebuggerOverlayQueryHandler,
65
73
  GetWorkflowDetailQueryHandler,
@@ -72,6 +80,17 @@ import { OpenAiApiKeyCredentialHealthTester } from "../infrastructure/credential
72
80
  import { OpenAiApiKeyCredentialTypeFactory } from "../infrastructure/credentials/OpenAiApiKeyCredentialTypeFactory";
73
81
  import { CodemationPluginRegistrar } from "../infrastructure/config/CodemationPluginRegistrar";
74
82
  import { WorkflowRunEventWebsocketRelay } from "../application/websocket/WorkflowRunEventWebsocketRelay";
83
+ import { FrameworkCostCatalogEntries } from "../application/cost/FrameworkCostCatalogEntries";
84
+ import { CompositeTelemetryExporter } from "../application/telemetry/CompositeTelemetryExporter";
85
+ import { LazyExecutionTelemetryFactory } from "../application/telemetry/LazyExecutionTelemetryFactory";
86
+ import { NoOpTelemetryExporter } from "../application/telemetry/NoOpTelemetryExporter";
87
+ import { OtelExecutionTelemetryFactory } from "../application/telemetry/OtelExecutionTelemetryFactory";
88
+ import { OtelIdentityFactory } from "../application/telemetry/OtelIdentityFactory";
89
+ import { RunEventBusTelemetryReporter } from "../application/telemetry/RunEventBusTelemetryReporter";
90
+ import { TelemetryEnricherChain } from "../application/telemetry/TelemetryEnricherChain";
91
+ import { TelemetryPrivacyPolicy } from "../application/telemetry/TelemetryPrivacyPolicy";
92
+ import { TelemetryQueryService } from "../application/telemetry/TelemetryQueryService";
93
+ import { TelemetryRetentionTimestampFactory } from "../application/telemetry/TelemetryRetentionTimestampFactory";
75
94
  import { ApplicationTokens } from "../applicationTokens";
76
95
  import type { CredentialType } from "../domain/credentials/CredentialServices";
77
96
  import {
@@ -117,6 +136,7 @@ import { CredentialHonoApiRouteRegistrar } from "../presentation/http/hono/regis
117
136
  import { DevHonoApiRouteRegistrar } from "../presentation/http/hono/registrars/DevHonoApiRouteRegistrar";
118
137
  import { OAuth2HonoApiRouteRegistrar } from "../presentation/http/hono/registrars/OAuth2HonoApiRouteRegistrar";
119
138
  import { RunHonoApiRouteRegistrar } from "../presentation/http/hono/registrars/RunHonoApiRouteRegistrar";
139
+ import { TelemetryHonoApiRouteRegistrar } from "../presentation/http/hono/registrars/TelemetryHonoApiRouteRegistrar";
120
140
  import { UserHonoApiRouteRegistrar } from "../presentation/http/hono/registrars/UserHonoApiRouteRegistrar";
121
141
  import { WebhookHonoApiRouteRegistrar } from "../presentation/http/hono/registrars/WebhookHonoApiRouteRegistrar";
122
142
  import { WhitelabelHonoApiRouteRegistrar } from "../presentation/http/hono/registrars/WhitelabelHonoApiRouteRegistrar";
@@ -145,6 +165,10 @@ import {
145
165
  PrismaCredentialStore,
146
166
  } from "../infrastructure/persistence/CredentialPersistenceStore";
147
167
  import { InMemoryTriggerSetupStateRepository } from "../infrastructure/persistence/InMemoryTriggerSetupStateRepository";
168
+ import { InMemoryRunTraceContextRepository } from "../infrastructure/persistence/InMemoryRunTraceContextRepository";
169
+ import { InMemoryTelemetryArtifactStore } from "../infrastructure/persistence/InMemoryTelemetryArtifactStore";
170
+ import { InMemoryTelemetryMetricPointStore } from "../infrastructure/persistence/InMemoryTelemetryMetricPointStore";
171
+ import { InMemoryTelemetrySpanStore } from "../infrastructure/persistence/InMemoryTelemetrySpanStore";
148
172
  import { InMemoryWorkflowActivationRepository } from "../infrastructure/persistence/InMemoryWorkflowActivationRepository";
149
173
  import { InMemoryWorkflowDebuggerOverlayRepository } from "../infrastructure/persistence/InMemoryWorkflowDebuggerOverlayRepository";
150
174
  import { InMemoryWorkflowRunRepository } from "../infrastructure/persistence/InMemoryWorkflowRunRepository";
@@ -154,6 +178,10 @@ import {
154
178
  } from "../infrastructure/persistence/PrismaDatabaseClient";
155
179
  import { PrismaClientFactory } from "../infrastructure/persistence/PrismaClientFactory";
156
180
  import { PrismaTriggerSetupStateRepository } from "../infrastructure/persistence/PrismaTriggerSetupStateRepository";
181
+ import { PrismaRunTraceContextRepository } from "../infrastructure/persistence/PrismaRunTraceContextRepository";
182
+ import { PrismaTelemetryArtifactStore } from "../infrastructure/persistence/PrismaTelemetryArtifactStore";
183
+ import { PrismaTelemetryMetricPointStore } from "../infrastructure/persistence/PrismaTelemetryMetricPointStore";
184
+ import { PrismaTelemetrySpanStore } from "../infrastructure/persistence/PrismaTelemetrySpanStore";
157
185
  import { PrismaWorkflowActivationRepository } from "../infrastructure/persistence/PrismaWorkflowActivationRepository";
158
186
  import { PrismaWorkflowDebuggerOverlayRepository } from "../infrastructure/persistence/PrismaWorkflowDebuggerOverlayRepository";
159
187
  import { PrismaWorkflowRunRepository } from "../infrastructure/persistence/PrismaWorkflowRunRepository";
@@ -169,6 +197,7 @@ import { LocalFilesystemBinaryStorage } from "../infrastructure/binary/LocalFile
169
197
  import { InMemoryBinaryStorage } from "@codemation/core/bootstrap";
170
198
  import { RedisRunEventBus } from "@codemation/eventbus-redis";
171
199
  import { AppContainerLifecycle } from "./AppContainerLifecycle";
200
+ import { WorkflowRunRetentionPruneScheduler } from "../application/runs/WorkflowRunRetentionPruneScheduler";
172
201
  import { DatabaseMigrations } from "./runtime/DatabaseMigrations";
173
202
  import { FrontendRuntime } from "./runtime/FrontendRuntime";
174
203
  import { WorkerRuntime } from "./runtime/WorkerRuntime";
@@ -194,6 +223,11 @@ export class AppContainerFactory {
194
223
  ListUserAccountsQueryHandler,
195
224
  VerifyUserInviteQueryHandler,
196
225
  GetRunBinaryAttachmentQueryHandler,
226
+ GetTelemetryDashboardDimensionsQueryHandler,
227
+ GetTelemetryDashboardRunsQueryHandler,
228
+ GetTelemetryRunTraceQueryHandler,
229
+ GetTelemetryDashboardSummaryQueryHandler,
230
+ GetTelemetryDashboardTimeseriesQueryHandler,
197
231
  GetRunStateQueryHandler,
198
232
  GetWorkflowRunDetailQueryHandler,
199
233
  GetWorkflowDebuggerOverlayQueryHandler,
@@ -231,6 +265,7 @@ export class AppContainerFactory {
231
265
  DevHonoApiRouteRegistrar,
232
266
  OAuth2HonoApiRouteRegistrar,
233
267
  RunHonoApiRouteRegistrar,
268
+ TelemetryHonoApiRouteRegistrar,
234
269
  UserHonoApiRouteRegistrar,
235
270
  WebhookHonoApiRouteRegistrar,
236
271
  WhitelabelHonoApiRouteRegistrar,
@@ -330,7 +365,7 @@ export class AppContainerFactory {
330
365
  dependencyContainer.resolve(CredentialTypeRegistryImpl),
331
366
  ),
332
367
  });
333
- container.register(CodemationIdFactory, { useClass: CodemationIdFactory });
368
+ container.registerSingleton(CodemationIdFactory, CodemationIdFactory);
334
369
  container.register(CoreTokens.RunIdFactory, {
335
370
  useFactory: instanceCachingFactory((dependencyContainer) => dependencyContainer.resolve(CodemationIdFactory)),
336
371
  });
@@ -356,6 +391,7 @@ export class AppContainerFactory {
356
391
  container.registerInstance(CoreTokens.WorkflowActivationPolicy, runtimeWorkflowActivationPolicy);
357
392
  new EngineRuntimeRegistrar().register(container, {
358
393
  resolveEngineExecutionLimits: () => inputs.appConfig.engineExecutionLimits,
394
+ workflowPolicyRuntimeDefaults: this.createWorkflowPolicyRuntimeDefaults(inputs.appConfig),
359
395
  webhookTriggerMatcherProvider: {
360
396
  createMatcher: (dependencyContainer) => {
361
397
  const webhookRoutingLogger = dependencyContainer
@@ -384,7 +420,7 @@ export class AppContainerFactory {
384
420
  },
385
421
  });
386
422
  container.registerInstance(LogLevelPolicyFactory, logLevelPolicyFactory);
387
- container.register(ServerLoggerFactory, { useClass: ServerLoggerFactory });
423
+ container.registerSingleton(ServerLoggerFactory, ServerLoggerFactory);
388
424
  container.register(ApplicationTokens.LoggerFactory, {
389
425
  useFactory: instanceCachingFactory((dependencyContainer) => dependencyContainer.resolve(ServerLoggerFactory)),
390
426
  });
@@ -405,43 +441,41 @@ export class AppContainerFactory {
405
441
  );
406
442
  }),
407
443
  });
408
- container.register(PrismaClientFactory, { useClass: PrismaClientFactory });
409
- container.register(WorkflowPolicyUiPresentationFactory, { useClass: WorkflowPolicyUiPresentationFactory });
410
- container.register(WorkflowDefinitionMapper, { useClass: WorkflowDefinitionMapper });
411
- container.register(RequestToWebhookItemMapper, { useClass: RequestToWebhookItemMapper });
412
- container.register(WebhookEndpointPathValidator, { useClass: WebhookEndpointPathValidator });
413
- container.register(CredentialSecretCipher, { useClass: CredentialSecretCipher });
414
- container.register(CredentialMaterialResolver, { useClass: CredentialMaterialResolver });
415
- container.register(CredentialFieldEnvOverlayService, { useClass: CredentialFieldEnvOverlayService });
416
- container.register(CredentialRuntimeMaterialService, { useClass: CredentialRuntimeMaterialService });
417
- container.register(WorkflowCredentialNodeResolver, { useClass: WorkflowCredentialNodeResolver });
418
- container.register(CredentialInstanceService, { useClass: CredentialInstanceService });
419
- container.register(CredentialBindingService, { useClass: CredentialBindingService });
420
- container.register(WorkflowActivationPreflightRules, { useClass: WorkflowActivationPreflightRules });
421
- container.register(WorkflowActivationPreflight, { useClass: WorkflowActivationPreflight });
422
- container.register(CredentialTestService, { useClass: CredentialTestService });
423
- container.register(CredentialSessionServiceImpl, { useClass: CredentialSessionServiceImpl });
444
+ container.registerSingleton(PrismaClientFactory, PrismaClientFactory);
445
+ container.registerSingleton(WorkflowPolicyUiPresentationFactory, WorkflowPolicyUiPresentationFactory);
446
+ container.registerSingleton(WorkflowDefinitionMapper, WorkflowDefinitionMapper);
447
+ container.registerSingleton(RequestToWebhookItemMapper, RequestToWebhookItemMapper);
448
+ container.registerSingleton(WebhookEndpointPathValidator, WebhookEndpointPathValidator);
449
+ container.registerSingleton(CredentialSecretCipher, CredentialSecretCipher);
450
+ container.registerSingleton(CredentialMaterialResolver, CredentialMaterialResolver);
451
+ container.registerSingleton(CredentialFieldEnvOverlayService, CredentialFieldEnvOverlayService);
452
+ container.registerSingleton(CredentialRuntimeMaterialService, CredentialRuntimeMaterialService);
453
+ container.registerSingleton(WorkflowCredentialNodeResolver, WorkflowCredentialNodeResolver);
454
+ container.registerSingleton(CredentialInstanceService, CredentialInstanceService);
455
+ container.registerSingleton(CredentialBindingService, CredentialBindingService);
456
+ container.registerSingleton(WorkflowActivationPreflightRules, WorkflowActivationPreflightRules);
457
+ container.registerSingleton(WorkflowActivationPreflight, WorkflowActivationPreflight);
458
+ container.registerSingleton(CredentialTestService, CredentialTestService);
459
+ container.registerSingleton(CredentialSessionServiceImpl, CredentialSessionServiceImpl);
424
460
  if (!inputs.appConfig.hasConfiguredCredentialSessionServiceRegistration) {
425
461
  container.register(CoreTokens.CredentialSessionService, { useToken: CredentialSessionServiceImpl });
426
462
  }
427
- container.register(OAuth2ProviderRegistry, { useClass: OAuth2ProviderRegistry });
428
- container.register(OAuth2ConnectService, { useClass: OAuth2ConnectService });
429
- container.register(CodemationFrontendAuthSnapshotFactory, { useClass: CodemationFrontendAuthSnapshotFactory });
430
- container.register(FrontendAppConfigFactory, { useClass: FrontendAppConfigFactory });
431
- container.register(PublicFrontendBootstrapFactory, { useClass: PublicFrontendBootstrapFactory });
432
- container.register(InternalAuthBootstrapFactory, { useClass: InternalAuthBootstrapFactory });
433
- container.register(DatabaseMigrations, { useClass: DatabaseMigrations });
434
- container.register(FrontendRuntime, { useClass: FrontendRuntime });
435
- container.register(WorkerRuntime, { useClass: WorkerRuntime });
436
- container.register(DevelopmentSessionBypassVerifier, { useClass: DevelopmentSessionBypassVerifier });
437
- container.register(SecureRequestDetector, { useClass: SecureRequestDetector });
438
- container.register(InAppCallbackUrlPolicy, { useClass: InAppCallbackUrlPolicy });
439
- container.register(AuthSessionCookieFactory, { useClass: AuthSessionCookieFactory });
440
- container.register(CodemationBetterAuthBcryptPasswordCodec, { useClass: CodemationBetterAuthBcryptPasswordCodec });
441
- container.register(CodemationBetterAuthDatabaseOptionsFactory, {
442
- useClass: CodemationBetterAuthDatabaseOptionsFactory,
443
- });
444
- container.register(UserAccountSessionPolicy, { useClass: UserAccountSessionPolicy });
463
+ container.registerSingleton(OAuth2ProviderRegistry, OAuth2ProviderRegistry);
464
+ container.registerSingleton(OAuth2ConnectService, OAuth2ConnectService);
465
+ container.registerSingleton(CodemationFrontendAuthSnapshotFactory, CodemationFrontendAuthSnapshotFactory);
466
+ container.registerSingleton(FrontendAppConfigFactory, FrontendAppConfigFactory);
467
+ container.registerSingleton(PublicFrontendBootstrapFactory, PublicFrontendBootstrapFactory);
468
+ container.registerSingleton(InternalAuthBootstrapFactory, InternalAuthBootstrapFactory);
469
+ container.registerSingleton(DatabaseMigrations, DatabaseMigrations);
470
+ container.registerSingleton(FrontendRuntime, FrontendRuntime);
471
+ container.registerSingleton(WorkerRuntime, WorkerRuntime);
472
+ container.registerSingleton(DevelopmentSessionBypassVerifier, DevelopmentSessionBypassVerifier);
473
+ container.registerSingleton(SecureRequestDetector, SecureRequestDetector);
474
+ container.registerSingleton(InAppCallbackUrlPolicy, InAppCallbackUrlPolicy);
475
+ container.registerSingleton(AuthSessionCookieFactory, AuthSessionCookieFactory);
476
+ container.registerSingleton(CodemationBetterAuthBcryptPasswordCodec, CodemationBetterAuthBcryptPasswordCodec);
477
+ container.registerSingleton(CodemationBetterAuthDatabaseOptionsFactory, CodemationBetterAuthDatabaseOptionsFactory);
478
+ container.registerSingleton(UserAccountSessionPolicy, UserAccountSessionPolicy);
445
479
  container.register(CodemationBetterAuthBaseUrlPolicy, {
446
480
  useFactory: instanceCachingFactory(
447
481
  (dependencyContainer) =>
@@ -488,7 +522,7 @@ export class AppContainerFactory {
488
522
  return new BetterAuthApiSessionVerifier(runtime, eligibility);
489
523
  }),
490
524
  });
491
- container.register(CodemationSessionVerifier, { useClass: CodemationSessionVerifier });
525
+ container.registerSingleton(CodemationSessionVerifier, CodemationSessionVerifier);
492
526
  container.register(ApplicationTokens.SessionVerifier, {
493
527
  useFactory: instanceCachingFactory((dependencyContainer) => {
494
528
  const appConfig = dependencyContainer.resolve<AppConfig>(ApplicationTokens.AppConfig);
@@ -528,33 +562,51 @@ export class AppContainerFactory {
528
562
  }
529
563
 
530
564
  private registerRepositoriesAndBuses(container: Container): void {
531
- container.register(WorkflowDefinitionRepositoryAdapter, { useClass: WorkflowDefinitionRepositoryAdapter });
532
- container.register(InMemoryWorkflowRunRepository, { useClass: InMemoryWorkflowRunRepository });
533
- container.register(InMemoryTriggerSetupStateRepository, { useClass: InMemoryTriggerSetupStateRepository });
534
- container.register(InMemoryCredentialStore, { useClass: InMemoryCredentialStore });
535
- container.register(SqlWorkflowRunRepository, { useClass: SqlWorkflowRunRepository });
536
- container.register(InMemoryWorkflowDebuggerOverlayRepository, {
537
- useClass: InMemoryWorkflowDebuggerOverlayRepository,
565
+ container.registerSingleton(OtelIdentityFactory, OtelIdentityFactory);
566
+ container.registerSingleton(TelemetryPrivacyPolicy, TelemetryPrivacyPolicy);
567
+ container.registerSingleton(TelemetryEnricherChain, TelemetryEnricherChain);
568
+ container.registerSingleton(TelemetryRetentionTimestampFactory, TelemetryRetentionTimestampFactory);
569
+ container.registerSingleton(TelemetryQueryService, TelemetryQueryService);
570
+ container.registerSingleton(NoOpTelemetryExporter, NoOpTelemetryExporter);
571
+ container.register(CompositeTelemetryExporter, {
572
+ useFactory: instanceCachingFactory(
573
+ (dependencyContainer) => new CompositeTelemetryExporter([dependencyContainer.resolve(NoOpTelemetryExporter)]),
574
+ ),
538
575
  });
539
- container.register(PrismaTriggerSetupStateRepository, { useClass: PrismaTriggerSetupStateRepository });
540
- container.register(PrismaWorkflowDebuggerOverlayRepository, { useClass: PrismaWorkflowDebuggerOverlayRepository });
541
- container.register(PrismaWorkflowActivationRepository, { useClass: PrismaWorkflowActivationRepository });
542
- container.register(InMemoryWorkflowActivationRepository, { useClass: InMemoryWorkflowActivationRepository });
543
- container.register(PrismaCredentialStore, { useClass: PrismaCredentialStore });
576
+ container.registerSingleton(OtelExecutionTelemetryFactory, OtelExecutionTelemetryFactory);
577
+ container.registerSingleton(InMemoryRunTraceContextRepository, InMemoryRunTraceContextRepository);
578
+ container.registerSingleton(InMemoryTelemetrySpanStore, InMemoryTelemetrySpanStore);
579
+ container.registerSingleton(InMemoryTelemetryArtifactStore, InMemoryTelemetryArtifactStore);
580
+ container.registerSingleton(InMemoryTelemetryMetricPointStore, InMemoryTelemetryMetricPointStore);
581
+ container.registerSingleton(PrismaRunTraceContextRepository, PrismaRunTraceContextRepository);
582
+ container.registerSingleton(PrismaTelemetrySpanStore, PrismaTelemetrySpanStore);
583
+ container.registerSingleton(PrismaTelemetryArtifactStore, PrismaTelemetryArtifactStore);
584
+ container.registerSingleton(PrismaTelemetryMetricPointStore, PrismaTelemetryMetricPointStore);
585
+ container.registerSingleton(WorkflowDefinitionRepositoryAdapter, WorkflowDefinitionRepositoryAdapter);
586
+ container.registerSingleton(InMemoryWorkflowRunRepository, InMemoryWorkflowRunRepository);
587
+ container.registerSingleton(InMemoryTriggerSetupStateRepository, InMemoryTriggerSetupStateRepository);
588
+ container.registerSingleton(InMemoryCredentialStore, InMemoryCredentialStore);
589
+ container.registerSingleton(SqlWorkflowRunRepository, SqlWorkflowRunRepository);
590
+ container.registerSingleton(InMemoryWorkflowDebuggerOverlayRepository, InMemoryWorkflowDebuggerOverlayRepository);
591
+ container.registerSingleton(PrismaTriggerSetupStateRepository, PrismaTriggerSetupStateRepository);
592
+ container.registerSingleton(PrismaWorkflowDebuggerOverlayRepository, PrismaWorkflowDebuggerOverlayRepository);
593
+ container.registerSingleton(PrismaWorkflowActivationRepository, PrismaWorkflowActivationRepository);
594
+ container.registerSingleton(InMemoryWorkflowActivationRepository, InMemoryWorkflowActivationRepository);
595
+ container.registerSingleton(PrismaCredentialStore, PrismaCredentialStore);
544
596
  container.register(ApplicationTokens.WorkflowDefinitionRepository, {
545
597
  useFactory: instanceCachingFactory(
546
598
  (dependencyContainer) =>
547
599
  dependencyContainer.resolve(WorkflowDefinitionRepositoryAdapter) as unknown as WorkflowDefinitionRepository,
548
600
  ),
549
601
  });
550
- container.register(InMemoryQueryBus, { useClass: InMemoryQueryBus });
551
- container.register(InMemoryCommandBus, { useClass: InMemoryCommandBus });
552
- container.register(InMemoryDomainEventBus, { useClass: InMemoryDomainEventBus });
602
+ container.registerSingleton(InMemoryQueryBus, InMemoryQueryBus);
603
+ container.registerSingleton(InMemoryCommandBus, InMemoryCommandBus);
604
+ container.registerSingleton(InMemoryDomainEventBus, InMemoryDomainEventBus);
553
605
  for (const handler of AppContainerFactory.queryHandlers) {
554
- container.register(ApplicationTokens.QueryHandler, { useClass: handler });
606
+ container.registerSingleton(ApplicationTokens.QueryHandler, handler);
555
607
  }
556
608
  for (const handler of AppContainerFactory.commandHandlers) {
557
- container.register(ApplicationTokens.CommandHandler, { useClass: handler });
609
+ container.registerSingleton(ApplicationTokens.CommandHandler, handler);
558
610
  }
559
611
  container.register(ApplicationTokens.QueryBus, {
560
612
  useFactory: instanceCachingFactory((dependencyContainer) => dependencyContainer.resolve(InMemoryQueryBus)),
@@ -565,26 +617,33 @@ export class AppContainerFactory {
565
617
  container.register(ApplicationTokens.DomainEventBus, {
566
618
  useFactory: instanceCachingFactory((dependencyContainer) => dependencyContainer.resolve(InMemoryDomainEventBus)),
567
619
  });
620
+ container.register(ApplicationTokens.TelemetryExporter, {
621
+ useFactory: instanceCachingFactory((dependencyContainer) =>
622
+ dependencyContainer.resolve(CompositeTelemetryExporter),
623
+ ),
624
+ });
568
625
  }
569
626
 
570
627
  private registerApplicationServicesAndRoutes(container: Container): void {
571
- container.register(DevBootstrapSummaryAssembler, { useClass: DevBootstrapSummaryAssembler });
572
- container.register(DevBootstrapSummaryHttpRouteHandler, { useClass: DevBootstrapSummaryHttpRouteHandler });
573
- container.register(AuthHttpRouteHandler, { useClass: AuthHttpRouteHandler });
574
- container.register(PublicFrontendBootstrapHttpRouteHandler, { useClass: PublicFrontendBootstrapHttpRouteHandler });
575
- container.register(InternalAuthBootstrapHttpRouteHandler, { useClass: InternalAuthBootstrapHttpRouteHandler });
576
- container.register(WhitelabelLogoHttpRouteHandler, { useClass: WhitelabelLogoHttpRouteHandler });
628
+ container.registerSingleton(DevBootstrapSummaryAssembler, DevBootstrapSummaryAssembler);
629
+ container.registerSingleton(DevBootstrapSummaryHttpRouteHandler, DevBootstrapSummaryHttpRouteHandler);
630
+ container.registerSingleton(AuthHttpRouteHandler, AuthHttpRouteHandler);
631
+ container.registerSingleton(PublicFrontendBootstrapHttpRouteHandler, PublicFrontendBootstrapHttpRouteHandler);
632
+ container.registerSingleton(InternalAuthBootstrapHttpRouteHandler, InternalAuthBootstrapHttpRouteHandler);
633
+ container.registerSingleton(WhitelabelLogoHttpRouteHandler, WhitelabelLogoHttpRouteHandler);
577
634
  for (const registrar of AppContainerFactory.honoRouteRegistrars) {
578
- container.register(ApplicationTokens.HonoApiRouteRegistrar, { useClass: registrar });
635
+ container.registerSingleton(ApplicationTokens.HonoApiRouteRegistrar, registrar);
579
636
  }
580
- container.register(CodemationHonoApiApp, { useClass: CodemationHonoApiApp });
637
+ container.registerSingleton(CodemationHonoApiApp, CodemationHonoApiApp);
581
638
  }
582
639
 
583
640
  private registerOperationalInfrastructure(container: Container): void {
584
641
  container.register(ApplicationTokens.WorkflowWebsocketPublisher, {
585
642
  useFactory: instanceCachingFactory((dependencyContainer) => dependencyContainer.resolve(WorkflowWebsocketServer)),
586
643
  });
587
- container.register(WorkflowRunEventWebsocketRelay, { useClass: WorkflowRunEventWebsocketRelay });
644
+ container.registerSingleton(WorkflowRunEventWebsocketRelay, WorkflowRunEventWebsocketRelay);
645
+ container.registerSingleton(RunEventBusTelemetryReporter, RunEventBusTelemetryReporter);
646
+ container.registerSingleton(WorkflowRunRetentionPruneScheduler, WorkflowRunRetentionPruneScheduler);
588
647
  }
589
648
 
590
649
  private async registerRuntimeInfrastructure(container: Container, appConfig: AppConfig): Promise<PrismaOwnership> {
@@ -597,7 +656,6 @@ export class AppContainerFactory {
597
656
  const binaryStorage = this.createBinaryStorage(appConfig.repoRoot);
598
657
  container.registerInstance(CoreTokens.RunDataFactory, new InMemoryRunDataFactory());
599
658
  container.registerInstance(CoreTokens.BinaryStorage, binaryStorage);
600
- container.registerInstance(CoreTokens.ExecutionContextFactory, new DefaultExecutionContextFactory(binaryStorage));
601
659
  container.registerInstance(ApplicationTokens.Clock, new SystemClock());
602
660
 
603
661
  if (appConfig.persistence.kind === "none") {
@@ -620,6 +678,27 @@ export class AppContainerFactory {
620
678
  container.resolve(InMemoryWorkflowActivationRepository),
621
679
  );
622
680
  container.registerInstance(ApplicationTokens.CredentialStore, container.resolve(InMemoryCredentialStore));
681
+ container.registerInstance(
682
+ ApplicationTokens.RunTraceContextRepository,
683
+ container.resolve(InMemoryRunTraceContextRepository),
684
+ );
685
+ container.registerInstance(ApplicationTokens.TelemetrySpanStore, container.resolve(InMemoryTelemetrySpanStore));
686
+ container.registerInstance(
687
+ ApplicationTokens.TelemetryArtifactStore,
688
+ container.resolve(InMemoryTelemetryArtifactStore),
689
+ );
690
+ container.registerInstance(
691
+ ApplicationTokens.TelemetryMetricPointStore,
692
+ container.resolve(InMemoryTelemetryMetricPointStore),
693
+ );
694
+ container.registerInstance(
695
+ CoreTokens.ExecutionContextFactory,
696
+ new DefaultExecutionContextFactory(
697
+ binaryStorage,
698
+ new LazyExecutionTelemetryFactory(() => container.resolve(OtelExecutionTelemetryFactory)),
699
+ new CatalogBackedCostTrackingTelemetryFactory(new StaticCostCatalog(FrameworkCostCatalogEntries)),
700
+ ),
701
+ );
623
702
  this.registerRuntimeNodeActivationScheduler(container);
624
703
  return {
625
704
  ownedPrismaClient: null,
@@ -632,6 +711,10 @@ export class AppContainerFactory {
632
711
  const workflowRunRepository = childContainer.resolve(PrismaWorkflowRunRepository);
633
712
  const triggerSetupStateRepository = childContainer.resolve(PrismaTriggerSetupStateRepository);
634
713
  const workflowDebuggerOverlayRepository = childContainer.resolve(PrismaWorkflowDebuggerOverlayRepository);
714
+ const runTraceContextRepository = childContainer.resolve(PrismaRunTraceContextRepository);
715
+ const telemetrySpanStore = childContainer.resolve(PrismaTelemetrySpanStore);
716
+ const telemetryArtifactStore = childContainer.resolve(PrismaTelemetryArtifactStore);
717
+ const telemetryMetricPointStore = childContainer.resolve(PrismaTelemetryMetricPointStore);
635
718
  container.registerInstance(PrismaDatabaseClientToken, prismaOwnership.prismaClient);
636
719
  container.registerInstance(ApplicationTokens.PrismaClient, prismaOwnership.prismaClient);
637
720
  container.registerInstance(
@@ -649,6 +732,18 @@ export class AppContainerFactory {
649
732
  container.resolve(PrismaWorkflowActivationRepository),
650
733
  );
651
734
  container.registerInstance(ApplicationTokens.CredentialStore, container.resolve(PrismaCredentialStore));
735
+ container.registerInstance(ApplicationTokens.RunTraceContextRepository, runTraceContextRepository);
736
+ container.registerInstance(ApplicationTokens.TelemetrySpanStore, telemetrySpanStore);
737
+ container.registerInstance(ApplicationTokens.TelemetryArtifactStore, telemetryArtifactStore);
738
+ container.registerInstance(ApplicationTokens.TelemetryMetricPointStore, telemetryMetricPointStore);
739
+ container.registerInstance(
740
+ CoreTokens.ExecutionContextFactory,
741
+ new DefaultExecutionContextFactory(
742
+ binaryStorage,
743
+ new LazyExecutionTelemetryFactory(() => container.resolve(OtelExecutionTelemetryFactory)),
744
+ new CatalogBackedCostTrackingTelemetryFactory(new StaticCostCatalog(FrameworkCostCatalogEntries)),
745
+ ),
746
+ );
652
747
  if (appConfig.scheduler.kind === "bullmq") {
653
748
  container.registerInstance(
654
749
  ApplicationTokens.WorkerRuntimeScheduler,
@@ -705,6 +800,22 @@ export class AppContainerFactory {
705
800
  });
706
801
  }
707
802
 
803
+ private createWorkflowPolicyRuntimeDefaults(appConfig: AppConfig): WorkflowPolicyRuntimeDefaults {
804
+ return {
805
+ retentionSeconds: this.readPositiveInteger(appConfig.env.CODEMATION_RUN_RETENTION_DEFAULT_SECONDS),
806
+ binaryRetentionSeconds: this.readPositiveInteger(appConfig.env.CODEMATION_BINARY_RETENTION_DEFAULT_SECONDS),
807
+ telemetrySpanRetentionSeconds: this.readPositiveInteger(
808
+ appConfig.env.CODEMATION_TELEMETRY_SPAN_RETENTION_DEFAULT_SECONDS,
809
+ ),
810
+ telemetryArtifactRetentionSeconds: this.readPositiveInteger(
811
+ appConfig.env.CODEMATION_TELEMETRY_ARTIFACT_RETENTION_DEFAULT_SECONDS,
812
+ ),
813
+ telemetryMetricRetentionSeconds: this.readPositiveInteger(
814
+ appConfig.env.CODEMATION_TELEMETRY_METRIC_RETENTION_DEFAULT_SECONDS,
815
+ ),
816
+ };
817
+ }
818
+
708
819
  private createBinaryStorage(repoRoot: string): InMemoryBinaryStorage | LocalFilesystemBinaryStorage {
709
820
  if (!repoRoot) {
710
821
  return new InMemoryBinaryStorage();
@@ -730,6 +841,14 @@ export class AppContainerFactory {
730
841
  return redisUrl;
731
842
  }
732
843
 
844
+ private readPositiveInteger(value: string | undefined): number | undefined {
845
+ if (!value) {
846
+ return undefined;
847
+ }
848
+ const parsed = Number(value);
849
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
850
+ }
851
+
733
852
  private synchronizeLiveWorkflowRepository(container: Container, workflows: ReadonlyArray<WorkflowDefinition>): void {
734
853
  const liveWorkflowRepository = container.resolve(CoreTokens.LiveWorkflowRepository);
735
854
  liveWorkflowRepository.setWorkflows(workflows);
@@ -1,5 +1,7 @@
1
1
  import type { Container } from "@codemation/core";
2
2
  import { Engine } from "@codemation/core/bootstrap";
3
+ import { RunEventBusTelemetryReporter } from "../application/telemetry/RunEventBusTelemetryReporter";
4
+ import { WorkflowRunRetentionPruneScheduler } from "../application/runs/WorkflowRunRetentionPruneScheduler";
3
5
  import type { PrismaDatabaseClient } from "../infrastructure/persistence/PrismaDatabaseClient";
4
6
  import { WorkflowRunEventWebsocketRelay } from "../application/websocket/WorkflowRunEventWebsocketRelay";
5
7
  import { WorkflowWebsocketServer } from "../presentation/websocket/WorkflowWebsocketServer";
@@ -17,6 +19,12 @@ export class AppContainerLifecycle {
17
19
  if (this.container.isRegistered(WorkflowRunEventWebsocketRelay, true)) {
18
20
  await this.container.resolve(WorkflowRunEventWebsocketRelay).stop();
19
21
  }
22
+ if (this.container.isRegistered(RunEventBusTelemetryReporter, true)) {
23
+ await this.container.resolve(RunEventBusTelemetryReporter).stop();
24
+ }
25
+ if (this.container.isRegistered(WorkflowRunRetentionPruneScheduler, true)) {
26
+ this.container.resolve(WorkflowRunRetentionPruneScheduler).stop();
27
+ }
20
28
  if (args?.stopWebsocketServer !== false && this.container.isRegistered(WorkflowWebsocketServer, true)) {
21
29
  await this.container.resolve(WorkflowWebsocketServer).stop();
22
30
  }
@@ -18,9 +18,7 @@ export class CodemationContainerRegistrationRegistrar {
18
18
  return;
19
19
  }
20
20
  if (this.isClassRegistration(registration)) {
21
- container.register(registration.token, {
22
- useClass: registration.useClass as never,
23
- });
21
+ container.registerSingleton(registration.token as never, registration.useClass as never);
24
22
  return;
25
23
  }
26
24
  container.register(registration.token, {
@@ -3,10 +3,12 @@ import { Engine } from "@codemation/core/bootstrap";
3
3
  import { ApplicationTokens } from "../../applicationTokens";
4
4
  import type { AppConfig } from "../../presentation/config/AppConfig";
5
5
  import { RuntimeWorkflowActivationPolicy } from "../../infrastructure/persistence/RuntimeWorkflowActivationPolicy";
6
+ import { RunEventBusTelemetryReporter } from "../../application/telemetry/RunEventBusTelemetryReporter";
6
7
  import { WorkflowRunEventWebsocketRelay } from "../../application/websocket/WorkflowRunEventWebsocketRelay";
7
8
  import { WorkflowWebsocketServer } from "../../presentation/websocket/WorkflowWebsocketServer";
8
9
  import { DatabaseMigrations } from "./DatabaseMigrations";
9
10
  import type { WorkflowActivationRepository } from "../../domain/workflows/WorkflowActivationRepository";
11
+ import { WorkflowRunRetentionPruneScheduler } from "../../application/runs/WorkflowRunRetentionPruneScheduler";
10
12
 
11
13
  @injectable()
12
14
  export class FrontendRuntime {
@@ -25,6 +27,10 @@ export class FrontendRuntime {
25
27
  private readonly workflowWebsocketServer: WorkflowWebsocketServer,
26
28
  @inject(WorkflowRunEventWebsocketRelay)
27
29
  private readonly workflowRunEventWebsocketRelay: WorkflowRunEventWebsocketRelay,
30
+ @inject(RunEventBusTelemetryReporter)
31
+ private readonly runEventBusTelemetryReporter: RunEventBusTelemetryReporter,
32
+ @inject(WorkflowRunRetentionPruneScheduler)
33
+ private readonly workflowRunRetentionPruneScheduler: WorkflowRunRetentionPruneScheduler,
28
34
  @inject(Engine)
29
35
  private readonly engine: Engine,
30
36
  ) {}
@@ -39,6 +45,8 @@ export class FrontendRuntime {
39
45
  }
40
46
  await this.engine.start([...this.workflowRepository.list()]);
41
47
  await this.workflowWebsocketServer.start();
48
+ await this.runEventBusTelemetryReporter.start();
49
+ this.workflowRunRetentionPruneScheduler.start();
42
50
  await this.workflowRunEventWebsocketRelay.start();
43
51
  }
44
52
  }
@@ -11,6 +11,8 @@ import { RuntimeWorkflowActivationPolicy } from "../../infrastructure/persistenc
11
11
  import type { WorkflowActivationRepository } from "../../domain/workflows/WorkflowActivationRepository";
12
12
  import { DatabaseMigrations } from "./DatabaseMigrations";
13
13
  import { AppContainerLifecycle } from "../AppContainerLifecycle";
14
+ import { RunEventBusTelemetryReporter } from "../../application/telemetry/RunEventBusTelemetryReporter";
15
+ import { WorkflowRunRetentionPruneScheduler } from "../../application/runs/WorkflowRunRetentionPruneScheduler";
14
16
 
15
17
  @injectable()
16
18
  export class WorkerRuntime {
@@ -27,6 +29,10 @@ export class WorkerRuntime {
27
29
  private readonly workflowRepository: WorkflowRepository,
28
30
  @inject(Engine)
29
31
  private readonly engine: Engine,
32
+ @inject(RunEventBusTelemetryReporter)
33
+ private readonly runEventBusTelemetryReporter: RunEventBusTelemetryReporter,
34
+ @inject(WorkflowRunRetentionPruneScheduler)
35
+ private readonly workflowRunRetentionPruneScheduler: WorkflowRunRetentionPruneScheduler,
30
36
  @inject(ApplicationTokens.WorkerRuntimeScheduler)
31
37
  private readonly scheduler: WorkerRuntimeScheduler,
32
38
  @inject(AppContainerLifecycle)
@@ -40,6 +46,8 @@ export class WorkerRuntime {
40
46
  await this.runtimeWorkflowActivationPolicy.hydrateFromRepository(this.workflowActivationRepository);
41
47
  const workflows = [...this.workflowRepository.list()];
42
48
  await this.engine.start(workflows);
49
+ await this.runEventBusTelemetryReporter.start();
50
+ this.workflowRunRetentionPruneScheduler.start();
43
51
  const worker = this.scheduler.createWorker({
44
52
  queues,
45
53
  requestHandler: this.engine,
@@ -9,7 +9,9 @@ export interface WorkflowRunRepository {
9
9
 
10
10
  listRuns(args: Readonly<{ workflowId?: string; limit?: number }>): Promise<ReadonlyArray<RunSummary>>;
11
11
 
12
- listRunsOlderThan?(args: Readonly<{ beforeIso: string; limit?: number }>): Promise<ReadonlyArray<RunPruneCandidate>>;
12
+ listRunsOlderThan?(
13
+ args: Readonly<{ nowIso: string; defaultRetentionSeconds: number; limit?: number }>,
14
+ ): Promise<ReadonlyArray<RunPruneCandidate>>;
13
15
 
14
16
  listBinaryStorageKeys?(runId: RunId): Promise<ReadonlyArray<string>>;
15
17