@vercel/client 18.3.3 → 18.3.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.
package/README.md CHANGED
@@ -41,6 +41,28 @@ async function deploy() {
41
41
  }
42
42
  ```
43
43
 
44
+ The optional second argument accepts deployment options, either as an object or
45
+ as a `Promise<DeploymentOptions>`. Use a promise to resolve metadata concurrently
46
+ with local file collection:
47
+
48
+ ```js
49
+ const options = readDeploymentMetadata().then(gitMetadata => ({ gitMetadata }));
50
+
51
+ for await (const event of createDeployment(
52
+ { token: process.env.TOKEN, path: '/path/to/project' },
53
+ options
54
+ )) {
55
+ // Handle deployment progress.
56
+ }
57
+ ```
58
+
59
+ Start consuming the iterator immediately after creating the promise: the async
60
+ generator begins running on its first iteration. File collection and the
61
+ `hashes-calculated` event can finish before the options resolve, but uploads and
62
+ deployment creation wait for them. If the options reject, iteration throws before
63
+ uploading or creating the deployment. If local file collection fails first, that
64
+ error is reported and a later options rejection is handled internally.
65
+
44
66
  Full list of events:
45
67
 
46
68
  ```js
@@ -8,6 +8,7 @@ export interface CollectedDeploymentFiles {
8
8
  workPath: string;
9
9
  isDirectory: boolean;
10
10
  ignoreList: string[];
11
+ warning?: string;
11
12
  }
12
13
  export declare function assertDeploymentPath(path: VercelClientOptions['path'] | undefined, debug: Debug): asserts path is VercelClientOptions['path'];
13
14
  export declare function collectDeploymentFiles(path: VercelClientOptions['path'] | undefined, clientOptions: CollectDeploymentFilesOptions, debug: Debug): Promise<CollectedDeploymentFiles>;
@@ -66,7 +66,7 @@ async function collectDeploymentFiles(path, clientOptions, debug) {
66
66
  } else {
67
67
  debug(`Provided 'path' is a single file`);
68
68
  }
