@softarc/native-federation-orchestrator 4.8.0 → 4.9.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.
Files changed (28) hide show
  1. package/fesm2022/@softarc/native-federation-orchestrator.mjs +399 -235
  2. package/fesm2022/@softarc/native-federation-orchestrator.mjs.map +3 -3
  3. package/fesm2022/module-federation.mjs +78 -21
  4. package/fesm2022/module-federation.mjs.map +3 -3
  5. package/fesm2022/node.mjs +468 -238
  6. package/fesm2022/node.mjs.map +3 -3
  7. package/fesm2022/options.mjs +4 -2
  8. package/fesm2022/options.mjs.map +2 -2
  9. package/package.json +1 -1
  10. package/quickstart.mjs +14 -14
  11. package/types/lib/core/1.domain/externals/claims.d.ts +1 -2
  12. package/types/lib/core/1.domain/externals/serving.d.ts +2 -2
  13. package/types/lib/core/1.domain/externals/specifier.d.ts +11 -6
  14. package/types/lib/core/1.domain/externals/version.contract.d.ts +1 -0
  15. package/types/lib/core/1.domain/pooling/builds.d.ts +2 -2
  16. package/types/lib/core/1.domain/pooling/election.d.ts +2 -1
  17. package/types/lib/core/1.domain/pooling/gate.d.ts +4 -2
  18. package/types/lib/core/1.domain/pooling/membership.d.ts +4 -2
  19. package/types/lib/core/1.domain/pooling/plan.d.ts +2 -0
  20. package/types/lib/core/1.domain/remote-entry/mark-dense.d.ts +2 -0
  21. package/types/lib/core/1.domain/remote-entry/remote-entry.contract.d.ts +5 -2
  22. package/types/lib/core/2.app/config/mode.contract.d.ts +1 -0
  23. package/types/lib/core/2.app/steps/get-remote-entries.d.ts +1 -1
  24. package/types/lib/core/2.app/steps/store-remote-entry.d.ts +3 -3
  25. package/types/lib/core/3.adapters/remote-entry/normalize-remote-entry.d.ts +4 -0
  26. package/types/lib/core/4.config/storage/storage.config.d.ts +2 -1
  27. package/types/lib/node/adapters/fs-remote-entry-provider.d.ts +2 -1
  28. package/types/lib/utils/union-find.d.ts +4 -0
@@ -1325,8 +1325,129 @@ function getScope(path) {
1325
1325
  return `${parts.join("/")}/`;
1326
1326
  }
1327
1327
 
1328
+ // src/lib/core/2.app/steps/store-remote-entry.ts
1329
+ function createRemoveCachedRemoteEntries(ports) {
1330
+ return (remoteNames) => {
1331
+ if (remoteNames.size === 0) return;
1332
+ for (const remoteName of remoteNames) {
1333
+ ports.remoteInfoRepo.remove(remoteName);
1334
+ ports.scopedExternalsRepo.remove(remoteName);
1335
+ ports.sharedChunksRepo.remove(remoteName);
1336
+ }
1337
+ ports.sharedExternalsRepo.removeFromAllScopes(remoteNames);
1338
+ };
1339
+ }
1340
+ function createStoreRemoteEntry(config, ports, logStep) {
1341
+ return (remoteEntry, onSharedExternal) => {
1342
+ addRemoteInfoToStorage(remoteEntry);
1343
+ addExternalsToStorage(remoteEntry, onSharedExternal);
1344
+ addSharedChunksToStorage(remoteEntry);
1345
+ };
1346
+ function addRemoteInfoToStorage({ name, url, exposes, integrity }) {
1347
+ ports.remoteInfoRepo.addOrUpdate(name, {
1348
+ scopeUrl: getScope(url),
1349
+ exposes: Object.values(exposes ?? []).map((m) => ({
1350
+ moduleName: m.key,
1351
+ file: m.outFileName
1352
+ })),
1353
+ ...integrity ? { integrity } : {}
1354
+ });
1355
+ }
1356
+ function addExternalsToStorage(remoteEntry, onSharedExternal) {
1357
+ remoteEntry.shared.forEach((external) => {
1358
+ const tag = resolveVersion(remoteEntry, external);
1359
+ if (tag === null) return;
1360
+ if (external.singleton) {
1361
+ if (external.requiredVersion && !ports.versionCheck.isCompatible(tag, external.requiredVersion))
1362
+ config.log.warn(
1363
+ logStep,
1364
+ `[${remoteEntry.name}][${external.packageName}] requiredVersion '${external.requiredVersion}' excludes its own version '${tag}'; '${tag}' is still accepted for it.`
1365
+ );
1366
+ onSharedExternal(remoteEntry, external, sharedExternalContext(remoteEntry, external, tag));
1367
+ } else {
1368
+ addScopedExternal(remoteEntry, external, tag);
1369
+ }
1370
+ });
1371
+ }
1372
+ function addSharedChunksToStorage(remoteEntry) {
1373
+ if (!remoteEntry.chunks) return;
1374
+ config.log.debug(
1375
+ logStep,
1376
+ `Adding chunks for remote "${remoteEntry.name}", bundles: [${Object.keys(remoteEntry.chunks).join(", ")}]`
1377
+ );
1378
+ Object.entries(remoteEntry.chunks).forEach(([bundleName, chunks]) => {
1379
+ ports.sharedChunksRepo.addOrReplace(remoteEntry.name, bundleName, chunks);
1380
+ });
1381
+ }
1382
+ function addScopedExternal(remoteEntry, sharedInfo, tag) {
1383
+ ports.scopedExternalsRepo.addExternal(remoteEntry.name, sharedInfo.packageName, {
1384
+ tag,
1385
+ bundle: sharedInfo.bundle,
1386
+ entries: sharedInfo.entries
1387
+ });
1388
+ }
1389
+ function resolveVersion(remoteEntry, external) {
1390
+ if (external.version && ports.versionCheck.isValidSemver(external.version)) {
1391
+ return external.version;
1392
+ }
1393
+ const errorMsg = `[${remoteEntry.name}][${external.packageName}] Version '${external.version}' is not a valid version.`;
1394
+ if (config.strict.strictExternalVersion) {
1395
+ config.log.error(logStep, errorMsg);
1396
+ throw new NFError(`Could not process remote '${remoteEntry.name}'`);
1397
+ }
1398
+ if (config.profile.skipInvalidExternalVersions) {
1399
+ config.log.warn(logStep, `${errorMsg} Skipping external.`);
1400
+ return null;
1401
+ }
1402
+ config.log.warn(logStep, errorMsg);
1403
+ return ports.versionCheck.smallestVersion(external.requiredVersion);
1404
+ }
1405
+ function sharedExternalContext(remoteEntry, sharedInfo, tag) {
1406
+ const scopeType = ports.sharedExternalsRepo.scopeType(sharedInfo.shareScope);
1407
+ const remote = {
1408
+ name: remoteEntry.name,
1409
+ bundle: sharedInfo.bundle,
1410
+ strictVersion: sharedInfo.strictVersion,
1411
+ cached: false,
1412
+ requiredVersion: scopeType === "strict" ? tag : sharedInfo.requiredVersion || tag,
1413
+ ...sharedInfo.pool?.trim() ? { pool: sharedInfo.pool } : {},
1414
+ ...sharedInfo.dense ? { dense: true } : {},
1415
+ entries: sharedInfo.entries
1416
+ };
1417
+ let stored;
1418
+ const readRecord = () => stored ??= ports.sharedExternalsRepo.tryGet(sharedInfo.packageName, sharedInfo.shareScope).get() ?? { dirty: false, versions: [] };
1419
+ return {
1420
+ tag,
1421
+ remote,
1422
+ readRecord,
1423
+ scopeType,
1424
+ assertSameVersionCompatibility(matchingVersion) {
1425
+ if (!remote.strictVersion) return;
1426
+ if (matchingVersion.remotes[0].requiredVersion === remote.requiredVersion) return;
1427
+ const errorMsg = `[${remoteEntry.name}][${sharedInfo.packageName}@${sharedInfo.version}] Required version-range '${remote.requiredVersion}' does not match cached version-range '${matchingVersion.remotes[0].requiredVersion}'`;
1428
+ if (config.strict.strictExternalSameVersionCompatibility) {
1429
+ config.log.error(logStep, errorMsg);
1430
+ throw new NFError(`Could not process remote '${remoteEntry.name}'`);
1431
+ }
1432
+ config.log.warn(logStep, errorMsg);
1433
+ },
1434
+ write() {
1435
+ ports.sharedExternalsRepo.addOrUpdate(
1436
+ sharedInfo.packageName,
1437
+ {
1438
+ ...readRecord(),
1439
+ versions: readRecord().versions.sort((a, b) => ports.versionCheck.compare(b.tag, a.tag))
1440
+ },
1441
+ sharedInfo.shareScope
1442
+ );
1443
+ }
1444
+ };
1445
+ }
1446
+ }
1447
+
1328
1448
  // src/lib/core/2.app/steps/get-remote-entries.ts
