@tangle-network/agent-integrations 0.25.1 → 0.25.3
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/README.md +28 -5
- package/dist/bin/tangle-catalog-runtime.js +5 -1
- package/dist/bin/tangle-catalog-runtime.js.map +1 -1
- package/dist/catalog.d.ts +4 -0
- package/dist/catalog.js +15 -0
- package/dist/catalog.js.map +1 -0
- package/dist/chunk-376UBTNB.js +1 -0
- package/dist/chunk-376UBTNB.js.map +1 -0
- package/dist/chunk-6KWCC42J.js +120 -0
- package/dist/chunk-6KWCC42J.js.map +1 -0
- package/dist/chunk-FQAT4IEE.js +246 -0
- package/dist/chunk-FQAT4IEE.js.map +1 -0
- package/dist/chunk-IDX3KIPA.js +3233 -0
- package/dist/chunk-IDX3KIPA.js.map +1 -0
- package/dist/{chunk-VJ57GPYO.js → chunk-MU3UTIOX.js} +3234 -6787
- package/dist/chunk-MU3UTIOX.js.map +1 -0
- package/dist/connectors/adapters/index.d.ts +1 -0
- package/dist/connectors/adapters/index.js +39 -0
- package/dist/connectors/adapters/index.js.map +1 -0
- package/dist/connectors/index.d.ts +180 -0
- package/dist/connectors/index.js +74 -0
- package/dist/connectors/index.js.map +1 -0
- package/dist/index-BNb1A0Id.d.ts +810 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +51 -44
- package/dist/registry.d.ts +1982 -0
- package/dist/registry.js +20 -0
- package/dist/registry.js.map +1 -0
- package/dist/runtime.d.ts +4 -0
- package/dist/runtime.js +12 -0
- package/dist/runtime.js.map +1 -0
- package/dist/specs.d.ts +4 -2962
- package/dist/tangle-catalog-runtime.d.ts +4 -0
- package/dist/tangle-catalog-runtime.js +22 -0
- package/dist/tangle-catalog-runtime.js.map +1 -0
- package/docs/adapter-triage.md +1 -1
- package/docs/platform-control-plane.md +54 -0
- package/docs/product-hub-ownership.md +126 -0
- package/docs/production-completion-checklist.md +2 -0
- package/docs/provider-decision-matrix.md +3 -3
- package/examples/calendar-exercise-app.ts +3 -3
- package/package.json +40 -12
- package/dist/chunk-VJ57GPYO.js.map +0 -1
package/README.md
CHANGED
|
@@ -25,6 +25,7 @@ provider SDK.
|
|
|
25
25
|
- [Product Adoption](#product-adoption)
|
|
26
26
|
- [Provider Strategy](#provider-strategy)
|
|
27
27
|
- [Executable Coverage](#executable-coverage)
|
|
28
|
+
- [Product Hub Ownership](#product-hub-ownership)
|
|
28
29
|
- [Examples](#examples)
|
|
29
30
|
- [Security Model](#security-model)
|
|
30
31
|
- [Development](#development)
|
|
@@ -48,9 +49,9 @@ provider SDK.
|
|
|
48
49
|
executable backend state explicit.
|
|
49
50
|
- A canonical registry that deduplicates overlapping catalogs, keeps support
|
|
50
51
|
tiers explicit, and reports auth/category conflicts.
|
|
51
|
-
- App/agent manifests, grants, and sandbox bundles so
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
- App/agent manifests, grants, and sandbox bundles so generated apps, domain
|
|
53
|
+
agents, and executor-backed runtimes can reuse the same user-owned
|
|
54
|
+
connections safely.
|
|
54
55
|
- Workflow trigger installation and normalized event dispatch for non-agent UI
|
|
55
56
|
automation, sync jobs, webhooks, and product workflows.
|
|
56
57
|
- Approval persistence, audit events, healthchecks, credential resolution,
|
|
@@ -237,6 +238,17 @@ const bundle = await runtime.buildSandboxBundle({
|
|
|
237
238
|
})
|
|
238
239
|
```
|
|
239
240
|
|
|
241
|
+
Installed apps and published templates can bind to explicit pre-created grants:
|
|
242
|
+
|
|
243
|
+
```ts
|
|
244
|
+
const bundle = await runtime.buildSandboxBundle({
|
|
245
|
+
grantIds: ['grant_calendar_read'],
|
|
246
|
+
grantee: { type: 'app', id: installedAppId },
|
|
247
|
+
subject: { type: 'sandbox', id: sandboxId },
|
|
248
|
+
ttlMs: 15 * 60_000,
|
|
249
|
+
})
|
|
250
|
+
```
|
|
251
|
+
|
|
240
252
|
Generated apps and sandboxes receive scoped capability tokens and tool
|
|
241
253
|
definitions. They never receive OAuth refresh tokens, API keys, or raw secrets.
|
|
242
254
|
For sandbox processes, pass the bundle through `buildIntegrationBridgeEnvironment()`;
|
|
@@ -246,7 +258,7 @@ Generated app code should use the tiny client instead of raw provider tokens:
|
|
|
246
258
|
|
|
247
259
|
```ts
|
|
248
260
|
const integrations = createTangleIntegrationsClient({
|
|
249
|
-
endpoint: 'https://
|
|
261
|
+
endpoint: 'https://integrations.example.com',
|
|
250
262
|
env: process.env,
|
|
251
263
|
})
|
|
252
264
|
|
|
@@ -271,7 +283,18 @@ lets the product dispatch normalized events to UI workflows, sync jobs, or
|
|
|
271
283
|
agent runs.
|
|
272
284
|
|
|
273
285
|
For a full product checklist, see
|
|
274
|
-
[External Product Integration](./docs/external-product-integration.md)
|
|
286
|
+
[External Product Integration](./docs/external-product-integration.md) and
|
|
287
|
+
[Platform Control Plane Adoption](./docs/platform-control-plane.md).
|
|
288
|
+
|
|
289
|
+
## Product Hub Ownership
|
|
290
|
+
|
|
291
|
+
Use a hosted hub when multiple apps intentionally share identity, billing,
|
|
292
|
+
consent, and connection custody. Use a product-owned hub when a standalone
|
|
293
|
+
deployment needs its own customer boundary, OAuth branding, vault, policy, or
|
|
294
|
+
data residency. Both modes use the same package contracts.
|
|
295
|
+
|
|
296
|
+
See [Product Hub Ownership](./docs/product-hub-ownership.md) for the
|
|
297
|
+
deployment model and launch gates.
|
|
275
298
|
|
|
276
299
|
## Provider Strategy
|
|
277
300
|
|
|
@@ -4,8 +4,12 @@ import {
|
|
|
4
4
|
buildTangleCatalogRuntimePackageManifest,
|
|
5
5
|
renderTangleCatalogRuntimePnpmAddCommand,
|
|
6
6
|
startTangleCatalogRuntimeNodeServer
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-MU3UTIOX.js";
|
|
8
|
+
import "../chunk-FQAT4IEE.js";
|
|
9
|
+
import "../chunk-6KWCC42J.js";
|
|
8
10
|
import "../chunk-4JQ754PA.js";
|
|
11
|
+
import "../chunk-376UBTNB.js";
|
|
12
|
+
import "../chunk-IDX3KIPA.js";
|
|
9
13
|
|
|
10
14
|
// src/bin/tangle-catalog-runtime.ts
|
|
11
15
|
var args = new Set(process.argv.slice(2));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/bin/tangle-catalog-runtime.ts"],"sourcesContent":["#!/usr/bin/env node\nimport {\n buildTangleCatalogRuntimePackageManifest,\n renderTangleCatalogRuntimePnpmAddCommand,\n} from '../tangle-catalog.js'\nimport { auditTangleCatalogRuntimePackages } from '../tangle-catalog-runtime.js'\nimport { startTangleCatalogRuntimeNodeServer } from '../tangle-catalog-runtime-server.js'\n\nconst args = new Set(process.argv.slice(2))\nif (args.has('--print-package-json')) {\n console.log(JSON.stringify(buildTangleCatalogRuntimePackageManifest({\n agentIntegrationsVersion: process.env.TANGLE_AGENT_INTEGRATIONS_VERSION,\n }), null, 2))\n process.exit(0)\n}\n\nif (args.has('--print-pnpm-add')) {\n console.log(renderTangleCatalogRuntimePnpmAddCommand({\n agentIntegrationsVersion: process.env.TANGLE_AGENT_INTEGRATIONS_VERSION,\n }))\n process.exit(0)\n}\n\nif (args.has('--audit-packages')) {\n const connectorIds = process.env.TANGLE_CATALOG_AUDIT_CONNECTORS\n ?.split(',')\n .map((id) => id.trim())\n .filter(Boolean)\n console.log(JSON.stringify(await auditTangleCatalogRuntimePackages({ connectorIds }), null, 2))\n process.exit(0)\n}\n\nconst secret = process.env.TANGLE_CATALOG_RUNTIME_SECRET\nif (!secret || secret.length < 32) {\n console.error('TANGLE_CATALOG_RUNTIME_SECRET must be set to at least 32 characters.')\n process.exit(1)\n}\n\nconst authResolverUrl = process.env.TANGLE_CATALOG_AUTH_RESOLVER_URL\nconst authResolverSecret = process.env.TANGLE_CATALOG_AUTH_RESOLVER_SECRET\nif (Boolean(authResolverUrl) !== Boolean(authResolverSecret)) {\n console.error('TANGLE_CATALOG_AUTH_RESOLVER_URL and TANGLE_CATALOG_AUTH_RESOLVER_SECRET must be set together.')\n process.exit(1)\n}\n\nconst port = Number(process.env.PORT ?? process.env.TANGLE_CATALOG_RUNTIME_PORT ?? 4109)\nif (!Number.isInteger(port) || port < 1 || port > 65_535) {\n console.error('PORT must be an integer between 1 and 65535.')\n process.exit(1)\n}\n\nconst server = await startTangleCatalogRuntimeNodeServer({\n secret,\n host: process.env.HOST ?? process.env.TANGLE_CATALOG_RUNTIME_HOST ?? '0.0.0.0',\n port,\n authResolver: authResolverUrl && authResolverSecret\n ? {\n endpoint: authResolverUrl,\n secret: authResolverSecret,\n }\n : false,\n onLog: (event) => {\n const line = JSON.stringify({\n level: event.level,\n message: event.message,\n ...event.metadata,\n })\n if (event.level === 'error') console.error(line)\n else console.log(line)\n },\n})\n\nconsole.log(JSON.stringify({\n level: 'info',\n message: 'Tangle catalog runtime listening.',\n url: server.url,\n}))\n\nfor (const signal of ['SIGINT', 'SIGTERM'] as const) {\n process.once(signal, async () => {\n await server.close()\n process.exit(0)\n })\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../src/bin/tangle-catalog-runtime.ts"],"sourcesContent":["#!/usr/bin/env node\nimport {\n buildTangleCatalogRuntimePackageManifest,\n renderTangleCatalogRuntimePnpmAddCommand,\n} from '../tangle-catalog.js'\nimport { auditTangleCatalogRuntimePackages } from '../tangle-catalog-runtime.js'\nimport { startTangleCatalogRuntimeNodeServer } from '../tangle-catalog-runtime-server.js'\n\nconst args = new Set(process.argv.slice(2))\nif (args.has('--print-package-json')) {\n console.log(JSON.stringify(buildTangleCatalogRuntimePackageManifest({\n agentIntegrationsVersion: process.env.TANGLE_AGENT_INTEGRATIONS_VERSION,\n }), null, 2))\n process.exit(0)\n}\n\nif (args.has('--print-pnpm-add')) {\n console.log(renderTangleCatalogRuntimePnpmAddCommand({\n agentIntegrationsVersion: process.env.TANGLE_AGENT_INTEGRATIONS_VERSION,\n }))\n process.exit(0)\n}\n\nif (args.has('--audit-packages')) {\n const connectorIds = process.env.TANGLE_CATALOG_AUDIT_CONNECTORS\n ?.split(',')\n .map((id) => id.trim())\n .filter(Boolean)\n console.log(JSON.stringify(await auditTangleCatalogRuntimePackages({ connectorIds }), null, 2))\n process.exit(0)\n}\n\nconst secret = process.env.TANGLE_CATALOG_RUNTIME_SECRET\nif (!secret || secret.length < 32) {\n console.error('TANGLE_CATALOG_RUNTIME_SECRET must be set to at least 32 characters.')\n process.exit(1)\n}\n\nconst authResolverUrl = process.env.TANGLE_CATALOG_AUTH_RESOLVER_URL\nconst authResolverSecret = process.env.TANGLE_CATALOG_AUTH_RESOLVER_SECRET\nif (Boolean(authResolverUrl) !== Boolean(authResolverSecret)) {\n console.error('TANGLE_CATALOG_AUTH_RESOLVER_URL and TANGLE_CATALOG_AUTH_RESOLVER_SECRET must be set together.')\n process.exit(1)\n}\n\nconst port = Number(process.env.PORT ?? process.env.TANGLE_CATALOG_RUNTIME_PORT ?? 4109)\nif (!Number.isInteger(port) || port < 1 || port > 65_535) {\n console.error('PORT must be an integer between 1 and 65535.')\n process.exit(1)\n}\n\nconst server = await startTangleCatalogRuntimeNodeServer({\n secret,\n host: process.env.HOST ?? process.env.TANGLE_CATALOG_RUNTIME_HOST ?? '0.0.0.0',\n port,\n authResolver: authResolverUrl && authResolverSecret\n ? {\n endpoint: authResolverUrl,\n secret: authResolverSecret,\n }\n : false,\n onLog: (event) => {\n const line = JSON.stringify({\n level: event.level,\n message: event.message,\n ...event.metadata,\n })\n if (event.level === 'error') console.error(line)\n else console.log(line)\n },\n})\n\nconsole.log(JSON.stringify({\n level: 'info',\n message: 'Tangle catalog runtime listening.',\n url: server.url,\n}))\n\nfor (const signal of ['SIGINT', 'SIGTERM'] as const) {\n process.once(signal, async () => {\n await server.close()\n process.exit(0)\n })\n}\n"],"mappings":";;;;;;;;;;;;;;AAQA,IAAM,OAAO,IAAI,IAAI,QAAQ,KAAK,MAAM,CAAC,CAAC;AAC1C,IAAI,KAAK,IAAI,sBAAsB,GAAG;AACpC,UAAQ,IAAI,KAAK,UAAU,yCAAyC;AAAA,IAClE,0BAA0B,QAAQ,IAAI;AAAA,EACxC,CAAC,GAAG,MAAM,CAAC,CAAC;AACZ,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAI,KAAK,IAAI,kBAAkB,GAAG;AAChC,UAAQ,IAAI,yCAAyC;AAAA,IACnD,0BAA0B,QAAQ,IAAI;AAAA,EACxC,CAAC,CAAC;AACF,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAI,KAAK,IAAI,kBAAkB,GAAG;AAChC,QAAM,eAAe,QAAQ,IAAI,iCAC7B,MAAM,GAAG,EACV,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,EACrB,OAAO,OAAO;AACjB,UAAQ,IAAI,KAAK,UAAU,MAAM,kCAAkC,EAAE,aAAa,CAAC,GAAG,MAAM,CAAC,CAAC;AAC9F,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAM,SAAS,QAAQ,IAAI;AAC3B,IAAI,CAAC,UAAU,OAAO,SAAS,IAAI;AACjC,UAAQ,MAAM,sEAAsE;AACpF,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAM,kBAAkB,QAAQ,IAAI;AACpC,IAAM,qBAAqB,QAAQ,IAAI;AACvC,IAAI,QAAQ,eAAe,MAAM,QAAQ,kBAAkB,GAAG;AAC5D,UAAQ,MAAM,gGAAgG;AAC9G,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAM,OAAO,OAAO,QAAQ,IAAI,QAAQ,QAAQ,IAAI,+BAA+B,IAAI;AACvF,IAAI,CAAC,OAAO,UAAU,IAAI,KAAK,OAAO,KAAK,OAAO,OAAQ;AACxD,UAAQ,MAAM,8CAA8C;AAC5D,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAM,SAAS,MAAM,oCAAoC;AAAA,EACvD;AAAA,EACA,MAAM,QAAQ,IAAI,QAAQ,QAAQ,IAAI,+BAA+B;AAAA,EACrE;AAAA,EACA,cAAc,mBAAmB,qBAC7B;AAAA,IACE,UAAU;AAAA,IACV,QAAQ;AAAA,EACV,IACA;AAAA,EACJ,OAAO,CAAC,UAAU;AAChB,UAAM,OAAO,KAAK,UAAU;AAAA,MAC1B,OAAO,MAAM;AAAA,MACb,SAAS,MAAM;AAAA,MACf,GAAG,MAAM;AAAA,IACX,CAAC;AACD,QAAI,MAAM,UAAU,QAAS,SAAQ,MAAM,IAAI;AAAA,QAC1C,SAAQ,IAAI,IAAI;AAAA,EACvB;AACF,CAAC;AAED,QAAQ,IAAI,KAAK,UAAU;AAAA,EACzB,OAAO;AAAA,EACP,SAAS;AAAA,EACT,KAAK,OAAO;AACd,CAAC,CAAC;AAEF,WAAW,UAAU,CAAC,UAAU,SAAS,GAAY;AACnD,UAAQ,KAAK,QAAQ,YAAY;AAC/B,UAAM,OAAO,MAAM;AACnB,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AACH;","names":[]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { I as IntegrationToolDefinition, a as IntegrationToolSearchFilters, b as IntegrationToolSearchResult, M as McpToolDefinition, c as buildIntegrationToolCatalog, i as integrationToolName, p as parseIntegrationToolName, s as searchIntegrationTools, t as toMcpTools } from './registry.js';
|
|
2
|
+
import './index-BNb1A0Id.js';
|
|
3
|
+
import './connectors/index.js';
|
|
4
|
+
import 'node:http';
|
package/dist/catalog.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildIntegrationToolCatalog,
|
|
3
|
+
integrationToolName,
|
|
4
|
+
parseIntegrationToolName,
|
|
5
|
+
searchIntegrationTools,
|
|
6
|
+
toMcpTools
|
|
7
|
+
} from "./chunk-6KWCC42J.js";
|
|
8
|
+
export {
|
|
9
|
+
buildIntegrationToolCatalog,
|
|
10
|
+
integrationToolName,
|
|
11
|
+
parseIntegrationToolName,
|
|
12
|
+
searchIntegrationTools,
|
|
13
|
+
toMcpTools
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=chunk-376UBTNB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// src/catalog.ts
|
|
2
|
+
var riskRank = {
|
|
3
|
+
read: 0,
|
|
4
|
+
write: 1,
|
|
5
|
+
destructive: 2
|
|
6
|
+
};
|
|
7
|
+
function integrationToolName(providerId, connectorId, actionId) {
|
|
8
|
+
return `int_${encodeToolPart(providerId)}_${encodeToolPart(connectorId)}_${encodeToolPart(actionId)}`;
|
|
9
|
+
}
|
|
10
|
+
function parseIntegrationToolName(name) {
|
|
11
|
+
const parts = name.split("_");
|
|
12
|
+
if (parts.length !== 4 || parts[0] !== "int") {
|
|
13
|
+
throw new Error(`Invalid integration tool name: ${name}`);
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
providerId: decodeToolPart(parts[1]),
|
|
17
|
+
connectorId: decodeToolPart(parts[2]),
|
|
18
|
+
actionId: decodeToolPart(parts[3])
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function buildIntegrationToolCatalog(connectors) {
|
|
22
|
+
const tools = [];
|
|
23
|
+
for (const connector of connectors) {
|
|
24
|
+
for (const action of connector.actions) {
|
|
25
|
+
const tags = unique([
|
|
26
|
+
connector.id,
|
|
27
|
+
connector.providerId,
|
|
28
|
+
connector.title,
|
|
29
|
+
connector.category,
|
|
30
|
+
action.id,
|
|
31
|
+
action.title,
|
|
32
|
+
action.risk,
|
|
33
|
+
action.dataClass,
|
|
34
|
+
...connector.scopes ?? [],
|
|
35
|
+
...action.requiredScopes ?? []
|
|
36
|
+
].flatMap(tokenize));
|
|
37
|
+
tools.push({
|
|
38
|
+
name: integrationToolName(connector.providerId, connector.id, action.id),
|
|
39
|
+
title: `${connector.title}: ${action.title}`,
|
|
40
|
+
description: action.description ?? `${action.risk} action ${action.id} on ${connector.title}`,
|
|
41
|
+
providerId: connector.providerId,
|
|
42
|
+
connectorId: connector.id,
|
|
43
|
+
connectorTitle: connector.title,
|
|
44
|
+
category: connector.category,
|
|
45
|
+
action,
|
|
46
|
+
risk: action.risk,
|
|
47
|
+
dataClass: action.dataClass,
|
|
48
|
+
requiredScopes: action.requiredScopes,
|
|
49
|
+
inputSchema: action.inputSchema,
|
|
50
|
+
outputSchema: action.outputSchema,
|
|
51
|
+
tags
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return tools;
|
|
56
|
+
}
|
|
57
|
+
function searchIntegrationTools(catalog, query, filters = {}) {
|
|
58
|
+
const terms = tokenize(query);
|
|
59
|
+
const filtered = catalog.filter((tool) => {
|
|
60
|
+
if (filters.providerId && tool.providerId !== filters.providerId) return false;
|
|
61
|
+
if (filters.connectorId && tool.connectorId !== filters.connectorId) return false;
|
|
62
|
+
if (filters.category && tool.category !== filters.category) return false;
|
|
63
|
+
if (filters.dataClass && tool.dataClass !== filters.dataClass) return false;
|
|
64
|
+
if (filters.maxRisk && riskRank[tool.risk] > riskRank[filters.maxRisk]) return false;
|
|
65
|
+
return true;
|
|
66
|
+
});
|
|
67
|
+
const scored = filtered.map((tool) => scoreTool(tool, terms));
|
|
68
|
+
return scored.filter((result) => terms.length === 0 || result.score > 0).sort((a, b) => b.score - a.score || a.tool.name.localeCompare(b.tool.name)).slice(0, filters.limit ?? 20);
|
|
69
|
+
}
|
|
70
|
+
function toMcpTools(tools) {
|
|
71
|
+
return tools.map((tool) => ({
|
|
72
|
+
name: tool.name,
|
|
73
|
+
description: `${tool.title}. ${tool.description}`,
|
|
74
|
+
inputSchema: tool.inputSchema ?? {
|
|
75
|
+
type: "object",
|
|
76
|
+
additionalProperties: true,
|
|
77
|
+
properties: {}
|
|
78
|
+
}
|
|
79
|
+
}));
|
|
80
|
+
}
|
|
81
|
+
function scoreTool(tool, terms) {
|
|
82
|
+
if (terms.length === 0) return { tool, score: 1, matched: [] };
|
|
83
|
+
const haystack = new Set(tool.tags);
|
|
84
|
+
const matched = [];
|
|
85
|
+
let score = 0;
|
|
86
|
+
for (const term of terms) {
|
|
87
|
+
if (haystack.has(term)) {
|
|
88
|
+
matched.push(term);
|
|
89
|
+
score += 4;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (tool.tags.some((tag) => tag.includes(term))) {
|
|
93
|
+
matched.push(term);
|
|
94
|
+
score += 1;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (tool.risk === "read") score += 0.25;
|
|
98
|
+
return { tool, score, matched: unique(matched) };
|
|
99
|
+
}
|
|
100
|
+
function tokenize(value) {
|
|
101
|
+
return value.toLowerCase().split(/[^a-z0-9]+/g).map((part) => part.trim()).filter(Boolean);
|
|
102
|
+
}
|
|
103
|
+
function encodeToolPart(value) {
|
|
104
|
+
return Buffer.from(value, "utf8").toString("base64url").replace(/_/g, ".");
|
|
105
|
+
}
|
|
106
|
+
function decodeToolPart(value) {
|
|
107
|
+
return Buffer.from(value.replace(/\./g, "_"), "base64url").toString("utf8");
|
|
108
|
+
}
|
|
109
|
+
function unique(values) {
|
|
110
|
+
return [...new Set(values)];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export {
|
|
114
|
+
integrationToolName,
|
|
115
|
+
parseIntegrationToolName,
|
|
116
|
+
buildIntegrationToolCatalog,
|
|
117
|
+
searchIntegrationTools,
|
|
118
|
+
toMcpTools
|
|
119
|
+
};
|
|
120
|
+
//# sourceMappingURL=chunk-6KWCC42J.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/catalog.ts"],"sourcesContent":["import type {\n IntegrationConnector,\n IntegrationConnectorAction,\n IntegrationConnectorCategory,\n IntegrationActionRisk,\n IntegrationDataClass,\n} from './index.js'\n\nexport interface IntegrationToolDefinition {\n name: string\n title: string\n description: string\n providerId: string\n connectorId: string\n connectorTitle: string\n category: IntegrationConnectorCategory\n action: IntegrationConnectorAction\n risk: IntegrationActionRisk\n dataClass: IntegrationDataClass\n requiredScopes: string[]\n inputSchema?: unknown\n outputSchema?: unknown\n tags: string[]\n}\n\nexport interface IntegrationToolSearchFilters {\n providerId?: string\n connectorId?: string\n category?: IntegrationConnectorCategory\n maxRisk?: IntegrationActionRisk\n dataClass?: IntegrationDataClass\n limit?: number\n}\n\nexport interface IntegrationToolSearchResult {\n tool: IntegrationToolDefinition\n score: number\n matched: string[]\n}\n\nexport interface McpToolDefinition {\n name: string\n description: string\n inputSchema: unknown\n}\n\nconst riskRank: Record<IntegrationActionRisk, number> = {\n read: 0,\n write: 1,\n destructive: 2,\n}\n\nexport function integrationToolName(providerId: string, connectorId: string, actionId: string): string {\n return `int_${encodeToolPart(providerId)}_${encodeToolPart(connectorId)}_${encodeToolPart(actionId)}`\n}\n\nexport function parseIntegrationToolName(name: string): { providerId: string; connectorId: string; actionId: string } {\n const parts = name.split('_')\n if (parts.length !== 4 || parts[0] !== 'int') {\n throw new Error(`Invalid integration tool name: ${name}`)\n }\n return {\n providerId: decodeToolPart(parts[1]),\n connectorId: decodeToolPart(parts[2]),\n actionId: decodeToolPart(parts[3]),\n }\n}\n\nexport function buildIntegrationToolCatalog(connectors: IntegrationConnector[]): IntegrationToolDefinition[] {\n const tools: IntegrationToolDefinition[] = []\n for (const connector of connectors) {\n for (const action of connector.actions) {\n const tags = unique([\n connector.id,\n connector.providerId,\n connector.title,\n connector.category,\n action.id,\n action.title,\n action.risk,\n action.dataClass,\n ...(connector.scopes ?? []),\n ...(action.requiredScopes ?? []),\n ].flatMap(tokenize))\n tools.push({\n name: integrationToolName(connector.providerId, connector.id, action.id),\n title: `${connector.title}: ${action.title}`,\n description: action.description ?? `${action.risk} action ${action.id} on ${connector.title}`,\n providerId: connector.providerId,\n connectorId: connector.id,\n connectorTitle: connector.title,\n category: connector.category,\n action,\n risk: action.risk,\n dataClass: action.dataClass,\n requiredScopes: action.requiredScopes,\n inputSchema: action.inputSchema,\n outputSchema: action.outputSchema,\n tags,\n })\n }\n }\n return tools\n}\n\nexport function searchIntegrationTools(\n catalog: IntegrationToolDefinition[],\n query: string,\n filters: IntegrationToolSearchFilters = {},\n): IntegrationToolSearchResult[] {\n const terms = tokenize(query)\n const filtered = catalog.filter((tool) => {\n if (filters.providerId && tool.providerId !== filters.providerId) return false\n if (filters.connectorId && tool.connectorId !== filters.connectorId) return false\n if (filters.category && tool.category !== filters.category) return false\n if (filters.dataClass && tool.dataClass !== filters.dataClass) return false\n if (filters.maxRisk && riskRank[tool.risk] > riskRank[filters.maxRisk]) return false\n return true\n })\n const scored = filtered.map((tool) => scoreTool(tool, terms))\n return scored\n .filter((result) => terms.length === 0 || result.score > 0)\n .sort((a, b) => b.score - a.score || a.tool.name.localeCompare(b.tool.name))\n .slice(0, filters.limit ?? 20)\n}\n\nexport function toMcpTools(tools: IntegrationToolDefinition[]): McpToolDefinition[] {\n return tools.map((tool) => ({\n name: tool.name,\n description: `${tool.title}. ${tool.description}`,\n inputSchema: tool.inputSchema ?? {\n type: 'object',\n additionalProperties: true,\n properties: {},\n },\n }))\n}\n\nfunction scoreTool(tool: IntegrationToolDefinition, terms: string[]): IntegrationToolSearchResult {\n if (terms.length === 0) return { tool, score: 1, matched: [] }\n const haystack = new Set(tool.tags)\n const matched: string[] = []\n let score = 0\n for (const term of terms) {\n if (haystack.has(term)) {\n matched.push(term)\n score += 4\n continue\n }\n if (tool.tags.some((tag) => tag.includes(term))) {\n matched.push(term)\n score += 1\n }\n }\n if (tool.risk === 'read') score += 0.25\n return { tool, score, matched: unique(matched) }\n}\n\nfunction tokenize(value: string): string[] {\n return value\n .toLowerCase()\n .split(/[^a-z0-9]+/g)\n .map((part) => part.trim())\n .filter(Boolean)\n}\n\nfunction encodeToolPart(value: string): string {\n return Buffer.from(value, 'utf8').toString('base64url').replace(/_/g, '.')\n}\n\nfunction decodeToolPart(value: string): string {\n return Buffer.from(value.replace(/\\./g, '_'), 'base64url').toString('utf8')\n}\n\nfunction unique<T>(values: T[]): T[] {\n return [...new Set(values)]\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildIntegrationToolCatalog
|
|
3
|
+
} from "./chunk-6KWCC42J.js";
|
|
4
|
+
|
|
5
|
+
// src/runtime.ts
|
|
6
|
+
var InMemoryIntegrationGrantStore = class {
|
|
7
|
+
grants = /* @__PURE__ */ new Map();
|
|
8
|
+
get(grantId) {
|
|
9
|
+
return this.grants.get(grantId);
|
|
10
|
+
}
|
|
11
|
+
put(grant) {
|
|
12
|
+
this.grants.set(grant.id, grant);
|
|
13
|
+
}
|
|
14
|
+
listByManifest(manifestId, grantee) {
|
|
15
|
+
return [...this.grants.values()].filter(
|
|
16
|
+
(grant) => grant.manifestId === manifestId && (!grantee || sameActor(grant.grantee, grantee))
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
listByGrantee(grantee) {
|
|
20
|
+
return [...this.grants.values()].filter((grant) => sameActor(grant.grantee, grantee));
|
|
21
|
+
}
|
|
22
|
+
listByIds(grantIds) {
|
|
23
|
+
const wanted = new Set(grantIds);
|
|
24
|
+
return [...this.grants.values()].filter((grant) => wanted.has(grant.id));
|
|
25
|
+
}
|
|
26
|
+
delete(grantId) {
|
|
27
|
+
this.grants.delete(grantId);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
var IntegrationRuntime = class {
|
|
31
|
+
hub;
|
|
32
|
+
grants;
|
|
33
|
+
now;
|
|
34
|
+
constructor(options) {
|
|
35
|
+
this.hub = options.hub;
|
|
36
|
+
this.grants = options.grants ?? new InMemoryIntegrationGrantStore();
|
|
37
|
+
this.now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
38
|
+
}
|
|
39
|
+
async registry() {
|
|
40
|
+
return this.hub.listRegistry();
|
|
41
|
+
}
|
|
42
|
+
async resolveManifest(manifest, owner) {
|
|
43
|
+
const registry = await this.registry();
|
|
44
|
+
const connections = await this.hub.listConnections(owner);
|
|
45
|
+
const resolutions = manifest.requirements.map(
|
|
46
|
+
(requirement) => resolveRequirement(requirement, owner, registry, connections)
|
|
47
|
+
);
|
|
48
|
+
return {
|
|
49
|
+
manifest,
|
|
50
|
+
owner,
|
|
51
|
+
ready: resolutions.filter((resolution) => resolution.status === "ready"),
|
|
52
|
+
missing: resolutions.filter((resolution) => resolution.status !== "ready" && !resolution.requirement.optional),
|
|
53
|
+
optionalMissing: resolutions.filter((resolution) => resolution.status !== "ready" && resolution.requirement.optional === true)
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
async createGrants(input) {
|
|
57
|
+
const resolution = await this.resolveManifest(input.manifest, input.owner);
|
|
58
|
+
if (resolution.missing.length > 0) {
|
|
59
|
+
throw new Error(`Cannot create integration grants; missing requirements: ${resolution.missing.map((r) => r.requirement.id).join(", ")}`);
|
|
60
|
+
}
|
|
61
|
+
const now = this.now().toISOString();
|
|
62
|
+
const grants = resolution.ready.map((ready) => ({
|
|
63
|
+
id: `grant_${input.manifest.id}_${ready.requirement.id}_${ready.connection.id}`,
|
|
64
|
+
manifestId: input.manifest.id,
|
|
65
|
+
requirementId: ready.requirement.id,
|
|
66
|
+
owner: input.owner,
|
|
67
|
+
grantee: input.grantee,
|
|
68
|
+
connectionId: ready.connection.id,
|
|
69
|
+
connectorId: ready.connector.id,
|
|
70
|
+
scopes: requiredScopes(ready.requirement, ready.connector),
|
|
71
|
+
allowedActions: requiredActions(ready.requirement, ready.connector),
|
|
72
|
+
allowedTriggers: requiredTriggers(ready.requirement, ready.connector),
|
|
73
|
+
status: "active",
|
|
74
|
+
createdAt: now,
|
|
75
|
+
updatedAt: now,
|
|
76
|
+
metadata: input.metadata
|
|
77
|
+
}));
|
|
78
|
+
for (const grant of grants) await this.grants.put(grant);
|
|
79
|
+
return grants;
|
|
80
|
+
}
|
|
81
|
+
async buildSandboxBundle(input) {
|
|
82
|
+
const grants = await this.resolveBundleGrants(input);
|
|
83
|
+
const registry = await this.registry();
|
|
84
|
+
const bindings = [];
|
|
85
|
+
const connectors = [];
|
|
86
|
+
let expiresAt = "";
|
|
87
|
+
for (const grant of grants) {
|
|
88
|
+
const entry = registry.byId.get(grant.connectorId);
|
|
89
|
+
if (!entry) continue;
|
|
90
|
+
const connector = {
|
|
91
|
+
...entry.connector,
|
|
92
|
+
actions: entry.connector.actions.filter((action) => grant.allowedActions.includes(action.id)),
|
|
93
|
+
triggers: entry.connector.triggers?.filter((trigger) => grant.allowedTriggers.includes(trigger.id)),
|
|
94
|
+
scopes: entry.connector.scopes.filter((scope) => grant.scopes.includes(scope))
|
|
95
|
+
};
|
|
96
|
+
const capability = await this.hub.issueCapability({
|
|
97
|
+
subject: input.subject,
|
|
98
|
+
connectionId: grant.connectionId,
|
|
99
|
+
scopes: grant.scopes,
|
|
100
|
+
allowedActions: grant.allowedActions,
|
|
101
|
+
ttlMs: input.ttlMs,
|
|
102
|
+
metadata: {
|
|
103
|
+
manifestId: grant.manifestId,
|
|
104
|
+
grantId: grant.id,
|
|
105
|
+
requirementId: grant.requirementId
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
bindings.push({
|
|
109
|
+
requirementId: grant.requirementId,
|
|
110
|
+
connectorId: grant.connectorId,
|
|
111
|
+
connectionId: grant.connectionId,
|
|
112
|
+
grantId: grant.id,
|
|
113
|
+
scopes: grant.scopes,
|
|
114
|
+
allowedActions: grant.allowedActions,
|
|
115
|
+
allowedTriggers: grant.allowedTriggers,
|
|
116
|
+
capability
|
|
117
|
+
});
|
|
118
|
+
connectors.push(connector);
|
|
119
|
+
expiresAt = capability.capability.expiresAt;
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
manifestId: input.manifestId ?? grants[0]?.manifestId ?? "explicit-grants",
|
|
123
|
+
subject: input.subject,
|
|
124
|
+
capabilities: bindings,
|
|
125
|
+
connectors,
|
|
126
|
+
tools: buildIntegrationToolCatalog(connectors),
|
|
127
|
+
expiresAt
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
async resolveBundleGrants(input) {
|
|
131
|
+
if (input.grantIds?.length) {
|
|
132
|
+
const uniqueGrantIds = unique(input.grantIds);
|
|
133
|
+
const grants = this.grants.listByIds ? await this.grants.listByIds(uniqueGrantIds) : await Promise.all(uniqueGrantIds.map((grantId) => this.grants.get(grantId)));
|
|
134
|
+
const found = grants.filter((grant) => Boolean(grant));
|
|
135
|
+
const foundIds = new Set(found.map((grant) => grant.id));
|
|
136
|
+
const missing2 = uniqueGrantIds.filter((grantId) => !foundIds.has(grantId));
|
|
137
|
+
if (missing2.length > 0) {
|
|
138
|
+
throw new Error(`Cannot build integration bundle; unknown grant id(s): ${missing2.join(", ")}`);
|
|
139
|
+
}
|
|
140
|
+
const badGrantee = input.grantee ? found.find((grant) => !sameActor(grant.grantee, input.grantee)) : void 0;
|
|
141
|
+
if (badGrantee) {
|
|
142
|
+
throw new Error(`Cannot build integration bundle; grant ${badGrantee.id} belongs to a different grantee.`);
|
|
143
|
+
}
|
|
144
|
+
const badManifest = input.manifestId ? found.find((grant) => grant.manifestId !== input.manifestId) : void 0;
|
|
145
|
+
if (badManifest) {
|
|
146
|
+
throw new Error(`Cannot build integration bundle; grant ${badManifest.id} is not for manifest ${input.manifestId}.`);
|
|
147
|
+
}
|
|
148
|
+
return found.filter((grant) => grant.status === "active");
|
|
149
|
+
}
|
|
150
|
+
if (!input.manifestId) {
|
|
151
|
+
throw new Error("Cannot build integration bundle; manifestId or grantIds is required.");
|
|
152
|
+
}
|
|
153
|
+
return (await this.grants.listByManifest(input.manifestId, input.grantee)).filter((grant) => grant.status === "active");
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
function createIntegrationRuntime(options) {
|
|
157
|
+
return new IntegrationRuntime(options);
|
|
158
|
+
}
|
|
159
|
+
function resolveRequirement(requirement, owner, registry, connections) {
|
|
160
|
+
const entry = registry.byId.get(requirement.connectorId);
|
|
161
|
+
if (!entry) {
|
|
162
|
+
return missing(requirement, "unknown_connector", `Unknown connector ${requirement.connectorId}.`);
|
|
163
|
+
}
|
|
164
|
+
const connector = entry.connector;
|
|
165
|
+
if (connector.actions.length === 0 && (connector.triggers?.length ?? 0) === 0) {
|
|
166
|
+
return missing(requirement, "not_executable", `${connector.title} is catalog-only and cannot be invoked yet.`, connector, entry);
|
|
167
|
+
}
|
|
168
|
+
const scopes = requiredScopes(requirement, connector);
|
|
169
|
+
const actions = requiredActions(requirement, connector);
|
|
170
|
+
const triggers = requiredTriggers(requirement, connector);
|
|
171
|
+
const connection = connections.find(
|
|
172
|
+
(candidate) => sameActor(candidate.owner, owner) && candidate.status === "active" && (candidate.connectorId === connector.id || entry.aliases.includes(candidate.connectorId)) && scopes.every((scope) => candidate.grantedScopes.includes(scope))
|
|
173
|
+
);
|
|
174
|
+
if (!connection) {
|
|
175
|
+
return {
|
|
176
|
+
requirement,
|
|
177
|
+
status: "missing_connection",
|
|
178
|
+
connector,
|
|
179
|
+
registryEntry: entry,
|
|
180
|
+
missingScopes: scopes,
|
|
181
|
+
missingActions: actions,
|
|
182
|
+
missingTriggers: triggers,
|
|
183
|
+
message: `${connector.title} needs an active user connection with the required scopes.`
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
requirement,
|
|
188
|
+
status: "ready",
|
|
189
|
+
connector,
|
|
190
|
+
registryEntry: entry,
|
|
191
|
+
connection,
|
|
192
|
+
missingScopes: [],
|
|
193
|
+
missingActions: [],
|
|
194
|
+
missingTriggers: [],
|
|
195
|
+
message: `${connector.title} is ready.`
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
function missing(requirement, status, message, connector, registryEntry) {
|
|
199
|
+
return {
|
|
200
|
+
requirement,
|
|
201
|
+
status,
|
|
202
|
+
connector,
|
|
203
|
+
registryEntry,
|
|
204
|
+
missingScopes: [],
|
|
205
|
+
missingActions: [],
|
|
206
|
+
missingTriggers: [],
|
|
207
|
+
message
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
function requiredActions(requirement, connector) {
|
|
211
|
+
if (requirement.mode === "trigger") return [];
|
|
212
|
+
if (requirement.requiredActions?.length) return unique(requirement.requiredActions);
|
|
213
|
+
const actions = connector.actions.filter((action) => {
|
|
214
|
+
if (requirement.mode === "read") return action.risk === "read";
|
|
215
|
+
if (requirement.mode === "write") return action.risk !== "read";
|
|
216
|
+
return false;
|
|
217
|
+
});
|
|
218
|
+
return unique(actions.map((action) => action.id));
|
|
219
|
+
}
|
|
220
|
+
function requiredTriggers(requirement, connector) {
|
|
221
|
+
if (requirement.requiredTriggers?.length) return unique(requirement.requiredTriggers);
|
|
222
|
+
if (requirement.mode !== "trigger") return [];
|
|
223
|
+
return unique((connector.triggers ?? []).map((trigger) => trigger.id));
|
|
224
|
+
}
|
|
225
|
+
function requiredScopes(requirement, connector) {
|
|
226
|
+
if (requirement.requiredScopes?.length) return unique(requirement.requiredScopes);
|
|
227
|
+
const actionIds = new Set(requiredActions(requirement, connector));
|
|
228
|
+
const triggerIds = new Set(requiredTriggers(requirement, connector));
|
|
229
|
+
return unique([
|
|
230
|
+
...connector.actions.filter((action) => actionIds.has(action.id)).flatMap((action) => action.requiredScopes),
|
|
231
|
+
...(connector.triggers ?? []).filter((trigger) => triggerIds.has(trigger.id)).flatMap((trigger) => trigger.requiredScopes)
|
|
232
|
+
]);
|
|
233
|
+
}
|
|
234
|
+
function sameActor(a, b) {
|
|
235
|
+
return a.type === b.type && a.id === b.id;
|
|
236
|
+
}
|
|
237
|
+
function unique(values) {
|
|
238
|
+
return [...new Set(values)];
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export {
|
|
242
|
+
InMemoryIntegrationGrantStore,
|
|
243
|
+
IntegrationRuntime,
|
|
244
|
+
createIntegrationRuntime
|
|
245
|
+
};
|
|
246
|
+
//# sourceMappingURL=chunk-FQAT4IEE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime.ts"],"sourcesContent":["import {\n buildIntegrationToolCatalog,\n type IntegrationToolDefinition,\n} from './catalog.js'\nimport type {\n IntegrationActor,\n IntegrationConnection,\n IntegrationConnector,\n IssuedIntegrationCapability,\n} from './index.js'\nimport type {\n IntegrationRegistry,\n IntegrationRegistryEntry,\n} from './registry.js'\n\nexport type IntegrationRequirementMode = 'read' | 'write' | 'trigger'\nexport type IntegrationRequirementStatus = 'ready' | 'missing_connection' | 'not_executable' | 'unknown_connector'\n\nexport interface IntegrationRequirement {\n id: string\n connectorId: string\n reason: string\n mode: IntegrationRequirementMode\n requiredActions?: string[]\n requiredTriggers?: string[]\n requiredScopes?: string[]\n optional?: boolean\n}\n\nexport interface IntegrationManifest {\n id: string\n title?: string\n owner?: IntegrationActor\n requirements: IntegrationRequirement[]\n metadata?: Record<string, unknown>\n}\n\nexport interface IntegrationRequirementResolution {\n requirement: IntegrationRequirement\n status: IntegrationRequirementStatus\n connector?: IntegrationConnector\n registryEntry?: IntegrationRegistryEntry\n connection?: IntegrationConnection\n missingScopes: string[]\n missingActions: string[]\n missingTriggers: string[]\n message: string\n}\n\nexport interface IntegrationManifestResolution {\n manifest: IntegrationManifest\n owner: IntegrationActor\n ready: IntegrationRequirementResolution[]\n missing: IntegrationRequirementResolution[]\n optionalMissing: IntegrationRequirementResolution[]\n}\n\nexport interface IntegrationGrant {\n id: string\n manifestId: string\n requirementId: string\n owner: IntegrationActor\n grantee: IntegrationActor\n connectionId: string\n connectorId: string\n scopes: string[]\n allowedActions: string[]\n allowedTriggers: string[]\n status: 'active' | 'revoked'\n createdAt: string\n updatedAt: string\n metadata?: Record<string, unknown>\n}\n\nexport interface IntegrationGrantStore {\n get(grantId: string): Promise<IntegrationGrant | undefined> | IntegrationGrant | undefined\n put(grant: IntegrationGrant): Promise<void> | void\n listByManifest(manifestId: string, grantee?: IntegrationActor): Promise<IntegrationGrant[]> | IntegrationGrant[]\n listByGrantee(grantee: IntegrationActor): Promise<IntegrationGrant[]> | IntegrationGrant[]\n listByIds?(grantIds: string[]): Promise<IntegrationGrant[]> | IntegrationGrant[]\n delete?(grantId: string): Promise<void> | void\n}\n\nexport interface IntegrationCapabilityBinding {\n requirementId: string\n connectorId: string\n connectionId: string\n grantId: string\n scopes: string[]\n allowedActions: string[]\n allowedTriggers: string[]\n capability: IssuedIntegrationCapability\n}\n\nexport interface IntegrationSandboxBundle {\n manifestId: string\n subject: IntegrationActor\n capabilities: IntegrationCapabilityBinding[]\n connectors: IntegrationConnector[]\n tools: IntegrationToolDefinition[]\n expiresAt: string\n}\n\nexport interface IntegrationRuntimeHub {\n listRegistry(): Promise<IntegrationRegistry> | IntegrationRegistry\n listConnections(owner: IntegrationActor): Promise<IntegrationConnection[]> | IntegrationConnection[]\n issueCapability(input: {\n subject: IntegrationActor\n connectionId: string\n scopes: string[]\n allowedActions: string[]\n ttlMs: number\n metadata?: Record<string, unknown>\n }): Promise<IssuedIntegrationCapability> | IssuedIntegrationCapability\n}\n\nexport interface IntegrationRuntimeOptions {\n hub: IntegrationRuntimeHub\n grants?: IntegrationGrantStore\n now?: () => Date\n}\n\nexport class InMemoryIntegrationGrantStore implements IntegrationGrantStore {\n private readonly grants = new Map<string, IntegrationGrant>()\n\n get(grantId: string): IntegrationGrant | undefined {\n return this.grants.get(grantId)\n }\n\n put(grant: IntegrationGrant): void {\n this.grants.set(grant.id, grant)\n }\n\n listByManifest(manifestId: string, grantee?: IntegrationActor): IntegrationGrant[] {\n return [...this.grants.values()].filter((grant) =>\n grant.manifestId === manifestId && (!grantee || sameActor(grant.grantee, grantee))\n )\n }\n\n listByGrantee(grantee: IntegrationActor): IntegrationGrant[] {\n return [...this.grants.values()].filter((grant) => sameActor(grant.grantee, grantee))\n }\n\n listByIds(grantIds: string[]): IntegrationGrant[] {\n const wanted = new Set(grantIds)\n return [...this.grants.values()].filter((grant) => wanted.has(grant.id))\n }\n\n delete(grantId: string): void {\n this.grants.delete(grantId)\n }\n}\n\nexport class IntegrationRuntime {\n private readonly hub: IntegrationRuntimeHub\n private readonly grants: IntegrationGrantStore\n private readonly now: () => Date\n\n constructor(options: IntegrationRuntimeOptions) {\n this.hub = options.hub\n this.grants = options.grants ?? new InMemoryIntegrationGrantStore()\n this.now = options.now ?? (() => new Date())\n }\n\n async registry(): Promise<IntegrationRegistry> {\n return this.hub.listRegistry()\n }\n\n async resolveManifest(manifest: IntegrationManifest, owner: IntegrationActor): Promise<IntegrationManifestResolution> {\n const registry = await this.registry()\n const connections = await this.hub.listConnections(owner)\n const resolutions = manifest.requirements.map((requirement) =>\n resolveRequirement(requirement, owner, registry, connections),\n )\n return {\n manifest,\n owner,\n ready: resolutions.filter((resolution) => resolution.status === 'ready'),\n missing: resolutions.filter((resolution) => resolution.status !== 'ready' && !resolution.requirement.optional),\n optionalMissing: resolutions.filter((resolution) => resolution.status !== 'ready' && resolution.requirement.optional === true),\n }\n }\n\n async createGrants(input: {\n manifest: IntegrationManifest\n owner: IntegrationActor\n grantee: IntegrationActor\n metadata?: Record<string, unknown>\n }): Promise<IntegrationGrant[]> {\n const resolution = await this.resolveManifest(input.manifest, input.owner)\n if (resolution.missing.length > 0) {\n throw new Error(`Cannot create integration grants; missing requirements: ${resolution.missing.map((r) => r.requirement.id).join(', ')}`)\n }\n const now = this.now().toISOString()\n const grants = resolution.ready.map((ready): IntegrationGrant => ({\n id: `grant_${input.manifest.id}_${ready.requirement.id}_${ready.connection!.id}`,\n manifestId: input.manifest.id,\n requirementId: ready.requirement.id,\n owner: input.owner,\n grantee: input.grantee,\n connectionId: ready.connection!.id,\n connectorId: ready.connector!.id,\n scopes: requiredScopes(ready.requirement, ready.connector!),\n allowedActions: requiredActions(ready.requirement, ready.connector!),\n allowedTriggers: requiredTriggers(ready.requirement, ready.connector!),\n status: 'active',\n createdAt: now,\n updatedAt: now,\n metadata: input.metadata,\n }))\n for (const grant of grants) await this.grants.put(grant)\n return grants\n }\n\n async buildSandboxBundle(input: {\n manifestId?: string\n grantIds?: string[]\n subject: IntegrationActor\n ttlMs: number\n grantee?: IntegrationActor\n }): Promise<IntegrationSandboxBundle> {\n const grants = await this.resolveBundleGrants(input)\n const registry = await this.registry()\n const bindings: IntegrationCapabilityBinding[] = []\n const connectors: IntegrationConnector[] = []\n let expiresAt = ''\n\n for (const grant of grants) {\n const entry = registry.byId.get(grant.connectorId)\n if (!entry) continue\n const connector = {\n ...entry.connector,\n actions: entry.connector.actions.filter((action) => grant.allowedActions.includes(action.id)),\n triggers: entry.connector.triggers?.filter((trigger) => grant.allowedTriggers.includes(trigger.id)),\n scopes: entry.connector.scopes.filter((scope) => grant.scopes.includes(scope)),\n }\n const capability = await this.hub.issueCapability({\n subject: input.subject,\n connectionId: grant.connectionId,\n scopes: grant.scopes,\n allowedActions: grant.allowedActions,\n ttlMs: input.ttlMs,\n metadata: {\n manifestId: grant.manifestId,\n grantId: grant.id,\n requirementId: grant.requirementId,\n },\n })\n bindings.push({\n requirementId: grant.requirementId,\n connectorId: grant.connectorId,\n connectionId: grant.connectionId,\n grantId: grant.id,\n scopes: grant.scopes,\n allowedActions: grant.allowedActions,\n allowedTriggers: grant.allowedTriggers,\n capability,\n })\n connectors.push(connector)\n expiresAt = capability.capability.expiresAt\n }\n\n return {\n manifestId: input.manifestId ?? grants[0]?.manifestId ?? 'explicit-grants',\n subject: input.subject,\n capabilities: bindings,\n connectors,\n tools: buildIntegrationToolCatalog(connectors),\n expiresAt,\n }\n }\n\n private async resolveBundleGrants(input: {\n manifestId?: string\n grantIds?: string[]\n grantee?: IntegrationActor\n }): Promise<IntegrationGrant[]> {\n if (input.grantIds?.length) {\n const uniqueGrantIds = unique(input.grantIds)\n const grants = this.grants.listByIds\n ? await this.grants.listByIds(uniqueGrantIds)\n : await Promise.all(uniqueGrantIds.map((grantId) => this.grants.get(grantId)))\n const found = grants.filter((grant): grant is IntegrationGrant => Boolean(grant))\n const foundIds = new Set(found.map((grant) => grant.id))\n const missing = uniqueGrantIds.filter((grantId) => !foundIds.has(grantId))\n if (missing.length > 0) {\n throw new Error(`Cannot build integration bundle; unknown grant id(s): ${missing.join(', ')}`)\n }\n const badGrantee = input.grantee\n ? found.find((grant) => !sameActor(grant.grantee, input.grantee!))\n : undefined\n if (badGrantee) {\n throw new Error(`Cannot build integration bundle; grant ${badGrantee.id} belongs to a different grantee.`)\n }\n const badManifest = input.manifestId\n ? found.find((grant) => grant.manifestId !== input.manifestId)\n : undefined\n if (badManifest) {\n throw new Error(`Cannot build integration bundle; grant ${badManifest.id} is not for manifest ${input.manifestId}.`)\n }\n return found.filter((grant) => grant.status === 'active')\n }\n if (!input.manifestId) {\n throw new Error('Cannot build integration bundle; manifestId or grantIds is required.')\n }\n return (await this.grants.listByManifest(input.manifestId, input.grantee))\n .filter((grant) => grant.status === 'active')\n }\n}\n\nexport function createIntegrationRuntime(options: IntegrationRuntimeOptions): IntegrationRuntime {\n return new IntegrationRuntime(options)\n}\n\nfunction resolveRequirement(\n requirement: IntegrationRequirement,\n owner: IntegrationActor,\n registry: IntegrationRegistry,\n connections: IntegrationConnection[],\n): IntegrationRequirementResolution {\n const entry = registry.byId.get(requirement.connectorId)\n if (!entry) {\n return missing(requirement, 'unknown_connector', `Unknown connector ${requirement.connectorId}.`)\n }\n const connector = entry.connector\n if (connector.actions.length === 0 && (connector.triggers?.length ?? 0) === 0) {\n return missing(requirement, 'not_executable', `${connector.title} is catalog-only and cannot be invoked yet.`, connector, entry)\n }\n const scopes = requiredScopes(requirement, connector)\n const actions = requiredActions(requirement, connector)\n const triggers = requiredTriggers(requirement, connector)\n const connection = connections.find((candidate) =>\n sameActor(candidate.owner, owner)\n && candidate.status === 'active'\n && (candidate.connectorId === connector.id || entry.aliases.includes(candidate.connectorId))\n && scopes.every((scope) => candidate.grantedScopes.includes(scope))\n )\n if (!connection) {\n return {\n requirement,\n status: 'missing_connection',\n connector,\n registryEntry: entry,\n missingScopes: scopes,\n missingActions: actions,\n missingTriggers: triggers,\n message: `${connector.title} needs an active user connection with the required scopes.`,\n }\n }\n return {\n requirement,\n status: 'ready',\n connector,\n registryEntry: entry,\n connection,\n missingScopes: [],\n missingActions: [],\n missingTriggers: [],\n message: `${connector.title} is ready.`,\n }\n}\n\nfunction missing(\n requirement: IntegrationRequirement,\n status: Exclude<IntegrationRequirementStatus, 'ready' | 'missing_connection'>,\n message: string,\n connector?: IntegrationConnector,\n registryEntry?: IntegrationRegistryEntry,\n): IntegrationRequirementResolution {\n return {\n requirement,\n status,\n connector,\n registryEntry,\n missingScopes: [],\n missingActions: [],\n missingTriggers: [],\n message,\n }\n}\n\nfunction requiredActions(requirement: IntegrationRequirement, connector: IntegrationConnector): string[] {\n if (requirement.mode === 'trigger') return []\n if (requirement.requiredActions?.length) return unique(requirement.requiredActions)\n const actions = connector.actions.filter((action) => {\n if (requirement.mode === 'read') return action.risk === 'read'\n if (requirement.mode === 'write') return action.risk !== 'read'\n return false\n })\n return unique(actions.map((action) => action.id))\n}\n\nfunction requiredTriggers(requirement: IntegrationRequirement, connector: IntegrationConnector): string[] {\n if (requirement.requiredTriggers?.length) return unique(requirement.requiredTriggers)\n if (requirement.mode !== 'trigger') return []\n return unique((connector.triggers ?? []).map((trigger) => trigger.id))\n}\n\nfunction requiredScopes(requirement: IntegrationRequirement, connector: IntegrationConnector): string[] {\n if (requirement.requiredScopes?.length) return unique(requirement.requiredScopes)\n const actionIds = new Set(requiredActions(requirement, connector))\n const triggerIds = new Set(requiredTriggers(requirement, connector))\n return unique([\n ...connector.actions\n .filter((action) => actionIds.has(action.id))\n .flatMap((action) => action.requiredScopes),\n ...(connector.triggers ?? [])\n .filter((trigger) => triggerIds.has(trigger.id))\n .flatMap((trigger) => trigger.requiredScopes),\n ])\n}\n\nfunction sameActor(a: IntegrationActor, b: IntegrationActor): boolean {\n return a.type === b.type && a.id === b.id\n}\n\nfunction unique<T>(values: T[]): T[] {\n return [...new Set(values)]\n}\n"],"mappings":"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","names":["missing"]}
|