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