@vercel/build-utils 4.0.0 → 4.1.1-canary.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.
@@ -7,7 +7,7 @@ interface ErrorResponse {
7
7
  link?: string;
8
8
  }
9
9
  interface Options {
10
- tag?: 'canary' | 'latest' | string;
10
+ tag?: string;
11
11
  functions?: BuilderFunctions;
12
12
  ignoreBuildScript?: boolean;
13
13
  projectSettings?: ProjectSettings;
@@ -187,7 +187,7 @@ async function detectBuilders(files, pkg, options = {}) {
187
187
  // and package.json can be served as static files
188
188
  frontendBuilder = {
189
189
  use: '@vercel/static',
190
- src: '!{api/**,package.json}',
190
+ src: '!{api/**,package.json,middleware.[jt]s}',
191
191
  config: {
192
192
  zeroConfig: true,
193
193
  },
@@ -237,7 +237,13 @@ async function detectBuilders(files, pkg, options = {}) {
237
237
  }
238
238
  exports.detectBuilders = detectBuilders;
239
239
  function maybeGetApiBuilder(fileName, apiMatches, options) {
240
- if (!fileName.startsWith('api/')) {
240
+ const middleware = fileName === 'middleware.js' || fileName === 'middleware.ts';
241
+ // Root-level Middleware file is handled by `@vercel/next`, so don't
242
+ // schedule a separate Builder when "nextjs" framework is selected
243
+ if (middleware && options.projectSettings?.framework === 'nextjs') {
244
+ return null;
245
+ }
246
+ if (!(fileName.startsWith('api/') || middleware)) {
241
247
  return null;
242
248
  }
243
249
  if (fileName.includes('/.')) {
@@ -256,11 +262,14 @@ function maybeGetApiBuilder(fileName, apiMatches, options) {
256
262
  return src === fileName || minimatch_1.default(fileName, src);
257
263
  });
258
264
  const { fnPattern, func } = getFunction(fileName, options);
259
- const use = (func && func.runtime) || (match && match.use);
265
+ const use = func?.runtime || match?.use;
260
266
  if (!use) {
261
267
  return null;
262
268
  }
263
269
  const config = { zeroConfig: true };
270
+ if (middleware) {
271
+ config.middleware = true;
272
+ }
264
273
  if (fnPattern && func) {
265
274
  config.functions = { [fnPattern]: func };
266
275
  if (func.includeFiles) {
@@ -290,6 +299,7 @@ function getFunction(fileName, { functions = {} }) {
290
299
  function getApiMatches() {
291
300
  const config = { zeroConfig: true };
292
301
  return [
302
+ { src: 'middleware.[jt]s', use: `@vercel/node`, config },
293
303
  { src: 'api/**/*.js', use: `@vercel/node`, config },
294
304
  { src: 'api/**/*.mjs', use: `@vercel/node`, config },
295
305
  { src: 'api/**/*.ts', use: `@vercel/node`, config },
@@ -0,0 +1,6 @@
1
+ /// <reference types="node" />
2
+ import fs from 'fs';
3
+ import { DetectorFilesystem } from '../detectors/filesystem';
4
+ declare type GlobFs = typeof fs;
5
+ export declare function getGlobFs(_fs: DetectorFilesystem): GlobFs;
6
+ export {};
@@ -0,0 +1,71 @@
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.getGlobFs = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ function normalizePath(path) {
9
+ // on windows, this will return a path like
10
+ // D:/c/package.json
11
+ // since we abstract the filesystem, we need to remove windows specific info from the path
12
+ // and let the FS decide how to process the path
13
+ // D:/c/package.json => /c/package.json
14
+ return path.replace(/^[a-zA-Z]:/, '');
15
+ }
16
+ function getGlobFs(_fs) {
17
+ const readdir = (path, callback) => {
18
+ _fs
19
+ .readdir(normalizePath(String(path)))
20
+ .then(stats => callback(null, stats.map(stat => stat.name)))
21
+ .catch(err => callback(err, []));
22
+ };
23
+ const stat = (path, callback) => {
24
+ _fs
25
+ .isFile(normalizePath(String(path)))
26
+ .then(isPathAFile => {
27
+ callback(null, {
28
+ ino: 0,
29
+ mode: 0,
30
+ nlink: 0,
31
+ uid: 0,
32
+ gid: 0,
33
+ rdev: 0,
34
+ size: 0,
35
+ blksize: 0,
36
+ blocks: 0,
37
+ atimeMs: 0,
38
+ mtimeMs: 0,
39
+ ctimeMs: 0,
40
+ birthtimeMs: 0,
41
+ atime: new Date(),
42
+ mtime: new Date(),
43
+ ctime: new Date(),
44
+ birthtime: new Date(),
45
+ dev: 0,
46
+ isBlockDevice: () => false,
47
+ isCharacterDevice: () => false,
48
+ isDirectory: () => !isPathAFile,
49
+ isFIFO: () => false,
50
+ isFile: () => isPathAFile,
51
+ isSocket: () => false,
52
+ isSymbolicLink: () => false,
53
+ });
54
+ })
55
+ .catch(err => callback(err, null));
56
+ };
57
+ return new Proxy(fs_1.default, {
58
+ get(_target, prop) {
59
+ switch (prop) {
60
+ case 'readdir':
61
+ return readdir;
62
+ case 'lstat':
63
+ case 'stat':
64
+ return stat;
65
+ default:
66
+ throw new Error('Not Implemented');
67
+ }
68
+ },
69
+ });
70
+ }
71
+ exports.getGlobFs = getGlobFs;
@@ -0,0 +1,9 @@
1
+ import { DetectorFilesystem } from './detectors/filesystem';
2
+ export interface GetProjectPathsOptions {
3
+ fs: DetectorFilesystem;
4
+ path?: string;
5
+ skipPaths?: string[];
6
+ depth?: number;
7
+ }
8
+ export declare type ProjectPath = string;
9
+ export declare const getProjectPaths: ({ fs, path, skipPaths, depth, }: GetProjectPathsOptions) => Promise<ProjectPath[]>;
@@ -0,0 +1,39 @@
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.getProjectPaths = void 0;
7
+ const detect_framework_1 = require("./detect-framework");
8
+ const frameworks_1 = __importDefault(require("@vercel/frameworks"));
9
+ const MAX_DEPTH_TRAVERSE = 3;
10
+ const getProjectPaths = async ({ fs, path, skipPaths, depth = MAX_DEPTH_TRAVERSE, }) => {
11
+ if (depth === 0)
12
+ return [];
13
+ const allPaths = [];
14
+ const topPath = path ?? './';
15
+ if (path && skipPaths?.includes(path)) {
16
+ return allPaths;
17
+ }
18
+ const framework = await detect_framework_1.detectFramework({
19
+ fs: fs.chdir(topPath),
20
+ frameworkList: frameworks_1.default,
21
+ });
22
+ if (framework !== null)
23
+ allPaths.push(topPath);
24
+ if (depth > 1) {
25
+ const directoryContents = await fs.readdir(topPath);
26
+ const childDirectories = directoryContents.filter(stat => stat.type === 'dir' && !skipPaths?.includes(stat.path));
27
+ const paths = (await Promise.all(childDirectories.map(({ path }) => {
28
+ return exports.getProjectPaths({
29
+ fs,
30
+ path,
31
+ depth: depth - 1,
32
+ skipPaths,
33
+ });
34
+ }))).flat();
35
+ return [...paths, ...allPaths];
36
+ }
37
+ return allPaths;
38
+ };
39
+ exports.getProjectPaths = getProjectPaths;
package/dist/index.d.ts CHANGED
@@ -19,6 +19,7 @@ export { EdgeFunction } from './edge-function';
19
19
  export { detectBuilders, detectOutputDirectory, detectApiDirectory, detectApiExtensions, } from './detect-builders';
20
20
  export { detectFileSystemAPI } from './detect-file-system-api';
21
21
  export { detectFramework } from './detect-framework';
22
+ export { getProjectPaths } from './get-project-paths';
22
23
  export { DetectorFilesystem } from './detectors/filesystem';
23
24
  export { readConfigFile } from './fs/read-config-file';
24
25
  export { normalizePath } from './fs/normalize-path';
@@ -32,5 +33,6 @@ export * from './errors';
32
33
  export declare const isOfficialRuntime: (desired: string, name?: string | undefined) => boolean;
33
34
  export declare const isStaticRuntime: (name?: string | undefined) => boolean;
34
35
  export { workspaceManagers } from './workspaces/workspace-managers';
35
- export { getWorkspaces } from './workspaces/get-workspaces';
36
+ export { getWorkspaces, GetWorkspaceOptions, Workspace, WorkspaceType, } from './workspaces/get-workspaces';
37
+ export { getWorkspacePackagePaths, GetWorkspacePackagePathsOptions, } from './workspaces/get-workspace-package-paths';
36
38
  export { monorepoManagers } from './monorepos/monorepo-managers';