@vercel/connect 0.0.5-alpha.1 → 0.1.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/dist/token.js CHANGED
@@ -1,20 +1,34 @@
1
- import { getVercelOidcToken } from "@vercel/oidc";
2
- export class NoValidTokenError extends Error {
3
- constructor(message) {
1
+ import { getVercelOidcToken } from '@vercel/oidc';
2
+ export class ConnectError extends Error {
3
+ code;
4
+ status;
5
+ statusText;
6
+ vendor;
7
+ constructor(message, options = {}) {
4
8
  super(message);
5
- this.name = "NoValidTokenError";
9
+ this.name = 'ConnectError';
10
+ this.code = options.code;
11
+ this.status = options.status;
12
+ this.statusText = options.statusText;
13
+ this.vendor = options.vendor;
6
14
  }
7
15
  }
8
- export class UserAuthorizationRequiredError extends Error {
9
- constructor(message) {
10
- super(message);
11
- this.name = "UserAuthorizationRequiredError";
16
+ export class NoValidTokenError extends ConnectError {
17
+ constructor(message, options) {
18
+ super(message, options);
19
+ this.name = 'NoValidTokenError';
12
20
  }
13
21
  }
14
- export class ConnectorInstallationRequiredError extends Error {
15
- constructor(message) {
16
- super(message);
17
- this.name = "ConnectorInstallationRequiredError";
22
+ export class UserAuthorizationRequiredError extends ConnectError {
23
+ constructor(message, options) {
24
+ super(message, options);
25
+ this.name = 'UserAuthorizationRequiredError';
26
+ }
27
+ }
28
+ export class ConnectorInstallationRequiredError extends ConnectError {
29
+ constructor(message, options) {
30
+ super(message, options);
31
+ this.name = 'ConnectorInstallationRequiredError';
18
32
  }
19
33
  }
20
34
  export async function getToken(connector, params, options) {
@@ -36,46 +50,16 @@ export async function getTokenResponse(connector, params, options) {
36
50
  const vercelToken = options?.vercelToken ?? (await getVercelOidcToken());
37
51
  const endpoint = `https://api.vercel.com/v1/connect/token/${encodeURIComponent(connector)}`;
38
52
  const response = await fetch(endpoint, {
39
- method: "POST",
53
+ method: 'POST',
40
54
  headers: {
41
- Accept: "application/json",
42
- "Content-Type": "application/json",
55
+ Accept: 'application/json',
56
+ 'Content-Type': 'application/json',
43
57
  Authorization: `Bearer ${vercelToken}`,
44
58
  },
45
59
  body: JSON.stringify(params),
46
60
  });
47
61
  if (!response.ok) {
48
- let errorText;
49
- let errorObject;
50
- try {
51
- errorText = await response.text();
52
- const errorJson = JSON.parse(errorText);
53
- if (typeof errorJson === "object" && errorJson !== null) {
54
- errorObject = errorJson;
55
- }
56
- }
57
- catch { }
58
- const code = errorObject?.error?.code;
59
- const message = errorObject?.error?.message;
60
- if (code === "no_token") {
61
- throw new NoValidTokenError(message || errorText || "No valid token available");
62
- }
63
- if (code === "user_authorization_required") {
64
- throw new UserAuthorizationRequiredError(message || errorText || "User authorization is required");
65
- }
66
- if (code === "client_installation_required" ||
67
- code === "connector_installation_required") {
68
- throw new ConnectorInstallationRequiredError(message || errorText || "Connector installation is required");
69
- }
70
- throw new Error([
71
- "Failed to get token:",
72
- `${response.status}`,
73
- response.statusText,
74
- code ? ` - ${code}` : "",
75
- errorText ? ` - ${errorText}` : "",
76
- ]
77
- .filter(Boolean)
78
- .join(" "));
62
+ throw await createConnectErrorFromResponse(response, 'Failed to get token');
79
63
  }
80
64
  const data = await response.json();
81
65
  if (cache.size >= MAX_CACHE_SIZE) {
@@ -100,3 +84,89 @@ function evictLru() {
100
84
  cache.delete(oldestKey);
101
85
  }
102
86
  }
87
+ export async function createConnectErrorFromResponse(response, fallbackMessage) {
88
+ const parsedError = await readConnectErrorResponse(response);
89
+ return createConnectError(response, parsedError, fallbackMessage);
90
+ }
91
+ function createConnectError(response, parsedError, fallbackMessage) {
92
+ const { code, message, bodyText } = parsedError;
93
+ const errorOptions = connectErrorOptions(response, parsedError);
94
+ if (code === 'no_token') {
95
+ return new NoValidTokenError(message || bodyText || 'No valid token available', errorOptions);
96
+ }
97
+ if (code === 'user_authorization_required') {
98
+ return new UserAuthorizationRequiredError(message || bodyText || 'User authorization is required', errorOptions);
99
+ }
100
+ if (code === 'client_installation_required' ||
101
+ code === 'connector_installation_required') {
102
+ return new ConnectorInstallationRequiredError(message || bodyText || 'Connector installation is required', errorOptions);
103
+ }
104
+ return new ConnectError(buildConnectResponseErrorMessage(response, parsedError, fallbackMessage), errorOptions);
105
+ }
106
+ async function readConnectErrorResponse(response) {
107
+ let bodyText;
108
+ try {
109
+ bodyText = await response.text();
110
+ }
111
+ catch { }
112
+ if (!bodyText) {
113
+ return {};
114
+ }
115
+ try {
116
+ const body = JSON.parse(bodyText);
117
+ if (!isRecord(body)) {
118
+ return { bodyText };
119
+ }
120
+ const error = isRecord(body.error)
121
+ ? body.error
122
+ : isRecord(body.err)
123
+ ? body.err
124
+ : undefined;
125
+ if (!error) {
126
+ return { bodyText, vendor: vendorPayload(body) };
127
+ }
128
+ return {
129
+ bodyText,
130
+ code: typeof error.code === 'string' ? error.code : undefined,
131
+ message: typeof error.message === 'string' ? error.message : undefined,
132
+ vendor: vendorPayload(error) ?? vendorPayload(body),
133
+ };
134
+ }
135
+ catch {
136
+ return { bodyText };
137
+ }
138
+ }
139
+ function connectErrorOptions(response, parsedError) {
140
+ return {
141
+ code: parsedError.code,
142
+ status: response.status,
143
+ statusText: response.statusText,
144
+ vendor: parsedError.vendor,
145
+ };
146
+ }
147
+ function buildConnectResponseErrorMessage(response, parsedError, fallbackMessage) {
148
+ if (parsedError.message) {
149
+ return parsedError.message;
150
+ }
151
+ return [
152
+ `${fallbackMessage}:`,
153
+ `${response.status}`,
154
+ response.statusText,
155
+ parsedError.code ? ` - ${parsedError.code}` : '',
156
+ parsedError.bodyText ? ` - ${parsedError.bodyText}` : '',
157
+ ]
158
+ .filter(Boolean)
159
+ .join(' ');
160
+ }
161
+ function vendorPayload(error) {
162
+ if (isRecord(error.vendor)) {
163
+ return error.vendor;
164
+ }
165
+ if (isRecord(error.meta) && isRecord(error.meta.vendor)) {
166
+ return error.meta.vendor;
167
+ }
168
+ return undefined;
169
+ }
170
+ function isRecord(value) {
171
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
172
+ }
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "@vercel/connect",
3
- "version": "0.0.5-alpha.1",
3
+ "version": "0.1.1",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
+ "repository": {
7
+ "directory": "packages/connect",
8
+ "type": "git",
9
+ "url": "git+https://github.com/vercel/vercel.git"
10
+ },
6
11
  "exports": {
7
12
  ".": {
8
13
  "types": "./dist/index.d.ts",
@@ -25,7 +30,7 @@
25
30
  "dist"
26
31
  ],
27
32
  "dependencies": {
28
- "@vercel/oidc": "*"
33
+ "@vercel/oidc": "3.5.0"
29
34
  },
30
35
  "peerDependencies": {
31
36
  "@auth/core": ">=0.37.0",
@@ -46,7 +51,7 @@
46
51
  "devDependencies": {
47
52
  "@auth/core": "0.37.4",
48
53
  "better-auth": "1.5.5",
49
- "experimental-ash": "0.3.0-alpha.29",
54
+ "experimental-ash": "0.31.0",
50
55
  "typescript": "^5"
51
56
  },
52
57
  "private": false,