@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.cjs CHANGED
@@ -43,7 +43,7 @@ var import_node_fs = __toESM(require("fs"), 1);
43
43
  var import_node_path = __toESM(require("path"), 1);
44
44
 
45
45
  // src/version.ts
46
- var RUNTIME_VERSION = "2.0.1";
46
+ var RUNTIME_VERSION = "2.0.3";
47
47
 
48
48
  // src/options.ts
49
49
  var DEFAULT_FILENAME = "fulgurjs-remoteEntry.js";
@@ -402,28 +402,45 @@ var import_node_path2 = __toESM(require("path"), 1);
402
402
  function jsonReplacer(_k, v) {
403
403
  return v;
404
404
  }
405
- function genSharedFacade(specifier, exportNames) {
405
+ function genSharedFacade(specifier, exportNames, dynamic = false) {
406
406
  const names = (exportNames ?? []).filter(
407
407
  (n) => n !== "default" && /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(n)
408
408
  );
409
- if (names.length === 0) {
409
+ if (!dynamic) {
410
+ if (names.length === 0) {
411
+ return [
412
+ `import * as __fulgurjs_facade from ${JSON.stringify(specifier)};`,
413
+ `export * from ${JSON.stringify(specifier)};`,
414
+ `export default __fulgurjs_facade.default ?? __fulgurjs_facade;`,
415
+ ""
416
+ ].join("\n");
417
+ }
410
418
  return [
411
419
  `import * as __fulgurjs_facade from ${JSON.stringify(specifier)};`,
420
+ ...names.map((n) => `export const ${n} = __fulgurjs_facade[${JSON.stringify(n)}];`),
421
+ `export default __fulgurjs_facade.default ?? __fulgurjs_facade;`,
422
+ ""
423
+ ].join("\n");
424
+ }
425
+ if (names.length === 0) {
426
+ return [
427
+ `const __fulgurjs_facade = await import(${JSON.stringify(specifier)});`,
412
428
  `export * from ${JSON.stringify(specifier)};`,
413
429
  `export default __fulgurjs_facade.default ?? __fulgurjs_facade;`,
414
430
  ""
415
431
  ].join("\n");
416
432
  }
417
433
  return [
418
- `import * as __fulgurjs_facade from ${JSON.stringify(specifier)};`,
419
- ...names.map((n) => `export const ${n} = __fulgurjs_facade[${JSON.stringify(n)}];`),
420
- `export default __fulgurjs_facade.default ?? __fulgurjs_facade;`,
434
+ `const __fulgurjs_facade = await import(${JSON.stringify(specifier)});`,
435
+ `const __fulgurjs_ns = { ...__fulgurjs_facade };`,
436
+ ...names.map((n) => `export const ${n} = __fulgurjs_ns[${JSON.stringify(n)}];`),
437
+ `export default __fulgurjs_ns.default ?? __fulgurjs_ns;`,
421
438
  ""
422
439
  ].join("\n");
423
440
  }
424
- function genSharedNsFacade(item, loadShareCall, exportNames) {
441
+ function genSharedNsFacade(item, loadShareCall, exportNames, dynamic = false) {
425
442
  const lines = [
426
- `import { loadShare as __fulgurjs_loadShare, unwrapDefault as __fulgurjsU } from "virtual:fulgurjs-runtime";`,
443
+ dynamic ? `const { loadShare: __fulgurjs_loadShare, unwrapDefault: __fulgurjsU } = await import("virtual:fulgurjs-runtime");` : `import { loadShare as __fulgurjs_loadShare, unwrapDefault as __fulgurjsU } from "virtual:fulgurjs-runtime";`,
427
444
  `const __fulgurjs_m = await ${loadShareCall};`,
428
445
  `const __fulgurjs_d = __fulgurjsU(__fulgurjs_m);`,
429
446
  `export default __fulgurjs_d;`
@@ -437,9 +454,9 @@ function genSharedNsFacade(item, loadShareCall, exportNames) {
437
454
  lines.push("");
438
455
  return lines.join("\n");
439
456
  }
440
- function genBindingFacade(item, bindings, loadShareCall) {
457
+ function genBindingFacade(item, bindings, loadShareCall, dynamic = false) {
441
458
  const lines = [
442
- `import { loadShare as __fulgurjs_loadShare, unwrapDefault as __fulgurjsU } from "virtual:fulgurjs-runtime";`,
459
+ dynamic ? `const { loadShare: __fulgurjs_loadShare, unwrapDefault: __fulgurjsU } = await import("virtual:fulgurjs-runtime");` : `import { loadShare as __fulgurjs_loadShare, unwrapDefault as __fulgurjsU } from "virtual:fulgurjs-runtime";`,
443
460
  `const __fulgurjs_m = await ${loadShareCall};`
444
461
  ];
445
462
  const seen = /* @__PURE__ */ new Set();
@@ -455,9 +472,9 @@ function genBindingFacade(item, bindings, loadShareCall) {
455
472
  lines.push("");
456
473
  return lines.join("\n");
457
474
  }
458
- function genRemoteBindingFacade(remoteSpec, bindings) {
475
+ function genRemoteBindingFacade(remoteSpec, bindings, dynamic = false) {
459
476
  const lines = [
460
- `import { loadRemote as __fulgurjs_loadRemote, unwrapDefault as __fulgurjsU } from "virtual:fulgurjs-runtime";`,
477
+ 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"),
461
478
  `const __fulgurjs_m = await __fulgurjs_loadRemote(${JSON.stringify(remoteSpec)});`
462
479
  ];
463
480
  const seen = /* @__PURE__ */ new Set();
@@ -524,13 +541,17 @@ function manifestUrlFor(r, command) {
524
541
  const entry = command === "serve" ? r.devEntry : r.prodEntry;
525
542
  if (!entry) return null;
526
543
  try {
527
- const u = new URL(entry);
544
+ const hasScheme = /^[a-z][a-z\d+.-]*:/i.test(entry);
545
+ const isProtocolRelative = entry.startsWith("//");
546
+ const u = new URL(entry, hasScheme ? void 0 : "http://fulgurjs.invalid");
528
547
  if (u.pathname.includes("@fulgurjs-entry.js")) {
529
548
  u.pathname = u.pathname.replace("@fulgurjs-entry.js", "@fulgurjs-manifest.json");
530
549
  } else {
531
550
  u.pathname = u.pathname.replace(/[^/]*$/, "") + "fulgurjs-manifest.json";
532
551
  }
533
- return u.href;
552
+ if (hasScheme) return u.href;
553
+ if (isProtocolRelative) return `//${u.host}${u.pathname}${u.search}${u.hash}`;
554
+ return `${u.pathname}${u.search}${u.hash}`;
534
555
  } catch {
535
556
  return null;
536
557
  }
@@ -814,6 +835,10 @@ function parseImportClause(clause) {
814
835
  return { ns: nsMatch?.[1] ?? null, bindings, defaultLocal };
815
836
  }
816
837
  var JS_EXT_RE = /\.(m|c)?[jt]sx?$/;
838
+ function inSharedClosure(moduleId, roots) {
839
+ if (!roots || roots.length === 0) return false;
840
+ return roots.some((r) => moduleId.startsWith(r.root));
841
+ }
817
842
  function isTransformableId(id, allowNodeModules = false) {
818
843
  const clean = id.split("?")[0];
819
844
  if (!JS_EXT_RE.test(clean) && !clean.endsWith(".vue")) return false;
@@ -864,6 +889,7 @@ function remoteFacadeSpecFor(ctx, remoteName, exposeName, bindings) {
864
889
  }
865
890
  async function transformModule(code, id, ctx) {
866
891
  const { options } = ctx;
892
+ const clean = id.split("?")[0];
867
893
  if (options.shared.length === 0 && options.remotes.length === 0) return null;
868
894
  const candidates = [];
869
895
  for (const s2 of options.shared) candidates.push(s2.configKey.replace(/\/$/, ""));
@@ -950,7 +976,8 @@ export { ${nsAs[1]} };`);
950
976
  while (code[stmtEnd] === ";") stmtEnd++;
951
977
  const head = code.slice(stmtStart, stmtStart + 24);
952
978
  if (/^\s*(import|export)\s+type[\s{]/.test(head)) continue;
953
- const shared2 = matcher ? matchShared(spec2, matcher) : null;
979
+ const matched2 = matcher ? matchShared(spec2, matcher) : null;
980
+ const shared2 = matched2 && inSharedClosure(clean, ctx.sharedClosureRoots) ? null : matched2;
954
981
  const firstSeg2 = spec2.split("/")[0];
955
982
  const remote2 = remotesByKey.get(firstSeg2);
956
983
  const exposeName2 = remote2 ? remoteExposeName(spec2, remote2.key) : null;
@@ -983,7 +1010,8 @@ export { ${nsAs[1]} };`);
983
1010
  const literal = specExpr.match(/^['"](.*)['"]$/s);
984
1011
  if (!literal) continue;
985
1012
  const spec = remap(literal[1]);
986
- const shared = matcher ? matchShared(spec, matcher) : null;
1013
+ const matched = matcher ? matchShared(spec, matcher) : null;
1014
+ const shared = matched && inSharedClosure(clean, ctx.sharedClosureRoots) ? null : matched;
987
1015
  const firstSeg = spec.split("/")[0];
988
1016
  const remote = remotesByKey.get(firstSeg);
989
1017
  const exposeName = remote ? remoteExposeName(spec, remote.key) : null;
@@ -1298,7 +1326,7 @@ function syncViteCacheMarker(root, pluginVersion, log) {
1298
1326
  }
1299
1327
 
1300
1328
  // src/runtime-code.gen.ts
1301
- 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';
1329
+ 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';
1302
1330
 
1303
1331
  // src/index.ts
1304
1332
  function readRuntimeCode() {
@@ -1339,6 +1367,29 @@ function injectInitScript(html, scriptSrc) {
1339
1367
  }
1340
1368
  return tag + html;
1341
1369
  }
1370
+ var RUNTIME_CHUNK_NAME = "fulgurjs-runtime";
1371
+ var REMOTE_FACADE_CHUNK_NAME = "fulgurjs-remote-facades";
1372
+ function facadeChunkOf(id) {
1373
+ const bare = id.split("?")[0];
1374
+ if (bare === "virtual:fulgurjs-runtime" || bare === "virtual:fulgurjs-runtime-proxy") {
1375
+ return RUNTIME_CHUNK_NAME;
1376
+ }
1377
+ if (bare.startsWith("virtual:fulgurjs-shared:")) {
1378
+ const body = bare.slice("virtual:fulgurjs-shared:".length);
1379
+ if (body.startsWith("__remote__/")) {
1380
+ const remoteName = body.slice("__remote__/".length).split("/")[0] || "unknown";
1381
+ return REMOTE_FACADE_CHUNK_NAME + "-" + remoteName.replace(/[^A-Za-z0-9_-]/g, "_");
1382
+ }
1383
+ const shareKey = body.split("?")[0];
1384
+ return "fulgurjs-shared-" + (shareKey.replace(/[^A-Za-z0-9_-]/g, "_") || "unknown");
1385
+ }
1386
+ if (bare.startsWith("virtual:fulgurjs-shared-ns:") || bare.startsWith("virtual:fulgurjs-cjs-ns:")) {
1387
+ const prefix = bare.startsWith("virtual:fulgurjs-shared-ns:") ? "virtual:fulgurjs-shared-ns:" : "virtual:fulgurjs-cjs-ns:";
1388
+ const shareKey = bare.slice(prefix.length);
1389
+ return "fulgurjs-shared-" + (shareKey.replace(/[^A-Za-z0-9_-]/g, "_") || "unknown");
1390
+ }
1391
+ return null;
1392
+ }
1342
1393
  function federation(options) {
1343
1394
  const warnedUnknownPrefixes = /* @__PURE__ */ new Set();
1344
1395
  let remoteSchemaPromise = null;
@@ -1349,7 +1400,10 @@ function federation(options) {
1349
1400
  exposeFiles: {},
1350
1401
  resolvedSharedPaths: /* @__PURE__ */ new Map(),
1351
1402
  entryAbsPaths: /* @__PURE__ */ new Set(),
1352
- entryInitInjected: /* @__PURE__ */ new Set()
1403
+ entryInitInjected: /* @__PURE__ */ new Set(),
1404
+ manualChunkGroups: /* @__PURE__ */ new Map(),
1405
+ sharedClosureRoots: [],
1406
+ facadeDynamic: false
1353
1407
  };
1354
1408
  const pre = {
1355
1409
  name: "fulgurjs:core",
@@ -1417,6 +1471,43 @@ export { default } from ${JSON.stringify(url)};
1417
1471
  ;
1418
1472
  extra.build = { target: "es2022" };
1419
1473
  }
1474
+ if (normalized.remotes.length > 0 && normalized.devSharedSelf) {
1475
+ state.facadeDynamic = true;
1476
+ const userOutput = userConfig.build?.rollupOptions?.output;
1477
+ if (Array.isArray(userOutput)) {
1478
+ console.warn(
1479
+ formatFulgurjsDiagnostic({
1480
+ code: "BLD-006",
1481
+ symptom: "build.rollupOptions.output is an array; fulgurjs cannot inject the shared-facade chunk guard automatically",
1482
+ 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",
1483
+ fix: `\u5728\u6BCF\u4E2A output \u9879\u7684 manualChunks \u6700\u524D\u9762\u52A0\u5206\u652F\uFF1Aif (id.startsWith('virtual:fulgurjs-')) return 'fulgurjs-shared-facades'`
1484
+ })
1485
+ );
1486
+ } else {
1487
+ const userManualChunks = userOutput?.manualChunks;
1488
+ if (typeof userManualChunks === "function") {
1489
+ const userFn = userManualChunks;
1490
+ const wrapped = (id, meta) => {
1491
+ const facade = facadeChunkOf(id);
1492
+ if (facade) return facade;
1493
+ return userFn(id, meta);
1494
+ };
1495
+ const extraBuild = extra.build ??= {};
1496
+ extraBuild.rollupOptions = { ...extraBuild.rollupOptions ?? {}, output: { manualChunks: wrapped } };
1497
+ } else if (userManualChunks && typeof userManualChunks === "object") {
1498
+ state.manualChunkSpecsPending = Object.entries(userManualChunks).flatMap(
1499
+ ([group, specs]) => specs.map((s) => [group, s])
1500
+ );
1501
+ const wrapped = (id) => {
1502
+ const facade = facadeChunkOf(id);
1503
+ if (facade) return facade;
1504
+ return state.manualChunkGroups.get(id.split("?")[0]) ?? state.manualChunkGroups.get(id);
1505
+ };
1506
+ const extraBuild = extra.build ??= {};
1507
+ extraBuild.rollupOptions = { ...extraBuild.rollupOptions ?? {}, output: { manualChunks: wrapped } };
1508
+ }
1509
+ }
1510
+ }
1420
1511
  }
1421
1512
  for (const w of normalized.warnings) console.warn(`[fulgurjs] ${w}`);
1422
1513
  return extra;
@@ -1458,7 +1549,7 @@ export { default } from ${JSON.stringify(url)};
1458
1549
  const query = q === -1 ? "" : s.slice(q);
1459
1550
  const bareClean = bare.startsWith("\0") ? bare.slice(1) : bare;
1460
1551
  const n = state.normalized;
1461
- if (n && !bareClean.startsWith("\0") && !bareClean.startsWith(".") && !bareClean.startsWith("/") && !bareClean.startsWith("virtual:")) {
1552
+ if (n && !bare.startsWith("\0") && !bareClean.startsWith(".") && !bareClean.startsWith("/") && !bareClean.startsWith("virtual:")) {
1462
1553
  const slash = bareClean.indexOf("/");
1463
1554
  if (slash > 0) {
1464
1555
  const prefix = bareClean.slice(0, slash);
@@ -1521,7 +1612,7 @@ export { default } from ${JSON.stringify(url)};
1521
1612
  if (!names.includes(compat)) names.push(compat);
1522
1613
  }
1523
1614
  }
1524
- return genSharedNsFacade(item, serializeShareCallForFacade(item), names);
1615
+ return genSharedNsFacade(item, serializeShareCallForFacade(item), names, state.facadeDynamic);
1525
1616
  }
1526
1617
  if (clean.startsWith("virtual:fulgurjs-shared:") && state.normalized) {
1527
1618
  const body = clean.slice("virtual:fulgurjs-shared:".length);
@@ -1530,14 +1621,14 @@ export { default } from ${JSON.stringify(url)};
1530
1621
  const item2 = state.normalized.shared.find((x) => x.shareKey === body);
1531
1622
  if (item2 && item2.import !== false) {
1532
1623
  const names = /^(\.|\/)/.test(item2.import) ? [] : enumerateCjsExports(item2.import, state.normalized.root);
1533
- return genSharedFacade(item2.import, names);
1624
+ return genSharedFacade(item2.import, names, state.facadeDynamic);
1534
1625
  }
1535
1626
  return null;
1536
1627
  }
1537
1628
  const entry = getFacadeEntry(raw.slice(f + 3));
1538
1629
  if (!entry) return null;
1539
1630
  if (entry.remoteName && entry.exposeName) {
1540
- return genRemoteBindingFacade(entry.remoteName + "/" + entry.exposeName, entry.bindings);
1631
+ return genRemoteBindingFacade(entry.remoteName + "/" + entry.exposeName, entry.bindings, state.facadeDynamic);
1541
1632
  }
1542
1633
  const item = state.normalized.shared.find((x) => x.shareKey === entry.shareKey);
1543
1634
  if (!item || item.import === false) return null;
@@ -1550,7 +1641,7 @@ export { default } from ${JSON.stringify(url)};
1550
1641
  "fallback: () => import(" + JSON.stringify(item.import) + ")"
1551
1642
  ];
1552
1643
  const call = "__fulgurjs_loadShare(" + JSON.stringify(item.shareKey) + ", { " + opts.join(", ") + " })";
1553
- return genBindingFacade(item, entry.bindings, call);
1644
+ return genBindingFacade(item, entry.bindings, call, state.facadeDynamic);
1554
1645
  }
1555
1646
  return null;
1556
1647
  },
@@ -1571,7 +1662,8 @@ ${code}`, map: null };
1571
1662
  options: state.normalized,
1572
1663
  rewriteShared: true,
1573
1664
  allowNodeModules,
1574
- cjsRequireRewrite: true
1665
+ cjsRequireRewrite: true,
1666
+ sharedClosureRoots: state.sharedClosureRoots
1575
1667
  });
1576
1668
  }
1577
1669
  return null;
@@ -1583,7 +1675,8 @@ ${code}`, map: null };
1583
1675
  // 双角色宿主可显式 devSharedSelf: true 参与协商
1584
1676
  rewriteShared: state.command === "build" || state.normalized.devSharedSelf,
1585
1677
  allowNodeModules,
1586
- cjsRequireRewrite: state.command === "build"
1678
+ cjsRequireRewrite: state.command === "build",
1679
+ sharedClosureRoots: state.sharedClosureRoots
1587
1680
  });
1588
1681
  },
1589
1682
  transformIndexHtml: {
@@ -1608,6 +1701,68 @@ ${code}`, map: null };
1608
1701
  async buildStart() {
1609
1702
  if (state.command !== "build" || !state.normalized) return;
1610
1703
  const n = state.normalized;
1704
+ if (state.manualChunkSpecsPending) {
1705
+ for (const [group, specifier] of state.manualChunkSpecsPending) {
1706
+ try {
1707
+ const r = await this.resolve(specifier, import_node_path5.default.join(n.root, "index.html"));
1708
+ if (r?.id) {
1709
+ state.manualChunkGroups.set(r.id, group);
1710
+ state.manualChunkGroups.set(r.id.split("?")[0], group);
1711
+ } else {
1712
+ console.warn(
1713
+ `[fulgurjs] manualChunks: could not resolve "${specifier}" for group "${group}"; those modules will fall back to automatic chunking. (Their shared-negotiation facades are still guarded.)`
1714
+ );
1715
+ }
1716
+ } catch {
1717
+ console.warn(
1718
+ `[fulgurjs] manualChunks: resolving "${specifier}" (group "${group}") failed; those modules will fall back to automatic chunking.`
1719
+ );
1720
+ }
1721
+ }
1722
+ state.manualChunkSpecsPending = void 0;
1723
+ }
1724
+ if (n.remotes.length > 0 && n.devSharedSelf && state.sharedClosureRoots.length === 0) {
1725
+ const rootKeys = /* @__PURE__ */ new Map();
1726
+ const pkgRootOf = (file) => {
1727
+ const NM = "/node_modules/";
1728
+ const i = file.lastIndexOf(NM);
1729
+ if (i === -1) return null;
1730
+ const rest = file.slice(i + NM.length);
1731
+ const segs = rest.split("/");
1732
+ const pkgDir = segs[0].startsWith("@") ? segs.slice(0, 2).join("/") : segs[0];
1733
+ return file.slice(0, i + NM.length) + pkgDir + "/";
1734
+ };
1735
+ for (const item of n.shared) {
1736
+ if (item.import === false) continue;
1737
+ const selfFile = await this.resolve(item.import, import_node_path5.default.join(n.root, "index.html")).then(
1738
+ (r) => r?.id?.split("?")[0] ?? null
1739
+ ).catch(() => null);
1740
+ for (const alias of item.aliases) {
1741
+ if (alias.endsWith("/")) continue;
1742
+ let file = null;
1743
+ if (selfFile) {
1744
+ try {
1745
+ const req = (0, import_node_module2.createRequire)(selfFile);
1746
+ file = req.resolve(`${alias}/package.json`, { paths: [selfFile] }).replace(/\/package\.json$/, "");
1747
+ } catch {
1748
+ file = null;
1749
+ }
1750
+ }
1751
+ if (!file) {
1752
+ file = await this.resolve(alias, import_node_path5.default.join(n.root, "index.html")).then(
1753
+ (r) => r?.id?.split("?")[0] ?? null
1754
+ ).catch(() => null);
1755
+ }
1756
+ if (!file) continue;
1757
+ const root = pkgRootOf(file);
1758
+ if (!root) continue;
1759
+ let keys = rootKeys.get(root);
1760
+ if (!keys) rootKeys.set(root, keys = /* @__PURE__ */ new Set());
1761
+ keys.add(item.shareKey);
1762
+ }
1763
+ }
1764
+ state.sharedClosureRoots = [...rootKeys.entries()].map(([root, keys]) => ({ root, keys }));
1765
+ }
1611
1766
  if (n.exposes.length > 0) {
1612
1767
  for (const e of n.exposes) {
1613
1768
  const resolved = await this.resolve(e.import, import_node_path5.default.join(n.root, "index.html"));
@@ -1625,33 +1780,50 @@ ${code}`, map: null };
1625
1780
  });
1626
1781
  }
1627
1782
  },
1628
- async generateBundle(_opts, bundle) {
1629
- const n = state.normalized;
1630
- if (state.command !== "build" || !n || n.exposes.length === 0 || !n.manifest) return;
1631
- const facadeToChunk = {};
1632
- for (const [fileName, chunk] of Object.entries(bundle)) {
1633
- if (chunk.type !== "chunk") continue;
1634
- const facade = chunk.facadeModuleId?.split("?")[0];
1635
- if (facade) {
1636
- const viteMeta = chunk.viteMetadata;
1637
- facadeToChunk[facade] = {
1638
- file: fileName,
1639
- css: viteMeta ? [...viteMeta.importedCss ?? []] : []
1783
+ generateBundle: {
1784
+ order: "post",
1785
+ handler(_opts, bundle) {
1786
+ const n = state.normalized;
1787
+ if (state.command !== "build" || !n || n.exposes.length === 0 || !n.manifest) return;
1788
+ const collectStaticCss = (entryFile) => {
1789
+ const visited = /* @__PURE__ */ new Set();
1790
+ const cssFiles = /* @__PURE__ */ new Set();
1791
+ const visit = (fileName) => {
1792
+ if (visited.has(fileName)) return;
1793
+ visited.add(fileName);
1794
+ const chunk = bundle[fileName];
1795
+ if (!chunk || chunk.type !== "chunk") return;
1796
+ const viteMeta = chunk.viteMetadata;
1797
+ for (const css of viteMeta?.importedCss ?? []) cssFiles.add(css);
1798
+ for (const importedFile of chunk.imports) visit(importedFile);
1640
1799
  };
1800
+ visit(entryFile);
1801
+ return [...cssFiles];
1802
+ };
1803
+ const facadeToChunk = {};
1804
+ for (const [fileName, chunk] of Object.entries(bundle)) {
1805
+ if (chunk.type !== "chunk") continue;
1806
+ const facade = chunk.facadeModuleId?.split("?")[0];
1807
+ if (facade) {
1808
+ facadeToChunk[facade] = {
1809
+ file: fileName,
1810
+ css: collectStaticCss(fileName)
1811
+ };
1812
+ }
1641
1813
  }
1814
+ for (const e of n.exposes) {
1815
+ const abs = state.exposeAbsPaths[e.import];
1816
+ const hit = abs ? facadeToChunk[abs] : void 0;
1817
+ if (hit) state.exposeFiles[e.name] = hit;
1818
+ }
1819
+ const entryChunkName = Object.keys(bundle).find((k) => bundle[k].type === "chunk" && k === n.filename);
1820
+ const manifest = genProdManifest(n, state.exposeFiles, entryChunkName ?? n.filename);
1821
+ this.emitFile({
1822
+ type: "asset",
1823
+ fileName: "fulgurjs-manifest.json",
1824
+ source: JSON.stringify(manifest, null, 2)
1825
+ });
1642
1826
  }
1643
- for (const e of n.exposes) {
1644
- const abs = state.exposeAbsPaths[e.import];
1645
- const hit = abs ? facadeToChunk[abs] : void 0;
1646
- if (hit) state.exposeFiles[e.name] = hit;
1647
- }
1648
- const entryChunkName = Object.keys(bundle).find((k) => bundle[k].type === "chunk" && k === n.filename);
1649
- const manifest = genProdManifest(n, state.exposeFiles, entryChunkName ?? n.filename);
1650
- this.emitFile({
1651
- type: "asset",
1652
- fileName: "fulgurjs-manifest.json",
1653
- source: JSON.stringify(manifest, null, 2)
1654
- });
1655
1827
  },
1656
1828
  configureServer(server) {
1657
1829
  const n = state.normalized;
@@ -1737,13 +1909,26 @@ ${code}`, map: null };
1737
1909
  if (state.command === "serve" && code.includes("virtual:fulgurjs-runtime") && !code.includes("virtual:fulgurjs-runtime-proxy") && isExposeTargetFile(clean, state.normalized.root, state.normalized.exposes)) {
1738
1910
  return { code: code.split("virtual:fulgurjs-runtime").join("virtual:fulgurjs-runtime-proxy"), map: null };
1739
1911
  }
1740
- if (isPluginProcessedModule(code)) return null;
1741
- if (state.command === "build" && !/\.vue(\?|$)/.test(id)) return null;
1912
+ if (state.command === "serve" && isPluginProcessedModule(code)) return null;
1742
1913
  if (/type=(style|template)/.test(id)) return null;
1743
1914
  const isJsLike = /\.(m|c)?[jt]sx?$/.test(clean) || clean.endsWith(".vue");
1744
1915
  if (!isJsLike) return null;
1745
1916
  const devRewriteAll = state.command === "serve" && state.normalized.devSharedSelf;
1746
- if (clean.includes("node_modules") && !id.includes(".vite/deps") && !devRewriteAll) return null;
1917
+ const isPureRemoteBuild = state.normalized.exposes.length > 0 && state.normalized.remotes.length === 0;
1918
+ if (state.command === "serve" && clean.includes("node_modules") && !id.includes(".vite/deps") && !devRewriteAll) {
1919
+ return null;
1920
+ }
1921
+ if (state.command === "build" && !/\.vue(\?|$)/.test(id)) {
1922
+ const quickCheck = /require\s*\(\s*["']|(?:from|import)\s*["']/.test(code);
1923
+ if (!quickCheck) return null;
1924
+ const allowNodeModules = isPureRemoteBuild;
1925
+ return transformModule(code, id, {
1926
+ options: state.normalized,
1927
+ rewriteShared: true,
1928
+ allowNodeModules,
1929
+ sharedClosureRoots: state.sharedClosureRoots
1930
+ });
1931
+ }
1747
1932
  const rewriteShared = state.command === "build" || state.normalized.devSharedSelf;
1748
1933
  const remapSpecifier = (spec) => {
1749
1934
  if (state.normalized.shared.some((s) => s.aliases.includes(spec))) return spec;
@@ -1757,7 +1942,14 @@ ${code}`, map: null };
1757
1942
  if (!cleanPath.startsWith("/")) return null;
1758
1943
  return state.resolvedSharedPaths.get(cleanPath) ?? null;
1759
1944
  };
1760
- return transformModule(code, id, { options: state.normalized, remapSpecifier, rewriteShared });
1945
+ const __r = await transformModule(code, id, {
1946
+ options: state.normalized,
1947
+ remapSpecifier,
1948
+ rewriteShared,
1949
+ allowNodeModules: state.command === "build" ? isPureRemoteBuild || state.normalized.devSharedSelf : void 0,
1950
+ sharedClosureRoots: state.sharedClosureRoots
1951
+ });
1952
+ return __r;
1761
1953
  }
1762
1954
  };
1763
1955
  function warmResolvedSharedPaths(server) {