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