@vercel/microfrontends 0.10.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.
Files changed (62) hide show
  1. package/README.md +5 -5
  2. package/dist/bin/cli.cjs +172 -86
  3. package/dist/config/client.d.ts +1 -1
  4. package/dist/config/edge.d.ts +2 -2
  5. package/dist/config.cjs +1 -6
  6. package/dist/config.cjs.map +1 -1
  7. package/dist/config.d.ts +3 -3
  8. package/dist/config.js +1 -6
  9. package/dist/config.js.map +1 -1
  10. package/dist/{index-05742bef.d.ts → index-acb44057.d.ts} +2 -2
  11. package/dist/{microfrontend-config-2425db74.d.ts → microfrontend-config-983a5139.d.ts} +1 -1
  12. package/dist/next/client.cjs +1 -1
  13. package/dist/next/client.cjs.map +1 -1
  14. package/dist/next/client.js +1 -1
  15. package/dist/next/client.js.map +1 -1
  16. package/dist/next/config.cjs +3 -10
  17. package/dist/next/config.cjs.map +1 -1
  18. package/dist/next/config.js +3 -10
  19. package/dist/next/config.js.map +1 -1
  20. package/dist/next/middleware.cjs +5 -7
  21. package/dist/next/middleware.cjs.map +1 -1
  22. package/dist/next/middleware.js +5 -7
  23. package/dist/next/middleware.js.map +1 -1
  24. package/dist/next/testing.cjs +1 -6
  25. package/dist/next/testing.cjs.map +1 -1
  26. package/dist/next/testing.d.ts +2 -2
  27. package/dist/next/testing.js +1 -6
  28. package/dist/next/testing.js.map +1 -1
  29. package/dist/overrides.d.ts +2 -2
  30. package/dist/{schema-83a75e61.d.ts → schema-2922d49e.d.ts} +1 -7
  31. package/dist/{types-4fd1c7c6.d.ts → types-7b1cd9f7.d.ts} +1 -7
  32. package/dist/{types-13f3e535.d.ts → types-c3d15d04.d.ts} +1 -1
  33. package/dist/v2/config.d.ts +3 -3
  34. package/dist/v2/microfrontends/server.cjs +122 -32
  35. package/dist/v2/microfrontends/server.cjs.map +1 -1
  36. package/dist/v2/microfrontends/server.d.ts +7 -4
  37. package/dist/v2/microfrontends/server.js +122 -32
  38. package/dist/v2/microfrontends/server.js.map +1 -1
  39. package/dist/v2/microfrontends.d.ts +3 -3
  40. package/dist/v2/next/client.cjs +1 -1
  41. package/dist/v2/next/client.cjs.map +1 -1
  42. package/dist/v2/next/client.js +1 -1
  43. package/dist/v2/next/client.js.map +1 -1
  44. package/dist/v2/next/config.cjs +128 -40
  45. package/dist/v2/next/config.cjs.map +1 -1
  46. package/dist/v2/next/config.js +128 -40
  47. package/dist/v2/next/config.js.map +1 -1
  48. package/dist/v2/next/middleware.cjs +1 -1
  49. package/dist/v2/next/middleware.cjs.map +1 -1
  50. package/dist/v2/next/middleware.js +1 -1
  51. package/dist/v2/next/middleware.js.map +1 -1
  52. package/dist/v2/overrides.d.ts +3 -3
  53. package/dist/v2/schema.cjs.map +1 -1
  54. package/dist/v2/schema.d.ts +1 -1
  55. package/dist/validation.cjs +0 -8
  56. package/dist/validation.cjs.map +1 -1
  57. package/dist/validation.d.ts +2 -8
  58. package/dist/validation.js +0 -8
  59. package/dist/validation.js.map +1 -1
  60. package/package.json +8 -7
  61. package/schema/schema-v2.json +0 -4
  62. package/schema/schema.json +0 -4
@@ -1,3 +1,3 @@
1
1
  "use client";
