@vercel/connect 0.1.2 → 0.1.3

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.
@@ -28,8 +28,8 @@
28
28
  * `@vercel/connect/ash` requires Ash to be installed in the consumer
29
29
  * project, but the rest of `@vercel/connect` works without it.
30
30
  */
31
- import { type InteractiveAuthorizationDefinition, type JsonValue, type NonInteractiveAuthorizationDefinition } from 'experimental-ash/connections';
32
- import type { ConnectOptions, ConnectTokenParams } from '../token.js';
31
+ import { type ConnectionPrincipal, type InteractiveAuthorizationDefinition, type JsonValue, type NonInteractiveAuthorizationDefinition } from 'experimental-ash/connections';
32
+ import type { ConnectOptions, ConnectTokenParams, ConnectTokenSubject } from '../token.js';
33
33
  /**
34
34
  * Authorization phase passed to {@link AshAuthorizationOptions.onError}
35
35
  * so consumers can branch their error translation per callback.
@@ -82,6 +82,13 @@ export interface AshAuthorizationOptions {
82
82
  * `authorizationDetails`. Passed through verbatim.
83
83
  */
84
84
  readonly tokenParams?: Omit<ConnectTokenParams, 'subject'>;
85
+ /**
86
+ * Override how Ash's framework-resolved principal is mapped to a
87
+ * Vercel Connect token subject. When omitted, app principals map to
88
+ * `{ type: "app" }` and user principals map to
89
+ * `{ type: "user", id, issuer }`.
90
+ */
91
+ readonly principalToSubject?: (principal: ConnectionPrincipal) => ConnectTokenSubject | Promise<ConnectTokenSubject>;
85
92
  /**
86
93
  * Low-level Vercel Connect SDK options (currently `vercelToken`
87
94
  * for overriding the OIDC bearer). Most callers leave this unset
@@ -50,7 +50,7 @@ function buildInteractiveDefinition(options) {
50
50
  principalType: 'user',
51
51
  async getToken({ principal }) {
52
52
  try {
53
- const response = await getTokenResponse(options.connector, buildTokenParams(options, principal), options.connectOptions);
53
+ const response = await getTokenResponse(options.connector, await buildTokenParams(options, principal), options.connectOptions);
54
54
  return { token: response.token, expiresAt: response.expiresAt };
55
55
  }
56
56
  catch (error) {
@@ -80,7 +80,7 @@ function buildInteractiveDefinition(options) {
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.
83
- const response = await startAuthorization(options.connector, buildTokenParams(options, principal), {
83
+ const response = await startAuthorization(options.connector, await buildTokenParams(options, principal), {
84
84
  ...options.connectOptions,
85
85
  callbackUrl: callbackUrl ?? webhook,
86
86
  deviceCode: true,
@@ -105,7 +105,7 @@ function buildInteractiveDefinition(options) {
105
105
  },
106
106
  async completeAuthorization({ principal, }) {
107
107
  try {
108
- const response = await getTokenResponse(options.connector, buildTokenParams(options, principal), options.connectOptions);
108
+ const response = await getTokenResponse(options.connector, await buildTokenParams(options, principal), options.connectOptions);
109
109
  return { token: response.token, expiresAt: response.expiresAt };
110
110
  }
111
111
  catch (error) {
@@ -119,7 +119,7 @@ function buildNonInteractiveDefinition(options) {
119
119
  principalType: 'app',
120
120
  async getToken({ principal }) {
121
121
  try {
122
- const response = await getTokenResponse(options.connector, buildTokenParams(options, principal), options.connectOptions);
122
+ const response = await getTokenResponse(options.connector, await buildTokenParams(options, principal), options.connectOptions);
123
123
  return { token: response.token, expiresAt: response.expiresAt };
124
124
  }
125
125
  catch (error) {
@@ -128,10 +128,11 @@ function buildNonInteractiveDefinition(options) {
128
128
  },
129
129
  };
130
130
  }
131
- function buildTokenParams(options, principal) {
131
+ async function buildTokenParams(options, principal) {
132
+ const toSubject = options.principalToSubject ?? principalToSubject;
132
133
  return {
133
134
  ...options.tokenParams,
134
- subject: principalToSubject(principal),
135
+ subject: await toSubject(principal),
135
136
  };
136
137
  }
137
138
  function principalToSubject(principal) {
@@ -1,4 +1,14 @@
1
1
  import type { SlackChannelCredentials } from 'experimental-ash/channels/slack';
2
+ import { type ConnectOptions, type ConnectTokenParams } from '../index.js';
3
+ /**
4
+ * Token parameters accepted by {@link connectSlackCredentials}.
5
+ *
6
+ * Mirrors {@link ConnectTokenParams} from `@vercel/connect`, minus
7
+ * `subject` — Slack bot tokens are always app-scoped, so `subject`
8
+ * is pinned to `{ type: "app" }` by this helper and cannot be
9
+ * overridden.
10
+ */
11
+ export type ConnectSlackCredentialsParams = Omit<ConnectTokenParams, 'subject'>;
2
12
  /**
3
13
  * Build {@link SlackChannelCredentials} backed by a Vercel Connect
4
14
  * connector that stores a Slack workspace's bot token.
@@ -13,6 +23,10 @@ import type { SlackChannelCredentials } from 'experimental-ash/channels/slack';
13
23
  * with `subject: { type: "app" }`. End-user identity (per-user OAuth
14
24
  * into Slack) is a separate concern handled elsewhere.
15
25
  *
26
+ * The optional `params` and `options` arguments mirror the signature
27
+ * of {@link getToken}, allowing callers to pass through fields like
28
+ * `installationId`, `scopes`, or `validityBufferMs`.
29
+ *
16
30
  * ```ts
17
31
  * import { slackRoute } from "experimental-ash/channels/slack";
18
32
  * import { connectSlackCredentials } from "@vercel/connect/ash";
@@ -21,5 +35,12 @@ import type { SlackChannelCredentials } from 'experimental-ash/channels/slack';
21
35
  * credentials: connectSlackCredentials("scl_..."),
22
36
  * });
23
37
  * ```
38
+ *
39
+ * Multi-workspace deployments can select a specific workspace install
40
+ * via `installationId`:
41
+ *
42
+ * ```ts
43
+ * connectSlackCredentials("scl_...", { installationId: workspaceId });
44
+ * ```
24
45
  */
