@vercel/microfrontends 0.10.1 → 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 (53) hide show
  1. package/dist/bin/cli.cjs +261 -91
  2. package/dist/{index-acb44057.d.ts → index-a99d5459.d.ts} +2 -2
  3. package/dist/next/config.cjs +10 -1
  4. package/dist/next/config.cjs.map +1 -1
  5. package/dist/next/config.js +10 -1
  6. package/dist/next/config.js.map +1 -1
  7. package/dist/next/middleware.cjs +17 -1
  8. package/dist/next/middleware.cjs.map +1 -1
  9. package/dist/next/middleware.js +17 -1
  10. package/dist/next/middleware.js.map +1 -1
  11. package/dist/{types-7b1cd9f7.d.ts → types-0030abae.d.ts} +0 -1
  12. package/dist/{types-c3d15d04.d.ts → types-c777c2f5.d.ts} +1 -1
  13. package/dist/v2/config.cjs +1 -1
  14. package/dist/v2/config.cjs.map +1 -1
  15. package/dist/v2/config.d.ts +3 -3
  16. package/dist/v2/config.js +1 -1
  17. package/dist/v2/config.js.map +1 -1
  18. package/dist/v2/microfrontends/server.cjs +214 -44
  19. package/dist/v2/microfrontends/server.cjs.map +1 -1
  20. package/dist/v2/microfrontends/server.d.ts +22 -3
  21. package/dist/v2/microfrontends/server.js +214 -44
  22. package/dist/v2/microfrontends/server.js.map +1 -1
  23. package/dist/v2/microfrontends.cjs +1 -1
  24. package/dist/v2/microfrontends.cjs.map +1 -1
  25. package/dist/v2/microfrontends.d.ts +3 -3
  26. package/dist/v2/microfrontends.js +1 -1
  27. package/dist/v2/microfrontends.js.map +1 -1
  28. package/dist/v2/next/config.cjs +248 -73
  29. package/dist/v2/next/config.cjs.map +1 -1
  30. package/dist/v2/next/config.js +248 -73
  31. package/dist/v2/next/config.js.map +1 -1
  32. package/dist/v2/next/endpoints.cjs +5 -2
  33. package/dist/v2/next/endpoints.cjs.map +1 -1
  34. package/dist/v2/next/endpoints.d.ts +1 -1
  35. package/dist/v2/next/endpoints.js +5 -2
  36. package/dist/v2/next/endpoints.js.map +1 -1
  37. package/dist/v2/next/middleware.cjs +107 -87
  38. package/dist/v2/next/middleware.cjs.map +1 -1
  39. package/dist/v2/next/middleware.js +107 -87
  40. package/dist/v2/next/middleware.js.map +1 -1
  41. package/dist/v2/overrides.cjs +1 -1
  42. package/dist/v2/overrides.cjs.map +1 -1
  43. package/dist/v2/overrides.d.ts +3 -3
  44. package/dist/v2/overrides.js +1 -1
  45. package/dist/v2/overrides.js.map +1 -1
  46. package/dist/v2/schema.d.ts +1 -1
  47. package/dist/validation.cjs +0 -3
  48. package/dist/validation.cjs.map +1 -1
  49. package/dist/validation.d.ts +0 -1
  50. package/dist/validation.js +0 -3
  51. package/dist/validation.js.map +1 -1
  52. package/package.json +7 -7
  53. package/schema/schema-v2.json +0 -3
@@ -33,11 +33,11 @@ __export(server_exports, {
33
33
  MicrofrontendsServer: () => MicrofrontendsServer
34
34
  });
35
35
  module.exports = __toCommonJS(server_exports);
36
- var import_node_fs3 = __toESM(require("fs"), 1);
37
- var import_node_path4 = require("path");
36
+ var import_node_fs6 = __toESM(require("fs"), 1);
37
+ var import_node_path7 = require("path");
38
38
 
39
39
  // src/config-v2/overrides/constants.ts
40
- var OVERRIDES_COOKIE_PREFIX = "vercel-microfrontends-override";
40
+ var OVERRIDES_COOKIE_PREFIX = "vercel-micro-frontends-override";
41
41
  var OVERRIDES_ENV_COOKIE_PREFIX = `${OVERRIDES_COOKIE_PREFIX}:env:`;
42
42
 
43
43
  // src/config-v2/overrides/is-override-cookie.ts
