@vercel/connect 0.1.3 → 0.2.1

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/README.md CHANGED
@@ -2,10 +2,12 @@
2
2
 
3
3
  SDK for obtaining scoped tokens for third-party services on behalf of apps or users. Authenticates the calling Vercel project via [`@vercel/oidc`](https://www.npmjs.com/package/@vercel/oidc) and exchanges the OIDC token for a Vercel Connect-issued credential.
4
4
 
5
- Four entrypoints, all ESM:
5
+ Six entrypoints, all ESM:
6
6
 
7
7
  - `@vercel/connect` — core token / authorization SDK
8
- - `@vercel/connect/ash` — adapter helpers for [Ash](https://github.com/vercel/ash) connections (optional peer: `experimental-ash`)
8
+ - `@vercel/connect/ai-sdk` — [Vercel AI SDK](https://ai-sdk.dev) glue: re-exports `connectAuthProvider` for MCP transports (optional peers: `ai`, `@ai-sdk/mcp`)
9
+ - `@vercel/connect/mcp` — canonical MCP-spec `OAuthClientProvider` for any MCP client (optional peer: `@ai-sdk/mcp`)
10
+ - `@vercel/connect/eve` — adapter helpers for [Eve](https://github.com/vercel/eve) connections (optional peer: `eve`)
9
11
  - `@vercel/connect/betterauth` — [Better Auth](https://www.better-auth.com/) `genericOAuth` provider (optional peer: `better-auth`)
10
12
  - `@vercel/connect/authjs` — [Auth.js](https://authjs.dev/) `OAuth2Config` provider (optional peer: `@auth/core`)
11
13
 
@@ -27,11 +29,50 @@ const token = await getToken(process.env.CONNECTOR_LINEAR!, {
27
29
  });
28
30
  ```
29
31
 
30
- ### Ash
32
+ ### Vercel AI SDK + MCP
31
33
 
32
34
  ```ts
33
- import { defineMcpClientConnection } from 'experimental-ash/connections';
34
- import { connect } from '@vercel/connect/ash';
35
+ import { createMCPClient } from '@ai-sdk/mcp';
36
+ import { streamText } from 'ai';
37
+ import {
38
+ connectAuthProvider,
39
+ ConsentRequiredError,
40
+ } from '@vercel/connect/ai-sdk';
41
+
42
+ const mcp = await createMCPClient({
43
+ transport: {
44
+ type: 'http',
45
+ url: 'https://mcp.linear.app',
46
+ authProvider: connectAuthProvider('oauth/linear', {
47
+ subject: { type: 'user', id: 'user_123' },
48
+ }),
49
+ },
50
+ });
51
+
52
+ try {
53
+ const result = await streamText({
54
+ model: 'openai/gpt-5.4',
55
+ tools: await mcp.tools(),
56
+ prompt,
57
+ });
58
+ return result.toUIMessageStreamResponse();
59
+ } catch (err) {
60
+ if (err instanceof ConsentRequiredError) return Response.redirect(err.url);
61
+ throw err;
62
+ }
63
+ ```
64
+
65
+ Tool-call approval (Human-in-the-Loop) is independent of Connect — use the AI
66
+ SDK's `toolApproval` option or `wrapMcpTools` from `@ai-sdk/policy-opa`.
67
+
68
+ Non-AI-SDK MCP clients (the official MCP TypeScript SDK, Mastra, etc.)
69
+ can import the same `connectAuthProvider` from `@vercel/connect/mcp`.
70
+
71
+ ### Eve
72
+
73
+ ```ts
74
+ import { defineMcpClientConnection } from 'eve/connections';
75
+ import { connect } from '@vercel/connect/eve';
35
76
 
36
77
  export default defineMcpClientConnection({
37
78
  url: 'https://mcp.linear.app/sse',
@@ -56,4 +97,4 @@ import { connect } from '@vercel/connect/authjs';
56
97
  const providers = [connect({ connector: 'linear' })];
57
98
  ```
58
99
 
59
- See the source under `src/` for the full API (additional helpers like `getTokenResponse`, `startAuthorization`, typed error classes, and per-adapter options).
100
+ See the source under `src/` for the full API (additional helpers like `revokeToken`, `getTokenResponse`, `startAuthorization`, typed error classes, and per-adapter options).
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Public surface of the `@vercel/connect/ai-sdk` subpath.
3
+ *
4
+ * Re-exports the MCP-spec `connectAuthProvider` (and its consent
5
+ * types) so AI SDK users have a single, ergonomic import. The
6
+ * provider plugs straight into `@ai-sdk/mcp`'s `createMCPClient`
7
+ * `authProvider` and works with AI SDK v6 and v7.
8
+ *
9
+ * Tool-call approval (Human-in-the-Loop) is intentionally not
10
+ * provided here — it is independent of Connect and already covered by
11
+ * the AI SDK's own `toolApproval` primitive (and `wrapMcpTools` in
12
+ * `@ai-sdk/policy-opa`). See `docs/ai-sdk-mcp-integration.md`.
13
+ *
14
+ * Both `ai` and `@ai-sdk/mcp` are optional peer dependencies:
15
+ * importing this entrypoint requires them to be installed in the
16
+ * consumer project, but the rest of `@vercel/connect` works without
17
+ * them.
18
+ *
19
+ * ```ts
20
+ * import { createMCPClient } from '@ai-sdk/mcp';
21
+ * import { streamText } from 'ai';
22
+ * import {
23
+ * connectAuthProvider,
24
+ * ConsentRequiredError,
25
+ * } from '@vercel/connect/ai-sdk';
26
+ *
27
+ * const mcpClient = await createMCPClient({
28
+ * transport: {
29
+ * type: 'http',
30
+ * url: 'https://mcp.linear.app',
31
+ * authProvider: connectAuthProvider('oauth/linear', {
32
+ * subject: { type: 'user', id: userId },
33
+ * scopes: ['read'],
34
+ * }),
35
+ * },
36
+ * });
37
+ *
38
+ * try {
39
+ * const result = await streamText({
40
+ * model: 'openai/gpt-5.4',
41
+ * tools: await mcpClient.tools(),
42
+ * prompt,
43
+ * });
44
+ * return result.toUIMessageStreamResponse();
45
+ * } catch (err) {
46
+ * if (err instanceof ConsentRequiredError) return Response.redirect(err.url);
47
+ * throw err;
48
+ * }
49
+ * ```
50
+ */
51
+ export { connectAuthProvider, ConsentRequiredError, type ConnectAuthProviderOptions, type ConsentChallenge, } from '../mcp/connect-auth-provider.js';
52
+ export { ConnectError, ConnectorInstallationRequiredError, NoValidTokenError, UserAuthorizationRequiredError, type ConnectErrorOptions, type ConnectTokenParams, type ConnectTokenSubject, type ConnectVendorErrorPayload, } from '../token.js';
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Public surface of the `@vercel/connect/ai-sdk` subpath.
3
+ *
4
+ * Re-exports the MCP-spec `connectAuthProvider` (and its consent
5
+ * types) so AI SDK users have a single, ergonomic import. The
6
+ * provider plugs straight into `@ai-sdk/mcp`'s `createMCPClient`
7
+ * `authProvider` and works with AI SDK v6 and v7.
8
+ *
9
+ * Tool-call approval (Human-in-the-Loop) is intentionally not
10
+ * provided here — it is independent of Connect and already covered by
11
+ * the AI SDK's own `toolApproval` primitive (and `wrapMcpTools` in
12
+ * `@ai-sdk/policy-opa`). See `docs/ai-sdk-mcp-integration.md`.
13
+ *
14
+ * Both `ai` and `@ai-sdk/mcp` are optional peer dependencies:
15
+ * importing this entrypoint requires them to be installed in the
16
+ * consumer project, but the rest of `@vercel/connect` works without
17
+ * them.
18
+ *
19
+ * ```ts
20
+ * import { createMCPClient } from '@ai-sdk/mcp';
21
+ * import { streamText } from 'ai';
22
+ * import {
23
+ * connectAuthProvider,
24
+ * ConsentRequiredError,
25
+ * } from '@vercel/connect/ai-sdk';
26
+ *
27
+ * const mcpClient = await createMCPClient({
28
+ * transport: {
29
+ * type: 'http',
30
+ * url: 'https://mcp.linear.app',
31
+ * authProvider: connectAuthProvider('oauth/linear', {
32
+ * subject: { type: 'user', id: userId },
33
+ * scopes: ['read'],
34
+ * }),
35
+ * },
36
+ * });
37
+ *
38
+ * try {
39
+ * const result = await streamText({
40
+ * model: 'openai/gpt-5.4',
41
+ * tools: await mcpClient.tools(),
42
+ * prompt,
43
+ * });
44
+ * return result.toUIMessageStreamResponse();
45
+ * } catch (err) {
46
+ * if (err instanceof ConsentRequiredError) return Response.redirect(err.url);
47
+ * throw err;
48
+ * }
49
+ * ```
50
+ */
51
+ export { connectAuthProvider, ConsentRequiredError, } from '../mcp/connect-auth-provider.js';
52
+ export { ConnectError, ConnectorInstallationRequiredError, NoValidTokenError, UserAuthorizationRequiredError, } from '../token.js';
@@ -1,4 +1,4 @@
1
- import { type AuthFn, type VerifyOidcConfig } from 'experimental-ash/channels/auth';
1
+ import { type AuthFn, type VerifyOidcConfig } from 'eve/channels/auth';
2
2
  export declare const CONNECT_OAUTH_ISSUER = "https://connect.vercel.com";
3
3
  export type ConnectOAuthEnvironment = 'production' | 'preview' | 'development';
4
4
  export type ConnectOAuthAudienceEnvironment = ConnectOAuthEnvironment | '*';
@@ -23,7 +23,7 @@ export interface ConnectOAuthOptions {
23
23
  */
24
24
  readonly environment?: ConnectOAuthAudienceEnvironment;
25
25
  /**
26
- * Optional gateway session id (`sub`) matchers. Patterns use Ash's
26
+ * Optional gateway session id (`sub`) matchers. Patterns use Eve's
27
27
  * IAM-style `*` wildcard matching.
28
28
  */
29
29
  readonly subjects?: readonly string[];
@@ -49,11 +49,11 @@ export interface ConnectOAuthOptions {
49
49
  * `https://connect.vercel.com/.well-known/openid-configuration`.
50
50
  */
51
51
  readonly discoveryUrl?: string;
52
- /** Clock skew in seconds. Defaults to Ash's OIDC verifier default. */
52
+ /** Clock skew in seconds. Defaults to Eve's OIDC verifier default. */
53
53
  readonly clockSkewSeconds?: number;
54
54
  }
55
55
  /**
56
- * Returns an Ash route auth callback for Vercel Connect OAuth gateway
56
+ * Returns an Eve route auth callback for Vercel Connect OAuth gateway
57
57
  * access tokens.
58
58
  *
59
59
  * The accepted token must be a bearer JWT issued by
@@ -1,7 +1,7 @@
1
- import { extractBearerToken, verifyOidc, } from 'experimental-ash/channels/auth';
1
+ import { extractBearerToken, verifyOidc, } from 'eve/channels/auth';
2
2
  export const CONNECT_OAUTH_ISSUER = 'https://connect.vercel.com';
3
3
  /**
4
- * Returns an Ash route auth callback for Vercel Connect OAuth gateway
4
+ * Returns an Eve route auth callback for Vercel Connect OAuth gateway
5
5
  * access tokens.
6
6
  *
7
7
  * The accepted token must be a bearer JWT issued by
@@ -1,8 +1,8 @@
1
1
  /**
2
- * Ash adapter helper for `@vercel/connect`.
2
+ * Eve adapter helper for `@vercel/connect`.
3
3
  *
4
4
  * {@link connect} turns a Vercel Connect OAuth connector id plus a
5
- * principal type into a ready-made Ash
5
+ * principal type into a ready-made Eve
6
6
  * {@link AuthorizationDefinition} that the connection runtime
7
7
  * consumes directly. The helper collapses the ~100 lines of
8
8
  * `getToken` / `startAuthorization` / `completeAuthorization`
@@ -10,8 +10,8 @@
10
10
  * to a single call:
11
11
  *
12
12
  * ```ts
13
- * import { defineMcpClientConnection } from "experimental-ash/connections";
14
- * import { connect } from "@vercel/connect/ash";
13
+ * import { defineMcpClientConnection } from "eve/connections";
14
+ * import { connect } from "@vercel/connect/eve";
15
15
  *
16
16
  * export default defineMcpClientConnection({
17
17
  * url: "https://mcp.linear.app/sse",
@@ -22,34 +22,21 @@
22
22
  *
23
23
  * # Module layout
24
24
  *
25
- * This entrypoint is exposed at the `@vercel/connect/ash` subpath so
26
- * consumers that don't use Ash never load it. `experimental-ash` is
25
+ * This entrypoint is exposed at the `@vercel/connect/eve` subpath so
26
+ * consumers that don't use Eve never load it. `eve` is
27
27
  * declared as an optional peer dependency: importing
28
- * `@vercel/connect/ash` requires Ash to be installed in the consumer
28
+ * `@vercel/connect/eve` requires Eve to be installed in the consumer
29
29
  * project, but the rest of `@vercel/connect` works without it.
30
30
  */
31
- import { type ConnectionPrincipal, type InteractiveAuthorizationDefinition, type JsonValue, type NonInteractiveAuthorizationDefinition } from 'experimental-ash/connections';
31
+ import { type ConnectionPrincipal, type InteractiveAuthorizationDefinition, type NonInteractiveAuthorizationDefinition } from 'eve/connections';
32
32
  import type { ConnectOptions, ConnectTokenParams, ConnectTokenSubject } from '../token.js';
33
33
  /**
34
- * Authorization phase passed to {@link AshAuthorizationOptions.onError}
34
+ * Authorization phase passed to {@link EveAuthorizationOptions.onError}
35
35
  * so consumers can branch their error translation per callback.
36
36
  */
37
37
  export type ConnectAuthorizationPhase = 'getToken' | 'startAuthorization' | 'completeAuthorization';
38
- /**
39
- * State journaled by Ash between
40
- * {@link InteractiveAuthorizationDefinition.startAuthorization} and
41
- * {@link InteractiveAuthorizationDefinition.completeAuthorization}.
42
- *
43
- * Currently just the PKCE verifier. The index signature exists to
44
- * satisfy Ash's `State extends JsonValue` constraint; in practice
45
- * the only key the helper produces or reads is `verifier`.
46
- */
47
- export type ConnectAuthorizationState = {
48
- readonly verifier: string;
49
- readonly [key: string]: JsonValue;
50
- };
51
38
  /** Options accepted by {@link connect}. */
52
- export interface AshAuthorizationOptions {
39
+ export interface EveAuthorizationOptions {
53
40
  /**
54
41
  * Vercel Connect OAuth connector identifier. Accepts either the
55
42
  * opaque service connector key (`scl_...`) or the human-readable
@@ -64,9 +51,9 @@ export interface AshAuthorizationOptions {
64
51
  * on this choice:
65
52
  *
66
53
  * - `"user"` → full interactive OAuth definition with `getToken`,
67
- * `startAuthorization`, and `completeAuthorization`. Ash will
54
+ * `startAuthorization`, and `completeAuthorization`. Eve will
68
55
  * drive a consent flow through its framework-owned webhook.
69
- * - `"app"` → non-interactive definition with `getToken` only. Ash
56
+ * - `"app"` → non-interactive definition with `getToken` only. Eve
70
57
  * never runs a consent flow for app-scoped connectors; a failure
71
58
  * to fetch the token surfaces as a terminal authorization
72
59
  * failure so the channel can prompt an operator to install the
@@ -83,7 +70,7 @@ export interface AshAuthorizationOptions {
83
70
  */
84
71
  readonly tokenParams?: Omit<ConnectTokenParams, 'subject'>;
85
72
  /**
86
- * Override how Ash's framework-resolved principal is mapped to a
73
+ * Override how Eve's framework-resolved principal is mapped to a
87
74
  * Vercel Connect token subject. When omitted, app principals map to
88
75
  * `{ type: "app" }` and user principals map to
89
76
  * `{ type: "user", id, issuer }`.
@@ -97,14 +84,14 @@ export interface AshAuthorizationOptions {
97
84
  readonly connectOptions?: ConnectOptions;
98
85
  /**
99
86
  * Custom call-to-action rendered on the
100
- * `connection.authorization_required` event. When omitted, Ash
87
+ * `connection.authorization_required` event. When omitted, Eve
101
88
  * fills in `Authorize <ConnectionName> in your browser to continue.`
102
89
  * from the connection's filename.
103
90
  */
104
91
  readonly instructions?: string;
105
92
  /**
106
93
  * Escape hatch for turning an unexpected Vercel Connect / network
107
- * error into an Ash-recognizable error. Called once per failure
94
+ * error into an Eve-recognizable error. Called once per failure
108
95
  * with the raw error and the phase that produced it.
109
96
  *
110
97
  * Return a new `Error` to replace the helper's default translation,
@@ -115,7 +102,7 @@ export interface AshAuthorizationOptions {
115
102
  readonly onError?: (error: unknown, phase: ConnectAuthorizationPhase) => Error | undefined;
116
103
  }
117
104
  /** Input accepted by {@link connect}. */
118
- export type AshAuthorizationInput = string | AshAuthorizationOptions;
105
+ export type EveAuthorizationInput = string | EveAuthorizationOptions;
119
106
  /**
120
107
  * Structurally-readable marker exposed on every {@link connect} return
121
108
  * value so downstream tooling can detect Vercel Connect-backed
@@ -139,35 +126,35 @@ export interface VercelConnectMetadata {
139
126
  readonly connector: string;
140
127
  }
141
128
  /**
142
- * Augments the standard Ash authorization shape with the
129
+ * Augments the standard Eve authorization shape with the
143
130
  * {@link VercelConnectMetadata} marker, narrowed to whichever flavour
144
131
  * `connect()` produces.
145
132
  */
146
- export type AshConnectAuthorizationDefinition<TAuthorization extends InteractiveAuthorizationDefinition<ConnectAuthorizationState> | NonInteractiveAuthorizationDefinition> = TAuthorization & {
133
+ export type EveConnectAuthorizationDefinition<TAuthorization extends InteractiveAuthorizationDefinition | NonInteractiveAuthorizationDefinition> = TAuthorization & {
147
134
  readonly vercelConnect: VercelConnectMetadata;
148
135
  };
149
136
  /**
150
- * Builds an Ash {@link AuthorizationDefinition} backed by Vercel
137
+ * Builds an Eve {@link AuthorizationDefinition} backed by Vercel
151
138
  * Connect. The return type narrows based on
152
- * {@link AshAuthorizationOptions.principalType}:
139
+ * {@link EveAuthorizationOptions.principalType}:
153
140
  *
154
141
  * - omitted or `principalType: "user"` returns an
155
- * {@link InteractiveAuthorizationDefinition}; Ash drives a consent
142
+ * {@link InteractiveAuthorizationDefinition}; Eve drives a consent
156
143
  * flow through its framework-owned webhook.
157
144
  * - `principalType: "app"` returns a
158
- * {@link NonInteractiveAuthorizationDefinition}; Ash never runs a
145
+ * {@link NonInteractiveAuthorizationDefinition}; Eve never runs a
159
146
  * consent flow for app-scoped connectors.
160
147
  *
161
148
  * Every returned definition also carries a {@link VercelConnectMetadata}
162
- * marker on its `vercelConnect` field so downstream tooling (Ash
149
+ * marker on its `vercelConnect` field so downstream tooling (Eve
163
150
  * compiler, dashboards) can detect Vercel Connect-backed connections
164
151
  * without inspecting closure state.
165
152
  */
166
- export declare function connect(connector: string): AshConnectAuthorizationDefinition<InteractiveAuthorizationDefinition<ConnectAuthorizationState>>;
167
- export declare function connect(options: AshAuthorizationOptions & {
153
+ export declare function connect(connector: string): EveConnectAuthorizationDefinition<InteractiveAuthorizationDefinition>;
154
+ export declare function connect(options: EveAuthorizationOptions & {
168
155
  readonly principalType?: 'user';
169
- }): AshConnectAuthorizationDefinition<InteractiveAuthorizationDefinition<ConnectAuthorizationState>>;
170
- export declare function connect(options: AshAuthorizationOptions & {
156
+ }): EveConnectAuthorizationDefinition<InteractiveAuthorizationDefinition>;
157
+ export declare function connect(options: EveAuthorizationOptions & {
171
158
  readonly principalType: 'app';
172
- }): AshConnectAuthorizationDefinition<NonInteractiveAuthorizationDefinition>;
173
- export declare function connect(options: AshAuthorizationInput): AshConnectAuthorizationDefinition<InteractiveAuthorizationDefinition<ConnectAuthorizationState> | NonInteractiveAuthorizationDefinition>;
159
+ }): EveConnectAuthorizationDefinition<NonInteractiveAuthorizationDefinition>;
160
+ export declare function connect(options: EveAuthorizationInput): EveConnectAuthorizationDefinition<InteractiveAuthorizationDefinition | NonInteractiveAuthorizationDefinition>;
@@ -1,8 +1,8 @@
1
1
  /**
2
- * Ash adapter helper for `@vercel/connect`.
2
+ * Eve adapter helper for `@vercel/connect`.
3
3
  *
4
4
  * {@link connect} turns a Vercel Connect OAuth connector id plus a
5
- * principal type into a ready-made Ash
5
+ * principal type into a ready-made Eve
6
6
  * {@link AuthorizationDefinition} that the connection runtime
7
7
  * consumes directly. The helper collapses the ~100 lines of
8
8
  * `getToken` / `startAuthorization` / `completeAuthorization`
@@ -10,8 +10,8 @@
10
10
  * to a single call:
11
11
  *
12
12
  * ```ts
13
- * import { defineMcpClientConnection } from "experimental-ash/connections";
14
- * import { connect } from "@vercel/connect/ash";
13
+ * import { defineMcpClientConnection } from "eve/connections";
14
+ * import { connect } from "@vercel/connect/eve";
15
15
  *
16
16
  * export default defineMcpClientConnection({
17
17
  * url: "https://mcp.linear.app/sse",
@@ -22,13 +22,13 @@
22
22
  *
23
23
  * # Module layout
24
24
  *
25
- * This entrypoint is exposed at the `@vercel/connect/ash` subpath so
26
- * consumers that don't use Ash never load it. `experimental-ash` is
25
+ * This entrypoint is exposed at the `@vercel/connect/eve` subpath so
26
+ * consumers that don't use Eve never load it. `eve` is
27
27
  * declared as an optional peer dependency: importing
28
- * `@vercel/connect/ash` requires Ash to be installed in the consumer
28
+ * `@vercel/connect/eve` requires Eve to be installed in the consumer
29
29
  * project, but the rest of `@vercel/connect` works without it.
30
30
  */
31
- import { ConnectionAuthorizationFailedError, ConnectionAuthorizationRequiredError, } from 'experimental-ash/connections';
31
+ import { ConnectionAuthorizationFailedError, ConnectionAuthorizationRequiredError, } from 'eve/connections';
32
32
  import { startAuthorization } from '../authorization.js';
33
33
  import { ConnectorInstallationRequiredError, getTokenResponse, NoValidTokenError, UserAuthorizationRequiredError, } from '../token.js';
34
34
  export function connect(input) {
@@ -59,7 +59,7 @@ function buildInteractiveDefinition(options) {
59
59
  },
60
60
  async startAuthorization({ principal, callbackUrl, webhook, }) {
61
61
  try {
62
- // Ash's `webhook` parameter is semantically a browser-redirect
62
+ // Eve's `webhook` parameter is semantically a browser-redirect
63
63
  // target — the orchestrator mints it via `createWebhook({
64
64
  // respondWith: buildAuthorizationCompletePage() })` so the
65
65
  // user lands on a friendly "you can close this tab" page after
@@ -74,9 +74,9 @@ function buildInteractiveDefinition(options) {
74
74
  // `webhook:` (server-POST) field, even though it would
75
75
  // survive the user closing the consent tab right after IdP
76
76
  // callback. That mode shows the user Vercel Connect's
77
- // generic "close this window" page instead of Ash's branded
77
+ // generic "close this window" page instead of Eve's branded
78
78
  // landing page, and the helper would need to grow
79
- // protocol-aware logic that diverges from the simple "Ash
79
+ // protocol-aware logic that diverges from the simple "Eve
80
80
  // mints one URL, Vercel Connect redirects there" mental
81
81
  // model. Revisit if tab-close timeouts become a real problem
82
82
  // in production.
@@ -96,7 +96,6 @@ function buildInteractiveDefinition(options) {
96
96
  ? { instructions: options.instructions }
97
97
  : null),
98
98
  },
99
- state: { verifier: response.verifier },
100
99
  };
101
100
  }
102
101
  catch (error) {
@@ -142,11 +141,11 @@ function principalToSubject(principal) {
142
141
  return { type: 'user', id: principal.id, issuer: principal.issuer };
143
142
  }
144
143
  /**
145
- * Translates raw Vercel Connect errors into Ash's public
144
+ * Translates raw Vercel Connect errors into Eve's public
146
145
  * {@link ConnectionAuthorizationRequiredError} /
147
- * {@link ConnectionAuthorizationFailedError} classes. Ash discriminates
146
+ * {@link ConnectionAuthorizationFailedError} classes. Eve discriminates
148
147
  * on `err.name` (not `instanceof`), so even if the consumer's bundle
149
- * loads a different copy of `experimental-ash` than this helper, the
148
+ * loads a different copy of `eve` than this helper, the
150
149
  * runtime still recognizes the throw.
151
150
  */
152
151
  function translate(error, phase, options) {
@@ -156,7 +155,7 @@ function translate(error, phase, options) {
156
155
  // `UserAuthorizationRequiredError` and `NoValidTokenError` both
157
156
  // mean "Vercel Connect has no valid credential for this principal
158
157
  // yet". For interactive (user) connectors that's recoverable via
159
- // a consent flow; Ash will see the `Required` throw and drive
158
+ // a consent flow; Eve will see the `Required` throw and drive
160
159
  // `startAuthorization`. For app connectors it's terminal — there
161
160
  // is nobody to consent — so we surface `Failed` with
162
161
  // `retryable: false`.
@@ -170,7 +169,7 @@ function translate(error, phase, options) {
170
169
  });
171
170
  }
172
171
  if (phase === 'completeAuthorization') {
173
- // The consent leg reported success (Ash would not call us
172
+ // The consent leg reported success (Eve would not call us
174
173
  // otherwise) but Vercel Connect still says the user is
175
174
  // unauthorized. Default to retryable so the model can
176
175
  // re-prompt; most cases (network blip, replay) resolve on
@@ -193,7 +192,7 @@ function translate(error, phase, options) {
193
192
  retryable: false,
194
193
  });
195
194
  }
196
- // Every other error is re-thrown verbatim. Ash treats an unknown
195
+ // Every other error is re-thrown verbatim. Eve treats an unknown
197
196
  // throw from `completeAuthorization` as a retryable failure, so the
198
197
  // default behavior stays intuitive.
199
198
  return error instanceof Error ? error : new Error(String(error));
@@ -0,0 +1,24 @@
1
+ import type { GitHubChannelCredentials } from 'eve/channels/github';
2
+ import { type ConnectOptions, type ConnectTokenParams } from '../index.js';
3
+ /**
4
+ * Token parameters accepted by {@link connectGitHubCredentials}.
5
+ *
6
+ * Mirrors {@link ConnectTokenParams} from `@vercel/connect`, minus
7
+ * `subject` — GitHub installation tokens are app-scoped, so `subject`
8
+ * is pinned to `{ type: "app" }` by this helper and cannot be
9
+ * overridden.
10
+ */
11
+ export type ConnectGitHubCredentialsParams = Omit<ConnectTokenParams, 'subject'>;
12
+ /**
13
+ * Build {@link GitHubChannelCredentials} backed by a Vercel Connect
14
+ * connector that stores a GitHub installation access token.
15
+ *
16
+ * Eve uses `installationToken` directly for authenticated GitHub API
17
+ * calls and skips its native GitHub App JWT exchange. The token is a
18
+ * function form so rotation, refresh, and multi-installation tenancy
19
+ * stay delegated to Vercel Connect.
20
+ *
21
+ * The webhook verifier accepts Connect-forwarded webhooks authenticated
22
+ * with Vercel OIDC instead of GitHub's webhook secret.
23
+ */
24
+ export declare function connectGitHubCredentials(connector: string, params?: ConnectGitHubCredentialsParams, options?: ConnectOptions): GitHubChannelCredentials;
@@ -0,0 +1,20 @@
1
+ import { vercelOidc } from 'eve/channels/auth';
2
+ import { getToken, } from '../index.js';
3
+ /**
4
+ * Build {@link GitHubChannelCredentials} backed by a Vercel Connect
5
+ * connector that stores a GitHub installation access token.
6
+ *
7
+ * Eve uses `installationToken` directly for authenticated GitHub API
8
+ * calls and skips its native GitHub App JWT exchange. The token is a
9
+ * function form so rotation, refresh, and multi-installation tenancy
10
+ * stay delegated to Vercel Connect.
11
+ *
12
+ * The webhook verifier accepts Connect-forwarded webhooks authenticated
13
+ * with Vercel OIDC instead of GitHub's webhook secret.
14
+ */
15
+ export function connectGitHubCredentials(connector, params = {}, options) {
16
+ return {
17
+ installationToken: () => getToken(connector, { ...params, subject: { type: 'app' } }, options),
18
+ webhookVerifier: vercelOidc(),
19
+ };
20
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Public surface of the `@vercel/connect/eve` subpath.
3
+ *
4
+ * Holds Eve-specific helpers that adapt the Vercel Connect SDK to
5
+ * Eve's connection runtime. Each helper lives in its own module;
6
+ * this barrel re-exports the public API so consumers import
7
+ * everything from `@vercel/connect/eve`.
8
+ */
9
+ export { connect, type EveAuthorizationInput, type EveAuthorizationOptions, type EveConnectAuthorizationDefinition, type ConnectAuthorizationPhase, type VercelConnectMetadata, } from './connection-authorization.js';
10
+ export { CONNECT_OAUTH_ISSUER, connectOAuth, type ConnectOAuthAudienceEnvironment, type ConnectOAuthEnvironment, type ConnectOAuthOptions, } from './connect-oauth.js';
11
+ export { connectGitHubCredentials, type ConnectGitHubCredentialsParams, } from './github-credentials.js';
12
+ export { connectLinearCredentials, type ConnectLinearCredentialsParams, } from './linear-credentials.js';
13
+ export { connectSlackCredentials, type ConnectSlackCredentialsParams, } from './slack-credentials.js';
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Public surface of the `@vercel/connect/eve` subpath.
3
+ *
4
+ * Holds Eve-specific helpers that adapt the Vercel Connect SDK to
5
+ * Eve's connection runtime. Each helper lives in its own module;
6
+ * this barrel re-exports the public API so consumers import
7
+ * everything from `@vercel/connect/eve`.
8
+ */
9
+ export { connect, } from './connection-authorization.js';
10
+ export { CONNECT_OAUTH_ISSUER, connectOAuth, } from './connect-oauth.js';
11
+ export { connectGitHubCredentials, } from './github-credentials.js';
12
+ export { connectLinearCredentials, } from './linear-credentials.js';
13
+ export { connectSlackCredentials, } from './slack-credentials.js';
@@ -0,0 +1,22 @@
1
+ import type { LinearChannelCredentials } from 'eve/channels/linear';
2
+ import { type ConnectOptions, type ConnectTokenParams } from '../index.js';
3
+ /**
4
+ * Token parameters accepted by {@link connectLinearCredentials}.
5
+ *
6
+ * Mirrors {@link ConnectTokenParams} from `@vercel/connect`, minus
7
+ * `subject` — Linear Agent tokens are app-scoped, so `subject` is
8
+ * pinned to `{ type: "app" }` by this helper and cannot be overridden.
9
+ */
10
+ export type ConnectLinearCredentialsParams = Omit<ConnectTokenParams, 'subject'>;
11
+ /**
12
+ * Build {@link LinearChannelCredentials} backed by a Vercel Connect
13
+ * connector that stores a Linear app access token.
14
+ *
15
+ * Eve uses `accessToken` for Linear GraphQL calls. The token is a
16
+ * function form so rotation, refresh, and multi-workspace tenancy stay
17
+ * delegated to Vercel Connect.
18
+ *
19
+ * The webhook verifier accepts Connect-forwarded webhooks authenticated
20
+ * with Vercel OIDC instead of Linear's webhook secret.
21
+ */
22
+ export declare function connectLinearCredentials(connector: string, params?: ConnectLinearCredentialsParams, options?: ConnectOptions): LinearChannelCredentials;
@@ -0,0 +1,19 @@
1
+ import { vercelOidc } from 'eve/channels/auth';
2
+ import { getToken, } from '../index.js';
3
+ /**
4
+ * Build {@link LinearChannelCredentials} backed by a Vercel Connect
5
+ * connector that stores a Linear app access token.
6
+ *
7
+ * Eve uses `accessToken` for Linear GraphQL calls. The token is a
8
+ * function form so rotation, refresh, and multi-workspace tenancy stay
9
+ * delegated to Vercel Connect.
10
+ *
11
+ * The webhook verifier accepts Connect-forwarded webhooks authenticated
12
+ * with Vercel OIDC instead of Linear's webhook secret.
13
+ */
14
+ export function connectLinearCredentials(connector, params = {}, options) {
15
+ return {
16
+ accessToken: () => getToken(connector, { ...params, subject: { type: 'app' } }, options),
17
+ webhookVerifier: vercelOidc(),
18
+ };
19
+ }
@@ -1,4 +1,4 @@
1
- import type { SlackChannelCredentials } from 'experimental-ash/channels/slack';
1
+ import type { SlackChannelCredentials } from 'eve/channels/slack';
2
2
  import { type ConnectOptions, type ConnectTokenParams } from '../index.js';
3
3
  /**
4
4
  * Token parameters accepted by {@link connectSlackCredentials}.
@@ -28,8 +28,8 @@ export type ConnectSlackCredentialsParams = Omit<ConnectTokenParams, 'subject'>;
28
28
  * `installationId`, `scopes`, or `validityBufferMs`.
29
29
  *
30
30
  * ```ts
31
- * import { slackRoute } from "experimental-ash/channels/slack";
32
- * import { connectSlackCredentials } from "@vercel/connect/ash";
31
+ * import { slackRoute } from "eve/channels/slack";
32
+ * import { connectSlackCredentials } from "@vercel/connect/eve";
33
33
  *
34
34
  * export default slackRoute({
35
35
  * credentials: connectSlackCredentials("scl_..."),
@@ -1,5 +1,5 @@
1
1
  import { getToken, } from '../index.js';
2
- import { vercelOidc } from 'experimental-ash/channels/auth';
2
+ import { vercelOidc } from 'eve/channels/auth';
3
3
  /**
4
4
  * Build {@link SlackChannelCredentials} backed by a Vercel Connect
5
5
  * connector that stores a Slack workspace's bot token.
@@ -19,8 +19,8 @@ import { vercelOidc } from 'experimental-ash/channels/auth';
19
19
  * `installationId`, `scopes`, or `validityBufferMs`.
20
20
  *
21
21
  * ```ts
22
- * import { slackRoute } from "experimental-ash/channels/slack";
23
- * import { connectSlackCredentials } from "@vercel/connect/ash";
22
+ * import { slackRoute } from "eve/channels/slack";
23
+ * import { connectSlackCredentials } from "@vercel/connect/eve";
24
24
  *
25
25
  * export default slackRoute({
26
26
  * credentials: connectSlackCredentials("scl_..."),
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { getToken, getTokenResponse, ConnectError, NoValidTokenError, UserAuthorizationRequiredError, ConnectorInstallationRequiredError, type ConnectErrorOptions, type ConnectOptions, type ConnectTokenParams, type ConnectTokenResponse, type ConnectTokenSubject, type ConnectVendorErrorPayload, } from './token.js';
1
+ export { getToken, getTokenResponse, revokeToken, ConnectError, NoValidTokenError, UserAuthorizationRequiredError, ConnectorInstallationRequiredError, type ConnectErrorOptions, type ConnectOptions, type ConnectTokenParams, type ConnectTokenResponse, type ConnectTokenSubject, type ConnectVendorErrorPayload, } from './token.js';
2
2
  export { startAuthorization, type ConnectAuthorizationOptions, type ConnectAuthorizationResponse, } from './authorization.js';
3
3
  export type { ConnectAuthorizationDetail } from './authorization-details.js';
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export { getToken, getTokenResponse, ConnectError, NoValidTokenError, UserAuthorizationRequiredError, ConnectorInstallationRequiredError, } from './token.js';
1
+ export { getToken, getTokenResponse, revokeToken, ConnectError, NoValidTokenError, UserAuthorizationRequiredError, ConnectorInstallationRequiredError, } from './token.js';
2
2
  export { startAuthorization, } from './authorization.js';
@@ -0,0 +1,99 @@
1
+ import type { OAuthClientProvider } from '@ai-sdk/mcp';
2
+ import { type ConnectTokenParams } from '../token.js';
3
+ /** Options accepted by {@link connectAuthProvider}. */
4
+ export interface ConnectAuthProviderOptions {
5
+ /**
6
+ * Override the Vercel OIDC token used to authenticate against the
7
+ * Connect API. Defaults to the `@vercel/oidc` resolver used by the
8
+ * rest of `@vercel/connect`. Useful for tests and non-Vercel
9
+ * runtimes.
10
+ *
11
+ * Accepts a callback because the adapter is long-lived: `tokens()`
12
+ * is invoked across many turns and refreshes, so a captured string
13
+ * would go stale. When a function is provided it is resolved at
14
+ * call time.
15
+ */
16
+ readonly vercelToken?: string | (() => string | Promise<string>);
17
+ /**
18
+ * Where to send the user after they finish granting access on
19
+ * Connect's hosted consent page. Forwarded to Connect's
20
+ * `startAuthorization` (as its `callbackUrl`) and also surfaced
21
+ * through the MCP-spec `OAuthClientProvider.redirectUrl` getter.
22
+ *
23
+ * Defaults to an empty string — Connect then falls back to the
24
+ * connector's server-side registered redirect.
25
+ */
26
+ readonly redirectUrl?: string;
27
+ /**
28
+ * Request the device-authorization flow when minting a consent
29
+ * challenge. When `true`, Connect returns a `deviceCode` (and
30
+ * `expiresAt`) on the {@link ConsentChallenge} for out-of-band /
31
+ * headless approval. Defaults to `false`.
32
+ */
33
+ readonly deviceCode?: boolean;
34
+ /**
35
+ * Called when Vercel Connect reports that the user has not yet
36
+ * authorized the connector. The caller decides how to surface the
37
+ * consent URL — `redirect()`, throw a typed error, emit a custom
38
+ * UI chunk, etc. If omitted, `connectAuthProvider` throws
39
+ * {@link ConsentRequiredError}.
40
+ */
41
+ readonly onConsentRequired?: (challenge: ConsentChallenge) => void | Promise<void>;
42
+ }
43
+ /**
44
+ * Returned to {@link ConnectAuthProviderOptions.onConsentRequired} (or
45
+ * raised inside {@link ConsentRequiredError}) when Connect has no
46
+ * cached grant for the configured subject and the caller must surface
47
+ * the consent URL.
48
+ */
49
+ export interface ConsentChallenge {
50
+ readonly connector: string;
51
+ readonly subject: ConnectTokenParams['subject'];
52
+ /** Consent URL to redirect the user to. */
53
+ readonly url: string;
54
+ readonly request: string;
55
+ readonly verifier: string;
56
+ /**
57
+ * Device code to display to the user when Connect issues a
58
+ * device-flow authorization. Present only when the connector uses
59
+ * device flow.
60
+ */
61
+ readonly deviceCode?: string;
62
+ /** Epoch-ms expiry of the consent challenge, when Connect reports one. */
63
+ readonly expiresAt?: number;
64
+ }
65
+ /**
66
+ * Thrown by the {@link connectAuthProvider} default
67
+ * `onConsentRequired` handler when the user has no Connect grant for
68
+ * the configured subject. Catch at the boundary
69
+ * (`route handler` / `streamText` call site) and redirect to
70
+ * `error.url`.
71
+ */
72
+ export declare class ConsentRequiredError extends Error {
73
+ readonly name = "ConsentRequiredError";
74
+ readonly connector: string;
75
+ readonly subject: ConnectTokenParams['subject'];
76
+ readonly url: string;
77
+ readonly request: string;
78
+ readonly verifier: string;
79
+ readonly deviceCode?: string;
80
+ readonly expiresAt?: number;
81
+ constructor(challenge: ConsentChallenge);
82
+ }
83
+ /**
84
+ * Builds an MCP-spec {@link OAuthClientProvider} backed by Vercel
85
+ * Connect. The returned object delegates `tokens()` to
86
+ * {@link getTokenResponse} and `redirectToAuthorization` to
87
+ * {@link startAuthorization}. Connect owns client registration, PKCE,
88
+ * state, and the callback handshake server-side, so most of the
89
+ * `OAuthClientProvider` surface is intentionally a no-op.
90
+ *
91
+ * @param connector Vercel Connect connector UID (e.g. `oauth/linear`)
92
+ * or opaque connector id.
93
+ * @param params Token request parameters — always specify a
94
+ * `subject`; the three subject types
95
+ * (`'app'` / `'user'` / `'jwt-bearer'`) have distinct security
96
+ * semantics.
97
+ * @param options Optional adapter behavior overrides.
98
+ */
99
+ export declare function connectAuthProvider(connector: string, params: ConnectTokenParams, options?: ConnectAuthProviderOptions): OAuthClientProvider;
@@ -0,0 +1,148 @@
1
+ import { startAuthorization } from '../authorization.js';
2
+ import { ConnectorInstallationRequiredError, UserAuthorizationRequiredError, getTokenResponse, } from '../token.js';
3
+ /**
4
+ * Thrown by the {@link connectAuthProvider} default
5
+ * `onConsentRequired` handler when the user has no Connect grant for
6
+ * the configured subject. Catch at the boundary
7
+ * (`route handler` / `streamText` call site) and redirect to
8
+ * `error.url`.
9
+ */
10
+ export class ConsentRequiredError extends Error {
11
+ name = 'ConsentRequiredError';
12
+ connector;
13
+ subject;
14
+ url;
15
+ request;
16
+ verifier;
17
+ deviceCode;
18
+ expiresAt;
19
+ constructor(challenge) {
20
+ super(`Vercel Connect: user authorization required for connector "${challenge.connector}". Redirect the user to challenge.url to grant access.`);
21
+ this.connector = challenge.connector;
22
+ this.subject = challenge.subject;
23
+ this.url = challenge.url;
24
+ this.request = challenge.request;
25
+ this.verifier = challenge.verifier;
26
+ this.deviceCode = challenge.deviceCode;
27
+ this.expiresAt = challenge.expiresAt;
28
+ }
29
+ }
30
+ const EMPTY_CLIENT_METADATA = {
31
+ redirect_uris: [],
32
+ };
33
+ /**
34
+ * Builds an MCP-spec {@link OAuthClientProvider} backed by Vercel
35
+ * Connect. The returned object delegates `tokens()` to
36
+ * {@link getTokenResponse} and `redirectToAuthorization` to
37
+ * {@link startAuthorization}. Connect owns client registration, PKCE,
38
+ * state, and the callback handshake server-side, so most of the
39
+ * `OAuthClientProvider` surface is intentionally a no-op.
40
+ *
41
+ * @param connector Vercel Connect connector UID (e.g. `oauth/linear`)
42
+ * or opaque connector id.
43
+ * @param params Token request parameters — always specify a
44
+ * `subject`; the three subject types
45
+ * (`'app'` / `'user'` / `'jwt-bearer'`) have distinct security
46
+ * semantics.
47
+ * @param options Optional adapter behavior overrides.
48
+ */
49
+ export function connectAuthProvider(connector, params, options) {
50
+ const redirectUrl = options?.redirectUrl ?? '';
51
+ async function resolveVercelToken() {
52
+ const { vercelToken } = options ?? {};
53
+ if (typeof vercelToken === 'function') {
54
+ return vercelToken();
55
+ }
56
+ return vercelToken;
57
+ }
58
+ return {
59
+ async tokens() {
60
+ try {
61
+ const vercelToken = await resolveVercelToken();
62
+ const response = await getTokenResponse(connector, params, vercelToken !== undefined ? { vercelToken } : undefined);
63
+ const expiresInSeconds = Math.max(1, Math.floor((response.expiresAt - Date.now()) / 1000));
64
+ return {
65
+ access_token: response.token,
66
+ token_type: 'Bearer',
67
+ expires_in: expiresInSeconds,
68
+ };
69
+ }
70
+ catch (err) {
71
+ if (err instanceof UserAuthorizationRequiredError) {
72
+ // Returning undefined lets the MCP transport's auth()
73
+ // orchestrator trigger redirectToAuthorization below,
74
+ // where we surface the Connect consent URL.
75
+ return undefined;
76
+ }
77
+ if (err instanceof ConnectorInstallationRequiredError) {
78
+ // Configuration problem, not a per-user issue. Surface
79
+ // immediately rather than masking as a consent challenge.
80
+ throw err;
81
+ }
82
+ throw err;
83
+ }
84
+ },
85
+ async redirectToAuthorization(_authorizationUrl) {
86
+ // The URL argument is the MCP server's discovered authorization
87
+ // endpoint. We ignore it — Connect has its own consent URL
88
+ // backed by the connector's registered OAuth client.
89
+ const vercelToken = await resolveVercelToken();
90
+ const response = await startAuthorization(connector, params, {
91
+ ...(vercelToken !== undefined && { vercelToken }),
92
+ // Forward the post-consent return URL so the user lands back
93
+ // in the app. Falsy (the default empty string) => Connect uses
94
+ // the connector's registered redirect.
95
+ ...(redirectUrl && { callbackUrl: redirectUrl }),
96
+ ...(options?.deviceCode && { deviceCode: true }),
97
+ });
98
+ const challenge = {
99
+ connector,
100
+ subject: params.subject,
101
+ url: response.url,
102
+ request: response.request,
103
+ verifier: response.verifier,
104
+ deviceCode: response.deviceCode,
105
+ expiresAt: response.expiresAt,
106
+ };
107
+ if (options?.onConsentRequired) {
108
+ await options.onConsentRequired(challenge);
109
+ return;
110
+ }
111
+ throw new ConsentRequiredError(challenge);
112
+ },
113
+ saveTokens(_tokens) {
114
+ // No-op: Connect owns token persistence server-side. The
115
+ // in-memory LRU cache in @vercel/connect's token module
116
+ // handles per-request reuse.
117
+ },
118
+ saveCodeVerifier(_codeVerifier) {
119
+ // No-op: Connect owns PKCE.
120
+ },
121
+ codeVerifier() {
122
+ // The MCP transport never reaches this when tokens() /
123
+ // redirectToAuthorization are wired correctly. If a future
124
+ // transport change starts calling it, throw loudly rather
125
+ // than fabricate a bogus verifier.
126
+ throw new Error('@vercel/connect: OAuthClientProvider.codeVerifier() is unsupported. Vercel Connect owns the PKCE flow server-side; this method should never be invoked by a correctly-configured MCP transport.');
127
+ },
128
+ get redirectUrl() {
129
+ // Same value forwarded to Connect as the post-consent return
130
+ // URL. Surfaced here to satisfy the OAuthClientProvider
131
+ // contract; the standard flow that reads it is never triggered.
132
+ return redirectUrl;
133
+ },
134
+ get clientMetadata() {
135
+ // Returned only during dynamic client registration, which we
136
+ // never trigger. A minimal but valid value satisfies the
137
+ // contract.
138
+ return EMPTY_CLIENT_METADATA;
139
+ },
140
+ clientInformation() {
141
+ // The connector UID stands in as the logical client id. The
142
+ // MCP transport uses this for cache keys and debug output;
143
+ // tying it to the Connect identifier is more useful than
144
+ // returning a synthetic value.
145
+ return { client_id: connector };
146
+ },
147
+ };
148
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Public surface of the `@vercel/connect/mcp` subpath.
3
+ *
4
+ * Holds the MCP-spec `OAuthClientProvider` adapter for Vercel
5
+ * Connect. Plug the returned object into any MCP client that
6
+ * consumes the spec — `@ai-sdk/mcp`, the official
7
+ * `@modelcontextprotocol/typescript-sdk`, Mastra's MCP client,
8
+ * etc. AI SDK consumers should import the same function from
9
+ * `@vercel/connect/ai-sdk` instead; that subpath re-exports from
10
+ * here.
11
+ *
12
+ * `@ai-sdk/mcp` is an optional peer dependency: importing this
13
+ * entrypoint requires it to be installed in the consumer project,
14
+ * but the rest of `@vercel/connect` works without it.
15
+ *
16
+ * ```ts
17
+ * import { createMCPClient } from '@ai-sdk/mcp';
18
+ * import { connectAuthProvider } from '@vercel/connect/mcp';
19
+ *
20
+ * const mcpClient = await createMCPClient({
21
+ * transport: {
22
+ * type: 'http',
23
+ * url: 'https://mcp.linear.app',
24
+ * authProvider: connectAuthProvider('oauth/linear', {
25
+ * subject: { type: 'user', id: userId },
26
+ * scopes: ['read'],
27
+ * }),
28
+ * },
29
+ * });
30
+ * ```
31
+ */
32
+ export { connectAuthProvider, ConsentRequiredError, type ConnectAuthProviderOptions, type ConsentChallenge, } from './connect-auth-provider.js';
33
+ export { ConnectError, ConnectorInstallationRequiredError, NoValidTokenError, UserAuthorizationRequiredError, type ConnectErrorOptions, type ConnectTokenParams, type ConnectTokenSubject, type ConnectVendorErrorPayload, } from '../token.js';
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Public surface of the `@vercel/connect/mcp` subpath.
3
+ *
4
+ * Holds the MCP-spec `OAuthClientProvider` adapter for Vercel
5
+ * Connect. Plug the returned object into any MCP client that
6
+ * consumes the spec — `@ai-sdk/mcp`, the official
7
+ * `@modelcontextprotocol/typescript-sdk`, Mastra's MCP client,
8
+ * etc. AI SDK consumers should import the same function from
9
+ * `@vercel/connect/ai-sdk` instead; that subpath re-exports from
10
+ * here.
11
+ *
12
+ * `@ai-sdk/mcp` is an optional peer dependency: importing this
13
+ * entrypoint requires it to be installed in the consumer project,
14
+ * but the rest of `@vercel/connect` works without it.
15
+ *
16
+ * ```ts
17
+ * import { createMCPClient } from '@ai-sdk/mcp';
18
+ * import { connectAuthProvider } from '@vercel/connect/mcp';
19
+ *
20
+ * const mcpClient = await createMCPClient({
21
+ * transport: {
22
+ * type: 'http',
23
+ * url: 'https://mcp.linear.app',
24
+ * authProvider: connectAuthProvider('oauth/linear', {
25
+ * subject: { type: 'user', id: userId },
26
+ * scopes: ['read'],
27
+ * }),
28
+ * },
29
+ * });
30
+ * ```
31
+ */
32
+ export { connectAuthProvider, ConsentRequiredError, } from './connect-auth-provider.js';
33
+ export { ConnectError, ConnectorInstallationRequiredError, NoValidTokenError, UserAuthorizationRequiredError, } from '../token.js';
package/dist/token.d.ts CHANGED
@@ -22,6 +22,10 @@ export interface ConnectTokenParams {
22
22
  subject: ConnectTokenSubject;
23
23
  installationId?: string;
24
24
  audience?: string[];
25
+ /**
26
+ * Access scopes to request. Use `['*']` to request the default scopes for
27
+ * the specified subject type.
28
+ */
25
29
  scopes?: string[];
26
30
  resources?: string[];
27
31
  authorizationDetails?: ConnectAuthorizationDetail[];
@@ -79,4 +83,8 @@ export interface ConnectOptions {
79
83
  }
80
84
  export declare function getToken(connector: string, params: ConnectTokenParams, options?: ConnectOptions): Promise<string>;
81
85
  export declare function getTokenResponse(connector: string, params: ConnectTokenParams, options?: ConnectOptions): Promise<ConnectTokenResponse>;
86
+ export declare function revokeToken(connector: string, params: {
87
+ subject: ConnectTokenSubject;
88
+ installationId?: string;
89
+ }, options?: ConnectOptions): Promise<void>;
82
90
  export declare function createConnectErrorFromResponse(response: Response, fallbackMessage: string): Promise<ConnectError>;
package/dist/token.js CHANGED
@@ -68,6 +68,23 @@ export async function getTokenResponse(connector, params, options) {
68
68
  cache.set(cacheKey, { response: data, lastUsed: Date.now() });
69
69
  return data;
70
70
  }
71
+ export async function revokeToken(connector, params, options) {
72
+ const vercelToken = options?.vercelToken ?? (await getVercelOidcToken());
73
+ const endpoint = `https://api.vercel.com/v1/connect/connectors/${encodeURIComponent(connector)}/tokens`;
74
+ const response = await fetch(endpoint, {
75
+ method: 'DELETE',
76
+ headers: {
77
+ Accept: 'application/json',
78
+ 'Content-Type': 'application/json',
79
+ Authorization: `Bearer ${vercelToken}`,
80
+ },
81
+ body: JSON.stringify(params),
82
+ });
83
+ if (!response.ok) {
84
+ throw await createConnectErrorFromResponse(response, 'Failed to revoke token');
85
+ }
86
+ cache.clear();
87
+ }
71
88
  const DEFAULT_VALIDITY_BUFFER_MS = 30_000;
72
89
  const MAX_CACHE_SIZE = 100;
73
90
  const cache = new Map();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/connect",
3
- "version": "0.1.3",
3
+ "version": "0.2.1",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "repository": {
@@ -13,9 +13,9 @@
13
13
  "types": "./dist/index.d.ts",
14
14
  "default": "./dist/index.js"
15
15
  },
16
- "./ash": {
17
- "types": "./dist/ash/index.d.ts",
18
- "default": "./dist/ash/index.js"
16
+ "./eve": {
17
+ "types": "./dist/eve/index.d.ts",
18
+ "default": "./dist/eve/index.js"
19
19
  },
20
20
  "./betterauth": {
21
21
  "types": "./dist/betterauth/index.d.ts",
@@ -24,34 +24,52 @@
24
24
  "./authjs": {
25
25
  "types": "./dist/authjs/index.d.ts",
26
26
  "default": "./dist/authjs/index.js"
27
+ },
28
+ "./mcp": {
29
+ "types": "./dist/mcp/index.d.ts",
30
+ "default": "./dist/mcp/index.js"
31
+ },
32
+ "./ai-sdk": {
33
+ "types": "./dist/ai-sdk/index.d.ts",
34
+ "default": "./dist/ai-sdk/index.js"
27
35
  }
28
36
  },
29
37
  "files": [
30
38
  "dist"
31
39
  ],
32
40
  "dependencies": {
33
- "@vercel/oidc": "3.6.0"
41
+ "@vercel/oidc": "3.6.1"
34
42
  },
35
43
  "peerDependencies": {
44
+ "@ai-sdk/mcp": "^1 || ^2",
36
45
  "@auth/core": ">=0.37.0",
46
+ "ai": "^6 || ^7",
37
47
  "better-auth": ">=1.5.0",
38
- "experimental-ash": ">=0.8.2"
48
+ "eve": ">=0.6.0-beta.1"
39
49
  },
40
50
  "peerDependenciesMeta": {
51
+ "@ai-sdk/mcp": {
52
+ "optional": true
53
+ },
41
54
  "@auth/core": {
42
55
  "optional": true
43
56
  },
57
+ "ai": {
58
+ "optional": true
59
+ },
44
60
  "better-auth": {
45
61
  "optional": true
46
62
  },
47
- "experimental-ash": {
63
+ "eve": {
48
64
  "optional": true
49
65
  }
50
66
  },
51
67
  "devDependencies": {
68
+ "@ai-sdk/mcp": "2.0.0-beta.37",
52
69
  "@auth/core": "0.37.4",
70
+ "ai": "7.0.0-beta.116",
53
71
  "better-auth": "1.5.5",
54
- "experimental-ash": "0.31.0",
72
+ "eve": "0.6.0-beta.1",
55
73
  "typescript": "^5"
56
74
  },
57
75
  "private": false,
@@ -60,6 +78,9 @@
60
78
  },
61
79
  "scripts": {
62
80
  "build": "tsc",
63
- "typecheck": "tsc --noEmit"
81
+ "typecheck": "tsc --noEmit",
82
+ "type-check": "tsc --noEmit",
83
+ "test": "vitest run --config ../../vitest.config.mts",
84
+ "vitest-unit": "vitest run --config ../../vitest.config.mts"
64
85
  }
65
86
  }
@@ -1,11 +0,0 @@
1
- /**
2
- * Public surface of the `@vercel/connect/ash` subpath.
3
- *
4
- * Holds Ash-specific helpers that adapt the Vercel Connect SDK to
5
- * Ash's connection runtime. Each helper lives in its own module;
6
- * this barrel re-exports the public API so consumers import
7
- * everything from `@vercel/connect/ash`.
8
- */
9
- export { connect, type AshAuthorizationInput, type AshAuthorizationOptions, type AshConnectAuthorizationDefinition, type ConnectAuthorizationPhase, type ConnectAuthorizationState, type VercelConnectMetadata, } from './connection-authorization.js';
10
- export { CONNECT_OAUTH_ISSUER, connectOAuth, type ConnectOAuthAudienceEnvironment, type ConnectOAuthEnvironment, type ConnectOAuthOptions, } from './connect-oauth.js';
11
- export { connectSlackCredentials } from './slack-credentials.js';
package/dist/ash/index.js DELETED
@@ -1,11 +0,0 @@
1
- /**
2
- * Public surface of the `@vercel/connect/ash` subpath.
3
- *
4
- * Holds Ash-specific helpers that adapt the Vercel Connect SDK to
5
- * Ash's connection runtime. Each helper lives in its own module;
6
- * this barrel re-exports the public API so consumers import
7
- * everything from `@vercel/connect/ash`.
8
- */
9
- export { connect, } from './connection-authorization.js';
10
- export { CONNECT_OAUTH_ISSUER, connectOAuth, } from './connect-oauth.js';
11
- export { connectSlackCredentials } from './slack-credentials.js';