1329
1449
  function createGetRemoteEntries(config, ports) {
1450
+ const removeCachedRemoteEntries = createRemoveCachedRemoteEntries(ports);
1330
1451
  return (remotesOrManifestUrl = {}) => {
1331
1452
  const manifestPromise = config.manifestIntegrity ? ports.manifestProvider.provide(remotesOrManifestUrl, {
1332
1453
  integrity: config.manifestIntegrity
@@ -1334,7 +1455,7 @@ function createGetRemoteEntries(config, ports) {
1334
1455
  return manifestPromise.catch((e) => {
1335
1456
  config.log.error(1, "Could not fetch manifest.", e);
1336
1457
  return Promise.reject(new NFError("Failed to fetch manifest"));
1337
- }).then(addHostRemoteEntry).then(fetchRemoteEntries).then(removeSkippedRemotes).then(checkForSSE);
1458
+ }).then(addHostRemoteEntry).then(dropUnlistedRemotes).then(fetchRemoteEntries).then(removeSkippedRemotes).then(checkForSSE);
1338
1459
  };
1339
1460
  function addHostRemoteEntry(manifest) {
1340
1461
  if (!config.hostRemoteEntry) return manifest;
@@ -1344,6 +1465,26 @@ function createGetRemoteEntries(config, ports) {
1344
1465
  [name]: integrity ? { url, integrity } : url
1345
1466
  };
1346
1467
  }
1468
+ function dropUnlistedRemotes(manifest) {
1469
+ if (config.profile.mergeManifests !== false) return manifest;
1470
+ const listedUrls = new Set(
1471
+ Object.values(manifest).map((descriptor) => normalizeEntry(descriptor).url)
1472
+ );
1473
+ const isListed = (remoteName, info) => Object.hasOwn(manifest, remoteName) || listedUrls.has(storedEntryUrl(info));
1474
+ const unlisted = new Set(
1475
+ Object.entries(ports.remoteInfoRepo.getAll()).filter(([remoteName, info]) => !isListed(remoteName, info)).map(([remoteName]) => remoteName)
1476
+ );
1477
+ if (unlisted.size > 0)
1478
+ config.log.debug(
1479
+ 1,
1480
+ `Removing stored remotes the manifest doesn't list: ${[...unlisted].join(", ")}.`
1481
+ );
1482
+ removeCachedRemoteEntries(unlisted);
1483
+ return manifest;
1484
+ }
1485
+ function storedEntryUrl(info) {
1486
+ return join(info.scopeUrl, "remoteEntry.json");
1487
+ }
1347
1488
  function normalizeEntry(descriptor) {
1348
1489
  return typeof descriptor === "string" ? { url: descriptor } : descriptor;
1349
1490
  }
@@ -1368,7 +1509,7 @@ function createGetRemoteEntries(config, ports) {
1368
1509
  let isOverride = false;
1369
1510
  let skip = false;
1370
1511
  ports.remoteInfoRepo.tryGet(remoteName).ifPresent((cachedRemoteInfo) => {
1371
- if (config.profile.overrideCachedRemotes !== "never" && (remoteEntryUrl !== join(cachedRemoteInfo.scopeUrl, "remoteEntry.json") || config.profile.overrideCachedRemotesIfURLMatches)) {
1512
+ if (config.profile.overrideCachedRemotes !== "never" && (remoteEntryUrl !== storedEntryUrl(cachedRemoteInfo) || config.profile.overrideCachedRemotesIfURLMatches)) {
1372
1513
  config.log.debug(1, `Overriding existing remote '${remoteName}' with '${remoteEntryUrl}'.`);
1373
1514
  isOverride = true;
1374
1515
  } else {
@@ -1561,125 +1702,6 @@ function scopeRemotes(versions, remotes) {
1561
1702
  return rows.filter((v) => v.remotes.length > 0);
1562
1703
  }
1563
1704
 
1564
- // src/lib/core/2.app/steps/store-remote-entry.ts
1565
- function createRemoveCachedRemoteEntries(ports) {
1566
- return (remoteNames) => {
1567
- if (remoteNames.size === 0) return;
1568
- for (const remoteName of remoteNames) {
1569
- ports.remoteInfoRepo.remove(remoteName);
1570
- ports.scopedExternalsRepo.remove(remoteName);
1571
- ports.sharedChunksRepo.remove(remoteName);
1572
- }
1573
- ports.sharedExternalsRepo.removeFromAllScopes(remoteNames);
1574
- };
1575
- }
1576
- function createStoreRemoteEntry(config, ports, logStep) {
1577
- return (remoteEntry, onSharedExternal) => {
1578
- addRemoteInfoToStorage(remoteEntry);
1579
- addExternalsToStorage(remoteEntry, onSharedExternal);
1580
- addSharedChunksToStorage(remoteEntry);
1581
- };
1582
- function addRemoteInfoToStorage({ name, url, exposes, integrity }) {
1583
- ports.remoteInfoRepo.addOrUpdate(name, {
1584
- scopeUrl: getScope(url),
1585
- exposes: Object.values(exposes ?? []).map((m) => ({
1586
- moduleName: m.key,
1587
- file: m.outFileName
1588
- })),
1589
- ...integrity ? { integrity } : {}
1590
- });
1591
- }
1592
- function addExternalsToStorage(remoteEntry, onSharedExternal) {
1593
- remoteEntry.shared.forEach((external) => {
1594
- const tag = resolveVersion(remoteEntry, external);
1595
- if (tag === null) return;
1596
- if (external.singleton) {
1597
- if (external.requiredVersion && !ports.versionCheck.isCompatible(tag, external.requiredVersion))
1598
- config.log.warn(
1599
- logStep,
1600
- `[${remoteEntry.name}][${external.packageName}] requiredVersion '${external.requiredVersion}' excludes its own version '${tag}'; '${tag}' is still accepted for it.`
1601
- );
1602
- onSharedExternal(remoteEntry, external, sharedExternalContext(remoteEntry, external, tag));
1603
- } else {
1604
- addScopedExternal(remoteEntry, external, tag);
1605
- }
1606
- });
1607
- }
1608
- function addSharedChunksToStorage(remoteEntry) {
1609
- if (!remoteEntry.chunks) return;
1610
- config.log.debug(
1611
- logStep,
1612
- `Adding chunks for remote "${remoteEntry.name}", bundles: [${Object.keys(remoteEntry.chunks).join(", ")}]`
1613
- );
1614
- Object.entries(remoteEntry.chunks).forEach(([bundleName, chunks]) => {
1615
- ports.sharedChunksRepo.addOrReplace(remoteEntry.name, bundleName, chunks);
1616
- });
1617
- }
1618
- function addScopedExternal(remoteEntry, sharedInfo, tag) {
1619
- ports.scopedExternalsRepo.addExternal(remoteEntry.name, sharedInfo.packageName, {
1620
- tag,
1621
- bundle: sharedInfo.bundle,
1622
- entries: sharedInfo.entries
1623
- });
1624
- }
1625
- function resolveVersion(remoteEntry, external) {
1626
- if (external.version && ports.versionCheck.isValidSemver(external.version)) {
1627
- return external.version;
1628
- }
1629
- const errorMsg = `[${remoteEntry.name}][${external.packageName}] Version '${external.version}' is not a valid version.`;
1630
- if (config.strict.strictExternalVersion) {
1631
- config.log.error(logStep, errorMsg);
1632
- throw new NFError(`Could not process remote '${remoteEntry.name}'`);
1633
- }
1634
- if (config.profile.skipInvalidExternalVersions) {
1635
- config.log.warn(logStep, `${errorMsg} Skipping external.`);
1636
- return null;
1637
- }
1638
- config.log.warn(logStep, errorMsg);
1639
- return ports.versionCheck.smallestVersion(external.requiredVersion);
1640
- }
1641
- function sharedExternalContext(remoteEntry, sharedInfo, tag) {
1642
- const scopeType = ports.sharedExternalsRepo.scopeType(sharedInfo.shareScope);
1643
- const remote = {
1644
- name: remoteEntry.name,
1645
- bundle: sharedInfo.bundle,
1646
- strictVersion: sharedInfo.strictVersion,
1647
- cached: false,
1648
- requiredVersion: scopeType === "strict" ? tag : sharedInfo.requiredVersion || tag,
1649
- ...sharedInfo.pool?.trim() ? { pool: sharedInfo.pool } : {},
1650
- entries: sharedInfo.entries
1651
- };
1652
- let stored;
1653
- const readRecord = () => stored ??= ports.sharedExternalsRepo.tryGet(sharedInfo.packageName, sharedInfo.shareScope).get() ?? { dirty: false, versions: [] };
1654
- return {
1655
- tag,
1656
- remote,
1657
- readRecord,
1658
- scopeType,
1659
- assertSameVersionCompatibility(matchingVersion) {
1660
- if (!remote.strictVersion) return;
1661
- if (matchingVersion.remotes[0].requiredVersion === remote.requiredVersion) return;
1662
- const errorMsg = `[${remoteEntry.name}][${sharedInfo.packageName}@${sharedInfo.version}] Required version-range '${remote.requiredVersion}' does not match cached version-range '${matchingVersion.remotes[0].requiredVersion}'`;
1663
- if (config.strict.strictExternalSameVersionCompatibility) {
1664
- config.log.error(logStep, errorMsg);
1665
- throw new NFError(`Could not process remote '${remoteEntry.name}'`);
1666
- }
1667
- config.log.warn(logStep, errorMsg);
1668
- },
1669
- write() {
1670
- ports.sharedExternalsRepo.addOrUpdate(
1671
- sharedInfo.packageName,
1672
- {
1673
- ...readRecord(),
1674
- versions: readRecord().versions.sort((a, b) => ports.versionCheck.compare(b.tag, a.tag))
1675
- },
1676
- sharedInfo.shareScope
1677
- );
1678
- }
1679
- };
1680
- }
1681
- }
1682
-
1683
1705
  // src/lib/core/2.app/steps/process-remote-entries.ts
1684
1706
  function createProcessRemoteEntries(config, ports) {
1685
1707
  const storeRemoteEntry = createStoreRemoteEntry(config, ports, 2);
@@ -1847,6 +1869,7 @@ function createDetermineSharedExternals(config, ports) {
1847
1869
  if (!sharedVersion) {
1848
1870
  let leastExtraDownloads = Number.MAX_VALUE;
1849
1871
  let leastTears = Number.MAX_VALUE;
1872
+ let leaderShared = false;
1850
1873
  const selfServing = new Map(
1851
1874
  external.versions.map((v) => {
1852
1875
  const groups = /* @__PURE__ */ new Map();
@@ -1869,16 +1892,19 @@ function createDetermineSharedExternals(config, ports) {
1869
1892
  );
1870
1893
  external.versions.forEach((vA) => {
1871
1894
  const extraDownloads = external.versions.reduce((sum, vB) => sum + costOf(vB, vA.tag), 0);
1895
+ const alreadyShared = vA.action === "share" && !!vA.remotes[0]?.cached;
1872
1896
  if (extraDownloads < leastExtraDownloads) {
1873
1897
  leastExtraDownloads = extraDownloads;
1874
1898
  leastTears = uncoveredTears(external, vA, accepts);
1899
+ leaderShared = alreadyShared;
1875
1900
  sharedVersion = vA;
1876
1901
  return;
1877
1902
  }
1878
- if (extraDownloads > leastExtraDownloads) return;
1903
+ if (extraDownloads > leastExtraDownloads || leaderShared) return;
1879
1904
  const tears = uncoveredTears(external, vA, accepts);
1880
- if (tears < leastTears) {
1905
+ if (alreadyShared || tears < leastTears) {
1881
1906
  leastTears = tears;
1907
+ leaderShared = alreadyShared;
1882
1908
  sharedVersion = vA;
1883
1909
  }
1884
1910
  });
@@ -1890,28 +1916,81 @@ function createDetermineSharedExternals(config, ports) {
1890
1916
  }
1891
1917
  }
1892
1918
 
1919
+ // src/lib/utils/union-find.ts
1920
+ function unionFind() {
1921
+ const parent = /* @__PURE__ */ new Map();
1922
+ const find = (node) => {
1923
+ for (let up = parent.get(node); up !== void 0; up = parent.get(node)) {
1924
+ const grand = parent.get(up);
1925
+ if (grand === void 0) return up;
1926
+ parent.set(node, grand);
1927
+ node = grand;
1928
+ }
1929
+ return node;
1930
+ };
1931
+ const union = (a, b) => {
1932
+ const rootA = find(a);
1933
+ const rootB = find(b);
1934
+ if (rootA !== rootB) parent.set(rootB, rootA);
1935
+ };
1936
+ return { find, union };
1937
+ }
1938
+
1893
1939
  // src/lib/core/1.domain/externals/specifier.ts
1894
- function owningPackage(name) {
1940
+ function npmPackageOf(name) {
1895
1941
  const depth = name.startsWith("@") ? 2 : 1;
1896
1942
  let cut = -1;
1897
1943
  for (let seen = 0; seen < depth; seen++) {
1898
1944
  cut = name.indexOf("/", cut + 1);
1899
- if (cut === -1) return void 0;
1945
+ if (cut === -1) return name;
1900
1946
  }
1901
1947
  return name.slice(0, cut);
1902
1948
  }
1903
- var packageOf = (name) => owningPackage(name) ?? name;
1949
+ function packageOfIn(scope, loading = []) {
1950
+ if (!declaresLibrary(scope, loading)) return npmPackageOf;
1951
+ const { find, union } = unionFind();
1952
+ const shortest = /* @__PURE__ */ new Map();
1953
+ for (const [name, copy] of copiesIn(scope, loading)) {
1954
+ const anchor = anchorOf(name, copy);
1955
+ for (const specifier in copy.entries) {
1956
+ const best = shorter(
1957
+ shortest.get(find(anchor)) ?? anchor,
1958
+ shortest.get(find(specifier)) ?? specifier
1959
+ );
1960
+ union(anchor, specifier);
1961
+ shortest.set(find(anchor), best);
1962
+ }
1963
+ }
1964
+ return (specifier) => {
1965
+ const npm = npmPackageOf(specifier);
1966
+ return shortest.get(find(specifier)) ?? shortest.get(find(npm)) ?? npm;
1967
+ };
1968
+ }
1969
+ var shorter = (a, b) => b.length < a.length || b.length === a.length && compareStrings(b, a) < 0 ? b : a;
1970
+ function declaresLibrary(scope, loading) {
1971
+ const isLibrary = (name, copies) => npmPackageOf(name) !== name && copies.some((copy) => copy.dense);
1972
+ return loading.some(([name, copy]) => isLibrary(name, [copy])) || Object.entries(scope).some(
1973
+ ([name, external]) => external.versions.some((version) => isLibrary(name, version.remotes))
1974
+ );
1975
+ }
1976
+ var anchorOf = (name, copy) => copy.dense ? name : npmPackageOf(name);
1977
+ function* copiesIn(scope, loading) {
1978
+ yield* loading;
1979
+ for (const [name, external] of Object.entries(scope))
1980
+ for (const version of external.versions) for (const copy of version.remotes) yield [name, copy];
1981
+ }
1904
1982
  var SpecifierTags = class extends Map {
1905
- packages = /* @__PURE__ */ new Map();
1906
- constructor(entries = []) {
1983
+ constructor(packageOf, entries = []) {
1907
1984
  super();
1985
+ this.packageOf = packageOf;
1908
1986
  for (const [specifier, tag] of entries) this.set(specifier, tag);
1909
1987
  }
1988
+ packageOf;
1989
+ packages = /* @__PURE__ */ new Map();
1910
1990
  set(specifier, tag) {
1911
1991
  super.set(specifier, tag);
1912
- const pkg = owningPackage(specifier);
1913
- if (pkg === void 0) this.packages.set(specifier, tag);
1914
- else if (!this.packages.has(pkg)) this.packages.set(pkg, tag);
1992
+ const pkg = this.packageOf(specifier);
1993
+ if (pkg === specifier || !this.packages.has(pkg)) this.packages.set(pkg, tag);
1915
1994
  return this;
1916
1995
  }
1917
1996
  clear() {
@@ -1919,10 +1998,10 @@ var SpecifierTags = class extends Map {
1919
1998
  this.packages.clear();
1920
1999
  }
1921
2000
  pinnedTag(specifier) {
1922
- return this.get(specifier) ?? this.packages.get(owningPackage(specifier) ?? specifier);
2001
+ return this.get(specifier) ?? this.packages.get(this.packageOf(specifier));
1923
2002
  }
1924
2003
  };
1925
- function groupByPackage(items, nameOf) {
2004
+ function groupByPackage(items, nameOf, packageOf) {
1926
2005
  const packages = /* @__PURE__ */ new Map();
1927
2006
  for (const item of items) {
1928
2007
  const pkg = packageOf(nameOf(item));
@@ -1957,8 +2036,8 @@ function copiesByRemote(members) {
1957
2036
  return shipped;
1958
2037
  }
1959
2038
  var specifierCount = (copies) => copies.reduce((n, copy) => n + copy.specifiers.length, 0);
1960
- function buildOf(owner, copies) {
1961
- const tags = new SpecifierTags();
2039
+ function buildOf(owner, copies, packageOf) {
2040
+ const tags = new SpecifierTags(packageOf);
1962
2041
  const tagByMember = /* @__PURE__ */ new Map();
1963
2042
  for (const copy of copies) {
1964
2043
  for (const specifier of copy.specifiers)
@@ -2000,12 +2079,14 @@ function unwitnessedGap(copies, tags, builds) {
2000
2079
  function elect(input) {
2001
2080
  const shipped = copiesByRemote(input.members);
2002
2081
  const builds = /* @__PURE__ */ new Map();
2003
- for (const [owner, copies] of shipped) builds.set(owner, buildOf(owner, copies));
2082
+ for (const [owner, copies] of shipped) builds.set(owner, buildOf(owner, copies, input.packageOf));
2004
2083
  const pool = {
2005
2084
  ...input,
2006
2085
  shipped,
2007
2086
  builds,
2008
- packages: new Map([...shipped].map(([owner, copies]) => [owner, packageCopies(owner, copies)])),
2087
+ packages: new Map(
2088
+ [...shipped].map(([owner, copies]) => [owner, packageCopies(owner, copies, input.packageOf)])
2089
+ ),
2009
2090
  remotes: [...shipped.keys()],
2010
2091
  servesAt: (remote, tags) => serves(shipped.get(remote), tags, input.acceptsTag),
2011
2092
  agreesAt: (remote, tags) => agrees(shipped.get(remote), tags)
@@ -2068,7 +2149,7 @@ function roundOne(pool, hostRemote) {
2068
2149
  (c) => c.build.owner === pool.previousWinner ? 1 : 0
2069
2150
  ]);
2070
2151
  const winner = round1Winner.build.owner;
2071
- const globalTags = new SpecifierTags(round1Winner.build.tags);
2152
+ const globalTags = new SpecifierTags(pool.packageOf, round1Winner.build.tags);
2072
2153
  const globalRemotes = /* @__PURE__ */ new Set([winner, ...round1Winner.served]);
2073
2154
  const pending = remotes.filter((r) => !globalRemotes.has(r));
2074
2155
  return { winner, globalTags, globalRemotes, extensions: /* @__PURE__ */ new Set(), subpools: [], pending };
@@ -2125,7 +2206,7 @@ function addExtensions(pool, state) {
2125
2206
  for (const s of offer.specifiers) globalTags.set(s, offer.tag);
2126
2207
  }
2127
2208
  }
2128
- function packageCopies(owner, copies) {
2209
+ function packageCopies(owner, copies, packageOf) {
2129
2210
  const packages = /* @__PURE__ */ new Map();
2130
2211
  for (const copy of copies)
2131
2212
  for (const s of copy.specifiers) {
@@ -2167,7 +2248,7 @@ function settle(pool, state) {
2167
2248
  const dropped = new Set([...extensions].filter((pkg) => !publishedWhole(pool, state, pkg)));
2168
2249
  if (dropped.size === 0) return demoted;
2169
2250
  for (const pkg of dropped) extensions.delete(pkg);
2170
- const kept = [...globalTags].filter(([s]) => !dropped.has(packageOf(s)));
2251
+ const kept = [...globalTags].filter(([s]) => !dropped.has(pool.packageOf(s)));
2171
2252
  globalTags.clear();
2172
2253
  for (const [s, tag] of kept) globalTags.set(s, tag);
2173
2254
  for (const remote of globalRemotes)
@@ -2183,7 +2264,7 @@ function settle(pool, state) {
2183
2264
  }
2184
2265
  }
2185
2266
  function publishedWhole(pool, state, pkg) {
2186
- const published = new Set([...state.globalTags.keys()].filter((s) => packageOf(s) === pkg));
2267
+ const published = new Set([...state.globalTags.keys()].filter((s) => pool.packageOf(s) === pkg));
2187
2268
  const tag = state.globalTags.pinnedTag(pkg);
2188
2269
  return [...state.globalRemotes].some((remote) => {
2189
2270
  const copy = pool.packages.get(remote).get(pkg);
@@ -2232,24 +2313,6 @@ function placeRemotes(globalRemotes, subpools, self, missOf2) {
2232
2313
  }
2233
2314
 
2234
2315
  // src/lib/core/1.domain/pooling/membership.ts
2235
- function unionFind() {
2236
- const parent = /* @__PURE__ */ new Map();
2237
- const find = (node) => {
2238
- for (let up = parent.get(node); up !== void 0; up = parent.get(node)) {
2239
- const grand = parent.get(up);
2240
- if (grand === void 0) return up;
2241
- parent.set(node, grand);
2242
- node = grand;
2243
- }
2244
- return node;
2245
- };
2246
- const union = (a, b) => {
2247
- const rootA = find(a);
2248
- const rootB = find(b);
2249
- if (rootA !== rootB) parent.set(rootB, rootA);
2250
- };
2251
- return { find, union };
2252
- }
2253
2316
  var extNode = (name) => `ext\0${name}`;
2254
2317
  var labelNode = (label) => `label\0${label}`;
2255
2318
  var labelOf = (pool) => pool?.trim() || void 0;
@@ -2262,13 +2325,13 @@ function labelsIn(sharedExternals) {
2262
2325
  );
2263
2326
  return labelsOf;
2264
2327
  }
2265
- function labelledComponents(labelsOf) {
2328
+ function labelledComponents(labelsOf, packageOf) {
2266
2329
  const { find, union } = unionFind();
2267
2330
  for (const [name, labels] of labelsOf)
2268
2331
  for (const label of labels) union(extNode(name), labelNode(label));
2269
2332
  for (const name of labelsOf.keys()) {
2270
- const owner = owningPackage(name);
2271
- if (owner !== void 0) union(extNode(name), extNode(owner));
2333
+ const owner = packageOf(name);
2334
+ if (owner !== name) union(extNode(name), extNode(owner));
2272
2335
  }
2273
2336
  const byComponent = /* @__PURE__ */ new Map();
2274
2337
  for (const name of labelsOf.keys()) {
@@ -2278,11 +2341,11 @@ function labelledComponents(labelsOf) {
2278
2341
  }
2279
2342
  return [...byComponent.values()].filter((names) => names.some((n) => labelsOf.get(n).length > 0));
2280
2343
  }
2281
- function buildPools(sharedExternals) {
2344
+ function buildPools(sharedExternals, packageOf = packageOfIn(sharedExternals)) {
2282
2345
  const labelsOf = labelsIn(sharedExternals);
2283
2346
  const pools = /* @__PURE__ */ new Map();
2284
2347
  const labelledAlone = [];
2285
- for (const names of labelledComponents(labelsOf)) {
2348
+ for (const names of labelledComponents(labelsOf, packageOf)) {
2286
2349
  if (names.length < 2) labelledAlone.push(names[0]);
2287
2350
  else {
2288
2351
  const members = names.map((name) => ({ name, external: sharedExternals[name] }));
@@ -2292,9 +2355,9 @@ function buildPools(sharedExternals) {
2292
2355
  );
2293
2356
  }
2294
2357
  }
2295
- return { pools, labelledAlone };
2358
+ return { pools, labelledAlone, packageOf };
2296
2359
  }
2297
- function pooledPackagesWith(sharedExternals, copies) {
2360
+ function pooledPackagesWith(sharedExternals, copies, packageOf) {
2298
2361
  const labelsOf = labelsIn(sharedExternals);
2299
2362
  for (const { name, pool } of copies) {
2300
2363
  const labels = labelsOf.get(name) ?? [];
@@ -2302,7 +2365,7 @@ function pooledPackagesWith(sharedExternals, copies) {
2302
2365
  labelsOf.set(name, label === void 0 ? labels : [...labels, label]);
2303
2366
  }
2304
2367
  return new Set(
2305
- labelledComponents(labelsOf).filter((names) => names.length > 1).flatMap((names) => names.map(packageOf))
2368
+ labelledComponents(labelsOf, packageOf).filter((names) => names.length > 1).flatMap((names) => names.map(packageOf))
2306
2369
  );
2307
2370
  }
2308
2371
  function mostDeclaredLabel(members, labelsOf) {
@@ -2438,14 +2501,14 @@ function renamedRecords(scope, pools) {
2438
2501
  // src/lib/core/1.domain/pooling/plan.ts
2439
2502
  function planElection(scope, poolable) {
2440
2503
  if (!poolable || !Object.values(scope).some((external) => external.dirty) || !scopeHasPoolState(scope))
2441
- return { pools: /* @__PURE__ */ new Map(), stripped: /* @__PURE__ */ new Map(), labelledAlone: [] };
2442
- const { pools, labelledAlone } = buildPools(scope);
2504
+ return { pools: /* @__PURE__ */ new Map(), stripped: /* @__PURE__ */ new Map(), labelledAlone: [], packageOf: npmPackageOf };
2505
+ const { pools, labelledAlone, packageOf } = buildPools(scope);
2443
2506
  const pooled = new Set([...pools.values()].flatMap((members) => members.map((m) => m.name)));
2444
2507
  const stripped = /* @__PURE__ */ new Map();
2445
2508
  for (const [name, external] of Object.entries(scope))
2446
2509
  if (!pooled.has(name) && hasPoolResults(external))
2447
2510
  stripped.set(name, { ...withoutPoolResults(external), dirty: true });
2448
- return { pools, stripped, labelledAlone };
2511
+ return { pools, stripped, labelledAlone, packageOf };
2449
2512
  }
2450
2513
 
2451
2514
  // src/lib/core/2.app/steps/pooling/pool-shared-externals.ts
@@ -2459,7 +2522,7 @@ function createPoolSharedExternals(config, ports) {
2459
2522
  const plan = planElection(sharedExternals, repo.scopeType(scope) !== "strict");
2460
2523
  logPlan(plan, sharedExternals, scope);
2461
2524
  for (const [poolName, members] of plan.pools)
2462
- for (const [name, record] of poolRecords(poolName, members, scope))
2525
+ for (const [name, record] of poolRecords(poolName, members, plan.packageOf, scope))
2463
2526
  repo.addOrUpdate(name, record, scope);
2464
2527
  for (const [name, external] of plan.stripped) repo.addOrUpdate(name, external, scope);
2465
2528
  } catch (error) {
@@ -2494,9 +2557,10 @@ function createPoolSharedExternals(config, ports) {
2494
2557
  `[${scope}] '${name}' has a 'pool' label that joins no other external; likely a typo or a missing sibling.`
2495
2558
  );
2496
2559
  }
2497
- function poolRecords(poolName, members, scope) {
2560
+ function poolRecords(poolName, members, packageOf, scope) {
2498
2561
  const election = elect({
2499
2562
  members,
2563
+ packageOf,
2500
2564
  acceptsTag: createAcceptsTag(ports.versionCheck.isCompatible, compare),
2501
2565
  compare,
2502
2566
  previousWinner: previousWinner(members),
@@ -2557,12 +2621,13 @@ function missWarning(remote, miss, placed, counts) {
2557
2621
 
2558
2622
  // src/lib/core/1.domain/externals/serving.ts
2559
2623
  var byServingRank = (a, b) => Number(b.host) - Number(a.host) || a.downloads - b.downloads || a.fallbacks - b.fallbacks || Number(b.rootBasis) - Number(a.rootBasis) || compareStrings(a.remote, b.remote);
2560
- var packagesOf = (scope) => groupByPackage(Object.keys(scope), (name) => name);
2624
+ var packagesOf = (scope) => groupByPackage(Object.keys(scope), (name) => name, packageOfIn(scope));
2561
2625
  var isPooled = (externals) => externals.some(([, e]) => e.poolName !== void 0);
2562
- function servingBuildOf(externals, accepts) {
2626
+ function servingBuildOf(pkg, externals, accepts) {
2563
2627
  if (externals.length === 0) return void 0;
2564
- const pkg = packageOf(externals[0][0]);
2565
- const rootRows = shareRows(externals.find(([name]) => name === pkg)?.[1]);
2628
+ const rootRows = shareRows(externals.find(([name]) => name === pkg)?.[1]).filter(
2629
+ (row) => row.remotes.some((copy) => pkg in copy.entries)
2630
+ );
2566
2631
  const rows = rootRows.length > 0 ? rootRows : externals.flatMap(([, e]) => shareRows(e));
2567
2632
  if (isPooled(externals)) return pooledBuild(externals, rows);
2568
2633
  const consumers = consumersOf(externals);
@@ -2763,8 +2828,8 @@ function splitsPackage(placed, surface, tag, accepts) {
2763
2828
  });
2764
2829
  return placed.some(onMap) && (shipsTwoTags(placed) || placed.some((p) => !onMap(p) || uncovered(p)));
2765
2830
  }
2766
- function loadSplitsPackage(copies, claims, accepts) {
2767
- const root = claims.find(([specifier]) => specifier === packageOf(specifier))?.[1];
2831
+ function loadSplitsPackage(pkg, copies, claims, accepts) {
2832
+ const root = claims.find(([specifier]) => specifier === pkg)?.[1];
2768
2833
  const servingTag = root?.tag ?? claims[0][1].tag;
2769
2834
  const surface = new Map(
2770
2835
  claims.map(([specifier, { tag }]) => [specifier, root ? tag : servingTag])
@@ -2810,7 +2875,7 @@ function createDecideServingBuilds(config, ports) {
2810
2875
  }
2811
2876
  };
2812
2877
  function decidePackage(shareScope, pkg, externals, accepts) {
2813
- const serving = servingBuildOf(externals, accepts);
2878
+ const serving = servingBuildOf(pkg, externals, accepts);
2814
2879
  const before = externals.map(([, external]) => shapeOf(external));
2815
2880
  const pooled = isPooled(externals);
2816
2881
  const toFollow = pooled ? void 0 : serving;
@@ -2896,7 +2961,6 @@ function committedClaims(externals, { shareScope, without }) {
2896
2961
  const publishes = (copy) => copy.name !== without && (shareScope !== GLOBAL_SCOPE || copy.cached);
2897
2962
  return claimTable(externals, publishes).claims;
2898
2963
  }
2899
- var claimsByPackage = (claims) => groupByPackage(claims, ([specifier]) => specifier);
2900
2964
  function versionClaims(version, servingBuild) {
2901
2965
  const claims = /* @__PURE__ */ new Map();
2902
2966
  const claim = (specifier, copy) => {
@@ -2907,7 +2971,7 @@ function versionClaims(version, servingBuild) {
2907
2971
  return claims;
2908
2972
  }
2909
2973
 
2910
- // node_modules/.pnpm/@softarc+native-federation@4.8.0/node_modules/@softarc/native-federation/dist/lib/domain/core/build-notification-options.contract.js
2974
+ // node_modules/.pnpm/@softarc+native-federation@4.9.0/node_modules/@softarc/native-federation/dist/lib/domain/core/build-notification-options.contract.js
2911
2975
  var BuildNotificationType = /* @__PURE__ */ ((BuildNotificationType2) => {
2912
2976
  BuildNotificationType2["COMPLETED"] = "federation-rebuild-complete";
2913
2977
  BuildNotificationType2["ERROR"] = "federation-rebuild-error";
@@ -2915,13 +2979,14 @@ var BuildNotificationType = /* @__PURE__ */ ((BuildNotificationType2) => {
2915
2979
  return BuildNotificationType2;
2916
2980
  })(BuildNotificationType || {});
2917
2981
 
2918
- // node_modules/.pnpm/@softarc+native-federation@4.8.0/node_modules/@softarc/native-federation/dist/lib/domain/core/chunk.js
2982
+ // node_modules/.pnpm/@softarc+native-federation@4.9.0/node_modules/@softarc/native-federation/dist/lib/domain/core/chunk.js
2919
2983
  var CHUNK_PREFIX = "@nf-internal";
2984
+ var SCRIPT_EXTENSION = /\.(m|c)?js$/;
2920
2985
  function toChunkImport(fileName) {
2921
2986
  if (fileName.startsWith("./")) {
2922
2987
  fileName = fileName.slice(2);
2923
2988
  }
2924
- const packageName = fileName.replace(/.(m|c)?js$/, "");
2989
+ const packageName = fileName.replace(SCRIPT_EXTENSION, "");
2925
2990
  return CHUNK_PREFIX + "/" + packageName;
2926
2991
  }
2927
2992
 
@@ -3522,18 +3587,19 @@ function createUpdateCache(config, ports) {
3522
3587
  function decidePackages(remoteEntry, pending) {
3523
3588
  const decisions = /* @__PURE__ */ new Map();
3524
3589
  const viewOf = loadViewOf(remoteEntry, pending);
3525
- for (const group of pendingPerPackage(pending)) {
3590
+ for (const group of pendingPerPackage(pending, viewOf)) {
3526
3591
  const decision = group[0].ctx.scopeType === "strict" ? { action: "share" } : decidePackage(remoteEntry, group, viewOf(group[0].external.shareScope));
3527
3592
  for (const item of group) decisions.set(item, decision);
3528
3593
  }
3529
3594
  scopeOpenedPackages(decisions);
3530
3595
  return decisions;
3531
3596
  }
3532
- function pendingPerPackage(pending) {
3597
+ function pendingPerPackage(pending, viewOf) {
3533
3598
  const packages = /* @__PURE__ */ new Map();
3534
3599
  for (const item of pending) {
3535
3600
  const { shareScope, packageName } = item.external;
3536
- const key = `${shareScope ?? GLOBAL_SCOPE}\0${packageOf(packageName)}`;
3601
+ const pkg = item.ctx.scopeType === "strict" ? packageName : viewOf(shareScope).packageOf(packageName);
3602
+ const key = `${shareScope ?? GLOBAL_SCOPE}\0${pkg}`;
3537
3603
  const group = packages.get(key);
3538
3604
  if (group) group.push(item);
3539
3605
  else packages.set(key, [item]);
@@ -3551,20 +3617,34 @@ function createUpdateCache(config, ports) {
3551
3617
  shareScope: scope,
3552
3618
  without: remoteEntry.name
3553
3619
  });
3554
- const claimsIn = claimsByPackage(claims);
3620
+ const packageOf = packageOfIn(record, loadingIn(pending, scope));
3621
+ const claimsIn = groupByPackage(claims, ([specifier]) => specifier, packageOf);
3555
3622
  let pooled;
3556
3623
  view = {
3624
+ packageOf,
3557
3625
  claims,
3558
3626
  claimsOf: (pkg) => claimsIn.get(pkg) ?? [],
3559
- inPool: (pkg) => (pooled ??= pooledPackagesWith(record, copiesIn(pending, scope))).has(pkg)
3627
+ inPool: (pkg) => {
3628
+ pooled ??= pooledPackagesWith(record, labelledCopiesIn(pending, scope), packageOf);
3629
+ return pooled.has(pkg);
3630
+ }
3560
3631
  };
3561
3632
  views.set(scope, view);
3562
3633
  }
3563
3634
  return view;
3564
3635
  };
3565
3636
  }
3566
- function copiesIn(pending, scope) {
3567
- return pending.filter(({ external }) => (external.shareScope ?? GLOBAL_SCOPE) === scope).map(({ external, ctx }) => ({ name: external.packageName, pool: ctx.remote.pool }));
3637
+ function inScope(pending, scope) {
3638
+ return pending.filter(({ external }) => (external.shareScope ?? GLOBAL_SCOPE) === scope);
3639
+ }
3640
+ function loadingIn(pending, scope) {
3641
+ return inScope(pending, scope).map(({ external, ctx }) => [external.packageName, ctx.remote]);
3642
+ }
3643
+ function labelledCopiesIn(pending, scope) {
3644
+ return inScope(pending, scope).map(({ external, ctx }) => ({
3645
+ name: external.packageName,
3646
+ pool: ctx.remote.pool
3647
+ }));
3568
3648
  }
3569
3649
  function scopeOpenedPackages(decisions) {
3570
3650
  if (![...decisions.values()].some((d) => d.action === "scope" && d.partlyServed)) return;
@@ -3573,15 +3653,16 @@ function createUpdateCache(config, ports) {
3573
3653
  decisions.set(item, { action: "scope", partlyServed: false });
3574
3654
  }
3575
3655
  function decidePackage(remoteEntry, group, view) {
3576
- const pkg = packageOf(group[0].external.packageName);
3656
+ const pkg = view.packageOf(group[0].external.packageName);
3577
3657
  const claims = view.claimsOf(pkg);
3578
3658
  if (claims.length === 0) return { action: "share" };
3579
3659
  const specifiers = group.flatMap(({ external }) => Object.keys(external.entries));
3580
3660
  const builds = specifiers.every((specifier) => view.claims.has(specifier)) ? new Set(specifiers.map((specifier) => view.claims.get(specifier).copy.name)) : void 0;
3581
3661
  const rejections = group.flatMap((item) => rejectionsOf(item, view.claims));
3582
3662
  if (rejections.length > 0) {
3583
- const fromTwoBuilds = builds !== void 0 && builds.size > 1;
3584
- for (const rejection of refused(group, rejections, fromTwoBuilds, claims, view.inPool(pkg)))
3663
+ const copies = group.map(({ ctx }) => ({ tag: ctx.tag, copy: ctx.remote }));
3664
+ const splits = builds !== void 0 && builds.size > 1 || loadSplitsPackage(pkg, copies, claims, accepts);
3665
+ for (const rejection of refused(rejections, splits, view.inPool(pkg)))
3585
3666
  reportIncompatible(remoteEntry, rejection);
3586
3667
  return { action: "scope", partlyServed: false };
3587
3668
  }
@@ -3602,9 +3683,7 @@ function createUpdateCache(config, ports) {
3602
3683
  return claim && !accepts(claim.tag, ctx.tag, ctx.remote.requiredVersion) ? [{ item, specifier, claim }] : [];
3603
3684
  });
3604
3685
  }
3605
- function refused(group, rejections, fromTwoBuilds, claims, pooled) {
3606
- const copies = group.map(({ ctx }) => ({ tag: ctx.tag, copy: ctx.remote }));
3607
- const splits = fromTwoBuilds || loadSplitsPackage(copies, claims, accepts);
3686
+ function refused(rejections, splits, pooled) {
3608
3687
  const first = /* @__PURE__ */ new Map();
3609
3688
  for (const rejection of rejections)
3610
3689
  if (!first.has(rejection.item) && (pooled || !splits || electionKeeps(rejection)))
@@ -3681,16 +3760,25 @@ function createUpdateCache(config, ports) {
3681
3760
  }
3682
3761
 
3683
3762
  // src/lib/core/1.domain/pooling/gate.ts
3684
- function committedView(members, shipped, recordOrder, { shareScope, without }) {
3763
+ function committedView(members, shipped, recordOrder, {
3764
+ shareScope,
3765
+ without,
3766
+ packageOf
3767
+ }) {
3685
3768
  const global = /* @__PURE__ */ new Map();
3686
3769
  const claims = committedClaims(inRecordOrder(members, recordOrder), { shareScope, without });
3687
3770
  for (const [specifier, { tag, copy }] of claims)
3688
3771
  global.set(specifier, { tag, remote: copy.name, file: copy.entries[specifier] });
3689
3772
  const builds = /* @__PURE__ */ new Map();
3690
3773
  for (const [owner, copies] of shipped)
3691
- if (owner !== without) builds.set(owner, buildOf(owner, copies));
3774
+ if (owner !== without) builds.set(owner, buildOf(owner, copies, packageOf));
3692
3775
  const fileOf = subpoolFilesOf(members);
3693
- return { builds, global, runsOffMap: runsOffMapOf(members, global, builds, fileOf) };
3776
+ return {
3777
+ packageOf,
3778
+ builds,
3779
+ global,
3780
+ runsOffMap: runsOffMapOf(members, global, builds, fileOf)
3781
+ };
3694
3782
  }
3695
3783
  function subpoolFilesOf(members) {
3696
3784
  const subpoolOwners = /* @__PURE__ */ new Set();
@@ -3733,14 +3821,30 @@ function runsOffMapOf(members, global, builds, fileOf) {
3733
3821
  function judgeRemote(copies, view, accepts) {
3734
3822
  const { rejected, missing } = scan(copies, view, accepts);
3735
3823
  if (rejected) return { cause: "incompatible", ...rejected };
3736
- const globalTags = new SpecifierTags([...view.global].map(([s, { tag }]) => [s, tag]));
3824
+ const globalTags = new SpecifierTags(
3825
+ view.packageOf,
3826
+ [...view.global].map(([s, { tag }]) => [s, tag])
3827
+ );
3737
3828
  const binding = offMapBinding(copies, view, globalTags);
3738
3829
  if (binding) return { cause: "uncovered", ...binding };
3830
+ if (servedSplit(copies, view)) return { cause: "uncovered", unshipped: true };
3739
3831
  if (agrees(copies, globalTags)) return "global";
3740
3832
  if (missing !== void 0) return { cause: "uncovered", specifier: missing };
3741
3833
  if (unwitnessedGap(copies, globalTags, view.builds.values()) === void 0) return "global";
3742
3834
  return { cause: "uncovered", unshipped: true };
3743
3835
  }
3836
+ function servedSplit(copies, view) {
3837
+ const loaded = new Set(copies.flatMap((copy) => copy.specifiers.map(view.packageOf)));
3838
+ const servedBy = /* @__PURE__ */ new Map();
3839
+ for (const [specifier, { remote }] of view.global) {
3840
+ const pkg = view.packageOf(specifier);
3841
+ if (!loaded.has(pkg)) continue;
3842
+ const first = servedBy.get(pkg);
3843
+ if (first === void 0) servedBy.set(pkg, remote);
3844
+ else if (first !== remote) return true;
3845
+ }
3846
+ return false;
3847
+ }
3744
3848
  function coverFromMap(remote, mine, view, actions, policy) {
3745
3849
  const files = [];
3746
3850
  for (const member of mine) {
@@ -3754,12 +3858,12 @@ function coverFromMap(remote, mine, view, actions, policy) {
3754
3858
  const reaches = reachesOf(remote, files, view);
3755
3859
  const bound = boundByFile(reaches, view);
3756
3860
  if (bound !== void 0) return { bound };
3757
- const servedPackages = new Set([...view.global.keys()].map(packageOf));
3758
- const gap = files.map((file) => gapOf(file, servedPackages)).find((specifier) => specifier !== void 0);
3861
+ const servedPackages = new Set([...view.global.keys()].map(view.packageOf));
3862
+ const gap = files.map((file) => gapOf(file, servedPackages, view.packageOf)).find((specifier) => specifier !== void 0);
3759
3863
  if (gap !== void 0) return { gap };
3760
3864
  return { covers: files.filter(covering).map(coverOf) };
3761
3865
  }
3762
- function gapOf({ copy, covered }, servedPackages) {
3866
+ function gapOf({ copy, covered }, servedPackages, packageOf) {
3763
3867
  const entrypoints = Object.keys(copy.entries);
3764
3868
  const missing = entrypoints.filter((specifier) => !covered.has(specifier));
3765
3869
  if (missing.length < entrypoints.length) return missing[0];
@@ -3837,14 +3941,17 @@ function scan(copies, view, accepts) {
3837
3941
  return { rejected, missing };
3838
3942
  }
3839
3943
  function offMapBinding(copies, view, globalTags) {
3840
- const own = new SpecifierTags(copies.flatMap((c) => c.specifiers.map((s) => [s, c.tag])));
3944
+ const own = new SpecifierTags(
3945
+ view.packageOf,
3946
+ copies.flatMap((c) => c.specifiers.map((s) => [s, c.tag]))
3947
+ );
3841
3948
  const servers = /* @__PURE__ */ new Set();
3842
3949
  for (const copy of copies)
3843
3950
  for (const specifier of copy.specifiers) {
3844
3951
  const build = view.global.get(specifier)?.remote;
3845
3952
  if (build !== void 0) servers.add(build);
3846
3953
  }
3847
- const firstRun = new SpecifierTags();
3954
+ const firstRun = new SpecifierTags(view.packageOf);
3848
3955
  for (const build of servers)
3849
3956
  for (const [specifier, { tag }] of view.runsOffMap.get(build) ?? []) {
3850
3957
  const reached = globalTags.pinnedTag(specifier) ?? own.pinnedTag(specifier) ?? firstRun.pinnedTag(specifier);
@@ -3869,13 +3976,21 @@ function createPoolDynamicExternals(config, ports) {
3869
3976
  for (const [scope, names] of poolableNames(entry, actions)) {
3870
3977
  const committed = ports.sharedExternalsRepo.getFromScope(scope);
3871
3978
  if (!scopeHasPoolState(committed)) continue;
3872
- const { pools } = buildPools(committed);
3873
- const moves = judgeScope(entry.name, names, actions, pools, Object.keys(committed), scope);
3979
+ const { pools, packageOf } = buildPools(committed);
3980
+ const moves = judgeScope(
3981
+ entry.name,
3982
+ names,
3983
+ actions,
3984
+ pools,
3985
+ packageOf,
3986
+ Object.keys(committed),
3987
+ scope
3988
+ );
3874
3989
  writeMoves(entry.name, names, moves, committed, pools, scope);
3875
3990
  }
3876
3991
  return Promise.resolve({ entry, actions: publicActions(actions) });
3877
3992
  };
3878
- function judgeScope(remote, names, actions, pools, recordOrder, scope) {
3993
+ function judgeScope(remote, names, actions, pools, packageOf, recordOrder, scope) {
3879
3994
  const policy = { shareScope: scope, scopeUrlOf };
3880
3995
  const moves = /* @__PURE__ */ new Map();
3881
3996
  const selfServe = (members, cause) => {
@@ -3891,7 +4006,8 @@ function createPoolDynamicExternals(config, ports) {
3891
4006
  const shipped = copiesByRemote(pool);
3892
4007
  const view = committedView(pool, shipped, recordOrder, {
3893
4008
  shareScope: scope,
3894
- without: remote
4009
+ without: remote,
4010
+ packageOf
3895
4011
  });
3896
4012
  const own = shipped.get(remote) ?? [];
3897
4013
  const verdict = judgeRemote(own, view, accepts);
@@ -4226,7 +4342,12 @@ var createManifestProvider = () => {
4226
4342
  };
4227
4343
  };
4228
4344
 
4229
- // node_modules/.pnpm/@softarc+native-federation@4.8.0/node_modules/@softarc/native-federation/dist/lib/utils/normalize.js
4345
+ // src/lib/core/1.domain/remote-entry/mark-dense.ts
4346
+ function markDense(shared) {
4347
+ return shared.map((entry) => "entries" in entry ? { ...entry, dense: true } : entry);
4348
+ }
4349
+
4350
+ // node_modules/.pnpm/@softarc+native-federation@4.9.0/node_modules/@softarc/native-federation/dist/lib/utils/normalize.js
4230
4351
  function inferPackageFromSecondary(secondary) {
4231
4352
  const parts = secondary.split("/");
4232
4353
  if (secondary.startsWith("@") && parts.length >= 2) {
@@ -4235,14 +4356,14 @@ function inferPackageFromSecondary(secondary) {
4235
4356
  return parts[0];
4236
4357
  }
4237
4358
 
4238
- // node_modules/.pnpm/@softarc+native-federation@4.8.0/node_modules/@softarc/native-federation/dist/lib/core/output/densify-externals.js
4359
+ // node_modules/.pnpm/@softarc+native-federation@4.9.0/node_modules/@softarc/native-federation/dist/lib/core/output/densify-externals.js
4239
4360
  function isDense(entry) {
4240
4361
  return "entries" in entry;
4241
4362
  }
4242
4363
  function isFlatChunk(entry) {
4243
4364
  return entry.packageName.startsWith(CHUNK_PREFIX);
4244
4365
  }
4245
- function densifyExternals(shared) {
4366
+ function densifyExternals(shared, declaredPackages) {
4246
4367
  const result = [];
4247
4368
  const groupIndex = /* @__PURE__ */ new Map();
4248
4369
  for (const entry of shared) {
@@ -4256,7 +4377,7 @@ function densifyExternals(shared) {
4256
4377
  continue;
4257
4378
  }
4258
4379
  const { outFileName, packageName, dev, ...meta } = entry;
4259
- const parent = inferPackageFromSecondary(packageName);
4380
+ const parent = declaredPackages.get(packageName) ?? inferPackageFromSecondary(packageName);
4260
4381
  const sig = JSON.stringify(meta, Object.keys(meta).sort());
4261
4382
  const key = parent + " " + sig;
4262
4383
  const existing = groupIndex.get(key);
@@ -4286,6 +4407,16 @@ function toDenseSharedInfoFormat(shared) {
4286
4407
  });
4287
4408
  }
4288
4409
 
4410
+ // src/lib/core/3.adapters/remote-entry/normalize-remote-entry.ts
4411
+ var normalizeRemoteEntry = (raw, remoteEntryUrl, config) => {
4412
+ const marked = markDense(raw.shared ?? []);
4413
+ const shared = config.feature.convertFlatSharedInfo ? densifyExternals(marked, /* @__PURE__ */ new Map()) : toDenseSharedInfoFormat(marked);
4414
+ const remoteEntry = { ...raw, shared };
4415
+ if (!remoteEntry.exposes) remoteEntry.exposes = [];
4416
+ if (!remoteEntry.url) remoteEntry.url = remoteEntryUrl;
4417
+ return remoteEntry;
4418
+ };
4419
+
4289
4420
  // src/lib/core/3.adapters/http/remote-entry-provider.ts
4290
4421
  var createRemoteEntryProvider = (config) => {
4291
4422
  const ensureOk = (response) => {
@@ -4293,16 +4424,6 @@ var createRemoteEntryProvider = (config) => {
4293
4424
  return Promise.reject(new Error(`${response.status} - ${response.statusText}`));
4294
4425
  return response;
4295
4426
  };
4296
- const fillEmptyFields = (remoteEntryUrl) => (remoteEntry) => {
4297
- if (!remoteEntry.exposes) remoteEntry.exposes = [];
4298
- if (!remoteEntry.shared) remoteEntry.shared = [];
4299
- if (!remoteEntry.url) remoteEntry.url = remoteEntryUrl;
4300
- return remoteEntry;
4301
- };
4302
- const normalizeRemoteEntry = (raw) => {
4303
- const shared = config.feature.convertFlatSharedInfo ? densifyExternals(raw.shared ?? []) : toDenseSharedInfoFormat(raw.shared ?? []);
4304
- return { ...raw, shared };
4305
- };
4306
4427
  const formatError = (remoteEntryUrl) => (err) => {
4307
4428
  const msg = err instanceof Error ? err.message : String(err);
4308
4429
  throw new NFError(`Fetch of '${remoteEntryUrl}' returned ${msg}`);
@@ -4315,7 +4436,7 @@ var createRemoteEntryProvider = (config) => {
4315
4436
  await verifyIntegrity(bytes, opts.integrity);
4316
4437
  return JSON.parse(new TextDecoder().decode(bytes));
4317
4438
  };
4318
- return fetch(remoteEntryUrl).then(ensureOk).then(parse).then(normalizeRemoteEntry).then(fillEmptyFields(remoteEntryUrl)).catch(formatError(remoteEntryUrl));
4439
+ return fetch(remoteEntryUrl).then(ensureOk).then(parse).then((raw) => normalizeRemoteEntry(raw, remoteEntryUrl, config)).catch(formatError(remoteEntryUrl));
4319
4440
  }
4320
4441
  };
4321
4442
  };
@@ -4923,7 +5044,7 @@ globalThisStorageEntry.type = "globalThis";
4923
5044
  Object.freeze(globalThisStorageEntry);
4924
5045
 
4925
5046
  // src/lib/core/4.config/orchestrator-version.ts
4926
- var ORCHESTRATOR_VERSION = true ? "4.8.0" : "dev";
5047
+ var ORCHESTRATOR_VERSION = true ? "4.9.0" : "dev";
4927
5048
 
4928
5049
  // src/lib/core/4.config/storage/publish-storage-info.ts
4929
5050
  var KEYS = Object.freeze(Object.values(STORAGE_KEYS));
@@ -4966,10 +5087,49 @@ var isOutdatedCache = (storage) => {
4966
5087
  cacheState.update({ version: ORCHESTRATOR_VERSION, undecidedScopes: [] });
4967
5088
  return Object.values(STORAGE_KEYS).filter((key) => key !== STORAGE_KEYS.cacheState).some((key) => storage(key, null).get() !== null);
4968
5089
  };
4969
- var createStorageConfig = (override) => {
5090
+ var guardWrites = (storage, log) => {
5091
+ let failed = false;
5092
+ const memory = /* @__PURE__ */ new Map();
5093
+ const write = (key, value, persist) => {
5094
+ if (!failed) {
5095
+ try {
5096
+ persist();
5097
+ return;
5098
+ } catch (error) {
5099
+ failed = true;
5100
+ try {
5101
+ storage(STORAGE_KEYS.cacheState, null).set(null);
5102
+ } catch {
5103
+ }
5104
+ log.warn(
5105
+ 5,
5106
+ `Could not save '${key}' to storage; this page runs from memory and the next page starts without a cache.`,
5107
+ error
5108
+ );
5109
+ }
5110
+ }
5111
+ memory.set(key, cloneEntry(key, value));
5112
+ };
5113
+ return (key, initialValue) => {
5114
+ const inner = storage(key, initialValue);
5115
+ const entry = {
5116
+ get: () => memory.has(key) ? cloneEntry(key, memory.get(key)) : inner.get(),
5117
+ set: (value) => {
5118
+ write(key, value, () => void inner.set(value));
5119
+ return entry;
5120
+ },
5121
+ clear: () => {
5122
+ write(key, initialValue, () => void inner.clear());
5123
+ return entry;
5124
+ }
5125
+ };
5126
+ return entry;
5127
+ };
5128
+ };
5129
+ var createStorageConfig = (override, log) => {
4970
5130
  const creator = override.storage ?? globalThisStorageEntry;
4971
5131
  const namespace = override.storageNamespace ?? "__NATIVE_FEDERATION__";
4972
- const storage = creator(namespace);
5132
+ const storage = guardWrites(creator(namespace), log);
4973
5133
  publishStorageInfo({
4974
5134
  type: creator.type ?? "custom",
4975
5135
  namespace,
@@ -4988,7 +5148,8 @@ var defaultProfile = {
4988
5148
  latestSharedExternal: false,
4989
5149
  skipInvalidExternalVersions: false,
4990
5150
  overrideCachedRemotes: "init-only",
4991
- overrideCachedRemotesIfURLMatches: false
5151
+ overrideCachedRemotesIfURLMatches: false,
5152
+ mergeManifests: true
4992
5153
  };
4993
5154
 
4994
5155
  // src/lib/core/4.config/mode/mode.config.ts
@@ -5016,13 +5177,16 @@ var createModeConfig = (override) => {
5016
5177
  };
5017
5178
 
5018
5179
  // src/lib/core/5.di/config.factory.ts
5019
- var createConfigHandlers = (overrides) => ({
5020
- ...createImportMapConfig(overrides),
5021
- ...createHostConfig(overrides),
5022
- ...createLogConfig(overrides),
5023
- ...createStorageConfig(overrides),
5024
- ...createModeConfig(overrides)
5025
- });
5180
+ var createConfigHandlers = (overrides) => {
5181
+ const logConfig = createLogConfig(overrides);
5182
+ return {
5183
+ ...createImportMapConfig(overrides),
5184
+ ...createHostConfig(overrides),
5185
+ ...logConfig,
5186
+ ...createStorageConfig(overrides, logConfig.log),
5187
+ ...createModeConfig(overrides)
5188
+ };
5189
+ };
5026
5190
 
5027
5191
  // src/lib/core/5.di/federation-result.factory.ts
5028
5192
  var createFederationResult = ({