@vercel/client 17.3.0-canary.20260211174907.cdd2da6 → 17.3.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.
@@ -85,7 +85,7 @@ async function* checkDeploymentStatus(deployment, clientOptions) {
85
85
  let deploymentResponse;
86
86
  let retriesLeft = RETRY_COUNT;
87
87
  while (true) {
88
- deploymentResponse = await (0, import_utils.fetch)(
88
+ deploymentResponse = await (0, import_utils.fetchApi)(
89
89
  `${apiDeployments}/${deployment.id || deployment.deploymentId}${teamId ? `?teamId=${teamId}` : ""}`,
90
90
  token,
91
91
  { apiUrl, userAgent, agent: clientOptions.agent }
@@ -156,6 +156,14 @@ async function* checkDeploymentStatus(deployment, clientOptions) {
156
156
  yield { type: "checks-running", payload: deploymentUpdate };
157
157
  }
158
158
  }
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
+ }
159
167
  if ((0, import_ready_state.isAliasAssigned)(deploymentUpdate)) {
160
168
  debug("Deployment alias assigned");
161
169
  return yield { type: "alias-assigned", payload: deploymentUpdate };
@@ -0,0 +1,23 @@
1
+ /// <reference types="node" />
2
+ import type { Agent } from 'http';
3
+ import type { ArchiveFormat, DeploymentEventType } from './types';
4
+ /**
5
+ * Continues a manual deployment by uploading build outputs and calling the
6
+ * continue endpoint. Waits for READY state unless the caller stops consuming
7
+ * events early.
8
+ */
9
+ export declare function continueDeployment(options: {
10
+ agent?: Agent;
11
+ apiUrl?: string;
12
+ debug?: boolean;
13
+ deploymentId: string;
14
+ path: string;
15
+ teamId?: string;
16
+ token: string;
17
+ userAgent?: string;
18
+ vercelOutputDir?: string;
19
+ archive?: ArchiveFormat;
20
+ }): AsyncIterableIterator<{
21
+ type: DeploymentEventType;
22
+ payload: any;
23
+ }>;
@@ -0,0 +1,224 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var continue_exports = {};
30
+ __export(continue_exports, {
31
+ continueDeployment: () => continueDeployment
32
+ });
33
+ module.exports = __toCommonJS(continue_exports);
34
+ var import_path = require("path");
35
+ var import_fs_extra = __toESM(require("fs-extra"));
36
+ var import_check_deployment_status = require("./check-deployment-status");
37
+ var import_utils = require("./utils");
38
+ var import_hashes = require("./utils/hashes");
39
+ var import_ready_state = require("./utils/ready-state");
40
+ var import_upload = require("./upload");
41
+ var import_errors = require("./errors");
42
+ var import_archive = require("./utils/archive");
43
+ async function* continueDeployment(options) {
44
+ const debug = (0, import_utils.createDebug)(options.debug);
45
+ debug(`Continuing deployment: ${options.deploymentId}`);
46
+ const outputDir = options.vercelOutputDir || (0, import_path.join)(options.path, ".vercel", "output");
47
+ if (!await import_fs_extra.default.pathExists(outputDir)) {
48
+ return yield {
49
+ type: "error",
50
+ payload: new import_errors.DeploymentError({
51
+ code: "output_dir_not_found",
52
+ message: `Output directory not found at ${outputDir}. Run 'vercel build' first.`
53
+ })
54
+ };
55
+ }
56
+ const { fileList } = await (0, import_utils.buildFileTree)(
57
+ options.path,
58
+ { isDirectory: true, prebuilt: true, vercelOutputDir: outputDir },
59
+ debug
60
+ );
61
+ const provisionJsonPath = (0, import_path.join)(outputDir, "provision.json");
62
+ const unbundledFiles = fileList.filter((f) => f === provisionJsonPath);
63
+ let files;
64
+ if (options.archive === "tgz") {
65
+ files = await (0, import_archive.createTgzFiles)(options.path, fileList, debug, unbundledFiles);
66
+ if (unbundledFiles.length > 0) {
67
+ const individualFiles = await (0, import_hashes.hashes)(unbundledFiles);
68
+ for (const [sha, entry] of individualFiles) {
69
+ files.set(sha, entry);
70
+ }
71
+ }
72
+ } else {
73
+ files = await (0, import_hashes.hashes)(fileList);
74
+ }
75
+ debug(`Calculated ${files.size} unique hashes`);
76
+ yield { type: "hashes-calculated", payload: (0, import_hashes.mapToObject)(files) };
77
+ let deployment;
78
+ let result = await postContinue({
79
+ deploymentId: options.deploymentId,
80
+ files,
81
+ outputDir,
82
+ path: options.path,
83
+ token: options.token,
84
+ teamId: options.teamId,
85
+ apiUrl: options.apiUrl,
86
+ userAgent: options.userAgent,
87
+ agent: options.agent,
88
+ debug: options.debug
89
+ });
90
+ if (result.type === "missing_files") {
91
+ debug(`Uploading ${result.missing.length} missing files...`);
92
+ const uploads = result.missing.map(
93
+ (sha) => new import_upload.UploadProgress(sha, files.get(sha))
94
+ );
95
+ yield {
96
+ type: "file-count",
97
+ payload: { total: files, missing: result.missing, uploads }
98
+ };
99
+ for await (const event of (0, import_upload.uploadFiles)({
100
+ agent: options.agent,
101
+ apiUrl: options.apiUrl,
102
+ debug: options.debug,
103
+ teamId: options.teamId,
104
+ token: options.token,
105
+ userAgent: options.userAgent,
106
+ shas: result.missing,
107
+ files,
108
+ uploads
109
+ })) {
110
+ if (event.type === "error") {
111
+ return yield event;
112
+ }
113
+ yield event;
114
+ }
115
+ yield { type: "all-files-uploaded", payload: files };
116
+ result = await postContinue({
117
+ deploymentId: options.deploymentId,
118
+ files,
119
+ outputDir,
120
+ path: options.path,
121
+ token: options.token,
122
+ teamId: options.teamId,
123
+ apiUrl: options.apiUrl,
124
+ userAgent: options.userAgent,
125
+ agent: options.agent,
126
+ debug: options.debug
127
+ });
128
+ if (result.type === "missing_files") {
129
+ return yield {
130
+ type: "error",
131
+ payload: {
132
+ code: "missing_files",
133
+ message: "Missing files",
134
+ missing: result.missing
135
+ }
136
+ };
137
+ }
138
+ }
139
+ if (result.type === "error") {
140
+ return yield { type: "error", payload: result.error };
141
+ }
142
+ if (result.type === "success") {
143
+ deployment = result.deployment;
144
+ yield { type: "created", payload: deployment };
145
+ }
146
+ if (!deployment) {
147
+ return yield {
148
+ type: "error",
149
+ payload: new import_errors.DeploymentError({
150
+ code: "continue_failed",
151
+ message: "Failed to continue deployment after uploading files"
152
+ })
153
+ };
154
+ }
155
+ if ((0, import_ready_state.isReady)(deployment) && (0, import_ready_state.isAliasAssigned)(deployment)) {
156
+ yield { type: "ready", payload: deployment };
157
+ return yield { type: "alias-assigned", payload: deployment };
158
+ }
159
+ yield* (0, import_check_deployment_status.checkDeploymentStatus)(deployment, {
160
+ agent: options.agent,
161
+ apiUrl: options.apiUrl,
162
+ debug: options.debug,
163
+ path: options.path,
164
+ teamId: options.teamId,
165
+ token: options.token,
166
+ userAgent: options.userAgent
167
+ });
168
+ }
169
+ async function postContinue(options) {
170
+ const debug = (0, import_utils.createDebug)(options.debug);
171
+ debug(`Calling continue deployment endpoint for ${options.deploymentId}`);
172
+ const response = await (0, import_utils.fetchApi)(
173
+ `/deployments/${options.deploymentId}/continue${options.teamId ? `?teamId=${options.teamId}` : ""}`,
174
+ options.token,
175
+ {
176
+ method: "POST",
177
+ headers: {
178
+ Accept: "application/json",
179
+ "Content-Type": "application/json"
180
+ },
181
+ body: JSON.stringify({
182
+ files: (0, import_utils.prepareFiles)(options.files, {
183
+ isDirectory: true,
184
+ path: options.path,
185
+ token: options.token
186
+ })
187
+ }),
188
+ apiUrl: options.apiUrl,
189
+ userAgent: options.userAgent,
190
+ agent: options.agent
191
+ }
192
+ );
193
+ let result;
194
+ try {
195
+ result = await response.json();
196
+ } catch {
197
+ return {
198
+ type: "error",
199
+ error: new Error("Invalid JSON response from continue endpoint")
200
+ };
201
+ }
202
+ if (!response.ok || result.error) {
203
+ if (result.error?.code === "missing_files" || result.code === "missing_files") {
204
+ debug(
205
+ `Continue deployment returned missing_files: ${(result.error?.missing || result.missing || []).length} files`
206
+ );
207
+ return {
208
+ type: "missing_files",
209
+ missing: result.error?.missing || result.missing || []
210
+ };
211
+ }
212
+ debug("Continue deployment request failed");
213
+ return {
214
+ type: "error",
215
+ error: result.error ? { ...result.error, status: response.status } : { ...result, status: response.status }
216
+ };
217
+ }
218
+ debug("Continue deployment succeeded");
219
+ return { type: "success", deployment: result };
220
+ }
221
+ // Annotate the CommonJS export names for ESM import in node:
222
+ 0 && (module.exports = {
223
+ continueDeployment
224
+ });
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,14 +15,6 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
  var create_deployment_exports = {};
30
20
  __export(create_deployment_exports, {
@@ -34,13 +24,12 @@ module.exports = __toCommonJS(create_deployment_exports);
34
24
  var import_fs_extra = require("fs-extra");
35
25
  var import_path = require("path");
36
26
  var import_hashes = require("./utils/hashes");
27
+ var import_deploy = require("./deploy");
37
28
  var import_upload = require("./upload");
38
29
  var import_utils = require("./utils");
39
30
  var import_errors = require("./errors");
40
31
  var import_error_utils = require("@vercel/error-utils");
41
- var import_build_utils = require("@vercel/build-utils");
42
- var import_tar_fs = __toESM(require("tar-fs"));
43
- var import_zlib = require("zlib");
32
+ var import_archive = require("./utils/archive");
44
33
  function buildCreateDeployment() {
45
34
  return async function* createDeployment(clientOptions, deploymentOptions = {}) {
46
35
  const { path } = clientOptions;
@@ -64,6 +53,22 @@ function buildCreateDeployment() {
64
53
  message: "Options object must include a `token`"
65
54
  });
66
55
  }
56
+ if (clientOptions.manual) {
57
+ debug("Manual provisioning mode enabled");
58
+ if (!clientOptions.prebuilt) {
59
+ throw new import_errors.DeploymentError({
60
+ code: "invalid_options",
61
+ message: "The `manual` option requires `prebuilt` to be true"
62
+ });
63
+ }
64
+ deploymentOptions.build = deploymentOptions.build || {};
65
+ deploymentOptions.build.env = deploymentOptions.build.env || {};
66
+ deploymentOptions.build.env.VERCEL_MANUAL_PROVISIONING = "1";
67
+ deploymentOptions.version = 2;
68
+ debug("Creating deployment with manual provisioning...");
69
+ yield* (0, import_deploy.deploy)(/* @__PURE__ */ new Map(), clientOptions, deploymentOptions);
70
+ return;
71
+ }
67
72
  clientOptions.isDirectory = !Array.isArray(path) && (0, import_fs_extra.lstatSync)(path).isDirectory();
68
73
  if (Array.isArray(path)) {
69
74
  for (const filePath of path) {
@@ -99,22 +104,7 @@ function buildCreateDeployment() {
99
104
  let files;
100
105
  try {
101
106
  if (clientOptions.archive === "tgz") {
102
- debug("Packing tarball");
103
- const tarStream = import_tar_fs.default.pack(workPath, {
104
- entries: fileList.map((file) => (0, import_path.relative)(workPath, file))
105
- }).pipe((0, import_zlib.createGzip)());
106
- const chunkedTarBuffers = await (0, import_build_utils.streamToBufferChunks)(tarStream);
107
- debug(`Packed tarball into ${chunkedTarBuffers.length} chunks`);
108
- files = new Map(
109
- chunkedTarBuffers.map((chunk, index) => [
110
- (0, import_hashes.hash)(chunk),
111
- {
112
- names: [(0, import_path.join)(workPath, `.vercel/source.tgz.part${index + 1}`)],
113
- data: chunk,
114
- mode: 438
115
- }
116
- ])
117
- );
107
+ files = await (0, import_archive.createTgzFiles)(workPath, fileList, debug);
118
108
  } else {
119
109
  files = await (0, import_hashes.hashes)(fileList);
120
110
  }
package/dist/deploy.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { FilesMap } from './utils/hashes';
2
- import { DeploymentOptions, VercelClientOptions } from './types';
2
+ import { DeploymentOptions, VercelClientOptions, DeploymentEventType } from './types';
3
3
  export declare function deploy(files: FilesMap, clientOptions: VercelClientOptions, deploymentOptions: DeploymentOptions): AsyncIterableIterator<{
4
- type: string;
4
+ type: DeploymentEventType;
5
5
  payload: any;
6
6
  }>;
package/dist/deploy.js CHANGED
@@ -41,7 +41,7 @@ async function* postDeployment(files, clientOptions, deploymentOptions) {
41
41
  }
42
42
  debug("Sending deployment creation API request");
43
43
  try {
44
- const response = await (0, import_utils.fetch)(
44
+ const response = await (0, import_utils.fetchApi)(
45
45
  `${apiDeployments}${(0, import_query_string.generateQueryString)(clientOptions)}`,
46
46
  clientOptions.token,
47
47
  {
@@ -62,7 +62,7 @@ async function* postDeployment(files, clientOptions, deploymentOptions) {
62
62
  let deployment = void 0;
63
63
  try {
64
64
  deployment = await response.json();
65
- } catch (error) {
65
+ } catch (_error) {
66
66
  throw new Error("Invalid JSON response");
67
67
  }
68
68
  if (clientOptions.debug) {
@@ -110,14 +110,14 @@ function getDefaultName(files, clientOptions) {
110
110
  }
111
111
  async function* deploy(files, clientOptions, deploymentOptions) {
112
112
  const debug = (0, import_utils.createDebug)(clientOptions.debug);
113
- if (!deploymentOptions.name) {
113
+ if (!deploymentOptions.name && files.size > 0) {
114
114
  deploymentOptions.version = 2;
115
115
  deploymentOptions.name = files.size === 1 ? "file" : getDefaultName(files, clientOptions);
116
116
  if (deploymentOptions.name === "file") {
117
117
  debug('Setting deployment name to "file" for single-file deployment');
118
118
  }
119
119
  }
120
- if (!deploymentOptions.name) {
120
+ if (!deploymentOptions.name && files.size > 0) {
121
121
  deploymentOptions.name = clientOptions.defaultName || getDefaultName(files, clientOptions);
122
122
  debug("No name provided. Defaulting to", deploymentOptions.name);
123
123
  }
@@ -144,6 +144,10 @@ async function* deploy(files, clientOptions, deploymentOptions) {
144
144
  debug("An unexpected error occurred when creating the deployment");
145
145
  return yield { type: "error", payload: e };
146
146
  }
147
+ if (clientOptions.manual) {
148
+ debug("Manual mode - skipping ready state check");
149
+ return;
150
+ }
147
151
  if (deployment) {
148
152
  if ((0, import_ready_state.isReady)(deployment) && (0, import_ready_state.isAliasAssigned)(deployment)) {
149
153
  debug("Deployment state changed to READY 3");
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
+ export { continueDeployment } from './continue';
1
2
  export { checkDeploymentStatus } from './check-deployment-status';
2
3
  export { getVercelIgnore, buildFileTree } from './utils/index';
3
4
  export declare const createDeployment: (clientOptions: import("./types").VercelClientOptions, deploymentOptions?: import("./types").DeploymentOptions) => AsyncIterableIterator<{
4
- type: "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";
5
+ type: "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";
5
6
  payload: any;
6
7
  }>;
7
8
  export * from './errors';
package/dist/index.js CHANGED
@@ -31,11 +31,13 @@ var src_exports = {};
31
31
  __export(src_exports, {
32
32
  buildFileTree: () => import_utils.buildFileTree,
33
33
  checkDeploymentStatus: () => import_check_deployment_status.checkDeploymentStatus,
34
+ continueDeployment: () => import_continue.continueDeployment,
34
35
  createDeployment: () => createDeployment,
35
36
  getVercelIgnore: () => import_utils.getVercelIgnore
36
37
  });
37
38
  module.exports = __toCommonJS(src_exports);
38
39
  var import_create_deployment = __toESM(require("./create-deployment"));
40
+ var import_continue = require("./continue");
39
41
  var import_check_deployment_status = require("./check-deployment-status");
40
42
  var import_utils = require("./utils/index");
41
43
  __reExport(src_exports, require("./errors"), module.exports);
@@ -45,6 +47,7 @@ const createDeployment = (0, import_create_deployment.default)();
45
47
  0 && (module.exports = {
46
48
  buildFileTree,
47
49
  checkDeploymentStatus,
50
+ continueDeployment,
48
51
  createDeployment,
49
52
  getVercelIgnore,
50
53
  ...require("./errors"),
package/dist/types.d.ts CHANGED
@@ -31,6 +31,11 @@ export interface VercelClientOptions {
31
31
  * This file will be included in prebuilt deployments.
32
32
  */
33
33
  bulkRedirectsPath?: string | null;
34
+ /**
35
+ * When true, creates an experimental manual deployment. This mode requires
36
+ * that the user later continues the deployment with an API call.
37
+ */
38
+ manual?: boolean;
34
39
  }
35
40
  /** @deprecated Use VercelClientOptions instead. */
36
41
  export type NowClientOptions = VercelClientOptions;
@@ -71,6 +76,11 @@ export interface Deployment {
71
76
  alias: string[];
72
77
  aliasAssigned: boolean;
73
78
  aliasError: string | null;
79
+ checks?: Record<string, {
80
+ state: 'pending' | 'succeeded' | 'failed';
81
+ startedAt?: string;
82
+ completedAt?: string;
83
+ }>;
74
84
  expiration?: number;
75
85
  proposedExpiration?: number;
76
86
  undeletedAt?: number;
package/dist/upload.d.ts CHANGED
@@ -1,3 +1,30 @@
1
- import { FilesMap } from './utils/hashes';
2
- import { VercelClientOptions, DeploymentOptions } from './types';
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ import { EventEmitter } from 'node:events';
4
+ import { DeploymentFile, FilesMap } from './utils/hashes';
5
+ import type { Agent } from 'http';
6
+ import type { VercelClientOptions, DeploymentOptions, DeploymentEventType } from './types';
3
7
  export declare function upload(files: FilesMap, clientOptions: VercelClientOptions, deploymentOptions: DeploymentOptions): AsyncIterableIterator<any>;
8
+ /**
9
+ * Uploads files to the /v2/files endpoint with retry and fault tolerance.
10
+ */
11
+ export declare function uploadFiles(options: {
12
+ agent?: Agent;
13
+ apiUrl?: string;
14
+ debug?: boolean;
15
+ files: FilesMap;
16
+ shas: string[];
17
+ teamId?: string;
18
+ token: string;
19
+ uploads: UploadProgress[];
20
+ userAgent?: string;
21
+ }): AsyncIterableIterator<{
22
+ type: DeploymentEventType;
23
+ payload: any;
24
+ }>;
25
+ export declare class UploadProgress extends EventEmitter {
26
+ sha: string;
27
+ file: DeploymentFile;
28
+ bytesUploaded: number;
29
+ constructor(sha: string, file: DeploymentFile);
30
+ }
package/dist/upload.js CHANGED
@@ -28,7 +28,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
  var upload_exports = {};
30
30
  __export(upload_exports, {
31
- upload: () => upload
31
+ UploadProgress: () => UploadProgress,
32
+ upload: () => upload,
33
+ uploadFiles: () => uploadFiles
32
34
  });
33
35
  module.exports = __toCommonJS(upload_exports);
34
36
  var import_http = __toESM(require("http"));
@@ -47,9 +49,8 @@ const isClientNetworkError = (err) => {
47
49
  return false;
48
50
  };
49
51
  async function* upload(files, clientOptions, deploymentOptions) {
50
- const { token, teamId, apiUrl, userAgent } = clientOptions;
51
52
  const debug = (0, import_utils.createDebug)(clientOptions.debug);
52
- if (!files && !token && !teamId) {
53
+ if (!files && !clientOptions.token && !clientOptions.teamId) {
53
54
  debug(`Neither 'files', 'token' nor 'teamId are present. Exiting`);
54
55
  return;
55
56
  }
@@ -64,8 +65,10 @@ async function* upload(files, clientOptions, deploymentOptions) {
64
65
  return yield event;
65
66
  }
66
67
  } else {
67
- if (event.type === "alias-assigned") {
68
- debug("Deployment succeeded on file check");
68
+ if (event.type === "alias-assigned" || event.type === "checks-v2-failed") {
69
+ debug(
70
+ event.type === "alias-assigned" ? "Deployment succeeded on file check" : "v2 deployment-alias check failed on file check"
71
+ );
69
72
  return yield event;
70
73
  }
71
74
  yield event;
@@ -78,23 +81,60 @@ async function* upload(files, clientOptions, deploymentOptions) {
78
81
  type: "file-count",
79
82
  payload: { total: files, missing: shas, uploads }
80
83
  };
84
+ const uploadGenerator = uploadFiles({
85
+ agent: clientOptions.agent,
86
+ apiUrl: clientOptions.apiUrl,
87
+ debug: clientOptions.debug,
88
+ teamId: clientOptions.teamId,
89
+ token: clientOptions.token,
90
+ userAgent: clientOptions.userAgent,
91
+ files,
92
+ shas,
93
+ uploads
94
+ });
95
+ for await (const event of uploadGenerator) {
96
+ if (event.type === "error") {
97
+ return yield event;
98
+ } else {
99
+ yield event;
100
+ }
101
+ }
102
+ debug("All files uploaded");
103
+ yield { type: "all-files-uploaded", payload: files };
104
+ try {
105
+ debug("Starting deployment creation");
106
+ for await (const event of (0, import_deploy.deploy)(files, clientOptions, deploymentOptions)) {
107
+ if (event.type === "alias-assigned" || event.type === "checks-v2-failed") {
108
+ debug("Deployment is ready");
109
+ return yield event;
110
+ }
111
+ yield event;
112
+ }
113
+ } catch (e) {
114
+ debug("An unexpected error occurred when starting deployment creation");
115
+ yield { type: "error", payload: e };
116
+ }
117
+ }
118
+ async function* uploadFiles(options) {
119
+ const debug = (0, import_utils.createDebug)(options.debug);
81
120
  const uploadList = {};
82
121
  debug("Building an upload list...");
83
122
  const semaphore = new import_async_sema.Sema(50, { capacity: 50 });
84
- const defaultAgent = apiUrl?.startsWith("https://") ? new import_https.default.Agent({ keepAlive: true }) : new import_http.default.Agent({ keepAlive: true });
123
+ const defaultAgent = options.apiUrl?.startsWith("https://") ? new import_https.default.Agent({ keepAlive: true }) : new import_http.default.Agent({ keepAlive: true });
85
124
  const abortControllers = /* @__PURE__ */ new Set();
86
125
  let aborted = false;
87
- shas.forEach((sha, index) => {
88
- const uploadProgress = uploads[index];
126
+ options.shas.forEach((sha, index) => {
127
+ const uploadProgress = options.uploads[index];
89
128
  uploadList[sha] = (0, import_async_retry.default)(
90
129
  async (bail) => {
91
- const file = files.get(sha);
130
+ const file = options.files.get(sha);
92
131
  if (!file) {
93
132
  debug(`File ${sha} is undefined. Bailing`);
94
133
  return bail(new Error(`File ${sha} is undefined`));
95
134
  }
96
135
  await semaphore.acquire();
97
136
  if (aborted) {
137
+ semaphore.release();
98
138
  return bail(new Error("Upload aborted"));
99
139
  }
100
140
  const { data } = file;
@@ -123,11 +163,11 @@ async function* upload(files, clientOptions, deploymentOptions) {
123
163
  const abortController = new AbortController();
124
164
  abortControllers.add(abortController);
125
165
  try {
126
- const res = await (0, import_utils.fetch)(
166
+ const res = await (0, import_utils.fetchApi)(
127
167
  import_utils.API_FILES,
128
- token,
168
+ options.token,
129
169
  {
130
- agent: clientOptions.agent || defaultAgent,
170
+ agent: options.agent || defaultAgent,
131
171
  method: "POST",
132
172
  headers: {
133
173
  "Content-Type": "application/octet-stream",
@@ -136,13 +176,13 @@ async function* upload(files, clientOptions, deploymentOptions) {
136
176
  "x-now-size": data.length
137
177
  },
138
178
  body,
139
- teamId,
140
- apiUrl,
141
- userAgent,
179
+ teamId: options.teamId,
180
+ apiUrl: options.apiUrl,
181
+ userAgent: options.userAgent,
142
182
  // @ts-expect-error: typescript is getting confused with the signal types from node (web & server) and node-fetch (server only)
143
183
  signal: abortController.signal
144
184
  },
145
- clientOptions.debug
185
+ options.debug
146
186
  );
147
187
  if (res.status === 200) {
148
188
  debug(
@@ -202,21 +242,6 @@ ${e}`);
202
242
  return yield { type: "error", payload: e };
203
243
  }
204
244
  }
205
- debug("All files uploaded");
206
- yield { type: "all-files-uploaded", payload: files };
207
- try {
208
- debug("Starting deployment creation");
209
- for await (const event of (0, import_deploy.deploy)(files, clientOptions, deploymentOptions)) {
210
- if (event.type === "alias-assigned") {
211
- debug("Deployment is ready");
212
- return yield event;
213
- }
214
- yield event;
215
- }
216
- } catch (e) {
217
- debug("An unexpected error occurred when starting deployment creation");
218
- yield { type: "error", payload: e };
219
- }
220
245
  }
221
246
  class UploadProgress extends import_node_events.EventEmitter {
222
247
  constructor(sha, file) {
@@ -228,5 +253,7 @@ class UploadProgress extends import_node_events.EventEmitter {
228
253
  }
229
254
  // Annotate the CommonJS export names for ESM import in node:
230
255
  0 && (module.exports = {
231
- upload
256
+ UploadProgress,
257
+ upload,
258
+ uploadFiles
232
259
  });
@@ -0,0 +1,2 @@
1
+ import { type FilesMap } from './hashes';
2
+ export declare function createTgzFiles(workPath: string, fileList: string[], debug?: (message: string) => void, exclude?: string[]): Promise<FilesMap>;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var archive_exports = {};
30
+ __export(archive_exports, {
31
+ createTgzFiles: () => createTgzFiles
32
+ });
33
+ module.exports = __toCommonJS(archive_exports);
34
+ var import_node_path = require("node:path");
35
+ var import_node_zlib = require("node:zlib");
36
+ var import_build_utils = require("@vercel/build-utils");
37
+ var import_tar_fs = __toESM(require("tar-fs"));
38
+ var import_hashes = require("./hashes");
39
+ async function createTgzFiles(workPath, fileList, debug, exclude) {
40
+ const filesToArchive = exclude ? fileList.filter((file) => !exclude.includes(file)) : fileList;
41
+ debug?.("Packing tarball");
42
+ const tarStream = import_tar_fs.default.pack(workPath, {
43
+ entries: filesToArchive.map((file) => (0, import_node_path.relative)(workPath, file))
44
+ }).pipe((0, import_node_zlib.createGzip)());
45
+ const chunkedTarBuffers = await (0, import_build_utils.streamToBufferChunks)(tarStream);
46
+ debug?.(`Packed tarball into ${chunkedTarBuffers.length} chunks`);
47
+ return new Map(
48
+ chunkedTarBuffers.map((chunk, index) => [
49
+ (0, import_hashes.hash)(chunk),
50
+ {
51
+ names: [(0, import_node_path.join)(workPath, `.vercel/source.tgz.part${index + 1}`)],
52
+ data: chunk,
53
+ mode: 438
54
+ }
55
+ ])
56
+ );
57
+ }
58
+ // Annotate the CommonJS export names for ESM import in node:
59
+ 0 && (module.exports = {
60
+ createTgzFiles
61
+ });
@@ -4,9 +4,9 @@ import ignore from 'ignore';
4
4
  import { VercelClientOptions, VercelConfig } from '../types';
5
5
  type Ignore = ReturnType<typeof ignore>;
6
6
  export declare const API_FILES = "/v2/files";
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"];
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">;
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">;
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<{
@@ -26,7 +26,7 @@ interface FetchOpts extends RequestInit {
26
26
  };
27
27
  userAgent?: string;
28
28
  }
29
- export declare const fetch: (url: string, token: string, opts?: FetchOpts, debugEnabled?: boolean) => Promise<any>;
29
+ export declare const fetchApi: (url: string, token: string, opts?: FetchOpts, debugEnabled?: boolean) => Promise<any>;
30
30
  export interface PreparedFile {
31
31
  file: string;
32
32
  sha?: string;
@@ -32,7 +32,7 @@ __export(utils_exports, {
32
32
  EVENTS: () => EVENTS,
33
33
  buildFileTree: () => buildFileTree,
34
34
  createDebug: () => createDebug,
35
- fetch: () => fetch,
35
+ fetchApi: () => fetchApi,
36
36
  getApiDeploymentsUrl: () => getApiDeploymentsUrl,
37
37
  getVercelIgnore: () => getVercelIgnore,
38
38
  parseVercelConfig: () => parseVercelConfig,
@@ -67,14 +67,16 @@ const EVENTS_ARRAY = [
67
67
  "notice",
68
68
  "tip",
69
69
  "canceled",
70
- // Checks events
70
+ // v1 Checks events
71
71
  "checks-registered",
72
72
  "checks-completed",
73
73
  "checks-running",
74
74
  "checks-conclusion-succeeded",
75
75
  "checks-conclusion-failed",
76
76
  "checks-conclusion-skipped",
77
- "checks-conclusion-canceled"
77
+ "checks-conclusion-canceled",
78
+ // v2 Checks events
79
+ "checks-v2-failed"
78
80
  ];
79
81
  const EVENTS = new Set(EVENTS_ARRAY);
80
82
  function getApiDeploymentsUrl() {
@@ -95,7 +97,7 @@ async function parseVercelConfig(filePath) {
95
97
  const maybeRead = async function(path, default_) {
96
98
  try {
97
99
  return await (0, import_fs_extra.readFile)(path, "utf8");
98
- } catch (err) {
100
+ } catch (_err) {
99
101
  return default_;
100
102
  }
101
103
  };
@@ -178,24 +180,31 @@ async function buildFileTree(path, {
178
180
  const relativeFromRoot = (0, import_path.relative)(projectRoot, bulkRedirectsFullPath);
179
181
  if (relativeFromRoot.startsWith("..")) {
180
182
  debug(
181
- `Skipping bulk redirects file "${bulkRedirectsPath}" - path traversal detected (resolves outside project root)`
183
+ `Skipping bulk redirects path "${bulkRedirectsPath}" - path traversal detected (resolves outside project root)`
182
184
  );
183
185
  } else {
184
- const bulkRedirectsContent = await maybeRead(
185
- bulkRedirectsFullPath,
186
- null
187
- );
188
- if (bulkRedirectsContent !== null) {
189
- refs.add(bulkRedirectsFullPath);
190
- debug(
191
- `Including bulk redirects file "${bulkRedirectsPath}" in deployment`
192
- );
193
- } else {
194
- debug(`Bulk redirects file "${bulkRedirectsPath}" not found`);
186
+ try {
187
+ const stats = await (0, import_fs_extra.stat)(bulkRedirectsFullPath);
188
+ if (stats.isDirectory()) {
189
+ const dirFiles = await (0, import_readdir_recursive.default)(bulkRedirectsFullPath, []);
190
+ for (const file of dirFiles) {
191
+ refs.add(file);
192
+ }
193
+ debug(
194
+ `Including ${dirFiles.length} files from bulk redirects directory "${bulkRedirectsPath}" in deployment`
195
+ );
196
+ } else if (stats.isFile()) {
197
+ refs.add(bulkRedirectsFullPath);
198
+ debug(
199
+ `Including bulk redirects file "${bulkRedirectsPath}" in deployment`
200
+ );
201
+ }
202
+ } catch (_e) {
203
+ debug(`Bulk redirects path "${bulkRedirectsPath}" not found`);
195
204
  }
196
205
  }
197
206
  } catch (e) {
198
- debug(`Error checking for bulk redirects file: ${e}`);
207
+ debug(`Error checking for bulk redirects path: ${e}`);
199
208
  }
200
209
  }
201
210
  if (refs.size > 0) {
@@ -287,7 +296,7 @@ ${clearRelative(ignoreFile)}`);
287
296
  function clearRelative(str) {
288
297
  return str.replace(/(\n|^)\.\//g, "$1");
289
298
  }
290
- const fetch = async (url, token, opts = {}, debugEnabled) => {
299
+ const fetchApi = async (url, token, opts = {}, debugEnabled) => {
291
300
  semaphore.acquire();
292
301
  const debug = createDebug(debugEnabled);
293
302
  let time;
@@ -357,7 +366,7 @@ function createDebug(debug) {
357
366
  EVENTS,
358
367
  buildFileTree,
359
368
  createDebug,
360
- fetch,
369
+ fetchApi,
361
370
  getApiDeploymentsUrl,
362
371
  getVercelIgnore,
363
372
  parseVercelConfig,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/client",
3
- "version": "17.3.0-canary.20260211174907.cdd2da6",
3
+ "version": "17.3.0",
4
4
  "main": "dist/index.js",
5
5
  "typings": "dist/index.d.ts",
6
6
  "homepage": "https://vercel.com",
@@ -42,9 +42,9 @@
42
42
  "querystring": "^0.2.0",
43
43
  "sleep-promise": "8.0.1",
44
44
  "tar-fs": "1.16.3",
45
- "@vercel/build-utils": "13.4.0-canary.20260211174907.cdd2da6",
46
- "@vercel/error-utils": "2.1.0-canary.20260211174907.cdd2da6",
47
- "@vercel/routing-utils": "5.4.0-canary.20260211174907.cdd2da6"
45
+ "@vercel/build-utils": "13.14.1",
46
+ "@vercel/error-utils": "2.0.3",
47
+ "@vercel/routing-utils": "6.1.1"
48
48
  },
49
49
  "scripts": {
50
50
  "build": "node ../../utils/build.mjs",