@vercel/microfrontends 0.17.4 → 0.19.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/README.md +7 -159
  2. package/dist/bin/cli.cjs +202 -139
  3. package/dist/config.cjs +103 -57
  4. package/dist/config.cjs.map +1 -1
  5. package/dist/config.d.ts +4 -4
  6. package/dist/config.js +103 -57
  7. package/dist/config.js.map +1 -1
  8. package/dist/{index-f094deb1.d.ts → index-09b1ddf9.d.ts} +16 -19
  9. package/dist/{index-5fcf0863.d.ts → index-2f78c0ca.d.ts} +44 -17
  10. package/dist/microfrontends/server.cjs +180 -133
  11. package/dist/microfrontends/server.cjs.map +1 -1
  12. package/dist/microfrontends/server.d.ts +4 -4
  13. package/dist/microfrontends/server.js +180 -133
  14. package/dist/microfrontends/server.js.map +1 -1
  15. package/dist/microfrontends.cjs +104 -58
  16. package/dist/microfrontends.cjs.map +1 -1
  17. package/dist/microfrontends.d.ts +4 -4
  18. package/dist/microfrontends.js +104 -58
  19. package/dist/microfrontends.js.map +1 -1
  20. package/dist/next/client.cjs +1 -1
  21. package/dist/next/client.cjs.map +1 -1
  22. package/dist/next/client.d.ts +1 -1
  23. package/dist/next/client.js +1 -1
  24. package/dist/next/client.js.map +1 -1
  25. package/dist/next/config.cjs +197 -145
  26. package/dist/next/config.cjs.map +1 -1
  27. package/dist/next/config.js +197 -145
  28. package/dist/next/config.js.map +1 -1
  29. package/dist/next/endpoints.d.ts +2 -2
  30. package/dist/next/middleware.cjs +121 -80
  31. package/dist/next/middleware.cjs.map +1 -1
  32. package/dist/next/middleware.js +121 -80
  33. package/dist/next/middleware.js.map +1 -1
  34. package/dist/next/testing.cjs +110 -63
  35. package/dist/next/testing.cjs.map +1 -1
  36. package/dist/next/testing.d.ts +4 -4
  37. package/dist/next/testing.js +110 -63
  38. package/dist/next/testing.js.map +1 -1
  39. package/dist/overrides.d.ts +3 -3
  40. package/dist/schema.d.ts +1 -1
  41. package/dist/{types-5900be7c.d.ts → types-4ef2bddb.d.ts} +1 -1
  42. package/dist/{types-ecd7b91b.d.ts → types-b6d38aea.d.ts} +1 -1
  43. package/dist/utils/mfe-port.cjs +181 -134
  44. package/dist/utils/mfe-port.cjs.map +1 -1
  45. package/dist/utils/mfe-port.js +181 -134
  46. package/dist/utils/mfe-port.js.map +1 -1
  47. package/dist/validation.cjs +74 -73
  48. package/dist/validation.cjs.map +1 -1
  49. package/dist/validation.d.ts +1 -1
  50. package/dist/validation.js +74 -73
  51. package/dist/validation.js.map +1 -1
  52. package/package.json +19 -3
  53. package/schema/schema.json +80 -73
