@vercel/microfrontends 0.10.1 → 0.12.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 (61) hide show
  1. package/dist/bin/cli.cjs +263 -102
  2. package/dist/config.cjs +0 -2
  3. package/dist/config.cjs.map +1 -1
  4. package/dist/config.js +0 -2
  5. package/dist/config.js.map +1 -1
  6. package/dist/{index-acb44057.d.ts → index-35038aec.d.ts} +2 -2
  7. package/dist/next/config.cjs +10 -3
  8. package/dist/next/config.cjs.map +1 -1
  9. package/dist/next/config.js +10 -3
  10. package/dist/next/config.js.map +1 -1
  11. package/dist/next/middleware.cjs +17 -1
  12. package/dist/next/middleware.cjs.map +1 -1
  13. package/dist/next/middleware.js +17 -1
  14. package/dist/next/middleware.js.map +1 -1
  15. package/dist/next/testing.cjs +0 -2
  16. package/dist/next/testing.cjs.map +1 -1
  17. package/dist/next/testing.js +0 -2
  18. package/dist/next/testing.js.map +1 -1
  19. package/dist/{types-c3d15d04.d.ts → types-15b7f215.d.ts} +1 -1
  20. package/dist/{types-7b1cd9f7.d.ts → types-a995174e.d.ts} +1 -4
  21. package/dist/v2/config.cjs +1 -1
  22. package/dist/v2/config.cjs.map +1 -1
  23. package/dist/v2/config.d.ts +3 -3
  24. package/dist/v2/config.js +1 -1
  25. package/dist/v2/config.js.map +1 -1
  26. package/dist/v2/microfrontends/server.cjs +215 -53
  27. package/dist/v2/microfrontends/server.cjs.map +1 -1
  28. package/dist/v2/microfrontends/server.d.ts +22 -3
  29. package/dist/v2/microfrontends/server.js +215 -53
  30. package/dist/v2/microfrontends/server.js.map +1 -1
  31. package/dist/v2/microfrontends.cjs +1 -2
  32. package/dist/v2/microfrontends.cjs.map +1 -1
  33. package/dist/v2/microfrontends.d.ts +3 -4
  34. package/dist/v2/microfrontends.js +1 -2
  35. package/dist/v2/microfrontends.js.map +1 -1
  36. package/dist/v2/next/config.cjs +249 -82
  37. package/dist/v2/next/config.cjs.map +1 -1
  38. package/dist/v2/next/config.js +249 -82
  39. package/dist/v2/next/config.js.map +1 -1
  40. package/dist/v2/next/endpoints.cjs +5 -2
  41. package/dist/v2/next/endpoints.cjs.map +1 -1
  42. package/dist/v2/next/endpoints.d.ts +1 -1
  43. package/dist/v2/next/endpoints.js +5 -2
  44. package/dist/v2/next/endpoints.js.map +1 -1
  45. package/dist/v2/next/middleware.cjs +107 -88
  46. package/dist/v2/next/middleware.cjs.map +1 -1
  47. package/dist/v2/next/middleware.js +107 -88
  48. package/dist/v2/next/middleware.js.map +1 -1
  49. package/dist/v2/overrides.cjs +1 -1
  50. package/dist/v2/overrides.cjs.map +1 -1
  51. package/dist/v2/overrides.d.ts +3 -3
  52. package/dist/v2/overrides.js +1 -1
  53. package/dist/v2/overrides.js.map +1 -1
  54. package/dist/v2/schema.d.ts +1 -1
  55. package/dist/validation.cjs +1 -11
  56. package/dist/validation.cjs.map +1 -1
  57. package/dist/validation.d.ts +0 -3
  58. package/dist/validation.js +1 -11
  59. package/dist/validation.js.map +1 -1
  60. package/package.json +8 -7
  61. package/schema/schema-v2.json +0 -14
