@vercel/connect 0.2.4 → 0.2.5
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.
|
@@ -35,6 +35,23 @@ import type { ConnectOptions, ConnectTokenParams, ConnectTokenSubject } from '..
|
|
|
35
35
|
* so consumers can branch their error translation per callback.
|
|
36
36
|
*/
|
|
37
37
|
export type ConnectAuthorizationPhase = 'getToken' | 'startAuthorization' | 'completeAuthorization';
|
|
38
|
+
/**
|
|
39
|
+
* Eve's per-connection authorization context — the `connection` argument
|
|
40
|
+
* Eve's runtime hands to every `getToken` / `startAuthorization` /
|
|
41
|
+
* `completeAuthorization` callback alongside the resolved principal.
|
|
42
|
+
* Currently carries the connection's declared server `url`; Eve documents
|
|
43
|
+
* the shape as strictly additive, so destructuring only the fields you
|
|
44
|
+
* need stays forward-compatible.
|
|
45
|
+
*
|
|
46
|
+
* eve 0.6.0-beta.1 declares this type as
|
|
47
|
+
* `ConnectionAuthorizationContext` but does not re-export it from
|
|
48
|
+
* `eve/connections` (or any other public subpath), so it is derived
|
|
49
|
+
* structurally here from the exported authorization definition — this is
|
|
50
|
+
* exactly the type Eve passes at runtime. Once eve exports the type
|
|
51
|
+
* directly, this alias can switch to a plain re-export without a
|
|
52
|
+
* breaking change.
|
|
53
|
+
*/
|
|
54
|
+
export type EveConnectionAuthorizationContext = Parameters<NonInteractiveAuthorizationDefinition['getToken']>[0]['connection'];
|
|
38
55
|
/** Options accepted by {@link connect}. */
|
|
39
56
|
export interface EveAuthorizationOptions {
|
|
40
57
|
/**
|
|
@@ -69,11 +86,27 @@ export interface EveAuthorizationOptions {
|
|
|
69
86
|
* `authorizationDetails`. Passed through verbatim.
|
|
70
87
|
*/
|
|
71
88
|
readonly tokenParams?: Omit<ConnectTokenParams, 'subject'>;
|
|
89
|
+
/**
|
|
90
|
+
* Builds the Vercel Connect token subject from the framework-resolved
|
|
91
|
+
* principal plus the connection's authorization context (Eve's
|
|
92
|
+
* per-connection metadata — currently the declared server `url`).
|
|
93
|
+
*
|
|
94
|
+
* Needed by jwt-bearer-style connectors whose subject/assertion
|
|
95
|
+
* depends on more than the principal: custom claims, the connection
|
|
96
|
+
* URL, or an audience derived from it. Takes precedence over the
|
|
97
|
+
* deprecated {@link principalToSubject}. When neither is set, the
|
|
98
|
+
* default mapping applies — app principals map to `{ type: "app" }`
|
|
99
|
+
* and user principals map to `{ type: "user", id, issuer }`.
|
|
100
|
+
*/
|
|
101
|
+
readonly createSubject?: (principal: ConnectionPrincipal, ctx: EveConnectionAuthorizationContext) => ConnectTokenSubject | Promise<ConnectTokenSubject>;
|
|
72
102
|
/**
|
|
73
103
|
* Override how Eve's framework-resolved principal is mapped to a
|
|
74
104
|
* Vercel Connect token subject. When omitted, app principals map to
|
|
75
105
|
* `{ type: "app" }` and user principals map to
|
|
76
106
|
* `{ type: "user", id, issuer }`.
|
|
107
|
+
*
|
|
108
|
+
* @deprecated Use {@link createSubject}, which also receives the
|
|
109
|
+
* connection authorization context.
|
|
77
110
|
*/
|
|
78
111
|
readonly principalToSubject?: (principal: ConnectionPrincipal) => ConnectTokenSubject | Promise<ConnectTokenSubject>;
|
|
79
112
|
/**
|
|
@@ -173,9 +206,17 @@ export type EveConnectAuthorizationDefinition<TAuthorization extends Interactive
|
|
|
173
206
|
* failed or duplicate revoke is swallowed so it never masks the error
|
|
174
207
|
* that triggered eviction, and the local cache entry is dropped either
|
|
175
208
|
* way.
|
|
209
|
+
*
|
|
210
|
+
* Pass `connection` (Eve's per-connection authorization context) when
|
|
211
|
+
* the connection uses {@link EveAuthorizationOptions.createSubject}:
|
|
212
|
+
* the cache entry is keyed by the resolved subject, and a
|
|
213
|
+
* context-dependent subject can only be reproduced with the context in
|
|
214
|
+
* hand. Without it, eviction falls back to the legacy
|
|
215
|
+
* principal-only mapping and may miss the entry.
|
|
176
216
|
*/
|
|
177
217
|
readonly evict: (opts: {
|
|
178
218
|
readonly principal: ConnectionPrincipal;
|
|
219
|
+
readonly connection?: EveConnectionAuthorizationContext;
|
|
179
220
|
readonly revoke?: boolean;
|
|
180
221
|
}) => Promise<void>;
|
|
181
222
|
};
|
|
@@ -51,8 +51,8 @@ export function connect(input) {
|
|
|
51
51
|
* local cache drop if the revoke request fails).
|
|
52
52
|
*/
|
|
53
53
|
function makeEvict(options) {
|
|
54
|
-
return async ({ principal, revoke }) => {
|
|
55
|
-
const params = await buildTokenParams(options, principal);
|
|
54
|
+
return async ({ principal, connection, revoke }) => {
|
|
55
|
+
const params = await buildTokenParams(options, principal, connection);
|
|
56
56
|
if (revoke) {
|
|
57
57
|
try {
|
|
58
58
|
// Destructive: tears down the grant at Vercel Connect (refresh
|
|
@@ -82,16 +82,16 @@ function normalizeAuthorizationOptions(input) {
|
|
|
82
82
|
function buildInteractiveDefinition(options) {
|
|
83
83
|
return {
|
|
84
84
|
principalType: 'user',
|
|
85
|
-
async getToken({ principal }) {
|
|
85
|
+
async getToken({ principal, connection, }) {
|
|
86
86
|
try {
|
|
87
|
-
const response = await getTokenResponse(options.connector, await buildTokenParams(options, principal), getTokenConnectOptions(options));
|
|
87
|
+
const response = await getTokenResponse(options.connector, await buildTokenParams(options, principal, connection), getTokenConnectOptions(options));
|
|
88
88
|
return { token: response.token, expiresAt: response.expiresAt };
|
|
89
89
|
}
|
|
90
90
|
catch (error) {
|
|
91
91
|
throw translate(error, 'getToken', options);
|
|
92
92
|
}
|
|
93
93
|
},
|
|
94
|
-
async startAuthorization({ principal, callbackUrl, webhook, }) {
|
|
94
|
+
async startAuthorization({ principal, connection, callbackUrl, webhook, }) {
|
|
95
95
|
try {
|
|
96
96
|
// Eve's `webhook` parameter is semantically a browser-redirect
|
|
97
97
|
// target — the orchestrator mints it via `createWebhook({
|
|
@@ -114,7 +114,7 @@ function buildInteractiveDefinition(options) {
|
|
|
114
114
|
// mints one URL, Vercel Connect redirects there" mental
|
|
115
115
|
// model. Revisit if tab-close timeouts become a real problem
|
|
116
116
|
// in production.
|
|
117
|
-
const response = await startAuthorization(options.connector, await buildTokenParams(options, principal), {
|
|
117
|
+
const response = await startAuthorization(options.connector, await buildTokenParams(options, principal, connection), {
|
|
118
118
|
...options.connectOptions,
|
|
119
119
|
callbackUrl: callbackUrl ?? webhook,
|
|
120
120
|
deviceCode: true,
|
|
@@ -136,9 +136,9 @@ function buildInteractiveDefinition(options) {
|
|
|
136
136
|
throw translate(error, 'startAuthorization', options);
|
|
137
137
|
}
|
|
138
138
|
},
|
|
139
|
-
async completeAuthorization({ principal, }) {
|
|
139
|
+
async completeAuthorization({ principal, connection, }) {
|
|
140
140
|
try {
|
|
141
|
-
const response = await getTokenResponse(options.connector, await buildTokenParams(options, principal), options.connectOptions);
|
|
141
|
+
const response = await getTokenResponse(options.connector, await buildTokenParams(options, principal, connection), options.connectOptions);
|
|
142
142
|
return { token: response.token, expiresAt: response.expiresAt };
|
|
143
143
|
}
|
|
144
144
|
catch (error) {
|
|
@@ -150,9 +150,9 @@ function buildInteractiveDefinition(options) {
|
|
|
150
150
|
function buildNonInteractiveDefinition(options) {
|
|
151
151
|
return {
|
|
152
152
|
principalType: 'app',
|
|
153
|
-
async getToken({ principal }) {
|
|
153
|
+
async getToken({ principal, connection, }) {
|
|
154
154
|
try {
|
|
155
|
-
const response = await getTokenResponse(options.connector, await buildTokenParams(options, principal), getTokenConnectOptions(options));
|
|
155
|
+
const response = await getTokenResponse(options.connector, await buildTokenParams(options, principal, connection), getTokenConnectOptions(options));
|
|
156
156
|
return { token: response.token, expiresAt: response.expiresAt };
|
|
157
157
|
}
|
|
158
158
|
catch (error) {
|
|
@@ -173,13 +173,35 @@ function getTokenConnectOptions(options) {
|
|
|
173
173
|
}
|
|
174
174
|
return { ...options.connectOptions, forceRefresh: true };
|
|
175
175
|
}
|
|
176
|
-
async function buildTokenParams(options, principal) {
|
|
177
|
-
const toSubject = options.principalToSubject ?? principalToSubject;
|
|
176
|
+
async function buildTokenParams(options, principal, connection) {
|
|
178
177
|
return {
|
|
179
178
|
...options.tokenParams,
|
|
180
|
-
subject: await
|
|
179
|
+
subject: await resolveSubject(options, principal, connection),
|
|
181
180
|
};
|
|
182
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* Resolves the Vercel Connect token subject for `principal`, applying
|
|
184
|
+
* the documented precedence: {@link EveAuthorizationOptions.createSubject}
|
|
185
|
+
* (when the connection context is in hand), then the deprecated
|
|
186
|
+
* {@link EveAuthorizationOptions.principalToSubject}, then the default
|
|
187
|
+
* principal mapping.
|
|
188
|
+
*
|
|
189
|
+
* Eve's runtime passes `connection` to every authorization callback, so
|
|
190
|
+
* on the `getToken` / `startAuthorization` / `completeAuthorization`
|
|
191
|
+
* paths `createSubject` always receives it. Only the adapter's own
|
|
192
|
+
* `evict` entry point may run without a context (its callers predate the
|
|
193
|
+
* context plumbing); in that case the resolution falls back past
|
|
194
|
+
* `createSubject` so eviction stays best-effort instead of throwing.
|
|
195
|
+
*/
|
|
196
|
+
function resolveSubject(options, principal, connection) {
|
|
197
|
+
if (options.createSubject !== undefined && connection !== undefined) {
|
|
198
|
+
return options.createSubject(principal, connection);
|
|
199
|
+
}
|
|
200
|
+
if (options.principalToSubject !== undefined) {
|
|
201
|
+
return options.principalToSubject(principal);
|
|
202
|
+
}
|
|
203
|
+
return principalToSubject(principal);
|
|
204
|
+
}
|
|
183
205
|
function principalToSubject(principal) {
|
|
184
206
|
if (principal.type === 'app') {
|
|
185
207
|
return { type: 'app' };
|
package/dist/eve/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* this barrel re-exports the public API so consumers import
|
|
7
7
|
* everything from `@vercel/connect/eve`.
|
|
8
8
|
*/
|
|
9
|
-
export { connect, type EveAuthorizationInput, type EveAuthorizationOptions, type EveConnectAuthorizationDefinition, type ConnectAuthorizationPhase, type VercelConnectMetadata, } from './connection-authorization.js';
|
|
9
|
+
export { connect, type EveAuthorizationInput, type EveAuthorizationOptions, type EveConnectAuthorizationDefinition, type EveConnectionAuthorizationContext, type ConnectAuthorizationPhase, type VercelConnectMetadata, } from './connection-authorization.js';
|
|
10
10
|
export { CONNECT_OAUTH_ISSUER, connectOAuth, type ConnectOAuthAudienceEnvironment, type ConnectOAuthEnvironment, type ConnectOAuthOptions, } from './connect-oauth.js';
|
|
11
11
|
export { connectGitHubCredentials, type ConnectGitHubCredentialsParams, } from './github-credentials.js';
|
|
12
12
|
export { connectLinearCredentials, type ConnectLinearCredentialsParams, } from './linear-credentials.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vercel/connect",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"peerDependencies": {
|
|
44
44
|
"@ai-sdk/mcp": "^1 || ^2",
|
|
45
45
|
"@auth/core": ">=0.37.0",
|
|
46
|
-
"ai": "^6 || ^7",
|
|
46
|
+
"ai": "^6 || ^7.0.0-beta.0",
|
|
47
47
|
"better-auth": ">=1.5.0",
|
|
48
48
|
"eve": ">=0.6.0-beta.1"
|
|
49
49
|
},
|