@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
@@ -42,9 +42,9 @@ __export(testing_exports, {
42
42
  });
43
43
  module.exports = __toCommonJS(testing_exports);
44
44
  var import_node_fs = require("fs");
45
+ var import_jsonc_parser2 = require("jsonc-parser");
45
46
  var import_server = require("next/server.js");
46
47
  var import_path_to_regexp3 = require("path-to-regexp");
47
- var import_jsonc_parser2 = require("jsonc-parser");
48
48
 
49
49
  // src/config/microfrontends-config/isomorphic/index.ts
50
50
  var import_jsonc_parser = require("jsonc-parser");
@@ -141,23 +141,6 @@ var MicrofrontendError = class extends Error {
141
141
  }
142
142
  };
143
143
 
144
- // src/config/microfrontends-config/utils/get-config-from-env.ts
145
- function getConfigStringFromEnv() {
146
- const config = process.env.MFE_CONFIG;
147
- if (!config) {
148
- throw new MicrofrontendError(`Missing "MFE_CONFIG" in environment.`, {
149
- type: "config",
150
- subtype: "not_found_in_env"
151
- });
152
- }
153
- return config;
154
- }
155
-
156
- // src/config/schema/utils/is-default-app.ts
157
- function isDefaultApp(a) {
158
- return !("routing" in a);
159
- }
160
-
161
144
  // src/config/overrides/constants.ts
162
145
  var OVERRIDES_COOKIE_PREFIX = "vercel-micro-frontends-override";
163
146
  var OVERRIDES_ENV_COOKIE_PREFIX = `${OVERRIDES_COOKIE_PREFIX}:env:`;
@@ -191,6 +174,11 @@ function parseOverrides(cookies) {
191
174
  return overridesConfig;
192
175
  }
193
176
 
177
+ // src/config/schema/utils/is-default-app.ts
178
+ function isDefaultApp(a) {
179
+ return !("routing" in a);
180
+ }
181
+
194
182
  // src/config/microfrontends-config/client/index.ts
195
183
  var import_path_to_regexp = require("path-to-regexp");
196
184
  var regexpCache = /* @__PURE__ */ new Map();
@@ -289,6 +277,183 @@ var MicrofrontendConfigClient = class {
289
277
  }
290
278
  };
291
279
 
