@vercel/connect 0.9.0 → 1.0.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/authorization.d.ts +6 -0
- package/dist/authorization.js +5 -2
- package/dist/connector.js +3 -1
- package/dist/eve/provision-oauth-connector.js +7 -3
- package/dist/installation.d.ts +6 -0
- package/dist/installation.js +3 -1
- package/dist/internal/base-url.d.ts +10 -0
- package/dist/internal/base-url.js +12 -0
- package/dist/internal/default-scopes.d.ts +2 -0
- package/dist/internal/default-scopes.js +3 -0
- package/dist/token.d.ts +8 -2
- package/dist/token.js +11 -6
- package/package.json +1 -1
package/dist/authorization.d.ts
CHANGED
|
@@ -7,6 +7,12 @@ export interface ConnectAuthorizationOptions {
|
|
|
7
7
|
expiresInMs?: number;
|
|
8
8
|
/** OAuth prompt value to pass to the connector's authorization server. */
|
|
9
9
|
prompt?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Region to send the request to, e.g. `sfo1`. Defaults to the
|
|
12
|
+
* `VERCEL_REGION` environment variable; override it to target a
|
|
13
|
+
* different region.
|
|
14
|
+
*/
|
|
15
|
+
region?: string;
|
|
10
16
|
}
|
|
11
17
|
export interface ConnectAuthorizationResponse {
|
|
12
18
|
request: string;
|
package/dist/authorization.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { getVercelOidcToken } from '@vercel/oidc';
|
|
2
2
|
import { isDetachedInteractiveAuth, validateCallbackUrl, validateWebhookUrl, } from './internal/url-validation.js';
|
|
3
|
+
import { withDefaultScopes } from './internal/default-scopes.js';
|
|
4
|
+
import { resolveBaseUrl } from './internal/base-url.js';
|
|
3
5
|
export async function startAuthorization(connector, params, options) {
|
|
4
6
|
if (!connector) {
|
|
5
7
|
throw new Error('connector is required');
|
|
@@ -12,13 +14,14 @@ export async function startAuthorization(connector, params, options) {
|
|
|
12
14
|
validateWebhookUrl(options.webhook);
|
|
13
15
|
}
|
|
14
16
|
const vercelToken = options?.vercelToken ?? (await getVercelOidcToken());
|
|
15
|
-
const
|
|
17
|
+
const baseUrl = resolveBaseUrl(options);
|
|
18
|
+
const endpoint = `${baseUrl}/v1/connect/authorize/${encodeURIComponent(connector)}`;
|
|
16
19
|
const deviceCode = options?.deviceCode ?? (detachedInteractiveAuth ? true : undefined);
|
|
17
20
|
const returnUrl = !detachedInteractiveAuth && options?.callbackUrl !== undefined
|
|
18
21
|
? { returnUrl: options.callbackUrl }
|
|
19
22
|
: {};
|
|
20
23
|
const body = {
|
|
21
|
-
...params,
|
|
24
|
+
...withDefaultScopes(params),
|
|
22
25
|
...returnUrl,
|
|
23
26
|
...(options?.webhook !== undefined && { webhook: options.webhook }),
|
|
24
27
|
...(deviceCode !== undefined && {
|
package/dist/connector.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getVercelOidcToken } from '@vercel/oidc';
|
|
2
2
|
import { createConnectErrorFromResponse, } from './token.js';
|
|
3
|
+
import { resolveBaseUrl } from './internal/base-url.js';
|
|
3
4
|
/**
|
|
4
5
|
* Fetch a connector's metadata from Vercel Connect.
|
|
5
6
|
*
|
|
@@ -11,7 +12,8 @@ import { createConnectErrorFromResponse, } from './token.js';
|
|
|
11
12
|
*/
|
|
12
13
|
export async function getConnectorMetadata(connector, options) {
|
|
13
14
|
const vercelToken = options?.vercelToken ?? (await getVercelOidcToken());
|
|
14
|
-
const
|
|
15
|
+
const baseUrl = resolveBaseUrl(options);
|
|
16
|
+
const endpoint = `${baseUrl}/v1/connect/connectors/${encodeURIComponent(connector)}`;
|
|
15
17
|
const response = await fetch(endpoint, {
|
|
16
18
|
method: 'GET',
|
|
17
19
|
headers: {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getVercelOidcToken } from '@vercel/oidc';
|
|
2
2
|
import { ConnectError, createConnectErrorFromResponse } from '../token.js';
|
|
3
|
-
|
|
3
|
+
import { resolveBaseUrl } from '../internal/base-url.js';
|
|
4
|
+
const MANAGED_OAUTH_CONNECTOR_PATH = '/v1/connect/connectors/managed/oauth';
|
|
4
5
|
const RESERVED_UID_PATTERN = /^(vc\/|[^/]*\.vercel\.com\/)/;
|
|
5
6
|
const ALLOWED_RESERVED_UID_PREFIXES = ['mcp.vercel.com/'];
|
|
6
7
|
const RESERVED_ID_PREFIXES = ['scl_', 'sca_', 'store_', 'ir_'];
|
|
@@ -12,9 +13,11 @@ export async function provisionEveOAuthConnector({ connector, connection, connec
|
|
|
12
13
|
return;
|
|
13
14
|
}
|
|
14
15
|
const vercelToken = connectOptions?.vercelToken ?? (await getVercelOidcToken());
|
|
16
|
+
const endpoint = `${resolveBaseUrl(connectOptions)}${MANAGED_OAUTH_CONNECTOR_PATH}`;
|
|
15
17
|
const cacheKey = JSON.stringify({
|
|
16
18
|
connector,
|
|
17
19
|
serverUrl,
|
|
20
|
+
endpoint,
|
|
18
21
|
token: await tokenCacheKeyPart(vercelToken),
|
|
19
22
|
});
|
|
20
23
|
let promise = provisionCache.get(cacheKey);
|
|
@@ -23,6 +26,7 @@ export async function provisionEveOAuthConnector({ connector, connection, connec
|
|
|
23
26
|
connector,
|
|
24
27
|
serverUrl,
|
|
25
28
|
vercelToken,
|
|
29
|
+
endpoint,
|
|
26
30
|
}).catch(error => {
|
|
27
31
|
if (isNonOAuthConnectorConflict(error)) {
|
|
28
32
|
return;
|
|
@@ -80,8 +84,8 @@ function isNonOAuthConnectorConflict(error) {
|
|
|
80
84
|
error.status === 409 &&
|
|
81
85
|
/not an OAuth connector/i.test(error.message));
|
|
82
86
|
}
|
|
83
|
-
async function provisionManagedOAuthConnector({ connector, serverUrl, vercelToken, }) {
|
|
84
|
-
const response = await fetch(
|
|
87
|
+
async function provisionManagedOAuthConnector({ connector, serverUrl, vercelToken, endpoint, }) {
|
|
88
|
+
const response = await fetch(endpoint, {
|
|
85
89
|
method: 'POST',
|
|
86
90
|
headers: {
|
|
87
91
|
Accept: 'application/json',
|
package/dist/installation.d.ts
CHANGED
|
@@ -7,6 +7,12 @@ export interface ConnectInstallationOptions {
|
|
|
7
7
|
tenantId?: string;
|
|
8
8
|
deviceCode?: boolean;
|
|
9
9
|
expiresInMs?: number;
|
|
10
|
+
/**
|
|
11
|
+
* Region to send the request to, e.g. `sfo1`. Defaults to the
|
|
12
|
+
* `VERCEL_REGION` environment variable; override it to target a
|
|
13
|
+
* different region.
|
|
14
|
+
*/
|
|
15
|
+
region?: string;
|
|
10
16
|
}
|
|
11
17
|
export interface ConnectInstallationResponse {
|
|
12
18
|
request: string;
|
package/dist/installation.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getVercelOidcToken } from '@vercel/oidc';
|
|
2
2
|
import { isDetachedInteractiveAuth, validateCallbackUrl, validateWebhookUrl, } from './internal/url-validation.js';
|
|
3
3
|
import { createConnectErrorFromResponse } from './token.js';
|
|
4
|
+
import { resolveBaseUrl } from './internal/base-url.js';
|
|
4
5
|
/**
|
|
5
6
|
* Create an operator installation request for an app-scoped connector.
|
|
6
7
|
*
|
|
@@ -19,7 +20,8 @@ export async function experimental_startInstallation(connector, params = {}, opt
|
|
|
19
20
|
validateWebhookUrl(options.webhook);
|
|
20
21
|
}
|
|
21
22
|
const vercelToken = options?.vercelToken ?? (await getVercelOidcToken());
|
|
22
|
-
const
|
|
23
|
+
const baseUrl = resolveBaseUrl(options);
|
|
24
|
+
const endpoint = `${baseUrl}/v1/connect/install/${encodeURIComponent(connector)}`;
|
|
23
25
|
const deviceCode = options?.deviceCode ?? (detachedInteractiveAuth ? true : undefined);
|
|
24
26
|
const returnUrl = !detachedInteractiveAuth && options?.returnUrl !== undefined
|
|
25
27
|
? { returnUrl: options.returnUrl }
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Base URL for the Vercel API when no region is available. */
|
|
2
|
+
export declare const API_BASE_URL = "https://api.vercel.com";
|
|
3
|
+
/**
|
|
4
|
+
* Resolves the Vercel API base URL for a region. The region comes from the
|
|
5
|
+
* `region` argument, then the `VERCEL_REGION` environment variable; without
|
|
6
|
+
* either, requests go to the global {@link API_BASE_URL}.
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveBaseUrl({ region }?: {
|
|
9
|
+
region?: string;
|
|
10
|
+
}): string;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { readNonEmptyEnv } from './env.js';
|
|
2
|
+
/** Base URL for the Vercel API when no region is available. */
|
|
3
|
+
export const API_BASE_URL = 'https://api.vercel.com';
|
|
4
|
+
/**
|
|
5
|
+
* Resolves the Vercel API base URL for a region. The region comes from the
|
|
6
|
+
* `region` argument, then the `VERCEL_REGION` environment variable; without
|
|
7
|
+
* either, requests go to the global {@link API_BASE_URL}.
|
|
8
|
+
*/
|
|
9
|
+
export function resolveBaseUrl({ region } = {}) {
|
|
10
|
+
const resolved = region ?? readNonEmptyEnv('VERCEL_REGION');
|
|
11
|
+
return resolved ? `https://api-${resolved}.vercel.com` : API_BASE_URL;
|
|
12
|
+
}
|
package/dist/token.d.ts
CHANGED
|
@@ -27,8 +27,8 @@ export interface ConnectTokenParams {
|
|
|
27
27
|
installationId?: string;
|
|
28
28
|
audience?: string[];
|
|
29
29
|
/**
|
|
30
|
-
* Access scopes to request.
|
|
31
|
-
* the specified subject type.
|
|
30
|
+
* Access scopes to request. Defaults to `['*']`, which requests the default
|
|
31
|
+
* scopes for the specified subject type.
|
|
32
32
|
*/
|
|
33
33
|
scopes?: string[];
|
|
34
34
|
resources?: string[];
|
|
@@ -103,6 +103,12 @@ export interface ConnectOptions {
|
|
|
103
103
|
* a stale bearer.
|
|
104
104
|
*/
|
|
105
105
|
forceRefresh?: boolean;
|
|
106
|
+
/**
|
|
107
|
+
* Region to send the request to, e.g. `sfo1`. Defaults to the
|
|
108
|
+
* `VERCEL_REGION` environment variable; override it to target a
|
|
109
|
+
* different region.
|
|
110
|
+
*/
|
|
111
|
+
region?: string;
|
|
106
112
|
}
|
|
107
113
|
export declare function getToken(connector: string, params: ConnectTokenParams, options?: ConnectOptions): Promise<string>;
|
|
108
114
|
export declare function getTokenResponse(connector: string, params: ConnectTokenParams, options?: ConnectOptions): Promise<ConnectTokenResponse>;
|
package/dist/token.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { getVercelOidcToken } from '@vercel/oidc';
|
|
2
|
+
import { resolveBaseUrl } from './internal/base-url.js';
|
|
3
|
+
import { withDefaultScopes } from './internal/default-scopes.js';
|
|
2
4
|
export class ConnectError extends Error {
|
|
3
5
|
code;
|
|
4
6
|
status;
|
|
@@ -36,8 +38,9 @@ export async function getToken(connector, params, options) {
|
|
|
36
38
|
return token;
|
|
37
39
|
}
|
|
38
40
|
export async function getTokenResponse(connector, params, options) {
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
+
const requestParams = withDefaultScopes(params);
|
|
42
|
+
const bufferMs = requestParams.validityBufferMs ?? DEFAULT_VALIDITY_BUFFER_MS;
|
|
43
|
+
const cacheKey = tokenCacheKey(connector, requestParams);
|
|
41
44
|
if (options?.forceRefresh) {
|
|
42
45
|
cache.delete(cacheKey);
|
|
43
46
|
}
|
|
@@ -53,7 +56,8 @@ export async function getTokenResponse(connector, params, options) {
|
|
|
53
56
|
}
|
|
54
57
|
}
|
|
55
58
|
const vercelToken = options?.vercelToken ?? (await getVercelOidcToken());
|
|
56
|
-
const
|
|
59
|
+
const baseUrl = resolveBaseUrl(options);
|
|
60
|
+
const endpoint = `${baseUrl}/v1/connect/token/${encodeURIComponent(connector)}`;
|
|
57
61
|
const response = await fetch(endpoint, {
|
|
58
62
|
method: 'POST',
|
|
59
63
|
headers: {
|
|
@@ -61,7 +65,7 @@ export async function getTokenResponse(connector, params, options) {
|
|
|
61
65
|
'Content-Type': 'application/json',
|
|
62
66
|
Authorization: `Bearer ${vercelToken}`,
|
|
63
67
|
},
|
|
64
|
-
body: JSON.stringify(
|
|
68
|
+
body: JSON.stringify(requestParams),
|
|
65
69
|
});
|
|
66
70
|
if (!response.ok) {
|
|
67
71
|
throw await createConnectErrorFromResponse(response, 'Failed to get token');
|
|
@@ -75,7 +79,8 @@ export async function getTokenResponse(connector, params, options) {
|
|
|
75
79
|
}
|
|
76
80
|
export async function revokeToken(connector, params, options) {
|
|
77
81
|
const vercelToken = options?.vercelToken ?? (await getVercelOidcToken());
|
|
78
|
-
const
|
|
82
|
+
const baseUrl = resolveBaseUrl(options);
|
|
83
|
+
const endpoint = `${baseUrl}/v1/connect/connectors/${encodeURIComponent(connector)}/tokens`;
|
|
79
84
|
const response = await fetch(endpoint, {
|
|
80
85
|
method: 'DELETE',
|
|
81
86
|
headers: {
|
|
@@ -108,7 +113,7 @@ export async function revokeToken(connector, params, options) {
|
|
|
108
113
|
* call. No-op when no matching entry exists.
|
|
109
114
|
*/
|
|
110
115
|
export function deleteTokenCacheEntry(connector, params) {
|
|
111
|
-
cache.delete(tokenCacheKey(connector, params));
|
|
116
|
+
cache.delete(tokenCacheKey(connector, withDefaultScopes(params)));
|
|
112
117
|
}
|
|
113
118
|
const DEFAULT_VALIDITY_BUFFER_MS = 30_000;
|
|
114
119
|
const MAX_CACHE_SIZE = 100;
|