@shipfox/api-integration-core 4.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.
- package/.turbo/turbo-build.log +4 -4
- package/CHANGELOG.md +35 -0
- package/dist/db/webhook-deliveries.d.ts +4 -0
- package/dist/db/webhook-deliveries.d.ts.map +1 -1
- package/dist/db/webhook-deliveries.js +10 -2
- package/dist/db/webhook-deliveries.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/presentation/routes/index.js +1 -1
- package/dist/presentation/routes/index.js.map +1 -1
- package/dist/presentation/routes/manage-connections.d.ts +1 -1
- package/dist/presentation/routes/manage-connections.d.ts.map +1 -1
- package/dist/presentation/routes/manage-connections.js +28 -3
- package/dist/presentation/routes/manage-connections.js.map +1 -1
- package/dist/providers/jira.d.ts.map +1 -1
- package/dist/providers/jira.js +110 -3
- package/dist/providers/jira.js.map +1 -1
- package/dist/providers/linear.d.ts.map +1 -1
- package/dist/providers/linear.js +15 -1
- package/dist/providers/linear.js.map +1 -1
- package/dist/providers/slack.d.ts.map +1 -1
- package/dist/providers/slack.js +17 -2
- package/dist/providers/slack.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +28 -38
- package/src/db/webhook-deliveries.test.ts +11 -0
- package/src/db/webhook-deliveries.ts +12 -3
- package/src/index.ts +2 -1
- package/src/presentation/routes/index.ts +1 -1
- package/src/presentation/routes/manage-connections.test.ts +113 -0
- package/src/presentation/routes/manage-connections.ts +26 -2
- package/src/providers/jira.ts +152 -7
- package/src/providers/linear.test.ts +136 -0
- package/src/providers/linear.ts +14 -0
- package/src/providers/slack.test.ts +139 -0
- package/src/providers/slack.ts +20 -1
- package/tsconfig.build.tsbuildinfo +1 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
$ shipfox-swc && shipfox-temporal-bundle dist/temporal/workflows/index.js
|
|
2
|
-
Successfully compiled: 49 files with swc (
|
|
3
|
-
2026-07-
|
|
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
|
|
19
|
-
2026-07-
|
|
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,40 @@
|
|
|
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
|
+
|
|
3
38
|
## 4.0.0
|
|
4
39
|
|
|
5
40
|
### Minor Changes
|
|
@@ -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,
|
|
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
|
|
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":"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"}
|
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;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,sBAAsB,CAAC;AAExD,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAEL,KAAK,2BAA2B,EACjC,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAEL,KAAK,+BAA+B,EACrC,MAAM,iCAAiC,CAAC;AAKzC,OAAO,EAA0B,KAAK,qBAAqB,EAAC,MAAM,+BAA+B,CAAC;AAElG,OAAO,KAAK,EAAC,sBAAsB,EAAE,0BAA0B,EAAC,MAAM,qBAAqB,CAAC;AAO5F,OAAO,EACL,yBAAyB,EACzB,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,mCAAmC,CAAC;AAC3C,YAAY,EACV,iBAAiB,EACjB,0BAA0B,EAC1B,+BAA+B,EAC/B,2BAA2B,EAC3B,gCAAgC,GACjC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,sBAAsB,EACtB,+BAA+B,EAC/B,uCAAuC,GACxC,MAAM,+BAA+B,CAAC;AACvC,YAAY,EACV,qBAAqB,EACrB,oCAAoC,GACrC,MAAM,8BAA8B,CAAC;AACtC,YAAY,EACV,qBAAqB,EACrB,mBAAmB,EACnB,2BAA2B,EAC3B,uBAAuB,EACvB,6BAA6B,GAC9B,MAAM,4BAA4B,CAAC;AACpC,YAAY,EAAC,8BAA8B,EAAC,MAAM,iBAAiB,CAAC;AACpE,OAAO,EACL,2BAA2B,EAC3B,qCAAqC,EACrC,mCAAmC,EACnC,kCAAkC,EAClC,kCAAkC,EAClC,2CAA2C,EAC3C,wBAAwB,EACxB,mCAAmC,GACpC,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,kBAAkB,EAClB,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,kBAAkB,EAClB,0BAA0B,GAC3B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAC,kBAAkB,EAAC,MAAM,yCAAyC,CAAC;AAC3E,YAAY,EAAC,2BAA2B,EAAC,MAAM,6BAA6B,CAAC;AAC7E,YAAY,EACV,mBAAmB,EACnB,mBAAmB,EACnB,YAAY,EACZ,uBAAuB,EACvB,cAAc,EACd,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,qBAAqB,EACrB,cAAc,EACd,kBAAkB,EAClB,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,mCAAmC,CAAC;AAC3C,YAAY,EAAC,+BAA+B,EAAC,MAAM,iCAAiC,CAAC;AACrF,OAAO,EAAC,qCAAqC,EAAC,MAAM,iCAAiC,CAAC;AACtF,YAAY,EAAC,8BAA8B,EAAC,MAAM,oBAAoB,CAAC;AACvE,OAAO,EAAC,4BAA4B,EAAC,MAAM,oBAAoB,CAAC;AAChE,YAAY,EACV,iCAAiC,EACjC,qCAAqC,EACrC,qCAAqC,EACrC,mBAAmB,EACnB,uBAAuB,EACvB,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAC,sBAAsB,EAAC,MAAM,2BAA2B,CAAC;
|
|
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":"AAAA,SAAQA,OAAO,EAAEC,OAAO,QAAO,YAAY;AAC3C,SAAQC,aAAa,QAAO,WAAW;AACvC,SAAQC,wBAAwB,QAAO,oCAAoC;AAE3E,SAAQC,MAAM,QAAO,8BAA8B;AAEnD,SACEC,iCAAiC,QAE5B,8BAA8B;AACrC,SACEC,qCAAqC,QAEhC,kCAAkC;AACzC,SAAQC,4BAA4B,QAAO,qBAAqB;AAChE,SAAQC,EAAE,QAAO,YAAY;AAC7B,SAAQC,cAAc,QAAO,oBAAoB;AACjD,SAAQC,kBAAkB,QAAO,uBAAuB;AACxD,SAAQC,uBAAuB,QAAmC,gCAAgC;AAClG,SAAQC,0BAA0B,QAAO,wBAAwB;AAEjE,SAAQC,uCAAuC,QAAO,gCAAgC;AACtF,SAAQC,mCAAmC,QAAO,yBAAyB;AAE3E,MAAMC,cAAcd,QAAQD,QAAQE,cAAc,YAAYc,GAAG,IAAI;AACrE,MAAMC,2BAA2BhB,QAAQc,aAAa;AAEtD,SACEG,yBAAyB,EACzBC,yBAAyB,EACzBC,yBAAyB,QACpB,oCAAoC;AAQ3C,SACEC,sBAAsB,EACtBC,+BAA+B,EAC/BC,uCAAuC,QAClC,gCAAgC;AAavC,SACEC,2BAA2B,EAC3BC,qCAAqC,EACrCC,mCAAmC,EACnCC,kCAAkC,EAClCC,kCAAkC,EAClCC,2CAA2C,EAC3CC,wBAAwB,EACxBC,mCAAmC,QAC9B,kBAAkB;AAWzB,SAAQC,kBAAkB,QAAO,0CAA0C;AAoB3E,SAAQ1B,qCAAqC,QAAO,kCAAkC;AAEtF,SAAQC,4BAA4B,QAAO,qBAAqB;AAWhE,SAAQ0B,oBAAoB,EAAEC,sBAAsB,QAAO,4BAA4B;AACvF,SAAQC,4BAA4B,QAAO,iCAAiC;AAiC5E,OAAO,eAAeC,yBACpBC,UAA2C,CAAC,CAAC;IAE7C,OAAO,AAAC,CAAA,MAAMC,0BAA0BD,QAAO,EAAGE,MAAM;AAC1D;AAEA,OAAO,eAAeD,0BACpBD,UAA2C,CAAC,CAAC;IAE7C,MAAMG,QACJH,QAAQG,KAAK,IACZH,CAAAA,QAAQI,SAAS,GACdJ,QAAQI,SAAS,CAACC,GAAG,CAAC,CAACC,WAAc,CAAA;YAACA;QAAQ,CAAA,KAC9C,MAAM/B,2BAA2B;QAACgC,SAASP,QAAQO,OAAO;IAAA,EAAC;IAEjE,MAAMC,WAAWxC,kCAAkCmC,MAAME,GAAG,CAAC,CAACI,OAASA,KAAKH,QAAQ;IACpF,MAAMI,gBAAgBzC,sCAAsC;QAC1DuC;QACAtC;IACF;IAEA,eAAeyC;QACb,KAAK,MAAMC,QAAQT,MAAMU,OAAO,CAAC,CAACJ,OAASA,KAAKK,YAAY,IAAI,EAAE,EAAG;YACnE,mDAAmD;YACnD,IAAI;gBACF,MAAMF;YACR,EAAE,OAAOG,OAAO;gBACdhD,SAASgD,KAAK,CAAC;oBAACC,KAAKD;gBAAK,GAAG;YAC/B;QACF;IACF;IAEA,MAAMb,SAAwB;QAC5Be,MAAM;QACNH,cAAcH;QACdO,UAAU;YACR;gBAAC/C;gBAAIC;YAAc;eAChB+B,MAAMU,OAAO,CAAC,CAACJ,OAAUA,KAAKS,QAAQ,GAAG;oBAACT,KAAKS,QAAQ;iBAAC,GAAG,EAAE;SACjE;QACDC,QAAQ7C,wBAAwBkC,UAAUE,eAAe;YACvDU,YAAYpB,QAAQoB,UAAU,GAC1B;gBACEC,qBAAqBrB,QAAQoB,UAAU,CAACC,mBAAmB;gBAC3DnD;YACF,IACAoD;QACN;QACAC,WAAWpB,MAAMU,OAAO,CAAC,CAACJ,OAASA,KAAKc,SAAS,IAAI,EAAE;QACvDC,YAAY;YACV;gBAACP,MAAM;gBAAgBQ,OAAOpD;gBAAoBF;gBAAIuD,cAAc5D;YAAwB;SAC7F;QACD6D,SAAS;YACP;gBACEC,WAAWnD;gBACXoD,eAAejD;gBACfkD,YAAYtD;gBACZuD,WAAW;oBACT;wBACEd,MAAM;wBACNe,IAAI;wBACJC,cAAc;oBAChB;iBACD;YACH;eACG9B,MAAMU,OAAO,CAAC,CAACJ,OAASA,KAAKkB,OAAO,IAAI,EAAE;SAC9C;IACH;IAEA,OAAO;QAACzB;QAAQM;QAAU0B,cAAc;YAACxB;QAAa;QAAGA;QAAeC;IAAe;AACzF"}
|
|
@@ -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;
|
|
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;
|
|
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
|
-
|
|
74
|
-
|
|
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,
|
|
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":"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,EAAE,QAAO,YAAY;AAC7B,SAAQC,0BAA0B,QAAO,oCAAoC;AAE7E,MAAMC,yBAAyBN,EAAEO,MAAM,CAAC;IACtCC,cAAcR,EAAES,MAAM,GAAGC,IAAI;AAC/B;AAEA,OAAO,SAASC,uCAAuCC,QAAqC;IAC1F,OAAOb,YAAY;QACjBc,QAAQ;QACRC,MAAM;QACNC,MAAMrB;QACNsB,aAAa;QACbC,QAAQ;YACNC,QAAQZ;YACRa,MAAMtB;YACNuB,UAAU;gBACR,KAAKxB;YACP;QACF;QACAyB,SAAS,OAAOC;YACd,MAAMC,aAAa,MAAMrB,6BAA6BoB,QAAQJ,MAAM,CAACV,YAAY;YACjF,IAAI,CAACe,YAAY;gBACf,MAAM,IAAIzB,YAAY,oCAAoC,aAAa;oBAAC0B,QAAQ;gBAAG;YACrF;YAEA7B,uBAAuB;gBAAC2B;gBAASG,aAAaF,WAAWE,WAAW;YAAA;YACpE,MAAMC,UAAU,MAAMvB,2CAA2C;gBAC/DwB,IAAIJ,WAAWI,EAAE;gBACjBC,iBAAiBN,QAAQH,IAAI,CAACU,gBAAgB;YAChD;YACA,IAAI,CAACH,SAAS;gBACZ,MAAM,IAAI5B,YAAY,oCAAoC,aAAa;oBAAC0B,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,uCAAuCvB,QAAqC;IAC1F,OAAOb,YAAY;QACjBc,QAAQ;QACRC,MAAM;QACNC,MAAMrB;QACNsB,aAAa;QACbC,QAAQ;YACNC,QAAQZ;YACRc,UAAU;gBACR,KAAKpB,EAAEoC,IAAI;YACb;QACF;QACAf,SAAS,OAAOC,SAASe;YACvB,MAAMd,aAAa,MAAMrB,6BAA6BoB,QAAQJ,MAAM,CAACV,YAAY;YACjF,IAAI,CAACe,YAAY;gBACf,MAAM,IAAIzB,YAAY,oCAAoC,aAAa;oBAAC0B,QAAQ;gBAAG;YACrF;YAEA7B,uBAAuB;gBAAC2B;gBAASG,aAAaF,WAAWE,WAAW;YAAA;YACpE,MAAMK,WAAWlB,SACdmB,IAAI,GACJC,IAAI,CAAC,CAACC,YAAcA,UAAUH,QAAQ,KAAKP,WAAWO,QAAQ;YACjE,MAAMQ,kBACJR,UAAUS,4BAA4BC,aACtCV,UAAUW,4BAA4BD;YACxC,IAAI,CAACF,iBAAiB;gBACpBhB,QAAQoB,GAAG,CAACC,IAAI,CACd;oBAACnC,cAAce,WAAWI,EAAE;oBAAEG,UAAUP,WAAWO,QAAQ;gBAAA,GAC3D;YAEJ;YACA,MAAM1B,KAAKwC,WAAW,CAAC,OAAOC;gBAC5B,MAAMf,UAAUS,0BAA0BhB,YAAY;oBAACsB;gBAAE;gBACzD,MAAM5C,4BAA4B;oBAAC0B,IAAIJ,WAAWI,EAAE;gBAAA,GAAG;oBAACkB;gBAAE;YAC5D;YACA,IAAI;gBACF,MAAMf,UAAUW,0BAA0BlB;YAC5C,EAAE,OAAOuB,OAAO;gBACdxB,QAAQoB,GAAG,CAACI,KAAK,CACf;oBAACtC,cAAce,WAAWI,EAAE;oBAAEG,UAAUP,WAAWO,QAAQ;oBAAEiB,KAAKD;gBAAK,GACvE;YAEJ;YACAT,MAAMb,MAAM,CAAC;QACf;IACF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jira.d.ts","sourceRoot":"","sources":["../../src/providers/jira.ts"],"names":[],"mappings":"
|
|
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"}
|
package/dist/providers/jira.js
CHANGED
|
@@ -1,9 +1,110 @@
|
|
|
1
|
+
import { slugifyConnectionSlug } from '@shipfox/api-integration-core-dto';
|
|
1
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';
|
|
2
6
|
const JIRA_MIGRATIONS_TABLE = '__drizzle_migrations_integrations_jira';
|
|
3
|
-
|
|
4
|
-
|
|
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
|
+
});
|
|
5
98
|
return {
|
|
6
|
-
provider: createJiraIntegrationProvider(
|
|
99
|
+
provider: createJiraIntegrationProvider({
|
|
100
|
+
routes: {
|
|
101
|
+
tokenStore,
|
|
102
|
+
pendingStore,
|
|
103
|
+
getExistingJiraConnection,
|
|
104
|
+
connectJiraInstallation,
|
|
105
|
+
disconnectJiraInstallation
|
|
106
|
+
}
|
|
107
|
+
}),
|
|
7
108
|
database: {
|
|
8
109
|
db: jiraDb,
|
|
9
110
|
migrationsPath,
|
|
@@ -16,5 +117,11 @@ export const jiraProviderModule = {
|
|
|
16
117
|
enabled: config.INTEGRATIONS_ENABLE_JIRA_PROVIDER,
|
|
17
118
|
load: loadJiraModuleParts
|
|
18
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
|
+
}
|
|
19
126
|
|
|
20
127
|
//# sourceMappingURL=jira.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/providers/jira.ts"],"sourcesContent":["import {config} from '#config.js';\nimport type {IntegrationModuleParts, IntegrationProviderModule} from '#providers/types.js';\n\nconst JIRA_MIGRATIONS_TABLE = '__drizzle_migrations_integrations_jira';\n\nasync function loadJiraModuleParts(): Promise<IntegrationModuleParts> {\n const {\n createJiraIntegrationProvider,\n db: jiraDb,\n migrationsPath,\n } = await import('@shipfox/api-integration-jira');\n\n return {\n provider: createJiraIntegrationProvider(),\n database: {\n db: jiraDb,\n migrationsPath,\n migrationsTableName: JIRA_MIGRATIONS_TABLE,\n },\n };\n}\n\nexport const jiraProviderModule: IntegrationProviderModule = {\n id: 'jira',\n enabled: config.INTEGRATIONS_ENABLE_JIRA_PROVIDER,\n load: loadJiraModuleParts,\n};\n"],"names":["config","JIRA_MIGRATIONS_TABLE","loadJiraModuleParts","createJiraIntegrationProvider","db","jiraDb","migrationsPath","provider","database","migrationsTableName","jiraProviderModule","id","enabled","INTEGRATIONS_ENABLE_JIRA_PROVIDER","load"],"mappings":"AAAA,SAAQA,MAAM,QAAO,aAAa;AAGlC,MAAMC,wBAAwB;AAE9B,eAAeC;IACb,MAAM,EACJC,6BAA6B,EAC7BC,IAAIC,MAAM,EACVC,cAAc,EACf,GAAG,MAAM,MAAM,CAAC;IAEjB,OAAO;QACLC,UAAUJ;QACVK,UAAU;YACRJ,IAAIC;YACJC;YACAG,qBAAqBR;QACvB;IACF;AACF;AAEA,OAAO,MAAMS,qBAAgD;IAC3DC,IAAI;IACJC,SAASZ,OAAOa,iCAAiC;IACjDC,MAAMZ;AACR,EAAE"}
|
|
1
|
+
{"version":3,"sources":["../../src/providers/jira.ts"],"sourcesContent":["import {\n type IntegrationConnection as CoreIntegrationConnection,\n slugifyConnectionSlug,\n} from '@shipfox/api-integration-core-dto';\nimport type {\n ConnectJiraInstallationInput,\n JiraPendingSelectionSecretsStore,\n JiraSecretsStore,\n} from '@shipfox/api-integration-jira';\nimport {config} from '#config.js';\nimport {\n deleteIntegrationConnection,\n getIntegrationConnectionById,\n resolveUniqueConnectionSlug,\n updateIntegrationConnectionLifecycleStatus,\n upsertIntegrationConnection,\n} from '#db/connections.js';\nimport {db} from '#db/db.js';\nimport {retryConnectionSlugCollision} from '#providers/connection-slug.js';\nimport type {IntegrationModuleParts, IntegrationProviderModule} from '#providers/types.js';\n\nconst JIRA_MIGRATIONS_TABLE = '__drizzle_migrations_integrations_jira';\nconst JIRA_SECRETS_NAMESPACE_PREFIX = 'system/integrations/jira/';\ntype IntegrationDb = ReturnType<typeof db>;\ntype IntegrationTx = Parameters<Parameters<IntegrationDb['transaction']>[0]>[0];\n\nasync function loadJiraModuleParts(\n options: Parameters<IntegrationProviderModule['load']>[0] = {},\n): Promise<IntegrationModuleParts> {\n const {\n createJiraIntegrationProvider,\n createJiraPendingSelectionStore,\n createJiraTokenStore,\n db: jiraDb,\n disconnectJiraInstallation: disconnectJiraInstallationRecords,\n getJiraInstallationByCloudId,\n migrationsPath,\n upsertJiraInstallation,\n } = await import('@shipfox/api-integration-jira');\n\n async function getExistingJiraConnection(input: {\n cloudId: string;\n }): Promise<CoreIntegrationConnection<'jira'> | undefined> {\n const installation = await getJiraInstallationByCloudId(input.cloudId);\n if (!installation) return undefined;\n return (await getIntegrationConnectionById(installation.connectionId)) as\n | CoreIntegrationConnection<'jira'>\n | undefined;\n }\n\n function connectJiraInstallation(\n input: ConnectJiraInstallationInput,\n ): Promise<CoreIntegrationConnection<'jira'>> {\n return retryConnectionSlugCollision(() =>\n db().transaction(async (tx) => {\n const slug = await resolveUniqueConnectionSlug(\n {\n workspaceId: input.workspaceId,\n provider: 'jira',\n externalAccountId: input.cloudId,\n baseSlug: slugifyConnectionSlug(`jira_${input.siteName || input.cloudId}`, {\n fallback: 'jira',\n }),\n },\n {tx},\n );\n const connection = await upsertIntegrationConnection(\n {\n workspaceId: input.workspaceId,\n provider: 'jira',\n externalAccountId: input.cloudId,\n slug,\n displayName: input.displayName,\n lifecycleStatus: 'active',\n },\n {tx},\n );\n await upsertJiraInstallation(\n {\n connectionId: connection.id,\n cloudId: input.cloudId,\n siteUrl: input.siteUrl,\n siteName: input.siteName,\n authorizingAccountId: input.authorizingAccountId,\n scopes: input.scopes,\n status: 'installed',\n tokenExpiresAt: input.tokenExpiresAt,\n },\n {tx},\n );\n return connection as CoreIntegrationConnection<'jira'>;\n }),\n );\n }\n\n async function disconnectJiraInstallation(input: {connectionId: string}): Promise<void> {\n await disconnectJiraInstallationRecords<IntegrationTx>({\n connectionId: input.connectionId,\n getConnection: getIntegrationConnectionById,\n deleteSecrets: (params) =>\n options.secrets?.jira?.deleteSecrets({\n ...params,\n namespace: jiraNamespaceSuffix(params.namespace),\n }) ?? Promise.resolve(0),\n transaction: (fn) => db().transaction((tx) => fn(tx)),\n deleteConnection: (params, transactionOptions) =>\n deleteIntegrationConnection({id: params.connectionId}, transactionOptions),\n });\n }\n\n const fallbackSecrets: JiraSecretsStore & JiraPendingSelectionSecretsStore = {\n getSecret: () => Promise.resolve(null),\n setSecrets: () => Promise.reject(new Error('Jira token storage is not configured')),\n deleteSecrets: () => Promise.resolve(0),\n };\n const secrets: JiraSecretsStore & JiraPendingSelectionSecretsStore = options.secrets?.jira\n ? {\n getSecret: (params) =>\n options.secrets?.jira?.getSecret({\n ...params,\n namespace: jiraNamespaceSuffix(params.namespace),\n }) ?? Promise.resolve(null),\n setSecrets: (params) =>\n options.secrets?.jira?.setSecrets({\n ...params,\n namespace: jiraNamespaceSuffix(params.namespace),\n }) ?? Promise.resolve(),\n deleteSecrets: (params) =>\n options.secrets?.jira?.deleteSecrets({\n ...params,\n namespace: jiraNamespaceSuffix(params.namespace),\n }) ?? Promise.resolve(0),\n }\n : fallbackSecrets;\n const tokenStore = createJiraTokenStore({\n resolveConnection: getIntegrationConnectionById,\n secrets,\n markConnectionError: async ({connectionId}) => {\n await updateIntegrationConnectionLifecycleStatus({\n id: connectionId,\n lifecycleStatus: 'error',\n });\n },\n });\n const pendingStore = createJiraPendingSelectionStore({secrets});\n\n return {\n provider: createJiraIntegrationProvider({\n routes: {\n tokenStore,\n pendingStore,\n getExistingJiraConnection,\n connectJiraInstallation,\n disconnectJiraInstallation,\n },\n }),\n database: {db: jiraDb, migrationsPath, migrationsTableName: JIRA_MIGRATIONS_TABLE},\n };\n}\n\nexport const jiraProviderModule: IntegrationProviderModule = {\n id: 'jira',\n enabled: config.INTEGRATIONS_ENABLE_JIRA_PROVIDER,\n load: loadJiraModuleParts,\n};\n\nfunction jiraNamespaceSuffix(namespace: string): string {\n if (!namespace.startsWith(JIRA_SECRETS_NAMESPACE_PREFIX)) {\n throw new Error('Jira provider attempted to access an unscoped secret namespace');\n }\n return namespace.slice(JIRA_SECRETS_NAMESPACE_PREFIX.length);\n}\n"],"names":["slugifyConnectionSlug","config","deleteIntegrationConnection","getIntegrationConnectionById","resolveUniqueConnectionSlug","updateIntegrationConnectionLifecycleStatus","upsertIntegrationConnection","db","retryConnectionSlugCollision","JIRA_MIGRATIONS_TABLE","JIRA_SECRETS_NAMESPACE_PREFIX","loadJiraModuleParts","options","createJiraIntegrationProvider","createJiraPendingSelectionStore","createJiraTokenStore","jiraDb","disconnectJiraInstallation","disconnectJiraInstallationRecords","getJiraInstallationByCloudId","migrationsPath","upsertJiraInstallation","getExistingJiraConnection","input","installation","cloudId","undefined","connectionId","connectJiraInstallation","transaction","tx","slug","workspaceId","provider","externalAccountId","baseSlug","siteName","fallback","connection","displayName","lifecycleStatus","id","siteUrl","authorizingAccountId","scopes","status","tokenExpiresAt","getConnection","deleteSecrets","params","secrets","jira","namespace","jiraNamespaceSuffix","Promise","resolve","fn","deleteConnection","transactionOptions","fallbackSecrets","getSecret","setSecrets","reject","Error","tokenStore","resolveConnection","markConnectionError","pendingStore","routes","database","migrationsTableName","jiraProviderModule","enabled","INTEGRATIONS_ENABLE_JIRA_PROVIDER","load","startsWith","slice","length"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"linear.d.ts","sourceRoot":"","sources":["../../src/providers/linear.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAyB,yBAAyB,EAAC,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"linear.d.ts","sourceRoot":"","sources":["../../src/providers/linear.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAyB,yBAAyB,EAAC,MAAM,qBAAqB,CAAC;AAmK3F,eAAO,MAAM,oBAAoB,EAAE,yBAIlC,CAAC"}
|
package/dist/providers/linear.js
CHANGED
|
@@ -7,7 +7,7 @@ import { retryConnectionSlugCollision } from '#providers/connection-slug.js';
|
|
|
7
7
|
const LINEAR_MIGRATIONS_TABLE = '__drizzle_migrations_integrations_linear';
|
|
8
8
|
const LINEAR_SECRETS_NAMESPACE_PREFIX = 'system/integrations/linear/';
|
|
9
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');
|
|
10
|
+
const { createLinearTokenStore, createLinearE2eRoutes, createLinearIntegrationProvider, config: linearConfig, deleteLinearInstallationByConnectionId, disconnectLinearInstallation: disconnectLinearInstallationRecords, getLinearInstallationByOrganizationId, db: linearDb, linearSecretsNamespace, migrationsPath: linearMigrationsPath, upsertLinearInstallation } = await import('@shipfox/api-integration-linear');
|
|
11
11
|
async function getExistingLinearConnection(input) {
|
|
12
12
|
const installation = await getLinearInstallationByOrganizationId(input.organizationId);
|
|
13
13
|
if (!installation) return undefined;
|
|
@@ -90,6 +90,20 @@ async function loadLinearModuleParts(options = {}) {
|
|
|
90
90
|
tokenStore,
|
|
91
91
|
endpoint: linearConfig.LINEAR_MCP_ENDPOINT
|
|
92
92
|
},
|
|
93
|
+
cleanup: {
|
|
94
|
+
deleteConnectionRecords: async (connection, { tx })=>{
|
|
95
|
+
await deleteLinearInstallationByConnectionId(connection.id, {
|
|
96
|
+
tx
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
deleteConnectionSecrets: async (connection)=>{
|
|
100
|
+
// Scoped secrets accept the provider-local suffix, after this helper validates its prefix.
|
|
101
|
+
await (options.secrets?.linear?.deleteSecrets({
|
|
102
|
+
workspaceId: connection.workspaceId,
|
|
103
|
+
namespace: linearNamespaceSuffix(linearSecretsNamespace(connection.id))
|
|
104
|
+
}) ?? Promise.resolve());
|
|
105
|
+
}
|
|
106
|
+
},
|
|
93
107
|
routes: {
|
|
94
108
|
tokenStore,
|
|
95
109
|
getExistingLinearConnection,
|