@shipfox/api-integration-core 4.0.0 → 6.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 +100 -0
- package/dist/core/entities/provider.d.ts +7 -2
- package/dist/core/entities/provider.d.ts.map +1 -1
- package/dist/core/entities/provider.js.map +1 -1
- package/dist/core/errors.d.ts +7 -0
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +8 -2
- package/dist/core/errors.js.map +1 -1
- 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 +19 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +51 -6
- package/dist/index.js.map +1 -1
- package/dist/presentation/inter-module.d.ts +9 -0
- package/dist/presentation/inter-module.d.ts.map +1 -0
- package/dist/presentation/inter-module.js +121 -0
- package/dist/presentation/inter-module.js.map +1 -0
- package/dist/presentation/routes/agent-tools-gateway/index.d.ts +1 -0
- package/dist/presentation/routes/agent-tools-gateway/index.d.ts.map +1 -1
- package/dist/presentation/routes/agent-tools-gateway/index.js +1 -0
- package/dist/presentation/routes/agent-tools-gateway/index.js.map +1 -1
- package/dist/presentation/routes/agent-tools-gateway/resolve-authorized-tools.d.ts +5 -2
- package/dist/presentation/routes/agent-tools-gateway/resolve-authorized-tools.d.ts.map +1 -1
- package/dist/presentation/routes/agent-tools-gateway/resolve-authorized-tools.js +53 -17
- package/dist/presentation/routes/agent-tools-gateway/resolve-authorized-tools.js.map +1 -1
- package/dist/presentation/routes/index.d.ts +2 -3
- package/dist/presentation/routes/index.d.ts.map +1 -1
- package/dist/presentation/routes/index.js +3 -3
- 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/gitea.d.ts.map +1 -1
- package/dist/providers/gitea.js +10 -8
- package/dist/providers/gitea.js.map +1 -1
- package/dist/providers/github.d.ts.map +1 -1
- package/dist/providers/github.js +18 -13
- package/dist/providers/github.js.map +1 -1
- package/dist/providers/jira.d.ts.map +1 -1
- package/dist/providers/jira.js +113 -3
- package/dist/providers/jira.js.map +1 -1
- package/dist/providers/linear.d.ts.map +1 -1
- package/dist/providers/linear.js +35 -16
- package/dist/providers/linear.js.map +1 -1
- package/dist/providers/sentry.d.ts.map +1 -1
- package/dist/providers/sentry.js +13 -11
- package/dist/providers/sentry.js.map +1 -1
- package/dist/providers/slack.d.ts.map +1 -1
- package/dist/providers/slack.js +36 -16
- package/dist/providers/slack.js.map +1 -1
- package/dist/providers/types.d.ts +12 -0
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/types.js.map +1 -1
- package/dist/providers/webhook.d.ts.map +1 -1
- package/dist/providers/webhook.js +11 -9
- package/dist/providers/webhook.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +33 -38
- package/src/core/entities/provider.ts +7 -1
- package/src/core/errors.ts +12 -2
- package/src/db/webhook-deliveries.test.ts +11 -0
- package/src/db/webhook-deliveries.ts +12 -3
- package/src/index.test.ts +112 -0
- package/src/index.ts +104 -10
- package/src/presentation/inter-module.ts +155 -0
- package/src/presentation/routes/agent-tools-gateway/index.ts +1 -0
- package/src/presentation/routes/agent-tools-gateway/resolve-authorized-tools.test.ts +36 -0
- package/src/presentation/routes/agent-tools-gateway/resolve-authorized-tools.ts +64 -22
- package/src/presentation/routes/index.ts +5 -6
- package/src/presentation/routes/manage-connections.test.ts +113 -0
- package/src/presentation/routes/manage-connections.ts +26 -2
- package/src/providers/gitea.ts +11 -8
- package/src/providers/github.ts +17 -11
- package/src/providers/jira.ts +155 -7
- package/src/providers/linear.test.ts +136 -0
- package/src/providers/linear.ts +33 -13
- package/src/providers/sentry.ts +15 -12
- package/src/providers/slack.test.ts +139 -0
- package/src/providers/slack.ts +39 -14
- package/src/providers/types.ts +15 -0
- package/src/providers/webhook.ts +11 -9
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { integrationsInterModuleContract } from '@shipfox/api-integration-core-dto';
|
|
2
|
+
import { type InterModulePresentation } from '@shipfox/inter-module';
|
|
3
|
+
import type { IntegrationProviderRegistry } from '#core/providers/registry.js';
|
|
4
|
+
import type { IntegrationSourceControlService } from '#core/source-control-service.js';
|
|
5
|
+
export declare function createIntegrationsInterModulePresentation(params: {
|
|
6
|
+
registry: IntegrationProviderRegistry;
|
|
7
|
+
sourceControl: IntegrationSourceControlService;
|
|
8
|
+
}): InterModulePresentation<typeof integrationsInterModuleContract>;
|
|
9
|
+
//# sourceMappingURL=inter-module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inter-module.d.ts","sourceRoot":"","sources":["../../src/presentation/inter-module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,+BAA+B,EAAC,MAAM,mCAAmC,CAAC;AAClF,OAAO,EAIL,KAAK,uBAAuB,EAC7B,MAAM,uBAAuB,CAAC;AAe/B,OAAO,KAAK,EAAC,2BAA2B,EAAC,MAAM,6BAA6B,CAAC;AAC7E,OAAO,KAAK,EAAC,+BAA+B,EAAC,MAAM,iCAAiC,CAAC;AAGrF,wBAAgB,yCAAyC,CAAC,MAAM,EAAE;IAChE,QAAQ,EAAE,2BAA2B,CAAC;IACtC,aAAa,EAAE,+BAA+B,CAAC;CAChD,GAAG,uBAAuB,CAAC,OAAO,+BAA+B,CAAC,CA+ElE"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { integrationsInterModuleContract } from '@shipfox/api-integration-core-dto';
|
|
2
|
+
import { createInterModuleKnownError, defineInterModulePresentation } from '@shipfox/inter-module';
|
|
3
|
+
import { buildAgentToolCatalogs, buildAgentToolSelectionCatalogs, createWorkspaceConnectionSnapshotLoader } from '#core/agent-tool-selection.js';
|
|
4
|
+
import { IntegrationCapabilityUnavailableError, IntegrationCheckoutUnsupportedError, IntegrationConnectionInactiveError, IntegrationConnectionNotFoundError, IntegrationConnectionWorkspaceMismatchError, IntegrationProviderError, IntegrationProviderUnavailableError } from '#core/errors.js';
|
|
5
|
+
import { getIntegrationConnectionById } from '#db/connections.js';
|
|
6
|
+
export function createIntegrationsInterModulePresentation(params) {
|
|
7
|
+
const contract = integrationsInterModuleContract;
|
|
8
|
+
return defineInterModulePresentation(contract, {
|
|
9
|
+
resolveSourceRepository: async (input)=>await known(contract.methods.resolveSourceRepository, input, async ()=>{
|
|
10
|
+
const resolved = await params.sourceControl.resolveRepository(input);
|
|
11
|
+
return {
|
|
12
|
+
connection: {
|
|
13
|
+
id: resolved.connection.id,
|
|
14
|
+
provider: resolved.connection.provider,
|
|
15
|
+
slug: resolved.connection.slug
|
|
16
|
+
},
|
|
17
|
+
repository: resolved.repository
|
|
18
|
+
};
|
|
19
|
+
}),
|
|
20
|
+
listSourceFiles: async (input)=>await known(contract.methods.listSourceFiles, input, async ()=>await params.sourceControl.listFiles(input)),
|
|
21
|
+
fetchSourceFile: async (input)=>await known(contract.methods.fetchSourceFile, input, async ()=>await params.sourceControl.fetchFile(input)),
|
|
22
|
+
createCheckoutSpec: async (input)=>await known(contract.methods.createCheckoutSpec, input, async ()=>{
|
|
23
|
+
const spec = await params.sourceControl.createCheckoutSpec(input);
|
|
24
|
+
return {
|
|
25
|
+
repositoryUrl: spec.repositoryUrl,
|
|
26
|
+
ref: spec.ref,
|
|
27
|
+
...spec.credentials ? {
|
|
28
|
+
credentials: {
|
|
29
|
+
...spec.credentials,
|
|
30
|
+
expiresAt: spec.credentials.expiresAt.toISOString()
|
|
31
|
+
}
|
|
32
|
+
} : {},
|
|
33
|
+
...spec.gitAuthor === undefined ? {} : {
|
|
34
|
+
gitAuthor: spec.gitAuthor
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}),
|
|
38
|
+
getAgentToolsContext: async (input)=>await known(contract.methods.getAgentToolsContext, input, async ()=>{
|
|
39
|
+
const [selectionCatalogs, catalogs, snapshot, defaultConnection] = await Promise.all([
|
|
40
|
+
buildAgentToolSelectionCatalogs(params.registry),
|
|
41
|
+
buildAgentToolCatalogs(params.registry),
|
|
42
|
+
createWorkspaceConnectionSnapshotLoader(params.registry)(input.workspaceId),
|
|
43
|
+
getIntegrationConnectionById(input.defaultConnectionId)
|
|
44
|
+
]);
|
|
45
|
+
return {
|
|
46
|
+
selectionCatalogs: [
|
|
47
|
+
...selectionCatalogs
|
|
48
|
+
].map(([provider, value])=>({
|
|
49
|
+
provider,
|
|
50
|
+
selectors: value.selectors.map((selector)=>({
|
|
51
|
+
...selector
|
|
52
|
+
}))
|
|
53
|
+
})),
|
|
54
|
+
catalogs: [
|
|
55
|
+
...catalogs
|
|
56
|
+
].map(([provider, tools])=>({
|
|
57
|
+
provider,
|
|
58
|
+
tools: tools.map(({ methods, ...tool })=>({
|
|
59
|
+
...tool,
|
|
60
|
+
...methods === undefined ? {} : {
|
|
61
|
+
methods: methods.map((method)=>({
|
|
62
|
+
...method
|
|
63
|
+
}))
|
|
64
|
+
}
|
|
65
|
+
}))
|
|
66
|
+
})),
|
|
67
|
+
workspaceConnections: [
|
|
68
|
+
...snapshot
|
|
69
|
+
].map(([slug, value])=>({
|
|
70
|
+
slug,
|
|
71
|
+
...value,
|
|
72
|
+
capabilities: [
|
|
73
|
+
...value.capabilities
|
|
74
|
+
]
|
|
75
|
+
})),
|
|
76
|
+
defaultConnection: defaultConnection ? {
|
|
77
|
+
id: defaultConnection.id,
|
|
78
|
+
slug: defaultConnection.slug,
|
|
79
|
+
provider: defaultConnection.provider
|
|
80
|
+
} : null
|
|
81
|
+
};
|
|
82
|
+
})
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
async function known(method, input, operation) {
|
|
86
|
+
try {
|
|
87
|
+
return await operation();
|
|
88
|
+
} catch (error) {
|
|
89
|
+
throw mapError(method, input, error);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function mapError(method, input, error) {
|
|
93
|
+
if (error instanceof IntegrationConnectionNotFoundError) return createInterModuleKnownError(method, 'connection-not-found', {
|
|
94
|
+
connectionId: input.connectionId ?? input.defaultConnectionId
|
|
95
|
+
});
|
|
96
|
+
if (error instanceof IntegrationConnectionInactiveError) return createInterModuleKnownError(method, 'connection-inactive', {
|
|
97
|
+
connectionId: input.connectionId
|
|
98
|
+
});
|
|
99
|
+
if (error instanceof IntegrationConnectionWorkspaceMismatchError) return createInterModuleKnownError(method, 'connection-workspace-mismatch', {
|
|
100
|
+
connectionId: input.connectionId
|
|
101
|
+
});
|
|
102
|
+
if (error instanceof IntegrationProviderUnavailableError) return createInterModuleKnownError(method, 'provider-unavailable', {
|
|
103
|
+
provider: error.provider
|
|
104
|
+
});
|
|
105
|
+
if (error instanceof IntegrationCapabilityUnavailableError) return createInterModuleKnownError(method, 'capability-unavailable', {
|
|
106
|
+
provider: error.provider,
|
|
107
|
+
capability: error.capability
|
|
108
|
+
});
|
|
109
|
+
if (error instanceof IntegrationCheckoutUnsupportedError) return createInterModuleKnownError(method, 'checkout-unsupported', {
|
|
110
|
+
provider: error.provider
|
|
111
|
+
});
|
|
112
|
+
if (error instanceof IntegrationProviderError) return createInterModuleKnownError(method, 'provider-failure', {
|
|
113
|
+
reason: error.reason,
|
|
114
|
+
...error.retryAfterSeconds === undefined ? {} : {
|
|
115
|
+
retryAfterSeconds: error.retryAfterSeconds
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
return error;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
//# sourceMappingURL=inter-module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/presentation/inter-module.ts"],"sourcesContent":["import {integrationsInterModuleContract} from '@shipfox/api-integration-core-dto';\nimport {\n createInterModuleKnownError,\n defineInterModulePresentation,\n type InterModuleMethodContract,\n type InterModulePresentation,\n} from '@shipfox/inter-module';\nimport {\n buildAgentToolCatalogs,\n buildAgentToolSelectionCatalogs,\n createWorkspaceConnectionSnapshotLoader,\n} from '#core/agent-tool-selection.js';\nimport {\n IntegrationCapabilityUnavailableError,\n IntegrationCheckoutUnsupportedError,\n IntegrationConnectionInactiveError,\n IntegrationConnectionNotFoundError,\n IntegrationConnectionWorkspaceMismatchError,\n IntegrationProviderError,\n IntegrationProviderUnavailableError,\n} from '#core/errors.js';\nimport type {IntegrationProviderRegistry} from '#core/providers/registry.js';\nimport type {IntegrationSourceControlService} from '#core/source-control-service.js';\nimport {getIntegrationConnectionById} from '#db/connections.js';\n\nexport function createIntegrationsInterModulePresentation(params: {\n registry: IntegrationProviderRegistry;\n sourceControl: IntegrationSourceControlService;\n}): InterModulePresentation<typeof integrationsInterModuleContract> {\n const contract = integrationsInterModuleContract;\n return defineInterModulePresentation(contract, {\n resolveSourceRepository: async (input) =>\n await known(contract.methods.resolveSourceRepository, input, async () => {\n const resolved = await params.sourceControl.resolveRepository(input);\n return {\n connection: {\n id: resolved.connection.id,\n provider: resolved.connection.provider,\n slug: resolved.connection.slug,\n },\n repository: resolved.repository,\n };\n }),\n listSourceFiles: async (input) =>\n await known(\n contract.methods.listSourceFiles,\n input,\n async () => await params.sourceControl.listFiles(input),\n ),\n fetchSourceFile: async (input) =>\n await known(\n contract.methods.fetchSourceFile,\n input,\n async () => await params.sourceControl.fetchFile(input),\n ),\n createCheckoutSpec: async (input) =>\n await known(contract.methods.createCheckoutSpec, input, async () => {\n const spec = await params.sourceControl.createCheckoutSpec(input);\n return {\n repositoryUrl: spec.repositoryUrl,\n ref: spec.ref,\n ...(spec.credentials\n ? {\n credentials: {\n ...spec.credentials,\n expiresAt: spec.credentials.expiresAt.toISOString(),\n },\n }\n : {}),\n ...(spec.gitAuthor === undefined ? {} : {gitAuthor: spec.gitAuthor}),\n };\n }),\n getAgentToolsContext: async (input) =>\n await known(contract.methods.getAgentToolsContext, input, async () => {\n const [selectionCatalogs, catalogs, snapshot, defaultConnection] = await Promise.all([\n buildAgentToolSelectionCatalogs(params.registry),\n buildAgentToolCatalogs(params.registry),\n createWorkspaceConnectionSnapshotLoader(params.registry)(input.workspaceId),\n getIntegrationConnectionById(input.defaultConnectionId),\n ]);\n return {\n selectionCatalogs: [...selectionCatalogs].map(([provider, value]) => ({\n provider,\n selectors: value.selectors.map((selector) => ({...selector})),\n })),\n catalogs: [...catalogs].map(([provider, tools]) => ({\n provider,\n tools: tools.map(({methods, ...tool}) => ({\n ...tool,\n ...(methods === undefined ? {} : {methods: methods.map((method) => ({...method}))}),\n })),\n })),\n workspaceConnections: [...snapshot].map(([slug, value]) => ({\n slug,\n ...value,\n capabilities: [...value.capabilities],\n })),\n defaultConnection: defaultConnection\n ? {\n id: defaultConnection.id,\n slug: defaultConnection.slug,\n provider: defaultConnection.provider,\n }\n : null,\n };\n }),\n });\n}\n\nasync function known<Output>(\n method: InterModuleMethodContract,\n input: {connectionId?: string; defaultConnectionId?: string},\n operation: () => Promise<Output>,\n): Promise<Output> {\n try {\n return await operation();\n } catch (error) {\n throw mapError(method, input, error);\n }\n}\nfunction mapError(\n method: InterModuleMethodContract,\n input: {connectionId?: string; defaultConnectionId?: string},\n error: unknown,\n): unknown {\n if (error instanceof IntegrationConnectionNotFoundError)\n return createInterModuleKnownError(method, 'connection-not-found', {\n connectionId: input.connectionId ?? input.defaultConnectionId,\n });\n if (error instanceof IntegrationConnectionInactiveError)\n return createInterModuleKnownError(method, 'connection-inactive', {\n connectionId: input.connectionId,\n });\n if (error instanceof IntegrationConnectionWorkspaceMismatchError)\n return createInterModuleKnownError(method, 'connection-workspace-mismatch', {\n connectionId: input.connectionId,\n });\n if (error instanceof IntegrationProviderUnavailableError)\n return createInterModuleKnownError(method, 'provider-unavailable', {provider: error.provider});\n if (error instanceof IntegrationCapabilityUnavailableError)\n return createInterModuleKnownError(method, 'capability-unavailable', {\n provider: error.provider,\n capability: error.capability,\n });\n if (error instanceof IntegrationCheckoutUnsupportedError)\n return createInterModuleKnownError(method, 'checkout-unsupported', {provider: error.provider});\n if (error instanceof IntegrationProviderError)\n return createInterModuleKnownError(method, 'provider-failure', {\n reason: error.reason,\n ...(error.retryAfterSeconds === undefined\n ? {}\n : {retryAfterSeconds: error.retryAfterSeconds}),\n });\n return error;\n}\n"],"names":["integrationsInterModuleContract","createInterModuleKnownError","defineInterModulePresentation","buildAgentToolCatalogs","buildAgentToolSelectionCatalogs","createWorkspaceConnectionSnapshotLoader","IntegrationCapabilityUnavailableError","IntegrationCheckoutUnsupportedError","IntegrationConnectionInactiveError","IntegrationConnectionNotFoundError","IntegrationConnectionWorkspaceMismatchError","IntegrationProviderError","IntegrationProviderUnavailableError","getIntegrationConnectionById","createIntegrationsInterModulePresentation","params","contract","resolveSourceRepository","input","known","methods","resolved","sourceControl","resolveRepository","connection","id","provider","slug","repository","listSourceFiles","listFiles","fetchSourceFile","fetchFile","createCheckoutSpec","spec","repositoryUrl","ref","credentials","expiresAt","toISOString","gitAuthor","undefined","getAgentToolsContext","selectionCatalogs","catalogs","snapshot","defaultConnection","Promise","all","registry","workspaceId","defaultConnectionId","map","value","selectors","selector","tools","tool","method","workspaceConnections","capabilities","operation","error","mapError","connectionId","capability","reason","retryAfterSeconds"],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@ import type { IntegrationProviderRegistry } from '#core/providers/registry.js';
|
|
|
3
3
|
import type { GetIntegrationConnectionByIdFn } from '#db/connections.js';
|
|
4
4
|
import { type LeasedAgentStepLoader } from './resolve-authorized-tools.js';
|
|
5
5
|
export type { LeasedAgentStepLoader } from './resolve-authorized-tools.js';
|
|
6
|
+
export { createWorkflowsLeasedAgentStepLoader } from './resolve-authorized-tools.js';
|
|
6
7
|
export interface CreateAgentToolsGatewayRoutesParams {
|
|
7
8
|
loadLeasedAgentStep: LeasedAgentStepLoader;
|
|
8
9
|
registry: IntegrationProviderRegistry;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/presentation/routes/agent-tools-gateway/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,KAAK,UAAU,EAAC,MAAM,uBAAuB,CAAC;AACnE,OAAO,KAAK,EAAC,2BAA2B,EAAC,MAAM,6BAA6B,CAAC;AAC7E,OAAO,KAAK,EAAC,8BAA8B,EAAC,MAAM,oBAAoB,CAAC;AAIvE,OAAO,EACL,KAAK,qBAAqB,EAE3B,MAAM,+BAA+B,CAAC;AAEvC,YAAY,EAAC,qBAAqB,EAAC,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/presentation/routes/agent-tools-gateway/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,KAAK,UAAU,EAAC,MAAM,uBAAuB,CAAC;AACnE,OAAO,KAAK,EAAC,2BAA2B,EAAC,MAAM,6BAA6B,CAAC;AAC7E,OAAO,KAAK,EAAC,8BAA8B,EAAC,MAAM,oBAAoB,CAAC;AAIvE,OAAO,EACL,KAAK,qBAAqB,EAE3B,MAAM,+BAA+B,CAAC;AAEvC,YAAY,EAAC,qBAAqB,EAAC,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAC,oCAAoC,EAAC,MAAM,+BAA+B,CAAC;AAEnF,MAAM,WAAW,mCAAmC;IAClD,mBAAmB,EAAE,qBAAqB,CAAC;IAC3C,QAAQ,EAAE,2BAA2B,CAAC;IACtC,4BAA4B,EAAE,8BAA8B,CAAC;CAC9D;AAED,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,mCAAmC,GAC1C,UAAU,CAqCZ"}
|
|
@@ -5,6 +5,7 @@ import { createIntegrationToolCallRecorder } from './audit.js';
|
|
|
5
5
|
import { createIntegrationToolDispatcher } from './dispatch.js';
|
|
6
6
|
import { buildAgentToolsMcpServer } from './mcp-server.js';
|
|
7
7
|
import { resolveAuthorizedIntegrationTools } from './resolve-authorized-tools.js';
|
|
8
|
+
export { createWorkflowsLeasedAgentStepLoader } from './resolve-authorized-tools.js';
|
|
8
9
|
export function createAgentToolsGatewayRoutes(params) {
|
|
9
10
|
const dispatchIntegrationToolCall = createIntegrationToolDispatcher({
|
|
10
11
|
registry: params.registry
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/presentation/routes/agent-tools-gateway/index.ts"],"sourcesContent":["import {StreamableHTTPServerTransport} from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport type {Transport} from '@modelcontextprotocol/sdk/shared/transport.js';\nimport {AUTH_LEASED_JOB, requireLeasedJobContext} from '@shipfox/api-auth-context';\nimport {defineRoute, type RouteGroup} from '@shipfox/node-fastify';\nimport type {IntegrationProviderRegistry} from '#core/providers/registry.js';\nimport type {GetIntegrationConnectionByIdFn} from '#db/connections.js';\nimport {createIntegrationToolCallRecorder} from './audit.js';\nimport {createIntegrationToolDispatcher} from './dispatch.js';\nimport {buildAgentToolsMcpServer} from './mcp-server.js';\nimport {\n type LeasedAgentStepLoader,\n resolveAuthorizedIntegrationTools,\n} from './resolve-authorized-tools.js';\n\nexport type {LeasedAgentStepLoader} from './resolve-authorized-tools.js';\n\nexport interface CreateAgentToolsGatewayRoutesParams {\n loadLeasedAgentStep: LeasedAgentStepLoader;\n registry: IntegrationProviderRegistry;\n getIntegrationConnectionById: GetIntegrationConnectionByIdFn;\n}\n\nexport function createAgentToolsGatewayRoutes(\n params: CreateAgentToolsGatewayRoutesParams,\n): RouteGroup {\n const dispatchIntegrationToolCall = createIntegrationToolDispatcher({registry: params.registry});\n\n return {\n prefix: '/runs/jobs/current/integration-tools',\n auth: AUTH_LEASED_JOB,\n routes: [\n defineRoute({\n method: 'POST',\n path: '/mcp',\n description: 'Gateway MCP endpoint for integration-backed agent tools',\n handler: async (request, reply) => {\n const authorizedTools = await resolveAuthorizedIntegrationTools({\n request,\n loadLeasedAgentStep: params.loadLeasedAgentStep,\n registry: params.registry,\n getIntegrationConnectionById: params.getIntegrationConnectionById,\n });\n const server = buildAgentToolsMcpServer({\n authorizedTools,\n dispatch: dispatchIntegrationToolCall,\n recordCall: createIntegrationToolCallRecorder(requireLeasedJobContext(request)),\n });\n const transport = new StreamableHTTPServerTransport();\n\n await server.connect(transport as unknown as Transport);\n reply.raw.on('close', () => {\n void transport.close();\n void server.close();\n });\n\n reply.hijack();\n await transport.handleRequest(request.raw, reply.raw, request.body);\n },\n }),\n ],\n };\n}\n"],"names":["StreamableHTTPServerTransport","AUTH_LEASED_JOB","requireLeasedJobContext","defineRoute","createIntegrationToolCallRecorder","createIntegrationToolDispatcher","buildAgentToolsMcpServer","resolveAuthorizedIntegrationTools","createAgentToolsGatewayRoutes","params","dispatchIntegrationToolCall","registry","prefix","auth","routes","method","path","description","handler","request","reply","authorizedTools","loadLeasedAgentStep","getIntegrationConnectionById","server","dispatch","recordCall","transport","connect","raw","on","close","hijack","handleRequest","body"],"mappings":"AAAA,SAAQA,6BAA6B,QAAO,qDAAqD;AAEjG,SAAQC,eAAe,EAAEC,uBAAuB,QAAO,4BAA4B;AACnF,SAAQC,WAAW,QAAwB,wBAAwB;AAGnE,SAAQC,iCAAiC,QAAO,aAAa;AAC7D,SAAQC,+BAA+B,QAAO,gBAAgB;AAC9D,SAAQC,wBAAwB,QAAO,kBAAkB;AACzD,SAEEC,iCAAiC,QAC5B,gCAAgC;
|
|
1
|
+
{"version":3,"sources":["../../../../src/presentation/routes/agent-tools-gateway/index.ts"],"sourcesContent":["import {StreamableHTTPServerTransport} from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport type {Transport} from '@modelcontextprotocol/sdk/shared/transport.js';\nimport {AUTH_LEASED_JOB, requireLeasedJobContext} from '@shipfox/api-auth-context';\nimport {defineRoute, type RouteGroup} from '@shipfox/node-fastify';\nimport type {IntegrationProviderRegistry} from '#core/providers/registry.js';\nimport type {GetIntegrationConnectionByIdFn} from '#db/connections.js';\nimport {createIntegrationToolCallRecorder} from './audit.js';\nimport {createIntegrationToolDispatcher} from './dispatch.js';\nimport {buildAgentToolsMcpServer} from './mcp-server.js';\nimport {\n type LeasedAgentStepLoader,\n resolveAuthorizedIntegrationTools,\n} from './resolve-authorized-tools.js';\n\nexport type {LeasedAgentStepLoader} from './resolve-authorized-tools.js';\nexport {createWorkflowsLeasedAgentStepLoader} from './resolve-authorized-tools.js';\n\nexport interface CreateAgentToolsGatewayRoutesParams {\n loadLeasedAgentStep: LeasedAgentStepLoader;\n registry: IntegrationProviderRegistry;\n getIntegrationConnectionById: GetIntegrationConnectionByIdFn;\n}\n\nexport function createAgentToolsGatewayRoutes(\n params: CreateAgentToolsGatewayRoutesParams,\n): RouteGroup {\n const dispatchIntegrationToolCall = createIntegrationToolDispatcher({registry: params.registry});\n\n return {\n prefix: '/runs/jobs/current/integration-tools',\n auth: AUTH_LEASED_JOB,\n routes: [\n defineRoute({\n method: 'POST',\n path: '/mcp',\n description: 'Gateway MCP endpoint for integration-backed agent tools',\n handler: async (request, reply) => {\n const authorizedTools = await resolveAuthorizedIntegrationTools({\n request,\n loadLeasedAgentStep: params.loadLeasedAgentStep,\n registry: params.registry,\n getIntegrationConnectionById: params.getIntegrationConnectionById,\n });\n const server = buildAgentToolsMcpServer({\n authorizedTools,\n dispatch: dispatchIntegrationToolCall,\n recordCall: createIntegrationToolCallRecorder(requireLeasedJobContext(request)),\n });\n const transport = new StreamableHTTPServerTransport();\n\n await server.connect(transport as unknown as Transport);\n reply.raw.on('close', () => {\n void transport.close();\n void server.close();\n });\n\n reply.hijack();\n await transport.handleRequest(request.raw, reply.raw, request.body);\n },\n }),\n ],\n };\n}\n"],"names":["StreamableHTTPServerTransport","AUTH_LEASED_JOB","requireLeasedJobContext","defineRoute","createIntegrationToolCallRecorder","createIntegrationToolDispatcher","buildAgentToolsMcpServer","resolveAuthorizedIntegrationTools","createWorkflowsLeasedAgentStepLoader","createAgentToolsGatewayRoutes","params","dispatchIntegrationToolCall","registry","prefix","auth","routes","method","path","description","handler","request","reply","authorizedTools","loadLeasedAgentStep","getIntegrationConnectionById","server","dispatch","recordCall","transport","connect","raw","on","close","hijack","handleRequest","body"],"mappings":"AAAA,SAAQA,6BAA6B,QAAO,qDAAqD;AAEjG,SAAQC,eAAe,EAAEC,uBAAuB,QAAO,4BAA4B;AACnF,SAAQC,WAAW,QAAwB,wBAAwB;AAGnE,SAAQC,iCAAiC,QAAO,aAAa;AAC7D,SAAQC,+BAA+B,QAAO,gBAAgB;AAC9D,SAAQC,wBAAwB,QAAO,kBAAkB;AACzD,SAEEC,iCAAiC,QAC5B,gCAAgC;AAGvC,SAAQC,oCAAoC,QAAO,gCAAgC;AAQnF,OAAO,SAASC,8BACdC,MAA2C;IAE3C,MAAMC,8BAA8BN,gCAAgC;QAACO,UAAUF,OAAOE,QAAQ;IAAA;IAE9F,OAAO;QACLC,QAAQ;QACRC,MAAMb;QACNc,QAAQ;YACNZ,YAAY;gBACVa,QAAQ;gBACRC,MAAM;gBACNC,aAAa;gBACbC,SAAS,OAAOC,SAASC;oBACvB,MAAMC,kBAAkB,MAAMf,kCAAkC;wBAC9Da;wBACAG,qBAAqBb,OAAOa,mBAAmB;wBAC/CX,UAAUF,OAAOE,QAAQ;wBACzBY,8BAA8Bd,OAAOc,4BAA4B;oBACnE;oBACA,MAAMC,SAASnB,yBAAyB;wBACtCgB;wBACAI,UAAUf;wBACVgB,YAAYvB,kCAAkCF,wBAAwBkB;oBACxE;oBACA,MAAMQ,YAAY,IAAI5B;oBAEtB,MAAMyB,OAAOI,OAAO,CAACD;oBACrBP,MAAMS,GAAG,CAACC,EAAE,CAAC,SAAS;wBACpB,KAAKH,UAAUI,KAAK;wBACpB,KAAKP,OAAOO,KAAK;oBACnB;oBAEAX,MAAMY,MAAM;oBACZ,MAAML,UAAUM,aAAa,CAACd,QAAQU,GAAG,EAAET,MAAMS,GAAG,EAAEV,QAAQe,IAAI;gBACpE;YACF;SACD;IACH;AACF"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type MaterializedAgentIntegrationConfigDto, type MaterializedAgentIntegrationToolConfigDto } from '@shipfox/api-agent-dto';
|
|
2
|
+
import { type WorkflowsModuleClient } from '@shipfox/api-workflows-dto/inter-module';
|
|
2
3
|
import type { IntegrationConnection } from '#core/entities/connection.js';
|
|
3
4
|
import type { AgentToolJsonSchema } from '#core/providers/agent-tools.js';
|
|
4
5
|
import type { IntegrationProviderRegistry } from '#core/providers/registry.js';
|
|
@@ -8,12 +9,14 @@ export type LeasedAgentStepLoader = (params: {
|
|
|
8
9
|
stepId: string;
|
|
9
10
|
attempt: number;
|
|
10
11
|
}) => Promise<{
|
|
11
|
-
|
|
12
|
+
workspaceId: string;
|
|
13
|
+
integrations?: MaterializedAgentIntegrationConfigDto[];
|
|
14
|
+
step?: {
|
|
12
15
|
type: string;
|
|
13
16
|
config: Record<string, unknown>;
|
|
14
17
|
};
|
|
15
|
-
workspaceId: string;
|
|
16
18
|
}>;
|
|
19
|
+
export declare function createWorkflowsLeasedAgentStepLoader(workflows: WorkflowsModuleClient): LeasedAgentStepLoader;
|
|
17
20
|
export interface AuthorizedIntegrationTool {
|
|
18
21
|
mcpName: string;
|
|
19
22
|
integration: MaterializedAgentIntegrationConfigDto;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-authorized-tools.d.ts","sourceRoot":"","sources":["../../../../src/presentation/routes/agent-tools-gateway/resolve-authorized-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,qCAAqC,EAC1C,KAAK,yCAAyC,EAE/C,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"resolve-authorized-tools.d.ts","sourceRoot":"","sources":["../../../../src/presentation/routes/agent-tools-gateway/resolve-authorized-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,qCAAqC,EAC1C,KAAK,yCAAyC,EAE/C,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,KAAK,qBAAqB,EAE3B,MAAM,yCAAyC,CAAC;AAGjD,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,8BAA8B,CAAC;AAExE,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,gCAAgC,CAAC;AACxE,OAAO,KAAK,EAAC,2BAA2B,EAAC,MAAM,6BAA6B,CAAC;AAC7E,OAAO,KAAK,EAAC,8BAA8B,EAAC,MAAM,oBAAoB,CAAC;AAEvE,MAAM,MAAM,qBAAqB,GAAG,CAAC,MAAM,EAAE;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB,KAAK,OAAO,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,qCAAqC,EAAE,CAAC;IACvD,IAAI,CAAC,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAC,CAAC;CACxD,CAAC,CAAC;AAEH,wBAAgB,oCAAoC,CAClD,SAAS,EAAE,qBAAqB,GAC/B,qBAAqB,CAmBvB;AAiBD,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,qCAAqC,CAAC;IACnD,IAAI,EAAE,yCAAyC,CAAC;IAChD,UAAU,EAAE,qBAAqB,CAAC;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,mBAAmB,CAAC;IACjC,YAAY,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC;CAChD;AAED,MAAM,MAAM,4BAA4B,GAAG,GAAG,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC;AAElF,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,mBAAmB,EAAE,qBAAqB,CAAC;IAC3C,QAAQ,EAAE,2BAA2B,CAAC;IACtC,4BAA4B,EAAE,8BAA8B,CAAC;CAC9D;AAED,wBAAsB,iCAAiC,CACrD,MAAM,EAAE,4BAA4B,GACnC,OAAO,CAAC,4BAA4B,CAAC,CAsDvC;AAkBD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wBAAgB,WAAW,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE1E;AAED,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,mBAAmB,EAChC,iBAAiB,EAAE,SAAS,MAAM,EAAE,GACnC,mBAAmB,CAYrB"}
|
|
@@ -1,6 +1,41 @@
|
|
|
1
1
|
import { materializedAgentStepConfigSchema } from '@shipfox/api-agent-dto';
|
|
2
2
|
import { requireLeasedJobContext } from '@shipfox/api-auth-context';
|
|
3
|
+
import { workflowsInterModuleContract } from '@shipfox/api-workflows-dto/inter-module';
|
|
4
|
+
import { isInterModuleKnownError } from '@shipfox/inter-module';
|
|
3
5
|
import { ClientError } from '@shipfox/node-fastify';
|
|
6
|
+
export function createWorkflowsLeasedAgentStepLoader(workflows) {
|
|
7
|
+
return async ({ request, stepId, attempt })=>{
|
|
8
|
+
const leasedJob = requireLeasedJobContext(request);
|
|
9
|
+
try {
|
|
10
|
+
const context = await workflows.getLeasedAgentToolContext({
|
|
11
|
+
jobId: leasedJob.jobId,
|
|
12
|
+
jobExecutionId: leasedJob.jobExecutionId,
|
|
13
|
+
runnerSessionId: leasedJob.runnerSessionId,
|
|
14
|
+
stepId,
|
|
15
|
+
attempt
|
|
16
|
+
});
|
|
17
|
+
return {
|
|
18
|
+
workspaceId: context.workspaceId,
|
|
19
|
+
integrations: context.integrations
|
|
20
|
+
};
|
|
21
|
+
} catch (error) {
|
|
22
|
+
throw toLeasedAgentToolClientError(error);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function toLeasedAgentToolClientError(error) {
|
|
27
|
+
const method = workflowsInterModuleContract.methods.getLeasedAgentToolContext;
|
|
28
|
+
if (!isInterModuleKnownError(method, error)) return error;
|
|
29
|
+
const status = [
|
|
30
|
+
'step-attempt-mismatch',
|
|
31
|
+
'step-not-running',
|
|
32
|
+
'leased-step-not-agent',
|
|
33
|
+
'agent-step-config-invalid'
|
|
34
|
+
].includes(error.code) ? 409 : 404;
|
|
35
|
+
return new ClientError(error.code.replaceAll('-', ' '), error.code, {
|
|
36
|
+
status
|
|
37
|
+
});
|
|
38
|
+
}
|
|
4
39
|
export async function resolveAuthorizedIntegrationTools(params) {
|
|
5
40
|
const leasedJob = requireLeasedJobContext(params.request);
|
|
6
41
|
if (!leasedJob.currentStepId || leasedJob.currentStepAttempt === undefined) {
|
|
@@ -8,17 +43,13 @@ export async function resolveAuthorizedIntegrationTools(params) {
|
|
|
8
43
|
status: 409
|
|
9
44
|
});
|
|
10
45
|
}
|
|
11
|
-
const
|
|
46
|
+
const loaded = await params.loadLeasedAgentStep({
|
|
12
47
|
request: params.request,
|
|
13
48
|
stepId: leasedJob.currentStepId,
|
|
14
49
|
attempt: leasedJob.currentStepAttempt
|
|
15
50
|
});
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
status: 409
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
const integrations = parseAgentIntegrations(step.config);
|
|
51
|
+
const workspaceId = loaded.workspaceId;
|
|
52
|
+
const integrations = loaded.integrations ?? legacyIntegrations(loaded.step);
|
|
22
53
|
const authorizedTools = new Map();
|
|
23
54
|
for (const integration of integrations){
|
|
24
55
|
const connection = await loadAuthorizedConnection({
|
|
@@ -54,6 +85,21 @@ export async function resolveAuthorizedIntegrationTools(params) {
|
|
|
54
85
|
}
|
|
55
86
|
return authorizedTools;
|
|
56
87
|
}
|
|
88
|
+
function legacyIntegrations(step) {
|
|
89
|
+
if (step?.type !== 'agent') {
|
|
90
|
+
throw new ClientError('Current leased step is not an agent step', 'leased-step-not-agent', {
|
|
91
|
+
status: 409
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
return materializedAgentStepConfigSchema.parse(step.config).integrations ?? [];
|
|
96
|
+
} catch (error) {
|
|
97
|
+
throw new ClientError('Agent step config is invalid', 'agent-step-config-invalid', {
|
|
98
|
+
status: 409,
|
|
99
|
+
cause: error
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
57
103
|
export function sanitizeSlug(slug) {
|
|
58
104
|
return slug.replaceAll('-', '_');
|
|
59
105
|
}
|
|
@@ -75,16 +121,6 @@ function toolInputSchema(tool) {
|
|
|
75
121
|
const authorizedMethods = tool.methods?.map((method)=>method.id) ?? [];
|
|
76
122
|
return narrowMethodEnum(tool.inputSchema, authorizedMethods);
|
|
77
123
|
}
|
|
78
|
-
function parseAgentIntegrations(config) {
|
|
79
|
-
try {
|
|
80
|
-
return materializedAgentStepConfigSchema.parse(config).integrations ?? [];
|
|
81
|
-
} catch (error) {
|
|
82
|
-
throw new ClientError('Agent step config is invalid', 'agent-step-config-invalid', {
|
|
83
|
-
status: 409,
|
|
84
|
-
cause: error
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
124
|
async function loadAuthorizedConnection(params) {
|
|
89
125
|
const connection = await params.getIntegrationConnectionById(params.integration.connectionId);
|
|
90
126
|
if (!connection) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/presentation/routes/agent-tools-gateway/resolve-authorized-tools.ts"],"sourcesContent":["import {\n type MaterializedAgentIntegrationConfigDto,\n type MaterializedAgentIntegrationToolConfigDto,\n materializedAgentStepConfigSchema,\n} from '@shipfox/api-agent-dto';\nimport {requireLeasedJobContext} from '@shipfox/api-auth-context';\nimport {ClientError} from '@shipfox/node-fastify';\nimport type {IntegrationConnection} from '#core/entities/connection.js';\nimport type {IntegrationProviderKind} from '#core/entities/provider.js';\nimport type {AgentToolJsonSchema} from '#core/providers/agent-tools.js';\nimport type {IntegrationProviderRegistry} from '#core/providers/registry.js';\nimport type {GetIntegrationConnectionByIdFn} from '#db/connections.js';\n\nexport type LeasedAgentStepLoader = (params: {\n request: object;\n stepId: string;\n attempt: number;\n}) => Promise<{\n step: {type: string; config: Record<string, unknown>};\n workspaceId: string;\n}>;\n\nexport interface AuthorizedIntegrationTool {\n mcpName: string;\n integration: MaterializedAgentIntegrationConfigDto;\n tool: MaterializedAgentIntegrationToolConfigDto;\n connection: IntegrationConnection;\n description: string;\n inputSchema: AgentToolJsonSchema;\n outputSchema?: AgentToolJsonSchema | undefined;\n}\n\nexport type AuthorizedIntegrationToolMap = Map<string, AuthorizedIntegrationTool>;\n\nexport interface ResolveAuthorizedToolsParams {\n request: object;\n loadLeasedAgentStep: LeasedAgentStepLoader;\n registry: IntegrationProviderRegistry;\n getIntegrationConnectionById: GetIntegrationConnectionByIdFn;\n}\n\nexport async function resolveAuthorizedIntegrationTools(\n params: ResolveAuthorizedToolsParams,\n): Promise<AuthorizedIntegrationToolMap> {\n const leasedJob = requireLeasedJobContext(params.request);\n if (!leasedJob.currentStepId || leasedJob.currentStepAttempt === undefined) {\n throw new ClientError('Lease does not identify a current step', 'lease-missing-step', {\n status: 409,\n });\n }\n\n const {step, workspaceId} = await params.loadLeasedAgentStep({\n request: params.request,\n stepId: leasedJob.currentStepId,\n attempt: leasedJob.currentStepAttempt,\n });\n if (step.type !== 'agent') {\n throw new ClientError('Current leased step is not an agent step', 'leased-step-not-agent', {\n status: 409,\n });\n }\n\n const integrations = parseAgentIntegrations(step.config);\n const authorizedTools: AuthorizedIntegrationToolMap = new Map();\n\n for (const integration of integrations) {\n const connection = await loadAuthorizedConnection({\n integration,\n workspaceId,\n registry: params.registry,\n getIntegrationConnectionById: params.getIntegrationConnectionById,\n });\n const catalog = await params.registry.getAdapter(integration.provider, 'agent_tools').catalog();\n const catalogByToolId = new Map(catalog.map((entry) => [entry.id, entry]));\n\n for (const tool of integration.tools) {\n const catalogTool = catalogByToolId.get(tool.id);\n const mcpName = mcpToolName(integration.connectionSlug, tool.id);\n if (authorizedTools.has(mcpName)) {\n throw new ClientError(\n 'Integration tool names collide after MCP namespacing',\n 'integration-tool-name-collision',\n {\n status: 409,\n },\n );\n }\n\n authorizedTools.set(mcpName, {\n mcpName,\n integration,\n tool,\n connection,\n // The live catalog enriches display metadata only. Frozen step config remains the allowlist.\n description: catalogTool?.description ?? tool.id,\n inputSchema: tool.methods ? toolInputSchema(tool) : tool.inputSchema,\n outputSchema: tool.outputSchema ?? catalogTool?.outputSchema,\n });\n }\n }\n\n return authorizedTools;\n}\n\nexport function sanitizeSlug(slug: string): string {\n return slug.replaceAll('-', '_');\n}\n\nexport function mcpToolName(connectionSlug: string, toolId: string): string {\n return `${sanitizeSlug(connectionSlug)}__${toolId}`;\n}\n\nexport function narrowMethodEnum(\n inputSchema: AgentToolJsonSchema,\n authorizedMethods: readonly string[],\n): AgentToolJsonSchema {\n const schema = cloneSchema(inputSchema);\n const methodSchema = getObjectProperty(schema, 'method');\n if (methodSchema) {\n narrowEnumOrConst(methodSchema, authorizedMethods);\n }\n\n // Claude rejects MCP tools with a top-level oneOf. The narrowed method enum remains the\n // authority boundary, while provider validation enforces method-specific argument shapes.\n delete schema.oneOf;\n\n return schema;\n}\n\nfunction toolInputSchema(tool: MaterializedAgentIntegrationToolConfigDto): AgentToolJsonSchema {\n const authorizedMethods = tool.methods?.map((method) => method.id) ?? [];\n return narrowMethodEnum(tool.inputSchema, authorizedMethods);\n}\n\nfunction parseAgentIntegrations(\n config: Record<string, unknown>,\n): MaterializedAgentIntegrationConfigDto[] {\n try {\n return materializedAgentStepConfigSchema.parse(config).integrations ?? [];\n } catch (error) {\n throw new ClientError('Agent step config is invalid', 'agent-step-config-invalid', {\n status: 409,\n cause: error,\n });\n }\n}\n\nasync function loadAuthorizedConnection(params: {\n integration: MaterializedAgentIntegrationConfigDto;\n workspaceId: string;\n registry: IntegrationProviderRegistry;\n getIntegrationConnectionById: GetIntegrationConnectionByIdFn;\n}): Promise<IntegrationConnection> {\n const connection = await params.getIntegrationConnectionById(params.integration.connectionId);\n if (!connection) {\n throw new ClientError(\n 'Integration connection is no longer available',\n 'integration-tool-connection-unavailable',\n {\n status: 409,\n },\n );\n }\n if (connection.workspaceId !== params.workspaceId) {\n throw new ClientError(\n 'Integration connection does not belong to the leased workspace',\n 'integration-tool-connection-unavailable',\n {\n status: 409,\n },\n );\n }\n if (connection.lifecycleStatus !== 'active') {\n throw new ClientError(\n 'Integration connection is not active',\n 'integration-tool-connection-unavailable',\n {\n status: 409,\n },\n );\n }\n if (connection.provider !== params.integration.provider) {\n throw new ClientError(\n 'Integration connection provider changed',\n 'integration-tool-connection-unavailable',\n {\n status: 409,\n },\n );\n }\n if (!providerSupportsAgentTools(params.registry, params.integration.provider)) {\n throw new ClientError(\n 'Integration provider no longer exposes agent tools',\n 'integration-tool-connection-unavailable',\n {\n status: 409,\n },\n );\n }\n\n return connection;\n}\n\nfunction providerSupportsAgentTools(\n registry: IntegrationProviderRegistry,\n provider: IntegrationProviderKind,\n): boolean {\n try {\n return registry.get(provider).capabilities.includes('agent_tools');\n } catch {\n return false;\n }\n}\n\nfunction cloneSchema(schema: AgentToolJsonSchema): AgentToolJsonSchema {\n return structuredClone(schema);\n}\n\nfunction getObjectProperty(\n schema: AgentToolJsonSchema,\n property: string,\n): AgentToolJsonSchema | null {\n const properties = schema.properties;\n if (!isRecord(properties)) return null;\n const value = properties[property];\n return isRecord(value) ? value : null;\n}\n\nfunction narrowEnumOrConst(\n schema: AgentToolJsonSchema,\n authorizedMethods: readonly string[],\n): void {\n if (Array.isArray(schema.enum)) {\n schema.enum = schema.enum.filter(\n (value): value is string => typeof value === 'string' && authorizedMethods.includes(value),\n );\n }\n if (typeof schema.const === 'string' && !authorizedMethods.includes(schema.const)) {\n delete schema.const;\n }\n}\n\nfunction isRecord(value: unknown): value is AgentToolJsonSchema {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"],"names":["materializedAgentStepConfigSchema","requireLeasedJobContext","ClientError","resolveAuthorizedIntegrationTools","params","leasedJob","request","currentStepId","currentStepAttempt","undefined","status","step","workspaceId","loadLeasedAgentStep","stepId","attempt","type","integrations","parseAgentIntegrations","config","authorizedTools","Map","integration","connection","loadAuthorizedConnection","registry","getIntegrationConnectionById","catalog","getAdapter","provider","catalogByToolId","map","entry","id","tool","tools","catalogTool","get","mcpName","mcpToolName","connectionSlug","has","set","description","inputSchema","methods","toolInputSchema","outputSchema","sanitizeSlug","slug","replaceAll","toolId","narrowMethodEnum","authorizedMethods","schema","cloneSchema","methodSchema","getObjectProperty","narrowEnumOrConst","oneOf","method","parse","error","cause","connectionId","lifecycleStatus","providerSupportsAgentTools","capabilities","includes","structuredClone","property","properties","isRecord","value","Array","isArray","enum","filter","const"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/presentation/routes/agent-tools-gateway/resolve-authorized-tools.ts"],"sourcesContent":["import {\n type MaterializedAgentIntegrationConfigDto,\n type MaterializedAgentIntegrationToolConfigDto,\n materializedAgentStepConfigSchema,\n} from '@shipfox/api-agent-dto';\nimport {requireLeasedJobContext} from '@shipfox/api-auth-context';\nimport {\n type WorkflowsModuleClient,\n workflowsInterModuleContract,\n} from '@shipfox/api-workflows-dto/inter-module';\nimport {isInterModuleKnownError} from '@shipfox/inter-module';\nimport {ClientError} from '@shipfox/node-fastify';\nimport type {IntegrationConnection} from '#core/entities/connection.js';\nimport type {IntegrationProviderKind} from '#core/entities/provider.js';\nimport type {AgentToolJsonSchema} from '#core/providers/agent-tools.js';\nimport type {IntegrationProviderRegistry} from '#core/providers/registry.js';\nimport type {GetIntegrationConnectionByIdFn} from '#db/connections.js';\n\nexport type LeasedAgentStepLoader = (params: {\n request: object;\n stepId: string;\n attempt: number;\n}) => Promise<{\n workspaceId: string;\n integrations?: MaterializedAgentIntegrationConfigDto[];\n step?: {type: string; config: Record<string, unknown>};\n}>;\n\nexport function createWorkflowsLeasedAgentStepLoader(\n workflows: WorkflowsModuleClient,\n): LeasedAgentStepLoader {\n return async ({request, stepId, attempt}) => {\n const leasedJob = requireLeasedJobContext(request);\n try {\n const context = await workflows.getLeasedAgentToolContext({\n jobId: leasedJob.jobId,\n jobExecutionId: leasedJob.jobExecutionId,\n runnerSessionId: leasedJob.runnerSessionId,\n stepId,\n attempt,\n });\n return {\n workspaceId: context.workspaceId,\n integrations: context.integrations,\n };\n } catch (error) {\n throw toLeasedAgentToolClientError(error);\n }\n };\n}\n\nfunction toLeasedAgentToolClientError(error: unknown): unknown {\n const method = workflowsInterModuleContract.methods.getLeasedAgentToolContext;\n if (!isInterModuleKnownError(method, error)) return error;\n\n const status = [\n 'step-attempt-mismatch',\n 'step-not-running',\n 'leased-step-not-agent',\n 'agent-step-config-invalid',\n ].includes(error.code)\n ? 409\n : 404;\n return new ClientError(error.code.replaceAll('-', ' '), error.code, {status});\n}\n\nexport interface AuthorizedIntegrationTool {\n mcpName: string;\n integration: MaterializedAgentIntegrationConfigDto;\n tool: MaterializedAgentIntegrationToolConfigDto;\n connection: IntegrationConnection;\n description: string;\n inputSchema: AgentToolJsonSchema;\n outputSchema?: AgentToolJsonSchema | undefined;\n}\n\nexport type AuthorizedIntegrationToolMap = Map<string, AuthorizedIntegrationTool>;\n\nexport interface ResolveAuthorizedToolsParams {\n request: object;\n loadLeasedAgentStep: LeasedAgentStepLoader;\n registry: IntegrationProviderRegistry;\n getIntegrationConnectionById: GetIntegrationConnectionByIdFn;\n}\n\nexport async function resolveAuthorizedIntegrationTools(\n params: ResolveAuthorizedToolsParams,\n): Promise<AuthorizedIntegrationToolMap> {\n const leasedJob = requireLeasedJobContext(params.request);\n if (!leasedJob.currentStepId || leasedJob.currentStepAttempt === undefined) {\n throw new ClientError('Lease does not identify a current step', 'lease-missing-step', {\n status: 409,\n });\n }\n\n const loaded = await params.loadLeasedAgentStep({\n request: params.request,\n stepId: leasedJob.currentStepId,\n attempt: leasedJob.currentStepAttempt,\n });\n const workspaceId = loaded.workspaceId;\n const integrations = loaded.integrations ?? legacyIntegrations(loaded.step);\n const authorizedTools: AuthorizedIntegrationToolMap = new Map();\n\n for (const integration of integrations) {\n const connection = await loadAuthorizedConnection({\n integration,\n workspaceId,\n registry: params.registry,\n getIntegrationConnectionById: params.getIntegrationConnectionById,\n });\n const catalog = await params.registry.getAdapter(integration.provider, 'agent_tools').catalog();\n const catalogByToolId = new Map(catalog.map((entry) => [entry.id, entry]));\n\n for (const tool of integration.tools) {\n const catalogTool = catalogByToolId.get(tool.id);\n const mcpName = mcpToolName(integration.connectionSlug, tool.id);\n if (authorizedTools.has(mcpName)) {\n throw new ClientError(\n 'Integration tool names collide after MCP namespacing',\n 'integration-tool-name-collision',\n {\n status: 409,\n },\n );\n }\n\n authorizedTools.set(mcpName, {\n mcpName,\n integration,\n tool,\n connection,\n // The live catalog enriches display metadata only. Frozen step config remains the allowlist.\n description: catalogTool?.description ?? tool.id,\n inputSchema: tool.methods ? toolInputSchema(tool) : tool.inputSchema,\n outputSchema: tool.outputSchema ?? catalogTool?.outputSchema,\n });\n }\n }\n\n return authorizedTools;\n}\n\nfunction legacyIntegrations(step: {type: string; config: Record<string, unknown>} | undefined) {\n if (step?.type !== 'agent') {\n throw new ClientError('Current leased step is not an agent step', 'leased-step-not-agent', {\n status: 409,\n });\n }\n try {\n return materializedAgentStepConfigSchema.parse(step.config).integrations ?? [];\n } catch (error) {\n throw new ClientError('Agent step config is invalid', 'agent-step-config-invalid', {\n status: 409,\n cause: error,\n });\n }\n}\n\nexport function sanitizeSlug(slug: string): string {\n return slug.replaceAll('-', '_');\n}\n\nexport function mcpToolName(connectionSlug: string, toolId: string): string {\n return `${sanitizeSlug(connectionSlug)}__${toolId}`;\n}\n\nexport function narrowMethodEnum(\n inputSchema: AgentToolJsonSchema,\n authorizedMethods: readonly string[],\n): AgentToolJsonSchema {\n const schema = cloneSchema(inputSchema);\n const methodSchema = getObjectProperty(schema, 'method');\n if (methodSchema) {\n narrowEnumOrConst(methodSchema, authorizedMethods);\n }\n\n // Claude rejects MCP tools with a top-level oneOf. The narrowed method enum remains the\n // authority boundary, while provider validation enforces method-specific argument shapes.\n delete schema.oneOf;\n\n return schema;\n}\n\nfunction toolInputSchema(tool: MaterializedAgentIntegrationToolConfigDto): AgentToolJsonSchema {\n const authorizedMethods = tool.methods?.map((method) => method.id) ?? [];\n return narrowMethodEnum(tool.inputSchema, authorizedMethods);\n}\n\nasync function loadAuthorizedConnection(params: {\n integration: MaterializedAgentIntegrationConfigDto;\n workspaceId: string;\n registry: IntegrationProviderRegistry;\n getIntegrationConnectionById: GetIntegrationConnectionByIdFn;\n}): Promise<IntegrationConnection> {\n const connection = await params.getIntegrationConnectionById(params.integration.connectionId);\n if (!connection) {\n throw new ClientError(\n 'Integration connection is no longer available',\n 'integration-tool-connection-unavailable',\n {\n status: 409,\n },\n );\n }\n if (connection.workspaceId !== params.workspaceId) {\n throw new ClientError(\n 'Integration connection does not belong to the leased workspace',\n 'integration-tool-connection-unavailable',\n {\n status: 409,\n },\n );\n }\n if (connection.lifecycleStatus !== 'active') {\n throw new ClientError(\n 'Integration connection is not active',\n 'integration-tool-connection-unavailable',\n {\n status: 409,\n },\n );\n }\n if (connection.provider !== params.integration.provider) {\n throw new ClientError(\n 'Integration connection provider changed',\n 'integration-tool-connection-unavailable',\n {\n status: 409,\n },\n );\n }\n if (!providerSupportsAgentTools(params.registry, params.integration.provider)) {\n throw new ClientError(\n 'Integration provider no longer exposes agent tools',\n 'integration-tool-connection-unavailable',\n {\n status: 409,\n },\n );\n }\n\n return connection;\n}\n\nfunction providerSupportsAgentTools(\n registry: IntegrationProviderRegistry,\n provider: IntegrationProviderKind,\n): boolean {\n try {\n return registry.get(provider).capabilities.includes('agent_tools');\n } catch {\n return false;\n }\n}\n\nfunction cloneSchema(schema: AgentToolJsonSchema): AgentToolJsonSchema {\n return structuredClone(schema);\n}\n\nfunction getObjectProperty(\n schema: AgentToolJsonSchema,\n property: string,\n): AgentToolJsonSchema | null {\n const properties = schema.properties;\n if (!isRecord(properties)) return null;\n const value = properties[property];\n return isRecord(value) ? value : null;\n}\n\nfunction narrowEnumOrConst(\n schema: AgentToolJsonSchema,\n authorizedMethods: readonly string[],\n): void {\n if (Array.isArray(schema.enum)) {\n schema.enum = schema.enum.filter(\n (value): value is string => typeof value === 'string' && authorizedMethods.includes(value),\n );\n }\n if (typeof schema.const === 'string' && !authorizedMethods.includes(schema.const)) {\n delete schema.const;\n }\n}\n\nfunction isRecord(value: unknown): value is AgentToolJsonSchema {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"],"names":["materializedAgentStepConfigSchema","requireLeasedJobContext","workflowsInterModuleContract","isInterModuleKnownError","ClientError","createWorkflowsLeasedAgentStepLoader","workflows","request","stepId","attempt","leasedJob","context","getLeasedAgentToolContext","jobId","jobExecutionId","runnerSessionId","workspaceId","integrations","error","toLeasedAgentToolClientError","method","methods","status","includes","code","replaceAll","resolveAuthorizedIntegrationTools","params","currentStepId","currentStepAttempt","undefined","loaded","loadLeasedAgentStep","legacyIntegrations","step","authorizedTools","Map","integration","connection","loadAuthorizedConnection","registry","getIntegrationConnectionById","catalog","getAdapter","provider","catalogByToolId","map","entry","id","tool","tools","catalogTool","get","mcpName","mcpToolName","connectionSlug","has","set","description","inputSchema","toolInputSchema","outputSchema","type","parse","config","cause","sanitizeSlug","slug","toolId","narrowMethodEnum","authorizedMethods","schema","cloneSchema","methodSchema","getObjectProperty","narrowEnumOrConst","oneOf","connectionId","lifecycleStatus","providerSupportsAgentTools","capabilities","structuredClone","property","properties","isRecord","value","Array","isArray","enum","filter","const"],"mappings":"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"}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
+
import type { WorkflowsModuleClient } from '@shipfox/api-workflows-dto/inter-module';
|
|
1
2
|
import type { RouteExport } from '@shipfox/node-fastify';
|
|
2
3
|
import type { IntegrationProviderRegistry } from '#core/providers/registry.js';
|
|
3
4
|
import type { IntegrationSourceControlService } from '#core/source-control-service.js';
|
|
4
5
|
import type { GetIntegrationConnectionByIdFn } from '#db/connections.js';
|
|
5
|
-
import { type LeasedAgentStepLoader } from './agent-tools-gateway/index.js';
|
|
6
|
-
export type { LeasedAgentStepLoader } from './agent-tools-gateway/index.js';
|
|
7
6
|
export interface CreateIntegrationRoutesOptions {
|
|
8
7
|
agentTools?: {
|
|
9
|
-
|
|
8
|
+
workflows: WorkflowsModuleClient;
|
|
10
9
|
getIntegrationConnectionById: GetIntegrationConnectionByIdFn;
|
|
11
10
|
} | undefined;
|
|
12
11
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAC,2BAA2B,EAAC,MAAM,6BAA6B,CAAC;AAC7E,OAAO,KAAK,EAAC,+BAA+B,EAAC,MAAM,iCAAiC,CAAC;AACrF,OAAO,KAAK,EAAC,8BAA8B,EAAC,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/presentation/routes/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,yCAAyC,CAAC;AACnF,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAC,2BAA2B,EAAC,MAAM,6BAA6B,CAAC;AAC7E,OAAO,KAAK,EAAC,+BAA+B,EAAC,MAAM,iCAAiC,CAAC;AACrF,OAAO,KAAK,EAAC,8BAA8B,EAAC,MAAM,oBAAoB,CAAC;AAavE,MAAM,WAAW,8BAA8B;IAC7C,UAAU,CAAC,EACP;QACE,SAAS,EAAE,qBAAqB,CAAC;QACjC,4BAA4B,EAAE,8BAA8B,CAAC;KAC9D,GACD,SAAS,CAAC;CACf;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,2BAA2B,EACrC,aAAa,EAAE,+BAA+B,EAC9C,OAAO,GAAE,8BAAmC,GAC3C,WAAW,EAAE,CAqBf"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createAgentToolsGatewayRoutes } from './agent-tools-gateway/index.js';
|
|
1
|
+
import { createAgentToolsGatewayRoutes, createWorkflowsLeasedAgentStepLoader } from './agent-tools-gateway/index.js';
|
|
2
2
|
import { createListIntegrationConnectionsRoute } from './list-connections.js';
|
|
3
3
|
import { createListIntegrationProvidersRoute } from './list-providers.js';
|
|
4
4
|
import { createListRepositoriesRoute } from './list-repositories.js';
|
|
@@ -8,7 +8,7 @@ export function createIntegrationRoutes(registry, sourceControl, options = {}) {
|
|
|
8
8
|
const agentToolsRoutes = options.agentTools ? [
|
|
9
9
|
createAgentToolsGatewayRoutes({
|
|
10
10
|
registry,
|
|
11
|
-
loadLeasedAgentStep: options.agentTools.
|
|
11
|
+
loadLeasedAgentStep: createWorkflowsLeasedAgentStepLoader(options.agentTools.workflows),
|
|
12
12
|
getIntegrationConnectionById: options.agentTools.getIntegrationConnectionById
|
|
13
13
|
})
|
|
14
14
|
] : [];
|
|
@@ -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
|
|
1
|
+
{"version":3,"sources":["../../../src/presentation/routes/index.ts"],"sourcesContent":["import type {WorkflowsModuleClient} from '@shipfox/api-workflows-dto/inter-module';\nimport 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 createWorkflowsLeasedAgentStepLoader,\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 interface CreateIntegrationRoutesOptions {\n agentTools?:\n | {\n workflows: WorkflowsModuleClient;\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: createWorkflowsLeasedAgentStepLoader(options.agentTools.workflows),\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","createWorkflowsLeasedAgentStepLoader","createListIntegrationConnectionsRoute","createListIntegrationProvidersRoute","createListRepositoriesRoute","createDeleteIntegrationConnectionRoute","createUpdateIntegrationConnectionRoute","createIntegrationRoutes","registry","sourceControl","options","providerRoutes","list","flatMap","provider","routes","agentToolsRoutes","agentTools","loadLeasedAgentStep","workflows","getIntegrationConnectionById"],"mappings":"AAKA,SACEA,6BAA6B,EAC7BC,oCAAoC,QAC/B,iCAAiC;AACxC,SAAQC,qCAAqC,QAAO,wBAAwB;AAC5E,SAAQC,mCAAmC,QAAO,sBAAsB;AACxE,SAAQC,2BAA2B,QAAO,yBAAyB;AACnE,SACEC,sCAAsC,EACtCC,sCAAsC,QACjC,0BAA0B;AAWjC,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;QACEjB,8BAA8B;YAC5BQ;YACAU,qBAAqBjB,qCAAqCS,QAAQO,UAAU,CAACE,SAAS;YACtFC,8BAA8BV,QAAQO,UAAU,CAACG,4BAA4B;QAC/E;KACD,GACD,EAAE;IAEN,OAAO;QACLjB,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":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gitea.d.ts","sourceRoot":"","sources":["../../src/providers/gitea.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAyB,yBAAyB,EAAC,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"gitea.d.ts","sourceRoot":"","sources":["../../src/providers/gitea.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAyB,yBAAyB,EAAC,MAAM,qBAAqB,CAAC;AAuF3F,eAAO,MAAM,mBAAmB,EAAE,yBAIjC,CAAC"}
|