@vercel/microfrontends 2.2.1 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/cli/index.cjs +0 -1
  3. package/dist/bin/cli.cjs +486 -397
  4. package/dist/config.cjs +193 -171
  5. package/dist/config.cjs.map +1 -1
  6. package/dist/config.d.ts +3 -2
  7. package/dist/config.js +194 -172
  8. package/dist/config.js.map +1 -1
  9. package/dist/experimental/sveltekit.cjs +585 -513
  10. package/dist/experimental/sveltekit.cjs.map +1 -1
  11. package/dist/experimental/sveltekit.js +591 -519
  12. package/dist/experimental/sveltekit.js.map +1 -1
  13. package/dist/experimental/vite.cjs +607 -535
  14. package/dist/experimental/vite.cjs.map +1 -1
  15. package/dist/experimental/vite.js +616 -544
  16. package/dist/experimental/vite.js.map +1 -1
  17. package/dist/microfrontends/server.cjs +603 -531
  18. package/dist/microfrontends/server.cjs.map +1 -1
  19. package/dist/microfrontends/server.d.ts +2 -2
  20. package/dist/microfrontends/server.js +609 -537
  21. package/dist/microfrontends/server.js.map +1 -1
  22. package/dist/microfrontends/utils.cjs +101 -50
  23. package/dist/microfrontends/utils.cjs.map +1 -1
  24. package/dist/microfrontends/utils.d.ts +4 -4
  25. package/dist/microfrontends/utils.js +102 -51
  26. package/dist/microfrontends/utils.js.map +1 -1
  27. package/dist/next/client.cjs +1 -1
  28. package/dist/next/client.cjs.map +1 -1
  29. package/dist/next/client.d.ts +8 -8
  30. package/dist/next/client.js +1 -1
  31. package/dist/next/client.js.map +1 -1
  32. package/dist/next/config.cjs +725 -649
  33. package/dist/next/config.cjs.map +1 -1
  34. package/dist/next/config.js +722 -646
  35. package/dist/next/config.js.map +1 -1
  36. package/dist/next/middleware.cjs +246 -224
  37. package/dist/next/middleware.cjs.map +1 -1
  38. package/dist/next/middleware.js +247 -225
  39. package/dist/next/middleware.js.map +1 -1
  40. package/dist/next/testing.cjs +194 -172
  41. package/dist/next/testing.cjs.map +1 -1
  42. package/dist/next/testing.d.ts +1 -1
  43. package/dist/next/testing.js +195 -173
  44. package/dist/next/testing.js.map +1 -1
  45. package/dist/overrides.cjs +5 -5
  46. package/dist/overrides.cjs.map +1 -1
  47. package/dist/overrides.d.ts +9 -9
  48. package/dist/overrides.js +5 -5
  49. package/dist/overrides.js.map +1 -1
  50. package/dist/utils/mfe-port.cjs +622 -535
  51. package/dist/utils/mfe-port.cjs.map +1 -1
  52. package/dist/utils/mfe-port.d.ts +9 -1
  53. package/dist/utils/mfe-port.js +634 -548
  54. package/dist/utils/mfe-port.js.map +1 -1
  55. package/dist/validation.cjs +8 -24
  56. package/dist/validation.cjs.map +1 -1
  57. package/dist/validation.js +8 -24
  58. package/dist/validation.js.map +1 -1
  59. package/package.json +5 -7
@@ -1,10 +1,10 @@
1
1
  // src/next/testing/index.ts
2
2
  import { readFileSync } from "node:fs";
3
+ import { parse as parse2 } from "jsonc-parser";
3
4
  import {
4
5
  NextRequest
5
6
  } from "next/server.js";
6
7
  import { match, pathToRegexp as pathToRegexp3 } from "path-to-regexp";
7
- import { parse as parse2 } from "jsonc-parser";
8
8
 
9
9
  // src/config/microfrontends-config/isomorphic/index.ts
10
10
  import { parse } from "jsonc-parser";
@@ -101,23 +101,6 @@ var MicrofrontendError = class extends Error {
101
101
  }
102
102
  };
103
103
 
