@fulgurjs/federation 4.0.0 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  RUNTIME_VERSION
3
- } from "./chunk-X4LZDAZQ.js";
3
+ } from "./chunk-75PP6EAK.js";
4
4
 
5
5
  // src/index.ts
6
6
  import path6 from "path";
@@ -39,6 +39,8 @@ function isNonLoopbackHost(host) {
39
39
 
40
40
  // src/options.ts
41
41
  var DEFAULT_FILENAME = "fulgurjs-remoteEntry.js";
42
+ var SETUP_EXPOSE_KEY = "./__fulgurjs_setup__";
43
+ var SETUP_CONTAINER_KEY = "__fulgurjsSetup";
42
44
  var RUNTIME_VIRTUAL_ID = "virtual:fulgurjs-runtime";
43
45
  var RUNTIME_PROXY_VIRTUAL_ID = "virtual:fulgurjs-runtime-proxy";
44
46
  var INIT_VIRTUAL_ID = "virtual:fulgurjs-init";
@@ -246,6 +248,51 @@ function validateOptions(options) {
246
248
  `federation({ name: 'my-app', ... })`
247
249
  );
248
250
  }
251
+ if (options.remoteType !== void 0 && options.remoteType !== "module") {
252
+ configError(
253
+ 'CFG-011: remoteType other than "module" is not supported',
254
+ options.remoteType,
255
+ '"module"\uFF08\u7F3A\u7701\u5373\u53EF\uFF09\u2014\u2014webpack script/var remote \u4E92\u64CD\u4F5C\u672A\u5B9E\u73B0',
256
+ `// \u5220\u9664 remoteType \u914D\u7F6E\uFF08fulgurjs \u53EA\u4EA7\u51FA ESM module remote\uFF09`
257
+ );
258
+ }
259
+ if (options.library?.type !== void 0 && options.library.type !== "module" && options.library.type !== "esm") {
260
+ configError(
261
+ 'CFG-011: library.type other than "module"/"esm" is not supported',
262
+ options.library.type,
263
+ '"module" \u6216 "esm"\uFF08\u7F3A\u7701\u5373\u53EF\uFF09\u2014\u2014webpack UMD/var \u8F93\u51FA\u4E92\u64CD\u4F5C\u672A\u5B9E\u73B0',
264
+ `// \u5220\u9664 library \u914D\u7F6E\uFF08fulgurjs remoteEntry \u6052\u4E3A ESM\uFF09`
265
+ );
266
+ }
267
+ if (options.automaticAsyncBoundary === false) {
268
+ configError(
269
+ "CFG-011: automaticAsyncBoundary=false cannot be honored",
270
+ options.automaticAsyncBoundary,
271
+ "\u7F3A\u7701\u6216 true\u2014\u2014fulgurjs \u4F7F\u7528 TLA \u81EA\u52A8\u5F02\u6B65\u8FB9\u754C\uFF0C\u4E0D\u5B58\u5728\u624B\u5DE5 bootstrap \u6A21\u5F0F",
272
+ `// \u5220\u9664 automaticAsyncBoundary \u914D\u7F6E\uFF08\u5BB9\u5668\u534F\u8BAE\u5929\u7136\u5F02\u6B65\uFF09`
273
+ );
274
+ }
275
+ for (const key of Object.keys(options.exposes ?? {})) {
276
+ const norm = key.startsWith("./") ? key : `./${key}`;
277
+ if (norm === SETUP_EXPOSE_KEY) {
278
+ configError(
279
+ `CFG-012: exposes key "${norm}" is reserved for the federation setup entry`,
280
+ key,
281
+ `a public expose name\uFF08\u5185\u90E8\u4FDD\u7559\u952E "${SETUP_EXPOSE_KEY}" \u7531 setup \u9009\u9879\u81EA\u52A8\u751F\u6210\uFF09`,
282
+ `// \u628A\u8BE5 expose \u6539\u540D\uFF0C\u6216\u5220\u9664\u5B83\u5E76\u628A\u539F\u6587\u4EF6\u8DEF\u5F84\u914D\u7F6E\u5230 federation({ setup })`
283
+ );
284
+ }
285
+ }
286
+ if (options.setup !== void 0) {
287
+ if (typeof options.setup !== "string" || options.setup.trim() === "") {
288
+ configError(
289
+ "CFG-012: setup must be a non-empty module path relative to the app root",
290
+ options.setup,
291
+ 'e.g. "./src/fulgurjs/setup.ts"\uFF08\u9ED8\u8BA4\u5BFC\u51FA setup(context)\uFF0C\u53EF\u9009\u5177\u540D\u5BFC\u51FA onSession(context)\uFF09',
292
+ `federation({ name: 'my-app', setup: './src/fulgurjs/setup.ts', ... })`
293
+ );
294
+ }
295
+ }
249
296
  if (options.exposes !== void 0 && typeof options.exposes !== "object") {
250
297
  configError("`exposes` must be an object", options.exposes, 'an object of { "./Module": "./src/path" }', `exposes: { './Button': './src/Button.vue' }`);
251
298
  }
