@codemation/host 0.7.0 → 0.9.0

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 (164) hide show
  1. package/CHANGELOG.md +89 -0
  2. package/LICENSE +37 -1
  3. package/dist/{ApiPaths-Dv1dcHu_.js → ApiPaths-DCvrlIjg.js} +12 -1
  4. package/dist/{ApiPaths-Dv1dcHu_.js.map → ApiPaths-DCvrlIjg.js.map} +1 -1
  5. package/dist/{AppConfigFactory-Cx4qQvRk.js → AppConfigFactory-D4LL1aOR.js} +77 -297
  6. package/dist/AppConfigFactory-D4LL1aOR.js.map +1 -0
  7. package/dist/{AppConfigFactory-DnLoQ9Li.d.ts → AppConfigFactory-DncmwCD1.d.ts} +2918 -199
  8. package/dist/{AppContainerFactory-DqKYCRNP.js → AppContainerFactory-jpYXGZGe.js} +1733 -475
  9. package/dist/AppContainerFactory-jpYXGZGe.js.map +1 -0
  10. package/dist/{CodemationAppContext-CKVv9W9q.d.ts → CodemationAppContext-K51b7oXe.d.ts} +9 -3
  11. package/dist/{CodemationAuthoring.types-DA3G3s6d.d.ts → CodemationAuthoring.types-BXlXIl4K.d.ts} +9 -4
  12. package/dist/{CodemationAuthoring.types-NGkBcmmT.js → CodemationAuthoring.types-BteaR3Dc.js} +3 -2
  13. package/dist/CodemationAuthoring.types-BteaR3Dc.js.map +1 -0
  14. package/dist/{CodemationConfigNormalizer-BAKjetJ6.d.ts → CodemationConfigNormalizer-B4rDYC9h.d.ts} +3 -3
  15. package/dist/{CodemationConsumerConfigLoader-GYpBBvqE.js → CodemationConsumerConfigLoader-By-6tuGc.js} +3 -1
  16. package/dist/CodemationConsumerConfigLoader-By-6tuGc.js.map +1 -0
  17. package/dist/{CodemationConsumerConfigLoader-nxOqvv46.d.ts → CodemationConsumerConfigLoader-Dt4jyLx6.d.ts} +3 -2
  18. package/dist/{CodemationPluginListMerger-DKLAHT2b.d.ts → CodemationPluginListMerger-DS6I3Xe0.d.ts} +64 -27
  19. package/dist/{persistenceServer-C-hH4z6l.js → CodemationPostgresPrismaClientFactory-C7156Fe-.js} +2 -2
  20. package/dist/CodemationPostgresPrismaClientFactory-C7156Fe-.js.map +1 -0
  21. package/dist/CodemationPostgresPrismaClientFactory-CTNTPnDr.d.ts +9 -0
  22. package/dist/{CredentialContractsRegistry-Bq2bq28t.d.ts → CredentialContractsRegistry-Dgu-rEXi.d.ts} +16 -3
  23. package/dist/{CredentialServices-Be2I60Th.d.ts → CredentialServices-B3wPyp2y.d.ts} +4 -4
  24. package/dist/{CredentialServices-Dk8yypeL.js → CredentialServices-Bios0dM8.js} +10 -4
  25. package/dist/CredentialServices-Bios0dM8.js.map +1 -0
  26. package/dist/{InternalPingRegistrar-DY3kSfxP.js → InternalPingRegistrar-BavAAnvk.js} +19 -16
  27. package/dist/InternalPingRegistrar-BavAAnvk.js.map +1 -0
  28. package/dist/{ItemsInputNormalizer-_RwIfRIQ.d.ts → ItemsInputNormalizer-CFkfNMLt.d.ts} +1434 -1225
  29. package/dist/PrismaMigrationDeployer-DdEcXXVi.d.ts +14 -0
  30. package/dist/{PublicFrontendBootstrapFactory-CY2FS-5g.d.ts → PublicFrontendBootstrapFactory-ClEjZP74.d.ts} +2 -2
  31. package/dist/{PublicFrontendBootstrapJsonCodec-CXG9Dxft.d.ts → PublicFrontendBootstrapJsonCodec-HNItQ7ol.d.ts} +6 -1
  32. package/dist/{TelemetryContracts-BtDx84Cp.d.ts → TelemetryContracts-DpZEODQM.d.ts} +2 -2
  33. package/dist/{WorkflowPolicyUiPresentationFactory-6MyjCvBO.d.ts → WorkflowPolicyUiPresentationFactory-BNn2fvR_.d.ts} +2 -2
  34. package/dist/{WorkflowPolicyUiPresentationFactory-Bb-ae_Zh.js → WorkflowPolicyUiPresentationFactory-DfvD2VHk.js} +1 -1
  35. package/dist/{WorkflowPolicyUiPresentationFactory-Bb-ae_Zh.js.map → WorkflowPolicyUiPresentationFactory-DfvD2VHk.js.map} +1 -1
  36. package/dist/authoring.d.ts +4 -4
  37. package/dist/authoring.js +1 -1
  38. package/dist/client.d.ts +1 -1
  39. package/dist/client.js +1 -1
  40. package/dist/consumer.d.ts +5 -5
  41. package/dist/consumer.js +1 -1
  42. package/dist/credentials.d.ts +5 -5
  43. package/dist/credentials.js +1 -1
  44. package/dist/devServerSidecar.d.ts +2 -2
  45. package/dist/dto.d.ts +5 -5
  46. package/dist/{index-DilAYwnH.d.ts → index-ChIfeWzk.d.ts} +71 -28
  47. package/dist/index.d.ts +49 -17
  48. package/dist/index.js +106 -13
  49. package/dist/index.js.map +1 -0
  50. package/dist/infrastructure/persistence/PrismaMigrationOperations.d.ts +44 -0
  51. package/dist/infrastructure/persistence/PrismaMigrationOperations.js +302 -0
  52. package/dist/infrastructure/persistence/PrismaMigrationOperations.js.map +1 -0
  53. package/dist/mapping.d.ts +2 -2
  54. package/dist/mapping.js +1 -1
  55. package/dist/nextServer.d.ts +15 -39
  56. package/dist/nextServer.js +6 -6
  57. package/dist/pairing.d.ts +27 -8
  58. package/dist/pairing.js +19 -3
  59. package/dist/pairing.js.map +1 -0
  60. package/dist/{pairing.types-snfZ_OzB.d.ts → pairing.types-D9Bjn98U.d.ts} +1 -1
  61. package/dist/persistenceServer.d.ts +31 -7
  62. package/dist/persistenceServer.js +2 -2
  63. package/dist/{server-C4bS62rg.d.ts → server-B5trn7y4.d.ts} +5 -5
  64. package/dist/{server-Y7kxwtCK.js → server-BlG9qV5S.js} +5 -5
  65. package/dist/{server-Y7kxwtCK.js.map → server-BlG9qV5S.js.map} +1 -1
  66. package/dist/server.d.ts +10 -10
  67. package/dist/server.js +9 -9
  68. package/package.json +28 -25
  69. package/playwright.config.ts +8 -2
  70. package/playwright.scaffolded-dev.config.ts +8 -2
  71. package/prisma/migrations/20260526120000_credential_material_pointer/migration.sql +18 -0
  72. package/prisma/migrations/20260527120000_add_human_task/migration.sql +32 -0
  73. package/prisma/migrations/20260527130000_add_hitl_state_json/migration.sql +6 -0
  74. package/prisma/migrations/20260527130000_add_hmac_nonce/migration.sql +12 -0
  75. package/prisma/migrations.sqlite/20260526120000_credential_material_pointer/migration.sql +13 -0
  76. package/prisma/migrations.sqlite/20260527120000_add_human_task/migration.sql +30 -0
  77. package/prisma/migrations.sqlite/20260527130000_add_hitl_state_json/migration.sql +6 -0
  78. package/prisma/migrations.sqlite/20260527130000_add_hmac_nonce/migration.sql +9 -0
  79. package/prisma/schema.postgresql.prisma +48 -0
  80. package/prisma/schema.sqlite.prisma +48 -0
  81. package/prisma-generated/prisma-postgresql-client/edge.js +40 -6
  82. package/prisma-generated/prisma-postgresql-client/index-browser.js +36 -2
  83. package/prisma-generated/prisma-postgresql-client/index.d.ts +3179 -163
  84. package/prisma-generated/prisma-postgresql-client/index.js +40 -6
  85. package/prisma-generated/prisma-postgresql-client/package.json +1 -1
  86. package/prisma-generated/prisma-postgresql-client/schema.prisma +48 -0
  87. package/prisma-generated/prisma-sqlite-client/edge.js +40 -6
  88. package/prisma-generated/prisma-sqlite-client/index-browser.js +36 -2
  89. package/prisma-generated/prisma-sqlite-client/index.d.ts +3175 -163
  90. package/prisma-generated/prisma-sqlite-client/index.js +40 -6
  91. package/prisma-generated/prisma-sqlite-client/package.json +1 -1
  92. package/prisma-generated/prisma-sqlite-client/schema.prisma +48 -0
  93. package/src/application/contracts/CredentialContractsRegistry.ts +15 -0
  94. package/src/application/credentials/AppGalleryProjector.ts +69 -0
  95. package/src/application/hitl/DecideHumanTaskCommandHandler.ts +149 -0
  96. package/src/application/hitl/DecisionSchemaValidator.ts +22 -0
  97. package/src/application/hitl/HitlCallbackHandler.ts +96 -0
  98. package/src/application/mapping/WorkflowDefinitionMapper.ts +1 -3
  99. package/src/application/queries/CredentialQueryHandlers.ts +2 -0
  100. package/src/application/queries/GetCredentialAppsQuery.ts +4 -0
  101. package/src/application/queries/GetCredentialAppsQueryHandler.ts +27 -0
  102. package/src/application/telemetry/ResumeTelemetryContextForRun.ts +53 -0
  103. package/src/application/telemetry/TelemetryRetentionTimestampFactory.ts +9 -8
  104. package/src/applicationTokens.ts +11 -1
  105. package/src/auth/managed/ManagedCorsMiddleware.ts +20 -5
  106. package/src/bootstrap/AppContainerFactory.ts +121 -3
  107. package/src/bootstrap/runtime/HeadlessApiRuntime.ts +47 -0
  108. package/src/credentials/CachingCredentialMaterialProvider.ts +96 -0
  109. package/src/credentials/CompositeCredentialMaterialProvider.ts +47 -0
  110. package/src/credentials/ControlPlaneCatalogFetcher.ts +8 -28
  111. package/src/credentials/ControlPlaneCredentialMaterialProvider.ts +79 -0
  112. package/src/credentials/CredentialOAuth2MaterialReader.ts +2 -7
  113. package/src/credentials/InternalCredentialsBindingRegistrar.ts +83 -0
  114. package/src/credentials/LocalCredentialMaterialProvider.ts +92 -0
  115. package/src/domain/credentials/CredentialInstanceService.ts +5 -1
  116. package/src/domain/credentials/CredentialTypeRegistryImpl.ts +18 -4
  117. package/src/domain/workflows/WorkflowActivationPreflightRules.ts +7 -4
  118. package/src/dto.ts +2 -0
  119. package/src/hitl/ControlPlaneInboxChannel.ts +102 -0
  120. package/src/hitl/HitlResumeTokenSigner.ts +80 -0
  121. package/src/hitl/HitlTimeoutJobScheduler.ts +77 -0
  122. package/src/hitl/HitlTimeoutWorker.ts +138 -0
  123. package/src/hitl/InboxChannelResolver.ts +49 -0
  124. package/src/hitl/LocalInboxChannel.ts +37 -0
  125. package/src/index.ts +3 -0
  126. package/src/infrastructure/persistence/PrismaCredentialStore.ts +10 -0
  127. package/src/infrastructure/persistence/PrismaHmacNonceStore.ts +29 -0
  128. package/src/infrastructure/persistence/PrismaHumanTaskStore.ts +156 -0
  129. package/src/infrastructure/persistence/PrismaMigrationDeployer.ts +53 -383
  130. package/src/infrastructure/persistence/PrismaMigrationOperations.ts +401 -0
  131. package/src/infrastructure/persistence/PrismaWorkflowRunRepository.ts +39 -0
  132. package/src/mcp/AgentMcpIntegrationImpl.ts +5 -1
  133. package/src/pairing/HmacNonceStore.ts +14 -0
  134. package/src/pairing/HmacNonceStoreToken.ts +4 -0
  135. package/src/pairing/HmacRequestSigner.ts +10 -1
  136. package/src/pairing/InMemoryHmacNonceStore.ts +24 -0
  137. package/src/pairing/IncomingHmacVerifier.ts +28 -12
  138. package/src/pairing/InternalHmacAuthMiddleware.ts +1 -1
  139. package/src/pairing/index.ts +3 -0
  140. package/src/presentation/config/CodemationAuthoring.types.ts +7 -1
  141. package/src/presentation/config/CodemationConfig.ts +6 -0
  142. package/src/presentation/http/ApiPaths.ts +14 -0
  143. package/src/presentation/http/HeadlessHttpServerFactory.ts +56 -0
  144. package/src/presentation/http/hono/HonoHttpAnonymousRoutePolicyRegistry.ts +4 -0
  145. package/src/presentation/http/hono/registrars/CredentialHonoApiRouteRegistrar.ts +1 -0
  146. package/src/presentation/http/hono/registrars/HitlDecideHonoApiRouteRegistrar.ts +54 -0
  147. package/src/presentation/http/hono/registrars/HitlInternalCallbackHonoApiRouteRegistrar.ts +33 -0
  148. package/src/presentation/http/hono/registrars/HitlResumeHonoApiRouteRegistrar.ts +43 -0
  149. package/src/presentation/http/routeHandlers/CredentialHttpRouteHandler.ts +9 -0
  150. package/src/presentation/http/routeHandlers/OAuth2HttpRouteHandlerFactory.ts +1 -1
  151. package/src/presentation/server/CodemationConsumerConfigLoader.ts +7 -2
  152. package/src/presentation/websocket/WorkflowWebsocketServerFactory.ts +16 -0
  153. package/src/server.ts +7 -2
  154. package/src/workflows/InternalWorkflowTestRunRegistrar.ts +9 -0
  155. package/tsconfig.json +1 -0
  156. package/dist/AppConfigFactory-Cx4qQvRk.js.map +0 -1
  157. package/dist/AppContainerFactory-DqKYCRNP.js.map +0 -1
  158. package/dist/CodemationAuthoring.types-NGkBcmmT.js.map +0 -1
  159. package/dist/CodemationConsumerConfigLoader-GYpBBvqE.js.map +0 -1
  160. package/dist/CredentialServices-Dk8yypeL.js.map +0 -1
  161. package/dist/InternalPingRegistrar-DY3kSfxP.js.map +0 -1
  162. package/dist/persistenceServer-C-hH4z6l.js.map +0 -1
  163. package/dist/persistenceServer-CeTHtC6E.d.ts +0 -30
  164. package/src/credentials/catalogTypes.ts +0 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CredentialServices-Bios0dM8.js","names":["fetchImpl: typeof globalThis.fetch","healthTester: OpenAiApiKeyCredentialHealthTester","SOURCE_PRIORITY: Record<CredentialTypeSource, number>","CredentialTypeRegistryImpl","loggers: LoggerFactory","SOURCE_PRIORITY","nextType: AnyCredentialType","stubType: AnyCredentialType","SOURCE_PRIORITY: Record<McpServerDeclarationSource, number>","McpServerCatalog","loggers: LoggerFactory","appConfig: AppConfig","WorkflowCredentialNodeResolver","mcpCatalog?: McpServerCatalog","entry","labels: string[]","CredentialFieldEnvOverlayService","appConfig: AppConfig","pub: Record<string, unknown>","mat: Record<string, unknown>","CredentialSecretCipher","appConfig: AppConfig","CredentialMaterialResolver","credentialStore: CredentialStore","credentialSecretCipher: CredentialSecretCipher","appConfig: AppConfig","resolved: Record<string, unknown>","missingEnvironmentVariables: string[]","CredentialOAuth2ScopeResolver","CredentialInstanceService","credentialStore: CredentialStore","credentialTypeRegistry: CredentialTypeRegistryImpl","credentialSecretCipher: CredentialSecretCipher","credentialFieldEnvOverlayService: CredentialFieldEnvOverlayService","credentialMaterialResolver: CredentialMaterialResolver","credentialOAuth2ScopeResolver: CredentialOAuth2ScopeResolver","credentialSessionService: MutableCredentialSessionService","instance: CredentialInstanceRecord","updatedInstance: CredentialInstanceRecord","out: Record<string, unknown>","CredentialBindingService","credentialStore: CredentialStore","credentialInstanceService: CredentialInstanceService","workflowRepository: WorkflowRepository","credentialSessionService: MutableCredentialSessionService","workflowCredentialNodeResolver: WorkflowCredentialNodeResolver","loggerFactory: LoggerFactory","binding: CredentialBinding","slots: WorkflowCredentialHealthSlotDto[]","CredentialRuntimeMaterialService","credentialStore: CredentialStore","credentialMaterialResolver: CredentialMaterialResolver","credentialSecretCipher: CredentialSecretCipher","credentialTypeRegistry: CredentialTypeRegistryImpl","CredentialSessionServiceImpl","credentialStore: CredentialStore","credentialRuntimeMaterialService: CredentialRuntimeMaterialService","credentialFieldEnvOverlayService: CredentialFieldEnvOverlayService","credentialTypeRegistry: CredentialTypeRegistryImpl","workflowRepository: WorkflowRepository","workflowCredentialNodeResolver: WorkflowCredentialNodeResolver","bindingKey: CredentialBindingKey","CredentialTestService","credentialInstanceService: CredentialInstanceService","credentialRuntimeMaterialService: CredentialRuntimeMaterialService","credentialFieldEnvOverlayService: CredentialFieldEnvOverlayService","credentialTypeRegistry: CredentialTypeRegistryImpl","credentialStore: CredentialStore","credentialSessionService: MutableCredentialSessionService"],"sources":["../src/infrastructure/credentials/OpenAiApiKeyCredentialHealthTester.ts","../src/infrastructure/credentials/OpenAiApiKeyCredentialTypeFactory.ts","../src/applicationTokens.ts","../src/domain/credentials/CredentialTypeRegistryImpl.ts","../src/application/ApplicationRequestError.ts","../src/mcp/McpServerCatalog.ts","../src/domain/credentials/WorkflowCredentialNodeResolver.ts","../src/domain/credentials/CredentialFieldEnvOverlayService.ts","../src/domain/credentials/CredentialKeyRotatedError.ts","../src/domain/credentials/CredentialSecretCipher.ts","../src/domain/credentials/CredentialMaterialResolver.ts","../src/domain/credentials/CredentialOAuth2ScopeResolver.ts","../src/domain/credentials/CredentialInstanceService.ts","../src/domain/credentials/CredentialBindingService.ts","../src/domain/credentials/CredentialRuntimeMaterialService.ts","../src/domain/credentials/CredentialSessionServiceImpl.ts","../src/domain/credentials/CredentialTestService.ts"],"sourcesContent":["import type { CredentialHealth, CredentialSessionFactoryArgs } from \"@codemation/core\";\n\nimport type { OpenAiApiKeyMaterial, OpenAiApiKeyPublicConfig } from \"./OpenAiApiKeyCredentialShapes.types\";\n\n/**\n * Verifies an OpenAI-compatible API key by calling the provider's models list endpoint\n * (GET `/v1/models` relative to the configured base URL).\n */\nexport class OpenAiApiKeyCredentialHealthTester {\n constructor(private readonly fetchImpl: typeof globalThis.fetch) {}\n\n async test(\n args: CredentialSessionFactoryArgs<OpenAiApiKeyPublicConfig, OpenAiApiKeyMaterial>,\n ): Promise<CredentialHealth> {\n const testedAt = new Date().toISOString();\n const apiKey = String(args.material.apiKey ?? \"\").trim();\n if (apiKey.length === 0) {\n return {\n status: \"failing\",\n message: \"OpenAI API key is empty.\",\n testedAt,\n };\n }\n\n const modelsUrl = this.resolveModelsListUrl(args.publicConfig.baseUrl);\n\n try {\n const response = await this.fetchImpl(modelsUrl, {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${apiKey}`,\n },\n signal: AbortSignal.timeout(25_000),\n });\n\n if (response.ok) {\n return {\n status: \"healthy\",\n message: \"API key verified against the models endpoint.\",\n testedAt,\n };\n }\n\n const message = await this.parseErrorMessage(response);\n return {\n status: \"failing\",\n message,\n testedAt,\n };\n } catch (error) {\n return {\n status: \"failing\",\n message: error instanceof Error ? error.message : String(error),\n testedAt,\n };\n }\n }\n\n private resolveModelsListUrl(baseUrlRaw: unknown): string {\n const defaultBase = \"https://api.openai.com/v1\";\n const raw = typeof baseUrlRaw === \"string\" ? baseUrlRaw.trim() : \"\";\n const base = raw === \"\" ? defaultBase : raw.replace(/\\/+$/, \"\");\n if (base.endsWith(\"/models\")) {\n return base;\n }\n if (base.endsWith(\"/v1\")) {\n return `${base}/models`;\n }\n return `${base}/v1/models`;\n }\n\n private async parseErrorMessage(response: Response): Promise<string> {\n const prefix = `HTTP ${response.status}`;\n try {\n const text = await response.text();\n if (text.trim() === \"\") {\n return prefix;\n }\n const parsed = JSON.parse(text) as { error?: { message?: string } };\n const fromApi = parsed.error?.message;\n if (typeof fromApi === \"string\" && fromApi.trim() !== \"\") {\n return `${prefix}: ${fromApi.trim()}`;\n }\n return `${prefix}: ${text.length > 280 ? `${text.slice(0, 280)}…` : text}`;\n } catch {\n return prefix;\n }\n }\n}\n","import type { CredentialType } from \"../../domain/credentials/CredentialServices\";\n\nimport type { OpenAiApiKeyCredentialHealthTester } from \"./OpenAiApiKeyCredentialHealthTester\";\nimport type {\n OpenAiApiKeyMaterial,\n OpenAiApiKeyPublicConfig,\n OpenAiApiKeySession,\n} from \"./OpenAiApiKeyCredentialShapes.types\";\n\n/**\n * Builds the OpenAI-compatible API key credential (`openai.apiKey`) registration.\n * Used by {@link FrameworkBuiltinCredentialTypesRegistrar} and may be listed in {@link CodemationConfig.credentialTypes}\n * so consumer apps always register the type even when bootstrap order differs.\n */\nexport class OpenAiApiKeyCredentialTypeFactory {\n constructor(private readonly healthTester: OpenAiApiKeyCredentialHealthTester) {}\n\n createCredentialType(): CredentialType<OpenAiApiKeyPublicConfig, OpenAiApiKeyMaterial, OpenAiApiKeySession> {\n return {\n definition: {\n typeId: \"openai.apiKey\",\n displayName: \"OpenAI API key\",\n description: \"API key and optional base URL for OpenAI or OpenAI-compatible chat endpoints.\",\n publicFields: [\n {\n key: \"baseUrl\",\n label: \"Base URL\",\n type: \"string\",\n placeholder: \"https://api.openai.com/v1\",\n helpText: \"Leave empty to use the default OpenAI API endpoint.\",\n },\n ],\n secretFields: [{ key: \"apiKey\", label: \"API key\", type: \"password\", required: true }],\n supportedSourceKinds: [\"db\", \"env\", \"code\"],\n },\n createSession: async (args) => {\n const baseUrlRaw = args.publicConfig.baseUrl;\n const baseUrl = typeof baseUrlRaw === \"string\" && baseUrlRaw.trim() !== \"\" ? baseUrlRaw.trim() : undefined;\n return {\n apiKey: String(args.material.apiKey ?? \"\"),\n baseUrl,\n };\n },\n test: async (args) => this.healthTester.test(args),\n };\n }\n}\n","import type { Clock, CredentialMaterialProvider, OAuthFlowExecutor, TypeToken } from \"@codemation/core\";\nimport type { SessionVerifier } from \"./application/auth/SessionVerifier\";\nimport type { Command } from \"./application/bus/Command\";\nimport type { CommandBus } from \"./application/bus/CommandBus\";\nimport type { CommandHandler } from \"./application/bus/CommandHandler\";\nimport type { DomainEvent } from \"./application/bus/DomainEvent\";\nimport type { DomainEventBus } from \"./application/bus/DomainEventBus\";\nimport type { DomainEventHandler } from \"./application/bus/DomainEventHandler\";\nimport type { Query } from \"./application/bus/Query\";\nimport type { QueryBus } from \"./application/bus/QueryBus\";\nimport type { QueryHandler } from \"./application/bus/QueryHandler\";\nimport type { Logger, LoggerFactory } from \"./application/logging/Logger\";\nimport type { ProcessRunner } from \"./process/ProcessRunner.types\";\nimport type { WorkflowWebsocketPublisher } from \"./application/websocket/WorkflowWebsocketPublisher\";\nimport type { TelemetrySpanPublisher } from \"./application/telemetry/TelemetrySpanPublisher\";\nimport type { CredentialStore } from \"./domain/credentials/CredentialServices\";\nimport type {\n RunTraceContextRepository,\n TelemetryArtifactStore,\n TelemetryExporter,\n TelemetryMetricPointStore,\n TelemetrySpanStore,\n} from \"./domain/telemetry/TelemetryContracts\";\nimport type { WorkflowRunRepository } from \"./domain/runs/WorkflowRunRepository\";\nimport type { WorkflowDebuggerOverlayRepository } from \"./domain/workflows/WorkflowDebuggerOverlayRepository\";\nimport type { WorkflowDefinitionRepository } from \"./domain/workflows/WorkflowDefinitionRepository\";\nimport type { WorkflowActivationRepository } from \"./domain/workflows/WorkflowActivationRepository\";\nimport type { PrismaDatabaseClient } from \"./infrastructure/persistence/PrismaDatabaseClient\";\nimport type { WorkerRuntimeScheduler } from \"./infrastructure/scheduler/WorkerRuntimeScheduler\";\nimport type { AppConfig } from \"./presentation/config/AppConfig\";\nimport type { CodemationAuthConfig } from \"./presentation/config/CodemationAuthConfig\";\nimport type { CodemationWhitelabelConfig } from \"./presentation/config/CodemationWhitelabelConfig\";\nimport type { HonoApiRouteRegistrar } from \"./presentation/http/hono/HonoApiRouteRegistrar\";\nimport type { InternalHonoApiRouteRegistrar } from \"./presentation/http/hono/InternalHonoApiRouteRegistrar\";\nimport type { ManagedCorsMiddleware } from \"./auth/managed/ManagedCorsMiddleware\";\nimport type { WebsocketAuthenticator } from \"./presentation/websocket/WebsocketAuthenticator.types\";\nimport type { IWorkflowAuditEmitter } from \"./audit/IAuditEmitter\";\n\nexport const ApplicationTokens = {\n CodemationAuthConfig: Symbol.for(\"codemation.application.CodemationAuthConfig\") as TypeToken<\n CodemationAuthConfig | undefined\n >,\n CodemationWhitelabelConfig: Symbol.for(\n \"codemation.application.CodemationWhitelabelConfig\",\n ) as TypeToken<CodemationWhitelabelConfig>,\n AppConfig: Symbol.for(\"codemation.application.AppConfig\") as TypeToken<AppConfig>,\n WebSocketPort: Symbol.for(\"codemation.application.WebSocketPort\") as TypeToken<number>,\n WebSocketBindHost: Symbol.for(\"codemation.application.WebSocketBindHost\") as TypeToken<string>,\n QueryBus: Symbol.for(\"codemation.application.QueryBus\") as TypeToken<QueryBus>,\n CommandBus: Symbol.for(\"codemation.application.CommandBus\") as TypeToken<CommandBus>,\n DomainEventBus: Symbol.for(\"codemation.application.DomainEventBus\") as TypeToken<DomainEventBus>,\n QueryHandler: Symbol.for(\"codemation.application.QueryHandler\") as TypeToken<QueryHandler<Query<unknown>, unknown>>,\n CommandHandler: Symbol.for(\"codemation.application.CommandHandler\") as TypeToken<\n CommandHandler<Command<unknown>, unknown>\n >,\n DomainEventHandler: Symbol.for(\"codemation.application.DomainEventHandler\") as TypeToken<\n DomainEventHandler<DomainEvent>\n >,\n HonoApiRouteRegistrar: Symbol.for(\"codemation.application.HonoApiRouteRegistrar\") as TypeToken<HonoApiRouteRegistrar>,\n InternalHonoApiRouteRegistrar: Symbol.for(\n \"codemation.application.InternalHonoApiRouteRegistrar\",\n ) as TypeToken<InternalHonoApiRouteRegistrar>,\n ManagedCorsMiddleware: Symbol.for(\"codemation.application.ManagedCorsMiddleware\") as TypeToken<ManagedCorsMiddleware>,\n WebsocketAuthenticator: Symbol.for(\n \"codemation.application.WebsocketAuthenticator\",\n ) as TypeToken<WebsocketAuthenticator | null>,\n WorkflowWebsocketPublisher: Symbol.for(\n \"codemation.application.WorkflowWebsocketPublisher\",\n ) as TypeToken<WorkflowWebsocketPublisher>,\n TelemetrySpanPublisher: Symbol.for(\n \"codemation.application.TelemetrySpanPublisher\",\n ) as TypeToken<TelemetrySpanPublisher>,\n WorkerRuntimeScheduler: Symbol.for(\n \"codemation.application.WorkerRuntimeScheduler\",\n ) as TypeToken<WorkerRuntimeScheduler>,\n WorkflowDefinitionRepository: Symbol.for(\n \"codemation.application.WorkflowDefinitionRepository\",\n ) as TypeToken<WorkflowDefinitionRepository>,\n WorkflowActivationRepository: Symbol.for(\n \"codemation.application.WorkflowActivationRepository\",\n ) as TypeToken<WorkflowActivationRepository>,\n WorkflowDebuggerOverlayRepository: Symbol.for(\n \"codemation.application.WorkflowDebuggerOverlayRepository\",\n ) as TypeToken<WorkflowDebuggerOverlayRepository>,\n WorkflowRunRepository: Symbol.for(\"codemation.application.WorkflowRunRepository\") as TypeToken<WorkflowRunRepository>,\n LoggerFactory: Symbol.for(\"codemation.application.LoggerFactory\") as TypeToken<LoggerFactory>,\n /**\n * Opt-in timing/diagnostics logger (`CODEMATION_PERFORMANCE_LOGGING` + normal minimum log level).\n */\n PerformanceDiagnosticsLogger: Symbol.for(\"codemation.application.PerformanceDiagnosticsLogger\") as TypeToken<Logger>,\n CredentialStore: Symbol.for(\"codemation.application.CredentialStore\") as TypeToken<CredentialStore>,\n RunTraceContextRepository: Symbol.for(\n \"codemation.application.RunTraceContextRepository\",\n ) as TypeToken<RunTraceContextRepository>,\n TelemetrySpanStore: Symbol.for(\"codemation.application.TelemetrySpanStore\") as TypeToken<TelemetrySpanStore>,\n TelemetryArtifactStore: Symbol.for(\n \"codemation.application.TelemetryArtifactStore\",\n ) as TypeToken<TelemetryArtifactStore>,\n TelemetryMetricPointStore: Symbol.for(\n \"codemation.application.TelemetryMetricPointStore\",\n ) as TypeToken<TelemetryMetricPointStore>,\n TelemetryExporter: Symbol.for(\"codemation.application.TelemetryExporter\") as TypeToken<TelemetryExporter>,\n PrismaClient: Symbol.for(\"codemation.application.PrismaClient\") as TypeToken<PrismaDatabaseClient>,\n SessionVerifier: Symbol.for(\"codemation.application.SessionVerifier\") as TypeToken<SessionVerifier>,\n Clock: Symbol.for(\"codemation.application.Clock\") as TypeToken<Clock>,\n WorkflowAuditEmitter: Symbol.for(\"codemation.application.WorkflowAuditEmitter\") as TypeToken<IWorkflowAuditEmitter>,\n ProcessRunner: Symbol.for(\"codemation.application.ProcessRunner\") as TypeToken<ProcessRunner>,\n OAuthFlowExecutor: Symbol.for(\"codemation.application.OAuthFlowExecutor\") as TypeToken<OAuthFlowExecutor>,\n /**\n * The provider that `CachingCredentialMaterialProvider` wraps. Bound to\n * `LocalCredentialMaterialProvider` in standalone mode and to\n * `CompositeCredentialMaterialProvider` in managed mode (which dispatches\n * by `ref.source`). See `packages/host/src/credentials/` and\n * `planning/sprints/credentials-vault/02-controlplane-material-provider.md`.\n */\n CredentialMaterialInnerProvider: Symbol.for(\n \"codemation.application.CredentialMaterialInnerProvider\",\n ) as TypeToken<CredentialMaterialProvider>,\n} as const;\n","import type { CredentialTypeDefinition, CredentialTypeId, CredentialTypeRegistry } from \"@codemation/core\";\n\nimport { inject, injectable } from \"@codemation/core\";\n\nimport { ApplicationTokens } from \"../../applicationTokens\";\nimport type { LoggerFactory } from \"../../application/logging/Logger\";\nimport type { AnyCredentialType } from \"./CredentialServices\";\n\nexport type CredentialTypeSource = \"plugin\" | \"config\" | \"controlPlane\";\n\nconst SOURCE_PRIORITY: Record<CredentialTypeSource, number> = {\n plugin: 0,\n config: 1,\n controlPlane: 2,\n};\n\ntype RegistryEntry = Readonly<{\n type: AnyCredentialType;\n source: CredentialTypeSource;\n}>;\n\n@injectable()\nexport class CredentialTypeRegistryImpl implements CredentialTypeRegistry {\n private readonly entries = new Map<CredentialTypeId, RegistryEntry>();\n private readonly bySource = new Map<CredentialTypeSource, Set<CredentialTypeId>>();\n\n constructor(@inject(ApplicationTokens.LoggerFactory) private readonly loggers: LoggerFactory) {}\n\n merge(source: CredentialTypeSource, types: ReadonlyArray<AnyCredentialType>): void {\n const logger = this.loggers.create(\"CredentialTypeRegistryImpl\");\n for (const type of types) {\n this.insert(source, type, logger);\n }\n }\n\n mergeDefinitions(source: CredentialTypeSource, definitions: ReadonlyArray<CredentialTypeDefinition>): void {\n const logger = this.loggers.create(\"CredentialTypeRegistryImpl\");\n for (const definition of definitions) {\n const existing = this.entries.get(definition.typeId);\n const sourcePriority = SOURCE_PRIORITY[source];\n if (existing) {\n if (sourcePriority < SOURCE_PRIORITY[existing.source]) {\n logger.warn(\n `CredentialTypeRegistryImpl: id collision — lower-priority source \"${source}\" ignored for typeId \"${definition.typeId}\" (current source: \"${existing.source}\")`,\n );\n continue;\n }\n if (sourcePriority > SOURCE_PRIORITY[existing.source]) {\n logger.warn(\n `CredentialTypeRegistryImpl: typeId \"${definition.typeId}\" shadowed — \"${existing.source}\" overridden by higher-priority source \"${source}\"`,\n );\n this.bySource.get(existing.source)?.delete(definition.typeId);\n }\n const nextType: AnyCredentialType =\n sourcePriority === SOURCE_PRIORITY[existing.source]\n ? { ...existing.type, definition }\n : {\n definition,\n createSession: this.createUnsupportedSessionFactory(definition.typeId, source),\n test: this.createUnsupportedHealthTester(definition.typeId, source),\n };\n this.recordEntry(definition.typeId, { type: nextType, source });\n continue;\n }\n const stubType: AnyCredentialType = {\n definition,\n createSession: this.createUnsupportedSessionFactory(definition.typeId, source),\n test: this.createUnsupportedHealthTester(definition.typeId, source),\n };\n this.recordEntry(definition.typeId, { type: stubType, source });\n }\n }\n\n clear(source: CredentialTypeSource): void {\n const ids = this.bySource.get(source);\n if (!ids) {\n return;\n }\n for (const id of ids) {\n this.entries.delete(id);\n }\n this.bySource.delete(source);\n }\n\n listTypes(): ReadonlyArray<CredentialTypeDefinition> {\n return [...this.entries.values()].map((entry) => entry.type.definition);\n }\n\n getType(typeId: CredentialTypeId): CredentialTypeDefinition | undefined {\n return this.entries.get(typeId)?.type.definition;\n }\n\n getCredentialType(typeId: CredentialTypeId): AnyCredentialType | undefined {\n return this.entries.get(typeId)?.type;\n }\n\n private insert(\n source: CredentialTypeSource,\n type: AnyCredentialType,\n logger: ReturnType<LoggerFactory[\"create\"]>,\n ): void {\n const typeId = type.definition.typeId;\n const existing = this.entries.get(typeId);\n const sourcePriority = SOURCE_PRIORITY[source];\n if (existing) {\n if (sourcePriority < SOURCE_PRIORITY[existing.source]) {\n logger.warn(\n `CredentialTypeRegistryImpl: id collision — lower-priority source \"${source}\" ignored for typeId \"${typeId}\" (current source: \"${existing.source}\")`,\n );\n return;\n }\n if (sourcePriority > SOURCE_PRIORITY[existing.source]) {\n logger.warn(\n `CredentialTypeRegistryImpl: typeId \"${typeId}\" shadowed — \"${existing.source}\" overridden by higher-priority source \"${source}\"`,\n );\n this.bySource.get(existing.source)?.delete(typeId);\n }\n }\n this.recordEntry(typeId, { type, source });\n }\n\n private recordEntry(typeId: CredentialTypeId, entry: RegistryEntry): void {\n this.entries.set(typeId, entry);\n if (!this.bySource.has(entry.source)) {\n this.bySource.set(entry.source, new Set());\n }\n this.bySource.get(entry.source)!.add(typeId);\n }\n\n private createUnsupportedSessionFactory(\n typeId: CredentialTypeId,\n source: CredentialTypeSource,\n ): AnyCredentialType[\"createSession\"] {\n return async () => {\n throw new Error(\n `Credential type \"${typeId}\" (source \"${source}\") was registered with definition only — no createSession implementation is available in this runtime.`,\n );\n };\n }\n\n private createUnsupportedHealthTester(\n typeId: CredentialTypeId,\n source: CredentialTypeSource,\n ): AnyCredentialType[\"test\"] {\n return async () => ({\n status: \"unknown\" as const,\n message: `Credential type \"${typeId}\" (source \"${source}\") has no local test implementation.`,\n });\n }\n}\n","export class ApplicationRequestError extends Error {\n readonly status: number;\n\n readonly payload: Readonly<{ error: string; errors?: ReadonlyArray<string> }>;\n\n constructor(status: number, message: string, errors?: ReadonlyArray<string>) {\n super(message);\n this.name = \"ApplicationRequestError\";\n this.status = status;\n this.payload = errors && errors.length > 0 ? { error: message, errors } : { error: message };\n }\n}\n","import { inject, injectable } from \"@codemation/core\";\nimport type { McpServerDeclaration } from \"@codemation/core\";\nimport { ApplicationTokens } from \"../applicationTokens\";\nimport type { LoggerFactory } from \"../application/logging/Logger\";\nimport type { AppConfig } from \"../presentation/config/AppConfig\";\n\nexport type McpServerDeclarationSource = \"plugin\" | \"config\" | \"controlPlane\";\n\nconst SOURCE_PRIORITY: Record<McpServerDeclarationSource, number> = {\n plugin: 0,\n config: 1,\n controlPlane: 2,\n};\n\nconst ID_PATTERN = /^[a-z0-9-]+$/;\n\ntype CatalogEntry = Readonly<{\n decl: McpServerDeclaration;\n source: McpServerDeclarationSource;\n}>;\n\n@injectable()\nexport class McpServerCatalog {\n private readonly entries = new Map<string, CatalogEntry>();\n private readonly bySource = new Map<McpServerDeclarationSource, Set<string>>();\n private readonly env: NodeJS.ProcessEnv;\n\n constructor(\n @inject(ApplicationTokens.LoggerFactory) private readonly loggers: LoggerFactory,\n @inject(ApplicationTokens.AppConfig) appConfig: AppConfig,\n ) {\n this.env = appConfig.env;\n }\n\n merge(source: McpServerDeclarationSource, declarations: ReadonlyArray<McpServerDeclaration>): void {\n const logger = this.loggers.create(\"McpServerCatalog\");\n for (const decl of declarations) {\n if (!this.validate(decl, source, logger)) {\n continue;\n }\n const existing = this.entries.get(decl.id);\n if (existing) {\n if (SOURCE_PRIORITY[source] <= SOURCE_PRIORITY[existing.source]) {\n logger.warn(\n `McpServerCatalog: id collision — lower-priority source \"${source}\" ignored for id \"${decl.id}\" (current source: \"${existing.source}\")`,\n );\n continue;\n }\n logger.warn(\n `McpServerCatalog: id \"${decl.id}\" shadowed — \"${existing.source}\" overridden by higher-priority source \"${source}\"`,\n );\n this.bySource.get(existing.source)?.delete(decl.id);\n }\n this.entries.set(decl.id, { decl, source });\n if (!this.bySource.has(source)) {\n this.bySource.set(source, new Set());\n }\n this.bySource.get(source)!.add(decl.id);\n }\n }\n\n get(id: string): McpServerDeclaration | undefined {\n return this.entries.get(id)?.decl;\n }\n\n getAll(): readonly McpServerDeclaration[] {\n return [...this.entries.values()].map((entry) => entry.decl);\n }\n\n clear(source: McpServerDeclarationSource): void {\n const ids = this.bySource.get(source);\n if (!ids) {\n return;\n }\n for (const id of ids) {\n this.entries.delete(id);\n }\n this.bySource.delete(source);\n }\n\n private validate(\n decl: McpServerDeclaration,\n source: McpServerDeclarationSource,\n logger: ReturnType<LoggerFactory[\"create\"]>,\n ): boolean {\n if (!ID_PATTERN.test(decl.id)) {\n logger.warn(\n `McpServerCatalog: declaration from \"${source}\" has invalid id \"${decl.id}\" (must match /^[a-z0-9-]+$/) — skipped`,\n );\n return false;\n }\n\n if ((decl.transport as string) === \"stdio\") {\n if (this.env.CODEMATION_ALLOW_STDIO_MCP !== \"true\") {\n logger.warn(\n `McpServerCatalog: declaration \"${decl.id}\" from \"${source}\" uses stdio transport which is disabled (set CODEMATION_ALLOW_STDIO_MCP=true to allow) — skipped`,\n );\n return false;\n }\n }\n\n return true;\n }\n}\n","import type { CredentialRequirement, WorkflowDefinition } from \"@codemation/core\";\nimport {\n AgentConfigInspector,\n AgentConnectionNodeCollector,\n type AgentConnectionNodeDescriptor,\n ConnectionNodeIdFactory,\n inject,\n injectable,\n} from \"@codemation/core\";\nimport { McpServerCatalog } from \"../../mcp/McpServerCatalog\";\n\nexport type WorkflowCredentialSlotRef = Readonly<{\n workflowId: string;\n nodeId: string;\n nodeName: string;\n requirement: CredentialRequirement;\n}>;\n\n/**\n * Resolves credential requirements for workflow node ids, including connection-owned LLM/tool children.\n */\n@injectable()\nexport class WorkflowCredentialNodeResolver {\n constructor(\n @inject(McpServerCatalog)\n private readonly mcpCatalog?: McpServerCatalog,\n ) {}\n /**\n * Human-readable label for credential errors (workflow node name or agent › attachment).\n */\n describeCredentialNodeDisplay(workflow: WorkflowDefinition, nodeId: string): string {\n const direct = workflow.nodes.find((n) => n.id === nodeId);\n if (direct) {\n return direct.name ?? direct.config.name ?? direct.id;\n }\n const recursive = this.findRecursiveConnectionNode(workflow, nodeId);\n if (!recursive) {\n return nodeId;\n }\n return this.buildRecursiveDisplayLabel(recursive.rootAgentLabel, recursive.entry, recursive.entriesById);\n }\n\n isCredentialNodeIdInWorkflow(workflow: WorkflowDefinition, nodeId: string): boolean {\n if (workflow.nodes.some((n) => n.id === nodeId)) {\n return true;\n }\n return this.findRecursiveConnectionNode(workflow, nodeId) !== undefined;\n }\n\n findRequirement(\n workflow: WorkflowDefinition,\n nodeId: string,\n slotKey: string,\n ): Readonly<{ nodeName: string; requirement: CredentialRequirement }> | undefined {\n const direct = this.findDirectRequirement(workflow, nodeId, slotKey);\n if (direct) {\n return direct;\n }\n const recursive = this.findRecursiveConnectionNode(workflow, nodeId);\n if (!recursive) {\n return undefined;\n }\n const requirement = recursive.entry.credentialSource\n .getCredentialRequirements?.()\n ?.find((entry) => entry.slotKey === slotKey);\n return requirement ? { nodeName: recursive.entry.name, requirement } : undefined;\n }\n\n listSlots(workflow: WorkflowDefinition): ReadonlyArray<WorkflowCredentialSlotRef> {\n const slotsByKey = new Map<string, WorkflowCredentialSlotRef>();\n\n for (const node of workflow.nodes) {\n if (AgentConfigInspector.isAgentNodeConfig(node.config)) {\n this.addRecursiveAgentSlots(workflow.id, node.id, node.config, slotsByKey);\n continue;\n }\n this.addSlotsForRequirements(\n workflow.id,\n node.id,\n node.name ?? node.config.name ?? node.id,\n node.config.getCredentialRequirements?.() ?? [],\n slotsByKey,\n );\n }\n return [...slotsByKey.values()];\n }\n\n private findDirectRequirement(\n workflow: WorkflowDefinition,\n nodeId: string,\n slotKey: string,\n ): Readonly<{ nodeName: string; requirement: CredentialRequirement }> | undefined {\n const node = workflow.nodes.find((entry) => entry.id === nodeId);\n if (!node || AgentConfigInspector.isAgentNodeConfig(node.config)) {\n return undefined;\n }\n const requirement = node.config.getCredentialRequirements?.()?.find((entry) => entry.slotKey === slotKey);\n if (!requirement) {\n return undefined;\n }\n return { nodeName: node.name ?? node.config.name ?? node.id, requirement };\n }\n\n private addRecursiveAgentSlots(\n workflowId: string,\n rootAgentNodeId: string,\n agentConfig: Parameters<typeof AgentConnectionNodeCollector.collect>[1],\n slotsByKey: Map<string, WorkflowCredentialSlotRef>,\n ): void {\n const mcpResolver = this.mcpCatalog ? (id: string) => this.mcpCatalog!.get(id) : undefined;\n const descriptors = AgentConnectionNodeCollector.collect(rootAgentNodeId, agentConfig, mcpResolver);\n for (const entry of descriptors) {\n this.addSlotsForRequirements(\n workflowId,\n entry.nodeId,\n entry.name,\n entry.credentialSource.getCredentialRequirements?.() ?? [],\n slotsByKey,\n );\n }\n }\n\n private addSlotsForRequirements(\n workflowId: string,\n nodeId: string,\n nodeName: string,\n requirements: ReadonlyArray<CredentialRequirement>,\n slotsByKey: Map<string, WorkflowCredentialSlotRef>,\n ): void {\n for (const requirement of requirements) {\n const key = `${nodeId}\\0${requirement.slotKey}`;\n if (slotsByKey.has(key)) {\n continue;\n }\n slotsByKey.set(key, {\n workflowId,\n nodeId,\n nodeName,\n requirement,\n });\n }\n }\n\n private findRecursiveConnectionNode(\n workflow: WorkflowDefinition,\n nodeId: string,\n ):\n | Readonly<{\n rootAgentNodeId: string;\n rootAgentLabel: string;\n entry: AgentConnectionNodeDescriptor;\n entriesById: ReadonlyMap<string, AgentConnectionNodeDescriptor>;\n }>\n | undefined {\n if (\n !ConnectionNodeIdFactory.isLanguageModelConnectionNodeId(nodeId) &&\n !ConnectionNodeIdFactory.isToolConnectionNodeId(nodeId) &&\n !ConnectionNodeIdFactory.isMcpConnectionNodeId(nodeId)\n ) {\n return undefined;\n }\n const mcpResolver = this.mcpCatalog ? (id: string) => this.mcpCatalog!.get(id) : undefined;\n for (const node of workflow.nodes) {\n if (!AgentConfigInspector.isAgentNodeConfig(node.config)) {\n continue;\n }\n const entries = AgentConnectionNodeCollector.collect(node.id, node.config, mcpResolver);\n const entriesById = new Map(entries.map((entry) => [entry.nodeId, entry]));\n const entry = entriesById.get(nodeId);\n if (!entry) {\n continue;\n }\n return {\n rootAgentNodeId: node.id,\n rootAgentLabel: node.name ?? node.config.name ?? node.id,\n entry,\n entriesById,\n };\n }\n return undefined;\n }\n\n private buildRecursiveDisplayLabel(\n rootAgentLabel: string,\n entry: AgentConnectionNodeDescriptor,\n entriesById: ReadonlyMap<string, AgentConnectionNodeDescriptor>,\n ): string {\n const labels = [rootAgentLabel, ...this.collectAncestorToolLabels(entry.parentNodeId, entriesById)];\n labels.push(entry.role === \"languageModel\" ? \"Language model\" : entry.name);\n return labels.join(\" › \");\n }\n\n private collectAncestorToolLabels(\n parentNodeId: string,\n entriesById: ReadonlyMap<string, AgentConnectionNodeDescriptor>,\n ): ReadonlyArray<string> {\n const labels: string[] = [];\n let currentNodeId = parentNodeId;\n while (true) {\n const parentEntry = entriesById.get(currentNodeId);\n if (!parentEntry) {\n return labels.reverse();\n }\n if (parentEntry.role === \"tool\" || parentEntry.role === \"nestedAgent\") {\n labels.push(parentEntry.name);\n }\n currentNodeId = parentEntry.parentNodeId;\n }\n }\n}\n","import type { CredentialFieldSchema, CredentialTypeDefinition } from \"@codemation/core\";\nimport { inject, injectable } from \"@codemation/core\";\n\nimport { ApplicationTokens } from \"../../applicationTokens\";\nimport type { AppConfig } from \"../../presentation/config/AppConfig\";\n\nimport type { JsonRecord } from \"./CredentialServices\";\n\n@injectable()\nexport class CredentialFieldEnvOverlayService {\n constructor(\n @inject(ApplicationTokens.AppConfig)\n private readonly appConfig: AppConfig,\n ) {}\n\n /** True when the field declares an env var and process.env has a non-empty string for it. */\n isFieldResolvedFromEnv(field: CredentialFieldSchema): boolean {\n const name = field.envVarName?.trim();\n if (!name) {\n return false;\n }\n const v = this.appConfig.env[name];\n return typeof v === \"string\" && v.length > 0;\n }\n\n apply(\n args: Readonly<{\n definition: CredentialTypeDefinition;\n publicConfig: JsonRecord;\n material: JsonRecord;\n }>,\n ): Readonly<{ resolvedPublicConfig: JsonRecord; resolvedMaterial: JsonRecord }> {\n const pub: Record<string, unknown> = { ...args.publicConfig };\n const mat: Record<string, unknown> = { ...args.material };\n for (const field of args.definition.publicFields ?? []) {\n const name = field.envVarName?.trim();\n if (!name) {\n continue;\n }\n const v = this.appConfig.env[name];\n if (typeof v === \"string\" && v.length > 0) {\n pub[field.key] = v;\n }\n }\n for (const field of args.definition.secretFields ?? []) {\n const name = field.envVarName?.trim();\n if (!name) {\n continue;\n }\n const v = this.appConfig.env[name];\n if (typeof v === \"string\" && v.length > 0) {\n mat[field.key] = v;\n }\n }\n return Object.freeze({\n resolvedPublicConfig: Object.freeze(pub),\n resolvedMaterial: Object.freeze(mat),\n });\n }\n}\n","/**\n * Thrown by {@link CredentialSecretCipher.decrypt} when the credential's stored\n * `encryptionKeyId` does not match the current master key's id.\n *\n * This indicates the `CODEMATION_CREDENTIALS_MASTER_KEY` environment variable has\n * been rotated since the credential was encrypted. The operator must re-bind the\n * affected credential (which re-encrypts it with the new key).\n *\n * See {@link docs/security-boundary.md} for the key rotation contract.\n */\nexport class CredentialKeyRotatedError extends Error {\n readonly storedKeyId: string;\n\n constructor(storedKeyId: string) {\n super(\n `Credential was encrypted with key \"${storedKeyId}\" but the current master key produces a different id. ` +\n `Re-bind the credential to re-encrypt it with the active key.`,\n );\n this.name = \"CredentialKeyRotatedError\";\n this.storedKeyId = storedKeyId;\n }\n}\n","import { createCipheriv, createDecipheriv, createHash, hkdfSync, randomBytes } from \"node:crypto\";\n\nimport { inject, injectable } from \"@codemation/core\";\n\nimport { ApplicationTokens } from \"../../applicationTokens\";\nimport type { AppConfig } from \"../../presentation/config/AppConfig\";\n\nimport type { JsonRecord } from \"./CredentialServices\";\nimport { CredentialKeyRotatedError } from \"./CredentialKeyRotatedError\";\n\n/**\n * Schema versions:\n * 1 — key = SHA-256(rawValue) (legacy, read-only support retained for migration)\n * 2 — key = HKDF-SHA-256(rawKey32Bytes, ...) (current)\n *\n * All new encryptions are written as v2. Existing v1 records can still be\n * decrypted so operators can re-encrypt at their own pace (re-bind the\n * credential in the UI, or run the one-shot re-encrypt script).\n */\n@injectable()\nexport class CredentialSecretCipher {\n private static readonly algorithm = \"aes-256-gcm\";\n private static readonly currentSchemaVersion = 2;\n private static readonly ivLength = 12;\n\n private static readonly HKDF_SALT = \"codemation/credential-cipher/v1\";\n private static readonly HKDF_INFO = \"aes-256-gcm-key\";\n\n constructor(\n @inject(ApplicationTokens.AppConfig)\n private readonly appConfig: AppConfig,\n ) {}\n\n encrypt(value: JsonRecord): Readonly<{\n encryptedJson: string;\n encryptionKeyId: string;\n schemaVersion: number;\n }> {\n const iv = randomBytes(CredentialSecretCipher.ivLength);\n const cipher = createCipheriv(CredentialSecretCipher.algorithm, this.resolveKeyMaterialV2(), iv);\n const plaintext = Buffer.from(JSON.stringify(value), \"utf8\");\n // eslint-disable-next-line codemation/no-buffer-everything -- AES-GCM credential cipher operates on bounded KB-sized JSON payloads; streaming crypto is not applicable here.\n const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);\n const authTag = cipher.getAuthTag();\n return {\n // eslint-disable-next-line codemation/no-buffer-everything -- AES-GCM credential cipher operates on bounded KB-sized JSON payloads; streaming crypto is not applicable here.\n encryptedJson: Buffer.concat([iv, authTag, encrypted]).toString(\"base64\"),\n encryptionKeyId: this.resolveKeyId(),\n schemaVersion: CredentialSecretCipher.currentSchemaVersion,\n };\n }\n\n decrypt(\n record: Readonly<{\n encryptedJson: string;\n encryptionKeyId: string;\n schemaVersion: number;\n }>,\n ): JsonRecord {\n // resolveKeyMaterialV2 / resolveKeyMaterialV1 both throw if env is missing\n // — that check must come before the key-id comparison.\n const keyMaterial = (record.schemaVersion ?? 1) >= 2 ? this.resolveKeyMaterialV2() : this.resolveKeyMaterialV1();\n\n const currentKeyId = this.resolveKeyId();\n if (record.encryptionKeyId !== currentKeyId) {\n throw new CredentialKeyRotatedError(record.encryptionKeyId);\n }\n // eslint-disable-next-line codemation/no-buffer-everything -- AES-GCM credential cipher operates on bounded KB-sized JSON payloads; streaming crypto is not applicable here.\n const packed = Buffer.from(record.encryptedJson, \"base64\");\n const iv = packed.subarray(0, CredentialSecretCipher.ivLength);\n const authTag = packed.subarray(CredentialSecretCipher.ivLength, CredentialSecretCipher.ivLength + 16);\n const encrypted = packed.subarray(CredentialSecretCipher.ivLength + 16);\n const decipher = createDecipheriv(CredentialSecretCipher.algorithm, keyMaterial, iv);\n decipher.setAuthTag(authTag);\n // eslint-disable-next-line codemation/no-buffer-everything -- AES-GCM credential cipher operates on bounded KB-sized JSON payloads; streaming crypto is not applicable here.\n const plaintext = Buffer.concat([decipher.update(encrypted), decipher.final()]).toString(\"utf8\");\n return JSON.parse(plaintext) as JsonRecord;\n }\n\n /**\n * Current (v2) key derivation: HKDF-SHA-256 with a fixed application salt and info label.\n * Input must be a base64-encoded 32-byte value (`CODEMATION_CREDENTIALS_MASTER_KEY`).\n */\n private resolveKeyMaterialV2(): Buffer {\n const ikm = this.resolveBase64Key32Bytes();\n return Buffer.from(\n hkdfSync(\n \"sha256\",\n ikm,\n Buffer.from(CredentialSecretCipher.HKDF_SALT, \"utf8\"),\n Buffer.from(CredentialSecretCipher.HKDF_INFO, \"utf8\"),\n 32,\n ),\n );\n }\n\n /**\n * Legacy (v1) key derivation: SHA-256 of the raw env string.\n * Retained for decrypt-side backward compatibility only.\n */\n private resolveKeyMaterialV1(): Buffer {\n const rawValue = this.appConfig.env.CODEMATION_CREDENTIALS_MASTER_KEY;\n if (!rawValue || rawValue.trim().length === 0) {\n throw new Error(\"CODEMATION_CREDENTIALS_MASTER_KEY is required to encrypt database-managed credentials.\");\n }\n return createHash(\"sha256\").update(rawValue).digest();\n }\n\n /**\n * Validates and returns the raw 32-byte key material from the env var.\n * Throws if the env var is absent or does not decode to exactly 32 bytes.\n */\n private resolveBase64Key32Bytes(): Buffer {\n const rawValue = this.appConfig.env.CODEMATION_CREDENTIALS_MASTER_KEY;\n if (!rawValue || rawValue.trim().length === 0) {\n throw new Error(\"CODEMATION_CREDENTIALS_MASTER_KEY is required to encrypt database-managed credentials.\");\n }\n // eslint-disable-next-line codemation/no-buffer-everything -- key material is always 32 bytes; bounded by validation below.\n const decoded = Buffer.from(rawValue.trim(), \"base64\");\n if (decoded.length !== 32) {\n throw new Error(\n `CODEMATION_CREDENTIALS_MASTER_KEY must be a base64-encoded 32-byte value (got ${decoded.length} bytes). ` +\n `Generate a valid key with: openssl rand -base64 32`,\n );\n }\n return decoded;\n }\n\n private resolveKeyId(): string {\n const rawValue = this.appConfig.env.CODEMATION_CREDENTIALS_MASTER_KEY;\n return createHash(\"sha256\")\n .update(rawValue ?? \"\")\n .digest(\"hex\")\n .slice(0, 12);\n }\n}\n","import { inject, injectable } from \"@codemation/core\";\n\nimport { ApplicationTokens } from \"../../applicationTokens\";\nimport type { AppConfig } from \"../../presentation/config/AppConfig\";\n\nimport { CredentialSecretCipher } from \"./CredentialSecretCipher\";\nimport type { CredentialInstanceRecord, CredentialStore, JsonRecord } from \"./CredentialServices\";\n\n@injectable()\nexport class CredentialMaterialResolver {\n constructor(\n @inject(ApplicationTokens.CredentialStore)\n private readonly credentialStore: CredentialStore,\n @inject(CredentialSecretCipher)\n private readonly credentialSecretCipher: CredentialSecretCipher,\n @inject(ApplicationTokens.AppConfig)\n private readonly appConfig: AppConfig,\n ) {}\n\n async resolveMaterial(instance: CredentialInstanceRecord): Promise<JsonRecord> {\n if (instance.secretRef.kind === \"db\") {\n const secretMaterial = await this.credentialStore.getSecretMaterial(instance.instanceId);\n if (!secretMaterial) {\n throw new Error(`Credential ${instance.instanceId} is missing encrypted secret material.`);\n }\n return this.credentialSecretCipher.decrypt(secretMaterial);\n }\n if (instance.secretRef.kind === \"env\") {\n return this.resolveEnvMaterial(instance);\n }\n return instance.secretRef.value;\n }\n\n private resolveEnvMaterial(instance: CredentialInstanceRecord): JsonRecord {\n if (instance.secretRef.kind !== \"env\") {\n throw new Error(`Credential ${instance.instanceId} is not environment-backed.`);\n }\n const resolved: Record<string, unknown> = {};\n const missingEnvironmentVariables: string[] = [];\n for (const [fieldKey, envVarName] of Object.entries(instance.secretRef.envByField)) {\n const value = this.appConfig.env[envVarName];\n if (value === undefined || value.length === 0) {\n missingEnvironmentVariables.push(envVarName);\n continue;\n }\n resolved[fieldKey] = value;\n }\n if (missingEnvironmentVariables.length > 0) {\n throw new Error(\n `Credential ${instance.instanceId} requires environment variables that are not set: ${missingEnvironmentVariables.join(\", \")}.`,\n );\n }\n return resolved;\n }\n}\n","import type { CredentialOAuth2AuthDefinition } from \"@codemation/core\";\nimport { injectable } from \"@codemation/core\";\nimport type { JsonRecord } from \"./CredentialServices\";\n\n@injectable()\nexport class CredentialOAuth2ScopeResolver {\n resolveRequestedScopes(auth: CredentialOAuth2AuthDefinition, publicConfig: JsonRecord): ReadonlyArray<string> {\n const scopesFromPublicConfig = auth.scopesFromPublicConfig;\n if (!scopesFromPublicConfig) {\n return [...auth.scopes];\n }\n const preset = this.resolveString(publicConfig[scopesFromPublicConfig.presetFieldKey]);\n if (!preset) {\n return [...auth.scopes];\n }\n const presetScopes = scopesFromPublicConfig.presetScopes[preset];\n if (presetScopes) {\n return [...presetScopes];\n }\n const customPresetKey = scopesFromPublicConfig.customPresetKey ?? \"custom\";\n if (preset !== customPresetKey) {\n return [...auth.scopes];\n }\n const customScopes = this.resolveScopeList(\n publicConfig[scopesFromPublicConfig.customScopesFieldKey ?? \"customScopes\"],\n );\n if (customScopes.length > 0) {\n return customScopes;\n }\n return [...auth.scopes];\n }\n\n private resolveString(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const normalized = value.trim();\n return normalized.length > 0 ? normalized : undefined;\n }\n\n private resolveScopeList(value: unknown): ReadonlyArray<string> {\n if (Array.isArray(value)) {\n return this.dedupe(\n value.map((entry) => (typeof entry === \"string\" ? entry.trim() : \"\")).filter((entry) => entry.length > 0),\n );\n }\n if (typeof value !== \"string\") {\n return [];\n }\n return this.dedupe(\n value\n .split(/[\\s,]+/)\n .map((entry) => entry.trim())\n .filter((entry) => entry.length > 0),\n );\n }\n\n private dedupe(entries: ReadonlyArray<string>): ReadonlyArray<string> {\n return [...new Set(entries)];\n }\n}\n","import { randomUUID } from \"node:crypto\";\n\nimport type {\n CredentialFieldSchema,\n CredentialInstanceId,\n CredentialMaterialSourceKind,\n CredentialTypeId,\n} from \"@codemation/core\";\n\nimport { CoreTokens, inject, injectable } from \"@codemation/core\";\n\nimport { ApplicationRequestError } from \"../../application/ApplicationRequestError\";\n\nimport type {\n CreateCredentialInstanceRequest,\n CredentialInstanceDto,\n CredentialInstanceWithSecretsDto,\n CredentialOAuth2ConnectionDto,\n UpdateCredentialInstanceRequest,\n} from \"../../application/contracts/CredentialContractsRegistry\";\n\nimport { ApplicationTokens } from \"../../applicationTokens\";\n\nimport { CredentialFieldEnvOverlayService } from \"./CredentialFieldEnvOverlayService\";\nimport { CredentialMaterialResolver } from \"./CredentialMaterialResolver\";\nimport { CredentialOAuth2ScopeResolver } from \"./CredentialOAuth2ScopeResolver\";\nimport { CredentialSecretCipher } from \"./CredentialSecretCipher\";\nimport type {\n CredentialInstanceRecord,\n CredentialSecretMaterialRecord,\n CredentialSecretRef,\n CredentialStore,\n CredentialTestRecord,\n AnyCredentialType,\n JsonRecord,\n MutableCredentialSessionService,\n} from \"./CredentialServices\";\nimport { CredentialTypeRegistryImpl } from \"./CredentialServices\";\n\n@injectable()\nexport class CredentialInstanceService {\n constructor(\n @inject(ApplicationTokens.CredentialStore)\n private readonly credentialStore: CredentialStore,\n @inject(CredentialTypeRegistryImpl)\n private readonly credentialTypeRegistry: CredentialTypeRegistryImpl,\n @inject(CredentialSecretCipher)\n private readonly credentialSecretCipher: CredentialSecretCipher,\n @inject(CredentialFieldEnvOverlayService)\n private readonly credentialFieldEnvOverlayService: CredentialFieldEnvOverlayService,\n @inject(CredentialMaterialResolver)\n private readonly credentialMaterialResolver: CredentialMaterialResolver,\n @inject(CredentialOAuth2ScopeResolver)\n private readonly credentialOAuth2ScopeResolver: CredentialOAuth2ScopeResolver,\n @inject(CoreTokens.CredentialSessionService)\n private readonly credentialSessionService: MutableCredentialSessionService,\n ) {}\n\n async listInstances(): Promise<ReadonlyArray<CredentialInstanceDto>> {\n const instances = await this.credentialStore.listInstances();\n const latestTestResults = await this.credentialStore.getLatestTestResults(\n instances.map((instance) => instance.instanceId),\n );\n return await Promise.all(\n instances.map(async (instance) => await this.toDto(instance, latestTestResults.get(instance.instanceId))),\n );\n }\n\n async getInstance(instanceId: CredentialInstanceId): Promise<CredentialInstanceDto | undefined> {\n const instance = await this.credentialStore.getInstance(instanceId);\n if (!instance) {\n return undefined;\n }\n const latestTestResult = await this.credentialStore.getLatestTestResult(instanceId);\n return await this.toDto(instance, latestTestResult);\n }\n\n async getInstanceWithSecrets(\n instanceId: CredentialInstanceId,\n ): Promise<CredentialInstanceWithSecretsDto | undefined> {\n const instance = await this.credentialStore.getInstance(instanceId);\n if (!instance) {\n return undefined;\n }\n const latestTestResult = await this.credentialStore.getLatestTestResult(instanceId);\n const base = await this.toDto(instance, latestTestResult);\n try {\n const material = await this.credentialMaterialResolver.resolveMaterial(instance);\n const secretConfig = Object.fromEntries(Object.entries(material).map(([k, v]) => [k, String(v ?? \"\")])) as Record<\n string,\n string\n >;\n const envSecretRefs =\n instance.secretRef.kind === \"env\" ? (instance.secretRef.envByField as Record<string, string>) : undefined;\n return { ...base, secretConfig, envSecretRefs };\n } catch {\n return base;\n }\n }\n\n async create(request: CreateCredentialInstanceRequest): Promise<CredentialInstanceDto> {\n const credentialType = this.requireCredentialType(request.typeId);\n const publicFields = credentialType.definition.publicFields ?? [];\n const secretFields = credentialType.definition.secretFields ?? [];\n this.validateRequestFields({\n displayName: request.displayName,\n publicFields,\n publicConfig: request.publicConfig ?? {},\n secretFields,\n sourceKind: request.sourceKind,\n secretConfig: request.secretConfig ?? {},\n envSecretRefs: request.envSecretRefs ?? {},\n });\n const timestamp = new Date().toISOString();\n const strippedPublic = this.stripEnvManagedFieldValues(publicFields, request.publicConfig ?? {});\n const strippedSecretForRef = this.stripEnvManagedFieldValues(secretFields, request.secretConfig ?? {});\n const instanceId = randomUUID();\n const instance: CredentialInstanceRecord = {\n instanceId,\n typeId: request.typeId,\n displayName: request.displayName.trim(),\n sourceKind: request.sourceKind,\n publicConfig: Object.freeze({ ...strippedPublic }),\n secretRef: this.createSecretRef(request.sourceKind, strippedSecretForRef, request.envSecretRefs ?? {}),\n tags: Object.freeze([...(request.tags ?? [])]),\n setupStatus: credentialType.definition.auth?.kind === \"oauth2\" ? \"draft\" : \"ready\",\n createdAt: timestamp,\n updatedAt: timestamp,\n // New instances are local-mode by default. The CP material provider sets\n // source=\"control-plane\" when managed mode is detected.\n material: { source: \"local\", ref: instanceId },\n };\n await this.credentialStore.saveInstance({\n instance,\n secretMaterial: this.createSecretMaterial(instance, strippedSecretForRef, timestamp),\n });\n this.credentialSessionService.evictInstance(instance.instanceId);\n return this.toDto(instance, undefined);\n }\n\n async update(\n instanceId: CredentialInstanceId,\n request: UpdateCredentialInstanceRequest,\n ): Promise<CredentialInstanceDto> {\n const existing = await this.requireInstance(instanceId);\n const credentialType = this.requireCredentialType(existing.typeId);\n const mergedPublicRaw = { ...(request.publicConfig ?? existing.publicConfig) };\n const updatedAt = new Date().toISOString();\n const nextSecretConfig = request.secretConfig;\n const nextEnvSecretRefs = request.envSecretRefs;\n const secretFields = credentialType.definition.secretFields ?? [];\n this.validateRequestFields({\n displayName: request.displayName ?? existing.displayName,\n publicFields: credentialType.definition.publicFields ?? [],\n publicConfig: mergedPublicRaw,\n secretFields,\n sourceKind: existing.sourceKind,\n secretConfig: nextSecretConfig ?? {},\n envSecretRefs: nextEnvSecretRefs ?? {},\n allowSecretOmission: true,\n });\n const publicConfig = Object.freeze({\n ...this.stripEnvManagedFieldValues(credentialType.definition.publicFields ?? [], mergedPublicRaw),\n });\n const mergedSecretForRef =\n nextSecretConfig !== undefined ? this.stripEnvManagedFieldValues(secretFields, nextSecretConfig) : undefined;\n const instance: CredentialInstanceRecord = {\n ...existing,\n displayName: request.displayName?.trim() || existing.displayName,\n publicConfig,\n tags: Object.freeze([...(request.tags ?? existing.tags)]),\n setupStatus: request.setupStatus ?? existing.setupStatus,\n secretRef:\n nextSecretConfig || nextEnvSecretRefs\n ? this.createSecretRef(existing.sourceKind, mergedSecretForRef ?? {}, nextEnvSecretRefs ?? {})\n : existing.secretRef,\n updatedAt,\n };\n await this.credentialStore.saveInstance({\n instance,\n secretMaterial:\n nextSecretConfig !== undefined && mergedSecretForRef !== undefined\n ? this.createSecretMaterial(instance, mergedSecretForRef, updatedAt)\n : undefined,\n });\n this.credentialSessionService.evictInstance(instance.instanceId);\n return this.toDto(instance, await this.credentialStore.getLatestTestResult(instance.instanceId));\n }\n\n async delete(instanceId: CredentialInstanceId): Promise<void> {\n await this.credentialStore.deleteInstance(instanceId);\n this.credentialSessionService.evictInstance(instanceId);\n }\n\n async disconnectOAuth2(instanceId: CredentialInstanceId): Promise<CredentialInstanceDto> {\n const instance = await this.requireInstance(instanceId);\n const credentialType = this.requireCredentialType(instance.typeId);\n if (credentialType.definition.auth?.kind !== \"oauth2\") {\n throw new ApplicationRequestError(400, `Credential instance ${instanceId} does not use OAuth2.`);\n }\n const updatedInstance: CredentialInstanceRecord = {\n ...instance,\n setupStatus: \"draft\",\n updatedAt: new Date().toISOString(),\n };\n await this.credentialStore.saveInstance({\n instance: updatedInstance,\n });\n await this.credentialStore.deleteOAuth2Material(instanceId);\n this.credentialSessionService.evictInstance(instanceId);\n return await this.toDto(updatedInstance, await this.credentialStore.getLatestTestResult(instanceId));\n }\n\n async requireInstance(instanceId: CredentialInstanceId): Promise<CredentialInstanceRecord> {\n const instance = await this.credentialStore.getInstance(instanceId);\n if (!instance) {\n throw new ApplicationRequestError(404, `Unknown credential instance: ${instanceId}`);\n }\n return instance;\n }\n\n private createSecretRef(\n sourceKind: CredentialMaterialSourceKind,\n secretConfig: JsonRecord,\n envSecretRefs: Readonly<Record<string, string>>,\n ): CredentialSecretRef {\n if (sourceKind === \"db\") {\n return { kind: \"db\" };\n }\n if (sourceKind === \"env\") {\n return {\n kind: \"env\",\n envByField: Object.freeze({ ...envSecretRefs }),\n };\n }\n return {\n kind: \"code\",\n value: Object.freeze({ ...secretConfig }),\n };\n }\n\n private createSecretMaterial(\n instance: CredentialInstanceRecord,\n secretConfig: JsonRecord,\n updatedAt: string,\n ): CredentialSecretMaterialRecord | undefined {\n if (instance.sourceKind !== \"db\") {\n return undefined;\n }\n const encrypted = this.credentialSecretCipher.encrypt(secretConfig);\n return {\n instanceId: instance.instanceId,\n encryptedJson: encrypted.encryptedJson,\n encryptionKeyId: encrypted.encryptionKeyId,\n schemaVersion: encrypted.schemaVersion,\n updatedAt,\n };\n }\n\n private validateRequestFields(\n args: Readonly<{\n displayName: string;\n publicFields: ReadonlyArray<CredentialFieldSchema>;\n publicConfig: JsonRecord;\n secretFields: ReadonlyArray<CredentialFieldSchema>;\n sourceKind: CredentialMaterialSourceKind;\n secretConfig: JsonRecord;\n envSecretRefs: Readonly<Record<string, string>>;\n allowSecretOmission?: boolean;\n }>,\n ): void {\n if (!args.displayName || args.displayName.trim().length === 0) {\n throw new ApplicationRequestError(400, \"Credential displayName is required.\");\n }\n this.assertRequiredFields(\"publicConfig\", args.publicFields, args.publicConfig);\n if (args.sourceKind === \"db\") {\n if (!args.allowSecretOmission || Object.keys(args.secretConfig).length > 0) {\n this.assertRequiredFields(\"secretConfig\", args.secretFields, args.secretConfig);\n }\n return;\n }\n if (args.sourceKind === \"env\") {\n if (!args.allowSecretOmission || Object.keys(args.envSecretRefs).length > 0) {\n this.assertRequiredEnvFields(args.secretFields, args.envSecretRefs);\n }\n return;\n }\n if (!args.allowSecretOmission || Object.keys(args.secretConfig).length > 0) {\n this.assertRequiredFields(\"secretConfig\", args.secretFields, args.secretConfig);\n }\n }\n\n private stripEnvManagedFieldValues(fields: ReadonlyArray<CredentialFieldSchema>, value: JsonRecord): JsonRecord {\n const out: Record<string, unknown> = { ...value };\n for (const field of fields) {\n if (this.credentialFieldEnvOverlayService.isFieldResolvedFromEnv(field)) {\n delete out[field.key];\n }\n }\n return Object.freeze(out);\n }\n\n private assertRequiredFields(\n fieldName: string,\n schema: ReadonlyArray<CredentialFieldSchema>,\n value: JsonRecord,\n ): void {\n const missing = schema\n .filter((field) => field.required === true)\n .filter((field) => !this.credentialFieldEnvOverlayService.isFieldResolvedFromEnv(field))\n .filter((field) => value[field.key] === undefined || value[field.key] === null || value[field.key] === \"\")\n .map((field) => field.key);\n if (missing.length > 0) {\n throw new ApplicationRequestError(400, `Missing required ${fieldName} field(s): ${missing.join(\", \")}`);\n }\n }\n\n private assertRequiredEnvFields(\n schema: ReadonlyArray<CredentialFieldSchema>,\n envSecretRefs: Readonly<Record<string, string>>,\n ): void {\n const missing = schema\n .filter((field) => field.required === true)\n .filter((field) => !this.credentialFieldEnvOverlayService.isFieldResolvedFromEnv(field))\n .filter((field) => !envSecretRefs[field.key] || envSecretRefs[field.key]!.trim().length === 0)\n .map((field) => field.key);\n if (missing.length > 0) {\n throw new ApplicationRequestError(400, `Missing required envSecretRefs field(s): ${missing.join(\", \")}`);\n }\n }\n\n private requireCredentialType(typeId: CredentialTypeId): AnyCredentialType {\n const credentialType = this.credentialTypeRegistry.getCredentialType(typeId);\n if (!credentialType) {\n throw new ApplicationRequestError(400, `Unknown credential type: ${typeId}`);\n }\n return credentialType;\n }\n\n async markOAuth2Connected(instanceId: CredentialInstanceId, connectedAt: string): Promise<void> {\n const instance = await this.requireInstance(instanceId);\n await this.credentialStore.saveInstance({\n instance: {\n ...instance,\n setupStatus: \"ready\",\n updatedAt: connectedAt,\n },\n });\n this.credentialSessionService.evictInstance(instanceId);\n }\n\n private async toDto(\n instance: CredentialInstanceRecord,\n latestTestResult: CredentialTestRecord | undefined,\n ): Promise<CredentialInstanceDto> {\n const oauth2Connection = await this.toOAuth2ConnectionDto(instance);\n return {\n instanceId: instance.instanceId,\n typeId: instance.typeId,\n displayName: instance.displayName,\n sourceKind: instance.sourceKind,\n publicConfig: instance.publicConfig,\n tags: instance.tags,\n setupStatus: instance.setupStatus,\n createdAt: instance.createdAt,\n updatedAt: instance.updatedAt,\n latestHealth: latestTestResult?.health,\n oauth2Connection,\n };\n }\n\n private async toOAuth2ConnectionDto(\n instance: CredentialInstanceRecord,\n ): Promise<CredentialOAuth2ConnectionDto | undefined> {\n const credentialType = this.credentialTypeRegistry.getCredentialType(instance.typeId);\n if (credentialType?.definition.auth?.kind !== \"oauth2\") {\n return undefined;\n }\n const providerId =\n \"providerId\" in credentialType.definition.auth ? credentialType.definition.auth.providerId : \"custom\";\n const material = await this.credentialStore.getOAuth2Material(instance.instanceId);\n if (!material) {\n const requestedScopes = this.credentialOAuth2ScopeResolver.resolveRequestedScopes(\n credentialType.definition.auth,\n instance.publicConfig,\n );\n return {\n status: \"disconnected\",\n providerId,\n scopes: [...requestedScopes],\n };\n }\n return {\n status: \"connected\",\n providerId: material.providerId,\n connectedEmail: material.connectedEmail,\n connectedAt: material.connectedAt,\n scopes: material.scopes,\n updatedAt: material.updatedAt,\n };\n }\n}\n","import type {\n CredentialBinding,\n CredentialBindingKey,\n CredentialInstanceId,\n CredentialRequirement,\n WorkflowDefinition,\n WorkflowRepository,\n} from \"@codemation/core\";\n\nimport { CoreTokens, CredentialUnboundError, inject, injectable } from \"@codemation/core\";\n\nimport { ApplicationRequestError } from \"../../application/ApplicationRequestError\";\n\nimport type {\n WorkflowCredentialHealthDto,\n WorkflowCredentialHealthSlotDto,\n} from \"../../application/contracts/CredentialContractsRegistry\";\n\nimport { ApplicationTokens } from \"../../applicationTokens\";\nimport type { Logger, LoggerFactory } from \"../../application/logging/Logger\";\n\nimport { WorkflowCredentialNodeResolver } from \"./WorkflowCredentialNodeResolver\";\nimport { CredentialInstanceService } from \"./CredentialInstanceService\";\nimport type { CredentialStore, MutableCredentialSessionService } from \"./CredentialServices\";\n\n@injectable()\nexport class CredentialBindingService {\n private readonly logger: Logger;\n\n constructor(\n @inject(ApplicationTokens.CredentialStore)\n private readonly credentialStore: CredentialStore,\n @inject(CredentialInstanceService)\n private readonly credentialInstanceService: CredentialInstanceService,\n @inject(CoreTokens.WorkflowRepository)\n private readonly workflowRepository: WorkflowRepository,\n @inject(CoreTokens.CredentialSessionService)\n private readonly credentialSessionService: MutableCredentialSessionService,\n @inject(WorkflowCredentialNodeResolver)\n private readonly workflowCredentialNodeResolver: WorkflowCredentialNodeResolver,\n @inject(ApplicationTokens.LoggerFactory)\n loggerFactory: LoggerFactory,\n ) {\n this.logger = loggerFactory.create(\"CredentialBindingService\");\n }\n\n async upsertBinding(\n args: Readonly<{ workflowId: string; nodeId: string; slotKey: string; instanceId: CredentialInstanceId }>,\n ): Promise<CredentialBinding> {\n const workflow = this.requireWorkflow(args.workflowId);\n const requirement = this.requireRequirement(workflow, args.nodeId, args.slotKey);\n const instance = await this.credentialInstanceService.requireInstance(args.instanceId);\n if (!requirement.acceptedTypes.includes(instance.typeId)) {\n throw new ApplicationRequestError(\n 400,\n `Credential instance ${instance.instanceId} (${instance.typeId}) is not compatible with slot ${args.slotKey}. Accepted types: ${requirement.acceptedTypes.join(\", \")}`,\n );\n }\n const binding: CredentialBinding = {\n key: {\n workflowId: args.workflowId,\n nodeId: args.nodeId,\n slotKey: args.slotKey,\n },\n instanceId: args.instanceId,\n updatedAt: new Date().toISOString(),\n };\n await this.credentialStore.upsertBinding(binding);\n this.credentialSessionService.evictBinding(binding.key);\n return binding;\n }\n\n async assertRequiredCredentialsBound(workflowId: string): Promise<void> {\n const workflow = this.requireWorkflow(workflowId);\n const bindings = await this.credentialStore.listBindingsByWorkflowId(workflowId);\n const boundKeys = new Set(bindings.map((b) => this.toBindingKeyString(b.key)));\n const unboundByDb = this.workflowCredentialNodeResolver\n .listSlots(workflow)\n .filter((slot) => !slot.requirement.optional)\n .filter(\n (slot) =>\n !boundKeys.has(\n this.toBindingKeyString({ workflowId, nodeId: slot.nodeId, slotKey: slot.requirement.slotKey }),\n ),\n );\n if (unboundByDb.length === 0) return;\n // Confirm each apparently-unbound slot by attempting session resolution. A custom\n // CredentialSessionService (e.g. a test harness) can satisfy slots that have no DB\n // binding row; only slots that still fail are truly unresolvable.\n const confirmed = [];\n for (const slot of unboundByDb) {\n try {\n await this.credentialSessionService.getSession({\n workflowId,\n nodeId: slot.nodeId,\n slotKey: slot.requirement.slotKey,\n });\n } catch (error) {\n if (!(error instanceof CredentialUnboundError)) {\n this.logger.debug(\n `CredentialBindingService: unexpected error resolving session for slot ${slot.requirement.slotKey} on ${slot.nodeId}`,\n error instanceof Error ? error : undefined,\n );\n }\n confirmed.push(slot);\n }\n }\n if (confirmed.length === 0) return;\n const descriptions = confirmed\n .map((slot) => `\"${slot.requirement.label}\" on ${slot.nodeName ?? slot.nodeId}`)\n .join(\", \");\n throw new ApplicationRequestError(\n 400,\n `Cannot run workflow: required credential slot${confirmed.length > 1 ? \"s\" : \"\"} not bound: ${descriptions}`,\n );\n }\n\n async listWorkflowHealth(workflowId: string): Promise<WorkflowCredentialHealthDto> {\n const workflow = this.requireWorkflow(workflowId);\n const bindings = await this.credentialStore.listBindingsByWorkflowId(workflowId);\n const bindingsByKey = new Map(bindings.map((binding) => [this.toBindingKeyString(binding.key), binding] as const));\n const slots: WorkflowCredentialHealthSlotDto[] = [];\n for (const slotRef of this.workflowCredentialNodeResolver.listSlots(workflow)) {\n const requirement = slotRef.requirement;\n const bindingKey = {\n workflowId,\n nodeId: slotRef.nodeId,\n slotKey: requirement.slotKey,\n } satisfies CredentialBindingKey;\n const binding = bindingsByKey.get(this.toBindingKeyString(bindingKey));\n if (!binding) {\n slots.push({\n workflowId,\n nodeId: slotRef.nodeId,\n nodeName: slotRef.nodeName,\n requirement,\n health: {\n status: requirement.optional ? \"optional-unbound\" : \"unbound\",\n },\n });\n continue;\n }\n const instance = await this.credentialInstanceService.requireInstance(binding.instanceId);\n const latestTestResult = await this.credentialStore.getLatestTestResult(instance.instanceId);\n slots.push({\n workflowId,\n nodeId: slotRef.nodeId,\n nodeName: slotRef.nodeName,\n requirement,\n instance: {\n instanceId: instance.instanceId,\n typeId: instance.typeId,\n displayName: instance.displayName,\n setupStatus: instance.setupStatus,\n },\n health: {\n status: latestTestResult?.health.status ?? \"unknown\",\n message: latestTestResult?.health.message,\n testedAt: latestTestResult?.health.testedAt,\n },\n });\n }\n return {\n workflowId,\n slots,\n };\n }\n\n private requireWorkflow(workflowId: string): WorkflowDefinition {\n const workflow = this.workflowRepository.get(decodeURIComponent(workflowId));\n if (!workflow) {\n throw new ApplicationRequestError(404, `Unknown workflowId: ${workflowId}`);\n }\n return workflow;\n }\n\n private requireRequirement(workflow: WorkflowDefinition, nodeId: string, slotKey: string): CredentialRequirement {\n const resolved = this.workflowCredentialNodeResolver.findRequirement(workflow, nodeId, slotKey);\n if (!resolved) {\n if (!this.workflowCredentialNodeResolver.isCredentialNodeIdInWorkflow(workflow, nodeId)) {\n throw new ApplicationRequestError(404, `Unknown workflow node: ${nodeId}`);\n }\n throw new ApplicationRequestError(400, `Node ${nodeId} does not declare credential slot ${slotKey}.`);\n }\n return resolved.requirement;\n }\n\n private toBindingKeyString(bindingKey: CredentialBindingKey): string {\n return `${bindingKey.workflowId}:${bindingKey.nodeId}:${bindingKey.slotKey}`;\n }\n}\n","import { inject, injectable } from \"@codemation/core\";\n\nimport { ApplicationTokens } from \"../../applicationTokens\";\n\nimport { CredentialMaterialResolver } from \"./CredentialMaterialResolver\";\nimport { CredentialSecretCipher } from \"./CredentialSecretCipher\";\nimport type { CredentialInstanceRecord, CredentialStore, JsonRecord } from \"./CredentialServices\";\nimport { CredentialTypeRegistryImpl } from \"./CredentialServices\";\n\n@injectable()\nexport class CredentialRuntimeMaterialService {\n constructor(\n @inject(ApplicationTokens.CredentialStore)\n private readonly credentialStore: CredentialStore,\n @inject(CredentialMaterialResolver)\n private readonly credentialMaterialResolver: CredentialMaterialResolver,\n @inject(CredentialSecretCipher)\n private readonly credentialSecretCipher: CredentialSecretCipher,\n @inject(CredentialTypeRegistryImpl)\n private readonly credentialTypeRegistry: CredentialTypeRegistryImpl,\n ) {}\n\n async compose(instance: CredentialInstanceRecord): Promise<JsonRecord> {\n const baseMaterial = await this.credentialMaterialResolver.resolveMaterial(instance);\n const auth = this.credentialTypeRegistry.getCredentialType(instance.typeId)?.definition.auth;\n if (auth?.kind !== \"oauth2\") {\n return baseMaterial;\n }\n const oauth2Material = await this.credentialStore.getOAuth2Material(instance.instanceId);\n if (!oauth2Material) {\n return baseMaterial;\n }\n const decryptedOauth2Material = this.credentialSecretCipher.decrypt(oauth2Material);\n return Object.freeze({\n ...baseMaterial,\n ...decryptedOauth2Material,\n });\n }\n}\n","import type {\n CredentialBindingKey,\n CredentialInstanceId,\n CredentialSessionService,\n WorkflowRepository,\n} from \"@codemation/core\";\n\nimport { CoreTokens, CredentialUnboundError, inject, injectable } from \"@codemation/core\";\n\nimport { ApplicationRequestError } from \"../../application/ApplicationRequestError\";\n\nimport { ApplicationTokens } from \"../../applicationTokens\";\n\nimport { WorkflowCredentialNodeResolver } from \"./WorkflowCredentialNodeResolver\";\nimport { CredentialFieldEnvOverlayService } from \"./CredentialFieldEnvOverlayService\";\nimport { CredentialRuntimeMaterialService } from \"./CredentialRuntimeMaterialService\";\nimport type { CredentialStore } from \"./CredentialServices\";\nimport { CredentialTypeRegistryImpl } from \"./CredentialServices\";\n\n@injectable()\nexport class CredentialSessionServiceImpl implements CredentialSessionService {\n private readonly cachedSessionsByInstanceId = new Map<CredentialInstanceId, Promise<unknown>>();\n private readonly cachedInstanceIdsByBindingKey = new Map<string, CredentialInstanceId>();\n\n constructor(\n @inject(ApplicationTokens.CredentialStore)\n private readonly credentialStore: CredentialStore,\n @inject(CredentialRuntimeMaterialService)\n private readonly credentialRuntimeMaterialService: CredentialRuntimeMaterialService,\n @inject(CredentialFieldEnvOverlayService)\n private readonly credentialFieldEnvOverlayService: CredentialFieldEnvOverlayService,\n @inject(CredentialTypeRegistryImpl)\n private readonly credentialTypeRegistry: CredentialTypeRegistryImpl,\n @inject(CoreTokens.WorkflowRepository)\n private readonly workflowRepository: WorkflowRepository,\n @inject(WorkflowCredentialNodeResolver)\n private readonly workflowCredentialNodeResolver: WorkflowCredentialNodeResolver,\n ) {}\n\n async getSession<TSession = unknown>(\n args: Readonly<{ workflowId: string; nodeId: string; slotKey: string }>,\n ): Promise<TSession> {\n const workflow = this.workflowRepository.get(decodeURIComponent(args.workflowId));\n const displayLabel = workflow\n ? this.workflowCredentialNodeResolver.describeCredentialNodeDisplay(workflow, args.nodeId)\n : undefined;\n const requirement = workflow\n ? this.workflowCredentialNodeResolver.findRequirement(workflow, args.nodeId, args.slotKey)?.requirement\n : undefined;\n const bindingKey: CredentialBindingKey = {\n workflowId: args.workflowId,\n nodeId: args.nodeId,\n slotKey: args.slotKey,\n };\n const binding = await this.credentialStore.getBinding(bindingKey);\n if (!binding) {\n const unbound = new CredentialUnboundError(bindingKey, requirement?.acceptedTypes ?? []);\n if (displayLabel) {\n throw new Error(`${displayLabel}: ${unbound.message}`, { cause: unbound });\n }\n throw unbound;\n }\n const bindingCacheKey = this.toBindingKeyString(bindingKey);\n this.cachedInstanceIdsByBindingKey.set(bindingCacheKey, binding.instanceId);\n const cachedSession = this.cachedSessionsByInstanceId.get(binding.instanceId);\n if (cachedSession) {\n return (await cachedSession) as TSession;\n }\n const nextSessionPromise = this.createSession(binding.instanceId, displayLabel).catch((error) => {\n this.cachedSessionsByInstanceId.delete(binding.instanceId);\n throw error;\n });\n this.cachedSessionsByInstanceId.set(binding.instanceId, nextSessionPromise);\n return (await nextSessionPromise) as TSession;\n }\n\n evictInstance(instanceId: CredentialInstanceId): void {\n this.cachedSessionsByInstanceId.delete(instanceId);\n }\n\n evictBinding(bindingKey: CredentialBindingKey): void {\n const cacheKey = this.toBindingKeyString(bindingKey);\n const instanceId = this.cachedInstanceIdsByBindingKey.get(cacheKey);\n if (instanceId) {\n this.cachedSessionsByInstanceId.delete(instanceId);\n }\n this.cachedInstanceIdsByBindingKey.delete(cacheKey);\n }\n\n private async createSession(instanceId: CredentialInstanceId, displayLabel?: string): Promise<unknown> {\n const instance = await this.credentialStore.getInstance(instanceId);\n if (!instance) {\n throw new ApplicationRequestError(404, `Unknown credential instance: ${instanceId}`);\n }\n const credentialType = this.credentialTypeRegistry.getCredentialType(instance.typeId);\n if (!credentialType) {\n const prefix = displayLabel ? `${displayLabel}: ` : \"\";\n throw new ApplicationRequestError(\n 400,\n `${prefix}Credential type \"${instance.typeId}\" is not registered in this runtime (binding points at an unknown type).`,\n );\n }\n const material = await this.credentialRuntimeMaterialService.compose(instance);\n const { resolvedPublicConfig, resolvedMaterial } = this.credentialFieldEnvOverlayService.apply({\n definition: credentialType.definition,\n publicConfig: instance.publicConfig,\n material,\n });\n return await credentialType.createSession({\n instance,\n material: resolvedMaterial,\n publicConfig: resolvedPublicConfig,\n });\n }\n\n private toBindingKeyString(bindingKey: CredentialBindingKey): string {\n return `${bindingKey.workflowId}:${bindingKey.nodeId}:${bindingKey.slotKey}`;\n }\n}\n","import { randomUUID } from \"node:crypto\";\n\nimport type { CredentialHealth, CredentialInstanceId, CredentialTypeId } from \"@codemation/core\";\n\nimport { CoreTokens, inject, injectable } from \"@codemation/core\";\n\nimport { ApplicationRequestError } from \"../../application/ApplicationRequestError\";\n\nimport { ApplicationTokens } from \"../../applicationTokens\";\n\nimport { CredentialFieldEnvOverlayService } from \"./CredentialFieldEnvOverlayService\";\nimport { CredentialInstanceService } from \"./CredentialInstanceService\";\nimport { CredentialRuntimeMaterialService } from \"./CredentialRuntimeMaterialService\";\nimport type { CredentialStore, AnyCredentialType, MutableCredentialSessionService } from \"./CredentialServices\";\nimport { CredentialTypeRegistryImpl } from \"./CredentialServices\";\n\n@injectable()\nexport class CredentialTestService {\n constructor(\n @inject(CredentialInstanceService)\n private readonly credentialInstanceService: CredentialInstanceService,\n @inject(CredentialRuntimeMaterialService)\n private readonly credentialRuntimeMaterialService: CredentialRuntimeMaterialService,\n @inject(CredentialFieldEnvOverlayService)\n private readonly credentialFieldEnvOverlayService: CredentialFieldEnvOverlayService,\n @inject(CredentialTypeRegistryImpl)\n private readonly credentialTypeRegistry: CredentialTypeRegistryImpl,\n @inject(ApplicationTokens.CredentialStore)\n private readonly credentialStore: CredentialStore,\n @inject(CoreTokens.CredentialSessionService)\n private readonly credentialSessionService: MutableCredentialSessionService,\n ) {}\n\n async test(instanceId: CredentialInstanceId): Promise<CredentialHealth> {\n const instance = await this.credentialInstanceService.requireInstance(instanceId);\n const credentialType = this.requireCredentialType(instance.typeId);\n const material = await this.credentialRuntimeMaterialService.compose(instance);\n const { resolvedPublicConfig, resolvedMaterial } = this.credentialFieldEnvOverlayService.apply({\n definition: credentialType.definition,\n publicConfig: instance.publicConfig,\n material,\n });\n const health = await credentialType.test({\n instance,\n material: resolvedMaterial,\n publicConfig: resolvedPublicConfig,\n });\n const testedAt = health.testedAt ?? new Date().toISOString();\n await this.credentialStore.saveTestResult({\n testId: randomUUID(),\n instanceId,\n health: {\n ...health,\n testedAt,\n },\n testedAt,\n expiresAt: health.expiresAt,\n });\n this.credentialSessionService.evictInstance(instanceId);\n return {\n ...health,\n testedAt,\n };\n }\n\n private requireCredentialType(typeId: CredentialTypeId): AnyCredentialType {\n const credentialType = this.credentialTypeRegistry.getCredentialType(typeId);\n if (!credentialType) {\n throw new ApplicationRequestError(400, `Unknown credential type: ${typeId}`);\n }\n return credentialType;\n }\n}\n"],"mappings":"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"}
