@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.
- package/CHANGELOG.md +89 -0
- package/LICENSE +37 -1
- package/dist/{ApiPaths-Dv1dcHu_.js → ApiPaths-DCvrlIjg.js} +12 -1
- package/dist/{ApiPaths-Dv1dcHu_.js.map → ApiPaths-DCvrlIjg.js.map} +1 -1
- package/dist/{AppConfigFactory-Cx4qQvRk.js → AppConfigFactory-D4LL1aOR.js} +77 -297
- package/dist/AppConfigFactory-D4LL1aOR.js.map +1 -0
- package/dist/{AppConfigFactory-DnLoQ9Li.d.ts → AppConfigFactory-DncmwCD1.d.ts} +2918 -199
- package/dist/{AppContainerFactory-DqKYCRNP.js → AppContainerFactory-jpYXGZGe.js} +1733 -475
- package/dist/AppContainerFactory-jpYXGZGe.js.map +1 -0
- package/dist/{CodemationAppContext-CKVv9W9q.d.ts → CodemationAppContext-K51b7oXe.d.ts} +9 -3
- package/dist/{CodemationAuthoring.types-DA3G3s6d.d.ts → CodemationAuthoring.types-BXlXIl4K.d.ts} +9 -4
- package/dist/{CodemationAuthoring.types-NGkBcmmT.js → CodemationAuthoring.types-BteaR3Dc.js} +3 -2
- package/dist/CodemationAuthoring.types-BteaR3Dc.js.map +1 -0
- package/dist/{CodemationConfigNormalizer-BAKjetJ6.d.ts → CodemationConfigNormalizer-B4rDYC9h.d.ts} +3 -3
- package/dist/{CodemationConsumerConfigLoader-GYpBBvqE.js → CodemationConsumerConfigLoader-By-6tuGc.js} +3 -1
- package/dist/CodemationConsumerConfigLoader-By-6tuGc.js.map +1 -0
- package/dist/{CodemationConsumerConfigLoader-nxOqvv46.d.ts → CodemationConsumerConfigLoader-Dt4jyLx6.d.ts} +3 -2
- package/dist/{CodemationPluginListMerger-DKLAHT2b.d.ts → CodemationPluginListMerger-DS6I3Xe0.d.ts} +64 -27
- package/dist/{persistenceServer-C-hH4z6l.js → CodemationPostgresPrismaClientFactory-C7156Fe-.js} +2 -2
- package/dist/CodemationPostgresPrismaClientFactory-C7156Fe-.js.map +1 -0
- package/dist/CodemationPostgresPrismaClientFactory-CTNTPnDr.d.ts +9 -0
- package/dist/{CredentialContractsRegistry-Bq2bq28t.d.ts → CredentialContractsRegistry-Dgu-rEXi.d.ts} +16 -3
- package/dist/{CredentialServices-Be2I60Th.d.ts → CredentialServices-B3wPyp2y.d.ts} +4 -4
- package/dist/{CredentialServices-Dk8yypeL.js → CredentialServices-Bios0dM8.js} +10 -4
- package/dist/CredentialServices-Bios0dM8.js.map +1 -0
- package/dist/{InternalPingRegistrar-DY3kSfxP.js → InternalPingRegistrar-BavAAnvk.js} +19 -16
- package/dist/InternalPingRegistrar-BavAAnvk.js.map +1 -0
- package/dist/{ItemsInputNormalizer-_RwIfRIQ.d.ts → ItemsInputNormalizer-CFkfNMLt.d.ts} +1434 -1225
- package/dist/PrismaMigrationDeployer-DdEcXXVi.d.ts +14 -0
- package/dist/{PublicFrontendBootstrapFactory-CY2FS-5g.d.ts → PublicFrontendBootstrapFactory-ClEjZP74.d.ts} +2 -2
- package/dist/{PublicFrontendBootstrapJsonCodec-CXG9Dxft.d.ts → PublicFrontendBootstrapJsonCodec-HNItQ7ol.d.ts} +6 -1
- package/dist/{TelemetryContracts-BtDx84Cp.d.ts → TelemetryContracts-DpZEODQM.d.ts} +2 -2
- package/dist/{WorkflowPolicyUiPresentationFactory-6MyjCvBO.d.ts → WorkflowPolicyUiPresentationFactory-BNn2fvR_.d.ts} +2 -2
- package/dist/{WorkflowPolicyUiPresentationFactory-Bb-ae_Zh.js → WorkflowPolicyUiPresentationFactory-DfvD2VHk.js} +1 -1
- package/dist/{WorkflowPolicyUiPresentationFactory-Bb-ae_Zh.js.map → WorkflowPolicyUiPresentationFactory-DfvD2VHk.js.map} +1 -1
- package/dist/authoring.d.ts +4 -4
- package/dist/authoring.js +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js +1 -1
- package/dist/consumer.d.ts +5 -5
- package/dist/consumer.js +1 -1
- package/dist/credentials.d.ts +5 -5
- package/dist/credentials.js +1 -1
- package/dist/devServerSidecar.d.ts +2 -2
- package/dist/dto.d.ts +5 -5
- package/dist/{index-DilAYwnH.d.ts → index-ChIfeWzk.d.ts} +71 -28
- package/dist/index.d.ts +49 -17
- package/dist/index.js +106 -13
- package/dist/index.js.map +1 -0
- package/dist/infrastructure/persistence/PrismaMigrationOperations.d.ts +44 -0
- package/dist/infrastructure/persistence/PrismaMigrationOperations.js +302 -0
- package/dist/infrastructure/persistence/PrismaMigrationOperations.js.map +1 -0
- package/dist/mapping.d.ts +2 -2
- package/dist/mapping.js +1 -1
- package/dist/nextServer.d.ts +15 -39
- package/dist/nextServer.js +6 -6
- package/dist/pairing.d.ts +27 -8
- package/dist/pairing.js +19 -3
- package/dist/pairing.js.map +1 -0
- package/dist/{pairing.types-snfZ_OzB.d.ts → pairing.types-D9Bjn98U.d.ts} +1 -1
- package/dist/persistenceServer.d.ts +31 -7
- package/dist/persistenceServer.js +2 -2
- package/dist/{server-C4bS62rg.d.ts → server-B5trn7y4.d.ts} +5 -5
- package/dist/{server-Y7kxwtCK.js → server-BlG9qV5S.js} +5 -5
- package/dist/{server-Y7kxwtCK.js.map → server-BlG9qV5S.js.map} +1 -1
- package/dist/server.d.ts +10 -10
- package/dist/server.js +9 -9
- package/package.json +28 -25
- package/playwright.config.ts +8 -2
- package/playwright.scaffolded-dev.config.ts +8 -2
- package/prisma/migrations/20260526120000_credential_material_pointer/migration.sql +18 -0
- package/prisma/migrations/20260527120000_add_human_task/migration.sql +32 -0
- package/prisma/migrations/20260527130000_add_hitl_state_json/migration.sql +6 -0
- package/prisma/migrations/20260527130000_add_hmac_nonce/migration.sql +12 -0
- package/prisma/migrations.sqlite/20260526120000_credential_material_pointer/migration.sql +13 -0
- package/prisma/migrations.sqlite/20260527120000_add_human_task/migration.sql +30 -0
- package/prisma/migrations.sqlite/20260527130000_add_hitl_state_json/migration.sql +6 -0
- package/prisma/migrations.sqlite/20260527130000_add_hmac_nonce/migration.sql +9 -0
- package/prisma/schema.postgresql.prisma +48 -0
- package/prisma/schema.sqlite.prisma +48 -0
- package/prisma-generated/prisma-postgresql-client/edge.js +40 -6
- package/prisma-generated/prisma-postgresql-client/index-browser.js +36 -2
- package/prisma-generated/prisma-postgresql-client/index.d.ts +3179 -163
- package/prisma-generated/prisma-postgresql-client/index.js +40 -6
- package/prisma-generated/prisma-postgresql-client/package.json +1 -1
- package/prisma-generated/prisma-postgresql-client/schema.prisma +48 -0
- package/prisma-generated/prisma-sqlite-client/edge.js +40 -6
- package/prisma-generated/prisma-sqlite-client/index-browser.js +36 -2
- package/prisma-generated/prisma-sqlite-client/index.d.ts +3175 -163
- package/prisma-generated/prisma-sqlite-client/index.js +40 -6
- package/prisma-generated/prisma-sqlite-client/package.json +1 -1
- package/prisma-generated/prisma-sqlite-client/schema.prisma +48 -0
- package/src/application/contracts/CredentialContractsRegistry.ts +15 -0
- package/src/application/credentials/AppGalleryProjector.ts +69 -0
- package/src/application/hitl/DecideHumanTaskCommandHandler.ts +149 -0
- package/src/application/hitl/DecisionSchemaValidator.ts +22 -0
- package/src/application/hitl/HitlCallbackHandler.ts +96 -0
- package/src/application/mapping/WorkflowDefinitionMapper.ts +1 -3
- package/src/application/queries/CredentialQueryHandlers.ts +2 -0
- package/src/application/queries/GetCredentialAppsQuery.ts +4 -0
- package/src/application/queries/GetCredentialAppsQueryHandler.ts +27 -0
- package/src/application/telemetry/ResumeTelemetryContextForRun.ts +53 -0
- package/src/application/telemetry/TelemetryRetentionTimestampFactory.ts +9 -8
- package/src/applicationTokens.ts +11 -1
- package/src/auth/managed/ManagedCorsMiddleware.ts +20 -5
- package/src/bootstrap/AppContainerFactory.ts +121 -3
- package/src/bootstrap/runtime/HeadlessApiRuntime.ts +47 -0
- package/src/credentials/CachingCredentialMaterialProvider.ts +96 -0
- package/src/credentials/CompositeCredentialMaterialProvider.ts +47 -0
- package/src/credentials/ControlPlaneCatalogFetcher.ts +8 -28
- package/src/credentials/ControlPlaneCredentialMaterialProvider.ts +79 -0
- package/src/credentials/CredentialOAuth2MaterialReader.ts +2 -7
- package/src/credentials/InternalCredentialsBindingRegistrar.ts +83 -0
- package/src/credentials/LocalCredentialMaterialProvider.ts +92 -0
- package/src/domain/credentials/CredentialInstanceService.ts +5 -1
- package/src/domain/credentials/CredentialTypeRegistryImpl.ts +18 -4
- package/src/domain/workflows/WorkflowActivationPreflightRules.ts +7 -4
- package/src/dto.ts +2 -0
- package/src/hitl/ControlPlaneInboxChannel.ts +102 -0
- package/src/hitl/HitlResumeTokenSigner.ts +80 -0
- package/src/hitl/HitlTimeoutJobScheduler.ts +77 -0
- package/src/hitl/HitlTimeoutWorker.ts +138 -0
- package/src/hitl/InboxChannelResolver.ts +49 -0
- package/src/hitl/LocalInboxChannel.ts +37 -0
- package/src/index.ts +3 -0
- package/src/infrastructure/persistence/PrismaCredentialStore.ts +10 -0
- package/src/infrastructure/persistence/PrismaHmacNonceStore.ts +29 -0
- package/src/infrastructure/persistence/PrismaHumanTaskStore.ts +156 -0
- package/src/infrastructure/persistence/PrismaMigrationDeployer.ts +53 -383
- package/src/infrastructure/persistence/PrismaMigrationOperations.ts +401 -0
- package/src/infrastructure/persistence/PrismaWorkflowRunRepository.ts +39 -0
- package/src/mcp/AgentMcpIntegrationImpl.ts +5 -1
- package/src/pairing/HmacNonceStore.ts +14 -0
- package/src/pairing/HmacNonceStoreToken.ts +4 -0
- package/src/pairing/HmacRequestSigner.ts +10 -1
- package/src/pairing/InMemoryHmacNonceStore.ts +24 -0
- package/src/pairing/IncomingHmacVerifier.ts +28 -12
- package/src/pairing/InternalHmacAuthMiddleware.ts +1 -1
- package/src/pairing/index.ts +3 -0
- package/src/presentation/config/CodemationAuthoring.types.ts +7 -1
- package/src/presentation/config/CodemationConfig.ts +6 -0
- package/src/presentation/http/ApiPaths.ts +14 -0
- package/src/presentation/http/HeadlessHttpServerFactory.ts +56 -0
- package/src/presentation/http/hono/HonoHttpAnonymousRoutePolicyRegistry.ts +4 -0
- package/src/presentation/http/hono/registrars/CredentialHonoApiRouteRegistrar.ts +1 -0
- package/src/presentation/http/hono/registrars/HitlDecideHonoApiRouteRegistrar.ts +54 -0
- package/src/presentation/http/hono/registrars/HitlInternalCallbackHonoApiRouteRegistrar.ts +33 -0
- package/src/presentation/http/hono/registrars/HitlResumeHonoApiRouteRegistrar.ts +43 -0
- package/src/presentation/http/routeHandlers/CredentialHttpRouteHandler.ts +9 -0
- package/src/presentation/http/routeHandlers/OAuth2HttpRouteHandlerFactory.ts +1 -1
- package/src/presentation/server/CodemationConsumerConfigLoader.ts +7 -2
- package/src/presentation/websocket/WorkflowWebsocketServerFactory.ts +16 -0
- package/src/server.ts +7 -2
- package/src/workflows/InternalWorkflowTestRunRegistrar.ts +9 -0
- package/tsconfig.json +1 -0
- package/dist/AppConfigFactory-Cx4qQvRk.js.map +0 -1
- package/dist/AppContainerFactory-DqKYCRNP.js.map +0 -1
- package/dist/CodemationAuthoring.types-NGkBcmmT.js.map +0 -1
- package/dist/CodemationConsumerConfigLoader-GYpBBvqE.js.map +0 -1
- package/dist/CredentialServices-Dk8yypeL.js.map +0 -1
- package/dist/InternalPingRegistrar-DY3kSfxP.js.map +0 -1
- package/dist/persistenceServer-C-hH4z6l.js.map +0 -1
- package/dist/persistenceServer-CeTHtC6E.d.ts +0 -30
- package/src/credentials/catalogTypes.ts +0 -4
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"CodemationAuthoring.types-NGkBcmmT.js","names":[],"sources":["../src/presentation/config/CodemationAuthoring.types.ts"],"sourcesContent":["import type { AnyCredentialType, DefinedCollection, DefinedNode, McpServerDeclaration } from \"@codemation/core\";\nimport type { CodemationAppContext } from \"./CodemationAppContext\";\nimport type {\n CodemationAppDefinition,\n CodemationAppSchedulerConfig,\n CodemationConfig,\n CodemationDatabaseConfig,\n} from \"./CodemationConfig\";\nimport type { CodemationPlugin, CodemationPluginContext } from \"./CodemationPlugin\";\nimport type { CodemationWhitelabelConfig } from \"./CodemationWhitelabelConfig\";\n\nexport interface FriendlyCodemationDatabaseConfig {\n readonly kind: \"postgresql\" | \"sqlite\";\n readonly url?: string;\n /** Name of an environment variable whose value is the PostgreSQL connection URL. Co-exclusive with `url`. */\n readonly urlEnv?: string;\n readonly filePath?: string;\n}\n\nexport interface FriendlyCodemationExecutionConfig {\n readonly mode?: \"inline\" | \"queue\";\n /** Name of an environment variable whose value is \"inline\" or \"queue\". Co-exclusive with `mode`. */\n readonly modeEnv?: string;\n readonly queuePrefix?: string;\n readonly workerQueues?: ReadonlyArray<string>;\n readonly redisUrl?: string;\n /** Name of an environment variable whose value is the Redis connection URL. Co-exclusive with `redisUrl`. */\n readonly redisUrlEnv?: string;\n}\n\nexport interface DefineCodemationAppOptions extends Omit<\n CodemationConfig,\n \"app\" | \"credentialTypes\" | \"register\" | \"whitelabel\" | \"auth\" | \"collections\"\n> {\n readonly name?: string;\n readonly auth?: CodemationConfig[\"auth\"];\n readonly database?: FriendlyCodemationDatabaseConfig;\n readonly execution?: FriendlyCodemationExecutionConfig;\n readonly nodes?: ReadonlyArray<DefinedNode<string, Record<string, unknown>, unknown, unknown>>;\n readonly collections?: ReadonlyArray<DefinedCollection>;\n readonly credentialTypes?: ReadonlyArray<AnyCredentialType>;\n readonly credentials?: ReadonlyArray<AnyCredentialType>;\n readonly register?: (context: CodemationAppContext) => void;\n readonly whitelabel?: CodemationWhitelabelConfig;\n /**\n * Path (relative to the consumer project root) to a directory from which workflows are auto-discovered.\n * All `*.ts` / `*.tsx` files (excluding `*.test.*` and `*.d.ts`) are imported and any exported\n * `WorkflowDefinition` values are registered. Co-exclusive with providing this directory in\n * `workflowDiscovery.directories`.\n */\n readonly workflowsDir?: string;\n}\n\nexport interface DefinePluginOptions {\n readonly name?: string;\n readonly pluginPackageId?: string;\n readonly nodes?: ReadonlyArray<DefinedNode<string, Record<string, unknown>, unknown, unknown>>;\n readonly collections?: ReadonlyArray<DefinedCollection>;\n readonly credentials?: ReadonlyArray<AnyCredentialType>;\n readonly mcpServers?: ReadonlyArray<McpServerDeclaration>;\n readonly register?: (context: CodemationPluginContext) => void | Promise<void>;\n readonly sandbox?: CodemationConfig;\n}\n\nclass CodemationAuthoringConfigFactory {\n static createApp(options: DefineCodemationAppOptions): CodemationConfig {\n const appDefinition = this.createAppDefinition(options);\n const credentialTypes = [...(options.credentialTypes ?? []), ...(options.credentials ?? [])];\n const register = this.composeAppRegister(options.register, options.nodes, options.collections);\n const { workflows, plugins, runtime, log, mcpServers } = options;\n const workflowDiscovery = this.mergeWorkflowDiscovery(options.workflowDiscovery, options.workflowsDir);\n return {\n workflows,\n workflowDiscovery,\n plugins,\n runtime,\n log,\n mcpServers,\n app: appDefinition,\n credentialTypes,\n register,\n };\n }\n\n static createPlugin(options: DefinePluginOptions): CodemationPlugin & Readonly<{ sandbox?: CodemationConfig }> {\n return {\n pluginPackageId: options.pluginPackageId,\n sandbox: options.sandbox,\n mcpServers: options.mcpServers,\n async register(context: CodemationPluginContext): Promise<void> {\n for (const nodeDefinition of options.nodes ?? []) {\n nodeDefinition.register(context);\n }\n for (const collection of options.collections ?? []) {\n collection.register(context);\n }\n for (const credential of options.credentials ?? []) {\n context.registerCredentialType(credential);\n }\n await options.register?.(context);\n },\n };\n }\n\n private static createAppDefinition(options: DefineCodemationAppOptions): CodemationAppDefinition | undefined {\n const scheduler = this.createSchedulerConfig(options.execution);\n const database = this.createDatabaseConfig(options.database);\n const whitelabel = this.createWhitelabel(options.name, options.whitelabel);\n if (!options.auth && !database && !scheduler && !whitelabel) {\n return undefined;\n }\n return {\n auth: options.auth,\n database,\n scheduler,\n whitelabel,\n };\n }\n\n private static createDatabaseConfig(\n database: FriendlyCodemationDatabaseConfig | undefined,\n ): CodemationDatabaseConfig | undefined {\n if (!database) {\n return undefined;\n }\n if (database.kind === \"sqlite\") {\n return {\n kind: \"sqlite\",\n sqliteFilePath: database.filePath,\n };\n }\n if (database.url !== undefined && database.urlEnv !== undefined) {\n throw new Error(\n \"defineCodemationApp: database.url and database.urlEnv are mutually exclusive — provide one or the other.\",\n );\n }\n const url = database.urlEnv !== undefined ? process.env[database.urlEnv] : database.url;\n return {\n kind: \"postgresql\",\n url,\n };\n }\n\n private static createSchedulerConfig(\n execution: FriendlyCodemationExecutionConfig | undefined,\n ): CodemationAppSchedulerConfig | undefined {\n if (!execution) {\n return undefined;\n }\n if (execution.mode !== undefined && execution.modeEnv !== undefined) {\n throw new Error(\n \"defineCodemationApp: execution.mode and execution.modeEnv are mutually exclusive — provide one or the other.\",\n );\n }\n if (execution.redisUrl !== undefined && execution.redisUrlEnv !== undefined) {\n throw new Error(\n \"defineCodemationApp: execution.redisUrl and execution.redisUrlEnv are mutually exclusive — provide one or the other.\",\n );\n }\n const rawMode = execution.modeEnv !== undefined ? process.env[execution.modeEnv] : execution.mode;\n const mode = rawMode === \"inline\" || rawMode === \"queue\" ? rawMode : undefined;\n const redisUrl = execution.redisUrlEnv !== undefined ? process.env[execution.redisUrlEnv] : execution.redisUrl;\n return {\n kind: mode,\n queuePrefix: execution.queuePrefix,\n workerQueues: execution.workerQueues,\n redisUrl,\n };\n }\n\n private static mergeWorkflowDiscovery(\n existing: CodemationConfig[\"workflowDiscovery\"],\n workflowsDir: string | undefined,\n ): CodemationConfig[\"workflowDiscovery\"] {\n if (!workflowsDir) {\n return existing;\n }\n const existingDirectories = existing?.directories ?? [];\n return {\n directories: [...existingDirectories, workflowsDir],\n };\n }\n\n private static createWhitelabel(\n name: string | undefined,\n whitelabel: CodemationWhitelabelConfig | undefined,\n ): CodemationWhitelabelConfig | undefined {\n if (!name && !whitelabel) {\n return undefined;\n }\n return {\n productName: name ?? whitelabel?.productName,\n logoPath: whitelabel?.logoPath,\n };\n }\n\n private static composeAppRegister(\n register: ((context: CodemationAppContext) => void) | undefined,\n nodes: ReadonlyArray<DefinedNode<string, Record<string, unknown>, unknown, unknown>> | undefined,\n collections: ReadonlyArray<DefinedCollection> | undefined,\n ): ((context: CodemationAppContext) => void) | undefined {\n if (!register && (!nodes || nodes.length === 0) && (!collections || collections.length === 0)) {\n return undefined;\n }\n return (context: CodemationAppContext) => {\n for (const nodeDefinition of nodes ?? []) {\n nodeDefinition.register(context);\n }\n for (const collection of collections ?? []) {\n collection.register(context);\n }\n register?.(context);\n };\n }\n}\n\nexport function defineCodemationApp(options: DefineCodemationAppOptions): CodemationConfig {\n return CodemationAuthoringConfigFactory.createApp(options);\n}\n\nexport function definePlugin(\n options: DefinePluginOptions,\n): CodemationPlugin & Readonly<{ sandbox?: CodemationConfig }> {\n return CodemationAuthoringConfigFactory.createPlugin(options);\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"CodemationConsumerConfigLoader-GYpBBvqE.js","names":["containerRegistrations: Array<CodemationContainerRegistration<unknown>>","credentialTypes: Array<AnyCredentialType>","collections: Array<CollectionDefinition>","workflows: Array<WorkflowDefinition>","workflowDirectories: Array<string>","workflows: WorkflowDefinition[]","workflowModulePaths: string[]","bestRoot: string | null","resolvedConfig: NormalizedCodemationConfig"],"sources":["../src/presentation/config/CodemationConfigNormalizer.ts","../src/presentation/server/CodemationConsumerConfigExportsResolver.ts","../src/presentation/server/DiscoveredWorkflowsEmptyMessageFactory.ts","../src/presentation/server/WorkflowDefinitionExportsResolver.ts","../src/presentation/server/CodemationConsumerAppResolver.ts","../src/presentation/server/WorkflowModulePathFinder.ts","../src/presentation/server/WorkflowDiscoveryPathSegmentsComputer.ts","../src/presentation/server/CodemationConsumerConfigLoader.ts"],"sourcesContent":["import type {\n AnyCredentialType,\n CollectionDefinition,\n Container,\n DefinedCollection,\n TypeToken,\n WorkflowDefinition,\n} from \"@codemation/core\";\nimport type { CodemationContainerRegistration } from \"../../bootstrap/CodemationContainerRegistration\";\nimport type { CodemationAppContext } from \"./CodemationAppContext\";\nimport type { CodemationAuthConfig } from \"./CodemationAuthConfig\";\nimport type { CodemationClassToken } from \"./CodemationClassToken\";\nimport type {\n CodemationApplicationRuntimeConfig,\n CodemationConfig,\n CodemationDatabaseConfig,\n CodemationEventBusConfig,\n CodemationSchedulerConfig,\n} from \"./CodemationConfig\";\n\nexport type NormalizedCodemationConfig = Omit<CodemationConfig, \"collections\"> &\n Readonly<{\n containerRegistrations: ReadonlyArray<CodemationContainerRegistration<unknown>>;\n collections: ReadonlyArray<CollectionDefinition>;\n }>;\n\nexport class CodemationConfigNormalizer {\n normalize(config: CodemationConfig): NormalizedCodemationConfig {\n const auth = config.app?.auth ?? config.auth;\n this.assertAuthConfig(auth);\n this.assertManagedModeConstraints(config, auth);\n const collected = this.collectRegistration(config);\n const normalizedRuntime = this.normalizeRuntimeConfig(config);\n const normalizedWorkflowDiscoveryDirectories = [\n ...(config.workflowDiscovery?.directories ?? []),\n ...collected.workflowDirectories,\n ];\n\n return {\n ...config,\n auth,\n containerRegistrations: collected.containerRegistrations,\n credentialTypes: [...(config.credentialTypes ?? []), ...collected.credentialTypes],\n collections: [...this.unwrapCollections(config.collections), ...collected.collections],\n log: config.app?.log ?? config.log,\n runtime: normalizedRuntime,\n whitelabel: config.app?.whitelabel ?? config.whitelabel,\n workflowDiscovery:\n normalizedWorkflowDiscoveryDirectories.length > 0\n ? { directories: normalizedWorkflowDiscoveryDirectories }\n : config.workflowDiscovery,\n workflows: this.mergeWorkflows(config.workflows ?? [], collected.workflows),\n };\n }\n\n /**\n * Enforces managed-mode invariants beyond what `assertAuthConfig` covers:\n * managed-mode workspaces are always Postgres and always require at least one workflow source.\n */\n private assertManagedModeConstraints(config: CodemationConfig, auth: CodemationAuthConfig | undefined): void {\n if (auth?.kind !== \"managed\") {\n return;\n }\n const hasWorkflows = (config.workflows?.length ?? 0) > 0;\n const hasWorkflowDiscovery = (config.workflowDiscovery?.directories?.length ?? 0) > 0;\n if (!hasWorkflows && !hasWorkflowDiscovery) {\n throw new Error(\n 'Managed-mode workspaces require at least one workflow source. Provide \"workflows\" or \"workflowsDir\" (which maps to workflowDiscovery.directories) in defineCodemationApp.',\n );\n }\n }\n\n private collectRegistration(config: CodemationConfig): Readonly<{\n containerRegistrations: ReadonlyArray<CodemationContainerRegistration<unknown>>;\n credentialTypes: ReadonlyArray<AnyCredentialType>;\n collections: ReadonlyArray<CollectionDefinition>;\n workflows: ReadonlyArray<WorkflowDefinition>;\n workflowDirectories: ReadonlyArray<string>;\n }> {\n if (!config.register) {\n return {\n containerRegistrations: [],\n credentialTypes: [],\n collections: [],\n workflows: [],\n workflowDirectories: [],\n };\n }\n\n const containerRegistrations: Array<CodemationContainerRegistration<unknown>> = [];\n const credentialTypes: Array<AnyCredentialType> = [];\n const collections: Array<CollectionDefinition> = [];\n const workflows: Array<WorkflowDefinition> = [];\n const workflowDirectories: Array<string> = [];\n\n const context: CodemationAppContext = {\n registerCredentialType(type) {\n credentialTypes.push(type);\n },\n registerCollection(definition) {\n collections.push(definition);\n },\n registerNode<TValue>(token: TypeToken<TValue>, implementation?: CodemationClassToken<TValue>) {\n containerRegistrations.push({\n token,\n useClass: implementation ?? (token as CodemationClassToken<TValue>),\n });\n },\n registerValue<TValue>(token: TypeToken<TValue>, value: TValue) {\n containerRegistrations.push({ token, useValue: value });\n },\n registerClass<TValue>(token: TypeToken<TValue>, implementation: CodemationClassToken<TValue>) {\n containerRegistrations.push({ token, useClass: implementation });\n },\n registerFactory<TValue>(token: TypeToken<TValue>, factory: (container: Container) => TValue) {\n containerRegistrations.push({ token, useFactory: factory });\n },\n registerWorkflow(workflow: WorkflowDefinition) {\n workflows.push(workflow);\n },\n registerWorkflows(nextWorkflows: ReadonlyArray<WorkflowDefinition>) {\n workflows.push(...nextWorkflows);\n },\n discoverWorkflows(...directories: ReadonlyArray<string>) {\n workflowDirectories.push(...directories);\n },\n };\n\n config.register(context);\n\n return {\n containerRegistrations,\n credentialTypes,\n collections,\n workflows,\n workflowDirectories,\n };\n }\n\n private unwrapCollections(\n entries: ReadonlyArray<CollectionDefinition | DefinedCollection> | undefined,\n ): ReadonlyArray<CollectionDefinition> {\n if (!entries) return [];\n return entries.map((entry) => (this.isDefinedCollection(entry) ? entry.definition : entry));\n }\n\n private isDefinedCollection(entry: CollectionDefinition | DefinedCollection): entry is DefinedCollection {\n return \"kind\" in entry && entry.kind === \"defined-collection\";\n }\n\n private normalizeRuntimeConfig(config: CodemationConfig): CodemationApplicationRuntimeConfig | undefined {\n if (!config.app) {\n return config.runtime;\n }\n const nextRuntime: CodemationApplicationRuntimeConfig = {\n ...(config.runtime ?? {}),\n frontendPort: config.app.frontendPort ?? config.runtime?.frontendPort,\n database: this.normalizeDatabaseConfig(config),\n eventBus: this.normalizeEventBusConfig(config),\n scheduler: this.normalizeSchedulerConfig(config),\n engineExecutionLimits: config.app.engineExecutionLimits ?? config.runtime?.engineExecutionLimits,\n };\n return nextRuntime;\n }\n\n private normalizeDatabaseConfig(config: CodemationConfig): CodemationDatabaseConfig | undefined {\n if (!config.app) {\n return config.runtime?.database;\n }\n if (config.app.database) {\n return config.app.database;\n }\n if (!config.app.databaseUrl) {\n return config.runtime?.database;\n }\n return {\n ...(config.runtime?.database ?? {}),\n url: config.app.databaseUrl,\n };\n }\n\n private normalizeSchedulerConfig(config: CodemationConfig): CodemationSchedulerConfig | undefined {\n if (!config.app?.scheduler) {\n return config.runtime?.scheduler;\n }\n const scheduler = config.app.scheduler;\n return {\n ...(config.runtime?.scheduler ?? {}),\n kind:\n scheduler.kind === \"queue\" ? \"bullmq\" : scheduler.kind === \"inline\" ? \"local\" : config.runtime?.scheduler?.kind,\n queuePrefix: scheduler.queuePrefix ?? config.runtime?.scheduler?.queuePrefix,\n workerQueues: scheduler.workerQueues ?? config.runtime?.scheduler?.workerQueues,\n };\n }\n\n private normalizeEventBusConfig(config: CodemationConfig): CodemationEventBusConfig | undefined {\n if (!config.app?.scheduler) {\n return config.runtime?.eventBus;\n }\n const scheduler = config.app.scheduler;\n const eventBusKind =\n scheduler.kind === \"queue\" ? \"redis\" : scheduler.kind === \"inline\" ? \"memory\" : config.runtime?.eventBus?.kind;\n return {\n ...(config.runtime?.eventBus ?? {}),\n kind: eventBusKind,\n queuePrefix: scheduler.queuePrefix ?? config.runtime?.eventBus?.queuePrefix,\n redisUrl: scheduler.redisUrl ?? config.runtime?.eventBus?.redisUrl,\n };\n }\n\n private assertAuthConfig(authConfig: CodemationConfig[\"auth\"]): void {\n if (authConfig?.kind !== \"managed\") {\n return;\n }\n if (authConfig.oauth && authConfig.oauth.length > 0) {\n throw new Error('auth.kind \"managed\" cannot be combined with oauth providers. Remove the oauth config.');\n }\n if (authConfig.oidc && authConfig.oidc.length > 0) {\n throw new Error('auth.kind \"managed\" cannot be combined with oidc providers. Remove the oidc config.');\n }\n if (authConfig.allowUnauthenticatedInDevelopment === true) {\n throw new Error(\n 'auth.kind \"managed\" cannot be combined with allowUnauthenticatedInDevelopment. Remove that flag.',\n );\n }\n }\n\n private mergeWorkflows(\n configuredWorkflows: ReadonlyArray<WorkflowDefinition>,\n registeredWorkflows: ReadonlyArray<WorkflowDefinition>,\n ): ReadonlyArray<WorkflowDefinition> | undefined {\n if (configuredWorkflows.length === 0 && registeredWorkflows.length === 0) {\n return undefined;\n }\n const workflowsById = new Map<string, WorkflowDefinition>();\n for (const workflow of registeredWorkflows) {\n workflowsById.set(workflow.id, workflow);\n }\n for (const workflow of configuredWorkflows) {\n workflowsById.set(workflow.id, workflow);\n }\n return [...workflowsById.values()];\n }\n}\n","import type { CodemationConfig } from \"../config/CodemationConfig\";\n\nexport class CodemationConsumerConfigExportsResolver {\n resolveConfig(moduleExports: Readonly<Record<string, unknown>>): CodemationConfig | null {\n const defaultExport = moduleExports.default;\n if (this.isConfig(defaultExport)) {\n return defaultExport;\n }\n const namedConfig = moduleExports.codemationHost ?? moduleExports.config;\n if (this.isConfig(namedConfig)) {\n return namedConfig;\n }\n return null;\n }\n\n private isConfig(value: unknown): value is CodemationConfig {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n return (\n \"app\" in value ||\n \"register\" in value ||\n \"credentials\" in value ||\n \"runtime\" in value ||\n \"workflows\" in value ||\n \"workflowDiscovery\" in value ||\n \"plugins\" in value ||\n \"whitelabel\" in value ||\n \"auth\" in value ||\n \"log\" in value\n );\n }\n}\n","export class DiscoveredWorkflowsEmptyMessageFactory {\n create(discoveredPaths: ReadonlyArray<string>): string {\n const lines = discoveredPaths.map((p) => ` - ${p}`).join(\"\\n\");\n return [\n `Discovered ${discoveredPaths.length} file(s) under workflow discovery, but none export a WorkflowDefinition.`,\n lines,\n \"\",\n \"Move shared helpers outside the discovery directories (for example src/lib), or export at least one object with id, name, nodes, and edges from a workflow module.\",\n ].join(\"\\n\");\n }\n}\n","import type { WorkflowDefinition } from \"@codemation/core\";\nimport { WorkflowEdgePortValidator } from \"@codemation/core\";\n\n/**\n * Collects exported values that match the {@link WorkflowDefinition} shape.\n * Other exports (helpers, constants, type-only re-exports) are ignored.\n *\n * Throws if any workflow's edges reference output ports not declared by the\n * source node config. All violations are reported at once so an agent can\n * self-correct in a single pass.\n */\nexport class WorkflowDefinitionExportsResolver {\n private readonly portValidator = new WorkflowEdgePortValidator();\n\n resolve(moduleExports: Readonly<Record<string, unknown>>): ReadonlyArray<WorkflowDefinition> {\n const workflows: WorkflowDefinition[] = [];\n for (const exportedValue of Object.values(moduleExports)) {\n if (this.isWorkflowDefinition(exportedValue)) {\n this.validatePorts(exportedValue);\n workflows.push(exportedValue);\n }\n }\n return workflows;\n }\n\n private validatePorts(workflow: WorkflowDefinition): void {\n const result = this.portValidator.validate(workflow);\n if (!result.valid) {\n const lines = result.errors.map((e) => ` - ${e.message}`).join(\"\\n\");\n throw new Error(\n `Workflow \"${workflow.id}\" (\"${workflow.name}\") has ${result.errors.length} invalid edge port(s):\\n${lines}`,\n );\n }\n }\n\n private isWorkflowDefinition(value: unknown): value is WorkflowDefinition {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n return \"id\" in value && \"name\" in value && \"nodes\" in value && \"edges\" in value;\n }\n}\n","import type { WorkflowDefinition } from \"@codemation/core\";\nimport { CodemationConfigNormalizer } from \"../config/CodemationConfigNormalizer\";\nimport type { NormalizedCodemationConfig } from \"../config/CodemationConfigNormalizer\";\nimport { CodemationConsumerConfigExportsResolver } from \"./CodemationConsumerConfigExportsResolver\";\nimport { DiscoveredWorkflowsEmptyMessageFactory } from \"./DiscoveredWorkflowsEmptyMessageFactory\";\nimport { WorkflowDefinitionExportsResolver } from \"./WorkflowDefinitionExportsResolver\";\n\nexport type CodemationConsumerApp = Readonly<{\n config: NormalizedCodemationConfig;\n workflowSources: ReadonlyArray<string>;\n}>;\n\nexport class CodemationConsumerAppResolver {\n private readonly configExportsResolver = new CodemationConsumerConfigExportsResolver();\n private readonly configNormalizer = new CodemationConfigNormalizer();\n private readonly workflowDefinitionExportsResolver = new WorkflowDefinitionExportsResolver();\n private readonly discoveredWorkflowsEmptyMessageFactory = new DiscoveredWorkflowsEmptyMessageFactory();\n\n resolve(\n args: Readonly<{\n configModule: Readonly<Record<string, unknown>>;\n workflowModules: ReadonlyArray<Readonly<Record<string, unknown>>>;\n workflowSourcePaths: ReadonlyArray<string>;\n workflowDiscoveryPathSegmentsList?: ReadonlyArray<readonly string[]>;\n }>,\n ): CodemationConsumerApp {\n const rawConfig = this.configExportsResolver.resolveConfig(args.configModule);\n if (!rawConfig) {\n throw new Error(\"Consumer app module does not export a Codemation config object.\");\n }\n const config = this.configNormalizer.normalize(rawConfig);\n const discoveredWorkflows = this.resolveDiscoveredWorkflows(\n args.workflowModules,\n args.workflowSourcePaths,\n args.workflowDiscoveryPathSegmentsList,\n );\n return {\n config: {\n ...config,\n workflows: this.mergeWorkflows(config.workflows ?? [], discoveredWorkflows),\n },\n workflowSources: args.workflowSourcePaths,\n };\n }\n\n private resolveDiscoveredWorkflows(\n workflowModules: ReadonlyArray<Readonly<Record<string, unknown>>>,\n workflowSourcePaths: ReadonlyArray<string>,\n workflowDiscoveryPathSegmentsList: ReadonlyArray<readonly string[]> | undefined,\n ): ReadonlyArray<WorkflowDefinition> {\n const workflowsById = new Map<string, WorkflowDefinition>();\n workflowModules.forEach((workflowModule: Readonly<Record<string, unknown>>, index: number) => {\n const pathSegments = workflowDiscoveryPathSegmentsList?.[index];\n const workflows = this.workflowDefinitionExportsResolver.resolve(workflowModule);\n workflows.forEach((workflow: WorkflowDefinition) => {\n const enriched =\n pathSegments && pathSegments.length > 0\n ? ({ ...workflow, discoveryPathSegments: pathSegments } satisfies WorkflowDefinition)\n : workflow;\n workflowsById.set(workflow.id, enriched);\n });\n });\n if (workflowsById.size === 0 && workflowSourcePaths.length > 0) {\n throw new Error(this.discoveredWorkflowsEmptyMessageFactory.create(workflowSourcePaths));\n }\n return [...workflowsById.values()];\n }\n\n private mergeWorkflows(\n configuredWorkflows: ReadonlyArray<WorkflowDefinition>,\n discoveredWorkflows: ReadonlyArray<WorkflowDefinition>,\n ): ReadonlyArray<WorkflowDefinition> {\n const workflowsById = new Map<string, WorkflowDefinition>();\n for (const workflow of discoveredWorkflows) {\n workflowsById.set(workflow.id, workflow);\n }\n for (const workflow of configuredWorkflows) {\n workflowsById.set(workflow.id, workflow);\n }\n return [...workflowsById.values()];\n }\n}\n","import { readdir } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nexport class WorkflowModulePathFinder {\n static readonly defaultWorkflowDirectories = [\"src/workflows\", \"workflows\"] as const;\n private readonly workflowExtensions = new Set([\".ts\", \".js\", \".mts\", \".mjs\"]);\n\n async discoverModulePaths(\n args: Readonly<{\n consumerRoot: string;\n workflowDirectories: ReadonlyArray<string> | undefined;\n exists: (absolutePath: string) => Promise<boolean>;\n }>,\n ): Promise<ReadonlyArray<string>> {\n const directories = args.workflowDirectories ?? WorkflowModulePathFinder.defaultWorkflowDirectories;\n const workflowModulePaths: string[] = [];\n for (const directory of directories) {\n const absoluteDirectory = path.resolve(args.consumerRoot, directory);\n if (!(await args.exists(absoluteDirectory))) {\n continue;\n }\n workflowModulePaths.push(...(await this.collectWorkflowModulePaths(absoluteDirectory)));\n }\n return workflowModulePaths;\n }\n\n private async collectWorkflowModulePaths(directoryPath: string): Promise<ReadonlyArray<string>> {\n const entries = await readdir(directoryPath, { withFileTypes: true });\n const workflowModulePaths: string[] = [];\n for (const entry of entries) {\n const entryPath = path.resolve(directoryPath, entry.name);\n if (entry.isDirectory()) {\n workflowModulePaths.push(...(await this.collectWorkflowModulePaths(entryPath)));\n continue;\n }\n if (this.isWorkflowModulePath(entryPath)) {\n workflowModulePaths.push(entryPath);\n }\n }\n return workflowModulePaths;\n }\n\n private isWorkflowModulePath(modulePath: string): boolean {\n const extension = path.extname(modulePath);\n if (!this.workflowExtensions.has(extension)) {\n return false;\n }\n const basename = path.basename(modulePath);\n if (basename.endsWith(\".d.ts\") || basename.endsWith(\".d.mts\")) {\n return false;\n }\n const withoutExt = basename.slice(0, -extension.length);\n if (withoutExt.endsWith(\".test\") || withoutExt.endsWith(\".spec\")) {\n return false;\n }\n return true;\n }\n}\n","import path from \"node:path\";\n\nimport { WorkflowModulePathFinder } from \"./WorkflowModulePathFinder\";\n\nexport class WorkflowDiscoveryPathSegmentsComputer {\n compute(\n args: Readonly<{\n consumerRoot: string;\n workflowDiscoveryDirectories: ReadonlyArray<string>;\n absoluteWorkflowModulePath: string;\n }>,\n ): readonly string[] | undefined {\n const normalizedConsumer = path.resolve(args.consumerRoot);\n const normalizedWorkflowPath = path.resolve(args.absoluteWorkflowModulePath);\n const directories =\n args.workflowDiscoveryDirectories.length > 0\n ? args.workflowDiscoveryDirectories\n : [...WorkflowModulePathFinder.defaultWorkflowDirectories];\n\n let bestRoot: string | null = null;\n for (const directory of directories) {\n const absoluteDirectory = path.resolve(normalizedConsumer, directory);\n const isPrefix =\n normalizedWorkflowPath === absoluteDirectory ||\n normalizedWorkflowPath.startsWith(`${absoluteDirectory}${path.sep}`);\n if (!isPrefix) {\n continue;\n }\n if (!bestRoot || absoluteDirectory.length > bestRoot.length) {\n bestRoot = absoluteDirectory;\n }\n }\n if (!bestRoot) {\n return undefined;\n }\n const relative = path.relative(bestRoot, normalizedWorkflowPath);\n if (relative.startsWith(\"..\") || path.isAbsolute(relative)) {\n return undefined;\n }\n if (relative.length === 0) {\n return undefined;\n }\n const parts = relative.split(path.sep).filter((segment) => segment.length > 0);\n if (parts.length === 0) {\n return undefined;\n }\n const lastIndex = parts.length - 1;\n const last = parts[lastIndex] ?? \"\";\n const ext = path.extname(last);\n parts[lastIndex] = ext ? last.slice(0, -ext.length) : last;\n return parts;\n }\n}\n","import type { WorkflowDefinition } from \"@codemation/core\";\nimport { access, stat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport type { NamespacedUnregister } from \"tsx/esm/api\";\nimport type { CodemationConfig } from \"../config/CodemationConfig\";\nimport { CodemationConfigNormalizer } from \"../config/CodemationConfigNormalizer\";\nimport type { NormalizedCodemationConfig } from \"../config/CodemationConfigNormalizer\";\nimport { BootTimer } from \"../../bootstrap/perf/BootTimer\";\nimport { logLevelPolicyFactory } from \"../../infrastructure/logging/LogLevelPolicyFactory\";\nimport { ServerLoggerFactory } from \"../../infrastructure/logging/ServerLoggerFactory\";\nimport { DiscoveredWorkflowsEmptyMessageFactory } from \"./DiscoveredWorkflowsEmptyMessageFactory\";\nimport { CodemationConsumerConfigExportsResolver } from \"./CodemationConsumerConfigExportsResolver\";\nimport { WorkflowDefinitionExportsResolver } from \"./WorkflowDefinitionExportsResolver\";\nimport { WorkflowDiscoveryPathSegmentsComputer } from \"./WorkflowDiscoveryPathSegmentsComputer\";\nimport { WorkflowModulePathFinder } from \"./WorkflowModulePathFinder\";\n\nexport type CodemationConsumerConfigResolution = Readonly<{\n config: NormalizedCodemationConfig;\n bootstrapSource: string | null;\n workflowSources: ReadonlyArray<string>;\n}>;\n\ntype ConsumerImportSession = Readonly<{\n shouldResetImporter: boolean;\n resetCacheKeys: Set<string>;\n}>;\n\nexport class CodemationConsumerConfigLoader {\n private static readonly importerRegistrationsByTsconfig = new Map<string, NamespacedUnregister>();\n private static readonly importerNamespaceVersionByTsconfig = new Map<string, number>();\n private readonly configExportsResolver = new CodemationConsumerConfigExportsResolver();\n private readonly configNormalizer = new CodemationConfigNormalizer();\n private readonly workflowModulePathFinder = new WorkflowModulePathFinder();\n private readonly workflowDefinitionExportsResolver = new WorkflowDefinitionExportsResolver();\n private readonly discoveredWorkflowsEmptyMessageFactory = new DiscoveredWorkflowsEmptyMessageFactory();\n private readonly pathSegmentsComputer = new WorkflowDiscoveryPathSegmentsComputer();\n private readonly performanceDiagnosticsLogger = new ServerLoggerFactory(\n logLevelPolicyFactory,\n ).createPerformanceDiagnostics(\"codemation-config-loader.timing\");\n /**\n * In-flight + completed load promises keyed by `${consumerRoot}|${configPathOverride}`. The\n * boot path constructs MULTIPLE CodemationConsumerConfigLoader instances (one inside the CLI's\n * DatabaseMigrationsApplyService, another inside NextHostEdgeSeedLoader, another inside\n * AppConfigLoader for the disposable runtime) and each independently calls `load(...)`. Without\n * a cache shared across instances, the same `${consumerRoot}` ends up importing\n * codemation.config.ts + discovered workflow modules ~3 times for a single dev boot. The cache\n * has to be static so it spans every loader instance in the process.\n *\n * Callers MUST invoke `invalidateAll()` on a source-change reload — the dev source watcher\n * already tears the runtime down and reboots; it just needs to clear this map first.\n */\n private static readonly resolutionCache = new Map<string, Promise<CodemationConsumerConfigResolution>>();\n\n static invalidateAll(): void {\n this.resolutionCache.clear();\n }\n\n async load(\n args: Readonly<{ consumerRoot: string; configPathOverride?: string }>,\n ): Promise<CodemationConsumerConfigResolution> {\n const cacheKey = `${args.consumerRoot}|${args.configPathOverride ?? \"\"}`;\n const cached = CodemationConsumerConfigLoader.resolutionCache.get(cacheKey);\n if (cached) {\n return cached;\n }\n const promise = this.loadUncached(args);\n CodemationConsumerConfigLoader.resolutionCache.set(cacheKey, promise);\n try {\n return await promise;\n } catch (error) {\n // A failed load shouldn't poison the cache — future retries should re-attempt.\n CodemationConsumerConfigLoader.resolutionCache.delete(cacheKey);\n throw error;\n }\n }\n\n private async loadUncached(\n args: Readonly<{ consumerRoot: string; configPathOverride?: string }>,\n ): Promise<CodemationConsumerConfigResolution> {\n const loadStarted = performance.now();\n let mark = loadStarted;\n const importSession = this.createImportSession();\n const phaseDurations = new Map<string, number>();\n const phaseMs = (label: string): void => {\n const now = performance.now();\n const delta = now - mark;\n mark = now;\n phaseDurations.set(label, delta);\n this.performanceDiagnosticsLogger.info(\n `load.${label} +${delta.toFixed(1)}ms (cumulative ${(now - loadStarted).toFixed(1)}ms)`,\n );\n };\n const bootstrapSource = await BootTimer.measureAsync(\"config.resolveConfigPath\", () =>\n this.resolveConfigPath(args.consumerRoot, args.configPathOverride),\n );\n phaseMs(\"resolveConfigPath\");\n if (!bootstrapSource) {\n throw new Error(\n 'Codemation config not found. Expected \"codemation.config.ts\" in the consumer project root or \"src/\".',\n );\n }\n const moduleExports = await BootTimer.measureAsync(\"config.importConfigModule\", () =>\n this.importModule(bootstrapSource, importSession),\n );\n phaseMs(\"importConfigModule\");\n const rawConfig = this.configExportsResolver.resolveConfig(moduleExports);\n if (!rawConfig) {\n throw new Error(`Config file does not export a Codemation config object: ${bootstrapSource}`);\n }\n const config = this.configNormalizer.normalize(rawConfig);\n const workflowSources = await BootTimer.measureAsync(\"config.resolveWorkflowSources\", () =>\n this.resolveWorkflowSources(args.consumerRoot, config),\n );\n phaseMs(\"resolveWorkflowSources\");\n const workflows = await BootTimer.measureAsync(\"config.loadDiscoveredWorkflows\", async () =>\n this.mergeWorkflows(\n config.workflows ?? [],\n await this.loadDiscoveredWorkflows(args.consumerRoot, config, workflowSources, importSession),\n ),\n );\n phaseMs(\"loadDiscoveredWorkflows\");\n const resolvedConfig: NormalizedCodemationConfig = {\n ...config,\n workflows,\n };\n logLevelPolicyFactory.create().applyCodemationLogConfig(resolvedConfig.log);\n return {\n config: resolvedConfig,\n bootstrapSource,\n workflowSources,\n };\n }\n\n private async resolveConfigPath(\n consumerRoot: string,\n configPathOverride: string | undefined,\n ): Promise<string | null> {\n if (configPathOverride) {\n const explicitPath = path.isAbsolute(configPathOverride)\n ? configPathOverride\n : path.resolve(consumerRoot, configPathOverride);\n if (!(await this.exists(explicitPath))) {\n throw new Error(`Config file not found: ${explicitPath}`);\n }\n return explicitPath;\n }\n for (const candidate of this.getConventionCandidates(consumerRoot)) {\n if (await this.exists(candidate)) {\n return candidate;\n }\n }\n return null;\n }\n\n private getConventionCandidates(consumerRoot: string): ReadonlyArray<string> {\n return [\n path.resolve(consumerRoot, \"codemation.config.ts\"),\n path.resolve(consumerRoot, \"codemation.config.js\"),\n path.resolve(consumerRoot, \"src\", \"codemation.config.ts\"),\n path.resolve(consumerRoot, \"src\", \"codemation.config.js\"),\n ];\n }\n\n private async resolveWorkflowSources(consumerRoot: string, config: CodemationConfig): Promise<ReadonlyArray<string>> {\n if ((config.workflowDiscovery?.directories?.length ?? 0) === 0) {\n return [];\n }\n const discoveredPaths = await this.workflowModulePathFinder.discoverModulePaths({\n consumerRoot,\n workflowDirectories: config.workflowDiscovery?.directories,\n exists: (absolutePath) => this.exists(absolutePath),\n });\n return [...discoveredPaths].sort((left: string, right: string) => left.localeCompare(right));\n }\n\n private async loadDiscoveredWorkflows(\n consumerRoot: string,\n config: CodemationConfig,\n workflowSources: ReadonlyArray<string>,\n importSession: ConsumerImportSession,\n ): Promise<ReadonlyArray<WorkflowDefinition>> {\n const workflowDiscoveryDirectories = config.workflowDiscovery?.directories ?? [];\n const workflowsById = new Map<string, WorkflowDefinition>();\n const loadedWorkflowModules = await Promise.all(\n workflowSources.map(async (workflowSource: string) => ({\n workflowSource,\n segments: this.pathSegmentsComputer.compute({\n consumerRoot,\n workflowDiscoveryDirectories,\n absoluteWorkflowModulePath: workflowSource,\n }),\n moduleExports: await BootTimer.measureAsync(`workflow.${path.basename(workflowSource).replace(/\\.tsx?$/, \"\")}`, () =>\n this.importModule(workflowSource, importSession),\n ),\n })),\n );\n for (const loadedWorkflowModule of loadedWorkflowModules) {\n for (const workflow of this.workflowDefinitionExportsResolver.resolve(loadedWorkflowModule.moduleExports)) {\n const enriched =\n loadedWorkflowModule.segments && loadedWorkflowModule.segments.length > 0\n ? ({ ...workflow, discoveryPathSegments: loadedWorkflowModule.segments } satisfies WorkflowDefinition)\n : workflow;\n workflowsById.set(workflow.id, enriched);\n }\n }\n if (workflowsById.size === 0 && workflowSources.length > 0) {\n throw new Error(this.discoveredWorkflowsEmptyMessageFactory.create(workflowSources));\n }\n return [...workflowsById.values()];\n }\n\n private mergeWorkflows(\n configuredWorkflows: ReadonlyArray<WorkflowDefinition>,\n discoveredWorkflows: ReadonlyArray<WorkflowDefinition>,\n ): ReadonlyArray<WorkflowDefinition> {\n const workflowsById = new Map<string, WorkflowDefinition>();\n for (const workflow of discoveredWorkflows) {\n workflowsById.set(workflow.id, workflow);\n }\n for (const workflow of configuredWorkflows) {\n workflowsById.set(workflow.id, workflow);\n }\n return [...workflowsById.values()];\n }\n\n private async importModule(\n modulePath: string,\n importSession: ConsumerImportSession,\n ): Promise<Record<string, unknown>> {\n if (this.shouldUseNativeRuntimeImport()) {\n return await this.importModuleWithNativeRuntime(modulePath);\n }\n const tsconfigPath = await this.resolveTsconfigPath(modulePath);\n const cacheKey = tsconfigPath || \"default\";\n const shouldResetImporter = importSession.shouldResetImporter;\n const didResetImporterForThisImport = shouldResetImporter && !importSession.resetCacheKeys.has(cacheKey);\n if (didResetImporterForThisImport) {\n await this.resetImporter(tsconfigPath);\n importSession.resetCacheKeys.add(cacheKey);\n }\n const importSpecifier = await this.createImportSpecifier(modulePath);\n for (let attempt = 0; attempt < 3; attempt += 1) {\n try {\n const importedModule = await (\n await this.getOrCreateImporter(tsconfigPath)\n ).import(importSpecifier, import.meta.url);\n return importedModule as Record<string, unknown>;\n } catch (error) {\n if (!this.isStoppedTransformServiceError(error) || attempt === 2) {\n throw error;\n }\n await this.resetImporter(tsconfigPath);\n }\n }\n throw new Error(`Failed to import consumer module after retries: ${modulePath}`);\n }\n\n private async importModuleWithNativeRuntime(modulePath: string): Promise<Record<string, unknown>> {\n const importedModule = await import(await this.createImportSpecifier(modulePath));\n return importedModule as Record<string, unknown>;\n }\n\n private async resolveTsconfigPath(modulePath: string): Promise<string | false> {\n const overridePath = process.env.CODEMATION_TSCONFIG_PATH;\n if (overridePath && (await this.exists(overridePath))) {\n return overridePath;\n }\n const discoveredPath = await this.findNearestTsconfig(modulePath);\n return discoveredPath ?? false;\n }\n\n private async getOrCreateImporter(tsconfigPath: string | false): Promise<NamespacedUnregister> {\n const cacheKey = tsconfigPath || \"default\";\n const existingImporter = CodemationConsumerConfigLoader.importerRegistrationsByTsconfig.get(cacheKey);\n if (existingImporter) {\n return existingImporter;\n }\n const { register } = await import(/* webpackIgnore: true */ this.resolveTsxImporterModuleSpecifier());\n const namespaceVersion = this.nextNamespaceVersion(cacheKey);\n const nextImporter = register({\n // A fresh namespace prevents cache hits from prior scoped imports after a dev rebuild.\n namespace: this.toNamespace(cacheKey, namespaceVersion),\n tsconfig: tsconfigPath,\n });\n CodemationConsumerConfigLoader.importerRegistrationsByTsconfig.set(cacheKey, nextImporter);\n return nextImporter;\n }\n\n private async resetImporter(tsconfigPath: string | false): Promise<void> {\n const cacheKey = tsconfigPath || \"default\";\n const existingImporter = CodemationConsumerConfigLoader.importerRegistrationsByTsconfig.get(cacheKey);\n if (!existingImporter) {\n return;\n }\n CodemationConsumerConfigLoader.importerRegistrationsByTsconfig.delete(cacheKey);\n await existingImporter.unregister().catch(() => null);\n }\n\n private nextNamespaceVersion(cacheKey: string): number {\n const nextVersion = (CodemationConsumerConfigLoader.importerNamespaceVersionByTsconfig.get(cacheKey) ?? 0) + 1;\n CodemationConsumerConfigLoader.importerNamespaceVersionByTsconfig.set(cacheKey, nextVersion);\n return nextVersion;\n }\n\n private toNamespace(cacheKey: string, namespaceVersion: number): string {\n return `codemation_consumer_${cacheKey.replace(/[^a-zA-Z0-9_-]+/g, \"_\")}_${namespaceVersion}`;\n }\n\n private resolveTsxImporterModuleSpecifier(): string {\n return [\"tsx\", \"esm\", \"api\"].join(\"/\");\n }\n\n private async findNearestTsconfig(modulePath: string): Promise<string | null> {\n let currentDirectory = path.dirname(modulePath);\n while (true) {\n const candidate = path.resolve(currentDirectory, \"tsconfig.json\");\n if (await this.exists(candidate)) {\n return candidate;\n }\n const parentDirectory = path.dirname(currentDirectory);\n if (parentDirectory === currentDirectory) {\n return null;\n }\n currentDirectory = parentDirectory;\n }\n }\n\n private async createImportSpecifier(modulePath: string): Promise<string> {\n const moduleUrl = pathToFileURL(modulePath);\n const moduleStats = await stat(modulePath);\n moduleUrl.searchParams.set(\"t\", String(moduleStats.mtimeMs));\n return moduleUrl.href;\n }\n\n private shouldUseNativeRuntimeImport(): boolean {\n return process.env.CODEMATION_TS_RUNTIME === \"ts-node\";\n }\n\n private shouldResetImporterBeforeImport(): boolean {\n return (process.env.CODEMATION_DEV_SERVER_TOKEN?.trim().length ?? 0) > 0;\n }\n\n private createImportSession(): ConsumerImportSession {\n return {\n resetCacheKeys: new Set<string>(),\n shouldResetImporter: this.shouldResetImporterBeforeImport(),\n };\n }\n\n private isStoppedTransformServiceError(error: unknown): boolean {\n return error instanceof Error && error.message.includes(\"The service is no longer running\");\n }\n\n private async exists(filePath: string): Promise<boolean> {\n try {\n await access(filePath);\n return true;\n } catch {\n return false;\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"CredentialServices-Dk8yypeL.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, 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} 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 : { definition, createSession: this.createUnsupportedSessionFactory(definition.typeId, source), test: this.createUnsupportedHealthTester(definition.typeId, source) };\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(source: CredentialTypeSource, type: AnyCredentialType, logger: ReturnType<LoggerFactory[\"create\"]>): 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(typeId: CredentialTypeId, source: CredentialTypeSource): 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(typeId: CredentialTypeId, source: CredentialTypeSource): 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 instance: CredentialInstanceRecord = {\n instanceId: randomUUID(),\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 };\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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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"InternalPingRegistrar-DY3kSfxP.js","names":["HmacRequestSigner","config: PairingConfig","PairedFetch","signer: HmacRequestSigner","IncomingHmacVerifier","config: PairingConfig","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/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) private readonly config: PairingConfig) {}\n\n sign(method: string, urlOrPath: string, body: string): SignedHeaders {\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 { createHmac, createHash, timingSafeEqual } from \"node:crypto\";\nimport { inject, injectable } from \"@codemation/core\";\nimport type { PairingConfig, PairingVerificationResult } from \"./pairing.types\";\nimport { PairingConfigToken } from \"./PairingConfigToken\";\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@injectable()\nexport class IncomingHmacVerifier {\n private readonly usedNonces = new Map<string, number>();\n private readonly nonceTtlSeconds = 600; // 10 minutes\n\n constructor(@inject(PairingConfigToken) private readonly config: PairingConfig) {}\n\n verify(method: string, url: string, body: string, authHeader: string | null): PairingVerificationResult {\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 this.pruneExpiredNonces(nowSec);\n const nonceKey = `${parts.workspaceId}:${parts.nonce}`;\n if (this.usedNonces.has(nonceKey)) return { failure: \"replay\" };\n this.usedNonces.set(nonceKey, nowSec + this.nonceTtlSeconds);\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 private pruneExpiredNonces(nowSec: number): void {\n for (const [key, expiry] of this.usedNonces.entries()) {\n if (expiry <= nowSec) this.usedNonces.delete(key);\n }\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 = 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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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"persistenceServer-C-hH4z6l.js","names":["PrismaClient"],"sources":["../src/infrastructure/persistence/CodemationPostgresPrismaClientFactory.ts"],"sourcesContent":["import { PrismaPg } from \"@prisma/adapter-pg\";\nimport { PrismaClient } from \"../../../prisma-generated/prisma-postgresql-client/client.js\";\n\nexport class CodemationPostgresPrismaClientFactory {\n static create(databaseUrl: string): PrismaClient {\n const adapter = new PrismaPg({ connectionString: databaseUrl });\n return new PrismaClient({ adapter });\n }\n}\n"],"mappings":";;;;;;AAGA,IAAa,wCAAb,MAAmD;CACjD,OAAO,OAAO,aAAmC;AAE/C,SAAO,IAAIA,2BAAa,EAAE,SADV,IAAI,SAAS,EAAE,kBAAkB,aAAa,CAAC,EAC5B,CAAC"}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { i as AppPersistenceConfig } from "./CodemationAppContext-CKVv9W9q.js";
|
|
2
|
-
import { i as PrismaClient } from "./AppConfigFactory-DnLoQ9Li.js";
|
|
3
|
-
|
|
4
|
-
//#region src/infrastructure/persistence/CodemationPostgresPrismaClientFactory.d.ts
|
|
5
|
-
declare class CodemationPostgresPrismaClientFactory {
|
|
6
|
-
static create(databaseUrl: string): PrismaClient;
|
|
7
|
-
}
|
|
8
|
-
//#endregion
|
|
9
|
-
//#region src/infrastructure/persistence/CodemationDatabaseUrlParser.d.ts
|
|
10
|
-
/**
|
|
11
|
-
* Parses `CODEMATION_DATABASE_URL` into an {@link AppPersistenceConfig}.
|
|
12
|
-
*
|
|
13
|
-
* Supported schemes (case-insensitive):
|
|
14
|
-
* - `sqlite://relative/path/to/file.db` → resolved relative to consumerRoot
|
|
15
|
-
* - `sqlite:///absolute/path/to/file.db` → leading slash = POSIX absolute
|
|
16
|
-
* - `sqlite://C:/path/file.db` → Windows-style absolute (path.isAbsolute()
|
|
17
|
-
* returns true for these)
|
|
18
|
-
* - `pgsql://user:pass@host:5432/dbname` → normalised to postgresql://
|
|
19
|
-
* - `postgresql://user:pass@host:5432/db` → pass-through (Prisma's expected scheme)
|
|
20
|
-
* - `postgres://user:pass@host:5432/db` → pass-through (common alias)
|
|
21
|
-
*
|
|
22
|
-
* Throws on any other scheme. Empty / whitespace input is also an error — callers
|
|
23
|
-
* should default before calling parse().
|
|
24
|
-
*/
|
|
25
|
-
declare class CodemationDatabaseUrlParser {
|
|
26
|
-
parse(url: string, consumerRoot: string): AppPersistenceConfig;
|
|
27
|
-
}
|
|
28
|
-
//#endregion
|
|
29
|
-
export { CodemationPostgresPrismaClientFactory as n, CodemationDatabaseUrlParser as t };
|
|
30
|
-
//# sourceMappingURL=persistenceServer-CeTHtC6E.d.ts.map
|