280
+ // src/config/microfrontends-config/utils/get-config-from-env.ts
281
+ function getConfigStringFromEnv() {
282
+ const config = process.env.MFE_CONFIG;
283
+ if (!config) {
284
+ throw new MicrofrontendError(`Missing "MFE_CONFIG" in environment.`, {
285
+ type: "config",
286
+ subtype: "not_found_in_env"
287
+ });
288
+ }
289
+ return config;
290
+ }
291
+
292
+ // src/config/microfrontends-config/isomorphic/constants.ts
293
+ var DEFAULT_LOCAL_PROXY_PORT = 3024;
294
+ var MFE_APP_PORT_ENV = "MFE_APP_PORT";
295
+ var MFE_LOCAL_PROXY_PORT_ENV = "MFE_LOCAL_PROXY_PORT";
296
+
297
+ // src/config/microfrontends-config/isomorphic/utils/generate-port.ts
298
+ function generatePortFromName({
299
+ name,
300
+ minPort = 3e3,
301
+ maxPort = 8e3
302
+ }) {
303
+ if (!name) {
304
+ throw new Error("Name is required to generate a port");
305
+ }
306
+ let hash = 0;
307
+ for (let i = 0; i < name.length; i++) {
308
+ hash = (hash << 5) - hash + name.charCodeAt(i);
309
+ hash |= 0;
310
+ }
311
+ hash = Math.abs(hash);
312
+ const range = maxPort - minPort;
313
+ const port = minPort + hash % range;
314
+ return port;
315
+ }
316
+
317
+ // src/config/microfrontends-config/isomorphic/host.ts
318
+ var Host = class {
319
+ constructor(hostConfig, options) {
320
+ if (typeof hostConfig === "string") {
321
+ ({
322
+ protocol: this.protocol,
323
+ host: this.host,
324
+ port: this.port
325
+ } = Host.parseUrl(hostConfig));
326
+ } else {
327
+ const { protocol = "https", host, port } = hostConfig;
328
+ this.protocol = protocol;
329
+ this.host = host;
330
+ this.port = port;
331
+ }
332
+ this.local = options?.isLocal;
333
+ }
334
+ static parseUrl(url, defaultProtocol = "https") {
335
+ let hostToParse = url;
336
+ if (!/^https?:\/\//.exec(hostToParse)) {
337
+ hostToParse = `${defaultProtocol}://${hostToParse}`;
338
+ }
339
+ const parsed = new URL(hostToParse);
340
+ if (!parsed.hostname) {
341
+ throw new Error(Host.getMicrofrontendsError(url, "requires a host"));
342
+ }
343
+ if (parsed.hash) {
344
+ throw new Error(
345
+ Host.getMicrofrontendsError(url, "cannot have a fragment")
346
+ );
347
+ }
348
+ if (parsed.username || parsed.password) {
349
+ throw new Error(
350
+ Host.getMicrofrontendsError(
351
+ url,
352
+ "cannot have authentication credentials (username and/or password)"
353
+ )
354
+ );
355
+ }
356
+ if (parsed.pathname !== "/") {
357
+ throw new Error(Host.getMicrofrontendsError(url, "cannot have a path"));
358
+ }
359
+ if (parsed.search) {
360
+ throw new Error(
361
+ Host.getMicrofrontendsError(url, "cannot have query parameters")
362
+ );
363
+ }
364
+ const protocol = parsed.protocol.slice(0, -1);
365
+ return {
366
+ protocol,
367
+ host: parsed.hostname,
368
+ port: parsed.port ? Number.parseInt(parsed.port, 10) : void 0
369
+ };
370
+ }
371
+ static getMicrofrontendsError(url, message) {
372
+ return `Microfrontends configuration error: the URL ${url} in your microfrontends.json ${message}.`;
373
+ }
374
+ isLocal() {
375
+ return this.local || this.host === "localhost" || this.host === "127.0.0.1";
376
+ }
377
+ toString() {
378
+ const url = this.toUrl();
379
+ return url.toString().replace(/\/$/, "");
380
+ }
381
+ toUrl() {
382
+ const url = `${this.protocol}://${this.host}${this.port ? `:${this.port}` : ""}`;
383
+ return new URL(url);
384
+ }
385
+ };
386
+ var LocalHost = class extends Host {
387
+ constructor({
388
+ appName,
389
+ local
390
+ }) {
391
+ const portOverride = process.env[MFE_APP_PORT_ENV];
392
+ if (portOverride) {
393
+ const overridePort = Number.parseInt(portOverride, 10);
394
+ if (!Number.isNaN(overridePort) && overridePort > 0 && overridePort < 65536) {
395
+ super({
396
+ protocol: "http",
397
+ host: "localhost",
398
+ port: overridePort
399
+ });
400
+ return;
401
+ }
402
+ }
403
+ let protocol;
404
+ let host;
405
+ let port;
406
+ if (typeof local === "number") {
407
+ port = local;
408
+ } else if (typeof local === "string") {
409
+ if (/^\d+$/.test(local)) {
410
+ port = Number.parseInt(local, 10);
411
+ } else {
412
+ const parsed = Host.parseUrl(local, "http");
413
+ protocol = parsed.protocol;
414
+ host = parsed.host;
415
+ port = parsed.port;
416
+ }
417
+ } else if (local) {
418
+ protocol = local.protocol;
419
+ host = local.host;
420
+ port = local.port;
421
+ }
422
+ super({
423
+ protocol: protocol ?? "http",
424
+ host: host ?? "localhost",
425
+ port: port ?? generatePortFromName({ name: appName })
426
+ });
427
+ }
428
+ };
429
+
430
+ // src/config/microfrontends-config/isomorphic/utils/hash-application-name.ts
431
+ var import_md5 = __toESM(require("md5"), 1);
432
+ function hashApplicationName(name) {
433
+ if (!name) {
434
+ throw new Error("Application name is required to generate hash");
435
+ }
436
+ return (0, import_md5.default)(name).substring(0, 6).padStart(6, "0");
437
+ }
438
+
439
+ // src/config/microfrontends-config/isomorphic/utils/generate-asset-prefix.ts
440
+ var PREFIX = "vc-ap";
441
+ function generateAssetPrefixFromName({
442
+ name
443
+ }) {
444
+ if (!name) {
445
+ throw new Error("Name is required to generate an asset prefix");
446
+ }
447
+ return `${PREFIX}-${hashApplicationName(name)}`;
448
+ }
449
+
450
+ // src/config/microfrontends-config/isomorphic/utils/generate-automation-bypass-env-var-name.ts
451
+ function generateAutomationBypassEnvVarName({
452
+ name
453
+ }) {
454
+ return `AUTOMATION_BYPASS_${name.toUpperCase().replace(/[^a-zA-Z0-9]/g, "_")}`;
455
+ }
456
+
292
457
  // src/config/microfrontends-config/isomorphic/validation.ts
