@tangle-network/agent-integrations 0.25.0 → 0.25.2
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
CHANGED
|
@@ -1,23 +1,31 @@
|
|
|
1
1
|
# @tangle-network/agent-integrations
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
software
|
|
3
|
+
Integration infrastructure for agent products, sandbox apps, and generated
|
|
4
|
+
software.
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
Use this package when users connect external accounts and agents or apps need
|
|
7
|
+
controlled read/write access to those accounts. It gives products one stable
|
|
8
|
+
contract for connector discovery, OAuth/API-key connections, scoped sandbox
|
|
9
|
+
capabilities, action invocation, workflow triggers, approval, audit,
|
|
10
|
+
healthchecks, and provider/runtime adapters.
|
|
11
|
+
|
|
12
|
+
The product keeps ownership of UI, tenant policy, persistence, and secret
|
|
13
|
+
storage. `agent-integrations` keeps the runtime contract stable so generated
|
|
14
|
+
apps and agents do not depend on a specific OAuth broker, workflow vendor, or
|
|
15
|
+
provider SDK.
|
|
11
16
|
|
|
12
17
|
## Contents
|
|
13
18
|
|
|
14
19
|
- [What It Provides](#what-it-provides)
|
|
15
20
|
- [Architecture](#architecture)
|
|
16
21
|
- [Install](#install)
|
|
22
|
+
- [Quick Start](#quick-start)
|
|
17
23
|
- [Core Primitives](#core-primitives)
|
|
18
24
|
- [Catalog Registry](#catalog-registry)
|
|
25
|
+
- [Product Adoption](#product-adoption)
|
|
19
26
|
- [Provider Strategy](#provider-strategy)
|
|
20
27
|
- [Executable Coverage](#executable-coverage)
|
|
28
|
+
- [Product Hub Ownership](#product-hub-ownership)
|
|
21
29
|
- [Examples](#examples)
|
|
22
30
|
- [Security Model](#security-model)
|
|
23
31
|
- [Development](#development)
|
|
@@ -25,7 +33,7 @@ contract.
|
|
|
25
33
|
## What It Provides
|
|
26
34
|
|
|
27
35
|
- A normalized connector/action/trigger catalog.
|
|
28
|
-
-
|
|
36
|
+
- Tangle integration contracts for every catalog connector.
|
|
29
37
|
- User-owned connection records that reference secrets without storing raw
|
|
30
38
|
credentials in public shapes.
|
|
31
39
|
- Short-lived capability tokens for sandbox-safe access to a subset of a user's
|
|
@@ -37,13 +45,13 @@ contract.
|
|
|
37
45
|
runtimes, and internal connector registries.
|
|
38
46
|
- A first-party `ConnectorAdapter` boundary for direct provider execution.
|
|
39
47
|
- A declarative REST adapter factory for promoting REST APIs from reviewed specs.
|
|
40
|
-
- A broad
|
|
41
|
-
|
|
48
|
+
- A broad catalog for discovering hundreds of integrations while keeping
|
|
49
|
+
executable backend state explicit.
|
|
42
50
|
- A canonical registry that deduplicates overlapping catalogs, keeps support
|
|
43
51
|
tiers explicit, and reports auth/category conflicts.
|
|
44
|
-
- App/agent manifests, grants, and sandbox bundles so
|
|
45
|
-
|
|
46
|
-
|
|
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.
|
|
47
55
|
- Workflow trigger installation and normalized event dispatch for non-agent UI
|
|
48
56
|
automation, sync jobs, webhooks, and product workflows.
|
|
49
57
|
- Approval persistence, audit events, healthchecks, credential resolution,
|
|
@@ -57,8 +65,10 @@ contract.
|
|
|
57
65
|
## Architecture
|
|
58
66
|
|
|
59
67
|
```txt
|
|
60
|
-
connector
|
|
68
|
+
connector contract
|
|
61
69
|
-> user connection
|
|
70
|
+
-> app/agent manifest
|
|
71
|
+
-> grant
|
|
62
72
|
-> scoped capability
|
|
63
73
|
-> policy decision
|
|
64
74
|
-> provider/action invocation
|
|
@@ -80,6 +90,63 @@ Main boundaries:
|
|
|
80
90
|
pnpm add @tangle-network/agent-integrations
|
|
81
91
|
```
|
|
82
92
|
|
|
93
|
+
## Quick Start
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import {
|
|
97
|
+
buildDefaultIntegrationRegistry,
|
|
98
|
+
buildIntegrationToolCatalog,
|
|
99
|
+
createIntegrationRuntime,
|
|
100
|
+
createPlatformIntegrationPolicyPreset,
|
|
101
|
+
InMemoryConnectionStore,
|
|
102
|
+
IntegrationHub,
|
|
103
|
+
} from '@tangle-network/agent-integrations'
|
|
104
|
+
|
|
105
|
+
const registry = buildDefaultIntegrationRegistry({
|
|
106
|
+
tangleCatalogRuntimeExecutable: false,
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
const hub = new IntegrationHub({
|
|
110
|
+
providers: [/* native, gateway, or catalog-runtime providers */],
|
|
111
|
+
store: productConnectionStore ?? new InMemoryConnectionStore(),
|
|
112
|
+
capabilitySecret: process.env.INTEGRATION_CAPABILITY_SECRET!,
|
|
113
|
+
policy: createPlatformIntegrationPolicyPreset(),
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
const runtime = createIntegrationRuntime({
|
|
117
|
+
hub,
|
|
118
|
+
grants: productGrantStore,
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
const tools = buildIntegrationToolCatalog(registry.connectors)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
For a generated app or sandbox:
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
const resolution = await runtime.resolveManifest(manifest, user)
|
|
128
|
+
|
|
129
|
+
if (resolution.missing.length > 0) {
|
|
130
|
+
// Show connect UI using IntegrationSpec renderers.
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
await runtime.createGrants({
|
|
134
|
+
manifest,
|
|
135
|
+
owner: user,
|
|
136
|
+
grantee: { type: 'app', id: manifest.id },
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
const bundle = await runtime.buildSandboxBundle({
|
|
140
|
+
manifestId: manifest.id,
|
|
141
|
+
subject: { type: 'sandbox', id: sandboxId },
|
|
142
|
+
ttlMs: 15 * 60_000,
|
|
143
|
+
})
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Generated code calls your product integration endpoint with the scoped
|
|
147
|
+
capability bundle. It never receives provider refresh tokens, API keys, or raw
|
|
148
|
+
OAuth credentials.
|
|
149
|
+
|
|
83
150
|
## Core Primitives
|
|
84
151
|
|
|
85
152
|
| Primitive | Purpose |
|
|
@@ -129,9 +196,9 @@ pnpm add @tangle-network/agent-integrations
|
|
|
129
196
|
|
|
130
197
|
## Catalog Registry
|
|
131
198
|
|
|
132
|
-
Every catalog connector has a
|
|
133
|
-
package runtimes are implementation backends behind that contract; product
|
|
134
|
-
should route through `IntegrationHub` either way.
|
|
199
|
+
Every catalog connector has a Tangle contract. Native adapters, hosted gateways,
|
|
200
|
+
and package runtimes are implementation backends behind that contract; product
|
|
201
|
+
code should route through `IntegrationHub` either way.
|
|
135
202
|
|
|
136
203
|
Use `buildDefaultIntegrationRegistry()` before creating tool catalogs or
|
|
137
204
|
connection pickers. It produces one canonical connector per integration,
|
|
@@ -144,16 +211,16 @@ catalogOnly < setupReady < gatewayExecutable < firstPartyExecutable < sandboxExe
|
|
|
144
211
|
|
|
145
212
|
Use `buildDefaultIntegrationRegistry({ tangleCatalogRuntimeExecutable: true })`
|
|
146
213
|
when the Tangle catalog runtime is deployed and should be exposed as executable
|
|
147
|
-
tools. These states describe the backend currently wired into a product
|
|
148
|
-
|
|
214
|
+
tools. These states describe the backend currently wired into a product. They
|
|
215
|
+
do not change the connector contract.
|
|
149
216
|
|
|
150
217
|
See [Catalog Registry](./docs/catalog-registry.md).
|
|
151
218
|
|
|
152
|
-
##
|
|
219
|
+
## Product Adoption
|
|
153
220
|
|
|
154
221
|
Use `IntegrationManifest` for any app or agent that needs integrations:
|
|
155
|
-
|
|
156
|
-
|
|
222
|
+
generated apps, domain agents, sandbox agents, workflow apps, and
|
|
223
|
+
executor-backed runtimes all use the same shape.
|
|
157
224
|
|
|
158
225
|
```ts
|
|
159
226
|
const runtime = createIntegrationRuntime({ hub, grants })
|
|
@@ -180,7 +247,7 @@ Generated app code should use the tiny client instead of raw provider tokens:
|
|
|
180
247
|
|
|
181
248
|
```ts
|
|
182
249
|
const integrations = createTangleIntegrationsClient({
|
|
183
|
-
endpoint: 'https://
|
|
250
|
+
endpoint: 'https://integrations.example.com',
|
|
184
251
|
env: process.env,
|
|
185
252
|
})
|
|
186
253
|
|
|
@@ -204,6 +271,19 @@ That installs provider trigger subscriptions against the user's connection and
|
|
|
204
271
|
lets the product dispatch normalized events to UI workflows, sync jobs, or
|
|
205
272
|
agent runs.
|
|
206
273
|
|
|
274
|
+
For a full product checklist, see
|
|
275
|
+
[External Product Integration](./docs/external-product-integration.md).
|
|
276
|
+
|
|
277
|
+
## Product Hub Ownership
|
|
278
|
+
|
|
279
|
+
Use a hosted hub when multiple apps intentionally share identity, billing,
|
|
280
|
+
consent, and connection custody. Use a product-owned hub when a standalone
|
|
281
|
+
deployment needs its own customer boundary, OAuth branding, vault, policy, or
|
|
282
|
+
data residency. Both modes use the same package contracts.
|
|
283
|
+
|
|
284
|
+
See [Product Hub Ownership](./docs/product-hub-ownership.md) for the
|
|
285
|
+
deployment model and launch gates.
|
|
286
|
+
|
|
207
287
|
## Provider Strategy
|
|
208
288
|
|
|
209
289
|
The package deliberately avoids vendor lock-in.
|
package/docs/adapter-triage.md
CHANGED
|
@@ -63,7 +63,7 @@ import {
|
|
|
63
63
|
|
|
64
64
|
const provider = createTangleCatalogExecutorProvider({
|
|
65
65
|
executeAction: createTangleCatalogHttpExecutor({
|
|
66
|
-
endpoint: 'https://
|
|
66
|
+
endpoint: 'https://integrations.example.com/integration-runtime',
|
|
67
67
|
secret: process.env.TANGLE_CATALOG_RUNTIME_SECRET,
|
|
68
68
|
}),
|
|
69
69
|
})
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# External Product Integration
|
|
2
|
+
|
|
3
|
+
This guide is for product teams using `@tangle-network/agent-integrations`
|
|
4
|
+
outside this repository. The package gives you stable contracts and runtime
|
|
5
|
+
helpers; your product supplies persistence, secret storage, UI, and deployment
|
|
6
|
+
policy.
|
|
7
|
+
|
|
8
|
+
## Mental Model
|
|
9
|
+
|
|
10
|
+
```txt
|
|
11
|
+
user connects account
|
|
12
|
+
-> product stores IntegrationConnection + secret refs
|
|
13
|
+
-> app/agent declares IntegrationManifest
|
|
14
|
+
-> product creates IntegrationGrant
|
|
15
|
+
-> sandbox/app receives short-lived capability bundle
|
|
16
|
+
-> sandbox/app invokes product /integrations/invoke endpoint
|
|
17
|
+
-> IntegrationHub validates capability, policy, approval, idempotency
|
|
18
|
+
-> provider backend executes action
|
|
19
|
+
-> product stores audit event and returns normalized result
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The invariant: generated apps and agents call the same Tangle integration tools
|
|
23
|
+
no matter whether a connector is backed by a native adapter, hosted gateway, or
|
|
24
|
+
catalog runtime.
|
|
25
|
+
|
|
26
|
+
## Product-Owned Pieces
|
|
27
|
+
|
|
28
|
+
You must provide:
|
|
29
|
+
|
|
30
|
+
- `IntegrationConnection` storage in your database.
|
|
31
|
+
- `IntegrationGrant` storage mapping user-owned connections to apps, agents, or
|
|
32
|
+
sandboxes.
|
|
33
|
+
- Approval, audit, healthcheck, workflow, and event stores.
|
|
34
|
+
- `IntegrationSecretStore` backed by your vault or KMS.
|
|
35
|
+
- OAuth/API-key connect UI built from `IntegrationSpec` renderers.
|
|
36
|
+
- Tenant policy for which connectors are enabled.
|
|
37
|
+
- Human approval UX for write/destructive actions.
|
|
38
|
+
- A deployed invocation endpoint such as `/v1/integrations/invoke`.
|
|
39
|
+
|
|
40
|
+
The package provides interfaces and helpers for all of these. It does not store
|
|
41
|
+
your secrets or run your product UI.
|
|
42
|
+
|
|
43
|
+
## Setup Flow
|
|
44
|
+
|
|
45
|
+
1. Build the registry.
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import { buildDefaultIntegrationRegistry } from '@tangle-network/agent-integrations'
|
|
49
|
+
|
|
50
|
+
const registry = buildDefaultIntegrationRegistry({
|
|
51
|
+
tangleCatalogRuntimeExecutable: process.env.TANGLE_CATALOG_RUNTIME === '1',
|
|
52
|
+
})
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
2. Render setup UI from specs.
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
import {
|
|
59
|
+
listIntegrationSpecs,
|
|
60
|
+
renderConsoleSteps,
|
|
61
|
+
validateCredentialSet,
|
|
62
|
+
} from '@tangle-network/agent-integrations'
|
|
63
|
+
|
|
64
|
+
const spec = listIntegrationSpecs().find((candidate) => candidate.kind === 'google-calendar')
|
|
65
|
+
const steps = renderConsoleSteps(spec!, { host: 'id.example.com' })
|
|
66
|
+
const validation = validateCredentialSet(spec!, submittedCredentials)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
3. Store provider credentials in your vault, then persist an
|
|
70
|
+
`IntegrationConnection` with secret refs, scopes, owner, connector id, and
|
|
71
|
+
status.
|
|
72
|
+
|
|
73
|
+
4. Run `runIntegrationHealthchecks()` after setup and on a schedule.
|
|
74
|
+
|
|
75
|
+
## Runtime Flow
|
|
76
|
+
|
|
77
|
+
Create one hub per product runtime.
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import {
|
|
81
|
+
createConnectorAdapterProvider,
|
|
82
|
+
createDefaultIntegrationActionGuard,
|
|
83
|
+
IntegrationHub,
|
|
84
|
+
createPlatformIntegrationPolicyPreset,
|
|
85
|
+
} from '@tangle-network/agent-integrations'
|
|
86
|
+
|
|
87
|
+
const hub = new IntegrationHub({
|
|
88
|
+
providers: [
|
|
89
|
+
createConnectorAdapterProvider({
|
|
90
|
+
adapters,
|
|
91
|
+
resolveDataSource: (connection) => credentialResolver.resolve(connection),
|
|
92
|
+
}),
|
|
93
|
+
// createHttpIntegrationProvider(...) or createTangleCatalogExecutorProvider(...)
|
|
94
|
+
],
|
|
95
|
+
store: connections,
|
|
96
|
+
capabilitySecret: process.env.INTEGRATION_CAPABILITY_SECRET!,
|
|
97
|
+
policy: createPlatformIntegrationPolicyPreset(),
|
|
98
|
+
guard: createDefaultIntegrationActionGuard({
|
|
99
|
+
audit,
|
|
100
|
+
idempotency,
|
|
101
|
+
}),
|
|
102
|
+
})
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Your `/v1/integrations/invoke` route should:
|
|
106
|
+
|
|
107
|
+
1. Parse the invocation envelope.
|
|
108
|
+
2. Validate the capability token.
|
|
109
|
+
3. Resolve the user's connection and credentials.
|
|
110
|
+
4. Run policy and approval checks.
|
|
111
|
+
5. Execute through the matching provider.
|
|
112
|
+
6. Store an audit event.
|
|
113
|
+
7. Return a normalized result or `approval_required`.
|
|
114
|
+
|
|
115
|
+
## Generated Apps And Sandboxes
|
|
116
|
+
|
|
117
|
+
Generated apps declare needs through `IntegrationManifest`.
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
const manifest = {
|
|
121
|
+
id: 'calendar-workout-planner',
|
|
122
|
+
requirements: [
|
|
123
|
+
{
|
|
124
|
+
connectorId: 'google-calendar',
|
|
125
|
+
mode: 'read',
|
|
126
|
+
reason: 'Find open workout windows from calendar events.',
|
|
127
|
+
requiredActions: ['events.list'],
|
|
128
|
+
scopes: ['calendar.read'],
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
When a user previews or installs the app:
|
|
135
|
+
|
|
136
|
+
1. Resolve the manifest against the user's existing connections.
|
|
137
|
+
2. Ask the user to connect missing accounts.
|
|
138
|
+
3. Show consent using `renderConsentSummary()`.
|
|
139
|
+
4. Create grants from the user's connections to the app.
|
|
140
|
+
5. Build a sandbox bundle with short-lived capabilities.
|
|
141
|
+
6. Inject the bridge environment into the sandbox.
|
|
142
|
+
|
|
143
|
+
Generated app code should use `createTangleIntegrationsClient()` or the product
|
|
144
|
+
equivalent. It should not call Google, Slack, GitHub, or any provider directly
|
|
145
|
+
with user credentials.
|
|
146
|
+
|
|
147
|
+
## Workflows And Triggers
|
|
148
|
+
|
|
149
|
+
Use `createIntegrationWorkflowRuntime()` for non-agent automations:
|
|
150
|
+
|
|
151
|
+
- GitHub issue or pull-request sync.
|
|
152
|
+
- Slack message triggers.
|
|
153
|
+
- Calendar event updates.
|
|
154
|
+
- CRM record changes.
|
|
155
|
+
- Webhook-to-sandbox workflows.
|
|
156
|
+
|
|
157
|
+
Inbound provider webhooks should go through `receiveIntegrationWebhook()` for
|
|
158
|
+
signature verification, provider-event dedupe, and normalized event dispatch.
|
|
159
|
+
|
|
160
|
+
## Long-Tail Connectors
|
|
161
|
+
|
|
162
|
+
The registry distinguishes connector contracts from executable backend state.
|
|
163
|
+
Products can expose long-tail connectors only when they have configured a
|
|
164
|
+
backend:
|
|
165
|
+
|
|
166
|
+
- native adapter
|
|
167
|
+
- hosted integration gateway
|
|
168
|
+
- Tangle catalog runtime
|
|
169
|
+
- product-specific provider
|
|
170
|
+
|
|
171
|
+
Use `buildDefaultIntegrationRegistry({ tangleCatalogRuntimeExecutable: true })`
|
|
172
|
+
only after the catalog runtime is deployed and audited with
|
|
173
|
+
`auditTangleCatalogRuntimePackages()`.
|
|
174
|
+
|
|
175
|
+
## Security Requirements
|
|
176
|
+
|
|
177
|
+
- Never pass provider refresh tokens or API keys into a sandbox.
|
|
178
|
+
- Use short-lived capability tokens scoped to connector, action, subject, and
|
|
179
|
+
connection.
|
|
180
|
+
- Require approval for writes by default.
|
|
181
|
+
- Deny destructive actions unless the product explicitly enables them.
|
|
182
|
+
- Use idempotency keys for state-changing actions.
|
|
183
|
+
- Store audit events for connect, grant, invoke, approve, revoke, rotate, and
|
|
184
|
+
webhook flows.
|
|
185
|
+
- Redact provider credentials from logs, traces, errors, and generated app
|
|
186
|
+
payloads.
|
|
187
|
+
|
|
188
|
+
## Launch Checklist
|
|
189
|
+
|
|
190
|
+
- [ ] Connection, grant, approval, audit, healthcheck, workflow, and event stores
|
|
191
|
+
are backed by production persistence.
|
|
192
|
+
- [ ] Secret refs resolve through vault/KMS and never serialize raw credentials.
|
|
193
|
+
- [ ] OAuth/API-key setup UI renders from `IntegrationSpec`.
|
|
194
|
+
- [ ] Connect, revoke, rotate, approve, and audit-log screens exist.
|
|
195
|
+
- [ ] Generated app manifests feed into `resolveManifest()` and
|
|
196
|
+
`createGrants()`.
|
|
197
|
+
- [ ] Sandbox launches receive `buildIntegrationBridgeEnvironment()` output.
|
|
198
|
+
- [ ] Sandbox invocations route through your product integration endpoint.
|
|
199
|
+
- [ ] Writes require approval and idempotency.
|
|
200
|
+
- [ ] Webhooks verify signatures and dedupe provider event ids.
|
|
201
|
+
- [ ] Healthchecks run after setup and on a schedule.
|
|
202
|
+
- [ ] Browser E2E covers connect, consent, preview, invoke, approval, revoke,
|
|
203
|
+
and failure recovery.
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Integration Hub Ownership
|
|
2
|
+
|
|
3
|
+
Status: deployment guidance
|
|
4
|
+
|
|
5
|
+
This document describes where integration custody should live when a product
|
|
6
|
+
uses `@tangle-network/agent-integrations`.
|
|
7
|
+
|
|
8
|
+
## Decision
|
|
9
|
+
|
|
10
|
+
Use one contract everywhere, not one deployment everywhere.
|
|
11
|
+
|
|
12
|
+
- Products that share identity, billing, and consent can use a hosted platform
|
|
13
|
+
hub.
|
|
14
|
+
- Standalone products can run a product-owned hub.
|
|
15
|
+
- Both modes must use `@tangle-network/agent-integrations` contracts:
|
|
16
|
+
`IntegrationSpec`, `IntegrationManifest`, `IntegrationGrant`, capability
|
|
17
|
+
bundles, `/v1/integrations/invoke`, approvals, healthchecks, audit, webhooks,
|
|
18
|
+
and provider/runtime adapters.
|
|
19
|
+
- Product-owned hubs may federate to a hosted platform hub when the deployment
|
|
20
|
+
wants a shared connection wallet.
|
|
21
|
+
|
|
22
|
+
The package defines the shared protocol. Each deployment decides where to store
|
|
23
|
+
connections, secrets, grants, approvals, audit records, and workflow state.
|
|
24
|
+
|
|
25
|
+
## Ownership Modes
|
|
26
|
+
|
|
27
|
+
| Mode | Use When | Owns OAuth, Vault, Audit | Invocation Path |
|
|
28
|
+
|---|---|---:|---|
|
|
29
|
+
| Hosted platform hub | Multiple apps share account, consent, billing, and connection custody | Platform service | App/sandbox calls platform hub or product proxy with scoped capability |
|
|
30
|
+
| Product-owned hub | Standalone SaaS, private deployment, or customer-owned data boundary | Product app | App/sandbox calls product `/v1/integrations/invoke` |
|
|
31
|
+
| Federated product hub | Product wants local policy with remote connection custody | Product policy + hosted custody | Product issues local grants over remote platform connections |
|
|
32
|
+
|
|
33
|
+
The important invariant: sandboxes and generated apps never receive provider
|
|
34
|
+
refresh tokens, API keys, or raw OAuth credentials in any mode.
|
|
35
|
+
|
|
36
|
+
## Where Duplication Is Bad
|
|
37
|
+
|
|
38
|
+
Fully duplicating hubs is bad when apps are intentionally part of the same
|
|
39
|
+
account system:
|
|
40
|
+
|
|
41
|
+
- Users reconnect Gmail, Slack, GitHub, and Drive in every app.
|
|
42
|
+
- OAuth app verification, scopes, redirect configuration, and consent review
|
|
43
|
+
are repeated.
|
|
44
|
+
- Revocation, audit, healthchecks, and billing attribution fragment.
|
|
45
|
+
- Generated apps cannot inherit a user's already-approved connection.
|
|
46
|
+
|
|
47
|
+
For those deployments, use a hosted hub as the connection source of truth and
|
|
48
|
+
pass scoped grants down to apps, sandboxes, and agents.
|
|
49
|
+
|
|
50
|
+
## Where Centralization Is Bad
|
|
51
|
+
|
|
52
|
+
Forcing every deployment through a hosted platform hub is bad when the product
|
|
53
|
+
needs a separate customer, compliance, or operational boundary:
|
|
54
|
+
|
|
55
|
+
- The buyer may not want shared identity or billing in their end-user flow.
|
|
56
|
+
- Enterprise deployments may require product-branded OAuth apps, product-owned
|
|
57
|
+
vaults, customer-managed keys, private networking, or data residency.
|
|
58
|
+
- Product-specific subscriptions and compliance boundaries may not match the
|
|
59
|
+
platform account model.
|
|
60
|
+
- A central platform outage should not necessarily take down a standalone app.
|
|
61
|
+
|
|
62
|
+
For those products, run a product-owned hub using the same package contracts.
|
|
63
|
+
Optionally add federation to a hosted platform hub as a deployment choice.
|
|
64
|
+
|
|
65
|
+
## Execution Checklist
|
|
66
|
+
|
|
67
|
+
- [x] One stable contract for specs, manifests, grants, capabilities, invocation,
|
|
68
|
+
approvals, healthchecks, webhooks, audit, and bridge payloads.
|
|
69
|
+
- [x] Long-tail connector contracts and runtime-backed execution path are
|
|
70
|
+
represented without leaking external catalog names into product UX.
|
|
71
|
+
- [x] External product adoption guide documents product-owned deployment.
|
|
72
|
+
- [x] This ownership decision documents platform versus product-owned custody.
|
|
73
|
+
|
|
74
|
+
### Hosted Hub Bar
|
|
75
|
+
|
|
76
|
+
- [ ] The hosted hub has production stores for connections, grants, approvals,
|
|
77
|
+
audit, healthchecks, workflows, webhook events, and idempotency.
|
|
78
|
+
- [ ] The hosted hub vault/KMS stores raw OAuth/API-key credentials behind
|
|
79
|
+
secret refs.
|
|
80
|
+
- [ ] The hosted hub exposes connect, callback, revoke, rotate, approve, audit,
|
|
81
|
+
healthcheck, and `/v1/integrations/invoke`.
|
|
82
|
+
- [ ] Sandbox and generated-app launches receive
|
|
83
|
+
`buildIntegrationBridgeEnvironment()` output.
|
|
84
|
+
- [ ] Browser E2E covers connect, consent, preview, invoke read, approval write,
|
|
85
|
+
revoke, expired token recovery, and missing-connection recovery.
|
|
86
|
+
|
|
87
|
+
### Product-Owned Hub Bar
|
|
88
|
+
|
|
89
|
+
- [ ] The product chooses local hub or federated platform hub per deployment.
|
|
90
|
+
- [ ] Local hubs use `IntegrationHub`; custom provider switch statements are
|
|
91
|
+
removed or wrapped as `IntegrationProvider` implementations.
|
|
92
|
+
- [ ] The product stores connections, grants, approvals, audit, healthchecks,
|
|
93
|
+
workflows, events, and idempotency in its own database.
|
|
94
|
+
- [ ] The product uses its own vault/KMS or explicitly delegates secret custody
|
|
95
|
+
to a hosted hub.
|
|
96
|
+
- [ ] The product has live OAuth/API-key setup UI generated from
|
|
97
|
+
`IntegrationSpec`.
|
|
98
|
+
- [ ] The product has browser E2E personas using real product UX and live
|
|
99
|
+
integration secrets where available.
|
|
100
|
+
|
|
101
|
+
## Product E2E Gates
|
|
102
|
+
|
|
103
|
+
Run these before launch for every product adopting integrations:
|
|
104
|
+
|
|
105
|
+
1. Existing connection: user asks for a task requiring Gmail, Calendar, Slack,
|
|
106
|
+
GitHub, Drive, Sheets, or CRM data; agent detects the existing connection and
|
|
107
|
+
uses it without asking for manual copy/paste.
|
|
108
|
+
2. Missing connection: user asks for the same task without a connection; product
|
|
109
|
+
renders connect/consent in flow, resumes the task after OAuth, and does not
|
|
110
|
+
lose conversation state.
|
|
111
|
+
3. Generated app preview: generated software declares an
|
|
112
|
+
`IntegrationManifest`; preview requests user consent, receives scoped
|
|
113
|
+
capabilities, and reads provider data through the invoke endpoint.
|
|
114
|
+
4. Write approval: generated app or agent proposes a write/send/update action;
|
|
115
|
+
product requires approval, records audit, and executes once with idempotency.
|
|
116
|
+
5. Revocation: user revokes a connection; existing grants fail closed and the UI
|
|
117
|
+
explains how to reconnect.
|
|
118
|
+
6. Healthcheck failure: expired or revoked upstream credentials surface in admin
|
|
119
|
+
UI and task UX without exposing secrets in logs or traces.
|
|
120
|
+
|
|
121
|
+
## Recommendation
|
|
122
|
+
|
|
123
|
+
Do not fork integration semantics by product. Make hub custody a deployment
|
|
124
|
+
choice while keeping the protocol stable. Hosted hubs, product-owned hubs, and
|
|
125
|
+
federated hubs should all expose the same manifest, grant, capability, approval,
|
|
126
|
+
audit, webhook, and invocation shapes.
|
|
@@ -74,9 +74,9 @@ Use gateway-backed coverage for the next large tranche:
|
|
|
74
74
|
- long-tail CRM/support/helpdesk systems
|
|
75
75
|
- vendor-specific workflow triggers
|
|
76
76
|
|
|
77
|
-
This gives
|
|
78
|
-
hundreds of OAuth apps, refresh-token edge cases, webhook subscription
|
|
79
|
-
rate-limit policies, and provider-specific APIs on day one.
|
|
77
|
+
This gives products useful breadth immediately without forcing every team to
|
|
78
|
+
own hundreds of OAuth apps, refresh-token edge cases, webhook subscription
|
|
79
|
+
models, rate-limit policies, and provider-specific APIs on day one.
|
|
80
80
|
|
|
81
81
|
## When To Roll Our Own
|
|
82
82
|
|
|
@@ -12,8 +12,8 @@ const consent = renderConsentSummary(manifest, { appName: 'Exercise Planner' })
|
|
|
12
12
|
|
|
13
13
|
console.log(consent.body)
|
|
14
14
|
|
|
15
|
-
// In production this bundle comes from
|
|
16
|
-
// the generated app access to their Google Calendar connection.
|
|
15
|
+
// In production this bundle comes from the product integration hub after the
|
|
16
|
+
// user grants the generated app access to their Google Calendar connection.
|
|
17
17
|
const bundle: IntegrationSandboxBundle = {
|
|
18
18
|
manifestId: manifest.id,
|
|
19
19
|
subject: { type: 'sandbox', id: 'sandbox_preview_1' },
|
|
@@ -64,7 +64,7 @@ const bundle: IntegrationSandboxBundle = {
|
|
|
64
64
|
|
|
65
65
|
const env = buildIntegrationBridgeEnvironment(bundle)
|
|
66
66
|
const client = createTangleIntegrationsClient({
|
|
67
|
-
endpoint: 'https://
|
|
67
|
+
endpoint: 'https://integrations.example.com',
|
|
68
68
|
env,
|
|
69
69
|
})
|
|
70
70
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-integrations",
|
|
3
|
-
"version": "0.25.
|
|
3
|
+
"version": "0.25.2",
|
|
4
4
|
"description": "Vendor-neutral integration contracts and runtime helpers for sandbox and agent apps.",
|
|
5
5
|
"homepage": "https://github.com/tangle-network/agent-integrations#readme",
|
|
6
6
|
"repository": {
|
|
@@ -38,15 +38,6 @@
|
|
|
38
38
|
"publishConfig": {
|
|
39
39
|
"access": "public"
|
|
40
40
|
},
|
|
41
|
-
"scripts": {
|
|
42
|
-
"build": "tsup",
|
|
43
|
-
"dev": "tsup --watch",
|
|
44
|
-
"audit:execution": "pnpm build >/dev/null && node scripts/audit-integration-execution.mjs",
|
|
45
|
-
"prepare": "tsup",
|
|
46
|
-
"test": "vitest run",
|
|
47
|
-
"test:watch": "vitest",
|
|
48
|
-
"typecheck": "tsc --noEmit"
|
|
49
|
-
},
|
|
50
41
|
"devDependencies": {
|
|
51
42
|
"@types/node": "^25.6.0",
|
|
52
43
|
"tsup": "^8.0.0",
|
|
@@ -57,5 +48,12 @@
|
|
|
57
48
|
"node": ">=20"
|
|
58
49
|
},
|
|
59
50
|
"license": "MIT",
|
|
60
|
-
"
|
|
61
|
-
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "tsup",
|
|
53
|
+
"dev": "tsup --watch",
|
|
54
|
+
"audit:execution": "pnpm build >/dev/null && node scripts/audit-integration-execution.mjs",
|
|
55
|
+
"test": "vitest run",
|
|
56
|
+
"test:watch": "vitest",
|
|
57
|
+
"typecheck": "tsc --noEmit"
|
|
58
|
+
}
|
|
59
|
+
}
|