@vercel/build-utils 2.12.3-canary.20 → 2.12.3-canary.24

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.
@@ -1,5 +1,5 @@
1
1
  import { Lambda } from './lambda';
2
- import type { BuildOptions } from './types';
2
+ import type { BuilderFunctions, BuildOptions } from './types';
3
3
  /**
4
4
  * Convert legacy Runtime to a Plugin.
5
5
  * @param buildRuntime - a legacy build() function from a Runtime
@@ -7,7 +7,11 @@ import type { BuildOptions } from './types';
7
7
  */
8
8
  export declare function convertRuntimeToPlugin(buildRuntime: (options: BuildOptions) => Promise<{
9
9
  output: Lambda;
10
- }>, ext: string): ({ workPath }: {
10
+ }>, ext: string): ({ vercelConfig, workPath, }: {
11
+ vercelConfig: {
12
+ functions?: BuilderFunctions;
13
+ regions?: string[];
14
+ };
11
15
  workPath: string;
12
16
  }) => Promise<void>;
13
17
  /**
@@ -15,18 +19,41 @@ export declare function convertRuntimeToPlugin(buildRuntime: (options: BuildOpti
15
19
  * property. Otherwise write a new file. This will also read `vercel.json`
16
20
  * and apply relevant `functions` property config.
17
21
  */
