@shipfox/api-integration-core 3.0.0 → 5.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 (57) hide show
  1. package/.turbo/turbo-build.log +4 -4
  2. package/CHANGELOG.md +62 -0
  3. package/dist/config.d.ts +2 -0
  4. package/dist/config.d.ts.map +1 -1
  5. package/dist/config.js +8 -0
  6. package/dist/config.js.map +1 -1
  7. package/dist/db/webhook-deliveries.d.ts +4 -0
  8. package/dist/db/webhook-deliveries.d.ts.map +1 -1
  9. package/dist/db/webhook-deliveries.js +10 -2
  10. package/dist/db/webhook-deliveries.js.map +1 -1
  11. package/dist/index.d.ts +2 -2
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +1 -1
  14. package/dist/index.js.map +1 -1
  15. package/dist/presentation/routes/index.js +1 -1
  16. package/dist/presentation/routes/index.js.map +1 -1
  17. package/dist/presentation/routes/manage-connections.d.ts +1 -1
  18. package/dist/presentation/routes/manage-connections.d.ts.map +1 -1
  19. package/dist/presentation/routes/manage-connections.js +28 -3
  20. package/dist/presentation/routes/manage-connections.js.map +1 -1
  21. package/dist/providers/jira.d.ts +3 -0
  22. package/dist/providers/jira.d.ts.map +1 -0
  23. package/dist/providers/jira.js +127 -0
  24. package/dist/providers/jira.js.map +1 -0
  25. package/dist/providers/linear.d.ts.map +1 -1
  26. package/dist/providers/linear.js +15 -1
  27. package/dist/providers/linear.js.map +1 -1
  28. package/dist/providers/modules.d.ts.map +1 -1
  29. package/dist/providers/modules.js +4 -0
  30. package/dist/providers/modules.js.map +1 -1
  31. package/dist/providers/slack.d.ts +3 -0
  32. package/dist/providers/slack.d.ts.map +1 -0
  33. package/dist/providers/slack.js +149 -0
  34. package/dist/providers/slack.js.map +1 -0
  35. package/dist/providers/types.d.ts +2 -0
  36. package/dist/providers/types.d.ts.map +1 -1
  37. package/dist/providers/types.js.map +1 -1
  38. package/dist/tsconfig.test.tsbuildinfo +1 -1
  39. package/package.json +28 -36
  40. package/src/config.ts +8 -0
  41. package/src/db/webhook-deliveries.test.ts +11 -0
  42. package/src/db/webhook-deliveries.ts +12 -3
  43. package/src/index.ts +2 -1
  44. package/src/presentation/routes/index.ts +1 -1
  45. package/src/presentation/routes/manage-connections.test.ts +113 -0
  46. package/src/presentation/routes/manage-connections.ts +26 -2
  47. package/src/providers/jira.test.ts +57 -0
  48. package/src/providers/jira.ts +172 -0
  49. package/src/providers/linear.test.ts +136 -0
  50. package/src/providers/linear.ts +14 -0
  51. package/src/providers/modules.test.ts +26 -0
  52. package/src/providers/modules.ts +4 -0
  53. package/src/providers/slack.test.ts +196 -0
  54. package/src/providers/slack.ts +196 -0
  55. package/src/providers/types.ts +2 -0
  56. package/test/env.ts +12 -0
  57. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1,6 +1,6 @@
1
1
  $ shipfox-swc && shipfox-temporal-bundle dist/temporal/workflows/index.js
2
- Successfully compiled: 47 files with swc (201.04ms)
3
- 2026-07-18T08:51:37.226Z [INFO] asset workflow-bundle-fe8baaf5b68e0b2328d8.js 1.45 MiB [emitted] [immutable] (name: main)
2
+ Successfully compiled: 49 files with swc (158.39ms)
3
+ 2026-07-19T19:41:21.630Z [INFO] asset workflow-bundle-fe8baaf5b68e0b2328d8.js 1.45 MiB [emitted] [immutable] (name: main)
4
4
  runtime modules 670 bytes 3 modules
5
5
  modules by path ../../../../node_modules/.pnpm/ 424 KiB
6
6
  modules by path ../../../../node_modules/.pnpm/@temporalio+common@1.18.1/node_modules/@temporal...(truncated) 155 KiB 34 modules
@@ -15,6 +15,6 @@ modules by path ./dist/temporal/workflows/ 1020 bytes
15
15
  optional modules 30 bytes [optional]
16
16
  __temporal_custom_payload_converter (ignored) 15 bytes [optional] [built] [code generated]
17
17
  __temporal_custom_failure_converter (ignored) 15 bytes [optional] [built] [code generated]
18
- webpack 5.107.2 compiled successfully in 943 ms
19
- 2026-07-18T08:51:37.230Z [INFO] Workflow bundle created { size: '1.45MB' }
18
+ webpack 5.107.2 compiled successfully in 1227 ms
19
+ 2026-07-19T19:41:21.634Z [INFO] Workflow bundle created { size: '1.45MB' }
20
20
  /home/runner/work/shipfox/shipfox/libs/api/integration/core/dist/temporal/workflows/index.js: 1516260 bytes
package/CHANGELOG.md CHANGED
@@ -1,5 +1,67 @@
1
1
  # @shipfox/api-integration-core
2
2
 
3
+ ## 5.0.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 2875241: Adds deduplicated Slack installation revocation for app uninstall and bot token-revocation events.
8
+
9
+ ### Patch Changes
10
+
11
+ - bb037af: Resolves workspace packages from source during development while published consumers continue to use compiled output.
12
+ - fb70438: Cascades provider installation and token deletion when removing a connection.
13
+ - Updated dependencies [2875241]
14
+ - Updated dependencies [bb037af]
15
+ - Updated dependencies [43d8e66]
16
+ - Updated dependencies [fb70438]
17
+ - @shipfox/api-integration-slack@5.0.0
18
+ - @shipfox/api-integration-core-dto@5.0.0
19
+ - @shipfox/api-agent-dto@5.0.0
20
+ - @shipfox/api-auth-context@5.0.0
21
+ - @shipfox/api-integration-gitea@5.0.0
22
+ - @shipfox/api-integration-github@5.0.0
23
+ - @shipfox/api-integration-jira@5.0.0
24
+ - @shipfox/api-integration-linear@5.0.0
25
+ - @shipfox/api-integration-sentry@5.0.0
26
+ - @shipfox/api-integration-webhook@5.0.0
27
+ - @shipfox/config@1.2.2
28
+ - @shipfox/node-drizzle@0.3.1
29
+ - @shipfox/node-fastify@0.2.3
30
+ - @shipfox/node-module@0.3.2
31
+ - @shipfox/node-opentelemetry@0.5.2
32
+ - @shipfox/node-outbox@0.2.3
33
+ - @shipfox/node-postgres@0.4.2
34
+ - @shipfox/node-temporal@0.3.1
35
+ - @shipfox/redact@0.2.2
36
+ - @shipfox/regex@0.2.2
37
+
38
+ ## 4.0.0
39
+
40
+ ### Minor Changes
41
+
42
+ - 67176d4: Adds the Slack OAuth connection flow with provider routes, secure bot-token storage, and E2E setup.
43
+
44
+ ### Patch Changes
45
+
46
+ - 5d129d6: Adds the default-off Jira provider scaffold with installation storage and token custody seams.
47
+ - bbba3b7: Adds the Slack integration provider scaffold with installation storage, bot-token custody, and flag-gated registration.
48
+ - 1951293: Adds in-process Slack agent tools for reading conversations and acting on messages through the lease-authenticated gateway.
49
+ - Updated dependencies [0745ee9]
50
+ - Updated dependencies [23c8e4d]
51
+ - Updated dependencies [67176d4]
52
+ - Updated dependencies [7267872]
53
+ - Updated dependencies [bbba3b7]
54
+ - Updated dependencies [1951293]
55
+ - @shipfox/api-integration-slack@4.0.0
56
+ - @shipfox/node-drizzle@0.3.0
57
+ - @shipfox/api-integration-linear@4.0.0
58
+ - @shipfox/api-integration-jira@4.0.0
59
+ - @shipfox/api-integration-gitea@4.0.0
60
+ - @shipfox/api-integration-github@4.0.0
61
+ - @shipfox/api-integration-sentry@4.0.0
62
+ - @shipfox/node-module@0.3.1
63
+ - @shipfox/node-outbox@0.2.2
64
+
3
65
  ## 3.0.0
4
66
 
5
67
  ### Patch Changes
package/dist/config.d.ts CHANGED
@@ -2,8 +2,10 @@ export declare const config: Readonly<{
2
2
  INTEGRATIONS_ENABLE_CRON_PROVIDER: boolean;
3
3
  INTEGRATIONS_ENABLE_GITEA_PROVIDER: boolean;
4
4
  INTEGRATIONS_ENABLE_GITHUB_PROVIDER: boolean;
5
+ INTEGRATIONS_ENABLE_JIRA_PROVIDER: boolean;
5
6
  INTEGRATIONS_ENABLE_LINEAR_PROVIDER: boolean;
6
7
  INTEGRATIONS_ENABLE_SENTRY_PROVIDER: boolean;
8
+ INTEGRATIONS_ENABLE_SLACK_PROVIDER: boolean;
7
9
  INTEGRATIONS_ENABLE_WEBHOOK_PROVIDER: boolean;
8
10
  } & import("@shipfox/config").CleanedEnvAccessors>;
