@vercel/microfrontends 0.9.0 → 0.10.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 (78) hide show
  1. package/README.md +2 -2
  2. package/dist/bin/cli.cjs +1483 -186
  3. package/dist/config/edge.cjs +47 -47
  4. package/dist/config/edge.cjs.map +1 -1
  5. package/dist/config/edge.d.ts +6 -6
  6. package/dist/config/edge.js +46 -46
  7. package/dist/config/edge.js.map +1 -1
  8. package/dist/config.cjs +66 -60
  9. package/dist/config.cjs.map +1 -1
  10. package/dist/config.d.ts +3 -3
  11. package/dist/config.js +65 -59
  12. package/dist/config.js.map +1 -1
  13. package/dist/{index-eff254d8.d.ts → index-05742bef.d.ts} +11 -22
  14. package/dist/{micro-frontend-config-42886104.d.ts → microfrontend-config-2425db74.d.ts} +12 -12
  15. package/dist/next/config.cjs +83 -77
  16. package/dist/next/config.cjs.map +1 -1
  17. package/dist/next/config.d.ts +3 -3
  18. package/dist/next/config.js +82 -76
  19. package/dist/next/config.js.map +1 -1
  20. package/dist/next/middleware.cjs +55 -55
  21. package/dist/next/middleware.cjs.map +1 -1
  22. package/dist/next/middleware.d.ts +11 -11
  23. package/dist/next/middleware.js +53 -53
  24. package/dist/next/middleware.js.map +1 -1
  25. package/dist/next/testing.cjs +79 -73
  26. package/dist/next/testing.cjs.map +1 -1
  27. package/dist/next/testing.d.ts +9 -9
  28. package/dist/next/testing.js +79 -73
  29. package/dist/next/testing.js.map +1 -1
  30. package/dist/overrides.cjs +9 -9
  31. package/dist/overrides.cjs.map +1 -1
  32. package/dist/overrides.d.ts +1 -1
  33. package/dist/overrides.js +9 -9
  34. package/dist/overrides.js.map +1 -1
  35. package/dist/types-13f3e535.d.ts +15 -0
  36. package/dist/v2/config.cjs +39 -39
  37. package/dist/v2/config.cjs.map +1 -1
  38. package/dist/v2/config.d.ts +2 -1
  39. package/dist/v2/config.js +38 -38
  40. package/dist/v2/config.js.map +1 -1
  41. package/dist/v2/microfrontends/server.cjs +102 -65
  42. package/dist/v2/microfrontends/server.cjs.map +1 -1
  43. package/dist/v2/microfrontends/server.d.ts +6 -1
  44. package/dist/v2/microfrontends/server.js +102 -65
  45. package/dist/v2/microfrontends/server.js.map +1 -1
  46. package/dist/v2/microfrontends.cjs +44 -44
  47. package/dist/v2/microfrontends.cjs.map +1 -1
  48. package/dist/v2/microfrontends.d.ts +5 -4
  49. package/dist/v2/microfrontends.js +44 -44
  50. package/dist/v2/microfrontends.js.map +1 -1
  51. package/dist/v2/next/client.cjs +1 -1
  52. package/dist/v2/next/client.cjs.map +1 -1
  53. package/dist/v2/next/client.js +1 -1
  54. package/dist/v2/next/client.js.map +1 -1
  55. package/dist/v2/next/config.cjs +120 -83
  56. package/dist/v2/next/config.cjs.map +1 -1
  57. package/dist/v2/next/config.d.ts +4 -4
  58. package/dist/v2/next/config.js +119 -82
  59. package/dist/v2/next/config.js.map +1 -1
  60. package/dist/v2/next/endpoints.cjs +5 -5
  61. package/dist/v2/next/endpoints.cjs.map +1 -1
  62. package/dist/v2/next/endpoints.js +5 -5
  63. package/dist/v2/next/endpoints.js.map +1 -1
  64. package/dist/v2/next/middleware.cjs +54 -54
  65. package/dist/v2/next/middleware.cjs.map +1 -1
  66. package/dist/v2/next/middleware.d.ts +8 -8
  67. package/dist/v2/next/middleware.js +52 -52
  68. package/dist/v2/next/middleware.js.map +1 -1
  69. package/dist/v2/overrides.cjs +75 -0
  70. package/dist/v2/overrides.cjs.map +1 -0
  71. package/dist/v2/overrides.d.ts +24 -0
  72. package/dist/v2/overrides.js +45 -0
  73. package/dist/v2/overrides.js.map +1 -0
  74. package/dist/validation.cjs +20 -20
  75. package/dist/validation.cjs.map +1 -1
  76. package/dist/validation.js +20 -20
  77. package/dist/validation.js.map +1 -1
  78. package/package.json +10 -3
package/dist/bin/cli.cjs CHANGED
@@ -29,7 +29,7 @@ var import_commander = require("commander");
29
29
  // package.json