25
- export declare function connectSlackCredentials(connector: string): SlackChannelCredentials;
46
+ export declare function connectSlackCredentials(connector: string, params?: ConnectSlackCredentialsParams, options?: ConnectOptions): SlackChannelCredentials;
@@ -1,4 +1,4 @@
1
- import { getToken } from '../index.js';
1
+ import { getToken, } from '../index.js';
2
2
  import { vercelOidc } from 'experimental-ash/channels/auth';
3
3
  /**
4
4
  * Build {@link SlackChannelCredentials} backed by a Vercel Connect
@@ -14,6 +14,10 @@ import { vercelOidc } from 'experimental-ash/channels/auth';
14
14
  * with `subject: { type: "app" }`. End-user identity (per-user OAuth
15
15
  * into Slack) is a separate concern handled elsewhere.
16
16
  *
17
+ * The optional `params` and `options` arguments mirror the signature
18
+ * of {@link getToken}, allowing callers to pass through fields like
19
+ * `installationId`, `scopes`, or `validityBufferMs`.
20
+ *
17
21
  * ```ts
18
22
  * import { slackRoute } from "experimental-ash/channels/slack";
19
23
  * import { connectSlackCredentials } from "@vercel/connect/ash";
@@ -22,10 +26,17 @@ import { vercelOidc } from 'experimental-ash/channels/auth';
22
26
  * credentials: connectSlackCredentials("scl_..."),
23
27
  * });
24
28
  * ```
29
+ *
30
+ * Multi-workspace deployments can select a specific workspace install
31
+ * via `installationId`:
32
+ *
33
+ * ```ts
34
+ * connectSlackCredentials("scl_...", { installationId: workspaceId });
35
+ * ```
25
36
  */
26
- export function connectSlackCredentials(connector) {
37
+ export function connectSlackCredentials(connector, params = {}, options) {
27
38
  return {
28
- botToken: () => getToken(connector, { subject: { type: 'app' } }),
39
+ botToken: () => getToken(connector, { ...params, subject: { type: 'app' } }, options),
29
40
  webhookVerifier: vercelOidc(),
30
41
  };
31
42
  }
@@ -0,0 +1,11 @@
1
+ export type ConnectAuthorizationDetail = ConnectGitHubAppInstallationAuthorizationDetail | ConnectCustomAuthorizationDetail;
2
+ export interface ConnectCustomAuthorizationDetail {
3
+ type: string;
4
+ [key: string]: unknown;
5
+ }
6
+ export interface ConnectGitHubAppInstallationAuthorizationDetail {
7
+ type: 'github_app_installation';
8
+ org?: string;
9
+ permissions?: string | string[];
10
+ repositories?: string | string[];
11
+ }
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
- export { getToken, getTokenResponse, ConnectError, NoValidTokenError, UserAuthorizationRequiredError, ConnectorInstallationRequiredError, type ConnectErrorOptions, type ConnectOptions, type ConnectTokenParams, type ConnectTokenResponse, type ConnectVendorErrorPayload, } from './token.js';
1
+ export { getToken, getTokenResponse, 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
+ export type { ConnectAuthorizationDetail } from './authorization-details.js';
package/dist/token.d.ts CHANGED
@@ -1,18 +1,30 @@
1
+ import type { ConnectAuthorizationDetail } from './authorization-details.js';
2
+ export type ConnectSubjectType = 'app' | 'user' | 'jwt-bearer';
3
+ export type ConnectTokenSubject = ConnectAppTokenSubject | ConnectUserTokenSubject | ConnectJwtBearerTokenSubject;
4
+ export interface ConnectAppTokenSubject {
5
+ type: 'app';
6
+ }
7
+ export interface ConnectUserTokenSubject {
8
+ type: 'user';
9
+ id: string;
10
+ issuer?: string;
11
+ }
12
+ export interface ConnectJwtBearerTokenSubject {
13
+ type: 'jwt-bearer';
14
+ sub: string;
15
+ /** Defaults to the connector's OAuth client id. */
16
+ iss?: string;
17
+ /** Defaults to the connector's OAuth token endpoint. */
18
+ aud?: string;
19
+ additionalClaims?: Record<string, unknown>;
20
+ }
1
21
  export interface ConnectTokenParams {
2
- subject: {
3
- type: 'app';
4
- } | {
5
- type: 'user';
6
- id: string;
7
- issuer?: string;
8
- };
22
+ subject: ConnectTokenSubject;
9
23
  installationId?: string;
10
24
  audience?: string[];
11
25
  scopes?: string[];
12
26
  resources?: string[];
13
- authorizationDetails?: Array<{
14
- type: string;
15
- } & Record<string, unknown>>;
27
+ authorizationDetails?: ConnectAuthorizationDetail[];
16
28
  /**
17
29
  * Buffer time in milliseconds before token expiration to consider it invalid.
18
30
  * If the token expires within this buffer, it will be refreshed.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/connect",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "repository": {