@vercel/build-utils 2.12.3-canary.9 → 2.13.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.
@@ -0,0 +1,173 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.detectFileSystemAPI = void 0;
7
+ const semver_1 = __importDefault(require("semver"));
8
+ const _1 = require("./");
9
+ const enableFileSystemApiFrameworks = new Set(['solidstart']);
10
+ /**
11
+ * If the Deployment can be built with the new File System API,
12
+ * return the new Builder. Otherwise an "Exclusion Condition"
13
+ * was hit so return `null` builder with a `reason` for exclusion.
14
+ */
15
+ async function detectFileSystemAPI({ files, projectSettings, builders, vercelConfig, pkg, tag, enableFlag = false, }) {
16
+ const framework = projectSettings.framework || '';
17
+ const deps = Object.assign({}, pkg === null || pkg === void 0 ? void 0 : pkg.dependencies, pkg === null || pkg === void 0 ? void 0 : pkg.devDependencies);
18
+ const plugins = Object.keys(deps).filter(dep => dep.startsWith('vercel-plugin-'));
19
+ const hasDotOutput = Object.keys(files).some(file => file.startsWith('.output/'));
20
+ const hasMiddleware = Boolean(files['_middleware.js'] || files['_middleware.ts']);
21
+ const metadata = {
22
+ plugins,
23
+ hasDotOutput,
24
+ hasMiddleware,
25
+ };
26
+ const isEnabled = enableFlag ||
27
+ hasMiddleware ||
28
+ hasDotOutput ||
29
+ enableFileSystemApiFrameworks.has(framework);
30
+ if (!isEnabled) {
31
+ return { metadata, fsApiBuilder: null, reason: 'Flag not enabled.' };
32
+ }
33
+ if ((vercelConfig === null || vercelConfig === void 0 ? void 0 : vercelConfig.builds) && vercelConfig.builds.length > 0) {
34
+ return {
35
+ metadata,
36
+ fsApiBuilder: null,
37
+ reason: 'Detected `builds` in vercel.json. Please remove it in favor of CLI plugins.',
38
+ };
39
+ }
40
+ if (Object.values((vercelConfig === null || vercelConfig === void 0 ? void 0 : vercelConfig.functions) || {}).some(fn => !!fn.runtime)) {
41
+ return {
42
+ metadata,
43
+ fsApiBuilder: null,
44
+ reason: 'Detected `functions.runtime` in vercel.json. Please remove it in favor of CLI plugins.',
45
+ };
46
+ }
47
+ if (process.env.HUGO_VERSION) {
48
+ return {
49
+ metadata,
50
+ fsApiBuilder: null,
51
+ reason: 'Detected `HUGO_VERSION` environment variable. Please remove it.',
52
+ };
53
+ }
54
+ if (process.env.ZOLA_VERSION) {
55
+ return {
56
+ metadata,
57
+ fsApiBuilder: null,
58
+ reason: 'Detected `ZOLA_VERSION` environment variable. Please remove it.',
59
+ };
60
+ }
61
+ if (process.env.GUTENBERG_VERSION) {
62
+ return {
63
+ metadata,
64
+ fsApiBuilder: null,
65
+ reason: 'Detected `GUTENBERG_VERSION` environment variable. Please remove it.',
66
+ };
67
+ }
68
+ const invalidBuilder = builders.find(({ use }) => {
69
+ const valid = _1.isOfficialRuntime('go', use) ||
70
+ _1.isOfficialRuntime('python', use) ||
71
+ _1.isOfficialRuntime('ruby', use) ||
72
+ _1.isOfficialRuntime('node', use) ||
73
+ _1.isOfficialRuntime('next', use) ||
74
+ _1.isOfficialRuntime('static', use) ||
75
+ _1.isOfficialRuntime('static-build', use);
76
+ return !valid;
77
+ });
78
+ if (invalidBuilder) {
79
+ return {
80
+ metadata,
81
+ fsApiBuilder: null,
82
+ reason: `Detected \`${invalidBuilder.use}\` in vercel.json. Please remove it in favor of CLI plugins.`,
83
+ };
84
+ }
85
+ for (const lang of ['go', 'python', 'ruby']) {
86
+ for (const { use } of builders) {
87
+ const plugin = 'vercel-plugin-' + lang;
88
+ if (_1.isOfficialRuntime(lang, use) && !deps[plugin]) {
89
+ return {
90
+ metadata,
91
+ fsApiBuilder: null,
92
+ reason: `Detected \`${lang}\` Serverless Function usage without plugin \`${plugin}\`. Please run \`npm i ${plugin}\`.`,
93
+ };
94
+ }
95
+ }
96
+ }
97
+ if (framework === 'nuxtjs' ||
98
+ framework === 'sveltekit' ||
99
+ framework === 'redwoodjs') {
100
+ return {
101
+ metadata,
102
+ fsApiBuilder: null,
103
+ reason: `Detected framework \`${framework}\` that only supports legacy File System API. Please contact the framework author.`,
104
+ };
105
+ }
106
+ if (framework === 'nextjs' && !hasDotOutput) {
107
+ // Use the old pipeline if a custom output directory was specified for Next.js
108
+ // because `vercel build` cannot ensure that the directory will be in the same
109
+ // location as `.output`, which can break imports (not just nft.json files).
110
+ if (projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.outputDirectory) {
111
+ return {
112
+ metadata,
113
+ fsApiBuilder: null,
114
+ reason: `Detected Next.js with Output Directory \`${projectSettings.outputDirectory}\` override. Please change it back to the default.`,
115
+ };
116
+ }
117
+ const nextVersion = deps['next'];
118
+ if (!nextVersion) {
119
+ return {
120
+ metadata,
121
+ fsApiBuilder: null,
122
+ reason: `Detected Next.js in Project Settings but missing \`next\` package.json dependencies. Please run \`npm i next\`.`,
123
+ };
124
+ }
125
+ // TODO: Read version from lockfile instead of package.json
126
+ if (nextVersion !== 'latest' && nextVersion !== 'canary') {
127
+ const fixedVersion = semver_1.default.valid(semver_1.default.coerce(nextVersion) || '');
128
+ if (!fixedVersion || !semver_1.default.gte(fixedVersion, '12.0.0')) {
129
+ return {
130
+ metadata,
131
+ fsApiBuilder: null,
132
+ reason: `Detected legacy Next.js version "${nextVersion}" in package.json. Please run \`npm i next@latest\` to upgrade.`,
133
+ };
134
+ }
135
+ }
136
+ }
137
+ if (!hasDotOutput) {
138
+ // TODO: Read version from lockfile instead of package.json
139
+ const vercelCliVersion = deps['vercel'];
140
+ if (vercelCliVersion &&
141
+ vercelCliVersion !== 'latest' &&
142
+ vercelCliVersion !== 'canary') {
143
+ const fixedVersion = semver_1.default.valid(semver_1.default.coerce(vercelCliVersion) || '');
144
+ // TODO: we might want to use '24.0.0' once its released
145
+ if (!fixedVersion || !semver_1.default.gte(fixedVersion, '23.1.3-canary.68')) {
146
+ return {
147
+ metadata,
148
+ fsApiBuilder: null,
149
+ reason: `Detected legacy Vercel CLI version "${vercelCliVersion}" in package.json. Please run \`npm i vercel@latest\` to upgrade.`,
150
+ };
151
+ }
152
+ }
153
+ }
154
+ const frontendBuilder = builders.find(({ use }) => _1.isOfficialRuntime('next', use) ||
155
+ _1.isOfficialRuntime('static', use) ||
156
+ _1.isOfficialRuntime('static-build', use));
157
+ const config = (frontendBuilder === null || frontendBuilder === void 0 ? void 0 : frontendBuilder.config) || {};
158
+ const withTag = tag ? `@${tag}` : '';
159
+ const fsApiBuilder = {
160
+ use: `@vercelruntimes/file-system-api${withTag}`,
161
+ src: '**',
162
+ config: {
163
+ ...config,
164
+ fileSystemAPI: true,
165
+ framework: config.framework || framework || null,
166
+ projectSettings,
167
+ hasMiddleware,
168
+ hasDotOutput,
169
+ },
170
+ };
171
+ return { metadata, fsApiBuilder, reason: null };
172
+ }
173
+ exports.detectFileSystemAPI = detectFileSystemAPI;
package/dist/fs/glob.js CHANGED
@@ -8,6 +8,7 @@ const assert_1 = __importDefault(require("assert"));
8
8
  const glob_1 = __importDefault(require("glob"));
