@fulgurjs/federation 2.0.3 → 2.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,15 +1,43 @@
1
1
  import {
2
2
  RUNTIME_VERSION
3
- } from "./chunk-RQPLFDDT.js";
3
+ } from "./chunk-RP6HNIQT.js";
4
4
 
5
5
  // src/index.ts
6
- import path5 from "path";
6
+ import path6 from "path";
7
7
  import { createRequire as createRequire2 } from "module";
8
8
 
9
9
  // src/options.ts
10
10
  import { createRequire } from "module";
11
11
  import fs from "fs";
12
12
  import path from "path";
13
+
14
+ // src/dev-cors.ts
15
+ function normalizeDevCorsOrigins(input) {
16
+ if (input === void 0 || input === "*") return { ok: true, value: input };
17
+ if (!Array.isArray(input) || input.length === 0) {
18
+ return { ok: false, reason: '\u5FC5\u987B\u662F "*" \u6216\u975E\u7A7A\u6570\u7EC4' };
19
+ }
20
+ for (const item of input) {
21
+ if (typeof item !== "string" || !/^https?:\/\/[^/]+$/i.test(item)) {
22
+ return { ok: false, reason: `\u6765\u6E90\u5FC5\u987B\u662F http(s)://host[:port] \u5F62\u6001\uFF08\u65E0\u8DEF\u5F84\uFF09\uFF0Cgot: ${JSON.stringify(item)}` };
23
+ }
24
+ }
25
+ return { ok: true, value: input };
26
+ }
27
+ function corsHeadersFor(origin, allowed) {
28
+ if (allowed === void 0 || allowed === "*") {
29
+ return { "Access-Control-Allow-Origin": "*" };
30
+ }
31
+ if (!origin || !allowed.includes(origin)) return {};
32
+ return { "Access-Control-Allow-Origin": origin, Vary: "Origin" };
33
+ }
34
+ function isNonLoopbackHost(host) {
35
+ if (host === void 0 || host === false) return false;
36
+ const h = host === true ? "0.0.0.0" : String(host);
37
+ return !["localhost", "127.0.0.1", "::1", "[::1]"].includes(h.toLowerCase());
38
+ }
39
+
40
+ // src/options.ts
13
41
  var DEFAULT_FILENAME = "fulgurjs-remoteEntry.js";
14
42
  var RUNTIME_VIRTUAL_ID = "virtual:fulgurjs-runtime";
15
43
  var RUNTIME_PROXY_VIRTUAL_ID = "virtual:fulgurjs-runtime-proxy";
@@ -264,6 +292,41 @@ function validateOptions(options) {
264
292
  // or split: { '${key}': { dev: 'http://localhost:5101', prod: '/${key}' } }`
265
293
  );
266
294
  }
295
+ if (cfg.timeout !== void 0 && (typeof cfg.timeout !== "number" || !Number.isFinite(cfg.timeout) || cfg.timeout <= 0)) {
296
+ configError(
297
+ `CFG-009: remotes["${key}"].timeout must be a finite positive number (ms)`,
298
+ cfg.timeout,
299
+ "e.g. 15000\uFF08\u7701\u7565\u7528\u9ED8\u8BA4 15s\uFF09",
300
+ `remotes: { '${key}': { external: '\u2026', timeout: 15000 } }`
301
+ );
302
+ }
303
+ if (cfg.retries !== void 0 && (typeof cfg.retries !== "number" || !Number.isInteger(cfg.retries) || cfg.retries < 0 || cfg.retries > 10)) {
304
+ configError(
305
+ `CFG-009: remotes["${key}"].retries must be an integer in 0..10`,
306
+ cfg.retries,
307
+ "e.g. 2\uFF08\u7701\u7565\u7528\u9ED8\u8BA4 2\uFF1B\u4E0A\u9650 10 \u9632\u9000\u907F\u98CE\u66B4\uFF09",
308
+ `remotes: { '${key}': { external: '\u2026', retries: 2 } }`
309
+ );
310
+ }
311
+ const brk = cfg.breaker;
312
+ if (brk) {
313
+ if (brk.threshold !== void 0 && (typeof brk.threshold !== "number" || !Number.isFinite(brk.threshold) || brk.threshold <= 0)) {
314
+ configError(
315
+ `CFG-009: remotes["${key}"].breaker.threshold must be a finite positive number`,
316
+ brk.threshold,
317
+ "e.g. 5\uFF08\u8FDE\u7EED\u5931\u8D25 5 \u6B21\u540E\u7194\u65AD\uFF09",
318
+ `remotes: { '${key}': { external: '\u2026', breaker: { threshold: 5, resetMs: 30000 } } }`
319
+ );
320
+ }
321
+ if (brk.resetMs !== void 0 && (typeof brk.resetMs !== "number" || !Number.isFinite(brk.resetMs) || brk.resetMs <= 0)) {
322
+ configError(
323
+ `CFG-009: remotes["${key}"].breaker.resetMs must be a finite positive number (ms)`,
324
+ brk.resetMs,
325
+ "e.g. 30000\uFF08\u7194\u65AD 30s \u540E\u534A\u5F00\uFF09",
326
+ `remotes: { '${key}': { external: '\u2026', breaker: { threshold: 5, resetMs: 30000 } } }`
327
+ );
328
+ }
329
+ }
267
330
  for (const slot of ["dev", "prod", "external"]) {
268
331
  const v = cfg[slot];
269
332
  if (v !== void 0 && typeof v !== "string") {
@@ -282,6 +345,23 @@ function validateOptions(options) {
282
345
  }
283
346
  }
284
347
  }
348
+ const corsCheck = normalizeDevCorsOrigins(options.devCorsOrigins);
349
+ if (!corsCheck.ok) {
350
+ configError(
351
+ `CFG-010: devCorsOrigins ${corsCheck.reason}`,
352
+ options.devCorsOrigins,
353
+ `'*'\uFF08\u5168\u653E\u5F00\uFF09\u6216\u6765\u6E90 allowlist \u6570\u7EC4`,
354
+ `devCorsOrigins: ['http://localhost:5100', 'http://127.0.0.1:5100']`
355
+ );
356
+ }
357
+ if (options.devFsRoot !== void 0 && typeof options.devFsRoot !== "boolean") {
358
+ configError(
359
+ "`devFsRoot` must be a boolean",
360
+ options.devFsRoot,
361
+ "true\uFF08dev manifest \u643A\u5E26 fsRoot\uFF0C\u73B0\u72B6\u9ED8\u8BA4\uFF09\u6216 false\uFF08\u4E0D\u66B4\u9732\u672C\u673A\u8DEF\u5F84\uFF09",
362
+ `devFsRoot: false`
363
+ );
364
+ }
285
365
  }
286
366
  function normalizeOptions(options, root, command) {
287
367
  const warnings = [];
@@ -353,7 +433,9 @@ function normalizeOptions(options, root, command) {
353
433
  pkgDependencies,
354
434
  warnings,
355
435
  // dev 改写开关:默认纯 remote 参与 shared 协商,宿主(有 remotes)不参与;可显式覆盖
356
- devSharedSelf: options.devSharedSelf ?? remotes.length === 0
436
+ devSharedSelf: options.devSharedSelf ?? remotes.length === 0,
437
+ devCorsOrigins: options.devCorsOrigins,
438
+ devFsRoot: options.devFsRoot ?? true
357
439
  };
358
440
  }
359
441
 
@@ -362,6 +444,145 @@ import { init as initLexer, parse } from "es-module-lexer";
362
444
  import MagicString from "magic-string";
363
445
  import path2 from "path";
364
446
 
