@tangle-network/agent-integrations 0.32.0 → 0.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/bin/tangle-catalog-runtime.js +7 -7
  2. package/dist/catalog.d.ts +74 -8
  3. package/dist/catalog.js +7 -7
  4. package/dist/{chunk-JCHD6L3B.js → chunk-43VQSANC.js} +2 -2
  5. package/dist/{chunk-F4YILONK.js → chunk-6N23S4JY.js} +21530 -257
  6. package/dist/chunk-6N23S4JY.js.map +1 -0
  7. package/dist/{chunk-VVC7U7W7.js → chunk-7T5YTVER.js} +51 -2
  8. package/dist/chunk-7T5YTVER.js.map +1 -0
  9. package/dist/{chunk-Q5X3QNHR.js → chunk-NQ7OPDUM.js} +261 -1
  10. package/dist/chunk-NQ7OPDUM.js.map +1 -0
  11. package/dist/{chunk-S2MVWQYL.js → chunk-RF3RH374.js} +2 -2
  12. package/dist/{chunk-DN6DNPPH.js → chunk-XO2RSS6Y.js} +125 -11
  13. package/dist/chunk-XO2RSS6Y.js.map +1 -0
  14. package/dist/{chunk-CDY2ETYT.js → chunk-YPZORI3G.js} +2 -2
  15. package/dist/connect/index.d.ts +2 -1
  16. package/dist/connect/index.js +2 -2
  17. package/dist/connectors/adapters/index.d.ts +113 -25
  18. package/dist/connectors/adapters/index.js +4 -2
  19. package/dist/connectors/index.d.ts +3 -2
  20. package/dist/connectors/index.js +4 -2
  21. package/dist/consumer-CzJgntej.d.ts +292 -0
  22. package/dist/consumer.d.ts +6 -8
  23. package/dist/consumer.js +2 -2
  24. package/dist/core-types-D5Dc65Ud.d.ts +355 -0
  25. package/dist/index.d.ts +1282 -4
  26. package/dist/index.js +13 -7
  27. package/dist/middleware/index.d.ts +2 -1
  28. package/dist/middleware/index.js +2 -2
  29. package/dist/registry.d.ts +3 -2424
  30. package/dist/registry.js +7 -7
  31. package/dist/runtime.d.ts +137 -8
  32. package/dist/runtime.js +7 -7
  33. package/dist/specs.d.ts +208 -8
  34. package/dist/specs.js +1 -1
  35. package/dist/tangle-catalog-runtime-2HddXxoM.d.ts +242 -0
  36. package/dist/tangle-catalog-runtime.d.ts +3 -8
  37. package/dist/tangle-catalog-runtime.js +7 -7
  38. package/dist/tangle-id-DA_qj-O_.d.ts +192 -0
  39. package/dist/{tangle-id-Dj0ipP4E.d.ts → types-XdpvaIzW.d.ts} +1 -167
  40. package/docs/integration-execution-audit.md +7 -5
  41. package/docs/integration-execution-matrix.json +32 -0
  42. package/package.json +12 -10
  43. package/dist/chunk-DN6DNPPH.js.map +0 -1
  44. package/dist/chunk-F4YILONK.js.map +0 -1
  45. package/dist/chunk-Q5X3QNHR.js.map +0 -1
  46. package/dist/chunk-VVC7U7W7.js.map +0 -1
  47. /package/dist/{chunk-JCHD6L3B.js.map → chunk-43VQSANC.js.map} +0 -0
  48. /package/dist/{chunk-S2MVWQYL.js.map → chunk-RF3RH374.js.map} +0 -0
  49. /package/dist/{chunk-CDY2ETYT.js.map → chunk-YPZORI3G.js.map} +0 -0