@@ -367,21 +414,6 @@ function normalizeOptions(options, root, command) {
367
414
  const warnings = [];
368
415
  validateOptions(options);
369
416
  if (!options.name) throw new Error("[fulgurjs] option `name` is required.");
370
- if (options.remoteType && options.remoteType !== "module") {
371
- warnings.push(
372
- `remoteType "${options.remoteType}" requires webpack-host interop (P3 milestone); falling back to "module".`
373
- );
374
- }
375
- if (options.library?.type && options.library.type !== "module" && options.library.type !== "esm") {
376
- warnings.push(
377
- `library.type "${options.library.type}" requires webpack-host interop (P3 milestone); falling back to "module".`
378
- );
379
- }
380
- if (options.automaticAsyncBoundary === false) {
381
- warnings.push(
382
- "automaticAsyncBoundary=false has no effect: fulgurjs uses TLA-based automatic async boundaries (better than webpack manual bootstrap)."
383
- );
384
- }
385
417
  const exposes = [];
386
418
  for (const [rawName, val] of Object.entries(options.exposes ?? {})) {
387
419
  const name = rawName.startsWith("./") ? rawName : `./${rawName}`;
@@ -389,6 +421,11 @@ function normalizeOptions(options, root, command) {
389
421
  const hint = typeof val === "string" ? { import: val } : val;
390
422
  exposes.push({ name, import: hint.import, chunkName: hint.name });
391
423
  }
424
+ let setup;
425
+ if (options.setup) {
426
+ setup = { name: SETUP_EXPOSE_KEY, import: options.setup, internal: true };
427
+ exposes.push(setup);
428
+ }
392
429
  const shareScopeDefault = options.shareScope || "default";
393
430
  const filename = options.filename || DEFAULT_FILENAME;
394
431
  const pkgDependencies = readPkgDependencies(root);
@@ -419,6 +456,7 @@ function normalizeOptions(options, root, command) {
419
456
  uniqueName: options.name,
420
457
  filename,
421
458
  exposes,
459
+ setup,
422
460
  remotes,
423
461
  shared,
424
462
  shareScope: shareScopeDefault,
@@ -432,8 +470,10 @@ function normalizeOptions(options, root, command) {
432
470
  pluginVersion: RUNTIME_VERSION,
433
471
  pkgDependencies,
434
472
  warnings,
435
- // dev 改写开关:默认纯 remote 参与 shared 协商,宿主(有 remotes)不参与;可显式覆盖
436
- devSharedSelf: options.devSharedSelf ?? remotes.length === 0,
473
+ // dev 改写开关:纯 remote 与双角色(既 expose 又消费 remote)为 true——被宿主消费的
474
+ // 组件需协商到宿主实例,双向联邦漏配该项曾是已知错误配置(README 要求显式 true,
475
+ // §12.4 后默认推断:仅纯宿主为 false);显式配置永远优先
476
+ devSharedSelf: options.devSharedSelf ?? (remotes.length === 0 || exposes.length > 0),
437
477
  devCorsOrigins: options.devCorsOrigins,
438
478
  devFsRoot: options.devFsRoot ?? true
439
479
  };
@@ -584,6 +624,9 @@ function normalizeExposes(manifest) {
584
624
  }
585
625
 
586
626
  // src/virtual.ts
627
+ function setupMetaLine(options) {
628
+ return options.setup ? `export const ${SETUP_CONTAINER_KEY} = ${JSON.stringify(options.setup.name)};` : "";
629
+ }
587
630
  function jsonReplacer(_k, v) {
588
631
  return v;
589
632
  }
@@ -802,6 +845,7 @@ ${remoteLines.length > 0 ? `import { registerRemotes } from ${JSON.stringify(`${
802
845
  ${remoteLines.join("\n")}` : ""}
803
846
 
804
847
  export const name = _fulgurjs_name;
848
+ ${setupMetaLine(options)}
805
849
 
806
850
  export async function init(shareScopeMap) {
807
851
  for (const p of provides) {
@@ -865,6 +909,7 @@ function genBuildRemoteEntry(options, exposeAbsPaths) {
865
909
  ...provides,
866
910
  `];`,
867
911
  `export const name = ${JSON.stringify(options.name)};`,
912
+ setupMetaLine(options),
868
913
  ``,
869
914
  `export async function init(shareScopeMap) {`,
870
915
  ` for (const p of provides) {`,
@@ -894,11 +939,12 @@ function genApiFacade() {
894
939
  " registerRemote, registerRemotes, registerShare, initSharing, registerPlugins,",
895
940
  " parseSpec, getRuntime, shareScopeMap, unwrapDefault, version,",
896
941
  '} from "virtual:fulgurjs-runtime-proxy";',
897
- "export { provideAppContext, getAppContext, requireAppContext } from '@fulgurjs/federation/internal/context.js';",
942
+ "export { provideAppContext, getAppContext, requireAppContext, clearAppContext } from '@fulgurjs/federation/internal/context.js';",
898
943
  "export { definePages, validatePages } from '@fulgurjs/federation/internal/pages.js';",
899
- "import { createRemoteComponent } from '@fulgurjs/federation/internal/vue-adapter.js';",
944
+ "import { createRemoteComponent, createHostPages as __fulgurjs_chp } from '@fulgurjs/federation/internal/vue-adapter.js';",
900
945
  "import { loadRemote as __fulgurjs_loadRemote } from 'virtual:fulgurjs-runtime-proxy';",
901
946
  "export const remoteComponent = createRemoteComponent(__fulgurjs_loadRemote);",
947
+ "export const createHostPages = (options) => __fulgurjs_chp(options, __fulgurjs_loadRemote);",
902
948
  ""
903
949
  ].join("\n");
904
950
  }
@@ -926,6 +972,9 @@ function genDevManifest(options, base) {
926
972
  // dev 下 preload 全部 404。
927
973
  file: `${b}${e.import.replace(/^\.?\//, "")}`
928
974
  })),
975
+ // setup 生命周期入口(内部 expose 键;未配置 setup 时省略)。preloadRemote 据此把
976
+ // setup 资源纳入预载,doctor/explain 据此区分内部资源与公开 exposes。
977
+ ...options.setup ? { setup: options.setup.name } : {},
929
978
  shared: options.shared.map((s) => ({
930
979
  name: s.shareKey,
931
980
  version: s.version,
@@ -943,6 +992,7 @@ function genProdManifest(options, exposeFiles, entryFile) {
943
992
  name: options.name,
944
993
  entry: entryFile,
945
994
  exposes: exposeFiles,
995
+ ...options.setup && exposeFiles[options.setup.name] ? { setup: options.setup.name } : {},
946
996
  shared: options.shared.map((s) => ({
947
997
  name: s.shareKey,
948
998
  version: s.version,
@@ -1451,6 +1501,7 @@ async function generateDevTypes(options, _server) {
1451
1501
  ];
1452
1502
  let accepted = 0;
1453
1503
  for (const expose of manifest.exposes ?? []) {
1504
+ if (manifest.setup && expose.name === manifest.setup) continue;
1454
1505
  const skipped = (reason) => console.warn(`[fulgurjs] dts: remote "${remote.key}" expose ${JSON.stringify(expose.name)} \u8DF3\u8FC7\uFF1A${reason}`);
1455
1506
  const src = expose.src;
1456
1507
  if (!src || typeof src !== "string") {
@@ -1699,7 +1750,7 @@ function syncViteCacheMarker(root, pluginVersion, log) {
1699
1750
  }
1700
1751
 
1701
1752
  // src/runtime-code.gen.ts
1702
- var runtime_code_gen_default = 'var oe=/^v?(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?(?:-((?:[0-9A-Za-z-]+)(?:\\.[0-9A-Za-z-]+)*))?(?:\\+[0-9A-Za-z.-]+)?$/;function I(o){let i=oe.exec(String(o).trim());return i?{major:Number(i[1]),minor:Number(i[2]??0),patch:Number(i[3]??0),pre:i[4]?i[4].split("."):[]}:null}function ie(o,i){if(o.length===0&&i.length===0)return 0;if(o.length===0)return 1;if(i.length===0)return-1;let s=Math.max(o.length,i.length);for(let n=0;n<s;n++){let f=o[n],y=i[n];if(f===void 0)return-1;if(y===void 0)return 1;let b=/^\\d+$/.test(f),w=/^\\d+$/.test(y);if(b&&w){let T=Number(f)-Number(y);if(T!==0)return T}else{if(b!==w)return b?-1:1;if(f!==y)return f<y?-1:1}}return 0}function O(o,i){let s=I(o),n=I(i);return!s||!n?o<i?-1:o>i?1:0:s.major!==n.major?s.major-n.major:s.minor!==n.minor?s.minor-n.minor:s.patch!==n.patch?s.patch-n.patch:ie(s.pre,n.pre)}var se=/^[a-z]+[+:-]/i;function P(o,i){if(i===!1||i==null||i==="")return!0;let s=String(i).trim();return!s||s==="*"||s==="latest"||se.test(s)?!0:s.split("||").some(n=>ae(o,n.trim()))}function ae(o,i){if(!i||i==="*")return!I(o)?.pre.length;let s=i.split(/\\s+-\\s+/);if(s.length===2){let y=s[0].trim(),b=s[1].trim();return!(!P(o,`>=${y}`)||!P(o,`<=${b}`))}let n=I(o);if(!n)return!1;let f=ce(i);if(f===null)return!0;for(let y of f)if(!pe(n,o,y))return!1;return!(n.pre.length>0&&!f.some(y=>y.ver.pre.length>0)&&!f.some(b=>b.ver.major===n.major&&b.ver.minor===n.minor&&b.ver.patch===n.patch))}function ce(o){let i=[],s=o.trim().split(/\\s+/).filter(Boolean);if(s.length===0)return null;for(let n of s){let f=/^(>=|<=|>|<|=|\\^|~)?(.*)$/.exec(n);if(!f)return null;let y=f[1],b=f[2],w=le(y,b);if(w===null)return null;i.push(...w)}return i}function le(o,i){let s=me(i);if(!s)return null;let{ver:n,partial:f}=s;switch(o){case"^":{let y=ue(n);return y?[{op:">=",ver:n},{op:"<",ver:y}]:null}case"~":{let y=f>=2?{major:n.major,minor:n.minor+1,patch:0,pre:[]}:{major:n.major+1,minor:0,patch:0,pre:[]};return[{op:">=",ver:n},{op:"<",ver:y}]}case">=":return[{op:">=",ver:n}];case">":return f===1?[{op:">=",ver:{major:n.major+1,minor:0,patch:0,pre:[]}}]:f===2?[{op:">=",ver:{major:n.major,minor:n.minor+1,patch:0,pre:[]}}]:[{op:">",ver:n}];case"<":return f===1?[{op:"<",ver:{major:n.major,minor:0,patch:0,pre:[]}}]:f===2?[{op:"<",ver:{major:n.major,minor:n.minor,patch:0,pre:[]}}]:[{op:"<",ver:n}];case"<=":return[{op:"<=",ver:n}];case"=":case void 0:return f===1?[{op:">=",ver:n},{op:"<",ver:{major:n.major+1,minor:0,patch:0,pre:[]}}]:f===2?[{op:">=",ver:n},{op:"<",ver:{major:n.major,minor:n.minor+1,patch:0,pre:[]}}]:[{op:"=",ver:n}];default:return null}}function ue(o){return o.major>0?{major:o.major+1,minor:0,patch:0,pre:[]}:o.minor>0?{major:0,minor:o.minor+1,patch:0,pre:[]}:{major:0,minor:0,patch:o.patch+1,pre:[]}}function me(o){let i=o.replace(/^v/,"").trim();if(!i||i==="*"||i==="x"||i==="X")return{ver:{major:0,minor:0,patch:0,pre:[]},partial:0};let s=i.split("."),n=[],f=0;for(let w of s.slice(0,3))if(/^\\d+$/.test(w))n.push(Number(w)),f++;else{if(w==="x"||w==="X"||w==="*")break;break}let y=i.split("-"),b=y.length>1?y.slice(1).join("-").split("+")[0].split("."):[];return f===0&&b.length===0?{ver:{major:0,minor:0,patch:0,pre:[]},partial:0}:{ver:{major:n[0]??0,minor:n[1]??0,patch:n[2]??0,pre:b},partial:f}}function fe(o,i){switch(i){case">=":return o>=0;case">":return o>0;case"<":return o<0;case"<=":return o<=0;case"=":return o===0}}function pe(o,i,s){let n=`${o.major}.${o.minor}.${o.patch}`+(o.pre.length?`-${o.pre.join(".")}`:"");if(s.upper)return!(!(O(n,`${s.ver.major}.${s.ver.minor}.${s.ver.patch}`+(s.ver.pre.length?`-${s.ver.pre.join(".")}`:""))>=0)||!(O(n,`${s.upper.major}.${s.upper.minor}.${s.upper.patch}`)<0));let f=O(n,`${s.ver.major}.${s.ver.minor}.${s.ver.patch}`+(s.ver.pre.length?`-${s.ver.pre.join(".")}`:"")),y=fe(f,s.op);return s.ver.pre.length>0&&o.pre.length===0&&(s.op===">"||s.op==="<")?!1:y}var E=class extends Error{code;details;constructor(i,s,n){super(`[fulgurjs:${i}] ${s}`),this.name="FgError",this.code=i,this.details=n}},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 q="4.0.0";var U=15e3,z=2,de=5,ge=3e4,he=4e3,ye=.2;function Re(){let o=Object.create(null),i=new Map,s=[],n=new Map,f=new Map,y=new WeakMap,b=new WeakMap,w={},T=()=>{for(let e of s)try{e.init?.(w)}catch(t){console.warn("[fulgurjs] runtimePlugin init failed:",e.name,t)}},N=e=>o[e]??=Object.create(null);function k(e){try{w.onRemoteError?.(e)}catch{}typeof window<"u"&&window.dispatchEvent(new CustomEvent("fulgurjs:error",{detail:e}))}function B(e="default"){return N(e),o}function J(e,t,r,l,h={}){let a=N(e||"default"),p=Object.hasOwn(a,t)?a[t]:void 0,d=p&&typeof p=="object"?p:void 0;d||(d=Object.create(null),a[t]=d),!(Object.hasOwn(d,r)&&d[r])&&(d[r]={version:r,get:l,from:h.from??"unknown",eager:!!h.eager,loaded:!!h.loaded})}function G(e){let t=(r,l,h)=>{if(r===void 0)return;if(!(typeof r=="number"&&(h?Number.isInteger(r)&&r>=0&&r<=10:Number.isFinite(r)&&r>0)))throw new Error(`[fulgurjs] registerRemote("${e.name}"): ${l} must be a ${h?"integer 0..10":"finite positive number"}, got ${String(r)}`)};t(e.timeout,"timeout"),t(e.retries,"retries",!0),e.breaker&&(t(e.breaker.threshold,"breaker.threshold"),t(e.breaker.resetMs,"breaker.resetMs"))}function F(e){for(let t of e){G(t);let r=i.get(t.name);i.set(t.name,{timeout:U,retries:z,...r,...t,breakerThreshold:t.breaker?.threshold??r?.breakerThreshold??de,breakerResetMs:t.breaker?.resetMs??r?.breakerResetMs??ge,state:r?.state??"idle",breakerState:r?.breakerState??{fails:0,openUntil:0},entryInflight:r?.entryInflight??new Map,debug:r?.debug??{entry:t.entry,status:"idle"}})}}function X(e){F([e])}function Y(e){s.push(...e),T()}async function Z(e,t={}){let r=t.shareScope||"default",l=t.shareKey||e,a=N(r)[l]||{},p=Object.keys(a),d=t.requiredVersion,g=p.filter(c=>d===void 0||d===!1||P(c,d)),m;if(t.singleton&&p.length>0){let c=p.filter(u=>a[u].loaded);if(m=[...c.length?c:p].sort(O).pop(),p.length>1||!g.includes(m)){let u=a[m],_=`singleton skew "${l}": req "${d??"any"}" use ${m} from ${u.from}`;if(t.strictVersion){let $=new E(S.SHARE_STRICT_VERSION,_,{shareKey:l,requiredVersion:d});throw k({remote:u.from,error:$}),$}console.warn(`[fulgurjs:MFU-010] ${_}`)}}else if(m=[...g].sort(O).pop(),!m){if(t.strictVersion){let u=new E(S.SHARE_STRICT_VERSION,`no satisfying version for "${l}" (required "${d}") in share scope "${r}"`);throw k({remote:l,error:u}),u}if(t.fallback)return t.fallback();let c=new E(S.SHARE_NOT_AVAILABLE,`shared "${l}" (${d??"any"}) unavailable in scope "${r}" (no local fallback)`,{shareKey:l,requiredVersion:d});throw k({remote:l,error:c}),c}let R=a[m];if(w.resolveShare){let c=await w.resolveShare({shareKey:l,shareScope:r,requiredVersion:d,picked:R,available:Object.values(a)});c&&(R=c)}return R.loaded=!0,R.get()}function Q(e){try{let t=new URL(e,typeof location<"u"?location.href:"http://f.invalid");return t.protocol+"//"+t.host+t.pathname}catch{return String(e).replace(/[?#].*$/,"")}}function C(e,t,r){return new Promise((l,h)=>{let a=setTimeout(()=>h(new Error(`timeout after ${t}ms: ${r}`)),t);e.then(p=>{clearTimeout(a),l(p)},p=>{clearTimeout(a),h(p)})})}let ee=e=>new Promise(t=>setTimeout(t,e));function A(e,t){if(!e||typeof e.get!="function")throw new Error(`remoteEntry of "${t.name}" does not export a container interface (get/init)`);if(e.name&&t.name&&e.name!==t.name){let r=`remoteEntry self-reported name "${e.name}" mismatches configured name "${t.name}"`;if(t.promise)console.warn(`[fulgurjs] ${r} (promise-based remote, continuing)`);else throw Object.assign(new Error(r),{code:S.REMOTE_NAME_MISMATCH})}}async function D(e,t){let r=t.entryInflight.get(e),l=r??import(e);return r||(t.entryInflight.set(e,l),l.catch(()=>t.entryInflight.delete(e))),C(l,t.timeout??U,`load remoteEntry ${e}`)}async function V(e,t){let r=e.shareScope||"default";if(e.container){let a=b.get(e.container);if(a&&a!==r)throw new E(S.CONTAINER_REINIT_CONFLICT,`container "${e.name}" already initialized with share scope "${a}", cannot re-init with "${r}"`);return e.container}if(e.containerPromise)return e.containerPromise;let l=e.breakerState;if(l.openUntil>Date.now()){let a=new E(S.REMOTE_LOAD_FAILED,`circuit breaker open for remote "${e.name}" until ${new Date(l.openUntil).toISOString()}`,{remote:e.name});throw k({remote:e.name,error:a}),a}e.state="loading",e.debug.status="loading";let h=(async()=>{let a=[];if(e.promise)a.push(async()=>{let c=await C(e.promise(),e.timeout??U,`resolve promise remote "${e.name}"`),u=typeof c=="string"?await D(c,e):c;return A(u,e),u});else for(let c of[e.entry,...e.fallback??[]])a.push(async()=>{let u=await D(c,e);return A(u,e),u});let p,d,g=!1,m=t?.retries??e.retries??z;for(let c of a){for(let u=0;u<=m;u++){let _=performance.now();try{p=await c(),e.lastLoadMs=Math.round(performance.now()-_),e.debug.lastLoadMs=e.lastLoadMs,g=!0;break}catch($){if(d=$,$?.code)throw $;u<m&&await ee(Math.min(he,200*2**u)*(1-ye*(1-2*Math.random())))}}if(g)break}if(!g||!p){let c=Q(e.entry),u=[];throw/^https?:\\/\\//.test(e.entry)&&typeof location<"u"?(u.push(`1. is the remote dev server running? open ${c} in a browser \\u2014 it must return JS, not HTML`),u.push("2. is the URL correct in federation({ remotes })? dev/prod entries can differ"),u.push("3. CORS: the remote dev server must allow cross-origin requests (check its server.cors)")):(u.push(`1. is the remote deployed? open ${c} in a browser \\u2014 it must return JS`),u.push("2. NGINX/CDN routing: the entry path must serve the remoteEntry JS (check try_files)")),new E(S.REMOTE_LOAD_FAILED,`failed to load remote "${e.name}" from ${c}: ${String(d?.message??d)}\n`+u.join(`\n`),{remote:e.name})}A(p,e);let R=b.get(p);if(R&&R!==r)throw new E(S.CONTAINER_REINIT_CONFLICT,`container "${e.name}" already initialized with share scope "${R}", cannot re-init with "${r}"`);return typeof p.init=="function"&&await p.init(o),b.set(p,r),e.container=p,e.state="loaded",e.debug.status="loaded",l.fails=0,p})();e.containerPromise=h;try{return await h}catch(a){if(e.containerPromise=void 0,e.state="failed",e.debug.status="failed",e.debug.error=String(a?.message??a),l.fails+=1,l.fails>=e.breakerThreshold&&(l.openUntil=Date.now()+e.breakerResetMs,l.fails=0),a instanceof E)throw k({remote:e.name,error:a}),a;if(a?.code)throw k({remote:e.name,error:a}),a;let p=new E(S.REMOTE_LOAD_FAILED,String(a?.message??a),{remote:e.name});throw k({remote:e.name,error:p}),p}}function x(e){let t=e.indexOf("/");return t===-1?{remote:e,module:""}:{remote:e.slice(0,t),module:H(e.slice(t+1))}}function H(e){return e?e.startsWith(".")?e:`./${e}`:""}async function re(e,t){let{remote:r,module:l}=x(e);try{w.beforeLoadRemote?.({remote:r,module:l})}catch(g){console.warn("[fulgurjs] beforeLoadRemote hook error (ignored):",g)}let h=i.get(r);if(!h)throw new E(S.REMOTE_UNKNOWN,`unknown remote "${r}". Register it via federation({ remotes }) or registerRemote().`,{remote:r});let a;try{let g=l&&h.manifestUrl?K(e):Promise.resolve();[a]=await Promise.all([V(h,{retries:t?.retries}),g])}catch(g){if(t?.fallbackModule)return console.error(`[fulgurjs] loadRemote("${e}") failed; returning fallbackModule (\\u663E\\u5F0F\\u964D\\u7EA7\\uFF0C\\u9519\\u8BEF\\u5DF2\\u900F\\u51FA)`,g),k({remote:r,error:g}),await t.fallbackModule();throw g}if(!l)return a;let p=`${r}@${h.shareScope||"default"}#${l}`;n.has(p)||n.set(p,a.get(l).catch(g=>{throw n.delete(p),g instanceof E||g?.code?g:new E(S.REMOTE_LOAD_FAILED,`failed to load module "${l}" from remote "${r}": ${String(g?.message??g)}`,{remote:r,module:l})}));let d;try{d=await n.get(p)}catch(g){if(t?.fallbackModule)return console.error(`[fulgurjs] loadRemote("${e}") failed; returning fallbackModule (\\u663E\\u5F0F\\u964D\\u7EA7\\uFF0C\\u9519\\u8BEF\\u5DF2\\u900F\\u51FA)`,g),k({remote:r,error:g}),await t.fallbackModule();throw g}try{w.afterLoadRemote?.({remote:r,module:l,module_ns:d})}catch(g){console.warn("[fulgurjs] afterLoadRemote hook error (ignored):",g)}if(d&&typeof d=="object"&&Object.keys(d).length===0){let g=new E(S.EMPTY_EXPORTS,`no exports: ${l} @ ${r}`,{remote:r,module:l});k({remote:r,error:g}),console.error(`[fulgurjs:MFU-009] ${g.message}`)}return d}function te(e){let t=i.get(e);if(!t)throw new E(S.REMOTE_UNKNOWN,`unknown remote "${e}"`,{remote:e});return V(t)}async function K(e,t={}){let{remote:r,module:l}=x(e),h=i.get(r);if(!h)throw new E(S.REMOTE_UNKNOWN,`unknown remote "${r}"`,{remote:r});let a=t.mode??"preload",p=(m,R)=>{if(m.sheet)return Promise.resolve();let c=y.get(m);if(c)return c;let u=new Promise(_=>{let $=()=>{m.removeEventListener("load",$),m.removeEventListener("error",j),_()},j=()=>{k({remote:r,error:new E(S.PRELOAD_FAILED,`failed to load remote stylesheet ${R}`,{remote:r})}),$()};m.addEventListener("load",$,{once:!0}),m.addEventListener("error",j,{once:!0}),m.sheet&&$()});return y.set(m,u),u},d=(m,R)=>{if(typeof document>"u")return Promise.resolve();let c=document.querySelector(`link[href="${m}"]`);if(c)return R==="style"&&a==="preload"?y.get(c)??Promise.resolve():Promise.resolve();let u=document.createElement("link");u.rel=R==="style"?"stylesheet":"modulepreload",u.href=m,a==="prefetch"&&(u.fetchPriority="low");let _=R==="style"?p(u,m):Promise.resolve();return document.head.appendChild(u),R==="style"&&a==="preload"?_:Promise.resolve()},g=m=>{let R=typeof document<"u"?document.baseURI:void 0,c=new URL(h.entry,R||"http://fulgurjs.invalid/");return!c.pathname.endsWith("/")&&!c.pathname.split("/").pop().includes(".")&&(c.pathname+="/"),new URL(m,c).href};try{if(h.manifestUrl){let m=f.get(h.manifestUrl);m||(m=fetch(h.manifestUrl,{cache:"no-cache",signal:AbortSignal.timeout(8e3)}).then(c=>c.ok?c.json():void 0),f.set(h.manifestUrl,m),m.then(c=>{c||f.delete(h.manifestUrl)},()=>f.delete(h.manifestUrl)));let R=await m;if(R){let c=R.schemaVersion;if(typeof c=="number"&&(!Number.isInteger(c)||c>1)){k({remote:r,error:new E(S.PRELOAD_FAILED,`unsupported manifest schemaVersion ${String(c)} (expected 1)`,{remote:r})}),await d(h.entry,"modulepreload");return}await d(h.entry,"modulepreload");let u=R.exposes,_=Array.isArray(u)?u.filter(v=>v&&typeof v=="object").map(v=>[String(v.name??""),v]):u&&typeof u=="object"?Object.entries(u):[],$=l?_.filter(([v,L])=>H(String(L?.name??v))===l):_,j=[];for(let[,v]of $)if(typeof v?.file=="string"&&await d(g(v.file),"modulepreload"),Array.isArray(v?.css))for(let L of v.css){if(typeof L!="string")continue;let ne=d(g(L),"style");a==="preload"&&j.push(ne)}await Promise.all(j);return}}await d(h.entry,"modulepreload")}catch(m){k({remote:r,error:new E(S.PRELOAD_FAILED,String(m?.message??m),{remote:r})})}}return typeof window>"u"||(window.__FULGURJS_SCOPE__=o,window.__FULGURJS_INFO__={get remotes(){let e={};for(let[t,r]of i)e[t]={...r.debug,entry:r.entry};return e},errors:[]}),{shareScopeMap:o,initSharing:B,registerShare:J,registerRemotes:F,registerRemote:X,registerPlugins:Y,loadShare:Z,loadRemote:re,getContainer:te,preloadRemote:K,parseSpec:x}}var W=globalThis,M=W.__FULGURJS_RUNTIME__??Re();W.__FULGURJS_RUNTIME__=M;try{Object.freeze(M)}catch{}var ve=q;function _e(){return M}var Oe=M.initSharing,je=M.registerShare,Te=M.registerRemotes,Le=M.registerRemote,Ie=M.registerPlugins,Pe=M.loadShare,Ne=M.loadRemote,Ae=M.getContainer,xe=M.preloadRemote,Ue=M.parseSpec,Fe=M.shareScopeMap;function Ce(o){if(o&&typeof o=="object"&&"default"in o){let i=o.default;return i!==void 0?i:o}return o}var De=M;export{De as default,Ae as getContainer,_e as getRuntime,Oe as initSharing,Ne as loadRemote,Pe as loadShare,Ue as parseSpec,xe as preloadRemote,Ie as registerPlugins,Le as registerRemote,Te as registerRemotes,je as registerShare,M as runtime,Fe as shareScopeMap,Ce as unwrapDefault,ve as version};\n';
1753
+ var runtime_code_gen_default = 'var pe=/^v?(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?(?:-((?:[0-9A-Za-z-]+)(?:\\.[0-9A-Za-z-]+)*))?(?:\\+[0-9A-Za-z.-]+)?$/;function L(s){let c=pe.exec(String(s).trim());return c?{major:Number(c[1]),minor:Number(c[2]??0),patch:Number(c[3]??0),pre:c[4]?c[4].split("."):[]}:null}function de(s,c){if(s.length===0&&c.length===0)return 0;if(s.length===0)return 1;if(c.length===0)return-1;let l=Math.max(s.length,c.length);for(let n=0;n<l;n++){let g=s[n],y=c[n];if(g===void 0)return-1;if(y===void 0)return 1;let w=/^\\d+$/.test(g),b=/^\\d+$/.test(y);if(w&&b){let T=Number(g)-Number(y);if(T!==0)return T}else{if(w!==b)return w?-1:1;if(g!==y)return g<y?-1:1}}return 0}function x(s,c){let l=L(s),n=L(c);return!l||!n?s<c?-1:s>c?1:0:l.major!==n.major?l.major-n.major:l.minor!==n.minor?l.minor-n.minor:l.patch!==n.patch?l.patch-n.patch:de(l.pre,n.pre)}var ge=/^[a-z]+[+:-]/i;function k(s,c){if(c===!1||c==null||c==="")return!0;let l=String(c).trim();return!l||l==="*"||l==="latest"||ge.test(l)?!0:l.split("||").some(n=>he(s,n.trim()))}function he(s,c){if(!c||c==="*")return!L(s)?.pre.length;let l=c.split(/\\s+-\\s+/);if(l.length===2){let y=l[0].trim(),w=l[1].trim();return!(!k(s,`>=${y}`)||!k(s,`<=${w}`))}let n=L(s);if(!n)return!1;let g=ye(c);if(g===null)return!0;for(let y of g)if(!be(n,s,y))return!1;return!(n.pre.length>0&&!g.some(y=>y.ver.pre.length>0)&&!g.some(w=>w.ver.major===n.major&&w.ver.minor===n.minor&&w.ver.patch===n.patch))}function ye(s){let c=[],l=s.trim().split(/\\s+/).filter(Boolean);if(l.length===0)return null;for(let n of l){let g=/^(>=|<=|>|<|=|\\^|~)?(.*)$/.exec(n);if(!g)return null;let y=g[1],w=g[2],b=Se(y,w);if(b===null)return null;c.push(...b)}return c}function Se(s,c){let l=Ee(c);if(!l)return null;let{ver:n,partial:g}=l;switch(s){case"^":{let y=Re(n);return y?[{op:">=",ver:n},{op:"<",ver:y}]:null}case"~":{let y=g>=2?{major:n.major,minor:n.minor+1,patch:0,pre:[]}:{major:n.major+1,minor:0,patch:0,pre:[]};return[{op:">=",ver:n},{op:"<",ver:y}]}case">=":return[{op:">=",ver:n}];case">":return g===1?[{op:">=",ver:{major:n.major+1,minor:0,patch:0,pre:[]}}]:g===2?[{op:">=",ver:{major:n.major,minor:n.minor+1,patch:0,pre:[]}}]:[{op:">",ver:n}];case"<":return g===1?[{op:"<",ver:{major:n.major,minor:0,patch:0,pre:[]}}]:g===2?[{op:"<",ver:{major:n.major,minor:n.minor,patch:0,pre:[]}}]:[{op:"<",ver:n}];case"<=":return[{op:"<=",ver:n}];case"=":case void 0:return g===1?[{op:">=",ver:n},{op:"<",ver:{major:n.major+1,minor:0,patch:0,pre:[]}}]:g===2?[{op:">=",ver:n},{op:"<",ver:{major:n.major,minor:n.minor+1,patch:0,pre:[]}}]:[{op:"=",ver:n}];default:return null}}function Re(s){return s.major>0?{major:s.major+1,minor:0,patch:0,pre:[]}:s.minor>0?{major:0,minor:s.minor+1,patch:0,pre:[]}:{major:0,minor:0,patch:s.patch+1,pre:[]}}function Ee(s){let c=s.replace(/^v/,"").trim();if(!c||c==="*"||c==="x"||c==="X")return{ver:{major:0,minor:0,patch:0,pre:[]},partial:0};let l=c.split("."),n=[],g=0;for(let b of l.slice(0,3))if(/^\\d+$/.test(b))n.push(Number(b)),g++;else{if(b==="x"||b==="X"||b==="*")break;break}let y=c.split("-"),w=y.length>1?y.slice(1).join("-").split("+")[0].split("."):[];return g===0&&w.length===0?{ver:{major:0,minor:0,patch:0,pre:[]},partial:0}:{ver:{major:n[0]??0,minor:n[1]??0,patch:n[2]??0,pre:w},partial:g}}function we(s,c){switch(c){case">=":return s>=0;case">":return s>0;case"<":return s<0;case"<=":return s<=0;case"=":return s===0}}function be(s,c,l){let n=`${s.major}.${s.minor}.${s.patch}`+(s.pre.length?`-${s.pre.join(".")}`:"");if(l.upper)return!(!(x(n,`${l.ver.major}.${l.ver.minor}.${l.ver.patch}`+(l.ver.pre.length?`-${l.ver.pre.join(".")}`:""))>=0)||!(x(n,`${l.upper.major}.${l.upper.minor}.${l.upper.patch}`)<0));let g=x(n,`${l.ver.major}.${l.ver.minor}.${l.ver.patch}`+(l.ver.pre.length?`-${l.ver.pre.join(".")}`:"")),y=we(g,l.op);return l.ver.pre.length>0&&s.pre.length===0&&(l.op===">"||l.op==="<")?!1:y}var S=class extends Error{code;details;constructor(c,l,n){super(`[fulgurjs:${c}] ${l}`),this.name="FgError",this.code=c,this.details=n}},R={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",SETUP_INVALID_EXPORT:"MFU-011",SETUP_RUN_FAILED:"MFU-012",SETUP_SESSION_KEY_MISSING:"MFU-013",SETUP_RECURSION:"MFU-014"};var J="4.1.0";var Pe="__fulgurjsSetup",_e="__FULGURJS_APP_CONFIG__",D=15e3,B=2,ve=5,Me=3e4,$e=4e3,xe=.2;function Ie(){let s=Object.create(null),c=new Map,l=[],n=new Map,g=new Map,y=new WeakMap,w=new WeakMap,b={},T=()=>{for(let e of l)try{e.init?.(b)}catch(r){console.warn("[fulgurjs] runtimePlugin init failed:",e.name,r)}},U=new Map,j,Y=e=>{let r=U.get(e);return r||U.set(e,r={}),r},V=()=>globalThis[_e]??{};async function K(e,r,t,o){let a=u=>u instanceof S?u:new S(R.SETUP_RUN_FAILED,`${o} of "${e}" threw: ${String(u?.message??u)}\n \\u4FEE\\u6CD5: \\u4FEE\\u590D\\u8BE5 ${o} \\u7684\\u521D\\u59CB\\u5316\\u903B\\u8F91\\u540E\\u91CD\\u65B0\\u52A0\\u8F7D\\uFF08\\u5931\\u8D25\\u7684\\u521D\\u59CB\\u5316\\u7F13\\u5B58\\u5DF2\\u6E05\\u9664\\uFF0C\\u53EF\\u76F4\\u63A5\\u91CD\\u8BD5\\uFF09`,{remote:e,phase:o});j=e;let i;try{i=r(t)}catch(u){throw a(u)}finally{j=void 0}try{await i}catch(u){throw a(u)}}async function Z(e,r,t,o){e.debug.setup="pending";try{if(e.manifestUrl)try{await F(`${e.name}/${t}`)}catch{}let a=await r.get(t),i=a?.default;if(typeof i!="function")throw new S(R.SETUP_INVALID_EXPORT,`setup module "${t}" of "${e.name}": default export is ${a==null?String(a):typeof i}, expected a function\n expected: export default async function setup(context: RemoteSetupContext) { ... }\n \\u4FEE\\u6CD5: \\u5728 federation({ setup }) \\u6307\\u5411\\u7684\\u6587\\u4EF6\\u8865\\u9ED8\\u8BA4\\u5BFC\\u51FA\\u51FD\\u6570\\uFF08\\u5177\\u540D onSession \\u53EF\\u9009\\uFF1B\\u5176\\u4ED6\\u5BFC\\u51FA\\u4E0D\\u4F5C\\u4E3A\\u751F\\u547D\\u5468\\u671F\\u5165\\u53E3\\uFF09`,{remote:e.name,module:t});if(a.onSession!==void 0&&typeof a.onSession!="function")throw new S(R.SETUP_INVALID_EXPORT,`setup module "${t}" of "${e.name}": export "onSession" is ${typeof a.onSession}, expected a function\n \\u4FEE\\u6CD5: \\u5C06 onSession \\u4FEE\\u6B63\\u4E3A\\u51FD\\u6570\\u5BFC\\u51FA\\uFF0C\\u6216\\u5220\\u9664\\u8BE5\\u5177\\u540D\\u5BFC\\u51FA\\uFF08\\u5176\\u4ED6\\u5BFC\\u51FA\\u540D\\u4E0D\\u4F5C\\u4E3A\\u751F\\u547D\\u5468\\u671F\\u5165\\u53E3\\uFF09`,{remote:e.name,module:t});o.setupExports=a,await K(e.name,i,{appContext:V(),signal:(o.controller??=new AbortController).signal},"setup"),e.debug.setup="ready"}catch(a){throw e.debug.setup="failed",o.setupExports=void 0,a}}async function Q(e,r,t){let o=V(),a=o?.sessionKey;if(typeof a!="string"||a==="")throw new S(R.SETUP_SESSION_KEY_MISSING,`remote "${e.name}" declares onSession but AppContext.sessionKey is ${a===void 0?"missing":JSON.stringify(a)}\n expected: \\u5BBF\\u4E3B\\u767B\\u5F55\\u540E provideAppContext({ ..., sessionKey: \'<\\u975E\\u654F\\u611F\\u767B\\u5F55\\u4EE3\\u6B21 ID>\' })\n \\u4FEE\\u6CD5: \\u5BBF\\u4E3B\\u767B\\u5F55\\u6D41\\u7A0B\\u6BCF\\u6B21\\u6210\\u529F\\u767B\\u5F55/\\u91CD\\u767B\\u751F\\u6210\\u65B0\\u4EE3\\u6B21 ID\\uFF08\\u7981\\u6B62\\u7528 token \\u5145\\u5F53\\uFF09\\uFF0C\\u5E76\\u5728 loadRemote \\u524D\\u63D0\\u4F9B`,{remote:e.name});if(r.sessionPromise&&r.sessionKey===a)return r.sessionPromise;r.controller?.abort();let i=new AbortController;r.controller=i,r.sessionKey=a;let u=r.sessionPromise?r.sessionPromise.catch(()=>{}):Promise.resolve(),p=(async()=>{await u,!i.signal.aborted&&await K(e.name,t,{appContext:o,sessionKey:a,signal:i.signal},"onSession")})();return r.sessionPromise=p,p.catch(()=>{r.sessionKey===a&&(r.sessionKey=void 0,r.sessionPromise=void 0)}),p}async function ee(e,r){let t=r?.[Pe];if(typeof t!="string"||t==="")return;let o=Y(e.name);o.setupPromise||(o.setupPromise=Z(e,r,t,o).catch(i=>{throw o.setupPromise=void 0,i})),await o.setupPromise;let a=o.setupExports?.onSession;typeof a=="function"&&await Q(e,o,a)}function re(){for(let e of U.values()){try{e.controller?.abort()}catch{}e.sessionKey=void 0,e.sessionPromise=void 0}}let A=e=>s[e]??=Object.create(null);function _(e){try{b.onRemoteError?.(e)}catch{}typeof window<"u"&&window.dispatchEvent(new CustomEvent("fulgurjs:error",{detail:e}))}function te(e="default"){return A(e),s}function ne(e,r,t,o,a={}){let i=A(e||"default"),u=Object.hasOwn(i,r)?i[r]:void 0,p=u&&typeof u=="object"?u:void 0;p||(p=Object.create(null),i[r]=p),!(Object.hasOwn(p,t)&&p[t])&&(p[t]={version:t,get:o,from:a.from??"unknown",eager:!!a.eager,loaded:!!a.loaded})}function oe(e){let r=(t,o,a)=>{if(t===void 0)return;if(!(typeof t=="number"&&(a?Number.isInteger(t)&&t>=0&&t<=10:Number.isFinite(t)&&t>0)))throw new Error(`[fulgurjs] registerRemote("${e.name}"): ${o} must be a ${a?"integer 0..10":"finite positive number"}, got ${String(t)}`)};r(e.timeout,"timeout"),r(e.retries,"retries",!0),e.breaker&&(r(e.breaker.threshold,"breaker.threshold"),r(e.breaker.resetMs,"breaker.resetMs"))}function H(e){for(let r of e){oe(r);let t=c.get(r.name);c.set(r.name,{timeout:D,retries:B,...t,...r,breakerThreshold:r.breaker?.threshold??t?.breakerThreshold??ve,breakerResetMs:r.breaker?.resetMs??t?.breakerResetMs??Me,state:t?.state??"idle",breakerState:t?.breakerState??{fails:0,openUntil:0},entryInflight:t?.entryInflight??new Map,debug:t?.debug??{entry:r.entry,status:"idle",setup:"none"}})}}function ie(e){H([e])}function se(e){l.push(...e),T()}async function ae(e,r={}){let t=r.shareScope||"default",o=r.shareKey||e,i=A(t)[o]||{},u=Object.keys(i),p=r.requiredVersion,h=u.filter(f=>p===void 0||p===!1||k(f,p)),d;if(r.singleton&&u.length>0){let f=u.filter(m=>i[m].loaded);if(d=[...f.length?f:u].sort(x).pop(),u.length>1||!h.includes(d)){let m=i[d],$=`singleton skew "${o}": req "${p??"any"}" use ${d} from ${m.from}`;if(r.strictVersion){let v=new S(R.SHARE_STRICT_VERSION,$,{shareKey:o,requiredVersion:p});throw _({remote:m.from,error:v}),v}console.warn(`[fulgurjs:MFU-010] ${$}`)}}else if(d=[...h].sort(x).pop(),!d){if(r.strictVersion){let m=new S(R.SHARE_STRICT_VERSION,`no satisfying version for "${o}" (required "${p}") in share scope "${t}"`);throw _({remote:o,error:m}),m}if(r.fallback)return r.fallback();let f=new S(R.SHARE_NOT_AVAILABLE,`shared "${o}" (${p??"any"}) unavailable in scope "${t}" (no local fallback)`,{shareKey:o,requiredVersion:p});throw _({remote:o,error:f}),f}let E=i[d];if(b.resolveShare){let f=await b.resolveShare({shareKey:o,shareScope:t,requiredVersion:p,picked:E,available:Object.values(i)});f&&(E=f)}return E.loaded=!0,E.get()}function ce(e){try{let r=new URL(e,typeof location<"u"?location.href:"http://f.invalid");return r.protocol+"//"+r.host+r.pathname}catch{return String(e).replace(/[?#].*$/,"")}}function q(e,r,t){return new Promise((o,a)=>{let i=setTimeout(()=>a(new Error(`timeout after ${r}ms: ${t}`)),r);e.then(u=>{clearTimeout(i),o(u)},u=>{clearTimeout(i),a(u)})})}let le=e=>new Promise(r=>setTimeout(r,e));function N(e,r){if(!e||typeof e.get!="function")throw new Error(`remoteEntry of "${r.name}" does not export a container interface (get/init)`);if(e.name&&r.name&&e.name!==r.name){let t=`remoteEntry self-reported name "${e.name}" mismatches configured name "${r.name}"`;if(r.promise)console.warn(`[fulgurjs] ${t} (promise-based remote, continuing)`);else throw Object.assign(new Error(t),{code:R.REMOTE_NAME_MISMATCH})}}async function G(e,r){let t=r.entryInflight.get(e),o=t??import(e);return t||(r.entryInflight.set(e,o),o.catch(()=>r.entryInflight.delete(e))),q(o,r.timeout??D,`load remoteEntry ${e}`)}async function X(e,r){let t=e.shareScope||"default";if(e.container){let i=w.get(e.container);if(i&&i!==t)throw new S(R.CONTAINER_REINIT_CONFLICT,`container "${e.name}" already initialized with share scope "${i}", cannot re-init with "${t}"`);return e.container}if(e.containerPromise)return e.containerPromise;let o=e.breakerState;if(o.openUntil>Date.now()){let i=new S(R.REMOTE_LOAD_FAILED,`circuit breaker open for remote "${e.name}" until ${new Date(o.openUntil).toISOString()}`,{remote:e.name});throw _({remote:e.name,error:i}),i}e.state="loading",e.debug.status="loading";let a=(async()=>{let i=[];if(e.promise)i.push(async()=>{let f=await q(e.promise(),e.timeout??D,`resolve promise remote "${e.name}"`),m=typeof f=="string"?await G(f,e):f;return N(m,e),m});else for(let f of[e.entry,...e.fallback??[]])i.push(async()=>{let m=await G(f,e);return N(m,e),m});let u,p,h=!1,d=r?.retries??e.retries??B;for(let f of i){for(let m=0;m<=d;m++){let $=performance.now();try{u=await f(),e.lastLoadMs=Math.round(performance.now()-$),e.debug.lastLoadMs=e.lastLoadMs,h=!0;break}catch(v){if(p=v,v?.code)throw v;m<d&&await le(Math.min($e,200*2**m)*(1-xe*(1-2*Math.random())))}}if(h)break}if(!h||!u){let f=ce(e.entry),m=[];throw/^https?:\\/\\//.test(e.entry)&&typeof location<"u"?(m.push(`1. is the remote dev server running? open ${f} in a browser \\u2014 it must return JS, not HTML`),m.push("2. is the URL correct in federation({ remotes })? dev/prod entries can differ"),m.push("3. CORS: the remote dev server must allow cross-origin requests (check its server.cors)")):(m.push(`1. is the remote deployed? open ${f} in a browser \\u2014 it must return JS`),m.push("2. NGINX/CDN routing: the entry path must serve the remoteEntry JS (check try_files)")),new S(R.REMOTE_LOAD_FAILED,`failed to load remote "${e.name}" from ${f}: ${String(p?.message??p)}\n`+m.join(`\n`),{remote:e.name})}N(u,e);let E=w.get(u);if(E&&E!==t)throw new S(R.CONTAINER_REINIT_CONFLICT,`container "${e.name}" already initialized with share scope "${E}", cannot re-init with "${t}"`);return typeof u.init=="function"&&await u.init(s),w.set(u,t),e.container=u,e.state="loaded",e.debug.status="loaded",o.fails=0,u})();e.containerPromise=a;try{return await a}catch(i){if(e.containerPromise=void 0,e.state="failed",e.debug.status="failed",e.debug.error=String(i?.message??i),o.fails+=1,o.fails>=e.breakerThreshold&&(o.openUntil=Date.now()+e.breakerResetMs,o.fails=0),i instanceof S)throw _({remote:e.name,error:i}),i;if(i?.code)throw _({remote:e.name,error:i}),i;let u=new S(R.REMOTE_LOAD_FAILED,String(i?.message??i),{remote:e.name});throw _({remote:e.name,error:u}),u}}function C(e){let r=e.indexOf("/");return r===-1?{remote:e,module:""}:{remote:e.slice(0,r),module:z(e.slice(r+1))}}function z(e){return e?e.startsWith(".")?e:`./${e}`:""}async function ue(e,r){let{remote:t,module:o}=C(e);if(o&&j===t)throw new S(R.SETUP_RECURSION,`loadRemote("${e}") re-entered from setup/onSession of "${t}" \\u2014 the initialization promise would await itself (deadlock)\n \\u4FEE\\u6CD5: setup/onSession \\u5185\\u4E0D loadRemote \\u540C\\u4E00\\u8FDC\\u7A0B\\u7684\\u6A21\\u5757\\uFF1B\\u9700\\u8981\\u7684\\u4E1A\\u52A1\\u6A21\\u5757\\u6539\\u4E3A\\u5728\\u9875\\u9762\\u7EC4\\u4EF6\\u5185\\u52A0\\u8F7D\\uFF0C\\u6216\\u7ECF context \\u901A\\u9053\\u89E3\\u8026`,{remote:t});try{b.beforeLoadRemote?.({remote:t,module:o})}catch(h){console.warn("[fulgurjs] beforeLoadRemote hook error (ignored):",h)}let a=c.get(t);if(!a)throw new S(R.REMOTE_UNKNOWN,`unknown remote "${t}". Register it via federation({ remotes }) or registerRemote().`,{remote:t});let i;try{let h=o&&a.manifestUrl?F(e):Promise.resolve();[i]=await Promise.all([X(a,{retries:r?.retries}),h])}catch(h){if(r?.fallbackModule)return console.error(`[fulgurjs] loadRemote("${e}") failed; returning fallbackModule (\\u663E\\u5F0F\\u964D\\u7EA7\\uFF0C\\u9519\\u8BEF\\u5DF2\\u900F\\u51FA)`,h),_({remote:t,error:h}),await r.fallbackModule();throw h}if(!o)return i;await ee(a,i);let u=`${t}@${a.shareScope||"default"}#${o}`;n.has(u)||n.set(u,i.get(o).catch(h=>{throw n.delete(u),h instanceof S||h?.code?h:new S(R.REMOTE_LOAD_FAILED,`failed to load module "${o}" from remote "${t}": ${String(h?.message??h)}`,{remote:t,module:o})}));let p;try{p=await n.get(u)}catch(h){if(r?.fallbackModule)return console.error(`[fulgurjs] loadRemote("${e}") failed; returning fallbackModule (\\u663E\\u5F0F\\u964D\\u7EA7\\uFF0C\\u9519\\u8BEF\\u5DF2\\u900F\\u51FA)`,h),_({remote:t,error:h}),await r.fallbackModule();throw h}try{b.afterLoadRemote?.({remote:t,module:o,module_ns:p})}catch(h){console.warn("[fulgurjs] afterLoadRemote hook error (ignored):",h)}if(p&&typeof p=="object"&&Object.keys(p).length===0){let h=new S(R.EMPTY_EXPORTS,`no exports: ${o} @ ${t}`,{remote:t,module:o});_({remote:t,error:h}),console.error(`[fulgurjs:MFU-009] ${h.message}`)}return p}function fe(e){let r=c.get(e);if(!r)throw new S(R.REMOTE_UNKNOWN,`unknown remote "${e}"`,{remote:e});return X(r)}async function F(e,r={}){let{remote:t,module:o}=C(e),a=c.get(t);if(!a)throw new S(R.REMOTE_UNKNOWN,`unknown remote "${t}"`,{remote:t});let i=r.mode??"preload",u=(d,E)=>{if(d.sheet)return Promise.resolve();let f=y.get(d);if(f)return f;let m=new Promise($=>{let v=()=>{d.removeEventListener("load",v),d.removeEventListener("error",I),$()},I=()=>{_({remote:t,error:new S(R.PRELOAD_FAILED,`failed to load remote stylesheet ${E}`,{remote:t})}),v()};d.addEventListener("load",v,{once:!0}),d.addEventListener("error",I,{once:!0}),d.sheet&&v()});return y.set(d,m),m},p=(d,E)=>{if(typeof document>"u")return Promise.resolve();let f=document.querySelector(`link[href="${d}"]`);if(f)return E==="style"&&i==="preload"?y.get(f)??Promise.resolve():Promise.resolve();let m=document.createElement("link");m.rel=E==="style"?"stylesheet":"modulepreload",m.href=d,i==="prefetch"&&(m.fetchPriority="low");let $=E==="style"?u(m,d):Promise.resolve();return document.head.appendChild(m),E==="style"&&i==="preload"?$:Promise.resolve()},h=d=>{let E=typeof document<"u"?document.baseURI:void 0,f=new URL(a.entry,E||"http://fulgurjs.invalid/");return!f.pathname.endsWith("/")&&!f.pathname.split("/").pop().includes(".")&&(f.pathname+="/"),new URL(d,f).href};try{if(a.manifestUrl){let d=g.get(a.manifestUrl);d||(d=fetch(a.manifestUrl,{cache:"no-cache",signal:AbortSignal.timeout(8e3)}).then(f=>f.ok?f.json():void 0),g.set(a.manifestUrl,d),d.then(f=>{f||g.delete(a.manifestUrl)},()=>g.delete(a.manifestUrl)));let E=await d;if(E){let f=E.schemaVersion;if(typeof f=="number"&&(!Number.isInteger(f)||f>1)){_({remote:t,error:new S(R.PRELOAD_FAILED,`unsupported manifest schemaVersion ${String(f)} (expected 1)`,{remote:t})}),await p(a.entry,"modulepreload");return}await p(a.entry,"modulepreload");let m=E.exposes,$=Array.isArray(m)?m.filter(M=>M&&typeof M=="object").map(M=>[String(M.name??""),M]):m&&typeof m=="object"?Object.entries(m):[],v=o?$.filter(([M,O])=>z(String(O?.name??M))===o):$,I=[];for(let[,M]of v)if(typeof M?.file=="string"&&await p(h(M.file),"modulepreload"),Array.isArray(M?.css))for(let O of M.css){if(typeof O!="string")continue;let me=p(h(O),"style");i==="preload"&&I.push(me)}await Promise.all(I);return}}await p(a.entry,"modulepreload")}catch(d){_({remote:t,error:new S(R.PRELOAD_FAILED,String(d?.message??d),{remote:t})})}}return typeof window>"u"||(window.__FULGURJS_SCOPE__=s,window.__FULGURJS_INFO__={get remotes(){let e={};for(let[r,t]of c)e[r]={...t.debug,entry:t.entry};return e},errors:[]}),{shareScopeMap:s,initSharing:te,registerShare:ne,registerRemotes:H,registerRemote:ie,registerPlugins:se,loadShare:ae,loadRemote:ue,getContainer:fe,preloadRemote:F,parseSpec:C,clearSessionState:re}}var W=globalThis,P=W.__FULGURJS_RUNTIME__??Ie();W.__FULGURJS_RUNTIME__=P;try{Object.freeze(P)}catch{}var Ne=J;function Ce(){return P}var Fe=P.initSharing,De=P.registerShare,Ve=P.registerRemotes,Ke=P.registerRemote,He=P.registerPlugins,qe=P.loadShare,Ge=P.loadRemote,Xe=P.getContainer,ze=P.preloadRemote,Je=P.parseSpec,Be=P.clearSessionState,We=P.shareScopeMap;function Ye(s){if(s&&typeof s=="object"&&"default"in s){let c=s.default;return c!==void 0?c:s}return s}var Ze=P;export{Be as clearSessionState,Ze as default,Xe as getContainer,Ce as getRuntime,Fe as initSharing,Ge as loadRemote,qe as loadShare,Je as parseSpec,ze as preloadRemote,He as registerPlugins,Ke as registerRemote,Ve as registerRemotes,De as registerShare,P as runtime,We as shareScopeMap,Ye as unwrapDefault,Ne as version};\n';
1703
1754
 
1704
1755
  // src/index.ts
1705
1756
  function readRuntimeCode() {
@@ -0,0 +1,100 @@
1
+ interface SharedHint {
2
+ /** 放入共享作用域的本地模块;false 表示不提供本地副本 */
3
+ import?: string | false;
4
+ /** 用于从 package.json 推断 requiredVersion 的包名 */
5
+ packageName?: string;
6
+ /** 期望版本(完整 semver 语法 / false 接受任意) */
7
+ requiredVersion?: string | false;
8
+ /** 只允许单实例 */
9
+ singleton?: boolean;
10
+ /** 版本无效时抛运行时错误(默认:有本地副本且非 singleton 时为 true,对齐 webpack) */
11
+ strictVersion?: boolean;
12
+ /** 在共享作用域中的键(导入名与共享名不同时使用) */
13
+ shareKey?: string;
14
+ /** 共享作用域命名空间 */
15
+ shareScope?: string;
16
+ /** 同步提供(打进初始 chunk,总是被下载) */
17
+ eager?: boolean;
18
+ /** 提供版本显式指定 */
19
+ version?: string;
20
+ }
21
+ type SharedConfig = string[] | Record<string, string | SharedHint>;
22
+ interface ExposeHint {
23
+ import: string;
24
+ /** 稳定 chunk 文件名(不写则内部 id,随构建变化) */
25
+ name?: string;
26
+ }
27
+ interface RemoteEntryConfig {
28
+ external?: string;
29
+ shareScope?: string;
30
+ /** dev 专用地址(缺省回落 external) */
31
+ dev?: string;
32
+ /** prod 专用地址(缺省回落 external) */
33
+ prod?: string;
34
+ timeout?: number;
35
+ retries?: number;
36
+ /** 备用 remoteEntry 地址 */
37
+ fallback?: string[];
38
+ breaker?: {
39
+ threshold?: number;
40
+ resetMs?: number;
41
+ };
42
+ }
43
+ interface FederationOptions {
44
+ name: string;
45
+ filename?: string;
46
+ exposes?: Record<string, string | ExposeHint>;
47
+ /**
48
+ * 可选远程初始化入口:相对本应用根目录的 TS/JS 模块路径。
49
+ * 模块须默认导出 `setup(context)`(应用级,容器首次加载业务模块前执行一次),
50
+ * 可选具名导出 `onSession(context)`(会话级,按宿主 AppContext.sessionKey 去重执行)。
51
+ * 缺省时无初始化行为(普通 exposes 语义完全不变)。
52
+ */
53
+ setup?: string;
54
+ remotes?: Record<string, string | RemoteEntryConfig | (() => Promise<any>)>;
55
+ shared?: SharedConfig;
56
+ shareScope?: string;
57
+ /** 仅支持 'module'(ESM);其他值在配置期报 CFG-011(webpack script/var 互操作未实现) */
58
+ remoteType?: 'module';
59
+ library?: {
60
+ type?: string;
61
+ name?: string;
62
+ };
63
+ runtime?: string | false;
64
+ runtimeChunk?: boolean | 'single';
65
+ manifest?: boolean | Record<string, unknown>;
66
+ runtimePlugins?: string[];
67
+ dts?: boolean | {
68
+ dir?: string;
69
+ mode?: 'source' | 'shim';
70
+ };
71
+ /** 接受并恒为 true:TLA 天然异步边界,无需手工 bootstrap(比 webpack 更进一步) */
72
+ automaticAsyncBoundary?: boolean;
73
+ /** 接受并恒为 true:preloadRemote 能力始终可用 */
74
+ dataPrefetch?: boolean;
75
+ /** 接受 no-op:Rollup/Rolldown 原生 tree-shaking 已覆盖 */
76
+ usedExports?: boolean;
77
+ ignoreUnusedSharedExports?: boolean;
78
+ /**
79
+ * dev 下自身源码(含依赖,需配合 optimizeDeps.exclude)是否参与 shared 协商改写。
80
+ * 默认:纯 remote(无 remotes)为 true——被宿主消费的组件需协商到宿主实例;
81
+ * 有 remotes 的宿主为 false——自身 import 即自身 provide,避免巨型工程 TLA/循环依赖风险。
82
+ * 双向联邦(宿主同时 expose 组件给更高层消费)显式设 true。
83
+ */
84
+ devSharedSelf?: boolean;
85
+ /**
86
+ * dev 跨源访问策略(插件端点 /@fulgurjs-entry.js、/@fulgurjs-manifest.json 与 server.cors
87
+ * 共用同一来源)。缺省 = '*'(现状兼容:端点与 server.cors 全放开);'*' = 显式全放开(不告警);
88
+ * 数组 = 来源 allowlist(端点按 Origin 反射匹配,不匹配省略头;server.cors 传 { origin: [...] },
89
+ * 用户显式配置的 server.cors 永远优先)。
90
+ */
91
+ devCorsOrigins?: string[] | '*';
92
+ /**
93
+ * dev manifest 是否携带 fsRoot(remote 根目录本机绝对路径,宿主 dts 类型直连用)。
94
+ * 默认 true(现状兼容);false 时不写入 manifest,宿主 dts 降级为 any 桩并给出提示。
95
+ * fsRoot 是 dev-only 字段,永不进入 prod manifest。
96
+ */
97
+ devFsRoot?: boolean;
98
+ }
99
+
100
+ export type { FederationOptions as F };
@@ -0,0 +1,100 @@
1
+ interface SharedHint {
2
+ /** 放入共享作用域的本地模块;false 表示不提供本地副本 */
3
+ import?: string | false;
4
+ /** 用于从 package.json 推断 requiredVersion 的包名 */
5
+ packageName?: string;
6
+ /** 期望版本(完整 semver 语法 / false 接受任意) */
7
+ requiredVersion?: string | false;
8
+ /** 只允许单实例 */
9
+ singleton?: boolean;
10
+ /** 版本无效时抛运行时错误(默认:有本地副本且非 singleton 时为 true,对齐 webpack) */
11
+ strictVersion?: boolean;
12
+ /** 在共享作用域中的键(导入名与共享名不同时使用) */
13
+ shareKey?: string;
14
+ /** 共享作用域命名空间 */
15
+ shareScope?: string;
16
+ /** 同步提供(打进初始 chunk,总是被下载) */
17
+ eager?: boolean;
18
+ /** 提供版本显式指定 */
19
+ version?: string;
20
+ }
21
+ type SharedConfig = string[] | Record<string, string | SharedHint>;
22
+ interface ExposeHint {
23
+ import: string;
24
+ /** 稳定 chunk 文件名(不写则内部 id,随构建变化) */
25
+ name?: string;
26
+ }
27
+ interface RemoteEntryConfig {
28
+ external?: string;
29
+ shareScope?: string;
30
+ /** dev 专用地址(缺省回落 external) */
31
+ dev?: string;
32
+ /** prod 专用地址(缺省回落 external) */
33
+ prod?: string;
34
+ timeout?: number;
35
+ retries?: number;
36
+ /** 备用 remoteEntry 地址 */
37
+ fallback?: string[];
38
+ breaker?: {
39
+ threshold?: number;
40
+ resetMs?: number;
41
+ };
42
+ }
43
+ interface FederationOptions {
44
+ name: string;
45
+ filename?: string;
46
+ exposes?: Record<string, string | ExposeHint>;
47
+ /**
48
+ * 可选远程初始化入口:相对本应用根目录的 TS/JS 模块路径。
49
+ * 模块须默认导出 `setup(context)`(应用级,容器首次加载业务模块前执行一次),
50
+ * 可选具名导出 `onSession(context)`(会话级,按宿主 AppContext.sessionKey 去重执行)。
51
+ * 缺省时无初始化行为(普通 exposes 语义完全不变)。
52
+ */
53
+ setup?: string;
54
+ remotes?: Record<string, string | RemoteEntryConfig | (() => Promise<any>)>;
55
+ shared?: SharedConfig;
56
+ shareScope?: string;
57
+ /** 仅支持 'module'(ESM);其他值在配置期报 CFG-011(webpack script/var 互操作未实现) */
58
+ remoteType?: 'module';
59
+ library?: {
60
+ type?: string;
61
+ name?: string;
62
+ };
63
+ runtime?: string | false;
64
+ runtimeChunk?: boolean | 'single';
65
+ manifest?: boolean | Record<string, unknown>;
66
+ runtimePlugins?: string[];
67
+ dts?: boolean | {
68
+ dir?: string;
69
+ mode?: 'source' | 'shim';
70
+ };
71
+ /** 接受并恒为 true:TLA 天然异步边界,无需手工 bootstrap(比 webpack 更进一步) */
72
+ automaticAsyncBoundary?: boolean;
73
+ /** 接受并恒为 true:preloadRemote 能力始终可用 */
74
+ dataPrefetch?: boolean;
75
+ /** 接受 no-op:Rollup/Rolldown 原生 tree-shaking 已覆盖 */
76
+ usedExports?: boolean;
77
+ ignoreUnusedSharedExports?: boolean;
78
+ /**
79
+ * dev 下自身源码(含依赖,需配合 optimizeDeps.exclude)是否参与 shared 协商改写。
80
+ * 默认:纯 remote(无 remotes)为 true——被宿主消费的组件需协商到宿主实例;
81
+ * 有 remotes 的宿主为 false——自身 import 即自身 provide,避免巨型工程 TLA/循环依赖风险。
82
+ * 双向联邦(宿主同时 expose 组件给更高层消费)显式设 true。
83
+ */
84
+ devSharedSelf?: boolean;
85
+ /**
86
+ * dev 跨源访问策略(插件端点 /@fulgurjs-entry.js、/@fulgurjs-manifest.json 与 server.cors
87
+ * 共用同一来源)。缺省 = '*'(现状兼容:端点与 server.cors 全放开);'*' = 显式全放开(不告警);
88
+ * 数组 = 来源 allowlist(端点按 Origin 反射匹配,不匹配省略头;server.cors 传 { origin: [...] },
89
+ * 用户显式配置的 server.cors 永远优先)。
90
+ */
91
+ devCorsOrigins?: string[] | '*';
92
+ /**
93
+ * dev manifest 是否携带 fsRoot(remote 根目录本机绝对路径,宿主 dts 类型直连用)。
94
+ * 默认 true(现状兼容);false 时不写入 manifest,宿主 dts 降级为 any 桩并给出提示。
95
+ * fsRoot 是 dev-only 字段,永不进入 prod manifest。
96
+ */
97
+ devFsRoot?: boolean;
98
+ }
99
+
100
+ export type { FederationOptions as F };
package/dist/pages.js CHANGED
@@ -1,142 +1,7 @@
1
- // src/pages.ts
2
- var normSpec = (s) => s.replace(/^[./]+/, "").replace(/\/+$/, "");
3
- var hasParam = (route) => /(^|\/):[\w]+/.test(route);
4
- var segs = (route) => route.split("/").filter(Boolean);
5
- function defaultDeriveSpec(route) {
6
- return segs(route).slice(1).filter((seg) => !seg.startsWith(":")).join("/");
7
- }
8
- function shadows(earlier, later) {
9
- const a = segs(earlier);
10
- const b = segs(later);
11
- if (a.length !== b.length) return null;
12
- if (earlier === later) return "full";
13
- let hasParam2 = false;
14
- for (let i = 0; i < a.length; i++) {
15
- if (a[i] === b[i]) continue;
16
- if (a[i].startsWith(":")) {
17
- hasParam2 = true;
18
- continue;
19
- }
20
- return null;
21
- }
22
- return hasParam2 ? "param" : null;
23
- }
24
- function remoteOfRoute(route, remotes) {
25
- if (!remotes) return null;
26
- for (const [prefix, name] of Object.entries(remotes)) {
27
- if (route === prefix.replace(/\/+$/, "") || route.startsWith(prefix)) return name;
28
- }
29
- return null;
30
- }
31
- function validatePages(pages, options = {}) {
32
- const deriveSpec = options.deriveSpec ?? defaultDeriveSpec;
33
- const violations = [];
34
- const effective = pages.map((p) => normSpec(p.spec ?? deriveSpec(p.route)));
35
- pages.forEach((p, i) => {
36
- if (p.spec || !hasParam(p.route)) return;
37
- pages.forEach((q, j) => {
38
- if (i === j) return;
39
- if (effective[j] !== effective[i]) return;
40
- violations.push({
41
- rule: "R1",
42
- level: "error",
43
- message: `[R1] \u8DEF\u7531 "${p.route}" \u5265\u53C2\u63A8\u5BFC spec "${effective[i]}" \u4E0E\u8DEF\u7531 "${q.route}"${q.spec ? "\uFF08\u663E\u5F0F spec\uFF09" : ""}\u6536\u655B\u76F8\u540C\u3002
44
- \u6839\u56E0\uFF1A\u53C2\u6570\u6BB5\u5265\u79BB\u540E expose \u952E\u4E0E\u5176\u5B83\u6761\u76EE\u76F8\u540C\uFF0C\u8BE5\u8DEF\u7531\u4F1A\u9759\u9ED8\u52A0\u8F7D\u9519\u8BEF\u7EC4\u4EF6
45
- \uFF08\u771F\u5B9E\u4E8B\u6545\uFF1A\u5E26\u53C2\u52A8\u4F5C\u9875\u8BEF\u8D70\u5217\u8868/\u66F4\u65B0\u8BED\u4E49\uFF0C\u6570\u636E\u98CE\u9669\uFF09\u3002
46
- \u4FEE\u6CD5\uFF1A\u4E3A\u8BE5\u6761\u76EE\u663E\u5F0F\u58F0\u660E spec: '...'\uFF08\u6307\u5411\u5E26\u53C2\u9875\u9762\u81EA\u5DF1\u7684 expose\uFF09\uFF0C\u6216\u8C03\u6574\u8DEF\u7531\u62C6\u5206\u3002`
47
- });
48
- });
49
- });
50
- const seenSpec = /* @__PURE__ */ new Map();
51
- pages.forEach((p, i) => {
52
- const key = effective[i];
53
- if (seenSpec.has(key)) {
54
- const first = pages[seenSpec.get(key)];
55
- const bothExplicit = !!p.spec && !!first.spec;
56
- violations.push({
57
- rule: "R2",
58
- level: "warn",
59
- message: `[R2] \u8DEF\u7531 "${p.route}" \u4E0E "${first.route}" \u6709\u6548 spec \u76F8\u540C\uFF08"${key}"\uFF09\u3002${bothExplicit ? "\u4E24\u6761\u5747\u4E3A\u663E\u5F0F spec" : "\u5176\u4E2D\u542B\u63A8\u5BFC spec"}\u2014\u2014\u82E5\u4E3A\u523B\u610F\u7684\u83DC\u5355\u522B\u540D\u53EF\u5FFD\u7565\u672C\u8B66\u544A\uFF0C\u5426\u5219\u8BF7\u6838\u5BF9\u3002`
60
- });
61
- } else {
62
- seenSpec.set(key, i);
63
- }
64
- });
65
- if (options.schema && options.remotes) {
66
- pages.forEach((p, i) => {
67
- const remote = remoteOfRoute(p.route, options.remotes);
68
- if (!remote) return;
69
- const entry = options.schema[remote];
70
- if (!entry || entry.exists === false) return;
71
- const exposes = new Set((entry.exposes ?? []).map(normSpec));
72
- if (!exposes.has(effective[i])) {
73
- violations.push({
74
- rule: "R3",
75
- level: "error",
76
- message: `[R3] \u8DEF\u7531 "${p.route}" \u7684 spec "${effective[i]}" \u4E0D\u5728\u8FDC\u7A0B "${remote}" \u7684 exposes \u6E05\u5355\u4E2D\u3002
77
- \u6839\u56E0\uFF1Aspec \u62FC\u5199\u4E0E\u8FDC\u7A0B exposes \u952E\u4E0D\u4E00\u81F4\uFF08\u8FD0\u884C\u65F6\u5C06 MFU-006 \u52A0\u8F7D\u5931\u8D25\uFF09\u3002
78
- \u4FEE\u6CD5\uFF1A\u6838\u5BF9\u8FDC\u7A0B vite.config exposes \u952E\u540D\uFF0C\u6216\u4FEE\u6B63\u672C\u8868 spec\u3002
79
- \u8FDC\u7A0B\u5B9E\u9645 exposes\uFF08\u524D 10\uFF09\uFF1A${[...exposes].slice(0, 10).join("\u3001") || "\uFF08\u7A7A\uFF09"}`
80
- });
81
- }
82
- });
83
- }
84
- pages.forEach((p, i) => {
85
- pages.forEach((q, j) => {
86
- if (j <= i) return;
87
- const kind = shadows(p.route, q.route);
88
- if (!kind) return;
89
- violations.push({
90
- rule: "R4",
91
- level: "error",
92
- message: kind === "full" ? `[R4] \u8DEF\u7531\u5B8C\u5168\u91CD\u590D\uFF1A"${p.route}"\uFF08\u7B2C ${i + 1} \u6761\uFF09\u4E0E "${q.route}"\uFF08\u7B2C ${j + 1} \u6761\uFF09\u3002` : `[R4] \u8DEF\u7531 "${q.route}"\uFF08\u7B2C ${j + 1} \u6761\uFF09\u4F1A\u88AB\u66F4\u9760\u524D\u7684 "${p.route}" \u906E\u853D\uFF08\u5339\u914D\u5148\u5230\u5148\u5F97\uFF0C\u540E\u8005\u6210\u6B7B\u8DEF\u7531\uFF09\u3002
93
- \u4FEE\u6CD5\uFF1A\u8C03\u6574\u6570\u7EC4\u987A\u5E8F\uFF08\u66F4\u5177\u4F53\u7684\u9759\u6001\u8DEF\u7531\u653E\u524D\u9762\uFF09\u6216\u5408\u5E76\u6761\u76EE\u3002`
94
- });
95
- });
96
- });
97
- const seenName = /* @__PURE__ */ new Map();
98
- pages.forEach((p, i) => {
99
- const name = typeof p.name === "string" ? p.name : "";
100
- if (!name) return;
101
- if (seenName.has(name)) {
102
- violations.push({
103
- rule: "R5",
104
- level: "warn",
105
- message: `[R5] name "${name}" \u91CD\u590D\uFF08"${pages[seenName.get(name)].route}" \u4E0E "${p.route}"\uFF09\u2014\u2014vue-router \u547D\u540D\u8DF3\u8F6C push({name}) \u5C06\u547D\u4E2D\u524D\u8005\uFF0C\u8BF7\u6838\u5BF9\u3002`
106
- });
107
- } else {
108
- seenName.set(name, i);
109
- }
110
- });
111
- return violations;
112
- }
113
- function formatViolations(violations) {
114
- const errors = violations.filter((v) => v.level === "error");
115
- const warns = violations.filter((v) => v.level === "warn");
116
- let out = "";
117
- if (errors.length) {
118
- out += `[fulgurjs] \u8DEF\u7531\u8868\u6821\u9A8C\u5931\u8D25\uFF08${errors.length} \u9879\uFF0CERROR\uFF09\uFF1A
119
- ` + errors.map((v) => v.message).join("\n") + "\n";
120
- }
121
- if (warns.length) {
122
- out += `[fulgurjs] \u8DEF\u7531\u8868\u6821\u9A8C\u8B66\u544A\uFF08${warns.length} \u9879\uFF0CWARN\uFF09\uFF1A
123
- ` + warns.map((v) => v.message).join("\n");
124
- }
125
- return out.trim();
126
- }
127
- function definePages(pages, options = {}) {
128
- const violations = validatePages(pages, options);
129
- const errors = violations.filter((v) => v.level === "error");
130
- const warns = violations.filter((v) => v.level === "warn");
131
- const text = formatViolations(violations);
132
- if (text) {
133
- if (errors.length && options.strict !== false) {
134
- throw new Error(text);
135
- }
136
- console[errors.length ? "error" : "warn"](text);
137
- }
138
- return pages;
139
- }
1
+ import {
2
+ definePages,
3
+ validatePages
4
+ } from "./chunk-TSXZ7TWA.js";
140
5
  export {
141
6
  definePages,
142
7
  validatePages