@shipfox/api-integration-core 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (275) hide show
  1. package/.turbo/turbo-build.log +2 -0
  2. package/.turbo/turbo-type$colon$emit.log +1 -0
  3. package/.turbo/turbo-type.log +1 -0
  4. package/CHANGELOG.md +264 -0
  5. package/LICENSE +21 -0
  6. package/dist/config.d.ts +9 -0
  7. package/dist/config.d.ts.map +1 -0
  8. package/dist/config.js +29 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/core/agent-tool-selection.d.ts +15 -0
  11. package/dist/core/agent-tool-selection.d.ts.map +1 -0
  12. package/dist/core/agent-tool-selection.js +48 -0
  13. package/dist/core/agent-tool-selection.js.map +1 -0
  14. package/dist/core/entities/connection.d.ts +2 -0
  15. package/dist/core/entities/connection.d.ts.map +1 -0
  16. package/dist/core/entities/connection.js +3 -0
  17. package/dist/core/entities/connection.js.map +1 -0
  18. package/dist/core/entities/provider.d.ts +6 -0
  19. package/dist/core/entities/provider.d.ts.map +1 -0
  20. package/dist/core/entities/provider.js +3 -0
  21. package/dist/core/entities/provider.js.map +1 -0
  22. package/dist/core/errors.d.ts +29 -0
  23. package/dist/core/errors.d.ts.map +1 -0
  24. package/dist/core/errors.js +40 -0
  25. package/dist/core/errors.js.map +1 -0
  26. package/dist/core/providers/agent-tools.d.ts +2 -0
  27. package/dist/core/providers/agent-tools.d.ts.map +1 -0
  28. package/dist/core/providers/agent-tools.js +3 -0
  29. package/dist/core/providers/agent-tools.js.map +1 -0
  30. package/dist/core/providers/redact-checkout-spec.d.ts +9 -0
  31. package/dist/core/providers/redact-checkout-spec.d.ts.map +1 -0
  32. package/dist/core/providers/redact-checkout-spec.js +25 -0
  33. package/dist/core/providers/redact-checkout-spec.js.map +1 -0
  34. package/dist/core/providers/registry.d.ts +9 -0
  35. package/dist/core/providers/registry.d.ts.map +1 -0
  36. package/dist/core/providers/registry.js +52 -0
  37. package/dist/core/providers/registry.js.map +1 -0
  38. package/dist/core/providers/source-control.d.ts +2 -0
  39. package/dist/core/providers/source-control.d.ts.map +1 -0
  40. package/dist/core/providers/source-control.js +3 -0
  41. package/dist/core/providers/source-control.js.map +1 -0
  42. package/dist/core/source-control-service.d.ts +46 -0
  43. package/dist/core/source-control-service.d.ts.map +1 -0
  44. package/dist/core/source-control-service.js +84 -0
  45. package/dist/core/source-control-service.js.map +1 -0
  46. package/dist/db/connections.d.ts +67 -0
  47. package/dist/db/connections.d.ts.map +1 -0
  48. package/dist/db/connections.js +130 -0
  49. package/dist/db/connections.js.map +1 -0
  50. package/dist/db/db.d.ts +865 -0
  51. package/dist/db/db.d.ts.map +1 -0
  52. package/dist/db/db.js +22 -0
  53. package/dist/db/db.js.map +1 -0
  54. package/dist/db/migrations.d.ts +2 -0
  55. package/dist/db/migrations.d.ts.map +1 -0
  56. package/dist/db/migrations.js +5 -0
  57. package/dist/db/migrations.js.map +1 -0
  58. package/dist/db/schema/common.d.ts +2 -0
  59. package/dist/db/schema/common.d.ts.map +1 -0
  60. package/dist/db/schema/common.js +4 -0
  61. package/dist/db/schema/common.js.map +1 -0
  62. package/dist/db/schema/connections.d.ts +165 -0
  63. package/dist/db/schema/connections.d.ts.map +1 -0
  64. package/dist/db/schema/connections.js +37 -0
  65. package/dist/db/schema/connections.js.map +1 -0
  66. package/dist/db/schema/outbox.d.ts +195 -0
  67. package/dist/db/schema/outbox.d.ts.map +1 -0
  68. package/dist/db/schema/outbox.js +5 -0
  69. package/dist/db/schema/outbox.js.map +1 -0
  70. package/dist/db/schema/webhook-deliveries.d.ts +76 -0
  71. package/dist/db/schema/webhook-deliveries.d.ts.map +1 -0
  72. package/dist/db/schema/webhook-deliveries.js +22 -0
  73. package/dist/db/schema/webhook-deliveries.js.map +1 -0
  74. package/dist/db/webhook-deliveries.d.ts +55 -0
  75. package/dist/db/webhook-deliveries.d.ts.map +1 -0
  76. package/dist/db/webhook-deliveries.js +132 -0
  77. package/dist/db/webhook-deliveries.js.map +1 -0
  78. package/dist/index.d.ts +54 -0
  79. package/dist/index.d.ts.map +1 -0
  80. package/dist/index.js +105 -0
  81. package/dist/index.js.map +1 -0
  82. package/dist/metrics/index.d.ts +2 -0
  83. package/dist/metrics/index.d.ts.map +1 -0
  84. package/dist/metrics/index.js +3 -0
  85. package/dist/metrics/index.js.map +1 -0
  86. package/dist/metrics/instance.d.ts +8 -0
  87. package/dist/metrics/instance.d.ts.map +1 -0
  88. package/dist/metrics/instance.js +17 -0
  89. package/dist/metrics/instance.js.map +1 -0
  90. package/dist/presentation/dto/integrations.d.ts +36 -0
  91. package/dist/presentation/dto/integrations.d.ts.map +1 -0
  92. package/dist/presentation/dto/integrations.js +26 -0
  93. package/dist/presentation/dto/integrations.js.map +1 -0
  94. package/dist/presentation/routes/agent-tools-gateway/audit.d.ts +24 -0
  95. package/dist/presentation/routes/agent-tools-gateway/audit.d.ts.map +1 -0
  96. package/dist/presentation/routes/agent-tools-gateway/audit.js +52 -0
  97. package/dist/presentation/routes/agent-tools-gateway/audit.js.map +1 -0
  98. package/dist/presentation/routes/agent-tools-gateway/dispatch.d.ts +7 -0
  99. package/dist/presentation/routes/agent-tools-gateway/dispatch.d.ts.map +1 -0
  100. package/dist/presentation/routes/agent-tools-gateway/dispatch.js +108 -0
  101. package/dist/presentation/routes/agent-tools-gateway/dispatch.js.map +1 -0
  102. package/dist/presentation/routes/agent-tools-gateway/index.d.ts +12 -0
  103. package/dist/presentation/routes/agent-tools-gateway/index.d.ts.map +1 -0
  104. package/dist/presentation/routes/agent-tools-gateway/index.js +46 -0
  105. package/dist/presentation/routes/agent-tools-gateway/index.js.map +1 -0
  106. package/dist/presentation/routes/agent-tools-gateway/mcp-server.d.ts +17 -0
  107. package/dist/presentation/routes/agent-tools-gateway/mcp-server.d.ts.map +1 -0
  108. package/dist/presentation/routes/agent-tools-gateway/mcp-server.js +126 -0
  109. package/dist/presentation/routes/agent-tools-gateway/mcp-server.js.map +1 -0
  110. package/dist/presentation/routes/agent-tools-gateway/resolve-authorized-tools.d.ts +37 -0
  111. package/dist/presentation/routes/agent-tools-gateway/resolve-authorized-tools.d.ts.map +1 -0
  112. package/dist/presentation/routes/agent-tools-gateway/resolve-authorized-tools.js +145 -0
  113. package/dist/presentation/routes/agent-tools-gateway/resolve-authorized-tools.js.map +1 -0
  114. package/dist/presentation/routes/errors.d.ts +2 -0
  115. package/dist/presentation/routes/errors.d.ts.map +1 -0
  116. package/dist/presentation/routes/errors.js +53 -0
  117. package/dist/presentation/routes/errors.js.map +1 -0
  118. package/dist/presentation/routes/index.d.ts +14 -0
  119. package/dist/presentation/routes/index.d.ts.map +1 -0
  120. package/dist/presentation/routes/index.js +26 -0
  121. package/dist/presentation/routes/index.js.map +1 -0
  122. package/dist/presentation/routes/list-connections.d.ts +3 -0
  123. package/dist/presentation/routes/list-connections.d.ts.map +1 -0
  124. package/dist/presentation/routes/list-connections.js +58 -0
  125. package/dist/presentation/routes/list-connections.js.map +1 -0
  126. package/dist/presentation/routes/list-providers.d.ts +3 -0
  127. package/dist/presentation/routes/list-providers.d.ts.map +1 -0
  128. package/dist/presentation/routes/list-providers.js +27 -0
  129. package/dist/presentation/routes/list-providers.js.map +1 -0
  130. package/dist/presentation/routes/list-repositories.d.ts +3 -0
  131. package/dist/presentation/routes/list-repositories.d.ts.map +1 -0
  132. package/dist/presentation/routes/list-repositories.js +41 -0
  133. package/dist/presentation/routes/list-repositories.js.map +1 -0
  134. package/dist/presentation/routes/manage-connections.d.ts +4 -0
  135. package/dist/presentation/routes/manage-connections.d.ts.map +1 -0
  136. package/dist/presentation/routes/manage-connections.js +81 -0
  137. package/dist/presentation/routes/manage-connections.js.map +1 -0
  138. package/dist/providers/connection-slug.d.ts +2 -0
  139. package/dist/providers/connection-slug.d.ts.map +1 -0
  140. package/dist/providers/connection-slug.js +19 -0
  141. package/dist/providers/connection-slug.js.map +1 -0
  142. package/dist/providers/cron.d.ts +3 -0
  143. package/dist/providers/cron.d.ts.map +1 -0
  144. package/dist/providers/cron.js +13 -0
  145. package/dist/providers/cron.js.map +1 -0
  146. package/dist/providers/gitea.d.ts +3 -0
  147. package/dist/providers/gitea.d.ts.map +1 -0
  148. package/dist/providers/gitea.js +75 -0
  149. package/dist/providers/gitea.js.map +1 -0
  150. package/dist/providers/github.d.ts +3 -0
  151. package/dist/providers/github.d.ts.map +1 -0
  152. package/dist/providers/github.js +109 -0
  153. package/dist/providers/github.js.map +1 -0
  154. package/dist/providers/linear.d.ts +3 -0
  155. package/dist/providers/linear.d.ts.map +1 -0
  156. package/dist/providers/linear.js +134 -0
  157. package/dist/providers/linear.js.map +1 -0
  158. package/dist/providers/modules.d.ts +3 -0
  159. package/dist/providers/modules.d.ts.map +1 -0
  160. package/dist/providers/modules.js +26 -0
  161. package/dist/providers/modules.js.map +1 -0
  162. package/dist/providers/sentry.d.ts +3 -0
  163. package/dist/providers/sentry.d.ts.map +1 -0
  164. package/dist/providers/sentry.js +83 -0
  165. package/dist/providers/sentry.js.map +1 -0
  166. package/dist/providers/types.d.ts +58 -0
  167. package/dist/providers/types.d.ts.map +1 -0
  168. package/dist/providers/types.js +3 -0
  169. package/dist/providers/types.js.map +1 -0
  170. package/dist/providers/webhook.d.ts +3 -0
  171. package/dist/providers/webhook.d.ts.map +1 -0
  172. package/dist/providers/webhook.js +24 -0
  173. package/dist/providers/webhook.js.map +1 -0
  174. package/dist/temporal/activities/index.d.ts +5 -0
  175. package/dist/temporal/activities/index.d.ts.map +1 -0
  176. package/dist/temporal/activities/index.js +8 -0
  177. package/dist/temporal/activities/index.js.map +1 -0
  178. package/dist/temporal/activities/prune-webhook-deliveries.d.ts +4 -0
  179. package/dist/temporal/activities/prune-webhook-deliveries.d.ts.map +1 -0
  180. package/dist/temporal/activities/prune-webhook-deliveries.js +11 -0
  181. package/dist/temporal/activities/prune-webhook-deliveries.js.map +1 -0
  182. package/dist/temporal/constants.d.ts +3 -0
  183. package/dist/temporal/constants.d.ts.map +1 -0
  184. package/dist/temporal/constants.js +4 -0
  185. package/dist/temporal/constants.js.map +1 -0
  186. package/dist/temporal/workflows/index.d.ts +2 -0
  187. package/dist/temporal/workflows/index.d.ts.map +1 -0
  188. package/dist/temporal/workflows/index.js +3 -0
  189. package/dist/temporal/workflows/index.js.map +1 -0
  190. package/dist/temporal/workflows/prune-webhook-deliveries-cron.d.ts +2 -0
  191. package/dist/temporal/workflows/prune-webhook-deliveries-cron.d.ts.map +1 -0
  192. package/dist/temporal/workflows/prune-webhook-deliveries-cron.js +14 -0
  193. package/dist/temporal/workflows/prune-webhook-deliveries-cron.js.map +1 -0
  194. package/dist/tsconfig.test.tsbuildinfo +1 -0
  195. package/drizzle/0000_initial.sql +41 -0
  196. package/drizzle/meta/0001_snapshot.json +341 -0
  197. package/drizzle/meta/_journal.json +13 -0
  198. package/drizzle.config.ts +7 -0
  199. package/package.json +85 -0
  200. package/src/config.test.ts +32 -0
  201. package/src/config.ts +28 -0
  202. package/src/core/agent-tool-selection.test.ts +137 -0
  203. package/src/core/agent-tool-selection.ts +80 -0
  204. package/src/core/entities/connection.ts +4 -0
  205. package/src/core/entities/provider.ts +21 -0
  206. package/src/core/errors.ts +55 -0
  207. package/src/core/providers/agent-tools.ts +10 -0
  208. package/src/core/providers/redact-checkout-spec.test.ts +78 -0
  209. package/src/core/providers/redact-checkout-spec.ts +20 -0
  210. package/src/core/providers/registry.test.ts +138 -0
  211. package/src/core/providers/registry.ts +90 -0
  212. package/src/core/providers/source-control.ts +17 -0
  213. package/src/core/source-control-service.test.ts +230 -0
  214. package/src/core/source-control-service.ts +161 -0
  215. package/src/db/connections.test.ts +296 -0
  216. package/src/db/connections.ts +262 -0
  217. package/src/db/db.ts +22 -0
  218. package/src/db/migrations.ts +4 -0
  219. package/src/db/schema/common.ts +3 -0
  220. package/src/db/schema/connections.ts +49 -0
  221. package/src/db/schema/outbox.ts +4 -0
  222. package/src/db/schema/webhook-deliveries.ts +19 -0
  223. package/src/db/webhook-deliveries.test.ts +267 -0
  224. package/src/db/webhook-deliveries.ts +207 -0
  225. package/src/index.ts +212 -0
  226. package/src/metrics/index.ts +1 -0
  227. package/src/metrics/instance.ts +35 -0
  228. package/src/presentation/dto/integrations.ts +39 -0
  229. package/src/presentation/routes/agent-tools-gateway/agent-tools-gateway.route.test.ts +371 -0
  230. package/src/presentation/routes/agent-tools-gateway/audit.test.ts +86 -0
  231. package/src/presentation/routes/agent-tools-gateway/audit.ts +90 -0
  232. package/src/presentation/routes/agent-tools-gateway/dispatch.ts +139 -0
  233. package/src/presentation/routes/agent-tools-gateway/index.ts +62 -0
  234. package/src/presentation/routes/agent-tools-gateway/mcp-server.test.ts +308 -0
  235. package/src/presentation/routes/agent-tools-gateway/mcp-server.ts +155 -0
  236. package/src/presentation/routes/agent-tools-gateway/resolve-authorized-tools.test.ts +181 -0
  237. package/src/presentation/routes/agent-tools-gateway/resolve-authorized-tools.ts +245 -0
  238. package/src/presentation/routes/errors.ts +63 -0
  239. package/src/presentation/routes/index.ts +53 -0
  240. package/src/presentation/routes/list-connections.test.ts +227 -0
  241. package/src/presentation/routes/list-connections.ts +56 -0
  242. package/src/presentation/routes/list-providers.test.ts +113 -0
  243. package/src/presentation/routes/list-providers.ts +28 -0
  244. package/src/presentation/routes/list-repositories.test.ts +150 -0
  245. package/src/presentation/routes/list-repositories.ts +47 -0
  246. package/src/presentation/routes/manage-connections.test.ts +125 -0
  247. package/src/presentation/routes/manage-connections.ts +77 -0
  248. package/src/providers/connection-slug.ts +19 -0
  249. package/src/providers/cron.ts +13 -0
  250. package/src/providers/gitea.ts +103 -0
  251. package/src/providers/github.ts +150 -0
  252. package/src/providers/linear.ts +179 -0
  253. package/src/providers/modules.test.ts +40 -0
  254. package/src/providers/modules.ts +32 -0
  255. package/src/providers/sentry.ts +113 -0
  256. package/src/providers/types.ts +52 -0
  257. package/src/providers/webhook.ts +30 -0
  258. package/src/temporal/activities/index.ts +7 -0
  259. package/src/temporal/activities/prune-webhook-deliveries.test.ts +39 -0
  260. package/src/temporal/activities/prune-webhook-deliveries.ts +9 -0
  261. package/src/temporal/constants.ts +3 -0
  262. package/src/temporal/workflows/index.ts +1 -0
  263. package/src/temporal/workflows/prune-webhook-deliveries-cron.ts +15 -0
  264. package/test/agent-tools-gateway-helpers.ts +210 -0
  265. package/test/env.ts +23 -0
  266. package/test/factories/connection.ts +21 -0
  267. package/test/globalSetup.ts +22 -0
  268. package/test/index.ts +1 -0
  269. package/test/route-utils.ts +104 -0
  270. package/test/setup.ts +19 -0
  271. package/tsconfig.build.json +9 -0
  272. package/tsconfig.build.tsbuildinfo +1 -0
  273. package/tsconfig.json +3 -0
  274. package/tsconfig.test.json +8 -0
  275. package/vitest.config.ts +13 -0
