@vercel/microfrontends 0.17.1 → 0.17.3

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 (62) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +48 -89
  3. package/dist/bin/cli.cjs +299 -200
  4. package/dist/config.cjs +22 -45
  5. package/dist/config.cjs.map +1 -1
  6. package/dist/config.d.ts +4 -4
  7. package/dist/config.js +22 -45
  8. package/dist/config.js.map +1 -1
  9. package/dist/{types-a29d224a.d.ts → index-5fcf0863.d.ts} +2 -2
  10. package/dist/{index-4399aa8e.d.ts → index-f094deb1.d.ts} +5 -4
  11. package/dist/microfrontends/server.cjs +68 -75
  12. package/dist/microfrontends/server.cjs.map +1 -1
  13. package/dist/microfrontends/server.d.ts +4 -4
  14. package/dist/microfrontends/server.js +68 -75
  15. package/dist/microfrontends/server.js.map +1 -1
  16. package/dist/microfrontends.cjs +24 -48
  17. package/dist/microfrontends.cjs.map +1 -1
  18. package/dist/microfrontends.d.ts +4 -4
  19. package/dist/microfrontends.js +24 -48
  20. package/dist/microfrontends.js.map +1 -1
  21. package/dist/next/client.cjs +1 -1
  22. package/dist/next/client.cjs.map +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 +86 -101
  26. package/dist/next/config.cjs.map +1 -1
  27. package/dist/next/config.js +86 -101
  28. package/dist/next/config.js.map +1 -1
  29. package/dist/next/endpoints.cjs +1 -1
  30. package/dist/next/endpoints.cjs.map +1 -1
  31. package/dist/next/endpoints.d.ts +2 -2
  32. package/dist/next/endpoints.js +1 -1
  33. package/dist/next/endpoints.js.map +1 -1
  34. package/dist/next/middleware.cjs +32 -63
  35. package/dist/next/middleware.cjs.map +1 -1
  36. package/dist/next/middleware.js +32 -63
  37. package/dist/next/middleware.js.map +1 -1
  38. package/dist/next/testing.cjs +27 -54
  39. package/dist/next/testing.cjs.map +1 -1
  40. package/dist/next/testing.d.ts +4 -4
  41. package/dist/next/testing.js +27 -54
  42. package/dist/next/testing.js.map +1 -1
  43. package/dist/overrides.cjs +1 -2
  44. package/dist/overrides.cjs.map +1 -1
  45. package/dist/overrides.d.ts +3 -3
  46. package/dist/overrides.js +1 -2
  47. package/dist/overrides.js.map +1 -1
  48. package/dist/schema.cjs.map +1 -1
  49. package/dist/schema.d.ts +1 -1
  50. package/dist/{types-fc30696d.d.ts → types-5900be7c.d.ts} +1 -1
  51. package/dist/{types-cfe3308b.d.ts → types-ecd7b91b.d.ts} +1 -1
  52. package/dist/utils/mfe-port.cjs +68 -75
  53. package/dist/utils/mfe-port.cjs.map +1 -1
  54. package/dist/utils/mfe-port.js +68 -75
  55. package/dist/utils/mfe-port.js.map +1 -1
  56. package/dist/validation.cjs +46 -17
  57. package/dist/validation.cjs.map +1 -1
  58. package/dist/validation.d.ts +1 -1
  59. package/dist/validation.js +46 -17
  60. package/dist/validation.js.map +1 -1
  61. package/package.json +18 -22
  62. package/schema/schema.json +15 -8
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.17.1",
32
+ version: "0.17.3",
33
33
  private: false,
34
34
  description: "Defines configuration and utilities for micro-frontend development",
