@shipfox/api-integration-core 8.0.0 → 9.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/.turbo/turbo-build.log +4 -4
  2. package/CHANGELOG.md +101 -0
  3. package/dist/core/agent-tool-selection.d.ts +1 -1
  4. package/dist/core/agent-tool-selection.d.ts.map +1 -1
  5. package/dist/core/agent-tool-selection.js.map +1 -1
  6. package/dist/core/entities/connection.d.ts +1 -1
  7. package/dist/core/entities/connection.d.ts.map +1 -1
  8. package/dist/core/entities/connection.js.map +1 -1
  9. package/dist/core/entities/provider.d.ts +2 -2
  10. package/dist/core/entities/provider.d.ts.map +1 -1
  11. package/dist/core/entities/provider.js.map +1 -1
  12. package/dist/core/errors.d.ts +1 -1
  13. package/dist/core/errors.d.ts.map +1 -1
  14. package/dist/core/errors.js +1 -1
  15. package/dist/core/errors.js.map +1 -1
  16. package/dist/core/providers/agent-tools.d.ts +1 -1
  17. package/dist/core/providers/agent-tools.d.ts.map +1 -1
  18. package/dist/core/providers/agent-tools.js.map +1 -1
  19. package/dist/core/providers/redact-checkout-spec.d.ts +1 -1
  20. package/dist/core/providers/redact-checkout-spec.d.ts.map +1 -1
  21. package/dist/core/providers/redact-checkout-spec.js.map +1 -1
  22. package/dist/core/providers/source-control.d.ts +1 -1
  23. package/dist/core/providers/source-control.d.ts.map +1 -1
  24. package/dist/core/providers/source-control.js.map +1 -1
  25. package/dist/db/connections.d.ts.map +1 -1
  26. package/dist/db/connections.js +2 -1
  27. package/dist/db/connections.js.map +1 -1
  28. package/dist/db/webhook-deliveries.d.ts +1 -1
  29. package/dist/db/webhook-deliveries.d.ts.map +1 -1
  30. package/dist/db/webhook-deliveries.js +1 -1
  31. package/dist/db/webhook-deliveries.js.map +1 -1
  32. package/dist/index.d.ts +3 -3
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +4 -3
  35. package/dist/index.js.map +1 -1
  36. package/dist/presentation/dto/integrations.d.ts +2 -2
  37. package/dist/presentation/dto/integrations.d.ts.map +1 -1
  38. package/dist/presentation/dto/integrations.js +18 -2
  39. package/dist/presentation/dto/integrations.js.map +1 -1
  40. package/dist/presentation/routes/list-connections.js +1 -1
  41. package/dist/presentation/routes/list-connections.js.map +1 -1
  42. package/dist/presentation/routes/list-providers.js +1 -1
  43. package/dist/presentation/routes/list-providers.js.map +1 -1
  44. package/dist/presentation/routes/list-repositories.js +1 -1
  45. package/dist/presentation/routes/list-repositories.js.map +1 -1
  46. package/dist/presentation/routes/manage-connections.js +1 -1
  47. package/dist/presentation/routes/manage-connections.js.map +1 -1
  48. package/dist/providers/connection-slug.d.ts +3 -0
  49. package/dist/providers/connection-slug.d.ts.map +1 -1
  50. package/dist/providers/connection-slug.js +10 -1
  51. package/dist/providers/connection-slug.js.map +1 -1
  52. package/dist/providers/gitea.d.ts.map +1 -1
  53. package/dist/providers/gitea.js +2 -8
  54. package/dist/providers/gitea.js.map +1 -1
  55. package/dist/providers/github.d.ts.map +1 -1
  56. package/dist/providers/github.js +2 -8
  57. package/dist/providers/github.js.map +1 -1
  58. package/dist/providers/jira.d.ts.map +1 -1
  59. package/dist/providers/jira.js +2 -4
  60. package/dist/providers/jira.js.map +1 -1
  61. package/dist/providers/linear.d.ts.map +1 -1
  62. package/dist/providers/linear.js +2 -4
  63. package/dist/providers/linear.js.map +1 -1
  64. package/dist/providers/sentry.d.ts.map +1 -1
  65. package/dist/providers/sentry.js +2 -8
  66. package/dist/providers/sentry.js.map +1 -1
  67. package/dist/providers/slack.d.ts.map +1 -1
  68. package/dist/providers/slack.js +2 -4
  69. package/dist/providers/slack.js.map +1 -1
  70. package/dist/providers/types.d.ts +1 -1
  71. package/dist/providers/types.d.ts.map +1 -1
  72. package/dist/providers/types.js.map +1 -1
  73. package/dist/tsconfig.test.tsbuildinfo +1 -1
  74. package/package.json +37 -29
  75. package/src/core/agent-tool-selection.ts +1 -1
  76. package/src/core/entities/connection.ts +1 -1
  77. package/src/core/entities/provider.ts +2 -2
  78. package/src/core/errors.ts +1 -1
  79. package/src/core/providers/agent-tools.ts +1 -1
  80. package/src/core/providers/redact-checkout-spec.test.ts +1 -1
  81. package/src/core/providers/redact-checkout-spec.ts +1 -1
  82. package/src/core/providers/source-control.ts +1 -1
  83. package/src/db/connections.test.ts +1 -1
  84. package/src/db/connections.ts +2 -4
  85. package/src/db/webhook-deliveries.test.ts +1 -1
  86. package/src/db/webhook-deliveries.ts +1 -1
  87. package/src/index.test.ts +1 -4
  88. package/src/index.ts +4 -4
  89. package/src/presentation/dto/integrations.ts +21 -2
  90. package/src/presentation/routes/list-connections.ts +1 -1
  91. package/src/presentation/routes/list-providers.ts +1 -1
  92. package/src/presentation/routes/list-repositories.ts +1 -1
  93. package/src/presentation/routes/manage-connections.ts +1 -1
  94. package/src/providers/connection-slug.ts +18 -1
  95. package/src/providers/gitea.ts +3 -12
  96. package/src/providers/github.ts +3 -12
  97. package/src/providers/jira.test.ts +1 -1
  98. package/src/providers/jira.ts +3 -7
  99. package/src/providers/linear.test.ts +2 -2
  100. package/src/providers/linear.ts +3 -7
  101. package/src/providers/sentry.ts +3 -12
  102. package/src/providers/slack.test.ts +3 -3
  103. package/src/providers/slack.ts +3 -7
  104. package/src/providers/types.ts +1 -1
  105. package/tsconfig.build.tsbuildinfo +1 -1
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {dirname, resolve} from 'node:path';\nimport {fileURLToPath} from 'node:url';\nimport {\n integrationsEventSchemas,\n type StoredWebhookRequest,\n type WebhookProcessingResult,\n type WebhookRequestProcessor,\n type WebhookRouteId,\n} from '@shipfox/api-integration-core-dto';\nimport type {WorkflowsModuleClient} from '@shipfox/api-workflows-dto/inter-module';\nimport type {WorkspacesInterModuleClient} from '@shipfox/api-workspaces-dto/inter-module';\nimport {reportError} from '@shipfox/node-error-monitoring';\nimport type {ModuleService, ShipfoxModule} from '@shipfox/node-module';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport type {IntegrationProvider} from '#core/entities/provider.js';\nimport {WebhookProcessorNotConfiguredError} from '#core/errors.js';\nimport {\n createIntegrationProviderRegistry,\n type IntegrationProviderRegistry,\n} from '#core/providers/registry.js';\nimport {\n createSourceControlIntegrationService,\n type IntegrationSourceControlService,\n} from '#core/source-control-service.js';\nimport {getIntegrationConnectionById} from '#db/connections.js';\nimport {db} from '#db/db.js';\nimport {migrationsPath} from '#db/migrations.js';\nimport {integrationsOutbox} from '#db/schema/outbox.js';\nimport {createIntegrationsInterModulePresentation} from '#presentation/inter-module.js';\nimport {createIntegrationRoutes} from '#presentation/routes/index.js';\nimport {loadEnabledProviderModules} from '#providers/modules.js';\nimport type {\n IntegrationModuleParts,\n IntegrationProviderSecrets,\n WebhookProcessorRegistration,\n} from '#providers/types.js';\nimport {createIntegrationsMaintenanceActivities} from '#temporal/activities/index.js';\nimport {INTEGRATIONS_MAINTENANCE_TASK_QUEUE} from '#temporal/constants.js';\n\nconst packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');\nconst maintenanceWorkflowsPath = resolve(packageRoot, 'dist/temporal/workflows/index.js');\n\nexport type {\n StoredWebhookRequest,\n WebhookProcessingResult,\n WebhookRequestProcessor,\n WebhookRouteId,\n} from '@shipfox/api-integration-core-dto';\nexport {\n buildProviderRepositoryId,\n MAX_REPOSITORY_FILE_BYTES,\n parseProviderRepositoryId,\n} from '@shipfox/api-integration-core-dto';\nexport type {\n AgentToolCatalogs,\n AgentToolSelectionCatalogs,\n LoadWorkspaceConnectionSnapshot,\n WorkspaceConnectionSnapshot,\n WorkspaceConnectionSnapshotEntry,\n} from '#core/agent-tool-selection.js';\nexport {\n buildAgentToolCatalogs,\n buildAgentToolSelectionCatalogs,\n createWorkspaceConnectionSnapshotLoader,\n} from '#core/agent-tool-selection.js';\nexport type {\n IntegrationConnection,\n IntegrationConnectionLifecycleStatus,\n} from '#core/entities/connection.js';\nexport type {\n IntegrationCapability,\n IntegrationProvider,\n IntegrationProviderAdapters,\n IntegrationProviderKind,\n RegisteredIntegrationProvider,\n} from '#core/entities/provider.js';\nexport type {IntegrationProviderErrorReason} from '#core/errors.js';\nexport {\n ConnectionSlugConflictError,\n IntegrationCapabilityUnavailableError,\n IntegrationCheckoutUnsupportedError,\n IntegrationConnectionInactiveError,\n IntegrationConnectionNotFoundError,\n IntegrationConnectionWorkspaceMismatchError,\n IntegrationProviderError,\n IntegrationProviderUnavailableError,\n WebhookProcessorNotConfiguredError,\n} from '#core/errors.js';\nexport type {\n AgentToolCallInput,\n AgentToolCatalogEntry,\n AgentToolCatalogMethod,\n AgentToolJsonSchema,\n AgentToolSensitivity,\n AgentToolSession,\n AgentToolsProvider,\n OpenAgentToolsSessionInput,\n} from '#core/providers/agent-tools.js';\nexport {redactCheckoutSpec} from '#core/providers/redact-checkout-spec.js';\nexport type {IntegrationProviderRegistry} from '#core/providers/registry.js';\nexport type {\n CheckoutCredentials,\n CheckoutPermissions,\n CheckoutSpec,\n CreateCheckoutSpecInput,\n FetchFileInput,\n FileEntry,\n FilePage,\n FileSnapshot,\n ListFilesInput,\n ListRepositoriesInput,\n RepositoryPage,\n RepositorySnapshot,\n RepositoryVisibility,\n ResolveRepositoryInput,\n SourceControlProvider,\n} from '#core/providers/source-control.js';\nexport type {IntegrationSourceControlService} from '#core/source-control-service.js';\nexport {createSourceControlIntegrationService} from '#core/source-control-service.js';\nexport type {GetIntegrationConnectionByIdFn} from '#db/connections.js';\nexport {getIntegrationConnectionById} from '#db/connections.js';\nexport type {\n ClaimWebhookDeliveryFn,\n PublishIntegrationEventReceivedFn,\n PublishIntegrationEventReceivedParams,\n PublishIntegrationEventReceivedResult,\n PublishSourcePushFn,\n PublishSourcePushParams,\n RecordDeliveryOnlyFn,\n RecordDeliveryOnlyParams,\n} from '#db/webhook-deliveries.js';\nexport {claimWebhookDelivery, pruneWebhookDeliveries} from '#db/webhook-deliveries.js';\nexport {integrationRouteErrorHandler} from '#presentation/routes/errors.js';\n\nexport interface CreateIntegrationsModuleOptions {\n providers?: IntegrationProvider[] | undefined;\n /**\n * Pre-built module parts, bypassing config-gated provider loading. Test-only seam\n * for exercising a provider's database, workers, or startup tasks directly. Takes\n * precedence over `providers`.\n */\n parts?: IntegrationModuleParts[] | undefined;\n secrets?: IntegrationProviderSecrets | undefined;\n workspaces?: WorkspacesInterModuleClient | undefined;\n agentTools?:\n | {\n workflows: WorkflowsModuleClient;\n }\n | undefined;\n webhookDeliverySource?: WebhookDeliverySource | undefined;\n}\n\n/**\n * Hosted runtimes implement this port to receive stored webhook requests. The\n * integration module starts its returned service after migrations complete.\n */\nexport interface WebhookDeliverySource {\n createService(processor: WebhookRequestProcessor): ModuleService;\n}\n\nexport interface IntegrationsContext {\n module: ShipfoxModule;\n registry: IntegrationProviderRegistry;\n capabilities: {\n sourceControl: IntegrationSourceControlService;\n };\n sourceControl: IntegrationSourceControlService;\n webhookProcessor: WebhookRequestProcessor;\n /**\n * Runs every enabled provider's one-shot boot-time tasks, after modules are initialized\n * (migrations done). Failures are isolated and logged, never rethrown, so a provider task\n * can never gate API boot. No-op when no enabled provider contributes a task.\n */\n runStartupTasks: () => Promise<void>;\n}\n\nexport async function createIntegrationsModule(\n options: CreateIntegrationsModuleOptions = {},\n): Promise<ShipfoxModule> {\n return (await createIntegrationsContext(options)).module;\n}\n\nexport async function createIntegrationsContext(\n options: CreateIntegrationsModuleOptions = {},\n): Promise<IntegrationsContext> {\n const workspaces = options.workspaces;\n const parts: IntegrationModuleParts[] =\n options.parts ??\n (options.providers\n ? options.providers.map((provider) => ({\n provider,\n webhookProcessors: provider.webhookProcessors,\n }))\n : await loadEnabledProviderModules({\n secrets: options.secrets,\n ...(workspaces\n ? {\n requireActiveWorkspaceMembership: (input: {\n workspaceId: string;\n userId: string;\n memberships: ReadonlyArray<\n import('@shipfox/api-auth-context').UserContextMembership\n >;\n }) =>\n workspaces.requireActiveMembership({\n ...input,\n memberships: [...input.memberships],\n }),\n }\n : {}),\n }));\n\n const registry = createIntegrationProviderRegistry(parts.map((part) => part.provider));\n const sourceControl = createSourceControlIntegrationService({\n registry,\n getIntegrationConnectionById,\n });\n const webhookProcessor = createComposedWebhookProcessor(\n parts.flatMap((part) => part.webhookProcessors ?? []),\n );\n\n async function runStartupTasks(): Promise<void> {\n for (const task of parts.flatMap((part) => part.startupTasks ?? [])) {\n // A provider convenience must never gate API boot.\n try {\n await task();\n } catch (error) {\n logger().error({err: error}, 'Integration startup task failed, continuing boot');\n reportError(error, {boundary: 'integration.startup'});\n }\n }\n }\n\n const module: ShipfoxModule = {\n name: 'integrations',\n interModulePresentations: [\n createIntegrationsInterModulePresentation({registry, sourceControl}),\n ],\n startupTasks: runStartupTasks,\n database: [\n {db, migrationsPath},\n ...parts.flatMap((part) => (part.database ? [part.database] : [])),\n ],\n routes: createIntegrationRoutes(registry, sourceControl, {\n agentTools: options.agentTools\n ? {\n workflows: options.agentTools.workflows,\n getIntegrationConnectionById,\n }\n : undefined,\n }),\n e2eRoutes: parts.flatMap((part) => part.e2eRoutes ?? []),\n publishers: [\n {name: 'integrations', table: integrationsOutbox, db, eventSchemas: integrationsEventSchemas},\n ],\n workers: [\n {\n taskQueue: INTEGRATIONS_MAINTENANCE_TASK_QUEUE,\n workflowsPath: maintenanceWorkflowsPath,\n activities: createIntegrationsMaintenanceActivities,\n workflows: [\n {\n name: 'pruneWebhookDeliveriesCron',\n id: 'integrations-prune-webhook-deliveries',\n cronSchedule: '0 3 * * *',\n },\n ],\n },\n ...parts.flatMap((part) => part.workers ?? []),\n ],\n ...(options.webhookDeliverySource\n ? {services: [options.webhookDeliverySource.createService(webhookProcessor)]}\n : {}),\n };\n\n return {\n module,\n registry,\n capabilities: {sourceControl},\n sourceControl,\n webhookProcessor,\n runStartupTasks,\n };\n}\n\nfunction createComposedWebhookProcessor(\n registrations: WebhookProcessorRegistration[],\n): WebhookRequestProcessor {\n const processors = new Map<WebhookRouteId, WebhookRequestProcessor>();\n for (const registration of registrations) {\n for (const routeId of registration.routeIds) {\n if (processors.has(routeId)) {\n throw new Error(`Webhook processor is registered more than once for ${routeId}`);\n }\n processors.set(routeId, registration.processor);\n }\n }\n\n return {\n async process(request: StoredWebhookRequest): Promise<WebhookProcessingResult> {\n const processor = processors.get(request.route_id);\n if (!processor) {\n throw new WebhookProcessorNotConfiguredError(request.route_id);\n }\n return await processor.process(request);\n },\n };\n}\n"],"names":["dirname","resolve","fileURLToPath","integrationsEventSchemas","reportError","logger","WebhookProcessorNotConfiguredError","createIntegrationProviderRegistry","createSourceControlIntegrationService","getIntegrationConnectionById","db","migrationsPath","integrationsOutbox","createIntegrationsInterModulePresentation","createIntegrationRoutes","loadEnabledProviderModules","createIntegrationsMaintenanceActivities","INTEGRATIONS_MAINTENANCE_TASK_QUEUE","packageRoot","url","maintenanceWorkflowsPath","buildProviderRepositoryId","MAX_REPOSITORY_FILE_BYTES","parseProviderRepositoryId","buildAgentToolCatalogs","buildAgentToolSelectionCatalogs","createWorkspaceConnectionSnapshotLoader","ConnectionSlugConflictError","IntegrationCapabilityUnavailableError","IntegrationCheckoutUnsupportedError","IntegrationConnectionInactiveError","IntegrationConnectionNotFoundError","IntegrationConnectionWorkspaceMismatchError","IntegrationProviderError","IntegrationProviderUnavailableError","redactCheckoutSpec","claimWebhookDelivery","pruneWebhookDeliveries","integrationRouteErrorHandler","createIntegrationsModule","options","createIntegrationsContext","module","workspaces","parts","providers","map","provider","webhookProcessors","secrets","requireActiveWorkspaceMembership","input","requireActiveMembership","memberships","registry","part","sourceControl","webhookProcessor","createComposedWebhookProcessor","flatMap","runStartupTasks","task","startupTasks","error","err","boundary","name","interModulePresentations","database","routes","agentTools","workflows","undefined","e2eRoutes","publishers","table","eventSchemas","workers","taskQueue","workflowsPath","activities","id","cronSchedule","webhookDeliverySource","services","createService","capabilities","registrations","processors","Map","registration","routeId","routeIds","has","Error","set","processor","process","request","get","route_id"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {dirname, resolve} from 'node:path';\nimport {fileURLToPath} from 'node:url';\nimport {\n integrationsEventSchemas,\n type StoredWebhookRequest,\n type WebhookProcessingResult,\n type WebhookRequestProcessor,\n type WebhookRouteId,\n} from '@shipfox/api-integration-spi';\nimport type {WorkflowsModuleClient} from '@shipfox/api-workflows-dto/inter-module';\nimport type {WorkspacesInterModuleClient} from '@shipfox/api-workspaces-dto/inter-module';\nimport {reportError} from '@shipfox/node-error-monitoring';\nimport type {ModuleService, ShipfoxModule} from '@shipfox/node-module';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport type {IntegrationProvider} from '#core/entities/provider.js';\nimport {WebhookProcessorNotConfiguredError} from '#core/errors.js';\nimport {\n createIntegrationProviderRegistry,\n type IntegrationProviderRegistry,\n} from '#core/providers/registry.js';\nimport {\n createSourceControlIntegrationService,\n type IntegrationSourceControlService,\n} from '#core/source-control-service.js';\nimport {getIntegrationConnectionById} from '#db/connections.js';\nimport {db} from '#db/db.js';\nimport {migrationsPath} from '#db/migrations.js';\nimport {integrationsOutbox} from '#db/schema/outbox.js';\nimport {createIntegrationsInterModulePresentation} from '#presentation/inter-module.js';\nimport {createIntegrationRoutes} from '#presentation/routes/index.js';\nimport {loadEnabledProviderModules} from '#providers/modules.js';\nimport type {\n IntegrationModuleParts,\n IntegrationProviderSecrets,\n WebhookProcessorRegistration,\n} from '#providers/types.js';\nimport {createIntegrationsMaintenanceActivities} from '#temporal/activities/index.js';\nimport {INTEGRATIONS_MAINTENANCE_TASK_QUEUE} from '#temporal/constants.js';\n\nconst packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');\nconst maintenanceWorkflowsPath = resolve(packageRoot, 'dist/temporal/workflows/index.js');\n\nexport type {\n StoredWebhookRequest,\n WebhookProcessingResult,\n WebhookRequestProcessor,\n WebhookRouteId,\n} from '@shipfox/api-integration-spi';\nexport {\n buildProviderRepositoryId,\n MAX_REPOSITORY_FILE_BYTES,\n parseProviderRepositoryId,\n} from '@shipfox/api-integration-spi';\nexport type {\n AgentToolCatalogs,\n AgentToolSelectionCatalogs,\n LoadWorkspaceConnectionSnapshot,\n WorkspaceConnectionSnapshot,\n WorkspaceConnectionSnapshotEntry,\n} from '#core/agent-tool-selection.js';\nexport {\n buildAgentToolCatalogs,\n buildAgentToolSelectionCatalogs,\n createWorkspaceConnectionSnapshotLoader,\n} from '#core/agent-tool-selection.js';\nexport type {\n IntegrationConnection,\n IntegrationConnectionLifecycleStatus,\n} from '#core/entities/connection.js';\nexport type {\n IntegrationCapability,\n IntegrationProvider,\n IntegrationProviderAdapters,\n IntegrationProviderKind,\n RegisteredIntegrationProvider,\n} from '#core/entities/provider.js';\nexport type {IntegrationProviderErrorReason} from '#core/errors.js';\nexport {\n ConnectionSlugConflictError,\n IntegrationCapabilityUnavailableError,\n IntegrationCheckoutUnsupportedError,\n IntegrationConnectionInactiveError,\n IntegrationConnectionNotFoundError,\n IntegrationConnectionWorkspaceMismatchError,\n IntegrationProviderError,\n IntegrationProviderUnavailableError,\n WebhookProcessorNotConfiguredError,\n} from '#core/errors.js';\nexport type {\n AgentToolCallInput,\n AgentToolCatalogEntry,\n AgentToolCatalogMethod,\n AgentToolJsonSchema,\n AgentToolSensitivity,\n AgentToolSession,\n AgentToolsProvider,\n OpenAgentToolsSessionInput,\n} from '#core/providers/agent-tools.js';\nexport {redactCheckoutSpec} from '#core/providers/redact-checkout-spec.js';\nexport type {IntegrationProviderRegistry} from '#core/providers/registry.js';\nexport type {\n CheckoutCredentials,\n CheckoutPermissions,\n CheckoutSpec,\n CreateCheckoutSpecInput,\n FetchFileInput,\n FileEntry,\n FilePage,\n FileSnapshot,\n ListFilesInput,\n ListRepositoriesInput,\n RepositoryPage,\n RepositorySnapshot,\n RepositoryVisibility,\n ResolveRepositoryInput,\n SourceControlProvider,\n} from '#core/providers/source-control.js';\nexport type {IntegrationSourceControlService} from '#core/source-control-service.js';\nexport {createSourceControlIntegrationService} from '#core/source-control-service.js';\nexport type {GetIntegrationConnectionByIdFn} from '#db/connections.js';\nexport {getIntegrationConnectionById} from '#db/connections.js';\nexport type {\n ClaimWebhookDeliveryFn,\n PublishIntegrationEventReceivedFn,\n PublishIntegrationEventReceivedParams,\n PublishIntegrationEventReceivedResult,\n PublishSourcePushFn,\n PublishSourcePushParams,\n RecordDeliveryOnlyFn,\n RecordDeliveryOnlyParams,\n} from '#db/webhook-deliveries.js';\nexport {claimWebhookDelivery, pruneWebhookDeliveries} from '#db/webhook-deliveries.js';\nexport {integrationRouteErrorHandler} from '#presentation/routes/errors.js';\n\nexport interface CreateIntegrationsModuleOptions {\n providers?: IntegrationProvider[] | undefined;\n /**\n * Pre-built module parts, bypassing config-gated provider loading. Test-only seam\n * for exercising a provider's database, workers, or startup tasks directly. Takes\n * precedence over `providers`.\n */\n parts?: IntegrationModuleParts[] | undefined;\n secrets?: IntegrationProviderSecrets | undefined;\n workspaces?: WorkspacesInterModuleClient | undefined;\n agentTools?:\n | {\n workflows: WorkflowsModuleClient;\n }\n | undefined;\n webhookDeliverySource?: WebhookDeliverySource | undefined;\n}\n\n/**\n * Hosted runtimes implement this port to receive stored webhook requests. The\n * integration module starts its returned service after migrations complete.\n */\nexport interface WebhookDeliverySource {\n createService(processor: WebhookRequestProcessor): ModuleService;\n}\n\nexport interface IntegrationsContext {\n module: ShipfoxModule;\n registry: IntegrationProviderRegistry;\n capabilities: {\n sourceControl: IntegrationSourceControlService;\n };\n sourceControl: IntegrationSourceControlService;\n webhookProcessor: WebhookRequestProcessor;\n /**\n * Runs every enabled provider's one-shot boot-time tasks, after modules are initialized\n * (migrations done). Failures are isolated and logged, never rethrown, so a provider task\n * can never gate API boot. No-op when no enabled provider contributes a task.\n */\n runStartupTasks: () => Promise<void>;\n}\n\nexport async function createIntegrationsModule(\n options: CreateIntegrationsModuleOptions = {},\n): Promise<ShipfoxModule> {\n return (await createIntegrationsContext(options)).module;\n}\n\nexport async function createIntegrationsContext(\n options: CreateIntegrationsModuleOptions = {},\n): Promise<IntegrationsContext> {\n const workspaces = options.workspaces;\n const parts: IntegrationModuleParts[] =\n options.parts ??\n (options.providers\n ? options.providers.map((provider) => ({\n provider,\n webhookProcessors: provider.webhookProcessors,\n }))\n : await loadEnabledProviderModules({\n secrets: options.secrets,\n ...(workspaces\n ? {\n requireActiveWorkspaceMembership: (input: {\n workspaceId: string;\n userId: string;\n memberships: ReadonlyArray<\n import('@shipfox/api-auth-context').UserContextMembership\n >;\n }) =>\n workspaces.requireActiveMembership({\n ...input,\n memberships: [...input.memberships],\n }),\n }\n : {}),\n }));\n\n const registry = createIntegrationProviderRegistry(parts.map((part) => part.provider));\n const sourceControl = createSourceControlIntegrationService({\n registry,\n getIntegrationConnectionById,\n });\n const webhookProcessor = createComposedWebhookProcessor(\n parts.flatMap((part) => part.webhookProcessors ?? []),\n );\n\n async function runStartupTasks(): Promise<void> {\n for (const task of parts.flatMap((part) => part.startupTasks ?? [])) {\n // A provider convenience must never gate API boot.\n try {\n await task();\n } catch (error) {\n logger().error({err: error}, 'Integration startup task failed, continuing boot');\n reportError(error, {boundary: 'integration.startup'});\n }\n }\n }\n\n const module: ShipfoxModule = {\n name: 'integrations',\n interModulePresentations: [\n createIntegrationsInterModulePresentation({registry, sourceControl}),\n ],\n startupTasks: runStartupTasks,\n database: [\n {db, migrationsPath, databaseNamespace: 'integrations'},\n ...parts.flatMap((part) => (part.database ? [part.database] : [])),\n ],\n routes: createIntegrationRoutes(registry, sourceControl, {\n agentTools: options.agentTools\n ? {\n workflows: options.agentTools.workflows,\n getIntegrationConnectionById,\n }\n : undefined,\n }),\n e2eRoutes: parts.flatMap((part) => part.e2eRoutes ?? []),\n publishers: [\n {name: 'integrations', table: integrationsOutbox, db, eventSchemas: integrationsEventSchemas},\n ],\n workers: [\n {\n taskQueue: INTEGRATIONS_MAINTENANCE_TASK_QUEUE,\n workflowsPath: maintenanceWorkflowsPath,\n activities: createIntegrationsMaintenanceActivities,\n workflows: [\n {\n name: 'pruneWebhookDeliveriesCron',\n id: 'integrations-prune-webhook-deliveries',\n cronSchedule: '0 3 * * *',\n },\n ],\n },\n ...parts.flatMap((part) => part.workers ?? []),\n ],\n ...(options.webhookDeliverySource\n ? {services: [options.webhookDeliverySource.createService(webhookProcessor)]}\n : {}),\n };\n\n return {\n module,\n registry,\n capabilities: {sourceControl},\n sourceControl,\n webhookProcessor,\n runStartupTasks,\n };\n}\n\nfunction createComposedWebhookProcessor(\n registrations: WebhookProcessorRegistration[],\n): WebhookRequestProcessor {\n const processors = new Map<WebhookRouteId, WebhookRequestProcessor>();\n for (const registration of registrations) {\n for (const routeId of registration.routeIds) {\n if (processors.has(routeId)) {\n throw new Error(`Webhook processor is registered more than once for ${routeId}`);\n }\n processors.set(routeId, registration.processor);\n }\n }\n\n return {\n async process(request: StoredWebhookRequest): Promise<WebhookProcessingResult> {\n const processor = processors.get(request.route_id);\n if (!processor) {\n throw new WebhookProcessorNotConfiguredError(request.route_id);\n }\n return await processor.process(request);\n },\n };\n}\n"],"names":["dirname","resolve","fileURLToPath","integrationsEventSchemas","reportError","logger","WebhookProcessorNotConfiguredError","createIntegrationProviderRegistry","createSourceControlIntegrationService","getIntegrationConnectionById","db","migrationsPath","integrationsOutbox","createIntegrationsInterModulePresentation","createIntegrationRoutes","loadEnabledProviderModules","createIntegrationsMaintenanceActivities","INTEGRATIONS_MAINTENANCE_TASK_QUEUE","packageRoot","url","maintenanceWorkflowsPath","buildProviderRepositoryId","MAX_REPOSITORY_FILE_BYTES","parseProviderRepositoryId","buildAgentToolCatalogs","buildAgentToolSelectionCatalogs","createWorkspaceConnectionSnapshotLoader","ConnectionSlugConflictError","IntegrationCapabilityUnavailableError","IntegrationCheckoutUnsupportedError","IntegrationConnectionInactiveError","IntegrationConnectionNotFoundError","IntegrationConnectionWorkspaceMismatchError","IntegrationProviderError","IntegrationProviderUnavailableError","redactCheckoutSpec","claimWebhookDelivery","pruneWebhookDeliveries","integrationRouteErrorHandler","createIntegrationsModule","options","createIntegrationsContext","module","workspaces","parts","providers","map","provider","webhookProcessors","secrets","requireActiveWorkspaceMembership","input","requireActiveMembership","memberships","registry","part","sourceControl","webhookProcessor","createComposedWebhookProcessor","flatMap","runStartupTasks","task","startupTasks","error","err","boundary","name","interModulePresentations","database","databaseNamespace","routes","agentTools","workflows","undefined","e2eRoutes","publishers","table","eventSchemas","workers","taskQueue","workflowsPath","activities","id","cronSchedule","webhookDeliverySource","services","createService","capabilities","registrations","processors","Map","registration","routeId","routeIds","has","Error","set","processor","process","request","get","route_id"],"mappings":"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"}
@@ -19,7 +19,7 @@ export declare function toIntegrationConnectionDto(connection: IntegrationConnec
19
19
  external_account_id: string;
20
20
  slug: string;
21
21
  display_name: string;
22
- lifecycle_status: import("@shipfox/api-integration-core-dto").IntegrationConnectionLifecycleStatus;
22
+ lifecycle_status: import("#core/entities/connection.js").IntegrationConnectionLifecycleStatus;
23
23
  capabilities: IntegrationCapability[];
24
24
  };
