@vercel/microfrontends 0.10.0 → 0.11.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.
Files changed (79) hide show
  1. package/README.md +5 -5
  2. package/dist/bin/cli.cjs +346 -90
  3. package/dist/config/client.d.ts +1 -1
  4. package/dist/config/edge.d.ts +2 -2
  5. package/dist/config.cjs +1 -6
  6. package/dist/config.cjs.map +1 -1
  7. package/dist/config.d.ts +3 -3
  8. package/dist/config.js +1 -6
  9. package/dist/config.js.map +1 -1
  10. package/dist/{index-05742bef.d.ts → index-a99d5459.d.ts} +2 -2
  11. package/dist/{microfrontend-config-2425db74.d.ts → microfrontend-config-983a5139.d.ts} +1 -1
  12. package/dist/next/client.cjs +1 -1
  13. package/dist/next/client.cjs.map +1 -1
  14. package/dist/next/client.js +1 -1
  15. package/dist/next/client.js.map +1 -1
  16. package/dist/next/config.cjs +13 -11
  17. package/dist/next/config.cjs.map +1 -1
  18. package/dist/next/config.js +13 -11
  19. package/dist/next/config.js.map +1 -1
  20. package/dist/next/middleware.cjs +22 -8
  21. package/dist/next/middleware.cjs.map +1 -1
  22. package/dist/next/middleware.js +22 -8
  23. package/dist/next/middleware.js.map +1 -1
  24. package/dist/next/testing.cjs +1 -6
  25. package/dist/next/testing.cjs.map +1 -1
  26. package/dist/next/testing.d.ts +2 -2
  27. package/dist/next/testing.js +1 -6
  28. package/dist/next/testing.js.map +1 -1
  29. package/dist/overrides.d.ts +2 -2
  30. package/dist/{schema-83a75e61.d.ts → schema-2922d49e.d.ts} +1 -7
  31. package/dist/{types-4fd1c7c6.d.ts → types-0030abae.d.ts} +1 -8
  32. package/dist/{types-13f3e535.d.ts → types-c777c2f5.d.ts} +1 -1
  33. package/dist/v2/config.cjs +1 -1
  34. package/dist/v2/config.cjs.map +1 -1
  35. package/dist/v2/config.d.ts +3 -3
  36. package/dist/v2/config.js +1 -1
  37. package/dist/v2/config.js.map +1 -1
  38. package/dist/v2/microfrontends/server.cjs +296 -36
  39. package/dist/v2/microfrontends/server.cjs.map +1 -1
  40. package/dist/v2/microfrontends/server.d.ts +26 -4
  41. package/dist/v2/microfrontends/server.js +296 -36
  42. package/dist/v2/microfrontends/server.js.map +1 -1
  43. package/dist/v2/microfrontends.cjs +1 -1
  44. package/dist/v2/microfrontends.cjs.map +1 -1
  45. package/dist/v2/microfrontends.d.ts +3 -3
  46. package/dist/v2/microfrontends.js +1 -1
  47. package/dist/v2/microfrontends.js.map +1 -1
  48. package/dist/v2/next/client.cjs +1 -1
  49. package/dist/v2/next/client.cjs.map +1 -1
  50. package/dist/v2/next/client.js +1 -1
  51. package/dist/v2/next/client.js.map +1 -1
  52. package/dist/v2/next/config.cjs +331 -68
  53. package/dist/v2/next/config.cjs.map +1 -1
  54. package/dist/v2/next/config.js +331 -68
  55. package/dist/v2/next/config.js.map +1 -1
  56. package/dist/v2/next/endpoints.cjs +5 -2
  57. package/dist/v2/next/endpoints.cjs.map +1 -1
  58. package/dist/v2/next/endpoints.d.ts +1 -1
  59. package/dist/v2/next/endpoints.js +5 -2
  60. package/dist/v2/next/endpoints.js.map +1 -1
  61. package/dist/v2/next/middleware.cjs +108 -88
  62. package/dist/v2/next/middleware.cjs.map +1 -1
  63. package/dist/v2/next/middleware.js +108 -88
  64. package/dist/v2/next/middleware.js.map +1 -1
  65. package/dist/v2/overrides.cjs +1 -1
  66. package/dist/v2/overrides.cjs.map +1 -1
  67. package/dist/v2/overrides.d.ts +3 -3
  68. package/dist/v2/overrides.js +1 -1
  69. package/dist/v2/overrides.js.map +1 -1
  70. package/dist/v2/schema.cjs.map +1 -1
  71. package/dist/v2/schema.d.ts +1 -1
  72. package/dist/validation.cjs +0 -11
  73. package/dist/validation.cjs.map +1 -1
  74. package/dist/validation.d.ts +2 -9
  75. package/dist/validation.js +0 -11
  76. package/dist/validation.js.map +1 -1
  77. package/package.json +8 -7
  78. package/schema/schema-v2.json +0 -7
  79. package/schema/schema.json +0 -4
package/dist/bin/cli.cjs CHANGED
@@ -29,7 +29,7 @@ var import_commander = require("commander");
29
29
  // package.json