@@ -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}`
@@ -751,7 +751,6 @@ var MicrofrontendMainConfig = class extends MicrofrontendConfigIsomorphic {
751
751
  var _a, _b, _c;
752
752
  super({ config, overrides, meta });
753
753
  this.isMainConfig = true;
754
- this.provider = config.provider;
755
754
  const disableOverrides = ((_b = (_a = config.options) == null ? void 0 : _a.vercel) == null ? void 0 : _b.disableOverrides) ?? false;
756
755
  let defaultApplication;
757
756
  for (const [appId, appConfig] of Object.entries(config.applications)) {
@@ -883,8 +882,115 @@ function findPackagePath(opts) {
883
882
  return result;
884
883
  }
885
884
 
885
+ // src/config-v2/microfrontends/utils/find-default-package.ts
886
+ var import_node_path3 = require("path");
887
+ var import_node_fs3 = require("fs");
888
+ var import_fast_glob2 = __toESM(require("fast-glob"), 1);
889
+ var configCache2 = {};
890
+ function findDefaultMicrofrontendsPackages({
891
+ repositoryRoot,
892
+ applicationName
893
+ }) {
894
+ try {
895
+ const microfrontendsJsonPaths = import_fast_glob2.default.globSync("**/microfrontends.json", {
896
+ cwd: repositoryRoot,
897
+ absolute: true,
898
+ onlyFiles: true,
899
+ followSymbolicLinks: false,
900
+ ignore: ["**/node_modules/**", "**/.git/**"]
901
+ });
902
+ const matchingPaths = [];
903
+ for (const microfrontendsJsonPath of microfrontendsJsonPaths) {
904
+ const microfrontendsJsonContent = (0, import_node_fs3.readFileSync)(
905
+ microfrontendsJsonPath,
906
+ "utf-8"
907
+ );
908
+ const microfrontendsJson = JSON.parse(
909
+ microfrontendsJsonContent
910
+ );
911
+ if (isMainConfig(microfrontendsJson) && microfrontendsJson.applications[applicationName]) {
912
+ matchingPaths.push(microfrontendsJsonPath);
913
+ }
914
+ }
915
+ if (matchingPaths.length > 1) {
916
+ throw new Error(
917
+ `Found multiple default applications referencing "${applicationName}" in the repository, this is not yet supported.
918
+ ${matchingPaths.join("\n \u2022 ")}`
919
+ );
920
+ }
921
+ if (matchingPaths.length === 0) {
922
+ throw new Error(
923
+ `Could not find default application with "applications.${applicationName}"`
924
+ );
925
+ }
926
+ const [packageJsonPath] = matchingPaths;
927
+ return (0, import_node_path3.dirname)(packageJsonPath);
928
+ } catch (error) {
929
+ return null;
930
+ }
931
+ }
932
+ function findDefaultMicrofrontendsPackage(opts) {
933
+ const cacheKey = `${opts.repositoryRoot}-${opts.applicationName}`;
934
+ if (configCache2[cacheKey]) {
935
+ return configCache2[cacheKey];
936
+ }
937
+ const result = findDefaultMicrofrontendsPackages(opts);
938
+ if (!result) {
939
+ throw new Error(
940
+ `Error trying to resolve the main microfrontends.json configuration`
941
+ );
942
+ }
943
+ configCache2[cacheKey] = result;
944
+ return result;
945
+ }
946
+
947
+ // src/config-v2/microfrontends/utils/is-monorepo.ts
948
+ var import_node_fs4 = __toESM(require("fs"), 1);
949
+ var import_node_path4 = __toESM(require("path"), 1);
950
+ function isMonorepo({
951
+ repositoryRoot
952
+ }) {
953
+ try {
954
+ if (import_node_fs4.default.existsSync(import_node_path4.default.join(repositoryRoot, "pnpm-workspace.yaml"))) {
955
+ return true;
956
+ }
957
+ if (import_node_fs4.default.existsSync(import_node_path4.default.join(repositoryRoot, "vlt-workspaces.json"))) {
958
+ return true;
959
+ }
960
+ const packageJsonPath = import_node_path4.default.join(repositoryRoot, "package.json");
961
+ if (!import_node_fs4.default.existsSync(packageJsonPath)) {
962
+ return false;
963
+ }
964
+ const packageJson = JSON.parse(
965
+ import_node_fs4.default.readFileSync(packageJsonPath, "utf-8")
966
+ );
967
+ return packageJson.workspaces !== void 0;
968
+ } catch (error) {
969
+ console.error("Error determining if repository is a monorepo", error);
970
+ return false;
971
+ }
972
+ }
973
+
974
+ // src/config-v2/microfrontends/utils/find-package-root.ts
975
+ var import_node_fs5 = __toESM(require("fs"), 1);
976
+ var import_node_path5 = __toESM(require("path"), 1);
977
+ var PACKAGE_JSON = "package.json";
978
+ function findPackageRoot(startDir) {
979
+ let currentDir = startDir || process.cwd();
980
+ while (currentDir !== import_node_path5.default.parse(currentDir).root) {
981
+ const pkgJsonPath = import_node_path5.default.join(currentDir, PACKAGE_JSON);
982
+ if (import_node_fs5.default.existsSync(pkgJsonPath)) {
983
+ return currentDir;
984
+ }
985
+ currentDir = import_node_path5.default.dirname(currentDir);
986
+ }
987
+ throw new Error(
988
+ "Package root not found. Specify the root of the package with the `package.root` option."
989
+ );
990
+ }
991
+
886
992
  // src/config-v2/microfrontends/server/utils/get-output-file-path.ts
887
- var import_node_path3 = __toESM(require("path"), 1);
993
+ var import_node_path6 = __toESM(require("path"), 1);
888
994
 
889
995
  // src/config-v2/microfrontends/server/constants.ts
890
996
  var MFE_CONFIG_DEFAULT_FILE_PATH = "microfrontends";
@@ -898,13 +1004,13 @@ function isVercel() {
898
1004
  // src/config-v2/microfrontends/server/utils/get-output-file-path.ts
899
1005
  function getOutputFilePath() {
900
1006
  if (isVercel()) {
901
- return import_node_path3.default.join(
1007
+ return import_node_path6.default.join(
902
1008
  ".vercel",
903
1009
  MFE_CONFIG_DEFAULT_FILE_PATH,
904
1010
  MFE_CONFIG_DEFAULT_FILE_NAME
905
1011
  );
906
1012
  }
907
- return import_node_path3.default.join(MFE_CONFIG_DEFAULT_FILE_PATH, MFE_CONFIG_DEFAULT_FILE_NAME);
1013
+ return import_node_path6.default.join(MFE_CONFIG_DEFAULT_FILE_PATH, MFE_CONFIG_DEFAULT_FILE_NAME);
908
1014
  }
909
1015
 
910
1016
  // src/config-v2/microfrontends/server/validation.ts
@@ -1038,15 +1144,12 @@ var schema_v2_default = {
1038
1144
  },
1039
1145
  description: "Applications that only serve a subset of the microfrontend routes only need to reference the name of the primary application that owns the full microfrontends configuration."
1040
1146
  },
1041
- provider: {
1042
- $ref: "#/definitions/Provider"
1043
- },
1044
1147
  applications: {
1045
1148
  $ref: "#/definitions/ApplicationRouting",
1046
1149
  description: "Mapping of application names to the routes that they host. Only needs to be defined in the application that owns the primary microfrontend domain"
1047
1150
  }
1048
1151
  },
1049
- required: ["applications", "provider", "version"]
1152
+ required: ["applications", "version"]
1050
1153
  },
1051
1154
  Options: {
1052
1155
  type: "object",
@@ -1118,9 +1221,6 @@ var schema_v2_default = {
1118
1221
  projectId: {
1119
1222
  type: "string",
1120
1223
  description: "Vercel project ID"
1121
- },
1122
- routeSpeedInsightsToDefaultZone: {
1123
- type: "boolean"
1124
1224
  }
1125
1225
  },
1126
1226
  required: ["projectId"]
@@ -1223,10 +1323,6 @@ var schema_v2_default = {
1223
1323
  },
1224
1324
  required: ["paths"]
1225
1325
  },
1226
- Provider: {
1227
- type: "string",
1228
- enum: ["vercel", "other"]
1229
- },
1230
1326
  ApplicationRouting: {
1231
1327
  type: "object",
1232
1328
  additionalProperties: {
@@ -1290,8 +1386,8 @@ var MicrofrontendsServer = class extends Microfrontends {
1290
1386
  pretty: true
1291
1387
  }) {
1292
1388
  const outputPath = getOutputFilePath();
1293
- import_node_fs3.default.mkdirSync((0, import_node_path4.dirname)(outputPath), { recursive: true });
1294
- import_node_fs3.default.writeFileSync(
1389
+ import_node_fs6.default.mkdirSync((0, import_node_path7.dirname)(outputPath), { recursive: true });
1390
+ import_node_fs6.default.writeFileSync(
1295
1391
  outputPath,
1296
1392
  JSON.stringify(
1297
1393
  this.config.toSchemaJson(),
@@ -1353,6 +1449,69 @@ var MicrofrontendsServer = class extends Microfrontends {
1353
1449
  }
1354
1450
  return config;
1355
1451
  }
1452
+ /**
1453
+ * Looks up the configuration by inferring the package root and looking for a microfrontends.json file. If a file is not found,
1454
+ * it will look for a package in the repository with a microfrontends.json file that contains the current application
1455
+ * and use that configuration.
1456
+ *
1457
+ * This can return either a Child or Main configuration.
1458
+ */
1459
+ static infer({
1460
+ directory,
1461
+ filePath,
1462
+ meta,
1463
+ cookies,
1464
+ options
1465
+ } = {}) {
1466
+ if (filePath && meta) {
1467
+ return MicrofrontendsServer.fromFile({
1468
+ filePath,
1469
+ cookies,
1470
+ meta,
1471
+ options
1472
+ });
1473
+ }
1474
+ try {
1475
+ const packageRoot = findPackageRoot(directory);
1476
+ const packageJsonPath = (0, import_node_path7.join)(packageRoot, "package.json");
1477
+ const packageJson = JSON.parse(
1478
+ import_node_fs6.default.readFileSync(packageJsonPath, "utf-8")
1479
+ );
1480
+ if (!packageJson.name) {
1481
+ throw new Error(`No name found in package.json at ${packageJsonPath}`);
1482
+ }
1483
+ const configMeta = meta ?? { fromApp: packageJson.name };
1484
+ const maybeConfig = (0, import_node_path7.join)(packageRoot, "microfrontends.json");
1485
+ if (import_node_fs6.default.existsSync(maybeConfig)) {
1486
+ return MicrofrontendsServer.fromFile({
1487
+ filePath: maybeConfig,
1488
+ cookies,
1489
+ meta: configMeta,
1490
+ options
1491
+ });
1492
+ }
1493
+ const repositoryRoot = findRepositoryRoot();
1494
+ const isMonorepo2 = isMonorepo({ repositoryRoot });
1495
+ if (isMonorepo2) {
1496
+ const defaultPackage = findDefaultMicrofrontendsPackage({
1497
+ repositoryRoot,
1498
+ applicationName: packageJson.name
1499
+ });
1500
+ return MicrofrontendsServer.fromFile({
1501
+ filePath: (0, import_node_path7.join)(defaultPackage, "microfrontends.json"),
1502
+ cookies,
1503
+ meta: configMeta,
1504
+ options
1505
+ });
1506
+ }
1507
+ throw new Error("Unable to infer");
1508
+ } catch (e) {
1509
+ throw new MicrofrontendError(
1510
+ "Unable to infer microfrontends configuration",
1511
+ { type: "config", subtype: "inference_failed" }
1512
+ );
1513
+ }
1514
+ }
1356
1515
  /*
1357
1516
  * Generates a MicrofrontendsServer instance from a file.
1358
1517
  */
@@ -1363,25 +1522,28 @@ var MicrofrontendsServer = class extends Microfrontends {
1363
1522
  options
1364
1523
  }) {
1365
1524
  try {
1366
- const configJson = import_node_fs3.default.readFileSync(filePath, "utf-8");
1525
+ const configJson = import_node_fs6.default.readFileSync(filePath, "utf-8");
1367
1526
  const config = MicrofrontendsServer.validate(configJson);
1368
1527
  if (!isMainConfig(config) && (options == null ? void 0 : options.resolveMainConfig)) {
1369
1528
  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
- );
1529
+ const isMonorepo2 = isMonorepo({ repositoryRoot });
1530
+ if (isMonorepo2) {
1531
+ const packagePath = findPackagePath({
1532
+ repositoryRoot,
1533
+ name: config.partOf
1534
+ });
1535
+ if (!packagePath) {
1536
+ throw new MicrofrontendError(
1537
+ `Could not find default application "${config.partOf}" in the repository`,
1538
+ { type: "config", subtype: "not_found" }
1539
+ );
1540
+ }
1541
+ const mainConfigPath = (0, import_node_path7.join)(packagePath, "microfrontends.json");
1542
+ return MicrofrontendsServer.fromMainConfigFile({
1543
+ filePath: mainConfigPath,
1544
+ overrides: cookies ? parseOverrides(cookies) : void 0
1545
+ });
1379
1546
  }
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
1547
  }
1386
1548
  return new MicrofrontendsServer({
1387
1549
  config,
@@ -1402,7 +1564,7 @@ var MicrofrontendsServer = class extends Microfrontends {
1402
1564
  overrides
1403
1565
  }) {
1404
1566
  try {
1405
- const config = import_node_fs3.default.readFileSync(filePath, "utf-8");
1567
+ const config = import_node_fs6.default.readFileSync(filePath, "utf-8");
1406
1568
  const validatedConfig = MicrofrontendsServer.validate(config);
1407
1569
  if (!isMainConfig(validatedConfig)) {
1408
1570
  throw new MicrofrontendError(