@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 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 {};
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
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
- connectUrl: zod.z.string(),
588
- sessionToken: zod.z.string(),
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.connectUrl;
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.connectUrl;
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 never reach the end user — this is an unauthenticated-adjacent
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", "userConnectRoutes requires a non-empty providers allowlist: the end-user surface never defaults open.");
76669
- const providers = options.providers.map((provider) => {
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
- const allowlist = new Set(providers);
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
- /** Lists the caller's visible connections (global + own), filtered to the allowlist. */
76732
- const listVisibleConnections = async (client) => {
76733
- return (await listProjectConnections(client, projectId)).filter((connection) => allowlist.has(connection.integrationId.toLowerCase()));
76734
- };
76735
- const providerParam = (c) => {
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
- return allowlist.has(provider) ? provider : null;
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
- if (!entry) return [];
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
- return c.json({ connections: connections.map((connection) => ({
76773
- id: connection.id,
76774
- integrationId: connection.integrationId,
76775
- status: connection.status,
76776
- accountLabel: connection.accountLabel ?? null,
76777
- scope: connectionScope(connection)
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 provider = providerParam(c);
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
- connectUrl: session.connectUrl,
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 provider = providerParam(c);
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;