@@ -9,10 +9,11 @@ const PairingConfigToken = Symbol.for("codemation.pairing.PairingConfig");
9
9
  //#endregion
10
10
  //#region src/pairing/HmacRequestSigner.ts
11
11
  let HmacRequestSigner = class HmacRequestSigner$1 {
12
- constructor(config) {
12
+ constructor(config = null) {
13
13
  this.config = config;
14
14
  }
15
15
  sign(method, urlOrPath, body) {
16
+ if (this.config === null) throw new Error("HmacRequestSigner.sign called without a registered PairingConfig — workspace is not in managed mode.");
16
17
  const ts = Math.floor(Date.now() / 1e3);
17
18
  const nonce = randomBytes(16).toString("base64");
18
19
  const parsed = new URL(urlOrPath, "http://placeholder");
@@ -31,7 +32,7 @@ let HmacRequestSigner = class HmacRequestSigner$1 {
31
32
  };
32
33
  HmacRequestSigner = __decorate([
33
34
  injectable(),
34
- __decorateParam(0, inject(PairingConfigToken)),
35
+ __decorateParam(0, inject(PairingConfigToken, { isOptional: true })),
35
36
  __decorateMetadata("design:paramtypes", [Object])
36
37
  ], HmacRequestSigner);
37
38
 
@@ -104,15 +105,20 @@ var PairingConfigFactory = class {
104
105
  }
105
106
  };
106
107
 
108
+ //#endregion
109
+ //#region src/pairing/HmacNonceStoreToken.ts
110
+ const HmacNonceStoreToken = Symbol.for("codemation.pairing.HmacNonceStore");
111
+
107
112
  //#endregion
108
113
  //#region src/pairing/IncomingHmacVerifier.ts
109
114
  let IncomingHmacVerifier = class IncomingHmacVerifier$1 {
110
- usedNonces = /* @__PURE__ */ new Map();
111
115
  nonceTtlSeconds = 600;
112
- constructor(config) {
116
+ constructor(config = null, nonceStore) {
113
117
  this.config = config;
118
+ this.nonceStore = nonceStore;
114
119
  }
115
- verify(method, url, body, authHeader) {
120
+ async verify(method, url, body, authHeader) {
121
+ if (this.config === null) throw new Error("IncomingHmacVerifier.verify called without a registered PairingConfig — workspace is not in managed mode.");
116
122
  if (!this.config.pairingSecret || this.config.pairingSecret.trim().length === 0) throw new Error("IncomingHmacVerifier: pairingSecret is not configured — cannot verify HMAC requests.");
117
123
  if (!authHeader?.startsWith("Codemation-Hmac ")) return { failure: "missing" };
118
124
  const parts = this.parseHeader(authHeader);
@@ -135,10 +141,9 @@ let IncomingHmacVerifier = class IncomingHmacVerifier$1 {
135
141
  const expectedBuf = Buffer.from(expected);
136
142
  const actualBuf = Buffer.from(parts.sig);
137
143
  if (expectedBuf.length !== actualBuf.length || !timingSafeEqual(expectedBuf, actualBuf)) return { failure: "signature" };
138
- this.pruneExpiredNonces(nowSec);
139
144
  const nonceKey = `${parts.workspaceId}:${parts.nonce}`;
140
- if (this.usedNonces.has(nonceKey)) return { failure: "replay" };
141
- this.usedNonces.set(nonceKey, nowSec + this.nonceTtlSeconds);
145
+ const nonceExpiresAt = /* @__PURE__ */ new Date((nowSec + this.nonceTtlSeconds) * 1e3);
146
+ if (!await this.nonceStore.recordIfNew(nonceKey, nonceExpiresAt)) return { failure: "replay" };
142
147
  return { workspaceId: parts.workspaceId };
143
148
  }
144
149
  parseHeader(header) {
@@ -159,14 +164,12 @@ let IncomingHmacVerifier = class IncomingHmacVerifier$1 {
159
164
  sig
160
165
  };
161
166
  }
162
- pruneExpiredNonces(nowSec) {
163
- for (const [key, expiry] of this.usedNonces.entries()) if (expiry <= nowSec) this.usedNonces.delete(key);
164
- }
165
167
  };
166
168
  IncomingHmacVerifier = __decorate([
167
169
  injectable(),
168
- __decorateParam(0, inject(PairingConfigToken)),
169
- __decorateMetadata("design:paramtypes", [Object])
170
+ __decorateParam(0, inject(PairingConfigToken, { isOptional: true })),
171
+ __decorateParam(1, inject(HmacNonceStoreToken)),
172
+ __decorateMetadata("design:paramtypes", [Object, Object])
170
173
  ], IncomingHmacVerifier);
171
174
 
172
175
  //#endregion
@@ -179,7 +182,7 @@ let InternalHmacAuthMiddleware = class InternalHmacAuthMiddleware$1 {
179
182
  handle() {
180
183
  return async (c, next) => {
181
184
  const body = c.req.method === "GET" || c.req.method === "HEAD" ? "" : await c.req.text();
182
- if ("failure" in this.verifier.verify(c.req.method, c.req.url, body, c.req.header("authorization") ?? null)) return c.json({ error: "Unauthorized" }, 401);
185
+ if ("failure" in await this.verifier.verify(c.req.method, c.req.url, body, c.req.header("authorization") ?? null)) return c.json({ error: "Unauthorized" }, 401);
183
186
  c.set("body", body);
184
187
  await next();
185
188
  };
@@ -217,5 +220,5 @@ InternalPingRegistrar = __decorate([
217
220
  ], InternalPingRegistrar);
218
221
 
219
222
  //#endregion
220
- export { PairedFetch as a, PairingConfigFactory as i, InternalHmacAuthMiddleware as n, HmacRequestSigner as o, IncomingHmacVerifier as r, PairingConfigToken as s, InternalPingRegistrar as t };
221
- //# sourceMappingURL=InternalPingRegistrar-DY3kSfxP.js.map
223
+ export { PairingConfigFactory as a, PairingConfigToken as c, HmacNonceStoreToken as i, InternalHmacAuthMiddleware as n, PairedFetch as o, IncomingHmacVerifier as r, HmacRequestSigner as s, InternalPingRegistrar as t };
224
+ //# sourceMappingURL=InternalPingRegistrar-BavAAnvk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InternalPingRegistrar-BavAAnvk.js","names":["HmacRequestSigner","config: PairingConfig | null","PairedFetch","signer: HmacRequestSigner","IncomingHmacVerifier","config: PairingConfig | null","nonceStore: HmacNonceStore","fields: Record<string, string>","InternalHmacAuthMiddleware","verifier: IncomingHmacVerifier","InternalPingRegistrar","hmacMiddleware: InternalHmacAuthMiddleware","pairingConfig: PairingConfig"],"sources":["../src/pairing/PairingConfigToken.ts","../src/pairing/HmacRequestSigner.ts","../src/pairing/PairedFetch.ts","../src/pairing/PairingConfigFactory.ts","../src/pairing/HmacNonceStoreToken.ts","../src/pairing/IncomingHmacVerifier.ts","../src/pairing/InternalHmacAuthMiddleware.ts","../src/pairing/InternalPingRegistrar.ts"],"sourcesContent":["import type { TypeToken } from \"@codemation/core\";\nimport type { PairingConfig } from \"./pairing.types\";\n\n// Symbol token so the DI container can inject PairingConfig.\n// Registered by PairingConfigFactory in the composition root.\nexport const PairingConfigToken = Symbol.for(\"codemation.pairing.PairingConfig\") as TypeToken<PairingConfig>;\n","import { createHmac, createHash, randomBytes } from \"node:crypto\";\nimport { inject, injectable } from \"@codemation/core\";\nimport type { PairingConfig } from \"./pairing.types\";\nimport { PairingConfigToken } from \"./PairingConfigToken\";\n\nexport interface SignedHeaders {\n readonly Authorization: string;\n}\n\n@injectable()\nexport class HmacRequestSigner {\n constructor(@inject(PairingConfigToken, { isOptional: true }) private readonly config: PairingConfig | null = null) {}\n\n sign(method: string, urlOrPath: string, body: string): SignedHeaders {\n if (this.config === null) {\n // Should never happen in managed mode (PairingConfig is registered then). In non-managed\n // mode this signer should never be called — callers like `PairedFetch` are themselves\n // only reachable via `ControlPlaneCatalogFetcher` whose poll loop checks `pairingConfig`.\n // If we land here, a CP-bound call escaped that guard.\n throw new Error(\n \"HmacRequestSigner.sign called without a registered PairingConfig — workspace is not in managed mode.\",\n );\n }\n const ts = Math.floor(Date.now() / 1000);\n const nonce = randomBytes(16).toString(\"base64\");\n\n const parsed = new URL(urlOrPath, \"http://placeholder\");\n const path = (parsed.pathname + parsed.search).toLowerCase();\n\n const bodyHash = createHash(\"sha256\").update(body, \"utf8\").digest(\"hex\");\n const baseString = [method.toUpperCase(), path, ts, nonce, bodyHash].join(\"\\n\");\n\n // eslint-disable-next-line codemation/no-buffer-everything -- pairing secret is 32 bytes, never large\n const secretBytes = Buffer.from(this.config.pairingSecret, \"base64\");\n const sig = createHmac(\"sha256\", secretBytes).update(baseString, \"utf8\").digest(\"base64\");\n\n return {\n Authorization: `Codemation-Hmac v=1,workspaceId=${this.config.workspaceId},ts=${ts},nonce=${nonce},sig=${sig}`,\n };\n }\n}\n","import { inject, injectable } from \"@codemation/core\";\nimport { HmacRequestSigner } from \"./HmacRequestSigner\";\n\n/**\n * Thin fetch wrapper that automatically HMAC-signs outgoing requests\n * to the control plane using the workspace's pairing secret.\n *\n * Use this for any server-to-server request from the installation to the CP.\n */\n@injectable()\nexport class PairedFetch {\n constructor(@inject(HmacRequestSigner) private readonly signer: HmacRequestSigner) {}\n\n async get(url: string): Promise<Response> {\n const headers = this.signer.sign(\"GET\", url, \"\");\n return fetch(url, { method: \"GET\", headers: { ...headers } });\n }\n\n async post(url: string, body: unknown): Promise<Response> {\n const bodyString = JSON.stringify(body);\n const headers = this.signer.sign(\"POST\", url, bodyString);\n return fetch(url, {\n method: \"POST\",\n headers: { ...headers, \"Content-Type\": \"application/json\" },\n body: bodyString,\n });\n }\n\n async delete(url: string): Promise<Response> {\n const headers = this.signer.sign(\"DELETE\", url, \"\");\n return fetch(url, { method: \"DELETE\", headers: { ...headers } });\n }\n}\n","import type { PairingConfig } from \"./pairing.types\";\n\n/**\n * Reads pairing configuration from environment variables.\n *\n * Required env vars when pairing is enabled:\n * WORKSPACE_ID — the workspace's database ID\n * WORKSPACE_PAIRING_SECRET — base64-encoded 32-byte shared secret\n * CONTROL_PLANE_URL — base URL of the control plane API\n *\n * Returns null if any required variable is absent (pairing disabled).\n * See docs/pairing-protocol.md for full bootstrap instructions.\n */\nexport class PairingConfigFactory {\n create(env: Readonly<NodeJS.ProcessEnv>): PairingConfig | null {\n const workspaceId = env[\"WORKSPACE_ID\"];\n const pairingSecret = env[\"WORKSPACE_PAIRING_SECRET\"];\n const controlPlaneUrl = env[\"CONTROL_PLANE_URL\"];\n\n if (!workspaceId || !pairingSecret || !controlPlaneUrl) {\n return null;\n }\n\n // eslint-disable-next-line codemation/no-buffer-everything -- pairing secret is always 32 bytes; bounded by validation below.\n const decoded = Buffer.from(pairingSecret, \"base64\");\n if (decoded.length !== 32) {\n throw new Error(\n `WORKSPACE_PAIRING_SECRET must be a base64-encoded 32-byte value (got ${decoded.length} bytes). ` +\n `Generate a valid secret with: openssl rand -base64 32`,\n );\n }\n\n return { workspaceId, pairingSecret, controlPlaneUrl };\n }\n}\n","import type { TypeToken } from \"@codemation/core\";\nimport type { HmacNonceStore } from \"./HmacNonceStore\";\n\nexport const HmacNonceStoreToken = Symbol.for(\"codemation.pairing.HmacNonceStore\") as TypeToken<HmacNonceStore>;\n","import { createHmac, createHash, timingSafeEqual } from \"node:crypto\";\nimport { inject, injectable } from \"@codemation/core\";\nimport type { PairingConfig, PairingVerificationResult } from \"./pairing.types\";\nimport { PairingConfigToken } from \"./PairingConfigToken\";\nimport type { HmacNonceStore } from \"./HmacNonceStore\";\nimport { HmacNonceStoreToken } from \"./HmacNonceStoreToken\";\n\n/**\n * Verifies incoming HMAC-signed requests from the control plane.\n * Mirrors the control-plane HmacVerifier — both sides follow docs/pairing-protocol.md.\n *\n * Security (T6): The nonce store is injected and defaults to PrismaHmacNonceStore in\n * managed mode so replay protection survives process restarts within the 300-second\n * timestamp window.\n */\n@injectable()\nexport class IncomingHmacVerifier {\n private readonly nonceTtlSeconds = 600; // 10 minutes\n\n constructor(\n @inject(PairingConfigToken, { isOptional: true }) private readonly config: PairingConfig | null = null,\n @inject(HmacNonceStoreToken) private readonly nonceStore: HmacNonceStore,\n ) {}\n\n async verify(\n method: string,\n url: string,\n body: string,\n authHeader: string | null,\n ): Promise<PairingVerificationResult> {\n if (this.config === null) {\n // Same shape as HmacRequestSigner — verifier is reachable via the DI graph even in\n // non-managed mode (lazy CodemationHonoApiApp construction pulls every registered handler).\n // We accept construction without PairingConfig and throw only when verify() is actually\n // called, which shouldn't happen in non-managed mode (internal HMAC routes aren't mounted).\n throw new Error(\n \"IncomingHmacVerifier.verify called without a registered PairingConfig — workspace is not in managed mode.\",\n );\n }\n if (!this.config.pairingSecret || this.config.pairingSecret.trim().length === 0) {\n throw new Error(\"IncomingHmacVerifier: pairingSecret is not configured — cannot verify HMAC requests.\");\n }\n\n if (!authHeader?.startsWith(\"Codemation-Hmac \")) {\n return { failure: \"missing\" };\n }\n\n const parts = this.parseHeader(authHeader);\n if (!parts) return { failure: \"missing\" };\n if (parts.v !== \"1\") return { failure: \"version\" };\n\n const nowSec = Math.floor(Date.now() / 1000);\n if (Math.abs(nowSec - parts.ts) > 300) return { failure: \"expired\" };\n\n if (parts.workspaceId !== this.config.workspaceId) return { failure: \"workspace\" };\n\n const parsed = new URL(url, \"http://placeholder\");\n const path = (parsed.pathname + parsed.search).toLowerCase();\n const bodyHash = createHash(\"sha256\").update(body, \"utf8\").digest(\"hex\");\n const baseString = [method.toUpperCase(), path, parts.ts, parts.nonce, bodyHash].join(\"\\n\");\n\n // eslint-disable-next-line codemation/no-buffer-everything -- pairing secret is 32 bytes, never large\n const secretBytes = Buffer.from(this.config.pairingSecret, \"base64\");\n const expected = createHmac(\"sha256\", secretBytes).update(baseString, \"utf8\").digest(\"base64\");\n\n const expectedBuf = Buffer.from(expected);\n const actualBuf = Buffer.from(parts.sig);\n if (expectedBuf.length !== actualBuf.length || !timingSafeEqual(expectedBuf, actualBuf)) {\n return { failure: \"signature\" };\n }\n\n const nonceKey = `${parts.workspaceId}:${parts.nonce}`;\n const nonceExpiresAt = new Date((nowSec + this.nonceTtlSeconds) * 1000);\n const isNew = await this.nonceStore.recordIfNew(nonceKey, nonceExpiresAt);\n if (!isNew) return { failure: \"replay\" };\n\n return { workspaceId: parts.workspaceId };\n }\n\n private parseHeader(header: string): {\n v: string;\n workspaceId: string;\n ts: number;\n nonce: string;\n sig: string;\n } | null {\n const payload = header.slice(\"Codemation-Hmac \".length);\n const fields: Record<string, string> = {};\n for (const part of payload.split(\",\")) {\n const eq = part.indexOf(\"=\");\n if (eq === -1) return null;\n fields[part.slice(0, eq).trim()] = part.slice(eq + 1).trim();\n }\n const { v, workspaceId, ts, nonce, sig } = fields;\n if (!v || !workspaceId || !ts || !nonce || !sig) return null;\n return { v, workspaceId, ts: Number(ts), nonce, sig };\n }\n}\n","import { inject, injectable } from \"@codemation/core\";\nimport type { Context, MiddlewareHandler, Next } from \"hono\";\nimport { IncomingHmacVerifier } from \"./IncomingHmacVerifier\";\n\n/**\n * Hono middleware that verifies HMAC-signed requests on /internal/* routes.\n * Rejects with 401 on any auth failure (failure mode is never leaked).\n *\n * Downstream handlers read the consumed body from `c.get(\"body\")` when needed —\n * do NOT call `c.req.text()` again after this middleware runs.\n */\n@injectable()\nexport class InternalHmacAuthMiddleware {\n constructor(@inject(IncomingHmacVerifier) private readonly verifier: IncomingHmacVerifier) {}\n\n handle(): MiddlewareHandler {\n return async (c: Context, next: Next) => {\n const body = c.req.method === \"GET\" || c.req.method === \"HEAD\" ? \"\" : await c.req.text();\n\n const result = await this.verifier.verify(c.req.method, c.req.url, body, c.req.header(\"authorization\") ?? null);\n\n if (\"failure\" in result) {\n return c.json({ error: \"Unauthorized\" }, 401);\n }\n\n // Body stored for downstream handlers that need it (e.g., credential push).\n // Access via c.get(\"body\") — do NOT call c.req.text() again.\n // workspaceId is available from PairingConfig since installation has a single workspace.\n c.set(\"body\" as never, body);\n await next();\n };\n }\n}\n","import { inject, injectable } from \"@codemation/core\";\nimport type { Hono } from \"hono\";\nimport { InternalHmacAuthMiddleware } from \"./InternalHmacAuthMiddleware\";\nimport type { InternalHonoApiRouteRegistrar } from \"../presentation/http/hono/InternalHonoApiRouteRegistrar\";\nimport type { PairingConfig } from \"./pairing.types\";\nimport { PairingConfigToken } from \"./PairingConfigToken\";\n\n/**\n * Registers GET /internal/ping — a smoke-test endpoint for verifying workspace pairing.\n * Returns { pong: true, workspaceId } when the HMAC signature validates correctly.\n */\n@injectable()\nexport class InternalPingRegistrar implements InternalHonoApiRouteRegistrar {\n constructor(\n @inject(InternalHmacAuthMiddleware) private readonly hmacMiddleware: InternalHmacAuthMiddleware,\n @inject(PairingConfigToken) private readonly pairingConfig: PairingConfig,\n ) {}\n\n register(app: Hono): void {\n const { workspaceId } = this.pairingConfig;\n app.get(\"/internal/ping\", this.hmacMiddleware.handle(), (c) => {\n return c.json({ pong: true, workspaceId });\n });\n }\n}\n"],"mappings":"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"}