104
- // src/config/microfrontends-config/utils/get-config-from-env.ts
105
- function getConfigStringFromEnv() {
106
- const config = process.env.MFE_CONFIG;
107
- if (!config) {
108
- throw new MicrofrontendError(`Missing "MFE_CONFIG" in environment.`, {
109
- type: "config",
110
- subtype: "not_found_in_env"
111
- });
112
- }
113
- return config;
114
- }
115
-
116
- // src/config/schema/utils/is-default-app.ts
117
- function isDefaultApp(a) {
118
- return !("routing" in a);
119
- }
120
-
121
104
  // src/config/overrides/constants.ts
122
105
  var OVERRIDES_COOKIE_PREFIX = "vercel-micro-frontends-override";
123
106
  var OVERRIDES_ENV_COOKIE_PREFIX = `${OVERRIDES_COOKIE_PREFIX}:env:`;
@@ -151,6 +134,11 @@ function parseOverrides(cookies) {
151
134
  return overridesConfig;
152
135
  }
153
136
 
137
+ // src/config/schema/utils/is-default-app.ts
138
+ function isDefaultApp(a) {
139
+ return !("routing" in a);
140
+ }
141
+
154
142
  // src/config/microfrontends-config/client/index.ts
155
143
  import { pathToRegexp } from "path-to-regexp";
156
144
  var regexpCache = /* @__PURE__ */ new Map();
@@ -249,8 +237,185 @@ var MicrofrontendConfigClient = class {
249
237
  }
250
238
  };
251
239
 