447
+ // src/manifest.ts
448
+ var MANIFEST_SCHEMA_VERSION = 1;
449
+ var isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
450
+ function validAssetRef(v) {
451
+ if (typeof v !== "string" || v.length === 0) return false;
452
+ if (/[\s\u0000-\u001f]/.test(v)) return false;
453
+ if (/^https?:\/\/[^/@\s]+:[^/@\s]+@/.test(v)) return false;
454
+ return true;
455
+ }
456
+ function validExposeName(v) {
457
+ return typeof v === "string" && /^\.[\w./-]+$/.test(v);
458
+ }
459
+ function parseManifest(input) {
460
+ const issues = [];
461
+ if (!isPlainObject(input)) {
462
+ return { issues: [{ field: "$", message: "manifest \u5FC5\u987B\u662F JSON \u5BF9\u8C61", got: typeof input }] };
463
+ }
464
+ const m = input;
465
+ let schemaVersion = MANIFEST_SCHEMA_VERSION;
466
+ if (m.schemaVersion !== void 0) {
467
+ if (typeof m.schemaVersion !== "number" || !Number.isInteger(m.schemaVersion)) {
468
+ issues.push({ field: "schemaVersion", message: "\u5FC5\u987B\u662F\u6574\u6570", got: m.schemaVersion });
469
+ } else if (m.schemaVersion !== MANIFEST_SCHEMA_VERSION) {
470
+ return {
471
+ issues: [
472
+ {
473
+ field: "schemaVersion",
474
+ message: `\u4E0D\u652F\u6301\u7684 manifest \u4E3B\u7248\u672C\uFF08\u5F53\u524D\u6D88\u8D39\u7AEF\u652F\u6301 ${MANIFEST_SCHEMA_VERSION}\uFF09`,
475
+ got: m.schemaVersion
476
+ }
477
+ ],
478
+ unsupportedVersion: m.schemaVersion
479
+ };
480
+ }
481
+ }
482
+ if (typeof m.name !== "string" || m.name.length === 0) {
483
+ issues.push({ field: "name", message: "\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32", got: m.name });
484
+ }
485
+ const exposes = m.exposes;
486
+ const shared = m.shared;
487
+ const sharedIssues = validateShared(shared);
488
+ issues.push(...sharedIssues);
489
+ if (Array.isArray(exposes)) {
490
+ if (m.devServer !== true) {
491
+ issues.push({ field: "devServer", message: "dev \u6570\u7EC4\u5F62\u6001 exposes \u5FC5\u987B\u4F34\u968F devServer: true", got: m.devServer });
492
+ }
493
+ if (typeof m.base !== "string" || !/^\/(?:.*\/)?$/.test(m.base)) {
494
+ issues.push({ field: "base", message: "\u5FC5\u987B\u662F\u4EE5 / \u5F00\u5934\u4E14 / \u7ED3\u5C3E\u7684\u8DEF\u5F84", got: m.base });
495
+ }
496
+ if (!validAssetRef(m.entry)) {
497
+ issues.push({ field: "entry", message: "\u5FC5\u987B\u662F\u5408\u6CD5\u8D44\u6E90\u5730\u5740", got: m.entry });
498
+ }
499
+ for (const [i, e] of exposes.entries()) {
500
+ if (!isPlainObject(e)) {
501
+ issues.push({ field: `exposes[${i}]`, message: "\u5FC5\u987B\u662F\u5BF9\u8C61", got: typeof e });
502
+ continue;
503
+ }
504
+ if (!validExposeName(e.name)) {
505
+ issues.push({ field: `exposes[${i}].name`, message: '\u5FC5\u987B\u662F "./xxx" \u5F62\u6001\u7684 expose \u540D', got: e.name });
506
+ }
507
+ if (typeof e.src !== "string" || e.src.length === 0) {
508
+ issues.push({ field: `exposes[${i}].src`, message: "dev \u5F62\u6001\u5FC5\u987B\u63D0\u4F9B\u6E90\u7801\u76F8\u5BF9\u8DEF\u5F84", got: e.src });
509
+ }
510
+ if (!validAssetRef(e.file)) {
511
+ issues.push({ field: `exposes[${i}].file`, message: "\u5FC5\u987B\u662F\u53EF\u8BF7\u6C42\u7684\u6A21\u5757\u5730\u5740", got: e.file });
512
+ }
513
+ }
514
+ } else if (isPlainObject(exposes)) {
515
+ if (!validAssetRef(m.entry)) {
516
+ issues.push({ field: "entry", message: "\u5FC5\u987B\u662F\u5408\u6CD5\u8D44\u6E90\u5730\u5740\uFF08\u76F8\u5BF9\u57FA\u51C6 = \u6240\u5728\u76EE\u5F55\uFF09", got: m.entry });
517
+ }
518
+ for (const [key, v] of Object.entries(exposes)) {
519
+ if (!validExposeName(key)) {
520
+ issues.push({ field: `exposes["${key}"]`, message: '\u952E\u5FC5\u987B\u662F "./xxx" \u5F62\u6001\u7684 expose \u540D' });
521
+ }
522
+ if (!isPlainObject(v)) {
523
+ issues.push({ field: `exposes["${key}"]`, message: "\u503C\u5FC5\u987B\u662F\u5BF9\u8C61", got: typeof v });
524
+ continue;
525
+ }
526
+ if (!validAssetRef(v.file)) {
527
+ issues.push({ field: `exposes["${key}"].file`, message: "\u5FC5\u987B\u662F\u8D44\u6E90\u8DEF\u5F84\uFF08\u76F8\u5BF9 entry \u76EE\u5F55\uFF09", got: v.file });
528
+ }
529
+ if (v.css !== void 0) {
530
+ if (!Array.isArray(v.css)) {
531
+ issues.push({ field: `exposes["${key}"].css`, message: "\u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6570\u7EC4", got: typeof v.css });
532
+ } else {
533
+ v.css.forEach((css, i) => {
534
+ if (!validAssetRef(css)) {
535
+ issues.push({ field: `exposes["${key}"].css[${i}]`, message: "\u5FC5\u987B\u662F\u8D44\u6E90\u8DEF\u5F84", got: css });
536
+ }
537
+ });
538
+ }
539
+ }
540
+ }
541
+ } else {
542
+ issues.push({ field: "exposes", message: "\u5FC5\u987B\u662F\u6570\u7EC4\uFF08dev\uFF09\u6216\u5BF9\u8C61\uFF08prod\uFF09", got: typeof exposes });
543
+ }
544
+ if (issues.length > 0) return { issues };
545
+ return { manifest: input, issues };
546
+ }
547
+ function validateShared(shared) {
548
+ if (shared === void 0) return [];
549
+ const issues = [];
550
+ if (!Array.isArray(shared)) {
551
+ return [{ field: "shared", message: "\u5FC5\u987B\u662F\u6570\u7EC4", got: typeof shared }];
552
+ }
553
+ for (const [i, s] of shared.entries()) {
554
+ if (!isPlainObject(s)) {
555
+ issues.push({ field: `shared[${i}]`, message: "\u5FC5\u987B\u662F\u5BF9\u8C61", got: typeof s });
556
+ continue;
557
+ }
558
+ if (typeof s.name !== "string" || s.name.length === 0) {
559
+ issues.push({ field: `shared[${i}].name`, message: "\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32", got: s.name });
560
+ }
561
+ if (typeof s.version !== "string" || s.version.length === 0) {
562
+ issues.push({ field: `shared[${i}].version`, message: "\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32", got: s.version });
563
+ }
564
+ }
565
+ return issues;
566
+ }
567
+ function isDevManifest(m) {
568
+ return Array.isArray(m.exposes);
569
+ }
570
+ function normalizeExposes(manifest) {
571
+ const out = /* @__PURE__ */ new Map();
572
+ if (isDevManifest(manifest)) {
573
+ for (const e of manifest.exposes) {
574
+ if (!validExposeName(e.name)) continue;
575
+ out.set(e.name, { name: e.name, file: e.file, css: [], src: e.src });
576
+ }
577
+ } else {
578
+ for (const [key, v] of Object.entries(manifest.exposes)) {
579
+ if (!validExposeName(key)) continue;
580
+ out.set(key, { name: key, file: v.file, css: Array.isArray(v.css) ? v.css.filter((c) => typeof c === "string") : [] });
581
+ }
582
+ }
583
+ return out;
584
+ }
585
+
365
586
  // src/virtual.ts
366
587
  function jsonReplacer(_k, v) {
367
588
  return v;
@@ -660,17 +881,33 @@ function genBuildRemoteEntry(options, exposeAbsPaths) {
660
881
  ""
661
882
  ].join("\n");
662
883
  }