30
30
  var package_default = {
31
31
  name: "@vercel/microfrontends",
32
- version: "0.10.0",
32
+ version: "0.11.0",
33
33
  private: false,
34
34
  description: "Defines configuration and utilities for micro-frontend development",
35
35
  repository: {
@@ -161,6 +161,7 @@ var package_default = {
161
161
  ajv: "^8.17.1",
162
162
  commander: "^12.1.0",
163
163
  cookie: "0.4.0",
164
+ "fast-glob": "^3.3.2",
164
165
  "http-proxy": "^1.18.1",
165
166
  "jsonc-parser": "^3.3.1",
166
167
  "path-to-regexp": "6.2.1"
@@ -180,9 +181,9 @@ var package_default = {
180
181
  "@vercel-private/conformance": "^1.12.2-canary.0",
181
182
  jest: "^29.7.0",
182
183
  "jest-environment-jsdom": "29.2.2",
183
- next: "15.0.4-canary.26",
184
- react: "19.0.0-rc-380f5d67-20241113",
185
- "react-dom": "19.0.0-rc-380f5d67-20241113",
184
+ next: "15.0.4-canary.47",
185
+ react: "19.0.0",
186
+ "react-dom": "19.0.0",
186
187
  "ts-json-schema-generator": "^1.1.2",
187
188
  tsup: "^6.6.2",
188
189
  tsx: "^4.6.2",
@@ -190,9 +191,9 @@ var package_default = {
190
191
  webpack: "5"
191
192
  },
192
193
  peerDependencies: {
193
- next: "15.0.4-canary.26",
194
- react: "19.0.0-rc-380f5d67-20241113",
195
- "react-dom": "19.0.0-rc-380f5d67-20241113"
194
+ next: "15.0.4-canary.47",
195
+ react: "19.0.0",
196
+ "react-dom": "19.0.0"
196
197
  },
197
198
  publishConfig: {
198
199
  access: "restricted"
@@ -873,10 +874,6 @@ var schema_default = {
873
874
  flag: {
874
875
  type: "string",
875
876
  description: "flag name that can be used to enable/disable all paths in the group"
876
- },
877
- routeToDefaultApplication: {
878
- type: "boolean",
879
- description: "True to route the request to the default application for this micro-frontends set-up. This must be `true` when using `flag` or when you want to use custom logic to make the routing decision for this group of paths."
880
877
  }
881
878
  }
882
879
  },
@@ -1093,8 +1090,8 @@ function validateMainPath(applicationConfigsById) {
1093
1090
  });
1094
1091
  }
1095
1092
  for (const { id: otherId, paths } of pathsWithApp) {
1096
- const isValid = paths.every((path3) => {
1097
- const matcher = (0, import_path_to_regexp.pathToRegexp)(path3);
1093
+ const isValid = paths.every((path6) => {
1094
+ const matcher = (0, import_path_to_regexp.pathToRegexp)(path6);
1098
1095
  return !matcher.test(defaultRoute);
1099
1096
  });
1100
1097
  if (!isValid) {
@@ -1106,8 +1103,8 @@ function validateMainPath(applicationConfigsById) {
1106
1103
  }
1107
1104
  } else {
1108
1105
  const allPaths = app.routing.matches.flatMap((match) => match.paths);
1109
- const isValid = allPaths.some((path3) => {
1110
- const matcher = (0, import_path_to_regexp.pathToRegexp)(path3);
1106
+ const isValid = allPaths.some((path6) => {
1107
+ const matcher = (0, import_path_to_regexp.pathToRegexp)(path6);
1111
1108
  return matcher.test(defaultRoute);
1112
1109
  });
1113
1110
  if (!isValid) {
@@ -1127,18 +1124,18 @@ var validatePaths = (applicationConfigsById) => {
1127
1124
  continue;
1128
1125
  }
1129
1126
  for (const pathMatch of app.routing.matches) {
1130
- for (const path3 of pathMatch.paths) {
1131
- const maybeError = validatePathExpression(path3);
1127
+ for (const path6 of pathMatch.paths) {
1128
+ const maybeError = validatePathExpression(path6);
1132
1129
  if (maybeError) {
1133
1130
  errors.push(maybeError);
1134
1131
  }
1135
- const existing = pathsByApplicationId.get(path3);
1132
+ const existing = pathsByApplicationId.get(path6);
1136
1133
  if (existing) {
1137
1134
  existing.applications.push(id);
1138
1135
  } else {
1139
- pathsByApplicationId.set(path3, {
1136
+ pathsByApplicationId.set(path6, {
1140
1137
  applications: [id],
1141
- matcher: (0, import_path_to_regexp.pathToRegexp)(path3),
1138
+ matcher: (0, import_path_to_regexp.pathToRegexp)(path6),
1142
1139
  applicationId: id
1143
1140
  });
1144
1141
  }
@@ -1146,10 +1143,10 @@ var validatePaths = (applicationConfigsById) => {
1146
1143
  }
1147
1144
  }
1148
1145
  const entries = Array.from(pathsByApplicationId.entries());
1149
- entries.forEach(([path3, { applications: ids, matcher, applicationId }]) => {
1146
+ entries.forEach(([path6, { applications: ids, matcher, applicationId }]) => {
1150
1147
  if (ids.length > 1) {
1151
1148
  errors.push(
1152
- `Duplicate path "${path3}" for applications "${ids.join(", ")}"`
1149
+ `Duplicate path "${path6}" for applications "${ids.join(", ")}"`
1153
1150
  );
1154
1151
  }
1155
1152
  entries.forEach(
@@ -1157,14 +1154,14 @@ var validatePaths = (applicationConfigsById) => {
1157
1154
  matchPath,
1158
1155
  { applications: matchIds, applicationId: matchApplicationId }
1159
1156
  ]) => {
1160
- if (path3 === matchPath) {
1157
+ if (path6 === matchPath) {
1161
1158
  return;
1162
1159
  }
1163
1160
  if (applicationId === matchApplicationId) {
1164
1161
  return;
1165
1162
  }
1166
1163
  if (matcher.test(matchPath)) {
1167
- const source = `"${path3}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
1164
+ const source = `"${path6}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
1168
1165
  const destination = `"${matchPath}" of application${matchIds.length > 0 ? "s" : ""} ${matchIds.join(", ")}`;
1169
1166
  errors.push(
1170
1167
  `Overlapping path detected between ${source} and ${destination}`
@@ -1181,25 +1178,25 @@ var validatePaths = (applicationConfigsById) => {
1181
1178
  }
1182
1179
  };
1183
1180
  var PATH_DEFAULT_PATTERN = "[^\\/#\\?]+?";
1184
- function validatePathExpression(path3) {
1185
- const tokens = (0, import_path_to_regexp.parse)(path3);
1181
+ function validatePathExpression(path6) {
1182
+ const tokens = (0, import_path_to_regexp.parse)(path6);
1186
1183
  for (let i = 0; i < tokens.length; i++) {
1187
1184
  const token = tokens[i];
1188
1185
  if (token === void 0) {
1189
- return `token ${i} in ${path3} is undefined, this shouldn't happen`;
1186
+ return `token ${i} in ${path6} is undefined, this shouldn't happen`;
1190
1187
  }
1191
1188
  if (typeof token !== "string") {
1192
1189
  if (token.pattern !== PATH_DEFAULT_PATTERN) {
1193
- return `Path ${path3} cannot use a regular expression wildcard`;
1190
+ return `Path ${path6} cannot use a regular expression wildcard`;
1194
1191
  }
1195
1192
  if (token.prefix !== "/") {
1196
- return `Wildcard :${token.name} must be immediately after a / in ${path3}`;
1193
+ return `Wildcard :${token.name} must be immediately after a / in ${path6}`;
1197
1194
  }
1198
1195
  if (token.suffix) {
1199
1196
  return `Wildcard suffix on :${token.name} is not allowed. Suffixes are not supported`;
1200
1197
  }
1201
1198
  if (token.modifier && i !== tokens.length - 1) {
1202
- return `Modifier ${token.modifier} is not allowed on wildcard :${token.name} in ${path3}. Modifiers are only allowed in the last path component`;
1199
+ return `Modifier ${token.modifier} is not allowed on wildcard :${token.name} in ${path6}. Modifiers are only allowed in the last path component`;
1203
1200
  }
1204
1201
  }
1205
1202
  }
@@ -1237,11 +1234,10 @@ var validateOptions = (options) => {
1237
1234
  // src/config/utils/convert.ts
1238
1235
  function convertV1RoutingToV2Routing(routing) {
1239
1236
  return routing.matches.map((group) => {
1240
- var _a, _b;
1237
+ var _a;
1241
1238
  return {
1242
1239
  group: group.group,
1243
1240
  flag: (_a = group.options) == null ? void 0 : _a.flag,
1244
- routeToDefaultApplication: (_b = group.options) == null ? void 0 : _b.routeToDefaultApplication,
1245
1241
  paths: group.paths
1246
1242
  };
1247
1243
  });
@@ -1478,22 +1474,22 @@ var validateConfigPaths = (applicationConfigsById) => {
1478
1474
  continue;
1479
1475
  }
1480
1476
  for (const pathMatch of app.routing) {
1481
- for (const path3 of pathMatch.paths) {
1482
- const tokens = (0, import_path_to_regexp2.parse)(path3);
1477
+ for (const path6 of pathMatch.paths) {
1478
+ const tokens = (0, import_path_to_regexp2.parse)(path6);
1483
1479
  for (const token of tokens.slice(0, -1)) {
1484
1480
  if (typeof token !== "string") {
1485
1481
  errors.push(
1486
- `Path ${path3} may only have a :wildcard in the last path component`
1482
+ `Path ${path6} may only have a :wildcard in the last path component`
1487
1483
  );
1488
1484
  }
1489
1485
  }
1490
- const existing = pathsByApplicationId.get(path3);
1486
+ const existing = pathsByApplicationId.get(path6);
1491
1487
  if (existing) {
1492
1488
  existing.applications.push(id);
1493
1489
  } else {
1494
- pathsByApplicationId.set(path3, {
1490
+ pathsByApplicationId.set(path6, {
1495
1491
  applications: [id],
1496
- matcher: (0, import_path_to_regexp2.pathToRegexp)(path3),
1492
+ matcher: (0, import_path_to_regexp2.pathToRegexp)(path6),
1497
1493
  applicationId: id
1498
1494
  });
1499
1495
  }
@@ -1501,10 +1497,10 @@ var validateConfigPaths = (applicationConfigsById) => {
1501
1497
  }
1502
1498
  }
1503
1499
  const entries = Array.from(pathsByApplicationId.entries());
1504
- entries.forEach(([path3, { applications: ids, matcher, applicationId }]) => {
1500
+ entries.forEach(([path6, { applications: ids, matcher, applicationId }]) => {
1505
1501
  if (ids.length > 1) {
1506
1502
  errors.push(
1507
- `Duplicate path "${path3}" for applications "${ids.join(", ")}"`
1503
+ `Duplicate path "${path6}" for applications "${ids.join(", ")}"`
1508
1504
  );
1509
1505
  }
1510
1506
  entries.forEach(
@@ -1512,14 +1508,14 @@ var validateConfigPaths = (applicationConfigsById) => {
1512
1508
  matchPath,
1513
1509
  { applications: matchIds, applicationId: matchApplicationId }
1514
1510
  ]) => {
1515
- if (path3 === matchPath) {
1511
+ if (path6 === matchPath) {
1516
1512
  return;
1517
1513
  }
1518
1514
  if (applicationId === matchApplicationId) {
1519
1515
  return;
1520
1516
  }
1521
1517
  if (matcher.test(matchPath)) {
1522
- const source = `"${path3}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
1518
+ const source = `"${path6}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
1523
1519
  const destination = `"${matchPath}" of application${matchIds.length > 0 ? "s" : ""} ${matchIds.join(", ")}`;
1524
1520
  errors.push(
1525
1521
  `Overlapping path detected between ${source} and ${destination}`
@@ -1794,21 +1790,21 @@ var MicrofrontendConfigClient = class {
1794
1790
  isEqual(other) {
1795
1791
  return JSON.stringify(this.applications) === JSON.stringify(other.applications);
1796
1792
  }
1797
- getApplicationNameForPath(path3) {
1798
- if (!path3.startsWith("/")) {
1793
+ getApplicationNameForPath(path6) {
1794
+ if (!path6.startsWith("/")) {
1799
1795
  throw new Error(`Path must start with a /`);
1800
1796
  }
1801
- if (this.pathCache[path3]) {
1802
- return this.pathCache[path3];
1797
+ if (this.pathCache[path6]) {
1798
+ return this.pathCache[path6];
1803
1799
  }
1804
- const pathname = new URL(path3, "https://example.com").pathname;
1800
+ const pathname = new URL(path6, "https://example.com").pathname;
1805
1801
  for (const [name, application] of Object.entries(this.applications)) {
1806
1802
  if (application.routing) {
1807
1803
  for (const group of application.routing) {
1808
1804
  for (const childPath of group.paths) {
1809
1805
  const regexp = (0, import_path_to_regexp3.pathToRegexp)(childPath);
1810
1806
  if (regexp.test(pathname)) {
1811
- this.pathCache[path3] = name;
1807
+ this.pathCache[path6] = name;
1812
1808
  return name;
1813
1809
  }
1814
1810
  }
@@ -1821,7 +1817,7 @@ var MicrofrontendConfigClient = class {
1821
1817
  if (!defaultApplication) {
1822
1818
  return null;
1823
1819
  }
1824
- this.pathCache[path3] = defaultApplication[0];
1820
+ this.pathCache[path6] = defaultApplication[0];
1825
1821
  return defaultApplication[0];
1826
1822
  }
1827
1823
  serialize() {
@@ -1830,7 +1826,7 @@ var MicrofrontendConfigClient = class {
1830
1826
  };
1831
1827
 
1832
1828
  // src/config-v2/overrides/constants.ts
1833
- var OVERRIDES_COOKIE_PREFIX2 = "vercel-microfrontends-override";
1829
+ var OVERRIDES_COOKIE_PREFIX2 = "vercel-micro-frontends-override";
1834
1830
  var OVERRIDES_ENV_COOKIE_PREFIX = `${OVERRIDES_COOKIE_PREFIX2}:env:`;
1835
1831
 
1836
1832
  // src/config-v2/overrides/is-override-cookie.ts
@@ -2089,14 +2085,14 @@ var MicrofrontendMainConfig = class extends MicrofrontendConfigIsomorphic {
2089
2085
  }
2090
2086
  };
2091
2087
 
2092
- // src/config-v2/microfrontends/util/is-main-config.ts
2088
+ // src/config-v2/microfrontends/utils/is-main-config.ts
2093
2089
  function isMainConfig2(c) {
2094
2090
  return !("partOf" in c);
2095
2091
  }
2096
2092
 
2097
2093
  // src/config-v2/microfrontends/server/index.ts
2098
- var import_node_fs3 = __toESM(require("fs"), 1);
2099
- var import_node_path4 = require("path");
2094
+ var import_node_fs8 = __toESM(require("fs"), 1);
2095
+ var import_node_path9 = require("path");
2100
2096
 
2101
2097
  // src/config-v2/microfrontends-config/isomorphic/child.ts
2102
2098
  var MicrofrontendChildConfig = class extends MicrofrontendConfigIsomorphic {
@@ -2139,6 +2135,187 @@ var Microfrontends = class {
2139
2135
  }
2140
2136
  };
2141
2137
 
2138
+ // src/config-v2/microfrontends/utils/find-repository-root.ts
2139
+ var import_node_fs3 = __toESM(require("fs"), 1);
2140
+ var import_node_path4 = __toESM(require("path"), 1);
2141
+ var GIT_DIRECTORY = ".git";
2142
+ function findRepositoryRoot(startDir) {
2143
+ let currentDir = startDir || process.cwd();
2144
+ while (currentDir !== import_node_path4.default.parse(currentDir).root) {
2145
+ const gitPath = import_node_path4.default.join(currentDir, GIT_DIRECTORY);
2146
+ if (import_node_fs3.default.existsSync(gitPath) && import_node_fs3.default.statSync(gitPath).isDirectory()) {
2147
+ return currentDir;
2148
+ }
2149
+ currentDir = import_node_path4.default.dirname(currentDir);
2150
+ }
2151
+ throw new Error(
2152
+ "Repository root not found. Specify the root of the repository with the `repository.root` option."
2153
+ );
2154
+ }
2155
+
2156
+ // src/config-v2/microfrontends/utils/find-package-path.ts
2157
+ var import_node_path5 = require("path");
2158
+ var import_node_fs4 = require("fs");
2159
+ var import_fast_glob = __toESM(require("fast-glob"), 1);
2160
+ var configCache = {};
2161
+ function findPackagePathWithGlob({
2162
+ repositoryRoot,
2163
+ name
2164
+ }) {
2165
+ try {
2166
+ const packageJsonPaths = import_fast_glob.default.globSync("**/package.json", {
2167
+ cwd: repositoryRoot,
2168
+ absolute: true,
2169
+ onlyFiles: true,
2170
+ followSymbolicLinks: false,
2171
+ ignore: ["**/node_modules/**", "**/.git/**"]
2172
+ });
2173
+ const matchingPaths = [];
2174
+ for (const packageJsonPath2 of packageJsonPaths) {
2175
+ const packageJsonContent = (0, import_node_fs4.readFileSync)(packageJsonPath2, "utf-8");
2176
+ const packageJson = JSON.parse(packageJsonContent);
2177
+ if (packageJson.name === name) {
2178
+ matchingPaths.push(packageJsonPath2);
2179
+ }
2180
+ }
2181
+ if (matchingPaths.length > 1) {
2182
+ throw new Error(
2183
+ `Found multiple packages with the name "${name}" in the repository: ${matchingPaths.join(", ")}`
2184
+ );
2185
+ }
2186
+ if (matchingPaths.length === 0) {
2187
+ throw new Error(
2188
+ `Could not find package with the name "${name}" in the repository`
2189
+ );
2190
+ }
2191
+ const [packageJsonPath] = matchingPaths;
2192
+ return (0, import_node_path5.dirname)(packageJsonPath);
2193
+ } catch (error) {
2194
+ return null;
2195
+ }
2196
+ }
2197
+ function findPackagePath(opts) {
2198
+ const cacheKey = `${opts.repositoryRoot}-${opts.name}`;
2199
+ if (configCache[cacheKey]) {
2200
+ return configCache[cacheKey];
2201
+ }
2202
+ const result = findPackagePathWithGlob(opts);
2203
+ if (!result) {
2204
+ throw new Error(
2205
+ `Could not find package with the name "${opts.name}" in the repository`
2206
+ );
2207
+ }
2208
+ configCache[cacheKey] = result;
2209
+ return result;
2210
+ }
2211
+
2212
+ // src/config-v2/microfrontends/utils/find-default-package.ts
2213
+ var import_node_path6 = require("path");
2214
+ var import_node_fs5 = require("fs");
2215
+ var import_fast_glob2 = __toESM(require("fast-glob"), 1);
2216
+ var configCache2 = {};
2217
+ function findDefaultMicrofrontendsPackages({
2218
+ repositoryRoot,
2219
+ applicationName
2220
+ }) {
2221
+ try {
2222
+ const microfrontendsJsonPaths = import_fast_glob2.default.globSync("**/microfrontends.json", {
2223
+ cwd: repositoryRoot,
2224
+ absolute: true,
2225
+ onlyFiles: true,
2226
+ followSymbolicLinks: false,
2227
+ ignore: ["**/node_modules/**", "**/.git/**"]
2228
+ });
2229
+ const matchingPaths = [];
2230
+ for (const microfrontendsJsonPath of microfrontendsJsonPaths) {
2231
+ const microfrontendsJsonContent = (0, import_node_fs5.readFileSync)(
2232
+ microfrontendsJsonPath,
2233
+ "utf-8"
2234
+ );
2235
+ const microfrontendsJson = JSON.parse(
2236
+ microfrontendsJsonContent
2237
+ );
2238
+ if (isMainConfig(microfrontendsJson) && microfrontendsJson.applications[applicationName]) {
2239
+ matchingPaths.push(microfrontendsJsonPath);
2240
+ }
2241
+ }
2242
+ if (matchingPaths.length > 1) {
2243
+ throw new Error(
2244
+ `Found multiple default applications referencing "${applicationName}" in the repository, this is not yet supported.
2245
+ ${matchingPaths.join("\n \u2022 ")}`
2246
+ );
2247
+ }
2248
+ if (matchingPaths.length === 0) {
2249
+ throw new Error(
2250
+ `Could not find default application with "applications.${applicationName}"`
2251
+ );
2252
+ }
2253
+ const [packageJsonPath] = matchingPaths;
2254
+ return (0, import_node_path6.dirname)(packageJsonPath);
2255
+ } catch (error) {
2256
+ return null;
2257
+ }
2258
+ }
2259
+ function findDefaultMicrofrontendsPackage(opts) {
2260
+ const cacheKey = `${opts.repositoryRoot}-${opts.applicationName}`;
2261
+ if (configCache2[cacheKey]) {
2262
+ return configCache2[cacheKey];
2263
+ }
2264
+ const result = findDefaultMicrofrontendsPackages(opts);
2265
+ if (!result) {
2266
+ throw new Error(
2267
+ `Error trying to resolve the main microfrontends.json configuration`
2268
+ );
2269
+ }
2270
+ configCache2[cacheKey] = result;
2271
+ return result;
2272
+ }
2273
+
2274
+ // src/config-v2/microfrontends/utils/is-monorepo.ts
2275
+ var import_node_fs6 = __toESM(require("fs"), 1);
2276
+ var import_node_path7 = __toESM(require("path"), 1);
2277
+ function isMonorepo({
2278
+ repositoryRoot
2279
+ }) {
2280
+ try {
2281
+ if (import_node_fs6.default.existsSync(import_node_path7.default.join(repositoryRoot, "pnpm-workspace.yaml"))) {
2282
+ return true;
2283
+ }
2284
+ if (import_node_fs6.default.existsSync(import_node_path7.default.join(repositoryRoot, "vlt-workspaces.json"))) {
2285
+ return true;
2286
+ }
2287
+ const packageJsonPath = import_node_path7.default.join(repositoryRoot, "package.json");
2288
+ if (!import_node_fs6.default.existsSync(packageJsonPath)) {
2289
+ return false;
2290
+ }
2291
+ const packageJson = JSON.parse(
2292
+ import_node_fs6.default.readFileSync(packageJsonPath, "utf-8")
2293
+ );
2294
+ return packageJson.workspaces !== void 0;
2295
+ } catch (error) {
2296
+ console.error("Error determining if repository is a monorepo", error);
2297
+ return false;
2298
+ }
2299
+ }
2300
+
2301
+ // src/config-v2/microfrontends/utils/find-package-root.ts
2302
+ var import_node_fs7 = __toESM(require("fs"), 1);
2303
+ var import_node_path8 = __toESM(require("path"), 1);
2304
+ var PACKAGE_JSON = "package.json";
2305
+ function findPackageRoot(startDir) {
2306
+ let currentDir = startDir || process.cwd();
2307
+ while (currentDir !== import_node_path8.default.parse(currentDir).root) {
2308
+ const pkgJsonPath = import_node_path8.default.join(currentDir, PACKAGE_JSON);
2309
+ if (import_node_fs7.default.existsSync(pkgJsonPath)) {
2310
+ return currentDir;
2311
+ }
2312
+ currentDir = import_node_path8.default.dirname(currentDir);
2313
+ }
2314
+ throw new Error(
2315
+ "Package root not found. Specify the root of the package with the `package.root` option."
2316
+ );
2317
+ }
2318
+
2142
2319
  // src/config-v2/microfrontends/server/validation.ts
2143
2320
  var import_jsonc_parser3 = require("jsonc-parser");
2144
2321
  var import_ajv2 = require("ajv");
@@ -2258,9 +2435,6 @@ var schema_v2_default = {
2258
2435
  projectId: {
2259
2436
  type: "string",
2260
2437
  description: "Vercel project ID"
2261
- },
2262
- routeSpeedInsightsToDefaultZone: {
2263
- type: "boolean"
2264
2438
  }
2265
2439
  },
2266
2440
  required: ["projectId"]
@@ -2354,10 +2528,6 @@ var schema_v2_default = {
2354
2528
  type: "string",
2355
2529
  description: "flag name that can be used to enable/disable all paths in the group"
2356
2530
  },
2357
- routeToDefaultApplication: {
2358
- type: "boolean",
2359
- description: "True to route the request to the default application for this micro-frontends set-up. This must be `true` when using `flag` or when you want to use custom logic to make the routing decision for this group of paths."
2360
- },
2361
2531
  paths: {
2362
2532
  type: "array",
2363
2533
  items: {
@@ -2434,8 +2604,8 @@ var MicrofrontendsServer = class extends Microfrontends {
2434
2604
  pretty: true
2435
2605
  }) {
2436
2606
  const outputPath = getOutputFilePath();
2437
- import_node_fs3.default.mkdirSync((0, import_node_path4.dirname)(outputPath), { recursive: true });
2438
- import_node_fs3.default.writeFileSync(
2607
+ import_node_fs8.default.mkdirSync((0, import_node_path9.dirname)(outputPath), { recursive: true });
2608
+ import_node_fs8.default.writeFileSync(
2439
2609
  outputPath,
2440
2610
  JSON.stringify(
2441
2611
  this.config.toSchemaJson(),
@@ -2497,18 +2667,104 @@ var MicrofrontendsServer = class extends Microfrontends {
2497
2667
  }
2498
2668
  return config;
2499
2669
  }
2670
+ /**
2671
+ * Looks up the configuration by inferring the package root and looking for a microfrontends.json file. If a file is not found,
2672
+ * it will look for a package in the repository with a microfrontends.json file that contains the current application
2673
+ * and use that configuration.
2674
+ *
2675
+ * This can return either a Child or Main configuration.
2676
+ */
2677
+ static infer({
2678
+ directory,
2679
+ filePath,
2680
+ meta,
2681
+ cookies,
2682
+ options
2683
+ } = {}) {
2684
+ if (filePath && meta) {
2685
+ return MicrofrontendsServer.fromFile({
2686
+ filePath,
2687
+ cookies,
2688
+ meta,
2689
+ options
2690
+ });
2691
+ }
2692
+ try {
2693
+ const packageRoot = findPackageRoot(directory);
2694
+ const packageJsonPath = (0, import_node_path9.join)(packageRoot, "package.json");
2695
+ const packageJson = JSON.parse(
2696
+ import_node_fs8.default.readFileSync(packageJsonPath, "utf-8")
2697
+ );
2698
+ if (!packageJson.name) {
2699
+ throw new Error(`No name found in package.json at ${packageJsonPath}`);
2700
+ }
2701
+ const configMeta = meta ?? { fromApp: packageJson.name };
2702
+ const maybeConfig = (0, import_node_path9.join)(packageRoot, "microfrontends.json");
2703
+ if (import_node_fs8.default.existsSync(maybeConfig)) {
2704
+ return MicrofrontendsServer.fromFile({
2705
+ filePath: maybeConfig,
2706
+ cookies,
2707
+ meta: configMeta,
2708
+ options
2709
+ });
2710
+ }
2711
+ const repositoryRoot = findRepositoryRoot();
2712
+ const isMonorepo2 = isMonorepo({ repositoryRoot });
2713
+ if (isMonorepo2) {
2714
+ const defaultPackage = findDefaultMicrofrontendsPackage({
2715
+ repositoryRoot,
2716
+ applicationName: packageJson.name
2717
+ });
2718
+ return MicrofrontendsServer.fromFile({
2719
+ filePath: (0, import_node_path9.join)(defaultPackage, "microfrontends.json"),
2720
+ cookies,
2721
+ meta: configMeta,
2722
+ options
2723
+ });
2724
+ }
2725
+ throw new Error("Unable to infer");
2726
+ } catch (e) {
2727
+ throw new MicrofrontendError2(
2728
+ "Unable to infer microfrontends configuration",
2729
+ { type: "config", subtype: "inference_failed" }
2730
+ );
2731
+ }
2732
+ }
2500
2733
  /*
2501
2734
  * Generates a MicrofrontendsServer instance from a file.
2502
2735
  */
2503
2736
  static fromFile({
2504
2737
  filePath,
2505
2738
  cookies,
2506
- meta
2739
+ meta,
2740
+ options
2507
2741
  }) {
2508
2742
  try {
2509
- const config = import_node_fs3.default.readFileSync(filePath, "utf-8");
2743
+ const configJson = import_node_fs8.default.readFileSync(filePath, "utf-8");
2744
+ const config = MicrofrontendsServer.validate(configJson);
2745
+ if (!isMainConfig(config) && (options == null ? void 0 : options.resolveMainConfig)) {
2746
+ const repositoryRoot = findRepositoryRoot();
2747
+ const isMonorepo2 = isMonorepo({ repositoryRoot });
2748
+ if (isMonorepo2) {
2749
+ const packagePath = findPackagePath({
2750
+ repositoryRoot,
2751
+ name: config.partOf
2752
+ });
2753
+ if (!packagePath) {
2754
+ throw new MicrofrontendError2(
2755
+ `Could not find default application "${config.partOf}" in the repository`,
2756
+ { type: "config", subtype: "not_found" }
2757
+ );
2758
+ }
2759
+ const mainConfigPath = (0, import_node_path9.join)(packagePath, "microfrontends.json");
2760
+ return MicrofrontendsServer.fromMainConfigFile({
2761
+ filePath: mainConfigPath,
2762
+ overrides: cookies ? parseOverrides(cookies) : void 0
2763
+ });
2764
+ }
2765
+ }
2510
2766
  return new MicrofrontendsServer({
2511
- config: MicrofrontendsServer.validate(config),
2767
+ config,
2512
2768
  overrides: cookies ? parseOverrides(cookies) : void 0,
2513
2769
  meta
2514
2770
  });
@@ -2526,7 +2782,7 @@ var MicrofrontendsServer = class extends Microfrontends {
2526
2782
  overrides
2527
2783
  }) {
2528
2784
  try {
2529
- const config = import_node_fs3.default.readFileSync(filePath, "utf-8");
2785
+ const config = import_node_fs8.default.readFileSync(filePath, "utf-8");
2530
2786
  const validatedConfig = MicrofrontendsServer.validate(config);
2531
2787
  if (!isMainConfig(validatedConfig)) {
2532
2788
  throw new MicrofrontendError2(
@@ -2660,7 +2916,7 @@ var LocalProxy = class {
2660
2916
  const isJWTRedirect = url.searchParams.has("_vercel_jwt");
2661
2917
  const defaultHost = this.getDefaultHost(config);
2662
2918
  let hostname = null;
2663
- let path3 = request2.url;
2919
+ let path6 = request2.url;
2664
2920
  if (isAuthRedirect) {
2665
2921
  hostname = url.searchParams.get("_host_override");
2666
2922
  }
@@ -2670,12 +2926,12 @@ var LocalProxy = class {
2670
2926
  if (isJWTRedirect) {
2671
2927
  hostname = url.searchParams.get("_host_override");
2672
2928
  url.searchParams.delete("_host_override");
2673
- path3 = `${url.pathname}${url.search}`;
2929
+ path6 = `${url.pathname}${url.search}`;
2674
2930
  }
2675
2931
  if (!hostname) {
2676
2932
  return void 0;
2677
2933
  }
2678
- return { ...defaultHost, path: path3, hostname, protocol: "https", port: 443 };
2934
+ return { ...defaultHost, path: path6, hostname, protocol: "https", port: 443 };
2679
2935
  }
2680
2936
  getConfigWithOverrides(cookies) {
2681
2937
  if (isV2Config(this.config)) {
@@ -2706,19 +2962,19 @@ var LocalProxy = class {
2706
2962
  getTarget(request2) {
2707
2963
  const cookies = (0, import_cookie.parse)(request2.headers.cookie || "");
2708
2964
  const config = this.getConfigWithOverrides(cookies);
2709
- const path3 = request2.url;
2710
- if (!path3) {
2965
+ const path6 = request2.url;
2966
+ if (!path6) {
2711
2967
  return this.getDefaultHost(config);
2712
2968
  }
2713
2969
  const authTarget = this.getAuthTarget(request2, config);
2714
2970
  if (authTarget) {
2715
2971
  return authTarget;
2716
2972
  }
2717
- const url = new URL(`http://example.com${path3}`);
2973
+ const url = new URL(`http://example.com${path6}`);
2718
2974
  const pathname = url.pathname;
2719
2975
  if (isV2Config(config)) {
2720
2976
  const target = this.findMatchingApplicationV2(
2721
- path3,
2977
+ path6,
2722
2978
  pathname,
2723
2979
  config.getChildApplications()
2724
2980
  );
@@ -2726,7 +2982,7 @@ var LocalProxy = class {
2726
2982
  return target;
2727
2983
  } else {
2728
2984
  const target = this.findMatchingApplicationV1(
2729
- path3,
2985
+ path6,
2730
2986
  pathname,
2731
2987
  config.getAllApplications()
2732
2988
  );
@@ -2735,11 +2991,11 @@ var LocalProxy = class {
2735
2991
  }
2736
2992
  const defaultHost = this.getDefaultHost(config);
2737
2993
  mfeDebug(
2738
- `no matching routes, routing ${path3} to default application: ${JSON.stringify(defaultHost)}`
2994
+ `no matching routes, routing ${path6} to default application: ${JSON.stringify(defaultHost)}`
2739
2995
  );
2740
- return { path: path3, ...defaultHost };
2996
+ return { path: path6, ...defaultHost };
2741
2997
  }
2742
- findMatchingApplicationV1(path3, pathname, applications) {
2998
+ findMatchingApplicationV1(path6, pathname, applications) {
2743
2999
  for (const application of Object.values(applications)) {
2744
3000
  if (application.routing) {
2745
3001
  for (const group of application.routing.matches) {
@@ -2748,9 +3004,9 @@ var LocalProxy = class {
2748
3004
  if (regexp.test(pathname)) {
2749
3005
  const target = this.getApplicationTarget(application);
2750
3006
  mfeDebug(
2751
- `routing ${path3} to '${target.application}' at ${target.hostname}`
3007
+ `routing ${path6} to '${target.application}' at ${target.hostname}`
2752
3008
  );
2753
- return { path: path3, ...target };
3009
+ return { path: path6, ...target };
2754
3010
  }
2755
3011
  }
2756
3012
  if (application.routing.assetPrefix) {
@@ -2760,9 +3016,9 @@ var LocalProxy = class {
2760
3016
  if (pattern.test(pathname)) {
2761
3017
  const target = this.getApplicationTarget(application);
2762
3018
  mfeDebug(
2763
- `routing ${path3} to '${target.application}' at ${target.hostname}`
3019
+ `routing ${path6} to '${target.application}' at ${target.hostname}`
2764
3020
  );
2765
- return { path: path3, ...target };
3021
+ return { path: path6, ...target };
2766
3022
  }
2767
3023
  }
2768
3024
  }
@@ -2770,7 +3026,7 @@ var LocalProxy = class {
2770
3026
  }
2771
3027
  return null;
2772
3028
  }
2773
- findMatchingApplicationV2(path3, pathname, applications) {
3029
+ findMatchingApplicationV2(path6, pathname, applications) {
2774
3030
  for (const application of Object.values(applications)) {
2775
3031
  for (const group of application.routing) {
2776
3032
  for (const childPath of group.paths) {
@@ -2778,9 +3034,9 @@ var LocalProxy = class {
2778
3034
  if (regexp.test(pathname)) {
2779
3035
  const target = this.getApplicationTarget(application);
2780
3036
  mfeDebug(
2781
- `routing ${path3} to '${target.application}' at ${target.hostname}`
3037
+ `routing ${path6} to '${target.application}' at ${target.hostname}`
2782
3038
  );
2783
- return { path: path3, ...target };
3039
+ return { path: path6, ...target };
2784
3040
  }
2785
3041
  }
2786
3042
  }
@@ -2789,11 +3045,11 @@ var LocalProxy = class {
2789
3045
  }
2790
3046
  // Handles requests that return data from the local proxy itself.
2791
3047
  // Returns true if the request was handled, false otherwise.
2792
- handleProxyInfoRequest(path3, res) {
2793
- if (!path3) {
3048
+ handleProxyInfoRequest(path6, res) {
3049
+ if (!path6) {
2794
3050
  return false;
2795
3051
  }
2796
- const url = new URL(`http://example.comf${path3}`);
3052
+ const url = new URL(`http://example.comf${path6}`);
2797
3053
  const pathname = url.pathname;
2798
3054
  switch (pathname) {
2799
3055
  case "/.well-known/vercel/microfrontend-routing": {
@@ -2821,10 +3077,10 @@ var LocalProxy = class {
2821
3077
  }
2822
3078
  const target = this.getTarget(req);
2823
3079
  if (target.protocol === "https") {
2824
- const { hostname, port, path: path3 } = target;
3080
+ const { hostname, port, path: path6 } = target;
2825
3081
  const requestOptions = {
2826
3082
  hostname,
2827
- path: path3,
3083
+ path: path6,
2828
3084
  method: req.method,
2829
3085
  headers: {
2830
3086
  ...req.headers,
@@ -2852,7 +3108,7 @@ var LocalProxy = class {
2852
3108
  console.error("Proxy request error: ", err);
2853
3109
  res.writeHead(500, { "Content-Type": "text/plain" });
2854
3110
  res.end(
2855
- `Error proxying request for ${target.application} to ${hostname}:${port}${path3}`
3111
+ `Error proxying request for ${target.application} to ${hostname}:${port}${path6}`
2856
3112
  );
2857
3113
  });
2858
3114
  } else {