@vercel/client 17.6.3 → 17.6.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.
@@ -42,6 +42,36 @@ const RETRY_DELAY_MAX_MS = 6e4;
42
42
  const RETRY_DELAY_MIN_MS = 5e3;
43
43
  const RETRY_DELAY_SKEW_MS = 3e4;
44
44
  const RETRY_DELAY_DEFAULT_MS = 5e3;
45
+ function getAliasAssignedEvent(signal, deploymentId) {
46
+ if (!signal?.aborted)
47
+ return;
48
+ const event = signal.reason;
49
+ if (event?.type === "alias-assigned" && event.deploymentId === deploymentId && typeof event.date === "number" && Array.isArray(event.alias) && "aliasError" in event && "aliasWarning" in event) {
50
+ return event;
51
+ }
52
+ return void 0;
53
+ }
54
+ async function sleepUntilAliasAssigned(duration, signal, deploymentId) {
55
+ if (getAliasAssignedEvent(signal, deploymentId))
56
+ return;
57
+ if (!signal || signal.aborted) {
58
+ await (0, import_sleep_promise.default)(duration);
59
+ return;
60
+ }
61
+ await new Promise((resolve) => {
62
+ const timeout = setTimeout(finish, duration);
63
+ function finish() {
64
+ clearTimeout(timeout);
65
+ signal?.removeEventListener("abort", onAbort);
66
+ resolve();
67
+ }
68
+ function onAbort() {
69
+ if (getAliasAssignedEvent(signal, deploymentId))
70
+ finish();
71
+ }
72
+ signal.addEventListener("abort", onAbort, { once: true });
73
+ });
74
+ }
45
75
  function parseRetryAfterMs(response) {
46
76
  if (response.status === 429 || response.status === 503) {
47
77
  let header = response.headers.get("Retry-After");
@@ -71,6 +101,8 @@ async function* checkDeploymentStatus(deployment, clientOptions) {
71
101
  const { token, teamId, apiUrl, userAgent } = clientOptions;
72
102
  const debug = (0, import_utils2.createDebug)(clientOptions.debug);
73
103
  let deploymentState = deployment;
104
+ const deploymentId = deployment.id || deployment.deploymentId;
105
+ let aliasAssignedSignal = clientOptions.aliasAssignedSignal;
74
106
  const apiDeployments = (0, import_utils.getApiDeploymentsUrl)();
75
107
  if ((0, import_ready_state.isDone)(deploymentState) && (0, import_ready_state.isAliasAssigned)(deploymentState)) {
76
108
  debug(
@@ -81,109 +113,172 @@ async function* checkDeploymentStatus(deployment, clientOptions) {
81
113
  debug("Waiting for builds and the deployment to complete...");
82
114
  const finishedEvents = /* @__PURE__ */ new Set();
83
115
  const startTime = Date.now();
84
- while (true) {
85
- let deploymentResponse;
86
- let retriesLeft = RETRY_COUNT;
116
+ polling:
87
117
  while (true) {
88
- deploymentResponse = await (0, import_utils.fetchApi)(
89
- `${apiDeployments}/${deployment.id || deployment.deploymentId}${teamId ? `?teamId=${teamId}` : ""}`,
90
- token,
91
- { apiUrl, userAgent, agent: clientOptions.agent }
118
+ const aliasAssignedEvent = getAliasAssignedEvent(
119
+ aliasAssignedSignal,
120
+ deploymentId
92
121
  );
93
- retriesLeft--;
94
- if (retriesLeft == 0) {
122
+ if (aliasAssignedEvent) {
123
+ deploymentState = {
124
+ ...deploymentState,
125
+ readyState: "READY",
126
+ aliasAssigned: aliasAssignedEvent.date,
127
+ alias: aliasAssignedEvent.alias,
128
+ aliasError: aliasAssignedEvent.aliasError,
129
+ aliasWarning: aliasAssignedEvent.aliasWarning
130
+ };
131
+ if (!finishedEvents.has("ready")) {
132
+ debug("Deployment state changed to READY");
133
+ finishedEvents.add("ready");
134
+ yield { type: "ready", payload: deploymentState };
135
+ }
136
+ debug("Deployment alias assigned from event stream");
137
+ return yield { type: "alias-assigned", payload: deploymentState };
138
+ }
139
+ let deploymentResponse;
140
+ let retriesLeft = RETRY_COUNT;
141
+ while (true) {
142
+ try {
143
+ deploymentResponse = await (0, import_utils.fetchApi)(
144
+ `${apiDeployments}/${deploymentId}${teamId ? `?teamId=${teamId}` : ""}`,
145
+ token,
146
+ {
147
+ apiUrl,
148
+ userAgent,
149
+ agent: clientOptions.agent,
150
+ // node-fetch's bundled AbortSignal type predates the native one.
151
+ signal: aliasAssignedSignal
152
+ }
153
+ );
154
+ } catch (error) {
155
+ if (getAliasAssignedEvent(aliasAssignedSignal, deploymentId)) {
156
+ continue polling;
157
+ }
158
+ if (aliasAssignedSignal?.aborted) {
159
+ aliasAssignedSignal = void 0;
160
+ continue polling;
161
+ }
162
+ throw error;
163
+ }
164
+ if (getAliasAssignedEvent(aliasAssignedSignal, deploymentId)) {
165
+ continue polling;
166
+ }
167
+ retriesLeft--;
168
+ if (retriesLeft == 0) {
169
+ break;
170
+ }
171
+ const retryAfterMs = parseRetryAfterMs(deploymentResponse);
172
+ if (retryAfterMs != null) {
173
+ const randomSkewMs = Math.floor(RETRY_DELAY_SKEW_MS * Math.random());
174
+ debug(
175
+ `Received a transient error or rate limit (HTTP ${deploymentResponse.status}) while querying deployment status, retrying after ${retryAfterMs + randomSkewMs}ms (${retryAfterMs} + ${randomSkewMs}ms of random skew)`
176
+ );
177
+ await sleepUntilAliasAssigned(
178
+ retryAfterMs + randomSkewMs,
179
+ aliasAssignedSignal,
180
+ deploymentId
181
+ );
182
+ if (getAliasAssignedEvent(aliasAssignedSignal, deploymentId)) {
183
+ continue polling;
184
+ }
185
+ continue;
186
+ }
95
187
  break;
96
188
  }
97
- const retryAfterMs = parseRetryAfterMs(deploymentResponse);
98
- if (retryAfterMs != null) {
99
- const randomSkewMs = Math.floor(RETRY_DELAY_SKEW_MS * Math.random());
100
- debug(
101
- `Received a transient error or rate limit (HTTP ${deploymentResponse.status}) while querying deployment status, retrying after ${retryAfterMs + randomSkewMs}ms (${retryAfterMs} + ${randomSkewMs}ms of random skew)`
102
- );
103
- await (0, import_sleep_promise.default)(retryAfterMs + randomSkewMs);
189
+ let deploymentUpdate;
190
+ try {
191
+ deploymentUpdate = await deploymentResponse.json();
192
+ } catch (error) {
193
+ if (getAliasAssignedEvent(aliasAssignedSignal, deploymentId))
194
+ continue;
195
+ if (aliasAssignedSignal?.aborted) {
196
+ aliasAssignedSignal = void 0;
197
+ continue;
198
+ }
199
+ throw error;
200
+ }
201
+ if (getAliasAssignedEvent(aliasAssignedSignal, deploymentId))
104
202
  continue;
203
+ if (deploymentUpdate.error) {
204
+ debug("Deployment status check has errorred");
205
+ return yield { type: "error", payload: deploymentUpdate.error };
105
206
  }
106
- break;
107
- }
108
- const deploymentUpdate = await deploymentResponse.json();
109
- if (deploymentUpdate.error) {
110
- debug("Deployment status check has errorred");
111
- return yield { type: "error", payload: deploymentUpdate.error };
112
- }
113
- if (deploymentUpdate.readyState === "BUILDING" && !finishedEvents.has("building")) {
114
- debug("Deployment state changed to BUILDING");
115
- finishedEvents.add("building");
116
- yield { type: "building", payload: deploymentUpdate };
117
- }
118
- if (deploymentUpdate.readyState === "CANCELED" && !finishedEvents.has("canceled")) {
119
- debug("Deployment state changed to CANCELED");
120
- finishedEvents.add("canceled");
121
- yield { type: "canceled", payload: deploymentUpdate };
122
- }
123
- if ((0, import_ready_state.isReady)(deploymentUpdate) && !finishedEvents.has("ready")) {
124
- debug("Deployment state changed to READY");
125
- finishedEvents.add("ready");
126
- yield { type: "ready", payload: deploymentUpdate };
127
- }
128
- if (deploymentUpdate.checksState !== void 0) {
129
- if (deploymentUpdate.checksState === "completed" && !finishedEvents.has("checks-completed")) {
130
- finishedEvents.add("checks-completed");
131
- if (deploymentUpdate.checksConclusion === "succeeded") {
132
- yield {
133
- type: "checks-conclusion-succeeded",
134
- payload: deploymentUpdate
135
- };
136
- } else if (deploymentUpdate.checksConclusion === "failed") {
137
- yield { type: "checks-conclusion-failed", payload: deploymentUpdate };
138
- } else if (deploymentUpdate.checksConclusion === "skipped") {
139
- yield {
140
- type: "checks-conclusion-skipped",
141
- payload: deploymentUpdate
142
- };
143
- } else if (deploymentUpdate.checksConclusion === "canceled") {
144
- yield {
145
- type: "checks-conclusion-canceled",
146
- payload: deploymentUpdate
147
- };
207
+ deploymentState = deploymentUpdate;
208
+ if (deploymentUpdate.readyState === "BUILDING" && !finishedEvents.has("building")) {
209
+ debug("Deployment state changed to BUILDING");
210
+ finishedEvents.add("building");
211
+ yield { type: "building", payload: deploymentUpdate };
212
+ }
213
+ if (deploymentUpdate.readyState === "CANCELED" && !finishedEvents.has("canceled")) {
214
+ debug("Deployment state changed to CANCELED");
215
+ finishedEvents.add("canceled");
216
+ yield { type: "canceled", payload: deploymentUpdate };
217
+ }
218
+ if ((0, import_ready_state.isReady)(deploymentUpdate) && !finishedEvents.has("ready")) {
219
+ debug("Deployment state changed to READY");
220
+ finishedEvents.add("ready");
221
+ yield { type: "ready", payload: deploymentUpdate };
222
+ }
223
+ if (deploymentUpdate.checksState !== void 0) {
224
+ if (deploymentUpdate.checksState === "completed" && !finishedEvents.has("checks-completed")) {
225
+ finishedEvents.add("checks-completed");
226
+ if (deploymentUpdate.checksConclusion === "succeeded") {
227
+ yield {
228
+ type: "checks-conclusion-succeeded",
229
+ payload: deploymentUpdate
230
+ };
231
+ } else if (deploymentUpdate.checksConclusion === "failed") {
232
+ yield { type: "checks-conclusion-failed", payload: deploymentUpdate };
233
+ } else if (deploymentUpdate.checksConclusion === "skipped") {
234
+ yield {
235
+ type: "checks-conclusion-skipped",
236
+ payload: deploymentUpdate
237
+ };
238
+ } else if (deploymentUpdate.checksConclusion === "canceled") {
239
+ yield {
240
+ type: "checks-conclusion-canceled",
241
+ payload: deploymentUpdate
242
+ };
243
+ }
244
+ }
245
+ if (deploymentUpdate.checksState === "registered" && !finishedEvents.has("checks-registered")) {
246
+ finishedEvents.add("checks-registered");
247
+ yield { type: "checks-registered", payload: deploymentUpdate };
248
+ }
249
+ if (deploymentUpdate.checksState === "running" && !finishedEvents.has("checks-running")) {
250
+ finishedEvents.add("checks-running");
251
+ yield { type: "checks-running", payload: deploymentUpdate };
148
252
  }
149
253
  }
150
- if (deploymentUpdate.checksState === "registered" && !finishedEvents.has("checks-registered")) {
151
- finishedEvents.add("checks-registered");
152
- yield { type: "checks-registered", payload: deploymentUpdate };
254
+ if (deploymentUpdate.checks?.["deployment-alias"]?.state === "failed" && !finishedEvents.has("checks-v2-failed")) {
255
+ debug("v2 deployment-alias check failed");
256
+ finishedEvents.add("checks-v2-failed");
257
+ return yield {
258
+ type: "checks-v2-failed",
259
+ payload: deploymentUpdate
260
+ };
153
261
  }
154
- if (deploymentUpdate.checksState === "running" && !finishedEvents.has("checks-running")) {
155
- finishedEvents.add("checks-running");
156
- yield { type: "checks-running", payload: deploymentUpdate };
262
+ if ((0, import_ready_state.isAliasAssigned)(deploymentUpdate)) {
263
+ debug("Deployment alias assigned");
264
+ return yield { type: "alias-assigned", payload: deploymentUpdate };
157
265
  }
266
+ if ((0, import_ready_state.isAliasError)(deploymentUpdate)) {
267
+ return yield { type: "error", payload: deploymentUpdate.aliasError };
268
+ }
269
+ if (deploymentUpdate.readyState === "ERROR" && deploymentUpdate.errorCode === "BUILD_FAILED") {
270
+ return yield { type: "error", payload: deploymentUpdate };
271
+ }
272
+ if ((0, import_ready_state.isFailed)(deploymentUpdate)) {
273
+ return yield {
274
+ type: "error",
275
+ payload: deploymentUpdate.error || deploymentUpdate
276
+ };
277
+ }
278
+ const elapsed = Date.now() - startTime;
279
+ const duration = (0, import_get_polling_delay.getPollingDelay)(elapsed);
280
+ await sleepUntilAliasAssigned(duration, aliasAssignedSignal, deploymentId);
158
281
  }
159
- if (deploymentUpdate.checks?.["deployment-alias"]?.state === "failed" && !finishedEvents.has("checks-v2-failed")) {
160
- debug("v2 deployment-alias check failed");
161
- finishedEvents.add("checks-v2-failed");
162
- return yield {
163
- type: "checks-v2-failed",
164
- payload: deploymentUpdate
165
- };
166
- }
167
- if ((0, import_ready_state.isAliasAssigned)(deploymentUpdate)) {
168
- debug("Deployment alias assigned");
169
- return yield { type: "alias-assigned", payload: deploymentUpdate };
170
- }
171
- if ((0, import_ready_state.isAliasError)(deploymentUpdate)) {
172
- return yield { type: "error", payload: deploymentUpdate.aliasError };
173
- }
174
- if (deploymentUpdate.readyState === "ERROR" && deploymentUpdate.errorCode === "BUILD_FAILED") {
175
- return yield { type: "error", payload: deploymentUpdate };
176
- }
177
- if ((0, import_ready_state.isFailed)(deploymentUpdate)) {
178
- return yield {
179
- type: "error",
180
- payload: deploymentUpdate.error || deploymentUpdate
181
- };
182
- }
183
- const elapsed = Date.now() - startTime;
184
- const duration = (0, import_get_polling_delay.getPollingDelay)(elapsed);
185
- await (0, import_sleep_promise.default)(duration);
186
- }
187
282
  }
188
283
  // Annotate the CommonJS export names for ESM import in node:
189
284
  0 && (module.exports = {
package/dist/types.d.ts CHANGED
@@ -7,6 +7,22 @@ export interface Dictionary<T> {
7
7
  }
8
8
  export declare const VALID_ARCHIVE_FORMATS: readonly ["tgz"];
9
9
  export type ArchiveFormat = (typeof VALID_ARCHIVE_FORMATS)[number];
10
+ export interface DeploymentAliasError {
11
+ code: string;
12
+ message: string;
13
+ }
14
+ export interface DeploymentAliasWarning extends DeploymentAliasError {
15
+ link?: string;
16
+ action?: string;
17
+ }
18
+ export interface DeploymentAliasAssignedEvent {
19
+ type: 'alias-assigned';
20
+ deploymentId: string;
21
+ date: number;
22
+ alias: string[];
23
+ aliasError: DeploymentAliasError | null;
24
+ aliasWarning: DeploymentAliasWarning | null;
25
+ }
10
26
  export interface VercelClientOptions {
11
27
  token: string;
12
28
  path: string | string[];
@@ -35,6 +51,11 @@ export interface VercelClientOptions {
35
51
  * that the user later continues the deployment with an API call.
36
52
  */
37
53
  manual?: boolean;
54
+ /**
55
+ * Aborted with a `DeploymentAliasAssignedEvent` when an existing deployment
56
+ * event stream observes alias assignment.
57
+ */
58
+ aliasAssignedSignal?: AbortSignal;
38
59
  }
39
60
  /** @deprecated Use VercelClientOptions instead. */
40
61
  export type NowClientOptions = VercelClientOptions;
@@ -73,8 +94,9 @@ export interface Deployment {
73
94
  };
74
95
  target: string;
75
96
  alias: string[];
76
- aliasAssigned: boolean;
77
- aliasError: string | null;
97
+ aliasAssigned: boolean | number | null;
98
+ aliasError: string | DeploymentAliasError | null;
99
+ aliasWarning?: DeploymentAliasWarning | null;
78
100
  checks?: Record<string, {
79
101
  state: 'pending' | 'succeeded' | 'failed';
80
102
  startedAt?: string;
@@ -6,7 +6,7 @@ type Ignore = ReturnType<typeof ignore>;
6
6
  export declare const API_FILES = "/v2/files";
7
7
  declare const EVENTS_ARRAY: readonly ["hashes-calculated", "file-count", "file-uploaded", "all-files-uploaded", "created", "building", "ready", "alias-assigned", "warning", "error", "notice", "tip", "canceled", "checks-registered", "checks-completed", "checks-running", "checks-conclusion-succeeded", "checks-conclusion-failed", "checks-conclusion-skipped", "checks-conclusion-canceled", "checks-v2-failed"];
8
8
  export type DeploymentEventType = (typeof EVENTS_ARRAY)[number];
9
- export declare const EVENTS: Set<"hashes-calculated" | "file-count" | "file-uploaded" | "all-files-uploaded" | "created" | "building" | "ready" | "alias-assigned" | "warning" | "error" | "notice" | "tip" | "canceled" | "checks-registered" | "checks-completed" | "checks-running" | "checks-conclusion-succeeded" | "checks-conclusion-failed" | "checks-conclusion-skipped" | "checks-conclusion-canceled" | "checks-v2-failed">;
9
+ export declare const EVENTS: Set<"alias-assigned" | "hashes-calculated" | "file-count" | "file-uploaded" | "all-files-uploaded" | "created" | "building" | "ready" | "warning" | "error" | "notice" | "tip" | "canceled" | "checks-registered" | "checks-completed" | "checks-running" | "checks-conclusion-succeeded" | "checks-conclusion-failed" | "checks-conclusion-skipped" | "checks-conclusion-canceled" | "checks-v2-failed">;
10
10
  export declare function getApiDeploymentsUrl(): string;
11
11
  export declare function parseVercelConfig(filePath?: string): Promise<VercelConfig>;
12
12
  export declare function buildFileTree(path: string | string[], { isDirectory, prebuilt, vercelOutputDir, rootDirectory, projectName, bulkRedirectsPath, }: Pick<VercelClientOptions, 'isDirectory' | 'prebuilt' | 'vercelOutputDir' | 'rootDirectory' | 'projectName' | 'bulkRedirectsPath'>, debug: Debug): Promise<{
@@ -322,10 +322,13 @@ const fetchApi = async (url, token, opts = {}, debugEnabled) => {
322
322
  };
323
323
  debug(`${opts.method || "GET"} ${url}`);
324
324
  time = Date.now();
325
- const res = await (0, import_node_fetch.default)(url, opts);
326
- debug(`DONE in ${Date.now() - time}ms: ${opts.method || "GET"} ${url}`);
327
- semaphore.release();
328
- return res;
325
+ try {
326
+ const res = await (0, import_node_fetch.default)(url, opts);
327
+ debug(`DONE in ${Date.now() - time}ms: ${opts.method || "GET"} ${url}`);
328
+ return res;
329
+ } finally {
330
+ semaphore.release();
331
+ }
329
332
  };
330
333
  const isWin = process.platform.includes("win");
331
334
  const prepareFiles = (files, clientOptions) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/client",
3
- "version": "17.6.3",
3
+ "version": "17.6.5",
4
4
  "main": "dist/index.js",
5
5
  "typings": "dist/index.d.ts",
6
6
  "homepage": "https://vercel.com",
@@ -39,9 +39,9 @@
39
39
  "querystring": "^0.2.0",
40
40
  "sleep-promise": "8.0.1",
41
41
  "tar-fs": "1.16.3",
42
- "@vercel/build-utils": "13.32.2",
43
- "@vercel/routing-utils": "6.4.0",
44
- "@vercel/error-utils": "2.2.0"
42
+ "@vercel/build-utils": "13.33.0",
43
+ "@vercel/error-utils": "2.2.0",
44
+ "@vercel/routing-utils": "6.4.0"
45
45
  },
46
46
  "scripts": {
47
47
  "build": "node ../../utils/build.mjs",