@mastra/connect 1.1.0 → 1.2.0-alpha.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.
- package/dist/client.d.ts +29 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/connect-prompt-tool.d.ts +58 -0
- package/dist/connect-prompt-tool.d.ts.map +1 -0
- package/dist/index.cjs +251 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +251 -38
- package/dist/index.js.map +1 -1
- package/dist/tools.d.ts +11 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/user-connect-page.d.ts +5 -3
- package/dist/user-connect-page.d.ts.map +1 -1
- package/dist/user-connect-routes.d.ts +8 -4
- package/dist/user-connect-routes.d.ts.map +1 -1
- package/package.json +6 -6
package/dist/client.d.ts
CHANGED
|
@@ -74,6 +74,10 @@ export type ProjectConnection = z.infer<typeof connectionSchema>;
|
|
|
74
74
|
*/
|
|
75
75
|
export declare const catalogAuthFieldSchema: z.ZodObject<{
|
|
76
76
|
name: z.ZodString;
|
|
77
|
+
target: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
78
|
+
credentials: "credentials";
|
|
79
|
+
params: "params";
|
|
80
|
+
}>>>;
|
|
77
81
|
label: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
78
82
|
description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
79
83
|
placeholder: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
@@ -92,6 +96,10 @@ export declare const integrationCatalogEntrySchema: z.ZodObject<{
|
|
|
92
96
|
authType: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
93
97
|
authFields: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
|
|
94
98
|
name: z.ZodString;
|
|
99
|
+
target: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
100
|
+
credentials: "credentials";
|
|
101
|
+
params: "params";
|
|
102
|
+
}>>>;
|
|
95
103
|
label: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
96
104
|
description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
97
105
|
placeholder: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
@@ -101,6 +109,10 @@ export declare const integrationCatalogEntrySchema: z.ZodObject<{
|
|
|
101
109
|
}, z.core.$strip>>>>;
|
|
102
110
|
}, z.core.$strip>;
|
|
103
111
|
export type IntegrationCatalogEntry = z.infer<typeof integrationCatalogEntrySchema>;
|
|
112
|
+
declare const projectIntegrationSettingsResponseSchema: z.ZodObject<{
|
|
113
|
+
endUserProviders: z.ZodNullable<z.ZodArray<z.ZodString>>;
|
|
114
|
+
}, z.core.$strip>;
|
|
115
|
+
export type ProjectIntegrationSettings = z.infer<typeof projectIntegrationSettingsResponseSchema>;
|
|
104
116
|
/**
|
|
105
117
|
* Secondary access token minted by the vendor alongside the primary oauth2
|
|
106
118
|
* credential (e.g. `devPortalAccessToken` on Microsoft Teams connections).
|
|
@@ -138,6 +150,7 @@ export declare const connectionContextSchema: z.ZodObject<{
|
|
|
138
150
|
export type ConnectionContext = z.infer<typeof connectionContextSchema>;
|
|
139
151
|
export declare function listProjectConnections(client: ResolvedClient, projectId: string): Promise<ProjectConnection[]>;
|
|
140
152
|
export declare function listIntegrations(client: ResolvedClient): Promise<IntegrationCatalogEntry[]>;
|
|
153
|
+
export declare function getProjectIntegrationSettings(client: ResolvedClient, projectId: string): Promise<ProjectIntegrationSettings>;
|
|
141
154
|
export declare function getConnectionContext(client: ResolvedClient, connectionId: string): Promise<ConnectionContext>;
|
|
142
155
|
export declare function getCredential(client: ResolvedClient, connectionId: string): Promise<ConnectionCredential>;
|
|
143
156
|
type ProxyQueryPrimitive = string | number | boolean;
|
|
@@ -168,8 +181,8 @@ export declare function proxyRequestWithResponse(client: ResolvedClient, connect
|
|
|
168
181
|
export declare const connectSessionSchema: z.ZodObject<{
|
|
169
182
|
connectionId: z.ZodString;
|
|
170
183
|
integrationId: z.ZodString;
|
|
171
|
-
connectUrl: z.ZodString
|
|
172
|
-
sessionToken: z.ZodString
|
|
184
|
+
connectUrl: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
185
|
+
sessionToken: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
173
186
|
expiresAt: z.ZodString;
|
|
174
187
|
}, z.core.$strip>;
|
|
175
188
|
export type ConnectSession = z.infer<typeof connectSessionSchema>;
|
|
@@ -179,6 +192,20 @@ export type ConnectSession = z.infer<typeof connectSessionSchema>;
|
|
|
179
192
|
* end user; an unscoped client creates a global connection.
|
|
180
193
|
*/
|
|
181
194
|
export declare function createProjectConnectSession(client: ResolvedClient, projectId: string, integrationId: string): Promise<ConnectSession>;
|
|
195
|
+
export declare const connectUrlSchema: z.ZodObject<{
|
|
196
|
+
connectUrl: z.ZodString;
|
|
197
|
+
expiresAt: z.ZodString;
|
|
198
|
+
}, z.core.$strip>;
|
|
199
|
+
export type ConnectUrl = z.infer<typeof connectUrlSchema>;
|
|
200
|
+
/**
|
|
201
|
+
* Fetches the vendor connect link for a pending resource-scoped connection
|
|
202
|
+
* from the platform's launch gate. The platform serves it only while the
|
|
203
|
+
* session is pending and unexpired, and only when the client's
|
|
204
|
+
* `x-mastra-resource-id` assertion matches the row — any mismatch is a 404,
|
|
205
|
+
* which surfaces here as `connection_not_found`. This is how the browser's
|
|
206
|
+
* popup enters OAuth: the link itself never reaches browser-visible state.
|
|
207
|
+
*/
|
|
208
|
+
export declare function getConnectUrl(client: ResolvedClient, connectionId: string): Promise<ConnectUrl>;
|
|
182
209
|
/** Disconnects a connection. The platform tears down the vendor side asynchronously. */
|
|
183
210
|
export declare function disconnectConnection(client: ResolvedClient, connectionId: string): Promise<void>;
|
|
184
211
|
export {};
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAUxB;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,0GAA0G;IAC1G,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yGAAyG;IACzG,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4FAA4F;IAC5F,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,KAAK,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,wEAAwE;IACxE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA2BD,8EAA8E;AAC9E,eAAO,MAAM,kBAAkB,yBAAyB,CAAC;AAEzD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAY7D;AAED,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,cAAc,CAkC5E;AAmED,yFAAyF;AACzF,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM;;;mBAKxD,MAAM,GAAG,GAAG,SAAS,WAAW,KAAG,OAAO,CAAC,QAAQ,CAAC;EAyB5E;AAID,eAAO,MAAM,gBAAgB;;;;;;;;;iBAa3B,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAMjE;;;GAGG;AACH,eAAO,MAAM,sBAAsB
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { IntegrationCatalogEntry, ProjectConnection } from './client.js';
|
|
2
|
+
/**
|
|
3
|
+
* Record key of the built-in connect-prompt tool. Reserved: a provider tool
|
|
4
|
+
* resolving to the same key is a hard error, same as any duplicate.
|
|
5
|
+
*/
|
|
6
|
+
export declare const CONNECT_PROMPT_TOOL_KEY = "request_connection";
|
|
7
|
+
/** One connectable provider in a connect-prompt payload. */
|
|
8
|
+
export interface ConnectPromptProvider {
|
|
9
|
+
id: string;
|
|
10
|
+
displayName: string | null;
|
|
11
|
+
logoUrl: string | null;
|
|
12
|
+
authType: string | null;
|
|
13
|
+
/** Fields the UI must collect before starting headless authorization. */
|
|
14
|
+
authFields: NonNullable<IntegrationCatalogEntry['authFields']> | null;
|
|
15
|
+
/** Whether a usable (active) connection already serves this provider for the caller. */
|
|
16
|
+
connected: boolean;
|
|
17
|
+
/** Which connection serves it when connected: the caller's own wins over a global one. */
|
|
18
|
+
scope: 'global' | 'user' | null;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Structured output of the connect-prompt tool. Chat UIs detect
|
|
22
|
+
* `type: 'connect-prompt'` and render the providers as a connect card; the
|
|
23
|
+
* card drives the mounted `userConnectRoutes()` flow (session → launch gate →
|
|
24
|
+
* status polling), so the tool itself never creates sessions or handles URLs.
|
|
25
|
+
*/
|
|
26
|
+
export interface ConnectPromptPayload {
|
|
27
|
+
type: 'connect-prompt';
|
|
28
|
+
/** Echoed when the agent asked for one specific provider and it is connectable. */
|
|
29
|
+
requestedProvider?: string;
|
|
30
|
+
providers: ConnectPromptProvider[];
|
|
31
|
+
}
|
|
32
|
+
export interface ConnectPromptInputs {
|
|
33
|
+
catalog: IntegrationCatalogEntry[];
|
|
34
|
+
connections: ProjectConnection[];
|
|
35
|
+
/** Effective code or project allowlist; undefined means the full catalog. */
|
|
36
|
+
allowlist: Set<string> | undefined;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Builds the built-in tool that lets an agent prompt the end user to connect
|
|
40
|
+
* a provider account mid-conversation. Only added to resource-scoped
|
|
41
|
+
* resolutions: without an end-user identity there is nobody to scope a new
|
|
42
|
+
* connection to.
|
|
43
|
+
*
|
|
44
|
+
* The connectable set respects the effective project policy: an explicit
|
|
45
|
+
* `tools({ providers })` allowlist wins, otherwise the project's provider
|
|
46
|
+
* configuration is loaded from Mastra Platform.
|
|
47
|
+
*
|
|
48
|
+
* `loadInputs` is called per tool invocation so provider policy and connection state are fresh —
|
|
49
|
+
* after the user connects through the rendered card, the agent can call the
|
|
50
|
+
* tool again and see `connected: true` without waiting out the snapshot TTL.
|
|
51
|
+
*/
|
|
52
|
+
export declare function buildConnectPromptTool({ loadInputs, resourceId, }: {
|
|
53
|
+
loadInputs: () => Promise<ConnectPromptInputs>;
|
|
54
|
+
resourceId: string;
|
|
55
|
+
}): import("@mastra/core/tools").Tool<{
|
|
56
|
+
provider?: string | undefined;
|
|
57
|
+
}, unknown, unknown, unknown, import("@mastra/core/tools").ToolExecutionContext<unknown, unknown, unknown>, "request_connection", unknown>;
|
|
58
|
+
//# sourceMappingURL=connect-prompt-tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connect-prompt-tool.d.ts","sourceRoot":"","sources":["../src/connect-prompt-tool.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAE9E;;;GAGG;AACH,eAAO,MAAM,uBAAuB,uBAAuB,CAAC;AAE5D,4DAA4D;AAC5D,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,yEAAyE;IACzE,UAAU,EAAE,WAAW,CAAC,uBAAuB,CAAC,YAAY,CAAC,CAAC,GAAG,IAAI,CAAC;IACtE,wFAAwF;IACxF,SAAS,EAAE,OAAO,CAAC;IACnB,0FAA0F;IAC1F,KAAK,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAC;CACjC;AAED;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,gBAAgB,CAAC;IACvB,mFAAmF;IACnF,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,EAAE,qBAAqB,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,uBAAuB,EAAE,CAAC;IACnC,WAAW,EAAE,iBAAiB,EAAE,CAAC;IACjC,6EAA6E;IAC7E,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;CACpC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,UAAU,EACV,UAAU,GACX,EAAE;IACD,UAAU,EAAE,MAAM,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC/C,UAAU,EAAE,MAAM,CAAC;CACpB;;2IAkDA"}
|
package/dist/index.cjs
CHANGED
|
@@ -373,6 +373,13 @@ const connectionListSchema = zod.z.object({ connections: zod.z.array(connectionS
|
|
|
373
373
|
*/
|
|
374
374
|
const catalogAuthFieldSchema = zod.z.object({
|
|
375
375
|
name: zod.z.string(),
|
|
376
|
+
/**
|
|
377
|
+
* Where the value goes in a headless auth call: `credentials` are
|
|
378
|
+
* exchanged with the provider (API keys, passwords), `params` configure
|
|
379
|
+
* the flow (e.g. an MCP server URL). Absent on older platforms; clients
|
|
380
|
+
* treat missing as `credentials`.
|
|
381
|
+
*/
|
|
382
|
+
target: zod.z.enum(["credentials", "params"]).nullish(),
|
|
376
383
|
label: zod.z.string().nullish(),
|
|
377
384
|
description: zod.z.string().nullish(),
|
|
378
385
|
placeholder: zod.z.string().nullish(),
|
|
@@ -389,6 +396,9 @@ const integrationCatalogEntrySchema = zod.z.object({
|
|
|
389
396
|
authFields: zod.z.array(catalogAuthFieldSchema).nullish()
|
|
390
397
|
});
|
|
391
398
|
const integrationCatalogResponseSchema = zod.z.object({ integrations: zod.z.array(integrationCatalogEntrySchema) });
|
|
399
|
+
const projectIntegrationSettingsResponseSchema = zod.z.object({
|
|
400
|
+
/** Null inherits the full public catalog; an empty array explicitly disables end-user connections. */
|
|
401
|
+
endUserProviders: zod.z.array(zod.z.string()).nullable() });
|
|
392
402
|
/**
|
|
393
403
|
* Secondary access token minted by the vendor alongside the primary oauth2
|
|
394
404
|
* credential (e.g. `devPortalAccessToken` on Microsoft Teams connections).
|
|
@@ -440,6 +450,14 @@ async function listIntegrations(client) {
|
|
|
440
450
|
if (!parsed.success) throw new MastraConnectError("platform_error", "Platform returned an unexpected integration catalog shape.");
|
|
441
451
|
return parsed.data.integrations;
|
|
442
452
|
}
|
|
453
|
+
async function getProjectIntegrationSettings(client, projectId) {
|
|
454
|
+
const response = await platformFetch(client, `/v2/projects/${encodeURIComponent(projectId)}/integration-settings`);
|
|
455
|
+
if (response.status === 404) throw new MastraConnectError("platform_error", `Integration settings were not found for project ${projectId}.`, { status: 404 });
|
|
456
|
+
if (!response.ok) await throwPlatformError(response, `retrieving integration settings for project ${projectId}`);
|
|
457
|
+
const parsed = projectIntegrationSettingsResponseSchema.safeParse(await parsePlatformJson(response, `retrieving integration settings for project ${projectId}`));
|
|
458
|
+
if (!parsed.success) throw new MastraConnectError("platform_error", `Platform returned an unexpected integration settings shape for project ${projectId}.`);
|
|
459
|
+
return parsed.data;
|
|
460
|
+
}
|
|
443
461
|
async function getConnectionContext(client, connectionId) {
|
|
444
462
|
const response = await platformFetch(client, `/v2/connections/${encodeURIComponent(connectionId)}/context`);
|
|
445
463
|
if (!response.ok) await throwPlatformError(response, `retrieving context for connection ${connectionId}`);
|
|
@@ -584,8 +602,19 @@ async function proxyRequestWithResponse(client, connectionId, options) {
|
|
|
584
602
|
const connectSessionSchema = zod.z.object({
|
|
585
603
|
connectionId: zod.z.string(),
|
|
586
604
|
integrationId: zod.z.string(),
|
|
587
|
-
|
|
588
|
-
|
|
605
|
+
/**
|
|
606
|
+
* Vendor connect link. The platform nulls this for resource-scoped
|
|
607
|
+
* sessions: their link is a bearer capability served only by the launch
|
|
608
|
+
* gate (`getConnectUrl`) under a matching resource assertion, so it never
|
|
609
|
+
* appears in a creation response that could reach a browser.
|
|
610
|
+
*/
|
|
611
|
+
connectUrl: zod.z.string().nullish(),
|
|
612
|
+
/**
|
|
613
|
+
* Nango connect session token. Nulled by the platform for resource-scoped
|
|
614
|
+
* sessions for the same reason as `connectUrl`: the token alone can open
|
|
615
|
+
* the vendor Connect UI, so it is an equivalent launch capability.
|
|
616
|
+
*/
|
|
617
|
+
sessionToken: zod.z.string().nullish(),
|
|
589
618
|
expiresAt: zod.z.string()
|
|
590
619
|
});
|
|
591
620
|
/**
|
|
@@ -604,12 +633,89 @@ async function createProjectConnectSession(client, projectId, integrationId) {
|
|
|
604
633
|
if (!parsed.success) throw new MastraConnectError("platform_error", `Platform returned an unexpected connect-session shape for ${integrationId}.`);
|
|
605
634
|
return parsed.data;
|
|
606
635
|
}
|
|
636
|
+
const connectUrlSchema = zod.z.object({
|
|
637
|
+
connectUrl: zod.z.string(),
|
|
638
|
+
expiresAt: zod.z.string()
|
|
639
|
+
});
|
|
640
|
+
/**
|
|
641
|
+
* Fetches the vendor connect link for a pending resource-scoped connection
|
|
642
|
+
* from the platform's launch gate. The platform serves it only while the
|
|
643
|
+
* session is pending and unexpired, and only when the client's
|
|
644
|
+
* `x-mastra-resource-id` assertion matches the row — any mismatch is a 404,
|
|
645
|
+
* which surfaces here as `connection_not_found`. This is how the browser's
|
|
646
|
+
* popup enters OAuth: the link itself never reaches browser-visible state.
|
|
647
|
+
*/
|
|
648
|
+
async function getConnectUrl(client, connectionId) {
|
|
649
|
+
const response = await platformFetch(client, `/v2/connections/${encodeURIComponent(connectionId)}/connect-url`);
|
|
650
|
+
if (response.status === 404) throw new MastraConnectError("connection_not_found", `No launchable connect session found for connection ${connectionId}.`);
|
|
651
|
+
if (!response.ok) await throwPlatformError(response, `fetching the connect URL for ${connectionId}`);
|
|
652
|
+
const parsed = connectUrlSchema.safeParse(await parsePlatformJson(response, `fetching the connect URL for ${connectionId}`));
|
|
653
|
+
if (!parsed.success) throw new MastraConnectError("platform_error", `Platform returned an unexpected connect-url shape for ${connectionId}.`);
|
|
654
|
+
return parsed.data;
|
|
655
|
+
}
|
|
607
656
|
/** Disconnects a connection. The platform tears down the vendor side asynchronously. */
|
|
608
657
|
async function disconnectConnection(client, connectionId) {
|
|
609
658
|
const response = await platformFetch(client, `/v2/connections/${encodeURIComponent(connectionId)}`, { method: "DELETE" });
|
|
610
659
|
if (!response.ok) await throwPlatformError(response, `disconnecting connection ${connectionId}`);
|
|
611
660
|
}
|
|
612
661
|
//#endregion
|
|
662
|
+
//#region src/connect-prompt-tool.ts
|
|
663
|
+
/**
|
|
664
|
+
* Record key of the built-in connect-prompt tool. Reserved: a provider tool
|
|
665
|
+
* resolving to the same key is a hard error, same as any duplicate.
|
|
666
|
+
*/
|
|
667
|
+
const CONNECT_PROMPT_TOOL_KEY = "request_connection";
|
|
668
|
+
/**
|
|
669
|
+
* Builds the built-in tool that lets an agent prompt the end user to connect
|
|
670
|
+
* a provider account mid-conversation. Only added to resource-scoped
|
|
671
|
+
* resolutions: without an end-user identity there is nobody to scope a new
|
|
672
|
+
* connection to.
|
|
673
|
+
*
|
|
674
|
+
* The connectable set respects the effective project policy: an explicit
|
|
675
|
+
* `tools({ providers })` allowlist wins, otherwise the project's provider
|
|
676
|
+
* configuration is loaded from Mastra Platform.
|
|
677
|
+
*
|
|
678
|
+
* `loadInputs` is called per tool invocation so provider policy and connection state are fresh —
|
|
679
|
+
* after the user connects through the rendered card, the agent can call the
|
|
680
|
+
* tool again and see `connected: true` without waiting out the snapshot TTL.
|
|
681
|
+
*/
|
|
682
|
+
function buildConnectPromptTool({ loadInputs, resourceId }) {
|
|
683
|
+
return (0, _mastra_core_tools.createTool)({
|
|
684
|
+
id: CONNECT_PROMPT_TOOL_KEY,
|
|
685
|
+
description: "Ask the current user to connect a provider account (e.g. Linear, Slack). Call this when a task needs a provider whose tools are unavailable because no account is connected, or when the user asks to connect one. The result renders as a connect prompt in the UI — tell the user to use it, and do not fabricate links. Pass `provider` to request one specific provider; omit it to list everything the user can connect.",
|
|
686
|
+
inputSchema: zod.z.object({ provider: zod.z.string().optional().describe("Provider id to request (e.g. \"linear\"). Omit to list all connectable providers.") }),
|
|
687
|
+
execute: async (input) => {
|
|
688
|
+
const { catalog, connections, allowlist } = await loadInputs();
|
|
689
|
+
const allow = allowlist === void 0 ? void 0 : new Set(Array.from(allowlist, (id) => id.toLowerCase()));
|
|
690
|
+
const connectable = catalog.filter((entry) => allow === void 0 || allow.has(entry.id.toLowerCase()));
|
|
691
|
+
const toProvider = (entry) => {
|
|
692
|
+
const usable = connections.filter((connection) => connection.integrationId.toLowerCase() === entry.id.toLowerCase() && connection.status === "active");
|
|
693
|
+
const own = usable.some((connection) => connection.resourceId === resourceId);
|
|
694
|
+
return {
|
|
695
|
+
id: entry.id,
|
|
696
|
+
displayName: entry.displayName ?? null,
|
|
697
|
+
logoUrl: entry.logoUrl ?? null,
|
|
698
|
+
authType: entry.authType ?? null,
|
|
699
|
+
authFields: entry.authFields ?? null,
|
|
700
|
+
connected: usable.length > 0,
|
|
701
|
+
scope: own ? "user" : usable.length > 0 ? "global" : null
|
|
702
|
+
};
|
|
703
|
+
};
|
|
704
|
+
const requestedId = input.provider?.toLowerCase();
|
|
705
|
+
const requested = requestedId === void 0 ? void 0 : connectable.find((entry) => entry.id.toLowerCase() === requestedId);
|
|
706
|
+
if (requested) return {
|
|
707
|
+
type: "connect-prompt",
|
|
708
|
+
requestedProvider: requested.id,
|
|
709
|
+
providers: [toProvider(requested)]
|
|
710
|
+
};
|
|
711
|
+
return {
|
|
712
|
+
type: "connect-prompt",
|
|
713
|
+
providers: connectable.map(toProvider)
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
//#endregion
|
|
613
719
|
//#region src/toolset.ts
|
|
614
720
|
/**
|
|
615
721
|
* Compiles a tool-filter entry containing `*` wildcards into an anchored
|
|
@@ -75352,6 +75458,7 @@ function sharedStateKey(projectId, ttlMs, options) {
|
|
|
75352
75458
|
allowTools: options.allowTools,
|
|
75353
75459
|
disallowTools: options.disallowTools,
|
|
75354
75460
|
requireApproval: options.requireApproval,
|
|
75461
|
+
connectPrompt: options.connectPrompt,
|
|
75355
75462
|
client: {
|
|
75356
75463
|
baseUrl: options.client?.baseUrl,
|
|
75357
75464
|
orgId: options.client?.orgId,
|
|
@@ -75488,6 +75595,18 @@ async function loadSnapshotInputs(state, client) {
|
|
|
75488
75595
|
catalogAvailable: false
|
|
75489
75596
|
};
|
|
75490
75597
|
}
|
|
75598
|
+
/** Loads fresh prompt inputs and resolves project policy only when code did not provide an allowlist. */
|
|
75599
|
+
async function loadConnectPromptInputs(state, client) {
|
|
75600
|
+
const codeAllowlist = state.normalizedProviders.only;
|
|
75601
|
+
const [inputs, settings] = await Promise.all([loadSnapshotInputs(state, client), codeAllowlist === void 0 ? getProjectIntegrationSettings(client, state.projectId) : Promise.resolve(void 0)]);
|
|
75602
|
+
const projectProviders = settings?.endUserProviders;
|
|
75603
|
+
const allowlist = codeAllowlist ?? (projectProviders === null || projectProviders === void 0 ? void 0 : new Set(projectProviders));
|
|
75604
|
+
return {
|
|
75605
|
+
catalog: inputs.catalog,
|
|
75606
|
+
connections: inputs.connections,
|
|
75607
|
+
allowlist
|
|
75608
|
+
};
|
|
75609
|
+
}
|
|
75491
75610
|
/**
|
|
75492
75611
|
* Fetches a fresh snapshot for one scope, deduplicating concurrent calls per
|
|
75493
75612
|
* scope. Rejects on failure. A refresh requested while the state is closing
|
|
@@ -75506,6 +75625,14 @@ function refreshScope(state, scope) {
|
|
|
75506
75625
|
...scope.resourceId === void 0 ? {} : { resourceId: scope.resourceId }
|
|
75507
75626
|
};
|
|
75508
75627
|
const { record, mcpKeys } = await mapTools(connections, requests, state.options, clientOptions, scope.client, state.mcpClients, state.resolverId);
|
|
75628
|
+
if (scope.resourceId !== void 0 && state.options.connectPrompt !== false) {
|
|
75629
|
+
if (record["request_connection"]) throw new MastraConnectConfigError(`Tool key '${CONNECT_PROMPT_TOOL_KEY}' is reserved for the built-in connect-prompt tool; a provider resolved a tool with the same key. Disable it with connectPrompt: false or exclude the conflicting provider tool.`);
|
|
75630
|
+
const client = scope.client;
|
|
75631
|
+
record[CONNECT_PROMPT_TOOL_KEY] = buildConnectPromptTool({
|
|
75632
|
+
loadInputs: () => loadConnectPromptInputs(state, client),
|
|
75633
|
+
resourceId: scope.resourceId
|
|
75634
|
+
});
|
|
75635
|
+
}
|
|
75509
75636
|
scope.cache = {
|
|
75510
75637
|
snapshot: record,
|
|
75511
75638
|
fetchedAt: Date.now(),
|
|
@@ -75610,6 +75737,7 @@ function tools(options = {}) {
|
|
|
75610
75737
|
rejectRemovedAutoApproveTools(providerOverrides);
|
|
75611
75738
|
if (options.allowTools !== void 0 && options.disallowTools !== void 0) throw new MastraConnectError("invalid_options", "Top-level allowTools and disallowTools are mutually exclusive; set at most one.");
|
|
75612
75739
|
if (options.requireApproval !== void 0 && typeof options.requireApproval !== "boolean" && !(Array.isArray(options.requireApproval) && options.requireApproval.every((name) => typeof name === "string"))) throw new MastraConnectError("invalid_options", "Top-level requireApproval must be a boolean or an array of tool keys.");
|
|
75740
|
+
if (options.connectPrompt !== void 0 && typeof options.connectPrompt !== "boolean") throw new MastraConnectError("invalid_options", `Invalid connectPrompt: expected a boolean, got ${typeof options.connectPrompt}.`);
|
|
75613
75741
|
const state = acquireSharedState(projectId, ttlMs, options, normalizedProviders);
|
|
75614
75742
|
const validateDynamicResourceId = (raw) => raw === void 0 || raw === null ? void 0 : validateResourceId(raw);
|
|
75615
75743
|
const resolve = (ctx) => {
|
|
@@ -76519,14 +76647,18 @@ function renderConnectPage(params) {
|
|
|
76519
76647
|
return res.json();
|
|
76520
76648
|
})
|
|
76521
76649
|
.then(function (session) {
|
|
76650
|
+
// The popup enters OAuth through the launch gate (same-origin,
|
|
76651
|
+
// authenticated) rather than a raw vendor link: the server re-checks
|
|
76652
|
+
// that this browser's identity owns the pending session immediately
|
|
76653
|
+
// before redirecting into the provider's consent screen.
|
|
76522
76654
|
if (popup && !popup.closed) {
|
|
76523
|
-
popup.location = session.
|
|
76655
|
+
popup.location = session.launchUrl;
|
|
76524
76656
|
setStatus('Finish authorizing in the popup…', false);
|
|
76525
76657
|
} else {
|
|
76526
76658
|
// Popup blocked: offer a manual link instead of auto-navigating away.
|
|
76527
76659
|
status.textContent = '';
|
|
76528
76660
|
var link = document.createElement('a');
|
|
76529
|
-
link.href = session.
|
|
76661
|
+
link.href = session.launchUrl;
|
|
76530
76662
|
link.target = '_blank';
|
|
76531
76663
|
link.rel = 'noopener';
|
|
76532
76664
|
link.textContent = 'Popup blocked — click here to authorize';
|
|
@@ -76554,6 +76686,7 @@ const RESERVED_PROVIDER_IDS = /* @__PURE__ */ new Set([
|
|
|
76554
76686
|
"sessions"
|
|
76555
76687
|
]);
|
|
76556
76688
|
const NO_STORE = "no-store, private";
|
|
76689
|
+
const PROJECT_PROVIDER_POLICY_TTL_MS = 3e4;
|
|
76557
76690
|
function errorResponse(c, error) {
|
|
76558
76691
|
c.header("cache-control", NO_STORE);
|
|
76559
76692
|
return c.json({ error: {
|
|
@@ -76563,8 +76696,10 @@ function errorResponse(c, error) {
|
|
|
76563
76696
|
}
|
|
76564
76697
|
/**
|
|
76565
76698
|
* Maps a platform-call failure to a safe end-user response. Platform detail
|
|
76566
|
-
* strings
|
|
76567
|
-
* surface, and the details describe the developer's platform account.
|
|
76699
|
+
* strings do not reach the end user — this is an unauthenticated-adjacent
|
|
76700
|
+
* surface, and the details describe the developer's platform account. The one
|
|
76701
|
+
* exception is 409 conflicts, whose details describe the caller's own
|
|
76702
|
+
* connection state and are authored by the platform for display.
|
|
76568
76703
|
*/
|
|
76569
76704
|
function toRouteError(error) {
|
|
76570
76705
|
if (error instanceof MastraConnectError) {
|
|
@@ -76578,6 +76713,16 @@ function toRouteError(error) {
|
|
|
76578
76713
|
code: "misconfigured",
|
|
76579
76714
|
message: "Connect routes are not configured correctly."
|
|
76580
76715
|
};
|
|
76716
|
+
if (error.status === 409) return {
|
|
76717
|
+
status: 409,
|
|
76718
|
+
code: "conflict",
|
|
76719
|
+
message: error.detail ?? "The request conflicts with the current state of this connection."
|
|
76720
|
+
};
|
|
76721
|
+
if (error.status === 429) return {
|
|
76722
|
+
status: 429,
|
|
76723
|
+
code: "rate_limited",
|
|
76724
|
+
message: "Too many requests. Try again shortly."
|
|
76725
|
+
};
|
|
76581
76726
|
return {
|
|
76582
76727
|
status: 502,
|
|
76583
76728
|
code: "platform_error",
|
|
@@ -76665,18 +76810,44 @@ function connectionScope(connection) {
|
|
|
76665
76810
|
* ```
|
|
76666
76811
|
*/
|
|
76667
76812
|
function userConnectRoutes(options) {
|
|
76668
|
-
if (!Array.isArray(options.providers) || options.providers.length === 0) throw new MastraConnectError("invalid_options", "
|
|
76669
|
-
const providers = options.providers
|
|
76813
|
+
if (options.providers !== void 0 && (!Array.isArray(options.providers) || options.providers.length === 0)) throw new MastraConnectError("invalid_options", "Invalid providers: pass a non-empty allowlist, or omit the option to use the project provider configuration.");
|
|
76814
|
+
const providers = options.providers?.map((provider) => {
|
|
76670
76815
|
const id = typeof provider === "string" ? provider.trim().toLowerCase() : "";
|
|
76671
76816
|
if (!id) throw new MastraConnectError("invalid_options", "Invalid provider id in userConnectRoutes providers allowlist.");
|
|
76672
76817
|
if (RESERVED_PROVIDER_IDS.has(id) || id.includes("/")) throw new MastraConnectError("invalid_options", `Invalid provider id '${id}': reserved route segment.`);
|
|
76673
76818
|
return id;
|
|
76674
76819
|
});
|
|
76675
|
-
|
|
76820
|
+
/** Explicit code configuration wins without reading project settings from the platform. */
|
|
76821
|
+
const codeAllowlist = providers === void 0 ? void 0 : new Set(providers);
|
|
76676
76822
|
const basePath = options.basePath ?? "/connect";
|
|
76677
76823
|
if (!basePath.startsWith("/") || basePath.endsWith("/") || basePath.includes(":") || basePath.includes("*")) throw new MastraConnectError("invalid_options", `Invalid basePath '${basePath}': expected an absolute path without a trailing slash or route parameters.`);
|
|
76678
76824
|
const projectId = options.projectId?.trim() || process.env.MASTRA_PROJECT_ID?.trim();
|
|
76679
76825
|
if (!projectId) throw new MastraConnectError("missing_project_id", "Missing project id: set MASTRA_PROJECT_ID or pass projectId.");
|
|
76826
|
+
let cachedProjectPolicy;
|
|
76827
|
+
let projectPolicyInflight;
|
|
76828
|
+
/** Lazily loads project policy, sharing one short-lived snapshot across end-user requests and status polling. */
|
|
76829
|
+
const resolveProviderPolicy = (client) => {
|
|
76830
|
+
if (providers !== void 0) return Promise.resolve({
|
|
76831
|
+
providers,
|
|
76832
|
+
allowlist: codeAllowlist
|
|
76833
|
+
});
|
|
76834
|
+
if (cachedProjectPolicy && Date.now() - cachedProjectPolicy.fetchedAt < PROJECT_PROVIDER_POLICY_TTL_MS) return Promise.resolve(cachedProjectPolicy.policy);
|
|
76835
|
+
if (!projectPolicyInflight) projectPolicyInflight = getProjectIntegrationSettings(client, projectId).then((settings) => {
|
|
76836
|
+
const configured = settings.endUserProviders?.map((provider) => provider.toLowerCase());
|
|
76837
|
+
const policy = {
|
|
76838
|
+
providers: configured,
|
|
76839
|
+
allowlist: configured === void 0 ? void 0 : new Set(configured)
|
|
76840
|
+
};
|
|
76841
|
+
cachedProjectPolicy = {
|
|
76842
|
+
policy,
|
|
76843
|
+
fetchedAt: Date.now()
|
|
76844
|
+
};
|
|
76845
|
+
return policy;
|
|
76846
|
+
}).finally(() => {
|
|
76847
|
+
projectPolicyInflight = void 0;
|
|
76848
|
+
});
|
|
76849
|
+
return projectPolicyInflight;
|
|
76850
|
+
};
|
|
76680
76851
|
if (options.client?.resourceId !== void 0) throw new MastraConnectError("invalid_options", "userConnectRoutes derives the resource key per request; do not set client.resourceId.");
|
|
76681
76852
|
if (options.resourceId !== void 0 && typeof options.resourceId !== "function") throw new MastraConnectError("invalid_options", "Invalid resourceId: userConnectRoutes expects a callback deriving the key per request.");
|
|
76682
76853
|
const allowedOrigins = options.returnTo?.allowedOrigins ?? [];
|
|
@@ -76728,13 +76899,20 @@ function userConnectRoutes(options) {
|
|
|
76728
76899
|
return errorResponse(c, toRouteError(error));
|
|
76729
76900
|
}
|
|
76730
76901
|
};
|
|
76731
|
-
/**
|
|
76732
|
-
|
|
76733
|
-
|
|
76734
|
-
|
|
76735
|
-
|
|
76902
|
+
/**
|
|
76903
|
+
* Lists the caller's visible connections (global + own, scoped by the
|
|
76904
|
+
* platform via the resource header). Deliberately NOT filtered to the
|
|
76905
|
+
* provider policy: the allowlist gates what end users can newly connect,
|
|
76906
|
+
* not what already exists — agents keep resolving tools from existing
|
|
76907
|
+
* connections, and narrowing the allowlist must not hide (or orphan) a
|
|
76908
|
+
* user's own rows, which they still need to see and disconnect.
|
|
76909
|
+
*/
|
|
76910
|
+
const listVisibleConnections = async (client) => listProjectConnections(client, projectId);
|
|
76911
|
+
const providerParam = (c, policy) => {
|
|
76736
76912
|
const provider = String(c.req.param("provider") ?? "").trim().toLowerCase();
|
|
76737
|
-
|
|
76913
|
+
if (!provider || RESERVED_PROVIDER_IDS.has(provider) || provider.includes("/")) return null;
|
|
76914
|
+
if (policy.allowlist !== void 0 && !policy.allowlist.has(provider)) return null;
|
|
76915
|
+
return provider;
|
|
76738
76916
|
};
|
|
76739
76917
|
const notFound = (c, code, message) => errorResponse(c, {
|
|
76740
76918
|
status: 404,
|
|
@@ -76747,18 +76925,19 @@ function userConnectRoutes(options) {
|
|
|
76747
76925
|
method: "GET",
|
|
76748
76926
|
requiresAuth: true,
|
|
76749
76927
|
handler: gated(async (c, client) => {
|
|
76750
|
-
const catalog = await listIntegrations(client);
|
|
76928
|
+
const [catalog, policy] = await Promise.all([listIntegrations(client), resolveProviderPolicy(client)]);
|
|
76929
|
+
const toListed = (entry) => ({
|
|
76930
|
+
id: entry.id,
|
|
76931
|
+
displayName: entry.displayName ?? null,
|
|
76932
|
+
logoUrl: entry.logoUrl ?? null,
|
|
76933
|
+
authType: entry.authType ?? null,
|
|
76934
|
+
authFields: entry.authFields ?? null
|
|
76935
|
+
});
|
|
76936
|
+
if (policy.providers === void 0) return c.json({ providers: catalog.map(toListed) });
|
|
76751
76937
|
const byId = new Map(catalog.map((entry) => [entry.id.toLowerCase(), entry]));
|
|
76752
|
-
const visible = providers.flatMap((id) => {
|
|
76938
|
+
const visible = policy.providers.flatMap((id) => {
|
|
76753
76939
|
const entry = byId.get(id);
|
|
76754
|
-
|
|
76755
|
-
return [{
|
|
76756
|
-
id: entry.id,
|
|
76757
|
-
displayName: entry.displayName ?? null,
|
|
76758
|
-
logoUrl: entry.logoUrl ?? null,
|
|
76759
|
-
authType: entry.authType ?? null,
|
|
76760
|
-
authFields: entry.authFields ?? null
|
|
76761
|
-
}];
|
|
76940
|
+
return entry ? [toListed(entry)] : [];
|
|
76762
76941
|
});
|
|
76763
76942
|
return c.json({ providers: visible });
|
|
76764
76943
|
})
|
|
@@ -76768,14 +76947,20 @@ function userConnectRoutes(options) {
|
|
|
76768
76947
|
method: "GET",
|
|
76769
76948
|
requiresAuth: true,
|
|
76770
76949
|
handler: gated(async (c, client) => {
|
|
76771
|
-
const connections = await listVisibleConnections(client);
|
|
76772
|
-
|
|
76773
|
-
|
|
76774
|
-
|
|
76775
|
-
|
|
76776
|
-
|
|
76777
|
-
|
|
76778
|
-
|
|
76950
|
+
const [connections, catalog] = await Promise.all([listVisibleConnections(client), listIntegrations(client).catch(() => [])]);
|
|
76951
|
+
const catalogById = new Map(catalog.map((entry) => [entry.id.toLowerCase(), entry]));
|
|
76952
|
+
return c.json({ connections: connections.map((connection) => {
|
|
76953
|
+
const entry = catalogById.get(connection.integrationId.toLowerCase());
|
|
76954
|
+
return {
|
|
76955
|
+
id: connection.id,
|
|
76956
|
+
integrationId: connection.integrationId,
|
|
76957
|
+
displayName: entry?.displayName ?? null,
|
|
76958
|
+
logoUrl: entry?.logoUrl ?? null,
|
|
76959
|
+
status: connection.status,
|
|
76960
|
+
accountLabel: connection.accountLabel ?? null,
|
|
76961
|
+
scope: connectionScope(connection)
|
|
76962
|
+
};
|
|
76963
|
+
}) });
|
|
76779
76964
|
})
|
|
76780
76965
|
},
|
|
76781
76966
|
{
|
|
@@ -76810,19 +76995,46 @@ function userConnectRoutes(options) {
|
|
|
76810
76995
|
return c.body(null, 204);
|
|
76811
76996
|
})
|
|
76812
76997
|
},
|
|
76998
|
+
{
|
|
76999
|
+
path: `${basePath}/connections/:id/launch`,
|
|
77000
|
+
method: "GET",
|
|
77001
|
+
requiresAuth: true,
|
|
77002
|
+
handler: gated(async (c, client) => {
|
|
77003
|
+
const id = String(c.req.param("id") ?? "");
|
|
77004
|
+
if (!id) return notFound(c, "connection_not_found", "Connection not found.");
|
|
77005
|
+
const { connectUrl, expiresAt } = await getConnectUrl(client, id);
|
|
77006
|
+
c.header("Cache-Control", "no-store");
|
|
77007
|
+
if ((c.req.header("accept") ?? "").includes("application/json")) {
|
|
77008
|
+
let sessionToken = null;
|
|
77009
|
+
try {
|
|
77010
|
+
sessionToken = new URL(connectUrl).searchParams.get("session_token");
|
|
77011
|
+
} catch {
|
|
77012
|
+
sessionToken = null;
|
|
77013
|
+
}
|
|
77014
|
+
return c.json({
|
|
77015
|
+
sessionToken,
|
|
77016
|
+
expiresAt
|
|
77017
|
+
});
|
|
77018
|
+
}
|
|
77019
|
+
return c.redirect(connectUrl, 302);
|
|
77020
|
+
})
|
|
77021
|
+
},
|
|
76813
77022
|
{
|
|
76814
77023
|
path: `${basePath}/:provider/sessions`,
|
|
76815
77024
|
method: "POST",
|
|
76816
77025
|
requiresAuth: true,
|
|
76817
77026
|
handler: gated(async (c, client) => {
|
|
76818
|
-
const
|
|
77027
|
+
const policy = await resolveProviderPolicy(client);
|
|
77028
|
+
const provider = providerParam(c, policy);
|
|
76819
77029
|
if (!provider) return notFound(c, "provider_not_found", "Provider not available.");
|
|
77030
|
+
if (policy.allowlist === void 0) {
|
|
77031
|
+
if (!(await listIntegrations(client)).some((entry) => entry.id.toLowerCase() === provider)) return notFound(c, "provider_not_found", "Provider not available.");
|
|
77032
|
+
}
|
|
76820
77033
|
const session = await createProjectConnectSession(client, projectId, provider);
|
|
76821
77034
|
return c.json({
|
|
76822
77035
|
connectionId: session.connectionId,
|
|
76823
77036
|
integrationId: session.integrationId,
|
|
76824
|
-
|
|
76825
|
-
sessionToken: session.sessionToken,
|
|
77037
|
+
launchUrl: `${basePath}/connections/${encodeURIComponent(session.connectionId)}/launch`,
|
|
76826
77038
|
expiresAt: session.expiresAt
|
|
76827
77039
|
}, 201);
|
|
76828
77040
|
})
|
|
@@ -76832,7 +77044,8 @@ function userConnectRoutes(options) {
|
|
|
76832
77044
|
method: "GET",
|
|
76833
77045
|
requiresAuth: true,
|
|
76834
77046
|
handler: gated(async (c, client) => {
|
|
76835
|
-
const
|
|
77047
|
+
const policy = await resolveProviderPolicy(client);
|
|
77048
|
+
const provider = providerParam(c, policy);
|
|
76836
77049
|
if (!provider) return notFound(c, "provider_not_found", "Provider not available.");
|
|
76837
77050
|
const returnTo = validateReturnTo(c.req.query("returnTo") ?? void 0, allowedOrigins);
|
|
76838
77051
|
if (!returnTo.ok) return errorResponse(c, {
|
|
@@ -76867,6 +77080,7 @@ function userConnectRoutes(options) {
|
|
|
76867
77080
|
}
|
|
76868
77081
|
//#endregion
|
|
76869
77082
|
exports.CHANNELS = CHANNELS;
|
|
77083
|
+
exports.CONNECT_PROMPT_TOOL_KEY = CONNECT_PROMPT_TOOL_KEY;
|
|
76870
77084
|
exports.MastraConnectError = MastraConnectError;
|
|
76871
77085
|
exports.PROVIDERS = PROVIDERS;
|
|
76872
77086
|
exports.channels = channels;
|