@@ -38,7 +38,7 @@ function parseOverrides(cookies) {
38
38
  // src/config/errors.ts
39
39
  var MicrofrontendError = class extends Error {
40
40
  constructor(message, opts) {
41
- super(message);
41
+ super(message, { cause: opts?.cause });
42
42
  this.name = "MicrofrontendsError";
43
43
  this.source = opts?.source ?? "@vercel/microfrontends";
44
44
  this.type = opts?.type ?? "unknown";
@@ -230,7 +230,8 @@ var validateConfigPaths = (applicationConfigsById) => {
230
230
  if (isDefaultApp(app)) {
231
231
  continue;
232
232
  }
233
- for (const pathMatch of app.routing) {
233
+ const childApp = app;
234
+ for (const pathMatch of childApp.routing) {
234
235
  for (const path5 of pathMatch.paths) {
235
236
  const maybeError = validatePathExpression(path5);
236
237
  if (maybeError) {
@@ -250,33 +251,31 @@ var validateConfigPaths = (applicationConfigsById) => {
250
251
  }
251
252
  }
252
253
  const entries = Array.from(pathsByApplicationId.entries());
253
- entries.forEach(([path5, { applications: ids, matcher, applicationId }]) => {
254
+ for (const [path5, { applications: ids, matcher, applicationId }] of entries) {
254
255
  if (ids.length > 1) {
255
256
  errors.push(
256
257
  `Duplicate path "${path5}" for applications "${ids.join(", ")}"`
257
258
  );
258
259
  }
259
- entries.forEach(
260
- ([
261
- matchPath,
262
- { applications: matchIds, applicationId: matchApplicationId }
263
- ]) => {
264
- if (path5 === matchPath) {
265
- return;
266
- }
267
- if (applicationId === matchApplicationId) {
268
- return;
269
- }
270
- if (matcher.test(matchPath)) {
271
- const source = `"${path5}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
272
- const destination = `"${matchPath}" of application${matchIds.length > 0 ? "s" : ""} ${matchIds.join(", ")}`;
273
- errors.push(
274
- `Overlapping path detected between ${source} and ${destination}`
275
- );
276
- }
260
+ for (const [
261
+ matchPath,
262
+ { applications: matchIds, applicationId: matchApplicationId }
263
+ ] of entries) {
264
+ if (path5 === matchPath) {
265
+ continue;
277
266
  }
278
- );
279
- });
267
+ if (applicationId === matchApplicationId) {
268
+ continue;
269
+ }
270
+ if (matcher.test(matchPath)) {
271
+ const source = `"${path5}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
272
+ const destination = `"${matchPath}" of application${matchIds.length > 0 ? "s" : ""} ${matchIds.join(", ")}`;
273
+ errors.push(
274
+ `Overlapping path detected between ${source} and ${destination}`
275
+ );
276
+ }
277
+ }
278
+ }
280
279
  if (errors.length) {
281
280
  throw new MicrofrontendError(`Invalid paths: ${errors.join(", ")}`, {
282
281
  type: "config",
@@ -345,7 +344,7 @@ var validateConfigDefaultApplication = (applicationConfigsById) => {
345
344
  const numApplicationsWithoutRouting = numApplications - numApplicationsWithRouting;
346
345
  if (numApplicationsWithoutRouting === 0) {
347
346
  throw new MicrofrontendError(
348
- `No default application found. At least one application needs to be the default by omitting routing.`,
347
+ "No default application found. At least one application needs to be the default by omitting routing.",
349
348
  { type: "config", subtype: "no_default_application" }
350
349
  );
351
350
  }
@@ -391,47 +390,80 @@ function generatePortFromName({
391
390
  // src/config/microfrontends-config/isomorphic/host.ts
392
391
  var Host = class {
393
392
  constructor(hostConfig, options) {
394
- const { protocol = "https", host, port } = hostConfig;
395
- this.protocol = protocol;
396
- this.host = host;
397
- this.port = Host.getPort({ port, protocol: this.protocol });
393
+ if (typeof hostConfig === "string") {
394
+ ({
395
+ protocol: this.protocol,
396
+ host: this.host,
397
+ port: this.port
398
+ } = Host.parseUrl(hostConfig));
399
+ } else {
400
+ const { protocol = "https", host, port } = hostConfig;
401
+ this.protocol = protocol;
402
+ this.host = host;
403
+ this.port = port;
404
+ }
398
405
  this.local = options?.isLocal;
399
406
  }
400
- isLocal() {
401
- return this.local || this.host === "localhost" || this.host === "127.0.0.1";
402
- }
403
- static getPort({
404
- protocol,
405
- port
406
- }) {
407
- if (!port) {
408
- if (protocol === "http") {
409
- return 80;
410
- }
411
- return 443;
407
+ static parseUrl(url) {
408
+ let hostToParse = url;
409
+ if (!/^https?:\/\//.exec(hostToParse)) {
410
+ hostToParse = `https://${hostToParse}`;
411
+ }
412
+ const parsed = new URL(hostToParse);
413
+ if (!parsed.hostname) {
414
+ throw new Error(Host.getMicrofrontendsError(url, "requires a host"));
415
+ }
416
+ if (parsed.hash) {
417
+ throw new Error(
418
+ Host.getMicrofrontendsError(url, "cannot have a fragment")
419
+ );
412
420
  }
413
- return port;
421
+ if (parsed.username || parsed.password) {
422
+ throw new Error(
423
+ Host.getMicrofrontendsError(
424
+ url,
425
+ "cannot have authentication credentials (username and/or password)"
426
+ )
427
+ );
428
+ }
429
+ if (parsed.pathname !== "/") {
430
+ throw new Error(Host.getMicrofrontendsError(url, "cannot have a path"));
431
+ }
432
+ if (parsed.search) {
433
+ throw new Error(
434
+ Host.getMicrofrontendsError(url, "cannot have query parameters")
435
+ );
436
+ }
437
+ const protocol = parsed.protocol.slice(0, -1);
438
+ return {
439
+ protocol,
440
+ host: parsed.hostname,
441
+ port: parsed.port ? Number.parseInt(parsed.port) : void 0
442
+ };
414
443
  }
415
- isDefaultPort() {
416
- return this.port === Host.getPort({ protocol: this.protocol });
444
+ static getMicrofrontendsError(url, message) {
445
+ return `Microfrontends configuration error: the URL ${url} in your microfrontends.json ${message}.`;
446
+ }
447
+ isLocal() {
448
+ return this.local || this.host === "localhost" || this.host === "127.0.0.1";
417
449
  }
418
- toString(opts = {}) {
419
- const url = this.toUrl(opts);
450
+ toString() {
451
+ const url = this.toUrl();
420
452
  return url.toString().replace(/\/$/, "");
421
453
  }
422
- toUrl(opts = {}) {
423
- const { includeDefaultPort } = opts;
424
- const url = `${this.protocol}://${this.host}${this.isDefaultPort() && !includeDefaultPort ? "" : `:${this.port}`}`;
454
+ toUrl() {
455
+ const url = `${this.protocol}://${this.host}${this.port ? `:${this.port}` : ""}`;
425
456
  return new URL(url);
426
457
  }
427
458
  };
428
459
  var LocalHost = class extends Host {
429
460
  constructor({
430
461
  appName,
462
+ localPort,
431
463
  ...hostConfig
432
464
  }) {
433
465
  const host = hostConfig.host ?? "localhost";
434
- const port = hostConfig.port ?? generatePortFromName({ name: appName });
466
+ const port = localPort ?? hostConfig.port ?? generatePortFromName({ name: appName });
435
467
  const protocol = hostConfig.protocol ?? "http";
436
468
  super({ protocol, host, port });
437
469
  }
@@ -448,12 +480,17 @@ var Application = class {
448
480
  this.development = {
449
481
  local: new LocalHost({
450
482
  appName: name,
483
+ localPort: app.development?.localPort,
451
484
  ...app.development?.local
452
485
  }),
453
486
  fallback: app.development?.fallback ? new Host(app.development.fallback) : void 0
454
487
  };
455
- this.production = app.production ? new Host(app.production) : void 0;
456
- this.vercel = app.vercel;
488
+ if (app.development?.fallback) {
489
+ this.fallback = new Host(app.development.fallback);
490
+ } else if (app.production) {
491
+ this.fallback = new Host(app.production);
492
+ }
493
+ this.projectId = app.projectId ?? app.vercel?.projectId;
457
494
  this.overrides = overrides?.environment ? {
458
495
  environment: new Host(overrides.environment)
459
496
  } : void 0;
@@ -481,7 +518,16 @@ var DefaultApplication = class extends Application {
481
518
  isDefault: true
482
519
  });
483
520
  this.default = true;
484
- this.production = new Host(app.production);
521
+ const fallbackHost = app.development?.fallback ?? app.production;
522
+ if (fallbackHost === void 0) {
523
+ throw new Error(
524
+ "`app.production` or `app.development.fallback` must be set in the default application in microfrontends.json."
525
+ );
526
+ }
527
+ this.fallback = new Host(fallbackHost);
528
+ if (app.production) {
529
+ this.production = new Host(app.production);
530
+ }
485
531
  }
486
532
  getAssetPrefix() {
487
533
  return "";
@@ -551,7 +597,7 @@ var MicrofrontendConfigIsomorphic = class {
551
597
  }
552
598
  if (isMainConfig(config) && !this.defaultApplication) {
553
599
  throw new MicrofrontendError(
554
- `Could not find default application in microfrontends configuration`,
600
+ "Could not find default application in microfrontends configuration",
555
601
  {
556
602
  type: "application",
557
603
  subtype: "not_found"
@@ -627,11 +673,11 @@ var MicrofrontendConfigIsomorphic = class {
627
673
  return app;
628
674
  }
629
675
  getApplicationByProjectId(projectId) {
630
- if (this.defaultApplication?.vercel?.projectId === projectId) {
676
+ if (this.defaultApplication?.projectId === projectId) {
631
677
  return this.defaultApplication;
632
678
  }
633
679
  return Object.values(this.childApplications).find(
634
- (app) => app.vercel?.projectId === projectId
680
+ (app) => app.projectId === projectId
635
681
  );
636
682
  }
637
683
  /**
@@ -641,7 +687,7 @@ var MicrofrontendConfigIsomorphic = class {
641
687
  getDefaultApplication() {
642
688
  if (!this.defaultApplication) {
643
689
  throw new MicrofrontendError(
644
- `Could not find default application in microfrontends configuration`,
690
+ "Could not find default application in microfrontends configuration",
645
691
  {
646
692
  type: "application",
647
693
  subtype: "not_found"
@@ -654,7 +700,7 @@ var MicrofrontendConfigIsomorphic = class {
654
700
  * Returns the configured port for the local proxy
655
701
  */
656
702
  getLocalProxyPort() {
657
- return this.config.options?.localProxy?.port ?? DEFAULT_LOCAL_PROXY_PORT;
703
+ return this.config.options?.localProxyPort ?? this.config.options?.localProxy?.port ?? DEFAULT_LOCAL_PROXY_PORT;
658
704
  }
659
705
  /**
660
706
  * Serializes the class back to the Schema type.
@@ -728,7 +774,7 @@ var MicrofrontendMainConfig = class extends MicrofrontendConfigIsomorphic {
728
774
  }
729
775
  if (!defaultApplication) {
730
776
  throw new MicrofrontendError(
731
- `Could not find default application in microfrontends configuration`,
777
+ "Could not find default application in microfrontends configuration",
732
778
  {
733
779
  type: "application",
734
780
  subtype: "not_found"
@@ -1015,24 +1061,12 @@ var schema_default = {
1015
1061
  options: {
1016
1062
  $ref: "#/definitions/Options"
1017
1063
  },
1018
- remotes: {
1019
- type: "object",
1020
- additionalProperties: {
1021
- $ref: "#/definitions/Application"
1022
- },
1023
- propertyNames: {
1024
- description: "The unique identifier for a Microfrontend Application. Must match the `name` field of the application's `package.json`."
1025
- },
1026
- 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."
1027
- },
1028
1064
  applications: {
1029
1065
  $ref: "#/definitions/ApplicationRouting",
1030
1066
  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"
1031
1067
  }
1032
1068
  },
1033
- required: [
1034
- "applications"
1035
- ],
1069
+ required: ["applications"],
1036
1070
  additionalProperties: false
1037
1071
  },
1038
1072
  Options: {
@@ -1040,11 +1074,21 @@ var schema_default = {
1040
1074
  properties: {
1041
1075
  vercel: {
1042
1076
  $ref: "#/definitions/VercelOptions",
1043
- description: "Micro-Frontends wide options for Vercel."
1077
+ description: "Microfrontends wide options for Vercel.",
1078
+ deprecated: "This is being replaced by the `disableOverrides` field below."
1079
+ },
1080
+ disableOverrides: {
1081
+ type: "boolean",
1082
+ description: "If you want to disable the overrides for the site. For example, if you are managing rewrites between applications externally, you may wish to disable the overrides on the toolbar as they will have no effect."
1044
1083
  },
1045
1084
  localProxy: {
1046
1085
  $ref: "#/definitions/LocalProxyOptions",
1047
- description: "Options for local proxy."
1086
+ description: "Options for local proxy.",
1087
+ deprecated: "This is being replaced by the `localProxyPort` field below."
1088
+ },
1089
+ localProxyPort: {
1090
+ type: "number",
1091
+ description: "The port number used by the local proxy server.\n\nThe default is `3024`."
1048
1092
  }
1049
1093
  },
1050
1094
  additionalProperties: false
@@ -1052,10 +1096,6 @@ var schema_default = {
1052
1096
  VercelOptions: {
1053
1097
  type: "object",
1054
1098
  properties: {
1055
- teamSlug: {
1056
- type: "string",
1057
- description: "Team slug for the Vercel team"
1058
- },
1059
1099
  disableOverrides: {
1060
1100
  type: "boolean",
1061
1101
  description: "If you want to disable the overrides for the site. For example, if you are managing rewrites between applications externally, you may wish to disable the overrides on the toolbar as they will have no effect."
@@ -1073,6 +1113,15 @@ var schema_default = {
1073
1113
  },
1074
1114
  additionalProperties: false
1075
1115
  },
1116
+ ApplicationRouting: {
1117
+ type: "object",
1118
+ additionalProperties: {
1119
+ $ref: "#/definitions/Application"
1120
+ },
1121
+ propertyNames: {
1122
+ description: "The unique identifier for a Microfrontend Application. Must match the `name` field of the application's `package.json`."
1123
+ }
1124
+ },
1076
1125
  Application: {
1077
1126
  anyOf: [
1078
1127
  {
@@ -1087,18 +1136,22 @@ var schema_default = {
1087
1136
  type: "object",
1088
1137
  properties: {
1089
1138
  vercel: {
1090
- $ref: "#/definitions/Vercel"
1139
+ $ref: "#/definitions/Vercel",
1140
+ deprecated: "This is being replaced by the `projectId` field below."
1141
+ },
1142
+ projectId: {
1143
+ type: "string",
1144
+ description: "Vercel project ID"
1091
1145
  },
1092
1146
  development: {
1093
1147
  $ref: "#/definitions/Development"
1094
1148
  },
1095
1149
  production: {
1096
- $ref: "#/definitions/HostConfig"
1150
+ $ref: "#/definitions/HostConfig",
1151
+ deprecated: "This is a duplicate of the `development.fallback` field and this will be removed soon."
1097
1152
  }
1098
1153
  },
1099
- required: [
1100
- "production"
1101
- ],
1154
+ required: ["production"],
1102
1155
  additionalProperties: false
1103
1156
  },
1104
1157
  Vercel: {
@@ -1109,20 +1162,30 @@ var schema_default = {
1109
1162
  description: "Vercel project ID"
1110
1163
  }
1111
1164
  },
1112
- required: [
1113
- "projectId"
1114
- ],
1165
+ required: ["projectId"],
1115
1166
  additionalProperties: false
1116
1167
  },
1117
1168
  Development: {
1118
1169
  type: "object",
1119
1170
  properties: {
1120
1171
  local: {
1121
- $ref: "#/definitions/LocalHostConfig"
1172
+ $ref: "#/definitions/LocalHostConfig",
1173
+ deprecated: "This is being replaced by the `localPort` field below."
1174
+ },
1175
+ localPort: {
1176
+ type: "number",
1177
+ description: "The local port number that this application runs on when it is running locally. Common values include `80` for HTTP and `443` for HTTPS."
1122
1178
  },
1123
1179
  fallback: {
1124
- $ref: "#/definitions/HostConfig",
1125
- description: "Fallback for local development, could be a host config that points to any environment. If this is not provided, or the application is not running - requests to the application in local development will error."
1180
+ anyOf: [
1181
+ {
1182
+ $ref: "#/definitions/HostConfig"
1183
+ },
1184
+ {
1185
+ type: "string"
1186
+ }
1187
+ ],
1188
+ description: "Fallback for local development, could be a host config that points to any environment. If this is not provided, or the application is not running - requests to the application in local development will error.\n\nIf passing a string, include the protocol (optional), host (required) and port (optional). For example: `https://this.ismyhost:8080`. If omitted, the protocol defaults to HTTPS. If omitted, the port defaults to `80` for HTTP and `443` for HTTPS."
1126
1189
  },
1127
1190
  task: {
1128
1191
  type: "string",
@@ -1141,10 +1204,7 @@ var schema_default = {
1141
1204
  },
1142
1205
  protocol: {
1143
1206
  type: "string",
1144
- enum: [
1145
- "http",
1146
- "https"
1147
- ],
1207
+ enum: ["http", "https"],
1148
1208
  description: "The protocol to be used for the connection.\n- `http`: Hypertext Transfer Protocol (HTTP).\n- `https`: Secure Hypertext Transfer Protocol (HTTPS).\n\n*"
1149
1209
  },
1150
1210
  port: {
@@ -1158,10 +1218,7 @@ var schema_default = {
1158
1218
  properties: {
1159
1219
  protocol: {
1160
1220
  type: "string",
1161
- enum: [
1162
- "http",
1163
- "https"
1164
- ],
1221
+ enum: ["http", "https"],
1165
1222
  description: "The protocol to be used for the connection.\n- `http`: Hypertext Transfer Protocol (HTTP).\n- `https`: Secure Hypertext Transfer Protocol (HTTPS).\n\n*"
1166
1223
  },
1167
1224
  host: {
@@ -1173,16 +1230,19 @@ var schema_default = {
1173
1230
  description: "The port number to be used for the connection. Common values include `80` for HTTP and `443` for HTTPS."
1174
1231
  }
1175
1232
  },
1176
- required: [
1177
- "host"
1178
- ],
1233
+ required: ["host"],
1179
1234
  additionalProperties: false
1180
1235
  },
1181
1236
  ChildApplication: {
1182
1237
  type: "object",
1183
1238
  properties: {
1184
1239
  vercel: {
1185
- $ref: "#/definitions/Vercel"
1240
+ $ref: "#/definitions/Vercel",
1241
+ deprecated: "This is being replaced by the `projectId` field below."
1242
+ },
1243
+ projectId: {
1244
+ type: "string",
1245
+ description: "Vercel project ID"
1186
1246
  },
1187
1247
  development: {
1188
1248
  $ref: "#/definitions/Development"
@@ -1192,12 +1252,11 @@ var schema_default = {
1192
1252
  description: "Groups of path expressions that are routed to this application."
1193
1253
  },
1194
1254
  production: {
1195
- $ref: "#/definitions/HostConfig"
1255
+ $ref: "#/definitions/HostConfig",
1256
+ deprecated: "This is a duplicate of the `development.fallback` field and this will be removed soon."
1196
1257
  }
1197
1258
  },
1198
- required: [
1199
- "routing"
1200
- ],
1259
+ required: ["routing"],
1201
1260
  additionalProperties: false
1202
1261
  },
1203
1262
  Routing: {
@@ -1224,20 +1283,9 @@ var schema_default = {
1224
1283
  }
1225
1284
  }
1226
1285
  },
1227
- required: [
1228
- "paths"
1229
- ],
1286
+ required: ["paths"],
1230
1287
  additionalProperties: false
1231
1288
  },
1232
- ApplicationRouting: {
1233
- type: "object",
1234
- additionalProperties: {
1235
- $ref: "#/definitions/Application"
1236
- },
1237
- propertyNames: {
1238
- description: "The unique identifier for a Microfrontend Application. Must match the `name` field of the application's `package.json`."
1239
- }
1240
- },
1241
1289
  ChildConfig: {
1242
1290
  type: "object",
1243
1291
  properties: {
@@ -1251,24 +1299,12 @@ var schema_default = {
1251
1299
  options: {
1252
1300
  $ref: "#/definitions/Options"
1253
1301
  },
1254
- remotes: {
1255
- type: "object",
1256
- additionalProperties: {
1257
- $ref: "#/definitions/Application"
1258
- },
1259
- propertyNames: {
1260
- description: "The unique identifier for a Microfrontend Application. Must match the `name` field of the application's `package.json`."
1261
- },
1262
- 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."
1263
- },
1264
1302
  partOf: {
1265
1303
  type: "string",
1266
1304
  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."
1267
1305
  }
1268
1306
  },
1269
- required: [
1270
- "partOf"
1271
- ],
1307
+ required: ["partOf"],
1272
1308
  additionalProperties: false
1273
1309
  }
1274
1310
  }
@@ -1278,6 +1314,14 @@ var schema_default = {
1278
1314
  var SCHEMA = schema_default;
1279
1315
 
1280
1316
  // src/config/microfrontends/server/validation.ts
1317
+ function filterAjvErrors(errors) {
1318
+ if (!errors) {
1319
+ return [];
1320
+ }
1321
+ return errors.filter((error) => {
1322
+ return error.keyword === "additionalProperties" || error.keyword === "required";
1323
+ });
1324
+ }
1281
1325
  function validateSchema(configString) {
1282
1326
  const parsedConfig = parse3(configString);
1283
1327
  const ajv = new Ajv();
@@ -1285,7 +1329,10 @@ function validateSchema(configString) {
1285
1329
  const isValid = validate(parsedConfig);
1286
1330
  if (!isValid) {
1287
1331
  throw new MicrofrontendError(
1288
- `Invalid config: ${ajv.errorsText(validate.errors)}`,
1332
+ `Invalid microfrontends config:
1333
+ - ${ajv.errorsText(filterAjvErrors(validate.errors), { separator: "\n - " })}
1334
+
1335
+ See https://openapi.vercel.sh/microfrontends.json for the schema.`,
1289
1336
  { type: "config", subtype: "does_not_match_schema" }
1290
1337
  );
1291
1338
  }
@@ -1425,8 +1472,8 @@ var MicrofrontendsServer = class extends Microfrontends {
1425
1472
  throw new Error("Unable to infer");
1426
1473
  } catch (e) {
1427
1474
  throw new MicrofrontendError(
1428
- "Unable to infer microfrontends configuration",
1429
- { type: "config", subtype: "inference_failed" }
1475
+ "Unable to locate and parse microfrontends configuration",
1476
+ { cause: e, type: "config", subtype: "inference_failed" }
1430
1477
  );
1431
1478
  }
1432
1479
  }
@@ -1502,7 +1549,7 @@ var MicrofrontendsServer = class extends Microfrontends {
1502
1549
  const [defaultApplication] = Object.entries(validatedConfig.applications).filter(([, app]) => isDefaultApp(app)).map(([name]) => name);
1503
1550
  if (!defaultApplication) {
1504
1551
  throw new MicrofrontendError(
1505
- `No default application found. At least one application needs to be the default by omitting routing.`,
1552
+ "No default application found. At least one application needs to be the default by omitting routing.",
1506
1553
  { type: "config", subtype: "no_default_application" }
1507
1554
  );
1508
1555
  }