@fulgurjs/federation 2.0.1 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  RUNTIME_VERSION
3
- } from "./chunk-I5FNKR7E.js";
3
+ } from "./chunk-RQPLFDDT.js";
4
4
 
5
5
  // src/index.ts
6
6
  import path5 from "path";
@@ -366,28 +366,45 @@ import path2 from "path";
366
366
  function jsonReplacer(_k, v) {
367
367
  return v;
368
368
  }
369
- function genSharedFacade(specifier, exportNames) {
369
+ function genSharedFacade(specifier, exportNames, dynamic = false) {
370
370
  const names = (exportNames ?? []).filter(
371
371
  (n) => n !== "default" && /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(n)
372
372
  );
373
- if (names.length === 0) {
373
+ if (!dynamic) {
374
+ if (names.length === 0) {
375
+ return [
376
+ `import * as __fulgurjs_facade from ${JSON.stringify(specifier)};`,
377
+ `export * from ${JSON.stringify(specifier)};`,
378
+ `export default __fulgurjs_facade.default ?? __fulgurjs_facade;`,
379
+ ""
380
+ ].join("\n");
381
+ }
374
382
  return [
375
383
  `import * as __fulgurjs_facade from ${JSON.stringify(specifier)};`,
384
+ ...names.map((n) => `export const ${n} = __fulgurjs_facade[${JSON.stringify(n)}];`),
385
+ `export default __fulgurjs_facade.default ?? __fulgurjs_facade;`,
386
+ ""
387
+ ].join("\n");
388
+ }
389
+ if (names.length === 0) {
390
+ return [
391
+ `const __fulgurjs_facade = await import(${JSON.stringify(specifier)});`,
376
392
  `export * from ${JSON.stringify(specifier)};`,
377
393
  `export default __fulgurjs_facade.default ?? __fulgurjs_facade;`,
378
394
  ""
379
395
  ].join("\n");
380
396
  }
381
397
  return [
382
- `import * as __fulgurjs_facade from ${JSON.stringify(specifier)};`,
383
- ...names.map((n) => `export const ${n} = __fulgurjs_facade[${JSON.stringify(n)}];`),
384
- `export default __fulgurjs_facade.default ?? __fulgurjs_facade;`,
398
+ `const __fulgurjs_facade = await import(${JSON.stringify(specifier)});`,
399
+ `const __fulgurjs_ns = { ...__fulgurjs_facade };`,
400
+ ...names.map((n) => `export const ${n} = __fulgurjs_ns[${JSON.stringify(n)}];`),
401
+ `export default __fulgurjs_ns.default ?? __fulgurjs_ns;`,
385
402
  ""
386
403
  ].join("\n");
387
404
  }
388
- function genSharedNsFacade(item, loadShareCall, exportNames) {
405
+ function genSharedNsFacade(item, loadShareCall, exportNames, dynamic = false) {
389
406
  const lines = [
390
- `import { loadShare as __fulgurjs_loadShare, unwrapDefault as __fulgurjsU } from "virtual:fulgurjs-runtime";`,
407
+ dynamic ? `const { loadShare: __fulgurjs_loadShare, unwrapDefault: __fulgurjsU } = await import("virtual:fulgurjs-runtime");` : `import { loadShare as __fulgurjs_loadShare, unwrapDefault as __fulgurjsU } from "virtual:fulgurjs-runtime";`,
391
408
  `const __fulgurjs_m = await ${loadShareCall};`,
392
409
  `const __fulgurjs_d = __fulgurjsU(__fulgurjs_m);`,
393
410
  `export default __fulgurjs_d;`
@@ -401,9 +418,9 @@ function genSharedNsFacade(item, loadShareCall, exportNames) {
401
418
  lines.push("");
402
419
  return lines.join("\n");
403
420
  }
404
- function genBindingFacade(item, bindings, loadShareCall) {
421
+ function genBindingFacade(item, bindings, loadShareCall, dynamic = false) {
405
422
  const lines = [
406
- `import { loadShare as __fulgurjs_loadShare, unwrapDefault as __fulgurjsU } from "virtual:fulgurjs-runtime";`,
423
+ dynamic ? `const { loadShare: __fulgurjs_loadShare, unwrapDefault: __fulgurjsU } = await import("virtual:fulgurjs-runtime");` : `import { loadShare as __fulgurjs_loadShare, unwrapDefault as __fulgurjsU } from "virtual:fulgurjs-runtime";`,
407
424
  `const __fulgurjs_m = await ${loadShareCall};`
408
425
  ];
409
426
  const seen = /* @__PURE__ */ new Set();
@@ -419,9 +436,9 @@ function genBindingFacade(item, bindings, loadShareCall) {
419
436
  lines.push("");
420
437
  return lines.join("\n");
421
438
  }
422
- function genRemoteBindingFacade(remoteSpec, bindings) {
439
+ function genRemoteBindingFacade(remoteSpec, bindings, dynamic = false) {
423
440
  const lines = [
424
- `import { loadRemote as __fulgurjs_loadRemote, unwrapDefault as __fulgurjsU } from "virtual:fulgurjs-runtime";`,
441
+ dynamic ? `const { loadRemote: __fulgurjs_loadRemote, unwrapDefault: __fulgurjsU } = await import("virtual:fulgurjs-runtime");` : `import { loadRemote as __fulgurjs_loadRemote, unwrapDefault: __fulgurjsU } from "virtual:fulgurjs-runtime";`.replace("unwrapDefault: __fulgurjsU", "unwrapDefault as __fulgurjsU"),
425
442
  `const __fulgurjs_m = await __fulgurjs_loadRemote(${JSON.stringify(remoteSpec)});`
426
443
  ];
427
444
  const seen = /* @__PURE__ */ new Set();
@@ -488,13 +505,17 @@ function manifestUrlFor(r, command) {
488
505
  const entry = command === "serve" ? r.devEntry : r.prodEntry;
489
506
  if (!entry) return null;
490
507
  try {
491
- const u = new URL(entry);
508
+ const hasScheme = /^[a-z][a-z\d+.-]*:/i.test(entry);
509
+ const isProtocolRelative = entry.startsWith("//");
510
+ const u = new URL(entry, hasScheme ? void 0 : "http://fulgurjs.invalid");
492
511
  if (u.pathname.includes("@fulgurjs-entry.js")) {
493
512
  u.pathname = u.pathname.replace("@fulgurjs-entry.js", "@fulgurjs-manifest.json");
494
513
  } else {
495
514
  u.pathname = u.pathname.replace(/[^/]*$/, "") + "fulgurjs-manifest.json";
496
515
  }
497
- return u.href;
516
+ if (hasScheme) return u.href;
517
+ if (isProtocolRelative) return `//${u.host}${u.pathname}${u.search}${u.hash}`;
518
+ return `${u.pathname}${u.search}${u.hash}`;
498
519
  } catch {
499
520
  return null;
500
521
  }
@@ -778,6 +799,10 @@ function parseImportClause(clause) {
778
799
  return { ns: nsMatch?.[1] ?? null, bindings, defaultLocal };
779
800
  }
780
801
  var JS_EXT_RE = /\.(m|c)?[jt]sx?$/;
802
+ function inSharedClosure(moduleId, roots) {
803
+ if (!roots || roots.length === 0) return false;
804
+ return roots.some((r) => moduleId.startsWith(r.root));
805
+ }
781
806
  function isTransformableId(id, allowNodeModules = false) {
782
807
  const clean = id.split("?")[0];
783
808
  if (!JS_EXT_RE.test(clean) && !clean.endsWith(".vue")) return false;
@@ -828,6 +853,7 @@ function remoteFacadeSpecFor(ctx, remoteName, exposeName, bindings) {
828
853
  }
829
854
  async function transformModule(code, id, ctx) {
830
855
  const { options } = ctx;
856
+ const clean = id.split("?")[0];
831
857
  if (options.shared.length === 0 && options.remotes.length === 0) return null;
832
858
  const candidates = [];
833
859
  for (const s2 of options.shared) candidates.push(s2.configKey.replace(/\/$/, ""));
@@ -914,7 +940,8 @@ export { ${nsAs[1]} };`);
914
940
  while (code[stmtEnd] === ";") stmtEnd++;
915
941
  const head = code.slice(stmtStart, stmtStart + 24);
916
942
  if (/^\s*(import|export)\s+type[\s{]/.test(head)) continue;
917
- const shared2 = matcher ? matchShared(spec2, matcher) : null;
943
+ const matched2 = matcher ? matchShared(spec2, matcher) : null;
944
+ const shared2 = matched2 && inSharedClosure(clean, ctx.sharedClosureRoots) ? null : matched2;
918
945
  const firstSeg2 = spec2.split("/")[0];
919
946
  const remote2 = remotesByKey.get(firstSeg2);
920
947
  const exposeName2 = remote2 ? remoteExposeName(spec2, remote2.key) : null;
@@ -947,7 +974,8 @@ export { ${nsAs[1]} };`);
947
974
  const literal = specExpr.match(/^['"](.*)['"]$/s);
948
975
  if (!literal) continue;
949
976
  const spec = remap(literal[1]);
950
- const shared = matcher ? matchShared(spec, matcher) : null;
977
+ const matched = matcher ? matchShared(spec, matcher) : null;
978
+ const shared = matched && inSharedClosure(clean, ctx.sharedClosureRoots) ? null : matched;
951
979
  const firstSeg = spec.split("/")[0];
952
980
  const remote = remotesByKey.get(firstSeg);
953
981
  const exposeName = remote ? remoteExposeName(spec, remote.key) : null;
@@ -1262,7 +1290,7 @@ function syncViteCacheMarker(root, pluginVersion, log) {
1262
1290
  }
1263
1291
 
1264
1292
  // src/runtime-code.gen.ts
1265
- var runtime_code_gen_default = 'var X=/^v?(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?(?:-((?:[0-9A-Za-z-]+)(?:\\.[0-9A-Za-z-]+)*))?(?:\\+[0-9A-Za-z.-]+)?$/;function T(t){let n=X.exec(String(t).trim());return n?{major:Number(n[1]),minor:Number(n[2]??0),patch:Number(n[3]??0),pre:n[4]?n[4].split("."):[]}:null}function Y(t,n){if(t.length===0&&n.length===0)return 0;if(t.length===0)return 1;if(n.length===0)return-1;let o=Math.max(t.length,n.length);for(let r=0;r<o;r++){let l=t[r],m=n[r];if(l===void 0)return-1;if(m===void 0)return 1;let y=/^\\d+$/.test(l),E=/^\\d+$/.test(m);if(y&&E){let w=Number(l)-Number(m);if(w!==0)return w}else{if(y!==E)return y?-1:1;if(l!==m)return l<m?-1:1}}return 0}function v(t,n){let o=T(t),r=T(n);return!o||!r?t<n?-1:t>n?1:0:o.major!==r.major?o.major-r.major:o.minor!==r.minor?o.minor-r.minor:o.patch!==r.patch?o.patch-r.patch:Y(o.pre,r.pre)}var Z=/^[a-z]+[+:-]/i;function O(t,n){if(n===!1||n==null||n==="")return!0;let o=String(n).trim();return!o||o==="*"||o==="latest"||Z.test(o)?!0:o.split("||").some(r=>Q(t,r.trim()))}function Q(t,n){if(!n||n==="*")return!T(t)?.pre.length;let o=n.split(/\\s+-\\s+/);if(o.length===2){let m=o[0].trim(),y=o[1].trim();return!(!O(t,`>=${m}`)||!O(t,`<=${y}`))}let r=T(t);if(!r)return!1;let l=ee(n);if(l===null)return!0;for(let m of l)if(!ie(r,t,m))return!1;return!(r.pre.length>0&&!l.some(m=>m.ver.pre.length>0)&&!l.some(y=>y.ver.major===r.major&&y.ver.minor===r.minor&&y.ver.patch===r.patch))}function ee(t){let n=[],o=t.trim().split(/\\s+/).filter(Boolean);if(o.length===0)return null;for(let r of o){let l=/^(>=|<=|>|<|=|\\^|~)?(.*)$/.exec(r);if(!l)return null;let m=l[1],y=l[2],E=re(m,y);if(E===null)return null;n.push(...E)}return n}function re(t,n){let o=ne(n);if(!o)return null;let{ver:r,partial:l}=o;switch(t){case"^":{let m=te(r);return m?[{op:">=",ver:r},{op:"<",ver:m}]:null}case"~":{let m=l>=2?{major:r.major,minor:r.minor+1,patch:0,pre:[]}:{major:r.major+1,minor:0,patch:0,pre:[]};return[{op:">=",ver:r},{op:"<",ver:m}]}case">=":return[{op:">=",ver:r}];case">":return l===1?[{op:">=",ver:{major:r.major+1,minor:0,patch:0,pre:[]}}]:l===2?[{op:">=",ver:{major:r.major,minor:r.minor+1,patch:0,pre:[]}}]:[{op:">",ver:r}];case"<":return l===1?[{op:"<",ver:{major:r.major,minor:0,patch:0,pre:[]}}]:l===2?[{op:"<",ver:{major:r.major,minor:r.minor,patch:0,pre:[]}}]:[{op:"<",ver:r}];case"<=":return[{op:"<=",ver:r}];case"=":case void 0:return l===1?[{op:">=",ver:r},{op:"<",ver:{major:r.major+1,minor:0,patch:0,pre:[]}}]:l===2?[{op:">=",ver:r},{op:"<",ver:{major:r.major,minor:r.minor+1,patch:0,pre:[]}}]:[{op:"=",ver:r}];default:return null}}function te(t){return t.major>0?{major:t.major+1,minor:0,patch:0,pre:[]}:t.minor>0?{major:0,minor:t.minor+1,patch:0,pre:[]}:{major:0,minor:0,patch:t.patch+1,pre:[]}}function ne(t){let n=t.replace(/^v/,"").trim();if(!n||n==="*"||n==="x"||n==="X")return{ver:{major:0,minor:0,patch:0,pre:[]},partial:0};let o=n.split("."),r=[],l=0;for(let E of o.slice(0,3))if(/^\\d+$/.test(E))r.push(Number(E)),l++;else{if(E==="x"||E==="X"||E==="*")break;break}let m=n.split("-"),y=m.length>1?m.slice(1).join("-").split("+")[0].split("."):[];return l===0&&y.length===0?{ver:{major:0,minor:0,patch:0,pre:[]},partial:0}:{ver:{major:r[0]??0,minor:r[1]??0,patch:r[2]??0,pre:y},partial:l}}function oe(t,n){switch(n){case">=":return t>=0;case">":return t>0;case"<":return t<0;case"<=":return t<=0;case"=":return t===0}}function ie(t,n,o){let r=`${t.major}.${t.minor}.${t.patch}`+(t.pre.length?`-${t.pre.join(".")}`:"");if(o.upper)return!(!(v(r,`${o.ver.major}.${o.ver.minor}.${o.ver.patch}`+(o.ver.pre.length?`-${o.ver.pre.join(".")}`:""))>=0)||!(v(r,`${o.upper.major}.${o.upper.minor}.${o.upper.patch}`)<0));let l=v(r,`${o.ver.major}.${o.ver.minor}.${o.ver.patch}`+(o.ver.pre.length?`-${o.ver.pre.join(".")}`:"")),m=oe(l,o.op);return o.ver.pre.length>0&&t.pre.length===0&&(o.op===">"||o.op==="<")?!1:m}var g=class extends Error{code;details;constructor(n,o,r){super(`[fulgurjs:${n}] ${o}`),this.name="FgError",this.code=n,this.details=r}},S={REMOTE_LOAD_FAILED:"MFU-001",REMOTE_NAME_MISMATCH:"MFU-002",SHARE_STRICT_VERSION:"MFU-003",SHARE_NOT_AVAILABLE:"MFU-004",CONTAINER_REINIT_CONFLICT:"MFU-005",MODULE_NOT_EXPOSED:"MFU-006",PRELOAD_FAILED:"MFU-007",REMOTE_UNKNOWN:"MFU-008",EMPTY_EXPORTS:"MFU-009",SINGLETON_SKEW:"MFU-010"};var U="2.0.1";var A=15e3,P=2,ae=5,se=3e4;function ce(){let t={},n=new Map,o=[],r=new Map,l=new WeakMap,m={},y=()=>{for(let e of o)try{e.init?.(m)}catch(i){console.warn("[fulgurjs] runtimePlugin init failed:",e.name,i)}},E=e=>t[e]??={};function w(e){try{m.onRemoteError?.(e)}catch{}typeof window<"u"&&window.dispatchEvent(new CustomEvent("fulgurjs:error",{detail:e}))}function F(e="default"){return E(e),t}function V(e,i,a,c,R={}){let s=E(e||"default"),u=s[i]??={};u[a]||(u[a]={version:a,get:c,from:R.from??"unknown",eager:!!R.eager,loaded:!!R.loaded})}function I(e){for(let i of e){let a=n.get(i.name);n.set(i.name,{timeout:A,retries:P,...a,...i,state:a?.state??"idle",breakerState:a?.breakerState??{fails:0,openUntil:0},debug:a?.debug??{entry:i.entry,status:"idle"}})}}function D(e){I([e])}function H(e){o.push(...e),y()}async function K(e,i={}){let a=i.shareScope||"default",c=i.shareKey||e,s=E(a)[c]||{},u=Object.keys(s),d=i.requiredVersion,f=u.filter(p=>d===void 0||d===!1||O(p,d)),_;if(i.singleton&&u.length>0){let p=u.filter(h=>s[h].loaded);if(_=[...p.length?p:u].sort(v).pop(),u.length>1||!f.includes(_)){let h=s[_],j=`singleton skew "${c}": req "${d??"any"}" use ${_} from ${h.from}`;if(i.strictVersion){let M=new g(S.SHARE_STRICT_VERSION,j,{shareKey:c,requiredVersion:d});throw w({remote:h.from,error:M}),M}console.warn(`[fulgurjs:MFU-010] ${j}`)}}else if(_=[...f].sort(v).pop(),!_){if(i.strictVersion){let h=new g(S.SHARE_STRICT_VERSION,`no satisfying version for "${c}" (required "${d}") in share scope "${a}"`);throw w({remote:c,error:h}),h}if(i.fallback)return i.fallback();let p=new g(S.SHARE_NOT_AVAILABLE,`shared "${c}" (${d??"any"}) unavailable in scope "${a}" (no local fallback)`,{shareKey:c,requiredVersion:d});throw w({remote:c,error:p}),p}let $=s[_];if(m.resolveShare){let p=await m.resolveShare({shareKey:c,shareScope:a,requiredVersion:d,picked:$,available:Object.values(s)});p&&($=p)}return $.loaded=!0,$.get()}function q(e,i,a){return new Promise((c,R)=>{let s=setTimeout(()=>R(new Error(`timeout after ${i}ms: ${a}`)),i);e.then(u=>{clearTimeout(s),c(u)},u=>{clearTimeout(s),R(u)})})}let z=e=>new Promise(i=>setTimeout(i,e));function k(e,i){if(!e||typeof e.get!="function")throw new Error(`remoteEntry of "${i.name}" does not export a container interface (get/init)`);if(e.name&&i.name&&e.name!==i.name){let a=`remoteEntry self-reported name "${e.name}" mismatches configured name "${i.name}"`;if(i.promise)console.warn(`[fulgurjs] ${a} (promise-based remote, continuing)`);else throw Object.assign(new Error(a),{code:S.REMOTE_NAME_MISMATCH})}}async function L(e,i){return q(import(e),i.timeout??A,`load remoteEntry ${e}`)}async function x(e,i){let a=e.shareScope||"default";if(e.container){let s=l.get(e.container);if(s&&s!==a)throw new g(S.CONTAINER_REINIT_CONFLICT,`container "${e.name}" already initialized with share scope "${s}", cannot re-init with "${a}"`);return e.container}if(e.containerPromise)return e.containerPromise;let c=e.breakerState;if(c.openUntil>Date.now()){let s=new g(S.REMOTE_LOAD_FAILED,`circuit breaker open for remote "${e.name}" until ${new Date(c.openUntil).toISOString()}`,{remote:e.name});throw w({remote:e.name,error:s}),s}e.state="loading",e.debug.status="loading";let R=(async()=>{let s=[];if(e.promise)s.push(async()=>{let p=await e.promise(),h=typeof p=="string"?await L(p,e):p;return k(h,e),h});else for(let p of[e.entry,...e.fallback??[]])s.push(async()=>{let h=await L(p,e);return k(h,e),h});let u,d,f=!1,_=i?.retries??e.retries??P;for(let p of s){for(let h=0;h<=_;h++){let j=performance.now();try{u=await p(),e.lastLoadMs=Math.round(performance.now()-j),e.debug.lastLoadMs=e.lastLoadMs,f=!0;break}catch(M){if(d=M,M?.code)throw M;h<_&&await z(200*2**h)}}if(f)break}if(!f||!u){let p=[];throw/^https?:\\/\\//.test(e.entry)&&typeof location<"u"?(p.push(`1. is the remote dev server running? try opening ${e.entry} in the browser \\u2014 it must return JS, not HTML/an error`),p.push("2. is the URL correct in federation({ remotes })? dev and prod entries can differ"),p.push("3. CORS: the remote dev server must allow cross-origin requests (fulgurjs-federation enables server.cors automatically; a custom server config may have disabled it)")):(p.push(`1. is the remote deployed and reachable? try opening ${e.entry} in the browser \\u2014 it must return JS`),p.push("2. NGINX/CDN routing: the entry path must serve the remoteEntry JS file (check try_files / fallback rules)")),new g(S.REMOTE_LOAD_FAILED,`failed to load remote "${e.name}" from ${e.entry}: ${String(d?.message??d)}\n`+p.join(`\n`),{remote:e.name})}k(u,e);let $=l.get(u);if($&&$!==a)throw new g(S.CONTAINER_REINIT_CONFLICT,`container "${e.name}" already initialized with share scope "${$}", cannot re-init with "${a}"`);return typeof u.init=="function"&&await u.init(t),l.set(u,a),e.container=u,e.state="loaded",e.debug.status="loaded",c.fails=0,u})();e.containerPromise=R;try{return await R}catch(s){if(e.containerPromise=void 0,e.state="failed",e.debug.status="failed",e.debug.error=String(s?.message??s),c.fails+=1,c.fails>=ae&&(c.openUntil=Date.now()+se,c.fails=0),s instanceof g)throw w({remote:e.name,error:s}),s;if(s?.code)throw w({remote:e.name,error:s}),s;let u=new g(S.REMOTE_LOAD_FAILED,String(s?.message??s),{remote:e.name});throw w({remote:e.name,error:u}),u}}function N(e){let i=e.indexOf("/");return i===-1?{remote:e,module:""}:{remote:e.slice(0,i),module:G(e.slice(i+1))}}function G(e){return e?e.startsWith(".")?e:`./${e}`:""}async function J(e,i){let{remote:a,module:c}=N(e);m.beforeLoadRemote?.({remote:a,module:c});let R=n.get(a);if(!R)throw new g(S.REMOTE_UNKNOWN,`unknown remote "${a}". Register it via federation({ remotes }) or registerRemote().`,{remote:a});let s;try{s=await x(R,{retries:i?.retries})}catch(f){if(i?.fallbackModule)return console.error(`[fulgurjs] loadRemote("${e}") failed; returning fallbackModule (\\u663E\\u5F0F\\u964D\\u7EA7\\uFF0C\\u9519\\u8BEF\\u5DF2\\u900F\\u51FA)`,f),w({remote:a,error:f}),await i.fallbackModule();throw f}if(!c)return s;let u=`${a}@${R.shareScope||"default"}#${c}`;r.has(u)||r.set(u,s.get(c).catch(f=>{throw r.delete(u),f instanceof g||f?.code?f:new g(S.REMOTE_LOAD_FAILED,`failed to load module "${c}" from remote "${a}": ${String(f?.message??f)}`,{remote:a,module:c})}));let d;try{d=await r.get(u)}catch(f){if(i?.fallbackModule)return console.error(`[fulgurjs] loadRemote("${e}") failed; returning fallbackModule (\\u663E\\u5F0F\\u964D\\u7EA7\\uFF0C\\u9519\\u8BEF\\u5DF2\\u900F\\u51FA)`,f),w({remote:a,error:f}),await i.fallbackModule();throw f}if(m.afterLoadRemote?.({remote:a,module:c,module_ns:d}),d&&typeof d=="object"&&Object.keys(d).length===0){let f=new g(S.EMPTY_EXPORTS,`no exports: ${c} @ ${a}`,{remote:a,module:c});w({remote:a,error:f}),console.error(`[fulgurjs:MFU-009] ${f.message}`)}return d}function W(e){let i=n.get(e);if(!i)throw new g(S.REMOTE_UNKNOWN,`unknown remote "${e}"`,{remote:e});return x(i)}async function B(e,i={}){let{remote:a}=N(e),c=n.get(a);if(!c)throw new g(S.REMOTE_UNKNOWN,`unknown remote "${a}"`,{remote:a});let R=i.mode??"preload",s=(u,d)=>{if(typeof document>"u"||document.querySelector(`link[href="${u}"]`))return;let f=document.createElement("link");f.rel=d==="style"?"stylesheet":"modulepreload",f.href=u,R==="prefetch"&&(f.fetchPriority="low"),document.head.appendChild(f)};try{if(c.manifestUrl){let u=await fetch(c.manifestUrl,{cache:"no-cache"});if(u.ok){let d=await u.json();s(c.entry,"modulepreload");let f=d.exposes??{};for(let _ of Object.keys(f)){let $=f[_];$?.file&&s(new URL($.file,c.entry).href,"modulepreload");for(let p of $?.css??[])s(new URL(p,c.entry).href,"style")}return}}s(c.entry,"modulepreload")}catch(u){w({remote:a,error:new g(S.PRELOAD_FAILED,String(u?.message??u),{remote:a})})}}return typeof window>"u"||(window.__FULGURJS_SCOPE__=t,window.__FULGURJS_INFO__={get remotes(){let e={};for(let[i,a]of n)e[i]={...a.debug,entry:a.entry};return e},errors:[]}),{shareScopeMap:t,initSharing:F,registerShare:V,registerRemotes:I,registerRemote:D,registerPlugins:H,loadShare:K,loadRemote:J,getContainer:W,preloadRemote:B,parseSpec:N}}var C=globalThis,b=C.__FULGURJS_RUNTIME__??ce();C.__FULGURJS_RUNTIME__=b;try{Object.freeze(b)}catch{}var he=U;function ye(){return b}var Ee=b.initSharing,Re=b.registerShare,Se=b.registerRemotes,we=b.registerRemote,be=b.registerPlugins,_e=b.loadShare,$e=b.loadRemote,Me=b.getContainer,ve=b.preloadRemote,je=b.shareScopeMap;function Te(t){if(t&&typeof t=="object"&&"default"in t){let n=t.default;return n!==void 0?n:t}return t}var Oe=b;export{Oe as default,Me as getContainer,ye as getRuntime,Ee as initSharing,$e as loadRemote,_e as loadShare,ve as preloadRemote,be as registerPlugins,we as registerRemote,Se as registerRemotes,Re as registerShare,b as runtime,je as shareScopeMap,Te as unwrapDefault,he as version};\n';
1293
+ var runtime_code_gen_default = 'var re=/^v?(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?(?:-((?:[0-9A-Za-z-]+)(?:\\.[0-9A-Za-z-]+)*))?(?:\\+[0-9A-Za-z.-]+)?$/;function P(t){let n=re.exec(String(t).trim());return n?{major:Number(n[1]),minor:Number(n[2]??0),patch:Number(n[3]??0),pre:n[4]?n[4].split("."):[]}:null}function te(t,n){if(t.length===0&&n.length===0)return 0;if(t.length===0)return 1;if(n.length===0)return-1;let o=Math.max(t.length,n.length);for(let r=0;r<o;r++){let m=t[r],d=n[r];if(m===void 0)return-1;if(d===void 0)return 1;let S=/^\\d+$/.test(m),w=/^\\d+$/.test(d);if(S&&w){let L=Number(m)-Number(d);if(L!==0)return L}else{if(S!==w)return S?-1:1;if(m!==d)return m<d?-1:1}}return 0}function T(t,n){let o=P(t),r=P(n);return!o||!r?t<n?-1:t>n?1:0:o.major!==r.major?o.major-r.major:o.minor!==r.minor?o.minor-r.minor:o.patch!==r.patch?o.patch-r.patch:te(o.pre,r.pre)}var ne=/^[a-z]+[+:-]/i;function N(t,n){if(n===!1||n==null||n==="")return!0;let o=String(n).trim();return!o||o==="*"||o==="latest"||ne.test(o)?!0:o.split("||").some(r=>oe(t,r.trim()))}function oe(t,n){if(!n||n==="*")return!P(t)?.pre.length;let o=n.split(/\\s+-\\s+/);if(o.length===2){let d=o[0].trim(),S=o[1].trim();return!(!N(t,`>=${d}`)||!N(t,`<=${S}`))}let r=P(t);if(!r)return!1;let m=ie(n);if(m===null)return!0;for(let d of m)if(!ue(r,t,d))return!1;return!(r.pre.length>0&&!m.some(d=>d.ver.pre.length>0)&&!m.some(S=>S.ver.major===r.major&&S.ver.minor===r.minor&&S.ver.patch===r.patch))}function ie(t){let n=[],o=t.trim().split(/\\s+/).filter(Boolean);if(o.length===0)return null;for(let r of o){let m=/^(>=|<=|>|<|=|\\^|~)?(.*)$/.exec(r);if(!m)return null;let d=m[1],S=m[2],w=se(d,S);if(w===null)return null;n.push(...w)}return n}function se(t,n){let o=ce(n);if(!o)return null;let{ver:r,partial:m}=o;switch(t){case"^":{let d=ae(r);return d?[{op:">=",ver:r},{op:"<",ver:d}]:null}case"~":{let d=m>=2?{major:r.major,minor:r.minor+1,patch:0,pre:[]}:{major:r.major+1,minor:0,patch:0,pre:[]};return[{op:">=",ver:r},{op:"<",ver:d}]}case">=":return[{op:">=",ver:r}];case">":return m===1?[{op:">=",ver:{major:r.major+1,minor:0,patch:0,pre:[]}}]:m===2?[{op:">=",ver:{major:r.major,minor:r.minor+1,patch:0,pre:[]}}]:[{op:">",ver:r}];case"<":return m===1?[{op:"<",ver:{major:r.major,minor:0,patch:0,pre:[]}}]:m===2?[{op:"<",ver:{major:r.major,minor:r.minor,patch:0,pre:[]}}]:[{op:"<",ver:r}];case"<=":return[{op:"<=",ver:r}];case"=":case void 0:return m===1?[{op:">=",ver:r},{op:"<",ver:{major:r.major+1,minor:0,patch:0,pre:[]}}]:m===2?[{op:">=",ver:r},{op:"<",ver:{major:r.major,minor:r.minor+1,patch:0,pre:[]}}]:[{op:"=",ver:r}];default:return null}}function ae(t){return t.major>0?{major:t.major+1,minor:0,patch:0,pre:[]}:t.minor>0?{major:0,minor:t.minor+1,patch:0,pre:[]}:{major:0,minor:0,patch:t.patch+1,pre:[]}}function ce(t){let n=t.replace(/^v/,"").trim();if(!n||n==="*"||n==="x"||n==="X")return{ver:{major:0,minor:0,patch:0,pre:[]},partial:0};let o=n.split("."),r=[],m=0;for(let w of o.slice(0,3))if(/^\\d+$/.test(w))r.push(Number(w)),m++;else{if(w==="x"||w==="X"||w==="*")break;break}let d=n.split("-"),S=d.length>1?d.slice(1).join("-").split("+")[0].split("."):[];return m===0&&S.length===0?{ver:{major:0,minor:0,patch:0,pre:[]},partial:0}:{ver:{major:r[0]??0,minor:r[1]??0,patch:r[2]??0,pre:S},partial:m}}function le(t,n){switch(n){case">=":return t>=0;case">":return t>0;case"<":return t<0;case"<=":return t<=0;case"=":return t===0}}function ue(t,n,o){let r=`${t.major}.${t.minor}.${t.patch}`+(t.pre.length?`-${t.pre.join(".")}`:"");if(o.upper)return!(!(T(r,`${o.ver.major}.${o.ver.minor}.${o.ver.patch}`+(o.ver.pre.length?`-${o.ver.pre.join(".")}`:""))>=0)||!(T(r,`${o.upper.major}.${o.upper.minor}.${o.upper.patch}`)<0));let m=T(r,`${o.ver.major}.${o.ver.minor}.${o.ver.patch}`+(o.ver.pre.length?`-${o.ver.pre.join(".")}`:"")),d=le(m,o.op);return o.ver.pre.length>0&&t.pre.length===0&&(o.op===">"||o.op==="<")?!1:d}var R=class extends Error{code;details;constructor(n,o,r){super(`[fulgurjs:${n}] ${o}`),this.name="FgError",this.code=n,this.details=r}},b={REMOTE_LOAD_FAILED:"MFU-001",REMOTE_NAME_MISMATCH:"MFU-002",SHARE_STRICT_VERSION:"MFU-003",SHARE_NOT_AVAILABLE:"MFU-004",CONTAINER_REINIT_CONFLICT:"MFU-005",MODULE_NOT_EXPOSED:"MFU-006",PRELOAD_FAILED:"MFU-007",REMOTE_UNKNOWN:"MFU-008",EMPTY_EXPORTS:"MFU-009",SINGLETON_SKEW:"MFU-010"};var V="2.0.3";var H=15e3,K=2,me=5,fe=3e4;function pe(){let t={},n=new Map,o=[],r=new Map,m=new Map,d=new WeakMap,S=new WeakMap,w={},L=()=>{for(let e of o)try{e.init?.(w)}catch(i){console.warn("[fulgurjs] runtimePlugin init failed:",e.name,i)}},I=e=>t[e]??={};function $(e){try{w.onRemoteError?.(e)}catch{}typeof window<"u"&&window.dispatchEvent(new CustomEvent("fulgurjs:error",{detail:e}))}function z(e="default"){return I(e),t}function W(e,i,s,l,h={}){let c=I(e||"default"),f=c[i]??={};f[s]||(f[s]={version:s,get:l,from:h.from??"unknown",eager:!!h.eager,loaded:!!h.loaded})}function A(e){for(let i of e){let s=n.get(i.name);n.set(i.name,{timeout:H,retries:K,...s,...i,state:s?.state??"idle",breakerState:s?.breakerState??{fails:0,openUntil:0},debug:s?.debug??{entry:i.entry,status:"idle"}})}}function G(e){A([e])}function J(e){o.push(...e),L()}async function B(e,i={}){let s=i.shareScope||"default",l=i.shareKey||e,c=I(s)[l]||{},f=Object.keys(c),y=i.requiredVersion,g=f.filter(a=>y===void 0||y===!1||N(a,y)),u;if(i.singleton&&f.length>0){let a=f.filter(p=>c[p].loaded);if(u=[...a.length?a:f].sort(T).pop(),f.length>1||!g.includes(u)){let p=c[u],j=`singleton skew "${l}": req "${y??"any"}" use ${u} from ${p.from}`;if(i.strictVersion){let _=new R(b.SHARE_STRICT_VERSION,j,{shareKey:l,requiredVersion:y});throw $({remote:p.from,error:_}),_}console.warn(`[fulgurjs:MFU-010] ${j}`)}}else if(u=[...g].sort(T).pop(),!u){if(i.strictVersion){let p=new R(b.SHARE_STRICT_VERSION,`no satisfying version for "${l}" (required "${y}") in share scope "${s}"`);throw $({remote:l,error:p}),p}if(i.fallback)return i.fallback();let a=new R(b.SHARE_NOT_AVAILABLE,`shared "${l}" (${y??"any"}) unavailable in scope "${s}" (no local fallback)`,{shareKey:l,requiredVersion:y});throw $({remote:l,error:a}),a}let E=c[u];if(w.resolveShare){let a=await w.resolveShare({shareKey:l,shareScope:s,requiredVersion:y,picked:E,available:Object.values(c)});a&&(E=a)}return E.loaded=!0,E.get()}function X(e,i,s){return new Promise((l,h)=>{let c=setTimeout(()=>h(new Error(`timeout after ${i}ms: ${s}`)),i);e.then(f=>{clearTimeout(c),l(f)},f=>{clearTimeout(c),h(f)})})}let Y=e=>new Promise(i=>setTimeout(i,e));function k(e,i){if(!e||typeof e.get!="function")throw new Error(`remoteEntry of "${i.name}" does not export a container interface (get/init)`);if(e.name&&i.name&&e.name!==i.name){let s=`remoteEntry self-reported name "${e.name}" mismatches configured name "${i.name}"`;if(i.promise)console.warn(`[fulgurjs] ${s} (promise-based remote, continuing)`);else throw Object.assign(new Error(s),{code:b.REMOTE_NAME_MISMATCH})}}async function x(e,i){return X(import(e),i.timeout??H,`load remoteEntry ${e}`)}async function C(e,i){let s=e.shareScope||"default";if(e.container){let c=S.get(e.container);if(c&&c!==s)throw new R(b.CONTAINER_REINIT_CONFLICT,`container "${e.name}" already initialized with share scope "${c}", cannot re-init with "${s}"`);return e.container}if(e.containerPromise)return e.containerPromise;let l=e.breakerState;if(l.openUntil>Date.now()){let c=new R(b.REMOTE_LOAD_FAILED,`circuit breaker open for remote "${e.name}" until ${new Date(l.openUntil).toISOString()}`,{remote:e.name});throw $({remote:e.name,error:c}),c}e.state="loading",e.debug.status="loading";let h=(async()=>{let c=[];if(e.promise)c.push(async()=>{let a=await e.promise(),p=typeof a=="string"?await x(a,e):a;return k(p,e),p});else for(let a of[e.entry,...e.fallback??[]])c.push(async()=>{let p=await x(a,e);return k(p,e),p});let f,y,g=!1,u=i?.retries??e.retries??K;for(let a of c){for(let p=0;p<=u;p++){let j=performance.now();try{f=await a(),e.lastLoadMs=Math.round(performance.now()-j),e.debug.lastLoadMs=e.lastLoadMs,g=!0;break}catch(_){if(y=_,_?.code)throw _;p<u&&await Y(200*2**p)}}if(g)break}if(!g||!f){let a=[];throw/^https?:\\/\\//.test(e.entry)&&typeof location<"u"?(a.push(`1. is the remote dev server running? try opening ${e.entry} in the browser \\u2014 it must return JS, not HTML/an error`),a.push("2. is the URL correct in federation({ remotes })? dev and prod entries can differ"),a.push("3. CORS: the remote dev server must allow cross-origin requests (fulgurjs-federation enables server.cors automatically; a custom server config may have disabled it)")):(a.push(`1. is the remote deployed and reachable? try opening ${e.entry} in the browser \\u2014 it must return JS`),a.push("2. NGINX/CDN routing: the entry path must serve the remoteEntry JS file (check try_files / fallback rules)")),new R(b.REMOTE_LOAD_FAILED,`failed to load remote "${e.name}" from ${e.entry}: ${String(y?.message??y)}\n`+a.join(`\n`),{remote:e.name})}k(f,e);let E=S.get(f);if(E&&E!==s)throw new R(b.CONTAINER_REINIT_CONFLICT,`container "${e.name}" already initialized with share scope "${E}", cannot re-init with "${s}"`);return typeof f.init=="function"&&await f.init(t),S.set(f,s),e.container=f,e.state="loaded",e.debug.status="loaded",l.fails=0,f})();e.containerPromise=h;try{return await h}catch(c){if(e.containerPromise=void 0,e.state="failed",e.debug.status="failed",e.debug.error=String(c?.message??c),l.fails+=1,l.fails>=me&&(l.openUntil=Date.now()+fe,l.fails=0),c instanceof R)throw $({remote:e.name,error:c}),c;if(c?.code)throw $({remote:e.name,error:c}),c;let f=new R(b.REMOTE_LOAD_FAILED,String(c?.message??c),{remote:e.name});throw $({remote:e.name,error:f}),f}}function U(e){let i=e.indexOf("/");return i===-1?{remote:e,module:""}:{remote:e.slice(0,i),module:F(e.slice(i+1))}}function F(e){return e?e.startsWith(".")?e:`./${e}`:""}async function Z(e,i){let{remote:s,module:l}=U(e);w.beforeLoadRemote?.({remote:s,module:l});let h=n.get(s);if(!h)throw new R(b.REMOTE_UNKNOWN,`unknown remote "${s}". Register it via federation({ remotes }) or registerRemote().`,{remote:s});let c;try{let g=l&&h.manifestUrl?D(e):Promise.resolve();[c]=await Promise.all([C(h,{retries:i?.retries}),g])}catch(g){if(i?.fallbackModule)return console.error(`[fulgurjs] loadRemote("${e}") failed; returning fallbackModule (\\u663E\\u5F0F\\u964D\\u7EA7\\uFF0C\\u9519\\u8BEF\\u5DF2\\u900F\\u51FA)`,g),$({remote:s,error:g}),await i.fallbackModule();throw g}if(!l)return c;let f=`${s}@${h.shareScope||"default"}#${l}`;r.has(f)||r.set(f,c.get(l).catch(g=>{throw r.delete(f),g instanceof R||g?.code?g:new R(b.REMOTE_LOAD_FAILED,`failed to load module "${l}" from remote "${s}": ${String(g?.message??g)}`,{remote:s,module:l})}));let y;try{y=await r.get(f)}catch(g){if(i?.fallbackModule)return console.error(`[fulgurjs] loadRemote("${e}") failed; returning fallbackModule (\\u663E\\u5F0F\\u964D\\u7EA7\\uFF0C\\u9519\\u8BEF\\u5DF2\\u900F\\u51FA)`,g),$({remote:s,error:g}),await i.fallbackModule();throw g}if(w.afterLoadRemote?.({remote:s,module:l,module_ns:y}),y&&typeof y=="object"&&Object.keys(y).length===0){let g=new R(b.EMPTY_EXPORTS,`no exports: ${l} @ ${s}`,{remote:s,module:l});$({remote:s,error:g}),console.error(`[fulgurjs:MFU-009] ${g.message}`)}return y}function Q(e){let i=n.get(e);if(!i)throw new R(b.REMOTE_UNKNOWN,`unknown remote "${e}"`,{remote:e});return C(i)}async function D(e,i={}){let{remote:s,module:l}=U(e),h=n.get(s);if(!h)throw new R(b.REMOTE_UNKNOWN,`unknown remote "${s}"`,{remote:s});let c=i.mode??"preload",f=(u,E)=>{if(u.sheet)return Promise.resolve();let a=d.get(u);if(a)return a;let p=new Promise(j=>{let _=()=>{u.removeEventListener("load",_),u.removeEventListener("error",v),j()},v=()=>{$({remote:s,error:new R(b.PRELOAD_FAILED,`failed to load remote stylesheet ${E}`,{remote:s})}),_()};u.addEventListener("load",_,{once:!0}),u.addEventListener("error",v,{once:!0}),u.sheet&&_()});return d.set(u,p),p},y=(u,E)=>{if(typeof document>"u")return Promise.resolve();let a=document.querySelector(`link[href="${u}"]`);if(a)return E==="style"&&c==="preload"?d.get(a)??Promise.resolve():Promise.resolve();let p=document.createElement("link");p.rel=E==="style"?"stylesheet":"modulepreload",p.href=u,c==="prefetch"&&(p.fetchPriority="low");let j=E==="style"?f(p,u):Promise.resolve();return document.head.appendChild(p),E==="style"&&c==="preload"?j:Promise.resolve()},g=u=>{let E=typeof document<"u"?document.baseURI:void 0,a=new URL(h.entry,E||"http://fulgurjs.invalid/");return new URL(u,a).href};try{if(h.manifestUrl){let u=m.get(h.manifestUrl);u||(u=fetch(h.manifestUrl,{cache:"no-cache"}).then(a=>a.ok?a.json():void 0),m.set(h.manifestUrl,u),u.then(a=>{a||m.delete(h.manifestUrl)},()=>m.delete(h.manifestUrl)));let E=await u;if(E){await y(h.entry,"modulepreload");let a=E.exposes,p=Array.isArray(a)?a.filter(v=>v&&typeof v=="object").map(v=>[String(v.name??""),v]):a&&typeof a=="object"?Object.entries(a):[],j=l?p.filter(([v,O])=>F(String(O?.name??v))===l):p,_=[];for(let[,v]of j)if(typeof v?.file=="string"&&await y(g(v.file),"modulepreload"),Array.isArray(v?.css))for(let O of v.css){if(typeof O!="string")continue;let ee=y(g(O),"style");c==="preload"&&_.push(ee)}await Promise.all(_);return}}await y(h.entry,"modulepreload")}catch(u){$({remote:s,error:new R(b.PRELOAD_FAILED,String(u?.message??u),{remote:s})})}}return typeof window>"u"||(window.__FULGURJS_SCOPE__=t,window.__FULGURJS_INFO__={get remotes(){let e={};for(let[i,s]of n)e[i]={...s.debug,entry:s.entry};return e},errors:[]}),{shareScopeMap:t,initSharing:z,registerShare:W,registerRemotes:A,registerRemote:G,registerPlugins:J,loadShare:B,loadRemote:Z,getContainer:Q,preloadRemote:D,parseSpec:U}}var q=globalThis,M=q.__FULGURJS_RUNTIME__??pe();q.__FULGURJS_RUNTIME__=M;try{Object.freeze(M)}catch{}var we=V;function be(){return M}var ve=M.initSharing,_e=M.registerShare,Me=M.registerRemotes,$e=M.registerRemote,je=M.registerPlugins,Te=M.loadShare,Le=M.loadRemote,Oe=M.getContainer,Pe=M.preloadRemote,Ne=M.shareScopeMap;function Ie(t){if(t&&typeof t=="object"&&"default"in t){let n=t.default;return n!==void 0?n:t}return t}var ke=M;export{ke as default,Oe as getContainer,be as getRuntime,ve as initSharing,Le as loadRemote,Te as loadShare,Pe as preloadRemote,je as registerPlugins,$e as registerRemote,Me as registerRemotes,_e as registerShare,M as runtime,Ne as shareScopeMap,Ie as unwrapDefault,we as version};\n';
1266
1294
 
1267
1295
  // src/index.ts
1268
1296
  function readRuntimeCode() {
@@ -1303,6 +1331,29 @@ function injectInitScript(html, scriptSrc) {
1303
1331
  }
1304
1332
  return tag + html;
1305
1333
  }
1334
+ var RUNTIME_CHUNK_NAME = "fulgurjs-runtime";
1335
+ var REMOTE_FACADE_CHUNK_NAME = "fulgurjs-remote-facades";
1336
+ function facadeChunkOf(id) {
1337
+ const bare = id.split("?")[0];
1338
+ if (bare === "virtual:fulgurjs-runtime" || bare === "virtual:fulgurjs-runtime-proxy") {
1339
+ return RUNTIME_CHUNK_NAME;
1340
+ }
1341
+ if (bare.startsWith("virtual:fulgurjs-shared:")) {
1342
+ const body = bare.slice("virtual:fulgurjs-shared:".length);
1343
+ if (body.startsWith("__remote__/")) {
1344
+ const remoteName = body.slice("__remote__/".length).split("/")[0] || "unknown";
1345
+ return REMOTE_FACADE_CHUNK_NAME + "-" + remoteName.replace(/[^A-Za-z0-9_-]/g, "_");
1346
+ }
1347
+ const shareKey = body.split("?")[0];
1348
+ return "fulgurjs-shared-" + (shareKey.replace(/[^A-Za-z0-9_-]/g, "_") || "unknown");
1349
+ }
1350
+ if (bare.startsWith("virtual:fulgurjs-shared-ns:") || bare.startsWith("virtual:fulgurjs-cjs-ns:")) {
1351
+ const prefix = bare.startsWith("virtual:fulgurjs-shared-ns:") ? "virtual:fulgurjs-shared-ns:" : "virtual:fulgurjs-cjs-ns:";
1352
+ const shareKey = bare.slice(prefix.length);
1353
+ return "fulgurjs-shared-" + (shareKey.replace(/[^A-Za-z0-9_-]/g, "_") || "unknown");
1354
+ }
1355
+ return null;
1356
+ }
1306
1357
  function federation(options) {
1307
1358
  const warnedUnknownPrefixes = /* @__PURE__ */ new Set();
1308
1359
  let remoteSchemaPromise = null;
@@ -1313,7 +1364,10 @@ function federation(options) {
1313
1364
  exposeFiles: {},
1314
1365
  resolvedSharedPaths: /* @__PURE__ */ new Map(),
1315
1366
  entryAbsPaths: /* @__PURE__ */ new Set(),
1316
- entryInitInjected: /* @__PURE__ */ new Set()
1367
+ entryInitInjected: /* @__PURE__ */ new Set(),
1368
+ manualChunkGroups: /* @__PURE__ */ new Map(),
1369
+ sharedClosureRoots: [],
1370
+ facadeDynamic: false
1317
1371
  };
1318
1372
  const pre = {
1319
1373
  name: "fulgurjs:core",
@@ -1381,6 +1435,43 @@ export { default } from ${JSON.stringify(url)};
1381
1435
  ;
1382
1436
  extra.build = { target: "es2022" };
1383
1437
  }
1438
+ if (normalized.remotes.length > 0 && normalized.devSharedSelf) {
1439
+ state.facadeDynamic = true;
1440
+ const userOutput = userConfig.build?.rollupOptions?.output;
1441
+ if (Array.isArray(userOutput)) {
1442
+ console.warn(
1443
+ formatFulgurjsDiagnostic({
1444
+ code: "BLD-006",
1445
+ symptom: "build.rollupOptions.output is an array; fulgurjs cannot inject the shared-facade chunk guard automatically",
1446
+ cause: "devSharedSelf \u95E8\u9762\u5316 + manualChunks \u5F3A\u5236\u5206\u7EC4\u53EF\u80FD\u5F62\u6210 chunk \u5FAA\u73AF\u4F9D\u8D56\uFF08\u8FD0\u884C\u65F6 TypeError\uFF1A\u534F\u5546\u51FD\u6570\u672A\u521D\u59CB\u5316\uFF09",
1447
+ fix: `\u5728\u6BCF\u4E2A output \u9879\u7684 manualChunks \u6700\u524D\u9762\u52A0\u5206\u652F\uFF1Aif (id.startsWith('virtual:fulgurjs-')) return 'fulgurjs-shared-facades'`
1448
+ })
1449
+ );
1450
+ } else {
1451
+ const userManualChunks = userOutput?.manualChunks;
1452
+ if (typeof userManualChunks === "function") {
1453
+ const userFn = userManualChunks;
1454
+ const wrapped = (id, meta) => {
1455
+ const facade = facadeChunkOf(id);
1456
+ if (facade) return facade;
1457
+ return userFn(id, meta);
1458
+ };
1459
+ const extraBuild = extra.build ??= {};
1460
+ extraBuild.rollupOptions = { ...extraBuild.rollupOptions ?? {}, output: { manualChunks: wrapped } };
1461
+ } else if (userManualChunks && typeof userManualChunks === "object") {
1462
+ state.manualChunkSpecsPending = Object.entries(userManualChunks).flatMap(
1463
+ ([group, specs]) => specs.map((s) => [group, s])
1464
+ );
1465
+ const wrapped = (id) => {
1466
+ const facade = facadeChunkOf(id);
1467
+ if (facade) return facade;
1468
+ return state.manualChunkGroups.get(id.split("?")[0]) ?? state.manualChunkGroups.get(id);
1469
+ };
1470
+ const extraBuild = extra.build ??= {};
1471
+ extraBuild.rollupOptions = { ...extraBuild.rollupOptions ?? {}, output: { manualChunks: wrapped } };
1472
+ }
1473
+ }
1474
+ }
1384
1475
  }
1385
1476
  for (const w of normalized.warnings) console.warn(`[fulgurjs] ${w}`);
1386
1477
  return extra;
@@ -1422,7 +1513,7 @@ export { default } from ${JSON.stringify(url)};
1422
1513
  const query = q === -1 ? "" : s.slice(q);
1423
1514
  const bareClean = bare.startsWith("\0") ? bare.slice(1) : bare;
1424
1515
  const n = state.normalized;
1425
- if (n && !bareClean.startsWith("\0") && !bareClean.startsWith(".") && !bareClean.startsWith("/") && !bareClean.startsWith("virtual:")) {
1516
+ if (n && !bare.startsWith("\0") && !bareClean.startsWith(".") && !bareClean.startsWith("/") && !bareClean.startsWith("virtual:")) {
1426
1517
  const slash = bareClean.indexOf("/");
1427
1518
  if (slash > 0) {
1428
1519
  const prefix = bareClean.slice(0, slash);
@@ -1485,7 +1576,7 @@ export { default } from ${JSON.stringify(url)};
1485
1576
  if (!names.includes(compat)) names.push(compat);
1486
1577
  }
1487
1578
  }
1488
- return genSharedNsFacade(item, serializeShareCallForFacade(item), names);
1579
+ return genSharedNsFacade(item, serializeShareCallForFacade(item), names, state.facadeDynamic);
1489
1580
  }
1490
1581
  if (clean.startsWith("virtual:fulgurjs-shared:") && state.normalized) {
1491
1582
  const body = clean.slice("virtual:fulgurjs-shared:".length);
@@ -1494,14 +1585,14 @@ export { default } from ${JSON.stringify(url)};
1494
1585
  const item2 = state.normalized.shared.find((x) => x.shareKey === body);
1495
1586
  if (item2 && item2.import !== false) {
1496
1587
  const names = /^(\.|\/)/.test(item2.import) ? [] : enumerateCjsExports(item2.import, state.normalized.root);
1497
- return genSharedFacade(item2.import, names);
1588
+ return genSharedFacade(item2.import, names, state.facadeDynamic);
1498
1589
  }
1499
1590
  return null;
1500
1591
  }
1501
1592
  const entry = getFacadeEntry(raw.slice(f + 3));
1502
1593
  if (!entry) return null;
1503
1594
  if (entry.remoteName && entry.exposeName) {
1504
- return genRemoteBindingFacade(entry.remoteName + "/" + entry.exposeName, entry.bindings);
1595
+ return genRemoteBindingFacade(entry.remoteName + "/" + entry.exposeName, entry.bindings, state.facadeDynamic);
1505
1596
  }
1506
1597
  const item = state.normalized.shared.find((x) => x.shareKey === entry.shareKey);
1507
1598
  if (!item || item.import === false) return null;
@@ -1514,7 +1605,7 @@ export { default } from ${JSON.stringify(url)};
1514
1605
  "fallback: () => import(" + JSON.stringify(item.import) + ")"
1515
1606
  ];
1516
1607
  const call = "__fulgurjs_loadShare(" + JSON.stringify(item.shareKey) + ", { " + opts.join(", ") + " })";
1517
- return genBindingFacade(item, entry.bindings, call);
1608
+ return genBindingFacade(item, entry.bindings, call, state.facadeDynamic);
1518
1609
  }
1519
1610
  return null;
1520
1611
  },
@@ -1535,7 +1626,8 @@ ${code}`, map: null };
1535
1626
  options: state.normalized,
1536
1627
  rewriteShared: true,
1537
1628
  allowNodeModules,
1538
- cjsRequireRewrite: true
1629
+ cjsRequireRewrite: true,
1630
+ sharedClosureRoots: state.sharedClosureRoots
1539
1631
  });
1540
1632
  }
1541
1633
  return null;
@@ -1547,7 +1639,8 @@ ${code}`, map: null };
1547
1639
  // 双角色宿主可显式 devSharedSelf: true 参与协商
1548
1640
  rewriteShared: state.command === "build" || state.normalized.devSharedSelf,
1549
1641
  allowNodeModules,
1550
- cjsRequireRewrite: state.command === "build"
1642
+ cjsRequireRewrite: state.command === "build",
1643
+ sharedClosureRoots: state.sharedClosureRoots
1551
1644
  });
1552
1645
  },
1553
1646
  transformIndexHtml: {
@@ -1572,6 +1665,68 @@ ${code}`, map: null };
1572
1665
  async buildStart() {
1573
1666
  if (state.command !== "build" || !state.normalized) return;
1574
1667
  const n = state.normalized;
1668
+ if (state.manualChunkSpecsPending) {
1669
+ for (const [group, specifier] of state.manualChunkSpecsPending) {
1670
+ try {
1671
+ const r = await this.resolve(specifier, path5.join(n.root, "index.html"));
1672
+ if (r?.id) {
1673
+ state.manualChunkGroups.set(r.id, group);
1674
+ state.manualChunkGroups.set(r.id.split("?")[0], group);
1675
+ } else {
1676
+ console.warn(
1677
+ `[fulgurjs] manualChunks: could not resolve "${specifier}" for group "${group}"; those modules will fall back to automatic chunking. (Their shared-negotiation facades are still guarded.)`
1678
+ );
1679
+ }
1680
+ } catch {
1681
+ console.warn(
1682
+ `[fulgurjs] manualChunks: resolving "${specifier}" (group "${group}") failed; those modules will fall back to automatic chunking.`
1683
+ );
1684
+ }
1685
+ }
1686
+ state.manualChunkSpecsPending = void 0;
1687
+ }
1688
+ if (n.remotes.length > 0 && n.devSharedSelf && state.sharedClosureRoots.length === 0) {
1689
+ const rootKeys = /* @__PURE__ */ new Map();
1690
+ const pkgRootOf = (file) => {
1691
+ const NM = "/node_modules/";
1692
+ const i = file.lastIndexOf(NM);
1693
+ if (i === -1) return null;
1694
+ const rest = file.slice(i + NM.length);
1695
+ const segs = rest.split("/");
1696
+ const pkgDir = segs[0].startsWith("@") ? segs.slice(0, 2).join("/") : segs[0];
1697
+ return file.slice(0, i + NM.length) + pkgDir + "/";
1698
+ };
1699
+ for (const item of n.shared) {
1700
+ if (item.import === false) continue;
1701
+ const selfFile = await this.resolve(item.import, path5.join(n.root, "index.html")).then(
1702
+ (r) => r?.id?.split("?")[0] ?? null
1703
+ ).catch(() => null);
1704
+ for (const alias of item.aliases) {
1705
+ if (alias.endsWith("/")) continue;
1706
+ let file = null;
1707
+ if (selfFile) {
1708
+ try {
1709
+ const req = createRequire2(selfFile);
1710
+ file = req.resolve(`${alias}/package.json`, { paths: [selfFile] }).replace(/\/package\.json$/, "");
1711
+ } catch {
1712
+ file = null;
1713
+ }
1714
+ }
1715
+ if (!file) {
1716
+ file = await this.resolve(alias, path5.join(n.root, "index.html")).then(
1717
+ (r) => r?.id?.split("?")[0] ?? null
1718
+ ).catch(() => null);
1719
+ }
1720
+ if (!file) continue;
1721
+ const root = pkgRootOf(file);
1722
+ if (!root) continue;
1723
+ let keys = rootKeys.get(root);
1724
+ if (!keys) rootKeys.set(root, keys = /* @__PURE__ */ new Set());
1725
+ keys.add(item.shareKey);
1726
+ }
1727
+ }
1728
+ state.sharedClosureRoots = [...rootKeys.entries()].map(([root, keys]) => ({ root, keys }));
1729
+ }
1575
1730
  if (n.exposes.length > 0) {
1576
1731
  for (const e of n.exposes) {
1577
1732
  const resolved = await this.resolve(e.import, path5.join(n.root, "index.html"));
@@ -1589,33 +1744,50 @@ ${code}`, map: null };
1589
1744
  });
1590
1745
  }
1591
1746
  },
1592
- async generateBundle(_opts, bundle) {
1593
- const n = state.normalized;
1594
- if (state.command !== "build" || !n || n.exposes.length === 0 || !n.manifest) return;
1595
- const facadeToChunk = {};
1596
- for (const [fileName, chunk] of Object.entries(bundle)) {
1597
- if (chunk.type !== "chunk") continue;
1598
- const facade = chunk.facadeModuleId?.split("?")[0];
1599
- if (facade) {
1600
- const viteMeta = chunk.viteMetadata;
1601
- facadeToChunk[facade] = {
1602
- file: fileName,
1603
- css: viteMeta ? [...viteMeta.importedCss ?? []] : []
1747
+ generateBundle: {
1748
+ order: "post",
1749
+ handler(_opts, bundle) {
1750
+ const n = state.normalized;
1751
+ if (state.command !== "build" || !n || n.exposes.length === 0 || !n.manifest) return;
1752
+ const collectStaticCss = (entryFile) => {
1753
+ const visited = /* @__PURE__ */ new Set();
1754
+ const cssFiles = /* @__PURE__ */ new Set();
1755
+ const visit = (fileName) => {
1756
+ if (visited.has(fileName)) return;
1757
+ visited.add(fileName);
1758
+ const chunk = bundle[fileName];
1759
+ if (!chunk || chunk.type !== "chunk") return;
1760
+ const viteMeta = chunk.viteMetadata;
1761
+ for (const css of viteMeta?.importedCss ?? []) cssFiles.add(css);
1762
+ for (const importedFile of chunk.imports) visit(importedFile);
1604
1763
  };
1764
+ visit(entryFile);
1765
+ return [...cssFiles];
1766
+ };
1767
+ const facadeToChunk = {};
1768
+ for (const [fileName, chunk] of Object.entries(bundle)) {
1769
+ if (chunk.type !== "chunk") continue;
1770
+ const facade = chunk.facadeModuleId?.split("?")[0];
1771
+ if (facade) {
1772
+ facadeToChunk[facade] = {
1773
+ file: fileName,
1774
+ css: collectStaticCss(fileName)
1775
+ };
1776
+ }
1605
1777
  }
1778
+ for (const e of n.exposes) {
1779
+ const abs = state.exposeAbsPaths[e.import];
1780
+ const hit = abs ? facadeToChunk[abs] : void 0;
1781
+ if (hit) state.exposeFiles[e.name] = hit;
1782
+ }
1783
+ const entryChunkName = Object.keys(bundle).find((k) => bundle[k].type === "chunk" && k === n.filename);
1784
+ const manifest = genProdManifest(n, state.exposeFiles, entryChunkName ?? n.filename);
1785
+ this.emitFile({
1786
+ type: "asset",
1787
+ fileName: "fulgurjs-manifest.json",
1788
+ source: JSON.stringify(manifest, null, 2)
1789
+ });
1606
1790
  }
1607
- for (const e of n.exposes) {
1608
- const abs = state.exposeAbsPaths[e.import];
1609
- const hit = abs ? facadeToChunk[abs] : void 0;
1610
- if (hit) state.exposeFiles[e.name] = hit;
1611
- }
1612
- const entryChunkName = Object.keys(bundle).find((k) => bundle[k].type === "chunk" && k === n.filename);
1613
- const manifest = genProdManifest(n, state.exposeFiles, entryChunkName ?? n.filename);
1614
- this.emitFile({
1615
- type: "asset",
1616
- fileName: "fulgurjs-manifest.json",
1617
- source: JSON.stringify(manifest, null, 2)
1618
- });
1619
1791
  },
1620
1792
  configureServer(server) {
1621
1793
  const n = state.normalized;
@@ -1701,13 +1873,26 @@ ${code}`, map: null };
1701
1873
  if (state.command === "serve" && code.includes("virtual:fulgurjs-runtime") && !code.includes("virtual:fulgurjs-runtime-proxy") && isExposeTargetFile(clean, state.normalized.root, state.normalized.exposes)) {
1702
1874
  return { code: code.split("virtual:fulgurjs-runtime").join("virtual:fulgurjs-runtime-proxy"), map: null };
1703
1875
  }
1704
- if (isPluginProcessedModule(code)) return null;
1705
- if (state.command === "build" && !/\.vue(\?|$)/.test(id)) return null;
1876
+ if (state.command === "serve" && isPluginProcessedModule(code)) return null;
1706
1877
  if (/type=(style|template)/.test(id)) return null;
1707
1878
  const isJsLike = /\.(m|c)?[jt]sx?$/.test(clean) || clean.endsWith(".vue");
1708
1879
  if (!isJsLike) return null;
1709
1880
  const devRewriteAll = state.command === "serve" && state.normalized.devSharedSelf;
1710
- if (clean.includes("node_modules") && !id.includes(".vite/deps") && !devRewriteAll) return null;
1881
+ const isPureRemoteBuild = state.normalized.exposes.length > 0 && state.normalized.remotes.length === 0;
1882
+ if (state.command === "serve" && clean.includes("node_modules") && !id.includes(".vite/deps") && !devRewriteAll) {
1883
+ return null;
1884
+ }
1885
+ if (state.command === "build" && !/\.vue(\?|$)/.test(id)) {
1886
+ const quickCheck = /require\s*\(\s*["']|(?:from|import)\s*["']/.test(code);
1887
+ if (!quickCheck) return null;
1888
+ const allowNodeModules = isPureRemoteBuild;
1889
+ return transformModule(code, id, {
1890
+ options: state.normalized,
1891
+ rewriteShared: true,
1892
+ allowNodeModules,
1893
+ sharedClosureRoots: state.sharedClosureRoots
1894
+ });
1895
+ }
1711
1896
  const rewriteShared = state.command === "build" || state.normalized.devSharedSelf;
1712
1897
  const remapSpecifier = (spec) => {
1713
1898
  if (state.normalized.shared.some((s) => s.aliases.includes(spec))) return spec;
@@ -1721,7 +1906,14 @@ ${code}`, map: null };
1721
1906
  if (!cleanPath.startsWith("/")) return null;
1722
1907
  return state.resolvedSharedPaths.get(cleanPath) ?? null;
1723
1908
  };
1724
- return transformModule(code, id, { options: state.normalized, remapSpecifier, rewriteShared });
1909
+ const __r = await transformModule(code, id, {
1910
+ options: state.normalized,
1911
+ remapSpecifier,
1912
+ rewriteShared,
1913
+ allowNodeModules: state.command === "build" ? isPureRemoteBuild || state.normalized.devSharedSelf : void 0,
1914
+ sharedClosureRoots: state.sharedClosureRoots
1915
+ });
1916
+ return __r;
1725
1917
  }
1726
1918
  };
1727
1919
  function warmResolvedSharedPaths(server) {