2
- import{forwardRef as Z,useContext as I}from"react";import D from"next/link";import{useState as g,useEffect as b}from"react";import{pathToRegexp as N}from"path-to-regexp";var l=class{constructor(e,r){this.pathCache={};if(this.serialized=e,r!=null&&r.removeFlaggedPaths)for(let i of Object.values(e.applications))i.routing&&(i.routing=i.routing.filter(n=>!n.flag));this.applications=e.applications}static fromEnv(e,r){if(!e)throw new Error("No microfrontends configuration found");return new l(JSON.parse(e),r)}isEqual(e){return JSON.stringify(this.applications)===JSON.stringify(e.applications)}getApplicationNameForPath(e){if(!e.startsWith("/"))throw new Error("Path must start with a /");if(this.pathCache[e])return this.pathCache[e];let r=new URL(e,"https://example.com").pathname;for(let[n,o]of Object.entries(this.applications))if(o.routing){for(let a of o.routing)for(let s of a.paths)if(N(s).test(r))return this.pathCache[e]=n,n}let i=Object.entries(this.applications).find(([,n])=>n.default);return i?(this.pathCache[e]=i[0],i[0]):null}serialize(){return this.serialized}};var h=null;async function x(){try{let t=await fetch("/.well-known/vercel/micro-frontends/client-config");if(t.status!==200)return null;let e=await t.json();return new l(e.config)}catch{return null}}function p(t,{removeFlaggedPathsFromDefault:e}={}){let[r,i]=g(l.fromEnv(t,{removeFlaggedPaths:e})),[n,o]=g(!0);return b(()=>{if(process.env.NODE_ENV==="test"&&process.env.MFE_FORCE_CLIENT_CONFIG_FROM_SERVER!=="1"){o(!1);return}let a=l.fromEnv(t);if(!Object.values(a.applications).some(c=>{var u;return(u=c.routing)==null?void 0:u.some(C=>C.flag||C.routeToDefaultApplication)})){o(!1);return}h||(h=x()),h.then(c=>{c&&i(u=>u.isEqual(c)?u:c)}).finally(()=>{o(!1)})},[t,r.applications]),{clientConfig:r,isLoading:n}}import{createContext as O,useCallback as k,useEffect as R,useMemo as S,useState as E}from"react";import{Fragment as T,jsx as P,jsxs as A}from"react/jsx-runtime";var d=O({prefetchHref:()=>{}});function j({children:t}){let[e,r]=E(new Set),[i,n]=E(!1);R(()=>{n(typeof navigator<"u"&&(navigator.userAgent.includes("Firefox")||navigator.userAgent.includes("Safari")&&!navigator.userAgent.includes("Chrome")))},[]);let o=k(s=>{e.has(s)||r(new Set(e).add(s))},[e]),a=S(()=>({prefetchHref:o}),[o]);return i?A(d.Provider,{value:a,children:[t,[...e].map(s=>P("link",{as:"fetch",href:s,rel:"preload"},s))]}):P(T,{children:t})}import{useEffect as v,useState as F}from"react";import M from"next/script";import{jsx as H}from"react/jsx-runtime";var m="data-prefetch",f={anyZone:"[data-zone]",external:'[data-zone="null"]',sameZone:'[data-zone="same"]',prefetch:`[${m}]`},L={and:[{href_matches:"/*"},{selector_matches:f.anyZone},{not:{selector_matches:f.sameZone}},{not:{selector_matches:f.external}}]},w={and:[{href_matches:"/*"},{selector_matches:f.anyZone},{not:{selector_matches:f.sameZone}},{not:{selector_matches:f.external}},{selector_matches:f.prefetch}]};function y(t){if(!t)return!0;if("checkVisibility"in t)return t.checkVisibility({opacityProperty:!0});let e=t,r=window.getComputedStyle(e);return r.display==="none"||r.visibility==="hidden"||r.opacity==="0"?!1:y(e.parentElement)}function ne(){let{isLoading:t}=p(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG),[e,r]=F([]);return v(()=>{if(t)return;let n=new IntersectionObserver(o=>{o.forEach(a=>{a.isIntersecting&&!a.target.hasAttribute(m)&&y(a.target)&&a.target.setAttribute(m,"true")})},{root:null,rootMargin:"0px",threshold:.1});return e.forEach(o=>n.observe(o)),()=>{n.disconnect()}},[t,e]),v(()=>{if(t)return;let n=new MutationObserver(o=>{o.some(s=>s.type==="childList"&&s.addedNodes.length>0||s.type==="attributes"&&s.attributeName==="href")&&r(Array.from(document.querySelectorAll(`a${f.anyZone}:not(${f.prefetch}):not(${f.sameZone}):not(${f.external})`)))});return n.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["href"]}),()=>{n.disconnect()}},[t]),t?null:H(M,{dangerouslySetInnerHTML:{__html:`${JSON.stringify({prefetch:[{eagerness:"moderate",where:L},{eagerness:"immediate",where:w}],prerender:[{eagerness:"conservative",where:L}]})}`},id:"prefetch-zones-links",type:"speculationrules"})}import{jsx as _}from"react/jsx-runtime";var z=process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION;function B(t){let{clientConfig:e,isLoading:r}=p(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,{removeFlaggedPathsFromDefault:!0}),i=typeof t=="string"&&t.startsWith("/"),n=i?e.getApplicationNameForPath(t):null;return{zoneOfHref:n,isDifferentZone:!i||(n?z!==n:!1),isLoading:r}}var J=Z(({children:t,...e},r)=>{let{prefetchHref:i}=I(d),{zoneOfHref:n,isDifferentZone:o,isLoading:a}=B(e.href);function s(){e.href&&i(e.href)}return o&&n!==null?_("a",{...e,"data-zone":n,onMouseOver:e.prefetch!==!1?s:void 0,children:t}):_(D,{...e,"data-zone":n?"same":"null",prefetch:e.prefetch??(a?!1:void 0),ref:r,children:t})});J.displayName="MultiZonesLink";export{J as Link,ne as PrefetchCrossZoneLinks,d as PrefetchCrossZoneLinksContext,j as PrefetchCrossZoneLinksProvider,B as useZoneForHref};
2
+ import{forwardRef as Z,useContext as I}from"react";import D from"next/link";import{useState as C,useEffect as b}from"react";import{pathToRegexp as N}from"path-to-regexp";var c=class{constructor(e,r){this.pathCache={};if(this.serialized=e,r!=null&&r.removeFlaggedPaths)for(let i of Object.values(e.applications))i.routing&&(i.routing=i.routing.filter(n=>!n.flag));this.applications=e.applications}static fromEnv(e,r){if(!e)throw new Error("No microfrontends configuration found");return new c(JSON.parse(e),r)}isEqual(e){return JSON.stringify(this.applications)===JSON.stringify(e.applications)}getApplicationNameForPath(e){if(!e.startsWith("/"))throw new Error("Path must start with a /");if(this.pathCache[e])return this.pathCache[e];let r=new URL(e,"https://example.com").pathname;for(let[n,o]of Object.entries(this.applications))if(o.routing){for(let a of o.routing)for(let s of a.paths)if(N(s).test(r))return this.pathCache[e]=n,n}let i=Object.entries(this.applications).find(([,n])=>n.default);return i?(this.pathCache[e]=i[0],i[0]):null}serialize(){return this.serialized}};var h=null;async function x(){try{let t=await fetch("/.well-known/vercel/micro-frontends/client-config");if(t.status!==200)return null;let e=await t.json();return new c(e.config)}catch{return null}}function p(t,{removeFlaggedPathsFromDefault:e}={}){let[r,i]=C(c.fromEnv(t,{removeFlaggedPaths:e})),[n,o]=C(!0);return b(()=>{if(process.env.NODE_ENV==="test"&&process.env.MFE_FORCE_CLIENT_CONFIG_FROM_SERVER!=="1"){o(!1);return}let a=c.fromEnv(t);if(!Object.values(a.applications).some(l=>{var u;return(u=l.routing)==null?void 0:u.some(_=>_.flag)})){o(!1);return}h||(h=x()),h.then(l=>{l&&i(u=>u.isEqual(l)?u:l)}).finally(()=>{o(!1)})},[t,r.applications]),{clientConfig:r,isLoading:n}}import{createContext as O,useCallback as k,useEffect as R,useMemo as S,useState as g}from"react";import{Fragment as T,jsx as E,jsxs as F}from"react/jsx-runtime";var d=O({prefetchHref:()=>{}});function j({children:t}){let[e,r]=g(new Set),[i,n]=g(!1);R(()=>{n(typeof navigator<"u"&&(navigator.userAgent.includes("Firefox")||navigator.userAgent.includes("Safari")&&!navigator.userAgent.includes("Chrome")))},[]);let o=k(s=>{e.has(s)||r(new Set(e).add(s))},[e]),a=S(()=>({prefetchHref:o}),[o]);return i?F(d.Provider,{value:a,children:[t,[...e].map(s=>E("link",{as:"fetch",href:s,rel:"preload"},s))]}):E(T,{children:t})}import{useEffect as P,useState as A}from"react";import M from"next/script";import{jsx as H}from"react/jsx-runtime";var m="data-prefetch",f={anyZone:"[data-zone]",external:'[data-zone="null"]',sameZone:'[data-zone="same"]',prefetch:`[${m}]`},v={and:[{href_matches:"/*"},{selector_matches:f.anyZone},{not:{selector_matches:f.sameZone}},{not:{selector_matches:f.external}}]},w={and:[{href_matches:"/*"},{selector_matches:f.anyZone},{not:{selector_matches:f.sameZone}},{not:{selector_matches:f.external}},{selector_matches:f.prefetch}]};function L(t){if(!t)return!0;if("checkVisibility"in t)return t.checkVisibility({opacityProperty:!0});let e=t,r=window.getComputedStyle(e);return r.display==="none"||r.visibility==="hidden"||r.opacity==="0"?!1:L(e.parentElement)}function ne(){let{isLoading:t}=p(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG),[e,r]=A([]);return P(()=>{if(t)return;let n=new IntersectionObserver(o=>{o.forEach(a=>{a.isIntersecting&&!a.target.hasAttribute(m)&&L(a.target)&&a.target.setAttribute(m,"true")})},{root:null,rootMargin:"0px",threshold:.1});return e.forEach(o=>n.observe(o)),()=>{n.disconnect()}},[t,e]),P(()=>{if(t)return;let n=new MutationObserver(o=>{o.some(s=>s.type==="childList"&&s.addedNodes.length>0||s.type==="attributes"&&s.attributeName==="href")&&r(Array.from(document.querySelectorAll(`a${f.anyZone}:not(${f.prefetch}):not(${f.sameZone}):not(${f.external})`)))});return n.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["href"]}),()=>{n.disconnect()}},[t]),t?null:H(M,{dangerouslySetInnerHTML:{__html:`${JSON.stringify({prefetch:[{eagerness:"moderate",where:v},{eagerness:"immediate",where:w}],prerender:[{eagerness:"conservative",where:v}]})}`},id:"prefetch-zones-links",type:"speculationrules"})}import{jsx as y}from"react/jsx-runtime";var z=process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION;function B(t){let{clientConfig:e,isLoading:r}=p(process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,{removeFlaggedPathsFromDefault:!0}),i=typeof t=="string"&&t.startsWith("/"),n=i?e.getApplicationNameForPath(t):null;return{zoneOfHref:n,isDifferentZone:!i||(n?z!==n:!1),isLoading:r}}var J=Z(({children:t,...e},r)=>{let{prefetchHref:i}=I(d),{zoneOfHref:n,isDifferentZone:o,isLoading:a}=B(e.href);function s(){e.href&&i(e.href)}return o&&n!==null?y("a",{...e,"data-zone":n,onMouseOver:e.prefetch!==!1?s:void 0,children:t}):y(D,{...e,"data-zone":n?"same":"null",prefetch:e.prefetch??(a?!1:void 0),ref:r,children:t})});J.displayName="MultiZonesLink";export{J as Link,ne as PrefetchCrossZoneLinks,d as PrefetchCrossZoneLinksContext,j as PrefetchCrossZoneLinksProvider,B as useZoneForHref};
3
3
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/next-v2/client/link/multi-zones-link.tsx","../../../src/config-v2/react/use-client-config.ts","../../../src/config-v2/microfrontends-config/client/index.ts","../../../src/next-v2/client/prefetch/prefetch-cross-zone-links-context.tsx","../../../src/next-v2/client/prefetch/prefetch-cross-zone-links.tsx"],"sourcesContent":["import type { AnchorHTMLAttributes } from 'react';\nimport { forwardRef, useContext } from 'react';\nimport NextLink, { type LinkProps as NextLinkProps } from 'next/link';\nimport { useClientConfig } from '../../../config-v2/react/use-client-config';\nimport { PrefetchCrossZoneLinksContext } from '../prefetch';\n\ninterface BaseProps {\n children: React.ReactNode;\n href: string;\n}\nexport type LinkProps = BaseProps &\n Omit<NextLinkProps, keyof BaseProps> &\n Omit<AnchorHTMLAttributes<HTMLAnchorElement>, keyof BaseProps>;\n\nconst CURRENT_ZONE = process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION;\n\nexport function useZoneForHref(href: LinkProps['href'] | undefined): {\n zoneOfHref: string | null;\n isDifferentZone: boolean;\n isLoading: boolean;\n} {\n const { clientConfig, isLoading } = useClientConfig(\n process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,\n {\n removeFlaggedPathsFromDefault: true,\n },\n );\n const isRelativePath =\n typeof href === 'string' && (href as string).startsWith('/');\n const zoneOfHref = isRelativePath\n ? clientConfig.getApplicationNameForPath(href as string)\n : null;\n const isDifferentZone =\n !isRelativePath || (zoneOfHref ? CURRENT_ZONE !== zoneOfHref : false);\n return { zoneOfHref, isDifferentZone, isLoading };\n}\n\n/**\n * A Link component that works with Multi-Zones set-ups and will prefetch the\n * cross zone links automatically.\n */\nexport const Link = forwardRef<HTMLAnchorElement, LinkProps>(\n ({ children, ...props }, ref): JSX.Element => {\n const { prefetchHref } = useContext(PrefetchCrossZoneLinksContext);\n const { zoneOfHref, isDifferentZone, isLoading } = useZoneForHref(\n props.href,\n );\n\n function onHoverPrefetch(): void {\n if (!props.href) {\n return;\n }\n prefetchHref(props.href);\n }\n\n if (isDifferentZone && zoneOfHref !== null) {\n return (\n // biome-ignore lint/a11y/useKeyWithMouseEvents: Only used for prefetching.\n // biome-ignore lint/nursery/noStaticElementInteractions: Ignored using `--suppress`\n <a\n {...props}\n data-zone={zoneOfHref}\n onMouseOver={props.prefetch !== false ? onHoverPrefetch : undefined}\n >\n {children}\n </a>\n );\n }\n\n return (\n <NextLink\n {...props}\n data-zone={!zoneOfHref ? 'null' : 'same'}\n prefetch={props.prefetch ?? (isLoading ? false : undefined)}\n ref={ref}\n >\n {children}\n </NextLink>\n );\n },\n);\nLink.displayName = 'MultiZonesLink';\n","'use client';\n\nimport { useState, useEffect } from 'react';\nimport type { WellKnownClientData } from '../well-known/types';\nimport { MicrofrontendConfigClient } from '../microfrontends-config/client';\n\nlet cachedServerClientConfigPromise: Promise<MicrofrontendConfigClient | null> | null =\n null;\n\nasync function fetchClientConfigFromServer(): Promise<MicrofrontendConfigClient | null> {\n try {\n const response = await fetch(\n '/.well-known/vercel/micro-frontends/client-config',\n );\n if (response.status !== 200) {\n return null;\n }\n const responseJson = (await response.json()) as WellKnownClientData;\n return new MicrofrontendConfigClient(responseJson.config);\n } catch (err) {\n return null;\n }\n}\n\n/**\n * Hook to use the client microfrontends configuration. This hook will resolve\n * dynamic paths by fetching the configuration from the server if necessary,\n * allowing the server to specify the values for dynamic paths.\n */\nexport function useClientConfig(\n config: string | undefined,\n {\n removeFlaggedPathsFromDefault,\n }: {\n removeFlaggedPathsFromDefault?: boolean;\n } = {},\n): {\n clientConfig: MicrofrontendConfigClient;\n isLoading: boolean;\n} {\n const [clientConfig, setClientConfig] = useState<MicrofrontendConfigClient>(\n MicrofrontendConfigClient.fromEnv(config, {\n removeFlaggedPaths: removeFlaggedPathsFromDefault,\n }),\n );\n const [isLoading, setIsLoading] = useState(true);\n useEffect(() => {\n if (\n process.env.NODE_ENV === 'test' &&\n process.env.MFE_FORCE_CLIENT_CONFIG_FROM_SERVER !== '1'\n ) {\n setIsLoading(false);\n return;\n }\n // Since we may remove flagged paths from the client config above, we need\n // to use the original client config to determine if the config has any\n // dynamic paths.\n const originalClientConfig = MicrofrontendConfigClient.fromEnv(config);\n // As an optimization, only fetch the config from the server if the\n // microfrontends configuration has any dynamic paths. If it doesn't,\n // then the server won't return any different values.\n const hasDynamicPaths = Object.values(\n originalClientConfig.applications,\n ).some((app) =>\n app.routing?.some(\n (group) => group.flag || group.routeToDefaultApplication,\n ),\n );\n if (!hasDynamicPaths) {\n setIsLoading(false);\n return;\n }\n if (!cachedServerClientConfigPromise) {\n cachedServerClientConfigPromise = fetchClientConfigFromServer();\n }\n void cachedServerClientConfigPromise\n .then((newConfig) => {\n if (newConfig) {\n setClientConfig((prevConfig) => {\n return prevConfig.isEqual(newConfig) ? prevConfig : newConfig;\n });\n }\n })\n .finally(() => {\n setIsLoading(false);\n });\n }, [config, clientConfig.applications]);\n\n return { clientConfig, isLoading };\n}\n\nexport function resetCachedServerClientConfigPromise(): void {\n cachedServerClientConfigPromise = null;\n}\n","import { pathToRegexp } from 'path-to-regexp';\nimport type { ClientConfig } from './types';\n\ninterface MicrofrontendConfigClientOptions {\n removeFlaggedPaths?: boolean;\n}\n\nexport class MicrofrontendConfigClient {\n applications: ClientConfig['applications'];\n pathCache: Record<string, string> = {};\n private readonly serialized: ClientConfig;\n\n constructor(config: ClientConfig, opts?: MicrofrontendConfigClientOptions) {\n this.serialized = config;\n if (opts?.removeFlaggedPaths) {\n for (const app of Object.values(config.applications)) {\n if (app.routing) {\n app.routing = app.routing.filter((match) => !match.flag);\n }\n }\n }\n this.applications = config.applications;\n }\n\n /**\n * Create a new `MicrofrontendConfigClient` from a JSON string.\n * Config must be passed in to remain framework agnostic\n */\n static fromEnv(\n config: string | undefined,\n opts?: MicrofrontendConfigClientOptions,\n ): MicrofrontendConfigClient {\n if (!config) {\n throw new Error('No microfrontends configuration found');\n }\n return new MicrofrontendConfigClient(\n JSON.parse(config) as ClientConfig,\n opts,\n );\n }\n\n isEqual(other: MicrofrontendConfigClient): boolean {\n return (\n JSON.stringify(this.applications) === JSON.stringify(other.applications)\n );\n }\n\n getApplicationNameForPath(path: string): string | null {\n if (!path.startsWith('/')) {\n throw new Error(`Path must start with a /`);\n }\n\n if (this.pathCache[path]) {\n return this.pathCache[path];\n }\n\n const pathname = new URL(path, 'https://example.com').pathname;\n for (const [name, application] of Object.entries(this.applications)) {\n if (application.routing) {\n for (const group of application.routing) {\n for (const childPath of group.paths) {\n const regexp = pathToRegexp(childPath);\n if (regexp.test(pathname)) {\n this.pathCache[path] = name;\n return name;\n }\n }\n }\n }\n }\n const defaultApplication = Object.entries(this.applications).find(\n ([, application]) => application.default,\n );\n if (!defaultApplication) {\n return null;\n }\n\n this.pathCache[path] = defaultApplication[0];\n return defaultApplication[0];\n }\n\n serialize(): ClientConfig {\n return this.serialized;\n }\n}\n","import React, {\n createContext,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from 'react';\n\nexport interface PrefetchCrossZoneLinksContext {\n prefetchHref: (href: string) => void;\n}\n\nexport const PrefetchCrossZoneLinksContext =\n createContext<PrefetchCrossZoneLinksContext>({\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n prefetchHref: () => {},\n });\n\nexport function PrefetchCrossZoneLinksProvider({\n children,\n}: { children: React.ReactNode }): JSX.Element | null {\n const [seenHrefs, setSeenHrefs] = useState(new Set<string>());\n const [isSafariOrFirefox, setIsSafariOrFirefox] = useState(false);\n\n useEffect(() => {\n setIsSafariOrFirefox(\n typeof navigator !== 'undefined' &&\n (navigator.userAgent.includes('Firefox') ||\n (navigator.userAgent.includes('Safari') &&\n !navigator.userAgent.includes('Chrome'))),\n );\n }, []);\n\n const prefetchHref = useCallback(\n (href: string): void => {\n if (!seenHrefs.has(href)) {\n setSeenHrefs(new Set(seenHrefs).add(href));\n }\n },\n [seenHrefs],\n );\n\n const value = useMemo(() => ({ prefetchHref }), [prefetchHref]);\n\n if (!isSafariOrFirefox) {\n return <>{children}</>;\n }\n\n return (\n <PrefetchCrossZoneLinksContext.Provider value={value}>\n {children}\n {[...seenHrefs].map((href) => (\n <link as=\"fetch\" href={href} key={href} rel=\"preload\" />\n ))}\n </PrefetchCrossZoneLinksContext.Provider>\n );\n}\n","import { useEffect, useState } from 'react';\nimport Script from 'next/script';\nimport { useClientConfig } from '../../../config-v2/react/use-client-config';\n\nconst PREFETCH_ATTR = 'data-prefetch';\nconst DATA_ATTR_SELECTORS = {\n anyZone: '[data-zone]',\n external: '[data-zone=\"null\"]',\n sameZone: '[data-zone=\"same\"]',\n prefetch: `[${PREFETCH_ATTR}]`,\n} as const;\n\nconst PREFETCH_ON_HOVER_PREDICATES = {\n and: [\n { href_matches: '/*' },\n { selector_matches: DATA_ATTR_SELECTORS.anyZone },\n { not: { selector_matches: DATA_ATTR_SELECTORS.sameZone } },\n { not: { selector_matches: DATA_ATTR_SELECTORS.external } },\n ],\n};\n\nconst PREFETCH_WHEN_VISIBLE_PREDICATES = {\n and: [\n { href_matches: '/*' },\n { selector_matches: DATA_ATTR_SELECTORS.anyZone },\n { not: { selector_matches: DATA_ATTR_SELECTORS.sameZone } },\n { not: { selector_matches: DATA_ATTR_SELECTORS.external } },\n { selector_matches: DATA_ATTR_SELECTORS.prefetch },\n ],\n};\n\nfunction checkVisibility(element: Element | null): boolean {\n if (!element) return true;\n\n if ('checkVisibility' in element) {\n return element.checkVisibility({ opacityProperty: true });\n }\n\n // hack to get around TS thinking element is never;\n const el = element as Element;\n const style = window.getComputedStyle(el);\n\n if (\n style.display === 'none' ||\n style.visibility === 'hidden' ||\n style.opacity === '0'\n ) {\n return false;\n }\n\n return checkVisibility(el.parentElement);\n}\n\nexport function PrefetchCrossZoneLinks(): JSX.Element | null {\n const { isLoading } = useClientConfig(\n process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,\n );\n const [links, setLinks] = useState<HTMLAnchorElement[]>([]);\n\n useEffect(() => {\n if (isLoading) {\n return;\n }\n\n /**\n * Intersection observer to add the data-prefetch attribute to cross-zone\n * links that have yet to be prefetched and are visible.\n */\n const observer = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n if (\n entry.isIntersecting &&\n !entry.target.hasAttribute(PREFETCH_ATTR) &&\n // lazy perform the visibility check for nodes that are intersecting the viewport\n // and have not been prefetched.\n checkVisibility(entry.target)\n ) {\n entry.target.setAttribute(PREFETCH_ATTR, 'true');\n }\n });\n },\n {\n root: null,\n rootMargin: '0px',\n threshold: 0.1,\n },\n );\n\n links.forEach((link) => observer.observe(link));\n\n return () => {\n observer.disconnect();\n };\n }, [isLoading, links]);\n\n useEffect(() => {\n if (isLoading) {\n return;\n }\n\n /**\n * Mutation observer to notify when new nodes have entered/exited the document\n * or an href has changed.\n */\n const observer = new MutationObserver((mutations) => {\n const hasChanged = mutations.some((mutation) => {\n return (\n (mutation.type === 'childList' && mutation.addedNodes.length > 0) ||\n (mutation.type === 'attributes' && mutation.attributeName === 'href')\n );\n });\n\n if (hasChanged) {\n // Whenever there's a change, add all cross-zone links that haven't been\n // prefetched.\n setLinks(\n Array.from(\n document.querySelectorAll<HTMLAnchorElement>(\n `a${DATA_ATTR_SELECTORS.anyZone}:not(${DATA_ATTR_SELECTORS.prefetch}):not(${DATA_ATTR_SELECTORS.sameZone}):not(${DATA_ATTR_SELECTORS.external})`,\n ),\n ),\n );\n }\n });\n\n observer.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['href'],\n });\n\n return () => {\n observer.disconnect();\n };\n }, [isLoading]);\n\n // Wait till the zone-config loads to take into consideration any\n // flagged routes.\n if (isLoading) {\n return null;\n }\n\n // Prefetch links with moderate eagerness by default, immediately when marked \"data-prefetch\".\n // Prerender links with conservative eagerness by default, immediately when marked \"data-prefetch\".\n const speculationRules = {\n prefetch: [\n {\n eagerness: 'moderate',\n where: PREFETCH_ON_HOVER_PREDICATES,\n },\n {\n eagerness: 'immediate',\n where: PREFETCH_WHEN_VISIBLE_PREDICATES,\n },\n ],\n prerender: [\n {\n eagerness: 'conservative',\n where: PREFETCH_ON_HOVER_PREDICATES,\n },\n ],\n };\n\n return (\n <Script\n dangerouslySetInnerHTML={{\n __html: `${JSON.stringify(speculationRules)}`,\n }}\n id=\"prefetch-zones-links\"\n type=\"speculationrules\"\n />\n );\n}\n"],"mappings":"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","names":["forwardRef","useContext","NextLink","useState","useEffect","pathToRegexp","MicrofrontendConfigClient","config","opts","app","match","other","path","pathname","name","application","group","childPath","defaultApplication","cachedServerClientConfigPromise","fetchClientConfigFromServer","response","responseJson","MicrofrontendConfigClient","useClientConfig","config","removeFlaggedPathsFromDefault","clientConfig","setClientConfig","useState","isLoading","setIsLoading","useEffect","originalClientConfig","app","_a","group","newConfig","prevConfig","createContext","useCallback","useEffect","useMemo","useState","Fragment","jsx","jsxs","PrefetchCrossZoneLinksContext","PrefetchCrossZoneLinksProvider","children","seenHrefs","setSeenHrefs","isSafariOrFirefox","setIsSafariOrFirefox","prefetchHref","href","value","useEffect","useState","Script","jsx","PREFETCH_ATTR","DATA_ATTR_SELECTORS","PREFETCH_ON_HOVER_PREDICATES","PREFETCH_WHEN_VISIBLE_PREDICATES","checkVisibility","element","el","style","PrefetchCrossZoneLinks","isLoading","useClientConfig","links","setLinks","useState","useEffect","observer","entries","entry","link","mutations","mutation","Script","jsx","CURRENT_ZONE","useZoneForHref","href","clientConfig","isLoading","useClientConfig","isRelativePath","zoneOfHref","Link","forwardRef","children","props","ref","prefetchHref","useContext","PrefetchCrossZoneLinksContext","isDifferentZone","onHoverPrefetch","NextLink"]}
1
+ {"version":3,"sources":["../../../src/next-v2/client/link/multi-zones-link.tsx","../../../src/config-v2/react/use-client-config.ts","../../../src/config-v2/microfrontends-config/client/index.ts","../../../src/next-v2/client/prefetch/prefetch-cross-zone-links-context.tsx","../../../src/next-v2/client/prefetch/prefetch-cross-zone-links.tsx"],"sourcesContent":["import type { AnchorHTMLAttributes } from 'react';\nimport { forwardRef, useContext } from 'react';\nimport NextLink, { type LinkProps as NextLinkProps } from 'next/link';\nimport { useClientConfig } from '../../../config-v2/react/use-client-config';\nimport { PrefetchCrossZoneLinksContext } from '../prefetch';\n\ninterface BaseProps {\n children: React.ReactNode;\n href: string;\n}\nexport type LinkProps = BaseProps &\n Omit<NextLinkProps, keyof BaseProps> &\n Omit<AnchorHTMLAttributes<HTMLAnchorElement>, keyof BaseProps>;\n\nconst CURRENT_ZONE = process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION;\n\nexport function useZoneForHref(href: LinkProps['href'] | undefined): {\n zoneOfHref: string | null;\n isDifferentZone: boolean;\n isLoading: boolean;\n} {\n const { clientConfig, isLoading } = useClientConfig(\n process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,\n {\n removeFlaggedPathsFromDefault: true,\n },\n );\n const isRelativePath =\n typeof href === 'string' && (href as string).startsWith('/');\n const zoneOfHref = isRelativePath\n ? clientConfig.getApplicationNameForPath(href as string)\n : null;\n const isDifferentZone =\n !isRelativePath || (zoneOfHref ? CURRENT_ZONE !== zoneOfHref : false);\n return { zoneOfHref, isDifferentZone, isLoading };\n}\n\n/**\n * A Link component that works with Multi-Zones set-ups and will prefetch the\n * cross zone links automatically.\n */\nexport const Link = forwardRef<HTMLAnchorElement, LinkProps>(\n ({ children, ...props }, ref): JSX.Element => {\n const { prefetchHref } = useContext(PrefetchCrossZoneLinksContext);\n const { zoneOfHref, isDifferentZone, isLoading } = useZoneForHref(\n props.href,\n );\n\n function onHoverPrefetch(): void {\n if (!props.href) {\n return;\n }\n prefetchHref(props.href);\n }\n\n if (isDifferentZone && zoneOfHref !== null) {\n return (\n // biome-ignore lint/a11y/useKeyWithMouseEvents: Only used for prefetching.\n // biome-ignore lint/nursery/noStaticElementInteractions: Ignored using `--suppress`\n <a\n {...props}\n data-zone={zoneOfHref}\n onMouseOver={props.prefetch !== false ? onHoverPrefetch : undefined}\n >\n {children}\n </a>\n );\n }\n\n return (\n <NextLink\n {...props}\n data-zone={!zoneOfHref ? 'null' : 'same'}\n prefetch={props.prefetch ?? (isLoading ? false : undefined)}\n ref={ref}\n >\n {children}\n </NextLink>\n );\n },\n);\nLink.displayName = 'MultiZonesLink';\n","'use client';\n\nimport { useState, useEffect } from 'react';\nimport type { WellKnownClientData } from '../well-known/types';\nimport { MicrofrontendConfigClient } from '../microfrontends-config/client';\n\nlet cachedServerClientConfigPromise: Promise<MicrofrontendConfigClient | null> | null =\n null;\n\nasync function fetchClientConfigFromServer(): Promise<MicrofrontendConfigClient | null> {\n try {\n const response = await fetch(\n '/.well-known/vercel/micro-frontends/client-config',\n );\n if (response.status !== 200) {\n return null;\n }\n const responseJson = (await response.json()) as WellKnownClientData;\n return new MicrofrontendConfigClient(responseJson.config);\n } catch (err) {\n return null;\n }\n}\n\n/**\n * Hook to use the client microfrontends configuration. This hook will resolve\n * dynamic paths by fetching the configuration from the server if necessary,\n * allowing the server to specify the values for dynamic paths.\n */\nexport function useClientConfig(\n config: string | undefined,\n {\n removeFlaggedPathsFromDefault,\n }: {\n removeFlaggedPathsFromDefault?: boolean;\n } = {},\n): {\n clientConfig: MicrofrontendConfigClient;\n isLoading: boolean;\n} {\n const [clientConfig, setClientConfig] = useState<MicrofrontendConfigClient>(\n MicrofrontendConfigClient.fromEnv(config, {\n removeFlaggedPaths: removeFlaggedPathsFromDefault,\n }),\n );\n const [isLoading, setIsLoading] = useState(true);\n useEffect(() => {\n if (\n process.env.NODE_ENV === 'test' &&\n process.env.MFE_FORCE_CLIENT_CONFIG_FROM_SERVER !== '1'\n ) {\n setIsLoading(false);\n return;\n }\n // Since we may remove flagged paths from the client config above, we need\n // to use the original client config to determine if the config has any\n // dynamic paths.\n const originalClientConfig = MicrofrontendConfigClient.fromEnv(config);\n // As an optimization, only fetch the config from the server if the\n // microfrontends configuration has any dynamic paths. If it doesn't,\n // then the server won't return any different values.\n const hasDynamicPaths = Object.values(\n originalClientConfig.applications,\n ).some((app) => app.routing?.some((group) => group.flag));\n if (!hasDynamicPaths) {\n setIsLoading(false);\n return;\n }\n if (!cachedServerClientConfigPromise) {\n cachedServerClientConfigPromise = fetchClientConfigFromServer();\n }\n void cachedServerClientConfigPromise\n .then((newConfig) => {\n if (newConfig) {\n setClientConfig((prevConfig) => {\n return prevConfig.isEqual(newConfig) ? prevConfig : newConfig;\n });\n }\n })\n .finally(() => {\n setIsLoading(false);\n });\n }, [config, clientConfig.applications]);\n\n return { clientConfig, isLoading };\n}\n\nexport function resetCachedServerClientConfigPromise(): void {\n cachedServerClientConfigPromise = null;\n}\n","import { pathToRegexp } from 'path-to-regexp';\nimport type { ClientConfig } from './types';\n\ninterface MicrofrontendConfigClientOptions {\n removeFlaggedPaths?: boolean;\n}\n\nexport class MicrofrontendConfigClient {\n applications: ClientConfig['applications'];\n pathCache: Record<string, string> = {};\n private readonly serialized: ClientConfig;\n\n constructor(config: ClientConfig, opts?: MicrofrontendConfigClientOptions) {\n this.serialized = config;\n if (opts?.removeFlaggedPaths) {\n for (const app of Object.values(config.applications)) {\n if (app.routing) {\n app.routing = app.routing.filter((match) => !match.flag);\n }\n }\n }\n this.applications = config.applications;\n }\n\n /**\n * Create a new `MicrofrontendConfigClient` from a JSON string.\n * Config must be passed in to remain framework agnostic\n */\n static fromEnv(\n config: string | undefined,\n opts?: MicrofrontendConfigClientOptions,\n ): MicrofrontendConfigClient {\n if (!config) {\n throw new Error('No microfrontends configuration found');\n }\n return new MicrofrontendConfigClient(\n JSON.parse(config) as ClientConfig,\n opts,\n );\n }\n\n isEqual(other: MicrofrontendConfigClient): boolean {\n return (\n JSON.stringify(this.applications) === JSON.stringify(other.applications)\n );\n }\n\n getApplicationNameForPath(path: string): string | null {\n if (!path.startsWith('/')) {\n throw new Error(`Path must start with a /`);\n }\n\n if (this.pathCache[path]) {\n return this.pathCache[path];\n }\n\n const pathname = new URL(path, 'https://example.com').pathname;\n for (const [name, application] of Object.entries(this.applications)) {\n if (application.routing) {\n for (const group of application.routing) {\n for (const childPath of group.paths) {\n const regexp = pathToRegexp(childPath);\n if (regexp.test(pathname)) {\n this.pathCache[path] = name;\n return name;\n }\n }\n }\n }\n }\n const defaultApplication = Object.entries(this.applications).find(\n ([, application]) => application.default,\n );\n if (!defaultApplication) {\n return null;\n }\n\n this.pathCache[path] = defaultApplication[0];\n return defaultApplication[0];\n }\n\n serialize(): ClientConfig {\n return this.serialized;\n }\n}\n","import React, {\n createContext,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from 'react';\n\nexport interface PrefetchCrossZoneLinksContext {\n prefetchHref: (href: string) => void;\n}\n\nexport const PrefetchCrossZoneLinksContext =\n createContext<PrefetchCrossZoneLinksContext>({\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n prefetchHref: () => {},\n });\n\nexport function PrefetchCrossZoneLinksProvider({\n children,\n}: { children: React.ReactNode }): JSX.Element | null {\n const [seenHrefs, setSeenHrefs] = useState(new Set<string>());\n const [isSafariOrFirefox, setIsSafariOrFirefox] = useState(false);\n\n useEffect(() => {\n setIsSafariOrFirefox(\n typeof navigator !== 'undefined' &&\n (navigator.userAgent.includes('Firefox') ||\n (navigator.userAgent.includes('Safari') &&\n !navigator.userAgent.includes('Chrome'))),\n );\n }, []);\n\n const prefetchHref = useCallback(\n (href: string): void => {\n if (!seenHrefs.has(href)) {\n setSeenHrefs(new Set(seenHrefs).add(href));\n }\n },\n [seenHrefs],\n );\n\n const value = useMemo(() => ({ prefetchHref }), [prefetchHref]);\n\n if (!isSafariOrFirefox) {\n return <>{children}</>;\n }\n\n return (\n <PrefetchCrossZoneLinksContext.Provider value={value}>\n {children}\n {[...seenHrefs].map((href) => (\n <link as=\"fetch\" href={href} key={href} rel=\"preload\" />\n ))}\n </PrefetchCrossZoneLinksContext.Provider>\n );\n}\n","import { useEffect, useState } from 'react';\nimport Script from 'next/script';\nimport { useClientConfig } from '../../../config-v2/react/use-client-config';\n\nconst PREFETCH_ATTR = 'data-prefetch';\nconst DATA_ATTR_SELECTORS = {\n anyZone: '[data-zone]',\n external: '[data-zone=\"null\"]',\n sameZone: '[data-zone=\"same\"]',\n prefetch: `[${PREFETCH_ATTR}]`,\n} as const;\n\nconst PREFETCH_ON_HOVER_PREDICATES = {\n and: [\n { href_matches: '/*' },\n { selector_matches: DATA_ATTR_SELECTORS.anyZone },\n { not: { selector_matches: DATA_ATTR_SELECTORS.sameZone } },\n { not: { selector_matches: DATA_ATTR_SELECTORS.external } },\n ],\n};\n\nconst PREFETCH_WHEN_VISIBLE_PREDICATES = {\n and: [\n { href_matches: '/*' },\n { selector_matches: DATA_ATTR_SELECTORS.anyZone },\n { not: { selector_matches: DATA_ATTR_SELECTORS.sameZone } },\n { not: { selector_matches: DATA_ATTR_SELECTORS.external } },\n { selector_matches: DATA_ATTR_SELECTORS.prefetch },\n ],\n};\n\nfunction checkVisibility(element: Element | null): boolean {\n if (!element) return true;\n\n if ('checkVisibility' in element) {\n return element.checkVisibility({ opacityProperty: true });\n }\n\n // hack to get around TS thinking element is never;\n const el = element as Element;\n const style = window.getComputedStyle(el);\n\n if (\n style.display === 'none' ||\n style.visibility === 'hidden' ||\n style.opacity === '0'\n ) {\n return false;\n }\n\n return checkVisibility(el.parentElement);\n}\n\nexport function PrefetchCrossZoneLinks(): JSX.Element | null {\n const { isLoading } = useClientConfig(\n process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,\n );\n const [links, setLinks] = useState<HTMLAnchorElement[]>([]);\n\n useEffect(() => {\n if (isLoading) {\n return;\n }\n\n /**\n * Intersection observer to add the data-prefetch attribute to cross-zone\n * links that have yet to be prefetched and are visible.\n */\n const observer = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n if (\n entry.isIntersecting &&\n !entry.target.hasAttribute(PREFETCH_ATTR) &&\n // lazy perform the visibility check for nodes that are intersecting the viewport\n // and have not been prefetched.\n checkVisibility(entry.target)\n ) {\n entry.target.setAttribute(PREFETCH_ATTR, 'true');\n }\n });\n },\n {\n root: null,\n rootMargin: '0px',\n threshold: 0.1,\n },\n );\n\n links.forEach((link) => observer.observe(link));\n\n return () => {\n observer.disconnect();\n };\n }, [isLoading, links]);\n\n useEffect(() => {\n if (isLoading) {\n return;\n }\n\n /**\n * Mutation observer to notify when new nodes have entered/exited the document\n * or an href has changed.\n */\n const observer = new MutationObserver((mutations) => {\n const hasChanged = mutations.some((mutation) => {\n return (\n (mutation.type === 'childList' && mutation.addedNodes.length > 0) ||\n (mutation.type === 'attributes' && mutation.attributeName === 'href')\n );\n });\n\n if (hasChanged) {\n // Whenever there's a change, add all cross-zone links that haven't been\n // prefetched.\n setLinks(\n Array.from(\n document.querySelectorAll<HTMLAnchorElement>(\n `a${DATA_ATTR_SELECTORS.anyZone}:not(${DATA_ATTR_SELECTORS.prefetch}):not(${DATA_ATTR_SELECTORS.sameZone}):not(${DATA_ATTR_SELECTORS.external})`,\n ),\n ),\n );\n }\n });\n\n observer.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['href'],\n });\n\n return () => {\n observer.disconnect();\n };\n }, [isLoading]);\n\n // Wait till the zone-config loads to take into consideration any\n // flagged routes.\n if (isLoading) {\n return null;\n }\n\n // Prefetch links with moderate eagerness by default, immediately when marked \"data-prefetch\".\n // Prerender links with conservative eagerness by default, immediately when marked \"data-prefetch\".\n const speculationRules = {\n prefetch: [\n {\n eagerness: 'moderate',\n where: PREFETCH_ON_HOVER_PREDICATES,\n },\n {\n eagerness: 'immediate',\n where: PREFETCH_WHEN_VISIBLE_PREDICATES,\n },\n ],\n prerender: [\n {\n eagerness: 'conservative',\n where: PREFETCH_ON_HOVER_PREDICATES,\n },\n ],\n };\n\n return (\n <Script\n dangerouslySetInnerHTML={{\n __html: `${JSON.stringify(speculationRules)}`,\n }}\n id=\"prefetch-zones-links\"\n type=\"speculationrules\"\n />\n );\n}\n"],"mappings":";AACA,OAAS,cAAAA,EAAY,cAAAC,MAAkB,QACvC,OAAOC,MAAmD,YCA1D,OAAS,YAAAC,EAAU,aAAAC,MAAiB,QCFpC,OAAS,gBAAAC,MAAoB,iBAOtB,IAAMC,EAAN,KAAgC,CAKrC,YAAYC,EAAsBC,EAAyC,CAH3E,eAAoC,CAAC,EAKnC,GADA,KAAK,WAAaD,EACdC,GAAA,MAAAA,EAAM,mBACR,QAAWC,KAAO,OAAO,OAAOF,EAAO,YAAY,EAC7CE,EAAI,UACNA,EAAI,QAAUA,EAAI,QAAQ,OAAQC,GAAU,CAACA,EAAM,IAAI,GAI7D,KAAK,aAAeH,EAAO,YAC7B,CAMA,OAAO,QACLA,EACAC,EAC2B,CAC3B,GAAI,CAACD,EACH,MAAM,IAAI,MAAM,uCAAuC,EAEzD,OAAO,IAAID,EACT,KAAK,MAAMC,CAAM,EACjBC,CACF,CACF,CAEA,QAAQG,EAA2C,CACjD,OACE,KAAK,UAAU,KAAK,YAAY,IAAM,KAAK,UAAUA,EAAM,YAAY,CAE3E,CAEA,0BAA0BC,EAA6B,CACrD,GAAI,CAACA,EAAK,WAAW,GAAG,EACtB,MAAM,IAAI,MAAM,0BAA0B,EAG5C,GAAI,KAAK,UAAUA,CAAI,EACrB,OAAO,KAAK,UAAUA,CAAI,EAG5B,IAAMC,EAAW,IAAI,IAAID,EAAM,qBAAqB,EAAE,SACtD,OAAW,CAACE,EAAMC,CAAW,IAAK,OAAO,QAAQ,KAAK,YAAY,EAChE,GAAIA,EAAY,SACd,QAAWC,KAASD,EAAY,QAC9B,QAAWE,KAAaD,EAAM,MAE5B,GADeX,EAAaY,CAAS,EAC1B,KAAKJ,CAAQ,EACtB,YAAK,UAAUD,CAAI,EAAIE,EAChBA,EAMjB,IAAMI,EAAqB,OAAO,QAAQ,KAAK,YAAY,EAAE,KAC3D,CAAC,CAAC,CAAEH,CAAW,IAAMA,EAAY,OACnC,EACA,OAAKG,GAIL,KAAK,UAAUN,CAAI,EAAIM,EAAmB,CAAC,EACpCA,EAAmB,CAAC,GAJlB,IAKX,CAEA,WAA0B,CACxB,OAAO,KAAK,UACd,CACF,ED9EA,IAAIC,EACF,KAEF,eAAeC,GAAyE,CACtF,GAAI,CACF,IAAMC,EAAW,MAAM,MACrB,mDACF,EACA,GAAIA,EAAS,SAAW,IACtB,OAAO,KAET,IAAMC,EAAgB,MAAMD,EAAS,KAAK,EAC1C,OAAO,IAAIE,EAA0BD,EAAa,MAAM,CAC1D,MAAE,CACA,OAAO,IACT,CACF,CAOO,SAASE,EACdC,EACA,CACE,8BAAAC,CACF,EAEI,CAAC,EAIL,CACA,GAAM,CAACC,EAAcC,CAAe,EAAIC,EACtCN,EAA0B,QAAQE,EAAQ,CACxC,mBAAoBC,CACtB,CAAC,CACH,EACM,CAACI,EAAWC,CAAY,EAAIF,EAAS,EAAI,EAC/C,OAAAG,EAAU,IAAM,CACd,GACE,QAAQ,IAAI,WAAa,QACzB,QAAQ,IAAI,sCAAwC,IACpD,CACAD,EAAa,EAAK,EAClB,OAKF,IAAME,EAAuBV,EAA0B,QAAQE,CAAM,EAOrE,GAAI,CAHoB,OAAO,OAC7BQ,EAAqB,YACvB,EAAE,KAAMC,GAAK,CA/DjB,IAAAC,EA+DoB,OAAAA,EAAAD,EAAI,UAAJ,YAAAC,EAAa,KAAMC,GAAUA,EAAM,MAAK,EAClC,CACpBL,EAAa,EAAK,EAClB,OAEGZ,IACHA,EAAkCC,EAA4B,GAE3DD,EACF,KAAMkB,GAAc,CACfA,GACFT,EAAiBU,GACRA,EAAW,QAAQD,CAAS,EAAIC,EAAaD,CACrD,CAEL,CAAC,EACA,QAAQ,IAAM,CACbN,EAAa,EAAK,CACpB,CAAC,CACL,EAAG,CAACN,EAAQE,EAAa,YAAY,CAAC,EAE/B,CAAE,aAAAA,EAAc,UAAAG,CAAU,CACnC,CErFA,OACE,iBAAAS,EACA,eAAAC,EACA,aAAAC,EACA,WAAAC,EACA,YAAAC,MACK,QAuCI,mBAAAC,EAAA,OAAAC,EAIP,QAAAC,MAJO,oBAjCJ,IAAMC,EACXR,EAA6C,CAE3C,aAAc,IAAM,CAAC,CACvB,CAAC,EAEI,SAASS,EAA+B,CAC7C,SAAAC,CACF,EAAsD,CACpD,GAAM,CAACC,EAAWC,CAAY,EAAIR,EAAS,IAAI,GAAa,EACtD,CAACS,EAAmBC,CAAoB,EAAIV,EAAS,EAAK,EAEhEF,EAAU,IAAM,CACdY,EACE,OAAO,UAAc,MAClB,UAAU,UAAU,SAAS,SAAS,GACpC,UAAU,UAAU,SAAS,QAAQ,GACpC,CAAC,UAAU,UAAU,SAAS,QAAQ,EAC9C,CACF,EAAG,CAAC,CAAC,EAEL,IAAMC,EAAed,EAClBe,GAAuB,CACjBL,EAAU,IAAIK,CAAI,GACrBJ,EAAa,IAAI,IAAID,CAAS,EAAE,IAAIK,CAAI,CAAC,CAE7C,EACA,CAACL,CAAS,CACZ,EAEMM,EAAQd,EAAQ,KAAO,CAAE,aAAAY,CAAa,GAAI,CAACA,CAAY,CAAC,EAE9D,OAAKF,EAKHN,EAACC,EAA8B,SAA9B,CAAuC,MAAOS,EAC5C,UAAAP,EACA,CAAC,GAAGC,CAAS,EAAE,IAAKK,GACnBV,EAAC,QAAK,GAAG,QAAQ,KAAMU,EAAiB,IAAI,WAAVA,CAAoB,CACvD,GACH,EATOV,EAAAD,EAAA,CAAG,SAAAK,EAAS,CAWvB,CCxDA,OAAS,aAAAQ,EAAW,YAAAC,MAAgB,QACpC,OAAOC,MAAY,cAqKf,cAAAC,MAAA,oBAlKJ,IAAMC,EAAgB,gBAChBC,EAAsB,CAC1B,QAAS,cACT,SAAU,qBACV,SAAU,qBACV,SAAU,IAAID,IAChB,EAEME,EAA+B,CACnC,IAAK,CACH,CAAE,aAAc,IAAK,EACrB,CAAE,iBAAkBD,EAAoB,OAAQ,EAChD,CAAE,IAAK,CAAE,iBAAkBA,EAAoB,QAAS,CAAE,EAC1D,CAAE,IAAK,CAAE,iBAAkBA,EAAoB,QAAS,CAAE,CAC5D,CACF,EAEME,EAAmC,CACvC,IAAK,CACH,CAAE,aAAc,IAAK,EACrB,CAAE,iBAAkBF,EAAoB,OAAQ,EAChD,CAAE,IAAK,CAAE,iBAAkBA,EAAoB,QAAS,CAAE,EAC1D,CAAE,IAAK,CAAE,iBAAkBA,EAAoB,QAAS,CAAE,EAC1D,CAAE,iBAAkBA,EAAoB,QAAS,CACnD,CACF,EAEA,SAASG,EAAgBC,EAAkC,CACzD,GAAI,CAACA,EAAS,MAAO,GAErB,GAAI,oBAAqBA,EACvB,OAAOA,EAAQ,gBAAgB,CAAE,gBAAiB,EAAK,CAAC,EAI1D,IAAMC,EAAKD,EACLE,EAAQ,OAAO,iBAAiBD,CAAE,EAExC,OACEC,EAAM,UAAY,QAClBA,EAAM,aAAe,UACrBA,EAAM,UAAY,IAEX,GAGFH,EAAgBE,EAAG,aAAa,CACzC,CAEO,SAASE,IAA6C,CAC3D,GAAM,CAAE,UAAAC,CAAU,EAAIC,EACpB,QAAQ,IAAI,6BACd,EACM,CAACC,EAAOC,CAAQ,EAAIC,EAA8B,CAAC,CAAC,EAmF1D,OAjFAC,EAAU,IAAM,CACd,GAAIL,EACF,OAOF,IAAMM,EAAW,IAAI,qBAClBC,GAAY,CACXA,EAAQ,QAASC,GAAU,CAEvBA,EAAM,gBACN,CAACA,EAAM,OAAO,aAAajB,CAAa,GAGxCI,EAAgBa,EAAM,MAAM,GAE5BA,EAAM,OAAO,aAAajB,EAAe,MAAM,CAEnD,CAAC,CACH,EACA,CACE,KAAM,KACN,WAAY,MACZ,UAAW,EACb,CACF,EAEA,OAAAW,EAAM,QAASO,GAASH,EAAS,QAAQG,CAAI,CAAC,EAEvC,IAAM,CACXH,EAAS,WAAW,CACtB,CACF,EAAG,CAACN,EAAWE,CAAK,CAAC,EAErBG,EAAU,IAAM,CACd,GAAIL,EACF,OAOF,IAAMM,EAAW,IAAI,iBAAkBI,GAAc,CAChCA,EAAU,KAAMC,GAE9BA,EAAS,OAAS,aAAeA,EAAS,WAAW,OAAS,GAC9DA,EAAS,OAAS,cAAgBA,EAAS,gBAAkB,MAEjE,GAKCR,EACE,MAAM,KACJ,SAAS,iBACP,IAAIX,EAAoB,eAAeA,EAAoB,iBAAiBA,EAAoB,iBAAiBA,EAAoB,WACvI,CACF,CACF,CAEJ,CAAC,EAED,OAAAc,EAAS,QAAQ,SAAS,KAAM,CAC9B,UAAW,GACX,QAAS,GACT,WAAY,GACZ,gBAAiB,CAAC,MAAM,CAC1B,CAAC,EAEM,IAAM,CACXA,EAAS,WAAW,CACtB,CACF,EAAG,CAACN,CAAS,CAAC,EAIVA,EACK,KAyBPV,EAACsB,EAAA,CACC,wBAAyB,CACvB,OAAQ,GAAG,KAAK,UAtBG,CACvB,SAAU,CACR,CACE,UAAW,WACX,MAAOnB,CACT,EACA,CACE,UAAW,YACX,MAAOC,CACT,CACF,EACA,UAAW,CACT,CACE,UAAW,eACX,MAAOD,CACT,CACF,CACF,CAKgD,GAC5C,EACA,GAAG,uBACH,KAAK,mBACP,CAEJ,CJnHQ,cAAAoB,MAAA,oBA7CR,IAAMC,EAAe,QAAQ,IAAI,oCAE1B,SAASC,EAAeC,EAI7B,CACA,GAAM,CAAE,aAAAC,EAAc,UAAAC,CAAU,EAAIC,EAClC,QAAQ,IAAI,8BACZ,CACE,8BAA+B,EACjC,CACF,EACMC,EACJ,OAAOJ,GAAS,UAAaA,EAAgB,WAAW,GAAG,EACvDK,EAAaD,EACfH,EAAa,0BAA0BD,CAAc,EACrD,KAGJ,MAAO,CAAE,WAAAK,EAAY,gBADnB,CAACD,IAAmBC,EAAaP,IAAiBO,EAAa,IAC3B,UAAAH,CAAU,CAClD,CAMO,IAAMI,EAAOC,EAClB,CAAC,CAAE,SAAAC,EAAU,GAAGC,CAAM,EAAGC,IAAqB,CAC5C,GAAM,CAAE,aAAAC,CAAa,EAAIC,EAAWC,CAA6B,EAC3D,CAAE,WAAAR,EAAY,gBAAAS,EAAiB,UAAAZ,CAAU,EAAIH,EACjDU,EAAM,IACR,EAEA,SAASM,GAAwB,CAC1BN,EAAM,MAGXE,EAAaF,EAAM,IAAI,CACzB,CAEA,OAAIK,GAAmBT,IAAe,KAIlCR,EAAC,KACE,GAAGY,EACJ,YAAWJ,EACX,YAAaI,EAAM,WAAa,GAAQM,EAAkB,OAEzD,SAAAP,EACH,EAKFX,EAACmB,EAAA,CACE,GAAGP,EACJ,YAAYJ,EAAsB,OAAT,OACzB,SAAUI,EAAM,WAAaP,EAAY,GAAQ,QACjD,IAAKQ,EAEJ,SAAAF,EACH,CAEJ,CACF,EACAF,EAAK,YAAc","names":["forwardRef","useContext","NextLink","useState","useEffect","pathToRegexp","MicrofrontendConfigClient","config","opts","app","match","other","path","pathname","name","application","group","childPath","defaultApplication","cachedServerClientConfigPromise","fetchClientConfigFromServer","response","responseJson","MicrofrontendConfigClient","useClientConfig","config","removeFlaggedPathsFromDefault","clientConfig","setClientConfig","useState","isLoading","setIsLoading","useEffect","originalClientConfig","app","_a","group","newConfig","prevConfig","createContext","useCallback","useEffect","useMemo","useState","Fragment","jsx","jsxs","PrefetchCrossZoneLinksContext","PrefetchCrossZoneLinksProvider","children","seenHrefs","setSeenHrefs","isSafariOrFirefox","setIsSafariOrFirefox","prefetchHref","href","value","useEffect","useState","Script","jsx","PREFETCH_ATTR","DATA_ATTR_SELECTORS","PREFETCH_ON_HOVER_PREDICATES","PREFETCH_WHEN_VISIBLE_PREDICATES","checkVisibility","element","el","style","PrefetchCrossZoneLinks","isLoading","useClientConfig","links","setLinks","useState","useEffect","observer","entries","entry","link","mutations","mutation","Script","jsx","CURRENT_ZONE","useZoneForHref","href","clientConfig","isLoading","useClientConfig","isRelativePath","zoneOfHref","Link","forwardRef","children","props","ref","prefetchHref","useContext","PrefetchCrossZoneLinksContext","isDifferentZone","onHoverPrefetch","NextLink"]}
@@ -33,11 +33,11 @@ __export(config_exports, {
33
33
  withMicrofrontends: () => withMicrofrontends
34
34
  });
35
35
  module.exports = __toCommonJS(config_exports);
36
- var import_node_fs2 = __toESM(require("fs"), 1);
36
+ var import_node_fs4 = __toESM(require("fs"), 1);
37
37
 
38
38
  // src/config-v2/microfrontends/server/index.ts
39
- var import_node_fs = __toESM(require("fs"), 1);
40
- var import_node_path2 = require("path");
39
+ var import_node_fs3 = __toESM(require("fs"), 1);
40
+ var import_node_path4 = require("path");
41
41
 
42
42
  // src/config-v2/overrides/constants.ts
43
43
  var OVERRIDES_COOKIE_PREFIX = "vercel-microfrontends-override";
@@ -221,21 +221,21 @@ var MicrofrontendConfigClient = class {
221
221
  isEqual(other) {
222
222
  return JSON.stringify(this.applications) === JSON.stringify(other.applications);
223
223
  }
224
- getApplicationNameForPath(path2) {
225
- if (!path2.startsWith("/")) {
224
+ getApplicationNameForPath(path3) {
225
+ if (!path3.startsWith("/")) {
226
226
  throw new Error(`Path must start with a /`);
227
227
  }
228
- if (this.pathCache[path2]) {
229
- return this.pathCache[path2];
228
+ if (this.pathCache[path3]) {
229
+ return this.pathCache[path3];
230
230
  }
231
- const pathname = new URL(path2, "https://example.com").pathname;
231
+ const pathname = new URL(path3, "https://example.com").pathname;
232
232
  for (const [name, application] of Object.entries(this.applications)) {
233
233
  if (application.routing) {
234
234
  for (const group of application.routing) {
235
235
  for (const childPath of group.paths) {
236
236
  const regexp = (0, import_path_to_regexp.pathToRegexp)(childPath);
237
237
  if (regexp.test(pathname)) {
238
- this.pathCache[path2] = name;
238
+ this.pathCache[path3] = name;
239
239
  return name;
240
240
  }
241
241
  }
@@ -248,7 +248,7 @@ var MicrofrontendConfigClient = class {
248
248
  if (!defaultApplication) {
249
249
  return null;
250
250
  }
251
- this.pathCache[path2] = defaultApplication[0];
251
+ this.pathCache[path3] = defaultApplication[0];
252
252
  return defaultApplication[0];
253
253
  }
254
254
  serialize() {
@@ -280,22 +280,22 @@ var validateConfigPaths = (applicationConfigsById) => {
280
280
  continue;
281
281
  }
282
282
  for (const pathMatch of app.routing) {
283
- for (const path2 of pathMatch.paths) {
284
- const tokens = (0, import_path_to_regexp2.parse)(path2);
283
+ for (const path3 of pathMatch.paths) {
284
+ const tokens = (0, import_path_to_regexp2.parse)(path3);
285
285
  for (const token of tokens.slice(0, -1)) {
286
286
  if (typeof token !== "string") {
287
287
  errors.push(
288
- `Path ${path2} may only have a :wildcard in the last path component`
288
+ `Path ${path3} may only have a :wildcard in the last path component`
289
289
  );
290
290
  }
291
291
  }
292
- const existing = pathsByApplicationId.get(path2);
292
+ const existing = pathsByApplicationId.get(path3);
293
293
  if (existing) {
294
294
  existing.applications.push(id);
295
295
  } else {
296
- pathsByApplicationId.set(path2, {
296
+ pathsByApplicationId.set(path3, {
297
297
  applications: [id],
298
- matcher: (0, import_path_to_regexp2.pathToRegexp)(path2),
298
+ matcher: (0, import_path_to_regexp2.pathToRegexp)(path3),
299
299
  applicationId: id
300
300
  });
301
301
  }
@@ -303,10 +303,10 @@ var validateConfigPaths = (applicationConfigsById) => {
303
303
  }
304
304
  }
305
305
  const entries = Array.from(pathsByApplicationId.entries());
306
- entries.forEach(([path2, { applications: ids, matcher, applicationId }]) => {
306
+ entries.forEach(([path3, { applications: ids, matcher, applicationId }]) => {
307
307
  if (ids.length > 1) {
308
308
  errors.push(
309
- `Duplicate path "${path2}" for applications "${ids.join(", ")}"`
309
+ `Duplicate path "${path3}" for applications "${ids.join(", ")}"`
310
310
  );
311
311
  }
312
312
  entries.forEach(
@@ -314,14 +314,14 @@ var validateConfigPaths = (applicationConfigsById) => {
314
314
  matchPath,
315
315
  { applications: matchIds, applicationId: matchApplicationId }
316
316
  ]) => {
317
- if (path2 === matchPath) {
317
+ if (path3 === matchPath) {
318
318
  return;
319
319
  }
320
320
  if (applicationId === matchApplicationId) {
321
321
  return;
322
322
  }
323
323
  if (matcher.test(matchPath)) {
324
- const source = `"${path2}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
324
+ const source = `"${path3}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
325
325
  const destination = `"${matchPath}" of application${matchIds.length > 0 ? "s" : ""} ${matchIds.join(", ")}`;
326
326
  errors.push(
327
327
  `Overlapping path detected between ${source} and ${destination}`
@@ -812,8 +812,82 @@ var Microfrontends = class {
812
812
  }
813
813
  };
814
814
 
815
- // src/config-v2/microfrontends/server/utils/get-output-file-path.ts
815
+ // src/config-v2/microfrontends/utils/find-repository-root.ts
816
+ var import_node_fs = __toESM(require("fs"), 1);
816
817
  var import_node_path = __toESM(require("path"), 1);
818
+ var GIT_DIRECTORY = ".git";
819
+ function findRepositoryRoot(startDir) {
820
+ let currentDir = startDir || process.cwd();
821
+ while (currentDir !== import_node_path.default.parse(currentDir).root) {
822
+ const gitPath = import_node_path.default.join(currentDir, GIT_DIRECTORY);
823
+ if (import_node_fs.default.existsSync(gitPath) && import_node_fs.default.statSync(gitPath).isDirectory()) {
824
+ return currentDir;
825
+ }
826
+ currentDir = import_node_path.default.dirname(currentDir);
827
+ }
828
+ throw new Error(
829
+ "Repository root not found. Specify the root of the repository with the `repository.root` option."
830
+ );
831
+ }
832
+
833
+ // src/config-v2/microfrontends/utils/find-package-path.ts
834
+ var import_node_path2 = require("path");
835
+ var import_node_fs2 = require("fs");
836
+ var import_fast_glob = __toESM(require("fast-glob"), 1);
837
+ var configCache = {};
838
+ function findPackagePathWithGlob({
839
+ repositoryRoot,
840
+ name
841
+ }) {
842
+ try {
843
+ const packageJsonPaths = import_fast_glob.default.globSync("**/package.json", {
844
+ cwd: repositoryRoot,
845
+ absolute: true,
846
+ onlyFiles: true,
847
+ followSymbolicLinks: false,
848
+ ignore: ["**/node_modules/**", "**/.git/**"]
849
+ });
850
+ const matchingPaths = [];
851
+ for (const packageJsonPath2 of packageJsonPaths) {
852
+ const packageJsonContent = (0, import_node_fs2.readFileSync)(packageJsonPath2, "utf-8");
853
+ const packageJson = JSON.parse(packageJsonContent);
854
+ if (packageJson.name === name) {
855
+ matchingPaths.push(packageJsonPath2);
856
+ }
857
+ }
858
+ if (matchingPaths.length > 1) {
859
+ throw new Error(
860
+ `Found multiple packages with the name "${name}" in the repository: ${matchingPaths.join(", ")}`
861
+ );
862
+ }
863
+ if (matchingPaths.length === 0) {
864
+ throw new Error(
865
+ `Could not find package with the name "${name}" in the repository`
866
+ );
867
+ }
868
+ const [packageJsonPath] = matchingPaths;
869
+ return (0, import_node_path2.dirname)(packageJsonPath);
870
+ } catch (error) {
871
+ return null;
872
+ }
873
+ }
874
+ function findPackagePath(opts) {
875
+ const cacheKey = `${opts.repositoryRoot}-${opts.name}`;
876
+ if (configCache[cacheKey]) {
877
+ return configCache[cacheKey];
878
+ }
879
+ const result = findPackagePathWithGlob(opts);
880
+ if (!result) {
881
+ throw new Error(
882
+ `Could not find package with the name "${opts.name}" in the repository`
883
+ );
884
+ }
885
+ configCache[cacheKey] = result;
886
+ return result;
887
+ }
888
+
889
+ // src/config-v2/microfrontends/server/utils/get-output-file-path.ts
890
+ var import_node_path3 = __toESM(require("path"), 1);
817
891
 
818
892
  // src/config-v2/microfrontends/server/constants.ts
819
893
  var MFE_CONFIG_DEFAULT_FILE_PATH = "microfrontends";
@@ -827,13 +901,13 @@ function isVercel() {
827
901
  // src/config-v2/microfrontends/server/utils/get-output-file-path.ts
828
902
  function getOutputFilePath() {
829
903
  if (isVercel()) {
830
- return import_node_path.default.join(
904
+ return import_node_path3.default.join(
831
905
  ".vercel",
832
906
  MFE_CONFIG_DEFAULT_FILE_PATH,
833
907
  MFE_CONFIG_DEFAULT_FILE_NAME
834
908
  );
835
909
  }
836
- return import_node_path.default.join(MFE_CONFIG_DEFAULT_FILE_PATH, MFE_CONFIG_DEFAULT_FILE_NAME);
910
+ return import_node_path3.default.join(MFE_CONFIG_DEFAULT_FILE_PATH, MFE_CONFIG_DEFAULT_FILE_NAME);
837
911
  }
838
912
 
839
913
  // src/config-v2/microfrontends/server/validation.ts
@@ -1143,10 +1217,6 @@ var schema_v2_default = {
1143
1217
  type: "string",
1144
1218
  description: "flag name that can be used to enable/disable all paths in the group"
1145
1219
  },
1146
- routeToDefaultApplication: {
1147
- type: "boolean",
1148
- 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."
1149
- },
1150
1220
  paths: {
1151
1221
  type: "array",
1152
1222
  items: {
@@ -1223,8 +1293,8 @@ var MicrofrontendsServer = class extends Microfrontends {
1223
1293
  pretty: true
1224
1294
  }) {
1225
1295
  const outputPath = getOutputFilePath();
1226
- import_node_fs.default.mkdirSync((0, import_node_path2.dirname)(outputPath), { recursive: true });
1227
- import_node_fs.default.writeFileSync(
1296
+ import_node_fs3.default.mkdirSync((0, import_node_path4.dirname)(outputPath), { recursive: true });
1297
+ import_node_fs3.default.writeFileSync(
1228
1298
  outputPath,
1229
1299
  JSON.stringify(
1230
1300
  this.config.toSchemaJson(),
@@ -1292,12 +1362,32 @@ var MicrofrontendsServer = class extends Microfrontends {
1292
1362
  static fromFile({
1293
1363
  filePath,
1294
1364
  cookies,
1295
- meta
1365
+ meta,
1366
+ options
1296
1367
  }) {
1297
1368
  try {
1298
- const config = import_node_fs.default.readFileSync(filePath, "utf-8");
1369
+ const configJson = import_node_fs3.default.readFileSync(filePath, "utf-8");
1370
+ const config = MicrofrontendsServer.validate(configJson);
1371
+ if (!isMainConfig(config) && (options == null ? void 0 : options.resolveMainConfig)) {
1372
+ const repositoryRoot = findRepositoryRoot();
1373
+ const packagePath = findPackagePath({
1374
+ repositoryRoot,
1375
+ name: config.partOf
1376
+ });
1377
+ if (!packagePath) {
1378
+ throw new MicrofrontendError(
1379
+ `Could not find default application "${config.partOf}" in the repository`,
1380
+ { type: "config", subtype: "not_found" }
1381
+ );
1382
+ }
1383
+ const mainConfigPath = (0, import_node_path4.join)(packagePath, "microfrontends.json");
1384
+ return MicrofrontendsServer.fromMainConfigFile({
1385
+ filePath: mainConfigPath,
1386
+ overrides: cookies ? parseOverrides(cookies) : void 0
1387
+ });
1388
+ }
1299
1389
  return new MicrofrontendsServer({
1300
- config: MicrofrontendsServer.validate(config),
1390
+ config,
1301
1391
  overrides: cookies ? parseOverrides(cookies) : void 0,
1302
1392
  meta
1303
1393
  });
@@ -1315,7 +1405,7 @@ var MicrofrontendsServer = class extends Microfrontends {
1315
1405
  overrides
1316
1406
  }) {
1317
1407
  try {
1318
- const config = import_node_fs.default.readFileSync(filePath, "utf-8");
1408
+ const config = import_node_fs3.default.readFileSync(filePath, "utf-8");
1319
1409
  const validatedConfig = MicrofrontendsServer.validate(config);
1320
1410
  if (!isMainConfig(validatedConfig)) {
1321
1411
  throw new MicrofrontendError(
@@ -1546,11 +1636,11 @@ ${table}
1546
1636
  `);
1547
1637
  }
1548
1638
  }
1549
- function pathToRewrites(path2) {
1639
+ function pathToRewrites(path3) {
1550
1640
  var _a;
1551
1641
  const regex = /(?<base>^.+)\/:.+\*$/;
1552
- const match = regex.exec(path2);
1553
- const paths = [path2];
1642
+ const match = regex.exec(path3);
1643
+ const paths = [path3];
1554
1644
  if ((_a = match == null ? void 0 : match.groups) == null ? void 0 : _a.base) {
1555
1645
  paths.unshift(match.groups.base);
1556
1646
  }
@@ -1598,9 +1688,7 @@ function transform4(args) {
1598
1688
  }
1599
1689
  });
1600
1690
  for (const group of routing) {
1601
- if (group.routeToDefaultApplication) {
1602
- continue;
1603
- } else if (group.flag) {
1691
+ if (group.flag) {
1604
1692
  continue;
1605
1693
  } else {
1606
1694
  for (const source of group.paths) {
@@ -1800,7 +1888,7 @@ function getApplicationContext(opts) {
1800
1888
  return { name: opts.appName };
1801
1889
  }
1802
1890
  try {
1803
- const packageJsonString = import_node_fs2.default.readFileSync("./package.json", "utf-8");
1891
+ const packageJsonString = import_node_fs4.default.readFileSync("./package.json", "utf-8");
1804
1892
  const packageJson = JSON.parse(packageJsonString);
1805
1893
  if (!packageJson.name) {
1806
1894
  throw new MicrofrontendError(