@@ -218,21 +218,21 @@ var MicrofrontendConfigClient = class {
218
218
  isEqual(other) {
219
219
  return JSON.stringify(this.applications) === JSON.stringify(other.applications);
220
220
  }
221
- getApplicationNameForPath(path3) {
222
- if (!path3.startsWith("/")) {
221
+ getApplicationNameForPath(path5) {
222
+ if (!path5.startsWith("/")) {
223
223
  throw new Error(`Path must start with a /`);
224
224
  }
225
- if (this.pathCache[path3]) {
226
- return this.pathCache[path3];
225
+ if (this.pathCache[path5]) {
226
+ return this.pathCache[path5];
227
227
  }
228
- const pathname = new URL(path3, "https://example.com").pathname;
228
+ const pathname = new URL(path5, "https://example.com").pathname;
229
229
  for (const [name, application] of Object.entries(this.applications)) {
230
230
  if (application.routing) {
231
231
  for (const group of application.routing) {
232
232
  for (const childPath of group.paths) {
233
233
  const regexp = (0, import_path_to_regexp.pathToRegexp)(childPath);
234
234
  if (regexp.test(pathname)) {
235
- this.pathCache[path3] = name;
235
+ this.pathCache[path5] = name;
236
236
  return name;
237
237
  }
238
238
  }
@@ -245,7 +245,7 @@ var MicrofrontendConfigClient = class {
245
245
  if (!defaultApplication) {
246
246
  return null;
247
247
  }
248
- this.pathCache[path3] = defaultApplication[0];
248
+ this.pathCache[path5] = defaultApplication[0];
249
249
  return defaultApplication[0];
250
250
  }
251
251
  serialize() {
@@ -277,22 +277,22 @@ var validateConfigPaths = (applicationConfigsById) => {
277
277
  continue;
278
278
  }
279
279
  for (const pathMatch of app.routing) {
280
- for (const path3 of pathMatch.paths) {
281
- const tokens = (0, import_path_to_regexp2.parse)(path3);
280
+ for (const path5 of pathMatch.paths) {
281
+ const tokens = (0, import_path_to_regexp2.parse)(path5);
282
282
  for (const token of tokens.slice(0, -1)) {
283
283
  if (typeof token !== "string") {
284
284
  errors.push(
285
- `Path ${path3} may only have a :wildcard in the last path component`
285
+ `Path ${path5} may only have a :wildcard in the last path component`
286
286
  );
287
287
  }
288
288
  }
289
- const existing = pathsByApplicationId.get(path3);
289
+ const existing = pathsByApplicationId.get(path5);
290
290
  if (existing) {
291
291
  existing.applications.push(id);
292
292
  } else {
293
- pathsByApplicationId.set(path3, {
293
+ pathsByApplicationId.set(path5, {
294
294
  applications: [id],
295
- matcher: (0, import_path_to_regexp2.pathToRegexp)(path3),
295
+ matcher: (0, import_path_to_regexp2.pathToRegexp)(path5),
296
296
  applicationId: id
297
297
  });
298
298
  }
@@ -300,10 +300,10 @@ var validateConfigPaths = (applicationConfigsById) => {
300
300
  }
301
301
  }
302
302
  const entries = Array.from(pathsByApplicationId.entries());
303
- entries.forEach(([path3, { applications: ids, matcher, applicationId }]) => {
303
+ entries.forEach(([path5, { applications: ids, matcher, applicationId }]) => {
304
304
  if (ids.length > 1) {
305
305
  errors.push(
306
- `Duplicate path "${path3}" for applications "${ids.join(", ")}"`
306
+ `Duplicate path "${path5}" for applications "${ids.join(", ")}"`
307
307
  );
308
308
  }
309
309
  entries.forEach(
@@ -311,14 +311,14 @@ var validateConfigPaths = (applicationConfigsById) => {
311
311
  matchPath,
312
312
  { applications: matchIds, applicationId: matchApplicationId }
313
313
  ]) => {
314
- if (path3 === matchPath) {
314
+ if (path5 === matchPath) {
315
315
  return;
316
316
  }
317
317
  if (applicationId === matchApplicationId) {
318
318
  return;
319
319
  }
320
320
  if (matcher.test(matchPath)) {
321
- const source = `"${path3}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
321
+ const source = `"${path5}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
322
322
  const destination = `"${matchPath}" of application${matchIds.length > 0 ? "s" : ""} ${matchIds.join(", ")}`;
323
323
  errors.push(
324
324
  `Overlapping path detected between ${source} and ${destination}`
@@ -883,8 +883,115 @@ function findPackagePath(opts) {
883
883
  return result;
884
884
  }
885
885
 
886
+ // src/config-v2/microfrontends/utils/find-default-package.ts
887
+ var import_node_path3 = require("path");
888
+ var import_node_fs3 = require("fs");
889
+ var import_fast_glob2 = __toESM(require("fast-glob"), 1);
890
+ var configCache2 = {};
891
+ function findDefaultMicrofrontendsPackages({
892
+ repositoryRoot,
893
+ applicationName
894
+ }) {
895
+ try {
896
+ const microfrontendsJsonPaths = import_fast_glob2.default.globSync("**/microfrontends.json", {
897
+ cwd: repositoryRoot,
898
+ absolute: true,
899
+ onlyFiles: true,
900
+ followSymbolicLinks: false,
901
+ ignore: ["**/node_modules/**", "**/.git/**"]
902
+ });
903
+ const matchingPaths = [];
904
+ for (const microfrontendsJsonPath of microfrontendsJsonPaths) {
905
+ const microfrontendsJsonContent = (0, import_node_fs3.readFileSync)(
906
+ microfrontendsJsonPath,
907
+ "utf-8"
908
+ );
909
+ const microfrontendsJson = JSON.parse(
910
+ microfrontendsJsonContent
911
+ );
912
+ if (isMainConfig(microfrontendsJson) && microfrontendsJson.applications[applicationName]) {
913
+ matchingPaths.push(microfrontendsJsonPath);
914
+ }
915
+ }
916
+ if (matchingPaths.length > 1) {
917
+ throw new Error(
918
+ `Found multiple default applications referencing "${applicationName}" in the repository, this is not yet supported.
919
+ ${matchingPaths.join("\n \u2022 ")}`
920
+ );
921
+ }
922
+ if (matchingPaths.length === 0) {
923
+ throw new Error(
924
+ `Could not find default application with "applications.${applicationName}"`
925
+ );
926
+ }
927
+ const [packageJsonPath] = matchingPaths;
928
+ return (0, import_node_path3.dirname)(packageJsonPath);
929
+ } catch (error) {
930
+ return null;
931
+ }
932
+ }
933
+ function findDefaultMicrofrontendsPackage(opts) {
934
+ const cacheKey = `${opts.repositoryRoot}-${opts.applicationName}`;
935
+ if (configCache2[cacheKey]) {
936
+ return configCache2[cacheKey];
937
+ }
938
+ const result = findDefaultMicrofrontendsPackages(opts);
939
+ if (!result) {
940
+ throw new Error(
941
+ `Error trying to resolve the main microfrontends.json configuration`
942
+ );
943
+ }
944
+ configCache2[cacheKey] = result;
945
+ return result;
946
+ }
947
+
948
+ // src/config-v2/microfrontends/utils/is-monorepo.ts
949
+ var import_node_fs4 = __toESM(require("fs"), 1);
950
+ var import_node_path4 = __toESM(require("path"), 1);
951
+ function isMonorepo({
952
+ repositoryRoot
953
+ }) {
954
+ try {
955
+ if (import_node_fs4.default.existsSync(import_node_path4.default.join(repositoryRoot, "pnpm-workspace.yaml"))) {
956
+ return true;
957
+ }
958
+ if (import_node_fs4.default.existsSync(import_node_path4.default.join(repositoryRoot, "vlt-workspaces.json"))) {
959
+ return true;
960
+ }
961
+ const packageJsonPath = import_node_path4.default.join(repositoryRoot, "package.json");
962
+ if (!import_node_fs4.default.existsSync(packageJsonPath)) {
963
+ return false;
964
+ }
965
+ const packageJson = JSON.parse(
966
+ import_node_fs4.default.readFileSync(packageJsonPath, "utf-8")
967
+ );
968
+ return packageJson.workspaces !== void 0;
969
+ } catch (error) {
970
+ console.error("Error determining if repository is a monorepo", error);
971
+ return false;
972
+ }
973
+ }
974
+
975
+ // src/config-v2/microfrontends/utils/find-package-root.ts
976
+ var import_node_fs5 = __toESM(require("fs"), 1);
977
+ var import_node_path5 = __toESM(require("path"), 1);
978
+ var PACKAGE_JSON = "package.json";
979
+ function findPackageRoot(startDir) {
980
+ let currentDir = startDir || process.cwd();
981
+ while (currentDir !== import_node_path5.default.parse(currentDir).root) {
982
+ const pkgJsonPath = import_node_path5.default.join(currentDir, PACKAGE_JSON);
983
+ if (import_node_fs5.default.existsSync(pkgJsonPath)) {
984
+ return currentDir;
985
+ }
986
+ currentDir = import_node_path5.default.dirname(currentDir);
987
+ }
988
+ throw new Error(
989
+ "Package root not found. Specify the root of the package with the `package.root` option."
990
+ );
991
+ }
992
+
886
993
  // src/config-v2/microfrontends/server/utils/get-output-file-path.ts
887
- var import_node_path3 = __toESM(require("path"), 1);
994
+ var import_node_path6 = __toESM(require("path"), 1);
888
995
 
889
996
  // src/config-v2/microfrontends/server/constants.ts
890
997
  var MFE_CONFIG_DEFAULT_FILE_PATH = "microfrontends";
@@ -898,13 +1005,13 @@ function isVercel() {
898
1005
  // src/config-v2/microfrontends/server/utils/get-output-file-path.ts
899
1006
  function getOutputFilePath() {
900
1007
  if (isVercel()) {
901
- return import_node_path3.default.join(
1008
+ return import_node_path6.default.join(
902
1009
  ".vercel",
903
1010
  MFE_CONFIG_DEFAULT_FILE_PATH,
904
1011
  MFE_CONFIG_DEFAULT_FILE_NAME
905
1012
  );
906
1013
  }
907
- return import_node_path3.default.join(MFE_CONFIG_DEFAULT_FILE_PATH, MFE_CONFIG_DEFAULT_FILE_NAME);
1014
+ return import_node_path6.default.join(MFE_CONFIG_DEFAULT_FILE_PATH, MFE_CONFIG_DEFAULT_FILE_NAME);
908
1015
  }
909
1016
 
910
1017
  // src/config-v2/microfrontends/server/validation.ts
@@ -1118,9 +1225,6 @@ var schema_v2_default = {
1118
1225
  projectId: {
1119
1226
  type: "string",
1120
1227
  description: "Vercel project ID"
1121
- },
1122
- routeSpeedInsightsToDefaultZone: {
1123
- type: "boolean"
1124
1228
  }
1125
1229
  },
1126
1230
  required: ["projectId"]
@@ -1290,8 +1394,8 @@ var MicrofrontendsServer = class extends Microfrontends {
1290
1394
  pretty: true
1291
1395
  }) {
1292
1396
  const outputPath = getOutputFilePath();
1293
- import_node_fs3.default.mkdirSync((0, import_node_path4.dirname)(outputPath), { recursive: true });
1294
- import_node_fs3.default.writeFileSync(
1397
+ import_node_fs6.default.mkdirSync((0, import_node_path7.dirname)(outputPath), { recursive: true });
1398
+ import_node_fs6.default.writeFileSync(
1295
1399
  outputPath,
1296
1400
  JSON.stringify(
1297
1401
  this.config.toSchemaJson(),
@@ -1353,6 +1457,69 @@ var MicrofrontendsServer = class extends Microfrontends {
1353
1457
  }
1354
1458
  return config;
1355
1459
  }
1460
+ /**
1461
+ * Looks up the configuration by inferring the package root and looking for a microfrontends.json file. If a file is not found,
1462
+ * it will look for a package in the repository with a microfrontends.json file that contains the current application
1463
+ * and use that configuration.
1464
+ *
1465
+ * This can return either a Child or Main configuration.
1466
+ */
1467
+ static infer({
1468
+ directory,
1469
+ filePath,
1470
+ meta,
1471
+ cookies,
1472
+ options
1473
+ } = {}) {
1474
+ if (filePath && meta) {
1475
+ return MicrofrontendsServer.fromFile({
1476
+ filePath,
1477
+ cookies,
1478
+ meta,
1479
+ options
1480
+ });
1481
+ }
1482
+ try {
1483
+ const packageRoot = findPackageRoot(directory);
1484
+ const packageJsonPath = (0, import_node_path7.join)(packageRoot, "package.json");
1485
+ const packageJson = JSON.parse(
1486
+ import_node_fs6.default.readFileSync(packageJsonPath, "utf-8")
1487
+ );
1488
+ if (!packageJson.name) {
1489
+ throw new Error(`No name found in package.json at ${packageJsonPath}`);
1490
+ }
1491
+ const configMeta = meta ?? { fromApp: packageJson.name };
1492
+ const maybeConfig = (0, import_node_path7.join)(packageRoot, "microfrontends.json");
1493
+ if (import_node_fs6.default.existsSync(maybeConfig)) {
1494
+ return MicrofrontendsServer.fromFile({
1495
+ filePath: maybeConfig,
1496
+ cookies,
1497
+ meta: configMeta,
1498
+ options
1499
+ });
1500
+ }
1501
+ const repositoryRoot = findRepositoryRoot();
1502
+ const isMonorepo2 = isMonorepo({ repositoryRoot });
1503
+ if (isMonorepo2) {
1504
+ const defaultPackage = findDefaultMicrofrontendsPackage({
1505
+ repositoryRoot,
1506
+ applicationName: packageJson.name
1507
+ });
1508
+ return MicrofrontendsServer.fromFile({
1509
+ filePath: (0, import_node_path7.join)(defaultPackage, "microfrontends.json"),
1510
+ cookies,
1511
+ meta: configMeta,
1512
+ options
1513
+ });
1514
+ }
1515
+ throw new Error("Unable to infer");
1516
+ } catch (e) {
1517
+ throw new MicrofrontendError(
1518
+ "Unable to infer microfrontends configuration",
1519
+ { type: "config", subtype: "inference_failed" }
1520
+ );
1521
+ }
1522
+ }
1356
1523
  /*
1357
1524
  * Generates a MicrofrontendsServer instance from a file.
1358
1525
  */
@@ -1363,25 +1530,28 @@ var MicrofrontendsServer = class extends Microfrontends {
1363
1530
  options
1364
1531
  }) {
1365
1532
  try {
1366
- const configJson = import_node_fs3.default.readFileSync(filePath, "utf-8");
1533
+ const configJson = import_node_fs6.default.readFileSync(filePath, "utf-8");
1367
1534
  const config = MicrofrontendsServer.validate(configJson);
1368
1535
  if (!isMainConfig(config) && (options == null ? void 0 : options.resolveMainConfig)) {
1369
1536
  const repositoryRoot = findRepositoryRoot();
1370
- const packagePath = findPackagePath({
1371
- repositoryRoot,
1372
- name: config.partOf
1373
- });
1374
- if (!packagePath) {
1375
- throw new MicrofrontendError(
1376
- `Could not find default application "${config.partOf}" in the repository`,
1377
- { type: "config", subtype: "not_found" }
1378
- );
1537
+ const isMonorepo2 = isMonorepo({ repositoryRoot });
1538
+ if (isMonorepo2) {
1539
+ const packagePath = findPackagePath({
1540
+ repositoryRoot,
1541
+ name: config.partOf
1542
+ });
1543
+ if (!packagePath) {
1544
+ throw new MicrofrontendError(
1545
+ `Could not find default application "${config.partOf}" in the repository`,
1546
+ { type: "config", subtype: "not_found" }
1547
+ );
1548
+ }
1549
+ const mainConfigPath = (0, import_node_path7.join)(packagePath, "microfrontends.json");
1550
+ return MicrofrontendsServer.fromMainConfigFile({
1551
+ filePath: mainConfigPath,
1552
+ overrides: cookies ? parseOverrides(cookies) : void 0
1553
+ });
1379
1554
  }
1380
- const mainConfigPath = (0, import_node_path4.join)(packagePath, "microfrontends.json");
1381
- return MicrofrontendsServer.fromMainConfigFile({
1382
- filePath: mainConfigPath,
1383
- overrides: cookies ? parseOverrides(cookies) : void 0
1384
- });
1385
1555
  }
1386
1556
  return new MicrofrontendsServer({
1387
1557
  config,
@@ -1402,7 +1572,7 @@ var MicrofrontendsServer = class extends Microfrontends {
1402
1572
  overrides
1403
1573
  }) {
1404
1574
  try {
1405
- const config = import_node_fs3.default.readFileSync(filePath, "utf-8");
1575
+ const config = import_node_fs6.default.readFileSync(filePath, "utf-8");
1406
1576
  const validatedConfig = MicrofrontendsServer.validate(config);
1407
1577
  if (!isMainConfig(validatedConfig)) {
1408
1578
  throw new MicrofrontendError(