@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
@@ -1,9 +1,9 @@
1
1
  // src/config-v2/microfrontends/server/index.ts
2
- import fs from "node:fs";
3
- import { dirname } from "node:path";
2
+ import fs4 from "node:fs";
3
+ import { dirname as dirname3, join } from "node:path";
4
4
 
5
5
  // src/config-v2/overrides/constants.ts
6
- var OVERRIDES_COOKIE_PREFIX = "vercel-microfrontends-override";
6
+ var OVERRIDES_COOKIE_PREFIX = "vercel-micro-frontends-override";
7
7
  var OVERRIDES_ENV_COOKIE_PREFIX = `${OVERRIDES_COOKIE_PREFIX}:env:`;
8
8
 
9
9
  // src/config-v2/overrides/is-override-cookie.ts
@@ -184,21 +184,21 @@ var MicrofrontendConfigClient = class {
184
184
  isEqual(other) {
185
185
  return JSON.stringify(this.applications) === JSON.stringify(other.applications);
186
186
  }
187
- getApplicationNameForPath(path2) {
188
- if (!path2.startsWith("/")) {
187
+ getApplicationNameForPath(path5) {
188
+ if (!path5.startsWith("/")) {
189
189
  throw new Error(`Path must start with a /`);
190
190
  }
191
- if (this.pathCache[path2]) {
192
- return this.pathCache[path2];
191
+ if (this.pathCache[path5]) {
192
+ return this.pathCache[path5];
193
193
  }
194
- const pathname = new URL(path2, "https://example.com").pathname;
194
+ const pathname = new URL(path5, "https://example.com").pathname;
195
195
  for (const [name, application] of Object.entries(this.applications)) {
196
196
  if (application.routing) {
197
197
  for (const group of application.routing) {
198
198
  for (const childPath of group.paths) {
199
199
  const regexp = pathToRegexp(childPath);
200
200
  if (regexp.test(pathname)) {
201
- this.pathCache[path2] = name;
201
+ this.pathCache[path5] = name;
202
202
  return name;
203
203
  }
204
204
  }
@@ -211,7 +211,7 @@ var MicrofrontendConfigClient = class {
211
211
  if (!defaultApplication) {
212
212
  return null;
213
213
  }
214
- this.pathCache[path2] = defaultApplication[0];
214
+ this.pathCache[path5] = defaultApplication[0];
215
215
  return defaultApplication[0];
216
216
  }
217
217
  serialize() {
@@ -243,22 +243,22 @@ var validateConfigPaths = (applicationConfigsById) => {
243
243
  continue;
244
244
  }
245
245
  for (const pathMatch of app.routing) {
246
- for (const path2 of pathMatch.paths) {
247
- const tokens = parsePathRegexp(path2);
246
+ for (const path5 of pathMatch.paths) {
247
+ const tokens = parsePathRegexp(path5);
248
248
  for (const token of tokens.slice(0, -1)) {
249
249
  if (typeof token !== "string") {
250
250
  errors.push(
251
- `Path ${path2} may only have a :wildcard in the last path component`
251
+ `Path ${path5} may only have a :wildcard in the last path component`
252
252
  );
253
253
  }
254
254
  }
255
- const existing = pathsByApplicationId.get(path2);
255
+ const existing = pathsByApplicationId.get(path5);
256
256
  if (existing) {
257
257
  existing.applications.push(id);
258
258
  } else {
259
- pathsByApplicationId.set(path2, {
259
+ pathsByApplicationId.set(path5, {
260
260
  applications: [id],
261
- matcher: pathToRegexp2(path2),
261
+ matcher: pathToRegexp2(path5),
262
262
  applicationId: id
263
263
  });
264
264
  }
@@ -266,10 +266,10 @@ var validateConfigPaths = (applicationConfigsById) => {
266
266
  }
267
267
  }
268
268
  const entries = Array.from(pathsByApplicationId.entries());
269
- entries.forEach(([path2, { applications: ids, matcher, applicationId }]) => {
269
+ entries.forEach(([path5, { applications: ids, matcher, applicationId }]) => {
270
270
  if (ids.length > 1) {
271
271
  errors.push(
272
- `Duplicate path "${path2}" for applications "${ids.join(", ")}"`
272
+ `Duplicate path "${path5}" for applications "${ids.join(", ")}"`
273
273
  );
274
274
  }
275
275
  entries.forEach(
@@ -277,14 +277,14 @@ var validateConfigPaths = (applicationConfigsById) => {
277
277
  matchPath,
278
278
  { applications: matchIds, applicationId: matchApplicationId }
279
279
  ]) => {
280
- if (path2 === matchPath) {
280
+ if (path5 === matchPath) {
281
281
  return;
282
282
  }
283
283
  if (applicationId === matchApplicationId) {
284
284
  return;
285
285
  }
286
286
  if (matcher.test(matchPath)) {
287
- const source = `"${path2}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
287
+ const source = `"${path5}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
288
288
  const destination = `"${matchPath}" of application${matchIds.length > 0 ? "s" : ""} ${matchIds.join(", ")}`;
289
289
  errors.push(
290
290
  `Overlapping path detected between ${source} and ${destination}`
@@ -775,8 +775,189 @@ var Microfrontends = class {
775
775
  }
776
776
  };
777
777
 
778
- // src/config-v2/microfrontends/server/utils/get-output-file-path.ts
778
+ // src/config-v2/microfrontends/utils/find-repository-root.ts
779
+ import fs from "node:fs";
779
780
  import path from "node:path";
781
+ var GIT_DIRECTORY = ".git";
782
+ function findRepositoryRoot(startDir) {
783
+ let currentDir = startDir || process.cwd();
784
+ while (currentDir !== path.parse(currentDir).root) {
785
+ const gitPath = path.join(currentDir, GIT_DIRECTORY);
786
+ if (fs.existsSync(gitPath) && fs.statSync(gitPath).isDirectory()) {
787
+ return currentDir;
788
+ }
789
+ currentDir = path.dirname(currentDir);
790
+ }
791
+ throw new Error(
792
+ "Repository root not found. Specify the root of the repository with the `repository.root` option."
793
+ );
794
+ }
795
+
796
+ // src/config-v2/microfrontends/utils/find-package-path.ts
797
+ import { dirname } from "node:path";
798
+ import { readFileSync } from "node:fs";
799
+ import fg from "fast-glob";
800
+ var configCache = {};
801
+ function findPackagePathWithGlob({
802
+ repositoryRoot,
803
+ name
804
+ }) {
805
+ try {
806
+ const packageJsonPaths = fg.globSync("**/package.json", {
807
+ cwd: repositoryRoot,
808
+ absolute: true,
809
+ onlyFiles: true,
810
+ followSymbolicLinks: false,
811
+ ignore: ["**/node_modules/**", "**/.git/**"]
812
+ });
813
+ const matchingPaths = [];
814
+ for (const packageJsonPath2 of packageJsonPaths) {
815
+ const packageJsonContent = readFileSync(packageJsonPath2, "utf-8");
816
+ const packageJson = JSON.parse(packageJsonContent);
817
+ if (packageJson.name === name) {
818
+ matchingPaths.push(packageJsonPath2);
819
+ }
820
+ }
821
+ if (matchingPaths.length > 1) {
822
+ throw new Error(
823
+ `Found multiple packages with the name "${name}" in the repository: ${matchingPaths.join(", ")}`
824
+ );
825
+ }
826
+ if (matchingPaths.length === 0) {
827
+ throw new Error(
828
+ `Could not find package with the name "${name}" in the repository`
829
+ );
830
+ }
831
+ const [packageJsonPath] = matchingPaths;
832
+ return dirname(packageJsonPath);
833
+ } catch (error) {
834
+ return null;
835
+ }
836
+ }
837
+ function findPackagePath(opts) {
838
+ const cacheKey = `${opts.repositoryRoot}-${opts.name}`;
839
+ if (configCache[cacheKey]) {
840
+ return configCache[cacheKey];
841
+ }
842
+ const result = findPackagePathWithGlob(opts);
843
+ if (!result) {
844
+ throw new Error(
845
+ `Could not find package with the name "${opts.name}" in the repository`
846
+ );
847
+ }
848
+ configCache[cacheKey] = result;
849
+ return result;
850
+ }
851
+
852
+ // src/config-v2/microfrontends/utils/find-default-package.ts
853
+ import { dirname as dirname2 } from "node:path";
854
+ import { readFileSync as readFileSync2 } from "node:fs";
855
+ import fg2 from "fast-glob";
856
+ var configCache2 = {};
857
+ function findDefaultMicrofrontendsPackages({
858
+ repositoryRoot,
859
+ applicationName
860
+ }) {
861
+ try {
862
+ const microfrontendsJsonPaths = fg2.globSync("**/microfrontends.json", {
863
+ cwd: repositoryRoot,
864
+ absolute: true,
865
+ onlyFiles: true,
866
+ followSymbolicLinks: false,
867
+ ignore: ["**/node_modules/**", "**/.git/**"]
868
+ });
869
+ const matchingPaths = [];
870
+ for (const microfrontendsJsonPath of microfrontendsJsonPaths) {
871
+ const microfrontendsJsonContent = readFileSync2(
872
+ microfrontendsJsonPath,
873
+ "utf-8"
874
+ );
875
+ const microfrontendsJson = JSON.parse(
876
+ microfrontendsJsonContent
877
+ );
878
+ if (isMainConfig(microfrontendsJson) && microfrontendsJson.applications[applicationName]) {
879
+ matchingPaths.push(microfrontendsJsonPath);
880
+ }
881
+ }
882
+ if (matchingPaths.length > 1) {
883
+ throw new Error(
884
+ `Found multiple default applications referencing "${applicationName}" in the repository, this is not yet supported.
885
+ ${matchingPaths.join("\n \u2022 ")}`
886
+ );
887
+ }
888
+ if (matchingPaths.length === 0) {
889
+ throw new Error(
890
+ `Could not find default application with "applications.${applicationName}"`
891
+ );
892
+ }
893
+ const [packageJsonPath] = matchingPaths;
894
+ return dirname2(packageJsonPath);
895
+ } catch (error) {
896
+ return null;
897
+ }
898
+ }
899
+ function findDefaultMicrofrontendsPackage(opts) {
900
+ const cacheKey = `${opts.repositoryRoot}-${opts.applicationName}`;
901
+ if (configCache2[cacheKey]) {
902
+ return configCache2[cacheKey];
903
+ }
904
+ const result = findDefaultMicrofrontendsPackages(opts);
905
+ if (!result) {
906
+ throw new Error(
907
+ `Error trying to resolve the main microfrontends.json configuration`
908
+ );
909
+ }
910
+ configCache2[cacheKey] = result;
911
+ return result;
912
+ }
913
+
914
+ // src/config-v2/microfrontends/utils/is-monorepo.ts
915
+ import fs2 from "node:fs";
916
+ import path2 from "node:path";
917
+ function isMonorepo({
918
+ repositoryRoot
919
+ }) {
920
+ try {
921
+ if (fs2.existsSync(path2.join(repositoryRoot, "pnpm-workspace.yaml"))) {
922
+ return true;
923
+ }
924
+ if (fs2.existsSync(path2.join(repositoryRoot, "vlt-workspaces.json"))) {
925
+ return true;
926
+ }
927
+ const packageJsonPath = path2.join(repositoryRoot, "package.json");
928
+ if (!fs2.existsSync(packageJsonPath)) {
929
+ return false;
930
+ }
931
+ const packageJson = JSON.parse(
932
+ fs2.readFileSync(packageJsonPath, "utf-8")
933
+ );
934
+ return packageJson.workspaces !== void 0;
935
+ } catch (error) {
936
+ console.error("Error determining if repository is a monorepo", error);
937
+ return false;
938
+ }
939
+ }
940
+
941
+ // src/config-v2/microfrontends/utils/find-package-root.ts
942
+ import fs3 from "node:fs";
943
+ import path3 from "node:path";
944
+ var PACKAGE_JSON = "package.json";
945
+ function findPackageRoot(startDir) {
946
+ let currentDir = startDir || process.cwd();
947
+ while (currentDir !== path3.parse(currentDir).root) {
948
+ const pkgJsonPath = path3.join(currentDir, PACKAGE_JSON);
949
+ if (fs3.existsSync(pkgJsonPath)) {
950
+ return currentDir;
951
+ }
952
+ currentDir = path3.dirname(currentDir);
953
+ }
954
+ throw new Error(
955
+ "Package root not found. Specify the root of the package with the `package.root` option."
956
+ );
957
+ }
958
+
959
+ // src/config-v2/microfrontends/server/utils/get-output-file-path.ts
960
+ import path4 from "node:path";
780
961
 
781
962
  // src/config-v2/microfrontends/server/constants.ts
782
963
  var MFE_CONFIG_DEFAULT_FILE_PATH = "microfrontends";
@@ -790,13 +971,13 @@ function isVercel() {
790
971
  // src/config-v2/microfrontends/server/utils/get-output-file-path.ts
791
972
  function getOutputFilePath() {
792
973
  if (isVercel()) {
793
- return path.join(
974
+ return path4.join(
794
975
  ".vercel",
795
976
  MFE_CONFIG_DEFAULT_FILE_PATH,
796
977
  MFE_CONFIG_DEFAULT_FILE_NAME
797
978
  );
798
979
  }
799
- return path.join(MFE_CONFIG_DEFAULT_FILE_PATH, MFE_CONFIG_DEFAULT_FILE_NAME);
980
+ return path4.join(MFE_CONFIG_DEFAULT_FILE_PATH, MFE_CONFIG_DEFAULT_FILE_NAME);
800
981
  }
801
982
 
802
983
  // src/config-v2/microfrontends/server/validation.ts
@@ -1010,9 +1191,6 @@ var schema_v2_default = {
1010
1191
  projectId: {
1011
1192
  type: "string",
1012
1193
  description: "Vercel project ID"
1013
- },
1014
- routeSpeedInsightsToDefaultZone: {
1015
- type: "boolean"
1016
1194
  }
1017
1195
  },
1018
1196
  required: ["projectId"]
@@ -1106,10 +1284,6 @@ var schema_v2_default = {
1106
1284
  type: "string",
1107
1285
  description: "flag name that can be used to enable/disable all paths in the group"
1108
1286
  },
1109
- routeToDefaultApplication: {
1110
- type: "boolean",
1111
- 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."
1112
- },
1113
1287
  paths: {
1114
1288
  type: "array",
1115
1289
  items: {
@@ -1186,8 +1360,8 @@ var MicrofrontendsServer = class extends Microfrontends {
1186
1360
  pretty: true
1187
1361
  }) {
1188
1362
  const outputPath = getOutputFilePath();
1189
- fs.mkdirSync(dirname(outputPath), { recursive: true });
1190
- fs.writeFileSync(
1363
+ fs4.mkdirSync(dirname3(outputPath), { recursive: true });
1364
+ fs4.writeFileSync(
1191
1365
  outputPath,
1192
1366
  JSON.stringify(
1193
1367
  this.config.toSchemaJson(),
@@ -1249,18 +1423,104 @@ var MicrofrontendsServer = class extends Microfrontends {
1249
1423
  }
1250
1424
  return config;
1251
1425
  }
1426
+ /**
1427
+ * Looks up the configuration by inferring the package root and looking for a microfrontends.json file. If a file is not found,
1428
+ * it will look for a package in the repository with a microfrontends.json file that contains the current application
1429
+ * and use that configuration.
1430
+ *
1431
+ * This can return either a Child or Main configuration.
1432
+ */
1433
+ static infer({
1434
+ directory,
1435
+ filePath,
1436
+ meta,
1437
+ cookies,
1438
+ options
1439
+ } = {}) {
1440
+ if (filePath && meta) {
1441
+ return MicrofrontendsServer.fromFile({
1442
+ filePath,
1443
+ cookies,
1444
+ meta,
1445
+ options
1446
+ });
1447
+ }
1448
+ try {
1449
+ const packageRoot = findPackageRoot(directory);
1450
+ const packageJsonPath = join(packageRoot, "package.json");
1451
+ const packageJson = JSON.parse(
1452
+ fs4.readFileSync(packageJsonPath, "utf-8")
1453
+ );
1454
+ if (!packageJson.name) {
1455
+ throw new Error(`No name found in package.json at ${packageJsonPath}`);
1456
+ }
1457
+ const configMeta = meta ?? { fromApp: packageJson.name };
1458
+ const maybeConfig = join(packageRoot, "microfrontends.json");
1459
+ if (fs4.existsSync(maybeConfig)) {
1460
+ return MicrofrontendsServer.fromFile({
1461
+ filePath: maybeConfig,
1462
+ cookies,
1463
+ meta: configMeta,
1464
+ options
1465
+ });
1466
+ }
1467
+ const repositoryRoot = findRepositoryRoot();
1468
+ const isMonorepo2 = isMonorepo({ repositoryRoot });
1469
+ if (isMonorepo2) {
1470
+ const defaultPackage = findDefaultMicrofrontendsPackage({
1471
+ repositoryRoot,
1472
+ applicationName: packageJson.name
1473
+ });
1474
+ return MicrofrontendsServer.fromFile({
1475
+ filePath: join(defaultPackage, "microfrontends.json"),
1476
+ cookies,
1477
+ meta: configMeta,
1478
+ options
1479
+ });
1480
+ }
1481
+ throw new Error("Unable to infer");
1482
+ } catch (e) {
1483
+ throw new MicrofrontendError(
1484
+ "Unable to infer microfrontends configuration",
1485
+ { type: "config", subtype: "inference_failed" }
1486
+ );
1487
+ }
1488
+ }
1252
1489
  /*
1253
1490
  * Generates a MicrofrontendsServer instance from a file.
1254
1491
  */
1255
1492
  static fromFile({
1256
1493
  filePath,
1257
1494
  cookies,
1258
- meta
1495
+ meta,
1496
+ options
1259
1497
  }) {
1260
1498
  try {
1261
- const config = fs.readFileSync(filePath, "utf-8");
1499
+ const configJson = fs4.readFileSync(filePath, "utf-8");
1500
+ const config = MicrofrontendsServer.validate(configJson);
1501
+ if (!isMainConfig(config) && (options == null ? void 0 : options.resolveMainConfig)) {
1502
+ const repositoryRoot = findRepositoryRoot();
1503
+ const isMonorepo2 = isMonorepo({ repositoryRoot });
1504
+ if (isMonorepo2) {
1505
+ const packagePath = findPackagePath({
1506
+ repositoryRoot,
1507
+ name: config.partOf
1508
+ });
1509
+ if (!packagePath) {
1510
+ throw new MicrofrontendError(
1511
+ `Could not find default application "${config.partOf}" in the repository`,
1512
+ { type: "config", subtype: "not_found" }
1513
+ );
1514
+ }
1515
+ const mainConfigPath = join(packagePath, "microfrontends.json");
1516
+ return MicrofrontendsServer.fromMainConfigFile({
1517
+ filePath: mainConfigPath,
1518
+ overrides: cookies ? parseOverrides(cookies) : void 0
1519
+ });
1520
+ }
1521
+ }
1262
1522
  return new MicrofrontendsServer({
1263
- config: MicrofrontendsServer.validate(config),
1523
+ config,
1264
1524
  overrides: cookies ? parseOverrides(cookies) : void 0,
1265
1525
  meta
1266
1526
  });
@@ -1278,7 +1538,7 @@ var MicrofrontendsServer = class extends Microfrontends {
1278
1538
  overrides
1279
1539
  }) {
1280
1540
  try {
1281
- const config = fs.readFileSync(filePath, "utf-8");
1541
+ const config = fs4.readFileSync(filePath, "utf-8");
1282
1542
  const validatedConfig = MicrofrontendsServer.validate(config);
1283
1543
  if (!isMainConfig(validatedConfig)) {
1284
1544
  throw new MicrofrontendError(