35
35
  repository: {
@@ -39,12 +39,8 @@ var package_default = {
39
39
  },
40
40
  sideEffects: false,
41
41
  type: "module",
42
- bin: {
43
- microfrontends: "./cli/index.cjs",
44
- "micro-frontends": "./cli/index.cjs"
45
- },
46
42
  exports: {
47
- "./schema.json": "./schema/schema-v2.json",
43
+ "./schema.json": "./schema/schema.json",
48
44
  "./validation": {
49
45
  import: "./dist/validation.js",
50
46
  require: "./dist/validation.cjs"
@@ -104,35 +100,68 @@ var package_default = {
104
100
  },
105
101
  typesVersions: {
106
102
  "*": {
107
- validation: ["./dist/validation.d.ts"],
108
- config: ["./dist/config.d.ts"],
109
- microfrontends: ["./dist/microfrontends.d.ts"],
110
- overrides: ["./dist/overrides.d.ts"],
111
- routing: ["./dist/routing.d.ts"],
112
- "microfrontends/server": ["./dist/microfrontends/server.d.ts"],
113
- "microfrontends/utils": ["./dist/microfrontends/utils.d.ts"],
114
- schema: ["./dist/schema.d.ts"],
115
- "next/config": ["./dist/next/config.d.ts"],
116
- "next/middleware": ["./dist/next/middleware.d.ts"],
117
- "next/endpoints": ["./dist/next/endpoints.d.ts"],
118
- "next/testing": ["./dist/next/testing.d.ts"],
119
- "next/client": ["./dist/next/client.d.ts"],
120
- "utils/mfe-port": ["./dist/utils/mfe-port.d.ts"]
103
+ validation: [
104
+ "./dist/validation.d.ts"
105
+ ],
106
+ config: [
107
+ "./dist/config.d.ts"
108
+ ],
109
+ microfrontends: [
110
+ "./dist/microfrontends.d.ts"
111
+ ],
112
+ overrides: [
113
+ "./dist/overrides.d.ts"
114
+ ],
115
+ routing: [
116
+ "./dist/routing.d.ts"
117
+ ],
118
+ "microfrontends/server": [
119
+ "./dist/microfrontends/server.d.ts"
120
+ ],
121
+ "microfrontends/utils": [
122
+ "./dist/microfrontends/utils.d.ts"
123
+ ],
124
+ schema: [
125
+ "./dist/schema.d.ts"
126
+ ],
127
+ "next/config": [
128
+ "./dist/next/config.d.ts"
129
+ ],
130
+ "next/middleware": [
131
+ "./dist/next/middleware.d.ts"
132
+ ],
133
+ "next/endpoints": [
134
+ "./dist/next/endpoints.d.ts"
135
+ ],
136
+ "next/testing": [
137
+ "./dist/next/testing.d.ts"
138
+ ],
139
+ "next/client": [
140
+ "./dist/next/client.d.ts"
141
+ ],
142
+ "utils/mfe-port": [
143
+ "./dist/utils/mfe-port.d.ts"
144
+ ]
121
145
  }
122
146
  },
123
- files: ["dist", "schema"],
147
+ bin: {
148
+ microfrontends: "./cli/index.cjs"
149
+ },
150
+ files: [
151
+ "dist",
152
+ "schema"
153
+ ],
124
154
  scripts: {
125
155
  build: "tsup",
126
156
  postbuild: "pnpm generate:exports",
127
- "generate:schema": "tsx scripts/generate-json-schema.ts",
128
157
  "generate:exports": "tsx scripts/generate-exports/index.ts",
129
- conformance: "vercel conformance",
130
- eslint: "eslint-runner",
131
- "eslint-fix": "eslint-runner --fix",
158
+ "generate:schema": "tsx scripts/generate-json-schema.ts",
159
+ lint: "eslint .",
160
+ "lint-fix": "eslint . --fix",
132
161
  prepublishOnly: "pnpm build && pnpm generate:exports && pnpm generate:schema",
133
- "type-check": "tsc --noEmit",
134
- "unit-test": "cross-env TZ=UTC jest",
135
- proxy: "tsx src/proxy/index.ts"
162
+ proxy: "tsx src/proxy/index.ts",
163
+ test: "cross-env TZ=UTC jest",
164
+ typecheck: "tsc --noEmit"
136
165
  },
137
166
  dependencies: {
138
167
  ajv: "^8.17.1",
@@ -144,9 +173,8 @@ var package_default = {
144
173
  "path-to-regexp": "6.2.1"
145
174
  },
146
175
  devDependencies: {
176
+ "@edge-runtime/jest-environment": "^4.0.0",
147
177
  "@edge-runtime/types": "^3.0.2",
148
- "@pyra/eslint-config": "workspace:*",
149
- "@pyra/typescript-config": "workspace:*",
150
178
  "@testing-library/react": "^15.0.7",
151
179
  "@types/cookie": "0.5.1",
152
180
  "@types/http-proxy": "^1.17.15",
@@ -155,31 +183,31 @@ var package_default = {
155
183
  "@types/node": "20.11.30",
156
184
  "@types/react": "18.3.1",
157
185
  "@types/react-dom": "18.3.0",
158
- "@vercel-private/conformance": "^1.12.2-canary.0",
186
+ "eslint-config-custom": "workspace:*",
159
187
  jest: "^29.7.0",
160
188
  "jest-environment-jsdom": "29.2.2",
161
- next: "15.2.0-canary.23",
189
+ next: "15.2.0-canary.32",
162
190
  react: "19.0.0",
163
191
  "react-dom": "19.0.0",
192
+ "ts-config": "workspace:*",
164
193
  "ts-json-schema-generator": "^1.1.2",
194
+ "ts-node": "~10.9.2",
165
195
  tsup: "^6.6.2",
166
196
  tsx: "^4.6.2",
167
- typescript: "5.6.3",
197
+ typescript: "5.7.3",
168
198
  webpack: "5"
169
199
  },
170
200
  peerDependencies: {
171
- next: "15.2.0-canary.23",
201
+ next: "15.2.0-canary.32",
172
202
  react: "19.0.0",
173
203
  "react-dom": "19.0.0"
174
- },
175
- publishConfig: {
176
- access: "restricted"
177
204
  }
178
205
  };
179
206
 
180
207
  // src/bin/local-proxy.ts
181
208
  var http = __toESM(require("http"), 1);
182
209
  var https = __toESM(require("https"), 1);
210
+ var import_node_url = require("url");
183
211
  var import_cookie = require("cookie");
184
212
  var import_path_to_regexp3 = require("path-to-regexp");
185
213
  var import_http_proxy = __toESM(require("http-proxy"), 1);
@@ -194,9 +222,9 @@ var MicrofrontendError = class extends Error {
194
222
  constructor(message, opts) {
195
223
  super(message);
196
224
  this.name = "MicrofrontendsError";
197
- this.source = (opts == null ? void 0 : opts.source) ?? "@vercel/microfrontends";
198
- this.type = (opts == null ? void 0 : opts.type) ?? "unknown";
199
- this.subtype = opts == null ? void 0 : opts.subtype;
225
+ this.source = opts?.source ?? "@vercel/microfrontends";
226
+ this.type = opts?.type ?? "unknown";
227
+ this.subtype = opts?.subtype;
200
228
  Error.captureStackTrace(this, MicrofrontendError);
201
229
  }
202
230
  isKnown() {
@@ -211,7 +239,7 @@ var MicrofrontendError = class extends Error {
211
239
  * @returns The converted MicrofrontendsError.
212
240
  */
213
241
  static convert(original, opts) {
214
- if (opts == null ? void 0 : opts.fileName) {
242
+ if (opts?.fileName) {
215
243
  const err = MicrofrontendError.convertFSError(original, opts.fileName);
216
244
  if (err) {
217
245
  return err;
@@ -283,17 +311,6 @@ var MicrofrontendError = class extends Error {
283
311
 
284
312
  // src/config/microfrontends-config/isomorphic/validation.ts
285
313
  var import_path_to_regexp = require("path-to-regexp");
286
- var SUPPORTED_VERSIONS = ["2"];
287
- var validateConfigVersion = (version) => {
288
- if (!SUPPORTED_VERSIONS.includes(version)) {
289
- throw new MicrofrontendError(
290
- `Unsupported version: ${version}. Supported versions are: ${SUPPORTED_VERSIONS.join(
291
- ", "
292
- )}`,
293
- { type: "config", subtype: "unsupported_version" }
294
- );
295
- }
296
- };
297
314
  var validateConfigPaths = (applicationConfigsById) => {
298
315
  if (!applicationConfigsById) {
299
316
  return;
@@ -469,7 +486,7 @@ var Host = class {
469
486
  this.protocol = protocol;
470
487
  this.host = host;
471
488
  this.port = Host.getPort({ port, protocol: this.protocol });
472
- this.local = options == null ? void 0 : options.isLocal;
489
+ this.local = options?.isLocal;
473
490
  }
474
491
  isLocal() {
475
492
  return this.local || this.host === "localhost" || this.host === "127.0.0.1";
@@ -518,18 +535,17 @@ var Application = class {
518
535
  overrides,
519
536
  isDefault
520
537
  }) {
521
- var _a, _b;
522
538
  this.name = name;
523
539
  this.development = {
524
540
  local: new LocalHost({
525
541
  appName: name,
526
- ...(_a = app.development) == null ? void 0 : _a.local
542
+ ...app.development?.local
527
543
  }),
528
- fallback: ((_b = app.development) == null ? void 0 : _b.fallback) ? new Host(app.development.fallback) : void 0
544
+ fallback: app.development?.fallback ? new Host(app.development.fallback) : void 0
529
545
  };
530
546
  this.production = app.production ? new Host(app.production) : void 0;
531
547
  this.vercel = app.vercel;
532
- this.overrides = (overrides == null ? void 0 : overrides.environment) ? {
548
+ this.overrides = overrides?.environment ? {
533
549
  environment: new Host(overrides.environment)
534
550
  } : void 0;
535
551
  this.default = isDefault ?? false;
@@ -607,7 +623,7 @@ var MicrofrontendConfigClient = class {
607
623
  constructor(config, opts) {
608
624
  this.pathCache = {};
609
625
  this.serialized = config;
610
- if (opts == null ? void 0 : opts.removeFlaggedPaths) {
626
+ if (opts?.removeFlaggedPaths) {
611
627
  for (const app of Object.values(config.applications)) {
612
628
  if (app.routing) {
613
629
  app.routing = app.routing.filter((match) => !match.flag);
@@ -673,8 +689,7 @@ var OVERRIDES_ENV_COOKIE_PREFIX = `${OVERRIDES_COOKIE_PREFIX}:env:`;
673
689
 
674
690
  // src/config/overrides/is-override-cookie.ts
675
691
  function isOverrideCookie(cookie) {
676
- var _a;
677
- return Boolean((_a = cookie.name) == null ? void 0 : _a.startsWith(OVERRIDES_COOKIE_PREFIX));
692
+ return Boolean(cookie.name?.startsWith(OVERRIDES_COOKIE_PREFIX));
678
693
  }
679
694
 
680
695
  // src/config/overrides/get-override-from-cookie.ts
@@ -709,17 +724,17 @@ var MicrofrontendConfigIsomorphic = class {
709
724
  constructor({
710
725
  config,
711
726
  overrides,
712
- meta
727
+ meta,
728
+ opts
713
729
  }) {
714
730
  this.childApplications = {};
715
- var _a, _b, _c, _d;
716
- MicrofrontendConfigIsomorphic.validate(config);
717
- const disableOverrides = ((_b = (_a = config.options) == null ? void 0 : _a.vercel) == null ? void 0 : _b.disableOverrides) ?? false;
731
+ MicrofrontendConfigIsomorphic.validate(config, opts);
732
+ const disableOverrides = config.options?.vercel?.disableOverrides ?? false;
718
733
  this.overrides = overrides && !disableOverrides ? overrides : void 0;
719
734
  this.isMainConfig = isMainConfig(config);
720
735
  if (isMainConfig(config)) {
721
736
  for (const [appId, appConfig] of Object.entries(config.applications)) {
722
- const appOverrides = !disableOverrides ? (_c = this.overrides) == null ? void 0 : _c.applications[appId] : void 0;
737
+ const appOverrides = !disableOverrides ? this.overrides?.applications[appId] : void 0;
723
738
  if (isDefaultApp(appConfig)) {
724
739
  this.defaultApplication = new DefaultApplication(appId, {
725
740
  app: appConfig,
@@ -734,7 +749,7 @@ var MicrofrontendConfigIsomorphic = class {
734
749
  }
735
750
  } else {
736
751
  this.partOf = config.partOf;
737
- const appOverrides = !disableOverrides ? (_d = this.overrides) == null ? void 0 : _d.applications[meta.fromApp] : void 0;
752
+ const appOverrides = !disableOverrides ? this.overrides?.applications[meta.fromApp] : void 0;
738
753
  this.childApplications[meta.fromApp] = new ChildApplication(
739
754
  meta.fromApp,
740
755
  {
@@ -762,12 +777,9 @@ var MicrofrontendConfigIsomorphic = class {
762
777
  };
763
778
  }
764
779
  static validate(config, opts) {
765
- const skipValidation = (opts == null ? void 0 : opts.skipValidation) ?? [];
780
+ const skipValidation = opts?.skipValidation ?? [];
766
781
  const c = typeof config === "string" ? (0, import_jsonc_parser.parse)(config) : config;
767
782
  if (isMainConfig(c)) {
768
- if (!skipValidation.includes("version")) {
769
- validateConfigVersion(c.version);
770
- }
771
783
  if (!skipValidation.includes("paths")) {
772
784
  validateConfigPaths(c.applications);
773
785
  }
@@ -788,8 +800,7 @@ var MicrofrontendConfigIsomorphic = class {
788
800
  });
789
801
  }
790
802
  isOverridesDisabled() {
791
- var _a, _b;
792
- return ((_b = (_a = this.options) == null ? void 0 : _a.vercel) == null ? void 0 : _b.disableOverrides) ?? false;
803
+ return this.options?.vercel?.disableOverrides ?? false;
793
804
  }
794
805
  getConfig() {
795
806
  return this.config;
@@ -810,8 +821,7 @@ var MicrofrontendConfigIsomorphic = class {
810
821
  ].filter(Boolean);
811
822
  }
812
823
  getApplication(name) {
813
- var _a;
814
- if (((_a = this.defaultApplication) == null ? void 0 : _a.name) === name) {
824
+ if (this.defaultApplication?.name === name) {
815
825
  return this.defaultApplication;
816
826
  }
817
827
  const app = this.childApplications[name];
@@ -827,15 +837,11 @@ var MicrofrontendConfigIsomorphic = class {
827
837
  return app;
828
838
  }
829
839
  getApplicationByProjectId(projectId) {
830
- var _a, _b;
831
- if (((_b = (_a = this.defaultApplication) == null ? void 0 : _a.vercel) == null ? void 0 : _b.projectId) === projectId) {
840
+ if (this.defaultApplication?.vercel?.projectId === projectId) {
832
841
  return this.defaultApplication;
833
842
  }
834
843
  return Object.values(this.childApplications).find(
835
- (app) => {
836
- var _a2;
837
- return ((_a2 = app.vercel) == null ? void 0 : _a2.projectId) === projectId;
838
- }
844
+ (app) => app.vercel?.projectId === projectId
839
845
  );
840
846
  }
841
847
  /**
@@ -858,8 +864,7 @@ var MicrofrontendConfigIsomorphic = class {
858
864
  * Returns the configured port for the local proxy
859
865
  */
860
866
  getLocalProxyPort() {
861
- var _a, _b;
862
- return ((_b = (_a = this.config.options) == null ? void 0 : _a.localProxy) == null ? void 0 : _b.port) ?? DEFAULT_LOCAL_PROXY_PORT;
867
+ return this.config.options?.localProxy?.port ?? DEFAULT_LOCAL_PROXY_PORT;
863
868
  }
864
869
  /**
865
870
  * Serializes the class back to the Schema type.
@@ -900,13 +905,12 @@ var MicrofrontendMainConfig = class extends MicrofrontendConfigIsomorphic {
900
905
  overrides,
901
906
  meta
902
907
  }) {
903
- var _a, _b, _c;
904
908
  super({ config, overrides, meta });
905
909
  this.isMainConfig = true;
906
- const disableOverrides = ((_b = (_a = config.options) == null ? void 0 : _a.vercel) == null ? void 0 : _b.disableOverrides) ?? false;
910
+ const disableOverrides = config.options?.vercel?.disableOverrides ?? false;
907
911
  let defaultApplication;
908
912
  for (const [appId, appConfig] of Object.entries(config.applications)) {
909
- const appOverrides = !disableOverrides ? (_c = this.overrides) == null ? void 0 : _c.applications[appId] : void 0;
913
+ const appOverrides = !disableOverrides ? this.overrides?.applications[appId] : void 0;
910
914
  if (isDefaultApp(appConfig)) {
911
915
  defaultApplication = new DefaultApplication(appId, {
912
916
  app: appConfig,
@@ -1121,7 +1125,7 @@ function findDefaultMicrofrontendsPackage(opts) {
1121
1125
  const result = findDefaultMicrofrontendsPackages(opts);
1122
1126
  if (!result) {
1123
1127
  throw new Error(
1124
- `Error trying to resolve the main microfrontends configuration`
1128
+ "Error trying to resolve the main microfrontends configuration"
1125
1129
  );
1126
1130
  }
1127
1131
  configCache2[cacheKey] = result;
@@ -1193,20 +1197,8 @@ var import_node_path7 = __toESM(require("path"), 1);
1193
1197
  var MFE_CONFIG_DEFAULT_FILE_PATH = "microfrontends";
1194
1198
  var MFE_CONFIG_DEFAULT_FILE_NAME = "microfrontends.json";
1195
1199
 
1196
- // src/utils/is-vercel.ts
1197
- function isVercel() {
1198
- return process.env.VERCEL === "1";
1199
- }
1200
-
1201
1200
  // src/config/microfrontends/server/utils/get-output-file-path.ts
1202
1201
  function getOutputFilePath() {
1203
- if (isVercel()) {
1204
- return import_node_path7.default.join(
1205
- ".vercel",
1206
- MFE_CONFIG_DEFAULT_FILE_PATH,
1207
- MFE_CONFIG_DEFAULT_FILE_NAME
1208
- );
1209
- }
1210
1202
  return import_node_path7.default.join(MFE_CONFIG_DEFAULT_FILE_PATH, MFE_CONFIG_DEFAULT_FILE_NAME);
1211
1203
  }
1212
1204
 
@@ -1237,7 +1229,7 @@ var schema_default = {
1237
1229
  },
1238
1230
  version: {
1239
1231
  type: "string",
1240
- const: "2"
1232
+ const: "1"
1241
1233
  },
1242
1234
  options: {
1243
1235
  $ref: "#/definitions/Options"
@@ -1247,6 +1239,9 @@ var schema_default = {
1247
1239
  additionalProperties: {
1248
1240
  $ref: "#/definitions/Application"
1249
1241
  },
1242
+ propertyNames: {
1243
+ description: "The unique identifier for a Microfrontend Application. Must match the `name` field of the application's `package.json`."
1244
+ },
1250
1245
  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."
1251
1246
  },
1252
1247
  applications: {
@@ -1254,7 +1249,9 @@ var schema_default = {
1254
1249
  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"
1255
1250
  }
1256
1251
  },
1257
- required: ["applications", "version"],
1252
+ required: [
1253
+ "applications"
1254
+ ],
1258
1255
  additionalProperties: false
1259
1256
  },
1260
1257
  Options: {
@@ -1318,7 +1315,9 @@ var schema_default = {
1318
1315
  $ref: "#/definitions/HostConfig"
1319
1316
  }
1320
1317
  },
1321
- required: ["production"],
1318
+ required: [
1319
+ "production"
1320
+ ],
1322
1321
  additionalProperties: false
1323
1322
  },
1324
1323
  Vercel: {
@@ -1329,7 +1328,9 @@ var schema_default = {
1329
1328
  description: "Vercel project ID"
1330
1329
  }
1331
1330
  },
1332
- required: ["projectId"],
1331
+ required: [
1332
+ "projectId"
1333
+ ],
1333
1334
  additionalProperties: false
1334
1335
  },
1335
1336
  Development: {
@@ -1359,8 +1360,11 @@ var schema_default = {
1359
1360
  },
1360
1361
  protocol: {
1361
1362
  type: "string",
1362
- enum: ["http", "https"],
1363
- 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'
1363
+ enum: [
1364
+ "http",
1365
+ "https"
1366
+ ],
1367
+ description: "The protocol to be used for the connection.\n- `http`: Hypertext Transfer Protocol (HTTP).\n- `https`: Secure Hypertext Transfer Protocol (HTTPS).\n\n*"
1364
1368
  },
1365
1369
  port: {
1366
1370
  type: "number",
@@ -1373,8 +1377,11 @@ var schema_default = {
1373
1377
  properties: {
1374
1378
  protocol: {
1375
1379
  type: "string",
1376
- enum: ["http", "https"],
1377
- 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'
1380
+ enum: [
1381
+ "http",
1382
+ "https"
1383
+ ],
1384
+ description: "The protocol to be used for the connection.\n- `http`: Hypertext Transfer Protocol (HTTP).\n- `https`: Secure Hypertext Transfer Protocol (HTTPS).\n\n*"
1378
1385
  },
1379
1386
  host: {
1380
1387
  type: "string",
@@ -1385,7 +1392,9 @@ var schema_default = {
1385
1392
  description: "The port number to be used for the connection. Common values include `80` for HTTP and `443` for HTTPS."
1386
1393
  }
1387
1394
  },
1388
- required: ["host"],
1395
+ required: [
1396
+ "host"
1397
+ ],
1389
1398
  additionalProperties: false
1390
1399
  },
1391
1400
  ChildApplication: {
@@ -1405,7 +1414,9 @@ var schema_default = {
1405
1414
  $ref: "#/definitions/HostConfig"
1406
1415
  }
1407
1416
  },
1408
- required: ["routing"],
1417
+ required: [
1418
+ "routing"
1419
+ ],
1409
1420
  additionalProperties: false
1410
1421
  },
1411
1422
  Routing: {
@@ -1432,13 +1443,18 @@ var schema_default = {
1432
1443
  }
1433
1444
  }
1434
1445
  },
1435
- required: ["paths"],
1446
+ required: [
1447
+ "paths"
1448
+ ],
1436
1449
  additionalProperties: false
1437
1450
  },
1438
1451
  ApplicationRouting: {
1439
1452
  type: "object",
1440
1453
  additionalProperties: {
1441
1454
  $ref: "#/definitions/Application"
1455
+ },
1456
+ propertyNames: {
1457
+ description: "The unique identifier for a Microfrontend Application. Must match the `name` field of the application's `package.json`."
1442
1458
  }
1443
1459
  },
1444
1460
  ChildConfig: {
@@ -1449,7 +1465,7 @@ var schema_default = {
1449
1465
  },
1450
1466
  version: {
1451
1467
  type: "string",
1452
- const: "2"
1468
+ const: "1"
1453
1469
  },
1454
1470
  options: {
1455
1471
  $ref: "#/definitions/Options"
@@ -1459,6 +1475,9 @@ var schema_default = {
1459
1475
  additionalProperties: {
1460
1476
  $ref: "#/definitions/Application"
1461
1477
  },
1478
+ propertyNames: {
1479
+ description: "The unique identifier for a Microfrontend Application. Must match the `name` field of the application's `package.json`."
1480
+ },
1462
1481
  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."
1463
1482
  },
1464
1483
  partOf: {
@@ -1466,7 +1485,9 @@ var schema_default = {
1466
1485
  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."
1467
1486
  }
1468
1487
  },
1469
- required: ["partOf", "version"],
1488
+ required: [
1489
+ "partOf"
1490
+ ],
1470
1491
  additionalProperties: false
1471
1492
  }
1472
1493
  }
@@ -1640,7 +1661,7 @@ var MicrofrontendsServer = class extends Microfrontends {
1640
1661
  try {
1641
1662
  const configJson = import_node_fs7.default.readFileSync(filePath, "utf-8");
1642
1663
  const config = MicrofrontendsServer.validate(configJson);
1643
- if (!isMainConfig(config) && (options == null ? void 0 : options.resolveMainConfig)) {
1664
+ if (!isMainConfig(config) && options?.resolveMainConfig) {
1644
1665
  const repositoryRoot = findRepositoryRoot();
1645
1666
  const isMonorepo2 = isMonorepo({ repositoryRoot });
1646
1667
  if (isMonorepo2) {
@@ -1724,53 +1745,29 @@ var mfeDebug = (message) => {
1724
1745
  console.log(message);
1725
1746
  }
1726
1747
  };
1727
- var LocalProxy = class {
1748
+ var ProxyRequestRouter = class {
1728
1749
  constructor(config, {
1729
- localApps,
1730
- proxyPort
1750
+ localApps
1731
1751
  }) {
1732
1752
  this.config = config;
1733
1753
  this.localApps = localApps;
1734
- this.proxyPort = proxyPort ?? this.config.getLocalProxyPort();
1735
- this.proxy = import_http_proxy.default.createProxyServer({ secure: true });
1736
- this.proxy.on("error", (err, req, res) => {
1737
- if (res instanceof http.ServerResponse) {
1738
- res.writeHead(500, {
1739
- "Content-Type": "text/plain"
1740
- });
1741
- }
1742
- const target = this.getTarget(req);
1743
- res.end(
1744
- `Error proxying request to ${target.application}. Is the server running locally on port ${target.port}?`
1745
- );
1746
- console.error(`Error proxying request for ${target.application}: `, err);
1747
- });
1748
- }
1749
- static fromFile(filePath, {
1750
- localApps,
1751
- proxyPort
1752
- }) {
1753
- const microfrontends = MicrofrontendsServer.infer({
1754
- directory: filePath
1755
- });
1756
- if (isMainConfig2(microfrontends.config)) {
1757
- return new LocalProxy(microfrontends.config, { localApps, proxyPort });
1758
- }
1759
- throw new Error(
1760
- `Unable to find main config from child application (${filePath})`
1761
- );
1762
1754
  }
1763
1755
  getDefaultHost(config) {
1764
1756
  const defaultApp = config.getDefaultApplication();
1765
1757
  return this.getApplicationTarget(defaultApp);
1766
1758
  }
1767
1759
  getApplicationTarget(application) {
1768
- var _a, _b;
1769
1760
  const useDev = this.localApps.includes(application.name);
1770
- let host = useDev ? application.development.local : application.production ?? this.config.getDefaultApplication().production;
1771
- if ((_b = (_a = application.overrides) == null ? void 0 : _a.environment) == null ? void 0 : _b.host) {
1761
+ let applicationName = application.name;
1762
+ let host = useDev ? application.development.local : application.production;
1763
+ if (application.overrides?.environment?.host) {
1772
1764
  host = application.overrides.environment;
1773
1765
  }
1766
+ if (!host) {
1767
+ const defaultApp = this.config.getDefaultApplication();
1768
+ host = defaultApp.production;
1769
+ applicationName = defaultApp.name;
1770
+ }
1774
1771
  const protocol = host.protocol;
1775
1772
  const hostname = host.host;
1776
1773
  const port = host.port;
@@ -1779,7 +1776,7 @@ var LocalProxy = class {
1779
1776
  protocol,
1780
1777
  hostname,
1781
1778
  port,
1782
- application: application.name
1779
+ application: applicationName
1783
1780
  };
1784
1781
  }
1785
1782
  /**
@@ -1789,12 +1786,11 @@ var LocalProxy = class {
1789
1786
  * protected host.
1790
1787
  */
1791
1788
  getAuthTarget(request2, config) {
1792
- var _a, _b;
1793
- const url = new URL(request2.url ?? "", `http://${request2.headers.host}`);
1794
- const isAuthRedirect = (_a = request2.url) == null ? void 0 : _a.startsWith(
1789
+ const url = new import_node_url.URL(request2.url ?? "", `http://${request2.headers.host}`);
1790
+ const isAuthRedirect = request2.url?.startsWith(
1795
1791
  "/.well-known/vercel-auth-redirect"
1796
1792
  );
1797
- const isSsoRedirect = (_b = request2.url) == null ? void 0 : _b.startsWith("/sso-api");
1793
+ const isSsoRedirect = request2.url?.startsWith("/sso-api");
1798
1794
  const isJWTRedirect = url.searchParams.has("_vercel_jwt");
1799
1795
  const defaultHost = this.getDefaultHost(config);
1800
1796
  let hostname = null;
@@ -1842,13 +1838,13 @@ var LocalProxy = class {
1842
1838
  if (authTarget) {
1843
1839
  return authTarget;
1844
1840
  }
1845
- const url = new URL(`http://example.com${path6}`);
1846
- const pathname = url.pathname;
1847
- const target = this.findMatchingApplication(
1848
- path6,
1849
- pathname,
1850
- config.getChildApplications()
1851
- );
1841
+ const url = new import_node_url.URL(`http://example.com${path6}`);
1842
+ const target = this.findMatchingApplication({
1843
+ path: path6,
1844
+ url,
1845
+ applications: config.getChildApplications(),
1846
+ referer: request2.headers.referer
1847
+ });
1852
1848
  if (target)
1853
1849
  return target;
1854
1850
  const defaultHost = this.getDefaultHost(config);
@@ -1857,13 +1853,31 @@ var LocalProxy = class {
1857
1853
  );
1858
1854
  return { path: path6, ...defaultHost };
1859
1855
  }
1860
- findMatchingApplication(path6, pathname, applications) {
1856
+ findMatchingApplication({
1857
+ path: path6,
1858
+ url,
1859
+ applications,
1860
+ referer = void 0
1861
+ }) {
1861
1862
  for (const application of Object.values(applications)) {
1863
+ const target = this.getApplicationTarget(application);
1864
+ const builtInRewrite = this.checkBuiltinAssetPrefix({
1865
+ rewrites: [
1866
+ "/_next/static/:path+",
1867
+ "/.well-known/vercel/flags",
1868
+ "/_vercel/:path*"
1869
+ ],
1870
+ path: path6,
1871
+ url,
1872
+ app: application
1873
+ }) || this.checkNextOriginalFrame({ url, referer, applications });
1874
+ if (builtInRewrite) {
1875
+ return builtInRewrite;
1876
+ }
1862
1877
  for (const group of application.routing) {
1863
1878
  for (const childPath of group.paths) {
1864
1879
  const regexp = (0, import_path_to_regexp3.pathToRegexp)(childPath);
1865
- if (regexp.test(pathname)) {
1866
- const target = this.getApplicationTarget(application);
1880
+ if (regexp.test(url.pathname)) {
1867
1881
  mfeDebug(
1868
1882
  `routing ${path6} to '${target.application}' at ${target.hostname}`
1869
1883
  );
@@ -1874,39 +1888,112 @@ var LocalProxy = class {
1874
1888
  }
1875
1889
  return null;
1876
1890
  }
1877
- // Handles requests that return data from the local proxy itself.
1878
- // Returns true if the request was handled, false otherwise.
1879
- handleProxyInfoRequest(path6, res) {
1880
- if (!path6) {
1881
- return false;
1882
- }
1883
- const url = new URL(`http://example.comf${path6}`);
1891
+ checkBuiltinAssetPrefix({
1892
+ rewrites,
1893
+ path: path6,
1894
+ url,
1895
+ app
1896
+ }) {
1884
1897
  const pathname = url.pathname;
1885
- switch (pathname) {
1886
- case "/.well-known/vercel/microfrontends/routing": {
1887
- res.writeHead(200, {
1888
- "Content-Type": "application/json"
1889
- });
1890
- const payload = Object.fromEntries(
1891
- this.config.getAllApplications().map((app) => {
1892
- const { hostname, port, protocol } = this.getApplicationTarget(app);
1893
- return [
1894
- app.name,
1895
- { routing: { host: hostname, port, protocol } }
1896
- ];
1897
- })
1898
+ const target = this.getApplicationTarget(app);
1899
+ const isTargetDefault = target.application === this.config.getDefaultApplication().name;
1900
+ for (const rewrite of rewrites) {
1901
+ if ((0, import_path_to_regexp3.pathToRegexp)(`/${app.getAssetPrefix()}${rewrite}`).test(pathname)) {
1902
+ mfeDebug(
1903
+ `routing ${pathname} to '${target.application}' at ${target.hostname}`
1898
1904
  );
1899
- res.end(JSON.stringify(payload));
1900
- return true;
1905
+ const processedPath = isTargetDefault ? path6 : path6.replace(`/${app.getAssetPrefix()}`, "");
1906
+ return {
1907
+ path: processedPath,
1908
+ ...target
1909
+ };
1901
1910
  }
1902
1911
  }
1903
- return false;
1912
+ return null;
1913
+ }
1914
+ checkNextOriginalFrame({
1915
+ url,
1916
+ referer = void 0,
1917
+ applications
1918
+ }) {
1919
+ const isStackFrame = (0, import_path_to_regexp3.pathToRegexp)("/__nextjs_original-stack-frame").test(
1920
+ url.pathname
1921
+ );
1922
+ if (!referer || !isStackFrame) {
1923
+ return null;
1924
+ }
1925
+ const refererURL = new import_node_url.URL(referer);
1926
+ const refererPath = `${refererURL.pathname}?${refererURL.search}`;
1927
+ const refererApp = this.findMatchingApplication({
1928
+ path: refererPath,
1929
+ url: refererURL,
1930
+ applications
1931
+ });
1932
+ mfeDebug(
1933
+ `routing nextjs stack frame request to ${refererApp?.application}`
1934
+ );
1935
+ return refererApp ? {
1936
+ ...refererApp,
1937
+ path: `${url.pathname}${url.search}`
1938
+ } : null;
1939
+ }
1940
+ };
1941
+ var LocalProxy = class {
1942
+ constructor(config, {
1943
+ localApps,
1944
+ proxyPort
1945
+ }) {
1946
+ this.router = new ProxyRequestRouter(config, { localApps });
1947
+ this.proxyPort = proxyPort ?? this.router.config.getLocalProxyPort();
1948
+ this.proxy = import_http_proxy.default.createProxyServer({ secure: true });
1949
+ this.proxy.on("error", (err, req, res) => {
1950
+ if (res instanceof http.ServerResponse) {
1951
+ res.writeHead(500, {
1952
+ "Content-Type": "text/plain"
1953
+ });
1954
+ }
1955
+ const target = this.router.getTarget(req);
1956
+ res.end(
1957
+ `Error proxying request to ${target.application}. Is the server running locally on port ${target.port}?`
1958
+ );
1959
+ console.error(`Error proxying request for ${target.application}: `, err);
1960
+ });
1961
+ }
1962
+ static fromFile(filePath, {
1963
+ localApps,
1964
+ proxyPort
1965
+ }) {
1966
+ const microfrontends = MicrofrontendsServer.infer({
1967
+ directory: filePath
1968
+ });
1969
+ if (isMainConfig2(microfrontends.config)) {
1970
+ return new LocalProxy(microfrontends.config, { localApps, proxyPort });
1971
+ }
1972
+ throw new Error(
1973
+ `Unable to find main config from child application (${filePath})`
1974
+ );
1975
+ }
1976
+ startServer() {
1977
+ const httpServer = http.createServer(
1978
+ (req, res) => this.handleRequest(req, res)
1979
+ );
1980
+ httpServer.on("upgrade", (req, socket, head) => {
1981
+ const target = this.router.getTarget(req);
1982
+ try {
1983
+ this.proxy.ws(req, socket, head, { target: target.url });
1984
+ } catch (err) {
1985
+ console.error("Error proxying ws: ", err);
1986
+ }
1987
+ });
1988
+ httpServer.listen(this.proxyPort, () => {
1989
+ console.log(`Microfrontends Proxy: http://localhost:${this.proxyPort}`);
1990
+ });
1904
1991
  }
1905
1992
  handleRequest(req, res) {
1906
1993
  if (this.handleProxyInfoRequest(req.url, res)) {
1907
1994
  return;
1908
1995
  }
1909
- const target = this.getTarget(req);
1996
+ const target = this.router.getTarget(req);
1910
1997
  if (target.protocol === "https") {
1911
1998
  const { hostname, port, path: path6 } = target;
1912
1999
  const requestOptions = {
@@ -1924,7 +2011,7 @@ var LocalProxy = class {
1924
2011
  if (realRes.statusCode === 307) {
1925
2012
  const locationHeader = realRes.headers.location;
1926
2013
  if (locationHeader) {
1927
- const redirectUrl = new URL(
2014
+ const redirectUrl = new import_node_url.URL(
1928
2015
  locationHeader.replace(/https:\/\/[^/]+\//, "/"),
1929
2016
  localhost
1930
2017
  );
@@ -1948,21 +2035,33 @@ var LocalProxy = class {
1948
2035
  });
1949
2036
  }
1950
2037
  }
1951
- startServer() {
1952
- const httpServer = http.createServer(
1953
- (req, res) => this.handleRequest(req, res)
1954
- );
1955
- httpServer.on("upgrade", (req, socket, head) => {
1956
- const target = this.getTarget(req);
1957
- try {
1958
- this.proxy.ws(req, socket, head, { target: target.url });
1959
- } catch (err) {
1960
- console.error("Error proxying ws: ", err);
2038
+ // Handles requests that return data from the local proxy itself.
2039
+ // Returns true if the request was handled, false otherwise.
2040
+ handleProxyInfoRequest(path6, res) {
2041
+ if (!path6) {
2042
+ return false;
2043
+ }
2044
+ const url = new import_node_url.URL(`http://example.comf${path6}`);
2045
+ const pathname = url.pathname;
2046
+ switch (pathname) {
2047
+ case "/.well-known/vercel/microfrontends/routing": {
2048
+ res.writeHead(200, {
2049
+ "Content-Type": "application/json"
2050
+ });
2051
+ const payload = Object.fromEntries(
2052
+ this.router.config.getAllApplications().map((app) => {
2053
+ const { hostname, port, protocol } = this.router.getApplicationTarget(app);
2054
+ return [
2055
+ app.name,
2056
+ { routing: { host: hostname, port, protocol } }
2057
+ ];
2058
+ })
2059
+ );
2060
+ res.end(JSON.stringify(payload));
2061
+ return true;
1961
2062
  }
1962
- });
1963
- httpServer.listen(this.proxyPort, () => {
1964
- console.log(`Microfrontends Proxy: http://localhost:${this.proxyPort}`);
1965
- });
2063
+ }
2064
+ return false;
1966
2065
  }
1967
2066
  };
1968
2067