884
+ function genApiFacade() {
885
+ return [
886
+ "export {",
887
+ " initSharing, registerShare, registerRemotes, registerRemote, registerPlugins,",
888
+ " loadShare, loadRemote, getContainer, preloadRemote, parseSpec,",
889
+ " getRuntime, shareScopeMap, unwrapDefault, version,",
890
+ '} from "virtual:fulgurjs-runtime";',
891
+ 'export { definePages, validatePages } from "@fulgurjs/federation/pages";',
892
+ 'export { default as remoteSchema } from "virtual:fulgurjs-remote-schema";',
893
+ ""
894
+ ].join("\n");
895
+ }
663
896
  function genDevManifest(options, base) {
664
897
  const b = base.endsWith("/") ? base : `${base}/`;
665
898
  return {
899
+ schemaVersion: MANIFEST_SCHEMA_VERSION,
666
900
  id: options.name,
667
901
  name: options.name,
668
902
  version: options.pkgDependencies?.["fulgurjs"] ?? "0.0.0",
669
903
  devServer: true,
670
904
  base: b,
671
905
  entry: `${b}@fulgurjs-entry.js`,
672
- /** 本地联调时供宿主端 dts 类型直连(见 dts.ts);远程不在本机时宿主回退 any 桩 */
673
- fsRoot: options.root,
906
+ /**
907
+ * 本地联调时供宿主端 dts 类型直连(见 dts.ts);远程不在本机时宿主回退 any 桩。
908
+ * WP5:devFsRoot: false 时不写入(本机路径不外发);该字段永不进入 prod manifest。
909
+ */
910
+ ...options.devFsRoot === false ? {} : { fsRoot: options.root },
674
911
  exposes: options.exposes.map((e) => ({
675
912
  name: e.name,
676
913
  src: e.import,
@@ -692,6 +929,7 @@ function genDevManifest(options, base) {
692
929
  }
693
930
  function genProdManifest(options, exposeFiles, entryFile) {
694
931
  return {
932
+ schemaVersion: MANIFEST_SCHEMA_VERSION,
695
933
  id: options.name,
696
934
  name: options.name,
697
935
  entry: entryFile,
@@ -873,6 +1111,7 @@ async function transformModule(code, id, ctx) {
873
1111
  cjsEdited = true;
874
1112
  }
875
1113
  if (!cjsEdited) return null;
1114
+ ctx.onRewrite?.();
876
1115
  return { code, map: null };
877
1116
  }
878
1117
  await ensureLexer();
@@ -995,6 +1234,7 @@ export { ${nsAs[1]} };`);
995
1234
  }
996
1235
  }
997
1236
  if (!edited) return null;
1237
+ ctx.onRewrite?.();
998
1238
  if (usesRuntimeHelpers) {
999
1239
  const runtimeSpec = JSON.stringify(ctx.devUrls?.runtime ?? "virtual:fulgurjs-runtime");
1000
1240
  s.prepend(
@@ -1020,7 +1260,22 @@ async function fetchManifest(devEntry, attempts = 30, delayMs = 2e3) {
1020
1260
  for (let i = 0; i < attempts; i++) {
1021
1261
  try {
1022
1262
  const res = await fetch(manifestUrl, { signal: AbortSignal.timeout(3e3) });
1023
- if (res.ok) return await res.json();
1263
+ if (res.ok) {
1264
+ const parsed = parseManifest(await res.json());
1265
+ if (parsed.unsupportedVersion) {
1266
+ console.warn(
1267
+ `[fulgurjs] dts: remote manifest schemaVersion=${parsed.unsupportedVersion} \u4E0D\u88AB\u5F53\u524D\u63D2\u4EF6\u652F\u6301\uFF08\u672C\u673A\u652F\u6301 1\uFF09\uFF1B\u7C7B\u578B\u6620\u5C04\u8DF3\u8FC7\u3002\u8BF7\u5BF9\u9F50\u5BBF\u4E3B\u4E0E\u8FDC\u7A0B\u7684 @fulgurjs/federation \u7248\u672C\u3002`
1268
+ );
1269
+ return null;
1270
+ }
1271
+ if (parsed.issues.length > 0) {
1272
+ console.warn(
1273
+ `[fulgurjs] dts: remote manifest \u5951\u7EA6\u6821\u9A8C\u5931\u8D25\uFF08${manifestUrl.href}\uFF09\uFF1A` + parsed.issues.map((x) => `${x.field}: ${x.message}`).join("\uFF1B") + `\u3002\u7C7B\u578B\u6620\u5C04\u8DF3\u8FC7\u3002`
1274
+ );
1275
+ return null;
1276
+ }
1277
+ return parsed.manifest;
1278
+ }
1024
1279
  } catch {
1025
1280
  }
1026
1281
  await new Promise((r) => setTimeout(r, delayMs));
@@ -1083,7 +1338,7 @@ function resolveDtsMode(dtsOpt) {
1083
1338
  return (typeof dtsOpt === "object" ? dtsOpt.mode : void 0) ?? "source";
1084
1339
  }
1085
1340
  function buildShimModule(abs, moduleSpecifier) {
1086
- const lines = [`declare module '${moduleSpecifier}' {`];
1341
+ const lines = [`declare module ${JSON.stringify(moduleSpecifier)} {`];
1087
1342
  if (abs.endsWith(".vue")) {
1088
1343
  lines.push(` import type { DefineComponent } from 'vue'`);
1089
1344
  lines.push(` const component: DefineComponent<Record<string, unknown>, Record<string, unknown>, any>`);
@@ -1120,9 +1375,18 @@ async function generateDevTypes(options, _server) {
1120
1375
  continue;
1121
1376
  }
1122
1377
  const remoteRoot = manifest.fsRoot;
1123
- if (!remoteRoot || !fs2.existsSync(remoteRoot)) {
1378
+ if (!remoteRoot) {
1379
+ console.warn(
1380
+ `[fulgurjs] dts: remote "${remote.key}" \u7684 manifest \u672A\u643A\u5E26 fsRoot\uFF08devFsRoot: false \u6216\u8FDC\u7A0B\u63D2\u4EF6\u7248\u672C\u8FC7\u65E7\uFF09\uFF1B\u7C7B\u578B\u6620\u5C04\u964D\u7EA7\u4E3A any \u6869\u3002\u540C\u673A\u8054\u8C03\u9700\u8FDC\u7A0B devFsRoot: true\uFF08\u9ED8\u8BA4\uFF09\u5E76\u91CD\u542F\u5176 dev server\u3002`
1381
+ );
1382
+ continue;
1383
+ }
1384
+ let realRoot;
1385
+ try {
1386
+ realRoot = fs2.realpathSync(remoteRoot);
1387
+ } catch {
1124
1388
  console.warn(
1125
- `[fulgurjs] dts: remote "${remote.key}" is not on this machine; type mapping skipped (module types fall back to any).`
1389
+ `[fulgurjs] dts: remote "${remote.key}" is not on this machine (fsRoot unreachable); type mapping skipped (module types fall back to any).`
1126
1390
  );
1127
1391
  continue;
1128
1392
  }
@@ -1130,45 +1394,78 @@ async function generateDevTypes(options, _server) {
1130
1394
  `// \u81EA\u52A8\u751F\u6210\uFF1Afulgurjs-federation dev \u7C7B\u578B\u76F4\u8FDE\uFF08remote: ${remote.name}\uFF0Cmode: ${mode}\uFF09`,
1131
1395
  `// \u91CD\u65B0\u751F\u6210\uFF1A\u91CD\u542F host dev server`
1132
1396
  ];
1397
+ let accepted = 0;
1133
1398
  for (const expose of manifest.exposes ?? []) {
1134
- const abs = path3.join(remoteRoot, expose.src.replace(/^\//, ""));
1135
- if (!fs2.existsSync(abs)) continue;
1136
- const rel = path3.relative(outDir, abs).split(path3.sep).join("/");
1137
- const importPath = abs.endsWith(".vue") ? sourceImportPath(rel) : stripTsExtension(sourceImportPath(rel));
1399
+ const skipped = (reason) => console.warn(`[fulgurjs] dts: remote "${remote.key}" expose ${JSON.stringify(expose.name)} \u8DF3\u8FC7\uFF1A${reason}`);
1400
+ const src = expose.src;
1401
+ if (!src || typeof src !== "string") {
1402
+ skipped("src \u7F3A\u5931");
1403
+ continue;
1404
+ }
1405
+ if (src.startsWith("/") || /^[a-z]+:/i.test(src)) {
1406
+ skipped(`src \u5FC5\u987B\u662F\u76F8\u5BF9\u8DEF\u5F84\uFF0Cgot ${JSON.stringify(src)}`);
1407
+ continue;
1408
+ }
1409
+ if (src.split("/").includes("..")) {
1410
+ skipped(`src \u4E0D\u5F97\u5305\u542B ..\uFF0Cgot ${JSON.stringify(src)}`);
1411
+ continue;
1412
+ }
1413
+ const abs = path3.join(realRoot, src);
1414
+ let realAbs;
1415
+ try {
1416
+ realAbs = fs2.realpathSync(abs);
1417
+ } catch {
1418
+ skipped(`\u6E90\u6587\u4EF6\u4E0D\u5B58\u5728\uFF08${src}\uFF09`);
1419
+ continue;
1420
+ }
1421
+ if (path3.relative(realRoot, realAbs).startsWith("..")) {
1422
+ skipped(`\u89E3\u6790\u7ED3\u679C\u8D8A\u51FA fsRoot\uFF08${src} \u2192 ${realAbs}\uFF09`);
1423
+ continue;
1424
+ }
1425
+ if (!fs2.existsSync(realAbs)) continue;
1426
+ const rel = path3.relative(outDir, realAbs).split(path3.sep).join("/");
1427
+ const importPath = realAbs.endsWith(".vue") ? sourceImportPath(rel) : stripTsExtension(sourceImportPath(rel));
1138
1428
  const moduleSpecifier = `${remote.key}/${expose.name.replace(/^\.\//, "")}`;
1429
+ const moduleLiteral = JSON.stringify(moduleSpecifier);
1430
+ const importLiteral = JSON.stringify(importPath);
1139
1431
  lines.push("");
1140
1432
  if (mode === "shim") {
1141
- lines.push(buildShimModule(abs, moduleSpecifier));
1433
+ lines.push(buildShimModule(realAbs, moduleSpecifier));
1434
+ accepted++;
1142
1435
  continue;
1143
1436
  }
1144
- if (abs.endsWith(".vue")) {
1145
- lines.push(`declare module '${moduleSpecifier}' {`);
1437
+ if (realAbs.endsWith(".vue")) {
1438
+ lines.push(`declare module ${moduleLiteral} {`);
1146
1439
  lines.push(` import type { DefineComponent } from 'vue'`);
1147
1440
  lines.push(` const component: DefineComponent<Record<string, unknown>, Record<string, unknown>, unknown>`);
1148
1441
  lines.push(` export default component`);
1149
- lines.push(` export * from '${importPath}'`);
1442
+ lines.push(` export * from ${importLiteral}`);
1150
1443
  lines.push(`}`);
1151
1444
  } else {
1152
- lines.push(`declare module '${moduleSpecifier}' {`);
1153
- const names = extractTsExportNames(fs2.readFileSync(abs, "utf8"));
1445
+ lines.push(`declare module ${moduleLiteral} {`);
1446
+ const names = extractTsExportNames(fs2.readFileSync(realAbs, "utf8"));
1154
1447
  if (names.length > 0) {
1155
- lines.push(` export { ${names.join(", ")} } from '${importPath}'`);
1448
+ lines.push(` export { ${names.join(", ")} } from ${importLiteral}`);
1156
1449
  } else {
1157
- lines.push(` export * from '${importPath}'`);
1450
+ lines.push(` export * from ${importLiteral}`);
1158
1451
  }
1159
- if (sourceHasDefaultExport(abs)) lines.push(` export { default } from '${importPath}'`);
1452
+ if (sourceHasDefaultExport(realAbs)) lines.push(` export { default } from ${importLiteral}`);
1160
1453
  lines.push(`}`);
1161
1454
  }
1455
+ accepted++;
1162
1456
  }
1163
- fs2.writeFileSync(path3.join(outDir, `${remote.key}.d.ts`), `${lines.join("\n")}
1457
+ if (accepted > 0) {
1458
+ fs2.writeFileSync(path3.join(outDir, `${remote.key}.d.ts`), `${lines.join("\n")}
1164
1459
  `);
1460
+ }
1165
1461
  console.log(
1166
- `[fulgurjs] dts: generated ${dir}/${remote.key}.d.ts (${manifest.exposes?.length ?? 0} exposes, mode=${mode}). \u786E\u4FDD tsconfig include \u5305\u542B "${dir}" \u4EE5\u83B7\u5F97\u7C7B\u578B\u8865\u5168\u3002`
1462
+ `[fulgurjs] dts: generated ${dir}/${remote.key}.d.ts (${accepted}/${manifest.exposes?.length ?? 0} exposes, mode=${mode}). \u786E\u4FDD tsconfig include \u5305\u542B "${dir}" \u4EE5\u83B7\u5F97\u7C7B\u578B\u8865\u5168\u3002`
1167
1463
  );
1168
1464
  }
1169
1465
  }
1170
1466
 
1171
1467
  // src/diagnostics.ts
1468
+ import path4 from "path";
1172
1469
  function formatFulgurjsDiagnostic(input) {
1173
1470
  const ctx = input.details ? `
1174
1471
  \u4E0A\u4E0B\u6587\uFF1A${JSON.stringify(input.details)}` : "";
@@ -1191,6 +1488,33 @@ async function isPortReachable(host, port, timeoutMs = 800) {
1191
1488
  socket.connect(port, host);
1192
1489
  });
1193
1490
  }
1491
+ var __debugEnvCache = "";
1492
+ var __debugEnabledCache = {};
1493
+ function debugEnabled(category) {
1494
+ const spec = process.env.FULGURJS_DEBUG ?? process.env.DEBUG ?? "";
1495
+ if (spec !== __debugEnvCache) {
1496
+ __debugEnvCache = spec;
1497
+ __debugEnabledCache = {};
1498
+ }
1499
+ if (category in __debugEnabledCache) return __debugEnabledCache[category];
1500
+ const patterns = spec.split(",").map((x) => x.trim()).filter(Boolean);
1501
+ const enabled = patterns.some((p) => p === "fulgurjs" || p === "fulgurjs:*" || p === `fulgurjs:${category}`);
1502
+ __debugEnabledCache[category] = enabled;
1503
+ return enabled;
1504
+ }
1505
+ function debugLog(category, data) {
1506
+ if (!debugEnabled(category)) return;
1507
+ console.error(`[fulgurjs:debug:${category}] ${JSON.stringify(data)}`);
1508
+ }
1509
+ function redactModulePath(id, root) {
1510
+ const clean = id.split("?")[0];
1511
+ try {
1512
+ const rel = path4.relative(root, clean);
1513
+ if (rel && !rel.startsWith("..") && !path4.isAbsolute(rel)) return rel;
1514
+ } catch {
1515
+ }
1516
+ return clean.split("/").pop() ?? clean;
1517
+ }
1194
1518
 
1195
1519
  // src/remote-schema.ts
1196
1520
  function manifestUrlOf(devEntry) {
@@ -1217,8 +1541,35 @@ async function probeRemotesAndBuildSchema(options) {
1217
1541
  try {
1218
1542
  const res = await fetch(u, { signal: AbortSignal.timeout(3e3) });
1219
1543
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
1220
- const manifest = await res.json();
1221
- const exposes = (manifest?.exposes ?? []).map((e) => e.name);
1544
+ const parsed = parseManifest(await res.json());
1545
+ if (parsed.unsupportedVersion) {
1546
+ schema[remote.key] = { exposes: [], exists: false };
1547
+ console.warn(
1548
+ formatFulgurjsDiagnostic({
1549
+ code: "DEV-002",
1550
+ symptom: `remote "${remote.key}" \u7684 manifest schemaVersion=${parsed.unsupportedVersion} \u4E0D\u53D7\u652F\u6301\uFF08\u672C\u673A\u652F\u6301 1\uFF09`,
1551
+ cause: "\u5BBF\u4E3B\u4E0E\u8FDC\u7A0B\u7684 @fulgurjs/federation \u5927\u7248\u672C\u4E0D\u4E00\u81F4",
1552
+ fix: "\u5BF9\u9F50\u5BBF\u4E3B\u4E0E\u8FDC\u7A0B\u7684 @fulgurjs/federation \u7248\u672C\u540E\u91CD\u542F dev server",
1553
+ details: { remote: remote.key, url: u.href }
1554
+ })
1555
+ );
1556
+ continue;
1557
+ }
1558
+ if (parsed.issues.length > 0 || !parsed.manifest) {
1559
+ schema[remote.key] = { exposes: [], exists: false };
1560
+ console.warn(
1561
+ formatFulgurjsDiagnostic({
1562
+ code: "DEV-002",
1563
+ symptom: `remote "${remote.key}" \u7684 dev manifest \u5951\u7EA6\u6821\u9A8C\u5931\u8D25\uFF08${u.href}\uFF09`,
1564
+ cause: parsed.issues.map((x) => `${x.field}: ${x.message}`).join("\uFF1B"),
1565
+ fix: "\u6838\u5BF9 remote \u7684 federation \u914D\u7F6E exposes\uFF0C\u5E76\u786E\u8BA4 @fulgurjs/federation \u7248\u672C\u4E0E\u5BBF\u4E3B\u4E00\u81F4",
1566
+ details: { remote: remote.key, url: u.href, issues: parsed.issues.slice(0, 5) }
1567
+ })
1568
+ );
1569
+ continue;
1570
+ }
1571
+ const manifest = parsed.manifest;
1572
+ const exposes = [...normalizeExposes(manifest).keys()];
1222
1573
  schema[remote.key] = { exposes, exists: true };
1223
1574
  if (exposes.length === 0) {
1224
1575
  console.warn(
@@ -1227,11 +1578,11 @@ async function probeRemotesAndBuildSchema(options) {
1227
1578
  symptom: `remote "${remote.key}" \u7684 dev manifest \u53EF\u8FBE\u4F46 exposes \u4E3A\u7A7A\uFF08${u.href}\uFF09`,
1228
1579
  cause: "remote \u4FA7 federation({ exposes }) \u4E3A\u7A7A\uFF0C\u6216\u5176\u63D2\u4EF6\u7248\u672C\u8FC7\u65E7\u5BFC\u81F4 manifest \u7F3A\u5B57\u6BB5",
1229
1580
  fix: "\u6838\u5BF9 remote \u7684 federation \u914D\u7F6E exposes\uFF0C\u5E76\u786E\u8BA4 @fulgurjs/federation \u7248\u672C\u4E0E\u5BBF\u4E3B\u4E00\u81F4",
1230
- details: { remote: remote.key, url: u.href, pluginVersion: manifest?.buildInfo?.version }
1581
+ details: { remote: remote.key, url: u.href, pluginVersion: manifest.version }
1231
1582
  })
1232
1583
  );
1233
1584
  }
1234
- const remoteVersion = manifest?.buildInfo?.version;
1585
+ const remoteVersion = manifest.version;
1235
1586
  if (remoteVersion && remoteVersion !== options.pluginVersion) {
1236
1587
  console.warn(
1237
1588
  formatFulgurjsDiagnostic({
@@ -1267,17 +1618,17 @@ function genEmptyRemoteSchemaModule() {
1267
1618
 
1268
1619
  // src/vite-cache.ts
1269
1620
  import fs3 from "fs";
1270
- import path4 from "path";
1621
+ import path5 from "path";
1271
1622
  function syncViteCacheMarker(root, pluginVersion, log) {
1272
- const viteDir = path4.join(root, "node_modules", ".vite");
1273
- const marker = path4.join(viteDir, "fulgurjs-version.txt");
1623
+ const viteDir = path5.join(root, "node_modules", ".vite");
1624
+ const marker = path5.join(viteDir, "fulgurjs-version.txt");
1274
1625
  try {
1275
1626
  if (fs3.existsSync(viteDir)) {
1276
1627
  const prev = fs3.existsSync(marker) ? fs3.readFileSync(marker, "utf8").trim() : "";
1277
1628
  if (prev === pluginVersion) return;
1278
1629
  fs3.rmSync(viteDir, { recursive: true, force: true });
1279
1630
  log(
1280
- `[fulgurjs] \u63D2\u4EF6\u7248\u672C\u53D8\u5316\uFF08${prev || "\u65E0\u8BB0\u5F55"} \u2192 ${pluginVersion}\uFF09\uFF0C\u5DF2\u81EA\u52A8\u6E05\u9664 ${path4.relative(root, viteDir)} \u9884\u6784\u5EFA\u7F13\u5B58\uFF08\u907F\u514D\u65E7\u95E8\u9762\u7B7E\u540D 404 / DEV-009\uFF09\u3002\u672C\u6B21\u542F\u52A8\u5C06\u91CD\u65B0\u9884\u6784\u5EFA\uFF0C\u9996\u8F6E 30~60s \u5C5E\u6682\u6001\uFF08DEV-010\uFF09\u3002`
1631
+ `[fulgurjs] \u63D2\u4EF6\u7248\u672C\u53D8\u5316\uFF08${prev || "\u65E0\u8BB0\u5F55"} \u2192 ${pluginVersion}\uFF09\uFF0C\u5DF2\u81EA\u52A8\u6E05\u9664 ${path5.relative(root, viteDir)} \u9884\u6784\u5EFA\u7F13\u5B58\uFF08\u907F\u514D\u65E7\u95E8\u9762\u7B7E\u540D 404 / DEV-009\uFF09\u3002\u672C\u6B21\u542F\u52A8\u5C06\u91CD\u65B0\u9884\u6784\u5EFA\uFF0C\u9996\u8F6E 30~60s \u5C5E\u6682\u6001\uFF08DEV-010\uFF09\u3002`
1281
1632
  );
1282
1633
  }
1283
1634
  fs3.mkdirSync(viteDir, { recursive: true });
@@ -1290,7 +1641,7 @@ function syncViteCacheMarker(root, pluginVersion, log) {
1290
1641
  }
1291
1642
 
1292
1643
  // src/runtime-code.gen.ts
1293
- var runtime_code_gen_default = 'var re=/^v?(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?(?:-((?:[0-9A-Za-z-]+)(?:\\.[0-9A-Za-z-]+)*))?(?:\\+[0-9A-Za-z.-]+)?$/;function P(t){let n=re.exec(String(t).trim());return n?{major:Number(n[1]),minor:Number(n[2]??0),patch:Number(n[3]??0),pre:n[4]?n[4].split("."):[]}:null}function te(t,n){if(t.length===0&&n.length===0)return 0;if(t.length===0)return 1;if(n.length===0)return-1;let o=Math.max(t.length,n.length);for(let r=0;r<o;r++){let m=t[r],d=n[r];if(m===void 0)return-1;if(d===void 0)return 1;let S=/^\\d+$/.test(m),w=/^\\d+$/.test(d);if(S&&w){let L=Number(m)-Number(d);if(L!==0)return L}else{if(S!==w)return S?-1:1;if(m!==d)return m<d?-1:1}}return 0}function T(t,n){let o=P(t),r=P(n);return!o||!r?t<n?-1:t>n?1:0:o.major!==r.major?o.major-r.major:o.minor!==r.minor?o.minor-r.minor:o.patch!==r.patch?o.patch-r.patch:te(o.pre,r.pre)}var ne=/^[a-z]+[+:-]/i;function N(t,n){if(n===!1||n==null||n==="")return!0;let o=String(n).trim();return!o||o==="*"||o==="latest"||ne.test(o)?!0:o.split("||").some(r=>oe(t,r.trim()))}function oe(t,n){if(!n||n==="*")return!P(t)?.pre.length;let o=n.split(/\\s+-\\s+/);if(o.length===2){let d=o[0].trim(),S=o[1].trim();return!(!N(t,`>=${d}`)||!N(t,`<=${S}`))}let r=P(t);if(!r)return!1;let m=ie(n);if(m===null)return!0;for(let d of m)if(!ue(r,t,d))return!1;return!(r.pre.length>0&&!m.some(d=>d.ver.pre.length>0)&&!m.some(S=>S.ver.major===r.major&&S.ver.minor===r.minor&&S.ver.patch===r.patch))}function ie(t){let n=[],o=t.trim().split(/\\s+/).filter(Boolean);if(o.length===0)return null;for(let r of o){let m=/^(>=|<=|>|<|=|\\^|~)?(.*)$/.exec(r);if(!m)return null;let d=m[1],S=m[2],w=se(d,S);if(w===null)return null;n.push(...w)}return n}function se(t,n){let o=ce(n);if(!o)return null;let{ver:r,partial:m}=o;switch(t){case"^":{let d=ae(r);return d?[{op:">=",ver:r},{op:"<",ver:d}]:null}case"~":{let d=m>=2?{major:r.major,minor:r.minor+1,patch:0,pre:[]}:{major:r.major+1,minor:0,patch:0,pre:[]};return[{op:">=",ver:r},{op:"<",ver:d}]}case">=":return[{op:">=",ver:r}];case">":return m===1?[{op:">=",ver:{major:r.major+1,minor:0,patch:0,pre:[]}}]:m===2?[{op:">=",ver:{major:r.major,minor:r.minor+1,patch:0,pre:[]}}]:[{op:">",ver:r}];case"<":return m===1?[{op:"<",ver:{major:r.major,minor:0,patch:0,pre:[]}}]:m===2?[{op:"<",ver:{major:r.major,minor:r.minor,patch:0,pre:[]}}]:[{op:"<",ver:r}];case"<=":return[{op:"<=",ver:r}];case"=":case void 0:return m===1?[{op:">=",ver:r},{op:"<",ver:{major:r.major+1,minor:0,patch:0,pre:[]}}]:m===2?[{op:">=",ver:r},{op:"<",ver:{major:r.major,minor:r.minor+1,patch:0,pre:[]}}]:[{op:"=",ver:r}];default:return null}}function ae(t){return t.major>0?{major:t.major+1,minor:0,patch:0,pre:[]}:t.minor>0?{major:0,minor:t.minor+1,patch:0,pre:[]}:{major:0,minor:0,patch:t.patch+1,pre:[]}}function ce(t){let n=t.replace(/^v/,"").trim();if(!n||n==="*"||n==="x"||n==="X")return{ver:{major:0,minor:0,patch:0,pre:[]},partial:0};let o=n.split("."),r=[],m=0;for(let w of o.slice(0,3))if(/^\\d+$/.test(w))r.push(Number(w)),m++;else{if(w==="x"||w==="X"||w==="*")break;break}let d=n.split("-"),S=d.length>1?d.slice(1).join("-").split("+")[0].split("."):[];return m===0&&S.length===0?{ver:{major:0,minor:0,patch:0,pre:[]},partial:0}:{ver:{major:r[0]??0,minor:r[1]??0,patch:r[2]??0,pre:S},partial:m}}function le(t,n){switch(n){case">=":return t>=0;case">":return t>0;case"<":return t<0;case"<=":return t<=0;case"=":return t===0}}function ue(t,n,o){let r=`${t.major}.${t.minor}.${t.patch}`+(t.pre.length?`-${t.pre.join(".")}`:"");if(o.upper)return!(!(T(r,`${o.ver.major}.${o.ver.minor}.${o.ver.patch}`+(o.ver.pre.length?`-${o.ver.pre.join(".")}`:""))>=0)||!(T(r,`${o.upper.major}.${o.upper.minor}.${o.upper.patch}`)<0));let m=T(r,`${o.ver.major}.${o.ver.minor}.${o.ver.patch}`+(o.ver.pre.length?`-${o.ver.pre.join(".")}`:"")),d=le(m,o.op);return o.ver.pre.length>0&&t.pre.length===0&&(o.op===">"||o.op==="<")?!1:d}var R=class extends Error{code;details;constructor(n,o,r){super(`[fulgurjs:${n}] ${o}`),this.name="FgError",this.code=n,this.details=r}},b={REMOTE_LOAD_FAILED:"MFU-001",REMOTE_NAME_MISMATCH:"MFU-002",SHARE_STRICT_VERSION:"MFU-003",SHARE_NOT_AVAILABLE:"MFU-004",CONTAINER_REINIT_CONFLICT:"MFU-005",MODULE_NOT_EXPOSED:"MFU-006",PRELOAD_FAILED:"MFU-007",REMOTE_UNKNOWN:"MFU-008",EMPTY_EXPORTS:"MFU-009",SINGLETON_SKEW:"MFU-010"};var V="2.0.3";var H=15e3,K=2,me=5,fe=3e4;function pe(){let t={},n=new Map,o=[],r=new Map,m=new Map,d=new WeakMap,S=new WeakMap,w={},L=()=>{for(let e of o)try{e.init?.(w)}catch(i){console.warn("[fulgurjs] runtimePlugin init failed:",e.name,i)}},I=e=>t[e]??={};function $(e){try{w.onRemoteError?.(e)}catch{}typeof window<"u"&&window.dispatchEvent(new CustomEvent("fulgurjs:error",{detail:e}))}function z(e="default"){return I(e),t}function W(e,i,s,l,h={}){let c=I(e||"default"),f=c[i]??={};f[s]||(f[s]={version:s,get:l,from:h.from??"unknown",eager:!!h.eager,loaded:!!h.loaded})}function A(e){for(let i of e){let s=n.get(i.name);n.set(i.name,{timeout:H,retries:K,...s,...i,state:s?.state??"idle",breakerState:s?.breakerState??{fails:0,openUntil:0},debug:s?.debug??{entry:i.entry,status:"idle"}})}}function G(e){A([e])}function J(e){o.push(...e),L()}async function B(e,i={}){let s=i.shareScope||"default",l=i.shareKey||e,c=I(s)[l]||{},f=Object.keys(c),y=i.requiredVersion,g=f.filter(a=>y===void 0||y===!1||N(a,y)),u;if(i.singleton&&f.length>0){let a=f.filter(p=>c[p].loaded);if(u=[...a.length?a:f].sort(T).pop(),f.length>1||!g.includes(u)){let p=c[u],j=`singleton skew "${l}": req "${y??"any"}" use ${u} from ${p.from}`;if(i.strictVersion){let _=new R(b.SHARE_STRICT_VERSION,j,{shareKey:l,requiredVersion:y});throw $({remote:p.from,error:_}),_}console.warn(`[fulgurjs:MFU-010] ${j}`)}}else if(u=[...g].sort(T).pop(),!u){if(i.strictVersion){let p=new R(b.SHARE_STRICT_VERSION,`no satisfying version for "${l}" (required "${y}") in share scope "${s}"`);throw $({remote:l,error:p}),p}if(i.fallback)return i.fallback();let a=new R(b.SHARE_NOT_AVAILABLE,`shared "${l}" (${y??"any"}) unavailable in scope "${s}" (no local fallback)`,{shareKey:l,requiredVersion:y});throw $({remote:l,error:a}),a}let E=c[u];if(w.resolveShare){let a=await w.resolveShare({shareKey:l,shareScope:s,requiredVersion:y,picked:E,available:Object.values(c)});a&&(E=a)}return E.loaded=!0,E.get()}function X(e,i,s){return new Promise((l,h)=>{let c=setTimeout(()=>h(new Error(`timeout after ${i}ms: ${s}`)),i);e.then(f=>{clearTimeout(c),l(f)},f=>{clearTimeout(c),h(f)})})}let Y=e=>new Promise(i=>setTimeout(i,e));function k(e,i){if(!e||typeof e.get!="function")throw new Error(`remoteEntry of "${i.name}" does not export a container interface (get/init)`);if(e.name&&i.name&&e.name!==i.name){let s=`remoteEntry self-reported name "${e.name}" mismatches configured name "${i.name}"`;if(i.promise)console.warn(`[fulgurjs] ${s} (promise-based remote, continuing)`);else throw Object.assign(new Error(s),{code:b.REMOTE_NAME_MISMATCH})}}async function x(e,i){return X(import(e),i.timeout??H,`load remoteEntry ${e}`)}async function C(e,i){let s=e.shareScope||"default";if(e.container){let c=S.get(e.container);if(c&&c!==s)throw new R(b.CONTAINER_REINIT_CONFLICT,`container "${e.name}" already initialized with share scope "${c}", cannot re-init with "${s}"`);return e.container}if(e.containerPromise)return e.containerPromise;let l=e.breakerState;if(l.openUntil>Date.now()){let c=new R(b.REMOTE_LOAD_FAILED,`circuit breaker open for remote "${e.name}" until ${new Date(l.openUntil).toISOString()}`,{remote:e.name});throw $({remote:e.name,error:c}),c}e.state="loading",e.debug.status="loading";let h=(async()=>{let c=[];if(e.promise)c.push(async()=>{let a=await e.promise(),p=typeof a=="string"?await x(a,e):a;return k(p,e),p});else for(let a of[e.entry,...e.fallback??[]])c.push(async()=>{let p=await x(a,e);return k(p,e),p});let f,y,g=!1,u=i?.retries??e.retries??K;for(let a of c){for(let p=0;p<=u;p++){let j=performance.now();try{f=await a(),e.lastLoadMs=Math.round(performance.now()-j),e.debug.lastLoadMs=e.lastLoadMs,g=!0;break}catch(_){if(y=_,_?.code)throw _;p<u&&await Y(200*2**p)}}if(g)break}if(!g||!f){let a=[];throw/^https?:\\/\\//.test(e.entry)&&typeof location<"u"?(a.push(`1. is the remote dev server running? try opening ${e.entry} in the browser \\u2014 it must return JS, not HTML/an error`),a.push("2. is the URL correct in federation({ remotes })? dev and prod entries can differ"),a.push("3. CORS: the remote dev server must allow cross-origin requests (fulgurjs-federation enables server.cors automatically; a custom server config may have disabled it)")):(a.push(`1. is the remote deployed and reachable? try opening ${e.entry} in the browser \\u2014 it must return JS`),a.push("2. NGINX/CDN routing: the entry path must serve the remoteEntry JS file (check try_files / fallback rules)")),new R(b.REMOTE_LOAD_FAILED,`failed to load remote "${e.name}" from ${e.entry}: ${String(y?.message??y)}\n`+a.join(`\n`),{remote:e.name})}k(f,e);let E=S.get(f);if(E&&E!==s)throw new R(b.CONTAINER_REINIT_CONFLICT,`container "${e.name}" already initialized with share scope "${E}", cannot re-init with "${s}"`);return typeof f.init=="function"&&await f.init(t),S.set(f,s),e.container=f,e.state="loaded",e.debug.status="loaded",l.fails=0,f})();e.containerPromise=h;try{return await h}catch(c){if(e.containerPromise=void 0,e.state="failed",e.debug.status="failed",e.debug.error=String(c?.message??c),l.fails+=1,l.fails>=me&&(l.openUntil=Date.now()+fe,l.fails=0),c instanceof R)throw $({remote:e.name,error:c}),c;if(c?.code)throw $({remote:e.name,error:c}),c;let f=new R(b.REMOTE_LOAD_FAILED,String(c?.message??c),{remote:e.name});throw $({remote:e.name,error:f}),f}}function U(e){let i=e.indexOf("/");return i===-1?{remote:e,module:""}:{remote:e.slice(0,i),module:F(e.slice(i+1))}}function F(e){return e?e.startsWith(".")?e:`./${e}`:""}async function Z(e,i){let{remote:s,module:l}=U(e);w.beforeLoadRemote?.({remote:s,module:l});let h=n.get(s);if(!h)throw new R(b.REMOTE_UNKNOWN,`unknown remote "${s}". Register it via federation({ remotes }) or registerRemote().`,{remote:s});let c;try{let g=l&&h.manifestUrl?D(e):Promise.resolve();[c]=await Promise.all([C(h,{retries:i?.retries}),g])}catch(g){if(i?.fallbackModule)return console.error(`[fulgurjs] loadRemote("${e}") failed; returning fallbackModule (\\u663E\\u5F0F\\u964D\\u7EA7\\uFF0C\\u9519\\u8BEF\\u5DF2\\u900F\\u51FA)`,g),$({remote:s,error:g}),await i.fallbackModule();throw g}if(!l)return c;let f=`${s}@${h.shareScope||"default"}#${l}`;r.has(f)||r.set(f,c.get(l).catch(g=>{throw r.delete(f),g instanceof R||g?.code?g:new R(b.REMOTE_LOAD_FAILED,`failed to load module "${l}" from remote "${s}": ${String(g?.message??g)}`,{remote:s,module:l})}));let y;try{y=await r.get(f)}catch(g){if(i?.fallbackModule)return console.error(`[fulgurjs] loadRemote("${e}") failed; returning fallbackModule (\\u663E\\u5F0F\\u964D\\u7EA7\\uFF0C\\u9519\\u8BEF\\u5DF2\\u900F\\u51FA)`,g),$({remote:s,error:g}),await i.fallbackModule();throw g}if(w.afterLoadRemote?.({remote:s,module:l,module_ns:y}),y&&typeof y=="object"&&Object.keys(y).length===0){let g=new R(b.EMPTY_EXPORTS,`no exports: ${l} @ ${s}`,{remote:s,module:l});$({remote:s,error:g}),console.error(`[fulgurjs:MFU-009] ${g.message}`)}return y}function Q(e){let i=n.get(e);if(!i)throw new R(b.REMOTE_UNKNOWN,`unknown remote "${e}"`,{remote:e});return C(i)}async function D(e,i={}){let{remote:s,module:l}=U(e),h=n.get(s);if(!h)throw new R(b.REMOTE_UNKNOWN,`unknown remote "${s}"`,{remote:s});let c=i.mode??"preload",f=(u,E)=>{if(u.sheet)return Promise.resolve();let a=d.get(u);if(a)return a;let p=new Promise(j=>{let _=()=>{u.removeEventListener("load",_),u.removeEventListener("error",v),j()},v=()=>{$({remote:s,error:new R(b.PRELOAD_FAILED,`failed to load remote stylesheet ${E}`,{remote:s})}),_()};u.addEventListener("load",_,{once:!0}),u.addEventListener("error",v,{once:!0}),u.sheet&&_()});return d.set(u,p),p},y=(u,E)=>{if(typeof document>"u")return Promise.resolve();let a=document.querySelector(`link[href="${u}"]`);if(a)return E==="style"&&c==="preload"?d.get(a)??Promise.resolve():Promise.resolve();let p=document.createElement("link");p.rel=E==="style"?"stylesheet":"modulepreload",p.href=u,c==="prefetch"&&(p.fetchPriority="low");let j=E==="style"?f(p,u):Promise.resolve();return document.head.appendChild(p),E==="style"&&c==="preload"?j:Promise.resolve()},g=u=>{let E=typeof document<"u"?document.baseURI:void 0,a=new URL(h.entry,E||"http://fulgurjs.invalid/");return new URL(u,a).href};try{if(h.manifestUrl){let u=m.get(h.manifestUrl);u||(u=fetch(h.manifestUrl,{cache:"no-cache"}).then(a=>a.ok?a.json():void 0),m.set(h.manifestUrl,u),u.then(a=>{a||m.delete(h.manifestUrl)},()=>m.delete(h.manifestUrl)));let E=await u;if(E){await y(h.entry,"modulepreload");let a=E.exposes,p=Array.isArray(a)?a.filter(v=>v&&typeof v=="object").map(v=>[String(v.name??""),v]):a&&typeof a=="object"?Object.entries(a):[],j=l?p.filter(([v,O])=>F(String(O?.name??v))===l):p,_=[];for(let[,v]of j)if(typeof v?.file=="string"&&await y(g(v.file),"modulepreload"),Array.isArray(v?.css))for(let O of v.css){if(typeof O!="string")continue;let ee=y(g(O),"style");c==="preload"&&_.push(ee)}await Promise.all(_);return}}await y(h.entry,"modulepreload")}catch(u){$({remote:s,error:new R(b.PRELOAD_FAILED,String(u?.message??u),{remote:s})})}}return typeof window>"u"||(window.__FULGURJS_SCOPE__=t,window.__FULGURJS_INFO__={get remotes(){let e={};for(let[i,s]of n)e[i]={...s.debug,entry:s.entry};return e},errors:[]}),{shareScopeMap:t,initSharing:z,registerShare:W,registerRemotes:A,registerRemote:G,registerPlugins:J,loadShare:B,loadRemote:Z,getContainer:Q,preloadRemote:D,parseSpec:U}}var q=globalThis,M=q.__FULGURJS_RUNTIME__??pe();q.__FULGURJS_RUNTIME__=M;try{Object.freeze(M)}catch{}var we=V;function be(){return M}var ve=M.initSharing,_e=M.registerShare,Me=M.registerRemotes,$e=M.registerRemote,je=M.registerPlugins,Te=M.loadShare,Le=M.loadRemote,Oe=M.getContainer,Pe=M.preloadRemote,Ne=M.shareScopeMap;function Ie(t){if(t&&typeof t=="object"&&"default"in t){let n=t.default;return n!==void 0?n:t}return t}var ke=M;export{ke as default,Oe as getContainer,be as getRuntime,ve as initSharing,Le as loadRemote,Te as loadShare,Pe as preloadRemote,je as registerPlugins,$e as registerRemote,Me as registerRemotes,_e as registerShare,M as runtime,Ne as shareScopeMap,Ie as unwrapDefault,we as version};\n';
1644
+ 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 R=/^\\d+$/.test(f),w=/^\\d+$/.test(y);if(R&&w){let T=Number(f)-Number(y);if(T!==0)return T}else{if(R!==w)return R?-1:1;if(f!==y)return f<y?-1:1}}return 0}function j(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(),R=s[1].trim();return!(!P(o,`>=${y}`)||!P(o,`<=${R}`))}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(R=>R.ver.major===n.major&&R.ver.minor===n.minor&&R.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],R=f[2],w=le(y,R);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("-"),R=y.length>1?y.slice(1).join("-").split("+")[0].split("."):[];return f===0&&R.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:R},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!(!(j(n,`${s.ver.major}.${s.ver.minor}.${s.ver.patch}`+(s.ver.pre.length?`-${s.ver.pre.join(".")}`:""))>=0)||!(j(n,`${s.upper.major}.${s.upper.minor}.${s.upper.patch}`)<0));let f=j(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 b=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="2.1.0";var x=15e3,z=2,de=5,ge=3e4,he=4e3,ye=.2;function Ee(){let o=Object.create(null),i=new Map,s=[],n=new Map,f=new Map,y=new WeakMap,R=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 $(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:x,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(j).pop(),p.length>1||!g.includes(m)){let u=a[m],k=`singleton skew "${l}": req "${d??"any"}" use ${m} from ${u.from}`;if(t.strictVersion){let v=new b(S.SHARE_STRICT_VERSION,k,{shareKey:l,requiredVersion:d});throw $({remote:u.from,error:v}),v}console.warn(`[fulgurjs:MFU-010] ${k}`)}}else if(m=[...g].sort(j).pop(),!m){if(t.strictVersion){let u=new b(S.SHARE_STRICT_VERSION,`no satisfying version for "${l}" (required "${d}") in share scope "${r}"`);throw $({remote:l,error:u}),u}if(t.fallback)return t.fallback();let c=new b(S.SHARE_NOT_AVAILABLE,`shared "${l}" (${d??"any"}) unavailable in scope "${r}" (no local fallback)`,{shareKey:l,requiredVersion:d});throw $({remote:l,error:c}),c}let E=a[m];if(w.resolveShare){let c=await w.resolveShare({shareKey:l,shareScope:r,requiredVersion:d,picked:E,available:Object.values(a)});c&&(E=c)}return E.loaded=!0,E.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??x,`load remoteEntry ${e}`)}async function V(e,t){let r=e.shareScope||"default";if(e.container){let a=R.get(e.container);if(a&&a!==r)throw new b(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 b(S.REMOTE_LOAD_FAILED,`circuit breaker open for remote "${e.name}" until ${new Date(l.openUntil).toISOString()}`,{remote:e.name});throw $({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??x,`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 k=performance.now();try{p=await c(),e.lastLoadMs=Math.round(performance.now()-k),e.debug.lastLoadMs=e.lastLoadMs,g=!0;break}catch(v){if(d=v,v?.code)throw v;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 b(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 E=R.get(p);if(E&&E!==r)throw new b(S.CONTAINER_REINIT_CONFLICT,`container "${e.name}" already initialized with share scope "${E}", cannot re-init with "${r}"`);return typeof p.init=="function"&&await p.init(o),R.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 b)throw $({remote:e.name,error:a}),a;if(a?.code)throw $({remote:e.name,error:a}),a;let p=new b(S.REMOTE_LOAD_FAILED,String(a?.message??a),{remote:e.name});throw $({remote:e.name,error:p}),p}}function U(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}=U(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 b(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),$({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 b||g?.code?g:new b(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),$({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 b(S.EMPTY_EXPORTS,`no exports: ${l} @ ${r}`,{remote:r,module:l});$({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 b(S.REMOTE_UNKNOWN,`unknown remote "${e}"`,{remote:e});return V(t)}async function K(e,t={}){let{remote:r,module:l}=U(e),h=i.get(r);if(!h)throw new b(S.REMOTE_UNKNOWN,`unknown remote "${r}"`,{remote:r});let a=t.mode??"preload",p=(m,E)=>{if(m.sheet)return Promise.resolve();let c=y.get(m);if(c)return c;let u=new Promise(k=>{let v=()=>{m.removeEventListener("load",v),m.removeEventListener("error",O),k()},O=()=>{$({remote:r,error:new b(S.PRELOAD_FAILED,`failed to load remote stylesheet ${E}`,{remote:r})}),v()};m.addEventListener("load",v,{once:!0}),m.addEventListener("error",O,{once:!0}),m.sheet&&v()});return y.set(m,u),u},d=(m,E)=>{if(typeof document>"u")return Promise.resolve();let c=document.querySelector(`link[href="${m}"]`);if(c)return E==="style"&&a==="preload"?y.get(c)??Promise.resolve():Promise.resolve();let u=document.createElement("link");u.rel=E==="style"?"stylesheet":"modulepreload",u.href=m,a==="prefetch"&&(u.fetchPriority="low");let k=E==="style"?p(u,m):Promise.resolve();return document.head.appendChild(u),E==="style"&&a==="preload"?k:Promise.resolve()},g=m=>{let E=typeof document<"u"?document.baseURI:void 0,c=new URL(h.entry,E||"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 E=await m;if(E){let c=E.schemaVersion;if(typeof c=="number"&&(!Number.isInteger(c)||c>1)){$({remote:r,error:new b(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=E.exposes,k=Array.isArray(u)?u.filter(_=>_&&typeof _=="object").map(_=>[String(_.name??""),_]):u&&typeof u=="object"?Object.entries(u):[],v=l?k.filter(([_,L])=>H(String(L?.name??_))===l):k,O=[];for(let[,_]of v)if(typeof _?.file=="string"&&await d(g(_.file),"modulepreload"),Array.isArray(_?.css))for(let L of _.css){if(typeof L!="string")continue;let ne=d(g(L),"style");a==="preload"&&O.push(ne)}await Promise.all(O);return}}await d(h.entry,"modulepreload")}catch(m){$({remote:r,error:new b(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:U}}var W=globalThis,M=W.__FULGURJS_RUNTIME__??Ee();W.__FULGURJS_RUNTIME__=M;try{Object.freeze(M)}catch{}var _e=q;function ke(){return M}var je=M.initSharing,Oe=M.registerShare,Te=M.registerRemotes,Le=M.registerRemote,Ie=M.registerPlugins,Pe=M.loadShare,Ne=M.loadRemote,Ae=M.getContainer,Ue=M.preloadRemote,xe=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,ke as getRuntime,je as initSharing,Ne as loadRemote,Pe as loadShare,xe as parseSpec,Ue as preloadRemote,Ie as registerPlugins,Le as registerRemote,Te as registerRemotes,Oe as registerShare,M as runtime,Fe as shareScopeMap,Ce as unwrapDefault,_e as version};\n';
1294
1645
 
1295
1646
  // src/index.ts
1296
1647
  function readRuntimeCode() {
@@ -1307,7 +1658,7 @@ function enumerateCjsExports(packageName, appRoot) {
1307
1658
  if (cached) return cached;
1308
1659
  let names = [];
1309
1660
  try {
1310
- const appRequire = createRequire2(path5.join(appRoot, "package.json"));
1661
+ const appRequire = createRequire2(path6.join(appRoot, "package.json"));
1311
1662
  const mod = appRequire(packageName);
1312
1663
  names = Object.keys(mod);
1313
1664
  } catch {
@@ -1367,14 +1718,19 @@ function federation(options) {
1367
1718
  entryInitInjected: /* @__PURE__ */ new Set(),
1368
1719
  manualChunkGroups: /* @__PURE__ */ new Map(),
1369
1720
  sharedClosureRoots: [],
1370
- facadeDynamic: false
1721
+ facadeDynamic: false,
1722
+ transformedModules: /* @__PURE__ */ new Set()
1723
+ };
1724
+ const recordRewritten = (id) => {
1725
+ state.transformedModules.add(id);
1726
+ state.transformedModules.add(id.split("?")[0]);
1371
1727
  };
1372
1728
  const pre = {
1373
1729
  name: "fulgurjs:core",
1374
1730
  enforce: "pre",
1375
1731
  async config(userConfig, env) {
1376
1732
  state.command = env.command;
1377
- const root = path5.resolve(userConfig.root ?? process.cwd());
1733
+ const root = path6.resolve(userConfig.root ?? process.cwd());
1378
1734
  const normalized = normalizeOptions(options, root, env.command);
1379
1735
  state.normalized = normalized;
1380
1736
  const extra = {};
@@ -1419,10 +1775,34 @@ export { default } from ${JSON.stringify(url)};
1419
1775
  }
1420
1776
  if (env.command === "serve") {
1421
1777
  syncViteCacheMarker(root, normalized.pluginVersion, (msg) => console.warn(msg));
1778
+ const corsOption = normalized.devCorsOrigins && normalized.devCorsOrigins !== "*" ? { origin: normalized.devCorsOrigins } : true;
1422
1779
  extra.server = {
1423
1780
  ...userConfig.server ?? {},
1424
- cors: userConfig.server?.cors ?? true
1781
+ cors: userConfig.server?.cors ?? corsOption
1425
1782
  };
1783
+ const host = userConfig.server?.host;
1784
+ if (isNonLoopbackHost(host)) {
1785
+ if (!normalized.devCorsOrigins || normalized.devCorsOrigins === "*") {
1786
+ console.warn(
1787
+ formatFulgurjsDiagnostic({
1788
+ code: "DEV-011",
1789
+ symptom: `server.host=${String(host)} \u975E loopback \u4E14 dev \u8DE8\u6E90\u7B56\u7565\u4E3A\u901A\u914D\uFF08*\uFF09\uFF1A\u4EFB\u4F55\u80FD\u8BBF\u95EE\u8BE5\u673A\u7684\u6765\u6E90\u90FD\u53EF\u62C9\u53D6\u672C\u5E94\u7528\u8054\u90A6\u7AEF\u70B9\u4E0E\u6E90\u7801\u6A21\u5757`,
1790
+ cause: "devCorsOrigins \u672A\u914D\u7F6E\u65F6\u4FDD\u6301\u73B0\u72B6\u517C\u5BB9\uFF08*\uFF09\uFF1B\u8DE8\u673A\u5F00\u53D1\u66B4\u9732\u9762\u968F\u4E4B\u6269\u5927",
1791
+ fix: `\u6309\u5BBF\u4E3B\u6765\u6E90\u663E\u5F0F\u6536\u7D27\uFF1AdevCorsOrigins: ['http://<host>:<port>', ...]\uFF08\u6216\u786E\u8BA4\u8BE5\u673A\u5904\u4E8E\u53EF\u4FE1\u7F51\u7EDC\uFF09`
1792
+ })
1793
+ );
1794
+ }
1795
+ if (normalized.devFsRoot) {
1796
+ console.warn(
1797
+ formatFulgurjsDiagnostic({
1798
+ code: "DEV-012",
1799
+ symptom: `server.host=${String(host)} \u975E loopback \u4E14 dev manifest \u643A\u5E26 fsRoot\uFF08remote \u6839\u76EE\u5F55\u672C\u673A\u7EDD\u5BF9\u8DEF\u5F84\uFF09`,
1800
+ cause: "fsRoot \u4F9B\u540C\u673A\u8054\u8C03\u7684\u5BBF\u4E3B dts \u7C7B\u578B\u76F4\u8FDE\uFF1B2.x \u9ED8\u8BA4 true \u4FDD\u6301\u73B0\u72B6\uFF0C\u4E0B\u4E2A\u4E3B\u7248\u672C\u62DF\u6539\u4E3A\u663E\u5F0F\u5F00\u542F",
1801
+ fix: `\u540C\u673A\u8054\u8C03\u65E0\u9700\u52A8\u4F5C\uFF1B\u8DE8\u673A/\u4E0D\u53EF\u4FE1\u7F51\u7EDC\u53EF devFsRoot: false\uFF08\u5BBF\u4E3B dts \u5C06\u964D\u7EA7\u4E3A any \u6869\u5E76\u6709\u660E\u786E\u63D0\u793A\uFF09`
1802
+ })
1803
+ );
1804
+ }
1805
+ }
1426
1806
  } else {
1427
1807
  const userTarget = userConfig.build?.target;
1428
1808
  if (userTarget) {
@@ -1437,6 +1817,12 @@ export { default } from ${JSON.stringify(url)};
1437
1817
  }
1438
1818
  if (normalized.remotes.length > 0 && normalized.devSharedSelf) {
1439
1819
  state.facadeDynamic = true;
1820
+ const userMc = userConfig.build?.rollupOptions?.output?.manualChunks;
1821
+ debugLog("facade", {
1822
+ stage: "config",
1823
+ facadeDynamic: true,
1824
+ manualChunks: Array.isArray(userConfig.build?.rollupOptions?.output) ? "array" : typeof userMc
1825
+ });
1440
1826
  const userOutput = userConfig.build?.rollupOptions?.output;
1441
1827
  if (Array.isArray(userOutput)) {
1442
1828
  console.warn(
@@ -1504,7 +1890,7 @@ export { default } from ${JSON.stringify(url)};
1504
1890
  }
1505
1891
  }
1506
1892
  },
1507
- resolveId(source) {
1893
+ resolveId(source, importer) {
1508
1894
  let s = source;
1509
1895
  if (s.startsWith("/@id/")) s = s.slice(5);
1510
1896
  if (s.startsWith("__x00__")) s = "\0" + s.slice(7);
@@ -1512,6 +1898,16 @@ export { default } from ${JSON.stringify(url)};
1512
1898
  const bare = q === -1 ? s : s.slice(0, q);
1513
1899
  const query = q === -1 ? "" : s.slice(q);
1514
1900
  const bareClean = bare.startsWith("\0") ? bare.slice(1) : bare;
1901
+ if (state.normalized && importer) {
1902
+ const impClean = importer.split("?")[0];
1903
+ const isOurVirtual = impClean.startsWith("virtual:fulgurjs-") || impClean.startsWith("\0virtual:fulgurjs-");
1904
+ if (!isOurVirtual && !impClean.includes("/node_modules/.vite/") && !state.sharedClosureRoots.some((r) => impClean.startsWith(r.root)) && (state.transformedModules.has(importer) || state.transformedModules.has(impClean))) {
1905
+ const hit = state.normalized.shared.find((sh) => sh.aliases.includes(bareClean));
1906
+ if (hit) {
1907
+ return RESOLVED.sharedNsFacade(hit.shareKey) + query;
1908
+ }
1909
+ }
1910
+ }
1515
1911
  const n = state.normalized;
1516
1912
  if (n && !bare.startsWith("\0") && !bareClean.startsWith(".") && !bareClean.startsWith("/") && !bareClean.startsWith("virtual:")) {
1517
1913
  const slash = bareClean.indexOf("/");
@@ -1530,6 +1926,7 @@ export { default } from ${JSON.stringify(url)};
1530
1926
  if (bareClean === RUNTIME_PROXY_VIRTUAL_ID) return RESOLVED.runtimeProxy;
1531
1927
  if (bareClean === INIT_VIRTUAL_ID) return RESOLVED.init;
1532
1928
  if (bareClean === "virtual:fulgurjs-remote-schema") return bareClean;
1929
+ if (bareClean === "virtual:fulgurjs-api") return bareClean;
1533
1930
  if (bareClean === "virtual:fulgurjs-provides") return RESOLVED.provides;
1534
1931
  if (bareClean === "virtual:fulgurjs-remote-entry") return RESOLVED.remoteEntry;
1535
1932
  if (bareClean.startsWith(SHARED_NS_FACADE_PREFIX)) {
@@ -1556,6 +1953,9 @@ export { default } from ${JSON.stringify(url)};
1556
1953
  if (clean === "virtual:fulgurjs-provides" && state.normalized) {
1557
1954
  return genDevProvides(state.normalized);
1558
1955
  }
1956
+ if (clean === "virtual:fulgurjs-api") {
1957
+ return genApiFacade();
1958
+ }
1559
1959
  if (clean === "virtual:fulgurjs-remote-schema" && state.normalized) {
1560
1960
  if (state.command === "build") return genEmptyRemoteSchemaModule();
1561
1961
  remoteSchemaPromise ??= probeRemotesAndBuildSchema(state.normalized).then(
@@ -1623,6 +2023,7 @@ ${code}`, map: null };
1623
2023
  if (/\.vue(\?|$)/.test(id)) {
1624
2024
  if (state.command === "build" && /type=script/.test(id)) {
1625
2025
  return transformModule(code, id, {
2026
+ onRewrite: () => recordRewritten(id),
1626
2027
  options: state.normalized,
1627
2028
  rewriteShared: true,
1628
2029
  allowNodeModules,
@@ -1634,6 +2035,10 @@ ${code}`, map: null };
1634
2035
  }
1635
2036
  if (!isTransformableId(id, allowNodeModules)) return null;
1636
2037
  return transformModule(code, id, {
2038
+ onRewrite: () => {
2039
+ debugLog("transform", { stage: "pre", mode: state.command, module: redactModulePath(id, state.normalized.root) });
2040
+ recordRewritten(id);
2041
+ },
1637
2042
  options: state.normalized,
1638
2043
  // build:全量改写;dev:默认仅纯 remote 改写 shared(被宿主消费的组件需协商到宿主实例),
1639
2044
  // 双角色宿主可显式 devSharedSelf: true 参与协商
@@ -1656,7 +2061,7 @@ ${code}`, map: null };
1656
2061
  for (const tag of html.match(moduleScriptRe) ?? []) {
1657
2062
  const src = srcRe.exec(tag)?.[1];
1658
2063
  if (!src || src.startsWith("http") || src.startsWith("//")) continue;
1659
- const abs = path5.resolve(state.normalized.root, src.startsWith("/") ? src.slice(1) : src);
2064
+ const abs = path6.resolve(state.normalized.root, src.startsWith("/") ? src.slice(1) : src);
1660
2065
  state.entryAbsPaths.add(abs);
1661
2066
  }
1662
2067
  return html;
@@ -1668,7 +2073,7 @@ ${code}`, map: null };
1668
2073
  if (state.manualChunkSpecsPending) {
1669
2074
  for (const [group, specifier] of state.manualChunkSpecsPending) {
1670
2075
  try {
1671
- const r = await this.resolve(specifier, path5.join(n.root, "index.html"));
2076
+ const r = await this.resolve(specifier, path6.join(n.root, "index.html"));
1672
2077
  if (r?.id) {
1673
2078
  state.manualChunkGroups.set(r.id, group);
1674
2079
  state.manualChunkGroups.set(r.id.split("?")[0], group);
@@ -1698,7 +2103,7 @@ ${code}`, map: null };
1698
2103
  };
1699
2104
  for (const item of n.shared) {
1700
2105
  if (item.import === false) continue;
1701
- const selfFile = await this.resolve(item.import, path5.join(n.root, "index.html")).then(
2106
+ const selfFile = await this.resolve(item.import, path6.join(n.root, "index.html")).then(
1702
2107
  (r) => r?.id?.split("?")[0] ?? null
1703
2108
  ).catch(() => null);
1704
2109
  for (const alias of item.aliases) {
@@ -1713,7 +2118,7 @@ ${code}`, map: null };
1713
2118
  }
1714
2119
  }
1715
2120
  if (!file) {
1716
- file = await this.resolve(alias, path5.join(n.root, "index.html")).then(
2121
+ file = await this.resolve(alias, path6.join(n.root, "index.html")).then(
1717
2122
  (r) => r?.id?.split("?")[0] ?? null
1718
2123
  ).catch(() => null);
1719
2124
  }
@@ -1726,10 +2131,17 @@ ${code}`, map: null };
1726
2131
  }
1727
2132
  }
1728
2133
  state.sharedClosureRoots = [...rootKeys.entries()].map(([root, keys]) => ({ root, keys }));
2134
+ if (state.sharedClosureRoots.length > 0) {
2135
+ debugLog("facade", {
2136
+ stage: "buildStart",
2137
+ sharedClosureRoots: state.sharedClosureRoots.length,
2138
+ keys: [...new Set(state.sharedClosureRoots.flatMap((r) => [...r.keys]))]
2139
+ });
2140
+ }
1729
2141
  }
1730
2142
  if (n.exposes.length > 0) {
1731
2143
  for (const e of n.exposes) {
1732
- const resolved = await this.resolve(e.import, path5.join(n.root, "index.html"));
2144
+ const resolved = await this.resolve(e.import, path6.join(n.root, "index.html"));
1733
2145
  if (resolved) {
1734
2146
  state.exposeAbsPaths[e.import] = resolved.id.split("?")[0];
1735
2147
  } else {
@@ -1782,6 +2194,11 @@ ${code}`, map: null };
1782
2194
  }
1783
2195
  const entryChunkName = Object.keys(bundle).find((k) => bundle[k].type === "chunk" && k === n.filename);
1784
2196
  const manifest = genProdManifest(n, state.exposeFiles, entryChunkName ?? n.filename);
2197
+ debugLog("manifest", {
2198
+ stage: "generateBundle",
2199
+ exposes: Object.keys(state.exposeFiles).length,
2200
+ exposesWithCss: Object.values(state.exposeFiles).filter((e) => e.css.length > 0).length
2201
+ });
1785
2202
  this.emitFile({
1786
2203
  type: "asset",
1787
2204
  fileName: "fulgurjs-manifest.json",
@@ -1809,7 +2226,10 @@ ${code}`, map: null };
1809
2226
  const raw = (req.url ?? "").split("?")[0];
1810
2227
  const stripped = raw.startsWith(baseNorm) ? `/${raw.slice(baseNorm.length)}` : raw;
1811
2228
  if (stripped === "/@fulgurjs-entry.js" || stripped === "/@fulgurjs-manifest.json") {
1812
- res.setHeader("Access-Control-Allow-Origin", "*");
2229
+ const origin = Array.isArray(req.headers.origin) ? req.headers.origin[0] : req.headers.origin;
2230
+ for (const [k, v] of Object.entries(corsHeadersFor(origin, n.devCorsOrigins))) {
2231
+ res.setHeader(k, v);
2232
+ }
1813
2233
  res.setHeader("Access-Control-Allow-Methods", "GET,OPTIONS");
1814
2234
  res.setHeader("Access-Control-Allow-Headers", "*");
1815
2235
  if (req.method === "OPTIONS") {
@@ -1882,20 +2302,11 @@ ${code}`, map: null };
1882
2302
  if (state.command === "serve" && clean.includes("node_modules") && !id.includes(".vite/deps") && !devRewriteAll) {
1883
2303
  return null;
1884
2304
  }
1885
- if (state.command === "build" && !/\.vue(\?|$)/.test(id)) {
1886
- const quickCheck = /require\s*\(\s*["']|(?:from|import)\s*["']/.test(code);
1887
- if (!quickCheck) return null;
1888
- const allowNodeModules = isPureRemoteBuild;
1889
- return transformModule(code, id, {
1890
- options: state.normalized,
1891
- rewriteShared: true,
1892
- allowNodeModules,
1893
- sharedClosureRoots: state.sharedClosureRoots
1894
- });
2305
+ if (state.command === "build") {
2306
+ return buildFallbackTransform(code, id);
1895
2307
  }
1896
- const rewriteShared = state.command === "build" || state.normalized.devSharedSelf;
2308
+ const rewriteShared = state.normalized.devSharedSelf;
1897
2309
  const remapSpecifier = (spec) => {
1898
- if (state.normalized.shared.some((s) => s.aliases.includes(spec))) return spec;
1899
2310
  const depMatch = spec.match(/\/node_modules\/\.vite\/deps\/([^/?]+)\.js/);
1900
2311
  if (depMatch) {
1901
2312
  const depName = depMatch[1];
@@ -1906,14 +2317,13 @@ ${code}`, map: null };
1906
2317
  if (!cleanPath.startsWith("/")) return null;
1907
2318
  return state.resolvedSharedPaths.get(cleanPath) ?? null;
1908
2319
  };
1909
- const __r = await transformModule(code, id, {
2320
+ return transformModule(code, id, {
2321
+ onRewrite: () => recordRewritten(id),
1910
2322
  options: state.normalized,
1911
2323
  remapSpecifier,
1912
2324
  rewriteShared,
1913
- allowNodeModules: state.command === "build" ? isPureRemoteBuild || state.normalized.devSharedSelf : void 0,
1914
2325
  sharedClosureRoots: state.sharedClosureRoots
1915
2326
  });
1916
- return __r;
1917
2327
  }
1918
2328
  };
1919
2329
  function warmResolvedSharedPaths(server) {
@@ -1921,12 +2331,32 @@ ${code}`, map: null };
1921
2331
  if (!n) return;
1922
2332
  for (const s of n.shared) {
1923
2333
  if (s.import === false) continue;
1924
- void server.pluginContainer.resolveId(s.import, path5.join(n.root, "index.html")).then((r) => {
2334
+ void server.pluginContainer.resolveId(s.import, path6.join(n.root, "index.html")).then((r) => {
1925
2335
  if (r?.id) state.resolvedSharedPaths.set(r.id.split("?")[0], s.configKey);
1926
2336
  }).catch(() => {
1927
2337
  });
1928
2338
  }
1929
2339
  }
2340
+ async function buildFallbackTransform(code, id) {
2341
+ if (/type=(style|template)/.test(id)) return null;
2342
+ const clean = id.split("?")[0];
2343
+ const isJsLike = /\.(m|c)?[jt]sx?$/.test(clean) || clean.endsWith(".vue");
2344
+ if (!isJsLike) return null;
2345
+ const quickCheck = /require\s*\(\s*["']|(?:from|import)\s*["']/.test(code);
2346
+ if (!quickCheck) return null;
2347
+ const n = state.normalized;
2348
+ const isPureRemoteBuild = n.exposes.length > 0 && n.remotes.length === 0;
2349
+ return transformModule(code, id, {
2350
+ onRewrite: () => {
2351
+ debugLog("transform", { stage: "post-fallback", mode: "build", module: redactModulePath(id, n.root) });
2352
+ recordRewritten(id);
2353
+ },
2354
+ options: n,
2355
+ rewriteShared: true,
2356
+ allowNodeModules: isPureRemoteBuild || n.devSharedSelf,
2357
+ sharedClosureRoots: state.sharedClosureRoots
2358
+ });
2359
+ }
1930
2360
  return [pre, post];
1931
2361
  }
1932
2362
  var index_default = federation;