@@ -0,0 +1,292 @@
1
+ import { I as IntegrationActor, e as IntegrationConnectorAction, g as IntegrationDataClass, i as IntegrationActionGuard, c as IntegrationConnection, j as IntegrationActionRequest, b as IntegrationConnector, k as IntegrationActionResult } from './core-types-D5Dc65Ud.js';
2
+ import { IntegrationSandboxBundle, IntegrationRequirementMode, IntegrationRequirementResolution, IntegrationManifest, IntegrationManifestResolution, IntegrationGrant } from './runtime.js';
3
+ import { IntegrationRegistry } from './registry.js';
4
+
5
+ type IntegrationAuditEventType = 'connection.created' | 'connection.updated' | 'connection.revoked' | 'grant.created' | 'grant.revoked' | 'capability.issued' | 'action.invoked' | 'action.failed' | 'trigger.subscribed' | 'trigger.received' | 'workflow.installed' | 'approval.requested' | 'approval.resolved' | 'healthcheck.completed';
6
+ interface IntegrationAuditEvent {
7
+ id: string;
8
+ type: IntegrationAuditEventType;
9
+ occurredAt: string;
10
+ actor?: IntegrationActor;
11
+ connectionId?: string;
12
+ providerId?: string;
13
+ connectorId?: string;
14
+ action?: string;
15
+ risk?: IntegrationConnectorAction['risk'];
16
+ dataClass?: IntegrationDataClass;
17
+ ok?: boolean;
18
+ message?: string;
19
+ metadata?: Record<string, unknown>;
20
+ }
21
+ interface IntegrationAuditSink {
22
+ record(event: IntegrationAuditEvent): Promise<void> | void;
23
+ }
24
+ interface IntegrationAuditStore extends IntegrationAuditSink {
25
+ list(filter?: IntegrationAuditFilter): Promise<IntegrationAuditEvent[]> | IntegrationAuditEvent[];
26
+ }
27
+ interface IntegrationAuditFilter {
28
+ type?: IntegrationAuditEventType;
29
+ actor?: IntegrationActor;
30
+ connectionId?: string;
31
+ providerId?: string;
32
+ connectorId?: string;
33
+ action?: string;
34
+ }
35
+ declare class InMemoryIntegrationAuditStore implements IntegrationAuditStore {
36
+ private readonly events;
37
+ record(event: IntegrationAuditEvent): void;
38
+ list(filter?: IntegrationAuditFilter): IntegrationAuditEvent[];
39
+ }
40
+ declare function createIntegrationAuditEvent(input: Omit<IntegrationAuditEvent, 'id' | 'occurredAt'> & {
41
+ id?: string;
42
+ occurredAt?: string | Date;
43
+ now?: () => Date;
44
+ }): IntegrationAuditEvent;
45
+ declare function createAuditingActionGuard(options: {
46
+ sink: IntegrationAuditSink;
47
+ subject?: IntegrationActor;
48
+ now?: () => Date;
49
+ includeInputPreview?: boolean;
50
+ }): IntegrationActionGuard;
51
+ declare function sanitizeAuditConnection(connection: IntegrationConnection): Record<string, unknown>;
52
+
53
+ type IntegrationHealthcheckStatus = 'healthy' | 'degraded' | 'unhealthy' | 'unknown';
54
+ interface IntegrationHealthcheckCheck {
55
+ id: string;
56
+ status: IntegrationHealthcheckStatus;
57
+ message: string;
58
+ metadata?: Record<string, unknown>;
59
+ }
60
+ interface IntegrationHealthcheckResult {
61
+ connectionId: string;
62
+ providerId: string;
63
+ connectorId: string;
64
+ status: IntegrationHealthcheckStatus;
65
+ checkedAt: string;
66
+ checks: IntegrationHealthcheckCheck[];
67
+ metadata?: Record<string, unknown>;
68
+ }
69
+ interface IntegrationHealthcheckStore {
70
+ put(result: IntegrationHealthcheckResult): Promise<void> | void;
71
+ get(connectionId: string): Promise<IntegrationHealthcheckResult | undefined> | IntegrationHealthcheckResult | undefined;
72
+ list(): Promise<IntegrationHealthcheckResult[]> | IntegrationHealthcheckResult[];
73
+ }
74
+ declare class InMemoryIntegrationHealthcheckStore implements IntegrationHealthcheckStore {
75
+ private readonly results;
76
+ put(result: IntegrationHealthcheckResult): void;
77
+ get(connectionId: string): IntegrationHealthcheckResult | undefined;
78
+ list(): IntegrationHealthcheckResult[];
79
+ }
80
+ declare function runIntegrationHealthcheck(input: {
81
+ connection: IntegrationConnection;
82
+ connector?: IntegrationConnector;
83
+ registry?: IntegrationRegistry;
84
+ test?: (connection: IntegrationConnection, connector: IntegrationConnector) => Promise<IntegrationActionResult | boolean> | IntegrationActionResult | boolean;
85
+ audit?: IntegrationAuditSink;
86
+ now?: () => Date;
87
+ }): Promise<IntegrationHealthcheckResult>;
88
+ declare function runIntegrationHealthchecks(input: {
89
+ connections: IntegrationConnection[];
90
+ registry?: IntegrationRegistry;
91
+ store?: IntegrationHealthcheckStore;
92
+ audit?: IntegrationAuditSink;
93
+ now?: () => Date;
94
+ test?: (connection: IntegrationConnection, connector: IntegrationConnector) => Promise<IntegrationActionResult | boolean> | IntegrationActionResult | boolean;
95
+ }): Promise<IntegrationHealthcheckResult[]>;
96
+ declare function healthcheckRequest(action?: string): IntegrationActionRequest;
97
+
98
+ /**
99
+ * @stable Integration Hub consumer client.
100
+ *
101
+ * The third client-shaped surface a product needs, alongside the two that
102
+ * already ship:
103
+ *
104
+ * - `createTangleIntegrationsClient` (`client.ts`) — the *invoke* client.
105
+ * Capability-token auth, runs INSIDE a sandbox / generated app, single
106
+ * endpoint `/v1/integrations/invoke`.
107
+ * - `startConnectFlow` / `finishConnectFlow` (`connect/index.ts`) — the
108
+ * *user-consent* flow, mirrors `/cross-site/*`.
109
+ * - **this** — the S2S *management* client. A product BACKEND (blueprint-
110
+ * agent, sandbox, gtm-agent, tax-agent, legal-agent, evals, …) drives the
111
+ * `/v1/integrations/{resolve-manifest,grants,capabilities/bundle,
112
+ * healthchecks/run}` management surface on `id.tangle.tools` on behalf of
113
+ * an identified user.
114
+ *
115
+ * Every consumer needs the identical client — the wire protocol, the
116
+ * `{ success, data }` envelope, the auth header shape are all platform-owned.
117
+ * Re-implementing a bespoke fetch loop per product forks the protocol and the
118
+ * copies drift. This module is that shared implementation. It mirrors the
119
+ * `connect/index.ts` design rule one-for-one: DO NOT invent the wire protocol
120
+ * — speak exactly what `products/platform/api/src/routes/integrations.ts`
121
+ * serves.
122
+ *
123
+ * Two auth modes — the route layer (`authMiddleware`) accepts either:
124
+ *
125
+ * - `service` — a `svc_*` service token + `X-Service-Name`. The acting
126
+ * user travels in `X-Platform-User-Id`. The platform honors that header
127
+ * only for service tokens whose `SERVICE_SCOPES` set contains
128
+ * `impersonate:user`; a token without it is rejected (403). Reaches the
129
+ * four management paths the platform allowlists for service tokens.
130
+ * - `user-key` — a per-user `sk-tan-*` API key (minted via the connect
131
+ * flow). The key identifies the user; no impersonation header. Reaches
132
+ * every route the user themselves can.
133
+ *
134
+ * The capability-token `invoke` endpoint is intentionally NOT exposed here —
135
+ * that is `createTangleIntegrationsClient`'s job and uses a different auth.
136
+ */
137
+
138
+ type IntegrationHubAuth = {
139
+ mode: 'service';
140
+ /** The `svc_*` token issued to this product. */
141
+ serviceToken: string;
142
+ /** Registered service name — sent as `X-Service-Name`. Required
143
+ * because one token may be shared across services, in which case the
144
+ * platform demands the header to disambiguate. */
145
+ serviceName: string;
146
+ } | {
147
+ mode: 'user-key';
148
+ /** A per-user `sk-tan-*` key bound to the acting user. */
149
+ apiKey: string;
150
+ };
151
+ interface IntegrationHubClientOptions {
152
+ /** The product / consumer identifier (e.g. `blueprint-agent`). Sent as the
153
+ * `product` field of resolve-manifest calls; recorded platform-side. */
154
+ product: string;
155
+ /** Service-token or per-user-key auth. */
156
+ auth: IntegrationHubAuth;
157
+ /** Platform base URL. Defaults to `https://id.tangle.tools`. */
158
+ endpoint?: string;
159
+ /** Injected for tests. Defaults to the global `fetch`. */
160
+ fetchImpl?: typeof fetch;
161
+ /** Per-request timeout in ms. Default 10_000. */
162
+ timeoutMs?: number;
163
+ /** Max attempts on transient (network / 502 / 503 / 504) failures.
164
+ * Default 2 — i.e. one retry. */
165
+ maxAttempts?: number;
166
+ }
167
+ /** Thrown for every non-2xx response and every transport failure. Carries the
168
+ * HTTP status and the platform error code so callers can branch precisely
169
+ * (`403` + `impersonate` → the service token lacks the scope; `409` /
170
+ * `missing_connection` → prompt the user to connect). */
171
+ declare class IntegrationHubRequestError extends Error {
172
+ readonly name = "IntegrationHubRequestError";
173
+ /** HTTP status, or 0 for a network-level failure. */
174
+ readonly status: number;
175
+ /** Platform error code (`VALIDATION_ERROR`, `scope_missing`, …) or
176
+ * `network_error` / `http_error` when no structured code was returned. */
177
+ readonly code: string;
178
+ /** `METHOD /path` the request targeted. */
179
+ readonly endpoint: string;
180
+ /** True when the failure class is transient and a retry could succeed. */
181
+ readonly retryable: boolean;
182
+ constructor(input: {
183
+ status: number;
184
+ code: string;
185
+ message: string;
186
+ endpoint: string;
187
+ retryable: boolean;
188
+ });
189
+ }
190
+ interface ResolveManifestInput {
191
+ /** The acting user — the connection owner. */
192
+ userId: string;
193
+ manifest: IntegrationManifest;
194
+ /** Overrides the client-level `product` for this call. */
195
+ product?: string;
196
+ }
197
+ interface CreateGrantsInput {
198
+ /** The acting user — the connection owner. */
199
+ userId: string;
200
+ /** Who the grant is FOR (the sandbox / agent / app that will invoke). */
201
+ grantee: IntegrationActor;
202
+ manifest: IntegrationManifest;
203
+ metadata?: Record<string, unknown>;
204
+ }
205
+ interface ListGrantsInput {
206
+ /** The acting user — the connection owner. */
207
+ userId: string;
208
+ /** Optional grantee filter; both fields travel together as query params. */
209
+ grantee?: IntegrationActor;
210
+ }
211
+ interface MintCapabilityBundleInput {
212
+ /** The acting user — must own every connection behind the grants. */
213
+ userId: string;
214
+ /** Who the capability bundle is issued TO (the sandbox / agent process). */
215
+ subject: IntegrationActor;
216
+ /** Mint from every grant of a manifest … */
217
+ manifestId?: string;
218
+ /** … or from an explicit grant id list. Exactly one of the two is required. */
219
+ grantIds?: string[];
220
+ grantee?: IntegrationActor;
221
+ /** Bundle TTL in ms. Platform clamps to [1s, 60m]; default 15m. */
222
+ ttlMs?: number;
223
+ }
224
+ interface CapabilityBundleResult {
225
+ bundle: IntegrationSandboxBundle;
226
+ /** Bridge environment variables to inject into the sandbox process —
227
+ * `buildIntegrationBridgeEnvironment(bundle)`, computed platform-side. */
228
+ env: Record<string, string>;
229
+ }
230
+ interface CheckConnectorInput {
231
+ /** The acting user. */
232
+ userId: string;
233
+ /** Connector to probe — `github`, `google-calendar`, `tangle-id`, … */
234
+ connectorId: string;
235
+ /** Defaults to `read`. */
236
+ mode?: IntegrationRequirementMode;
237
+ requiredScopes?: string[];
238
+ requiredActions?: string[];
239
+ }
240
+ interface CheckConnectorResult {
241
+ /** True when the user has an active connection satisfying the requirement. */
242
+ connected: boolean;
243
+ /** The satisfying connection, present iff `connected`. */
244
+ connection?: IntegrationConnection;
245
+ /** The full requirement resolution — status, missing scopes/actions, message. */
246
+ resolution: IntegrationRequirementResolution;
247
+ }
248
+ /**
249
+ * S2S management client for the `id.tangle.tools` integration hub. One per
250
+ * product; methods are stateless and safe to call concurrently.
251
+ */
252
+ declare class IntegrationHubClient {
253
+ private readonly endpoint;
254
+ private readonly product;
255
+ private readonly auth;
256
+ private readonly fetchImpl;
257
+ private readonly timeoutMs;
258
+ private readonly maxAttempts;
259
+ constructor(options: IntegrationHubClientOptions);
260
+ /**
261
+ * Resolve a manifest against a user's connections. The returned
262
+ * `ready` / `missing` split is the canonical way to ask "does this user
263
+ * have the connections this work needs" — the raw connection list is not
264
+ * reachable by a service token by design.
265
+ */
266
+ resolveManifest(input: ResolveManifestInput): Promise<IntegrationManifestResolution>;
267
+ /**
268
+ * Convenience over {@link resolveManifest} — probe a single connector and
269
+ * get back a boolean plus the satisfying connection. The Surface-A quest
270
+ * primitive ("is the user's GitHub linked?").
271
+ */
272
+ checkConnector(input: CheckConnectorInput): Promise<CheckConnectorResult>;
273
+ /** Create grants for every satisfiable requirement of a manifest. The
274
+ * platform rejects the call if any non-optional requirement is missing a
275
+ * connection. */
276
+ createGrants(input: CreateGrantsInput): Promise<IntegrationGrant[]>;
277
+ /** List the acting user's grants, optionally filtered to one grantee. */
278
+ listGrants(input: ListGrantsInput): Promise<IntegrationGrant[]>;
279
+ /** Mint a short-lived capability bundle for a sandbox / agent process.
280
+ * Provider credentials never leave the platform — the bundle carries only
281
+ * scoped, expiring capability tokens. */
282
+ mintCapabilityBundle(input: MintCapabilityBundleInput): Promise<CapabilityBundleResult>;
283
+ /** Run live healthchecks across all of the acting user's connections. */
284
+ runHealthchecks(input: {
285
+ userId: string;
286
+ }): Promise<IntegrationHealthcheckResult[]>;
287
+ private buildHeaders;
288
+ private request;
289
+ }
290
+ declare function createIntegrationHubClient(options: IntegrationHubClientOptions): IntegrationHubClient;
291
+
292
+ export { type CapabilityBundleResult as C, type IntegrationAuditSink as I, type ListGrantsInput as L, type MintCapabilityBundleInput as M, type ResolveManifestInput as R, type CheckConnectorInput as a, type CheckConnectorResult as b, type CreateGrantsInput as c, InMemoryIntegrationAuditStore as d, InMemoryIntegrationHealthcheckStore as e, type IntegrationAuditEvent as f, type IntegrationAuditEventType as g, type IntegrationAuditFilter as h, type IntegrationAuditStore as i, type IntegrationHealthcheckCheck as j, type IntegrationHealthcheckResult as k, type IntegrationHealthcheckStatus as l, type IntegrationHealthcheckStore as m, type IntegrationHubAuth as n, IntegrationHubClient as o, type IntegrationHubClientOptions as p, IntegrationHubRequestError as q, createAuditingActionGuard as r, createIntegrationAuditEvent as s, createIntegrationHubClient as t, healthcheckRequest as u, runIntegrationHealthcheck as v, runIntegrationHealthchecks as w, sanitizeAuditConnection as x };
@@ -1,8 +1,6 @@
1
- export { C as CapabilityBundleResult, A as CheckConnectorInput, B as CheckConnectorResult, D as CreateGrantsInput, E as IntegrationHubAuth, F as IntegrationHubClient, G as IntegrationHubClientOptions, H as IntegrationHubRequestError, L as ListGrantsInput, J as MintCapabilityBundleInput, R as ResolveManifestInput, K as createIntegrationHubClient } from './registry.js';
2
- import './tangle-id-Dj0ipP4E.js';
3
- import './errors-Bg3_rxnQ.js';
4
- import './connect/index.js';
5
- import './middleware/index.js';
6
- import './connectors/index.js';
7
- import './connectors/adapters/index.js';
8
- import 'node:http';
1
+ import './core-types-D5Dc65Ud.js';
2
+ import './runtime.js';
3
+ export { C as CapabilityBundleResult, a as CheckConnectorInput, b as CheckConnectorResult, c as CreateGrantsInput, n as IntegrationHubAuth, o as IntegrationHubClient, p as IntegrationHubClientOptions, q as IntegrationHubRequestError, L as ListGrantsInput, M as MintCapabilityBundleInput, R as ResolveManifestInput, t as createIntegrationHubClient } from './consumer-CzJgntej.js';
4
+ import './types-XdpvaIzW.js';
5
+ import './catalog.js';
6
+ import './registry.js';
package/dist/consumer.js CHANGED
@@ -2,8 +2,8 @@ import {
2
2
  IntegrationHubClient,
3
3
  IntegrationHubRequestError,
4
4
  createIntegrationHubClient
5
- } from "./chunk-S2MVWQYL.js";
6
- import "./chunk-Q5X3QNHR.js";
5
+ } from "./chunk-RF3RH374.js";
6
+ import "./chunk-NQ7OPDUM.js";
7
7
  export {
8
8
  IntegrationHubClient,
9
9
  IntegrationHubRequestError,
@@ -0,0 +1,355 @@
1
+ import { a as ConnectorCredentials } from './types-XdpvaIzW.js';
2
+
3
+ /**
4
+ * Vendor-neutral integration contracts.
5
+ *
6
+ * Pure type module: every interface, type alias, and enum that other
7
+ * source files reference lives here. Holds zero runtime symbols so any
8
+ * module can import from it without forming a cycle through the package
9
+ * barrel (`./index.ts`).
10
+ *
11
+ * Runtime classes (`IntegrationError`, `InMemoryConnectionStore`,
12
+ * `IntegrationHub`, helpers) stay in `./index.ts` or are split out into
13
+ * their own focused modules (`./core-error.ts`).
14
+ */
15
+
16
+ type IntegrationProviderKind = 'first_party' | 'nango' | 'pipedream' | 'zapier' | 'activepieces' | 'tangle_catalog' | 'executor' | 'custom';
17
+ type IntegrationConnectorCategory = 'email' | 'calendar' | 'chat' | 'crm' | 'storage' | 'docs' | 'database' | 'webhook' | 'workflow' | 'internal' | 'other';
18
+ type IntegrationActionRisk = 'read' | 'write' | 'destructive';
19
+ type IntegrationDataClass = 'public' | 'internal' | 'private' | 'sensitive' | 'secret';
20
+ interface IntegrationActor {
21
+ type: 'user' | 'team' | 'app' | 'agent' | 'sandbox' | 'system';
22
+ id: string;
23
+ }
24
+ interface IntegrationConnectorAction {
25
+ id: string;
26
+ title: string;
27
+ risk: IntegrationActionRisk;
28
+ requiredScopes: string[];
29
+ dataClass: IntegrationDataClass;
30
+ description?: string;
31
+ approvalRequired?: boolean;
32
+ inputSchema?: unknown;
33
+ outputSchema?: unknown;
34
+ }
35
+ interface IntegrationConnectorTrigger {
36
+ id: string;
37
+ title: string;
38
+ requiredScopes: string[];
39
+ dataClass: IntegrationDataClass;
40
+ description?: string;
41
+ payloadSchema?: unknown;
42
+ }
43
+ interface IntegrationConnector {
44
+ id: string;
45
+ providerId: string;
46
+ title: string;
47
+ category: IntegrationConnectorCategory;
48
+ auth: 'oauth2' | 'api_key' | 'none' | 'custom';
49
+ scopes: string[];
50
+ actions: IntegrationConnectorAction[];
51
+ triggers?: IntegrationConnectorTrigger[];
52
+ metadata?: Record<string, unknown>;
53
+ }
54
+ interface SecretRef {
55
+ provider: string;
56
+ id: string;
57
+ label?: string;
58
+ }
59
+ interface IntegrationConnection {
60
+ id: string;
61
+ owner: IntegrationActor;
62
+ providerId: string;
63
+ connectorId: string;
64
+ status: 'pending' | 'active' | 'expired' | 'revoked' | 'error';
65
+ grantedScopes: string[];
66
+ account?: {
67
+ id?: string;
68
+ email?: string;
69
+ displayName?: string;
70
+ };
71
+ secretRef?: SecretRef;
72
+ createdAt: string;
73
+ updatedAt: string;
74
+ expiresAt?: string;
75
+ lastUsedAt?: string;
76
+ metadata?: Record<string, unknown>;
77
+ }
78
+ interface StartAuthRequest {
79
+ connectorId: string;
80
+ owner: IntegrationActor;
81
+ requestedScopes: string[];
82
+ redirectUri: string;
83
+ state?: string;
84
+ metadata?: Record<string, unknown>;
85
+ }
86
+ interface StartAuthResult {
87
+ providerId: string;
88
+ connectorId: string;
89
+ authUrl: string;
90
+ state: string;
91
+ expiresAt?: string;
92
+ metadata?: Record<string, unknown>;
93
+ }
94
+ interface CompleteAuthRequest {
95
+ connectorId: string;
96
+ owner: IntegrationActor;
97
+ code?: string;
98
+ state: string;
99
+ redirectUri: string;
100
+ metadata?: Record<string, unknown>;
101
+ }
102
+ interface IntegrationActionRequest {
103
+ connectionId: string;
104
+ action: string;
105
+ input?: unknown;
106
+ idempotencyKey?: string;
107
+ dryRun?: boolean;
108
+ metadata?: Record<string, unknown>;
109
+ }
110
+ interface IntegrationActionResult<T = unknown> {
111
+ ok: boolean;
112
+ action: string;
113
+ output?: T;
114
+ externalId?: string;
115
+ warnings?: string[];
116
+ metadata?: Record<string, unknown>;
117
+ }
118
+ interface IntegrationTriggerSubscription {
119
+ id: string;
120
+ connectionId: string;
121
+ trigger: string;
122
+ targetUrl?: string;
123
+ status: 'active' | 'paused' | 'error';
124
+ createdAt: string;
125
+ metadata?: Record<string, unknown>;
126
+ }
127
+ interface IntegrationTriggerEvent<T = unknown> {
128
+ id: string;
129
+ providerId: string;
130
+ connectorId: string;
131
+ connectionId: string;
132
+ trigger: string;
133
+ occurredAt: string;
134
+ payload: T;
135
+ metadata?: Record<string, unknown>;
136
+ }
137
+ interface IntegrationProvider {
138
+ id: string;
139
+ kind: IntegrationProviderKind;
140
+ listConnectors(): Promise<IntegrationConnector[]> | IntegrationConnector[];
141
+ startAuth?(request: StartAuthRequest): Promise<StartAuthResult> | StartAuthResult;
142
+ completeAuth?(request: CompleteAuthRequest): Promise<IntegrationConnection> | IntegrationConnection;
143
+ invokeAction(connection: IntegrationConnection, request: IntegrationActionRequest): Promise<IntegrationActionResult> | IntegrationActionResult;
144
+ subscribeTrigger?(connection: IntegrationConnection, trigger: string, targetUrl?: string): Promise<IntegrationTriggerSubscription> | IntegrationTriggerSubscription;
145
+ unsubscribeTrigger?(subscriptionId: string): Promise<void> | void;
146
+ normalizeTriggerEvent?(raw: unknown): Promise<IntegrationTriggerEvent> | IntegrationTriggerEvent;
147
+ }
148
+ interface IntegrationConnectionStore {
149
+ get(connectionId: string): Promise<IntegrationConnection | undefined> | IntegrationConnection | undefined;
150
+ put(connection: IntegrationConnection): Promise<void> | void;
151
+ listByOwner(owner: IntegrationActor): Promise<IntegrationConnection[]> | IntegrationConnection[];
152
+ delete?(connectionId: string): Promise<void> | void;
153
+ }
154
+ interface IssueCapabilityRequest {
155
+ subject: IntegrationActor;
156
+ connectionId: string;
157
+ scopes: string[];
158
+ allowedActions: string[];
159
+ ttlMs: number;
160
+ metadata?: Record<string, unknown>;
161
+ }
162
+ interface IntegrationCapability {
163
+ id: string;
164
+ subject: IntegrationActor;
165
+ connectionId: string;
166
+ scopes: string[];
167
+ allowedActions: string[];
168
+ issuedAt: string;
169
+ expiresAt: string;
170
+ metadata?: Record<string, unknown>;
171
+ }
172
+ interface IssuedIntegrationCapability {
173
+ capability: IntegrationCapability;
174
+ token: string;
175
+ }
176
+ /**
177
+ * Wraps every action invocation with cross-cutting discipline (idempotency,
178
+ * conflict detection, rate-limiting, audit logging). Optional. When set on
179
+ * the hub, runs BEFORE provider.invokeAction; can short-circuit (return a
180
+ * result directly) or pass through (call `proceed()` to invoke the provider).
181
+ *
182
+ * Why this hook exists: production deployments need conflict-resolution
183
+ * guarantees that span every provider, gateway, and webhook receiver. The
184
+ * canonical implementation is a "MutationGuard" that:
185
+ * 1. Short-circuits on a known idempotency key (returns recorded response).
186
+ * 2. Refuses same-key-different-args (drift detection).
187
+ * 3. Wraps `proceed()` and audit-logs the outcome.
188
+ * 4. Translates upstream conflict signals into a structured result with
189
+ * alternatives the agent can act on.
190
+ *
191
+ * Implementations live in consumers (every product has different
192
+ * persistence + telemetry needs); this interface is the contract.
193
+ */
194
+ interface IntegrationActionGuard {
195
+ /** Wrap an invokeAction call. Implementations MUST call `proceed()` to
196
+ * invoke the underlying provider unless they're returning a cached or
197
+ * short-circuited result.
198
+ *
199
+ * @param ctx connection + request the hub is about to dispatch
200
+ * @param proceed call to invoke the wrapped provider; returns the
201
+ * underlying IntegrationActionResult
202
+ * @returns the result the hub should return to the caller
203
+ */
204
+ invokeAction(ctx: IntegrationGuardContext, proceed: () => Promise<IntegrationActionResult>): Promise<IntegrationActionResult>;
205
+ }
206
+ interface IntegrationGuardContext {
207
+ connection: IntegrationConnection;
208
+ request: IntegrationActionRequest;
209
+ /** The action descriptor from the connector manifest, if discovered. */
210
+ action?: IntegrationConnectorAction;
211
+ }
212
+ type IntegrationPolicyDecision = {
213
+ decision: 'allow';
214
+ reason: string;
215
+ metadata?: Record<string, unknown>;
216
+ } | {
217
+ decision: 'require_approval';
218
+ reason: string;
219
+ approval: IntegrationApprovalRequest;
220
+ metadata?: Record<string, unknown>;
221
+ } | {
222
+ decision: 'deny';
223
+ reason: string;
224
+ metadata?: Record<string, unknown>;
225
+ };
226
+ interface IntegrationApprovalRequest {
227
+ id: string;
228
+ connectionId: string;
229
+ providerId: string;
230
+ connectorId: string;
231
+ action: string;
232
+ actor: IntegrationActor;
233
+ risk: IntegrationActionRisk;
234
+ dataClass: IntegrationDataClass;
235
+ reason: string;
236
+ requestedAt: string;
237
+ inputPreview?: unknown;
238
+ metadata?: Record<string, unknown>;
239
+ }
240
+ interface IntegrationPolicyEngine {
241
+ decide(ctx: IntegrationGuardContext & {
242
+ subject: IntegrationActor;
243
+ }): Promise<IntegrationPolicyDecision> | IntegrationPolicyDecision;
244
+ }
245
+ interface IntegrationHubOptions {
246
+ providers: IntegrationProvider[];
247
+ store: IntegrationConnectionStore;
248
+ capabilitySecret: string;
249
+ /** Optional cross-cutting guard. If provided, every invokeAction call
250
+ * passes through it before reaching the provider. See {@link IntegrationActionGuard}. */
251
+ guard?: IntegrationActionGuard;
252
+ /** Optional policy engine. Runs after capability/scope checks and before
253
+ * provider invocation. Use it to pause writes, deny destructive actions,
254
+ * or apply tenant-specific allow rules. */
255
+ policy?: IntegrationPolicyEngine;
256
+ /** Host-injectable secret store. Multi-tenant hubs inject a durable
257
+ * encrypted store; defaults to InMemoryIntegrationSecretStore for
258
+ * local/dev and tests. The interface is the contract — the lib never
259
+ * ships a D1/KV/encryption impl. */
260
+ secretStore?: IntegrationSecretStore;
261
+ /** Host-injectable single-use OAuth-state store guarding the start →
262
+ * callback CSRF boundary. Defaults to InMemoryIntegrationOAuthStateStore. */
263
+ oauthStateStore?: IntegrationOAuthStateStore;
264
+ /** TTL applied to OAuth-state records the hub stashes at startAuth.
265
+ * Defaults to 10 minutes. */
266
+ oauthStateTtlMs?: number;
267
+ /** Fired whenever a provider surfaces rotated credentials during an
268
+ * invoke (e.g. an OAuth access token refreshed on expiry). The host
269
+ * re-encrypts + persists the rotated envelope so the next expiry does
270
+ * not force a reconnect. The hub also writes the rotated credentials to
271
+ * {@link secretStore} when the connection carries a secretRef. */
272
+ credentialsRotated?: (event: IntegrationCredentialsRotatedEvent) => Promise<void> | void;
273
+ now?: () => Date;
274
+ }
275
+ /** Emitted when a provider rotates credentials mid-invoke. The host
276
+ * re-persists `credentials` against `secretRef` (when present) so the
277
+ * refreshed token survives the call. */
278
+ interface IntegrationCredentialsRotatedEvent {
279
+ connection: IntegrationConnection;
280
+ secretRef?: SecretRef;
281
+ credentials: ConnectorCredentials;
282
+ }
283
+ interface HttpIntegrationProviderOptions {
284
+ id: string;
285
+ kind?: IntegrationProviderKind;
286
+ connectors: IntegrationConnector[];
287
+ baseUrl: string;
288
+ bearer?: string;
289
+ fetchImpl?: typeof fetch;
290
+ }
291
+ interface InvokeWithCapabilityRequest extends Omit<IntegrationActionRequest, 'connectionId'> {
292
+ connectionId?: never;
293
+ }
294
+ /** A catalog of connectors keyed by stable source id. The registry merges
295
+ * multiple sources (first-party adapter packs, Activepieces import, custom
296
+ * HTTP catalog, …) into a canonical view with conflict reporting. */
297
+ interface IntegrationCatalogSource {
298
+ id: string;
299
+ connectors: IntegrationConnector[];
300
+ precedence?: number;
301
+ }
302
+ /** Host-injectable persistent store for OAuth tokens and other connector
303
+ * credentials. Multi-tenant hubs inject a durable encrypted store; defaults
304
+ * to an in-memory implementation for local/dev and tests. The interface is
305
+ * the contract — the lib never ships a D1/KV/encryption impl. */
306
+ interface IntegrationSecretStore {
307
+ get(ref: SecretRef): Promise<ConnectorCredentials | undefined> | ConnectorCredentials | undefined;
308
+ put(ref: SecretRef, credentials: ConnectorCredentials): Promise<void> | void;
309
+ delete?(ref: SecretRef): Promise<void> | void;
310
+ }
311
+ /** Single-use record stashed at OAuth-start and consumed once at callback to
312
+ * guard against CSRF / replay. The hub injects its own durable
313
+ * implementation (KV/Redis/D1) so the callback can land on any worker. */
314
+ interface IntegrationOAuthState {
315
+ /** Opaque value round-tripped through the provider redirect. */
316
+ state: string;
317
+ /** Provider the auth flow targets. */
318
+ providerId: string;
319
+ /** Connector the user is connecting. */
320
+ connectorId: string;
321
+ /** Owner initiating the flow. */
322
+ owner: IntegrationActor;
323
+ /** Scopes requested at start; verified against the granted scopes on callback. */
324
+ requestedScopes: string[];
325
+ /** Redirect URI used at start; MUST match exactly on callback exchange. */
326
+ redirectUri: string;
327
+ /** PKCE code_verifier, when the connector uses PKCE. */
328
+ codeVerifier?: string;
329
+ /** Absolute expiry (UTC ms since epoch). consume() MUST treat an expired
330
+ * record as a miss. */
331
+ expiresAt: number;
332
+ /** Arbitrary non-secret context the host pinned at start-time. */
333
+ metadata?: Record<string, unknown>;
334
+ }
335
+ /** Outcome of consuming an OAuth state record. Callers MUST inspect `ok`
336
+ * before using `state`; a miss (`unknown`/`expired`) is the CSRF/replay
337
+ * guard firing, not an exception. */
338
+ type IntegrationOAuthStateOutcome = {
339
+ ok: true;
340
+ state: IntegrationOAuthState;
341
+ } | {
342
+ ok: false;
343
+ reason: 'unknown' | 'expired';
344
+ };
345
+ /** Host-injectable store for single-use OAuth-start records. The default is
346
+ * in-memory for local/dev and tests; multi-tenant hubs inject a durable
347
+ * encrypted store so callbacks survive worker hops. consume() MUST be
348
+ * single-use: a second consume of the same state returns `{ ok: false }`. */
349
+ interface IntegrationOAuthStateStore {
350
+ put(state: IntegrationOAuthState): Promise<void> | void;
351
+ consume(state: string): Promise<IntegrationOAuthStateOutcome> | IntegrationOAuthStateOutcome;
352
+ sweep?(now: number): Promise<void> | void;
353
+ }
354
+
355
+ export type { IntegrationTriggerEvent as A, InvokeWithCapabilityRequest as B, CompleteAuthRequest as C, IntegrationCapability as D, IntegrationHubOptions as E, IssueCapabilityRequest as F, IntegrationConnectorTrigger as G, HttpIntegrationProviderOptions as H, IntegrationActor as I, StartAuthRequest as S, IssuedIntegrationCapability as a, IntegrationConnector as b, IntegrationConnection as c, IntegrationConnectorCategory as d, IntegrationConnectorAction as e, IntegrationActionRisk as f, IntegrationDataClass as g, IntegrationCatalogSource as h, IntegrationActionGuard as i, IntegrationActionRequest as j, IntegrationActionResult as k, StartAuthResult as l, IntegrationProvider as m, IntegrationSecretStore as n, IntegrationPolicyEngine as o, IntegrationApprovalRequest as p, IntegrationGuardContext as q, IntegrationPolicyDecision as r, IntegrationProviderKind as s, IntegrationConnectionStore as t, IntegrationCredentialsRotatedEvent as u, IntegrationOAuthStateStore as v, IntegrationOAuthState as w, IntegrationOAuthStateOutcome as x, SecretRef as y, IntegrationTriggerSubscription as z };