30
30
  var package_default = {
31
31
  name: "@vercel/microfrontends",
32
- version: "0.9.0",
32
+ version: "0.10.0",
33
33
  private: false,
34
34
  description: "Defines configuration and utilities for micro-frontend development",
35
35
  repository: {
@@ -87,6 +87,10 @@ var package_default = {
87
87
  import: "./dist/v2/microfrontends.js",
88
88
  require: "./dist/v2/microfrontends.cjs"
89
89
  },
90
+ "./v2/overrides": {
91
+ import: "./dist/v2/overrides.js",
92
+ require: "./dist/v2/overrides.cjs"
93
+ },
90
94
  "./v2/microfrontends/server": {
91
95
  import: "./dist/v2/microfrontends/server.js",
92
96
  require: "./dist/v2/microfrontends/server.cjs"
@@ -129,6 +133,7 @@ var package_default = {
129
133
  "next/testing": ["./dist/next/testing.d.ts"],
130
134
  "v2/config": ["./dist/v2/config.d.ts"],
131
135
  "v2/microfrontends": ["./dist/v2/microfrontends.d.ts"],
136
+ "v2/overrides": ["./dist/v2/overrides.d.ts"],
132
137
  "v2/microfrontends/server": ["./dist/v2/microfrontends/server.d.ts"],
133
138
  "v2/schema": ["./dist/v2/schema.d.ts"],
134
139
  "v2/next/config": ["./dist/v2/next/config.d.ts"],
@@ -175,7 +180,7 @@ var package_default = {
175
180
  "@vercel-private/conformance": "^1.12.2-canary.0",
176
181
  jest: "^29.7.0",
177
182
  "jest-environment-jsdom": "29.2.2",
178
- next: "15.0.4-canary.17",
183
+ next: "15.0.4-canary.26",
179
184
  react: "19.0.0-rc-380f5d67-20241113",
180
185
  "react-dom": "19.0.0-rc-380f5d67-20241113",
181
186
  "ts-json-schema-generator": "^1.1.2",
@@ -185,7 +190,7 @@ var package_default = {
185
190
  webpack: "5"
186
191
  },
187
192
  peerDependencies: {
188
- next: "15.0.4-canary.17",
193
+ next: "15.0.4-canary.26",
189
194
  react: "19.0.0-rc-380f5d67-20241113",
190
195
  "react-dom": "19.0.0-rc-380f5d67-20241113"
191
196
  },
@@ -197,14 +202,15 @@ var package_default = {
197
202
  // src/bin/local-proxy.ts
198
203
  var http = __toESM(require("http"), 1);
199
204
  var https = __toESM(require("https"), 1);
205
+ var import_types2 = require("util/types");
200
206
  var import_cookie = require("cookie");
201
- var import_path_to_regexp2 = require("path-to-regexp");
207
+ var import_path_to_regexp4 = require("path-to-regexp");
202
208
  var import_http_proxy = __toESM(require("http-proxy"), 1);
203
209
 
204
210
  // src/config/types.ts
205
211
  var isDefaultApplicationConfig = (app) => app.default && typeof app.routing === "undefined";
206
212
 
207
- // src/config/micro-frontend-config.ts
213
+ // src/config/microfrontend-config.ts
208
214
  var import_node_fs2 = __toESM(require("fs"), 1);
209
215
 
210
216
  // src/config-v2/microfrontends/server/utils/get-output-file-path.ts
@@ -232,14 +238,14 @@ function getOutputFilePath() {
232
238
  }
233
239
 
234
240
  // src/config/errors.ts
235
- var MicroFrontendError = class extends Error {
241
+ var MicrofrontendError = class extends Error {
236
242
  constructor(message, opts) {
237
243
  super(message);
238
- this.name = "MicroFrontendsError";
239
- this.source = (opts == null ? void 0 : opts.source) ?? "@vercel/micro-frontends";
244
+ this.name = "MicrofrontendsError";
245
+ this.source = (opts == null ? void 0 : opts.source) ?? "@vercel/microfrontends";
240
246
  this.type = (opts == null ? void 0 : opts.type) ?? "unknown";
241
247
  this.subtype = opts == null ? void 0 : opts.subtype;
242
- Error.captureStackTrace(this, MicroFrontendError);
248
+ Error.captureStackTrace(this, MicrofrontendError);
243
249
  }
244
250
  isKnown() {
245
251
  return this.type !== "unknown";
@@ -248,13 +254,13 @@ var MicroFrontendError = class extends Error {
248
254
  return !this.isKnown();
249
255
  }
250
256
  /**
251
- * Converts an error to a MicroFrontendsError.
257
+ * Converts an error to a MicrofrontendsError.
252
258
  * @param original - The original error to convert.
253
- * @returns The converted MicroFrontendsError.
259
+ * @returns The converted MicrofrontendsError.
254
260
  */
255
261
  static convert(original, opts) {
256
262
  if (opts == null ? void 0 : opts.fileName) {
257
- const err = MicroFrontendError.convertFSError(original, opts.fileName);
263
+ const err = MicrofrontendError.convertFSError(original, opts.fileName);
258
264
  if (err) {
259
265
  return err;
260
266
  }
@@ -262,25 +268,25 @@ var MicroFrontendError = class extends Error {
262
268
  if (original.message.includes(
263
269
  "Code generation from strings disallowed for this context"
264
270
  )) {
265
- return new MicroFrontendError(original.message, {
271
+ return new MicrofrontendError(original.message, {
266
272
  type: "config",
267
273
  subtype: "unsupported_validation_env",
268
274
  source: "ajv"
269
275
  });
270
276
  }
271
- return new MicroFrontendError(original.message);
277
+ return new MicrofrontendError(original.message);
272
278
  }
273
279
  static convertFSError(original, fileName) {
274
280
  if (original instanceof Error && "code" in original) {
275
281
  if (original.code === "ENOENT") {
276
- return new MicroFrontendError(`Could not find "${fileName}"`, {
282
+ return new MicrofrontendError(`Could not find "${fileName}"`, {
277
283
  type: "config",
278
284
  subtype: "unable_to_read_file",
279
285
  source: "fs"
280
286
  });
281
287
  }
282
288
  if (original.code === "EACCES") {
283
- return new MicroFrontendError(
289
+ return new MicrofrontendError(
284
290
  `Permission denied while accessing "${fileName}"`,
285
291
  {
286
292
  type: "config",
@@ -291,7 +297,7 @@ var MicroFrontendError = class extends Error {
291
297
  }
292
298
  }
293
299
  if (original instanceof SyntaxError) {
294
- return new MicroFrontendError(
300
+ return new MicrofrontendError(
295
301
  `Failed to parse "${fileName}": Invalid JSON format.`,
296
302
  {
297
303
  type: "config",
@@ -303,23 +309,23 @@ var MicroFrontendError = class extends Error {
303
309
  return null;
304
310
  }
305
311
  /**
306
- * Handles an unknown error and returns a MicroFrontendsError instance.
312
+ * Handles an unknown error and returns a MicrofrontendsError instance.
307
313
  * @param err - The error to handle.
308
- * @returns A MicroFrontendsError instance.
314
+ * @returns A MicrofrontendsError instance.
309
315
  */
310
316
  static handle(err, opts) {
311
- if (err instanceof MicroFrontendError) {
317
+ if (err instanceof MicrofrontendError) {
312
318
  return err;
313
319
  }
314
320
  if (err instanceof Error) {
315
- return MicroFrontendError.convert(err, opts);
321
+ return MicrofrontendError.convert(err, opts);
316
322
  }
317
323
  if (typeof err === "object" && err !== null) {
318
324
  if ("message" in err && typeof err.message === "string") {
319
- return MicroFrontendError.convert(new Error(err.message), opts);
325
+ return MicrofrontendError.convert(new Error(err.message), opts);
320
326
  }
321
327
  }
322
- return new MicroFrontendError("An unknown error occurred");
328
+ return new MicrofrontendError("An unknown error occurred");
323
329
  }
324
330
  };
325
331
 
@@ -402,27 +408,27 @@ var _Overrides = class {
402
408
  });
403
409
  return overridesConfig;
404
410
  }
405
- static validOverrideDomainsForZone(microFrontendConfig, zone) {
411
+ static validOverrideDomainsForZone(microfrontendConfig, zone) {
406
412
  var _a, _b, _c, _d, _e;
407
- const projectName = (_a = microFrontendConfig.getZone(zone).vercel) == null ? void 0 : _a.projectName;
413
+ const projectName = (_a = microfrontendConfig.getZone(zone).vercel) == null ? void 0 : _a.projectName;
408
414
  if (!projectName) {
409
- return [microFrontendConfig.getZone(zone).production.host];
415
+ return [microfrontendConfig.getZone(zone).production.host];
410
416
  }
411
417
  const parsedProjectName = makeUrlSafe(projectName);
412
- const previewDeploymentSuffix = (_c = (_b = microFrontendConfig.options) == null ? void 0 : _b.vercel) == null ? void 0 : _c.previewDeploymentSuffix;
413
- const teamSlug = (_e = (_d = microFrontendConfig.options) == null ? void 0 : _d.vercel) == null ? void 0 : _e.teamSlug;
418
+ const previewDeploymentSuffix = (_c = (_b = microfrontendConfig.options) == null ? void 0 : _b.vercel) == null ? void 0 : _c.previewDeploymentSuffix;
419
+ const teamSlug = (_e = (_d = microfrontendConfig.options) == null ? void 0 : _d.vercel) == null ? void 0 : _e.teamSlug;
414
420
  if (!teamSlug && !previewDeploymentSuffix) {
415
- return [microFrontendConfig.getZone(zone).production.host];
421
+ return [microfrontendConfig.getZone(zone).production.host];
416
422
  }
417
423
  const suffix = previewDeploymentSuffix ? `.${previewDeploymentSuffix}` : `-${teamSlug}.vercel.app`;
418
424
  return [
419
425
  `${parsedProjectName}-git-([a-zA-Z0-9-]+)${suffix}`,
420
- microFrontendConfig.getZone(zone).production.host
426
+ microfrontendConfig.getZone(zone).production.host
421
427
  ];
422
428
  }
423
- static validateOverrideDomain(microFrontendConfig, zone, domain) {
429
+ static validateOverrideDomain(microfrontendConfig, zone, domain) {
424
430
  return new RegExp(
425
- `^${_Overrides.validOverrideDomainsForZone(microFrontendConfig, zone).join(
431
+ `^${_Overrides.validOverrideDomainsForZone(microfrontendConfig, zone).join(
426
432
  "|"
427
433
  )}$`
428
434
  ).test(domain);
@@ -504,7 +510,7 @@ var Application = class {
504
510
  static validate(name, app) {
505
511
  var _a, _b, _c, _d, _e;
506
512
  if (((_b = (_a = app.routing) == null ? void 0 : _a.assetPrefix) == null ? void 0 : _b.startsWith("/")) || ((_d = (_c = app.routing) == null ? void 0 : _c.assetPrefix) == null ? void 0 : _d.endsWith("/"))) {
507
- throw new MicroFrontendError(
513
+ throw new MicrofrontendError(
508
514
  `Invalid assetPrefix for application "${name}". Must not start or end with a slash.`,
509
515
  { type: "zone", subtype: "invalid_asset_prefix" }
510
516
  );
@@ -515,13 +521,13 @@ var Application = class {
515
521
  continue;
516
522
  }
517
523
  if (p.endsWith("/")) {
518
- throw new MicroFrontendError(
524
+ throw new MicrofrontendError(
519
525
  `Invalid path for application "${name}". ${p} must not end with a slash.`,
520
526
  { type: "zone", subtype: "invalid_path" }
521
527
  );
522
528
  }
523
529
  if (!p.startsWith("/")) {
524
- throw new MicroFrontendError(
530
+ throw new MicrofrontendError(
525
531
  `Invalid path for application "${name}". ${p} must start with a slash.`,
526
532
  { type: "zone", subtype: "invalid_path" }
527
533
  );
@@ -555,10 +561,10 @@ var Application = class {
555
561
  }
556
562
  };
557
563
 
558
- // src/config/common/micro-frontend-config.ts
564
+ // src/config/common/microfrontend-config.ts
559
565
  var SUPPORTED_VERSIONS = ["1"];
560
566
  var DEFAULT_LOCAL_PROXY_PORT = 3024;
561
- var MicroFrontendConfigCommon = class {
567
+ var MicrofrontendConfigCommon = class {
562
568
  constructor({
563
569
  config,
564
570
  overrides
@@ -566,7 +572,7 @@ var MicroFrontendConfigCommon = class {
566
572
  this.zones = {};
567
573
  var _a, _b, _c;
568
574
  if (!SUPPORTED_VERSIONS.includes(config.version)) {
569
- throw new MicroFrontendError(
575
+ throw new MicrofrontendError(
570
576
  `Unsupported version: ${config.version}. Supported versions are: ${SUPPORTED_VERSIONS.join(
571
577
  ", "
572
578
  )}`,
@@ -594,7 +600,7 @@ var MicroFrontendConfigCommon = class {
594
600
  static getConfigFromEnv() {
595
601
  const config = process.env.MFE_CONFIG;
596
602
  if (!config) {
597
- throw new MicroFrontendError(`Missing "MFE_CONFIG" in environment.`, {
603
+ throw new MicrofrontendError(`Missing "MFE_CONFIG" in environment.`, {
598
604
  type: "config",
599
605
  subtype: "not_found_in_env"
600
606
  });
@@ -613,8 +619,8 @@ var MicroFrontendConfigCommon = class {
613
619
  getZone(name) {
614
620
  const zone = this.zones[name];
615
621
  if (!zone) {
616
- throw new MicroFrontendError(
617
- `Could not find micro-frontends configuration for application "${name}"`,
622
+ throw new MicrofrontendError(
623
+ `Could not find microfrontends configuration for application "${name}"`,
618
624
  {
619
625
  type: "zone",
620
626
  subtype: "not_found"
@@ -634,8 +640,8 @@ var MicroFrontendConfigCommon = class {
634
640
  getDefaultZone() {
635
641
  const zone = Object.values(this.zones).find((z) => z.default);
636
642
  if (!zone) {
637
- throw new MicroFrontendError(
638
- `Could not find default zone in micro-frontends configuration`,
643
+ throw new MicrofrontendError(
644
+ `Could not find default zone in microfrontends configuration`,
639
645
  {
640
646
  type: "zone",
641
647
  subtype: "not_found"
@@ -687,8 +693,8 @@ var MicroFrontendConfigCommon = class {
687
693
  };
688
694
  }
689
695
  write(_) {
690
- throw new MicroFrontendError(
691
- `Writing to file to disk requires using an instance of "MicroFrontendConfig".`,
696
+ throw new MicrofrontendError(
697
+ `Writing to file to disk requires using an instance of "MicrofrontendConfig".`,
692
698
  { type: "config", subtype: "unsupported_operation" }
693
699
  );
694
700
  }
@@ -1049,7 +1055,7 @@ var validateSchema = (configString) => {
1049
1055
  const validate = ajv.compile(SCHEMA);
1050
1056
  const isValid = validate(parsedConfig);
1051
1057
  if (!isValid) {
1052
- throw new MicroFrontendError(
1058
+ throw new MicrofrontendError(
1053
1059
  `Invalid config: ${ajv.errorsText(validate.errors)}`,
1054
1060
  { type: "config", subtype: "does_not_match_schema" }
1055
1061
  );
@@ -1059,7 +1065,7 @@ var validateSchema = (configString) => {
1059
1065
  var SUPPORTED_VERSIONS2 = ["1"];
1060
1066
  var validateVersion = (version) => {
1061
1067
  if (!SUPPORTED_VERSIONS2.includes(version)) {
1062
- throw new MicroFrontendError(
1068
+ throw new MicrofrontendError(
1063
1069
  `Unsupported version: ${version}. Supported versions are: ${SUPPORTED_VERSIONS2.join(
1064
1070
  ", "
1065
1071
  )}`,
@@ -1092,7 +1098,7 @@ function validateMainPath(applicationConfigsById) {
1092
1098
  return !matcher.test(defaultRoute);
1093
1099
  });
1094
1100
  if (!isValid) {
1095
- throw new MicroFrontendError(
1101
+ throw new MicrofrontendError(
1096
1102
  `default route "${defaultRoute}" cannot be used for "${id}" because it is matched by "${otherId}"`,
1097
1103
  { type: "config", subtype: "invalid_main_path" }
1098
1104
  );
@@ -1105,7 +1111,7 @@ function validateMainPath(applicationConfigsById) {
1105
1111
  return matcher.test(defaultRoute);
1106
1112
  });
1107
1113
  if (!isValid) {
1108
- throw new MicroFrontendError(
1114
+ throw new MicrofrontendError(
1109
1115
  `default route "${defaultRoute}" is not included by the routing config for application "${id}"`,
1110
1116
  { type: "config", subtype: "invalid_main_path" }
1111
1117
  );
@@ -1168,7 +1174,7 @@ var validatePaths = (applicationConfigsById) => {
1168
1174
  );
1169
1175
  });
1170
1176
  if (errors.length) {
1171
- throw new MicroFrontendError(`Invalid paths: ${errors.join(", ")}`, {
1177
+ throw new MicrofrontendError(`Invalid paths: ${errors.join(", ")}`, {
1172
1178
  type: "config",
1173
1179
  subtype: "conflicting_paths"
1174
1180
  });
@@ -1202,13 +1208,13 @@ function validatePathExpression(path3) {
1202
1208
  var validateDefaults = (applicationConfigsById) => {
1203
1209
  const defaultApplicationIds = Object.entries(applicationConfigsById).reduce((acc, [id, app]) => app.default ? [...acc, id] : acc, []);
1204
1210
  if (defaultApplicationIds.length === 0) {
1205
- throw new MicroFrontendError(
1211
+ throw new MicrofrontendError(
1206
1212
  `No default application found. At least one application must be marked as default.`,
1207
1213
  { type: "config", subtype: "no_default_application" }
1208
1214
  );
1209
1215
  }
1210
1216
  if (defaultApplicationIds.length > 1) {
1211
- throw new MicroFrontendError(
1217
+ throw new MicrofrontendError(
1212
1218
  `Only one default application is allowed. Found ${defaultApplicationIds.join(", ")}.`,
1213
1219
  { type: "config", subtype: "multiple_default_applications" }
1214
1220
  );
@@ -1220,7 +1226,7 @@ var validateOptions = (options) => {
1220
1226
  if (!/^[a-zA-Z]{2,}\.[a-zA-Z]{2,}$/.test(
1221
1227
  options.vercel.previewDeploymentSuffix
1222
1228
  )) {
1223
- throw new MicroFrontendError(
1229
+ throw new MicrofrontendError(
1224
1230
  `Invalid preview deployment suffix: ${options.vercel.previewDeploymentSuffix}. Should have be formatted like "vercel.app".`,
1225
1231
  { type: "config", subtype: "invalid_preview_deployment_suffix" }
1226
1232
  );
@@ -1275,9 +1281,15 @@ function convertV1ConfigToV2Config(config, fromApp) {
1275
1281
  )
1276
1282
  };
1277
1283
  }
1284
+ const defaultApplication = Object.entries(config.applications).find(
1285
+ ([, application]) => application.default
1286
+ );
1287
+ if (!defaultApplication) {
1288
+ throw new Error("No default application found in the config");
1289
+ }
1278
1290
  return {
1279
1291
  ...common,
1280
- partOf: fromApp
1292
+ partOf: defaultApplication[0]
1281
1293
  };
1282
1294
  }
1283
1295
 
@@ -1292,8 +1304,8 @@ function writeFile(outputPath, config, prettify) {
1292
1304
  );
1293
1305
  }
1294
1306
 
1295
- // src/config/micro-frontend-config.ts
1296
- var MicroFrontendConfig = class extends MicroFrontendConfigCommon {
1307
+ // src/config/microfrontend-config.ts
1308
+ var MicrofrontendConfig = class extends MicrofrontendConfigCommon {
1297
1309
  static validate(configString) {
1298
1310
  const config = validateSchema(configString);
1299
1311
  validateVersion(config.version);
@@ -1306,9 +1318,9 @@ var MicroFrontendConfig = class extends MicroFrontendConfigCommon {
1306
1318
  static fromEnv({
1307
1319
  cookies
1308
1320
  }) {
1309
- return new MicroFrontendConfigCommon({
1310
- config: MicroFrontendConfig.validate(
1311
- MicroFrontendConfigCommon.getConfigFromEnv()
1321
+ return new MicrofrontendConfigCommon({
1322
+ config: MicrofrontendConfig.validate(
1323
+ MicrofrontendConfigCommon.getConfigFromEnv()
1312
1324
  ),
1313
1325
  overrides: Overrides.parseOverrides(cookies)
1314
1326
  });
@@ -1318,11 +1330,11 @@ var MicroFrontendConfig = class extends MicroFrontendConfigCommon {
1318
1330
  }) {
1319
1331
  try {
1320
1332
  const config = import_node_fs2.default.readFileSync(filePath, "utf-8");
1321
- return new MicroFrontendConfig({
1322
- config: MicroFrontendConfig.validate(config)
1333
+ return new MicrofrontendConfig({
1334
+ config: MicrofrontendConfig.validate(config)
1323
1335
  });
1324
1336
  } catch (e) {
1325
- throw MicroFrontendError.handle(e, {
1337
+ throw MicrofrontendError.handle(e, {
1326
1338
  fileName: filePath
1327
1339
  });
1328
1340
  }
@@ -1345,150 +1357,1435 @@ var MicroFrontendConfig = class extends MicroFrontendConfigCommon {
1345
1357
  }
1346
1358
  };
1347
1359
 
1348
- // src/bin/local-proxy.ts
1349
- var MFE_DEBUG = process.env.MFE_DEBUG;
1350
- var mfeDebug = (message) => {
1351
- if (MFE_DEBUG === "true" || MFE_DEBUG === "1") {
1352
- console.log(message);
1360
+ // src/config-v2/schema/utils/is-default-app.ts
1361
+ function isDefaultApp(a) {
1362
+ return !("routing" in a);
1363
+ }
1364
+
1365
+ // src/config-v2/errors.ts
1366
+ var MicrofrontendError2 = class extends Error {
1367
+ constructor(message, opts) {
1368
+ super(message);
1369
+ this.name = "MicrofrontendsError";
1370
+ this.source = (opts == null ? void 0 : opts.source) ?? "@vercel/microfrontends";
1371
+ this.type = (opts == null ? void 0 : opts.type) ?? "unknown";
1372
+ this.subtype = opts == null ? void 0 : opts.subtype;
1373
+ Error.captureStackTrace(this, MicrofrontendError2);
1353
1374
  }
1354
- };
1355
- var LocalProxy = class {
1356
- constructor(config, {
1357
- localApps,
1358
- proxyPort
1359
- }) {
1360
- this.config = config;
1361
- this.localApps = localApps;
1362
- this.proxyPort = proxyPort ?? this.config.getLocalProxyPort();
1363
- this.proxy = import_http_proxy.default.createProxyServer({ secure: true });
1364
- this.proxy.on("error", (err, req, res) => {
1365
- if (res instanceof http.ServerResponse) {
1366
- res.writeHead(500, {
1367
- "Content-Type": "text/plain"
1368
- });
1369
- }
1370
- const target = this.getTarget(req);
1371
- res.end(
1372
- `Error proxying request to ${target.application}. Is the server running locally on port ${target.port}?`
1373
- );
1374
- console.error(`Error proxying request for ${target.application}: `, err);
1375
- });
1375
+ isKnown() {
1376
+ return this.type !== "unknown";
1376
1377
  }
1377
- static fromFile(filePath, {
1378
- localApps,
1379
- proxyPort
1380
- }) {
1381
- const config = MicroFrontendConfig.fromFile({ filePath });
1382
- return new LocalProxy(config, { localApps, proxyPort });
1378
+ isUnknown() {
1379
+ return !this.isKnown();
1383
1380
  }
1384
- getDefaultHost(config) {
1385
- const defaultApp = config.getDefaultZone();
1386
- return this.getApplicationTarget(defaultApp);
1381
+ /**
1382
+ * Converts an error to a MicrofrontendsError.
1383
+ * @param original - The original error to convert.
1384
+ * @returns The converted MicrofrontendsError.
1385
+ */
1386
+ static convert(original, opts) {
1387
+ if (opts == null ? void 0 : opts.fileName) {
1388
+ const err = MicrofrontendError2.convertFSError(original, opts.fileName);
1389
+ if (err) {
1390
+ return err;
1391
+ }
1392
+ }
1393
+ if (original.message.includes(
1394
+ "Code generation from strings disallowed for this context"
1395
+ )) {
1396
+ return new MicrofrontendError2(original.message, {
1397
+ type: "config",
1398
+ subtype: "unsupported_validation_env",
1399
+ source: "ajv"
1400
+ });
1401
+ }
1402
+ return new MicrofrontendError2(original.message);
1387
1403
  }
1388
- getApplicationTarget(application) {
1389
- var _a, _b;
1390
- const useDev = this.localApps.includes(application.name);
1391
- let host = useDev ? application.development.local : application.production;
1392
- if ((_b = (_a = application.overrides) == null ? void 0 : _a.environment) == null ? void 0 : _b.host) {
1393
- host = application.overrides.environment;
1404
+ static convertFSError(original, fileName) {
1405
+ if (original instanceof Error && "code" in original) {
1406
+ if (original.code === "ENOENT") {
1407
+ return new MicrofrontendError2(`Could not find "${fileName}"`, {
1408
+ type: "config",
1409
+ subtype: "unable_to_read_file",
1410
+ source: "fs"
1411
+ });
1412
+ }
1413
+ if (original.code === "EACCES") {
1414
+ return new MicrofrontendError2(
1415
+ `Permission denied while accessing "${fileName}"`,
1416
+ {
1417
+ type: "config",
1418
+ subtype: "invalid_permissions",
1419
+ source: "fs"
1420
+ }
1421
+ );
1422
+ }
1394
1423
  }
1395
- const protocol = host.protocol;
1396
- const hostname = host.host;
1397
- const port = host.port;
1398
- return {
1399
- url: host.toUrl(),
1400
- protocol,
1401
- hostname,
1402
- port,
1403
- application: application.name
1404
- };
1424
+ if (original instanceof SyntaxError) {
1425
+ return new MicrofrontendError2(
1426
+ `Failed to parse "${fileName}": Invalid JSON format.`,
1427
+ {
1428
+ type: "config",
1429
+ subtype: "invalid_syntax",
1430
+ source: "fs"
1431
+ }
1432
+ );
1433
+ }
1434
+ return null;
1405
1435
  }
1406
1436
  /**
1407
- * To enable preview deployments in localhost, we need to intercept some auth requests
1408
- * and make sure they proxy to the correct domain. The toolbar will initiate the `vercel-auth-redirect`
1409
- * with a `_host_override` param so that we can properly trigger the redirect flow for the
1410
- * protected host.
1437
+ * Handles an unknown error and returns a MicrofrontendsError instance.
1438
+ * @param err - The error to handle.
1439
+ * @returns A MicrofrontendsError instance.
1411
1440
  */
1412
- getAuthTarget(request2, config) {
1413
- var _a, _b;
1414
- const url = new URL(request2.url ?? "", `http://${request2.headers.host}`);
1415
- const isAuthRedirect = (_a = request2.url) == null ? void 0 : _a.startsWith(
1416
- "/.well-known/vercel-auth-redirect"
1417
- );
1418
- const isSsoRedirect = (_b = request2.url) == null ? void 0 : _b.startsWith("/sso-api");
1419
- const isJWTRedirect = url.searchParams.has("_vercel_jwt");
1420
- const defaultHost = this.getDefaultHost(config);
1421
- let hostname = null;
1422
- let path3 = request2.url;
1423
- if (isAuthRedirect) {
1424
- hostname = url.searchParams.get("_host_override");
1425
- }
1426
- if (isSsoRedirect) {
1427
- hostname = "vercel.com";
1441
+ static handle(err, opts) {
1442
+ if (err instanceof MicrofrontendError2) {
1443
+ return err;
1428
1444
  }
1429
- if (isJWTRedirect) {
1430
- hostname = url.searchParams.get("_host_override");
1431
- url.searchParams.delete("_host_override");
1432
- path3 = `${url.pathname}${url.search}`;
1445
+ if (err instanceof Error) {
1446
+ return MicrofrontendError2.convert(err, opts);
1433
1447
  }
1434
- if (!hostname) {
1435
- return void 0;
1448
+ if (typeof err === "object" && err !== null) {
1449
+ if ("message" in err && typeof err.message === "string") {
1450
+ return MicrofrontendError2.convert(new Error(err.message), opts);
1451
+ }
1436
1452
  }
1437
- return { ...defaultHost, path: path3, hostname, protocol: "https", port: 443 };
1453
+ return new MicrofrontendError2("An unknown error occurred");
1438
1454
  }
1439
- getTarget(request2) {
1440
- const cookies = (0, import_cookie.parse)(request2.headers.cookie || "");
1441
- const cookieOverrides = Overrides.parseOverrides(
1442
- Object.entries(cookies).map(([name, value]) => ({ name, value }))
1455
+ };
1456
+
1457
+ // src/config-v2/microfrontends-config/isomorphic/validation.ts
1458
+ var import_path_to_regexp2 = require("path-to-regexp");
1459
+ var SUPPORTED_VERSIONS3 = ["2"];
1460
+ var validateConfigVersion = (version) => {
1461
+ if (!SUPPORTED_VERSIONS3.includes(version)) {
1462
+ throw new MicrofrontendError2(
1463
+ `Unsupported version: ${version}. Supported versions are: ${SUPPORTED_VERSIONS3.join(
1464
+ ", "
1465
+ )}`,
1466
+ { type: "config", subtype: "unsupported_version" }
1443
1467
  );
1444
- const hasOverrides = Object.keys(cookieOverrides.applications).length > 0;
1445
- const config = hasOverrides ? new MicroFrontendConfig({
1446
- config: this.config.serialize().config,
1447
- overrides: cookieOverrides
1448
- }) : this.config;
1449
- const path3 = request2.url;
1450
- if (!path3) {
1451
- return this.getDefaultHost(config);
1452
- }
1453
- const authTarget = this.getAuthTarget(request2, config);
1454
- if (authTarget) {
1455
- return authTarget;
1468
+ }
1469
+ };
1470
+ var validateConfigPaths = (applicationConfigsById) => {
1471
+ if (!applicationConfigsById) {
1472
+ return;
1473
+ }
1474
+ const pathsByApplicationId = /* @__PURE__ */ new Map();
1475
+ const errors = [];
1476
+ for (const [id, app] of Object.entries(applicationConfigsById)) {
1477
+ if (isDefaultApp(app)) {
1478
+ continue;
1456
1479
  }
1457
- const url = new URL(`http://example.com${path3}`);
1458
- const pathname = url.pathname;
1459
- for (const application of Object.values(config.getAllApplications())) {
1460
- if (application.routing) {
1461
- for (const group of application.routing.matches) {
1462
- for (const childPath of group.paths) {
1463
- const regexp = (0, import_path_to_regexp2.pathToRegexp)(childPath);
1464
- if (regexp.test(pathname)) {
1465
- const target = this.getApplicationTarget(application);
1466
- mfeDebug(
1467
- `routing ${path3} to '${target.application}' at ${target.hostname}`
1468
- );
1469
- return { path: path3, ...target };
1470
- }
1471
- }
1472
- if (application.routing.assetPrefix) {
1473
- const pattern = (0, import_path_to_regexp2.pathToRegexp)(
1474
- `/${application.routing.assetPrefix}/:path+`
1480
+ for (const pathMatch of app.routing) {
1481
+ for (const path3 of pathMatch.paths) {
1482
+ const tokens = (0, import_path_to_regexp2.parse)(path3);
1483
+ for (const token of tokens.slice(0, -1)) {
1484
+ if (typeof token !== "string") {
1485
+ errors.push(
1486
+ `Path ${path3} may only have a :wildcard in the last path component`
1475
1487
  );
1476
- if (pattern.test(pathname)) {
1477
- const target = this.getApplicationTarget(application);
1478
- mfeDebug(
1479
- `routing ${path3} to '${target.application}' at ${target.hostname}`
1480
- );
1481
- return { path: path3, ...target };
1482
- }
1483
1488
  }
1484
1489
  }
1490
+ const existing = pathsByApplicationId.get(path3);
1491
+ if (existing) {
1492
+ existing.applications.push(id);
1493
+ } else {
1494
+ pathsByApplicationId.set(path3, {
1495
+ applications: [id],
1496
+ matcher: (0, import_path_to_regexp2.pathToRegexp)(path3),
1497
+ applicationId: id
1498
+ });
1499
+ }
1485
1500
  }
1486
1501
  }
1487
- const defaultHost = this.getDefaultHost(config);
1488
- mfeDebug(
1489
- `no matching routes, routing ${path3} to default application: ${JSON.stringify(defaultHost)}`
1502
+ }
1503
+ const entries = Array.from(pathsByApplicationId.entries());
1504
+ entries.forEach(([path3, { applications: ids, matcher, applicationId }]) => {
1505
+ if (ids.length > 1) {
1506
+ errors.push(
1507
+ `Duplicate path "${path3}" for applications "${ids.join(", ")}"`
1508
+ );
1509
+ }
1510
+ entries.forEach(
1511
+ ([
1512
+ matchPath,
1513
+ { applications: matchIds, applicationId: matchApplicationId }
1514
+ ]) => {
1515
+ if (path3 === matchPath) {
1516
+ return;
1517
+ }
1518
+ if (applicationId === matchApplicationId) {
1519
+ return;
1520
+ }
1521
+ if (matcher.test(matchPath)) {
1522
+ const source = `"${path3}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
1523
+ const destination = `"${matchPath}" of application${matchIds.length > 0 ? "s" : ""} ${matchIds.join(", ")}`;
1524
+ errors.push(
1525
+ `Overlapping path detected between ${source} and ${destination}`
1526
+ );
1527
+ }
1528
+ }
1490
1529
  );
1491
- return { path: path3, ...defaultHost };
1530
+ });
1531
+ if (errors.length) {
1532
+ throw new MicrofrontendError2(`Invalid paths: ${errors.join(", ")}`, {
1533
+ type: "config",
1534
+ subtype: "conflicting_paths"
1535
+ });
1536
+ }
1537
+ };
1538
+ var validateAppPaths = (name, app) => {
1539
+ for (const group of app.routing) {
1540
+ for (const p of group.paths) {
1541
+ if (p === "/") {
1542
+ continue;
1543
+ }
1544
+ if (p.endsWith("/")) {
1545
+ throw new MicrofrontendError2(
1546
+ `Invalid path for application "${name}". ${p} must not end with a slash.`,
1547
+ { type: "application", subtype: "invalid_path" }
1548
+ );
1549
+ }
1550
+ if (!p.startsWith("/")) {
1551
+ throw new MicrofrontendError2(
1552
+ `Invalid path for application "${name}". ${p} must start with a slash.`,
1553
+ { type: "application", subtype: "invalid_path" }
1554
+ );
1555
+ }
1556
+ }
1557
+ }
1558
+ };
1559
+ var validateConfigDefaultApplication = (applicationConfigsById) => {
1560
+ if (!applicationConfigsById) {
1561
+ return;
1562
+ }
1563
+ const applicationsWithRouting = Object.entries(applicationConfigsById).filter(
1564
+ ([, app]) => !isDefaultApp(app)
1565
+ );
1566
+ const applicationsWithRoutingNames = applicationsWithRouting.map(
1567
+ ([key]) => key
1568
+ );
1569
+ const numApplications = Object.keys(applicationConfigsById).length;
1570
+ const numApplicationsWithRouting = applicationsWithRoutingNames.length;
1571
+ const numApplicationsWithoutRouting = numApplications - numApplicationsWithRouting;
1572
+ if (numApplicationsWithoutRouting === 0) {
1573
+ throw new MicrofrontendError2(
1574
+ `No default application found. At least one application needs to be the default by omitting routing.`,
1575
+ { type: "config", subtype: "no_default_application" }
1576
+ );
1577
+ }
1578
+ if (numApplicationsWithoutRouting > 1) {
1579
+ throw new MicrofrontendError2(
1580
+ `Only one application can omit "routing". Found ${applicationsWithRoutingNames.length - Object.keys(applicationConfigsById).length > 1}.`,
1581
+ { type: "config", subtype: "multiple_default_applications" }
1582
+ );
1583
+ }
1584
+ };
1585
+ var validateConfigOptions = (options) => {
1586
+ var _a;
1587
+ if ((_a = options == null ? void 0 : options.vercel) == null ? void 0 : _a.previewDeploymentSuffix) {
1588
+ if (!/^[a-zA-Z]{2,}\.[a-zA-Z]{2,}$/.test(
1589
+ options.vercel.previewDeploymentSuffix
1590
+ )) {
1591
+ throw new MicrofrontendError2(
1592
+ `Invalid preview deployment suffix: ${options.vercel.previewDeploymentSuffix}. Should have be formatted like "vercel.app".`,
1593
+ { type: "config", subtype: "invalid_preview_deployment_suffix" }
1594
+ );
1595
+ }
1596
+ }
1597
+ };
1598
+
1599
+ // src/config-v2/microfrontends-config/isomorphic/utils/generate-asset-prefix.ts
1600
+ var PREFIX = "vc-ap";
1601
+ function generateAssetPrefixFromName({
1602
+ name
1603
+ }) {
1604
+ if (!name) {
1605
+ throw new Error("Name is required to generate an asset prefix");
1606
+ }
1607
+ return `${PREFIX}-${name}`;
1608
+ }
1609
+
1610
+ // src/config-v2/microfrontends-config/isomorphic/utils/generate-port.ts
1611
+ function generatePortFromName({
1612
+ name,
1613
+ minPort = 3e3,
1614
+ maxPort = 8e3
1615
+ }) {
1616
+ if (!name) {
1617
+ throw new Error("Name is required to generate a port");
1618
+ }
1619
+ let hash = 0;
1620
+ for (let i = 0; i < name.length; i++) {
1621
+ hash = (hash << 5) - hash + name.charCodeAt(i);
1622
+ hash |= 0;
1623
+ }
1624
+ hash = Math.abs(hash);
1625
+ const range = maxPort - minPort;
1626
+ const port = minPort + hash % range;
1627
+ return port;
1628
+ }
1629
+
1630
+ // src/config-v2/microfrontends-config/isomorphic/host.ts
1631
+ var Host2 = class {
1632
+ constructor(hostConfig, options) {
1633
+ const { protocol = "https", host, port } = hostConfig;
1634
+ this.protocol = protocol;
1635
+ this.host = host;
1636
+ this.port = Host2.getPort({ port, protocol: this.protocol });
1637
+ this.local = options == null ? void 0 : options.isLocal;
1638
+ }
1639
+ isLocal() {
1640
+ return this.local || this.host === "localhost" || this.host === "127.0.0.1";
1641
+ }
1642
+ static getPort({
1643
+ protocol,
1644
+ port
1645
+ }) {
1646
+ if (!port) {
1647
+ if (protocol === "http") {
1648
+ return 80;
1649
+ }
1650
+ return 443;
1651
+ }
1652
+ return port;
1653
+ }
1654
+ isDefaultPort() {
1655
+ return this.port === Host2.getPort({ protocol: this.protocol });
1656
+ }
1657
+ toString(opts = {}) {
1658
+ const url = this.toUrl(opts);
1659
+ return url.toString().replace(/\/$/, "");
1660
+ }
1661
+ toUrl(opts = {}) {
1662
+ const { includeDefaultPort } = opts;
1663
+ const url = `${this.protocol}://${this.host}${this.isDefaultPort() && !includeDefaultPort ? "" : `:${this.port}`}`;
1664
+ return new URL(url);
1665
+ }
1666
+ };
1667
+ var LocalHost = class extends Host2 {
1668
+ constructor({
1669
+ appName,
1670
+ ...hostConfig
1671
+ }) {
1672
+ const host = hostConfig.host ?? "localhost";
1673
+ const port = hostConfig.port ?? generatePortFromName({ name: appName });
1674
+ const protocol = hostConfig.protocol ?? "http";
1675
+ super({ protocol, host, port });
1676
+ }
1677
+ };
1678
+
1679
+ // src/config-v2/microfrontends-config/isomorphic/application.ts
1680
+ var Application2 = class {
1681
+ constructor(name, {
1682
+ app,
1683
+ overrides,
1684
+ isDefault
1685
+ }) {
1686
+ var _a, _b;
1687
+ this.name = name;
1688
+ this.development = {
1689
+ local: new LocalHost({
1690
+ appName: name,
1691
+ ...(_a = app.development) == null ? void 0 : _a.local
1692
+ }),
1693
+ fallback: ((_b = app.development) == null ? void 0 : _b.fallback) ? new Host2(app.development.fallback) : void 0
1694
+ };
1695
+ this.production = app.production ? new Host2(app.production) : void 0;
1696
+ this.vercel = app.vercel;
1697
+ this.overrides = (overrides == null ? void 0 : overrides.environment) ? {
1698
+ environment: new Host2(overrides.environment)
1699
+ } : void 0;
1700
+ this.default = isDefault ?? false;
1701
+ this.serialized = app;
1702
+ }
1703
+ isDefault() {
1704
+ return this.default;
1705
+ }
1706
+ getAssetPrefix() {
1707
+ return generateAssetPrefixFromName({ name: this.name });
1708
+ }
1709
+ serialize() {
1710
+ return this.serialized;
1711
+ }
1712
+ };
1713
+ var DefaultApplication = class extends Application2 {
1714
+ constructor(name, {
1715
+ app,
1716
+ overrides
1717
+ }) {
1718
+ super(name, {
1719
+ app,
1720
+ overrides,
1721
+ isDefault: true
1722
+ });
1723
+ this.default = true;
1724
+ this.production = new Host2(app.production);
1725
+ }
1726
+ };
1727
+ var ChildApplication = class extends Application2 {
1728
+ constructor(name, {
1729
+ app,
1730
+ overrides
1731
+ }) {
1732
+ ChildApplication.validate(name, app);
1733
+ super(name, {
1734
+ app,
1735
+ overrides,
1736
+ isDefault: false
1737
+ });
1738
+ this.default = false;
1739
+ this.routing = app.routing;
1740
+ }
1741
+ static validate(name, app) {
1742
+ validateAppPaths(name, app);
1743
+ }
1744
+ };
1745
+
1746
+ // src/config-v2/microfrontends-config/isomorphic/index.ts
1747
+ var import_jsonc_parser2 = require("jsonc-parser");
1748
+
1749
+ // src/config-v2/microfrontends-config/utils/get-config-from-env.ts
1750
+ function getConfigStringFromEnv() {
1751
+ const config = process.env.MFE_CONFIG;
1752
+ if (!config) {
1753
+ throw new MicrofrontendError2(`Missing "MFE_CONFIG" in environment.`, {
1754
+ type: "config",
1755
+ subtype: "not_found_in_env"
1756
+ });
1757
+ }
1758
+ return config;
1759
+ }
1760
+
1761
+ // src/config-v2/schema/utils/is-main-config.ts
1762
+ function isMainConfig(c) {
1763
+ return !("partOf" in c);
1764
+ }
1765
+
1766
+ // src/config-v2/microfrontends-config/client/index.ts
1767
+ var import_path_to_regexp3 = require("path-to-regexp");
1768
+ var MicrofrontendConfigClient = class {
1769
+ constructor(config, opts) {
1770
+ this.pathCache = {};
1771
+ this.serialized = config;
1772
+ if (opts == null ? void 0 : opts.removeFlaggedPaths) {
1773
+ for (const app of Object.values(config.applications)) {
1774
+ if (app.routing) {
1775
+ app.routing = app.routing.filter((match) => !match.flag);
1776
+ }
1777
+ }
1778
+ }
1779
+ this.applications = config.applications;
1780
+ }
1781
+ /**
1782
+ * Create a new `MicrofrontendConfigClient` from a JSON string.
1783
+ * Config must be passed in to remain framework agnostic
1784
+ */
1785
+ static fromEnv(config, opts) {
1786
+ if (!config) {
1787
+ throw new Error("No microfrontends configuration found");
1788
+ }
1789
+ return new MicrofrontendConfigClient(
1790
+ JSON.parse(config),
1791
+ opts
1792
+ );
1793
+ }
1794
+ isEqual(other) {
1795
+ return JSON.stringify(this.applications) === JSON.stringify(other.applications);
1796
+ }
1797
+ getApplicationNameForPath(path3) {
1798
+ if (!path3.startsWith("/")) {
1799
+ throw new Error(`Path must start with a /`);
1800
+ }
1801
+ if (this.pathCache[path3]) {
1802
+ return this.pathCache[path3];
1803
+ }
1804
+ const pathname = new URL(path3, "https://example.com").pathname;
1805
+ for (const [name, application] of Object.entries(this.applications)) {
1806
+ if (application.routing) {
1807
+ for (const group of application.routing) {
1808
+ for (const childPath of group.paths) {
1809
+ const regexp = (0, import_path_to_regexp3.pathToRegexp)(childPath);
1810
+ if (regexp.test(pathname)) {
1811
+ this.pathCache[path3] = name;
1812
+ return name;
1813
+ }
1814
+ }
1815
+ }
1816
+ }
1817
+ }
1818
+ const defaultApplication = Object.entries(this.applications).find(
1819
+ ([, application]) => application.default
1820
+ );
1821
+ if (!defaultApplication) {
1822
+ return null;
1823
+ }
1824
+ this.pathCache[path3] = defaultApplication[0];
1825
+ return defaultApplication[0];
1826
+ }
1827
+ serialize() {
1828
+ return this.serialized;
1829
+ }
1830
+ };
1831
+
1832
+ // src/config-v2/overrides/constants.ts
1833
+ var OVERRIDES_COOKIE_PREFIX2 = "vercel-microfrontends-override";
1834
+ var OVERRIDES_ENV_COOKIE_PREFIX = `${OVERRIDES_COOKIE_PREFIX2}:env:`;
1835
+
1836
+ // src/config-v2/overrides/is-override-cookie.ts
1837
+ function isOverrideCookie(cookie) {
1838
+ var _a;
1839
+ return Boolean((_a = cookie.name) == null ? void 0 : _a.startsWith(OVERRIDES_COOKIE_PREFIX2));
1840
+ }
1841
+
1842
+ // src/config-v2/overrides/get-override-from-cookie.ts
1843
+ function getOverrideFromCookie(cookie) {
1844
+ if (!isOverrideCookie(cookie) || !cookie.value)
1845
+ return;
1846
+ return {
1847
+ application: cookie.name.replace(OVERRIDES_ENV_COOKIE_PREFIX, ""),
1848
+ host: cookie.value
1849
+ };
1850
+ }
1851
+
1852
+ // src/config-v2/overrides/parse-overrides.ts
1853
+ function parseOverrides(cookies) {
1854
+ const overridesConfig = { applications: {} };
1855
+ cookies.forEach((cookie) => {
1856
+ const override = getOverrideFromCookie(cookie);
1857
+ if (!override)
1858
+ return;
1859
+ overridesConfig.applications[override.application] = {
1860
+ environment: { host: override.host }
1861
+ };
1862
+ });
1863
+ return overridesConfig;
1864
+ }
1865
+
1866
+ // src/config-v2/microfrontends-config/isomorphic/constants.ts
1867
+ var DEFAULT_LOCAL_PROXY_PORT2 = 3024;
1868
+
1869
+ // src/config-v2/microfrontends-config/isomorphic/index.ts
1870
+ var MicrofrontendConfigIsomorphic = class {
1871
+ constructor({
1872
+ config,
1873
+ overrides,
1874
+ meta
1875
+ }) {
1876
+ this.childApplications = {};
1877
+ var _a, _b, _c, _d;
1878
+ MicrofrontendConfigIsomorphic.validate(config);
1879
+ const disableOverrides = ((_b = (_a = config.options) == null ? void 0 : _a.vercel) == null ? void 0 : _b.disableOverrides) ?? false;
1880
+ this.overrides = overrides && !disableOverrides ? overrides : void 0;
1881
+ this.isMainConfig = isMainConfig(config);
1882
+ if (isMainConfig(config)) {
1883
+ for (const [appId, appConfig] of Object.entries(config.applications)) {
1884
+ const appOverrides = !disableOverrides ? (_c = this.overrides) == null ? void 0 : _c.applications[appId] : void 0;
1885
+ if (isDefaultApp(appConfig)) {
1886
+ this.defaultApplication = new DefaultApplication(appId, {
1887
+ app: appConfig,
1888
+ overrides: appOverrides
1889
+ });
1890
+ } else {
1891
+ this.childApplications[appId] = new ChildApplication(appId, {
1892
+ app: appConfig,
1893
+ overrides: appOverrides
1894
+ });
1895
+ }
1896
+ }
1897
+ } else {
1898
+ this.partOf = config.partOf;
1899
+ const appOverrides = !disableOverrides ? (_d = this.overrides) == null ? void 0 : _d.applications[meta.fromApp] : void 0;
1900
+ this.childApplications[meta.fromApp] = new ChildApplication(
1901
+ meta.fromApp,
1902
+ {
1903
+ // we don't know routing because we're not in the main config
1904
+ app: { routing: [] },
1905
+ overrides: appOverrides
1906
+ }
1907
+ );
1908
+ }
1909
+ if (isMainConfig(config) && !this.defaultApplication) {
1910
+ throw new MicrofrontendError2(
1911
+ `Could not find default application in microfrontends configuration`,
1912
+ {
1913
+ type: "application",
1914
+ subtype: "not_found"
1915
+ }
1916
+ );
1917
+ }
1918
+ this.config = config;
1919
+ this.options = config.options;
1920
+ this.serialized = {
1921
+ config,
1922
+ overrides,
1923
+ meta
1924
+ };
1925
+ }
1926
+ static validate(config) {
1927
+ const c = typeof config === "string" ? (0, import_jsonc_parser2.parse)(config) : config;
1928
+ if (isMainConfig(c)) {
1929
+ validateConfigVersion(c.version);
1930
+ validateConfigPaths(c.applications);
1931
+ validateConfigDefaultApplication(c.applications);
1932
+ }
1933
+ validateConfigOptions(c.options);
1934
+ return c;
1935
+ }
1936
+ static fromEnv({
1937
+ meta,
1938
+ cookies
1939
+ }) {
1940
+ return new MicrofrontendConfigIsomorphic({
1941
+ config: (0, import_jsonc_parser2.parse)(getConfigStringFromEnv()),
1942
+ overrides: parseOverrides(cookies ?? []),
1943
+ meta
1944
+ });
1945
+ }
1946
+ isOverridesDisabled() {
1947
+ var _a, _b;
1948
+ return ((_b = (_a = this.options) == null ? void 0 : _a.vercel) == null ? void 0 : _b.disableOverrides) ?? false;
1949
+ }
1950
+ getConfig() {
1951
+ return this.config;
1952
+ }
1953
+ getApplicationsByType() {
1954
+ return {
1955
+ defaultApplication: this.defaultApplication,
1956
+ applications: Object.values(this.childApplications)
1957
+ };
1958
+ }
1959
+ getChildApplications() {
1960
+ return Object.values(this.childApplications);
1961
+ }
1962
+ getAllApplications() {
1963
+ return [
1964
+ this.defaultApplication,
1965
+ ...Object.values(this.childApplications)
1966
+ ].filter(Boolean);
1967
+ }
1968
+ getApplication(name) {
1969
+ var _a;
1970
+ if (((_a = this.defaultApplication) == null ? void 0 : _a.name) === name) {
1971
+ return this.defaultApplication;
1972
+ }
1973
+ const app = this.childApplications[name];
1974
+ if (!app) {
1975
+ throw new MicrofrontendError2(
1976
+ `Could not find microfrontends configuration for application "${name}"`,
1977
+ {
1978
+ type: "application",
1979
+ subtype: "not_found"
1980
+ }
1981
+ );
1982
+ }
1983
+ return app;
1984
+ }
1985
+ getApplicationByProjectId(projectId) {
1986
+ var _a, _b;
1987
+ if (((_b = (_a = this.defaultApplication) == null ? void 0 : _a.vercel) == null ? void 0 : _b.projectId) === projectId) {
1988
+ return this.defaultApplication;
1989
+ }
1990
+ return Object.values(this.childApplications).find(
1991
+ (app) => {
1992
+ var _a2;
1993
+ return ((_a2 = app.vercel) == null ? void 0 : _a2.projectId) === projectId;
1994
+ }
1995
+ );
1996
+ }
1997
+ /**
1998
+ * Returns the default application. This can throw if the default application
1999
+ * is undefined ( )
2000
+ */
2001
+ getDefaultApplication() {
2002
+ if (!this.defaultApplication) {
2003
+ throw new MicrofrontendError2(
2004
+ `Could not find default application in microfrontends configuration`,
2005
+ {
2006
+ type: "application",
2007
+ subtype: "not_found"
2008
+ }
2009
+ );
2010
+ }
2011
+ return this.defaultApplication;
2012
+ }
2013
+ /**
2014
+ * Returns the configured port for the local proxy
2015
+ */
2016
+ getLocalProxyPort() {
2017
+ var _a, _b;
2018
+ return ((_b = (_a = this.config.options) == null ? void 0 : _a.localProxy) == null ? void 0 : _b.port) ?? DEFAULT_LOCAL_PROXY_PORT2;
2019
+ }
2020
+ /**
2021
+ * Serializes the class back to the Schema type.
2022
+ *
2023
+ * NOTE: This is used when writing the config to disk and must always match the input Schema
2024
+ */
2025
+ toSchemaJson() {
2026
+ return this.serialized.config;
2027
+ }
2028
+ toClientConfig() {
2029
+ const applications = Object.fromEntries(
2030
+ Object.entries(this.childApplications).map(([name, application]) => [
2031
+ name,
2032
+ {
2033
+ default: false,
2034
+ routing: application.routing
2035
+ }
2036
+ ])
2037
+ );
2038
+ if (this.defaultApplication) {
2039
+ applications[this.defaultApplication.name] = {
2040
+ default: true
2041
+ };
2042
+ }
2043
+ return new MicrofrontendConfigClient({
2044
+ applications
2045
+ });
2046
+ }
2047
+ serialize() {
2048
+ return this.serialized;
2049
+ }
2050
+ };
2051
+
2052
+ // src/config-v2/microfrontends-config/isomorphic/main.ts
2053
+ var MicrofrontendMainConfig = class extends MicrofrontendConfigIsomorphic {
2054
+ constructor({
2055
+ config,
2056
+ overrides,
2057
+ meta
2058
+ }) {
2059
+ var _a, _b, _c;
2060
+ super({ config, overrides, meta });
2061
+ this.isMainConfig = true;
2062
+ this.provider = config.provider;
2063
+ const disableOverrides = ((_b = (_a = config.options) == null ? void 0 : _a.vercel) == null ? void 0 : _b.disableOverrides) ?? false;
2064
+ let defaultApplication;
2065
+ for (const [appId, appConfig] of Object.entries(config.applications)) {
2066
+ const appOverrides = !disableOverrides ? (_c = this.overrides) == null ? void 0 : _c.applications[appId] : void 0;
2067
+ if (isDefaultApp(appConfig)) {
2068
+ defaultApplication = new DefaultApplication(appId, {
2069
+ app: appConfig,
2070
+ overrides: appOverrides
2071
+ });
2072
+ } else {
2073
+ this.childApplications[appId] = new ChildApplication(appId, {
2074
+ app: appConfig,
2075
+ overrides: appOverrides
2076
+ });
2077
+ }
2078
+ }
2079
+ if (!defaultApplication) {
2080
+ throw new MicrofrontendError2(
2081
+ `Could not find default application in microfrontends configuration`,
2082
+ {
2083
+ type: "application",
2084
+ subtype: "not_found"
2085
+ }
2086
+ );
2087
+ }
2088
+ this.defaultApplication = defaultApplication;
2089
+ }
2090
+ };
2091
+
2092
+ // src/config-v2/microfrontends/util/is-main-config.ts
2093
+ function isMainConfig2(c) {
2094
+ return !("partOf" in c);
2095
+ }
2096
+
2097
+ // src/config-v2/microfrontends/server/index.ts
2098
+ var import_node_fs3 = __toESM(require("fs"), 1);
2099
+ var import_node_path4 = require("path");
2100
+
2101
+ // src/config-v2/microfrontends-config/isomorphic/child.ts
2102
+ var MicrofrontendChildConfig = class extends MicrofrontendConfigIsomorphic {
2103
+ constructor({
2104
+ config,
2105
+ overrides,
2106
+ meta
2107
+ }) {
2108
+ super({ config, overrides, meta });
2109
+ this.isMainConfig = false;
2110
+ this.partOf = config.partOf;
2111
+ }
2112
+ };
2113
+
2114
+ // src/config-v2/microfrontends/isomorphic/index.ts
2115
+ var Microfrontends = class {
2116
+ constructor({
2117
+ config,
2118
+ overrides,
2119
+ meta
2120
+ }) {
2121
+ if (isMainConfig(config)) {
2122
+ this.config = new MicrofrontendMainConfig({ config, overrides, meta });
2123
+ } else {
2124
+ this.config = new MicrofrontendChildConfig({ config, overrides, meta });
2125
+ }
2126
+ }
2127
+ isChildConfig() {
2128
+ return this.config instanceof MicrofrontendChildConfig;
2129
+ }
2130
+ static fromEnv({
2131
+ cookies,
2132
+ meta
2133
+ }) {
2134
+ const config = MicrofrontendConfigIsomorphic.fromEnv({
2135
+ cookies,
2136
+ meta
2137
+ });
2138
+ return new Microfrontends(config.serialize());
2139
+ }
2140
+ };
2141
+
2142
+ // src/config-v2/microfrontends/server/validation.ts
2143
+ var import_jsonc_parser3 = require("jsonc-parser");
2144
+ var import_ajv2 = require("ajv");
2145
+
2146
+ // schema/schema-v2.json
2147
+ var schema_v2_default = {
2148
+ $schema: "http://json-schema.org/draft-07/schema#",
2149
+ $ref: "#/definitions/Config",
2150
+ definitions: {
2151
+ Config: {
2152
+ anyOf: [
2153
+ {
2154
+ $ref: "#/definitions/MainConfig"
2155
+ },
2156
+ {
2157
+ $ref: "#/definitions/ChildConfig"
2158
+ }
2159
+ ]
2160
+ },
2161
+ MainConfig: {
2162
+ type: "object",
2163
+ properties: {
2164
+ $schema: {
2165
+ type: "string"
2166
+ },
2167
+ version: {
2168
+ type: "string",
2169
+ const: "2"
2170
+ },
2171
+ options: {
2172
+ $ref: "#/definitions/Options"
2173
+ },
2174
+ remotes: {
2175
+ type: "object",
2176
+ additionalProperties: {
2177
+ $ref: "#/definitions/Application"
2178
+ },
2179
+ 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."
2180
+ },
2181
+ provider: {
2182
+ $ref: "#/definitions/Provider"
2183
+ },
2184
+ applications: {
2185
+ $ref: "#/definitions/ApplicationRouting",
2186
+ 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"
2187
+ }
2188
+ },
2189
+ required: ["applications", "provider", "version"]
2190
+ },
2191
+ Options: {
2192
+ type: "object",
2193
+ properties: {
2194
+ vercel: {
2195
+ $ref: "#/definitions/VercelOptions",
2196
+ description: "Micro-Frontends wide options for Vercel."
2197
+ },
2198
+ localProxy: {
2199
+ $ref: "#/definitions/LocalProxyOptions",
2200
+ description: "Options for local proxy."
2201
+ }
2202
+ }
2203
+ },
2204
+ VercelOptions: {
2205
+ type: "object",
2206
+ properties: {
2207
+ previewDeploymentSuffix: {
2208
+ type: "string",
2209
+ description: "If your team uses a custom Preview Deployment Suffix, please specify it here. See https://vercel.com/docs/deployments/preview-deployment-suffix. The default is `vercel.app`."
2210
+ },
2211
+ teamSlug: {
2212
+ type: "string",
2213
+ description: "Team slug for the Vercel team"
2214
+ },
2215
+ disableOverrides: {
2216
+ type: "boolean",
2217
+ 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."
2218
+ }
2219
+ }
2220
+ },
2221
+ LocalProxyOptions: {
2222
+ type: "object",
2223
+ properties: {
2224
+ port: {
2225
+ type: "number",
2226
+ description: "The port number used by the local proxy server.\n\nThe default is `3024`."
2227
+ }
2228
+ }
2229
+ },
2230
+ Application: {
2231
+ anyOf: [
2232
+ {
2233
+ $ref: "#/definitions/DefaultApplication"
2234
+ },
2235
+ {
2236
+ $ref: "#/definitions/ChildApplication"
2237
+ }
2238
+ ]
2239
+ },
2240
+ DefaultApplication: {
2241
+ type: "object",
2242
+ properties: {
2243
+ vercel: {
2244
+ $ref: "#/definitions/Vercel"
2245
+ },
2246
+ development: {
2247
+ $ref: "#/definitions/Development"
2248
+ },
2249
+ production: {
2250
+ $ref: "#/definitions/HostConfig"
2251
+ }
2252
+ },
2253
+ required: ["production"]
2254
+ },
2255
+ Vercel: {
2256
+ type: "object",
2257
+ properties: {
2258
+ projectId: {
2259
+ type: "string",
2260
+ description: "Vercel project ID"
2261
+ },
2262
+ routeSpeedInsightsToDefaultZone: {
2263
+ type: "boolean"
2264
+ }
2265
+ },
2266
+ required: ["projectId"]
2267
+ },
2268
+ Development: {
2269
+ type: "object",
2270
+ properties: {
2271
+ local: {
2272
+ $ref: "#/definitions/LocalHostConfig"
2273
+ },
2274
+ fallback: {
2275
+ $ref: "#/definitions/HostConfig",
2276
+ 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."
2277
+ },
2278
+ task: {
2279
+ type: "string",
2280
+ description: "Optional task to run when starting the development server. Should reference a script in the package.json of the application."
2281
+ }
2282
+ }
2283
+ },
2284
+ LocalHostConfig: {
2285
+ type: "object",
2286
+ properties: {
2287
+ host: {
2288
+ type: "string",
2289
+ description: "The hostname or IP address of the server. This can be a domain name (e.g., `example.com`) or an IP address (e.g., `192.168.1.1`)."
2290
+ },
2291
+ protocol: {
2292
+ type: "string",
2293
+ enum: ["http", "https"],
2294
+ description: 'The protocol to be used for the connection.\n- `http`: Hypertext Transfer Protocol (HTTP).\n- `https`: Secure Hypertext Transfer Protocol (HTTPS).\n\n* @defaultValue "http" for local development, "https" for otherwise'
2295
+ },
2296
+ port: {
2297
+ type: "number",
2298
+ description: "The port number to be used for the connection. Common values include `80` for HTTP and `443` for HTTPS."
2299
+ }
2300
+ }
2301
+ },
2302
+ HostConfig: {
2303
+ type: "object",
2304
+ properties: {
2305
+ protocol: {
2306
+ type: "string",
2307
+ enum: ["http", "https"],
2308
+ description: 'The protocol to be used for the connection.\n- `http`: Hypertext Transfer Protocol (HTTP).\n- `https`: Secure Hypertext Transfer Protocol (HTTPS).\n\n* @defaultValue "http" for local development, "https" for otherwise'
2309
+ },
2310
+ host: {
2311
+ type: "string",
2312
+ description: "The hostname or IP address of the server. This can be a domain name (e.g., `example.com`) or an IP address (e.g., `192.168.1.1`)."
2313
+ },
2314
+ port: {
2315
+ type: "number",
2316
+ description: "The port number to be used for the connection. Common values include `80` for HTTP and `443` for HTTPS."
2317
+ }
2318
+ },
2319
+ required: ["host"]
2320
+ },
2321
+ ChildApplication: {
2322
+ type: "object",
2323
+ properties: {
2324
+ vercel: {
2325
+ $ref: "#/definitions/Vercel"
2326
+ },
2327
+ development: {
2328
+ $ref: "#/definitions/Development"
2329
+ },
2330
+ routing: {
2331
+ $ref: "#/definitions/Routing",
2332
+ description: "Groups of path expressions that are routed to this application."
2333
+ },
2334
+ production: {
2335
+ $ref: "#/definitions/HostConfig"
2336
+ }
2337
+ },
2338
+ required: ["routing"]
2339
+ },
2340
+ Routing: {
2341
+ type: "array",
2342
+ items: {
2343
+ $ref: "#/definitions/PathGroup"
2344
+ }
2345
+ },
2346
+ PathGroup: {
2347
+ type: "object",
2348
+ properties: {
2349
+ group: {
2350
+ type: "string",
2351
+ description: "Optional group name for the paths"
2352
+ },
2353
+ flag: {
2354
+ type: "string",
2355
+ description: "flag name that can be used to enable/disable all paths in the group"
2356
+ },
2357
+ routeToDefaultApplication: {
2358
+ type: "boolean",
2359
+ 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."
2360
+ },
2361
+ paths: {
2362
+ type: "array",
2363
+ items: {
2364
+ type: "string"
2365
+ }
2366
+ }
2367
+ },
2368
+ required: ["paths"]
2369
+ },
2370
+ Provider: {
2371
+ type: "string",
2372
+ enum: ["vercel", "other"]
2373
+ },
2374
+ ApplicationRouting: {
2375
+ type: "object",
2376
+ additionalProperties: {
2377
+ $ref: "#/definitions/Application"
2378
+ }
2379
+ },
2380
+ ChildConfig: {
2381
+ type: "object",
2382
+ properties: {
2383
+ $schema: {
2384
+ type: "string"
2385
+ },
2386
+ version: {
2387
+ type: "string",
2388
+ const: "2"
2389
+ },
2390
+ options: {
2391
+ $ref: "#/definitions/Options"
2392
+ },
2393
+ remotes: {
2394
+ type: "object",
2395
+ additionalProperties: {
2396
+ $ref: "#/definitions/Application"
2397
+ },
2398
+ 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."
2399
+ },
2400
+ partOf: {
2401
+ type: "string",
2402
+ 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."
2403
+ }
2404
+ },
2405
+ required: ["partOf", "version"]
2406
+ }
2407
+ }
2408
+ };
2409
+
2410
+ // src/config-v2/schema/utils/load.ts
2411
+ var SCHEMA2 = schema_v2_default;
2412
+
2413
+ // src/config-v2/microfrontends/server/validation.ts
2414
+ function validateSchema2(configString) {
2415
+ const parsedConfig = (0, import_jsonc_parser3.parse)(configString);
2416
+ const ajv = new import_ajv2.Ajv();
2417
+ const validate = ajv.compile(SCHEMA2);
2418
+ const isValid = validate(parsedConfig);
2419
+ if (!isValid) {
2420
+ throw new MicrofrontendError(
2421
+ `Invalid config: ${ajv.errorsText(validate.errors)}`,
2422
+ { type: "config", subtype: "does_not_match_schema" }
2423
+ );
2424
+ }
2425
+ return parsedConfig;
2426
+ }
2427
+
2428
+ // src/config-v2/microfrontends/server/index.ts
2429
+ var MicrofrontendsServer = class extends Microfrontends {
2430
+ /**
2431
+ * Writes the configuration to a file.
2432
+ */
2433
+ writeConfig(opts = {
2434
+ pretty: true
2435
+ }) {
2436
+ const outputPath = getOutputFilePath();
2437
+ import_node_fs3.default.mkdirSync((0, import_node_path4.dirname)(outputPath), { recursive: true });
2438
+ import_node_fs3.default.writeFileSync(
2439
+ outputPath,
2440
+ JSON.stringify(
2441
+ this.config.toSchemaJson(),
2442
+ null,
2443
+ opts.pretty ?? true ? 2 : void 0
2444
+ )
2445
+ );
2446
+ }
2447
+ // --------- Static Methods ---------
2448
+ /**
2449
+ * Generates a MicrofrontendsServer instance from an unknown object.
2450
+ */
2451
+ static fromUnknown({
2452
+ config,
2453
+ cookies,
2454
+ meta
2455
+ }) {
2456
+ const overrides = cookies ? parseOverrides(cookies) : void 0;
2457
+ if (typeof config === "string") {
2458
+ return new MicrofrontendsServer({
2459
+ config: MicrofrontendsServer.validate(config),
2460
+ overrides,
2461
+ meta
2462
+ });
2463
+ }
2464
+ if (typeof config === "object") {
2465
+ return new MicrofrontendsServer({
2466
+ config,
2467
+ overrides,
2468
+ meta
2469
+ });
2470
+ }
2471
+ throw new MicrofrontendError2(
2472
+ "Invalid config: must be a string or an object",
2473
+ { type: "config", subtype: "does_not_match_schema" }
2474
+ );
2475
+ }
2476
+ /**
2477
+ * Generates a MicrofrontendsServer instance from the environment.
2478
+ * Uses additional validation that is only available when in a node runtime
2479
+ */
2480
+ static fromEnv({
2481
+ cookies,
2482
+ meta
2483
+ }) {
2484
+ return new MicrofrontendsServer({
2485
+ config: MicrofrontendsServer.validate(getConfigStringFromEnv()),
2486
+ overrides: parseOverrides(cookies),
2487
+ meta
2488
+ });
2489
+ }
2490
+ /**
2491
+ * Validates the configuration against the JSON schema
2492
+ */
2493
+ static validate(config) {
2494
+ if (typeof config === "string") {
2495
+ const c = validateSchema2(config);
2496
+ return c;
2497
+ }
2498
+ return config;
2499
+ }
2500
+ /*
2501
+ * Generates a MicrofrontendsServer instance from a file.
2502
+ */
2503
+ static fromFile({
2504
+ filePath,
2505
+ cookies,
2506
+ meta
2507
+ }) {
2508
+ try {
2509
+ const config = import_node_fs3.default.readFileSync(filePath, "utf-8");
2510
+ return new MicrofrontendsServer({
2511
+ config: MicrofrontendsServer.validate(config),
2512
+ overrides: cookies ? parseOverrides(cookies) : void 0,
2513
+ meta
2514
+ });
2515
+ } catch (e) {
2516
+ throw MicrofrontendError2.handle(e, {
2517
+ fileName: filePath
2518
+ });
2519
+ }
2520
+ }
2521
+ /*
2522
+ * Generates a MicrofrontendMainConfig instance from a file.
2523
+ */
2524
+ static fromMainConfigFile({
2525
+ filePath,
2526
+ overrides
2527
+ }) {
2528
+ try {
2529
+ const config = import_node_fs3.default.readFileSync(filePath, "utf-8");
2530
+ const validatedConfig = MicrofrontendsServer.validate(config);
2531
+ if (!isMainConfig(validatedConfig)) {
2532
+ throw new MicrofrontendError2(
2533
+ `${filePath} is not a main microfrontend config`,
2534
+ {
2535
+ type: "config",
2536
+ subtype: "invalid_main_path"
2537
+ }
2538
+ );
2539
+ }
2540
+ const [defaultApplication] = Object.entries(validatedConfig.applications).filter(([, app]) => isDefaultApp(app)).map(([name]) => name);
2541
+ if (!defaultApplication) {
2542
+ throw new MicrofrontendError2(
2543
+ `No default application found. At least one application needs to be the default by omitting routing.`,
2544
+ { type: "config", subtype: "no_default_application" }
2545
+ );
2546
+ }
2547
+ return new MicrofrontendsServer({
2548
+ config: validatedConfig,
2549
+ overrides,
2550
+ meta: { fromApp: defaultApplication }
2551
+ });
2552
+ } catch (e) {
2553
+ throw MicrofrontendError2.handle(e, {
2554
+ fileName: filePath
2555
+ });
2556
+ }
2557
+ }
2558
+ };
2559
+
2560
+ // src/bin/local-proxy.ts
2561
+ var MFE_DEBUG = process.env.MFE_DEBUG;
2562
+ var mfeDebug = (message) => {
2563
+ if (MFE_DEBUG === "true" || MFE_DEBUG === "1") {
2564
+ console.log(message);
2565
+ }
2566
+ };
2567
+ function isV2Config(c) {
2568
+ return "isMainConfig" in c;
2569
+ }
2570
+ var LocalProxy = class {
2571
+ constructor(config, {
2572
+ localApps,
2573
+ proxyPort
2574
+ }) {
2575
+ this.config = config;
2576
+ this.localApps = localApps;
2577
+ this.proxyPort = proxyPort ?? this.config.getLocalProxyPort();
2578
+ this.proxy = import_http_proxy.default.createProxyServer({ secure: true });
2579
+ this.proxy.on("error", (err, req, res) => {
2580
+ if (res instanceof http.ServerResponse) {
2581
+ res.writeHead(500, {
2582
+ "Content-Type": "text/plain"
2583
+ });
2584
+ }
2585
+ const target = this.getTarget(req);
2586
+ res.end(
2587
+ `Error proxying request to ${target.application}. Is the server running locally on port ${target.port}?`
2588
+ );
2589
+ console.error(`Error proxying request for ${target.application}: `, err);
2590
+ });
2591
+ }
2592
+ static fromFile(filePath, {
2593
+ localApps,
2594
+ proxyPort
2595
+ }) {
2596
+ let configV2;
2597
+ try {
2598
+ configV2 = MicrofrontendsServer.fromMainConfigFile({
2599
+ filePath
2600
+ });
2601
+ } catch (error) {
2602
+ if ((0, import_types2.isNativeError)(error)) {
2603
+ mfeDebug(`unable to parse v2 version: ${error.toString()}`);
2604
+ }
2605
+ }
2606
+ if (configV2) {
2607
+ if (isMainConfig2(configV2.config)) {
2608
+ return new LocalProxy(configV2.config, { localApps, proxyPort });
2609
+ }
2610
+ throw new Error("Got child config after parsing main config");
2611
+ }
2612
+ const configV1 = MicrofrontendConfig.fromFile({ filePath });
2613
+ return new LocalProxy(configV1, { localApps, proxyPort });
2614
+ }
2615
+ getDefaultHost(config) {
2616
+ let defaultApp;
2617
+ if (isV2Config(config)) {
2618
+ defaultApp = config.getDefaultApplication();
2619
+ } else {
2620
+ defaultApp = config.getDefaultZone();
2621
+ }
2622
+ return this.getApplicationTarget(defaultApp);
2623
+ }
2624
+ getApplicationTarget(application) {
2625
+ var _a, _b;
2626
+ const useDev = this.localApps.includes(application.name);
2627
+ let host = useDev ? application.development.local : application.production;
2628
+ if (!host) {
2629
+ throw new Error(
2630
+ `${application.name} does not have a production host configured`
2631
+ );
2632
+ }
2633
+ if ((_b = (_a = application.overrides) == null ? void 0 : _a.environment) == null ? void 0 : _b.host) {
2634
+ host = application.overrides.environment;
2635
+ }
2636
+ const protocol = host.protocol;
2637
+ const hostname = host.host;
2638
+ const port = host.port;
2639
+ return {
2640
+ url: host.toUrl(),
2641
+ protocol,
2642
+ hostname,
2643
+ port,
2644
+ application: application.name
2645
+ };
2646
+ }
2647
+ /**
2648
+ * To enable preview deployments in localhost, we need to intercept some auth requests
2649
+ * and make sure they proxy to the correct domain. The toolbar will initiate the `vercel-auth-redirect`
2650
+ * with a `_host_override` param so that we can properly trigger the redirect flow for the
2651
+ * protected host.
2652
+ */
2653
+ getAuthTarget(request2, config) {
2654
+ var _a, _b;
2655
+ const url = new URL(request2.url ?? "", `http://${request2.headers.host}`);
2656
+ const isAuthRedirect = (_a = request2.url) == null ? void 0 : _a.startsWith(
2657
+ "/.well-known/vercel-auth-redirect"
2658
+ );
2659
+ const isSsoRedirect = (_b = request2.url) == null ? void 0 : _b.startsWith("/sso-api");
2660
+ const isJWTRedirect = url.searchParams.has("_vercel_jwt");
2661
+ const defaultHost = this.getDefaultHost(config);
2662
+ let hostname = null;
2663
+ let path3 = request2.url;
2664
+ if (isAuthRedirect) {
2665
+ hostname = url.searchParams.get("_host_override");
2666
+ }
2667
+ if (isSsoRedirect) {
2668
+ hostname = "vercel.com";
2669
+ }
2670
+ if (isJWTRedirect) {
2671
+ hostname = url.searchParams.get("_host_override");
2672
+ url.searchParams.delete("_host_override");
2673
+ path3 = `${url.pathname}${url.search}`;
2674
+ }
2675
+ if (!hostname) {
2676
+ return void 0;
2677
+ }
2678
+ return { ...defaultHost, path: path3, hostname, protocol: "https", port: 443 };
2679
+ }
2680
+ getConfigWithOverrides(cookies) {
2681
+ if (isV2Config(this.config)) {
2682
+ const cookieOverrides2 = parseOverrides(
2683
+ Object.entries(cookies).map(([name, value]) => ({ name, value }))
2684
+ );
2685
+ const hasOverrides2 = Object.keys(cookieOverrides2.applications).length > 0;
2686
+ const fromApp = this.config.getDefaultApplication().name;
2687
+ const serialized = this.config.serialize().config;
2688
+ if (!isMainConfig(serialized)) {
2689
+ throw new Error("unreachable");
2690
+ }
2691
+ return hasOverrides2 ? new MicrofrontendMainConfig({
2692
+ config: serialized,
2693
+ meta: { fromApp },
2694
+ overrides: cookieOverrides2
2695
+ }) : this.config;
2696
+ }
2697
+ const cookieOverrides = Overrides.parseOverrides(
2698
+ Object.entries(cookies).map(([name, value]) => ({ name, value }))
2699
+ );
2700
+ const hasOverrides = Object.keys(cookieOverrides.applications).length > 0;
2701
+ return hasOverrides ? new MicrofrontendConfig({
2702
+ config: this.config.serialize().config,
2703
+ overrides: cookieOverrides
2704
+ }) : this.config;
2705
+ }
2706
+ getTarget(request2) {
2707
+ const cookies = (0, import_cookie.parse)(request2.headers.cookie || "");
2708
+ const config = this.getConfigWithOverrides(cookies);
2709
+ const path3 = request2.url;
2710
+ if (!path3) {
2711
+ return this.getDefaultHost(config);
2712
+ }
2713
+ const authTarget = this.getAuthTarget(request2, config);
2714
+ if (authTarget) {
2715
+ return authTarget;
2716
+ }
2717
+ const url = new URL(`http://example.com${path3}`);
2718
+ const pathname = url.pathname;
2719
+ if (isV2Config(config)) {
2720
+ const target = this.findMatchingApplicationV2(
2721
+ path3,
2722
+ pathname,
2723
+ config.getChildApplications()
2724
+ );
2725
+ if (target)
2726
+ return target;
2727
+ } else {
2728
+ const target = this.findMatchingApplicationV1(
2729
+ path3,
2730
+ pathname,
2731
+ config.getAllApplications()
2732
+ );
2733
+ if (target)
2734
+ return target;
2735
+ }
2736
+ const defaultHost = this.getDefaultHost(config);
2737
+ mfeDebug(
2738
+ `no matching routes, routing ${path3} to default application: ${JSON.stringify(defaultHost)}`
2739
+ );
2740
+ return { path: path3, ...defaultHost };
2741
+ }
2742
+ findMatchingApplicationV1(path3, pathname, applications) {
2743
+ for (const application of Object.values(applications)) {
2744
+ if (application.routing) {
2745
+ for (const group of application.routing.matches) {
2746
+ for (const childPath of group.paths) {
2747
+ const regexp = (0, import_path_to_regexp4.pathToRegexp)(childPath);
2748
+ if (regexp.test(pathname)) {
2749
+ const target = this.getApplicationTarget(application);
2750
+ mfeDebug(
2751
+ `routing ${path3} to '${target.application}' at ${target.hostname}`
2752
+ );
2753
+ return { path: path3, ...target };
2754
+ }
2755
+ }
2756
+ if (application.routing.assetPrefix) {
2757
+ const pattern = (0, import_path_to_regexp4.pathToRegexp)(
2758
+ `/${application.routing.assetPrefix}/:path+`
2759
+ );
2760
+ if (pattern.test(pathname)) {
2761
+ const target = this.getApplicationTarget(application);
2762
+ mfeDebug(
2763
+ `routing ${path3} to '${target.application}' at ${target.hostname}`
2764
+ );
2765
+ return { path: path3, ...target };
2766
+ }
2767
+ }
2768
+ }
2769
+ }
2770
+ }
2771
+ return null;
2772
+ }
2773
+ findMatchingApplicationV2(path3, pathname, applications) {
2774
+ for (const application of Object.values(applications)) {
2775
+ for (const group of application.routing) {
2776
+ for (const childPath of group.paths) {
2777
+ const regexp = (0, import_path_to_regexp4.pathToRegexp)(childPath);
2778
+ if (regexp.test(pathname)) {
2779
+ const target = this.getApplicationTarget(application);
2780
+ mfeDebug(
2781
+ `routing ${path3} to '${target.application}' at ${target.hostname}`
2782
+ );
2783
+ return { path: path3, ...target };
2784
+ }
2785
+ }
2786
+ }
2787
+ }
2788
+ return null;
1492
2789
  }
1493
2790
  // Handles requests that return data from the local proxy itself.
1494
2791
  // Returns true if the request was handled, false otherwise.