240
+ // src/config/microfrontends-config/utils/get-config-from-env.ts
241
+ function getConfigStringFromEnv() {
242
+ const config = process.env.MFE_CONFIG;
243
+ if (!config) {
244
+ throw new MicrofrontendError(`Missing "MFE_CONFIG" in environment.`, {
245
+ type: "config",
246
+ subtype: "not_found_in_env"
247
+ });
248
+ }
249
+ return config;
250
+ }
251
+
252
+ // src/config/microfrontends-config/isomorphic/constants.ts
253
+ var DEFAULT_LOCAL_PROXY_PORT = 3024;
254
+ var MFE_APP_PORT_ENV = "MFE_APP_PORT";
255
+ var MFE_LOCAL_PROXY_PORT_ENV = "MFE_LOCAL_PROXY_PORT";
256
+
257
+ // src/config/microfrontends-config/isomorphic/utils/generate-port.ts
258
+ function generatePortFromName({
259
+ name,
260
+ minPort = 3e3,
261
+ maxPort = 8e3
262
+ }) {
263
+ if (!name) {
264
+ throw new Error("Name is required to generate a port");
265
+ }
266
+ let hash = 0;
267
+ for (let i = 0; i < name.length; i++) {
268
+ hash = (hash << 5) - hash + name.charCodeAt(i);
269
+ hash |= 0;
270
+ }
271
+ hash = Math.abs(hash);
272
+ const range = maxPort - minPort;
273
+ const port = minPort + hash % range;
274
+ return port;
275
+ }
276
+
277
+ // src/config/microfrontends-config/isomorphic/host.ts
278
+ var Host = class {
279
+ constructor(hostConfig, options) {
280
+ if (typeof hostConfig === "string") {
281
+ ({
282
+ protocol: this.protocol,
283
+ host: this.host,
284
+ port: this.port
285
+ } = Host.parseUrl(hostConfig));
286
+ } else {
287
+ const { protocol = "https", host, port } = hostConfig;
288
+ this.protocol = protocol;
289
+ this.host = host;
290
+ this.port = port;
291
+ }
292
+ this.local = options?.isLocal;
293
+ }
294
+ static parseUrl(url, defaultProtocol = "https") {
295
+ let hostToParse = url;
296
+ if (!/^https?:\/\//.exec(hostToParse)) {
297
+ hostToParse = `${defaultProtocol}://${hostToParse}`;
298
+ }
299
+ const parsed = new URL(hostToParse);
300
+ if (!parsed.hostname) {
301
+ throw new Error(Host.getMicrofrontendsError(url, "requires a host"));
302
+ }
303
+ if (parsed.hash) {
304
+ throw new Error(
305
+ Host.getMicrofrontendsError(url, "cannot have a fragment")
306
+ );
307
+ }
308
+ if (parsed.username || parsed.password) {
309
+ throw new Error(
310
+ Host.getMicrofrontendsError(
311
+ url,
312
+ "cannot have authentication credentials (username and/or password)"
313
+ )
314
+ );
315
+ }
316
+ if (parsed.pathname !== "/") {
317
+ throw new Error(Host.getMicrofrontendsError(url, "cannot have a path"));
318
+ }
319
+ if (parsed.search) {
320
+ throw new Error(
321
+ Host.getMicrofrontendsError(url, "cannot have query parameters")
322
+ );
323
+ }
324
+ const protocol = parsed.protocol.slice(0, -1);
325
+ return {
326
+ protocol,
327
+ host: parsed.hostname,
328
+ port: parsed.port ? Number.parseInt(parsed.port, 10) : void 0
329
+ };
330
+ }
331
+ static getMicrofrontendsError(url, message) {
332
+ return `Microfrontends configuration error: the URL ${url} in your microfrontends.json ${message}.`;
333
+ }
334
+ isLocal() {
335
+ return this.local || this.host === "localhost" || this.host === "127.0.0.1";
336
+ }
337
+ toString() {
338
+ const url = this.toUrl();
339
+ return url.toString().replace(/\/$/, "");
340
+ }
341
+ toUrl() {
342
+ const url = `${this.protocol}://${this.host}${this.port ? `:${this.port}` : ""}`;
343
+ return new URL(url);
344
+ }
345
+ };
346
+ var LocalHost = class extends Host {
347
+ constructor({
348
+ appName,
349
+ local
350
+ }) {
351
+ const portOverride = process.env[MFE_APP_PORT_ENV];
352
+ if (portOverride) {
353
+ const overridePort = Number.parseInt(portOverride, 10);
354
+ if (!Number.isNaN(overridePort) && overridePort > 0 && overridePort < 65536) {
355
+ super({
356
+ protocol: "http",
357
+ host: "localhost",
358
+ port: overridePort
359
+ });
360
+ return;
361
+ }
362
+ }
363
+ let protocol;
364
+ let host;
365
+ let port;
366
+ if (typeof local === "number") {
367
+ port = local;
368
+ } else if (typeof local === "string") {
369
+ if (/^\d+$/.test(local)) {
370
+ port = Number.parseInt(local, 10);
371
+ } else {
372
+ const parsed = Host.parseUrl(local, "http");
373
+ protocol = parsed.protocol;
374
+ host = parsed.host;
375
+ port = parsed.port;
376
+ }
377
+ } else if (local) {
378
+ protocol = local.protocol;
379
+ host = local.host;
380
+ port = local.port;
381
+ }
382
+ super({
383
+ protocol: protocol ?? "http",
384
+ host: host ?? "localhost",
385
+ port: port ?? generatePortFromName({ name: appName })
386
+ });
387
+ }
388
+ };
389
+
390
+ // src/config/microfrontends-config/isomorphic/utils/hash-application-name.ts
391
+ import md5 from "md5";
392
+ function hashApplicationName(name) {
393
+ if (!name) {
394
+ throw new Error("Application name is required to generate hash");
395
+ }
396
+ return md5(name).substring(0, 6).padStart(6, "0");
397
+ }
398
+
399
+ // src/config/microfrontends-config/isomorphic/utils/generate-asset-prefix.ts
400
+ var PREFIX = "vc-ap";
401
+ function generateAssetPrefixFromName({
402
+ name
403
+ }) {
404
+ if (!name) {
405
+ throw new Error("Name is required to generate an asset prefix");
406
+ }
407
+ return `${PREFIX}-${hashApplicationName(name)}`;
408
+ }
409
+
410
+ // src/config/microfrontends-config/isomorphic/utils/generate-automation-bypass-env-var-name.ts
411
+ function generateAutomationBypassEnvVarName({
412
+ name
413
+ }) {
414
+ return `AUTOMATION_BYPASS_${name.toUpperCase().replace(/[^a-zA-Z0-9]/g, "_")}`;
415
+ }
416
+
252
417
  // src/config/microfrontends-config/isomorphic/validation.ts