25
25
  export declare function toRepositoryDto(connectionId: string, repository: RepositorySnapshot): {
@@ -29,7 +29,7 @@ export declare function toRepositoryDto(connectionId: string, repository: Reposi
29
29
  name: string;
30
30
  full_name: string;
31
31
  default_branch: string;
32
- visibility: import("@shipfox/api-integration-core-dto").RepositoryVisibility;
32
+ visibility: import("#core/providers/source-control.js").RepositoryVisibility;
33
33
  clone_url: string;
34
34
  html_url: string;
35
35
  };
@@ -1 +1 @@
1
- {"version":3,"file":"integrations.d.ts","sourceRoot":"","sources":["../../../src/presentation/dto/integrations.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,8BAA8B,CAAC;AACxE,OAAO,KAAK,EACV,qBAAqB,EACrB,6BAA6B,EAC9B,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,mCAAmC,CAAC;AAE1E,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,6BAA6B;;;;EAM/E;AAED,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,qBAAqB,EACjC,OAAO,EAAE;IACP,YAAY,EAAE,qBAAqB,EAAE,CAAC;IACtC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC;;;;;;;;;;;;EAGF;AAED,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB;;;;;;;;;;EAYnF"}
1
+ {"version":3,"file":"integrations.d.ts","sourceRoot":"","sources":["../../../src/presentation/dto/integrations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,8BAA8B,CAAC;AACxE,OAAO,KAAK,EACV,qBAAqB,EACrB,6BAA6B,EAC9B,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,mCAAmC,CAAC;AAE1E,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,6BAA6B;;;;EAM/E;AAED,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,qBAAqB,EACjC,OAAO,EAAE;IACP,YAAY,EAAE,qBAAqB,EAAE,CAAC;IACtC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC;;;;;;;;;;;;EAGF;AAsBD,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB;;;;;;;;;;EAYnF"}
@@ -1,4 +1,3 @@
1
- import { toIntegrationConnectionDto as toCoreIntegrationConnectionDto } from '@shipfox/api-integration-core-dto';
2
1
  export function toIntegrationProviderDto(provider) {
3
2
  return {
4
3
  provider: provider.provider,
@@ -7,7 +6,24 @@ export function toIntegrationProviderDto(provider) {
7
6
  };
8
7
  }
9
8
  export function toIntegrationConnectionDto(connection, options) {
10
- return toCoreIntegrationConnectionDto(connection, options);
9
+ return mapIntegrationConnection(connection, options.capabilities, options.externalUrl);
10
+ }
11
+ function mapIntegrationConnection(connection, capabilities, externalUrl) {
12
+ return {
13
+ id: connection.id,
14
+ workspace_id: connection.workspaceId,
15
+ provider: connection.provider,
16
+ external_account_id: connection.externalAccountId,
17
+ slug: connection.slug,
18
+ display_name: connection.displayName,
19
+ lifecycle_status: connection.lifecycleStatus,
20
+ capabilities,
21
+ ...externalUrl ? {
22
+ external_url: externalUrl
23
+ } : {},
24
+ created_at: connection.createdAt.toISOString(),
25
+ updated_at: connection.updatedAt.toISOString()
26
+ };
11
27
  }
12
28
  export function toRepositoryDto(connectionId, repository) {
13
29
  return {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/presentation/dto/integrations.ts"],"sourcesContent":["import {toIntegrationConnectionDto as toCoreIntegrationConnectionDto} from '@shipfox/api-integration-core-dto';\nimport type {IntegrationConnection} from '#core/entities/connection.js';\nimport type {\n IntegrationCapability,\n RegisteredIntegrationProvider,\n} from '#core/entities/provider.js';\nimport type {RepositorySnapshot} from '#core/providers/source-control.js';\n\nexport function toIntegrationProviderDto(provider: RegisteredIntegrationProvider) {\n return {\n provider: provider.provider,\n display_name: provider.displayName,\n capabilities: provider.capabilities,\n };\n}\n\nexport function toIntegrationConnectionDto(\n connection: IntegrationConnection,\n options: {\n capabilities: IntegrationCapability[];\n externalUrl?: string | undefined;\n },\n) {\n return toCoreIntegrationConnectionDto(connection, options);\n}\n\nexport function toRepositoryDto(connectionId: string, repository: RepositorySnapshot) {\n return {\n connection_id: connectionId,\n external_repository_id: repository.externalRepositoryId,\n owner: repository.owner,\n name: repository.name,\n full_name: repository.fullName,\n default_branch: repository.defaultBranch,\n visibility: repository.visibility,\n clone_url: repository.cloneUrl,\n html_url: repository.htmlUrl,\n };\n}\n"],"names":["toIntegrationConnectionDto","toCoreIntegrationConnectionDto","toIntegrationProviderDto","provider","display_name","displayName","capabilities","connection","options","toRepositoryDto","connectionId","repository","connection_id","external_repository_id","externalRepositoryId","owner","name","full_name","fullName","default_branch","defaultBranch","visibility","clone_url","cloneUrl","html_url","htmlUrl"],"mappings":"AAAA,SAAQA,8BAA8BC,8BAA8B,QAAO,oCAAoC;AAQ/G,OAAO,SAASC,yBAAyBC,QAAuC;IAC9E,OAAO;QACLA,UAAUA,SAASA,QAAQ;QAC3BC,cAAcD,SAASE,WAAW;QAClCC,cAAcH,SAASG,YAAY;IACrC;AACF;AAEA,OAAO,SAASN,2BACdO,UAAiC,EACjCC,OAGC;IAED,OAAOP,+BAA+BM,YAAYC;AACpD;AAEA,OAAO,SAASC,gBAAgBC,YAAoB,EAAEC,UAA8B;IAClF,OAAO;QACLC,eAAeF;QACfG,wBAAwBF,WAAWG,oBAAoB;QACvDC,OAAOJ,WAAWI,KAAK;QACvBC,MAAML,WAAWK,IAAI;QACrBC,WAAWN,WAAWO,QAAQ;QAC9BC,gBAAgBR,WAAWS,aAAa;QACxCC,YAAYV,WAAWU,UAAU;QACjCC,WAAWX,WAAWY,QAAQ;QAC9BC,UAAUb,WAAWc,OAAO;IAC9B;AACF"}
1
+ {"version":3,"sources":["../../../src/presentation/dto/integrations.ts"],"sourcesContent":["import type {IntegrationConnection} from '#core/entities/connection.js';\nimport type {\n IntegrationCapability,\n RegisteredIntegrationProvider,\n} from '#core/entities/provider.js';\nimport type {RepositorySnapshot} from '#core/providers/source-control.js';\n\nexport function toIntegrationProviderDto(provider: RegisteredIntegrationProvider) {\n return {\n provider: provider.provider,\n display_name: provider.displayName,\n capabilities: provider.capabilities,\n };\n}\n\nexport function toIntegrationConnectionDto(\n connection: IntegrationConnection,\n options: {\n capabilities: IntegrationCapability[];\n externalUrl?: string | undefined;\n },\n) {\n return mapIntegrationConnection(connection, options.capabilities, options.externalUrl);\n}\n\nfunction mapIntegrationConnection(\n connection: IntegrationConnection,\n capabilities: IntegrationCapability[],\n externalUrl?: string,\n) {\n return {\n id: connection.id,\n workspace_id: connection.workspaceId,\n provider: connection.provider,\n external_account_id: connection.externalAccountId,\n slug: connection.slug,\n display_name: connection.displayName,\n lifecycle_status: connection.lifecycleStatus,\n capabilities,\n ...(externalUrl ? {external_url: externalUrl} : {}),\n created_at: connection.createdAt.toISOString(),\n updated_at: connection.updatedAt.toISOString(),\n };\n}\n\nexport function toRepositoryDto(connectionId: string, repository: RepositorySnapshot) {\n return {\n connection_id: connectionId,\n external_repository_id: repository.externalRepositoryId,\n owner: repository.owner,\n name: repository.name,\n full_name: repository.fullName,\n default_branch: repository.defaultBranch,\n visibility: repository.visibility,\n clone_url: repository.cloneUrl,\n html_url: repository.htmlUrl,\n };\n}\n"],"names":["toIntegrationProviderDto","provider","display_name","displayName","capabilities","toIntegrationConnectionDto","connection","options","mapIntegrationConnection","externalUrl","id","workspace_id","workspaceId","external_account_id","externalAccountId","slug","lifecycle_status","lifecycleStatus","external_url","created_at","createdAt","toISOString","updated_at","updatedAt","toRepositoryDto","connectionId","repository","connection_id","external_repository_id","externalRepositoryId","owner","name","full_name","fullName","default_branch","defaultBranch","visibility","clone_url","cloneUrl","html_url","htmlUrl"],"mappings":"AAOA,OAAO,SAASA,yBAAyBC,QAAuC;IAC9E,OAAO;QACLA,UAAUA,SAASA,QAAQ;QAC3BC,cAAcD,SAASE,WAAW;QAClCC,cAAcH,SAASG,YAAY;IACrC;AACF;AAEA,OAAO,SAASC,2BACdC,UAAiC,EACjCC,OAGC;IAED,OAAOC,yBAAyBF,YAAYC,QAAQH,YAAY,EAAEG,QAAQE,WAAW;AACvF;AAEA,SAASD,yBACPF,UAAiC,EACjCF,YAAqC,EACrCK,WAAoB;IAEpB,OAAO;QACLC,IAAIJ,WAAWI,EAAE;QACjBC,cAAcL,WAAWM,WAAW;QACpCX,UAAUK,WAAWL,QAAQ;QAC7BY,qBAAqBP,WAAWQ,iBAAiB;QACjDC,MAAMT,WAAWS,IAAI;QACrBb,cAAcI,WAAWH,WAAW;QACpCa,kBAAkBV,WAAWW,eAAe;QAC5Cb;QACA,GAAIK,cAAc;YAACS,cAAcT;QAAW,IAAI,CAAC,CAAC;QAClDU,YAAYb,WAAWc,SAAS,CAACC,WAAW;QAC5CC,YAAYhB,WAAWiB,SAAS,CAACF,WAAW;IAC9C;AACF;AAEA,OAAO,SAASG,gBAAgBC,YAAoB,EAAEC,UAA8B;IAClF,OAAO;QACLC,eAAeF;QACfG,wBAAwBF,WAAWG,oBAAoB;QACvDC,OAAOJ,WAAWI,KAAK;QACvBC,MAAML,WAAWK,IAAI;QACrBC,WAAWN,WAAWO,QAAQ;QAC9BC,gBAAgBR,WAAWS,aAAa;QACxCC,YAAYV,WAAWU,UAAU;QACjCC,WAAWX,WAAWY,QAAQ;QAC9BC,UAAUb,WAAWc,OAAO;IAC9B;AACF"}
@@ -1,5 +1,5 @@
1
1
  import { AUTH_USER, requireWorkspaceAccess } from '@shipfox/api-auth-context';
2
- import { listIntegrationConnectionsQuerySchema, listIntegrationConnectionsResponseSchema } from '@shipfox/api-integration-core-dto';
2
+ import { listIntegrationConnectionsQuerySchema, listIntegrationConnectionsResponseSchema } from '@shipfox/api-integration-spi';
3
3
  import { defineRoute } from '@shipfox/node-fastify';
4
4
  import { listIntegrationConnections } from '#db/connections.js';
5
5
  import { toIntegrationConnectionDto } from '#presentation/dto/integrations.js';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/presentation/routes/list-connections.ts"],"sourcesContent":["import {AUTH_USER, requireWorkspaceAccess} from '@shipfox/api-auth-context';\nimport {\n listIntegrationConnectionsQuerySchema,\n listIntegrationConnectionsResponseSchema,\n} from '@shipfox/api-integration-core-dto';\nimport {defineRoute} from '@shipfox/node-fastify';\nimport type {IntegrationProviderRegistry} from '#core/providers/registry.js';\nimport {listIntegrationConnections} from '#db/connections.js';\nimport {toIntegrationConnectionDto} from '#presentation/dto/integrations.js';\n\nexport function createListIntegrationConnectionsRoute(registry: IntegrationProviderRegistry) {\n return defineRoute({\n method: 'GET',\n path: '/integration-connections',\n auth: AUTH_USER,\n description: 'List workspace integration connections across all lifecycle statuses.',\n schema: {\n querystring: listIntegrationConnectionsQuerySchema,\n response: {\n 200: listIntegrationConnectionsResponseSchema,\n },\n },\n handler: async (request) => {\n const {workspace_id: workspaceId, capability} = request.query;\n\n requireWorkspaceAccess({request, workspaceId});\n const connections = await listIntegrationConnections({workspaceId});\n const providers = new Map(\n registry.list(capability).map((provider) => [provider.provider, provider]),\n );\n const connectionDtos = await Promise.all(\n connections.map(async (connection) => {\n const provider = providers.get(connection.provider);\n if (!provider) return undefined;\n // Best-effort: the external link is cosmetic, so a failing or missing\n // provider-side lookup must never fail the whole connections list.\n let externalUrl: string | undefined;\n try {\n externalUrl = await provider.connectionExternalUrl?.(connection);\n } catch (error) {\n request.log.warn(\n {connectionId: connection.id, provider: connection.provider, err: error},\n 'Could not resolve integration connection external URL',\n );\n }\n return toIntegrationConnectionDto(connection, {\n capabilities: provider.capabilities,\n externalUrl,\n });\n }),\n );\n\n return {connections: connectionDtos.filter((connection) => connection !== undefined)};\n },\n });\n}\n"],"names":["AUTH_USER","requireWorkspaceAccess","listIntegrationConnectionsQuerySchema","listIntegrationConnectionsResponseSchema","defineRoute","listIntegrationConnections","toIntegrationConnectionDto","createListIntegrationConnectionsRoute","registry","method","path","auth","description","schema","querystring","response","handler","request","workspace_id","workspaceId","capability","query","connections","providers","Map","list","map","provider","connectionDtos","Promise","all","connection","get","undefined","externalUrl","connectionExternalUrl","error","log","warn","connectionId","id","err","capabilities","filter"],"mappings":"AAAA,SAAQA,SAAS,EAAEC,sBAAsB,QAAO,4BAA4B;AAC5E,SACEC,qCAAqC,EACrCC,wCAAwC,QACnC,oCAAoC;AAC3C,SAAQC,WAAW,QAAO,wBAAwB;AAElD,SAAQC,0BAA0B,QAAO,qBAAqB;AAC9D,SAAQC,0BAA0B,QAAO,oCAAoC;AAE7E,OAAO,SAASC,sCAAsCC,QAAqC;IACzF,OAAOJ,YAAY;QACjBK,QAAQ;QACRC,MAAM;QACNC,MAAMX;QACNY,aAAa;QACbC,QAAQ;YACNC,aAAaZ;YACba,UAAU;gBACR,KAAKZ;YACP;QACF;QACAa,SAAS,OAAOC;YACd,MAAM,EAACC,cAAcC,WAAW,EAAEC,UAAU,EAAC,GAAGH,QAAQI,KAAK;YAE7DpB,uBAAuB;gBAACgB;gBAASE;YAAW;YAC5C,MAAMG,cAAc,MAAMjB,2BAA2B;gBAACc;YAAW;YACjE,MAAMI,YAAY,IAAIC,IACpBhB,SAASiB,IAAI,CAACL,YAAYM,GAAG,CAAC,CAACC,WAAa;oBAACA,SAASA,QAAQ;oBAAEA;iBAAS;YAE3E,MAAMC,iBAAiB,MAAMC,QAAQC,GAAG,CACtCR,YAAYI,GAAG,CAAC,OAAOK;gBACrB,MAAMJ,WAAWJ,UAAUS,GAAG,CAACD,WAAWJ,QAAQ;gBAClD,IAAI,CAACA,UAAU,OAAOM;gBACtB,sEAAsE;gBACtE,mEAAmE;gBACnE,IAAIC;gBACJ,IAAI;oBACFA,cAAc,MAAMP,SAASQ,qBAAqB,GAAGJ;gBACvD,EAAE,OAAOK,OAAO;oBACdnB,QAAQoB,GAAG,CAACC,IAAI,CACd;wBAACC,cAAcR,WAAWS,EAAE;wBAAEb,UAAUI,WAAWJ,QAAQ;wBAAEc,KAAKL;oBAAK,GACvE;gBAEJ;gBACA,OAAO9B,2BAA2ByB,YAAY;oBAC5CW,cAAcf,SAASe,YAAY;oBACnCR;gBACF;YACF;YAGF,OAAO;gBAACZ,aAAaM,eAAee,MAAM,CAAC,CAACZ,aAAeA,eAAeE;YAAU;QACtF;IACF;AACF"}
1
+ {"version":3,"sources":["../../../src/presentation/routes/list-connections.ts"],"sourcesContent":["import {AUTH_USER, requireWorkspaceAccess} from '@shipfox/api-auth-context';\nimport {\n listIntegrationConnectionsQuerySchema,\n listIntegrationConnectionsResponseSchema,\n} from '@shipfox/api-integration-spi';\nimport {defineRoute} from '@shipfox/node-fastify';\nimport type {IntegrationProviderRegistry} from '#core/providers/registry.js';\nimport {listIntegrationConnections} from '#db/connections.js';\nimport {toIntegrationConnectionDto} from '#presentation/dto/integrations.js';\n\nexport function createListIntegrationConnectionsRoute(registry: IntegrationProviderRegistry) {\n return defineRoute({\n method: 'GET',\n path: '/integration-connections',\n auth: AUTH_USER,\n description: 'List workspace integration connections across all lifecycle statuses.',\n schema: {\n querystring: listIntegrationConnectionsQuerySchema,\n response: {\n 200: listIntegrationConnectionsResponseSchema,\n },\n },\n handler: async (request) => {\n const {workspace_id: workspaceId, capability} = request.query;\n\n requireWorkspaceAccess({request, workspaceId});\n const connections = await listIntegrationConnections({workspaceId});\n const providers = new Map(\n registry.list(capability).map((provider) => [provider.provider, provider]),\n );\n const connectionDtos = await Promise.all(\n connections.map(async (connection) => {\n const provider = providers.get(connection.provider);\n if (!provider) return undefined;\n // Best-effort: the external link is cosmetic, so a failing or missing\n // provider-side lookup must never fail the whole connections list.\n let externalUrl: string | undefined;\n try {\n externalUrl = await provider.connectionExternalUrl?.(connection);\n } catch (error) {\n request.log.warn(\n {connectionId: connection.id, provider: connection.provider, err: error},\n 'Could not resolve integration connection external URL',\n );\n }\n return toIntegrationConnectionDto(connection, {\n capabilities: provider.capabilities,\n externalUrl,\n });\n }),\n );\n\n return {connections: connectionDtos.filter((connection) => connection !== undefined)};\n },\n });\n}\n"],"names":["AUTH_USER","requireWorkspaceAccess","listIntegrationConnectionsQuerySchema","listIntegrationConnectionsResponseSchema","defineRoute","listIntegrationConnections","toIntegrationConnectionDto","createListIntegrationConnectionsRoute","registry","method","path","auth","description","schema","querystring","response","handler","request","workspace_id","workspaceId","capability","query","connections","providers","Map","list","map","provider","connectionDtos","Promise","all","connection","get","undefined","externalUrl","connectionExternalUrl","error","log","warn","connectionId","id","err","capabilities","filter"],"mappings":"AAAA,SAAQA,SAAS,EAAEC,sBAAsB,QAAO,4BAA4B;AAC5E,SACEC,qCAAqC,EACrCC,wCAAwC,QACnC,+BAA+B;AACtC,SAAQC,WAAW,QAAO,wBAAwB;AAElD,SAAQC,0BAA0B,QAAO,qBAAqB;AAC9D,SAAQC,0BAA0B,QAAO,oCAAoC;AAE7E,OAAO,SAASC,sCAAsCC,QAAqC;IACzF,OAAOJ,YAAY;QACjBK,QAAQ;QACRC,MAAM;QACNC,MAAMX;QACNY,aAAa;QACbC,QAAQ;YACNC,aAAaZ;YACba,UAAU;gBACR,KAAKZ;YACP;QACF;QACAa,SAAS,OAAOC;YACd,MAAM,EAACC,cAAcC,WAAW,EAAEC,UAAU,EAAC,GAAGH,QAAQI,KAAK;YAE7DpB,uBAAuB;gBAACgB;gBAASE;YAAW;YAC5C,MAAMG,cAAc,MAAMjB,2BAA2B;gBAACc;YAAW;YACjE,MAAMI,YAAY,IAAIC,IACpBhB,SAASiB,IAAI,CAACL,YAAYM,GAAG,CAAC,CAACC,WAAa;oBAACA,SAASA,QAAQ;oBAAEA;iBAAS;YAE3E,MAAMC,iBAAiB,MAAMC,QAAQC,GAAG,CACtCR,YAAYI,GAAG,CAAC,OAAOK;gBACrB,MAAMJ,WAAWJ,UAAUS,GAAG,CAACD,WAAWJ,QAAQ;gBAClD,IAAI,CAACA,UAAU,OAAOM;gBACtB,sEAAsE;gBACtE,mEAAmE;gBACnE,IAAIC;gBACJ,IAAI;oBACFA,cAAc,MAAMP,SAASQ,qBAAqB,GAAGJ;gBACvD,EAAE,OAAOK,OAAO;oBACdnB,QAAQoB,GAAG,CAACC,IAAI,CACd;wBAACC,cAAcR,WAAWS,EAAE;wBAAEb,UAAUI,WAAWJ,QAAQ;wBAAEc,KAAKL;oBAAK,GACvE;gBAEJ;gBACA,OAAO9B,2BAA2ByB,YAAY;oBAC5CW,cAAcf,SAASe,YAAY;oBACnCR;gBACF;YACF;YAGF,OAAO;gBAACZ,aAAaM,eAAee,MAAM,CAAC,CAACZ,aAAeA,eAAeE;YAAU;QACtF;IACF;AACF"}
@@ -1,5 +1,5 @@
1
1
  import { AUTH_USER } from '@shipfox/api-auth-context';
2
- import { listIntegrationProvidersQuerySchema, listIntegrationProvidersResponseSchema } from '@shipfox/api-integration-core-dto';
2
+ import { listIntegrationProvidersQuerySchema, listIntegrationProvidersResponseSchema } from '@shipfox/api-integration-spi';
3
3
  import { defineRoute } from '@shipfox/node-fastify';
4
4
  import { toIntegrationProviderDto } from '#presentation/dto/integrations.js';
5
5
  export function createListIntegrationProvidersRoute(registry) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/presentation/routes/list-providers.ts"],"sourcesContent":["import {AUTH_USER} from '@shipfox/api-auth-context';\nimport {\n listIntegrationProvidersQuerySchema,\n listIntegrationProvidersResponseSchema,\n} from '@shipfox/api-integration-core-dto';\nimport {defineRoute} from '@shipfox/node-fastify';\nimport type {IntegrationProviderRegistry} from '#core/providers/registry.js';\nimport {toIntegrationProviderDto} from '#presentation/dto/integrations.js';\n\nexport function createListIntegrationProvidersRoute(registry: IntegrationProviderRegistry) {\n return defineRoute({\n method: 'GET',\n path: '/integration-providers',\n auth: AUTH_USER,\n description: 'List integration providers available to the API.',\n schema: {\n querystring: listIntegrationProvidersQuerySchema,\n response: {\n 200: listIntegrationProvidersResponseSchema,\n },\n },\n handler: async (request) => {\n await Promise.resolve();\n const providers = registry.list(request.query.capability);\n return {providers: providers.map(toIntegrationProviderDto)};\n },\n });\n}\n"],"names":["AUTH_USER","listIntegrationProvidersQuerySchema","listIntegrationProvidersResponseSchema","defineRoute","toIntegrationProviderDto","createListIntegrationProvidersRoute","registry","method","path","auth","description","schema","querystring","response","handler","request","Promise","resolve","providers","list","query","capability","map"],"mappings":"AAAA,SAAQA,SAAS,QAAO,4BAA4B;AACpD,SACEC,mCAAmC,EACnCC,sCAAsC,QACjC,oCAAoC;AAC3C,SAAQC,WAAW,QAAO,wBAAwB;AAElD,SAAQC,wBAAwB,QAAO,oCAAoC;AAE3E,OAAO,SAASC,oCAAoCC,QAAqC;IACvF,OAAOH,YAAY;QACjBI,QAAQ;QACRC,MAAM;QACNC,MAAMT;QACNU,aAAa;QACbC,QAAQ;YACNC,aAAaX;YACbY,UAAU;gBACR,KAAKX;YACP;QACF;QACAY,SAAS,OAAOC;YACd,MAAMC,QAAQC,OAAO;YACrB,MAAMC,YAAYZ,SAASa,IAAI,CAACJ,QAAQK,KAAK,CAACC,UAAU;YACxD,OAAO;gBAACH,WAAWA,UAAUI,GAAG,CAAClB;YAAyB;QAC5D;IACF;AACF"}
1
+ {"version":3,"sources":["../../../src/presentation/routes/list-providers.ts"],"sourcesContent":["import {AUTH_USER} from '@shipfox/api-auth-context';\nimport {\n listIntegrationProvidersQuerySchema,\n listIntegrationProvidersResponseSchema,\n} from '@shipfox/api-integration-spi';\nimport {defineRoute} from '@shipfox/node-fastify';\nimport type {IntegrationProviderRegistry} from '#core/providers/registry.js';\nimport {toIntegrationProviderDto} from '#presentation/dto/integrations.js';\n\nexport function createListIntegrationProvidersRoute(registry: IntegrationProviderRegistry) {\n return defineRoute({\n method: 'GET',\n path: '/integration-providers',\n auth: AUTH_USER,\n description: 'List integration providers available to the API.',\n schema: {\n querystring: listIntegrationProvidersQuerySchema,\n response: {\n 200: listIntegrationProvidersResponseSchema,\n },\n },\n handler: async (request) => {\n await Promise.resolve();\n const providers = registry.list(request.query.capability);\n return {providers: providers.map(toIntegrationProviderDto)};\n },\n });\n}\n"],"names":["AUTH_USER","listIntegrationProvidersQuerySchema","listIntegrationProvidersResponseSchema","defineRoute","toIntegrationProviderDto","createListIntegrationProvidersRoute","registry","method","path","auth","description","schema","querystring","response","handler","request","Promise","resolve","providers","list","query","capability","map"],"mappings":"AAAA,SAAQA,SAAS,QAAO,4BAA4B;AACpD,SACEC,mCAAmC,EACnCC,sCAAsC,QACjC,+BAA+B;AACtC,SAAQC,WAAW,QAAO,wBAAwB;AAElD,SAAQC,wBAAwB,QAAO,oCAAoC;AAE3E,OAAO,SAASC,oCAAoCC,QAAqC;IACvF,OAAOH,YAAY;QACjBI,QAAQ;QACRC,MAAM;QACNC,MAAMT;QACNU,aAAa;QACbC,QAAQ;YACNC,aAAaX;YACbY,UAAU;gBACR,KAAKX;YACP;QACF;QACAY,SAAS,OAAOC;YACd,MAAMC,QAAQC,OAAO;YACrB,MAAMC,YAAYZ,SAASa,IAAI,CAACJ,QAAQK,KAAK,CAACC,UAAU;YACxD,OAAO;gBAACH,WAAWA,UAAUI,GAAG,CAAClB;YAAyB;QAC5D;IACF;AACF"}
@@ -1,5 +1,5 @@
1
1
  import { AUTH_USER, requireWorkspaceAccess } from '@shipfox/api-auth-context';
2
- import { listRepositoriesParamsSchema, listRepositoriesQuerySchema, listRepositoriesResponseSchema } from '@shipfox/api-integration-core-dto';
2
+ import { listRepositoriesParamsSchema, listRepositoriesQuerySchema, listRepositoriesResponseSchema } from '@shipfox/api-integration-spi';
3
3
  import { defineRoute } from '@shipfox/node-fastify';
4
4
  import { toRepositoryDto } from '#presentation/dto/integrations.js';
5
5
  import { integrationRouteErrorHandler } from './errors.js';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/presentation/routes/list-repositories.ts"],"sourcesContent":["import {AUTH_USER, requireWorkspaceAccess} from '@shipfox/api-auth-context';\nimport {\n listRepositoriesParamsSchema,\n listRepositoriesQuerySchema,\n listRepositoriesResponseSchema,\n} from '@shipfox/api-integration-core-dto';\nimport {defineRoute} from '@shipfox/node-fastify';\nimport type {IntegrationSourceControlService} from '#core/source-control-service.js';\nimport {toRepositoryDto} from '#presentation/dto/integrations.js';\nimport {integrationRouteErrorHandler} from './errors.js';\n\nexport function createListRepositoriesRoute(sourceControl: IntegrationSourceControlService) {\n return defineRoute({\n method: 'GET',\n path: '/integration-connections/:connectionId/repositories',\n auth: AUTH_USER,\n description: 'List repositories visible to a source-control integration connection.',\n schema: {\n params: listRepositoriesParamsSchema,\n querystring: listRepositoriesQuerySchema,\n response: {\n 200: listRepositoriesResponseSchema,\n },\n },\n errorHandler: integrationRouteErrorHandler,\n handler: async (request) => {\n const {connectionId} = request.params;\n const connection = await sourceControl.getConnection(connectionId);\n\n requireWorkspaceAccess({request, workspaceId: connection.workspaceId});\n\n const page = await sourceControl.listRepositories({\n connection,\n limit: request.query.limit,\n cursor: request.query.cursor,\n search: request.query.search,\n });\n\n return {\n repositories: page.repositories.map((repository) =>\n toRepositoryDto(connection.id, repository),\n ),\n next_cursor: page.nextCursor,\n };\n },\n });\n}\n"],"names":["AUTH_USER","requireWorkspaceAccess","listRepositoriesParamsSchema","listRepositoriesQuerySchema","listRepositoriesResponseSchema","defineRoute","toRepositoryDto","integrationRouteErrorHandler","createListRepositoriesRoute","sourceControl","method","path","auth","description","schema","params","querystring","response","errorHandler","handler","request","connectionId","connection","getConnection","workspaceId","page","listRepositories","limit","query","cursor","search","repositories","map","repository","id","next_cursor","nextCursor"],"mappings":"AAAA,SAAQA,SAAS,EAAEC,sBAAsB,QAAO,4BAA4B;AAC5E,SACEC,4BAA4B,EAC5BC,2BAA2B,EAC3BC,8BAA8B,QACzB,oCAAoC;AAC3C,SAAQC,WAAW,QAAO,wBAAwB;AAElD,SAAQC,eAAe,QAAO,oCAAoC;AAClE,SAAQC,4BAA4B,QAAO,cAAc;AAEzD,OAAO,SAASC,4BAA4BC,aAA8C;IACxF,OAAOJ,YAAY;QACjBK,QAAQ;QACRC,MAAM;QACNC,MAAMZ;QACNa,aAAa;QACbC,QAAQ;YACNC,QAAQb;YACRc,aAAab;YACbc,UAAU;gBACR,KAAKb;YACP;QACF;QACAc,cAAcX;QACdY,SAAS,OAAOC;YACd,MAAM,EAACC,YAAY,EAAC,GAAGD,QAAQL,MAAM;YACrC,MAAMO,aAAa,MAAMb,cAAcc,aAAa,CAACF;YAErDpB,uBAAuB;gBAACmB;gBAASI,aAAaF,WAAWE,WAAW;YAAA;YAEpE,MAAMC,OAAO,MAAMhB,cAAciB,gBAAgB,CAAC;gBAChDJ;gBACAK,OAAOP,QAAQQ,KAAK,CAACD,KAAK;gBAC1BE,QAAQT,QAAQQ,KAAK,CAACC,MAAM;gBAC5BC,QAAQV,QAAQQ,KAAK,CAACE,MAAM;YAC9B;YAEA,OAAO;gBACLC,cAAcN,KAAKM,YAAY,CAACC,GAAG,CAAC,CAACC,aACnC3B,gBAAgBgB,WAAWY,EAAE,EAAED;gBAEjCE,aAAaV,KAAKW,UAAU;YAC9B;QACF;IACF;AACF"}
1
+ {"version":3,"sources":["../../../src/presentation/routes/list-repositories.ts"],"sourcesContent":["import {AUTH_USER, requireWorkspaceAccess} from '@shipfox/api-auth-context';\nimport {\n listRepositoriesParamsSchema,\n listRepositoriesQuerySchema,\n listRepositoriesResponseSchema,\n} from '@shipfox/api-integration-spi';\nimport {defineRoute} from '@shipfox/node-fastify';\nimport type {IntegrationSourceControlService} from '#core/source-control-service.js';\nimport {toRepositoryDto} from '#presentation/dto/integrations.js';\nimport {integrationRouteErrorHandler} from './errors.js';\n\nexport function createListRepositoriesRoute(sourceControl: IntegrationSourceControlService) {\n return defineRoute({\n method: 'GET',\n path: '/integration-connections/:connectionId/repositories',\n auth: AUTH_USER,\n description: 'List repositories visible to a source-control integration connection.',\n schema: {\n params: listRepositoriesParamsSchema,\n querystring: listRepositoriesQuerySchema,\n response: {\n 200: listRepositoriesResponseSchema,\n },\n },\n errorHandler: integrationRouteErrorHandler,\n handler: async (request) => {\n const {connectionId} = request.params;\n const connection = await sourceControl.getConnection(connectionId);\n\n requireWorkspaceAccess({request, workspaceId: connection.workspaceId});\n\n const page = await sourceControl.listRepositories({\n connection,\n limit: request.query.limit,\n cursor: request.query.cursor,\n search: request.query.search,\n });\n\n return {\n repositories: page.repositories.map((repository) =>\n toRepositoryDto(connection.id, repository),\n ),\n next_cursor: page.nextCursor,\n };\n },\n });\n}\n"],"names":["AUTH_USER","requireWorkspaceAccess","listRepositoriesParamsSchema","listRepositoriesQuerySchema","listRepositoriesResponseSchema","defineRoute","toRepositoryDto","integrationRouteErrorHandler","createListRepositoriesRoute","sourceControl","method","path","auth","description","schema","params","querystring","response","errorHandler","handler","request","connectionId","connection","getConnection","workspaceId","page","listRepositories","limit","query","cursor","search","repositories","map","repository","id","next_cursor","nextCursor"],"mappings":"AAAA,SAAQA,SAAS,EAAEC,sBAAsB,QAAO,4BAA4B;AAC5E,SACEC,4BAA4B,EAC5BC,2BAA2B,EAC3BC,8BAA8B,QACzB,+BAA+B;AACtC,SAAQC,WAAW,QAAO,wBAAwB;AAElD,SAAQC,eAAe,QAAO,oCAAoC;AAClE,SAAQC,4BAA4B,QAAO,cAAc;AAEzD,OAAO,SAASC,4BAA4BC,aAA8C;IACxF,OAAOJ,YAAY;QACjBK,QAAQ;QACRC,MAAM;QACNC,MAAMZ;QACNa,aAAa;QACbC,QAAQ;YACNC,QAAQb;YACRc,aAAab;YACbc,UAAU;gBACR,KAAKb;YACP;QACF;QACAc,cAAcX;QACdY,SAAS,OAAOC;YACd,MAAM,EAACC,YAAY,EAAC,GAAGD,QAAQL,MAAM;YACrC,MAAMO,aAAa,MAAMb,cAAcc,aAAa,CAACF;YAErDpB,uBAAuB;gBAACmB;gBAASI,aAAaF,WAAWE,WAAW;YAAA;YAEpE,MAAMC,OAAO,MAAMhB,cAAciB,gBAAgB,CAAC;gBAChDJ;gBACAK,OAAOP,QAAQQ,KAAK,CAACD,KAAK;gBAC1BE,QAAQT,QAAQQ,KAAK,CAACC,MAAM;gBAC5BC,QAAQV,QAAQQ,KAAK,CAACE,MAAM;YAC9B;YAEA,OAAO;gBACLC,cAAcN,KAAKM,YAAY,CAACC,GAAG,CAAC,CAACC,aACnC3B,gBAAgBgB,WAAWY,EAAE,EAAED;gBAEjCE,aAAaV,KAAKW,UAAU;YAC9B;QACF;IACF;AACF"}
@@ -1,5 +1,5 @@
1
1
  import { AUTH_USER, requireWorkspaceAccess } from '@shipfox/api-auth-context';
2
- import { integrationConnectionDtoSchema, updateIntegrationConnectionBodySchema } from '@shipfox/api-integration-core-dto';
2
+ import { integrationConnectionDtoSchema, updateIntegrationConnectionBodySchema } from '@shipfox/api-integration-spi';
3
3
  import { ClientError, defineRoute } from '@shipfox/node-fastify';
4
4
  import { z } from 'zod';
5
5
  import { deleteIntegrationConnection, getIntegrationConnectionById, updateIntegrationConnectionLifecycleStatus } from '#db/connections.js';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/presentation/routes/manage-connections.ts"],"sourcesContent":["import {AUTH_USER, requireWorkspaceAccess} from '@shipfox/api-auth-context';\nimport {\n integrationConnectionDtoSchema,\n updateIntegrationConnectionBodySchema,\n} from '@shipfox/api-integration-core-dto';\nimport {ClientError, defineRoute} from '@shipfox/node-fastify';\nimport {z} from 'zod';\nimport type {IntegrationProviderRegistry} from '#core/providers/registry.js';\nimport {\n deleteIntegrationConnection,\n getIntegrationConnectionById,\n updateIntegrationConnectionLifecycleStatus,\n} from '#db/connections.js';\nimport {db} from '#db/db.js';\nimport {toIntegrationConnectionDto} from '#presentation/dto/integrations.js';\n\nconst connectionParamsSchema = z.object({\n connectionId: z.string().uuid(),\n});\n\nexport function createUpdateIntegrationConnectionRoute(registry: IntegrationProviderRegistry) {\n return defineRoute({\n method: 'PATCH',\n path: '/integration-connections/:connectionId',\n auth: AUTH_USER,\n description: 'Update an integration connection.',\n schema: {\n params: connectionParamsSchema,\n body: updateIntegrationConnectionBodySchema,\n response: {\n 200: integrationConnectionDtoSchema,\n },\n },\n handler: async (request) => {\n const connection = await getIntegrationConnectionById(request.params.connectionId);\n if (!connection) {\n throw new ClientError('Integration connection not found', 'not-found', {status: 404});\n }\n\n requireWorkspaceAccess({request, workspaceId: connection.workspaceId});\n const updated = await updateIntegrationConnectionLifecycleStatus({\n id: connection.id,\n lifecycleStatus: request.body.lifecycle_status,\n });\n if (!updated) {\n throw new ClientError('Integration connection not found', 'not-found', {status: 404});\n }\n\n const provider = registry.list().find((candidate) => candidate.provider === updated.provider);\n return toIntegrationConnectionDto(updated, {capabilities: provider?.capabilities ?? []});\n },\n });\n}\n\nexport function createDeleteIntegrationConnectionRoute(registry: IntegrationProviderRegistry) {\n return defineRoute({\n method: 'DELETE',\n path: '/integration-connections/:connectionId',\n auth: AUTH_USER,\n description: 'Delete an integration connection.',\n schema: {\n params: connectionParamsSchema,\n response: {\n 204: z.void(),\n },\n },\n handler: async (request, reply) => {\n const connection = await getIntegrationConnectionById(request.params.connectionId);\n if (!connection) {\n throw new ClientError('Integration connection not found', 'not-found', {status: 404});\n }\n\n requireWorkspaceAccess({request, workspaceId: connection.workspaceId});\n const provider = registry\n .list()\n .find((candidate) => candidate.provider === connection.provider);\n const hasCleanupHooks =\n provider?.deleteConnectionRecords !== undefined ||\n provider?.deleteConnectionSecrets !== undefined;\n if (!hasCleanupHooks) {\n request.log.warn(\n {connectionId: connection.id, provider: connection.provider},\n 'Deleting integration connection without provider cleanup',\n );\n }\n await db().transaction(async (tx) => {\n await provider?.deleteConnectionRecords?.(connection, {tx});\n await deleteIntegrationConnection({id: connection.id}, {tx});\n });\n try {\n await provider?.deleteConnectionSecrets?.(connection);\n } catch (error) {\n request.log.error(\n {connectionId: connection.id, provider: connection.provider, err: error},\n 'Integration connection secret cleanup failed after connection deletion',\n );\n }\n reply.status(204);\n },\n });\n}\n"],"names":["AUTH_USER","requireWorkspaceAccess","integrationConnectionDtoSchema","updateIntegrationConnectionBodySchema","ClientError","defineRoute","z","deleteIntegrationConnection","getIntegrationConnectionById","updateIntegrationConnectionLifecycleStatus","db","toIntegrationConnectionDto","connectionParamsSchema","object","connectionId","string","uuid","createUpdateIntegrationConnectionRoute","registry","method","path","auth","description","schema","params","body","response","handler","request","connection","status","workspaceId","updated","id","lifecycleStatus","lifecycle_status","provider","list","find","candidate","capabilities","createDeleteIntegrationConnectionRoute","void","reply","hasCleanupHooks","deleteConnectionRecords","undefined","deleteConnectionSecrets","log","warn","transaction","tx","error","err"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/presentation/routes/manage-connections.ts"],"sourcesContent":["import {AUTH_USER, requireWorkspaceAccess} from '@shipfox/api-auth-context';\nimport {\n integrationConnectionDtoSchema,\n updateIntegrationConnectionBodySchema,\n} from '@shipfox/api-integration-spi';\nimport {ClientError, defineRoute} from '@shipfox/node-fastify';\nimport {z} from 'zod';\nimport type {IntegrationProviderRegistry} from '#core/providers/registry.js';\nimport {\n deleteIntegrationConnection,\n getIntegrationConnectionById,\n updateIntegrationConnectionLifecycleStatus,\n} from '#db/connections.js';\nimport {db} from '#db/db.js';\nimport {toIntegrationConnectionDto} from '#presentation/dto/integrations.js';\n\nconst connectionParamsSchema = z.object({\n connectionId: z.string().uuid(),\n});\n\nexport function createUpdateIntegrationConnectionRoute(registry: IntegrationProviderRegistry) {\n return defineRoute({\n method: 'PATCH',\n path: '/integration-connections/:connectionId',\n auth: AUTH_USER,\n description: 'Update an integration connection.',\n schema: {\n params: connectionParamsSchema,\n body: updateIntegrationConnectionBodySchema,\n response: {\n 200: integrationConnectionDtoSchema,\n },\n },\n handler: async (request) => {\n const connection = await getIntegrationConnectionById(request.params.connectionId);\n if (!connection) {\n throw new ClientError('Integration connection not found', 'not-found', {status: 404});\n }\n\n requireWorkspaceAccess({request, workspaceId: connection.workspaceId});\n const updated = await updateIntegrationConnectionLifecycleStatus({\n id: connection.id,\n lifecycleStatus: request.body.lifecycle_status,\n });\n if (!updated) {\n throw new ClientError('Integration connection not found', 'not-found', {status: 404});\n }\n\n const provider = registry.list().find((candidate) => candidate.provider === updated.provider);\n return toIntegrationConnectionDto(updated, {capabilities: provider?.capabilities ?? []});\n },\n });\n}\n\nexport function createDeleteIntegrationConnectionRoute(registry: IntegrationProviderRegistry) {\n return defineRoute({\n method: 'DELETE',\n path: '/integration-connections/:connectionId',\n auth: AUTH_USER,\n description: 'Delete an integration connection.',\n schema: {\n params: connectionParamsSchema,\n response: {\n 204: z.void(),\n },\n },\n handler: async (request, reply) => {\n const connection = await getIntegrationConnectionById(request.params.connectionId);\n if (!connection) {\n throw new ClientError('Integration connection not found', 'not-found', {status: 404});\n }\n\n requireWorkspaceAccess({request, workspaceId: connection.workspaceId});\n const provider = registry\n .list()\n .find((candidate) => candidate.provider === connection.provider);\n const hasCleanupHooks =\n provider?.deleteConnectionRecords !== undefined ||\n provider?.deleteConnectionSecrets !== undefined;\n if (!hasCleanupHooks) {\n request.log.warn(\n {connectionId: connection.id, provider: connection.provider},\n 'Deleting integration connection without provider cleanup',\n );\n }\n await db().transaction(async (tx) => {\n await provider?.deleteConnectionRecords?.(connection, {tx});\n await deleteIntegrationConnection({id: connection.id}, {tx});\n });\n try {\n await provider?.deleteConnectionSecrets?.(connection);\n } catch (error) {\n request.log.error(\n {connectionId: connection.id, provider: connection.provider, err: error},\n 'Integration connection secret cleanup failed after connection deletion',\n );\n }\n reply.status(204);\n },\n });\n}\n"],"names":["AUTH_USER","requireWorkspaceAccess","integrationConnectionDtoSchema","updateIntegrationConnectionBodySchema","ClientError","defineRoute","z","deleteIntegrationConnection","getIntegrationConnectionById","updateIntegrationConnectionLifecycleStatus","db","toIntegrationConnectionDto","connectionParamsSchema","object","connectionId","string","uuid","createUpdateIntegrationConnectionRoute","registry","method","path","auth","description","schema","params","body","response","handler","request","connection","status","workspaceId","updated","id","lifecycleStatus","lifecycle_status","provider","list","find","candidate","capabilities","createDeleteIntegrationConnectionRoute","void","reply","hasCleanupHooks","deleteConnectionRecords","undefined","deleteConnectionSecrets","log","warn","transaction","tx","error","err"],"mappings":"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"}
@@ -1,2 +1,5 @@
1
+ export declare function slugifyConnectionSlug(input: string, options: {
2
+ fallback: string;
3
+ }): string;
1
4
  export declare function retryConnectionSlugCollision<T>(operation: () => Promise<T>): Promise<T>;
2
5
  //# sourceMappingURL=connection-slug.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"connection-slug.d.ts","sourceRoot":"","sources":["../../src/providers/connection-slug.ts"],"names":[],"mappings":"AAKA,wBAAsB,4BAA4B,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAa7F"}
1
+ {"version":3,"file":"connection-slug.d.ts","sourceRoot":"","sources":["../../src/providers/connection-slug.ts"],"names":[],"mappings":"AAMA,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAC,GAAG,MAAM,CAKxF;AAED,wBAAsB,4BAA4B,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAa7F"}
@@ -1,6 +1,12 @@
1
- import { ConnectionSlugConflictError } from '@shipfox/api-integration-core-dto';
1
+ import { CONNECTION_SLUG_MAX_LENGTH } from '@shipfox/api-integration-core-dto';
2
+ import { ConnectionSlugConflictError } from '@shipfox/api-integration-spi';
2
3
  import { isIntegrationConnectionSlugUniqueViolation } from '#db/connections.js';
3
4
  const MAX_CONNECTION_SLUG_ATTEMPTS = 3;
5
+ export function slugifyConnectionSlug(input, options) {
6
+ const slug = normalizeSlug(input);
7
+ if (slug) return slug;
8
+ return normalizeSlug(options.fallback) || 'connection';
9
+ }
4
10
  export async function retryConnectionSlugCollision(operation) {
5
11
  for(let attempt = 1;; attempt += 1){
6
12
  try {
@@ -15,5 +21,8 @@ export async function retryConnectionSlugCollision(operation) {
15
21
  }
16
22
  }
17
23
  }
24
+ function normalizeSlug(input) {
25
+ return input.toLowerCase().replaceAll(/[^a-z0-9]+/g, '_').replaceAll(/^_+|_+$/g, '').slice(0, CONNECTION_SLUG_MAX_LENGTH).replaceAll(/_+$/g, '');
26
+ }
18
27
 
19
28
  //# sourceMappingURL=connection-slug.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/connection-slug.ts"],"sourcesContent":["import {ConnectionSlugConflictError} from '@shipfox/api-integration-core-dto';\nimport {isIntegrationConnectionSlugUniqueViolation} from '#db/connections.js';\n\nconst MAX_CONNECTION_SLUG_ATTEMPTS = 3;\n\nexport async function retryConnectionSlugCollision<T>(operation: () => Promise<T>): Promise<T> {\n for (let attempt = 1; ; attempt += 1) {\n try {\n return await operation();\n } catch (error) {\n if (!isIntegrationConnectionSlugUniqueViolation(error)) {\n throw error;\n }\n if (attempt >= MAX_CONNECTION_SLUG_ATTEMPTS) {\n throw new ConnectionSlugConflictError(error);\n }\n }\n }\n}\n"],"names":["ConnectionSlugConflictError","isIntegrationConnectionSlugUniqueViolation","MAX_CONNECTION_SLUG_ATTEMPTS","retryConnectionSlugCollision","operation","attempt","error"],"mappings":"AAAA,SAAQA,2BAA2B,QAAO,oCAAoC;AAC9E,SAAQC,0CAA0C,QAAO,qBAAqB;AAE9E,MAAMC,+BAA+B;AAErC,OAAO,eAAeC,6BAAgCC,SAA2B;IAC/E,IAAK,IAAIC,UAAU,IAAKA,WAAW,EAAG;QACpC,IAAI;YACF,OAAO,MAAMD;QACf,EAAE,OAAOE,OAAO;YACd,IAAI,CAACL,2CAA2CK,QAAQ;gBACtD,MAAMA;YACR;YACA,IAAID,WAAWH,8BAA8B;gBAC3C,MAAM,IAAIF,4BAA4BM;YACxC;QACF;IACF;AACF"}
1
+ {"version":3,"sources":["../../src/providers/connection-slug.ts"],"sourcesContent":["import {CONNECTION_SLUG_MAX_LENGTH} from '@shipfox/api-integration-core-dto';\nimport {ConnectionSlugConflictError} from '@shipfox/api-integration-spi';\nimport {isIntegrationConnectionSlugUniqueViolation} from '#db/connections.js';\n\nconst MAX_CONNECTION_SLUG_ATTEMPTS = 3;\n\nexport function slugifyConnectionSlug(input: string, options: {fallback: string}): string {\n const slug = normalizeSlug(input);\n if (slug) return slug;\n\n return normalizeSlug(options.fallback) || 'connection';\n}\n\nexport async function retryConnectionSlugCollision<T>(operation: () => Promise<T>): Promise<T> {\n for (let attempt = 1; ; attempt += 1) {\n try {\n return await operation();\n } catch (error) {\n if (!isIntegrationConnectionSlugUniqueViolation(error)) {\n throw error;\n }\n if (attempt >= MAX_CONNECTION_SLUG_ATTEMPTS) {\n throw new ConnectionSlugConflictError(error);\n }\n }\n }\n}\n\nfunction normalizeSlug(input: string): string {\n return input\n .toLowerCase()\n .replaceAll(/[^a-z0-9]+/g, '_')\n .replaceAll(/^_+|_+$/g, '')\n .slice(0, CONNECTION_SLUG_MAX_LENGTH)\n .replaceAll(/_+$/g, '');\n}\n"],"names":["CONNECTION_SLUG_MAX_LENGTH","ConnectionSlugConflictError","isIntegrationConnectionSlugUniqueViolation","MAX_CONNECTION_SLUG_ATTEMPTS","slugifyConnectionSlug","input","options","slug","normalizeSlug","fallback","retryConnectionSlugCollision","operation","attempt","error","toLowerCase","replaceAll","slice"],"mappings":"AAAA,SAAQA,0BAA0B,QAAO,oCAAoC;AAC7E,SAAQC,2BAA2B,QAAO,+BAA+B;AACzE,SAAQC,0CAA0C,QAAO,qBAAqB;AAE9E,MAAMC,+BAA+B;AAErC,OAAO,SAASC,sBAAsBC,KAAa,EAAEC,OAA2B;IAC9E,MAAMC,OAAOC,cAAcH;IAC3B,IAAIE,MAAM,OAAOA;IAEjB,OAAOC,cAAcF,QAAQG,QAAQ,KAAK;AAC5C;AAEA,OAAO,eAAeC,6BAAgCC,SAA2B;IAC/E,IAAK,IAAIC,UAAU,IAAKA,WAAW,EAAG;QACpC,IAAI;YACF,OAAO,MAAMD;QACf,EAAE,OAAOE,OAAO;YACd,IAAI,CAACX,2CAA2CW,QAAQ;gBACtD,MAAMA;YACR;YACA,IAAID,WAAWT,8BAA8B;gBAC3C,MAAM,IAAIF,4BAA4BY;YACxC;QACF;IACF;AACF;AAEA,SAASL,cAAcH,KAAa;IAClC,OAAOA,MACJS,WAAW,GACXC,UAAU,CAAC,eAAe,KAC1BA,UAAU,CAAC,YAAY,IACvBC,KAAK,CAAC,GAAGhB,4BACTe,UAAU,CAAC,QAAQ;AACxB"}
@@ -1 +1 @@
1
- {"version":3,"file":"gitea.d.ts","sourceRoot":"","sources":["../../src/providers/gitea.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAyB,yBAAyB,EAAC,MAAM,qBAAqB,CAAC;AAuF3F,eAAO,MAAM,mBAAmB,EAAE,yBAIjC,CAAC"}
1
+ {"version":3,"file":"gitea.d.ts","sourceRoot":"","sources":["../../src/providers/gitea.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAyB,yBAAyB,EAAC,MAAM,qBAAqB,CAAC;AAiF3F,eAAO,MAAM,mBAAmB,EAAE,yBAIjC,CAAC"}
@@ -1,14 +1,8 @@
1
- import { slugifyConnectionSlug } from '@shipfox/api-integration-core-dto';
2
1
  import { config } from '#config.js';
3
2
  import { getIntegrationConnectionById, resolveUniqueConnectionSlug, upsertIntegrationConnection } from '#db/connections.js';
4
3
  import { db } from '#db/db.js';
5
4
  import { publishSourcePush, recordDeliveryOnly } from '#db/webhook-deliveries.js';
6
- import { retryConnectionSlugCollision } from '#providers/connection-slug.js';
7
- // Stable migration-tracking table name for the Gitea provider database. This
8
- // must NOT depend on the provider's position in the module `database` array. A
9
- // positional name would shift if a provider is flag-disabled and silently
10
- // re-run migrations against existing tables.
11
- const GITEA_MIGRATIONS_TABLE = '__drizzle_migrations_integrations_gitea';
5
+ import { retryConnectionSlugCollision, slugifyConnectionSlug } from '#providers/connection-slug.js';
12
6
  async function loadGiteaModuleParts() {
13
7
  const { createGiteaIntegrationProvider, getGiteaConnectionByOrg, upsertGiteaConnection, db: giteaDb, migrationsPath: giteaMigrationsPath } = await import('@shipfox/api-integration-gitea');
14
8
  async function getExistingGiteaConnection(input) {
@@ -64,7 +58,7 @@ async function loadGiteaModuleParts() {
64
58
  database: {
65
59
  db: giteaDb,
66
60
  migrationsPath: giteaMigrationsPath,
67
- migrationsTableName: GITEA_MIGRATIONS_TABLE
61
+ databaseNamespace: 'integrations_gitea'
68
62
  }
69
63
  };
70
64
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/gitea.ts"],"sourcesContent":["import {\n type IntegrationConnection as CoreIntegrationConnection,\n slugifyConnectionSlug,\n} from '@shipfox/api-integration-core-dto';\nimport type {ConnectGiteaConnectionInput} from '@shipfox/api-integration-gitea';\nimport {config} from '#config.js';\nimport {\n getIntegrationConnectionById,\n resolveUniqueConnectionSlug,\n upsertIntegrationConnection,\n} from '#db/connections.js';\nimport {db} from '#db/db.js';\nimport {publishSourcePush, recordDeliveryOnly} from '#db/webhook-deliveries.js';\nimport {retryConnectionSlugCollision} from '#providers/connection-slug.js';\nimport type {IntegrationModuleParts, IntegrationProviderModule} from '#providers/types.js';\n\n// Stable migration-tracking table name for the Gitea provider database. This\n// must NOT depend on the provider's position in the module `database` array. A\n// positional name would shift if a provider is flag-disabled and silently\n// re-run migrations against existing tables.\nconst GITEA_MIGRATIONS_TABLE = '__drizzle_migrations_integrations_gitea';\n\nasync function loadGiteaModuleParts(): Promise<IntegrationModuleParts> {\n const {\n createGiteaIntegrationProvider,\n getGiteaConnectionByOrg,\n upsertGiteaConnection,\n db: giteaDb,\n migrationsPath: giteaMigrationsPath,\n } = await import('@shipfox/api-integration-gitea');\n\n async function getExistingGiteaConnection(input: {\n org: string;\n }): Promise<CoreIntegrationConnection<'gitea'> | undefined> {\n const row = await getGiteaConnectionByOrg(input.org);\n if (!row) return undefined;\n const connection = await getIntegrationConnectionById(row.connectionId);\n if (!connection) return undefined;\n return connection as CoreIntegrationConnection<'gitea'>;\n }\n\n async function connectGiteaConnection(\n input: ConnectGiteaConnectionInput,\n ): Promise<CoreIntegrationConnection<'gitea'>> {\n return await retryConnectionSlugCollision(() =>\n db().transaction(async (tx) => {\n const baseSlug = slugifyConnectionSlug(`gitea_${input.org}`, {fallback: 'gitea'});\n const slug = await resolveUniqueConnectionSlug(\n {\n workspaceId: input.workspaceId,\n provider: 'gitea',\n externalAccountId: input.org,\n baseSlug,\n },\n {tx},\n );\n const connection = await upsertIntegrationConnection(\n {\n workspaceId: input.workspaceId,\n provider: 'gitea',\n externalAccountId: input.org,\n slug,\n displayName: input.displayName,\n lifecycleStatus: 'active',\n },\n {tx},\n );\n\n await upsertGiteaConnection(\n {\n connectionId: connection.id,\n org: input.org,\n },\n {tx},\n );\n\n return connection as CoreIntegrationConnection<'gitea'>;\n }),\n );\n }\n\n const integrationProvider = createGiteaIntegrationProvider({\n getExistingGiteaConnection,\n connectGiteaConnection,\n publishSourcePush,\n recordDeliveryOnly,\n getIntegrationConnectionById,\n coreDb: db,\n });\n\n return {\n provider: integrationProvider,\n webhookProcessors: integrationProvider.webhookProcessors,\n database: {\n db: giteaDb,\n migrationsPath: giteaMigrationsPath,\n migrationsTableName: GITEA_MIGRATIONS_TABLE,\n },\n };\n}\n\nexport const giteaProviderModule: IntegrationProviderModule = {\n id: 'gitea',\n enabled: config.INTEGRATIONS_ENABLE_GITEA_PROVIDER,\n load: loadGiteaModuleParts,\n};\n"],"names":["slugifyConnectionSlug","config","getIntegrationConnectionById","resolveUniqueConnectionSlug","upsertIntegrationConnection","db","publishSourcePush","recordDeliveryOnly","retryConnectionSlugCollision","GITEA_MIGRATIONS_TABLE","loadGiteaModuleParts","createGiteaIntegrationProvider","getGiteaConnectionByOrg","upsertGiteaConnection","giteaDb","migrationsPath","giteaMigrationsPath","getExistingGiteaConnection","input","row","org","undefined","connection","connectionId","connectGiteaConnection","transaction","tx","baseSlug","fallback","slug","workspaceId","provider","externalAccountId","displayName","lifecycleStatus","id","integrationProvider","coreDb","webhookProcessors","database","migrationsTableName","giteaProviderModule","enabled","INTEGRATIONS_ENABLE_GITEA_PROVIDER","load"],"mappings":"AAAA,SAEEA,qBAAqB,QAChB,oCAAoC;AAE3C,SAAQC,MAAM,QAAO,aAAa;AAClC,SACEC,4BAA4B,EAC5BC,2BAA2B,EAC3BC,2BAA2B,QACtB,qBAAqB;AAC5B,SAAQC,EAAE,QAAO,YAAY;AAC7B,SAAQC,iBAAiB,EAAEC,kBAAkB,QAAO,4BAA4B;AAChF,SAAQC,4BAA4B,QAAO,gCAAgC;AAG3E,6EAA6E;AAC7E,+EAA+E;AAC/E,0EAA0E;AAC1E,6CAA6C;AAC7C,MAAMC,yBAAyB;AAE/B,eAAeC;IACb,MAAM,EACJC,8BAA8B,EAC9BC,uBAAuB,EACvBC,qBAAqB,EACrBR,IAAIS,OAAO,EACXC,gBAAgBC,mBAAmB,EACpC,GAAG,MAAM,MAAM,CAAC;IAEjB,eAAeC,2BAA2BC,KAEzC;QACC,MAAMC,MAAM,MAAMP,wBAAwBM,MAAME,GAAG;QACnD,IAAI,CAACD,KAAK,OAAOE;QACjB,MAAMC,aAAa,MAAMpB,6BAA6BiB,IAAII,YAAY;QACtE,IAAI,CAACD,YAAY,OAAOD;QACxB,OAAOC;IACT;IAEA,eAAeE,uBACbN,KAAkC;QAElC,OAAO,MAAMV,6BAA6B,IACxCH,KAAKoB,WAAW,CAAC,OAAOC;gBACtB,MAAMC,WAAW3B,sBAAsB,CAAC,MAAM,EAAEkB,MAAME,GAAG,EAAE,EAAE;oBAACQ,UAAU;gBAAO;gBAC/E,MAAMC,OAAO,MAAM1B,4BACjB;oBACE2B,aAAaZ,MAAMY,WAAW;oBAC9BC,UAAU;oBACVC,mBAAmBd,MAAME,GAAG;oBAC5BO;gBACF,GACA;oBAACD;gBAAE;gBAEL,MAAMJ,aAAa,MAAMlB,4BACvB;oBACE0B,aAAaZ,MAAMY,WAAW;oBAC9BC,UAAU;oBACVC,mBAAmBd,MAAME,GAAG;oBAC5BS;oBACAI,aAAaf,MAAMe,WAAW;oBAC9BC,iBAAiB;gBACnB,GACA;oBAACR;gBAAE;gBAGL,MAAMb,sBACJ;oBACEU,cAAcD,WAAWa,EAAE;oBAC3Bf,KAAKF,MAAME,GAAG;gBAChB,GACA;oBAACM;gBAAE;gBAGL,OAAOJ;YACT;IAEJ;IAEA,MAAMc,sBAAsBzB,+BAA+B;QACzDM;QACAO;QACAlB;QACAC;QACAL;QACAmC,QAAQhC;IACV;IAEA,OAAO;QACL0B,UAAUK;QACVE,mBAAmBF,oBAAoBE,iBAAiB;QACxDC,UAAU;YACRlC,IAAIS;YACJC,gBAAgBC;YAChBwB,qBAAqB/B;QACvB;IACF;AACF;AAEA,OAAO,MAAMgC,sBAAiD;IAC5DN,IAAI;IACJO,SAASzC,OAAO0C,kCAAkC;IAClDC,MAAMlC;AACR,EAAE"}
1
+ {"version":3,"sources":["../../src/providers/gitea.ts"],"sourcesContent":["import type {ConnectGiteaConnectionInput} from '@shipfox/api-integration-gitea';\nimport type {IntegrationConnection as CoreIntegrationConnection} from '@shipfox/api-integration-spi';\nimport {config} from '#config.js';\nimport {\n getIntegrationConnectionById,\n resolveUniqueConnectionSlug,\n upsertIntegrationConnection,\n} from '#db/connections.js';\nimport {db} from '#db/db.js';\nimport {publishSourcePush, recordDeliveryOnly} from '#db/webhook-deliveries.js';\nimport {retryConnectionSlugCollision, slugifyConnectionSlug} from '#providers/connection-slug.js';\nimport type {IntegrationModuleParts, IntegrationProviderModule} from '#providers/types.js';\n\nasync function loadGiteaModuleParts(): Promise<IntegrationModuleParts> {\n const {\n createGiteaIntegrationProvider,\n getGiteaConnectionByOrg,\n upsertGiteaConnection,\n db: giteaDb,\n migrationsPath: giteaMigrationsPath,\n } = await import('@shipfox/api-integration-gitea');\n\n async function getExistingGiteaConnection(input: {\n org: string;\n }): Promise<CoreIntegrationConnection<'gitea'> | undefined> {\n const row = await getGiteaConnectionByOrg(input.org);\n if (!row) return undefined;\n const connection = await getIntegrationConnectionById(row.connectionId);\n if (!connection) return undefined;\n return connection as CoreIntegrationConnection<'gitea'>;\n }\n\n async function connectGiteaConnection(\n input: ConnectGiteaConnectionInput,\n ): Promise<CoreIntegrationConnection<'gitea'>> {\n return await retryConnectionSlugCollision(() =>\n db().transaction(async (tx) => {\n const baseSlug = slugifyConnectionSlug(`gitea_${input.org}`, {fallback: 'gitea'});\n const slug = await resolveUniqueConnectionSlug(\n {\n workspaceId: input.workspaceId,\n provider: 'gitea',\n externalAccountId: input.org,\n baseSlug,\n },\n {tx},\n );\n const connection = await upsertIntegrationConnection(\n {\n workspaceId: input.workspaceId,\n provider: 'gitea',\n externalAccountId: input.org,\n slug,\n displayName: input.displayName,\n lifecycleStatus: 'active',\n },\n {tx},\n );\n\n await upsertGiteaConnection(\n {\n connectionId: connection.id,\n org: input.org,\n },\n {tx},\n );\n\n return connection as CoreIntegrationConnection<'gitea'>;\n }),\n );\n }\n\n const integrationProvider = createGiteaIntegrationProvider({\n getExistingGiteaConnection,\n connectGiteaConnection,\n publishSourcePush,\n recordDeliveryOnly,\n getIntegrationConnectionById,\n coreDb: db,\n });\n\n return {\n provider: integrationProvider,\n webhookProcessors: integrationProvider.webhookProcessors,\n database: {\n db: giteaDb,\n migrationsPath: giteaMigrationsPath,\n databaseNamespace: 'integrations_gitea',\n },\n };\n}\n\nexport const giteaProviderModule: IntegrationProviderModule = {\n id: 'gitea',\n enabled: config.INTEGRATIONS_ENABLE_GITEA_PROVIDER,\n load: loadGiteaModuleParts,\n};\n"],"names":["config","getIntegrationConnectionById","resolveUniqueConnectionSlug","upsertIntegrationConnection","db","publishSourcePush","recordDeliveryOnly","retryConnectionSlugCollision","slugifyConnectionSlug","loadGiteaModuleParts","createGiteaIntegrationProvider","getGiteaConnectionByOrg","upsertGiteaConnection","giteaDb","migrationsPath","giteaMigrationsPath","getExistingGiteaConnection","input","row","org","undefined","connection","connectionId","connectGiteaConnection","transaction","tx","baseSlug","fallback","slug","workspaceId","provider","externalAccountId","displayName","lifecycleStatus","id","integrationProvider","coreDb","webhookProcessors","database","databaseNamespace","giteaProviderModule","enabled","INTEGRATIONS_ENABLE_GITEA_PROVIDER","load"],"mappings":"AAEA,SAAQA,MAAM,QAAO,aAAa;AAClC,SACEC,4BAA4B,EAC5BC,2BAA2B,EAC3BC,2BAA2B,QACtB,qBAAqB;AAC5B,SAAQC,EAAE,QAAO,YAAY;AAC7B,SAAQC,iBAAiB,EAAEC,kBAAkB,QAAO,4BAA4B;AAChF,SAAQC,4BAA4B,EAAEC,qBAAqB,QAAO,gCAAgC;AAGlG,eAAeC;IACb,MAAM,EACJC,8BAA8B,EAC9BC,uBAAuB,EACvBC,qBAAqB,EACrBR,IAAIS,OAAO,EACXC,gBAAgBC,mBAAmB,EACpC,GAAG,MAAM,MAAM,CAAC;IAEjB,eAAeC,2BAA2BC,KAEzC;QACC,MAAMC,MAAM,MAAMP,wBAAwBM,MAAME,GAAG;QACnD,IAAI,CAACD,KAAK,OAAOE;QACjB,MAAMC,aAAa,MAAMpB,6BAA6BiB,IAAII,YAAY;QACtE,IAAI,CAACD,YAAY,OAAOD;QACxB,OAAOC;IACT;IAEA,eAAeE,uBACbN,KAAkC;QAElC,OAAO,MAAMV,6BAA6B,IACxCH,KAAKoB,WAAW,CAAC,OAAOC;gBACtB,MAAMC,WAAWlB,sBAAsB,CAAC,MAAM,EAAES,MAAME,GAAG,EAAE,EAAE;oBAACQ,UAAU;gBAAO;gBAC/E,MAAMC,OAAO,MAAM1B,4BACjB;oBACE2B,aAAaZ,MAAMY,WAAW;oBAC9BC,UAAU;oBACVC,mBAAmBd,MAAME,GAAG;oBAC5BO;gBACF,GACA;oBAACD;gBAAE;gBAEL,MAAMJ,aAAa,MAAMlB,4BACvB;oBACE0B,aAAaZ,MAAMY,WAAW;oBAC9BC,UAAU;oBACVC,mBAAmBd,MAAME,GAAG;oBAC5BS;oBACAI,aAAaf,MAAMe,WAAW;oBAC9BC,iBAAiB;gBACnB,GACA;oBAACR;gBAAE;gBAGL,MAAMb,sBACJ;oBACEU,cAAcD,WAAWa,EAAE;oBAC3Bf,KAAKF,MAAME,GAAG;gBAChB,GACA;oBAACM;gBAAE;gBAGL,OAAOJ;YACT;IAEJ;IAEA,MAAMc,sBAAsBzB,+BAA+B;QACzDM;QACAO;QACAlB;QACAC;QACAL;QACAmC,QAAQhC;IACV;IAEA,OAAO;QACL0B,UAAUK;QACVE,mBAAmBF,oBAAoBE,iBAAiB;QACxDC,UAAU;YACRlC,IAAIS;YACJC,gBAAgBC;YAChBwB,mBAAmB;QACrB;IACF;AACF;AAEA,OAAO,MAAMC,sBAAiD;IAC5DN,IAAI;IACJO,SAASzC,OAAO0C,kCAAkC;IAClDC,MAAMlC;AACR,EAAE"}
@@ -1 +1 @@
1
- {"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/providers/github.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAEV,yBAAyB,EAE1B,MAAM,qBAAqB,CAAC;AAiI7B,eAAO,MAAM,oBAAoB,EAAE,yBAIlC,CAAC"}
1
+ {"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/providers/github.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAEV,yBAAyB,EAE1B,MAAM,qBAAqB,CAAC;AA2H7B,eAAO,MAAM,oBAAoB,EAAE,yBAIlC,CAAC"}
@@ -1,14 +1,8 @@
1
- import { slugifyConnectionSlug } from '@shipfox/api-integration-core-dto';
2
1
  import { config } from '#config.js';
3
2
  import { getIntegrationConnectionById, resolveUniqueConnectionSlug, upsertIntegrationConnection } from '#db/connections.js';
4
3
  import { db } from '#db/db.js';
5
4
  import { publishIntegrationEventReceived, publishSourcePush, recordDeliveryOnly } from '#db/webhook-deliveries.js';
6
- import { retryConnectionSlugCollision } from '#providers/connection-slug.js';
7
- // Stable migration-tracking table name for the GitHub provider database. This
8
- // must NOT depend on the provider's position in the module `database` array. A
9
- // positional name would shift if a provider is flag-disabled and silently
10
- // re-run migrations against existing tables.
11
- const GITHUB_MIGRATIONS_TABLE = '__drizzle_migrations_integrations_github';
5
+ import { retryConnectionSlugCollision, slugifyConnectionSlug } from '#providers/connection-slug.js';
12
6
  async function loadGithubModuleParts(options = {}) {
13
7
  const { createGithubInstallationTokenProvider, createGithubE2eRoutes, encodeInstallationTokenEnvelope, createGithubIntegrationProvider, getGithubInstallationByInstallationId, githubInstallationTokenNamespace, db: githubDb, migrationsPath: githubMigrationsPath, upsertGithubInstallation } = await import('@shipfox/api-integration-github');
14
8
  const tokenProvider = createGithubInstallationTokenProvider({
@@ -101,7 +95,7 @@ async function loadGithubModuleParts(options = {}) {
101
95
  database: {
102
96
  db: githubDb,
103
97
  migrationsPath: githubMigrationsPath,
104
- migrationsTableName: GITHUB_MIGRATIONS_TABLE
98
+ databaseNamespace: 'integrations_github'
105
99
  }
106
100
  };
107
101
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/github.ts"],"sourcesContent":["import {\n type IntegrationConnection as CoreIntegrationConnection,\n slugifyConnectionSlug,\n} from '@shipfox/api-integration-core-dto';\nimport type {ConnectGithubInstallationInput} from '@shipfox/api-integration-github';\nimport {config} from '#config.js';\nimport {\n getIntegrationConnectionById,\n resolveUniqueConnectionSlug,\n upsertIntegrationConnection,\n} from '#db/connections.js';\nimport {db} from '#db/db.js';\nimport {\n publishIntegrationEventReceived,\n publishSourcePush,\n recordDeliveryOnly,\n} from '#db/webhook-deliveries.js';\nimport {retryConnectionSlugCollision} from '#providers/connection-slug.js';\nimport type {\n IntegrationModuleParts,\n IntegrationProviderModule,\n IntegrationProviderModuleLoadOptions,\n} from '#providers/types.js';\n\n// Stable migration-tracking table name for the GitHub provider database. This\n// must NOT depend on the provider's position in the module `database` array. A\n// positional name would shift if a provider is flag-disabled and silently\n// re-run migrations against existing tables.\nconst GITHUB_MIGRATIONS_TABLE = '__drizzle_migrations_integrations_github';\n\nasync function loadGithubModuleParts(\n options: IntegrationProviderModuleLoadOptions = {},\n): Promise<IntegrationModuleParts> {\n const {\n createGithubInstallationTokenProvider,\n createGithubE2eRoutes,\n encodeInstallationTokenEnvelope,\n createGithubIntegrationProvider,\n getGithubInstallationByInstallationId,\n githubInstallationTokenNamespace,\n db: githubDb,\n migrationsPath: githubMigrationsPath,\n upsertGithubInstallation,\n } = await import('@shipfox/api-integration-github');\n\n const tokenProvider = createGithubInstallationTokenProvider({\n getIntegrationConnectionById,\n secretStore: options.secrets?.github\n ? {\n read: async (workspaceId, installationId) =>\n (await options.secrets?.github?.getSecret({\n workspaceId,\n namespace: githubInstallationTokenNamespace(installationId),\n key: 'envelope',\n })) ?? null,\n write: async (workspaceId, installationId, envelope) => {\n await options.secrets?.github?.setSecrets({\n workspaceId,\n namespace: githubInstallationTokenNamespace(installationId),\n values: {envelope: encodeInstallationTokenEnvelope(envelope)},\n });\n },\n }\n : undefined,\n });\n\n async function getExistingGithubConnection(input: {\n installationId: string;\n }): Promise<CoreIntegrationConnection<'github'> | undefined> {\n const installation = await getGithubInstallationByInstallationId(input.installationId);\n if (!installation) return undefined;\n const connection = await getIntegrationConnectionById(installation.connectionId);\n if (!connection) return undefined;\n return connection as CoreIntegrationConnection<'github'>;\n }\n\n async function connectGithubInstallation(\n input: ConnectGithubInstallationInput,\n ): Promise<CoreIntegrationConnection<'github'>> {\n return await retryConnectionSlugCollision(() =>\n db().transaction(async (tx) => {\n const baseSlug = slugifyConnectionSlug(`github_${input.installation.accountLogin}`, {\n fallback: 'github',\n });\n const slug = await resolveUniqueConnectionSlug(\n {\n workspaceId: input.workspaceId,\n provider: 'github',\n externalAccountId: input.installationId,\n baseSlug,\n },\n {tx},\n );\n const connection = await upsertIntegrationConnection(\n {\n workspaceId: input.workspaceId,\n provider: 'github',\n externalAccountId: input.installationId,\n slug,\n displayName: input.displayName,\n lifecycleStatus: 'active',\n },\n {tx},\n );\n\n await upsertGithubInstallation(\n {\n connectionId: connection.id,\n ...input.installation,\n },\n {tx},\n );\n\n return connection as CoreIntegrationConnection<'github'>;\n }),\n );\n }\n\n const integrationProvider = createGithubIntegrationProvider({\n getExistingGithubConnection,\n connectGithubInstallation,\n publishIntegrationEventReceived,\n publishSourcePush,\n recordDeliveryOnly,\n getIntegrationConnectionById,\n coreDb: db,\n deleteSecrets: options.secrets?.deleteSecrets,\n agentTools: {tokenProvider},\n ...(options.requireActiveWorkspaceMembership\n ? {requireActiveWorkspaceMembership: options.requireActiveWorkspaceMembership}\n : {}),\n });\n\n return {\n provider: integrationProvider,\n webhookProcessors: integrationProvider.webhookProcessors,\n e2eRoutes: [\n createGithubE2eRoutes({\n getExistingGithubConnection,\n connectGithubInstallation,\n connectionCapabilities: ['source_control', 'agent_tools'],\n }),\n ],\n database: {\n db: githubDb,\n migrationsPath: githubMigrationsPath,\n migrationsTableName: GITHUB_MIGRATIONS_TABLE,\n },\n };\n}\n\nexport const githubProviderModule: IntegrationProviderModule = {\n id: 'github',\n enabled: config.INTEGRATIONS_ENABLE_GITHUB_PROVIDER,\n load: loadGithubModuleParts,\n};\n"],"names":["slugifyConnectionSlug","config","getIntegrationConnectionById","resolveUniqueConnectionSlug","upsertIntegrationConnection","db","publishIntegrationEventReceived","publishSourcePush","recordDeliveryOnly","retryConnectionSlugCollision","GITHUB_MIGRATIONS_TABLE","loadGithubModuleParts","options","createGithubInstallationTokenProvider","createGithubE2eRoutes","encodeInstallationTokenEnvelope","createGithubIntegrationProvider","getGithubInstallationByInstallationId","githubInstallationTokenNamespace","githubDb","migrationsPath","githubMigrationsPath","upsertGithubInstallation","tokenProvider","secretStore","secrets","github","read","workspaceId","installationId","getSecret","namespace","key","write","envelope","setSecrets","values","undefined","getExistingGithubConnection","input","installation","connection","connectionId","connectGithubInstallation","transaction","tx","baseSlug","accountLogin","fallback","slug","provider","externalAccountId","displayName","lifecycleStatus","id","integrationProvider","coreDb","deleteSecrets","agentTools","requireActiveWorkspaceMembership","webhookProcessors","e2eRoutes","connectionCapabilities","database","migrationsTableName","githubProviderModule","enabled","INTEGRATIONS_ENABLE_GITHUB_PROVIDER","load"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/providers/github.ts"],"sourcesContent":["import type {ConnectGithubInstallationInput} from '@shipfox/api-integration-github';\nimport type {IntegrationConnection as CoreIntegrationConnection} from '@shipfox/api-integration-spi';\nimport {config} from '#config.js';\nimport {\n getIntegrationConnectionById,\n resolveUniqueConnectionSlug,\n upsertIntegrationConnection,\n} from '#db/connections.js';\nimport {db} from '#db/db.js';\nimport {\n publishIntegrationEventReceived,\n publishSourcePush,\n recordDeliveryOnly,\n} from '#db/webhook-deliveries.js';\nimport {retryConnectionSlugCollision, slugifyConnectionSlug} from '#providers/connection-slug.js';\nimport type {\n IntegrationModuleParts,\n IntegrationProviderModule,\n IntegrationProviderModuleLoadOptions,\n} from '#providers/types.js';\n\nasync function loadGithubModuleParts(\n options: IntegrationProviderModuleLoadOptions = {},\n): Promise<IntegrationModuleParts> {\n const {\n createGithubInstallationTokenProvider,\n createGithubE2eRoutes,\n encodeInstallationTokenEnvelope,\n createGithubIntegrationProvider,\n getGithubInstallationByInstallationId,\n githubInstallationTokenNamespace,\n db: githubDb,\n migrationsPath: githubMigrationsPath,\n upsertGithubInstallation,\n } = await import('@shipfox/api-integration-github');\n\n const tokenProvider = createGithubInstallationTokenProvider({\n getIntegrationConnectionById,\n secretStore: options.secrets?.github\n ? {\n read: async (workspaceId, installationId) =>\n (await options.secrets?.github?.getSecret({\n workspaceId,\n namespace: githubInstallationTokenNamespace(installationId),\n key: 'envelope',\n })) ?? null,\n write: async (workspaceId, installationId, envelope) => {\n await options.secrets?.github?.setSecrets({\n workspaceId,\n namespace: githubInstallationTokenNamespace(installationId),\n values: {envelope: encodeInstallationTokenEnvelope(envelope)},\n });\n },\n }\n : undefined,\n });\n\n async function getExistingGithubConnection(input: {\n installationId: string;\n }): Promise<CoreIntegrationConnection<'github'> | undefined> {\n const installation = await getGithubInstallationByInstallationId(input.installationId);\n if (!installation) return undefined;\n const connection = await getIntegrationConnectionById(installation.connectionId);\n if (!connection) return undefined;\n return connection as CoreIntegrationConnection<'github'>;\n }\n\n async function connectGithubInstallation(\n input: ConnectGithubInstallationInput,\n ): Promise<CoreIntegrationConnection<'github'>> {\n return await retryConnectionSlugCollision(() =>\n db().transaction(async (tx) => {\n const baseSlug = slugifyConnectionSlug(`github_${input.installation.accountLogin}`, {\n fallback: 'github',\n });\n const slug = await resolveUniqueConnectionSlug(\n {\n workspaceId: input.workspaceId,\n provider: 'github',\n externalAccountId: input.installationId,\n baseSlug,\n },\n {tx},\n );\n const connection = await upsertIntegrationConnection(\n {\n workspaceId: input.workspaceId,\n provider: 'github',\n externalAccountId: input.installationId,\n slug,\n displayName: input.displayName,\n lifecycleStatus: 'active',\n },\n {tx},\n );\n\n await upsertGithubInstallation(\n {\n connectionId: connection.id,\n ...input.installation,\n },\n {tx},\n );\n\n return connection as CoreIntegrationConnection<'github'>;\n }),\n );\n }\n\n const integrationProvider = createGithubIntegrationProvider({\n getExistingGithubConnection,\n connectGithubInstallation,\n publishIntegrationEventReceived,\n publishSourcePush,\n recordDeliveryOnly,\n getIntegrationConnectionById,\n coreDb: db,\n deleteSecrets: options.secrets?.deleteSecrets,\n agentTools: {tokenProvider},\n ...(options.requireActiveWorkspaceMembership\n ? {requireActiveWorkspaceMembership: options.requireActiveWorkspaceMembership}\n : {}),\n });\n\n return {\n provider: integrationProvider,\n webhookProcessors: integrationProvider.webhookProcessors,\n e2eRoutes: [\n createGithubE2eRoutes({\n getExistingGithubConnection,\n connectGithubInstallation,\n connectionCapabilities: ['source_control', 'agent_tools'],\n }),\n ],\n database: {\n db: githubDb,\n migrationsPath: githubMigrationsPath,\n databaseNamespace: 'integrations_github',\n },\n };\n}\n\nexport const githubProviderModule: IntegrationProviderModule = {\n id: 'github',\n enabled: config.INTEGRATIONS_ENABLE_GITHUB_PROVIDER,\n load: loadGithubModuleParts,\n};\n"],"names":["config","getIntegrationConnectionById","resolveUniqueConnectionSlug","upsertIntegrationConnection","db","publishIntegrationEventReceived","publishSourcePush","recordDeliveryOnly","retryConnectionSlugCollision","slugifyConnectionSlug","loadGithubModuleParts","options","createGithubInstallationTokenProvider","createGithubE2eRoutes","encodeInstallationTokenEnvelope","createGithubIntegrationProvider","getGithubInstallationByInstallationId","githubInstallationTokenNamespace","githubDb","migrationsPath","githubMigrationsPath","upsertGithubInstallation","tokenProvider","secretStore","secrets","github","read","workspaceId","installationId","getSecret","namespace","key","write","envelope","setSecrets","values","undefined","getExistingGithubConnection","input","installation","connection","connectionId","connectGithubInstallation","transaction","tx","baseSlug","accountLogin","fallback","slug","provider","externalAccountId","displayName","lifecycleStatus","id","integrationProvider","coreDb","deleteSecrets","agentTools","requireActiveWorkspaceMembership","webhookProcessors","e2eRoutes","connectionCapabilities","database","databaseNamespace","githubProviderModule","enabled","INTEGRATIONS_ENABLE_GITHUB_PROVIDER","load"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"jira.d.ts","sourceRoot":"","sources":["../../src/providers/jira.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAyB,yBAAyB,EAAC,MAAM,qBAAqB,CAAC;AAgJ3F,eAAO,MAAM,kBAAkB,EAAE,yBAIhC,CAAC"}
1
+ {"version":3,"file":"jira.d.ts","sourceRoot":"","sources":["../../src/providers/jira.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAyB,yBAAyB,EAAC,MAAM,qBAAqB,CAAC;AA+I3F,eAAO,MAAM,kBAAkB,EAAE,yBAIhC,CAAC"}
@@ -1,9 +1,7 @@
1
- import { slugifyConnectionSlug } from '@shipfox/api-integration-core-dto';
2
1
  import { config } from '#config.js';
3
2
  import { deleteIntegrationConnection, getIntegrationConnectionById, resolveUniqueConnectionSlug, updateIntegrationConnectionLifecycleStatus, upsertIntegrationConnection } from '#db/connections.js';
4
3
  import { db } from '#db/db.js';
5
- import { retryConnectionSlugCollision } from '#providers/connection-slug.js';
6
- const JIRA_MIGRATIONS_TABLE = '__drizzle_migrations_integrations_jira';
4
+ import { retryConnectionSlugCollision, slugifyConnectionSlug } from '#providers/connection-slug.js';
7
5
  const JIRA_SECRETS_NAMESPACE_PREFIX = 'system/integrations/jira/';
8
6
  async function loadJiraModuleParts(options = {}) {
9
7
  const { createJiraIntegrationProvider, createJiraPendingSelectionStore, createJiraTokenStore, db: jiraDb, disconnectJiraInstallation: disconnectJiraInstallationRecords, getJiraInstallationByCloudId, migrationsPath, upsertJiraInstallation } = await import('@shipfox/api-integration-jira');
@@ -111,7 +109,7 @@ async function loadJiraModuleParts(options = {}) {
111
109
  database: {
112
110
  db: jiraDb,
113
111
  migrationsPath,
114
- migrationsTableName: JIRA_MIGRATIONS_TABLE
112
+ databaseNamespace: 'integrations_jira'
115
113
  }
116
114
  };
117
115
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/jira.ts"],"sourcesContent":["import {\n type IntegrationConnection as CoreIntegrationConnection,\n slugifyConnectionSlug,\n} from '@shipfox/api-integration-core-dto';\nimport type {\n ConnectJiraInstallationInput,\n JiraPendingSelectionSecretsStore,\n JiraSecretsStore,\n} from '@shipfox/api-integration-jira';\nimport {config} from '#config.js';\nimport {\n deleteIntegrationConnection,\n getIntegrationConnectionById,\n resolveUniqueConnectionSlug,\n updateIntegrationConnectionLifecycleStatus,\n upsertIntegrationConnection,\n} from '#db/connections.js';\nimport {db} from '#db/db.js';\nimport {retryConnectionSlugCollision} from '#providers/connection-slug.js';\nimport type {IntegrationModuleParts, IntegrationProviderModule} from '#providers/types.js';\n\nconst JIRA_MIGRATIONS_TABLE = '__drizzle_migrations_integrations_jira';\nconst JIRA_SECRETS_NAMESPACE_PREFIX = 'system/integrations/jira/';\ntype IntegrationDb = ReturnType<typeof db>;\ntype IntegrationTx = Parameters<Parameters<IntegrationDb['transaction']>[0]>[0];\n\nasync function loadJiraModuleParts(\n options: Parameters<IntegrationProviderModule['load']>[0] = {},\n): Promise<IntegrationModuleParts> {\n const {\n createJiraIntegrationProvider,\n createJiraPendingSelectionStore,\n createJiraTokenStore,\n db: jiraDb,\n disconnectJiraInstallation: disconnectJiraInstallationRecords,\n getJiraInstallationByCloudId,\n migrationsPath,\n upsertJiraInstallation,\n } = await import('@shipfox/api-integration-jira');\n\n async function getExistingJiraConnection(input: {\n cloudId: string;\n }): Promise<CoreIntegrationConnection<'jira'> | undefined> {\n const installation = await getJiraInstallationByCloudId(input.cloudId);\n if (!installation) return undefined;\n return (await getIntegrationConnectionById(installation.connectionId)) as\n | CoreIntegrationConnection<'jira'>\n | undefined;\n }\n\n function connectJiraInstallation(\n input: ConnectJiraInstallationInput,\n ): Promise<CoreIntegrationConnection<'jira'>> {\n return retryConnectionSlugCollision(() =>\n db().transaction(async (tx) => {\n const slug = await resolveUniqueConnectionSlug(\n {\n workspaceId: input.workspaceId,\n provider: 'jira',\n externalAccountId: input.cloudId,\n baseSlug: slugifyConnectionSlug(`jira_${input.siteName || input.cloudId}`, {\n fallback: 'jira',\n }),\n },\n {tx},\n );\n const connection = await upsertIntegrationConnection(\n {\n workspaceId: input.workspaceId,\n provider: 'jira',\n externalAccountId: input.cloudId,\n slug,\n displayName: input.displayName,\n lifecycleStatus: 'active',\n },\n {tx},\n );\n await upsertJiraInstallation(\n {\n connectionId: connection.id,\n cloudId: input.cloudId,\n siteUrl: input.siteUrl,\n siteName: input.siteName,\n authorizingAccountId: input.authorizingAccountId,\n scopes: input.scopes,\n status: 'installed',\n tokenExpiresAt: input.tokenExpiresAt,\n },\n {tx},\n );\n return connection as CoreIntegrationConnection<'jira'>;\n }),\n );\n }\n\n async function disconnectJiraInstallation(input: {connectionId: string}): Promise<void> {\n await disconnectJiraInstallationRecords<IntegrationTx>({\n connectionId: input.connectionId,\n getConnection: getIntegrationConnectionById,\n deleteSecrets: (params) =>\n options.secrets?.jira?.deleteSecrets({\n ...params,\n namespace: jiraNamespaceSuffix(params.namespace),\n }) ?? Promise.resolve(0),\n transaction: (fn) => db().transaction((tx) => fn(tx)),\n deleteConnection: (params, transactionOptions) =>\n deleteIntegrationConnection({id: params.connectionId}, transactionOptions),\n });\n }\n\n const fallbackSecrets: JiraSecretsStore & JiraPendingSelectionSecretsStore = {\n getSecret: () => Promise.resolve(null),\n setSecrets: () => Promise.reject(new Error('Jira token storage is not configured')),\n deleteSecrets: () => Promise.resolve(0),\n };\n const secrets: JiraSecretsStore & JiraPendingSelectionSecretsStore = options.secrets?.jira\n ? {\n getSecret: (params) =>\n options.secrets?.jira?.getSecret({\n ...params,\n namespace: jiraNamespaceSuffix(params.namespace),\n }) ?? Promise.resolve(null),\n setSecrets: (params) =>\n options.secrets?.jira?.setSecrets({\n ...params,\n namespace: jiraNamespaceSuffix(params.namespace),\n }) ?? Promise.resolve(),\n deleteSecrets: (params) =>\n options.secrets?.jira?.deleteSecrets({\n ...params,\n namespace: jiraNamespaceSuffix(params.namespace),\n }) ?? Promise.resolve(0),\n }\n : fallbackSecrets;\n const tokenStore = createJiraTokenStore({\n resolveConnection: getIntegrationConnectionById,\n secrets,\n markConnectionError: async ({connectionId}) => {\n await updateIntegrationConnectionLifecycleStatus({\n id: connectionId,\n lifecycleStatus: 'error',\n });\n },\n });\n const pendingStore = createJiraPendingSelectionStore({secrets});\n\n return {\n provider: createJiraIntegrationProvider({\n routes: {\n tokenStore,\n pendingStore,\n getExistingJiraConnection,\n connectJiraInstallation,\n disconnectJiraInstallation,\n ...(options.requireActiveWorkspaceMembership\n ? {requireActiveWorkspaceMembership: options.requireActiveWorkspaceMembership}\n : {}),\n },\n }),\n database: {db: jiraDb, migrationsPath, migrationsTableName: JIRA_MIGRATIONS_TABLE},\n };\n}\n\nexport const jiraProviderModule: IntegrationProviderModule = {\n id: 'jira',\n enabled: config.INTEGRATIONS_ENABLE_JIRA_PROVIDER,\n load: loadJiraModuleParts,\n};\n\nfunction jiraNamespaceSuffix(namespace: string): string {\n if (!namespace.startsWith(JIRA_SECRETS_NAMESPACE_PREFIX)) {\n throw new Error('Jira provider attempted to access an unscoped secret namespace');\n }\n return namespace.slice(JIRA_SECRETS_NAMESPACE_PREFIX.length);\n}\n"],"names":["slugifyConnectionSlug","config","deleteIntegrationConnection","getIntegrationConnectionById","resolveUniqueConnectionSlug","updateIntegrationConnectionLifecycleStatus","upsertIntegrationConnection","db","retryConnectionSlugCollision","JIRA_MIGRATIONS_TABLE","JIRA_SECRETS_NAMESPACE_PREFIX","loadJiraModuleParts","options","createJiraIntegrationProvider","createJiraPendingSelectionStore","createJiraTokenStore","jiraDb","disconnectJiraInstallation","disconnectJiraInstallationRecords","getJiraInstallationByCloudId","migrationsPath","upsertJiraInstallation","getExistingJiraConnection","input","installation","cloudId","undefined","connectionId","connectJiraInstallation","transaction","tx","slug","workspaceId","provider","externalAccountId","baseSlug","siteName","fallback","connection","displayName","lifecycleStatus","id","siteUrl","authorizingAccountId","scopes","status","tokenExpiresAt","getConnection","deleteSecrets","params","secrets","jira","namespace","jiraNamespaceSuffix","Promise","resolve","fn","deleteConnection","transactionOptions","fallbackSecrets","getSecret","setSecrets","reject","Error","tokenStore","resolveConnection","markConnectionError","pendingStore","routes","requireActiveWorkspaceMembership","database","migrationsTableName","jiraProviderModule","enabled","INTEGRATIONS_ENABLE_JIRA_PROVIDER","load","startsWith","slice","length"],"mappings":"AAAA,SAEEA,qBAAqB,QAChB,oCAAoC;AAM3C,SAAQC,MAAM,QAAO,aAAa;AAClC,SACEC,2BAA2B,EAC3BC,4BAA4B,EAC5BC,2BAA2B,EAC3BC,0CAA0C,EAC1CC,2BAA2B,QACtB,qBAAqB;AAC5B,SAAQC,EAAE,QAAO,YAAY;AAC7B,SAAQC,4BAA4B,QAAO,gCAAgC;AAG3E,MAAMC,wBAAwB;AAC9B,MAAMC,gCAAgC;AAItC,eAAeC,oBACbC,UAA4D,CAAC,CAAC;IAE9D,MAAM,EACJC,6BAA6B,EAC7BC,+BAA+B,EAC/BC,oBAAoB,EACpBR,IAAIS,MAAM,EACVC,4BAA4BC,iCAAiC,EAC7DC,4BAA4B,EAC5BC,cAAc,EACdC,sBAAsB,EACvB,GAAG,MAAM,MAAM,CAAC;IAEjB,eAAeC,0BAA0BC,KAExC;QACC,MAAMC,eAAe,MAAML,6BAA6BI,MAAME,OAAO;QACrE,IAAI,CAACD,cAAc,OAAOE;QAC1B,OAAQ,MAAMvB,6BAA6BqB,aAAaG,YAAY;IAGtE;IAEA,SAASC,wBACPL,KAAmC;QAEnC,OAAOf,6BAA6B,IAClCD,KAAKsB,WAAW,CAAC,OAAOC;gBACtB,MAAMC,OAAO,MAAM3B,4BACjB;oBACE4B,aAAaT,MAAMS,WAAW;oBAC9BC,UAAU;oBACVC,mBAAmBX,MAAME,OAAO;oBAChCU,UAAUnC,sBAAsB,CAAC,KAAK,EAAEuB,MAAMa,QAAQ,IAAIb,MAAME,OAAO,EAAE,EAAE;wBACzEY,UAAU;oBACZ;gBACF,GACA;oBAACP;gBAAE;gBAEL,MAAMQ,aAAa,MAAMhC,4BACvB;oBACE0B,aAAaT,MAAMS,WAAW;oBAC9BC,UAAU;oBACVC,mBAAmBX,MAAME,OAAO;oBAChCM;oBACAQ,aAAahB,MAAMgB,WAAW;oBAC9BC,iBAAiB;gBACnB,GACA;oBAACV;gBAAE;gBAEL,MAAMT,uBACJ;oBACEM,cAAcW,WAAWG,EAAE;oBAC3BhB,SAASF,MAAME,OAAO;oBACtBiB,SAASnB,MAAMmB,OAAO;oBACtBN,UAAUb,MAAMa,QAAQ;oBACxBO,sBAAsBpB,MAAMoB,oBAAoB;oBAChDC,QAAQrB,MAAMqB,MAAM;oBACpBC,QAAQ;oBACRC,gBAAgBvB,MAAMuB,cAAc;gBACtC,GACA;oBAAChB;gBAAE;gBAEL,OAAOQ;YACT;IAEJ;IAEA,eAAerB,2BAA2BM,KAA6B;QACrE,MAAML,kCAAiD;YACrDS,cAAcJ,MAAMI,YAAY;YAChCoB,eAAe5C;YACf6C,eAAe,CAACC,SACdrC,QAAQsC,OAAO,EAAEC,MAAMH,cAAc;oBACnC,GAAGC,MAAM;oBACTG,WAAWC,oBAAoBJ,OAAOG,SAAS;gBACjD,MAAME,QAAQC,OAAO,CAAC;YACxB1B,aAAa,CAAC2B,KAAOjD,KAAKsB,WAAW,CAAC,CAACC,KAAO0B,GAAG1B;YACjD2B,kBAAkB,CAACR,QAAQS,qBACzBxD,4BAA4B;oBAACuC,IAAIQ,OAAOtB,YAAY;gBAAA,GAAG+B;QAC3D;IACF;IAEA,MAAMC,kBAAuE;QAC3EC,WAAW,IAAMN,QAAQC,OAAO,CAAC;QACjCM,YAAY,IAAMP,QAAQQ,MAAM,CAAC,IAAIC,MAAM;QAC3Cf,eAAe,IAAMM,QAAQC,OAAO,CAAC;IACvC;IACA,MAAML,UAA+DtC,QAAQsC,OAAO,EAAEC,OAClF;QACES,WAAW,CAACX,SACVrC,QAAQsC,OAAO,EAAEC,MAAMS,UAAU;gBAC/B,GAAGX,MAAM;gBACTG,WAAWC,oBAAoBJ,OAAOG,SAAS;YACjD,MAAME,QAAQC,OAAO,CAAC;QACxBM,YAAY,CAACZ,SACXrC,QAAQsC,OAAO,EAAEC,MAAMU,WAAW;gBAChC,GAAGZ,MAAM;gBACTG,WAAWC,oBAAoBJ,OAAOG,SAAS;YACjD,MAAME,QAAQC,OAAO;QACvBP,eAAe,CAACC,SACdrC,QAAQsC,OAAO,EAAEC,MAAMH,cAAc;gBACnC,GAAGC,MAAM;gBACTG,WAAWC,oBAAoBJ,OAAOG,SAAS;YACjD,MAAME,QAAQC,OAAO,CAAC;IAC1B,IACAI;IACJ,MAAMK,aAAajD,qBAAqB;QACtCkD,mBAAmB9D;QACnB+C;QACAgB,qBAAqB,OAAO,EAACvC,YAAY,EAAC;YACxC,MAAMtB,2CAA2C;gBAC/CoC,IAAId;gBACJa,iBAAiB;YACnB;QACF;IACF;IACA,MAAM2B,eAAerD,gCAAgC;QAACoC;IAAO;IAE7D,OAAO;QACLjB,UAAUpB,8BAA8B;YACtCuD,QAAQ;gBACNJ;gBACAG;gBACA7C;gBACAM;gBACAX;gBACA,GAAIL,QAAQyD,gCAAgC,GACxC;oBAACA,kCAAkCzD,QAAQyD,gCAAgC;gBAAA,IAC3E,CAAC,CAAC;YACR;QACF;QACAC,UAAU;YAAC/D,IAAIS;YAAQI;YAAgBmD,qBAAqB9D;QAAqB;IACnF;AACF;AAEA,OAAO,MAAM+D,qBAAgD;IAC3D/B,IAAI;IACJgC,SAASxE,OAAOyE,iCAAiC;IACjDC,MAAMhE;AACR,EAAE;AAEF,SAAS0C,oBAAoBD,SAAiB;IAC5C,IAAI,CAACA,UAAUwB,UAAU,CAAClE,gCAAgC;QACxD,MAAM,IAAIqD,MAAM;IAClB;IACA,OAAOX,UAAUyB,KAAK,CAACnE,8BAA8BoE,MAAM;AAC7D"}
1
+ {"version":3,"sources":["../../src/providers/jira.ts"],"sourcesContent":["import type {\n ConnectJiraInstallationInput,\n JiraPendingSelectionSecretsStore,\n JiraSecretsStore,\n} from '@shipfox/api-integration-jira';\nimport type {IntegrationConnection as CoreIntegrationConnection} from '@shipfox/api-integration-spi';\nimport {config} from '#config.js';\nimport {\n deleteIntegrationConnection,\n getIntegrationConnectionById,\n resolveUniqueConnectionSlug,\n updateIntegrationConnectionLifecycleStatus,\n upsertIntegrationConnection,\n} from '#db/connections.js';\nimport {db} from '#db/db.js';\nimport {retryConnectionSlugCollision, slugifyConnectionSlug} from '#providers/connection-slug.js';\nimport type {IntegrationModuleParts, IntegrationProviderModule} from '#providers/types.js';\n\nconst JIRA_SECRETS_NAMESPACE_PREFIX = 'system/integrations/jira/';\ntype IntegrationDb = ReturnType<typeof db>;\ntype IntegrationTx = Parameters<Parameters<IntegrationDb['transaction']>[0]>[0];\n\nasync function loadJiraModuleParts(\n options: Parameters<IntegrationProviderModule['load']>[0] = {},\n): Promise<IntegrationModuleParts> {\n const {\n createJiraIntegrationProvider,\n createJiraPendingSelectionStore,\n createJiraTokenStore,\n db: jiraDb,\n disconnectJiraInstallation: disconnectJiraInstallationRecords,\n getJiraInstallationByCloudId,\n migrationsPath,\n upsertJiraInstallation,\n } = await import('@shipfox/api-integration-jira');\n\n async function getExistingJiraConnection(input: {\n cloudId: string;\n }): Promise<CoreIntegrationConnection<'jira'> | undefined> {\n const installation = await getJiraInstallationByCloudId(input.cloudId);\n if (!installation) return undefined;\n return (await getIntegrationConnectionById(installation.connectionId)) as\n | CoreIntegrationConnection<'jira'>\n | undefined;\n }\n\n function connectJiraInstallation(\n input: ConnectJiraInstallationInput,\n ): Promise<CoreIntegrationConnection<'jira'>> {\n return retryConnectionSlugCollision(() =>\n db().transaction(async (tx) => {\n const slug = await resolveUniqueConnectionSlug(\n {\n workspaceId: input.workspaceId,\n provider: 'jira',\n externalAccountId: input.cloudId,\n baseSlug: slugifyConnectionSlug(`jira_${input.siteName || input.cloudId}`, {\n fallback: 'jira',\n }),\n },\n {tx},\n );\n const connection = await upsertIntegrationConnection(\n {\n workspaceId: input.workspaceId,\n provider: 'jira',\n externalAccountId: input.cloudId,\n slug,\n displayName: input.displayName,\n lifecycleStatus: 'active',\n },\n {tx},\n );\n await upsertJiraInstallation(\n {\n connectionId: connection.id,\n cloudId: input.cloudId,\n siteUrl: input.siteUrl,\n siteName: input.siteName,\n authorizingAccountId: input.authorizingAccountId,\n scopes: input.scopes,\n status: 'installed',\n tokenExpiresAt: input.tokenExpiresAt,\n },\n {tx},\n );\n return connection as CoreIntegrationConnection<'jira'>;\n }),\n );\n }\n\n async function disconnectJiraInstallation(input: {connectionId: string}): Promise<void> {\n await disconnectJiraInstallationRecords<IntegrationTx>({\n connectionId: input.connectionId,\n getConnection: getIntegrationConnectionById,\n deleteSecrets: (params) =>\n options.secrets?.jira?.deleteSecrets({\n ...params,\n namespace: jiraNamespaceSuffix(params.namespace),\n }) ?? Promise.resolve(0),\n transaction: (fn) => db().transaction((tx) => fn(tx)),\n deleteConnection: (params, transactionOptions) =>\n deleteIntegrationConnection({id: params.connectionId}, transactionOptions),\n });\n }\n\n const fallbackSecrets: JiraSecretsStore & JiraPendingSelectionSecretsStore = {\n getSecret: () => Promise.resolve(null),\n setSecrets: () => Promise.reject(new Error('Jira token storage is not configured')),\n deleteSecrets: () => Promise.resolve(0),\n };\n const secrets: JiraSecretsStore & JiraPendingSelectionSecretsStore = options.secrets?.jira\n ? {\n getSecret: (params) =>\n options.secrets?.jira?.getSecret({\n ...params,\n namespace: jiraNamespaceSuffix(params.namespace),\n }) ?? Promise.resolve(null),\n setSecrets: (params) =>\n options.secrets?.jira?.setSecrets({\n ...params,\n namespace: jiraNamespaceSuffix(params.namespace),\n }) ?? Promise.resolve(),\n deleteSecrets: (params) =>\n options.secrets?.jira?.deleteSecrets({\n ...params,\n namespace: jiraNamespaceSuffix(params.namespace),\n }) ?? Promise.resolve(0),\n }\n : fallbackSecrets;\n const tokenStore = createJiraTokenStore({\n resolveConnection: getIntegrationConnectionById,\n secrets,\n markConnectionError: async ({connectionId}) => {\n await updateIntegrationConnectionLifecycleStatus({\n id: connectionId,\n lifecycleStatus: 'error',\n });\n },\n });\n const pendingStore = createJiraPendingSelectionStore({secrets});\n\n return {\n provider: createJiraIntegrationProvider({\n routes: {\n tokenStore,\n pendingStore,\n getExistingJiraConnection,\n connectJiraInstallation,\n disconnectJiraInstallation,\n ...(options.requireActiveWorkspaceMembership\n ? {requireActiveWorkspaceMembership: options.requireActiveWorkspaceMembership}\n : {}),\n },\n }),\n database: {db: jiraDb, migrationsPath, databaseNamespace: 'integrations_jira'},\n };\n}\n\nexport const jiraProviderModule: IntegrationProviderModule = {\n id: 'jira',\n enabled: config.INTEGRATIONS_ENABLE_JIRA_PROVIDER,\n load: loadJiraModuleParts,\n};\n\nfunction jiraNamespaceSuffix(namespace: string): string {\n if (!namespace.startsWith(JIRA_SECRETS_NAMESPACE_PREFIX)) {\n throw new Error('Jira provider attempted to access an unscoped secret namespace');\n }\n return namespace.slice(JIRA_SECRETS_NAMESPACE_PREFIX.length);\n}\n"],"names":["config","deleteIntegrationConnection","getIntegrationConnectionById","resolveUniqueConnectionSlug","updateIntegrationConnectionLifecycleStatus","upsertIntegrationConnection","db","retryConnectionSlugCollision","slugifyConnectionSlug","JIRA_SECRETS_NAMESPACE_PREFIX","loadJiraModuleParts","options","createJiraIntegrationProvider","createJiraPendingSelectionStore","createJiraTokenStore","jiraDb","disconnectJiraInstallation","disconnectJiraInstallationRecords","getJiraInstallationByCloudId","migrationsPath","upsertJiraInstallation","getExistingJiraConnection","input","installation","cloudId","undefined","connectionId","connectJiraInstallation","transaction","tx","slug","workspaceId","provider","externalAccountId","baseSlug","siteName","fallback","connection","displayName","lifecycleStatus","id","siteUrl","authorizingAccountId","scopes","status","tokenExpiresAt","getConnection","deleteSecrets","params","secrets","jira","namespace","jiraNamespaceSuffix","Promise","resolve","fn","deleteConnection","transactionOptions","fallbackSecrets","getSecret","setSecrets","reject","Error","tokenStore","resolveConnection","markConnectionError","pendingStore","routes","requireActiveWorkspaceMembership","database","databaseNamespace","jiraProviderModule","enabled","INTEGRATIONS_ENABLE_JIRA_PROVIDER","load","startsWith","slice","length"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"linear.d.ts","sourceRoot":"","sources":["../../src/providers/linear.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAyB,yBAAyB,EAAC,MAAM,qBAAqB,CAAC;AAyK3F,eAAO,MAAM,oBAAoB,EAAE,yBAIlC,CAAC"}
1
+ {"version":3,"file":"linear.d.ts","sourceRoot":"","sources":["../../src/providers/linear.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAyB,yBAAyB,EAAC,MAAM,qBAAqB,CAAC;AAwK3F,eAAO,MAAM,oBAAoB,EAAE,yBAIlC,CAAC"}