@vercel/microfrontends 0.14.0 → 0.16.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 (121) hide show
  1. package/dist/bin/cli.cjs +392 -1620
  2. package/dist/config.cjs +478 -1001
  3. package/dist/config.cjs.map +1 -1
  4. package/dist/config.d.ts +4 -25
  5. package/dist/config.js +474 -980
  6. package/dist/config.js.map +1 -1
  7. package/dist/{v2/microfrontends → microfrontends}/server.cjs +91 -150
  8. package/dist/microfrontends/server.cjs.map +1 -0
  9. package/dist/{v2/microfrontends → microfrontends}/server.d.ts +4 -4
  10. package/dist/{v2/microfrontends → microfrontends}/server.js +91 -150
  11. package/dist/microfrontends/server.js.map +1 -0
  12. package/dist/{v2/microfrontends.cjs → microfrontends.cjs} +49 -28
  13. package/dist/microfrontends.cjs.map +1 -0
  14. package/dist/{v2/microfrontends.d.ts → microfrontends.d.ts} +4 -4
  15. package/dist/{v2/microfrontends.js → microfrontends.js} +48 -27
  16. package/dist/microfrontends.js.map +1 -0
  17. package/dist/next/client.cjs +1 -1
  18. package/dist/next/client.cjs.map +1 -1
  19. package/dist/next/client.js +1 -1
  20. package/dist/next/client.js.map +1 -1
  21. package/dist/next/config.cjs +1344 -1024
  22. package/dist/next/config.cjs.map +1 -1
  23. package/dist/next/config.d.ts +1 -1
  24. package/dist/next/config.js +1343 -1023
  25. package/dist/next/config.js.map +1 -1
  26. package/dist/next/endpoints.cjs +77 -18
  27. package/dist/next/endpoints.cjs.map +1 -1
  28. package/dist/next/endpoints.d.ts +13 -2
  29. package/dist/next/endpoints.js +77 -18
  30. package/dist/next/endpoints.js.map +1 -1
  31. package/dist/next/middleware.cjs +765 -395
  32. package/dist/next/middleware.cjs.map +1 -1
  33. package/dist/next/middleware.d.ts +10 -5
  34. package/dist/next/middleware.js +765 -395
  35. package/dist/next/middleware.js.map +1 -1
  36. package/dist/next/testing.cjs +615 -1031
  37. package/dist/next/testing.cjs.map +1 -1
  38. package/dist/next/testing.d.ts +14 -12
  39. package/dist/next/testing.js +609 -1015
  40. package/dist/next/testing.js.map +1 -1
  41. package/dist/overrides.cjs +40 -108
  42. package/dist/overrides.cjs.map +1 -1
  43. package/dist/overrides.d.ts +24 -2
  44. package/dist/overrides.js +36 -106
  45. package/dist/overrides.js.map +1 -1
  46. package/dist/{v2/routing.cjs → routing.cjs} +3 -3
  47. package/dist/routing.cjs.map +1 -0
  48. package/dist/{v2/schema.cjs → schema.cjs} +1 -1
  49. package/dist/schema.cjs.map +1 -0
  50. package/dist/schema.d.ts +1 -0
  51. package/dist/utils/mfe-port.cjs +237 -1338
  52. package/dist/utils/mfe-port.cjs.map +1 -1
  53. package/dist/utils/mfe-port.js +230 -1331
  54. package/dist/utils/mfe-port.js.map +1 -1
  55. package/dist/validation.cjs +31 -361
  56. package/dist/validation.cjs.map +1 -1
  57. package/dist/validation.d.ts +3 -146
  58. package/dist/validation.js +30 -359
  59. package/dist/validation.js.map +1 -1
  60. package/package.json +29 -92
  61. package/schema/schema.json +174 -244
  62. package/dist/config/client.cjs +0 -54
  63. package/dist/config/client.cjs.map +0 -1
  64. package/dist/config/client.d.ts +0 -23
  65. package/dist/config/client.js +0 -28
  66. package/dist/config/client.js.map +0 -1
  67. package/dist/config/edge.cjs +0 -508
  68. package/dist/config/edge.cjs.map +0 -1
  69. package/dist/config/edge.d.ts +0 -20
  70. package/dist/config/edge.js +0 -481
  71. package/dist/config/edge.js.map +0 -1
  72. package/dist/microfrontend-config-983a5139.d.ts +0 -154
  73. package/dist/schema-2922d49e.d.ts +0 -182
  74. package/dist/v2/config.cjs +0 -709
  75. package/dist/v2/config.cjs.map +0 -1
  76. package/dist/v2/config.d.ts +0 -4
  77. package/dist/v2/config.js +0 -684
  78. package/dist/v2/config.js.map +0 -1
  79. package/dist/v2/microfrontends/server.cjs.map +0 -1
  80. package/dist/v2/microfrontends/server.js.map +0 -1
  81. package/dist/v2/microfrontends.cjs.map +0 -1
  82. package/dist/v2/microfrontends.js.map +0 -1
  83. package/dist/v2/next/client.cjs +0 -3
  84. package/dist/v2/next/client.cjs.map +0 -1
  85. package/dist/v2/next/client.d.ts +0 -45
  86. package/dist/v2/next/client.js +0 -3
  87. package/dist/v2/next/client.js.map +0 -1
  88. package/dist/v2/next/config.cjs +0 -2178
  89. package/dist/v2/next/config.cjs.map +0 -1
  90. package/dist/v2/next/config.d.ts +0 -22
  91. package/dist/v2/next/config.js +0 -2143
  92. package/dist/v2/next/config.js.map +0 -1
  93. package/dist/v2/next/endpoints.cjs +0 -141
  94. package/dist/v2/next/endpoints.cjs.map +0 -1
  95. package/dist/v2/next/endpoints.d.ts +0 -26
  96. package/dist/v2/next/endpoints.js +0 -116
  97. package/dist/v2/next/endpoints.js.map +0 -1
  98. package/dist/v2/next/middleware.cjs +0 -1099
  99. package/dist/v2/next/middleware.cjs.map +0 -1
  100. package/dist/v2/next/middleware.d.ts +0 -34
  101. package/dist/v2/next/middleware.js +0 -1071
  102. package/dist/v2/next/middleware.js.map +0 -1
  103. package/dist/v2/next/testing.cjs +0 -992
  104. package/dist/v2/next/testing.cjs.map +0 -1
  105. package/dist/v2/next/testing.d.ts +0 -55
  106. package/dist/v2/next/testing.js +0 -961
  107. package/dist/v2/next/testing.js.map +0 -1
  108. package/dist/v2/overrides.cjs +0 -75
  109. package/dist/v2/overrides.cjs.map +0 -1
  110. package/dist/v2/overrides.d.ts +0 -24
  111. package/dist/v2/overrides.js +0 -45
  112. package/dist/v2/overrides.js.map +0 -1
  113. package/dist/v2/routing.cjs.map +0 -1
  114. package/dist/v2/schema.cjs.map +0 -1
  115. package/dist/v2/schema.d.ts +0 -1
  116. package/schema/schema-v2.json +0 -266
  117. /package/dist/{v2/routing.d.ts → routing.d.ts} +0 -0
  118. /package/dist/{v2/routing.js → routing.js} +0 -0
  119. /package/dist/{v2/routing.js.map → routing.js.map} +0 -0
  120. /package/dist/{v2/schema.js → schema.js} +0 -0
  121. /package/dist/{v2/schema.js.map → schema.js.map} +0 -0
@@ -1,8 +1,8 @@
1
1
  // src/next/middleware/middleware.ts
2
2
  import { NextResponse } from "next/server";