69
- const { fileList, ignoreList } = await (0, import_utils.buildFileTree)(
69
+ const { fileList, ignoreList, warning } = await (0, import_utils.buildFileTree)(
70
70
  path,
71
71
  clientOptions,
72
72
  debug
@@ -86,7 +86,7 @@ ${err.message}`;
86
86
  }
87
87
  throw err;
88
88
  }
89
- return { fileList, filesMap, workPath, isDirectory, ignoreList };
89
+ return { fileList, filesMap, workPath, isDirectory, ignoreList, warning };
90
90
  }
91
91
  // Annotate the CommonJS export names for ESM import in node:
92
92
  0 && (module.exports = {
@@ -18,4 +18,5 @@ export declare function continueDeployment(options: {
18
18
  }): AsyncIterableIterator<{
19
19
  type: DeploymentEventType;
20
20
  payload: any;
21
+ code?: string;
21
22
  }>;
package/dist/continue.js CHANGED
@@ -53,11 +53,19 @@ async function* continueDeployment(options) {
53
53
  })
54
54
  };
55
55
  }
56
- const { fileList } = await (0, import_utils.buildFileTree)(
56
+ const { fileList, warning } = await (0, import_utils.buildFileTree)(
57
57
  options.path,
58
58
  { isDirectory: true, prebuilt: true, vercelOutputDir: outputDir },
59
59
  debug
60
60
  );
61
+ if (warning) {
62
+ debug("Yielding a prebuilt filePathMap ignore warning");
63
+ yield {
64
+ type: "warning",
65
+ payload: warning,
66
+ code: "PREBUILT_FILEPATHMAP_IGNORED"
67
+ };
68
+ }
61
69
  const provisionJsonPath = (0, import_path.join)(outputDir, "provision.json");
62
70
  const unbundledFiles = fileList.filter((f) => f === provisionJsonPath);
63
71
  let files;
@@ -1,5 +1,6 @@
1
1
  import { VercelClientOptions, DeploymentOptions, DeploymentEventType } from './types';
2
- export default function buildCreateDeployment(): (clientOptions: VercelClientOptions, deploymentOptions?: DeploymentOptions) => AsyncIterableIterator<{
2
+ export default function buildCreateDeployment(): (clientOptions: VercelClientOptions, deploymentOptions?: DeploymentOptions | Promise<DeploymentOptions>) => AsyncIterableIterator<{
3
3
  type: DeploymentEventType;
4
4
  payload: any;
5
+ code?: string;
5
6
  }>;
@@ -29,6 +29,9 @@ var import_errors = require("./errors");
29
29
  var import_collect_deployment_files = require("./collect-deployment-files");
30
30
  function buildCreateDeployment() {
31
31
  return async function* createDeployment(clientOptions, deploymentOptions = {}) {
32
+ const options = Promise.resolve(deploymentOptions);
33
+ void options.catch(() => {
34
+ });
32
35
  const { path } = clientOptions;
33
36
  const debug = (0, import_utils.createDebug)(clientOptions.debug);
34
37
  debug("Creating deployment...");
@@ -50,19 +53,28 @@ function buildCreateDeployment() {
50
53
  message: "The `manual` option requires `prebuilt` to be true"
51
54
  });
52
55
  }
53
- deploymentOptions.build = deploymentOptions.build || {};
54
- deploymentOptions.build.env = deploymentOptions.build.env || {};
55
- deploymentOptions.build.env.VERCEL_MANUAL_PROVISIONING = "1";
56
- deploymentOptions.version = 2;
56
+ const deploymentOptions2 = await options;
57
+ deploymentOptions2.build = deploymentOptions2.build || {};
58
+ deploymentOptions2.build.env = deploymentOptions2.build.env || {};
59
+ deploymentOptions2.build.env.VERCEL_MANUAL_PROVISIONING = "1";
60
+ deploymentOptions2.version = 2;
57
61
  debug("Creating deployment with manual provisioning...");
58
- yield* (0, import_deploy.deploy)(/* @__PURE__ */ new Map(), clientOptions, deploymentOptions);
62
+ yield* (0, import_deploy.deploy)(/* @__PURE__ */ new Map(), clientOptions, deploymentOptions2);
59
63
  return;
60
64
  }
61
- const { fileList, filesMap: files } = await (0, import_collect_deployment_files.collectDeploymentFiles)(
62
- path,
63
- clientOptions,
64
- debug
65
- );
65
+ const {
66
+ fileList,
67
+ filesMap: files,
68
+ warning
69
+ } = await (0, import_collect_deployment_files.collectDeploymentFiles)(path, clientOptions, debug);
70
+ if (warning) {
71
+ debug("Yielding a prebuilt filePathMap ignore warning");
72
+ yield {
73
+ type: "warning",
74
+ payload: warning,
75
+ code: "PREBUILT_FILEPATHMAP_IGNORED"
76
+ };
77
+ }
66
78
  if (fileList.length === 0) {
67
79
  debug("Deployment path has no files. Yielding a warning event");
68
80
  yield {
@@ -78,10 +90,11 @@ function buildCreateDeployment() {
78
90
  if (clientOptions.userAgent) {
79
91
  debug(`Using provided user agent: ${clientOptions.userAgent}`);
80
92
  }
93
+ const resolvedOptions = await options;
81
94
  debug(`Setting platform version to harcoded value 2`);
82
- deploymentOptions.version = 2;
95
+ resolvedOptions.version = 2;
83
96
  debug(`Creating the deployment and starting upload...`);
84
- for await (const event of (0, import_upload.upload)(files, clientOptions, deploymentOptions)) {
97
+ for await (const event of (0, import_upload.upload)(files, clientOptions, resolvedOptions)) {
85
98
  debug(`Yielding a '${event.type}' event`);
86
99
  yield event;
87
100
  }
package/dist/index.d.ts CHANGED
@@ -2,9 +2,10 @@ export { continueDeployment } from './continue';
2
2
  export { checkDeploymentStatus } from './check-deployment-status';
3
3
  export { inspectDeploymentFiles } from './inspect-deployment-files';
4
4
  export { getVercelIgnore, buildFileTree } from './utils/index';
5
- export declare const createDeployment: (clientOptions: import("./types").VercelClientOptions, deploymentOptions?: import("./types").DeploymentOptions) => AsyncIterableIterator<{
5
+ export declare const createDeployment: (clientOptions: import("./types").VercelClientOptions, deploymentOptions?: import("./types").DeploymentOptions | Promise<import("./types").DeploymentOptions>) => AsyncIterableIterator<{
6
6
  type: import("./types").DeploymentEventType;
7
7
  payload: any;
8
+ code?: string;
8
9
  }>;
9
10
  export * from './errors';
10
11
  export * from './types';
@@ -12,5 +12,6 @@ export interface DeploymentFileSummary {
12
12
  ignoredCount: number;
13
13
  files: DeploymentFileItem[];
14
14
  ignored: string[];
15
+ warning?: string;
15
16
  }
16
17
  export declare function inspectDeploymentFiles(clientOptions: Pick<VercelClientOptions, 'archive' | 'bulkRedirectsPath' | 'debug' | 'path' | 'prebuilt' | 'projectName' | 'rootDirectory' | 'vercelOutputDir'>): Promise<DeploymentFileSummary>;
@@ -27,7 +27,7 @@ var import_utils = require("./utils");
27
27
  async function inspectDeploymentFiles(clientOptions) {
28
28
  const { path } = clientOptions;
29
29
  const debug = (0, import_utils.createDebug)(clientOptions.debug);
30
- const { filesMap, workPath, isDirectory, ignoreList } = await (0, import_collect_deployment_files.collectDeploymentFiles)(path, { ...clientOptions }, debug);
30
+ const { filesMap, workPath, isDirectory, ignoreList, warning } = await (0, import_collect_deployment_files.collectDeploymentFiles)(path, { ...clientOptions }, debug);
31
31
  const files = [];
32
32
  let totalSize = 0;
33
33
  for (const [sha, file] of filesMap) {
@@ -54,7 +54,8 @@ async function inspectDeploymentFiles(clientOptions) {
54
54
  totalSize,
55
55
  ignoredCount: ignoreList.length,
56
56
  files,
57
- ignored: ignoreList.sort()
57
+ ignored: ignoreList.sort(),
58
+ warning
58
59
  };
59
60
  }
60
61
  // Annotate the CommonJS export names for ESM import in node:
package/dist/types.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { Builder, BuilderFunctions, Images, ProjectSettings, Cron, Schedule, ExperimentalServices, ExperimentalServiceGroups, ExperimentalServicesV2, Services } from '@vercel/build-utils';
2
2
  import type { Header, Route, Redirect, Rewrite } from '@vercel/routing-utils';
3
- export { DeploymentEventType } from './utils';
3
+ export type { DeploymentEventType } from './utils';
4
4
  /**
5
5
  * Minimal interface of an undici `Dispatcher` (e.g. `undici.ProxyAgent`),
6
6
  * passed to `fetch` as the non-standard `dispatcher` init option to customize
package/dist/types.js CHANGED
@@ -18,17 +18,14 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var types_exports = {};
20
20
  __export(types_exports, {
21
- DeploymentEventType: () => import_utils.DeploymentEventType,
22
21
  VALID_ARCHIVE_FORMATS: () => VALID_ARCHIVE_FORMATS,
23
22
  fileNameSymbol: () => fileNameSymbol
24
23
  });
25
24
  module.exports = __toCommonJS(types_exports);
26
- var import_utils = require("./utils");
27
25
  const VALID_ARCHIVE_FORMATS = ["tgz"];
28
26
  const fileNameSymbol = Symbol("fileName");
29
27
  // Annotate the CommonJS export names for ESM import in node:
30
28
  0 && (module.exports = {
31
- DeploymentEventType,
32
29
  VALID_ARCHIVE_FORMATS,
33
30
  fileNameSymbol
34
31
  });
@@ -12,6 +12,7 @@ export declare function parseVercelConfig(filePath?: string): Promise<VercelConf
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<{
13
13
  fileList: string[];
14
14
  ignoreList: string[];
15
+ warning?: string;
15
16
  }>;
16
17
  export declare function getVercelIgnore(cwd: string | string[], prebuilt?: boolean, vercelOutputDir?: string): Promise<{
17
18
  ig: Ignore;
@@ -49,7 +49,6 @@ var import_build_utils = require("@vercel/build-utils");
49
49
  var import_async_sema = require("async-sema");
50
50
  var import_fs_extra = require("fs-extra");
51
51
  var import_readdir_recursive = __toESM(require("./readdir-recursive"));
52
- var import_utils = require("@vercel/microfrontends/microfrontends/utils");
53
52
  const semaphore = new import_async_sema.Sema(10);
54
53
  const API_FILES = "/v2/files";
55
54
  const EVENTS_ARRAY = [
@@ -118,7 +117,10 @@ async function getUserIgnore(cwd) {
118
117
  if (!ignoreFile) {
119
118
  return null;
120
119
  }
121
- return (0, import_ignore.default)().add(clearRelative(ignoreFile));
120
+ return {
121
+ ig: (0, import_ignore.default)().add(clearRelative(ignoreFile)),
122
+ ignoreFileName: vercelignore ? ".vercelignore" : ".nowignore"
123
+ };
122
124
  }
123
125
  const FILEPATHMAP_VERCELIGNORE_EXCEPTIONS = [
124
126
  "node_modules",
@@ -136,6 +138,24 @@ const filePathMapVercelignoreExceptions = (0, import_ignore.default)().add(
136
138
  function isFilePathMapIgnoreException(posixRel) {
137
139
  return filePathMapVercelignoreExceptions.ignores(posixRel);
138
140
  }
141
+ const FILEPATHMAP_IGNORE_ERROR_LIST_LIMIT = 20;
142
+ function formatFilePathMapIgnoreWarning(entries, ignoreFileName, truncated = false) {
143
+ const shown = entries.slice(0, FILEPATHMAP_IGNORE_ERROR_LIST_LIMIT);
144
+ const lines = shown.map((path) => ` ${path}`);
145
+ if (truncated) {
146
+ lines.push(" \u2026and more");
147
+ }
148
+ const count = truncated ? `at least ${shown.length}` : String(entries.length);
149
+ const fileWord = !truncated && entries.length === 1 ? "file" : "files";
150
+ const ignoreFileLabel = ignoreFileName === ".nowignore" ? `\`${ignoreFileName}\` (deprecated)` : `\`${ignoreFileName}\``;
151
+ return [
152
+ `${ignoreFileLabel} excludes ${count} ${fileWord} the prebuilt functions need. An upcoming CLI release will fail this deploy instead of uploading without them.`,
153
+ "",
154
+ ...lines,
155
+ "",
156
+ `Remove the colliding rules from \`${ignoreFileName}\`, or exclude those paths from tracing with \`outputFileTracingExcludes\`.`
157
+ ].join("\n");
158
+ }
139
159
  async function buildFileTree(path, {
140
160
  isDirectory,
141
161
  prebuilt,
@@ -146,6 +166,7 @@ async function buildFileTree(path, {
146
166
  }, debug) {
147
167
  const ignoreList = [];
148
168
  let fileList;
169
+ let warning;
149
170
  let { ig, ignores } = await getVercelIgnore(path, prebuilt, vercelOutputDir);
150
171
  debug(`Found ${ignores.length} rules in .vercelignore`);
151
172
  debug("Building file tree...");
@@ -165,45 +186,68 @@ async function buildFileTree(path, {
165
186
  (file) => (0, import_path.basename)(file) === ".vc-config.json"
166
187
  );
167
188
  const userIg = await getUserIgnore(path);
168
- await Promise.all(
189
+ const ignoredFilePathMap = /* @__PURE__ */ new Set();
190
+ let ignoredFilePathMapTruncated = false;
191
+ const vcConfigs = await Promise.all(
169
192
  vcConfigFilePaths.map(async (p) => {
170
193
  const configJson = await (0, import_fs_extra.readFile)(p, "utf8");
171
- const config = JSON.parse(configJson);
172
- if (!config.filePathMap)
173
- return;
174
- for (const v of Object.values(config.filePathMap)) {
175
- const absPath = (0, import_path.join)(path, v);
176
- const rel = (0, import_path.relative)(path, absPath);
177
- const posixRel = rel.split(import_path.sep).join("/");
178
- if (rel.startsWith("..") || (0, import_path.isAbsolute)(rel)) {
194
+ return JSON.parse(configJson);
195
+ })
196
+ );
197
+ for (const config of vcConfigs) {
198
+ if (!config.filePathMap)
199
+ continue;
200
+ for (const v of Object.values(config.filePathMap)) {
201
+ const absPath = (0, import_path.join)(path, v);
202
+ const rel = (0, import_path.relative)(path, absPath);
203
+ const posixRel = rel.split(import_path.sep).join("/");
204
+ if (rel.startsWith("..") || (0, import_path.isAbsolute)(rel)) {
205
+ debug(
206
+ `Ignoring "filePathMap" entry "${v}": resolves outside the deployment root`
207
+ );
208
+ continue;
209
+ }
210
+ if (userIg && userIg.ig.ignores(posixRel)) {
211
+ if (isFilePathMapIgnoreException(posixRel)) {
179
212
  debug(
180
- `Ignoring "filePathMap" entry "${v}": resolves outside the deployment root`
213
+ `Keeping "filePathMap" entry "${v}": matches a default-ignored dependency/output path`
181
214
  );
215
+ } else if (ignoredFilePathMap.has(posixRel)) {
216
+ continue;
217
+ } else if (fileList.includes(absPath)) {
218
+ debug(
219
+ `Skipping "filePathMap" entry "${v}": already in the upload set`
220
+ );
221
+ continue;
222
+ } else if (ignoredFilePathMap.size >= FILEPATHMAP_IGNORE_ERROR_LIST_LIMIT) {
223
+ ignoredFilePathMapTruncated = true;
224
+ continue;
225
+ } else {
226
+ ignoredFilePathMap.add(posixRel);
182
227
  continue;
183
228
  }
184
- if (userIg && userIg.ignores(posixRel)) {
185
- if (isFilePathMapIgnoreException(posixRel)) {
186
- debug(
187
- `Keeping "filePathMap" entry "${v}": matches a default-ignored dependency/output path`
188
- );
189
- } else {
190
- debug(
191
- `Ignoring "filePathMap" entry "${v}": matched by a rule in .vercelignore/.nowignore`
192
- );
193
- continue;
194
- }
195
- }
196
- refs.add(absPath);
197
229
  }
198
- })
199
- );
230
+ refs.add(absPath);
231
+ }
232
+ }
233
+ if (ignoredFilePathMap.size > 0) {
234
+ warning = formatFilePathMapIgnoreWarning(
235
+ [...ignoredFilePathMap].sort((a, b) => a.localeCompare(b)),
236
+ userIg?.ignoreFileName || ".vercelignore",
237
+ ignoredFilePathMapTruncated
238
+ );
239
+ }
200
240
  try {
201
- let microfrontendConfigPath = (0, import_utils.findConfig)({
241
+ const {
242
+ findConfig: findMicrofrontendsConfig,
243
+ inferMicrofrontendsLocation
244
+ } = await import("@vercel/microfrontends/microfrontends/utils");
245
+ let microfrontendConfigPath = findMicrofrontendsConfig({
202
246
  dir: (0, import_path.join)(path, rootDirectory || "")
203
247
  });
204
248
  if (!microfrontendConfigPath && !rootDirectory && projectName) {
205
- microfrontendConfigPath = (0, import_utils.findConfig)({
206
- dir: (0, import_utils.inferMicrofrontendsLocation)({
249
+ microfrontendConfigPath = findMicrofrontendsConfig({
250
+ dir: inferMicrofrontendsLocation({
207
251
  repositoryRoot: path,
208
252
  applicationName: projectName
209
253
  })
@@ -275,7 +319,7 @@ async function buildFileTree(path, {
275
319
  fileList = [path];
276
320
  debug(`Deploying the provided path as single file`);
277
321
  }
278
- return { fileList, ignoreList };
322
+ return { fileList, ignoreList, warning };
279
323
  }
280
324
  async function getVercelIgnore(cwd, prebuilt, vercelOutputDir) {
281
325
  const ig = (0, import_ignore.default)();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/client",
3
- "version": "18.3.3",
3
+ "version": "18.3.5",
4
4
  "main": "dist/index.js",
5
5
  "typings": "dist/index.d.ts",
6
6
  "homepage": "https://vercel.com",
@@ -37,9 +37,9 @@
37
37
  "querystring": "^0.2.0",
38
38
  "sleep-promise": "8.0.1",
39
39
  "tar-fs": "1.16.3",
40
- "@vercel/routing-utils": "6.5.0",
40
+ "@vercel/build-utils": "14.9.3",
41
41
  "@vercel/error-utils": "2.2.1",
42
- "@vercel/build-utils": "14.9.2"
42
+ "@vercel/routing-utils": "6.5.0"
43
43
  },
44
44
  "scripts": {
45
45
  "build": "node ../../utils/build.mjs",