18
- export declare function updateFunctionsManifest({ workPath, pages, }: {
22
+ export declare function updateFunctionsManifest({ vercelConfig, workPath, pages, }: {
23
+ vercelConfig: {
24
+ functions?: BuilderFunctions;
25
+ regions?: string[];
26
+ };
19
27
  workPath: string;
20
28
  pages: {
21
29
  [key: string]: any;
22
30
  };
23
31
  }): Promise<void>;
24
32
  /**
25
- * Will append routes to the `routes-manifest.json` file.
26
- * If the file does not exist, it'll be created.
33
+ * Append routes to the `routes-manifest.json` file.
34
+ * If the file does not exist, it will be created.
27
35
  */
28
- export declare function updateRoutesManifest({ workPath, dynamicRoutes, }: {
36
+ export declare function updateRoutesManifest({ workPath, redirects, rewrites, headers, dynamicRoutes, staticRoutes, }: {
29
37
  workPath: string;
38
+ redirects?: {
39
+ source: string;
40
+ destination: string;
41
+ statusCode: number;
42
+ regex: string;
43
+ }[];
44
+ rewrites?: {
45
+ source: string;
46
+ destination: string;
47
+ regex: string;
48
+ }[];
49
+ headers?: {
50
+ source: string;
51
+ headers: {
52
+ key: string;
53
+ value: string;
54
+ }[];
55
+ regex: string;
56
+ }[];
30
57
  dynamicRoutes?: {
31
58
  page: string;
32
59
  regex: string;
@@ -35,4 +62,12 @@ export declare function updateRoutesManifest({ workPath, dynamicRoutes, }: {
35
62
  [named: string]: string;
36
63
  };
37
64
  }[];
65
+ staticRoutes?: {
66
+ page: string;
67
+ regex: string;
68
+ namedRegex?: string;
69
+ routeKeys?: {
70
+ [named: string]: string;
71
+ };
72
+ }[];
38
73
  }): Promise<void>;
@@ -16,13 +16,14 @@ const minimatch_1 = __importDefault(require("minimatch"));
16
16
  * @param ext - the file extension, for example `.py`
17
17
  */
18
18
  function convertRuntimeToPlugin(buildRuntime, ext) {
19
- return async function build({ workPath }) {
19
+ // This `build()` signature should match `plugin.build()` signature in `vercel build`.
20
+ return async function build({ vercelConfig, workPath, }) {
20
21
  const opts = { cwd: workPath };
21
22
  const files = await glob_1.default('**', opts);
22
23
  delete files['vercel.json']; // Builders/Runtimes didn't have vercel.json
23
24
  const entrypoints = await glob_1.default(`api/**/*${ext}`, opts);
24
25
  const pages = {};
25
- const { functions = {} } = await readVercelConfig(workPath);
26
+ const { functions = {} } = vercelConfig;
26
27
  const traceDir = path_1.join(workPath, '.output', 'runtime-traced-files');
27
28
  await fs_extra_1.default.ensureDir(traceDir);
28
29
  for (const entrypoint of Object.keys(entrypoints)) {
@@ -45,7 +46,7 @@ function convertRuntimeToPlugin(buildRuntime, ext) {
45
46
  maxDuration: output.maxDuration,
46
47
  environment: output.environment,
47
48
  allowQuery: output.allowQuery,
48
- regions: output.regions,
49
+ //regions: output.regions,
49
50
  };
50
51
  // @ts-ignore This symbol is a private API
51
52
  const lambdaFiles = output[lambda_1.FILES_SYMBOL];
@@ -78,7 +79,7 @@ function convertRuntimeToPlugin(buildRuntime, ext) {
78
79
  await fs_extra_1.default.ensureDir(path_1.dirname(nft));
79
80
  await fs_extra_1.default.writeFile(nft, json);
80
81
  }
81
- await updateFunctionsManifest({ workPath, pages });
82
+ await updateFunctionsManifest({ vercelConfig, workPath, pages });
82
83
  };
83
84
  }
84
85
  exports.convertRuntimeToPlugin = convertRuntimeToPlugin;
@@ -104,18 +105,13 @@ async function readJson(filePath) {
104
105
  throw err;
105
106
  }
106
107
  }
107
- async function readVercelConfig(workPath) {
108
- const vercelJsonPath = path_1.join(workPath, 'vercel.json');
109
- return readJson(vercelJsonPath);
110
- }
111
108
  /**
112
109
  * If `.output/functions-manifest.json` exists, append to the pages
113
110
  * property. Otherwise write a new file. This will also read `vercel.json`
114
111
  * and apply relevant `functions` property config.
115
112
  */
116
- async function updateFunctionsManifest({ workPath, pages, }) {
113
+ async function updateFunctionsManifest({ vercelConfig, workPath, pages, }) {
117
114
  const functionsManifestPath = path_1.join(workPath, '.output', 'functions-manifest.json');
118
- const vercelConfig = await readVercelConfig(workPath);
119
115
  const functionsManifest = await readJson(functionsManifestPath);
120
116
  if (!functionsManifest.version)
121
117
  functionsManifest.version = 1;
@@ -137,21 +133,41 @@ async function updateFunctionsManifest({ workPath, pages, }) {
137
133
  }
138
134
  exports.updateFunctionsManifest = updateFunctionsManifest;
139
135
  /**
140
- * Will append routes to the `routes-manifest.json` file.
141
- * If the file does not exist, it'll be created.
136
+ * Append routes to the `routes-manifest.json` file.
137
+ * If the file does not exist, it will be created.
142
138
  */
143
- async function updateRoutesManifest({ workPath, dynamicRoutes, }) {
139
+ async function updateRoutesManifest({ workPath, redirects, rewrites, headers, dynamicRoutes, staticRoutes, }) {
144
140
  const routesManifestPath = path_1.join(workPath, '.output', 'routes-manifest.json');
145
141
  const routesManifest = await readJson(routesManifestPath);
146
142
  if (!routesManifest.version)
147
- routesManifest.version = 1;
143
+ routesManifest.version = 3;
148
144
  if (routesManifest.pages404 === undefined)
149
145
  routesManifest.pages404 = true;
146
+ if (redirects) {
147
+ if (!routesManifest.redirects)
148
+ routesManifest.redirects = [];
149
+ routesManifest.redirects.push(...redirects);
150
+ }
151
+ if (rewrites) {
152
+ if (!routesManifest.rewrites)
153
+ routesManifest.rewrites = [];
154
+ routesManifest.rewrites.push(...rewrites);
155
+ }
156
+ if (headers) {
157
+ if (!routesManifest.headers)
158
+ routesManifest.headers = [];
159
+ routesManifest.headers.push(...headers);
160
+ }
150
161
  if (dynamicRoutes) {
151
162
  if (!routesManifest.dynamicRoutes)
152
163
  routesManifest.dynamicRoutes = [];
153
164
  routesManifest.dynamicRoutes.push(...dynamicRoutes);
154
165
  }
166
+ if (staticRoutes) {
167
+ if (!routesManifest.staticRoutes)
168
+ routesManifest.staticRoutes = [];
169
+ routesManifest.staticRoutes.push(...staticRoutes);
170
+ }
155
171
  await fs_extra_1.default.writeFile(routesManifestPath, JSON.stringify(routesManifest));
156
172
  }
157
173
  exports.updateRoutesManifest = updateRoutesManifest;
@@ -34,5 +34,11 @@ export declare function detectBuilders(files: string[], pkg?: PackageJson | unde
34
34
  redirectRoutes: Route[] | null;
35
35
  rewriteRoutes: Route[] | null;
36
36
  errorRoutes: Route[] | null;
37
+ limitedRoutes: LimitedRoutes | null;
37
38
  }>;
39
+ interface LimitedRoutes {
40
+ defaultRoutes: Route[];
41
+ redirectRoutes: Route[];
42
+ rewriteRoutes: Route[];
43
+ }
38
44
  export {};
@@ -66,6 +66,7 @@ async function detectBuilders(files, pkg, options = {}) {
66
66
  redirectRoutes: null,
67
67
  rewriteRoutes: null,
68
68
  errorRoutes: null,
69
+ limitedRoutes: null,
69
70
  };
70
71
  }
71
72
  const sortedFiles = files.sort(sortFiles);
@@ -113,6 +114,7 @@ async function detectBuilders(files, pkg, options = {}) {
113
114
  redirectRoutes: null,
114
115
  rewriteRoutes: null,
115
116
  errorRoutes: null,
117
+ limitedRoutes: null,
116
118
  };
117
119
  }
118
120
  if (apiRoute) {
@@ -167,6 +169,7 @@ async function detectBuilders(files, pkg, options = {}) {
167
169
  defaultRoutes: null,
168
170
  rewriteRoutes: null,
169
171
  errorRoutes: null,
172
+ limitedRoutes: null,
170
173
  };
171
174
  }
172
175
  // If `outputDirectory` is an empty string,
@@ -203,6 +206,7 @@ async function detectBuilders(files, pkg, options = {}) {
203
206
  defaultRoutes: null,
204
207
  rewriteRoutes: null,
205
208
  errorRoutes: null,
209
+ limitedRoutes: null,
206
210
  };
207
211
  }
208
212
  const builders = [];
@@ -221,7 +225,7 @@ async function detectBuilders(files, pkg, options = {}) {
221
225
  });
222
226
  }
223
227
  }
224
- const routesResult = getRouteResult(apiRoutes, dynamicRoutes, usedOutputDirectory, apiBuilders, frontendBuilder, options);
228
+ const routesResult = getRouteResult(pkg, apiRoutes, dynamicRoutes, usedOutputDirectory, apiBuilders, frontendBuilder, options);
225
229
  return {
226
230
  warnings,
227
231
  builders: builders.length ? builders : null,
@@ -230,6 +234,7 @@ async function detectBuilders(files, pkg, options = {}) {
230
234
  defaultRoutes: routesResult.defaultRoutes,
231
235
  rewriteRoutes: routesResult.rewriteRoutes,
232
236
  errorRoutes: routesResult.errorRoutes,
237
+ limitedRoutes: routesResult.limitedRoutes,
233
238
  };
234
239
  }
235
240
  exports.detectBuilders = detectBuilders;
@@ -670,23 +675,51 @@ function createRouteFromPath(filePath, featHandleMiss, cleanUrls) {
670
675
  }
671
676
  return { route, isDynamic };
672
677
  }
673
- function getRouteResult(apiRoutes, dynamicRoutes, outputDirectory, apiBuilders, frontendBuilder, options) {
678
+ function getRouteResult(pkg, apiRoutes, dynamicRoutes, outputDirectory, apiBuilders, frontendBuilder, options) {
674
679
  var _a, _b;
680
+ const deps = Object.assign({}, pkg === null || pkg === void 0 ? void 0 : pkg.dependencies, pkg === null || pkg === void 0 ? void 0 : pkg.devDependencies);
675
681
  const defaultRoutes = [];
676
682
  const redirectRoutes = [];
677
683
  const rewriteRoutes = [];
678
684
  const errorRoutes = [];
685
+ const limitedRoutes = {
686
+ defaultRoutes: [],
687
+ redirectRoutes: [],
688
+ rewriteRoutes: [],
689
+ };
679
690
  const framework = ((_a = frontendBuilder === null || frontendBuilder === void 0 ? void 0 : frontendBuilder.config) === null || _a === void 0 ? void 0 : _a.framework) || '';
680
691
  const isNextjs = framework === 'nextjs' || _1.isOfficialRuntime('next', frontendBuilder === null || frontendBuilder === void 0 ? void 0 : frontendBuilder.use);
681
692
  const ignoreRuntimes = (_b = slugToFramework.get(framework)) === null || _b === void 0 ? void 0 : _b.ignoreRuntimes;
682
693
  if (apiRoutes && apiRoutes.length > 0) {
683
694
  if (options.featHandleMiss) {
695
+ // Exclude extension names if the corresponding plugin is not found in package.json
696
+ // detectBuilders({ignoreRoutesForBuilders: ['@vercel/python']})
697
+ // return a copy of routes.
698
+ // We should exclud errorRoutes and
684
699
  const extSet = detectApiExtensions(apiBuilders);
700
+ const withTag = options.tag ? `@${options.tag}` : '';
701
+ const extSetLimited = detectApiExtensions(apiBuilders.filter(b => {
702
+ if (b.use === `@vercel/python${withTag}` &&
703
+ !('vercel-plugin-python' in deps)) {
704
+ return false;
705
+ }
706
+ if (b.use === `@vercel/go${withTag}` &&
707
+ !('vercel-plugin-go' in deps)) {
708
+ return false;
709
+ }
710
+ if (b.use === `@vercel/ruby${withTag}` &&
711
+ !('vercel-plugin-ruby' in deps)) {
712
+ return false;
713
+ }
714
+ return true;
715
+ }));
685
716
  if (extSet.size > 0) {
686
- const exts = Array.from(extSet)
717
+ const extGroup = `(?:\\.(?:${Array.from(extSet)
687
718
  .map(ext => ext.slice(1))
688
- .join('|');
689
- const extGroup = `(?:\\.(?:${exts}))`;
719
+ .join('|')}))`;
720
+ const extGroupLimited = `(?:\\.(?:${Array.from(extSetLimited)
721
+ .map(ext => ext.slice(1))
722
+ .join('|')}))`;
690
723
  if (options.cleanUrls) {
691
724
  redirectRoutes.push({
692
725
  src: `^/(api(?:.+)?)/index${extGroup}?/?$`,
@@ -700,6 +733,18 @@ function getRouteResult(apiRoutes, dynamicRoutes, outputDirectory, apiBuilders,
700
733
  },
701
734
  status: 308,
702
735
  });
736
+ limitedRoutes.redirectRoutes.push({
737
+ src: `^/(api(?:.+)?)/index${extGroupLimited}?/?$`,
738
+ headers: { Location: options.trailingSlash ? '/$1/' : '/$1' },
739
+ status: 308,
740
+ });
741
+ limitedRoutes.redirectRoutes.push({
742
+ src: `^/api/(.+)${extGroupLimited}/?$`,
743
+ headers: {
744
+ Location: options.trailingSlash ? '/api/$1/' : '/api/$1',
745
+ },
746
+ status: 308,
747
+ });
703
748
  }
704
749
  else {
705
750
  defaultRoutes.push({ handle: 'miss' });
@@ -708,9 +753,16 @@ function getRouteResult(apiRoutes, dynamicRoutes, outputDirectory, apiBuilders,
708
753
  dest: '/api/$1',
709
754
  check: true,
710
755
  });
756
+ limitedRoutes.defaultRoutes.push({ handle: 'miss' });
757
+ limitedRoutes.defaultRoutes.push({
758
+ src: `^/api/(.+)${extGroupLimited}$`,
759
+ dest: '/api/$1',
760
+ check: true,
761
+ });
711
762
  }
712
763
  }
713
764
  rewriteRoutes.push(...dynamicRoutes);
765
+ limitedRoutes.rewriteRoutes.push(...dynamicRoutes);
714
766
  if (typeof ignoreRuntimes === 'undefined') {
715
767
  // This route is only necessary to hide the directory listing
716
768
  // to avoid enumerating serverless function names.
@@ -755,6 +807,7 @@ function getRouteResult(apiRoutes, dynamicRoutes, outputDirectory, apiBuilders,
755
807
  redirectRoutes,
756
808
  rewriteRoutes,
757
809
  errorRoutes,
810
+ limitedRoutes,
758
811
  };
759
812
  }
760
813
  function sortFilesBySegmentCount(fileA, fileB) {
package/dist/index.js CHANGED
@@ -26195,7 +26195,7 @@ exports.frameworks = [
26195
26195
  tagline: 'Gatsby helps developers build blazing fast websites and apps with React.',
26196
26196
  description: 'A Gatsby app, using the default starter theme and a Serverless Function API.',
26197
26197
  website: 'https://gatsbyjs.org',
26198
- sort: 2,
26198
+ sort: 5,
26199
26199
  envPrefix: 'GATSBY_',
26200
26200
  detectors: {
26201
26201
  every: [
@@ -26270,6 +26270,73 @@ exports.frameworks = [
26270
26270
  },
26271
26271
  cachePattern: '{.cache,public}/**',
26272
26272
  },
26273
+ {
26274
+ name: 'Remix',
26275
+ slug: 'remix',
26276
+ demo: 'https://remix.examples.vercel.com',
26277
+ logo: 'https://raw.githubusercontent.com/vercel/vercel/main/packages/frameworks/logos/remix.svg',
26278
+ tagline: 'Build Better Websites',
26279
+ description: 'A new Remix app — the result of running `npx create-remix`.',
26280
+ website: 'https://remix.run',
26281
+ sort: 6,
26282
+ detectors: {
26283
+ every: [
26284
+ {
26285
+ path: 'package.json',
26286
+ matchContent: '"(dev)?(d|D)ependencies":\\s*{[^}]*"remix":\\s*".+?"[^}]*}',
26287
+ },
26288
+ ],
26289
+ },
26290
+ settings: {
26291
+ installCommand: {
26292
+ placeholder: '`yarn install` or `npm install`',
26293
+ },
26294
+ buildCommand: {
26295
+ value: 'remix build',
26296
+ placeholder: '`npm run build` or `remix build`',
26297
+ },
26298
+ devCommand: {
26299
+ value: 'remix dev',
26300
+ placeholder: 'remix dev',
26301
+ },
26302
+ outputDirectory: {
26303
+ value: 'public',
26304
+ },
26305
+ },
26306
+ dependency: 'remix',
26307
+ getFsOutputDir: async () => 'public',
26308
+ getOutputDirName: async () => 'public',
26309
+ defaultRoutes: [
26310
+ {
26311
+ src: '^/build/(.*)$',
26312
+ headers: { 'cache-control': 'public, max-age=31536000, immutable' },
26313
+ continue: true,
26314
+ },
26315
+ {
26316
+ handle: 'filesystem',
26317
+ },
26318
+ {
26319
+ src: '/(.*)',
26320
+ dest: '/api',
26321
+ },
26322
+ ],
26323
+ defaultRewrites: [
26324
+ {
26325
+ source: '/(.*)',
26326
+ regex: '/(.*)',
26327
+ destination: '/api',
26328
+ },
26329
+ ],
26330
+ defaultHeaders: [
26331
+ {
26332
+ source: '/build/(.*)',
26333
+ regex: '/build/(.*)',
26334
+ headers: [
26335
+ { key: 'cache-control', value: 'public, max-age=31536000, immutable' },
26336
+ ],
26337
+ },
26338
+ ]
26339
+ },
26273
26340
  {
26274
26341
  name: 'Hexo',
26275
26342
  slug: 'hexo',
@@ -26278,7 +26345,6 @@ exports.frameworks = [
26278
26345
  tagline: 'Hexo is a fast, simple & powerful blog framework powered by Node.js.',
26279
26346
  description: 'A Hexo site, created with the Hexo CLI.',
26280
26347
  website: 'https://hexo.io',
26281
- sort: 3,
26282
26348
  detectors: {
26283
26349
  every: [
26284
26350
  {
@@ -26315,7 +26381,6 @@ exports.frameworks = [
26315
26381
  tagline: '11ty is a simpler static site generator written in JavaScript, created to be an alternative to Jekyll.',
26316
26382
  description: 'An Eleventy site, created with npm init.',
26317
26383
  website: 'https://www.11ty.dev',
26318
- sort: 4,
26319
26384
  detectors: {
26320
26385
  every: [
26321
26386
  {
@@ -27027,6 +27092,7 @@ exports.frameworks = [
27027
27092
  tagline: 'Svelte lets you write high performance reactive apps with significantly less boilerplate.',
27028
27093
  description: 'A basic Svelte app using the default template.',
27029
27094
  website: 'https://svelte.dev',
27095
+ sort: 3,
27030
27096
  detectors: {
27031
27097
  every: [
27032
27098
  {
@@ -27216,6 +27282,7 @@ exports.frameworks = [
27216
27282
  tagline: 'Create React App allows you to get going with React in no time.',
27217
27283
  description: 'A React app, bootstrapped with create-react-app, and a Serverless Function API.',
27218
27284
  website: 'https://create-react-app.dev',
27285
+ sort: 4,
27219
27286
  envPrefix: 'REACT_APP_',
27220
27287
  detectors: {
27221
27288
  some: [
@@ -27597,6 +27664,7 @@ exports.frameworks = [
27597
27664
  tagline: 'Nuxt.js is the web comprehensive framework that lets you dream big with Vue.js.',
27598
27665
  description: 'A Nuxt.js app, bootstrapped with create-nuxt-app.',
27599
27666
  website: 'https://nuxtjs.org',
27667
+ sort: 2,
27600
27668
  envPrefix: 'NUXT_ENV_',
27601
27669
  detectors: {
27602
27670
  every: [
@@ -27690,7 +27758,6 @@ exports.frameworks = [
27690
27758
  tagline: 'Hugo is the world’s fastest framework for building websites, written in Go.',
27691
27759
  description: 'A Hugo site, created with the Hugo CLI.',
27692
27760
  website: 'https://gohugo.io',
27693
- sort: 5,
27694
27761
  detectors: {
27695
27762
  some: [
27696
27763
  {
@@ -32226,13 +32293,14 @@ const minimatch_1 = __importDefault(__webpack_require__(9566));
32226
32293
  * @param ext - the file extension, for example `.py`
32227
32294
  */
32228
32295
  function convertRuntimeToPlugin(buildRuntime, ext) {
32229
- return async function build({ workPath }) {
32296
+ // This `build()` signature should match `plugin.build()` signature in `vercel build`.
32297
+ return async function build({ vercelConfig, workPath, }) {
32230
32298
  const opts = { cwd: workPath };
32231
32299
  const files = await glob_1.default('**', opts);
32232
32300
  delete files['vercel.json']; // Builders/Runtimes didn't have vercel.json
32233
32301
  const entrypoints = await glob_1.default(`api/**/*${ext}`, opts);
32234
32302
  const pages = {};
32235
- const { functions = {} } = await readVercelConfig(workPath);
32303
+ const { functions = {} } = vercelConfig;
32236
32304
  const traceDir = path_1.join(workPath, '.output', 'runtime-traced-files');
32237
32305
  await fs_extra_1.default.ensureDir(traceDir);
32238
32306
  for (const entrypoint of Object.keys(entrypoints)) {
@@ -32255,7 +32323,7 @@ function convertRuntimeToPlugin(buildRuntime, ext) {
32255
32323
  maxDuration: output.maxDuration,
32256
32324
  environment: output.environment,
32257
32325
  allowQuery: output.allowQuery,
32258
- regions: output.regions,
32326
+ //regions: output.regions,
32259
32327
  };
32260
32328
  // @ts-ignore This symbol is a private API
32261
32329
  const lambdaFiles = output[lambda_1.FILES_SYMBOL];
@@ -32288,7 +32356,7 @@ function convertRuntimeToPlugin(buildRuntime, ext) {
32288
32356
  await fs_extra_1.default.ensureDir(path_1.dirname(nft));
32289
32357
  await fs_extra_1.default.writeFile(nft, json);
32290
32358
  }
32291
- await updateFunctionsManifest({ workPath, pages });
32359
+ await updateFunctionsManifest({ vercelConfig, workPath, pages });
32292
32360
  };
32293
32361
  }
32294
32362
  exports.convertRuntimeToPlugin = convertRuntimeToPlugin;
@@ -32314,18 +32382,13 @@ async function readJson(filePath) {
32314
32382
  throw err;
32315
32383
  }
32316
32384
  }
32317
- async function readVercelConfig(workPath) {
32318
- const vercelJsonPath = path_1.join(workPath, 'vercel.json');
32319
- return readJson(vercelJsonPath);
32320
- }
32321
32385
  /**
32322
32386
  * If `.output/functions-manifest.json` exists, append to the pages
32323
32387
  * property. Otherwise write a new file. This will also read `vercel.json`
32324
32388
  * and apply relevant `functions` property config.
32325
32389
  */
32326
- async function updateFunctionsManifest({ workPath, pages, }) {
32390
+ async function updateFunctionsManifest({ vercelConfig, workPath, pages, }) {
32327
32391
  const functionsManifestPath = path_1.join(workPath, '.output', 'functions-manifest.json');
32328
- const vercelConfig = await readVercelConfig(workPath);
32329
32392
  const functionsManifest = await readJson(functionsManifestPath);
32330
32393
  if (!functionsManifest.version)
32331
32394
  functionsManifest.version = 1;
@@ -32347,21 +32410,41 @@ async function updateFunctionsManifest({ workPath, pages, }) {
32347
32410
  }
32348
32411
  exports.updateFunctionsManifest = updateFunctionsManifest;
32349
32412
  /**
32350
- * Will append routes to the `routes-manifest.json` file.
32351
- * If the file does not exist, it'll be created.
32413
+ * Append routes to the `routes-manifest.json` file.
32414
+ * If the file does not exist, it will be created.
32352
32415
  */
32353
- async function updateRoutesManifest({ workPath, dynamicRoutes, }) {
32416
+ async function updateRoutesManifest({ workPath, redirects, rewrites, headers, dynamicRoutes, staticRoutes, }) {
32354
32417
  const routesManifestPath = path_1.join(workPath, '.output', 'routes-manifest.json');
32355
32418
  const routesManifest = await readJson(routesManifestPath);
32356
32419
  if (!routesManifest.version)
32357
- routesManifest.version = 1;
32420
+ routesManifest.version = 3;
32358
32421
  if (routesManifest.pages404 === undefined)
32359
32422
  routesManifest.pages404 = true;
32423
+ if (redirects) {
32424
+ if (!routesManifest.redirects)
32425
+ routesManifest.redirects = [];
32426
+ routesManifest.redirects.push(...redirects);
32427
+ }
32428
+ if (rewrites) {
32429
+ if (!routesManifest.rewrites)
32430
+ routesManifest.rewrites = [];
32431
+ routesManifest.rewrites.push(...rewrites);
32432
+ }
32433
+ if (headers) {
32434
+ if (!routesManifest.headers)
32435
+ routesManifest.headers = [];
32436
+ routesManifest.headers.push(...headers);
32437
+ }
32360
32438
  if (dynamicRoutes) {
32361
32439
  if (!routesManifest.dynamicRoutes)
32362
32440
  routesManifest.dynamicRoutes = [];
32363
32441
  routesManifest.dynamicRoutes.push(...dynamicRoutes);
32364
32442
  }
32443
+ if (staticRoutes) {
32444
+ if (!routesManifest.staticRoutes)
32445
+ routesManifest.staticRoutes = [];
32446
+ routesManifest.staticRoutes.push(...staticRoutes);
32447
+ }
32365
32448
  await fs_extra_1.default.writeFile(routesManifestPath, JSON.stringify(routesManifest));
32366
32449
  }
32367
32450
  exports.updateRoutesManifest = updateRoutesManifest;
@@ -32458,6 +32541,7 @@ async function detectBuilders(files, pkg, options = {}) {
32458
32541
  redirectRoutes: null,
32459
32542
  rewriteRoutes: null,
32460
32543
  errorRoutes: null,
32544
+ limitedRoutes: null,
32461
32545
  };
32462
32546
  }
32463
32547
  const sortedFiles = files.sort(sortFiles);
@@ -32505,6 +32589,7 @@ async function detectBuilders(files, pkg, options = {}) {
32505
32589
  redirectRoutes: null,
32506
32590
  rewriteRoutes: null,
32507
32591
  errorRoutes: null,
32592
+ limitedRoutes: null,
32508
32593
  };
32509
32594
  }
32510
32595
  if (apiRoute) {
@@ -32559,6 +32644,7 @@ async function detectBuilders(files, pkg, options = {}) {
32559
32644
  defaultRoutes: null,
32560
32645
  rewriteRoutes: null,
32561
32646
  errorRoutes: null,
32647
+ limitedRoutes: null,
32562
32648
  };
32563
32649
  }
32564
32650
  // If `outputDirectory` is an empty string,
@@ -32595,6 +32681,7 @@ async function detectBuilders(files, pkg, options = {}) {
32595
32681
  defaultRoutes: null,
32596
32682
  rewriteRoutes: null,
32597
32683
  errorRoutes: null,
32684
+ limitedRoutes: null,
32598
32685
  };
32599
32686
  }
32600
32687
  const builders = [];
@@ -32613,7 +32700,7 @@ async function detectBuilders(files, pkg, options = {}) {
32613
32700
  });
32614
32701
  }
32615
32702
  }
32616
- const routesResult = getRouteResult(apiRoutes, dynamicRoutes, usedOutputDirectory, apiBuilders, frontendBuilder, options);
32703
+ const routesResult = getRouteResult(pkg, apiRoutes, dynamicRoutes, usedOutputDirectory, apiBuilders, frontendBuilder, options);
32617
32704
  return {
32618
32705
  warnings,
32619
32706
  builders: builders.length ? builders : null,
@@ -32622,6 +32709,7 @@ async function detectBuilders(files, pkg, options = {}) {
32622
32709
  defaultRoutes: routesResult.defaultRoutes,
32623
32710
  rewriteRoutes: routesResult.rewriteRoutes,
32624
32711
  errorRoutes: routesResult.errorRoutes,
32712
+ limitedRoutes: routesResult.limitedRoutes,
32625
32713
  };
32626
32714
  }
32627
32715
  exports.detectBuilders = detectBuilders;
@@ -33062,23 +33150,51 @@ function createRouteFromPath(filePath, featHandleMiss, cleanUrls) {
33062
33150
  }
33063
33151
  return { route, isDynamic };
33064
33152
  }
33065
- function getRouteResult(apiRoutes, dynamicRoutes, outputDirectory, apiBuilders, frontendBuilder, options) {
33153
+ function getRouteResult(pkg, apiRoutes, dynamicRoutes, outputDirectory, apiBuilders, frontendBuilder, options) {
33066
33154
  var _a, _b;
33155
+ const deps = Object.assign({}, pkg === null || pkg === void 0 ? void 0 : pkg.dependencies, pkg === null || pkg === void 0 ? void 0 : pkg.devDependencies);
33067
33156
  const defaultRoutes = [];
33068
33157
  const redirectRoutes = [];
33069
33158
  const rewriteRoutes = [];
33070
33159
  const errorRoutes = [];
33160
+ const limitedRoutes = {
33161
+ defaultRoutes: [],
33162
+ redirectRoutes: [],
33163
+ rewriteRoutes: [],
33164
+ };
33071
33165
  const framework = ((_a = frontendBuilder === null || frontendBuilder === void 0 ? void 0 : frontendBuilder.config) === null || _a === void 0 ? void 0 : _a.framework) || '';
33072
33166
  const isNextjs = framework === 'nextjs' || _1.isOfficialRuntime('next', frontendBuilder === null || frontendBuilder === void 0 ? void 0 : frontendBuilder.use);
33073
33167
  const ignoreRuntimes = (_b = slugToFramework.get(framework)) === null || _b === void 0 ? void 0 : _b.ignoreRuntimes;
33074
33168
  if (apiRoutes && apiRoutes.length > 0) {
33075
33169
  if (options.featHandleMiss) {
33170
+ // Exclude extension names if the corresponding plugin is not found in package.json
33171
+ // detectBuilders({ignoreRoutesForBuilders: ['@vercel/python']})
33172
+ // return a copy of routes.
33173
+ // We should exclud errorRoutes and
33076
33174
  const extSet = detectApiExtensions(apiBuilders);
33175
+ const withTag = options.tag ? `@${options.tag}` : '';
33176
+ const extSetLimited = detectApiExtensions(apiBuilders.filter(b => {
33177
+ if (b.use === `@vercel/python${withTag}` &&
33178
+ !('vercel-plugin-python' in deps)) {
33179
+ return false;
33180
+ }
33181
+ if (b.use === `@vercel/go${withTag}` &&
33182
+ !('vercel-plugin-go' in deps)) {
33183
+ return false;
33184
+ }
33185
+ if (b.use === `@vercel/ruby${withTag}` &&
33186
+ !('vercel-plugin-ruby' in deps)) {
33187
+ return false;
33188
+ }
33189
+ return true;
33190
+ }));
33077
33191
  if (extSet.size > 0) {
33078
- const exts = Array.from(extSet)
33192
+ const extGroup = `(?:\\.(?:${Array.from(extSet)
33193
+ .map(ext => ext.slice(1))
33194
+ .join('|')}))`;
33195
+ const extGroupLimited = `(?:\\.(?:${Array.from(extSetLimited)
33079
33196
  .map(ext => ext.slice(1))
33080
- .join('|');
33081
- const extGroup = `(?:\\.(?:${exts}))`;
33197
+ .join('|')}))`;
33082
33198
  if (options.cleanUrls) {
33083
33199
  redirectRoutes.push({
33084
33200
  src: `^/(api(?:.+)?)/index${extGroup}?/?$`,
@@ -33092,6 +33208,18 @@ function getRouteResult(apiRoutes, dynamicRoutes, outputDirectory, apiBuilders,
33092
33208
  },
33093
33209
  status: 308,
33094
33210
  });
33211
+ limitedRoutes.redirectRoutes.push({
33212
+ src: `^/(api(?:.+)?)/index${extGroupLimited}?/?$`,
33213
+ headers: { Location: options.trailingSlash ? '/$1/' : '/$1' },
33214
+ status: 308,
33215
+ });
33216
+ limitedRoutes.redirectRoutes.push({
33217
+ src: `^/api/(.+)${extGroupLimited}/?$`,
33218
+ headers: {
33219
+ Location: options.trailingSlash ? '/api/$1/' : '/api/$1',
33220
+ },
33221
+ status: 308,
33222
+ });
33095
33223
  }
33096
33224
  else {
33097
33225
  defaultRoutes.push({ handle: 'miss' });
@@ -33100,9 +33228,16 @@ function getRouteResult(apiRoutes, dynamicRoutes, outputDirectory, apiBuilders,
33100
33228
  dest: '/api/$1',
33101
33229
  check: true,
33102
33230
  });
33231
+ limitedRoutes.defaultRoutes.push({ handle: 'miss' });
33232
+ limitedRoutes.defaultRoutes.push({
33233
+ src: `^/api/(.+)${extGroupLimited}$`,
33234
+ dest: '/api/$1',
33235
+ check: true,
33236
+ });
33103
33237
  }
33104
33238
  }
33105
33239
  rewriteRoutes.push(...dynamicRoutes);
33240
+ limitedRoutes.rewriteRoutes.push(...dynamicRoutes);
33106
33241
  if (typeof ignoreRuntimes === 'undefined') {
33107
33242
  // This route is only necessary to hide the directory listing
33108
33243
  // to avoid enumerating serverless function names.
@@ -33147,6 +33282,7 @@ function getRouteResult(apiRoutes, dynamicRoutes, outputDirectory, apiBuilders,
33147
33282
  redirectRoutes,
33148
33283
  rewriteRoutes,
33149
33284
  errorRoutes,
33285
+ limitedRoutes,
33150
33286
  };
33151
33287
  }
33152
33288
  function sortFilesBySegmentCount(fileA, fileB) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/build-utils",
3
- "version": "2.12.3-canary.20",
3
+ "version": "2.12.3-canary.24",
4
4
  "license": "MIT",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.js",
@@ -30,7 +30,7 @@
30
30
  "@types/node-fetch": "^2.1.6",
31
31
  "@types/semver": "6.0.0",
32
32
  "@types/yazl": "^2.4.1",
33
- "@vercel/frameworks": "0.5.1-canary.12",
33
+ "@vercel/frameworks": "0.5.1-canary.14",
34
34
  "@vercel/ncc": "0.24.0",
35
35
  "aggregate-error": "3.0.1",
36
36
  "async-retry": "1.2.3",
@@ -49,5 +49,5 @@
49
49
  "typescript": "4.3.4",
50
50
  "yazl": "2.4.3"
51
51
  },
52
- "gitHead": "2721b3449dd3ccd213f9bdd558e61eeba3ba710c"
52
+ "gitHead": "3559531e4c14875a275059e3f43aeba38deda275"
53
53
  }