9
9
  const util_1 = require("util");
10
10
  const fs_extra_1 = require("fs-extra");
11
+ const normalize_path_1 = require("./normalize-path");
11
12
  const file_fs_ref_1 = __importDefault(require("../file-fs-ref"));
12
13
  const vanillaGlob = util_1.promisify(glob_1.default);
13
14
  async function glob(pattern, opts, mountpoint) {
@@ -31,7 +32,7 @@ async function glob(pattern, opts, mountpoint) {
31
32
  options.dot = true;
32
33
  const files = await vanillaGlob(pattern, options);
33
34
  for (const relativePath of files) {
34
- const fsPath = path_1.default.join(options.cwd, relativePath).replace(/\\/g, '/');
35
+ const fsPath = normalize_path_1.normalizePath(path_1.default.join(options.cwd, relativePath));
35
36
  let stat = options.statCache[fsPath];
36
37
  assert_1.default(stat, `statCache does not contain value for ${relativePath} (resolved to ${fsPath})`);
37
38
  const isSymlink = options.symlinks[fsPath];
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Convert Windows separators to Unix separators.
3
+ */
4
+ export declare function normalizePath(p: string): string;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizePath = void 0;
4
+ const isWin = process.platform === 'win32';
5
+ /**
6
+ * Convert Windows separators to Unix separators.
7
+ */
8
+ function normalizePath(p) {
9
+ return isWin ? p.replace(/\\/g, '/') : p;
10
+ }
11
+ exports.normalizePath = normalizePath;
@@ -0,0 +1 @@
1
+ export default function (downloadPath: string, rootDirectory?: string | undefined): Promise<(p: string) => any>;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const path_1 = __importDefault(require("path"));
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const ignore_1 = __importDefault(require("ignore"));
9
+ function isCodedError(error) {
10
+ return (error !== null &&
11
+ error !== undefined &&
12
+ error.code !== undefined);
13
+ }
14
+ function clearRelative(s) {
15
+ return s.replace(/(\n|^)\.\//g, '$1');
16
+ }
17
+ async function default_1(downloadPath, rootDirectory) {
18
+ const readFile = async (p) => {
19
+ try {
20
+ return await fs_extra_1.default.readFile(p, 'utf8');
21
+ }
22
+ catch (error) {
23
+ if (error.code === 'ENOENT' ||
24
+ (error instanceof Error && error.message.includes('ENOENT'))) {
25
+ return undefined;
26
+ }
27
+ throw error;
28
+ }
29
+ };
30
+ const vercelIgnorePath = path_1.default.join(downloadPath, rootDirectory || '', '.vercelignore');
31
+ const nowIgnorePath = path_1.default.join(downloadPath, rootDirectory || '', '.nowignore');
32
+ const ignoreContents = [];
33
+ try {
34
+ ignoreContents.push(...(await Promise.all([readFile(vercelIgnorePath), readFile(nowIgnorePath)])).filter(Boolean));
35
+ }
36
+ catch (error) {
37
+ if (isCodedError(error) && error.code === 'ENOTDIR') {
38
+ console.log(`Warning: Cannot read ignore file from ${vercelIgnorePath}`);
39
+ }
40
+ else {
41
+ throw error;
42
+ }
43
+ }
44
+ if (ignoreContents.length === 2) {
45
+ throw new Error('Cannot use both a `.vercelignore` and `.nowignore` file. Please delete the `.nowignore` file.');
46
+ }
47
+ if (ignoreContents.length === 0) {
48
+ return () => false;
49
+ }
50
+ const ignoreFilter = ignore_1.default().add(clearRelative(ignoreContents[0]));
51
+ return function (p) {
52
+ // we should not ignore now.json and vercel.json if it asked to.
53
+ // we depend on these files for building the app with sourceless
54
+ if (p === 'now.json' || p === 'vercel.json')
55
+ return false;
56
+ return ignoreFilter.test(p).ignored;
57
+ };
58
+ }
59
+ exports.default = default_1;
package/dist/index.d.ts CHANGED
@@ -12,11 +12,15 @@ import { getLatestNodeVersion, getDiscontinuedNodeVersions } from './fs/node-ver
12
12
  import streamToBuffer from './fs/stream-to-buffer';
13
13
  import shouldServe from './should-serve';
14
14
  import debug from './debug';
15
- export { FileBlob, FileFsRef, FileRef, Lambda, createLambda, Prerender, download, DownloadedFiles, getWriteableDirectory, glob, GlobOptions, rename, execAsync, spawnAsync, getScriptName, installDependencies, runPackageJsonScript, execCommand, spawnCommand, walkParentDirs, getNodeBinPath, runNpmInstall, runBundleInstall, runPipInstall, runShellScript, getNodeVersion, getLatestNodeVersion, getDiscontinuedNodeVersions, getSpawnOptions, streamToBuffer, shouldServe, debug, isSymbolicLink, getLambdaOptionsFromFunction, scanParentDirs, };
15
+ import getIgnoreFilter from './get-ignore-filter';
16
+ export { FileBlob, FileFsRef, FileRef, Lambda, createLambda, Prerender, download, DownloadedFiles, getWriteableDirectory, glob, GlobOptions, rename, execAsync, spawnAsync, getScriptName, installDependencies, runPackageJsonScript, execCommand, spawnCommand, walkParentDirs, getNodeBinPath, runNpmInstall, runBundleInstall, runPipInstall, runShellScript, getNodeVersion, getLatestNodeVersion, getDiscontinuedNodeVersions, getSpawnOptions, streamToBuffer, shouldServe, debug, isSymbolicLink, getLambdaOptionsFromFunction, scanParentDirs, getIgnoreFilter, };
16
17
  export { detectBuilders, detectOutputDirectory, detectApiDirectory, detectApiExtensions, } from './detect-builders';
18
+ export { detectFileSystemAPI } from './detect-file-system-api';
17
19
  export { detectFramework } from './detect-framework';
18
20
  export { DetectorFilesystem } from './detectors/filesystem';
19
21
  export { readConfigFile } from './fs/read-config-file';
22
+ export { normalizePath } from './fs/normalize-path';
23
+ export { _experimental_convertRuntimeToPlugin, _experimental_updateFunctionsManifest, _experimental_updateRoutesManifest, } from './convert-runtime-to-plugin';
20
24
  export * from './schemas';
21
25
  export * from './types';
22
26
  export * from './errors';