293
458
  var import_path_to_regexp2 = require("path-to-regexp");
294
459
  var LIST_FORMATTER = new Intl.ListFormat("en", {
@@ -362,7 +527,7 @@ var validateConfigPaths = (applicationConfigsById) => {
362
527
  );
363
528
  }
364
529
  };
365
- var PATH_DEFAULT_PATTERN = "[^\\/#\\?]+?";
530
+ var PATH_DEFAULT_PATTERNS = ["[^\\/#\\?]+?", "(?:(?!\\.)[^\\/#\\?])+?"];
366
531
  function validatePathExpression(path) {
367
532
  try {
368
533
  const tokens = (0, import_path_to_regexp2.parse)(path);
@@ -384,7 +549,7 @@ function validatePathExpression(path) {
384
549
  if (!token.name) {
385
550
  return `Only named wildcards are allowed: ${path} (hint: add ":path" to the wildcard)`;
386
551
  }
387
- if (token.pattern !== PATH_DEFAULT_PATTERN && // Allows (a|b|c) and ((?!a|b|c).*) regex
552
+ if (!PATH_DEFAULT_PATTERNS.includes(token.pattern) && // Allows (a|b|c) and ((?!a|b|c).*) regex
388
553
  // Only limited regex is supported for now, due to performance considerations
389
554
  // Allows all letters, numbers, and hyphens. Other characters must be escaped.
390
555
  !/^(?<allowed>[\w-~]+(?:\|[^:|()]+)+)$|^\(\?!(?<disallowed>[\w-~]+(?:\|[^:|()]+)*)\)\.\*$/.test(
@@ -470,154 +635,6 @@ var validateConfigDefaultApplication = (applicationConfigsById) => {
470
635
  }
471
636
  };
472
637
 
473
- // src/config/microfrontends-config/isomorphic/utils/hash-application-name.ts
474
- var import_md5 = __toESM(require("md5"), 1);
475
- function hashApplicationName(name) {
476
- if (!name) {
477
- throw new Error("Application name is required to generate hash");
478
- }
479
- return (0, import_md5.default)(name).substring(0, 6).padStart(6, "0");
480
- }
481
-
482
- // src/config/microfrontends-config/isomorphic/utils/generate-asset-prefix.ts
483
- var PREFIX = "vc-ap";
484
- function generateAssetPrefixFromName({
485
- name
486
- }) {
487
- if (!name) {
488
- throw new Error("Name is required to generate an asset prefix");
489
- }
490
- return `${PREFIX}-${hashApplicationName(name)}`;
491
- }
492
-
493
- // src/config/microfrontends-config/isomorphic/utils/generate-port.ts
494
- function generatePortFromName({
495
- name,
496
- minPort = 3e3,
497
- maxPort = 8e3
498
- }) {
499
- if (!name) {
500
- throw new Error("Name is required to generate a port");
501
- }
502
- let hash = 0;
503
- for (let i = 0; i < name.length; i++) {
504
- hash = (hash << 5) - hash + name.charCodeAt(i);
505
- hash |= 0;
506
- }
507
- hash = Math.abs(hash);
508
- const range = maxPort - minPort;
509
- const port = minPort + hash % range;
510
- return port;
511
- }
512
-
513
- // src/config/microfrontends-config/isomorphic/host.ts
514
- var Host = class {
515
- constructor(hostConfig, options) {
516
- if (typeof hostConfig === "string") {
517
- ({
518
- protocol: this.protocol,
519
- host: this.host,
520
- port: this.port
521
- } = Host.parseUrl(hostConfig));
522
- } else {
523
- const { protocol = "https", host, port } = hostConfig;
524
- this.protocol = protocol;
525
- this.host = host;
526
- this.port = port;
527
- }
528
- this.local = options?.isLocal;
529
- }
530
- static parseUrl(url, defaultProtocol = "https") {
531
- let hostToParse = url;
532
- if (!/^https?:\/\//.exec(hostToParse)) {
533
- hostToParse = `${defaultProtocol}://${hostToParse}`;
534
- }
535
- const parsed = new URL(hostToParse);
536
- if (!parsed.hostname) {
537
- throw new Error(Host.getMicrofrontendsError(url, "requires a host"));
538
- }
539
- if (parsed.hash) {
540
- throw new Error(
541
- Host.getMicrofrontendsError(url, "cannot have a fragment")
542
- );
543
- }
544
- if (parsed.username || parsed.password) {
545
- throw new Error(
546
- Host.getMicrofrontendsError(
547
- url,
548
- "cannot have authentication credentials (username and/or password)"
549
- )
550
- );
551
- }
552
- if (parsed.pathname !== "/") {
553
- throw new Error(Host.getMicrofrontendsError(url, "cannot have a path"));
554
- }
555
- if (parsed.search) {
556
- throw new Error(
557
- Host.getMicrofrontendsError(url, "cannot have query parameters")
558
- );
559
- }
560
- const protocol = parsed.protocol.slice(0, -1);
561
- return {
562
- protocol,
563
- host: parsed.hostname,
564
- port: parsed.port ? Number.parseInt(parsed.port) : void 0
565
- };
566
- }
567
- static getMicrofrontendsError(url, message) {
568
- return `Microfrontends configuration error: the URL ${url} in your microfrontends.json ${message}.`;
569
- }
570
- isLocal() {
571
- return this.local || this.host === "localhost" || this.host === "127.0.0.1";
572
- }
573
- toString() {
574
- const url = this.toUrl();
575
- return url.toString().replace(/\/$/, "");
576
- }
577
- toUrl() {
578
- const url = `${this.protocol}://${this.host}${this.port ? `:${this.port}` : ""}`;
579
- return new URL(url);
580
- }
581
- };
582
- var LocalHost = class extends Host {
583
- constructor({
584
- appName,
585
- local
586
- }) {
587
- let protocol;
588
- let host;
589
- let port;
590
- if (typeof local === "number") {
591
- port = local;
592
- } else if (typeof local === "string") {
593
- if (/^\d+$/.test(local)) {
594
- port = Number.parseInt(local);
595
- } else {
596
- const parsed = Host.parseUrl(local, "http");
597
- protocol = parsed.protocol;
598
- host = parsed.host;
599
- port = parsed.port;
600
- }
601
- } else if (local) {
602
- protocol = local.protocol;
603
- host = local.host;
604
- port = local.port;
605
- }
606
- super({
607
- protocol: protocol ?? "http",
608
- host: host ?? "localhost",
609
- port: port ?? generatePortFromName({ name: appName })
610
- });
611
- }
612
- };
613
-
614
- // src/config/microfrontends-config/isomorphic/utils/generate-automation-bypass-env-var-name.ts
615
- function generateAutomationBypassEnvVarName({
616
- name
617
- }) {
618
- return `AUTOMATION_BYPASS_${name.toUpperCase().replace(/[^a-zA-Z0-9]/g, "_")}`;
619
- }
620
-
621
638
  // src/config/microfrontends-config/isomorphic/application.ts
622
639
  var Application = class {
623
640
  constructor(name, {
@@ -698,9 +715,6 @@ var ChildApplication = class extends Application {
698
715
  }
699
716
  };
700
717
 
701
- // src/config/microfrontends-config/isomorphic/constants.ts
702
- var DEFAULT_LOCAL_PROXY_PORT = 3024;
703
-
704
718
  // src/config/microfrontends-config/isomorphic/index.ts
705
719
  var MicrofrontendConfigIsomorphic = class {
706
720
  constructor({
@@ -819,9 +833,17 @@ var MicrofrontendConfigIsomorphic = class {
819
833
  return this.defaultApplication;
820
834
  }
821
835
  /**
822
- * Returns the configured port for the local proxy
836
+ * Returns the configured port for the local proxy.
837
+ * Can be overridden via MFE_LOCAL_PROXY_PORT environment variable.
823
838
  */
824
839
  getLocalProxyPort() {
840
+ const portOverride = process.env[MFE_LOCAL_PROXY_PORT_ENV];
841
+ if (portOverride) {
842
+ const port = Number.parseInt(portOverride, 10);
843
+ if (!Number.isNaN(port) && port > 0 && port < 65536) {
844
+ return port;
845
+ }
846
+ }
825
847
  return this.config.options?.localProxyPort ?? DEFAULT_LOCAL_PROXY_PORT;
826
848
  }
827
849
  toClientConfig(options) {