@@ -0,0 +1,109 @@
1
+ import { slugifyConnectionSlug } from '@shipfox/api-integration-core-dto';
2
+ import { config } from '#config.js';
3
+ import { getIntegrationConnectionById, resolveUniqueConnectionSlug, upsertIntegrationConnection } from '#db/connections.js';
4
+ import { db } from '#db/db.js';
5
+ 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';
12
+ async function loadGithubModuleParts(options = {}) {
13
+ const { createGithubInstallationTokenProvider, createGithubE2eRoutes, encodeInstallationTokenEnvelope, createGithubIntegrationProvider, getGithubInstallationByInstallationId, githubInstallationTokenNamespace, db: githubDb, migrationsPath: githubMigrationsPath, upsertGithubInstallation } = await import('@shipfox/api-integration-github');
14
+ const tokenProvider = createGithubInstallationTokenProvider({
15
+ getIntegrationConnectionById,
16
+ secretStore: options.secrets?.github ? {
17
+ read: async (workspaceId, installationId)=>await options.secrets?.github?.getSecret({
18
+ workspaceId,
19
+ namespace: githubInstallationTokenNamespace(installationId),
20
+ key: 'envelope'
21
+ }) ?? null,
22
+ write: async (workspaceId, installationId, envelope)=>{
23
+ await options.secrets?.github?.setSecrets({
24
+ workspaceId,
25
+ namespace: githubInstallationTokenNamespace(installationId),
26
+ values: {
27
+ envelope: encodeInstallationTokenEnvelope(envelope)
28
+ }
29
+ });
30
+ }
31
+ } : undefined
32
+ });
33
+ async function getExistingGithubConnection(input) {
34
+ const installation = await getGithubInstallationByInstallationId(input.installationId);
35
+ if (!installation) return undefined;
36
+ const connection = await getIntegrationConnectionById(installation.connectionId);
37
+ if (!connection) return undefined;
38
+ return connection;
39
+ }
40
+ async function connectGithubInstallation(input) {
41
+ return await retryConnectionSlugCollision(()=>db().transaction(async (tx)=>{
42
+ const baseSlug = slugifyConnectionSlug(`github_${input.installation.accountLogin}`, {
43
+ fallback: 'github'
44
+ });
45
+ const slug = await resolveUniqueConnectionSlug({
46
+ workspaceId: input.workspaceId,
47
+ provider: 'github',
48
+ externalAccountId: input.installationId,
49
+ baseSlug
50
+ }, {
51
+ tx
52
+ });
53
+ const connection = await upsertIntegrationConnection({
54
+ workspaceId: input.workspaceId,
55
+ provider: 'github',
56
+ externalAccountId: input.installationId,
57
+ slug,
58
+ displayName: input.displayName,
59
+ lifecycleStatus: 'active'
60
+ }, {
61
+ tx
62
+ });
63
+ await upsertGithubInstallation({
64
+ connectionId: connection.id,
65
+ ...input.installation
66
+ }, {
67
+ tx
68
+ });
69
+ return connection;
70
+ }));
71
+ }
72
+ return {
73
+ provider: createGithubIntegrationProvider({
74
+ getExistingGithubConnection,
75
+ connectGithubInstallation,
76
+ publishIntegrationEventReceived,
77
+ publishSourcePush,
78
+ recordDeliveryOnly,
79
+ getIntegrationConnectionById,
80
+ coreDb: db,
81
+ deleteSecrets: options.secrets?.deleteSecrets,
82
+ agentTools: {
83
+ tokenProvider
84
+ }
85
+ }),
86
+ e2eRoutes: [
87
+ createGithubE2eRoutes({
88
+ getExistingGithubConnection,
89
+ connectGithubInstallation,
90
+ connectionCapabilities: [
91
+ 'source_control',
92
+ 'agent_tools'
93
+ ]
94
+ })
95
+ ],
96
+ database: {
97
+ db: githubDb,
98
+ migrationsPath: githubMigrationsPath,
99
+ migrationsTableName: GITHUB_MIGRATIONS_TABLE
100
+ }
101
+ };
102
+ }
103
+ export const githubProviderModule = {
104
+ id: 'github',
105
+ enabled: config.INTEGRATIONS_ENABLE_GITHUB_PROVIDER,
106
+ load: loadGithubModuleParts
107
+ };
108
+
109
+ //# sourceMappingURL=github.js.map
@@ -0,0 +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 return {\n provider: 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 }),\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","coreDb","deleteSecrets","agentTools","e2eRoutes","connectionCapabilities","database","migrationsTableName","githubProviderModule","enabled","INTEGRATIONS_ENABLE_GITHUB_PROVIDER","load"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { IntegrationProviderModule } from '#providers/types.js';
2
+ export declare const linearProviderModule: IntegrationProviderModule;
3
+ //# sourceMappingURL=linear.d.ts.map
@@ -0,0 +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;AAqJ3F,eAAO,MAAM,oBAAoB,EAAE,yBAIlC,CAAC"}
@@ -0,0 +1,134 @@
1
+ import { slugifyConnectionSlug } from '@shipfox/api-integration-core-dto';
2
+ import { config } from '#config.js';
3
+ import { deleteIntegrationConnection, getIntegrationConnectionById, resolveUniqueConnectionSlug, upsertIntegrationConnection } from '#db/connections.js';
4
+ import { db } from '#db/db.js';
5
+ import { publishIntegrationEventReceived, recordDeliveryOnly } from '#db/webhook-deliveries.js';
6
+ import { retryConnectionSlugCollision } from '#providers/connection-slug.js';
7
+ const LINEAR_MIGRATIONS_TABLE = '__drizzle_migrations_integrations_linear';
8
+ const LINEAR_SECRETS_NAMESPACE_PREFIX = 'system/integrations/linear/';
9
+ async function loadLinearModuleParts(options = {}) {
10
+ const { createLinearTokenStore, createLinearE2eRoutes, createLinearIntegrationProvider, config: linearConfig, disconnectLinearInstallation: disconnectLinearInstallationRecords, getLinearInstallationByOrganizationId, db: linearDb, migrationsPath: linearMigrationsPath, upsertLinearInstallation } = await import('@shipfox/api-integration-linear');
11
+ async function getExistingLinearConnection(input) {
12
+ const installation = await getLinearInstallationByOrganizationId(input.organizationId);
13
+ if (!installation) return undefined;
14
+ const connection = await getIntegrationConnectionById(installation.connectionId);
15
+ if (!connection) return undefined;
16
+ return connection;
17
+ }
18
+ async function connectLinearInstallation(input) {
19
+ return await retryConnectionSlugCollision(()=>db().transaction(async (tx)=>{
20
+ const baseSlug = slugifyConnectionSlug(`linear_${input.organizationUrlKey}`, {
21
+ fallback: 'linear'
22
+ });
23
+ const slug = await resolveUniqueConnectionSlug({
24
+ workspaceId: input.workspaceId,
25
+ provider: 'linear',
26
+ externalAccountId: input.organizationId,
27
+ baseSlug
28
+ }, {
29
+ tx
30
+ });
31
+ const connection = await upsertIntegrationConnection({
32
+ workspaceId: input.workspaceId,
33
+ provider: 'linear',
34
+ externalAccountId: input.organizationId,
35
+ slug,
36
+ displayName: input.displayName,
37
+ lifecycleStatus: 'active'
38
+ }, {
39
+ tx
40
+ });
41
+ await upsertLinearInstallation({
42
+ connectionId: connection.id,
43
+ organizationId: input.organizationId,
44
+ organizationUrlKey: input.organizationUrlKey,
45
+ appUserId: input.appUserId,
46
+ scopes: input.scopes,
47
+ tokenExpiresAt: input.tokenExpiresAt,
48
+ status: 'installed'
49
+ }, {
50
+ tx
51
+ });
52
+ return connection;
53
+ }));
54
+ }
55
+ async function disconnectLinearInstallation(input) {
56
+ await disconnectLinearInstallationRecords({
57
+ connectionId: input.connectionId,
58
+ getConnection: getIntegrationConnectionById,
59
+ deleteSecrets: (params)=>options.secrets?.linear?.deleteSecrets({
60
+ ...params,
61
+ namespace: linearNamespaceSuffix(params.namespace)
62
+ }) ?? Promise.resolve(0),
63
+ transaction: (fn)=>db().transaction((tx)=>fn(tx)),
64
+ deleteConnection: (params, options)=>deleteIntegrationConnection({
65
+ id: params.connectionId
66
+ }, options)
67
+ });
68
+ }
69
+ const fallbackSecrets = {
70
+ getSecret: ()=>Promise.resolve(null),
71
+ setSecrets: ()=>Promise.reject(new Error('Linear token storage is not configured'))
72
+ };
73
+ const secrets = options.secrets?.linear ? {
74
+ getSecret: (params)=>options.secrets?.linear?.getSecret({
75
+ ...params,
76
+ namespace: linearNamespaceSuffix(params.namespace)
77
+ }) ?? Promise.resolve(null),
78
+ setSecrets: (params)=>options.secrets?.linear?.setSecrets({
79
+ ...params,
80
+ namespace: linearNamespaceSuffix(params.namespace)
81
+ }) ?? Promise.resolve()
82
+ } : fallbackSecrets;
83
+ const tokenStore = createLinearTokenStore({
84
+ resolveConnection: async (connectionId)=>getIntegrationConnectionById(connectionId),
85
+ secrets
86
+ });
87
+ return {
88
+ provider: createLinearIntegrationProvider({
89
+ agentTools: {
90
+ tokenStore,
91
+ endpoint: linearConfig.LINEAR_MCP_ENDPOINT
92
+ },
93
+ routes: {
94
+ tokenStore,
95
+ getExistingLinearConnection,
96
+ connectLinearInstallation,
97
+ disconnectLinearInstallation,
98
+ publishIntegrationEventReceived,
99
+ recordDeliveryOnly,
100
+ getIntegrationConnectionById,
101
+ coreDb: db
102
+ }
103
+ }),
104
+ e2eRoutes: [
105
+ createLinearE2eRoutes({
106
+ tokenStore,
107
+ getExistingLinearConnection,
108
+ connectLinearInstallation,
109
+ disconnectLinearInstallation,
110
+ connectionCapabilities: [
111
+ 'agent_tools'
112
+ ]
113
+ })
114
+ ],
115
+ database: {
116
+ db: linearDb,
117
+ migrationsPath: linearMigrationsPath,
118
+ migrationsTableName: LINEAR_MIGRATIONS_TABLE
119
+ }
120
+ };
121
+ }
122
+ export const linearProviderModule = {
123
+ id: 'linear',
124
+ enabled: config.INTEGRATIONS_ENABLE_LINEAR_PROVIDER,
125
+ load: loadLinearModuleParts
126
+ };
127
+ function linearNamespaceSuffix(namespace) {
128
+ if (!namespace.startsWith(LINEAR_SECRETS_NAMESPACE_PREFIX)) {
129
+ throw new Error('Linear provider attempted to access an unscoped secret namespace');
130
+ }
131
+ return namespace.slice(LINEAR_SECRETS_NAMESPACE_PREFIX.length);
132
+ }
133
+
134
+ //# sourceMappingURL=linear.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/providers/linear.ts"],"sourcesContent":["import {\n type IntegrationConnection as CoreIntegrationConnection,\n slugifyConnectionSlug,\n} from '@shipfox/api-integration-core-dto';\nimport type {\n ConnectLinearInstallationInput,\n LinearSecretsStore,\n} from '@shipfox/api-integration-linear';\nimport {config} from '#config.js';\nimport {\n deleteIntegrationConnection,\n getIntegrationConnectionById,\n resolveUniqueConnectionSlug,\n upsertIntegrationConnection,\n} from '#db/connections.js';\nimport {db} from '#db/db.js';\nimport {publishIntegrationEventReceived, recordDeliveryOnly} from '#db/webhook-deliveries.js';\nimport {retryConnectionSlugCollision} from '#providers/connection-slug.js';\nimport type {IntegrationModuleParts, IntegrationProviderModule} from '#providers/types.js';\n\nconst LINEAR_MIGRATIONS_TABLE = '__drizzle_migrations_integrations_linear';\nconst LINEAR_SECRETS_NAMESPACE_PREFIX = 'system/integrations/linear/';\n\ntype IntegrationDb = ReturnType<typeof db>;\ntype IntegrationTx = Parameters<Parameters<IntegrationDb['transaction']>[0]>[0];\n\nasync function loadLinearModuleParts(\n options: Parameters<IntegrationProviderModule['load']>[0] = {},\n): Promise<IntegrationModuleParts> {\n const {\n createLinearTokenStore,\n createLinearE2eRoutes,\n createLinearIntegrationProvider,\n config: linearConfig,\n disconnectLinearInstallation: disconnectLinearInstallationRecords,\n getLinearInstallationByOrganizationId,\n db: linearDb,\n migrationsPath: linearMigrationsPath,\n upsertLinearInstallation,\n } = await import('@shipfox/api-integration-linear');\n\n async function getExistingLinearConnection(input: {\n organizationId: string;\n }): Promise<CoreIntegrationConnection<'linear'> | undefined> {\n const installation = await getLinearInstallationByOrganizationId(input.organizationId);\n if (!installation) return undefined;\n const connection = await getIntegrationConnectionById(installation.connectionId);\n if (!connection) return undefined;\n return connection as CoreIntegrationConnection<'linear'>;\n }\n\n async function connectLinearInstallation(\n input: ConnectLinearInstallationInput,\n ): Promise<CoreIntegrationConnection<'linear'>> {\n return await retryConnectionSlugCollision(() =>\n db().transaction(async (tx) => {\n const baseSlug = slugifyConnectionSlug(`linear_${input.organizationUrlKey}`, {\n fallback: 'linear',\n });\n const slug = await resolveUniqueConnectionSlug(\n {\n workspaceId: input.workspaceId,\n provider: 'linear',\n externalAccountId: input.organizationId,\n baseSlug,\n },\n {tx},\n );\n const connection = await upsertIntegrationConnection(\n {\n workspaceId: input.workspaceId,\n provider: 'linear',\n externalAccountId: input.organizationId,\n slug,\n displayName: input.displayName,\n lifecycleStatus: 'active',\n },\n {tx},\n );\n\n await upsertLinearInstallation(\n {\n connectionId: connection.id,\n organizationId: input.organizationId,\n organizationUrlKey: input.organizationUrlKey,\n appUserId: input.appUserId,\n scopes: input.scopes,\n tokenExpiresAt: input.tokenExpiresAt,\n status: 'installed',\n },\n {tx},\n );\n\n return connection as CoreIntegrationConnection<'linear'>;\n }),\n );\n }\n\n async function disconnectLinearInstallation(input: {connectionId: string}): Promise<void> {\n await disconnectLinearInstallationRecords<IntegrationTx>({\n connectionId: input.connectionId,\n getConnection: getIntegrationConnectionById,\n deleteSecrets: (params) =>\n options.secrets?.linear?.deleteSecrets({\n ...params,\n namespace: linearNamespaceSuffix(params.namespace),\n }) ?? Promise.resolve(0),\n transaction: (fn) => db().transaction((tx) => fn(tx)),\n deleteConnection: (params, options) =>\n deleteIntegrationConnection({id: params.connectionId}, options),\n });\n }\n\n const fallbackSecrets: LinearSecretsStore = {\n getSecret: () => Promise.resolve(null),\n setSecrets: () => Promise.reject(new Error('Linear token storage is not configured')),\n };\n const secrets: LinearSecretsStore = options.secrets?.linear\n ? {\n getSecret: (params: Parameters<LinearSecretsStore['getSecret']>[0]) =>\n options.secrets?.linear?.getSecret({\n ...params,\n namespace: linearNamespaceSuffix(params.namespace),\n }) ?? Promise.resolve(null),\n setSecrets: (params: Parameters<LinearSecretsStore['setSecrets']>[0]) =>\n options.secrets?.linear?.setSecrets({\n ...params,\n namespace: linearNamespaceSuffix(params.namespace),\n }) ?? Promise.resolve(),\n }\n : fallbackSecrets;\n const tokenStore = createLinearTokenStore({\n resolveConnection: async (connectionId) => getIntegrationConnectionById(connectionId),\n secrets,\n });\n\n return {\n provider: createLinearIntegrationProvider({\n agentTools: {tokenStore, endpoint: linearConfig.LINEAR_MCP_ENDPOINT},\n routes: {\n tokenStore,\n getExistingLinearConnection,\n connectLinearInstallation,\n disconnectLinearInstallation,\n publishIntegrationEventReceived,\n recordDeliveryOnly,\n getIntegrationConnectionById,\n coreDb: db,\n },\n }),\n e2eRoutes: [\n createLinearE2eRoutes({\n tokenStore,\n getExistingLinearConnection,\n connectLinearInstallation,\n disconnectLinearInstallation,\n connectionCapabilities: ['agent_tools'],\n }),\n ],\n database: {\n db: linearDb,\n migrationsPath: linearMigrationsPath,\n migrationsTableName: LINEAR_MIGRATIONS_TABLE,\n },\n };\n}\n\nexport const linearProviderModule: IntegrationProviderModule = {\n id: 'linear',\n enabled: config.INTEGRATIONS_ENABLE_LINEAR_PROVIDER,\n load: loadLinearModuleParts,\n};\n\nfunction linearNamespaceSuffix(namespace: string): string {\n if (!namespace.startsWith(LINEAR_SECRETS_NAMESPACE_PREFIX)) {\n throw new Error('Linear provider attempted to access an unscoped secret namespace');\n }\n return namespace.slice(LINEAR_SECRETS_NAMESPACE_PREFIX.length);\n}\n"],"names":["slugifyConnectionSlug","config","deleteIntegrationConnection","getIntegrationConnectionById","resolveUniqueConnectionSlug","upsertIntegrationConnection","db","publishIntegrationEventReceived","recordDeliveryOnly","retryConnectionSlugCollision","LINEAR_MIGRATIONS_TABLE","LINEAR_SECRETS_NAMESPACE_PREFIX","loadLinearModuleParts","options","createLinearTokenStore","createLinearE2eRoutes","createLinearIntegrationProvider","linearConfig","disconnectLinearInstallation","disconnectLinearInstallationRecords","getLinearInstallationByOrganizationId","linearDb","migrationsPath","linearMigrationsPath","upsertLinearInstallation","getExistingLinearConnection","input","installation","organizationId","undefined","connection","connectionId","connectLinearInstallation","transaction","tx","baseSlug","organizationUrlKey","fallback","slug","workspaceId","provider","externalAccountId","displayName","lifecycleStatus","id","appUserId","scopes","tokenExpiresAt","status","getConnection","deleteSecrets","params","secrets","linear","namespace","linearNamespaceSuffix","Promise","resolve","fn","deleteConnection","fallbackSecrets","getSecret","setSecrets","reject","Error","tokenStore","resolveConnection","agentTools","endpoint","LINEAR_MCP_ENDPOINT","routes","coreDb","e2eRoutes","connectionCapabilities","database","migrationsTableName","linearProviderModule","enabled","INTEGRATIONS_ENABLE_LINEAR_PROVIDER","load","startsWith","slice","length"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { IntegrationModuleParts, IntegrationProviderModuleLoadOptions } from '#providers/types.js';
2
+ export declare function loadEnabledProviderModules(options?: IntegrationProviderModuleLoadOptions): Promise<IntegrationModuleParts[]>;
3
+ //# sourceMappingURL=modules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modules.d.ts","sourceRoot":"","sources":["../../src/providers/modules.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,sBAAsB,EACtB,oCAAoC,EACrC,MAAM,qBAAqB,CAAC;AAc7B,wBAAsB,0BAA0B,CAC9C,OAAO,GAAE,oCAAyC,GACjD,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAOnC"}
@@ -0,0 +1,26 @@
1
+ import { cronProviderModule } from '#providers/cron.js';
2
+ import { giteaProviderModule } from '#providers/gitea.js';
3
+ import { githubProviderModule } from '#providers/github.js';
4
+ import { linearProviderModule } from '#providers/linear.js';
5
+ import { sentryProviderModule } from '#providers/sentry.js';
6
+ import { webhookProviderModule } from '#providers/webhook.js';
7
+ // Order is significant: databases are migrated in this order, so list a provider
8
+ // before any that depend on its tables.
9
+ const providerModules = [
10
+ githubProviderModule,
11
+ linearProviderModule,
12
+ sentryProviderModule,
13
+ giteaProviderModule,
14
+ cronProviderModule,
15
+ webhookProviderModule
16
+ ];
17
+ export async function loadEnabledProviderModules(options = {}) {
18
+ const parts = [];
19
+ for (const module of providerModules){
20
+ if (!module.enabled) continue;
21
+ parts.push(await module.load(options));
22
+ }
23
+ return parts;
24
+ }
25
+
26
+ //# sourceMappingURL=modules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/providers/modules.ts"],"sourcesContent":["import {cronProviderModule} from '#providers/cron.js';\nimport {giteaProviderModule} from '#providers/gitea.js';\nimport {githubProviderModule} from '#providers/github.js';\nimport {linearProviderModule} from '#providers/linear.js';\nimport {sentryProviderModule} from '#providers/sentry.js';\nimport type {\n IntegrationModuleParts,\n IntegrationProviderModuleLoadOptions,\n} from '#providers/types.js';\nimport {webhookProviderModule} from '#providers/webhook.js';\n\n// Order is significant: databases are migrated in this order, so list a provider\n// before any that depend on its tables.\nconst providerModules = [\n githubProviderModule,\n linearProviderModule,\n sentryProviderModule,\n giteaProviderModule,\n cronProviderModule,\n webhookProviderModule,\n];\n\nexport async function loadEnabledProviderModules(\n options: IntegrationProviderModuleLoadOptions = {},\n): Promise<IntegrationModuleParts[]> {\n const parts: IntegrationModuleParts[] = [];\n for (const module of providerModules) {\n if (!module.enabled) continue;\n parts.push(await module.load(options));\n }\n return parts;\n}\n"],"names":["cronProviderModule","giteaProviderModule","githubProviderModule","linearProviderModule","sentryProviderModule","webhookProviderModule","providerModules","loadEnabledProviderModules","options","parts","module","enabled","push","load"],"mappings":"AAAA,SAAQA,kBAAkB,QAAO,qBAAqB;AACtD,SAAQC,mBAAmB,QAAO,sBAAsB;AACxD,SAAQC,oBAAoB,QAAO,uBAAuB;AAC1D,SAAQC,oBAAoB,QAAO,uBAAuB;AAC1D,SAAQC,oBAAoB,QAAO,uBAAuB;AAK1D,SAAQC,qBAAqB,QAAO,wBAAwB;AAE5D,iFAAiF;AACjF,wCAAwC;AACxC,MAAMC,kBAAkB;IACtBJ;IACAC;IACAC;IACAH;IACAD;IACAK;CACD;AAED,OAAO,eAAeE,2BACpBC,UAAgD,CAAC,CAAC;IAElD,MAAMC,QAAkC,EAAE;IAC1C,KAAK,MAAMC,UAAUJ,gBAAiB;QACpC,IAAI,CAACI,OAAOC,OAAO,EAAE;QACrBF,MAAMG,IAAI,CAAC,MAAMF,OAAOG,IAAI,CAACL;IAC/B;IACA,OAAOC;AACT"}
@@ -0,0 +1,3 @@
1
+ import type { IntegrationProviderModule } from '#providers/types.js';
2
+ export declare const sentryProviderModule: IntegrationProviderModule;
3
+ //# sourceMappingURL=sentry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sentry.d.ts","sourceRoot":"","sources":["../../src/providers/sentry.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAyB,yBAAyB,EAAC,MAAM,qBAAqB,CAAC;AA6F3F,eAAO,MAAM,oBAAoB,EAAE,yBAIlC,CAAC"}
@@ -0,0 +1,83 @@
1
+ import { slugifyConnectionSlug } from '@shipfox/api-integration-core-dto';
2
+ import { config } from '#config.js';
3
+ import { getIntegrationConnectionById, resolveUniqueConnectionSlug, updateIntegrationConnectionLifecycleStatus, upsertIntegrationConnection } from '#db/connections.js';
4
+ import { db } from '#db/db.js';
5
+ import { publishIntegrationEventReceived, recordDeliveryOnly } from '#db/webhook-deliveries.js';
6
+ import { retryConnectionSlugCollision } from '#providers/connection-slug.js';
7
+ // Stable migration-tracking table name for the Sentry 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 SENTRY_MIGRATIONS_TABLE = '__drizzle_migrations_integrations_sentry';
12
+ async function loadSentryModuleParts() {
13
+ const { createSentryIntegrationProvider, createSentryMaintenanceWorker, getSentryInstallationByInstallationUuid, persistVerifiedUnclaimedInstallation, upsertSentryInstallation, db: sentryDb, migrationsPath: sentryMigrationsPath } = await import('@shipfox/api-integration-sentry');
14
+ async function getConnectionById(id) {
15
+ const connection = await getIntegrationConnectionById(id);
16
+ if (!connection) return undefined;
17
+ return connection;
18
+ }
19
+ async function connectSentryInstallation(input) {
20
+ return await retryConnectionSlugCollision(()=>db().transaction(async (tx)=>{
21
+ const baseSlug = slugifyConnectionSlug(`sentry_${input.orgSlug}`, {
22
+ fallback: 'sentry'
23
+ });
24
+ const slug = await resolveUniqueConnectionSlug({
25
+ workspaceId: input.workspaceId,
26
+ provider: 'sentry',
27
+ externalAccountId: input.installationUuid,
28
+ baseSlug
29
+ }, {
30
+ tx
31
+ });
32
+ const connection = await upsertIntegrationConnection({
33
+ workspaceId: input.workspaceId,
34
+ provider: 'sentry',
35
+ externalAccountId: input.installationUuid,
36
+ slug,
37
+ displayName: input.displayName,
38
+ lifecycleStatus: 'active'
39
+ }, {
40
+ tx
41
+ });
42
+ await upsertSentryInstallation({
43
+ connectionId: connection.id,
44
+ installationUuid: input.installationUuid,
45
+ orgSlug: input.orgSlug,
46
+ status: 'installed',
47
+ codeHash: input.codeHash,
48
+ installerUserId: input.installerUserId
49
+ }, {
50
+ tx
51
+ });
52
+ return connection;
53
+ }));
54
+ }
55
+ return {
56
+ provider: createSentryIntegrationProvider({
57
+ getSentryInstallation: ({ installationUuid })=>getSentryInstallationByInstallationUuid(installationUuid),
58
+ getConnectionById,
59
+ connectSentryInstallation,
60
+ persistVerifiedUnclaimedInstallation,
61
+ coreDb: db,
62
+ publishIntegrationEventReceived,
63
+ recordDeliveryOnly,
64
+ getIntegrationConnectionById,
65
+ updateConnectionLifecycleStatus: updateIntegrationConnectionLifecycleStatus
66
+ }),
67
+ database: {
68
+ db: sentryDb,
69
+ migrationsPath: sentryMigrationsPath,
70
+ migrationsTableName: SENTRY_MIGRATIONS_TABLE
71
+ },
72
+ workers: [
73
+ createSentryMaintenanceWorker()
74
+ ]
75
+ };
76
+ }
77
+ export const sentryProviderModule = {
78
+ id: 'sentry',
79
+ enabled: config.INTEGRATIONS_ENABLE_SENTRY_PROVIDER,
80
+ load: loadSentryModuleParts
81
+ };
82
+
83
+ //# sourceMappingURL=sentry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/providers/sentry.ts"],"sourcesContent":["import {\n type IntegrationConnection as CoreIntegrationConnection,\n slugifyConnectionSlug,\n} from '@shipfox/api-integration-core-dto';\nimport type {ConnectSentryInstallationInput} from '@shipfox/api-integration-sentry';\nimport {config} from '#config.js';\nimport {\n getIntegrationConnectionById,\n resolveUniqueConnectionSlug,\n updateIntegrationConnectionLifecycleStatus,\n upsertIntegrationConnection,\n} from '#db/connections.js';\nimport {db} from '#db/db.js';\nimport {publishIntegrationEventReceived, 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 Sentry 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 SENTRY_MIGRATIONS_TABLE = '__drizzle_migrations_integrations_sentry';\n\nasync function loadSentryModuleParts(): Promise<IntegrationModuleParts> {\n const {\n createSentryIntegrationProvider,\n createSentryMaintenanceWorker,\n getSentryInstallationByInstallationUuid,\n persistVerifiedUnclaimedInstallation,\n upsertSentryInstallation,\n db: sentryDb,\n migrationsPath: sentryMigrationsPath,\n } = await import('@shipfox/api-integration-sentry');\n\n async function getConnectionById(\n id: string,\n ): Promise<CoreIntegrationConnection<'sentry'> | undefined> {\n const connection = await getIntegrationConnectionById(id);\n if (!connection) return undefined;\n return connection as CoreIntegrationConnection<'sentry'>;\n }\n\n async function connectSentryInstallation(\n input: ConnectSentryInstallationInput,\n ): Promise<CoreIntegrationConnection<'sentry'>> {\n return await retryConnectionSlugCollision(() =>\n db().transaction(async (tx) => {\n const baseSlug = slugifyConnectionSlug(`sentry_${input.orgSlug}`, {fallback: 'sentry'});\n const slug = await resolveUniqueConnectionSlug(\n {\n workspaceId: input.workspaceId,\n provider: 'sentry',\n externalAccountId: input.installationUuid,\n baseSlug,\n },\n {tx},\n );\n const connection = await upsertIntegrationConnection(\n {\n workspaceId: input.workspaceId,\n provider: 'sentry',\n externalAccountId: input.installationUuid,\n slug,\n displayName: input.displayName,\n lifecycleStatus: 'active',\n },\n {tx},\n );\n\n await upsertSentryInstallation(\n {\n connectionId: connection.id,\n installationUuid: input.installationUuid,\n orgSlug: input.orgSlug,\n status: 'installed',\n codeHash: input.codeHash,\n installerUserId: input.installerUserId,\n },\n {tx},\n );\n\n return connection as CoreIntegrationConnection<'sentry'>;\n }),\n );\n }\n\n return {\n provider: createSentryIntegrationProvider({\n getSentryInstallation: ({installationUuid}) =>\n getSentryInstallationByInstallationUuid(installationUuid),\n getConnectionById,\n connectSentryInstallation,\n persistVerifiedUnclaimedInstallation,\n coreDb: db,\n publishIntegrationEventReceived,\n recordDeliveryOnly,\n getIntegrationConnectionById,\n updateConnectionLifecycleStatus: updateIntegrationConnectionLifecycleStatus,\n }),\n database: {\n db: sentryDb,\n migrationsPath: sentryMigrationsPath,\n migrationsTableName: SENTRY_MIGRATIONS_TABLE,\n },\n workers: [createSentryMaintenanceWorker()],\n };\n}\n\nexport const sentryProviderModule: IntegrationProviderModule = {\n id: 'sentry',\n enabled: config.INTEGRATIONS_ENABLE_SENTRY_PROVIDER,\n load: loadSentryModuleParts,\n};\n"],"names":["slugifyConnectionSlug","config","getIntegrationConnectionById","resolveUniqueConnectionSlug","updateIntegrationConnectionLifecycleStatus","upsertIntegrationConnection","db","publishIntegrationEventReceived","recordDeliveryOnly","retryConnectionSlugCollision","SENTRY_MIGRATIONS_TABLE","loadSentryModuleParts","createSentryIntegrationProvider","createSentryMaintenanceWorker","getSentryInstallationByInstallationUuid","persistVerifiedUnclaimedInstallation","upsertSentryInstallation","sentryDb","migrationsPath","sentryMigrationsPath","getConnectionById","id","connection","undefined","connectSentryInstallation","input","transaction","tx","baseSlug","orgSlug","fallback","slug","workspaceId","provider","externalAccountId","installationUuid","displayName","lifecycleStatus","connectionId","status","codeHash","installerUserId","getSentryInstallation","coreDb","updateConnectionLifecycleStatus","database","migrationsTableName","workers","sentryProviderModule","enabled","INTEGRATIONS_ENABLE_SENTRY_PROVIDER","load"],"mappings":"AAAA,SAEEA,qBAAqB,QAChB,oCAAoC;AAE3C,SAAQC,MAAM,QAAO,aAAa;AAClC,SACEC,4BAA4B,EAC5BC,2BAA2B,EAC3BC,0CAA0C,EAC1CC,2BAA2B,QACtB,qBAAqB;AAC5B,SAAQC,EAAE,QAAO,YAAY;AAC7B,SAAQC,+BAA+B,EAAEC,kBAAkB,QAAO,4BAA4B;AAC9F,SAAQC,4BAA4B,QAAO,gCAAgC;AAG3E,8EAA8E;AAC9E,+EAA+E;AAC/E,0EAA0E;AAC1E,6CAA6C;AAC7C,MAAMC,0BAA0B;AAEhC,eAAeC;IACb,MAAM,EACJC,+BAA+B,EAC/BC,6BAA6B,EAC7BC,uCAAuC,EACvCC,oCAAoC,EACpCC,wBAAwB,EACxBV,IAAIW,QAAQ,EACZC,gBAAgBC,oBAAoB,EACrC,GAAG,MAAM,MAAM,CAAC;IAEjB,eAAeC,kBACbC,EAAU;QAEV,MAAMC,aAAa,MAAMpB,6BAA6BmB;QACtD,IAAI,CAACC,YAAY,OAAOC;QACxB,OAAOD;IACT;IAEA,eAAeE,0BACbC,KAAqC;QAErC,OAAO,MAAMhB,6BAA6B,IACxCH,KAAKoB,WAAW,CAAC,OAAOC;gBACtB,MAAMC,WAAW5B,sBAAsB,CAAC,OAAO,EAAEyB,MAAMI,OAAO,EAAE,EAAE;oBAACC,UAAU;gBAAQ;gBACrF,MAAMC,OAAO,MAAM5B,4BACjB;oBACE6B,aAAaP,MAAMO,WAAW;oBAC9BC,UAAU;oBACVC,mBAAmBT,MAAMU,gBAAgB;oBACzCP;gBACF,GACA;oBAACD;gBAAE;gBAEL,MAAML,aAAa,MAAMjB,4BACvB;oBACE2B,aAAaP,MAAMO,WAAW;oBAC9BC,UAAU;oBACVC,mBAAmBT,MAAMU,gBAAgB;oBACzCJ;oBACAK,aAAaX,MAAMW,WAAW;oBAC9BC,iBAAiB;gBACnB,GACA;oBAACV;gBAAE;gBAGL,MAAMX,yBACJ;oBACEsB,cAAchB,WAAWD,EAAE;oBAC3Bc,kBAAkBV,MAAMU,gBAAgB;oBACxCN,SAASJ,MAAMI,OAAO;oBACtBU,QAAQ;oBACRC,UAAUf,MAAMe,QAAQ;oBACxBC,iBAAiBhB,MAAMgB,eAAe;gBACxC,GACA;oBAACd;gBAAE;gBAGL,OAAOL;YACT;IAEJ;IAEA,OAAO;QACLW,UAAUrB,gCAAgC;YACxC8B,uBAAuB,CAAC,EAACP,gBAAgB,EAAC,GACxCrB,wCAAwCqB;YAC1Cf;YACAI;YACAT;YACA4B,QAAQrC;YACRC;YACAC;YACAN;YACA0C,iCAAiCxC;QACnC;QACAyC,UAAU;YACRvC,IAAIW;YACJC,gBAAgBC;YAChB2B,qBAAqBpC;QACvB;QACAqC,SAAS;YAAClC;SAAgC;IAC5C;AACF;AAEA,OAAO,MAAMmC,uBAAkD;IAC7D3B,IAAI;IACJ4B,SAAShD,OAAOiD,mCAAmC;IACnDC,MAAMxC;AACR,EAAE"}
@@ -0,0 +1,58 @@
1
+ import type { RouteExport } from '@shipfox/node-fastify';
2
+ import type { ModuleDatabase, ModuleWorker } from '@shipfox/node-module';
3
+ import type { IntegrationProvider } from '#core/entities/provider.js';
4
+ /**
5
+ * Everything one integration contributes to the composed integrations module:
6
+ * a registry provider, plus an optional dedicated database, background workers,
7
+ * and one-shot boot-time tasks. Providers that own none of these simply omit them.
8
+ *
9
+ * A startup task is run once after modules are initialized (migrations done). The
10
+ * provider owns its own wiring — core runs each task generically and isolates
11
+ * failures so a task can never gate API boot.
12
+ */
13
+ export interface IntegrationModuleParts {
14
+ provider: IntegrationProvider;
15
+ database?: ModuleDatabase | undefined;
16
+ e2eRoutes?: RouteExport[] | undefined;
17
+ workers?: ModuleWorker[] | undefined;
18
+ startupTasks?: Array<() => Promise<void>> | undefined;
19
+ }
20
+ /**
21
+ * A config-gated integration, registered once in `providerModules`. `load` is
22
+ * called lazily and only when `enabled`, so a disabled provider never imports
23
+ * its (potentially heavy) implementation package.
24
+ */
25
+ export interface IntegrationProviderModule {
26
+ id: string;
27
+ enabled: boolean;
28
+ load(options?: IntegrationProviderModuleLoadOptions): Promise<IntegrationModuleParts>;
29
+ }
30
+ export interface IntegrationProviderModuleLoadOptions {
31
+ secrets?: IntegrationProviderSecrets | undefined;
32
+ }
33
+ export interface IntegrationProviderSecrets {
34
+ github?: IntegrationProviderScopedSecrets | undefined;
35
+ linear?: IntegrationProviderScopedSecrets | undefined;
36
+ deleteSecrets(params: {
37
+ workspaceId: string;
38
+ namespace: string;
39
+ }): Promise<number>;
40
+ }
41
+ export interface IntegrationProviderScopedSecrets {
42
+ getSecret(params: {
43
+ workspaceId: string;
44
+ namespace: string;
45
+ key: string;
46
+ }): Promise<string | null>;
47
+ setSecrets(params: {
48
+ workspaceId: string;
49
+ namespace: string;
50
+ values: Record<string, string>;
51
+ editedBy?: string | null | undefined;
52
+ }): Promise<void>;
53
+ deleteSecrets(params: {
54
+ workspaceId: string;
55
+ namespace: string;
56
+ }): Promise<number>;
57
+ }
58
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAC,cAAc,EAAE,YAAY,EAAC,MAAM,sBAAsB,CAAC;AACvE,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,4BAA4B,CAAC;AAEpE;;;;;;;;GAQG;AACH,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,QAAQ,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IACtC,SAAS,CAAC,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;IACtC,OAAO,CAAC,EAAE,YAAY,EAAE,GAAG,SAAS,CAAC;IACrC,YAAY,CAAC,EAAE,KAAK,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;CACvD;AAED;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,OAAO,CAAC,EAAE,oCAAoC,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;CACvF;AAED,MAAM,WAAW,oCAAoC;IACnD,OAAO,CAAC,EAAE,0BAA0B,GAAG,SAAS,CAAC;CAClD;AAED,MAAM,WAAW,0BAA0B;IACzC,MAAM,CAAC,EAAE,gCAAgC,GAAG,SAAS,CAAC;IACtD,MAAM,CAAC,EAAE,gCAAgC,GAAG,SAAS,CAAC;IACtD,aAAa,CAAC,MAAM,EAAE;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAClF;AAED,MAAM,WAAW,gCAAgC;IAC/C,SAAS,CAAC,MAAM,EAAE;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAC,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACjG,UAAU,CAAC,MAAM,EAAE;QACjB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC/B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;KACtC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClB,aAAa,CAAC,MAAM,EAAE;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAClF"}
@@ -0,0 +1,3 @@
1
+ export { };
2
+
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/providers/types.ts"],"sourcesContent":["import type {RouteExport} from '@shipfox/node-fastify';\nimport type {ModuleDatabase, ModuleWorker} from '@shipfox/node-module';\nimport type {IntegrationProvider} from '#core/entities/provider.js';\n\n/**\n * Everything one integration contributes to the composed integrations module:\n * a registry provider, plus an optional dedicated database, background workers,\n * and one-shot boot-time tasks. Providers that own none of these simply omit them.\n *\n * A startup task is run once after modules are initialized (migrations done). The\n * provider owns its own wiring — core runs each task generically and isolates\n * failures so a task can never gate API boot.\n */\nexport interface IntegrationModuleParts {\n provider: IntegrationProvider;\n database?: ModuleDatabase | undefined;\n e2eRoutes?: RouteExport[] | undefined;\n workers?: ModuleWorker[] | undefined;\n startupTasks?: Array<() => Promise<void>> | undefined;\n}\n\n/**\n * A config-gated integration, registered once in `providerModules`. `load` is\n * called lazily and only when `enabled`, so a disabled provider never imports\n * its (potentially heavy) implementation package.\n */\nexport interface IntegrationProviderModule {\n id: string;\n enabled: boolean;\n load(options?: IntegrationProviderModuleLoadOptions): Promise<IntegrationModuleParts>;\n}\n\nexport interface IntegrationProviderModuleLoadOptions {\n secrets?: IntegrationProviderSecrets | undefined;\n}\n\nexport interface IntegrationProviderSecrets {\n github?: IntegrationProviderScopedSecrets | undefined;\n linear?: IntegrationProviderScopedSecrets | undefined;\n deleteSecrets(params: {workspaceId: string; namespace: string}): Promise<number>;\n}\n\nexport interface IntegrationProviderScopedSecrets {\n getSecret(params: {workspaceId: string; namespace: string; key: string}): Promise<string | null>;\n setSecrets(params: {\n workspaceId: string;\n namespace: string;\n values: Record<string, string>;\n editedBy?: string | null | undefined;\n }): Promise<void>;\n deleteSecrets(params: {workspaceId: string; namespace: string}): Promise<number>;\n}\n"],"names":[],"mappings":"AA0CA,WASC"}
@@ -0,0 +1,3 @@
1
+ import type { IntegrationProviderModule } from '#providers/types.js';
2
+ export declare const webhookProviderModule: IntegrationProviderModule;
3
+ //# sourceMappingURL=webhook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../../src/providers/webhook.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,qBAAqB,CAAC;AAEnE,eAAO,MAAM,qBAAqB,EAAE,yBAiBnC,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { config } from '#config.js';
2
+ import { createIntegrationConnection, deleteIntegrationConnection, getIntegrationConnectionById, listIntegrationConnections, updateIntegrationConnectionLifecycleStatus } from '#db/connections.js';
3
+ import { db } from '#db/db.js';
4
+ import { publishIntegrationEventReceived } from '#db/webhook-deliveries.js';
5
+ export const webhookProviderModule = {
6
+ id: 'webhook',
7
+ enabled: config.INTEGRATIONS_ENABLE_WEBHOOK_PROVIDER,
8
+ load: async ()=>{
9
+ const { createWebhookIntegrationProvider } = await import('@shipfox/api-integration-webhook');
10
+ return {
11
+ provider: createWebhookIntegrationProvider({
12
+ coreDb: db,
13
+ createIntegrationConnection,
14
+ listIntegrationConnections,
15
+ getIntegrationConnectionById,
16
+ updateIntegrationConnectionLifecycleStatus,
17
+ deleteIntegrationConnection,
18
+ publishIntegrationEventReceived
19
+ })
20
+ };
21
+ }
22
+ };
23
+
24
+ //# sourceMappingURL=webhook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/providers/webhook.ts"],"sourcesContent":["import {config} from '#config.js';\nimport {\n createIntegrationConnection,\n deleteIntegrationConnection,\n getIntegrationConnectionById,\n listIntegrationConnections,\n updateIntegrationConnectionLifecycleStatus,\n} from '#db/connections.js';\nimport {db} from '#db/db.js';\nimport {publishIntegrationEventReceived} from '#db/webhook-deliveries.js';\nimport type {IntegrationProviderModule} from '#providers/types.js';\n\nexport const webhookProviderModule: IntegrationProviderModule = {\n id: 'webhook',\n enabled: config.INTEGRATIONS_ENABLE_WEBHOOK_PROVIDER,\n load: async () => {\n const {createWebhookIntegrationProvider} = await import('@shipfox/api-integration-webhook');\n return {\n provider: createWebhookIntegrationProvider({\n coreDb: db,\n createIntegrationConnection,\n listIntegrationConnections,\n getIntegrationConnectionById,\n updateIntegrationConnectionLifecycleStatus,\n deleteIntegrationConnection,\n publishIntegrationEventReceived,\n }),\n };\n },\n};\n"],"names":["config","createIntegrationConnection","deleteIntegrationConnection","getIntegrationConnectionById","listIntegrationConnections","updateIntegrationConnectionLifecycleStatus","db","publishIntegrationEventReceived","webhookProviderModule","id","enabled","INTEGRATIONS_ENABLE_WEBHOOK_PROVIDER","load","createWebhookIntegrationProvider","provider","coreDb"],"mappings":"AAAA,SAAQA,MAAM,QAAO,aAAa;AAClC,SACEC,2BAA2B,EAC3BC,2BAA2B,EAC3BC,4BAA4B,EAC5BC,0BAA0B,EAC1BC,0CAA0C,QACrC,qBAAqB;AAC5B,SAAQC,EAAE,QAAO,YAAY;AAC7B,SAAQC,+BAA+B,QAAO,4BAA4B;AAG1E,OAAO,MAAMC,wBAAmD;IAC9DC,IAAI;IACJC,SAASV,OAAOW,oCAAoC;IACpDC,MAAM;QACJ,MAAM,EAACC,gCAAgC,EAAC,GAAG,MAAM,MAAM,CAAC;QACxD,OAAO;YACLC,UAAUD,iCAAiC;gBACzCE,QAAQT;gBACRL;gBACAG;gBACAD;gBACAE;gBACAH;gBACAK;YACF;QACF;IACF;AACF,EAAE"}
@@ -0,0 +1,5 @@
1
+ import { pruneWebhookDeliveriesActivity } from './prune-webhook-deliveries.js';
2
+ export declare function createIntegrationsMaintenanceActivities(): {
3
+ pruneWebhookDeliveriesActivity: typeof pruneWebhookDeliveriesActivity;
4
+ };
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/temporal/activities/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,8BAA8B,EAAC,MAAM,+BAA+B,CAAC;AAE7E,wBAAgB,uCAAuC;;EAItD"}
@@ -0,0 +1,8 @@
1
+ import { pruneWebhookDeliveriesActivity } from './prune-webhook-deliveries.js';
2
+ export function createIntegrationsMaintenanceActivities() {
3
+ return {
4
+ pruneWebhookDeliveriesActivity
5
+ };
6
+ }
7
+
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/temporal/activities/index.ts"],"sourcesContent":["import {pruneWebhookDeliveriesActivity} from './prune-webhook-deliveries.js';\n\nexport function createIntegrationsMaintenanceActivities() {\n return {\n pruneWebhookDeliveriesActivity,\n };\n}\n"],"names":["pruneWebhookDeliveriesActivity","createIntegrationsMaintenanceActivities"],"mappings":"AAAA,SAAQA,8BAA8B,QAAO,gCAAgC;AAE7E,OAAO,SAASC;IACd,OAAO;QACLD;IACF;AACF"}
@@ -0,0 +1,4 @@
1
+ export declare function pruneWebhookDeliveriesActivity(): Promise<{
2
+ deleted: number;
3
+ }>;
4
+ //# sourceMappingURL=prune-webhook-deliveries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prune-webhook-deliveries.d.ts","sourceRoot":"","sources":["../../../src/temporal/activities/prune-webhook-deliveries.ts"],"names":[],"mappings":"AAKA,wBAAsB,8BAA8B,IAAI,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,CAAC,CAGjF"}
@@ -0,0 +1,11 @@
1
+ import { pruneWebhookDeliveries } from '#db/webhook-deliveries.js';
2
+ import { WEBHOOK_DELIVERY_RETENTION_DAYS } from '#temporal/constants.js';
3
+ const MS_PER_DAY = 24 * 60 * 60 * 1000;
4
+ export async function pruneWebhookDeliveriesActivity() {
5
+ const olderThan = new Date(Date.now() - WEBHOOK_DELIVERY_RETENTION_DAYS * MS_PER_DAY);
6
+ return await pruneWebhookDeliveries({
7
+ olderThan
8
+ });
9
+ }
10
+
11
+ //# sourceMappingURL=prune-webhook-deliveries.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/temporal/activities/prune-webhook-deliveries.ts"],"sourcesContent":["import {pruneWebhookDeliveries} from '#db/webhook-deliveries.js';\nimport {WEBHOOK_DELIVERY_RETENTION_DAYS} from '#temporal/constants.js';\n\nconst MS_PER_DAY = 24 * 60 * 60 * 1000;\n\nexport async function pruneWebhookDeliveriesActivity(): Promise<{deleted: number}> {\n const olderThan = new Date(Date.now() - WEBHOOK_DELIVERY_RETENTION_DAYS * MS_PER_DAY);\n return await pruneWebhookDeliveries({olderThan});\n}\n"],"names":["pruneWebhookDeliveries","WEBHOOK_DELIVERY_RETENTION_DAYS","MS_PER_DAY","pruneWebhookDeliveriesActivity","olderThan","Date","now"],"mappings":"AAAA,SAAQA,sBAAsB,QAAO,4BAA4B;AACjE,SAAQC,+BAA+B,QAAO,yBAAyB;AAEvE,MAAMC,aAAa,KAAK,KAAK,KAAK;AAElC,OAAO,eAAeC;IACpB,MAAMC,YAAY,IAAIC,KAAKA,KAAKC,GAAG,KAAKL,kCAAkCC;IAC1E,OAAO,MAAMF,uBAAuB;QAACI;IAAS;AAChD"}
@@ -0,0 +1,3 @@
1
+ export declare const INTEGRATIONS_MAINTENANCE_TASK_QUEUE = "integrations-maintenance";
2
+ export declare const WEBHOOK_DELIVERY_RETENTION_DAYS = 30;
3
+ //# sourceMappingURL=constants.d.ts.map