@tangle-network/agent-integrations 0.31.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-M2RFFAMB.js → chunk-XO2RSS6Y.js} +300 -13
  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 -2407
  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-F4YILONK.js.map +0 -1
  44. package/dist/chunk-M2RFFAMB.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
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  integrationSpecToConnector,
7
7
  listIntegrationSpecs
8
- } from "./chunk-VVC7U7W7.js";
8
+ } from "./chunk-7T5YTVER.js";
9
9
 
10
10
  // src/activepieces-catalog.ts
11
11
  import { readFileSync } from "fs";
@@ -201,10 +201,21 @@ function dataClassFor(category) {
201
201
  // src/index.ts
202
202
  import { createHmac as createHmac2, randomUUID as randomUUID5, timingSafeEqual as timingSafeEqual2 } from "crypto";
203
203
 
204
+ // src/core-error.ts
205
+ var IntegrationError = class extends Error {
206
+ constructor(message, code) {
207
+ super(message);
208
+ this.code = code;
209
+ this.name = "IntegrationError";
210
+ }
211
+ code;
212
+ };
213
+
204
214
  // src/adapter-provider.ts
205
215
  function createConnectorAdapterProvider(options) {
206
216
  const providerId = options.id ?? "first-party";
207
217
  const now = options.now ?? (() => /* @__PURE__ */ new Date());
218
+ const fetchImpl = options.fetchImpl ?? globalThis.fetch?.bind(globalThis);
208
219
  const adapters = /* @__PURE__ */ new Map();
209
220
  for (const adapter of options.adapters) {
210
221
  adapters.set(adapter.manifest.kind, adapter);
@@ -213,6 +224,159 @@ function createConnectorAdapterProvider(options) {
213
224
  id: providerId,
214
225
  kind: options.kind ?? "first_party",
215
226
  listConnectors: () => [...adapters.values()].map((adapter) => manifestToConnector(providerId, adapter)),
227
+ async startAuth(request) {
228
+ const adapter = adapters.get(request.connectorId);
229
+ if (!adapter) {
230
+ throw new IntegrationError(
231
+ `Connector adapter ${request.connectorId} not found.`,
232
+ "connector_not_found"
233
+ );
234
+ }
235
+ const auth = adapter.manifest.auth;
236
+ if (auth.kind !== "oauth2") {
237
+ throw new IntegrationError(
238
+ `Connector ${request.connectorId} does not support OAuth2 authorization (auth kind: ${auth.kind}).`,
239
+ "auth_not_supported"
240
+ );
241
+ }
242
+ if (!options.resolveOAuthClient) {
243
+ throw new IntegrationError(
244
+ `OAuth client resolver missing on adapter provider; cannot start auth for ${request.connectorId}.`,
245
+ "config_missing"
246
+ );
247
+ }
248
+ const client = await options.resolveOAuthClient({ connectorId: request.connectorId });
249
+ if (!client || !client.clientId || !client.clientSecret) {
250
+ throw new IntegrationError(
251
+ `OAuth client credentials unavailable for ${request.connectorId}.`,
252
+ "config_missing"
253
+ );
254
+ }
255
+ const scopes = request.requestedScopes && request.requestedScopes.length > 0 ? request.requestedScopes : auth.scopes;
256
+ const url = new URL(auth.authorizationUrl);
257
+ url.searchParams.set("response_type", "code");
258
+ url.searchParams.set("client_id", client.clientId);
259
+ url.searchParams.set("redirect_uri", request.redirectUri);
260
+ if (scopes.length > 0) {
261
+ url.searchParams.set("scope", scopes.join(" "));
262
+ }
263
+ const state = request.state ?? randomState();
264
+ url.searchParams.set("state", state);
265
+ if (auth.extraAuthParams) {
266
+ for (const [key, value] of Object.entries(auth.extraAuthParams)) {
267
+ url.searchParams.set(key, value);
268
+ }
269
+ }
270
+ return {
271
+ providerId,
272
+ connectorId: request.connectorId,
273
+ authUrl: url.toString(),
274
+ state,
275
+ metadata: request.metadata
276
+ };
277
+ },
278
+ async completeAuth(request) {
279
+ const adapter = adapters.get(request.connectorId);
280
+ if (!adapter) {
281
+ throw new IntegrationError(
282
+ `Connector adapter ${request.connectorId} not found.`,
283
+ "connector_not_found"
284
+ );
285
+ }
286
+ const auth = adapter.manifest.auth;
287
+ if (auth.kind !== "oauth2") {
288
+ throw new IntegrationError(
289
+ `Connector ${request.connectorId} does not support OAuth2 authorization (auth kind: ${auth.kind}).`,
290
+ "auth_not_supported"
291
+ );
292
+ }
293
+ if (!request.code) {
294
+ throw new IntegrationError(
295
+ `Authorization code missing on completeAuth for ${request.connectorId}.`,
296
+ "config_missing"
297
+ );
298
+ }
299
+ if (!options.resolveOAuthClient) {
300
+ throw new IntegrationError(
301
+ `OAuth client resolver missing on adapter provider; cannot complete auth for ${request.connectorId}.`,
302
+ "config_missing"
303
+ );
304
+ }
305
+ const client = await options.resolveOAuthClient({ connectorId: request.connectorId });
306
+ if (!client || !client.clientId || !client.clientSecret) {
307
+ throw new IntegrationError(
308
+ `OAuth client credentials unavailable for ${request.connectorId}.`,
309
+ "config_missing"
310
+ );
311
+ }
312
+ if (!fetchImpl) {
313
+ throw new IntegrationError(
314
+ "No fetch implementation available; inject fetchImpl into createConnectorAdapterProvider.",
315
+ "config_missing"
316
+ );
317
+ }
318
+ const body = new URLSearchParams({
319
+ grant_type: "authorization_code",
320
+ code: request.code,
321
+ client_id: client.clientId,
322
+ client_secret: client.clientSecret,
323
+ redirect_uri: request.redirectUri
324
+ });
325
+ let res;
326
+ try {
327
+ res = await fetchImpl(auth.tokenUrl, {
328
+ method: "POST",
329
+ headers: {
330
+ "content-type": "application/x-www-form-urlencoded",
331
+ accept: "application/json"
332
+ },
333
+ body
334
+ });
335
+ } catch (cause) {
336
+ throw new IntegrationError(
337
+ `OAuth token exchange transport error for ${request.connectorId}: ${cause?.message ?? "unknown"}`,
338
+ "provider_failure"
339
+ );
340
+ }
341
+ if (!res.ok) {
342
+ const text = await res.text().catch(() => "");
343
+ throw new IntegrationError(
344
+ `OAuth token exchange failed for ${request.connectorId}: ${res.status} ${res.statusText} \u2014 ${text.slice(0, 200)}`,
345
+ "provider_failure"
346
+ );
347
+ }
348
+ let json;
349
+ try {
350
+ json = await res.json();
351
+ } catch {
352
+ throw new IntegrationError(
353
+ `OAuth token exchange returned non-JSON body for ${request.connectorId}.`,
354
+ "provider_failure"
355
+ );
356
+ }
357
+ if (!json.access_token) {
358
+ throw new IntegrationError(
359
+ `OAuth token exchange returned no access_token for ${request.connectorId}.`,
360
+ "provider_failure"
361
+ );
362
+ }
363
+ const grantedScopes = typeof json.scope === "string" && json.scope.length > 0 ? json.scope.split(/[\s,]+/).filter(Boolean) : [];
364
+ const issued = now();
365
+ const issuedIso = issued.toISOString();
366
+ const expiresAt = typeof json.expires_in === "number" && json.expires_in > 0 ? new Date(issued.getTime() + json.expires_in * 1e3).toISOString() : void 0;
367
+ return {
368
+ id: randomConnectionId(),
369
+ owner: request.owner,
370
+ providerId,
371
+ connectorId: request.connectorId,
372
+ status: "active",
373
+ grantedScopes,
374
+ createdAt: issuedIso,
375
+ updatedAt: issuedIso,
376
+ expiresAt,
377
+ metadata: request.metadata
378
+ };
379
+ },
216
380
  async invokeAction(connection, request) {
217
381
  const adapter = adapters.get(connection.connectorId);
218
382
  if (!adapter) {
@@ -368,6 +532,25 @@ function toRecord(input) {
368
532
  if (input && typeof input === "object" && !Array.isArray(input)) return input;
369
533
  return {};
370
534
  }
535
+ function randomState() {
536
+ const bytes = new Uint8Array(24);
537
+ globalThis.crypto.getRandomValues(bytes);
538
+ return base64UrlEncode(bytes);
539
+ }
540
+ function randomConnectionId() {
541
+ if (typeof globalThis.crypto?.randomUUID === "function") {
542
+ return `conn_${globalThis.crypto.randomUUID().replace(/-/g, "")}`;
543
+ }
544
+ const bytes = new Uint8Array(16);
545
+ globalThis.crypto.getRandomValues(bytes);
546
+ return `conn_${base64UrlEncode(bytes)}`;
547
+ }
548
+ function base64UrlEncode(bytes) {
549
+ let bin = "";
550
+ for (const b of bytes) bin += String.fromCharCode(b);
551
+ const b64 = typeof btoa === "function" ? btoa(bin) : Buffer.from(bin, "binary").toString("base64");
552
+ return b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
553
+ }
371
554
 
372
555
  // src/credentials.ts
373
556
  var InMemoryIntegrationSecretStore = class {
@@ -1013,6 +1196,116 @@ function assertBridgePayload(value) {
1013
1196
  if (!Array.isArray(payload.tools)) throw new Error("Invalid integration bridge tools.");
1014
1197
  }
1015
1198
 
1199
+ // src/apps.ts
1200
+ var TangleAppsClient = class {
1201
+ endpoint;
1202
+ fetchImpl;
1203
+ constructor(options) {
1204
+ this.endpoint = options.endpoint.replace(/\/$/, "");
1205
+ this.fetchImpl = options.fetchImpl ?? fetch;
1206
+ }
1207
+ /**
1208
+ * Register a product as an app (ONE-TIME, with the owner's bearer — a Tangle
1209
+ * session or `sk-tan-*` key). Returns the client_id + the once-shown
1210
+ * client_secret; persist the secret immediately (never retrievable again).
1211
+ */
1212
+ async registerApp(input, ownerBearer) {
1213
+ const data = await this.request(
1214
+ "POST",
1215
+ "/v1/apps",
1216
+ input,
1217
+ ownerBearer
1218
+ );
1219
+ return { ...data.app, clientSecret: data.clientSecret };
1220
+ }
1221
+ /** List the caller's registered apps (no secrets). */
1222
+ async listApps(ownerBearer) {
1223
+ const data = await this.request("GET", "/v1/apps", void 0, ownerBearer);
1224
+ return data.apps ?? [];
1225
+ }
1226
+ /** Revoke an app and cascade-kill its grants + tokens. */
1227
+ revokeApp(appId, ownerBearer) {
1228
+ return this.request("POST", `/v1/apps/${encodeURIComponent(appId)}/revoke`, {}, ownerBearer);
1229
+ }
1230
+ /**
1231
+ * Durable re-mint: mint a fresh single-use `sk-tan-broker-` token against an
1232
+ * existing consented grant using ONLY the app credentials — no user session,
1233
+ * no `agc_` code. The runtime path: one call per `/v1/hub/exec`.
1234
+ */
1235
+ async mintBrokerToken(input) {
1236
+ const data = await this.request(
1237
+ "POST",
1238
+ `/v1/apps/grants/${encodeURIComponent(input.grantId)}/mint-broker-token`,
1239
+ {
1240
+ client_id: input.clientId,
1241
+ client_secret: input.clientSecret,
1242
+ grant_id: input.grantId,
1243
+ ...input.ttlSeconds ? { ttl_seconds: input.ttlSeconds } : {}
1244
+ }
1245
+ );
1246
+ return toBrokerToken(data);
1247
+ }
1248
+ /**
1249
+ * Exchange an `agc_` authorization code (from the user's one-time consent)
1250
+ * for the first broker token + the durable grant. Use on the consent
1251
+ * callback; afterward `mintBrokerToken` is enough.
1252
+ */
1253
+ async exchangeAuthCode(input) {
1254
+ const data = await this.request("POST", "/v1/apps/oauth/token", {
1255
+ grant_type: "authorization_code",
1256
+ client_id: input.clientId,
1257
+ client_secret: input.clientSecret,
1258
+ code: input.code,
1259
+ redirect_uri: input.redirectUri,
1260
+ ...input.connectionId ? { connection_id: input.connectionId } : {}
1261
+ });
1262
+ return toBrokerToken(data);
1263
+ }
1264
+ async request(method, path, body, bearer) {
1265
+ try {
1266
+ const headers = { accept: "application/json" };
1267
+ if (bearer) headers.authorization = `Bearer ${bearer}`;
1268
+ if (body !== void 0) headers["content-type"] = "application/json";
1269
+ const response = await this.fetchImpl(`${this.endpoint}${path}`, {
1270
+ method,
1271
+ headers,
1272
+ body: body !== void 0 ? JSON.stringify(body) : void 0
1273
+ });
1274
+ const json = await response.json().catch(() => void 0);
1275
+ if (!response.ok || json && json.success === false) {
1276
+ const platformCode = json?.error && typeof json.error === "object" ? json.error.code : void 0;
1277
+ const message = json?.error && typeof json.error === "object" && json.error.message || (typeof json?.error === "string" ? json.error : `Tangle apps request failed (HTTP ${response.status})`);
1278
+ throw new IntegrationRuntimeError({
1279
+ code: platformCode === "BROKER_DISABLED" ? "passthrough_disabled" : "unknown",
1280
+ message,
1281
+ status: response.status,
1282
+ metadata: { platformCode, path }
1283
+ });
1284
+ }
1285
+ return (json && "data" in json ? json.data : json) ?? {};
1286
+ } catch (error) {
1287
+ if (error instanceof IntegrationRuntimeError) throw error;
1288
+ const normalized = normalizeIntegrationError(error);
1289
+ throw new IntegrationRuntimeError({
1290
+ code: normalized.code,
1291
+ message: normalized.message,
1292
+ metadata: { path, userAction: normalized.userAction }
1293
+ });
1294
+ }
1295
+ }
1296
+ };
1297
+ function createTangleAppsClient(options) {
1298
+ return new TangleAppsClient(options);
1299
+ }
1300
+ function toBrokerToken(data) {
1301
+ return {
1302
+ accessToken: data.access_token,
1303
+ expiresIn: data.expires_in,
1304
+ scope: data.scope,
1305
+ connectionId: data.connection_id
1306
+ };
1307
+ }
1308
+
1016
1309
  // src/client.ts
1017
1310
  var TangleIntegrationsClient = class {
1018
1311
  endpoint;
@@ -3419,14 +3712,6 @@ function sameActor2(a, b) {
3419
3712
  }
3420
3713
 
3421
3714
  // src/index.ts
3422
- var IntegrationError = class extends Error {
3423
- constructor(message, code) {
3424
- super(message);
3425
- this.code = code;
3426
- this.name = "IntegrationError";
3427
- }
3428
- code;
3429
- };
3430
3715
  var InMemoryConnectionStore = class {
3431
3716
  connections = /* @__PURE__ */ new Map();
3432
3717
  get(connectionId) {
@@ -3735,7 +4020,7 @@ function createHttpIntegrationProvider(options) {
3735
4020
  };
3736
4021
  }
3737
4022
  function signCapability(capability, secret) {
3738
- const payload = base64UrlEncode(JSON.stringify(capability));
4023
+ const payload = base64UrlEncode2(JSON.stringify(capability));
3739
4024
  const signature = hmac(payload, secret);
3740
4025
  return `${payload}.${signature}`;
3741
4026
  }
@@ -3779,7 +4064,7 @@ function constantTimeEqual(a, b) {
3779
4064
  const right = Buffer.from(b);
3780
4065
  return left.length === right.length && timingSafeEqual2(left, right);
3781
4066
  }
3782
- function base64UrlEncode(value) {
4067
+ function base64UrlEncode2(value) {
3783
4068
  return Buffer.from(value, "utf8").toString("base64url");
3784
4069
  }
3785
4070
  function base64UrlDecode(value) {
@@ -4540,6 +4825,7 @@ export {
4540
4825
  summarizeIntegrationRegistry,
4541
4826
  canonicalConnectorId,
4542
4827
  inferIntegrationSupportTier,
4828
+ IntegrationError,
4543
4829
  createConnectorAdapterProvider,
4544
4830
  adapterManifestsToConnectors,
4545
4831
  createConnectorAdapterCatalogSource,
@@ -4568,6 +4854,8 @@ export {
4568
4854
  buildIntegrationBridgeEnvironment,
4569
4855
  parseIntegrationBridgeEnvironment,
4570
4856
  redactIntegrationBridgePayload,
4857
+ TangleAppsClient,
4858
+ createTangleAppsClient,
4571
4859
  TangleIntegrationsClient,
4572
4860
  createTangleIntegrationsClient,
4573
4861
  renderConsentSummary,
@@ -4623,7 +4911,6 @@ export {
4623
4911
  InMemoryIntegrationWorkflowStore,
4624
4912
  IntegrationWorkflowRuntime,
4625
4913
  createIntegrationWorkflowRuntime,
4626
- IntegrationError,
4627
4914
  InMemoryConnectionStore,
4628
4915
  IntegrationHub,
4629
4916
  sanitizeConnection,
@@ -4632,4 +4919,4 @@ export {
4632
4919
  signCapability,
4633
4920
  verifyCapabilityToken
4634
4921
  };
4635
- //# sourceMappingURL=chunk-M2RFFAMB.js.map
4922
+ //# sourceMappingURL=chunk-XO2RSS6Y.js.map