3
- import { pathToRegexp } from "path-to-regexp";
3
+ import { pathToRegexp as pathToRegexp3 } from "path-to-regexp";
4
4
 
5
- // src/config/edge/microfrontend-config.ts
5
+ // src/config/microfrontends-config/isomorphic/index.ts
6
6
  import { parse } from "jsonc-parser";
7
7
 
8
8
  // src/config/errors.ts
@@ -97,131 +97,320 @@ var MicrofrontendError = class extends Error {
97
97
  }
98
98
  };
99
99
 
100
- // src/routing/url.ts
101
- function buildUrlSafeString(givenOpts = {}) {
102
- const options = {
103
- joinString: "-",
104
- lowercaseOnly: true,
105
- maxLen: 100,
106
- regexRemovePattern: /(?:(?!(?:[a-z0-9])).)/gi,
107
- trimWhitespace: true,
108
- ...givenOpts
109
- };
110
- return {
111
- generate: (...args) => {
112
- const reJoinString = new RegExp(`${options.joinString}+`, "g");
113
- let tag;
114
- if (args.length === 0) {
115
- throw new Error("generate method must be passed at least one argument");
100
+ // src/config/microfrontends-config/utils/get-config-from-env.ts
101
+ function getConfigStringFromEnv() {
102
+ const config = process.env.MFE_CONFIG;
103
+ if (!config) {
104
+ throw new MicrofrontendError(`Missing "MFE_CONFIG" in environment.`, {
105
+ type: "config",
106
+ subtype: "not_found_in_env"
107
+ });
108
+ }
109
+ return config;
110
+ }
111
+
112
+ // src/config/schema/utils/is-main-config.ts
113
+ function isMainConfig(c) {
114
+ return !("partOf" in c);
115
+ }
116
+
117
+ // src/config/schema/utils/is-default-app.ts
118
+ function isDefaultApp(a) {
119
+ return !("routing" in a);
120
+ }
121
+
122
+ // src/config/microfrontends-config/client/index.ts
123
+ import { pathToRegexp } from "path-to-regexp";
124
+ var MicrofrontendConfigClient = class {
125
+ constructor(config, opts) {
126
+ this.pathCache = {};
127
+ this.serialized = config;
128
+ if (opts == null ? void 0 : opts.removeFlaggedPaths) {
129
+ for (const app of Object.values(config.applications)) {
130
+ if (app.routing) {
131
+ app.routing = app.routing.filter((match) => !match.flag);
132
+ }
116
133
  }
117
- for (let i = 0; i < args.length; i++) {
118
- const arg = args[i];
119
- if (typeof arg !== "string")
120
- throw new Error("all supplied arguments must be Strings");
121
- if (options.trimWhitespace) {
122
- args[i] = arg.trim();
134
+ }
135
+ this.applications = config.applications;
136
+ }
137
+ /**
138
+ * Create a new `MicrofrontendConfigClient` from a JSON string.
139
+ * Config must be passed in to remain framework agnostic
140
+ */
141
+ static fromEnv(config, opts) {
142
+ if (!config) {
143
+ throw new Error("No microfrontends configuration found");
144
+ }
145
+ return new MicrofrontendConfigClient(
146
+ JSON.parse(config),
147
+ opts
148
+ );
149
+ }
150
+ isEqual(other) {
151
+ return JSON.stringify(this.applications) === JSON.stringify(other.applications);
152
+ }
153
+ getApplicationNameForPath(path) {
154
+ if (!path.startsWith("/")) {
155
+ throw new Error(`Path must start with a /`);
156
+ }
157
+ if (this.pathCache[path]) {
158
+ return this.pathCache[path];
159
+ }
160
+ const pathname = new URL(path, "https://example.com").pathname;
161
+ for (const [name, application] of Object.entries(this.applications)) {
162
+ if (application.routing) {
163
+ for (const group of application.routing) {
164
+ for (const childPath of group.paths) {
165
+ const regexp = pathToRegexp(childPath);
166
+ if (regexp.test(pathname)) {
167
+ this.pathCache[path] = name;
168
+ return name;
169
+ }
170
+ }
123
171
  }
124
172
  }
125
- tag = args.join(options.joinString);
126
- tag = tag.replace(/\s/g, options.joinString);
127
- if (options.lowercaseOnly)
128
- tag = tag.toLowerCase();
129
- tag = tag.replace(options.regexRemovePattern, (match) => {
130
- if (match === options.joinString)
131
- return match;
132
- return "";
133
- });
134
- if (tag.length > options.maxLen)
135
- tag = tag.substring(0, options.maxLen);
136
- tag = tag.replace(reJoinString, options.joinString);
137
- return tag;
138
173
  }
174
+ const defaultApplication = Object.entries(this.applications).find(
175
+ ([, application]) => application.default
176
+ );
177
+ if (!defaultApplication) {
178
+ return null;
179
+ }
180
+ this.pathCache[path] = defaultApplication[0];
181
+ return defaultApplication[0];
182
+ }
183
+ serialize() {
184
+ return this.serialized;
185
+ }
186
+ };
187
+
188
+ // src/config/overrides/constants.ts
189
+ var OVERRIDES_COOKIE_PREFIX = "vercel-micro-frontends-override";
190
+ var OVERRIDES_ENV_COOKIE_PREFIX = `${OVERRIDES_COOKIE_PREFIX}:env:`;
191
+
192
+ // src/config/overrides/is-override-cookie.ts
193
+ function isOverrideCookie(cookie) {
194
+ var _a;
195
+ return Boolean((_a = cookie.name) == null ? void 0 : _a.startsWith(OVERRIDES_COOKIE_PREFIX));
196
+ }
197
+
198
+ // src/config/overrides/get-override-from-cookie.ts
199
+ function getOverrideFromCookie(cookie) {
200
+ if (!isOverrideCookie(cookie) || !cookie.value)
201
+ return;
202
+ return {
203
+ application: cookie.name.replace(OVERRIDES_ENV_COOKIE_PREFIX, ""),
204
+ host: cookie.value
139
205
  };
140
206
  }
141
- var urlSafeString = buildUrlSafeString().generate;
142
- function makeUrlSafe(name) {
143
- return urlSafeString(name.replace(/\//g, "-")).replace(/^-*/g, "").replace(/-*$/g, "");
207
+
208
+ // src/config/overrides/parse-overrides.ts
209
+ function parseOverrides(cookies) {
210
+ const overridesConfig = { applications: {} };
211
+ cookies.forEach((cookie) => {
212
+ const override = getOverrideFromCookie(cookie);
213
+ if (!override)
214
+ return;
215
+ overridesConfig.applications[override.application] = {
216
+ environment: { host: override.host }
217
+ };
218
+ });
219
+ return overridesConfig;
144
220
  }
145
221
 
146
- // src/config/overrides/config.ts
147
- var OVERRIDES_COOKIE_PREFIX = "vercel-micro-frontends-override";
148
- var _Overrides = class {
149
- constructor(config) {
150
- this.config = config;
151
- }
152
- static getAppEnvOverrideCookieName(zone) {
153
- return `${_Overrides.overrideEnvCookiePrefix}${zone}`;
222
+ // src/config/microfrontends-config/isomorphic/validation.ts
223
+ import { pathToRegexp as pathToRegexp2, parse as parsePathRegexp } from "path-to-regexp";
224
+ var SUPPORTED_VERSIONS = ["2"];
225
+ var validateConfigVersion = (version) => {
226
+ if (!SUPPORTED_VERSIONS.includes(version)) {
227
+ throw new MicrofrontendError(
228
+ `Unsupported version: ${version}. Supported versions are: ${SUPPORTED_VERSIONS.join(
229
+ ", "
230
+ )}`,
231
+ { type: "config", subtype: "unsupported_version" }
232
+ );
154
233
  }
155
- static isOverrideCookie(cookie) {
156
- var _a;
157
- return Boolean((_a = cookie.name) == null ? void 0 : _a.startsWith(OVERRIDES_COOKIE_PREFIX));
234
+ };
235
+ var validateConfigPaths = (applicationConfigsById) => {
236
+ if (!applicationConfigsById) {
237
+ return;
158
238
  }
159
- static getOverrideFromCookie(cookie) {
160
- if (!_Overrides.isOverrideCookie(cookie) || !cookie.value)
161
- return;
162
- return {
163
- zone: cookie.name.replace(_Overrides.overrideEnvCookiePrefix, ""),
164
- host: cookie.value
165
- };
239
+ const pathsByApplicationId = /* @__PURE__ */ new Map();
240
+ const errors = [];
241
+ for (const [id, app] of Object.entries(applicationConfigsById)) {
242
+ if (isDefaultApp(app)) {
243
+ continue;
244
+ }
245
+ for (const pathMatch of app.routing) {
246
+ for (const path of pathMatch.paths) {
247
+ const maybeError = validatePathExpression(path);
248
+ if (maybeError) {
249
+ errors.push(maybeError);
250
+ }
251
+ const existing = pathsByApplicationId.get(path);
252
+ if (existing) {
253
+ existing.applications.push(id);
254
+ } else {
255
+ pathsByApplicationId.set(path, {
256
+ applications: [id],
257
+ matcher: pathToRegexp2(path),
258
+ applicationId: id
259
+ });
260
+ }
261
+ }
262
+ }
166
263
  }
167
- static parseOverrides(cookies) {
168
- const overridesConfig = { applications: {} };
169
- cookies.forEach((cookie) => {
170
- const override = _Overrides.getOverrideFromCookie(cookie);
171
- if (!override)
172
- return;
173
- overridesConfig.applications[override.zone] = {
174
- environment: { host: override.host }
175
- };
264
+ const entries = Array.from(pathsByApplicationId.entries());
265
+ entries.forEach(([path, { applications: ids, matcher, applicationId }]) => {
266
+ if (ids.length > 1) {
267
+ errors.push(
268
+ `Duplicate path "${path}" for applications "${ids.join(", ")}"`
269
+ );
270
+ }
271
+ entries.forEach(
272
+ ([
273
+ matchPath,
274
+ { applications: matchIds, applicationId: matchApplicationId }
275
+ ]) => {
276
+ if (path === matchPath) {
277
+ return;
278
+ }
279
+ if (applicationId === matchApplicationId) {
280
+ return;
281
+ }
282
+ if (matcher.test(matchPath)) {
283
+ const source = `"${path}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
284
+ const destination = `"${matchPath}" of application${matchIds.length > 0 ? "s" : ""} ${matchIds.join(", ")}`;
285
+ errors.push(
286
+ `Overlapping path detected between ${source} and ${destination}`
287
+ );
288
+ }
289
+ }
290
+ );
291
+ });
292
+ if (errors.length) {
293
+ throw new MicrofrontendError(`Invalid paths: ${errors.join(", ")}`, {
294
+ type: "config",
295
+ subtype: "conflicting_paths"
176
296
  });
177
- return overridesConfig;
178
297
  }
179
- static validOverrideDomainsForZone(microfrontendConfig, zone) {
180
- var _a, _b, _c, _d, _e;
181
- const projectName = (_a = microfrontendConfig.getZone(zone).vercel) == null ? void 0 : _a.projectName;
182
- if (!projectName) {
183
- return [microfrontendConfig.getZone(zone).production.host];
298
+ };
299
+ var PATH_DEFAULT_PATTERN = "[^\\/#\\?]+?";
300
+ function validatePathExpression(path) {
301
+ const tokens = parsePathRegexp(path);
302
+ for (let i = 0; i < tokens.length; i++) {
303
+ const token = tokens[i];
304
+ if (token === void 0) {
305
+ return `token ${i} in ${path} is undefined, this shouldn't happen`;
184
306
  }
185
- const parsedProjectName = makeUrlSafe(projectName);
186
- const previewDeploymentSuffix = (_c = (_b = microfrontendConfig.options) == null ? void 0 : _b.vercel) == null ? void 0 : _c.previewDeploymentSuffix;
187
- const teamSlug = (_e = (_d = microfrontendConfig.options) == null ? void 0 : _d.vercel) == null ? void 0 : _e.teamSlug;
188
- if (!teamSlug && !previewDeploymentSuffix) {
189
- return [microfrontendConfig.getZone(zone).production.host];
307
+ if (typeof token !== "string") {
308
+ if (token.pattern !== PATH_DEFAULT_PATTERN) {
309
+ return `Path ${path} cannot use a regular expression wildcard`;
310
+ }
311
+ if (token.prefix !== "/") {
312
+ return `Wildcard :${token.name} must be immediately after a / in ${path}`;
313
+ }
314
+ if (token.suffix) {
315
+ return `Wildcard suffix on :${token.name} is not allowed. Suffixes are not supported`;
316
+ }
317
+ if (token.modifier && i !== tokens.length - 1) {
318
+ return `Modifier ${token.modifier} is not allowed on wildcard :${token.name} in ${path}. Modifiers are only allowed in the last path component`;
319
+ }
190
320
  }
191
- const suffix = previewDeploymentSuffix ? `.${previewDeploymentSuffix}` : `-${teamSlug}.vercel.app`;
192
- return [
193
- `${parsedProjectName}-git-([a-zA-Z0-9-]+)${suffix}`,
194
- microfrontendConfig.getZone(zone).production.host
195
- ];
196
321
  }
197
- static validateOverrideDomain(microfrontendConfig, zone, domain) {
198
- return new RegExp(
199
- `^${_Overrides.validOverrideDomainsForZone(microfrontendConfig, zone).join(
200
- "|"
201
- )}$`
202
- ).test(domain);
322
+ return void 0;
323
+ }
324
+ var validateAppPaths = (name, app) => {
325
+ for (const group of app.routing) {
326
+ for (const p of group.paths) {
327
+ if (p === "/") {
328
+ continue;
329
+ }
330
+ if (p.endsWith("/")) {
331
+ throw new MicrofrontendError(
332
+ `Invalid path for application "${name}". ${p} must not end with a slash.`,
333
+ { type: "application", subtype: "invalid_path" }
334
+ );
335
+ }
336
+ if (!p.startsWith("/")) {
337
+ throw new MicrofrontendError(
338
+ `Invalid path for application "${name}". ${p} must start with a slash.`,
339
+ { type: "application", subtype: "invalid_path" }
340
+ );
341
+ }
342
+ }
203
343
  }
204
- serialize() {
205
- return this.config;
344
+ };
345
+ var validateConfigDefaultApplication = (applicationConfigsById) => {
346
+ if (!applicationConfigsById) {
347
+ return;
348
+ }
349
+ const applicationsWithRouting = Object.entries(applicationConfigsById).filter(
350
+ ([, app]) => !isDefaultApp(app)
351
+ );
352
+ const applicationsWithRoutingNames = applicationsWithRouting.map(
353
+ ([key]) => key
354
+ );
355
+ const numApplications = Object.keys(applicationConfigsById).length;
356
+ const numApplicationsWithRouting = applicationsWithRoutingNames.length;
357
+ const numApplicationsWithoutRouting = numApplications - numApplicationsWithRouting;
358
+ if (numApplicationsWithoutRouting === 0) {
359
+ throw new MicrofrontendError(
360
+ `No default application found. At least one application needs to be the default by omitting routing.`,
361
+ { type: "config", subtype: "no_default_application" }
362
+ );
363
+ }
364
+ if (numApplicationsWithoutRouting > 1) {
365
+ throw new MicrofrontendError(
366
+ `Only one application can omit "routing". Found ${applicationsWithRoutingNames.length - Object.keys(applicationConfigsById).length > 1}.`,
367
+ { type: "config", subtype: "multiple_default_applications" }
368
+ );
206
369
  }
207
370
  };
208
- var Overrides = _Overrides;
209
- Overrides.overrideEnvCookiePrefix = `${OVERRIDES_COOKIE_PREFIX}:env:`;
210
371
 
211
- // src/config/common/host.ts
372
+ // src/config/microfrontends-config/isomorphic/utils/generate-asset-prefix.ts
373
+ var PREFIX = "vc-ap";
374
+ function generateAssetPrefixFromName({
375
+ name
376
+ }) {
377
+ if (!name) {
378
+ throw new Error("Name is required to generate an asset prefix");
379
+ }
380
+ return `${PREFIX}-${name}`;
381
+ }
382
+
383
+ // src/config/microfrontends-config/isomorphic/utils/generate-port.ts
384
+ function generatePortFromName({
385
+ name,
386
+ minPort = 3e3,
387
+ maxPort = 8e3
388
+ }) {
389
+ if (!name) {
390
+ throw new Error("Name is required to generate a port");
391
+ }
392
+ let hash = 0;
393
+ for (let i = 0; i < name.length; i++) {
394
+ hash = (hash << 5) - hash + name.charCodeAt(i);
395
+ hash |= 0;
396
+ }
397
+ hash = Math.abs(hash);
398
+ const range = maxPort - minPort;
399
+ const port = minPort + hash % range;
400
+ return port;
401
+ }
402
+
403
+ // src/config/microfrontends-config/isomorphic/host.ts
212
404
  var Host = class {
213
- constructor({ protocol, host, port }) {
214
- this.protocol = protocol || "https";
405
+ constructor(hostConfig, options) {
406
+ const { protocol = "https", host, port } = hostConfig;
407
+ this.protocol = protocol;
215
408
  this.host = host;
216
409
  this.port = Host.getPort({ port, protocol: this.protocol });
217
- this.serialized = {
218
- protocol,
219
- host,
220
- ...port ? { port } : void 0
221
- };
410
+ this.local = options == null ? void 0 : options.isLocal;
222
411
  }
223
412
  isLocal() {
224
- return this.host === "localhost" || this.host === "127.0.0.1";
413
+ return this.local || this.host === "localhost" || this.host === "127.0.0.1";
225
414
  }
226
415
  static getPort({
227
416
  protocol,
@@ -247,176 +436,234 @@ var Host = class {
247
436
  const url = `${this.protocol}://${this.host}${this.isDefaultPort() && !includeDefaultPort ? "" : `:${this.port}`}`;
248
437
  return new URL(url);
249
438
  }
250
- serialize() {
251
- return this.serialized;
439
+ };
440
+ var LocalHost = class extends Host {
441
+ constructor({
442
+ appName,
443
+ ...hostConfig
444
+ }) {
445
+ const host = hostConfig.host ?? "localhost";
446
+ const port = hostConfig.port ?? generatePortFromName({ name: appName });
447
+ const protocol = hostConfig.protocol ?? "http";
448
+ super({ protocol, host, port });
252
449
  }
253
450
  };
254
451
 
255
- // src/config/common/application.ts
452
+ // src/config/microfrontends-config/isomorphic/application.ts
256
453
  var Application = class {
257
454
  constructor(name, {
258
455
  app,
259
- overrides
456
+ overrides,
457
+ isDefault
260
458
  }) {
261
- Application.validate(name, app);
459
+ var _a, _b;
262
460
  this.name = name;
263
- this.default = app.default;
264
- this.routing = app.routing;
265
461
  this.development = {
266
- local: new Host(app.development.local),
267
- fallback: app.development.fallback ? new Host(app.development.fallback) : void 0
462
+ local: new LocalHost({
463
+ appName: name,
464
+ ...(_a = app.development) == null ? void 0 : _a.local
465
+ }),
466
+ fallback: ((_b = app.development) == null ? void 0 : _b.fallback) ? new Host(app.development.fallback) : void 0
268
467
  };
269
- this.production = new Host(app.production);
468
+ this.production = app.production ? new Host(app.production) : void 0;
270
469
  this.vercel = app.vercel;
271
470
  this.overrides = (overrides == null ? void 0 : overrides.environment) ? {
272
471
  environment: new Host(overrides.environment)
273
472
  } : void 0;
473
+ this.default = isDefault ?? false;
474
+ this.serialized = app;
274
475
  }
275
476
  isDefault() {
276
477
  return this.default;
277
478
  }
278
- static validate(name, app) {
279
- var _a, _b, _c, _d, _e;
280
- 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("/"))) {
281
- throw new MicrofrontendError(
282
- `Invalid assetPrefix for application "${name}". Must not start or end with a slash.`,
283
- { type: "zone", subtype: "invalid_asset_prefix" }
284
- );
285
- }
286
- for (const group of ((_e = app.routing) == null ? void 0 : _e.matches) ?? []) {
287
- for (const p of group.paths) {
288
- if (p === "/") {
289
- continue;
290
- }
291
- if (p.endsWith("/")) {
292
- throw new MicrofrontendError(
293
- `Invalid path for application "${name}". ${p} must not end with a slash.`,
294
- { type: "zone", subtype: "invalid_path" }
295
- );
296
- }
297
- if (!p.startsWith("/")) {
298
- throw new MicrofrontendError(
299
- `Invalid path for application "${name}". ${p} must start with a slash.`,
300
- { type: "zone", subtype: "invalid_path" }
301
- );
302
- }
303
- }
304
- }
479
+ getAssetPrefix() {
480
+ return generateAssetPrefixFromName({ name: this.name });
305
481
  }
306
482
  serialize() {
307
- var _a, _b;
308
- if (this.routing === void 0 || this.default) {
309
- return {
310
- default: true,
311
- development: {
312
- local: this.development.local.serialize(),
313
- fallback: (_a = this.development.fallback) == null ? void 0 : _a.serialize()
314
- },
315
- production: this.production.serialize(),
316
- vercel: this.vercel
317
- };
318
- }
319
- return {
320
- default: false,
321
- routing: this.routing,
322
- development: {
323
- local: this.development.local.serialize(),
324
- fallback: (_b = this.development.fallback) == null ? void 0 : _b.serialize()
325
- },
326
- production: this.production.serialize(),
327
- vercel: this.vercel
328
- };
483
+ return this.serialized;
484
+ }
485
+ };
486
+ var DefaultApplication = class extends Application {
487
+ constructor(name, {
488
+ app,
489
+ overrides
490
+ }) {
491
+ super(name, {
492
+ app,
493
+ overrides,
494
+ isDefault: true
495
+ });
496
+ this.default = true;
497
+ this.production = new Host(app.production);
498
+ }
499
+ getAssetPrefix() {
500
+ return "";
501
+ }
502
+ };
503
+ var ChildApplication = class extends Application {
504
+ constructor(name, {
505
+ app,
506
+ overrides
507
+ }) {
508
+ ChildApplication.validate(name, app);
509
+ super(name, {
510
+ app,
511
+ overrides,
512
+ isDefault: false
513
+ });
514
+ this.default = false;
515
+ this.routing = app.routing;
516
+ }
517
+ static validate(name, app) {
518
+ validateAppPaths(name, app);
329
519
  }
330
520
  };
331
521
 
332
- // src/config/common/microfrontend-config.ts
333
- var SUPPORTED_VERSIONS = ["1"];
522
+ // src/config/microfrontends-config/isomorphic/constants.ts
334
523
  var DEFAULT_LOCAL_PROXY_PORT = 3024;
335
- var MicrofrontendConfigCommon = class {
524
+
525
+ // src/config/microfrontends-config/isomorphic/index.ts
526
+ var MicrofrontendConfigIsomorphic = class {
336
527
  constructor({
337
528
  config,
338
- overrides
529
+ overrides,
530
+ meta
339
531
  }) {
340
- this.zones = {};
341
- var _a, _b, _c;
342
- if (!SUPPORTED_VERSIONS.includes(config.version)) {
343
- throw new MicrofrontendError(
344
- `Unsupported version: ${config.version}. Supported versions are: ${SUPPORTED_VERSIONS.join(
345
- ", "
346
- )}`,
347
- { type: "config", subtype: "unsupported_version" }
532
+ this.childApplications = {};
533
+ var _a, _b, _c, _d;
534
+ MicrofrontendConfigIsomorphic.validate(config);
535
+ const disableOverrides = ((_b = (_a = config.options) == null ? void 0 : _a.vercel) == null ? void 0 : _b.disableOverrides) ?? false;
536
+ this.overrides = overrides && !disableOverrides ? overrides : void 0;
537
+ this.isMainConfig = isMainConfig(config);
538
+ if (isMainConfig(config)) {
539
+ for (const [appId, appConfig] of Object.entries(config.applications)) {
540
+ const appOverrides = !disableOverrides ? (_c = this.overrides) == null ? void 0 : _c.applications[appId] : void 0;
541
+ if (isDefaultApp(appConfig)) {
542
+ this.defaultApplication = new DefaultApplication(appId, {
543
+ app: appConfig,
544
+ overrides: appOverrides
545
+ });
546
+ } else {
547
+ this.childApplications[appId] = new ChildApplication(appId, {
548
+ app: appConfig,
549
+ overrides: appOverrides
550
+ });
551
+ }
552
+ }
553
+ } else {
554
+ this.partOf = config.partOf;
555
+ const appOverrides = !disableOverrides ? (_d = this.overrides) == null ? void 0 : _d.applications[meta.fromApp] : void 0;
556
+ this.childApplications[meta.fromApp] = new ChildApplication(
557
+ meta.fromApp,
558
+ {
559
+ // we don't know routing because we're not in the main config
560
+ app: { routing: [] },
561
+ overrides: appOverrides
562
+ }
348
563
  );
349
564
  }
350
- const disableOverrides = ((_b = (_a = config.options) == null ? void 0 : _a.vercel) == null ? void 0 : _b.disableOverrides) ?? false;
351
- this.overrides = overrides && !disableOverrides ? new Overrides(overrides) : void 0;
352
- for (const [zoneName, zoneConfig] of Object.entries(config.applications)) {
353
- this.zones[zoneName] = new Application(zoneName, {
354
- app: zoneConfig,
355
- overrides: !disableOverrides ? (_c = this.overrides) == null ? void 0 : _c.config.applications[zoneName] : void 0
356
- });
565
+ if (isMainConfig(config) && !this.defaultApplication) {
566
+ throw new MicrofrontendError(
567
+ `Could not find default application in microfrontends configuration`,
568
+ {
569
+ type: "application",
570
+ subtype: "not_found"
571
+ }
572
+ );
357
573
  }
358
574
  this.config = config;
359
- this.name = config.name;
360
- this.version = config.version;
361
575
  this.options = config.options;
362
- this.$schema = config.$schema;
576
+ this.serialized = {
577
+ config,
578
+ overrides,
579
+ meta
580
+ };
581
+ }
582
+ static validate(config) {
583
+ const c = typeof config === "string" ? parse(config) : config;
584
+ if (isMainConfig(c)) {
585
+ validateConfigVersion(c.version);
586
+ validateConfigPaths(c.applications);
587
+ validateConfigDefaultApplication(c.applications);
588
+ }
589
+ return c;
590
+ }
591
+ static fromEnv({
592
+ meta,
593
+ cookies
594
+ }) {
595
+ return new MicrofrontendConfigIsomorphic({
596
+ config: parse(getConfigStringFromEnv()),
597
+ overrides: parseOverrides(cookies ?? []),
598
+ meta
599
+ });
363
600
  }
364
601
  isOverridesDisabled() {
365
602
  var _a, _b;
366
603
  return ((_b = (_a = this.options) == null ? void 0 : _a.vercel) == null ? void 0 : _b.disableOverrides) ?? false;
367
604
  }
368
- static getConfigFromEnv() {
369
- const config = process.env.MFE_CONFIG;
370
- if (!config) {
371
- throw new MicrofrontendError(`Missing "MFE_CONFIG" in environment.`, {
372
- type: "config",
373
- subtype: "not_found_in_env"
374
- });
375
- }
376
- return config;
377
- }
378
- static fromEnv(_) {
379
- throw new Error("Not implemented");
380
- }
381
605
  getConfig() {
382
606
  return this.config;
383
607
  }
608
+ getApplicationsByType() {
609
+ return {
610
+ defaultApplication: this.defaultApplication,
611
+ applications: Object.values(this.childApplications)
612
+ };
613
+ }
614
+ getChildApplications() {
615
+ return Object.values(this.childApplications);
616
+ }
384
617
  getAllApplications() {
385
- return Object.values(this.zones);
618
+ return [
619
+ this.defaultApplication,
620
+ ...Object.values(this.childApplications)
621
+ ].filter(Boolean);
386
622
  }
387
- getZone(name) {
388
- const zone = this.zones[name];
389
- if (!zone) {
623
+ getApplication(name) {
624
+ var _a;
625
+ if (((_a = this.defaultApplication) == null ? void 0 : _a.name) === name) {
626
+ return this.defaultApplication;
627
+ }
628
+ const app = this.childApplications[name];
629
+ if (!app) {
390
630
  throw new MicrofrontendError(
391
631
  `Could not find microfrontends configuration for application "${name}"`,
392
632
  {
393
- type: "zone",
633
+ type: "application",
394
634
  subtype: "not_found"
395
635
  }
396
636
  );
397
637
  }
398
- return zone;
638
+ return app;
399
639
  }
400
640
  getApplicationByProjectId(projectId) {
401
- return Object.values(this.zones).find(
402
- (zone) => {
403
- var _a;
404
- return ((_a = zone.vercel) == null ? void 0 : _a.projectId) === projectId;
641
+ var _a, _b;
642
+ if (((_b = (_a = this.defaultApplication) == null ? void 0 : _a.vercel) == null ? void 0 : _b.projectId) === projectId) {
643
+ return this.defaultApplication;
644
+ }
645
+ return Object.values(this.childApplications).find(
646
+ (app) => {
647
+ var _a2;
648
+ return ((_a2 = app.vercel) == null ? void 0 : _a2.projectId) === projectId;
405
649
  }
406
650
  );
407
651
  }
408
- getDefaultZone() {
409
- const zone = Object.values(this.zones).find((z) => z.default);
410
- if (!zone) {
652
+ /**
653
+ * Returns the default application. This can throw if the default application
654
+ * is undefined ( )
655
+ */
656
+ getDefaultApplication() {
657
+ if (!this.defaultApplication) {
411
658
  throw new MicrofrontendError(
412
- `Could not find default zone in microfrontends configuration`,
659
+ `Could not find default application in microfrontends configuration`,
413
660
  {
414
- type: "zone",
661
+ type: "application",
415
662
  subtype: "not_found"
416
663
  }
417
664
  );
418
665
  }
419
- return zone;
666
+ return this.defaultApplication;
420
667
  }
421
668
  /**
422
669
  * Returns the configured port for the local proxy
@@ -431,55 +678,147 @@ var MicrofrontendConfigCommon = class {
431
678
  * NOTE: This is used when writing the config to disk and must always match the input Schema
432
679
  */
433
680
  toSchemaJson() {
434
- const applications = {};
435
- for (const [name, zone] of Object.entries(this.zones)) {
436
- applications[name] = zone.serialize();
681
+ return this.serialized.config;
682
+ }
683
+ toClientConfig() {
684
+ const applications = Object.fromEntries(
685
+ Object.entries(this.childApplications).map(([name, application]) => [
686
+ name,
687
+ {
688
+ default: false,
689
+ routing: application.routing
690
+ }
691
+ ])
692
+ );
693
+ if (this.defaultApplication) {
694
+ applications[this.defaultApplication.name] = {
695
+ default: true
696
+ };
437
697
  }
438
- return {
439
- $schema: this.$schema,
440
- name: this.name,
441
- version: this.version,
442
- options: this.options,
698
+ return new MicrofrontendConfigClient({
443
699
  applications
444
- };
700
+ });
445
701
  }
446
702
  serialize() {
447
- var _a;
448
- const applications = {};
449
- for (const [name, zone] of Object.entries(this.zones)) {
450
- applications[name] = zone.serialize();
451
- }
452
- return {
453
- config: {
454
- name: this.name,
455
- version: this.version,
456
- applications,
457
- options: this.options,
458
- $schema: this.$schema
459
- },
460
- overrides: (_a = this.overrides) == null ? void 0 : _a.serialize()
461
- };
703
+ return this.serialized;
462
704
  }
463
- write(_) {
464
- throw new MicrofrontendError(
465
- `Writing to file to disk requires using an instance of "MicrofrontendConfig".`,
466
- { type: "config", subtype: "unsupported_operation" }
467
- );
705
+ };
706
+
707
+ // src/config/microfrontends-config/isomorphic/child.ts
708
+ var MicrofrontendChildConfig = class extends MicrofrontendConfigIsomorphic {
709
+ constructor({
710
+ config,
711
+ overrides,
712
+ meta
713
+ }) {
714
+ super({ config, overrides, meta });
715
+ this.isMainConfig = false;
716
+ this.partOf = config.partOf;
717
+ }
718
+ };
719
+
720
+ // src/config/microfrontends-config/isomorphic/main.ts
721
+ var MicrofrontendMainConfig = class extends MicrofrontendConfigIsomorphic {
722
+ constructor({
723
+ config,
724
+ overrides,
725
+ meta
726
+ }) {
727
+ var _a, _b, _c;
728
+ super({ config, overrides, meta });
729
+ this.isMainConfig = true;
730
+ const disableOverrides = ((_b = (_a = config.options) == null ? void 0 : _a.vercel) == null ? void 0 : _b.disableOverrides) ?? false;
731
+ let defaultApplication;
732
+ for (const [appId, appConfig] of Object.entries(config.applications)) {
733
+ const appOverrides = !disableOverrides ? (_c = this.overrides) == null ? void 0 : _c.applications[appId] : void 0;
734
+ if (isDefaultApp(appConfig)) {
735
+ defaultApplication = new DefaultApplication(appId, {
736
+ app: appConfig,
737
+ overrides: appOverrides
738
+ });
739
+ } else {
740
+ this.childApplications[appId] = new ChildApplication(appId, {
741
+ app: appConfig,
742
+ overrides: appOverrides
743
+ });
744
+ }
745
+ }
746
+ if (!defaultApplication) {
747
+ throw new MicrofrontendError(
748
+ `Could not find default application in microfrontends configuration`,
749
+ {
750
+ type: "application",
751
+ subtype: "not_found"
752
+ }
753
+ );
754
+ }
755
+ this.defaultApplication = defaultApplication;
468
756
  }
469
757
  };
470
758
 
471
- // src/config/edge/microfrontend-config.ts
472
- var MicrofrontendConfigEdge = class extends MicrofrontendConfigCommon {
759
+ // src/config/microfrontends/isomorphic/index.ts
760
+ var Microfrontends = class {
761
+ constructor({
762
+ config,
763
+ overrides,
764
+ meta
765
+ }) {
766
+ if (isMainConfig(config)) {
767
+ this.config = new MicrofrontendMainConfig({ config, overrides, meta });
768
+ } else {
769
+ this.config = new MicrofrontendChildConfig({ config, overrides, meta });
770
+ }
771
+ }
772
+ isChildConfig() {
773
+ return this.config instanceof MicrofrontendChildConfig;
774
+ }
473
775
  static fromEnv({
474
- cookies
776
+ cookies,
777
+ meta
475
778
  }) {
476
- return new MicrofrontendConfigCommon({
477
- config: parse(MicrofrontendConfigCommon.getConfigFromEnv()),
478
- overrides: Overrides.parseOverrides(cookies)
779
+ const config = MicrofrontendConfigIsomorphic.fromEnv({
780
+ cookies,
781
+ meta
479
782
  });
783
+ return new Microfrontends(config.serialize());
480
784
  }
481
785
  };
482
786
 
787
+ // src/routing/get-domain-from-environment.ts
788
+ function getDomainFromEnvironment({
789
+ app,
790
+ target
791
+ }) {
792
+ var _a;
793
+ const mfeProjects = JSON.parse(
794
+ process.env.VERCEL_MICROFRONTENDS_PROJECTS ?? "[]"
795
+ );
796
+ if (mfeProjects.length === 0) {
797
+ throw new Error("Missing related microfrontends project information");
798
+ }
799
+ if (!((_a = app.vercel) == null ? void 0 : _a.projectId)) {
800
+ throw new Error(`Missing applications[${app.name}].vercel.projectId`);
801
+ }
802
+ const vercelProject = mfeProjects.find(
803
+ (p) => {
804
+ var _a2;
805
+ return p.project.id === ((_a2 = app.vercel) == null ? void 0 : _a2.projectId);
806
+ }
807
+ );
808
+ if (!vercelProject) {
809
+ throw new Error(
810
+ `Missing related microfrontends project information for application "${app.name}"`
811
+ );
812
+ }
813
+ const domain = target === "preview" && vercelProject.preview.branch ? vercelProject.preview.branch : vercelProject.production.alias ?? vercelProject.production.url;
814
+ if (!domain) {
815
+ throw new Error(
816
+ `Missing domain for target "${target}" in application "${app.name}"`
817
+ );
818
+ }
819
+ return domain.startsWith("https://") ? domain : `https://${domain}`;
820
+ }
821
+
483
822
  // src/routing/get-domain-for-current-environment.ts
484
823
  function debugDomains(zone, env, domain) {
485
824
  if (process.env.MFE_DEBUG === "true") {
@@ -493,34 +832,45 @@ ${line}
493
832
  `);
494
833
  }
495
834
  }
496
- function getDomainForCurrentEnvironment(zone, opts = {}) {
835
+ function getCurrentEnvironment() {
836
+ const isDevelopment = !process.env.VERCEL_ENV || process.env.VERCEL_ENV === "development";
837
+ const isPreview = process.env.VERCEL_ENV === "preview";
838
+ const isProduction = process.env.VERCEL_ENV === "production";
839
+ if (isDevelopment) {
840
+ return { group: "development" };
841
+ } else if (isProduction) {
842
+ return { group: "production" };
843
+ } else if (isPreview) {
844
+ return { group: "preview" };
845
+ }
846
+ return { group: "custom", name: process.env.VERCEL_ENV };
847
+ }
848
+ function getDomainForCurrentEnvironment(config, appName, opts = {}) {
497
849
  var _a;
498
- if (!opts.ignoreOverride && ((_a = zone.overrides) == null ? void 0 : _a.environment)) {
499
- return zone.overrides.environment.toString();
500
- }
501
- const zoneName = zone.name;
502
- if (!process.env.VERCEL_ENV || process.env.VERCEL_ENV === "development") {
503
- const domain = process.env.NODE_ENV === "test" ? zone.development.local.toString() : zone.production.toString();
504
- debugDomains(zoneName, "development", domain);
505
- return domain;
506
- } else if (process.env.VERCEL_ENV === "production") {
507
- const domain = zone.production.toString();
508
- debugDomains(zoneName, "production", domain);
509
- return domain;
510
- } else if (process.env.VERCEL_ENV === "preview") {
511
- const MFE_PREVIEW_DOMAINS = JSON.parse(
512
- process.env.MFE_PREVIEW_DOMAINS ?? "{}"
513
- );
514
- if (MFE_PREVIEW_DOMAINS[zoneName]) {
515
- debugDomains(zoneName, "preview", MFE_PREVIEW_DOMAINS[zoneName]);
516
- return MFE_PREVIEW_DOMAINS[zoneName];
850
+ const app = config.getApplication(appName);
851
+ if (!opts.ignoreOverride && ((_a = app.overrides) == null ? void 0 : _a.environment)) {
852
+ return app.overrides.environment.toString();
853
+ }
854
+ const { group } = getCurrentEnvironment();
855
+ const productionHost = config.getDefaultApplication().production.toString();
856
+ switch (group) {
857
+ case "development": {
858
+ const domain = ["test", "development"].includes(process.env.NODE_ENV) ? app.development.local.toString() : productionHost;
859
+ debugDomains(appName, "development", domain);
860
+ return domain;
517
861
  }
518
- throw new Error(
519
- `Could not find preview domain for application "${zoneName}"`
520
- );
862
+ case "preview": {
863
+ return getDomainFromEnvironment({ app, target: "preview" });
864
+ }
865
+ case "production": {
866
+ return getDomainFromEnvironment({ app, target: "production" });
867
+ }
868
+ case "custom":
869
+ console.warn(
870
+ `Custom environments are not supported in getDomainForCurrentEnvironment`
871
+ );
872
+ return productionHost;
521
873
  }
522
- debugDomains(zoneName, process.env.VERCEL_ENV, zone.production.toString());
523
- return zone.production.toString();
524
874
  }
525
875
 
526
876
  // src/next/middleware/middleware.ts
@@ -544,167 +894,187 @@ async function verifyPreviewDomain(req, rewriteDomain) {
544
894
  return !(previewResponse.status === 404 && (vercelError === "DEPLOYMENT_NOT_FOUND" || vercelError === "NOT_FOUND"));
545
895
  }
546
896
  function getHandler({
897
+ config,
547
898
  application,
548
899
  flagFn,
549
- pattern
900
+ pattern,
901
+ production
550
902
  }) {
551
903
  return async (req) => {
552
- var _a, _b, _c;
553
- const pathname = req.nextUrl.pathname;
554
- const search = req.nextUrl.search;
555
- const proxyRouting = req.headers.get("X-Vercel-Mfe-Proxy") === "1";
556
- let rewriteDomain = proxyRouting ? null : getDomainForCurrentEnvironment(application);
557
- const patchedHeaders = new Headers(req.headers);
558
- const responseCallbacks = [];
559
- const onRewrite = (response) => {
560
- for (const callback of responseCallbacks) {
561
- callback(response);
562
- }
563
- return response;
564
- };
565
- if (process.env.VERCEL_ENV === "preview" && rewriteDomain) {
566
- const zoneFallbackCookieName = `__zone_${application.name}_production_fallback`;
567
- const assetPrefix = (_a = application.routing) == null ? void 0 : _a.assetPrefix;
568
- if (assetPrefix && pathname.startsWith(`/${assetPrefix}`) && ((_b = req.cookies.get(zoneFallbackCookieName)) == null ? void 0 : _b.value) === "1") {
569
- rewriteDomain = application.production.toString();
570
- } else {
571
- try {
572
- let deploymentFound;
573
- if (req.headers.get("x-vercel-skip-deployment-existence-check")) {
574
- deploymentFound = true;
575
- } else {
576
- deploymentFound = await verifyPreviewDomain(req, rewriteDomain);
577
- }
578
- if (!deploymentFound) {
579
- rewriteDomain = application.production.toString();
580
- responseCallbacks.push((response) => {
581
- response.cookies.set(zoneFallbackCookieName, "1", {
582
- httpOnly: true,
583
- sameSite: "lax",
584
- secure: true,
585
- maxAge: 60
586
- // 1 minute
904
+ var _a, _b;
905
+ try {
906
+ const pathname = req.nextUrl.pathname;
907
+ const search = req.nextUrl.search;
908
+ const proxyRouting = req.headers.get("X-Vercel-Mfe-Proxy") === "1";
909
+ let rewriteDomain = proxyRouting ? null : getDomainForCurrentEnvironment(config, application.name);
910
+ const patchedHeaders = new Headers(req.headers);
911
+ const responseCallbacks = [];
912
+ const onRewrite = (response) => {
913
+ for (const callback of responseCallbacks) {
914
+ callback(response);
915
+ }
916
+ return response;
917
+ };
918
+ if (process.env.VERCEL_ENV === "preview" && rewriteDomain) {
919
+ const zoneFallbackCookieName = `__zone_${application.name}_production_fallback`;
920
+ const assetPrefix = application.getAssetPrefix();
921
+ if (assetPrefix && pathname.startsWith(`/${assetPrefix}`) && ((_a = req.cookies.get(zoneFallbackCookieName)) == null ? void 0 : _a.value) === "1") {
922
+ rewriteDomain = production.toString();
923
+ } else {
924
+ try {
925
+ let deploymentFound;
926
+ if (req.headers.get("x-vercel-skip-deployment-existence-check")) {
927
+ deploymentFound = true;
928
+ } else {
929
+ deploymentFound = await verifyPreviewDomain(req, rewriteDomain);
930
+ }
931
+ if (!deploymentFound) {
932
+ rewriteDomain = production.toString();
933
+ responseCallbacks.push((response) => {
934
+ response.cookies.set(zoneFallbackCookieName, "1", {
935
+ httpOnly: true,
936
+ sameSite: "lax",
937
+ secure: true,
938
+ maxAge: 60
939
+ // 1 minute
940
+ });
587
941
  });
588
- });
589
- try {
590
- const existingCookie = patchedHeaders.get("cookie");
591
- if (!(existingCookie == null ? void 0 : existingCookie.includes("__vercel_toolbar"))) {
592
- patchedHeaders.set(
593
- "cookie",
594
- [`__vercel_toolbar=1`, existingCookie].join("; ")
595
- );
596
- responseCallbacks.push((response) => {
597
- response.cookies.set("__vercel_toolbar", "1", {
598
- httpOnly: false,
599
- sameSite: "lax",
600
- secure: true,
601
- maxAge: 29030400
942
+ try {
943
+ const existingCookie = patchedHeaders.get("cookie");
944
+ if (!(existingCookie == null ? void 0 : existingCookie.includes("__vercel_toolbar"))) {
945
+ patchedHeaders.set(
946
+ "cookie",
947
+ [`__vercel_toolbar=1`, existingCookie].join("; ")
948
+ );
949
+ responseCallbacks.push((response) => {
950
+ response.cookies.set("__vercel_toolbar", "1", {
951
+ httpOnly: false,
952
+ sameSite: "lax",
953
+ secure: true,
954
+ maxAge: 29030400
955
+ });
602
956
  });
603
- });
957
+ }
958
+ } catch (error) {
604
959
  }
605
- } catch (error) {
606
- }
607
- } else if (((_c = req.cookies.get(zoneFallbackCookieName)) == null ? void 0 : _c.value) === "1") {
608
- responseCallbacks.push((response) => {
609
- response.cookies.set(zoneFallbackCookieName, "", {
610
- httpOnly: true,
611
- sameSite: "lax",
612
- secure: true,
613
- maxAge: 0
960
+ } else if (((_b = req.cookies.get(zoneFallbackCookieName)) == null ? void 0 : _b.value) === "1") {
961
+ responseCallbacks.push((response) => {
962
+ response.cookies.set(zoneFallbackCookieName, "", {
963
+ httpOnly: true,
964
+ sameSite: "lax",
965
+ secure: true,
966
+ maxAge: 0
967
+ });
614
968
  });
615
- });
969
+ }
970
+ } catch {
616
971
  }
617
- } catch {
618
972
  }
619
973
  }
620
- }
621
- const isFlagEnabled = async () => flagFn ? flagFn() : true;
622
- if (pattern.test(pathname) && await isFlagEnabled()) {
623
- if (proxyRouting) {
624
- const headers = new Headers(req.headers);
625
- headers.set("x-vercel-mfe-zone", application.name);
974
+ const isFlagEnabled = async () => flagFn ? flagFn() : true;
975
+ if (pattern.test(pathname) && await isFlagEnabled()) {
976
+ if (proxyRouting) {
977
+ const headers = new Headers(req.headers);
978
+ headers.set("x-vercel-mfe-zone", application.name);
979
+ return onRewrite(
980
+ NextResponse.next({
981
+ request: {
982
+ headers
983
+ },
984
+ headers: {
985
+ // temporary, can delete when proxyRouting flag is removed
986
+ "x-vercel-mfe-middleware-sent-proxy": application.name
987
+ }
988
+ })
989
+ );
990
+ }
626
991
  return onRewrite(
627
- NextResponse.next({
992
+ NextResponse.rewrite(`${rewriteDomain}${pathname}${search}`, {
628
993
  request: {
629
- headers
630
- },
631
- headers: {
632
- // temporary, can delete when proxyRouting flag is removed
633
- "x-vercel-mfe-middleware-sent-proxy": application.name
994
+ headers: patchedHeaders
634
995
  }
635
996
  })
636
997
  );
637
998
  }
638
- return onRewrite(
639
- NextResponse.rewrite(`${rewriteDomain}${pathname}${search}`, {
640
- request: {
641
- headers: patchedHeaders
642
- }
643
- })
644
- );
999
+ } catch (e) {
1000
+ console.error("An error occured in the microfrontends middleware:", e);
1001
+ throw e;
645
1002
  }
646
1003
  };
647
1004
  }
648
1005
  function getMicrofrontendsMiddleware({
649
1006
  request,
650
- flagValues
1007
+ flagValues,
1008
+ fromApp
651
1009
  }) {
652
- var _a, _b;
653
- const config = MicrofrontendConfigEdge.fromEnv({
654
- cookies: request.cookies.getAll()
1010
+ const microfrontends = Microfrontends.fromEnv({
1011
+ cookies: request.cookies.getAll(),
1012
+ meta: {
1013
+ fromApp
1014
+ }
655
1015
  });
656
1016
  const middlewares = [];
657
- for (const application of config.getAllApplications()) {
1017
+ if (microfrontends.config instanceof MicrofrontendChildConfig) {
1018
+ return middlewares;
1019
+ }
1020
+ const config = microfrontends.config;
1021
+ const production = config.defaultApplication.production;
1022
+ for (const application of config.getChildApplications()) {
658
1023
  if (application.name === process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION) {
659
1024
  continue;
660
1025
  }
661
- if (application.routing) {
662
- if (process.env.VERCEL_ENV === "preview" && application.routing.assetPrefix) {
663
- const pattern = pathToRegexp(
664
- `/${application.routing.assetPrefix}/:path+`
665
- );
666
- middlewares.push({
667
- src: pattern,
668
- fn: getHandler({
669
- application,
670
- pattern
671
- })
672
- });
673
- }
674
- for (const pathGroup of application.routing.matches) {
675
- if (process.env.VERCEL_ENV === "preview" || ((_a = pathGroup.options) == null ? void 0 : _a.flag)) {
676
- const flagName = (_b = pathGroup.options) == null ? void 0 : _b.flag;
677
- let flagFn;
678
- if (flagName) {
679
- flagFn = flagValues == null ? void 0 : flagValues[flagName];
680
- if (!flagFn) {
681
- throw new Error(
682
- `Flag "${flagName}" was specified to control routing for path group "${pathGroup.group}" in application ${application.name} but not found in provided flag values.`
683
- );
684
- }
685
- }
686
- for (const path of pathGroup.paths) {
687
- const pattern = pathToRegexp(path);
688
- middlewares.push({
689
- src: pattern,
690
- fn: getHandler({
691
- application,
692
- flagFn,
693
- pattern
694
- })
695
- });
1026
+ if (process.env.VERCEL_ENV === "preview") {
1027
+ const pattern = pathToRegexp3(`/${application.getAssetPrefix()}/:path+`);
1028
+ middlewares.push({
1029
+ src: pattern,
1030
+ fn: getHandler({
1031
+ config,
1032
+ application,
1033
+ pattern,
1034
+ production
1035
+ })
1036
+ });
1037
+ }
1038
+ for (const pathGroup of application.routing) {
1039
+ if (process.env.VERCEL_ENV === "preview" || pathGroup.flag) {
1040
+ const flagName = pathGroup.flag;
1041
+ let flagFn;
1042
+ if (flagName) {
1043
+ flagFn = flagValues == null ? void 0 : flagValues[flagName];
1044
+ if (!flagFn) {
1045
+ throw new Error(
1046
+ `Flag "${flagName}" was specified to control routing for path group "${pathGroup.group}" in application ${application.name} but not found in provided flag values.`
1047
+ );
696
1048
  }
697
1049
  }
1050
+ for (const path of pathGroup.paths) {
1051
+ const pattern = pathToRegexp3(path);
1052
+ middlewares.push({
1053
+ src: pattern,
1054
+ fn: getHandler({
1055
+ config,
1056
+ application,
1057
+ flagFn,
1058
+ pattern,
1059
+ production
1060
+ })
1061
+ });
1062
+ }
698
1063
  }
699
1064
  }
700
1065
  }
701
1066
  return middlewares;
702
1067
  }
703
- async function runMicrofrontendsMiddleware(request, flagValues) {
1068
+ async function runMicrofrontendsMiddleware({
1069
+ request,
1070
+ fromApp,
1071
+ flagValues
1072
+ }) {
704
1073
  const pathname = request.nextUrl.pathname;
705
1074
  const middlewares = getMicrofrontendsMiddleware({
706
1075
  request,
707
- flagValues
1076
+ flagValues,
1077
+ fromApp
708
1078
  });
709
1079
  for (const mware of middlewares) {
710
1080
  if (typeof mware.src === "string" ? pathname === mware.src : mware.src.test(pathname)) {