@vercel/connect 0.0.4-alpha.2

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.
@@ -0,0 +1,10 @@
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 ConnectAuthorizationPhase, type ConnectAuthorizationState, } from "./connection-authorization.js";
10
+ export { connectSlackCredentials } from "./slack-credentials.js";
@@ -0,0 +1,10 @@
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 { connectSlackCredentials } from "./slack-credentials.js";
@@ -0,0 +1,25 @@
1
+ import type { SlackChannelCredentials } from "experimental-ash/channels/slack";
2
+ /**
3
+ * Build {@link SlackChannelCredentials} backed by a Vercel Connect
4
+ * connector that stores a Slack workspace's bot token.
5
+ *
6
+ * The returned `botToken` is a function form, invoked once per
7
+ * inbound webhook so the chat adapter always picks up a fresh token
8
+ * from Vercel Connect (rotation, refresh, multi-workspace tenancy
9
+ * are all handled server-side).
10
+ *
11
+ * Slack bot tokens are app-scoped — one token per workspace install,
12
+ * shared across every end-user — so this helper calls Vercel Connect
13
+ * with `subject: { type: "app" }`. End-user identity (per-user OAuth
14
+ * into Slack) is a separate concern handled elsewhere.
15
+ *
16
+ * ```ts
17
+ * import { slackRoute } from "experimental-ash/channels/slack";
18
+ * import { connectSlackCredentials } from "@vercel/connect/ash";
19
+ *
20
+ * export default slackRoute({
21
+ * credentials: connectSlackCredentials("scl_..."),
22
+ * });
23
+ * ```
24
+ */
25
+ export declare function connectSlackCredentials(connector: string): SlackChannelCredentials;
@@ -0,0 +1,31 @@
1
+ import { getToken } from "../index.js";
2
+ import { vercelOidc } from "experimental-ash/channels/auth";
3
+ /**
4
+ * Build {@link SlackChannelCredentials} backed by a Vercel Connect
5
+ * connector that stores a Slack workspace's bot token.
6
+ *
7
+ * The returned `botToken` is a function form, invoked once per
8
+ * inbound webhook so the chat adapter always picks up a fresh token
9
+ * from Vercel Connect (rotation, refresh, multi-workspace tenancy
10
+ * are all handled server-side).
11
+ *
12
+ * Slack bot tokens are app-scoped — one token per workspace install,
13
+ * shared across every end-user — so this helper calls Vercel Connect
14
+ * with `subject: { type: "app" }`. End-user identity (per-user OAuth
15
+ * into Slack) is a separate concern handled elsewhere.
16
+ *
17
+ * ```ts
18
+ * import { slackRoute } from "experimental-ash/channels/slack";
19
+ * import { connectSlackCredentials } from "@vercel/connect/ash";
20
+ *
21
+ * export default slackRoute({
22
+ * credentials: connectSlackCredentials("scl_..."),
23
+ * });
24
+ * ```
25
+ */
26
+ export function connectSlackCredentials(connector) {
27
+ return {
28
+ botToken: () => getToken(connector, { subject: { type: "app" } }),
29
+ webhookVerifier: vercelOidc(),
30
+ };
31
+ }
@@ -0,0 +1,43 @@
1
+ import type { OAuth2Config } from "@auth/core/providers";
2
+ /** Userinfo payload returned by Vercel Connect's OIDC userinfo endpoint. */
3
+ export interface ConnectProfile {
4
+ sub: string;
5
+ email?: string;
6
+ email_verified?: boolean;
7
+ name?: string;
8
+ picture?: string;
9
+ }
10
+ /** Options accepted by {@link connect}. */
11
+ export interface AuthJsConnectOptions {
12
+ /**
13
+ * Provider id surfaced by Auth.js (e.g. `"slack-via-connect"`).
14
+ * Becomes the path segment in callback URLs and the `provider`
15
+ * field on accounts.
16
+ */
17
+ readonly id: string;
18
+ /** Human-readable display name used by Auth.js sign-in UIs. */
19
+ readonly name: string;
20
+ /**
21
+ * Vercel Connect OAuth connector identifier. Accepts either the
22
+ * opaque service connector key (`scl_...`) or the human-readable
23
+ * UID (`oauth/mcp-linear-app`).
24
+ */
25
+ readonly connector: string;
26
+ /**
27
+ * Scopes to request. `offline_access` is added automatically so
28
+ * the Vercel Connect side can mint refresh tokens. Defaults to
29
+ * `["*"]`.
30
+ */
31
+ readonly scopes?: readonly string[];
32
+ /**
33
+ * Override the Vercel OIDC token fetcher. Defaults to
34
+ * {@link getVercelOidcToken} from `@vercel/oidc`. Useful for tests
35
+ * or non-Vercel runtimes that mint the OIDC token differently.
36
+ */
37
+ readonly getVercelOidcToken?: () => Promise<string>;
38
+ }
39
+ /**
40
+ * Builds an Auth.js `OAuth2Config` for Vercel Connect. Push the
41
+ * result into `AuthConfig.providers`.
42
+ */
43
+ export declare function connect(options: AuthJsConnectOptions): OAuth2Config<ConnectProfile>;
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Auth.js (NextAuth core) adapter helper for `@vercel/connect`.
3
+ *
4
+ * {@link connect} returns an `OAuth2Config` provider entry for use
5
+ * in `AuthConfig.providers`. Vercel Connect's OAuth client
6
+ * authentication is non-standard — the "client secret" is a
7
+ * per-request Vercel OIDC token — so we declare
8
+ * `token_endpoint_auth_method: "none"` and inject the real
9
+ * Authorization headers via the `customFetch` symbol.
10
+ *
11
+ * ```ts
12
+ * import type { AuthConfig } from "@auth/core";
13
+ * import { connect } from "@vercel/connect/authjs";
14
+ *
15
+ * export const authConfig: AuthConfig = {
16
+ * providers: [
17
+ * connect({
18
+ * id: "slack",
19
+ * name: "Slack",
20
+ * connector: process.env.CONNECTOR_SLACK!,
21
+ * }),
22
+ * ],
23
+ * };
24
+ * ```
25
+ */
26
+ import { customFetch } from "@auth/core";
27
+ import { getVercelOidcToken } from "@vercel/oidc";
28
+ import { tryGetVercelTeamId, withTeamId } from "../internal/team-id.js";
29
+ const CONNECT_AUTHORIZATION_URL = "https://vercel.com/api/connex/oauth/authorize";
30
+ const CONNECT_TOKEN_URL = "https://vercel.com/api/connex/oauth/token";
31
+ const CONNECT_USERINFO_URL = "https://vercel.com/api/connex/oauth/userinfo";
32
+ /**
33
+ * Builds an Auth.js `OAuth2Config` for Vercel Connect. Push the
34
+ * result into `AuthConfig.providers`.
35
+ */
36
+ export function connect(options) {
37
+ const fetchVercelToken = options.getVercelOidcToken ?? getVercelOidcToken;
38
+ const scope = Array.from(new Set([...(options.scopes ?? ["*"]), "offline_access"])).join(" ");
39
+ return {
40
+ id: options.id,
41
+ name: options.name,
42
+ type: "oauth",
43
+ clientId: options.connector,
44
+ // The token endpoint expects client_secret_basic, but the secret
45
+ // is a Vercel OIDC token that has to be fetched per-request. We
46
+ // rely on the customFetch hook below to inject the real
47
+ // Authorization header — Auth.js skips building one because we
48
+ // declared "none" here.
49
+ client: { token_endpoint_auth_method: "none" },
50
+ authorization: {
51
+ // Best-effort: scope the Vercel Connect consent UI to the
52
+ // deployment's Vercel team when we can read it from the OIDC
53
+ // token. Falls back to the unqualified URL when the token isn't
54
+ // present (e.g. running outside Vercel).
55
+ url: withTeamId(CONNECT_AUTHORIZATION_URL, tryGetVercelTeamId()),
56
+ params: { scope },
57
+ },
58
+ token: CONNECT_TOKEN_URL,
59
+ userinfo: CONNECT_USERINFO_URL,
60
+ checks: ["pkce"],
61
+ profile(profile) {
62
+ return {
63
+ id: profile.sub,
64
+ name: profile.name,
65
+ email: profile.email ?? null,
66
+ image: profile.picture,
67
+ };
68
+ },
69
+ [customFetch]: async (input, init) => {
70
+ const url = typeof input === "string"
71
+ ? input
72
+ : input instanceof URL
73
+ ? input.href
74
+ : input.url;
75
+ if (url.startsWith(CONNECT_TOKEN_URL)) {
76
+ const vercelToken = await fetchVercelToken();
77
+ const credentials = `${encodeURIComponent(options.connector)}:${encodeURIComponent(vercelToken)}`;
78
+ const headers = new Headers(init?.headers);
79
+ headers.set("authorization", `Basic ${btoa(credentials)}`);
80
+ return fetch(input, { ...init, headers });
81
+ }
82
+ if (url.startsWith(CONNECT_USERINFO_URL)) {
83
+ const headers = new Headers(init?.headers);
84
+ const accessToken = (headers.get("authorization") ?? "").replace(/^Bearer\s+/i, "");
85
+ const vercelToken = await fetchVercelToken();
86
+ const triple = [options.connector, vercelToken, accessToken]
87
+ .map(encodeURIComponent)
88
+ .join(":");
89
+ headers.set("authorization", `Bearer ${btoa(triple)}`);
90
+ return fetch(input, { ...init, headers });
91
+ }
92
+ return fetch(input, init);
93
+ },
94
+ };
95
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Public surface of the `@vercel/connect/authjs` subpath.
3
+ *
4
+ * Holds Auth.js (NextAuth core) helpers for adapting Vercel Connect
5
+ * to the `OAuth2Config` provider shape. `@auth/core` is an optional
6
+ * peer dependency: importing this entrypoint requires it to be
7
+ * installed in the consumer project, but the rest of
8
+ * `@vercel/connect` works without it.
9
+ */
10
+ export { connect, type AuthJsConnectOptions, type ConnectProfile, } from "./connect-provider.js";
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Public surface of the `@vercel/connect/authjs` subpath.
3
+ *
4
+ * Holds Auth.js (NextAuth core) helpers for adapting Vercel Connect
5
+ * to the `OAuth2Config` provider shape. `@auth/core` is an optional
6
+ * peer dependency: importing this entrypoint requires it to be
7
+ * installed in the consumer project, but the rest of
8
+ * `@vercel/connect` works without it.
9
+ */
10
+ export { connect, } from "./connect-provider.js";
@@ -0,0 +1,12 @@
1
+ import type { ConnectTokenParams } from "./token.js";
2
+ export interface ConnectAuthorizationOptions {
3
+ vercelToken?: string;
4
+ callbackUrl?: string;
5
+ webhook?: string;
6
+ }
7
+ export interface ConnectAuthorizationResponse {
8
+ request: string;
9
+ verifier: string;
10
+ url: string;
11
+ }
12
+ export declare function startAuthorization(connector: string, params: ConnectTokenParams, options?: ConnectAuthorizationOptions): Promise<ConnectAuthorizationResponse>;
@@ -0,0 +1,68 @@
1
+ import { getVercelOidcToken } from "@vercel/oidc";
2
+ export async function startAuthorization(connector, params, options) {
3
+ if (!connector) {
4
+ throw new Error("connector is required");
5
+ }
6
+ if (options?.callbackUrl !== undefined) {
7
+ validateCallbackUrl(options.callbackUrl);
8
+ }
9
+ if (options?.webhook !== undefined) {
10
+ validateWebhookUrl(options.webhook);
11
+ }
12
+ const vercelToken = options?.vercelToken ?? (await getVercelOidcToken());
13
+ const endpoint = `https://api.vercel.com/v1/connex/authorize/${encodeURIComponent(connector)}`;
14
+ const body = {
15
+ ...params,
16
+ ...(options?.callbackUrl !== undefined && {
17
+ returnUrl: options.callbackUrl,
18
+ }),
19
+ ...(options?.webhook !== undefined && { webhook: options.webhook }),
20
+ };
21
+ const response = await fetch(endpoint, {
22
+ method: "POST",
23
+ headers: {
24
+ Accept: "application/json",
25
+ "Content-Type": "application/json",
26
+ Authorization: `Bearer ${vercelToken}`,
27
+ },
28
+ body: JSON.stringify(body),
29
+ });
30
+ if (!response.ok) {
31
+ let errorText;
32
+ try {
33
+ errorText = await response.text();
34
+ }
35
+ catch { }
36
+ throw new Error(`Failed to start authorization: ${response.status} ${response.statusText}${errorText ? ` - ${errorText}` : ""}`);
37
+ }
38
+ const { request, verifier, url } = await response.json();
39
+ return { request, verifier, url };
40
+ }
41
+ function validateCallbackUrl(value) {
42
+ let url;
43
+ try {
44
+ url = new URL(value);
45
+ }
46
+ catch {
47
+ throw new Error(`Invalid callbackUrl: ${value}`);
48
+ }
49
+ if (url.protocol === "https:")
50
+ return;
51
+ if (url.protocol === "http:" &&
52
+ (url.hostname === "localhost" || url.hostname === "127.0.0.1")) {
53
+ return;
54
+ }
55
+ throw new Error(`callbackUrl must be https:// or http://localhost, got: ${value}`);
56
+ }
57
+ function validateWebhookUrl(value) {
58
+ let url;
59
+ try {
60
+ url = new URL(value);
61
+ }
62
+ catch {
63
+ throw new Error(`Invalid webhook URL: ${value}`);
64
+ }
65
+ if (url.protocol !== "https:") {
66
+ throw new Error(`webhook must be https://, got: ${value}`);
67
+ }
68
+ }
@@ -0,0 +1,32 @@
1
+ import type { GenericOAuthConfig } from "better-auth/plugins/generic-oauth";
2
+ /** Options accepted by {@link connect}. */
3
+ export interface BetterAuthConnectOptions {
4
+ /**
5
+ * Provider id used by Better Auth's generic OAuth plugin (e.g.
6
+ * `"slack"`). Surfaces in the sign-in URL and account
7
+ * rows; pick something stable that names the upstream IdP.
8
+ */
9
+ readonly providerId: string;
10
+ /**
11
+ * Vercel Connect OAuth connector identifier. Accepts either the
12
+ * opaque service connector key (`scl_...`) or the human-readable
13
+ * UID (`oauth/mcp-linear-app`).
14
+ */
15
+ readonly connector: string;
16
+ /**
17
+ * Scopes to request. `offline_access` is added automatically so the
18
+ * Vercel Connect side can mint refresh tokens. Defaults to `["*"]`.
19
+ */
20
+ readonly scopes?: readonly string[];
21
+ /**
22
+ * Override the Vercel OIDC token fetcher. Defaults to
23
+ * {@link getVercelOidcToken} from `@vercel/oidc`. Useful for tests
24
+ * or non-Vercel runtimes that mint the OIDC token differently.
25
+ */
26
+ readonly getVercelOidcToken?: () => Promise<string>;
27
+ }
28
+ /**
29
+ * Builds a `GenericOAuthConfig` entry for Vercel Connect. Pass the
30
+ * result into `genericOAuth({ config: [...] })`.
31
+ */
32
+ export declare function connect(options: BetterAuthConnectOptions): GenericOAuthConfig;
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Better Auth adapter helper for `@vercel/connect`.
3
+ *
4
+ * {@link connect} returns a `GenericOAuthConfig` entry that drops
5
+ * into `genericOAuth({ config: [...] })` from
6
+ * `better-auth/plugins/generic-oauth`. Vercel Connect's OAuth client
7
+ * authentication is non-standard — the "client secret" is a Vercel
8
+ * OIDC token that has to be fetched per-request — so we override
9
+ * `getToken` and `getUserInfo` to inject the right Authorization
10
+ * headers instead of relying on Better Auth's built-in flow.
11
+ *
12
+ * ```ts
13
+ * import { betterAuth } from "better-auth";
14
+ * import { genericOAuth } from "better-auth/plugins/generic-oauth";
15
+ * import { connect } from "@vercel/connect/betterauth";
16
+ *
17
+ * export const auth = betterAuth({
18
+ * plugins: [
19
+ * genericOAuth({
20
+ * config: [
21
+ * connect({
22
+ * providerId: "slack",
23
+ * connector: process.env.CONNECTOR_SLACK!,
24
+ * }),
25
+ * ],
26
+ * }),
27
+ * ],
28
+ * });
29
+ * ```
30
+ */
31
+ import { getVercelOidcToken } from "@vercel/oidc";
32
+ import { getOAuth2Tokens } from "better-auth/oauth2";
33
+ import { tryGetVercelTeamId, withTeamId } from "../internal/team-id.js";
34
+ const CONNECT_AUTHORIZATION_URL = "https://vercel.com/api/connex/oauth/authorize";
35
+ const CONNECT_TOKEN_URL = "https://vercel.com/api/connex/oauth/token";
36
+ const CONNECT_USERINFO_URL = "https://vercel.com/api/connex/oauth/userinfo";
37
+ /**
38
+ * Builds a `GenericOAuthConfig` entry for Vercel Connect. Pass the
39
+ * result into `genericOAuth({ config: [...] })`.
40
+ */
41
+ export function connect(options) {
42
+ const fetchVercelToken = options.getVercelOidcToken ?? getVercelOidcToken;
43
+ const scopes = Array.from(new Set([...(options.scopes ?? ["*"]), "offline_access"]));
44
+ return {
45
+ providerId: options.providerId,
46
+ clientId: options.connector,
47
+ // Best-effort: scope the Vercel Connect consent UI to the
48
+ // deployment's Vercel team when we can read it from the OIDC
49
+ // token. Falls back to the unqualified URL when the token isn't
50
+ // present (e.g. running outside Vercel).
51
+ authorizationUrl: withTeamId(CONNECT_AUTHORIZATION_URL, tryGetVercelTeamId()),
52
+ scopes,
53
+ pkce: true,
54
+ tokenUrl: CONNECT_TOKEN_URL,
55
+ getToken: async ({ code, redirectURI, codeVerifier, deviceId }) => {
56
+ const vercelToken = await fetchVercelToken();
57
+ const credentials = `${encodeURIComponent(options.connector)}:${encodeURIComponent(vercelToken)}`;
58
+ const basicAuth = btoa(credentials);
59
+ const body = new URLSearchParams({
60
+ grant_type: "authorization_code",
61
+ code,
62
+ redirect_uri: redirectURI,
63
+ });
64
+ if (codeVerifier)
65
+ body.set("code_verifier", codeVerifier);
66
+ if (deviceId)
67
+ body.set("device_id", deviceId);
68
+ const response = await fetch(CONNECT_TOKEN_URL, {
69
+ method: "POST",
70
+ headers: {
71
+ "Content-Type": "application/x-www-form-urlencoded",
72
+ Accept: "application/json",
73
+ Authorization: `Basic ${basicAuth}`,
74
+ },
75
+ body: body.toString(),
76
+ });
77
+ if (!response.ok) {
78
+ throw new Error(`Failed to exchange Vercel Connect authorization code: ${response.status} ${response.statusText}: ${await response.text()}`);
79
+ }
80
+ return getOAuth2Tokens(await response.json());
81
+ },
82
+ getUserInfo: async (tokens) => {
83
+ if (!tokens.accessToken) {
84
+ throw new Error("Missing access token for Vercel Connect userinfo request");
85
+ }
86
+ const vercelToken = await fetchVercelToken();
87
+ const triple = [options.connector, vercelToken, tokens.accessToken]
88
+ .map(encodeURIComponent)
89
+ .join(":");
90
+ const bearerToken = btoa(triple);
91
+ const response = await fetch(CONNECT_USERINFO_URL, {
92
+ headers: { Authorization: `Bearer ${bearerToken}` },
93
+ });
94
+ if (!response.ok) {
95
+ throw new Error(`Failed to fetch Vercel Connect user info: ${response.status} ${response.statusText}: ${await response.text()}`);
96
+ }
97
+ const user = (await response.json());
98
+ return {
99
+ id: user.sub,
100
+ email: user.email,
101
+ emailVerified: user.email_verified ?? false,
102
+ name: user.name,
103
+ image: user.picture,
104
+ };
105
+ },
106
+ };
107
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Public surface of the `@vercel/connect/betterauth` subpath.
3
+ *
4
+ * Holds Better Auth-specific helpers for adapting Vercel Connect to
5
+ * the `genericOAuth` plugin. `better-auth` is an optional peer
6
+ * dependency: importing this entrypoint requires it to be installed
7
+ * in the consumer project, but the rest of `@vercel/connect` works
8
+ * without it.
9
+ */
10
+ export { connect, type BetterAuthConnectOptions } from "./connect-provider.js";
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Public surface of the `@vercel/connect/betterauth` subpath.
3
+ *
4
+ * Holds Better Auth-specific helpers for adapting Vercel Connect to
5
+ * the `genericOAuth` plugin. `better-auth` is an optional peer
6
+ * dependency: importing this entrypoint requires it to be installed
7
+ * in the consumer project, but the rest of `@vercel/connect` works
8
+ * without it.
9
+ */
10
+ export { connect } from "./connect-provider.js";
@@ -0,0 +1,2 @@
1
+ export { getToken, getTokenResponse, NoValidTokenError, UserAuthorizationRequiredError, ConnectorInstallationRequiredError, type ConnectOptions, type ConnectTokenParams, type ConnectTokenResponse, } from "./token.js";
2
+ export { startAuthorization, type ConnectAuthorizationOptions, type ConnectAuthorizationResponse, } from "./authorization.js";
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { getToken, getTokenResponse, NoValidTokenError, UserAuthorizationRequiredError, ConnectorInstallationRequiredError, } from "./token.js";
2
+ export { startAuthorization, } from "./authorization.js";
@@ -0,0 +1,3 @@
1
+ export declare function tryGetVercelTeamId(): string | undefined;
2
+ export declare function extractTeamIdFromOidcToken(token: string): string | undefined;
3
+ export declare function withTeamId(baseUrl: string, teamId: string | undefined): string;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Best-effort Vercel team-id extraction for the OAuth adapters.
3
+ *
4
+ * Vercel Connect's `/api/connex/oauth/authorize` endpoint accepts an
5
+ * optional `?teamId=...` query parameter that scopes the consent UI
6
+ * to a specific team. The team id lives inside the Vercel OIDC
7
+ * token's `owner_id` claim, so we decode the JWT payload (no
8
+ * signature verification — we're reading our own token) and pull it
9
+ * out.
10
+ *
11
+ * Failure is silent: the helper returns `undefined` if the token
12
+ * isn't available (e.g. running outside Vercel) or the payload can't
13
+ * be decoded. Adapters then fall back to an unqualified
14
+ * authorization URL.
15
+ */
16
+ import { getVercelOidcTokenSync } from "@vercel/oidc";
17
+ export function tryGetVercelTeamId() {
18
+ let token;
19
+ try {
20
+ token = getVercelOidcTokenSync();
21
+ }
22
+ catch {
23
+ return undefined;
24
+ }
25
+ return extractTeamIdFromOidcToken(token);
26
+ }
27
+ export function extractTeamIdFromOidcToken(token) {
28
+ try {
29
+ const parts = token.split(".");
30
+ if (parts.length < 2)
31
+ return undefined;
32
+ const padded = parts[1].replace(/-/g, "+").replace(/_/g, "/");
33
+ const padLen = (4 - (padded.length % 4)) % 4;
34
+ const claims = JSON.parse(atob(padded + "=".repeat(padLen)));
35
+ return typeof claims.owner_id === "string" ? claims.owner_id : undefined;
36
+ }
37
+ catch {
38
+ return undefined;
39
+ }
40
+ }
41
+ export function withTeamId(baseUrl, teamId) {
42
+ if (!teamId)
43
+ return baseUrl;
44
+ const url = new URL(baseUrl);
45
+ url.searchParams.set("teamId", teamId);
46
+ return url.toString();
47
+ }
@@ -0,0 +1,47 @@
1
+ export interface ConnectTokenParams {
2
+ subject: {
3
+ type: "app";
4
+ } | {
5
+ type: "user";
6
+ id: string;
7
+ issuer?: string;
8
+ };
9
+ installationId?: string;
10
+ audience?: string[];
11
+ scopes?: string[];
12
+ resources?: string[];
13
+ authorizationDetails?: Array<{
14
+ type: string;
15
+ } & Record<string, unknown>>;
16
+ /**
17
+ * Buffer time in milliseconds before token expiration to consider it invalid.
18
+ * If the token expires within this buffer, it will be refreshed.
19
+ * Defaults to 30 seconds.
20
+ */
21
+ validityBufferMs?: number;
22
+ }
23
+ export interface ConnectTokenResponse {
24
+ token: string;
25
+ /** Token expiration timestamp in milliseconds since epoch. */
26
+ expiresAt: number;
27
+ name?: string;
28
+ installationId?: string;
29
+ tenantId?: string;
30
+ externalSubject?: string;
31
+ /** Driver-specific metadata stored during OAuth */
32
+ metadata?: Record<string, unknown>;
33
+ }
34
+ export declare class NoValidTokenError extends Error {
35
+ constructor(message: string);
36
+ }
37
+ export declare class UserAuthorizationRequiredError extends Error {
38
+ constructor(message: string);
39
+ }
40
+ export declare class ConnectorInstallationRequiredError extends Error {
41
+ constructor(message: string);
42
+ }
43
+ export interface ConnectOptions {
44
+ vercelToken?: string;
45
+ }
46
+ export declare function getToken(connector: string, params: ConnectTokenParams, options?: ConnectOptions): Promise<string>;
47
+ export declare function getTokenResponse(connector: string, params: ConnectTokenParams, options?: ConnectOptions): Promise<ConnectTokenResponse>;