@vercel/build-utils 2.12.3-canary.22 → 2.12.3-canary.23

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.
@@ -11,8 +11,6 @@ export declare function convertRuntimeToPlugin(buildRuntime: (options: BuildOpti
11
11
  vercelConfig: {
12
12
  functions?: BuilderFunctions;
13
13
  regions?: string[];
14
- trailingSlash?: boolean;
15
- cleanUrls?: boolean;
16
14
  };
17
15
  workPath: string;
18
16
  }) => Promise<void>;
@@ -8,7 +8,6 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
8
8
  const path_1 = require("path");
9
9
  const glob_1 = __importDefault(require("./fs/glob"));
10
10
  const normalize_path_1 = require("./fs/normalize-path");
11
- const detect_builders_1 = require("./detect-builders");
12
11
  const lambda_1 = require("./lambda");
13
12
  const minimatch_1 = __importDefault(require("minimatch"));
14
13
  /**
@@ -19,13 +18,12 @@ const minimatch_1 = __importDefault(require("minimatch"));
19
18
  function convertRuntimeToPlugin(buildRuntime, ext) {
20
19
  // This `build()` signature should match `plugin.build()` signature in `vercel build`.
21
20
  return async function build({ vercelConfig, workPath, }) {
22
- var _a;
23
21
  const opts = { cwd: workPath };
24
22
  const files = await glob_1.default('**', opts);
25
23
  delete files['vercel.json']; // Builders/Runtimes didn't have vercel.json
26
24
  const entrypoints = await glob_1.default(`api/**/*${ext}`, opts);
27
25
  const pages = {};
28
- const { functions = {}, cleanUrls, trailingSlash } = vercelConfig;
26
+ const { functions = {} } = vercelConfig;
29
27
  const traceDir = path_1.join(workPath, '.output', 'runtime-traced-files');
30
28
  await fs_extra_1.default.ensureDir(traceDir);
31
29
  for (const entrypoint of Object.keys(entrypoints)) {
@@ -48,7 +46,7 @@ function convertRuntimeToPlugin(buildRuntime, ext) {
48
46
  maxDuration: output.maxDuration,
49
47
  environment: output.environment,
50
48
  allowQuery: output.allowQuery,
51
- regions: output.regions,
49
+ //regions: output.regions,
52
50
  };
53
51
  // @ts-ignore This symbol is a private API
54
52
  const lambdaFiles = output[lambda_1.FILES_SYMBOL];
@@ -82,53 +80,6 @@ function convertRuntimeToPlugin(buildRuntime, ext) {
82
80
  await fs_extra_1.default.writeFile(nft, json);
83
81
  }
84
82
  await updateFunctionsManifest({ vercelConfig, workPath, pages });
85
- const { warnings, errors,
86
- //defaultRoutes,
87
- redirectRoutes,
88
- //rewriteRoutes,
89
- dynamicRoutesWithKeys,
90
- // errorRoutes, already handled by pages404
91
- } = await detect_builders_1.detectBuilders(Object.keys(files), null, {
92
- tag: 'latest',
93
- functions: functions,
94
- projectSettings: undefined,
95
- featHandleMiss: true,
96
- cleanUrls,
97
- trailingSlash,
98
- });
99
- if (errors) {
100
- throw new Error(errors[0].message);
101
- }
102
- if (warnings) {
103
- warnings.forEach(warning => console.warn(warning.message, warning.link));
104
- }
105
- const redirects = (_a = redirectRoutes === null || redirectRoutes === void 0 ? void 0 : redirectRoutes.filter(r => r.src && 'headers' in r)) === null || _a === void 0 ? void 0 : _a.map(r => {
106
- var _a;
107
- return ({
108
- source: r.src || '',
109
- destination: 'headers' in r && ((_a = r.headers) === null || _a === void 0 ? void 0 : _a.Location) ? r.headers.Location : '',
110
- statusCode: 'status' in r && r.status ? r.status : 307,
111
- regex: r.src || '',
112
- });
113
- });
114
- const dynamicRoutes = dynamicRoutesWithKeys === null || dynamicRoutesWithKeys === void 0 ? void 0 : dynamicRoutesWithKeys.map(r => {
115
- const keys = Object.keys(r.routeKeys);
116
- return {
117
- page: '/' + r.fileName.slice(0, -ext.length),
118
- regex: r.regex,
119
- routeKeys: r.routeKeys,
120
- namedRegex: r.regex
121
- .split('([^/]+)')
122
- .map((str, i) => str + (keys[i] ? `(?<${keys[i]}>[^/]+)` : ''))
123
- .join(''),
124
- };
125
- });
126
- await updateRoutesManifest({
127
- workPath,
128
- redirects,
129
- rewrites: [],
130
- dynamicRoutes,
131
- });
132
83
  };
133
84
  }
134
85
  exports.convertRuntimeToPlugin = convertRuntimeToPlugin;
@@ -6,13 +6,6 @@ interface ErrorResponse {
6
6
  action?: string;
7
7
  link?: string;
8
8
  }
9
- interface DynamicRoutesWithKeys {
10
- fileName: string;
11
- regex: string;
12
- routeKeys: {
13
- [key: string]: string;
14
- };
15
- }
16
9
  interface Options {
17
10
  tag?: 'canary' | 'latest' | string;
18
11
  functions?: BuilderFunctions;
@@ -41,6 +34,11 @@ export declare function detectBuilders(files: string[], pkg?: PackageJson | unde
41
34
  redirectRoutes: Route[] | null;
42
35
  rewriteRoutes: Route[] | null;
43
36
  errorRoutes: Route[] | null;
44
- dynamicRoutesWithKeys: DynamicRoutesWithKeys[] | null;
37
+ limitedRoutes: LimitedRoutes | null;
45
38
  }>;
39
+ interface LimitedRoutes {
40
+ defaultRoutes: Route[];
41
+ redirectRoutes: Route[];
42
+ rewriteRoutes: Route[];
43
+ }
46
44
  export {};
@@ -66,7 +66,7 @@ async function detectBuilders(files, pkg, options = {}) {
66
66
  redirectRoutes: null,
67
67
  rewriteRoutes: null,
68
68
  errorRoutes: null,
69
- dynamicRoutesWithKeys: null,
69
+ limitedRoutes: null,
70
70
  };
71
71
  }
72
72
  const sortedFiles = files.sort(sortFiles);
@@ -100,12 +100,11 @@ async function detectBuilders(files, pkg, options = {}) {
100
100
  let fallbackEntrypoint = null;
101
101
  const apiRoutes = [];
102
102
  const dynamicRoutes = [];
103
- const dynamicRoutesWithKeys = [];
104
103
  // API
105
104
  for (const fileName of sortedFiles) {
106
105
  const apiBuilder = maybeGetApiBuilder(fileName, apiMatches, options);
107
106
  if (apiBuilder) {
108
- const { routeError, apiRoute, isDynamic, routeKeys } = getApiRoute(fileName, apiSortedFiles, options, absolutePathCache);
107
+ const { routeError, apiRoute, isDynamic } = getApiRoute(fileName, apiSortedFiles, options, absolutePathCache);
109
108
  if (routeError) {
110
109
  return {
111
110
  builders: null,
@@ -115,18 +114,13 @@ async function detectBuilders(files, pkg, options = {}) {
115
114
  redirectRoutes: null,
116
115
  rewriteRoutes: null,
117
116
  errorRoutes: null,
118
- dynamicRoutesWithKeys: null,
117
+ limitedRoutes: null,
119
118
  };
120
119
  }
121
120
  if (apiRoute) {
122
121
  apiRoutes.push(apiRoute);
123
122
  if (isDynamic) {
124
123
  dynamicRoutes.push(apiRoute);
125
- dynamicRoutesWithKeys.push({
126
- fileName,
127
- regex: apiRoute.src,
128
- routeKeys,
129
- });
130
124
  }
131
125
  }
132
126
  addToUsedFunctions(apiBuilder);
@@ -175,7 +169,7 @@ async function detectBuilders(files, pkg, options = {}) {
175
169
  defaultRoutes: null,
176
170
  rewriteRoutes: null,
177
171
  errorRoutes: null,
178
- dynamicRoutesWithKeys: null,
172
+ limitedRoutes: null,
179
173
  };
180
174
  }
181
175
  // If `outputDirectory` is an empty string,
@@ -212,7 +206,7 @@ async function detectBuilders(files, pkg, options = {}) {
212
206
  defaultRoutes: null,
213
207
  rewriteRoutes: null,
214
208
  errorRoutes: null,
215
- dynamicRoutesWithKeys: null,
209
+ limitedRoutes: null,
216
210
  };
217
211
  }
218
212
  const builders = [];
@@ -231,7 +225,7 @@ async function detectBuilders(files, pkg, options = {}) {
231
225
  });
232
226
  }
233
227
  }
234
- const routesResult = getRouteResult(apiRoutes, dynamicRoutes, usedOutputDirectory, apiBuilders, frontendBuilder, options);
228
+ const routesResult = getRouteResult(pkg, apiRoutes, dynamicRoutes, usedOutputDirectory, apiBuilders, frontendBuilder, options);
235
229
  return {
236
230
  warnings,
237
231
  builders: builders.length ? builders : null,
@@ -240,7 +234,7 @@ async function detectBuilders(files, pkg, options = {}) {
240
234
  defaultRoutes: routesResult.defaultRoutes,
241
235
  rewriteRoutes: routesResult.rewriteRoutes,
242
236
  errorRoutes: routesResult.errorRoutes,
243
- dynamicRoutesWithKeys,
237
+ limitedRoutes: routesResult.limitedRoutes,
244
238
  };
245
239
  }
246
240
  exports.detectBuilders = detectBuilders;
@@ -495,7 +489,6 @@ function getApiRoute(fileName, sortedFiles, options, absolutePathCache) {
495
489
  return {
496
490
  apiRoute: null,
497
491
  isDynamic: false,
498
- routeKeys: {},
499
492
  routeError: {
500
493
  code: 'conflicting_path_segment',
501
494
  message: `The segment "${conflictingSegment}" occurs more than ` +
@@ -510,7 +503,6 @@ function getApiRoute(fileName, sortedFiles, options, absolutePathCache) {
510
503
  return {
511
504
  apiRoute: null,
512
505
  isDynamic: false,
513
- routeKeys: {},
514
506
  routeError: {
515
507
  code: 'conflicting_file_path',
516
508
  message: `Two or more files have conflicting paths or names. ` +
@@ -523,7 +515,6 @@ function getApiRoute(fileName, sortedFiles, options, absolutePathCache) {
523
515
  return {
524
516
  apiRoute: out.route,
525
517
  isDynamic: out.isDynamic,
526
- routeKeys: out.routeKeys,
527
518
  routeError: null,
528
519
  };
529
520
  }
@@ -633,7 +624,6 @@ function createRouteFromPath(filePath, featHandleMiss, cleanUrls) {
633
624
  const parts = filePath.split('/');
634
625
  let counter = 1;
635
626
  const query = [];
636
- const routeKeys = {};
637
627
  let isDynamic = false;
638
628
  const srcParts = parts.map((segment, i) => {
639
629
  const name = getSegmentName(segment);
@@ -641,7 +631,6 @@ function createRouteFromPath(filePath, featHandleMiss, cleanUrls) {
641
631
  if (name !== null) {
642
632
  // We can't use `URLSearchParams` because `$` would get escaped
643
633
  query.push(`${name}=$${counter++}`);
644
- routeKeys[name] = name;
645
634
  isDynamic = true;
646
635
  return `([^/]+)`;
647
636
  }
@@ -684,25 +673,53 @@ function createRouteFromPath(filePath, featHandleMiss, cleanUrls) {
684
673
  dest: `/${filePath}${queryString}`,
685
674
  };
686
675
  }
687
- return { route, isDynamic, routeKeys };
676
+ return { route, isDynamic };
688
677
  }
689
- function getRouteResult(apiRoutes, dynamicRoutes, outputDirectory, apiBuilders, frontendBuilder, options) {
678
+ function getRouteResult(pkg, apiRoutes, dynamicRoutes, outputDirectory, apiBuilders, frontendBuilder, options) {
690
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);
691
681
  const defaultRoutes = [];
692
682
  const redirectRoutes = [];
693
683
  const rewriteRoutes = [];
694
684
  const errorRoutes = [];
685
+ const limitedRoutes = {
686
+ defaultRoutes: [],
687
+ redirectRoutes: [],
688
+ rewriteRoutes: [],
689
+ };
695
690
  const framework = ((_a = frontendBuilder === null || frontendBuilder === void 0 ? void 0 : frontendBuilder.config) === null || _a === void 0 ? void 0 : _a.framework) || '';
696
691
  const isNextjs = framework === 'nextjs' || _1.isOfficialRuntime('next', frontendBuilder === null || frontendBuilder === void 0 ? void 0 : frontendBuilder.use);
697
692
  const ignoreRuntimes = (_b = slugToFramework.get(framework)) === null || _b === void 0 ? void 0 : _b.ignoreRuntimes;
698
693
  if (apiRoutes && apiRoutes.length > 0) {
699
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
700
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
+ }));
701
716
  if (extSet.size > 0) {
702
- const exts = Array.from(extSet)
717
+ const extGroup = `(?:\\.(?:${Array.from(extSet)
703
718
  .map(ext => ext.slice(1))
704
- .join('|');
705
- const extGroup = `(?:\\.(?:${exts}))`;
719
+ .join('|')}))`;
720
+ const extGroupLimited = `(?:\\.(?:${Array.from(extSetLimited)
721
+ .map(ext => ext.slice(1))
722
+ .join('|')}))`;
706
723
  if (options.cleanUrls) {
707
724
  redirectRoutes.push({
708
725
  src: `^/(api(?:.+)?)/index${extGroup}?/?$`,
@@ -716,6 +733,18 @@ function getRouteResult(apiRoutes, dynamicRoutes, outputDirectory, apiBuilders,
716
733
  },
717
734
  status: 308,
718
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
+ });
719
748
  }
720
749
  else {
721
750
  defaultRoutes.push({ handle: 'miss' });
@@ -724,9 +753,16 @@ function getRouteResult(apiRoutes, dynamicRoutes, outputDirectory, apiBuilders,
724
753
  dest: '/api/$1',
725
754
  check: true,
726
755
  });
756
+ limitedRoutes.defaultRoutes.push({ handle: 'miss' });
757
+ limitedRoutes.defaultRoutes.push({
758
+ src: `^/api/(.+)${extGroupLimited}$`,
759
+ dest: '/api/$1',
760
+ check: true,
761
+ });
727
762
  }
728
763
  }
729
764
  rewriteRoutes.push(...dynamicRoutes);
765
+ limitedRoutes.rewriteRoutes.push(...dynamicRoutes);
730
766
  if (typeof ignoreRuntimes === 'undefined') {
731
767
  // This route is only necessary to hide the directory listing
732
768
  // to avoid enumerating serverless function names.
@@ -771,6 +807,7 @@ function getRouteResult(apiRoutes, dynamicRoutes, outputDirectory, apiBuilders,
771
807
  redirectRoutes,
772
808
  rewriteRoutes,
773
809
  errorRoutes,
810
+ limitedRoutes,
774
811
  };
775
812
  }
776
813
  function sortFilesBySegmentCount(fileA, fileB) {
package/dist/index.js CHANGED
@@ -32285,7 +32285,6 @@ const fs_extra_1 = __importDefault(__webpack_require__(5392));
32285
32285
  const path_1 = __webpack_require__(5622);
32286
32286
  const glob_1 = __importDefault(__webpack_require__(4240));
32287
32287
  const normalize_path_1 = __webpack_require__(6261);
32288
- const detect_builders_1 = __webpack_require__(4246);
32289
32288
  const lambda_1 = __webpack_require__(6721);
32290
32289
  const minimatch_1 = __importDefault(__webpack_require__(9566));
32291
32290
  /**
@@ -32296,13 +32295,12 @@ const minimatch_1 = __importDefault(__webpack_require__(9566));
32296
32295
  function convertRuntimeToPlugin(buildRuntime, ext) {
32297
32296
  // This `build()` signature should match `plugin.build()` signature in `vercel build`.
32298
32297
  return async function build({ vercelConfig, workPath, }) {
32299
- var _a;
32300
32298
  const opts = { cwd: workPath };
32301
32299
  const files = await glob_1.default('**', opts);
32302
32300
  delete files['vercel.json']; // Builders/Runtimes didn't have vercel.json
32303
32301
  const entrypoints = await glob_1.default(`api/**/*${ext}`, opts);
32304
32302
  const pages = {};
32305
- const { functions = {}, cleanUrls, trailingSlash } = vercelConfig;
32303
+ const { functions = {} } = vercelConfig;
32306
32304
  const traceDir = path_1.join(workPath, '.output', 'runtime-traced-files');
32307
32305
  await fs_extra_1.default.ensureDir(traceDir);
32308
32306
  for (const entrypoint of Object.keys(entrypoints)) {
@@ -32325,7 +32323,7 @@ function convertRuntimeToPlugin(buildRuntime, ext) {
32325
32323
  maxDuration: output.maxDuration,
32326
32324
  environment: output.environment,
32327
32325
  allowQuery: output.allowQuery,
32328
- regions: output.regions,
32326
+ //regions: output.regions,
32329
32327
  };
32330
32328
  // @ts-ignore This symbol is a private API
32331
32329
  const lambdaFiles = output[lambda_1.FILES_SYMBOL];
@@ -32359,53 +32357,6 @@ function convertRuntimeToPlugin(buildRuntime, ext) {
32359
32357
  await fs_extra_1.default.writeFile(nft, json);
32360
32358
  }
32361
32359
  await updateFunctionsManifest({ vercelConfig, workPath, pages });
32362
- const { warnings, errors,
32363
- //defaultRoutes,
32364
- redirectRoutes,
32365
- //rewriteRoutes,
32366
- dynamicRoutesWithKeys,
32367
- // errorRoutes, already handled by pages404
32368
- } = await detect_builders_1.detectBuilders(Object.keys(files), null, {
32369
- tag: 'latest',
32370
- functions: functions,
32371
- projectSettings: undefined,
32372
- featHandleMiss: true,
32373
- cleanUrls,
32374
- trailingSlash,
32375
- });
32376
- if (errors) {
32377
- throw new Error(errors[0].message);
32378
- }
32379
- if (warnings) {
32380
- warnings.forEach(warning => console.warn(warning.message, warning.link));
32381
- }
32382
- const redirects = (_a = redirectRoutes === null || redirectRoutes === void 0 ? void 0 : redirectRoutes.filter(r => r.src && 'headers' in r)) === null || _a === void 0 ? void 0 : _a.map(r => {
32383
- var _a;
32384
- return ({
32385
- source: r.src || '',
32386
- destination: 'headers' in r && ((_a = r.headers) === null || _a === void 0 ? void 0 : _a.Location) ? r.headers.Location : '',
32387
- statusCode: 'status' in r && r.status ? r.status : 307,
32388
- regex: r.src || '',
32389
- });
32390
- });
32391
- const dynamicRoutes = dynamicRoutesWithKeys === null || dynamicRoutesWithKeys === void 0 ? void 0 : dynamicRoutesWithKeys.map(r => {
32392
- const keys = Object.keys(r.routeKeys);
32393
- return {
32394
- page: '/' + r.fileName.slice(0, -ext.length),
32395
- regex: r.regex,
32396
- routeKeys: r.routeKeys,
32397
- namedRegex: r.regex
32398
- .split('([^/]+)')
32399
- .map((str, i) => str + (keys[i] ? `(?<${keys[i]}>[^/]+)` : ''))
32400
- .join(''),
32401
- };
32402
- });
32403
- await updateRoutesManifest({
32404
- workPath,
32405
- redirects,
32406
- rewrites: [],
32407
- dynamicRoutes,
32408
- });
32409
32360
  };
32410
32361
  }
32411
32362
  exports.convertRuntimeToPlugin = convertRuntimeToPlugin;
@@ -32590,7 +32541,7 @@ async function detectBuilders(files, pkg, options = {}) {
32590
32541
  redirectRoutes: null,
32591
32542
  rewriteRoutes: null,
32592
32543
  errorRoutes: null,
32593
- dynamicRoutesWithKeys: null,
32544
+ limitedRoutes: null,
32594
32545
  };
32595
32546
  }
32596
32547
  const sortedFiles = files.sort(sortFiles);
@@ -32624,12 +32575,11 @@ async function detectBuilders(files, pkg, options = {}) {
32624
32575
  let fallbackEntrypoint = null;
32625
32576
  const apiRoutes = [];
32626
32577
  const dynamicRoutes = [];
32627
- const dynamicRoutesWithKeys = [];
32628
32578
  // API
32629
32579
  for (const fileName of sortedFiles) {
32630
32580
  const apiBuilder = maybeGetApiBuilder(fileName, apiMatches, options);
32631
32581
  if (apiBuilder) {
32632
- const { routeError, apiRoute, isDynamic, routeKeys } = getApiRoute(fileName, apiSortedFiles, options, absolutePathCache);
32582
+ const { routeError, apiRoute, isDynamic } = getApiRoute(fileName, apiSortedFiles, options, absolutePathCache);
32633
32583
  if (routeError) {
32634
32584
  return {
32635
32585
  builders: null,
@@ -32639,18 +32589,13 @@ async function detectBuilders(files, pkg, options = {}) {
32639
32589
  redirectRoutes: null,
32640
32590
  rewriteRoutes: null,
32641
32591
  errorRoutes: null,
32642
- dynamicRoutesWithKeys: null,
32592
+ limitedRoutes: null,
32643
32593
  };
32644
32594
  }
32645
32595
  if (apiRoute) {
32646
32596
  apiRoutes.push(apiRoute);
32647
32597
  if (isDynamic) {
32648
32598
  dynamicRoutes.push(apiRoute);
32649
- dynamicRoutesWithKeys.push({
32650
- fileName,
32651
- regex: apiRoute.src,
32652
- routeKeys,
32653
- });
32654
32599
  }
32655
32600
  }
32656
32601
  addToUsedFunctions(apiBuilder);
@@ -32699,7 +32644,7 @@ async function detectBuilders(files, pkg, options = {}) {
32699
32644
  defaultRoutes: null,
32700
32645
  rewriteRoutes: null,
32701
32646
  errorRoutes: null,
32702
- dynamicRoutesWithKeys: null,
32647
+ limitedRoutes: null,
32703
32648
  };
32704
32649
  }
32705
32650
  // If `outputDirectory` is an empty string,
@@ -32736,7 +32681,7 @@ async function detectBuilders(files, pkg, options = {}) {
32736
32681
  defaultRoutes: null,
32737
32682
  rewriteRoutes: null,
32738
32683
  errorRoutes: null,
32739
- dynamicRoutesWithKeys: null,
32684
+ limitedRoutes: null,
32740
32685
  };
32741
32686
  }
32742
32687
  const builders = [];
@@ -32755,7 +32700,7 @@ async function detectBuilders(files, pkg, options = {}) {
32755
32700
  });
32756
32701
  }
32757
32702
  }
32758
- const routesResult = getRouteResult(apiRoutes, dynamicRoutes, usedOutputDirectory, apiBuilders, frontendBuilder, options);
32703
+ const routesResult = getRouteResult(pkg, apiRoutes, dynamicRoutes, usedOutputDirectory, apiBuilders, frontendBuilder, options);
32759
32704
  return {
32760
32705
  warnings,
32761
32706
  builders: builders.length ? builders : null,
@@ -32764,7 +32709,7 @@ async function detectBuilders(files, pkg, options = {}) {
32764
32709
  defaultRoutes: routesResult.defaultRoutes,
32765
32710
  rewriteRoutes: routesResult.rewriteRoutes,
32766
32711
  errorRoutes: routesResult.errorRoutes,
32767
- dynamicRoutesWithKeys,
32712
+ limitedRoutes: routesResult.limitedRoutes,
32768
32713
  };
32769
32714
  }
32770
32715
  exports.detectBuilders = detectBuilders;
@@ -33019,7 +32964,6 @@ function getApiRoute(fileName, sortedFiles, options, absolutePathCache) {
33019
32964
  return {
33020
32965
  apiRoute: null,
33021
32966
  isDynamic: false,
33022
- routeKeys: {},
33023
32967
  routeError: {
33024
32968
  code: 'conflicting_path_segment',
33025
32969
  message: `The segment "${conflictingSegment}" occurs more than ` +
@@ -33034,7 +32978,6 @@ function getApiRoute(fileName, sortedFiles, options, absolutePathCache) {
33034
32978
  return {
33035
32979
  apiRoute: null,
33036
32980
  isDynamic: false,
33037
- routeKeys: {},
33038
32981
  routeError: {
33039
32982
  code: 'conflicting_file_path',
33040
32983
  message: `Two or more files have conflicting paths or names. ` +
@@ -33047,7 +32990,6 @@ function getApiRoute(fileName, sortedFiles, options, absolutePathCache) {
33047
32990
  return {
33048
32991
  apiRoute: out.route,
33049
32992
  isDynamic: out.isDynamic,
33050
- routeKeys: out.routeKeys,
33051
32993
  routeError: null,
33052
32994
  };
33053
32995
  }
@@ -33157,7 +33099,6 @@ function createRouteFromPath(filePath, featHandleMiss, cleanUrls) {
33157
33099
  const parts = filePath.split('/');
33158
33100
  let counter = 1;
33159
33101
  const query = [];
33160
- const routeKeys = {};
33161
33102
  let isDynamic = false;
33162
33103
  const srcParts = parts.map((segment, i) => {
33163
33104
  const name = getSegmentName(segment);
@@ -33165,7 +33106,6 @@ function createRouteFromPath(filePath, featHandleMiss, cleanUrls) {
33165
33106
  if (name !== null) {
33166
33107
  // We can't use `URLSearchParams` because `$` would get escaped
33167
33108
  query.push(`${name}=$${counter++}`);
33168
- routeKeys[name] = name;
33169
33109
  isDynamic = true;
33170
33110
  return `([^/]+)`;
33171
33111
  }
@@ -33208,25 +33148,53 @@ function createRouteFromPath(filePath, featHandleMiss, cleanUrls) {
33208
33148
  dest: `/${filePath}${queryString}`,
33209
33149
  };
33210
33150
  }
33211
- return { route, isDynamic, routeKeys };
33151
+ return { route, isDynamic };
33212
33152
  }
33213
- function getRouteResult(apiRoutes, dynamicRoutes, outputDirectory, apiBuilders, frontendBuilder, options) {
33153
+ function getRouteResult(pkg, apiRoutes, dynamicRoutes, outputDirectory, apiBuilders, frontendBuilder, options) {
33214
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);
33215
33156
  const defaultRoutes = [];
33216
33157
  const redirectRoutes = [];
33217
33158
  const rewriteRoutes = [];
33218
33159
  const errorRoutes = [];
33160
+ const limitedRoutes = {
33161
+ defaultRoutes: [],
33162
+ redirectRoutes: [],
33163
+ rewriteRoutes: [],
33164
+ };
33219
33165
  const framework = ((_a = frontendBuilder === null || frontendBuilder === void 0 ? void 0 : frontendBuilder.config) === null || _a === void 0 ? void 0 : _a.framework) || '';
33220
33166
  const isNextjs = framework === 'nextjs' || _1.isOfficialRuntime('next', frontendBuilder === null || frontendBuilder === void 0 ? void 0 : frontendBuilder.use);
33221
33167
  const ignoreRuntimes = (_b = slugToFramework.get(framework)) === null || _b === void 0 ? void 0 : _b.ignoreRuntimes;
33222
33168
  if (apiRoutes && apiRoutes.length > 0) {
33223
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
33224
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
+ }));
33225
33191
  if (extSet.size > 0) {
33226
- const exts = Array.from(extSet)
33192
+ const extGroup = `(?:\\.(?:${Array.from(extSet)
33227
33193
  .map(ext => ext.slice(1))
33228
- .join('|');
33229
- const extGroup = `(?:\\.(?:${exts}))`;
33194
+ .join('|')}))`;
33195
+ const extGroupLimited = `(?:\\.(?:${Array.from(extSetLimited)
33196
+ .map(ext => ext.slice(1))
33197
+ .join('|')}))`;
33230
33198
  if (options.cleanUrls) {
33231
33199
  redirectRoutes.push({
33232
33200
  src: `^/(api(?:.+)?)/index${extGroup}?/?$`,
@@ -33240,6 +33208,18 @@ function getRouteResult(apiRoutes, dynamicRoutes, outputDirectory, apiBuilders,
33240
33208
  },
33241
33209
  status: 308,
33242
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
+ });
33243
33223
  }
33244
33224
  else {
33245
33225
  defaultRoutes.push({ handle: 'miss' });
@@ -33248,9 +33228,16 @@ function getRouteResult(apiRoutes, dynamicRoutes, outputDirectory, apiBuilders,
33248
33228
  dest: '/api/$1',
33249
33229
  check: true,
33250
33230
  });
33231
+ limitedRoutes.defaultRoutes.push({ handle: 'miss' });
33232
+ limitedRoutes.defaultRoutes.push({
33233
+ src: `^/api/(.+)${extGroupLimited}$`,
33234
+ dest: '/api/$1',
33235
+ check: true,
33236
+ });
33251
33237
  }
33252
33238
  }
33253
33239
  rewriteRoutes.push(...dynamicRoutes);
33240
+ limitedRoutes.rewriteRoutes.push(...dynamicRoutes);
33254
33241
  if (typeof ignoreRuntimes === 'undefined') {
33255
33242
  // This route is only necessary to hide the directory listing
33256
33243
  // to avoid enumerating serverless function names.
@@ -33295,6 +33282,7 @@ function getRouteResult(apiRoutes, dynamicRoutes, outputDirectory, apiBuilders,
33295
33282
  redirectRoutes,
33296
33283
  rewriteRoutes,
33297
33284
  errorRoutes,
33285
+ limitedRoutes,
33298
33286
  };
33299
33287
  }
33300
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.22",
3
+ "version": "2.12.3-canary.23",
4
4
  "license": "MIT",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.js",
@@ -49,5 +49,5 @@
49
49
  "typescript": "4.3.4",
50
50
  "yazl": "2.4.3"
51
51
  },
52
- "gitHead": "0cacb1bdace342133fad4bd7a98354e5b2948df0"
52
+ "gitHead": "7bd338618c80681a09cd8d4c482f1038f8676f7f"
53
53
  }