253
- import { pathToRegexp as pathToRegexp2, parse as parsePathRegexp } from "path-to-regexp";
418
+ import { parse as parsePathRegexp, pathToRegexp as pathToRegexp2 } from "path-to-regexp";
254
419
  var LIST_FORMATTER = new Intl.ListFormat("en", {
255
420
  style: "long",
256
421
  type: "conjunction"
@@ -322,7 +487,7 @@ var validateConfigPaths = (applicationConfigsById) => {
322
487
  );
323
488
  }
324
489
  };
325
- var PATH_DEFAULT_PATTERN = "[^\\/#\\?]+?";
490
+ var PATH_DEFAULT_PATTERNS = ["[^\\/#\\?]+?", "(?:(?!\\.)[^\\/#\\?])+?"];
326
491
  function validatePathExpression(path) {
327
492
  try {
328
493
  const tokens = parsePathRegexp(path);
@@ -344,7 +509,7 @@ function validatePathExpression(path) {
344
509
  if (!token.name) {
345
510
  return `Only named wildcards are allowed: ${path} (hint: add ":path" to the wildcard)`;
346
511
  }
347
- if (token.pattern !== PATH_DEFAULT_PATTERN && // Allows (a|b|c) and ((?!a|b|c).*) regex
512
+ if (!PATH_DEFAULT_PATTERNS.includes(token.pattern) && // Allows (a|b|c) and ((?!a|b|c).*) regex
348
513
  // Only limited regex is supported for now, due to performance considerations
349
514
  // Allows all letters, numbers, and hyphens. Other characters must be escaped.
350
515
  !/^(?<allowed>[\w-~]+(?:\|[^:|()]+)+)$|^\(\?!(?<disallowed>[\w-~]+(?:\|[^:|()]+)*)\)\.\*$/.test(
@@ -430,154 +595,6 @@ var validateConfigDefaultApplication = (applicationConfigsById) => {
430
595
  }
431
596
  };
432
597
 
433
- // src/config/microfrontends-config/isomorphic/utils/hash-application-name.ts
434
- import md5 from "md5";
435
- function hashApplicationName(name) {
436
- if (!name) {
437
- throw new Error("Application name is required to generate hash");
438
- }
439
- return md5(name).substring(0, 6).padStart(6, "0");
440
- }
441
-
442
- // src/config/microfrontends-config/isomorphic/utils/generate-asset-prefix.ts
443
- var PREFIX = "vc-ap";
444
- function generateAssetPrefixFromName({
445
- name
446
- }) {
447
- if (!name) {
448
- throw new Error("Name is required to generate an asset prefix");
449
- }
450
- return `${PREFIX}-${hashApplicationName(name)}`;
451
- }
452
-
453
- // src/config/microfrontends-config/isomorphic/utils/generate-port.ts
454
- function generatePortFromName({
455
- name,
456
- minPort = 3e3,
457
- maxPort = 8e3
458
- }) {
459
- if (!name) {
460
- throw new Error("Name is required to generate a port");
461
- }
462
- let hash = 0;
463
- for (let i = 0; i < name.length; i++) {
464
- hash = (hash << 5) - hash + name.charCodeAt(i);
465
- hash |= 0;
466
- }
467
- hash = Math.abs(hash);
468
- const range = maxPort - minPort;
469
- const port = minPort + hash % range;
470
- return port;
471
- }
472
-
473
- // src/config/microfrontends-config/isomorphic/host.ts
474
- var Host = class {
475
- constructor(hostConfig, options) {
476
- if (typeof hostConfig === "string") {
477
- ({
478
- protocol: this.protocol,
479
- host: this.host,
480
- port: this.port
481
- } = Host.parseUrl(hostConfig));
482
- } else {
483
- const { protocol = "https", host, port } = hostConfig;
484
- this.protocol = protocol;
485
- this.host = host;
486
- this.port = port;
487
- }
488
- this.local = options?.isLocal;
489
- }
490
- static parseUrl(url, defaultProtocol = "https") {
491
- let hostToParse = url;
492
- if (!/^https?:\/\//.exec(hostToParse)) {
493
- hostToParse = `${defaultProtocol}://${hostToParse}`;
494
- }
495
- const parsed = new URL(hostToParse);
496
- if (!parsed.hostname) {
497
- throw new Error(Host.getMicrofrontendsError(url, "requires a host"));
498
- }
499
- if (parsed.hash) {
500
- throw new Error(
501
- Host.getMicrofrontendsError(url, "cannot have a fragment")
502
- );
503
- }
504
- if (parsed.username || parsed.password) {
505
- throw new Error(
506
- Host.getMicrofrontendsError(
507
- url,
508
- "cannot have authentication credentials (username and/or password)"
509
- )
510
- );
511
- }
512
- if (parsed.pathname !== "/") {
513
- throw new Error(Host.getMicrofrontendsError(url, "cannot have a path"));
514
- }
515
- if (parsed.search) {
516
- throw new Error(
517
- Host.getMicrofrontendsError(url, "cannot have query parameters")
518
- );
519
- }
520
- const protocol = parsed.protocol.slice(0, -1);
521
- return {
522
- protocol,
523
- host: parsed.hostname,
524
- port: parsed.port ? Number.parseInt(parsed.port) : void 0
525
- };
526
- }
527
- static getMicrofrontendsError(url, message) {
528
- return `Microfrontends configuration error: the URL ${url} in your microfrontends.json ${message}.`;
529
- }
530
- isLocal() {
531
- return this.local || this.host === "localhost" || this.host === "127.0.0.1";
532
- }
533
- toString() {
534
- const url = this.toUrl();
535
- return url.toString().replace(/\/$/, "");
536
- }
537
- toUrl() {
538
- const url = `${this.protocol}://${this.host}${this.port ? `:${this.port}` : ""}`;
539
- return new URL(url);
540
- }
541
- };
542
- var LocalHost = class extends Host {
543
- constructor({
544
- appName,
545
- local
546
- }) {
547
- let protocol;
548
- let host;
549
- let port;
550
- if (typeof local === "number") {
551
- port = local;
552
- } else if (typeof local === "string") {
553
- if (/^\d+$/.test(local)) {
554
- port = Number.parseInt(local);
555
- } else {
556
- const parsed = Host.parseUrl(local, "http");
557
- protocol = parsed.protocol;
558
- host = parsed.host;
559
- port = parsed.port;
560
- }
561
- } else if (local) {
562
- protocol = local.protocol;
563
- host = local.host;
564
- port = local.port;
565
- }
566
- super({
567
- protocol: protocol ?? "http",
568
- host: host ?? "localhost",
569
- port: port ?? generatePortFromName({ name: appName })
570
- });
571
- }
572
- };
573
-
574
- // src/config/microfrontends-config/isomorphic/utils/generate-automation-bypass-env-var-name.ts
575
- function generateAutomationBypassEnvVarName({
576
- name
577
- }) {
578
- return `AUTOMATION_BYPASS_${name.toUpperCase().replace(/[^a-zA-Z0-9]/g, "_")}`;
579
- }
580
-
581
598
  // src/config/microfrontends-config/isomorphic/application.ts
582
599
  var Application = class {
583
600
  constructor(name, {
@@ -658,9 +675,6 @@ var ChildApplication = class extends Application {
658
675
  }
659
676
  };
660
677
 
661
- // src/config/microfrontends-config/isomorphic/constants.ts
662
- var DEFAULT_LOCAL_PROXY_PORT = 3024;
663
-
664
678
  // src/config/microfrontends-config/isomorphic/index.ts
665
679
  var MicrofrontendConfigIsomorphic = class {
666
680
  constructor({
@@ -779,9 +793,17 @@ var MicrofrontendConfigIsomorphic = class {
779
793
  return this.defaultApplication;
780
794
  }
781
795
  /**
782
- * Returns the configured port for the local proxy
796
+ * Returns the configured port for the local proxy.
797
+ * Can be overridden via MFE_LOCAL_PROXY_PORT environment variable.
783
798
  */
784
799
  getLocalProxyPort() {
800
+ const portOverride = process.env[MFE_LOCAL_PROXY_PORT_ENV];
801
+ if (portOverride) {
802
+ const port = Number.parseInt(portOverride, 10);
803
+ if (!Number.isNaN(port) && port > 0 && port < 65536) {
804
+ return port;
805
+ }
806
+ }
785
807
  return this.config.options?.localProxyPort ?? DEFAULT_LOCAL_PROXY_PORT;
786
808
  }
787
809
  toClientConfig(options) {