@slashfi/agents-sdk 0.8.0 → 0.9.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 (59) hide show
  1. package/dist/agent-definitions/auth.d.ts +17 -0
  2. package/dist/agent-definitions/auth.d.ts.map +1 -1
  3. package/dist/agent-definitions/auth.js +135 -1
  4. package/dist/agent-definitions/auth.js.map +1 -1
  5. package/dist/agent-definitions/integrations.d.ts +19 -0
  6. package/dist/agent-definitions/integrations.d.ts.map +1 -1
  7. package/dist/agent-definitions/integrations.js +218 -5
  8. package/dist/agent-definitions/integrations.js.map +1 -1
  9. package/dist/index.d.ts +9 -4
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +6 -2
  12. package/dist/index.js.map +1 -1
  13. package/dist/integration-interface.d.ts +37 -0
  14. package/dist/integration-interface.d.ts.map +1 -0
  15. package/dist/integration-interface.js +94 -0
  16. package/dist/integration-interface.js.map +1 -0
  17. package/dist/integrations-store.d.ts +33 -0
  18. package/dist/integrations-store.d.ts.map +1 -0
  19. package/dist/integrations-store.js +50 -0
  20. package/dist/integrations-store.js.map +1 -0
  21. package/dist/jwt.d.ts +86 -17
  22. package/dist/jwt.d.ts.map +1 -1
  23. package/dist/jwt.js +140 -17
  24. package/dist/jwt.js.map +1 -1
  25. package/dist/registry.d.ts +7 -0
  26. package/dist/registry.d.ts.map +1 -1
  27. package/dist/registry.js +8 -21
  28. package/dist/registry.js.map +1 -1
  29. package/dist/secret-collection.d.ts +37 -0
  30. package/dist/secret-collection.d.ts.map +1 -0
  31. package/dist/secret-collection.js +37 -0
  32. package/dist/secret-collection.js.map +1 -0
  33. package/dist/server.d.ts +41 -44
  34. package/dist/server.d.ts.map +1 -1
  35. package/dist/server.js +232 -592
  36. package/dist/server.js.map +1 -1
  37. package/dist/types.d.ts +7 -1
  38. package/dist/types.d.ts.map +1 -1
  39. package/package.json +5 -2
  40. package/src/agent-definitions/auth.ts +187 -1
  41. package/src/agent-definitions/integrations.ts +260 -5
  42. package/src/index.ts +18 -4
  43. package/src/integration-interface.ts +118 -0
  44. package/src/integrations-store.ts +84 -0
  45. package/src/jwt.ts +233 -65
  46. package/src/registry.ts +17 -2
  47. package/src/secret-collection.ts +66 -0
  48. package/src/server.ts +268 -681
  49. package/src/types.ts +8 -1
  50. package/dist/slack-oauth.d.ts +0 -27
  51. package/dist/slack-oauth.d.ts.map +0 -1
  52. package/dist/slack-oauth.js +0 -48
  53. package/dist/slack-oauth.js.map +0 -1
  54. package/dist/web-pages.d.ts +0 -8
  55. package/dist/web-pages.d.ts.map +0 -1
  56. package/dist/web-pages.js +0 -169
  57. package/dist/web-pages.js.map +0 -1
  58. package/src/slack-oauth.ts +0 -66
  59. package/src/web-pages.ts +0 -178
@@ -24,7 +24,7 @@
24
24
  */
25
25
 
26
26
  import { defineAgent, defineTool } from "../define.js";
27
- import { pendingCollections, generateCollectionToken } from "../server.js";
27
+ import { pendingCollections, generateCollectionToken } from "../secret-collection.js";
28
28
  import type { AgentDefinition, ToolContext, ToolDefinition } from "../types.js";
29
29
 
30
30
  // ============================================