9
11
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,MAAM;;;;;;;kDAyBjB,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,MAAM;;;;;;;;;kDAiCjB,CAAC"}
package/dist/config.js CHANGED
@@ -12,6 +12,10 @@ export const config = createConfig({
12
12
  desc: 'Enables the GitHub integration provider so users can connect GitHub.',
13
13
  default: false
14
14
  }),
15
+ INTEGRATIONS_ENABLE_JIRA_PROVIDER: bool({
16
+ desc: 'Enables the Jira integration provider so users can connect Jira sites.',
17
+ default: false
18
+ }),
15
19
  INTEGRATIONS_ENABLE_LINEAR_PROVIDER: bool({
16
20
  desc: 'Enables the Linear integration provider so users can connect Linear workspaces.',
17
21
  default: false
@@ -20,6 +24,10 @@ export const config = createConfig({
20
24
  desc: 'Enables the Sentry integration provider so users can connect Sentry.',
21
25
  default: false
22
26
  }),
27
+ INTEGRATIONS_ENABLE_SLACK_PROVIDER: bool({
28
+ desc: 'Enables the Slack integration provider so users can connect Slack workspaces.',
29
+ default: false
30
+ }),
23
31
  INTEGRATIONS_ENABLE_WEBHOOK_PROVIDER: bool({
24
32
  desc: 'Enables the generic webhook integration provider so users can create inbound webhook URLs. It is enabled by default because it does not require provider setup.',
25
33
  default: true
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config.ts"],"sourcesContent":["import {bool, createConfig} from '@shipfox/config';\n\nexport const config = createConfig({\n INTEGRATIONS_ENABLE_CRON_PROVIDER: bool({\n desc: 'Enables the cron integration provider so workflow schedules can use the built-in cron source. It is enabled by default because it does not require provider setup.',\n default: true,\n }),\n INTEGRATIONS_ENABLE_GITEA_PROVIDER: bool({\n desc: 'Enables the Gitea integration provider so users can connect a Gitea instance.',\n default: false,\n }),\n INTEGRATIONS_ENABLE_GITHUB_PROVIDER: bool({\n desc: 'Enables the GitHub integration provider so users can connect GitHub.',\n default: false,\n }),\n INTEGRATIONS_ENABLE_LINEAR_PROVIDER: bool({\n desc: 'Enables the Linear integration provider so users can connect Linear workspaces.',\n default: false,\n }),\n INTEGRATIONS_ENABLE_SENTRY_PROVIDER: bool({\n desc: 'Enables the Sentry integration provider so users can connect Sentry.',\n default: false,\n }),\n INTEGRATIONS_ENABLE_WEBHOOK_PROVIDER: bool({\n desc: 'Enables the generic webhook integration provider so users can create inbound webhook URLs. It is enabled by default because it does not require provider setup.',\n default: true,\n }),\n});\n"],"names":["bool","createConfig","config","INTEGRATIONS_ENABLE_CRON_PROVIDER","desc","default","INTEGRATIONS_ENABLE_GITEA_PROVIDER","INTEGRATIONS_ENABLE_GITHUB_PROVIDER","INTEGRATIONS_ENABLE_LINEAR_PROVIDER","INTEGRATIONS_ENABLE_SENTRY_PROVIDER","INTEGRATIONS_ENABLE_WEBHOOK_PROVIDER"],"mappings":"AAAA,SAAQA,IAAI,EAAEC,YAAY,QAAO,kBAAkB;AAEnD,OAAO,MAAMC,SAASD,aAAa;IACjCE,mCAAmCH,KAAK;QACtCI,MAAM;QACNC,SAAS;IACX;IACAC,oCAAoCN,KAAK;QACvCI,MAAM;QACNC,SAAS;IACX;IACAE,qCAAqCP,KAAK;QACxCI,MAAM;QACNC,SAAS;IACX;IACAG,qCAAqCR,KAAK;QACxCI,MAAM;QACNC,SAAS;IACX;IACAI,qCAAqCT,KAAK;QACxCI,MAAM;QACNC,SAAS;IACX;IACAK,sCAAsCV,KAAK;QACzCI,MAAM;QACNC,SAAS;IACX;AACF,GAAG"}
1
+ {"version":3,"sources":["../src/config.ts"],"sourcesContent":["import {bool, createConfig} from '@shipfox/config';\n\nexport const config = createConfig({\n INTEGRATIONS_ENABLE_CRON_PROVIDER: bool({\n desc: 'Enables the cron integration provider so workflow schedules can use the built-in cron source. It is enabled by default because it does not require provider setup.',\n default: true,\n }),\n INTEGRATIONS_ENABLE_GITEA_PROVIDER: bool({\n desc: 'Enables the Gitea integration provider so users can connect a Gitea instance.',\n default: false,\n }),\n INTEGRATIONS_ENABLE_GITHUB_PROVIDER: bool({\n desc: 'Enables the GitHub integration provider so users can connect GitHub.',\n default: false,\n }),\n INTEGRATIONS_ENABLE_JIRA_PROVIDER: bool({\n desc: 'Enables the Jira integration provider so users can connect Jira sites.',\n default: false,\n }),\n INTEGRATIONS_ENABLE_LINEAR_PROVIDER: bool({\n desc: 'Enables the Linear integration provider so users can connect Linear workspaces.',\n default: false,\n }),\n INTEGRATIONS_ENABLE_SENTRY_PROVIDER: bool({\n desc: 'Enables the Sentry integration provider so users can connect Sentry.',\n default: false,\n }),\n INTEGRATIONS_ENABLE_SLACK_PROVIDER: bool({\n desc: 'Enables the Slack integration provider so users can connect Slack workspaces.',\n default: false,\n }),\n INTEGRATIONS_ENABLE_WEBHOOK_PROVIDER: bool({\n desc: 'Enables the generic webhook integration provider so users can create inbound webhook URLs. It is enabled by default because it does not require provider setup.',\n default: true,\n }),\n});\n"],"names":["bool","createConfig","config","INTEGRATIONS_ENABLE_CRON_PROVIDER","desc","default","INTEGRATIONS_ENABLE_GITEA_PROVIDER","INTEGRATIONS_ENABLE_GITHUB_PROVIDER","INTEGRATIONS_ENABLE_JIRA_PROVIDER","INTEGRATIONS_ENABLE_LINEAR_PROVIDER","INTEGRATIONS_ENABLE_SENTRY_PROVIDER","INTEGRATIONS_ENABLE_SLACK_PROVIDER","INTEGRATIONS_ENABLE_WEBHOOK_PROVIDER"],"mappings":"AAAA,SAAQA,IAAI,EAAEC,YAAY,QAAO,kBAAkB;AAEnD,OAAO,MAAMC,SAASD,aAAa;IACjCE,mCAAmCH,KAAK;QACtCI,MAAM;QACNC,SAAS;IACX;IACAC,oCAAoCN,KAAK;QACvCI,MAAM;QACNC,SAAS;IACX;IACAE,qCAAqCP,KAAK;QACxCI,MAAM;QACNC,SAAS;IACX;IACAG,mCAAmCR,KAAK;QACtCI,MAAM;QACNC,SAAS;IACX;IACAI,qCAAqCT,KAAK;QACxCI,MAAM;QACNC,SAAS;IACX;IACAK,qCAAqCV,KAAK;QACxCI,MAAM;QACNC,SAAS;IACX;IACAM,oCAAoCX,KAAK;QACvCI,MAAM;QACNC,SAAS;IACX;IACAO,sCAAsCZ,KAAK;QACzCI,MAAM;QACNC,SAAS;IACX;AACF,GAAG"}
@@ -40,6 +40,9 @@ export interface RecordDeliveryOnlyParams {
40
40
  provider: string;
41
41
  deliveryId: string;
42
42
  }
43
+ export declare function claimWebhookDelivery(params: RecordDeliveryOnlyParams): Promise<{
44
+ claimed: boolean;
45
+ }>;
43
46
  export declare function recordDeliveryOnly(params: RecordDeliveryOnlyParams): Promise<void>;
44
47
  export interface PruneWebhookDeliveriesParams {
45
48
  olderThan: Date;
@@ -50,6 +53,7 @@ export declare function pruneWebhookDeliveries(params: PruneWebhookDeliveriesPar
50
53
  export type PublishIntegrationEventReceivedFn = typeof publishIntegrationEventReceived;
51
54
  export type PublishSourcePushFn = typeof publishSourcePush;
52
55
  export type PublishSourceCommitPushedFn = typeof publishSourceCommitPushed;
56
+ export type ClaimWebhookDeliveryFn = typeof claimWebhookDelivery;
53
57
  export type RecordDeliveryOnlyFn = typeof recordDeliveryOnly;
54
58
  export {};
55
59
  //# sourceMappingURL=webhook-deliveries.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"webhook-deliveries.d.ts","sourceRoot":"","sources":["../../src/db/webhook-deliveries.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,6BAA6B,EAElC,KAAK,iBAAiB,EACvB,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EAAC,EAAE,EAAC,MAAM,SAAS,CAAC;AAI3B,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC;AAC3C,KAAK,aAAa,GAAG,UAAU,CAAC,UAAU,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChF,KAAK,QAAQ,GAAG,aAAa,GAAG,aAAa,CAAC;AAe9C,MAAM,WAAW,qCAAqC;IACpD,EAAE,EAAE,QAAQ,CAAC;IACb,KAAK,EAAE,6BAA6B,CAAC;CACtC;AAED,MAAM,WAAW,qCAAqC;IACpD,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,wBAAsB,+BAA+B,CACnD,MAAM,EAAE,qCAAqC,GAC5C,OAAO,CAAC,qCAAqC,CAAC,CAyBhD;AAED,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,aAAa,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,iBAAiB,CAAC;CACzB;AAOD,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAC,CAAC,CAgD/B;AAED,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,iBAAiB,CAAC;CACzB;AAMD,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,+BAA+B,GACtC,OAAO,CAAC,IAAI,CAAC,CAYf;AAED,MAAM,WAAW,wBAAwB;IACvC,EAAE,EAAE,QAAQ,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAexF;AAED,MAAM,WAAW,4BAA4B;IAC3C,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,4BAA4B,GACnC,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,CAAC,CAK5B;AAED,MAAM,MAAM,iCAAiC,GAAG,OAAO,+BAA+B,CAAC;AACvF,MAAM,MAAM,mBAAmB,GAAG,OAAO,iBAAiB,CAAC;AAC3D,MAAM,MAAM,2BAA2B,GAAG,OAAO,yBAAyB,CAAC;AAC3E,MAAM,MAAM,oBAAoB,GAAG,OAAO,kBAAkB,CAAC"}
1
+ {"version":3,"file":"webhook-deliveries.d.ts","sourceRoot":"","sources":["../../src/db/webhook-deliveries.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,6BAA6B,EAElC,KAAK,iBAAiB,EACvB,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EAAC,EAAE,EAAC,MAAM,SAAS,CAAC;AAI3B,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC;AAC3C,KAAK,aAAa,GAAG,UAAU,CAAC,UAAU,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChF,KAAK,QAAQ,GAAG,aAAa,GAAG,aAAa,CAAC;AAe9C,MAAM,WAAW,qCAAqC;IACpD,EAAE,EAAE,QAAQ,CAAC;IACb,KAAK,EAAE,6BAA6B,CAAC;CACtC;AAED,MAAM,WAAW,qCAAqC;IACpD,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,wBAAsB,+BAA+B,CACnD,MAAM,EAAE,qCAAqC,GAC5C,OAAO,CAAC,qCAAqC,CAAC,CAyBhD;AAED,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,aAAa,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,iBAAiB,CAAC;CACzB;AAOD,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAC,CAAC,CAgD/B;AAED,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,iBAAiB,CAAC;CACzB;AAMD,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,+BAA+B,GACtC,OAAO,CAAC,IAAI,CAAC,CAYf;AAED,MAAM,WAAW,wBAAwB;IACvC,EAAE,EAAE,QAAQ,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,wBAAwB,GAC/B,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAC,CAAC,CAiB7B;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAExF;AAED,MAAM,WAAW,4BAA4B;IAC3C,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,4BAA4B,GACnC,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,CAAC,CAK5B;AAED,MAAM,MAAM,iCAAiC,GAAG,OAAO,+BAA+B,CAAC;AACvF,MAAM,MAAM,mBAAmB,GAAG,OAAO,iBAAiB,CAAC;AAC3D,MAAM,MAAM,2BAA2B,GAAG,OAAO,yBAAyB,CAAC;AAC3E,MAAM,MAAM,sBAAsB,GAAG,OAAO,oBAAoB,CAAC;AACjE,MAAM,MAAM,oBAAoB,GAAG,OAAO,kBAAkB,CAAC"}
@@ -109,8 +109,8 @@ export async function publishSourceCommitPushed(params) {
109
109
  }
110
110
  });
111
111
  }
112
- export async function recordDeliveryOnly(params) {
113
- await params.tx.insert(integrationsWebhookDeliveries).values({
112
+ export async function claimWebhookDelivery(params) {
113
+ const inserted = await params.tx.insert(integrationsWebhookDeliveries).values({
114
114
  provider: params.provider,
115
115
  dedupScope: providerDedupScope(params.provider),
116
116
  deliveryId: params.deliveryId
@@ -120,7 +120,15 @@ export async function recordDeliveryOnly(params) {
120
120
  integrationsWebhookDeliveries.dedupScope,
121
121
  integrationsWebhookDeliveries.deliveryId
122
122
  ]
123
+ }).returning({
124
+ deliveryId: integrationsWebhookDeliveries.deliveryId
123
125
  });
126
+ return {
127
+ claimed: inserted.length > 0
128
+ };
129
+ }
130
+ export async function recordDeliveryOnly(params) {
131
+ await claimWebhookDelivery(params);
124
132
  }
125
133
  export async function pruneWebhookDeliveries(params) {
126
134
  const result = await db().delete(integrationsWebhookDeliveries).where(lt(integrationsWebhookDeliveries.receivedAt, params.olderThan));
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/db/webhook-deliveries.ts"],"sourcesContent":["import {\n INTEGRATION_EVENT_RECEIVED,\n INTEGRATION_SOURCE_COMMIT_PUSHED,\n type IntegrationEventReceivedEvent,\n type IntegrationsEventMap,\n type SourcePushPayload,\n} from '@shipfox/api-integration-core-dto';\nimport {writeOutboxEvent, writeOutboxEvents} from '@shipfox/node-outbox';\nimport {lt} from 'drizzle-orm';\nimport {db} from './db.js';\nimport {integrationsOutbox} from './schema/outbox.js';\nimport {integrationsWebhookDeliveries} from './schema/webhook-deliveries.js';\n\ntype IntegrationDb = ReturnType<typeof db>;\ntype IntegrationTx = Parameters<Parameters<IntegrationDb['transaction']>[0]>[0];\ntype Executor = IntegrationDb | IntegrationTx;\n\nfunction connectionDedupScope(connectionId: string): string {\n return `connection:${connectionId}`;\n}\n\nfunction providerDedupScope(provider: string): string {\n return `provider:${provider}`;\n}\n\nfunction receivedEventDedupScope(event: IntegrationEventReceivedEvent): string {\n if (event.provider === 'webhook') return connectionDedupScope(event.connectionId);\n return providerDedupScope(event.provider);\n}\n\nexport interface PublishIntegrationEventReceivedParams {\n tx: Executor;\n event: IntegrationEventReceivedEvent;\n}\n\nexport interface PublishIntegrationEventReceivedResult {\n published: boolean;\n}\n\nexport async function publishIntegrationEventReceived(\n params: PublishIntegrationEventReceivedParams,\n): Promise<PublishIntegrationEventReceivedResult> {\n const inserted = await params.tx\n .insert(integrationsWebhookDeliveries)\n .values({\n provider: params.event.provider,\n dedupScope: receivedEventDedupScope(params.event),\n deliveryId: params.event.deliveryId,\n })\n .onConflictDoNothing({\n target: [\n integrationsWebhookDeliveries.provider,\n integrationsWebhookDeliveries.dedupScope,\n integrationsWebhookDeliveries.deliveryId,\n ],\n })\n .returning({deliveryId: integrationsWebhookDeliveries.deliveryId});\n\n if (inserted.length === 0) return {published: false};\n\n await writeOutboxEvent(params.tx, integrationsOutbox, {\n type: INTEGRATION_EVENT_RECEIVED,\n payload: params.event,\n });\n\n return {published: true};\n}\n\nexport interface PublishSourcePushParams {\n tx: IntegrationTx;\n provider: string;\n source: string;\n workspaceId: string;\n connectionId: string;\n connectionName: string;\n deliveryId: string;\n receivedAt: string;\n rawPayload: unknown;\n push: SourcePushPayload;\n}\n\n// Emits a single source-control push as two outbox rows: the generic\n// `INTEGRATION_EVENT_RECEIVED` envelope with the raw provider payload for triggers, and the\n// typed `INTEGRATION_SOURCE_COMMIT_PUSHED` event for domain modules. One delivery-dedup gates\n// both, so a redelivered webhook writes nothing. Requires a transaction: the dedup insert and\n// both outbox rows must commit or roll back together.\nexport async function publishSourcePush(\n params: PublishSourcePushParams,\n): Promise<{published: boolean}> {\n const inserted = await params.tx\n .insert(integrationsWebhookDeliveries)\n .values({\n provider: params.provider,\n dedupScope: providerDedupScope(params.provider),\n deliveryId: params.deliveryId,\n })\n .onConflictDoNothing({\n target: [\n integrationsWebhookDeliveries.provider,\n integrationsWebhookDeliveries.dedupScope,\n integrationsWebhookDeliveries.deliveryId,\n ],\n })\n .returning({deliveryId: integrationsWebhookDeliveries.deliveryId});\n\n if (inserted.length === 0) return {published: false};\n\n await writeOutboxEvents<IntegrationsEventMap>(params.tx, integrationsOutbox, [\n {\n type: INTEGRATION_EVENT_RECEIVED,\n payload: {\n provider: params.provider,\n source: params.source,\n event: 'push',\n workspaceId: params.workspaceId,\n connectionId: params.connectionId,\n connectionName: params.connectionName,\n deliveryId: params.deliveryId,\n receivedAt: params.receivedAt,\n payload: params.rawPayload,\n },\n },\n {\n type: INTEGRATION_SOURCE_COMMIT_PUSHED,\n payload: {\n provider: params.provider,\n workspaceId: params.workspaceId,\n connectionId: params.connectionId,\n deliveryId: params.deliveryId,\n receivedAt: params.receivedAt,\n push: params.push,\n },\n },\n ]);\n\n return {published: true};\n}\n\nexport interface PublishSourceCommitPushedParams {\n provider: string;\n workspaceId: string;\n connectionId: string;\n deliveryId: string;\n receivedAt: string;\n push: SourcePushPayload;\n}\n\n// Emits ONLY the typed `INTEGRATION_SOURCE_COMMIT_PUSHED` event, intentionally skipping the\n// `INTEGRATION_EVENT_RECEIVED` envelope so triggers do not run workflows, and skipping the\n// delivery-dedup row so it is never suppressed. Used to force a definitions re-sync without\n// simulating an inbound webhook.\nexport async function publishSourceCommitPushed(\n params: PublishSourceCommitPushedParams,\n): Promise<void> {\n await writeOutboxEvent<IntegrationsEventMap>(db(), integrationsOutbox, {\n type: INTEGRATION_SOURCE_COMMIT_PUSHED,\n payload: {\n provider: params.provider,\n workspaceId: params.workspaceId,\n connectionId: params.connectionId,\n deliveryId: params.deliveryId,\n receivedAt: params.receivedAt,\n push: params.push,\n },\n });\n}\n\nexport interface RecordDeliveryOnlyParams {\n tx: Executor;\n provider: string;\n deliveryId: string;\n}\n\nexport async function recordDeliveryOnly(params: RecordDeliveryOnlyParams): Promise<void> {\n await params.tx\n .insert(integrationsWebhookDeliveries)\n .values({\n provider: params.provider,\n dedupScope: providerDedupScope(params.provider),\n deliveryId: params.deliveryId,\n })\n .onConflictDoNothing({\n target: [\n integrationsWebhookDeliveries.provider,\n integrationsWebhookDeliveries.dedupScope,\n integrationsWebhookDeliveries.deliveryId,\n ],\n });\n}\n\nexport interface PruneWebhookDeliveriesParams {\n olderThan: Date;\n}\n\nexport async function pruneWebhookDeliveries(\n params: PruneWebhookDeliveriesParams,\n): Promise<{deleted: number}> {\n const result = await db()\n .delete(integrationsWebhookDeliveries)\n .where(lt(integrationsWebhookDeliveries.receivedAt, params.olderThan));\n return {deleted: result.rowCount ?? 0};\n}\n\nexport type PublishIntegrationEventReceivedFn = typeof publishIntegrationEventReceived;\nexport type PublishSourcePushFn = typeof publishSourcePush;\nexport type PublishSourceCommitPushedFn = typeof publishSourceCommitPushed;\nexport type RecordDeliveryOnlyFn = typeof recordDeliveryOnly;\n"],"names":["INTEGRATION_EVENT_RECEIVED","INTEGRATION_SOURCE_COMMIT_PUSHED","writeOutboxEvent","writeOutboxEvents","lt","db","integrationsOutbox","integrationsWebhookDeliveries","connectionDedupScope","connectionId","providerDedupScope","provider","receivedEventDedupScope","event","publishIntegrationEventReceived","params","inserted","tx","insert","values","dedupScope","deliveryId","onConflictDoNothing","target","returning","length","published","type","payload","publishSourcePush","source","workspaceId","connectionName","receivedAt","rawPayload","push","publishSourceCommitPushed","recordDeliveryOnly","pruneWebhookDeliveries","result","delete","where","olderThan","deleted","rowCount"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/db/webhook-deliveries.ts"],"sourcesContent":["import {\n INTEGRATION_EVENT_RECEIVED,\n INTEGRATION_SOURCE_COMMIT_PUSHED,\n type IntegrationEventReceivedEvent,\n type IntegrationsEventMap,\n type SourcePushPayload,\n} from '@shipfox/api-integration-core-dto';\nimport {writeOutboxEvent, writeOutboxEvents} from '@shipfox/node-outbox';\nimport {lt} from 'drizzle-orm';\nimport {db} from './db.js';\nimport {integrationsOutbox} from './schema/outbox.js';\nimport {integrationsWebhookDeliveries} from './schema/webhook-deliveries.js';\n\ntype IntegrationDb = ReturnType<typeof db>;\ntype IntegrationTx = Parameters<Parameters<IntegrationDb['transaction']>[0]>[0];\ntype Executor = IntegrationDb | IntegrationTx;\n\nfunction connectionDedupScope(connectionId: string): string {\n return `connection:${connectionId}`;\n}\n\nfunction providerDedupScope(provider: string): string {\n return `provider:${provider}`;\n}\n\nfunction receivedEventDedupScope(event: IntegrationEventReceivedEvent): string {\n if (event.provider === 'webhook') return connectionDedupScope(event.connectionId);\n return providerDedupScope(event.provider);\n}\n\nexport interface PublishIntegrationEventReceivedParams {\n tx: Executor;\n event: IntegrationEventReceivedEvent;\n}\n\nexport interface PublishIntegrationEventReceivedResult {\n published: boolean;\n}\n\nexport async function publishIntegrationEventReceived(\n params: PublishIntegrationEventReceivedParams,\n): Promise<PublishIntegrationEventReceivedResult> {\n const inserted = await params.tx\n .insert(integrationsWebhookDeliveries)\n .values({\n provider: params.event.provider,\n dedupScope: receivedEventDedupScope(params.event),\n deliveryId: params.event.deliveryId,\n })\n .onConflictDoNothing({\n target: [\n integrationsWebhookDeliveries.provider,\n integrationsWebhookDeliveries.dedupScope,\n integrationsWebhookDeliveries.deliveryId,\n ],\n })\n .returning({deliveryId: integrationsWebhookDeliveries.deliveryId});\n\n if (inserted.length === 0) return {published: false};\n\n await writeOutboxEvent(params.tx, integrationsOutbox, {\n type: INTEGRATION_EVENT_RECEIVED,\n payload: params.event,\n });\n\n return {published: true};\n}\n\nexport interface PublishSourcePushParams {\n tx: IntegrationTx;\n provider: string;\n source: string;\n workspaceId: string;\n connectionId: string;\n connectionName: string;\n deliveryId: string;\n receivedAt: string;\n rawPayload: unknown;\n push: SourcePushPayload;\n}\n\n// Emits a single source-control push as two outbox rows: the generic\n// `INTEGRATION_EVENT_RECEIVED` envelope with the raw provider payload for triggers, and the\n// typed `INTEGRATION_SOURCE_COMMIT_PUSHED` event for domain modules. One delivery-dedup gates\n// both, so a redelivered webhook writes nothing. Requires a transaction: the dedup insert and\n// both outbox rows must commit or roll back together.\nexport async function publishSourcePush(\n params: PublishSourcePushParams,\n): Promise<{published: boolean}> {\n const inserted = await params.tx\n .insert(integrationsWebhookDeliveries)\n .values({\n provider: params.provider,\n dedupScope: providerDedupScope(params.provider),\n deliveryId: params.deliveryId,\n })\n .onConflictDoNothing({\n target: [\n integrationsWebhookDeliveries.provider,\n integrationsWebhookDeliveries.dedupScope,\n integrationsWebhookDeliveries.deliveryId,\n ],\n })\n .returning({deliveryId: integrationsWebhookDeliveries.deliveryId});\n\n if (inserted.length === 0) return {published: false};\n\n await writeOutboxEvents<IntegrationsEventMap>(params.tx, integrationsOutbox, [\n {\n type: INTEGRATION_EVENT_RECEIVED,\n payload: {\n provider: params.provider,\n source: params.source,\n event: 'push',\n workspaceId: params.workspaceId,\n connectionId: params.connectionId,\n connectionName: params.connectionName,\n deliveryId: params.deliveryId,\n receivedAt: params.receivedAt,\n payload: params.rawPayload,\n },\n },\n {\n type: INTEGRATION_SOURCE_COMMIT_PUSHED,\n payload: {\n provider: params.provider,\n workspaceId: params.workspaceId,\n connectionId: params.connectionId,\n deliveryId: params.deliveryId,\n receivedAt: params.receivedAt,\n push: params.push,\n },\n },\n ]);\n\n return {published: true};\n}\n\nexport interface PublishSourceCommitPushedParams {\n provider: string;\n workspaceId: string;\n connectionId: string;\n deliveryId: string;\n receivedAt: string;\n push: SourcePushPayload;\n}\n\n// Emits ONLY the typed `INTEGRATION_SOURCE_COMMIT_PUSHED` event, intentionally skipping the\n// `INTEGRATION_EVENT_RECEIVED` envelope so triggers do not run workflows, and skipping the\n// delivery-dedup row so it is never suppressed. Used to force a definitions re-sync without\n// simulating an inbound webhook.\nexport async function publishSourceCommitPushed(\n params: PublishSourceCommitPushedParams,\n): Promise<void> {\n await writeOutboxEvent<IntegrationsEventMap>(db(), integrationsOutbox, {\n type: INTEGRATION_SOURCE_COMMIT_PUSHED,\n payload: {\n provider: params.provider,\n workspaceId: params.workspaceId,\n connectionId: params.connectionId,\n deliveryId: params.deliveryId,\n receivedAt: params.receivedAt,\n push: params.push,\n },\n });\n}\n\nexport interface RecordDeliveryOnlyParams {\n tx: Executor;\n provider: string;\n deliveryId: string;\n}\n\nexport async function claimWebhookDelivery(\n params: RecordDeliveryOnlyParams,\n): Promise<{claimed: boolean}> {\n const inserted = await params.tx\n .insert(integrationsWebhookDeliveries)\n .values({\n provider: params.provider,\n dedupScope: providerDedupScope(params.provider),\n deliveryId: params.deliveryId,\n })\n .onConflictDoNothing({\n target: [\n integrationsWebhookDeliveries.provider,\n integrationsWebhookDeliveries.dedupScope,\n integrationsWebhookDeliveries.deliveryId,\n ],\n })\n .returning({deliveryId: integrationsWebhookDeliveries.deliveryId});\n return {claimed: inserted.length > 0};\n}\n\nexport async function recordDeliveryOnly(params: RecordDeliveryOnlyParams): Promise<void> {\n await claimWebhookDelivery(params);\n}\n\nexport interface PruneWebhookDeliveriesParams {\n olderThan: Date;\n}\n\nexport async function pruneWebhookDeliveries(\n params: PruneWebhookDeliveriesParams,\n): Promise<{deleted: number}> {\n const result = await db()\n .delete(integrationsWebhookDeliveries)\n .where(lt(integrationsWebhookDeliveries.receivedAt, params.olderThan));\n return {deleted: result.rowCount ?? 0};\n}\n\nexport type PublishIntegrationEventReceivedFn = typeof publishIntegrationEventReceived;\nexport type PublishSourcePushFn = typeof publishSourcePush;\nexport type PublishSourceCommitPushedFn = typeof publishSourceCommitPushed;\nexport type ClaimWebhookDeliveryFn = typeof claimWebhookDelivery;\nexport type RecordDeliveryOnlyFn = typeof recordDeliveryOnly;\n"],"names":["INTEGRATION_EVENT_RECEIVED","INTEGRATION_SOURCE_COMMIT_PUSHED","writeOutboxEvent","writeOutboxEvents","lt","db","integrationsOutbox","integrationsWebhookDeliveries","connectionDedupScope","connectionId","providerDedupScope","provider","receivedEventDedupScope","event","publishIntegrationEventReceived","params","inserted","tx","insert","values","dedupScope","deliveryId","onConflictDoNothing","target","returning","length","published","type","payload","publishSourcePush","source","workspaceId","connectionName","receivedAt","rawPayload","push","publishSourceCommitPushed","claimWebhookDelivery","claimed","recordDeliveryOnly","pruneWebhookDeliveries","result","delete","where","olderThan","deleted","rowCount"],"mappings":"AAAA,SACEA,0BAA0B,EAC1BC,gCAAgC,QAI3B,oCAAoC;AAC3C,SAAQC,gBAAgB,EAAEC,iBAAiB,QAAO,uBAAuB;AACzE,SAAQC,EAAE,QAAO,cAAc;AAC/B,SAAQC,EAAE,QAAO,UAAU;AAC3B,SAAQC,kBAAkB,QAAO,qBAAqB;AACtD,SAAQC,6BAA6B,QAAO,iCAAiC;AAM7E,SAASC,qBAAqBC,YAAoB;IAChD,OAAO,CAAC,WAAW,EAAEA,cAAc;AACrC;AAEA,SAASC,mBAAmBC,QAAgB;IAC1C,OAAO,CAAC,SAAS,EAAEA,UAAU;AAC/B;AAEA,SAASC,wBAAwBC,KAAoC;IACnE,IAAIA,MAAMF,QAAQ,KAAK,WAAW,OAAOH,qBAAqBK,MAAMJ,YAAY;IAChF,OAAOC,mBAAmBG,MAAMF,QAAQ;AAC1C;AAWA,OAAO,eAAeG,gCACpBC,MAA6C;IAE7C,MAAMC,WAAW,MAAMD,OAAOE,EAAE,CAC7BC,MAAM,CAACX,+BACPY,MAAM,CAAC;QACNR,UAAUI,OAAOF,KAAK,CAACF,QAAQ;QAC/BS,YAAYR,wBAAwBG,OAAOF,KAAK;QAChDQ,YAAYN,OAAOF,KAAK,CAACQ,UAAU;IACrC,GACCC,mBAAmB,CAAC;QACnBC,QAAQ;YACNhB,8BAA8BI,QAAQ;YACtCJ,8BAA8Ba,UAAU;YACxCb,8BAA8Bc,UAAU;SACzC;IACH,GACCG,SAAS,CAAC;QAACH,YAAYd,8BAA8Bc,UAAU;IAAA;IAElE,IAAIL,SAASS,MAAM,KAAK,GAAG,OAAO;QAACC,WAAW;IAAK;IAEnD,MAAMxB,iBAAiBa,OAAOE,EAAE,EAAEX,oBAAoB;QACpDqB,MAAM3B;QACN4B,SAASb,OAAOF,KAAK;IACvB;IAEA,OAAO;QAACa,WAAW;IAAI;AACzB;AAeA,qEAAqE;AACrE,4FAA4F;AAC5F,8FAA8F;AAC9F,8FAA8F;AAC9F,sDAAsD;AACtD,OAAO,eAAeG,kBACpBd,MAA+B;IAE/B,MAAMC,WAAW,MAAMD,OAAOE,EAAE,CAC7BC,MAAM,CAACX,+BACPY,MAAM,CAAC;QACNR,UAAUI,OAAOJ,QAAQ;QACzBS,YAAYV,mBAAmBK,OAAOJ,QAAQ;QAC9CU,YAAYN,OAAOM,UAAU;IAC/B,GACCC,mBAAmB,CAAC;QACnBC,QAAQ;YACNhB,8BAA8BI,QAAQ;YACtCJ,8BAA8Ba,UAAU;YACxCb,8BAA8Bc,UAAU;SACzC;IACH,GACCG,SAAS,CAAC;QAACH,YAAYd,8BAA8Bc,UAAU;IAAA;IAElE,IAAIL,SAASS,MAAM,KAAK,GAAG,OAAO;QAACC,WAAW;IAAK;IAEnD,MAAMvB,kBAAwCY,OAAOE,EAAE,EAAEX,oBAAoB;QAC3E;YACEqB,MAAM3B;YACN4B,SAAS;gBACPjB,UAAUI,OAAOJ,QAAQ;gBACzBmB,QAAQf,OAAOe,MAAM;gBACrBjB,OAAO;gBACPkB,aAAahB,OAAOgB,WAAW;gBAC/BtB,cAAcM,OAAON,YAAY;gBACjCuB,gBAAgBjB,OAAOiB,cAAc;gBACrCX,YAAYN,OAAOM,UAAU;gBAC7BY,YAAYlB,OAAOkB,UAAU;gBAC7BL,SAASb,OAAOmB,UAAU;YAC5B;QACF;QACA;YACEP,MAAM1B;YACN2B,SAAS;gBACPjB,UAAUI,OAAOJ,QAAQ;gBACzBoB,aAAahB,OAAOgB,WAAW;gBAC/BtB,cAAcM,OAAON,YAAY;gBACjCY,YAAYN,OAAOM,UAAU;gBAC7BY,YAAYlB,OAAOkB,UAAU;gBAC7BE,MAAMpB,OAAOoB,IAAI;YACnB;QACF;KACD;IAED,OAAO;QAACT,WAAW;IAAI;AACzB;AAWA,4FAA4F;AAC5F,2FAA2F;AAC3F,4FAA4F;AAC5F,iCAAiC;AACjC,OAAO,eAAeU,0BACpBrB,MAAuC;IAEvC,MAAMb,iBAAuCG,MAAMC,oBAAoB;QACrEqB,MAAM1B;QACN2B,SAAS;YACPjB,UAAUI,OAAOJ,QAAQ;YACzBoB,aAAahB,OAAOgB,WAAW;YAC/BtB,cAAcM,OAAON,YAAY;YACjCY,YAAYN,OAAOM,UAAU;YAC7BY,YAAYlB,OAAOkB,UAAU;YAC7BE,MAAMpB,OAAOoB,IAAI;QACnB;IACF;AACF;AAQA,OAAO,eAAeE,qBACpBtB,MAAgC;IAEhC,MAAMC,WAAW,MAAMD,OAAOE,EAAE,CAC7BC,MAAM,CAACX,+BACPY,MAAM,CAAC;QACNR,UAAUI,OAAOJ,QAAQ;QACzBS,YAAYV,mBAAmBK,OAAOJ,QAAQ;QAC9CU,YAAYN,OAAOM,UAAU;IAC/B,GACCC,mBAAmB,CAAC;QACnBC,QAAQ;YACNhB,8BAA8BI,QAAQ;YACtCJ,8BAA8Ba,UAAU;YACxCb,8BAA8Bc,UAAU;SACzC;IACH,GACCG,SAAS,CAAC;QAACH,YAAYd,8BAA8Bc,UAAU;IAAA;IAClE,OAAO;QAACiB,SAAStB,SAASS,MAAM,GAAG;IAAC;AACtC;AAEA,OAAO,eAAec,mBAAmBxB,MAAgC;IACvE,MAAMsB,qBAAqBtB;AAC7B;AAMA,OAAO,eAAeyB,uBACpBzB,MAAoC;IAEpC,MAAM0B,SAAS,MAAMpC,KAClBqC,MAAM,CAACnC,+BACPoC,KAAK,CAACvC,GAAGG,8BAA8B0B,UAAU,EAAElB,OAAO6B,SAAS;IACtE,OAAO;QAACC,SAASJ,OAAOK,QAAQ,IAAI;IAAC;AACvC"}
package/dist/index.d.ts CHANGED
@@ -19,8 +19,8 @@ export type { IntegrationSourceControlService } from '#core/source-control-servi
19
19
  export { createSourceControlIntegrationService } from '#core/source-control-service.js';
20
20
  export type { GetIntegrationConnectionByIdFn } from '#db/connections.js';
21
21
  export { getIntegrationConnectionById } from '#db/connections.js';
22
- export type { PublishIntegrationEventReceivedFn, PublishIntegrationEventReceivedParams, PublishIntegrationEventReceivedResult, PublishSourcePushFn, PublishSourcePushParams, RecordDeliveryOnlyFn, RecordDeliveryOnlyParams, } from '#db/webhook-deliveries.js';
23
- export { pruneWebhookDeliveries } from '#db/webhook-deliveries.js';
22
+ export type { ClaimWebhookDeliveryFn, PublishIntegrationEventReceivedFn, PublishIntegrationEventReceivedParams, PublishIntegrationEventReceivedResult, PublishSourcePushFn, PublishSourcePushParams, RecordDeliveryOnlyFn, RecordDeliveryOnlyParams, } from '#db/webhook-deliveries.js';
23
+ export { claimWebhookDelivery, pruneWebhookDeliveries } from '#db/webhook-deliveries.js';
24
24
  export { integrationRouteErrorHandler } from '#presentation/routes/errors.js';
25
25
  export interface CreateIntegrationsModuleOptions {
26
26
  providers?: IntegrationProvider[] | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -20,7 +20,7 @@ export { ConnectionSlugConflictError, IntegrationCapabilityUnavailableError, Int
20
20
  export { redactCheckoutSpec } from '#core/providers/redact-checkout-spec.js';
21
21
  export { createSourceControlIntegrationService } from '#core/source-control-service.js';
22
22
  export { getIntegrationConnectionById } from '#db/connections.js';
23
- export { pruneWebhookDeliveries } from '#db/webhook-deliveries.js';
23
+ export { claimWebhookDelivery, pruneWebhookDeliveries } from '#db/webhook-deliveries.js';
24
24
  export { integrationRouteErrorHandler } from '#presentation/routes/errors.js';
25
25
  export async function createIntegrationsModule(options = {}) {
26
26
  return (await createIntegrationsContext(options)).module;
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 {integrationsEventSchemas} from '@shipfox/api-integration-core-dto';\nimport type {ShipfoxModule} from '@shipfox/node-module';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport type {IntegrationProvider} from '#core/entities/provider.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 {createIntegrationRoutes, type LeasedAgentStepLoader} from '#presentation/routes/index.js';\nimport {loadEnabledProviderModules} from '#providers/modules.js';\nimport type {IntegrationModuleParts, IntegrationProviderSecrets} 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 {\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} 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 PublishIntegrationEventReceivedFn,\n PublishIntegrationEventReceivedParams,\n PublishIntegrationEventReceivedResult,\n PublishSourcePushFn,\n PublishSourcePushParams,\n RecordDeliveryOnlyFn,\n RecordDeliveryOnlyParams,\n} from '#db/webhook-deliveries.js';\nexport {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 agentTools?:\n | {\n loadLeasedAgentStep: LeasedAgentStepLoader;\n }\n | undefined;\n}\n\nexport interface IntegrationsContext {\n module: ShipfoxModule;\n registry: IntegrationProviderRegistry;\n capabilities: {\n sourceControl: IntegrationSourceControlService;\n };\n sourceControl: IntegrationSourceControlService;\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 parts: IntegrationModuleParts[] =\n options.parts ??\n (options.providers\n ? options.providers.map((provider) => ({provider}))\n : await loadEnabledProviderModules({secrets: options.secrets}));\n\n const registry = createIntegrationProviderRegistry(parts.map((part) => part.provider));\n const sourceControl = createSourceControlIntegrationService({\n registry,\n getIntegrationConnectionById,\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 }\n }\n }\n\n const module: ShipfoxModule = {\n name: 'integrations',\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 loadLeasedAgentStep: options.agentTools.loadLeasedAgentStep,\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 };\n\n return {module, registry, capabilities: {sourceControl}, sourceControl, runStartupTasks};\n}\n"],"names":["dirname","resolve","fileURLToPath","integrationsEventSchemas","logger","createIntegrationProviderRegistry","createSourceControlIntegrationService","getIntegrationConnectionById","db","migrationsPath","integrationsOutbox","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","pruneWebhookDeliveries","integrationRouteErrorHandler","createIntegrationsModule","options","createIntegrationsContext","module","parts","providers","map","provider","secrets","registry","part","sourceControl","runStartupTasks","task","flatMap","startupTasks","error","err","name","database","routes","agentTools","loadLeasedAgentStep","undefined","e2eRoutes","publishers","table","eventSchemas","workers","taskQueue","workflowsPath","activities","workflows","id","cronSchedule","capabilities"],"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 {integrationsEventSchemas} from '@shipfox/api-integration-core-dto';\nimport type {ShipfoxModule} from '@shipfox/node-module';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport type {IntegrationProvider} from '#core/entities/provider.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 {createIntegrationRoutes, type LeasedAgentStepLoader} from '#presentation/routes/index.js';\nimport {loadEnabledProviderModules} from '#providers/modules.js';\nimport type {IntegrationModuleParts, IntegrationProviderSecrets} 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 {\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} 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 agentTools?:\n | {\n loadLeasedAgentStep: LeasedAgentStepLoader;\n }\n | undefined;\n}\n\nexport interface IntegrationsContext {\n module: ShipfoxModule;\n registry: IntegrationProviderRegistry;\n capabilities: {\n sourceControl: IntegrationSourceControlService;\n };\n sourceControl: IntegrationSourceControlService;\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 parts: IntegrationModuleParts[] =\n options.parts ??\n (options.providers\n ? options.providers.map((provider) => ({provider}))\n : await loadEnabledProviderModules({secrets: options.secrets}));\n\n const registry = createIntegrationProviderRegistry(parts.map((part) => part.provider));\n const sourceControl = createSourceControlIntegrationService({\n registry,\n getIntegrationConnectionById,\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 }\n }\n }\n\n const module: ShipfoxModule = {\n name: 'integrations',\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 loadLeasedAgentStep: options.agentTools.loadLeasedAgentStep,\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 };\n\n return {module, registry, capabilities: {sourceControl}, sourceControl, runStartupTasks};\n}\n"],"names":["dirname","resolve","fileURLToPath","integrationsEventSchemas","logger","createIntegrationProviderRegistry","createSourceControlIntegrationService","getIntegrationConnectionById","db","migrationsPath","integrationsOutbox","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","parts","providers","map","provider","secrets","registry","part","sourceControl","runStartupTasks","task","flatMap","startupTasks","error","err","name","database","routes","agentTools","loadLeasedAgentStep","undefined","e2eRoutes","publishers","table","eventSchemas","workers","taskQueue","workflowsPath","activities","workflows","id","cronSchedule","capabilities"],"mappings":"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"}
@@ -16,7 +16,7 @@ export function createIntegrationRoutes(registry, sourceControl, options = {}) {
16
16
  createListIntegrationProvidersRoute(registry),
17
17
  createListIntegrationConnectionsRoute(registry),
18
18
  createUpdateIntegrationConnectionRoute(registry),
19
- createDeleteIntegrationConnectionRoute(),
19
+ createDeleteIntegrationConnectionRoute(registry),
20
20
  createListRepositoriesRoute(sourceControl),
21
21
  ...agentToolsRoutes,
22
22
  ...providerRoutes
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/presentation/routes/index.ts"],"sourcesContent":["import type {RouteExport} from '@shipfox/node-fastify';\nimport type {IntegrationProviderRegistry} from '#core/providers/registry.js';\nimport type {IntegrationSourceControlService} from '#core/source-control-service.js';\nimport type {GetIntegrationConnectionByIdFn} from '#db/connections.js';\nimport {\n createAgentToolsGatewayRoutes,\n type LeasedAgentStepLoader,\n} from './agent-tools-gateway/index.js';\nimport {createListIntegrationConnectionsRoute} from './list-connections.js';\nimport {createListIntegrationProvidersRoute} from './list-providers.js';\nimport {createListRepositoriesRoute} from './list-repositories.js';\nimport {\n createDeleteIntegrationConnectionRoute,\n createUpdateIntegrationConnectionRoute,\n} from './manage-connections.js';\n\nexport type {LeasedAgentStepLoader} from './agent-tools-gateway/index.js';\n\nexport interface CreateIntegrationRoutesOptions {\n agentTools?:\n | {\n loadLeasedAgentStep: LeasedAgentStepLoader;\n getIntegrationConnectionById: GetIntegrationConnectionByIdFn;\n }\n | undefined;\n}\n\nexport function createIntegrationRoutes(\n registry: IntegrationProviderRegistry,\n sourceControl: IntegrationSourceControlService,\n options: CreateIntegrationRoutesOptions = {},\n): RouteExport[] {\n const providerRoutes = registry.list().flatMap((provider) => provider.routes ?? []);\n const agentToolsRoutes = options.agentTools\n ? [\n createAgentToolsGatewayRoutes({\n registry,\n loadLeasedAgentStep: options.agentTools.loadLeasedAgentStep,\n getIntegrationConnectionById: options.agentTools.getIntegrationConnectionById,\n }),\n ]\n : [];\n\n return [\n createListIntegrationProvidersRoute(registry),\n createListIntegrationConnectionsRoute(registry),\n createUpdateIntegrationConnectionRoute(registry),\n createDeleteIntegrationConnectionRoute(),\n createListRepositoriesRoute(sourceControl),\n ...agentToolsRoutes,\n ...providerRoutes,\n ];\n}\n"],"names":["createAgentToolsGatewayRoutes","createListIntegrationConnectionsRoute","createListIntegrationProvidersRoute","createListRepositoriesRoute","createDeleteIntegrationConnectionRoute","createUpdateIntegrationConnectionRoute","createIntegrationRoutes","registry","sourceControl","options","providerRoutes","list","flatMap","provider","routes","agentToolsRoutes","agentTools","loadLeasedAgentStep","getIntegrationConnectionById"],"mappings":"AAIA,SACEA,6BAA6B,QAExB,iCAAiC;AACxC,SAAQC,qCAAqC,QAAO,wBAAwB;AAC5E,SAAQC,mCAAmC,QAAO,sBAAsB;AACxE,SAAQC,2BAA2B,QAAO,yBAAyB;AACnE,SACEC,sCAAsC,EACtCC,sCAAsC,QACjC,0BAA0B;AAajC,OAAO,SAASC,wBACdC,QAAqC,EACrCC,aAA8C,EAC9CC,UAA0C,CAAC,CAAC;IAE5C,MAAMC,iBAAiBH,SAASI,IAAI,GAAGC,OAAO,CAAC,CAACC,WAAaA,SAASC,MAAM,IAAI,EAAE;IAClF,MAAMC,mBAAmBN,QAAQO,UAAU,GACvC;QACEhB,8BAA8B;YAC5BO;YACAU,qBAAqBR,QAAQO,UAAU,CAACC,mBAAmB;YAC3DC,8BAA8BT,QAAQO,UAAU,CAACE,4BAA4B;QAC/E;KACD,GACD,EAAE;IAEN,OAAO;QACLhB,oCAAoCK;QACpCN,sCAAsCM;QACtCF,uCAAuCE;QACvCH;QACAD,4BAA4BK;WACzBO;WACAL;KACJ;AACH"}
1
+ {"version":3,"sources":["../../../src/presentation/routes/index.ts"],"sourcesContent":["import type {RouteExport} from '@shipfox/node-fastify';\nimport type {IntegrationProviderRegistry} from '#core/providers/registry.js';\nimport type {IntegrationSourceControlService} from '#core/source-control-service.js';\nimport type {GetIntegrationConnectionByIdFn} from '#db/connections.js';\nimport {\n createAgentToolsGatewayRoutes,\n type LeasedAgentStepLoader,\n} from './agent-tools-gateway/index.js';\nimport {createListIntegrationConnectionsRoute} from './list-connections.js';\nimport {createListIntegrationProvidersRoute} from './list-providers.js';\nimport {createListRepositoriesRoute} from './list-repositories.js';\nimport {\n createDeleteIntegrationConnectionRoute,\n createUpdateIntegrationConnectionRoute,\n} from './manage-connections.js';\n\nexport type {LeasedAgentStepLoader} from './agent-tools-gateway/index.js';\n\nexport interface CreateIntegrationRoutesOptions {\n agentTools?:\n | {\n loadLeasedAgentStep: LeasedAgentStepLoader;\n getIntegrationConnectionById: GetIntegrationConnectionByIdFn;\n }\n | undefined;\n}\n\nexport function createIntegrationRoutes(\n registry: IntegrationProviderRegistry,\n sourceControl: IntegrationSourceControlService,\n options: CreateIntegrationRoutesOptions = {},\n): RouteExport[] {\n const providerRoutes = registry.list().flatMap((provider) => provider.routes ?? []);\n const agentToolsRoutes = options.agentTools\n ? [\n createAgentToolsGatewayRoutes({\n registry,\n loadLeasedAgentStep: options.agentTools.loadLeasedAgentStep,\n getIntegrationConnectionById: options.agentTools.getIntegrationConnectionById,\n }),\n ]\n : [];\n\n return [\n createListIntegrationProvidersRoute(registry),\n createListIntegrationConnectionsRoute(registry),\n createUpdateIntegrationConnectionRoute(registry),\n createDeleteIntegrationConnectionRoute(registry),\n createListRepositoriesRoute(sourceControl),\n ...agentToolsRoutes,\n ...providerRoutes,\n ];\n}\n"],"names":["createAgentToolsGatewayRoutes","createListIntegrationConnectionsRoute","createListIntegrationProvidersRoute","createListRepositoriesRoute","createDeleteIntegrationConnectionRoute","createUpdateIntegrationConnectionRoute","createIntegrationRoutes","registry","sourceControl","options","providerRoutes","list","flatMap","provider","routes","agentToolsRoutes","agentTools","loadLeasedAgentStep","getIntegrationConnectionById"],"mappings":"AAIA,SACEA,6BAA6B,QAExB,iCAAiC;AACxC,SAAQC,qCAAqC,QAAO,wBAAwB;AAC5E,SAAQC,mCAAmC,QAAO,sBAAsB;AACxE,SAAQC,2BAA2B,QAAO,yBAAyB;AACnE,SACEC,sCAAsC,EACtCC,sCAAsC,QACjC,0BAA0B;AAajC,OAAO,SAASC,wBACdC,QAAqC,EACrCC,aAA8C,EAC9CC,UAA0C,CAAC,CAAC;IAE5C,MAAMC,iBAAiBH,SAASI,IAAI,GAAGC,OAAO,CAAC,CAACC,WAAaA,SAASC,MAAM,IAAI,EAAE;IAClF,MAAMC,mBAAmBN,QAAQO,UAAU,GACvC;QACEhB,8BAA8B;YAC5BO;YACAU,qBAAqBR,QAAQO,UAAU,CAACC,mBAAmB;YAC3DC,8BAA8BT,QAAQO,UAAU,CAACE,4BAA4B;QAC/E;KACD,GACD,EAAE;IAEN,OAAO;QACLhB,oCAAoCK;QACpCN,sCAAsCM;QACtCF,uCAAuCE;QACvCH,uCAAuCG;QACvCJ,4BAA4BK;WACzBO;WACAL;KACJ;AACH"}
@@ -1,4 +1,4 @@
1
1
  import type { IntegrationProviderRegistry } from '#core/providers/registry.js';
2
2
  export declare function createUpdateIntegrationConnectionRoute(registry: IntegrationProviderRegistry): import("@shipfox/node-fastify").RouteDefinition;
3
- export declare function createDeleteIntegrationConnectionRoute(): import("@shipfox/node-fastify").RouteDefinition;
3
+ export declare function createDeleteIntegrationConnectionRoute(registry: IntegrationProviderRegistry): import("@shipfox/node-fastify").RouteDefinition;
4
4
  //# sourceMappingURL=manage-connections.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"manage-connections.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/manage-connections.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAC,2BAA2B,EAAC,MAAM,6BAA6B,CAAC;AAY7E,wBAAgB,sCAAsC,CAAC,QAAQ,EAAE,2BAA2B,mDAgC3F;AAED,wBAAgB,sCAAsC,oDAuBrD"}
1
+ {"version":3,"file":"manage-connections.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/manage-connections.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAC,2BAA2B,EAAC,MAAM,6BAA6B,CAAC;AAa7E,wBAAgB,sCAAsC,CAAC,QAAQ,EAAE,2BAA2B,mDAgC3F;AAED,wBAAgB,sCAAsC,CAAC,QAAQ,EAAE,2BAA2B,mDA8C3F"}
@@ -3,6 +3,7 @@ import { integrationConnectionDtoSchema, updateIntegrationConnectionBodySchema }
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';
6
+ import { db } from '#db/db.js';
6
7
  import { toIntegrationConnectionDto } from '#presentation/dto/integrations.js';
7
8
  const connectionParamsSchema = z.object({
8
9
  connectionId: z.string().uuid()
@@ -47,7 +48,7 @@ export function createUpdateIntegrationConnectionRoute(registry) {
47
48
  }
48
49
  });
49
50
  }
50
- export function createDeleteIntegrationConnectionRoute() {
51
+ export function createDeleteIntegrationConnectionRoute(registry) {
51
52
  return defineRoute({
52
53
  method: 'DELETE',
53
54
  path: '/integration-connections/:connectionId',
@@ -70,9 +71,33 @@ export function createDeleteIntegrationConnectionRoute() {
70
71
  request,
71
72
  workspaceId: connection.workspaceId
72
73
  });
73
- await deleteIntegrationConnection({
74
- id: connection.id
74
+ const provider = registry.list().find((candidate)=>candidate.provider === connection.provider);
75
+ const hasCleanupHooks = provider?.deleteConnectionRecords !== undefined || provider?.deleteConnectionSecrets !== undefined;
76
+ if (!hasCleanupHooks) {
77
+ request.log.warn({
78
+ connectionId: connection.id,
79
+ provider: connection.provider
80
+ }, 'Deleting integration connection without provider cleanup');
81
+ }
82
+ await db().transaction(async (tx)=>{
83
+ await provider?.deleteConnectionRecords?.(connection, {
84
+ tx
85
+ });
86
+ await deleteIntegrationConnection({
87
+ id: connection.id
88
+ }, {
89
+ tx
90
+ });
75
91
  });
92
+ try {
93
+ await provider?.deleteConnectionSecrets?.(connection);
94
+ } catch (error) {
95
+ request.log.error({
96
+ connectionId: connection.id,
97
+ provider: connection.provider,
98
+ err: error
99
+ }, 'Integration connection secret cleanup failed after connection deletion');
100
+ }
76
101
  reply.status(204);
77
102
  }
78
103
  });
@@ -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 {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() {\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 await deleteIntegrationConnection({id: connection.id});\n reply.status(204);\n },\n });\n}\n"],"names":["AUTH_USER","requireWorkspaceAccess","integrationConnectionDtoSchema","updateIntegrationConnectionBodySchema","ClientError","defineRoute","z","deleteIntegrationConnection","getIntegrationConnectionById","updateIntegrationConnectionLifecycleStatus","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"],"mappings":"AAAA,SAAQA,SAAS,EAAEC,sBAAsB,QAAO,4BAA4B;AAC5E,SACEC,8BAA8B,EAC9BC,qCAAqC,QAChC,oCAAoC;AAC3C,SAAQC,WAAW,EAAEC,WAAW,QAAO,wBAAwB;AAC/D,SAAQC,CAAC,QAAO,MAAM;AAEtB,SACEC,2BAA2B,EAC3BC,4BAA4B,EAC5BC,0CAA0C,QACrC,qBAAqB;AAC5B,SAAQC,0BAA0B,QAAO,oCAAoC;AAE7E,MAAMC,yBAAyBL,EAAEM,MAAM,CAAC;IACtCC,cAAcP,EAAEQ,MAAM,GAAGC,IAAI;AAC/B;AAEA,OAAO,SAASC,uCAAuCC,QAAqC;IAC1F,OAAOZ,YAAY;QACjBa,QAAQ;QACRC,MAAM;QACNC,MAAMpB;QACNqB,aAAa;QACbC,QAAQ;YACNC,QAAQZ;YACRa,MAAMrB;YACNsB,UAAU;gBACR,KAAKvB;YACP;QACF;QACAwB,SAAS,OAAOC;YACd,MAAMC,aAAa,MAAMpB,6BAA6BmB,QAAQJ,MAAM,CAACV,YAAY;YACjF,IAAI,CAACe,YAAY;gBACf,MAAM,IAAIxB,YAAY,oCAAoC,aAAa;oBAACyB,QAAQ;gBAAG;YACrF;YAEA5B,uBAAuB;gBAAC0B;gBAASG,aAAaF,WAAWE,WAAW;YAAA;YACpE,MAAMC,UAAU,MAAMtB,2CAA2C;gBAC/DuB,IAAIJ,WAAWI,EAAE;gBACjBC,iBAAiBN,QAAQH,IAAI,CAACU,gBAAgB;YAChD;YACA,IAAI,CAACH,SAAS;gBACZ,MAAM,IAAI3B,YAAY,oCAAoC,aAAa;oBAACyB,QAAQ;gBAAG;YACrF;YAEA,MAAMM,WAAWlB,SAASmB,IAAI,GAAGC,IAAI,CAAC,CAACC,YAAcA,UAAUH,QAAQ,KAAKJ,QAAQI,QAAQ;YAC5F,OAAOzB,2BAA2BqB,SAAS;gBAACQ,cAAcJ,UAAUI,gBAAgB,EAAE;YAAA;QACxF;IACF;AACF;AAEA,OAAO,SAASC;IACd,OAAOnC,YAAY;QACjBa,QAAQ;QACRC,MAAM;QACNC,MAAMpB;QACNqB,aAAa;QACbC,QAAQ;YACNC,QAAQZ;YACRc,UAAU;gBACR,KAAKnB,EAAEmC,IAAI;YACb;QACF;QACAf,SAAS,OAAOC,SAASe;YACvB,MAAMd,aAAa,MAAMpB,6BAA6BmB,QAAQJ,MAAM,CAACV,YAAY;YACjF,IAAI,CAACe,YAAY;gBACf,MAAM,IAAIxB,YAAY,oCAAoC,aAAa;oBAACyB,QAAQ;gBAAG;YACrF;YAEA5B,uBAAuB;gBAAC0B;gBAASG,aAAaF,WAAWE,WAAW;YAAA;YACpE,MAAMvB,4BAA4B;gBAACyB,IAAIJ,WAAWI,EAAE;YAAA;YACpDU,MAAMb,MAAM,CAAC;QACf;IACF;AACF"}
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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"}
@@ -0,0 +1,3 @@
1
+ import type { IntegrationProviderModule } from '#providers/types.js';
2
+ export declare const jiraProviderModule: IntegrationProviderModule;
3
+ //# sourceMappingURL=jira.d.ts.map
@@ -0,0 +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;AA6I3F,eAAO,MAAM,kBAAkB,EAAE,yBAIhC,CAAC"}
@@ -0,0 +1,127 @@
1
+ import { slugifyConnectionSlug } from '@shipfox/api-integration-core-dto';
2
+ import { config } from '#config.js';
3
+ import { deleteIntegrationConnection, getIntegrationConnectionById, resolveUniqueConnectionSlug, updateIntegrationConnectionLifecycleStatus, upsertIntegrationConnection } from '#db/connections.js';
4
+ import { db } from '#db/db.js';
5
+ import { retryConnectionSlugCollision } from '#providers/connection-slug.js';
6
+ const JIRA_MIGRATIONS_TABLE = '__drizzle_migrations_integrations_jira';
7
+ const JIRA_SECRETS_NAMESPACE_PREFIX = 'system/integrations/jira/';
8
+ async function loadJiraModuleParts(options = {}) {
9
+ const { createJiraIntegrationProvider, createJiraPendingSelectionStore, createJiraTokenStore, db: jiraDb, disconnectJiraInstallation: disconnectJiraInstallationRecords, getJiraInstallationByCloudId, migrationsPath, upsertJiraInstallation } = await import('@shipfox/api-integration-jira');
10
+ async function getExistingJiraConnection(input) {
11
+ const installation = await getJiraInstallationByCloudId(input.cloudId);
12
+ if (!installation) return undefined;
13
+ return await getIntegrationConnectionById(installation.connectionId);
14
+ }
15
+ function connectJiraInstallation(input) {
16
+ return retryConnectionSlugCollision(()=>db().transaction(async (tx)=>{
17
+ const slug = await resolveUniqueConnectionSlug({
18
+ workspaceId: input.workspaceId,
19
+ provider: 'jira',
20
+ externalAccountId: input.cloudId,
21
+ baseSlug: slugifyConnectionSlug(`jira_${input.siteName || input.cloudId}`, {
22
+ fallback: 'jira'
23
+ })
24
+ }, {
25
+ tx
26
+ });
27
+ const connection = await upsertIntegrationConnection({
28
+ workspaceId: input.workspaceId,
29
+ provider: 'jira',
30
+ externalAccountId: input.cloudId,
31
+ slug,
32
+ displayName: input.displayName,
33
+ lifecycleStatus: 'active'
34
+ }, {
35
+ tx
36
+ });
37
+ await upsertJiraInstallation({
38
+ connectionId: connection.id,
39
+ cloudId: input.cloudId,
40
+ siteUrl: input.siteUrl,
41
+ siteName: input.siteName,
42
+ authorizingAccountId: input.authorizingAccountId,
43
+ scopes: input.scopes,
44
+ status: 'installed',
45
+ tokenExpiresAt: input.tokenExpiresAt
46
+ }, {
47
+ tx
48
+ });
49
+ return connection;
50
+ }));
51
+ }
52
+ async function disconnectJiraInstallation(input) {
53
+ await disconnectJiraInstallationRecords({
54
+ connectionId: input.connectionId,
55
+ getConnection: getIntegrationConnectionById,
56
+ deleteSecrets: (params)=>options.secrets?.jira?.deleteSecrets({
57
+ ...params,
58
+ namespace: jiraNamespaceSuffix(params.namespace)
59
+ }) ?? Promise.resolve(0),
60
+ transaction: (fn)=>db().transaction((tx)=>fn(tx)),
61
+ deleteConnection: (params, transactionOptions)=>deleteIntegrationConnection({
62
+ id: params.connectionId
63
+ }, transactionOptions)
64
+ });
65
+ }
66
+ const fallbackSecrets = {
67
+ getSecret: ()=>Promise.resolve(null),
68
+ setSecrets: ()=>Promise.reject(new Error('Jira token storage is not configured')),
69
+ deleteSecrets: ()=>Promise.resolve(0)
70
+ };
71
+ const secrets = options.secrets?.jira ? {
72
+ getSecret: (params)=>options.secrets?.jira?.getSecret({
73
+ ...params,
74
+ namespace: jiraNamespaceSuffix(params.namespace)
75
+ }) ?? Promise.resolve(null),
76
+ setSecrets: (params)=>options.secrets?.jira?.setSecrets({
77
+ ...params,
78
+ namespace: jiraNamespaceSuffix(params.namespace)
79
+ }) ?? Promise.resolve(),
80
+ deleteSecrets: (params)=>options.secrets?.jira?.deleteSecrets({
81
+ ...params,
82
+ namespace: jiraNamespaceSuffix(params.namespace)
83
+ }) ?? Promise.resolve(0)
84
+ } : fallbackSecrets;
85
+ const tokenStore = createJiraTokenStore({
86
+ resolveConnection: getIntegrationConnectionById,
87
+ secrets,
88
+ markConnectionError: async ({ connectionId })=>{
89
+ await updateIntegrationConnectionLifecycleStatus({
90
+ id: connectionId,
91
+ lifecycleStatus: 'error'
92
+ });
93
+ }
94
+ });
95
+ const pendingStore = createJiraPendingSelectionStore({
96
+ secrets
97
+ });
98
+ return {
99
+ provider: createJiraIntegrationProvider({
100
+ routes: {
101
+ tokenStore,
102
+ pendingStore,
103
+ getExistingJiraConnection,
104
+ connectJiraInstallation,
105
+ disconnectJiraInstallation
106
+ }
107
+ }),
108
+ database: {
109
+ db: jiraDb,
110
+ migrationsPath,
111
+ migrationsTableName: JIRA_MIGRATIONS_TABLE
112
+ }
113
+ };
114
+ }
115
+ export const jiraProviderModule = {
116
+ id: 'jira',
117
+ enabled: config.INTEGRATIONS_ENABLE_JIRA_PROVIDER,
118
+ load: loadJiraModuleParts
119
+ };
120
+ function jiraNamespaceSuffix(namespace) {
121
+ if (!namespace.startsWith(JIRA_SECRETS_NAMESPACE_PREFIX)) {
122
+ throw new Error('Jira provider attempted to access an unscoped secret namespace');
123
+ }
124
+ return namespace.slice(JIRA_SECRETS_NAMESPACE_PREFIX.length);
125
+ }
126
+
127
+ //# sourceMappingURL=jira.js.map