@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
@@ -75,7 +75,7 @@ function parseOverrides(cookies) {
75
75
  // src/config/errors.ts
76
76
  var MicrofrontendError = class extends Error {
77
77
  constructor(message, opts) {
78
- super(message);
78
+ super(message, { cause: opts?.cause });
79
79
  this.name = "MicrofrontendsError";
80
80
  this.source = opts?.source ?? "@vercel/microfrontends";
81
81
  this.type = opts?.type ?? "unknown";
@@ -267,7 +267,8 @@ var validateConfigPaths = (applicationConfigsById) => {
267
267
  if (isDefaultApp(app)) {
268
268
  continue;
269
269
  }
270
- for (const pathMatch of app.routing) {
270
+ const childApp = app;
271
+ for (const pathMatch of childApp.routing) {
271
272
  for (const path5 of pathMatch.paths) {
272
273
  const maybeError = validatePathExpression(path5);
273
274
  if (maybeError) {
@@ -287,33 +288,31 @@ var validateConfigPaths = (applicationConfigsById) => {
287
288
  }
288
289
  }
289
290
  const entries = Array.from(pathsByApplicationId.entries());
290
- entries.forEach(([path5, { applications: ids, matcher, applicationId }]) => {
291
+ for (const [path5, { applications: ids, matcher, applicationId }] of entries) {
291
292
  if (ids.length > 1) {
292
293
  errors.push(
293
294
  `Duplicate path "${path5}" for applications "${ids.join(", ")}"`
294
295
  );
295
296
  }
296
- entries.forEach(
297
- ([
298
- matchPath,
299
- { applications: matchIds, applicationId: matchApplicationId }
300
- ]) => {
301
- if (path5 === matchPath) {
302
- return;
303
- }
304
- if (applicationId === matchApplicationId) {
305
- return;
306
- }
307
- if (matcher.test(matchPath)) {
308
- const source = `"${path5}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
309
- const destination = `"${matchPath}" of application${matchIds.length > 0 ? "s" : ""} ${matchIds.join(", ")}`;
310
- errors.push(
311
- `Overlapping path detected between ${source} and ${destination}`
312
- );
313
- }
297
+ for (const [
298
+ matchPath,
299
+ { applications: matchIds, applicationId: matchApplicationId }
300
+ ] of entries) {
301
+ if (path5 === matchPath) {
302
+ continue;
314
303
  }
315
- );
316
- });
304
+ if (applicationId === matchApplicationId) {
305
+ continue;
306
+ }
307
+ if (matcher.test(matchPath)) {
308
+ const source = `"${path5}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
309
+ const destination = `"${matchPath}" of application${matchIds.length > 0 ? "s" : ""} ${matchIds.join(", ")}`;
310
+ errors.push(
311
+ `Overlapping path detected between ${source} and ${destination}`
312
+ );
313
+ }
314
+ }
315
+ }
317
316
  if (errors.length) {
318
317
  throw new MicrofrontendError(`Invalid paths: ${errors.join(", ")}`, {
319
318
  type: "config",
@@ -382,7 +381,7 @@ var validateConfigDefaultApplication = (applicationConfigsById) => {
382
381
  const numApplicationsWithoutRouting = numApplications - numApplicationsWithRouting;
383
382
  if (numApplicationsWithoutRouting === 0) {
384
383
  throw new MicrofrontendError(
385
- `No default application found. At least one application needs to be the default by omitting routing.`,
384
+ "No default application found. At least one application needs to be the default by omitting routing.",
386
385
  { type: "config", subtype: "no_default_application" }
387
386
  );
388
387
  }
@@ -428,47 +427,80 @@ function generatePortFromName({
428
427
  // src/config/microfrontends-config/isomorphic/host.ts
429
428
  var Host = class {
430
429
  constructor(hostConfig, options) {
431
- const { protocol = "https", host, port } = hostConfig;
432
- this.protocol = protocol;
433
- this.host = host;
434
- this.port = Host.getPort({ port, protocol: this.protocol });
430
+ if (typeof hostConfig === "string") {
431
+ ({
432
+ protocol: this.protocol,
433
+ host: this.host,
434
+ port: this.port
435
+ } = Host.parseUrl(hostConfig));
436
+ } else {
437
+ const { protocol = "https", host, port } = hostConfig;
438
+ this.protocol = protocol;
439
+ this.host = host;
440
+ this.port = port;
441
+ }
435
442
  this.local = options?.isLocal;
436
443
  }
437
- isLocal() {
438
- return this.local || this.host === "localhost" || this.host === "127.0.0.1";
439
- }
440
- static getPort({
441
- protocol,
442
- port
443
- }) {
444
- if (!port) {
445
- if (protocol === "http") {
446
- return 80;
447
- }
448
- return 443;
444
+ static parseUrl(url) {
445
+ let hostToParse = url;
446
+ if (!/^https?:\/\//.exec(hostToParse)) {
447
+ hostToParse = `https://${hostToParse}`;
448
+ }
449
+ const parsed = new URL(hostToParse);
450
+ if (!parsed.hostname) {
451
+ throw new Error(Host.getMicrofrontendsError(url, "requires a host"));
452
+ }
453
+ if (parsed.hash) {
454
+ throw new Error(
455
+ Host.getMicrofrontendsError(url, "cannot have a fragment")
456
+ );
457
+ }
458
+ if (parsed.username || parsed.password) {
459
+ throw new Error(
460
+ Host.getMicrofrontendsError(
461
+ url,
462
+ "cannot have authentication credentials (username and/or password)"
463
+ )
464
+ );
465
+ }
466
+ if (parsed.pathname !== "/") {
467
+ throw new Error(Host.getMicrofrontendsError(url, "cannot have a path"));
449
468
  }
450
- return port;
469
+ if (parsed.search) {
470
+ throw new Error(
471
+ Host.getMicrofrontendsError(url, "cannot have query parameters")
472
+ );
473
+ }
474
+ const protocol = parsed.protocol.slice(0, -1);
475
+ return {
476
+ protocol,
477
+ host: parsed.hostname,
478
+ port: parsed.port ? Number.parseInt(parsed.port) : void 0
479
+ };
451
480
  }
452
- isDefaultPort() {
453
- return this.port === Host.getPort({ protocol: this.protocol });
481
+ static getMicrofrontendsError(url, message) {
482
+ return `Microfrontends configuration error: the URL ${url} in your microfrontends.json ${message}.`;
454
483
  }
455
- toString(opts = {}) {
456
- const url = this.toUrl(opts);
484
+ isLocal() {
485
+ return this.local || this.host === "localhost" || this.host === "127.0.0.1";
486
+ }
487
+ toString() {
488
+ const url = this.toUrl();
457
489
  return url.toString().replace(/\/$/, "");
458
490
  }
459
- toUrl(opts = {}) {
460
- const { includeDefaultPort } = opts;
461
- const url = `${this.protocol}://${this.host}${this.isDefaultPort() && !includeDefaultPort ? "" : `:${this.port}`}`;
491
+ toUrl() {
492
+ const url = `${this.protocol}://${this.host}${this.port ? `:${this.port}` : ""}`;
462
493
  return new URL(url);
463
494
  }
464
495
  };
465
496
  var LocalHost = class extends Host {
466
497
  constructor({
467
498
  appName,
499
+ localPort,
468
500
  ...hostConfig
469
501
  }) {
470
502
  const host = hostConfig.host ?? "localhost";
471
- const port = hostConfig.port ?? generatePortFromName({ name: appName });
503
+ const port = localPort ?? hostConfig.port ?? generatePortFromName({ name: appName });
472
504
  const protocol = hostConfig.protocol ?? "http";
473
505
  super({ protocol, host, port });
474
506
  }
@@ -485,12 +517,17 @@ var Application = class {
485
517
  this.development = {
486
518
  local: new LocalHost({
487
519
  appName: name,
520
+ localPort: app.development?.localPort,
488
521
  ...app.development?.local
489
522
  }),
490
523
  fallback: app.development?.fallback ? new Host(app.development.fallback) : void 0
491
524
  };
492
- this.production = app.production ? new Host(app.production) : void 0;
493
- this.vercel = app.vercel;
525
+ if (app.development?.fallback) {
526
+ this.fallback = new Host(app.development.fallback);
527
+ } else if (app.production) {
528
+ this.fallback = new Host(app.production);
529
+ }
530
+ this.projectId = app.projectId ?? app.vercel?.projectId;
494
531
  this.overrides = overrides?.environment ? {
495
532
  environment: new Host(overrides.environment)
496
533
  } : void 0;
@@ -518,7 +555,16 @@ var DefaultApplication = class extends Application {
518
555
  isDefault: true
519
556
  });
520
557
  this.default = true;
521
- this.production = new Host(app.production);
558
+ const fallbackHost = app.development?.fallback ?? app.production;
559
+ if (fallbackHost === void 0) {
560
+ throw new Error(
561
+ "`app.production` or `app.development.fallback` must be set in the default application in microfrontends.json."
562
+ );
563
+ }
564
+ this.fallback = new Host(fallbackHost);
565
+ if (app.production) {
566
+ this.production = new Host(app.production);
567
+ }
522
568
  }
523
569
  getAssetPrefix() {
524
570
  return "";
@@ -588,7 +634,7 @@ var MicrofrontendConfigIsomorphic = class {
588
634
  }
589
635
  if (isMainConfig(config) && !this.defaultApplication) {
590
636
  throw new MicrofrontendError(
591
- `Could not find default application in microfrontends configuration`,
637
+ "Could not find default application in microfrontends configuration",
592
638
  {
593
639
  type: "application",
594
640
  subtype: "not_found"
@@ -664,11 +710,11 @@ var MicrofrontendConfigIsomorphic = class {
664
710
  return app;
665
711
  }
666
712
  getApplicationByProjectId(projectId) {
667
- if (this.defaultApplication?.vercel?.projectId === projectId) {
713
+ if (this.defaultApplication?.projectId === projectId) {
668
714
  return this.defaultApplication;
669
715
  }
670
716
  return Object.values(this.childApplications).find(
671
- (app) => app.vercel?.projectId === projectId
717
+ (app) => app.projectId === projectId
672
718
  );
673
719
  }
674
720
  /**
@@ -678,7 +724,7 @@ var MicrofrontendConfigIsomorphic = class {
678
724
  getDefaultApplication() {
679
725
  if (!this.defaultApplication) {
680
726
  throw new MicrofrontendError(
681
- `Could not find default application in microfrontends configuration`,
727
+ "Could not find default application in microfrontends configuration",
682
728
  {
683
729
  type: "application",
684
730
  subtype: "not_found"
@@ -691,7 +737,7 @@ var MicrofrontendConfigIsomorphic = class {
691
737
  * Returns the configured port for the local proxy
692
738
  */
693
739
  getLocalProxyPort() {
694
- return this.config.options?.localProxy?.port ?? DEFAULT_LOCAL_PROXY_PORT;
740
+ return this.config.options?.localProxyPort ?? this.config.options?.localProxy?.port ?? DEFAULT_LOCAL_PROXY_PORT;
695
741
  }
696
742
  /**
697
743
  * Serializes the class back to the Schema type.
@@ -765,7 +811,7 @@ var MicrofrontendMainConfig = class extends MicrofrontendConfigIsomorphic {
765
811
  }
766
812
  if (!defaultApplication) {
767
813
  throw new MicrofrontendError(
768
- `Could not find default application in microfrontends configuration`,
814
+ "Could not find default application in microfrontends configuration",
769
815
  {
770
816
  type: "application",
771
817
  subtype: "not_found"
@@ -1052,24 +1098,12 @@ var schema_default = {
1052
1098
  options: {
1053
1099
  $ref: "#/definitions/Options"
1054
1100
  },
1055
- remotes: {
1056
- type: "object",
1057
- additionalProperties: {
1058
- $ref: "#/definitions/Application"
1059
- },
1060
- propertyNames: {
1061
- description: "The unique identifier for a Microfrontend Application. Must match the `name` field of the application's `package.json`."
1062
- },
1063
- 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."
1064
- },
1065
1101
  applications: {
1066
1102
  $ref: "#/definitions/ApplicationRouting",
1067
1103
  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"
1068
1104
  }
1069
1105
  },
1070
- required: [
1071
- "applications"
1072
- ],
1106
+ required: ["applications"],
1073
1107
  additionalProperties: false
1074
1108
  },
1075
1109
  Options: {
@@ -1077,11 +1111,21 @@ var schema_default = {
1077
1111
  properties: {
1078
1112
  vercel: {
1079
1113
  $ref: "#/definitions/VercelOptions",
1080
- description: "Micro-Frontends wide options for Vercel."
1114
+ description: "Microfrontends wide options for Vercel.",
1115
+ deprecated: "This is being replaced by the `disableOverrides` field below."
1116
+ },
1117
+ disableOverrides: {
1118
+ type: "boolean",
1119
+ 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."
1081
1120
  },
1082
1121
  localProxy: {
1083
1122
  $ref: "#/definitions/LocalProxyOptions",
1084
- description: "Options for local proxy."
1123
+ description: "Options for local proxy.",
1124
+ deprecated: "This is being replaced by the `localProxyPort` field below."
1125
+ },
1126
+ localProxyPort: {
1127
+ type: "number",
1128
+ description: "The port number used by the local proxy server.\n\nThe default is `3024`."
1085
1129
  }
1086
1130
  },
1087
1131
  additionalProperties: false
@@ -1089,10 +1133,6 @@ var schema_default = {
1089
1133
  VercelOptions: {
1090
1134
  type: "object",
1091
1135
  properties: {
1092
- teamSlug: {
1093
- type: "string",
1094
- description: "Team slug for the Vercel team"
1095
- },
1096
1136
  disableOverrides: {
1097
1137
  type: "boolean",
1098
1138
  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."
@@ -1110,6 +1150,15 @@ var schema_default = {
1110
1150
  },
1111
1151
  additionalProperties: false
1112
1152
  },
1153
+ ApplicationRouting: {
1154
+ type: "object",
1155
+ additionalProperties: {
1156
+ $ref: "#/definitions/Application"
1157
+ },
1158
+ propertyNames: {
1159
+ description: "The unique identifier for a Microfrontend Application. Must match the `name` field of the application's `package.json`."
1160
+ }
1161
+ },
1113
1162
  Application: {
1114
1163
  anyOf: [
1115
1164
  {
@@ -1124,18 +1173,22 @@ var schema_default = {
1124
1173
  type: "object",
1125
1174
  properties: {
1126
1175
  vercel: {
1127
- $ref: "#/definitions/Vercel"
1176
+ $ref: "#/definitions/Vercel",
1177
+ deprecated: "This is being replaced by the `projectId` field below."
1178
+ },
1179
+ projectId: {
1180
+ type: "string",
1181
+ description: "Vercel project ID"
1128
1182
  },
1129
1183
  development: {
1130
1184
  $ref: "#/definitions/Development"
1131
1185
  },
1132
1186
  production: {
1133
- $ref: "#/definitions/HostConfig"
1187
+ $ref: "#/definitions/HostConfig",
1188
+ deprecated: "This is a duplicate of the `development.fallback` field and this will be removed soon."
1134
1189
  }
1135
1190
  },
1136
- required: [
1137
- "production"
1138
- ],
1191
+ required: ["production"],
1139
1192
  additionalProperties: false
1140
1193
  },
1141
1194
  Vercel: {
@@ -1146,20 +1199,30 @@ var schema_default = {
1146
1199
  description: "Vercel project ID"
1147
1200
  }
1148
1201
  },
1149
- required: [
1150
- "projectId"
1151
- ],
1202
+ required: ["projectId"],
1152
1203
  additionalProperties: false
1153
1204
  },
1154
1205
  Development: {
1155
1206
  type: "object",
1156
1207
  properties: {
1157
1208
  local: {
1158
- $ref: "#/definitions/LocalHostConfig"
1209
+ $ref: "#/definitions/LocalHostConfig",
1210
+ deprecated: "This is being replaced by the `localPort` field below."
1211
+ },
1212
+ localPort: {
1213
+ type: "number",
1214
+ 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."
1159
1215
  },
1160
1216
  fallback: {
1161
- $ref: "#/definitions/HostConfig",
1162
- 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."
1217
+ anyOf: [
1218
+ {
1219
+ $ref: "#/definitions/HostConfig"
1220
+ },
1221
+ {
1222
+ type: "string"
1223
+ }
1224
+ ],
1225
+ 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."
1163
1226
  },
1164
1227
  task: {
1165
1228
  type: "string",
@@ -1178,10 +1241,7 @@ var schema_default = {
1178
1241
  },
1179
1242
  protocol: {
1180
1243
  type: "string",
1181
- enum: [
1182
- "http",
1183
- "https"
1184
- ],
1244
+ enum: ["http", "https"],
1185
1245
  description: "The protocol to be used for the connection.\n- `http`: Hypertext Transfer Protocol (HTTP).\n- `https`: Secure Hypertext Transfer Protocol (HTTPS).\n\n*"
1186
1246
  },
1187
1247
  port: {
@@ -1195,10 +1255,7 @@ var schema_default = {
1195
1255
  properties: {
1196
1256
  protocol: {
1197
1257
  type: "string",
1198
- enum: [
1199
- "http",
1200
- "https"
1201
- ],
1258
+ enum: ["http", "https"],
1202
1259
  description: "The protocol to be used for the connection.\n- `http`: Hypertext Transfer Protocol (HTTP).\n- `https`: Secure Hypertext Transfer Protocol (HTTPS).\n\n*"
1203
1260
  },
1204
1261
  host: {
@@ -1210,16 +1267,19 @@ var schema_default = {
1210
1267
  description: "The port number to be used for the connection. Common values include `80` for HTTP and `443` for HTTPS."
1211
1268
  }
1212
1269
  },
1213
- required: [
1214
- "host"
1215
- ],
1270
+ required: ["host"],
1216
1271
  additionalProperties: false
1217
1272
  },
1218
1273
  ChildApplication: {
1219
1274
  type: "object",
1220
1275
  properties: {
1221
1276
  vercel: {
1222
- $ref: "#/definitions/Vercel"
1277
+ $ref: "#/definitions/Vercel",
1278
+ deprecated: "This is being replaced by the `projectId` field below."
1279
+ },
1280
+ projectId: {
1281
+ type: "string",
1282
+ description: "Vercel project ID"
1223
1283
  },
1224
1284
  development: {
1225
1285
  $ref: "#/definitions/Development"
@@ -1229,12 +1289,11 @@ var schema_default = {
1229
1289
  description: "Groups of path expressions that are routed to this application."
1230
1290
  },
1231
1291
  production: {
1232
- $ref: "#/definitions/HostConfig"
1292
+ $ref: "#/definitions/HostConfig",
1293
+ deprecated: "This is a duplicate of the `development.fallback` field and this will be removed soon."
1233
1294
  }
1234
1295
  },
1235
- required: [
1236
- "routing"
1237
- ],
1296
+ required: ["routing"],
1238
1297
  additionalProperties: false
1239
1298
  },
1240
1299
  Routing: {
@@ -1261,20 +1320,9 @@ var schema_default = {
1261
1320
  }
1262
1321
  }
1263
1322
  },
1264
- required: [
1265
- "paths"
1266
- ],
1323
+ required: ["paths"],
1267
1324
  additionalProperties: false
1268
1325
  },
1269
- ApplicationRouting: {
1270
- type: "object",
1271
- additionalProperties: {
1272
- $ref: "#/definitions/Application"
1273
- },
1274
- propertyNames: {
1275
- description: "The unique identifier for a Microfrontend Application. Must match the `name` field of the application's `package.json`."
1276
- }
1277
- },
1278
1326
  ChildConfig: {
1279
1327
  type: "object",
1280
1328
  properties: {
@@ -1288,24 +1336,12 @@ var schema_default = {
1288
1336
  options: {
1289
1337
  $ref: "#/definitions/Options"
1290
1338
  },
1291
- remotes: {
1292
- type: "object",
1293
- additionalProperties: {
1294
- $ref: "#/definitions/Application"
1295
- },
1296
- propertyNames: {
1297
- description: "The unique identifier for a Microfrontend Application. Must match the `name` field of the application's `package.json`."
1298
- },
1299
- 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."
1300
- },
1301
1339
  partOf: {
1302
1340
  type: "string",
1303
1341
  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."
1304
1342
  }
1305
1343
  },
1306
- required: [
1307
- "partOf"
1308
- ],
1344
+ required: ["partOf"],
1309
1345
  additionalProperties: false
1310
1346
  }
1311
1347
  }
@@ -1315,6 +1351,14 @@ var schema_default = {
1315
1351
  var SCHEMA = schema_default;
1316
1352
 
1317
1353
  // src/config/microfrontends/server/validation.ts
1354
+ function filterAjvErrors(errors) {
1355
+ if (!errors) {
1356
+ return [];
1357
+ }
1358
+ return errors.filter((error) => {
1359
+ return error.keyword === "additionalProperties" || error.keyword === "required";
1360
+ });
1361
+ }
1318
1362
  function validateSchema(configString) {
1319
1363
  const parsedConfig = (0, import_jsonc_parser3.parse)(configString);
1320
1364
  const ajv = new import_ajv.Ajv();
@@ -1322,7 +1366,10 @@ function validateSchema(configString) {
1322
1366
  const isValid = validate(parsedConfig);
1323
1367
  if (!isValid) {
1324
1368
  throw new MicrofrontendError(
1325
- `Invalid config: ${ajv.errorsText(validate.errors)}`,
1369
+ `Invalid microfrontends config:
1370
+ - ${ajv.errorsText(filterAjvErrors(validate.errors), { separator: "\n - " })}
1371
+
1372
+ See https://openapi.vercel.sh/microfrontends.json for the schema.`,
1326
1373
  { type: "config", subtype: "does_not_match_schema" }
1327
1374
  );
1328
1375
  }
@@ -1462,8 +1509,8 @@ var MicrofrontendsServer = class extends Microfrontends {
1462
1509
  throw new Error("Unable to infer");
1463
1510
  } catch (e) {
1464
1511
  throw new MicrofrontendError(
1465
- "Unable to infer microfrontends configuration",
1466
- { type: "config", subtype: "inference_failed" }
1512
+ "Unable to locate and parse microfrontends configuration",
1513
+ { cause: e, type: "config", subtype: "inference_failed" }
1467
1514
  );
1468
1515
  }
1469
1516
  }
@@ -1539,7 +1586,7 @@ var MicrofrontendsServer = class extends Microfrontends {
1539
1586
  const [defaultApplication] = Object.entries(validatedConfig.applications).filter(([, app]) => isDefaultApp(app)).map(([name]) => name);
1540
1587
  if (!defaultApplication) {
1541
1588
  throw new MicrofrontendError(
1542
- `No default application found. At least one application needs to be the default by omitting routing.`,
1589
+ "No default application found. At least one application needs to be the default by omitting routing.",
1543
1590
  { type: "config", subtype: "no_default_application" }
1544
1591
  );
1545
1592
  }
@@ -1668,12 +1715,10 @@ function getDomainFromEnvironment({
1668
1715
  if (mfeProjects.length === 0) {
1669
1716
  throw new Error("Missing related microfrontends project information");
1670
1717
  }
1671
- if (!app.vercel?.projectId) {
1718
+ if (!app.projectId) {
1672
1719
  throw new Error(`Missing applications[${app.name}].vercel.projectId`);
1673
1720
  }
1674
- const vercelProject = mfeProjects.find(
1675
- (p) => p.project.id === app.vercel?.projectId
1676
- );
1721
+ const vercelProject = mfeProjects.find((p) => p.project.id === app.projectId);
1677
1722
  if (!vercelProject) {
1678
1723
  throw new Error(
1679
1724
  `Missing related microfrontends project information for application "${app.name}"`
@@ -1707,9 +1752,11 @@ function getCurrentEnvironment() {
1707
1752
  const isProduction2 = process.env.VERCEL_ENV === "production";
1708
1753
  if (isDevelopment) {
1709
1754
  return { group: "development" };
1710
- } else if (isProduction2) {
1755
+ }
1756
+ if (isProduction2) {
1711
1757
  return { group: "production" };
1712
- } else if (isPreview) {
1758
+ }
1759
+ if (isPreview) {
1713
1760
  return { group: "preview" };
1714
1761
  }
1715
1762
  return { group: "custom", name: process.env.VERCEL_ENV };
@@ -1720,10 +1767,10 @@ function getDomainForCurrentEnvironment(config, appName, opts = {}) {
1720
1767
  return app.overrides.environment.toString();
1721
1768
  }
1722
1769
  const { group } = getCurrentEnvironment();
1723
- const productionHost = config.getDefaultApplication().production.toString();
1770
+ const fallbackHost = config.getDefaultApplication().fallback.toString();
1724
1771
  switch (group) {
1725
1772
  case "development": {
1726
- const domain = ["test", "development"].includes(process.env.NODE_ENV) ? app.development.local.toString() : productionHost;
1773
+ const domain = ["test", "development"].includes(process.env.NODE_ENV) ? app.development.local.toString() : fallbackHost;
1727
1774
  debugDomains(appName, "development", domain);
1728
1775
  return domain;
1729
1776
  }
@@ -1734,10 +1781,9 @@ function getDomainForCurrentEnvironment(config, appName, opts = {}) {
1734
1781
  return getDomainFromEnvironment({ app, target: "production" });
1735
1782
  }
1736
1783
  case "custom":
1737
- console.warn(
1738
- `Custom environments are not supported in getDomainForCurrentEnvironment`
1784
+ throw new Error(
1785
+ "Custom environments are not supported in getDomainForCurrentEnvironment"
1739
1786
  );
1740
- return productionHost;
1741
1787
  }
1742
1788
  }
1743
1789
 
@@ -1924,7 +1970,13 @@ function transform5(args) {
1924
1970
  // this deployments host
1925
1971
  ...process.env.VERCEL_URL ? [formatDomainForServerAction(process.env.VERCEL_URL)] : [],
1926
1972
  // default application host
1927
- formatDomainForServerAction(defaultApplication.production.toString()),
1973
+ formatDomainForServerAction(
1974
+ getDomainFromEnvironment({
1975
+ app: defaultApplication,
1976
+ target: "production"
1977
+ })
1978
+ ),
1979
+ formatDomainForServerAction(defaultApplication.fallback.toString()),
1928
1980
  // environment specific microfrontend hosts
1929
1981
  ...appsToAllow.flatMap((a) => [
1930
1982
  formatDomainForServerAction(