@@ -488,6 +488,23 @@ export interface IntegrationsAgentOptions {
488
488
  /** Integration store backend */
489
489
  store: IntegrationStore;
490
490
 
491
+ /**
492
+ * Callback to list all registered agents.
493
+ * Used by list_integrations to discover agents with integrationMethods.
494
+ * Typically wired to registry.list().
495
+ */
496
+ getAgents?: () => AgentDefinition[];
497
+
498
+ /** Registry instance for calling other agents' internal tools */
499
+ registry?: {
500
+ call(request: any): Promise<any>;
501
+ };
502
+
503
+ /** Integrations store for tracking installed integrations */
504
+ integrationsStore?: {
505
+ create(input: { agentPath: string; config: Record<string, unknown>; installedBy?: string; tenantId?: string }): Promise<any>;
506
+ };
507
+
491
508
  /** Secret store for storing/resolving client credentials and tokens */
492
509
  secretStore: {
493
510
  store(value: string, ownerId: string): Promise<string>;
@@ -518,7 +535,7 @@ const SYSTEM_OWNER = "__integrations__";
518
535
  export function createIntegrationsAgent(
519
536
  options: IntegrationsAgentOptions,
520
537
  ): AgentDefinition {
521
- const { store, callbackBaseUrl, secretStore } = options;
538
+ const { store, callbackBaseUrl, secretStore, getAgents, integrationsStore } = options;
522
539
 
523
540
  // ---- setup_integration ----
524
541
  const setupTool = defineTool({
@@ -663,11 +680,121 @@ export function createIntegrationsAgent(
663
680
  }
664
681
 
665
682
  await store.upsertProvider(config);
683
+
684
+ // Also track in integrations table
685
+ if (integrationsStore) {
686
+ try {
687
+ await integrationsStore.create({
688
+ agentPath: config.agentPath ?? `@${config.id}`,
689
+ config: { providerId: config.id, ...input },
690
+ installedBy: _ctx.callerId,
691
+ });
692
+ } catch {}
693
+ }
694
+
666
695
  result.provider = config;
667
696
  return result;
668
697
  },
669
698
  });
670
699
 
700
+
701
+ // ---- discover_integrations ----
702
+ const discoverTool = defineTool({
703
+ name: "discover_integrations",
704
+ description:
705
+ "Discover available integration types that can be set up. " +
706
+ "Returns a catalog of integrations with their setup/connect schemas " +
707
+ "so you know what parameters to pass to setup_integration.",
708
+ visibility: "public" as const,
709
+ inputSchema: {
710
+ type: "object" as const,
711
+ properties: {
712
+ query: {
713
+ type: "string",
714
+ description: "Search query to filter integrations by name or description",
715
+ },
716
+ category: {
717
+ type: "string",
718
+ description: "Filter by category (e.g. 'infrastructure', 'communication')",
719
+ },
720
+ },
721
+ },
722
+ execute: async (
723
+ input: { query?: string; category?: string },
724
+ _ctx: ToolContext,
725
+ ) => {
726
+ const catalog: Array<{
727
+ provider: string;
728
+ agentPath?: string;
729
+ displayName: string;
730
+ icon?: string;
731
+ category?: string;
732
+ description?: string;
733
+ setupSchema?: Record<string, unknown>;
734
+ connectSchema?: Record<string, unknown>;
735
+ hasOAuth?: boolean;
736
+ }> = [];
737
+
738
+ // 1. Agent-backed integrations
739
+ if (getAgents) {
740
+ for (const agent of getAgents()) {
741
+ if (agent.config?.integration) {
742
+ const ic = agent.config.integration;
743
+ catalog.push({
744
+ provider: ic.provider,
745
+ agentPath: agent.path,
746
+ displayName: ic.displayName,
747
+ icon: ic.icon,
748
+ category: ic.category,
749
+ description: ic.description,
750
+ setupSchema: ic.setupSchema,
751
+ connectSchema: ic.connectSchema,
752
+ });
753
+ }
754
+ }
755
+ }
756
+
757
+ // 2. DB-stored providers (legacy OAuth)
758
+ const providers = await store.listProviders();
759
+ for (const p of providers) {
760
+ // Skip if already in catalog from agent scan
761
+ if (catalog.some((c) => c.provider === p.id)) continue;
762
+ catalog.push({
763
+ provider: p.id,
764
+ displayName: p.name,
765
+ agentPath: p.agentPath,
766
+ hasOAuth: !!p.auth,
767
+ connectSchema: p.auth
768
+ ? {
769
+ type: "object",
770
+ description: "OAuth flow — use connect_integration to start",
771
+ properties: {
772
+ provider: { type: "string", const: p.id },
773
+ },
774
+ }
775
+ : undefined,
776
+ });
777
+ }
778
+
779
+ // 3. Filter
780
+ let results = catalog;
781
+ if (input.query) {
782
+ const q = input.query.toLowerCase();
783
+ results = results.filter(
784
+ (r) =>
785
+ r.provider.toLowerCase().includes(q) ||
786
+ r.displayName.toLowerCase().includes(q) ||
787
+ (r.description?.toLowerCase().includes(q) ?? false),
788
+ );
789
+ }
790
+ if (input.category) {
791
+ results = results.filter((r) => r.category === input.category);
792
+ }
793
+
794
+ return { integrations: results };
795
+ },
796
+ });
797
+
671
798
  // ---- list_integrations ----
672
799
  const listTool = defineTool({
673
800
  name: "list_integrations",
@@ -688,15 +815,64 @@ export function createIntegrationsAgent(
688
815
  const userId = input.userId ?? ctx.callerId;
689
816
  const connections = userId ? await store.listConnections(userId) : [];
690
817
 
691
- return {
692
- providers: providers.map((p) => ({
818
+ // Build unified integrations list
819
+ const integrations: Array<Record<string, unknown>> = [];
820
+
821
+ // 1. DB-stored providers (legacy OAuth integrations)
822
+ for (const p of providers) {
823
+ integrations.push({
693
824
  id: p.id,
694
825
  name: p.name,
826
+ provider: p.id,
695
827
  agentPath: p.agentPath,
696
828
  scope: p.scope ?? "user",
697
829
  hasOAuth: !!p.auth,
698
830
  connected: connections.some((c) => c.providerId === p.id),
699
- })),
831
+ });
832
+ }
833
+
834
+ // 2. Agent-backed integrations (agents with config.integration + integrationMethods)
835
+ if (getAgents) {
836
+ const agents = getAgents();
837
+ for (const agent of agents) {
838
+ if (agent.integrationMethods?.list && agent.config?.integration) {
839
+ const meta = {
840
+ provider: agent.config.integration.provider,
841
+ agentPath: agent.path,
842
+ displayName: agent.config.integration.displayName,
843
+ icon: agent.config.integration.icon,
844
+ category: agent.config.integration.category,
845
+ description: agent.config.integration.description,
846
+ };
847
+ try {
848
+ const result = await agent.integrationMethods.list({}, { ...ctx, provider: agent.config.integration.provider });
849
+ if (result.success && result.data) {
850
+ // Flatten: if data has an array field, each item becomes an integration
851
+ const items = Array.isArray(result.data)
852
+ ? result.data
853
+ : Object.values(result.data as Record<string, unknown>).find(Array.isArray) as unknown[] ?? [];
854
+ for (const item of items) {
855
+ integrations.push({
856
+ ...meta,
857
+ ...(typeof item === "object" && item !== null ? item as Record<string, unknown> : { value: item }),
858
+ });
859
+ }
860
+ // If no items found but agent exists, include it as a provider entry
861
+ if (items.length === 0) {
862
+ integrations.push({ ...meta, id: meta.provider });
863
+ }
864
+ } else {
865
+ integrations.push({ ...meta, id: meta.provider });
866
+ }
867
+ } catch {
868
+ integrations.push({ ...meta, id: meta.provider });
869
+ }
870
+ }
871
+ }
872
+ }
873
+
874
+ return {
875
+ integrations,
700
876
  connections: connections.map((c) => ({
701
877
  providerId: c.providerId,
702
878
  connectedAt: c.connectedAt,
@@ -1036,6 +1212,7 @@ export function createIntegrationsAgent(
1036
1212
  provider: config.id,
1037
1213
  userId,
1038
1214
  connectedAt: connection.connectedAt,
1215
+ accessToken: result.accessToken,
1039
1216
  };
1040
1217
  },
1041
1218
  });
@@ -1162,6 +1339,81 @@ export function createIntegrationsAgent(
1162
1339
  },
1163
1340
  });
1164
1341
 
1342
+
1343
+ // ---- Facade: discover_integrations (aggregates from all agents) ----
1344
+ const discoverFacadeTool = defineTool({
1345
+ name: "discover_integrations",
1346
+ description: "Discover all available integrations across all registered agents.",
1347
+ visibility: "public" as const,
1348
+ inputSchema: { type: "object" as const, properties: {} },
1349
+ execute: async () => {
1350
+ const agents = getAgents?.() ?? [];
1351
+ const results: any[] = [];
1352
+ if (options.registry) {
1353
+ for (const agent of agents) {
1354
+ const hasDiscoverTool = agent.tools?.some((t: any) => t.name === 'discover_integrations');
1355
+ if (hasDiscoverTool) {
1356
+ try {
1357
+ const res = await options.registry.call({
1358
+ action: 'execute_tool',
1359
+ path: agent.path,
1360
+ tool: 'discover_integrations',
1361
+ params: {},
1362
+ callerId: '@integrations',
1363
+ callerType: 'system',
1364
+ });
1365
+ if (res?.result && Array.isArray(res.result)) {
1366
+ results.push(...res.result);
1367
+ }
1368
+ } catch {}
1369
+ }
1370
+ }
1371
+ }
1372
+ return results;
1373
+ },
1374
+ });
1375
+
1376
+ // ---- Facade: list_integrations (aggregates from all agents) ----
1377
+ const listFacadeTool = defineTool({
1378
+ name: "list_integrations",
1379
+ description: "List all installed integrations across all agents.",
1380
+ visibility: "public" as const,
1381
+ inputSchema: {
1382
+ type: "object" as const,
1383
+ properties: {
1384
+ agent_path: { type: "string", description: "Filter by agent path" },
1385
+ },
1386
+ },
1387
+ execute: async (input: { agent_path?: string }) => {
1388
+ const agents = getAgents?.() ?? [];
1389
+ const results: any[] = [];
1390
+ if (options.registry) {
1391
+ const targetAgents = input.agent_path
1392
+ ? agents.filter((a: any) => a.path === input.agent_path)
1393
+ : agents;
1394
+ for (const agent of targetAgents) {
1395
+ const hasListTool = agent.tools?.some((t: any) => t.name === 'list_integrations');
1396
+ if (hasListTool) {
1397
+ try {
1398
+ const res = await options.registry.call({
1399
+ action: 'execute_tool',
1400
+ path: agent.path,
1401
+ tool: 'list_integrations',
1402
+ params: {},
1403
+ callerId: '@integrations',
1404
+ callerType: 'system',
1405
+ });
1406
+ if (res?.result && Array.isArray(res.result)) {
1407
+ results.push(...res.result);
1408
+ }
1409
+ } catch {}
1410
+ }
1411
+ }
1412
+ }
1413
+ return results;
1414
+ },
1415
+ });
1416
+
1165
1417
  return defineAgent({
1166
1418
  path: "@integrations",
1167
1419
  entrypoint:
@@ -1175,12 +1427,15 @@ export function createIntegrationsAgent(
1175
1427
  visibility: "public",
1176
1428
  tools: [
1177
1429
  setupTool,
1430
+ discoverTool,
1178
1431
  listTool,
1179
1432
  getTool,
1180
1433
  connectTool,
1181
1434
  callTool,
1182
1435
  callbackTool,
1183
1436
  collectSecretsTool,
1437
+ discoverFacadeTool,
1438
+ listFacadeTool,
1184
1439
  ] as ToolDefinition[],
1185
1440
  });
1186
1441
  }
package/src/index.ts CHANGED
@@ -97,8 +97,19 @@ export { createAgentRegistry } from "./registry.js";
97
97
  export type { AgentRegistry, AgentRegistryOptions } from "./registry.js";
98
98
 
99
99
  // Server
100
- export { createAgentServer } from "./server.js";
101
- export type { AgentServer, AgentServerOptions } from "./server.js";
100
+ export { createAgentServer, detectAuth, resolveAuth, canSeeAgent } from "./server.js";
101
+ export type { AgentServer, AgentServerOptions, AuthConfig, ResolvedAuth } from "./server.js";
102
+
103
+ // Secret Collection
104
+ export {
105
+ pendingCollections,
106
+ generateCollectionToken,
107
+ cleanupExpiredCollections,
108
+ } from "./secret-collection.js";
109
+ export type {
110
+ PendingCollection,
111
+ PendingCollectionField,
112
+ } from "./secret-collection.js";
102
113
 
103
114
  // Auth
104
115
  export {
@@ -134,8 +145,8 @@ export type {
134
145
  export { encryptSecret, decryptSecret } from "./crypto.js";
135
146
 
136
147
  // JWT
137
- export { signJwt, verifyJwt } from "./jwt.js";
138
- export type { JwtPayload } from "./jwt.js";
148
+ export { signJwt, verifyJwt, signJwtES256, verifyJwtLocal, verifyJwtFromIssuer, generateSigningKey, exportSigningKey, importSigningKey, buildJwks } from "./jwt.js";
149
+ export type { JwtPayload, AgentJwtPayload, SigningKey, ExportedKeyPair } from "./jwt.js";
139
150
 
140
151
  // Postgres Secret Store
141
152
 
@@ -179,3 +190,6 @@ export type {
179
190
  UserStore,
180
191
  UsersAgentOptions,
181
192
  } from "./agent-definitions/users.js";
193
+ export * from "./integrations-store.js";
194
+ export * from "./integration-interface.js";
195
+ export type { ContextFactory } from "./registry.js";
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Integration interface — standard tools that integration agents implement.
3
+ *
4
+ * Any agent that acts as an integration source should implement these tools.
5
+ * They are all internal visibility and only callable by @integrations.
6
+ */
7
+
8
+ import { defineTool } from './define.js';
9
+ import type { IntegrationsStore } from './integrations-store.js';
10
+ import type { ToolDefinition, ToolContext } from './types.js';
11
+
12
+ export interface IntegrationDefinition {
13
+ id: string;
14
+ agentPath: string;
15
+ name: string;
16
+ description: string;
17
+ type: 'oauth' | 'credentials' | 'config';
18
+ configSchema?: Record<string, unknown>;
19
+ }
20
+
21
+ export interface IntegrationInterfaceConfig {
22
+ agentPath: string;
23
+ store: IntegrationsStore;
24
+ discover: () => Promise<IntegrationDefinition[]>;
25
+ setup: (config: Record<string, unknown>, ctx: ToolContext) => Promise<{ success: boolean; integrationId?: string; oauthUrl?: string; error?: string }>;
26
+ connect?: (integrationId: string, ctx: ToolContext) => Promise<{ success: boolean; error?: string }>;
27
+ }
28
+
29
+ /**
30
+ * Create the standard _integration tools for an agent.
31
+ * Returns an array of ToolDefinitions to include in the agent's tools.
32
+ */
33
+ export function createIntegrationTools(config: IntegrationInterfaceConfig): ToolDefinition<ToolContext>[] {
34
+ const { agentPath, store, discover, setup, connect } = config;
35
+
36
+ const discoverTool = defineTool({
37
+ name: 'discover_integrations',
38
+ description: `Discover available integrations for ${agentPath}.`,
39
+ visibility: 'internal' as const,
40
+ inputSchema: {
41
+ type: 'object' as const,
42
+ properties: {},
43
+ },
44
+ execute: async () => {
45
+ const available = await discover();
46
+ return available;
47
+ },
48
+ });
49
+
50
+ const setupTool = defineTool({
51
+ name: 'setup_integration',
52
+ description: `Set up a new integration for ${agentPath}.`,
53
+ visibility: 'internal' as const,
54
+ inputSchema: {
55
+ type: 'object' as const,
56
+ properties: {
57
+ config: { type: 'object', description: 'Integration configuration' },
58
+ },
59
+ required: ['config'],
60
+ },
61
+ execute: async (input: { config: Record<string, unknown> }, ctx: ToolContext) => {
62
+ const result = await setup(input.config, ctx);
63
+ if (result.success && !result.oauthUrl) {
64
+ // Direct setup (no OAuth needed) — create integration row
65
+ const integration = await store.create({
66
+ agentPath,
67
+ config: input.config,
68
+ installedBy: ctx.callerId,
69
+ });
70
+ return { success: true, integrationId: integration.id };
71
+ }
72
+ return result;
73
+ },
74
+ });
75
+
76
+ const connectTool = defineTool({
77
+ name: 'connect_integration',
78
+ description: `Test or authorize a ${agentPath} integration connection.`,
79
+ visibility: 'internal' as const,
80
+ inputSchema: {
81
+ type: 'object' as const,
82
+ properties: {
83
+ integration_id: { type: 'string', description: 'Integration ID to connect' },
84
+ },
85
+ required: ['integration_id'],
86
+ },
87
+ execute: async (input: { integration_id: string }, ctx: ToolContext) => {
88
+ if (connect) {
89
+ const result = await connect(input.integration_id, ctx);
90
+ if (result.success) {
91
+ await store.update(input.integration_id, { status: 'active' });
92
+ } else {
93
+ await store.update(input.integration_id, { status: 'error' });
94
+ }
95
+ return result;
96
+ }
97
+ return { success: true };
98
+ },
99
+ });
100
+
101
+ const listTool = defineTool({
102
+ name: 'list_integrations',
103
+ description: `List installed integrations for ${agentPath}.`,
104
+ visibility: 'internal' as const,
105
+ inputSchema: {
106
+ type: 'object' as const,
107
+ properties: {
108
+ tenant_id: { type: 'string', description: 'Filter by tenant' },
109
+ },
110
+ },
111
+ execute: async (input: { tenant_id?: string }) => {
112
+ const integrations = await store.listByAgent(agentPath, input.tenant_id);
113
+ return integrations;
114
+ },
115
+ });
116
+
117
+ return [discoverTool, setupTool, connectTool, listTool] as ToolDefinition<ToolContext>[];
118
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * IntegrationsStore — persistence interface for installed integrations.
3
+ *
4
+ * Each integration is an agent that's been configured and connected.
5
+ * The store tracks what's installed, its config, and status.
6
+ */
7
+
8
+ export interface Integration {
9
+ id: string;
10
+ agentPath: string;
11
+ tenantId?: string;
12
+ status: 'active' | 'disabled' | 'error';
13
+ config: Record<string, unknown>;
14
+ installedBy?: string;
15
+ installedAt: number;
16
+ updatedAt: number;
17
+ }
18
+
19
+ export interface CreateIntegrationInput {
20
+ agentPath: string;
21
+ tenantId?: string;
22
+ config: Record<string, unknown>;
23
+ installedBy?: string;
24
+ }
25
+
26
+ export interface IntegrationsStore {
27
+ create(input: CreateIntegrationInput): Promise<Integration>;
28
+ get(id: string): Promise<Integration | null>;
29
+ list(tenantId?: string): Promise<Integration[]>;
30
+ listByAgent(agentPath: string, tenantId?: string): Promise<Integration[]>;
31
+ update(id: string, updates: Partial<Pick<Integration, 'status' | 'config' | 'updatedAt'>>): Promise<Integration | null>;
32
+ delete(id: string): Promise<boolean>;
33
+ }
34
+
35
+ /** In-memory implementation for testing / lightweight use */
36
+ export function createInMemoryIntegrationsStore(): IntegrationsStore {
37
+ const integrations = new Map<string, Integration>();
38
+
39
+ return {
40
+ async create(input) {
41
+ const id = `int_${Math.random().toString(36).slice(2, 14)}`;
42
+ const now = Date.now();
43
+ const integration: Integration = {
44
+ id,
45
+ agentPath: input.agentPath,
46
+ tenantId: input.tenantId,
47
+ status: 'active',
48
+ config: input.config,
49
+ installedBy: input.installedBy,
50
+ installedAt: now,
51
+ updatedAt: now,
52
+ };
53
+ integrations.set(id, integration);
54
+ return integration;
55
+ },
56
+
57
+ async get(id) {
58
+ return integrations.get(id) ?? null;
59
+ },
60
+
61
+ async list(tenantId?) {
62
+ const all = Array.from(integrations.values());
63
+ return tenantId ? all.filter(i => i.tenantId === tenantId) : all;
64
+ },
65
+
66
+ async listByAgent(agentPath, tenantId?) {
67
+ return Array.from(integrations.values()).filter(
68
+ i => i.agentPath === agentPath && (!tenantId || i.tenantId === tenantId)
69
+ );
70
+ },
71
+
72
+ async update(id, updates) {
73
+ const existing = integrations.get(id);
74
+ if (!existing) return null;
75
+ const updated = { ...existing, ...updates, updatedAt: Date.now() };
76
+ integrations.set(id, updated);
77
+ return updated;
78
+ },
79
+
80
+ async delete(id) {
81
+ return integrations.delete(id);
82
+ },
83
+ };
84
+ }