@softarc/native-federation-orchestrator 4.5.2 → 4.6.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/README.md +2 -2
- package/fesm2022/@softarc/native-federation-orchestrator.mjs +1310 -257
- package/fesm2022/@softarc/native-federation-orchestrator.mjs.map +4 -4
- package/fesm2022/module-federation.mjs +27 -8
- package/fesm2022/module-federation.mjs.map +3 -3
- package/fesm2022/node.mjs +1307 -254
- package/fesm2022/node.mjs.map +4 -4
- package/fesm2022/options.mjs +5 -10
- package/fesm2022/options.mjs.map +2 -2
- package/package.json +2 -2
- package/quickstart.mjs +15 -15
- package/types/lib/core/1.domain/externals/basis.d.ts +22 -0
- package/types/lib/core/1.domain/externals/version.contract.d.ts +1 -0
- package/types/lib/core/1.domain/remote-entry/remote-entry.contract.d.ts +2 -0
- package/types/lib/core/2.app/config/mode.contract.d.ts +1 -0
- package/types/lib/core/2.app/driver-ports/init/drivers.contract.d.ts +2 -0
- package/types/lib/core/2.app/driver-ports/init/for-determining-shared-externals.port.d.ts +8 -1
- package/types/lib/core/2.app/driver-ports/init/for-marking-pools-for-reelection.port.d.ts +6 -0
- package/types/lib/core/2.app/driver-ports/init/for-pooling-shared-externals.port.d.ts +3 -1
- package/types/lib/core/2.app/driving-ports/for-shared-chunks-storage.port.d.ts +1 -0
- package/types/lib/core/2.app/driving-ports/for-shared-externals-storage.port.d.ts +2 -3
- package/types/lib/core/2.app/steps/apply-winner.d.ts +18 -0
- package/types/lib/core/2.app/steps/pooling/anchoring.d.ts +69 -0
- package/types/lib/core/2.app/steps/pooling/mark-pools-for-reelection.d.ts +5 -0
- package/types/lib/core/2.app/steps/pooling/pool-dynamic-externals.d.ts +3 -1
- package/types/lib/core/2.app/steps/pooling/pool-graph.d.ts +10 -5
- package/types/lib/core/2.app/steps/pooling/pool-shared-externals.d.ts +30 -1
- package/types/lib/core/2.app/steps/pooling/pool-views.d.ts +63 -0
- package/types/lib/core/2.app/steps/pooling/pool.types.d.ts +30 -1
- package/types/lib/core/2.app/steps/pooling/pool.util.d.ts +15 -0
- package/types/lib/core/2.app/steps/store-remote-entry.d.ts +15 -7
- package/types/lib/testing/pooling/no-tear.d.ts +37 -0
package/fesm2022/node.mjs
CHANGED
|
@@ -1490,16 +1490,21 @@ var createRemoteInfoRepository = (config) => {
|
|
|
1490
1490
|
const STORAGE = config.storage("remotes", {});
|
|
1491
1491
|
if (config.clearStorage) STORAGE.clear();
|
|
1492
1492
|
const _cache = STORAGE.get() ?? {};
|
|
1493
|
+
let _dirty = false;
|
|
1493
1494
|
return {
|
|
1494
1495
|
contains: function(remoteName) {
|
|
1495
1496
|
return !!_cache[remoteName];
|
|
1496
1497
|
},
|
|
1497
1498
|
remove: function(remoteName) {
|
|
1498
|
-
|
|
1499
|
+
if (remoteName in _cache) {
|
|
1500
|
+
delete _cache[remoteName];
|
|
1501
|
+
_dirty = true;
|
|
1502
|
+
}
|
|
1499
1503
|
return this;
|
|
1500
1504
|
},
|
|
1501
1505
|
addOrUpdate: function(remoteName, remote) {
|
|
1502
1506
|
_cache[remoteName] = remote;
|
|
1507
|
+
_dirty = true;
|
|
1503
1508
|
return this;
|
|
1504
1509
|
},
|
|
1505
1510
|
tryGet: function(remoteName) {
|
|
@@ -1514,7 +1519,9 @@ var createRemoteInfoRepository = (config) => {
|
|
|
1514
1519
|
return _cache;
|
|
1515
1520
|
},
|
|
1516
1521
|
commit: function() {
|
|
1522
|
+
if (!_dirty) return this;
|
|
1517
1523
|
STORAGE.set(_cache);
|
|
1524
|
+
_dirty = false;
|
|
1518
1525
|
return this;
|
|
1519
1526
|
}
|
|
1520
1527
|
};
|
|
@@ -1525,14 +1532,19 @@ var createScopedExternalsRepository = (config) => {
|
|
|
1525
1532
|
const STORAGE = config.storage("scoped-externals", {});
|
|
1526
1533
|
if (config.clearStorage) STORAGE.clear();
|
|
1527
1534
|
const _cache = STORAGE.get() ?? {};
|
|
1535
|
+
let _dirty = false;
|
|
1528
1536
|
return {
|
|
1529
1537
|
addExternal: function(remoteName, external, version) {
|
|
1530
1538
|
if (!_cache[remoteName]) _cache[remoteName] = {};
|
|
1531
1539
|
_cache[remoteName][external] = version;
|
|
1540
|
+
_dirty = true;
|
|
1532
1541
|
return this;
|
|
1533
1542
|
},
|
|
1534
1543
|
remove: function(remoteName) {
|
|
1535
|
-
|
|
1544
|
+
if (remoteName in _cache) {
|
|
1545
|
+
delete _cache[remoteName];
|
|
1546
|
+
_dirty = true;
|
|
1547
|
+
}
|
|
1536
1548
|
return this;
|
|
1537
1549
|
},
|
|
1538
1550
|
getAll: function() {
|
|
@@ -1542,7 +1554,9 @@ var createScopedExternalsRepository = (config) => {
|
|
|
1542
1554
|
return Optional.of(_cache[remoteName]);
|
|
1543
1555
|
},
|
|
1544
1556
|
commit: function() {
|
|
1557
|
+
if (!_dirty) return this;
|
|
1545
1558
|
STORAGE.set(_cache);
|
|
1559
|
+
_dirty = false;
|
|
1546
1560
|
return this;
|
|
1547
1561
|
}
|
|
1548
1562
|
};
|
|
@@ -1559,14 +1573,19 @@ var createSharedExternalsRepository = (config) => {
|
|
|
1559
1573
|
{ [GLOBAL_SCOPE]: {} }
|
|
1560
1574
|
);
|
|
1561
1575
|
if (config.clearStorage) STORAGE.clear();
|
|
1562
|
-
const _cache = STORAGE.get();
|
|
1563
|
-
let
|
|
1576
|
+
const _cache = STORAGE.get() ?? { [GLOBAL_SCOPE]: {} };
|
|
1577
|
+
let _dirty = false;
|
|
1564
1578
|
return {
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
hasPoolTag: function() {
|
|
1569
|
-
|
|
1579
|
+
// Read from the cache rather than remembered from this init's entries: a warm init may not refetch
|
|
1580
|
+
// the tagged remote at all, and pooling has to coordinate its pool anyway. Exits on the first hit.
|
|
1581
|
+
// Per share scope, because a pool never spans one: a tag in another scope is no reason to pool here.
|
|
1582
|
+
hasPoolTag: function(shareScope) {
|
|
1583
|
+
const scope = _cache[shareScope ?? GLOBAL_SCOPE];
|
|
1584
|
+
if (!scope) return false;
|
|
1585
|
+
for (const external of Object.values(scope))
|
|
1586
|
+
for (const version of external.versions)
|
|
1587
|
+
for (const remote of version.remotes) if (remote.pool?.trim()) return true;
|
|
1588
|
+
return false;
|
|
1570
1589
|
},
|
|
1571
1590
|
getFromScope: function(shareScope) {
|
|
1572
1591
|
return { ..._cache[shareScope ?? GLOBAL_SCOPE] };
|
|
@@ -1574,28 +1593,41 @@ var createSharedExternalsRepository = (config) => {
|
|
|
1574
1593
|
addOrUpdate: function(externalName, external, shareScope) {
|
|
1575
1594
|
if (!_cache[shareScope ?? GLOBAL_SCOPE]) _cache[shareScope ?? GLOBAL_SCOPE] = {};
|
|
1576
1595
|
_cache[shareScope ?? GLOBAL_SCOPE][externalName] = external;
|
|
1596
|
+
_dirty = true;
|
|
1577
1597
|
return this;
|
|
1578
1598
|
},
|
|
1579
1599
|
getScopes: function(o = { includeGlobal: true }) {
|
|
1580
1600
|
if (o.includeGlobal) return Object.keys(_cache);
|
|
1581
1601
|
return Object.keys(_cache).filter((s) => s !== GLOBAL_SCOPE);
|
|
1582
1602
|
},
|
|
1583
|
-
|
|
1603
|
+
// Batched: one traversal of the graph per init instead of one per overridden remote.
|
|
1604
|
+
removeFromAllScopes: function(remoteNames) {
|
|
1605
|
+
if (remoteNames.size === 0) return;
|
|
1584
1606
|
Object.values(_cache).forEach((scope) => {
|
|
1585
1607
|
const removeExternals = [];
|
|
1586
1608
|
Object.entries(scope).forEach(([name, external]) => {
|
|
1587
|
-
|
|
1588
|
-
external.versions.
|
|
1589
|
-
const
|
|
1590
|
-
|
|
1591
|
-
|
|
1609
|
+
let removedCopy = false;
|
|
1610
|
+
for (let i = external.versions.length - 1; i >= 0; i--) {
|
|
1611
|
+
const version = external.versions[i];
|
|
1612
|
+
const remotes = version.remotes;
|
|
1613
|
+
const host = version.host ? remotes[0]?.name : void 0;
|
|
1614
|
+
let keep = 0;
|
|
1615
|
+
for (let r = 0; r < remotes.length; r++) {
|
|
1616
|
+
if (remoteNames.has(remotes[r].name)) continue;
|
|
1617
|
+
remotes[keep++] = remotes[r];
|
|
1592
1618
|
}
|
|
1593
|
-
if (
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1619
|
+
if (keep !== remotes.length) {
|
|
1620
|
+
remotes.length = keep;
|
|
1621
|
+
removedCopy = true;
|
|
1622
|
+
_dirty = true;
|
|
1623
|
+
if (host !== void 0 && remoteNames.has(host)) version.host = false;
|
|
1624
|
+
}
|
|
1625
|
+
if (remotes.length === 0) {
|
|
1626
|
+
external.versions.splice(i, 1);
|
|
1627
|
+
_dirty = true;
|
|
1598
1628
|
}
|
|
1629
|
+
}
|
|
1630
|
+
if (removedCopy) {
|
|
1599
1631
|
external.dirty = true;
|
|
1600
1632
|
if (external.versions.length === 0) removeExternals.push(name);
|
|
1601
1633
|
}
|
|
@@ -1619,7 +1651,9 @@ var createSharedExternalsRepository = (config) => {
|
|
|
1619
1651
|
return Optional.of(_cache[shareScope ?? GLOBAL_SCOPE]?.[external]);
|
|
1620
1652
|
},
|
|
1621
1653
|
commit: function() {
|
|
1654
|
+
if (!_dirty) return this;
|
|
1622
1655
|
STORAGE.set(_cache);
|
|
1656
|
+
_dirty = false;
|
|
1623
1657
|
return this;
|
|
1624
1658
|
}
|
|
1625
1659
|
};
|
|
@@ -1630,17 +1664,29 @@ var createChunkRepository = (config) => {
|
|
|
1630
1664
|
const STORAGE = config.storage("shared-chunks", {});
|
|
1631
1665
|
if (config.clearStorage) STORAGE.clear();
|
|
1632
1666
|
const _cache = STORAGE.get() ?? {};
|
|
1667
|
+
let _dirty = false;
|
|
1633
1668
|
return {
|
|
1634
1669
|
addOrReplace: function(remoteName, bundleName, chunks) {
|
|
1635
1670
|
if (!_cache[remoteName]) _cache[remoteName] = {};
|
|
1636
1671
|
_cache[remoteName][bundleName] = chunks;
|
|
1672
|
+
_dirty = true;
|
|
1673
|
+
return this;
|
|
1674
|
+
},
|
|
1675
|
+
// Whole-remote: a build that stops chunking a bundle omits the key, so `addOrReplace` cannot clear it.
|
|
1676
|
+
remove: function(remoteName) {
|
|
1677
|
+
if (remoteName in _cache) {
|
|
1678
|
+
delete _cache[remoteName];
|
|
1679
|
+
_dirty = true;
|
|
1680
|
+
}
|
|
1637
1681
|
return this;
|
|
1638
1682
|
},
|
|
1639
1683
|
tryGet: function(remoteName, bundleName) {
|
|
1640
1684
|
return Optional.of(_cache[remoteName]?.[bundleName]);
|
|
1641
1685
|
},
|
|
1642
1686
|
commit: function() {
|
|
1687
|
+
if (!_dirty) return this;
|
|
1643
1688
|
STORAGE.set(_cache);
|
|
1689
|
+
_dirty = false;
|
|
1644
1690
|
return this;
|
|
1645
1691
|
}
|
|
1646
1692
|
};
|
|
@@ -1830,10 +1876,9 @@ var globalThisStorageEntry = (namespace) => (key, initialValue) => {
|
|
|
1830
1876
|
globalThis[namespace] = {};
|
|
1831
1877
|
}
|
|
1832
1878
|
const storage = globalThis[namespace];
|
|
1833
|
-
if (!storage[key]) storage[key] = initialValue;
|
|
1834
1879
|
const entry = {
|
|
1835
1880
|
get() {
|
|
1836
|
-
return cloneEntry(key, storage[key]);
|
|
1881
|
+
return cloneEntry(key, key in storage ? storage[key] : initialValue);
|
|
1837
1882
|
},
|
|
1838
1883
|
set(value) {
|
|
1839
1884
|
storage[key] = cloneEntry(key, value);
|
|
@@ -1857,6 +1902,7 @@ var createStorageConfig = (override) => ({
|
|
|
1857
1902
|
var defaultProfile = {
|
|
1858
1903
|
latestSharedExternal: false,
|
|
1859
1904
|
skipInvalidExternalVersions: false,
|
|
1905
|
+
scopeUncoveredEntrypoints: false,
|
|
1860
1906
|
overrideCachedRemotes: "init-only",
|
|
1861
1907
|
overrideCachedRemotesIfURLMatches: false
|
|
1862
1908
|
};
|
|
@@ -1903,7 +1949,7 @@ var createInitFlow = ({
|
|
|
1903
1949
|
adapters,
|
|
1904
1950
|
config
|
|
1905
1951
|
}) => {
|
|
1906
|
-
return (remotesOrManifestUrl) => flow.getRemoteEntries(remotesOrManifestUrl).then(flow.processRemoteEntries).then(flow.determineSharedExternals).then(flow.poolSharedExternals).then(flow.generateImportMap).then((importMap) => flow.commitChanges(importMap, { override: true })).then(flow.exposeModuleLoader).then((loadRemoteModule) => ({
|
|
1952
|
+
return (remotesOrManifestUrl) => flow.getRemoteEntries(remotesOrManifestUrl).then(flow.processRemoteEntries).then(flow.markPoolsForReelection).then(flow.determineSharedExternals).then(flow.poolSharedExternals).then(flow.generateImportMap).then((importMap) => flow.commitChanges(importMap, { override: true })).then(flow.exposeModuleLoader).then((loadRemoteModule) => ({
|
|
1907
1953
|
config,
|
|
1908
1954
|
adapters,
|
|
1909
1955
|
loadRemoteModule
|
|
@@ -2022,19 +2068,92 @@ function createGetRemoteEntries(config, ports) {
|
|
|
2022
2068
|
}
|
|
2023
2069
|
}
|
|
2024
2070
|
|
|
2071
|
+
// src/lib/core/1.domain/externals/basis.ts
|
|
2072
|
+
var coverage = (remote) => Object.keys(remote.entries).length;
|
|
2073
|
+
function isBetterBasis(candidate, basis) {
|
|
2074
|
+
if (basis.cached !== candidate.cached) return candidate.cached;
|
|
2075
|
+
return coverage(candidate) > coverage(basis);
|
|
2076
|
+
}
|
|
2077
|
+
function addRemoteToVersion(version, remote, isHost = false) {
|
|
2078
|
+
if (isHost) {
|
|
2079
|
+
version.host = true;
|
|
2080
|
+
version.remotes.unshift(remote);
|
|
2081
|
+
return;
|
|
2082
|
+
}
|
|
2083
|
+
const basis = version.remotes[0];
|
|
2084
|
+
if (basis && !version.host && isBetterBasis(remote, basis)) {
|
|
2085
|
+
version.remotes.unshift(remote);
|
|
2086
|
+
return;
|
|
2087
|
+
}
|
|
2088
|
+
version.remotes.push(remote);
|
|
2089
|
+
}
|
|
2090
|
+
function versionDemands(version) {
|
|
2091
|
+
if (version.remotes.length < 2) return version.remotes;
|
|
2092
|
+
const distinct = /* @__PURE__ */ new Map();
|
|
2093
|
+
for (const remote of version.remotes) {
|
|
2094
|
+
const key = `${remote.requiredVersion}|${remote.strictVersion}|${remote.cached}`;
|
|
2095
|
+
if (!distinct.has(key)) distinct.set(key, remote);
|
|
2096
|
+
}
|
|
2097
|
+
return Array.from(distinct.values());
|
|
2098
|
+
}
|
|
2099
|
+
function findVersionForTag(versions, tag) {
|
|
2100
|
+
let scoped;
|
|
2101
|
+
for (const version of versions) {
|
|
2102
|
+
if (version.tag !== tag) continue;
|
|
2103
|
+
if (version.action !== "scope") return version;
|
|
2104
|
+
scoped ??= version;
|
|
2105
|
+
}
|
|
2106
|
+
return scoped;
|
|
2107
|
+
}
|
|
2108
|
+
function versionEntries(version) {
|
|
2109
|
+
return collectEntries(version, void 0);
|
|
2110
|
+
}
|
|
2111
|
+
function committedEntries(version) {
|
|
2112
|
+
return collectEntries(version, (remote) => remote.cached);
|
|
2113
|
+
}
|
|
2114
|
+
function forEachVersionEntry(version, accepts, visit) {
|
|
2115
|
+
for (const remote of version.remotes) {
|
|
2116
|
+
if (remote.servedBy) continue;
|
|
2117
|
+
if (accepts && !accepts(remote)) continue;
|
|
2118
|
+
for (const entrypoint in remote.entries) visit(entrypoint, remote);
|
|
2119
|
+
}
|
|
2120
|
+
}
|
|
2121
|
+
function collectEntries(version, accepts) {
|
|
2122
|
+
const entries = /* @__PURE__ */ new Map();
|
|
2123
|
+
forEachVersionEntry(version, accepts, (entrypoint, remote) => {
|
|
2124
|
+
if (!entries.has(entrypoint)) entries.set(entrypoint, remote);
|
|
2125
|
+
});
|
|
2126
|
+
return entries;
|
|
2127
|
+
}
|
|
2128
|
+
function uncoveredEntrypoints(remote, covered) {
|
|
2129
|
+
return Object.keys(remote.entries).filter((entrypoint) => !covered.has(entrypoint));
|
|
2130
|
+
}
|
|
2131
|
+
function countUncoveredEntrypoints(remote, covered) {
|
|
2132
|
+
let uncovered = 0;
|
|
2133
|
+
for (const entrypoint in remote.entries) {
|
|
2134
|
+
if (!covered.has(entrypoint)) uncovered++;
|
|
2135
|
+
}
|
|
2136
|
+
return uncovered;
|
|
2137
|
+
}
|
|
2138
|
+
|
|
2025
2139
|
// src/lib/core/2.app/steps/store-remote-entry.ts
|
|
2140
|
+
function createRemoveCachedRemoteEntries(ports) {
|
|
2141
|
+
return (remoteNames) => {
|
|
2142
|
+
if (remoteNames.size === 0) return;
|
|
2143
|
+
for (const remoteName of remoteNames) {
|
|
2144
|
+
ports.remoteInfoRepo.remove(remoteName);
|
|
2145
|
+
ports.scopedExternalsRepo.remove(remoteName);
|
|
2146
|
+
ports.sharedChunksRepo.remove(remoteName);
|
|
2147
|
+
}
|
|
2148
|
+
ports.sharedExternalsRepo.removeFromAllScopes(remoteNames);
|
|
2149
|
+
};
|
|
2150
|
+
}
|
|
2026
2151
|
function createStoreRemoteEntry(config, ports, logStep) {
|
|
2027
2152
|
return (remoteEntry, onSharedExternal) => {
|
|
2028
|
-
if (remoteEntry?.override) removeCachedRemoteEntry(remoteEntry);
|
|
2029
2153
|
addRemoteInfoToStorage(remoteEntry);
|
|
2030
2154
|
addExternalsToStorage(remoteEntry, onSharedExternal);
|
|
2031
2155
|
addSharedChunksToStorage(remoteEntry);
|
|
2032
2156
|
};
|
|
2033
|
-
function removeCachedRemoteEntry(remoteEntry) {
|
|
2034
|
-
ports.remoteInfoRepo.remove(remoteEntry.name);
|
|
2035
|
-
ports.scopedExternalsRepo.remove(remoteEntry.name);
|
|
2036
|
-
ports.sharedExternalsRepo.removeFromAllScopes(remoteEntry.name);
|
|
2037
|
-
}
|
|
2038
2157
|
function addRemoteInfoToStorage({ name, url, exposes, integrity }) {
|
|
2039
2158
|
ports.remoteInfoRepo.addOrUpdate(name, {
|
|
2040
2159
|
scopeUrl: getScope(url),
|
|
@@ -2050,7 +2169,6 @@ function createStoreRemoteEntry(config, ports, logStep) {
|
|
|
2050
2169
|
const tag = resolveVersion(remoteEntry, external);
|
|
2051
2170
|
if (tag === null) return;
|
|
2052
2171
|
if (external.singleton) {
|
|
2053
|
-
if (external.pool?.trim()) ports.sharedExternalsRepo.markPoolTagPresent();
|
|
2054
2172
|
onSharedExternal(remoteEntry, external, sharedExternalContext(remoteEntry, external, tag));
|
|
2055
2173
|
} else {
|
|
2056
2174
|
addScopedExternal(remoteEntry, external, tag);
|
|
@@ -2134,14 +2252,35 @@ function createStoreRemoteEntry(config, ports, logStep) {
|
|
|
2134
2252
|
// src/lib/core/2.app/steps/process-remote-entries.ts
|
|
2135
2253
|
function createProcessRemoteEntries(config, ports) {
|
|
2136
2254
|
const storeRemoteEntry = createStoreRemoteEntry(config, ports, 2);
|
|
2255
|
+
const removeCachedRemoteEntries = createRemoveCachedRemoteEntries(ports);
|
|
2137
2256
|
return (remoteEntries) => {
|
|
2138
2257
|
try {
|
|
2139
|
-
|
|
2258
|
+
const evictPerEntry = evictOverriddenRemotes(remoteEntries);
|
|
2259
|
+
remoteEntries.forEach((remoteEntry) => {
|
|
2260
|
+
if (remoteEntry?.override && evictPerEntry.has(remoteEntry.name)) {
|
|
2261
|
+
removeCachedRemoteEntries(/* @__PURE__ */ new Set([remoteEntry.name]));
|
|
2262
|
+
}
|
|
2263
|
+
storeRemoteEntry(remoteEntry, addSharedExternal);
|
|
2264
|
+
});
|
|
2140
2265
|
return Promise.resolve(remoteEntries);
|
|
2141
2266
|
} catch (e) {
|
|
2142
2267
|
return Promise.reject(e);
|
|
2143
2268
|
}
|
|
2144
2269
|
};
|
|
2270
|
+
function evictOverriddenRemotes(remoteEntries) {
|
|
2271
|
+
const batched = /* @__PURE__ */ new Set();
|
|
2272
|
+
const repeated = /* @__PURE__ */ new Set();
|
|
2273
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2274
|
+
for (const remoteEntry of remoteEntries) {
|
|
2275
|
+
if (!remoteEntry) continue;
|
|
2276
|
+
if (seen.has(remoteEntry.name)) repeated.add(remoteEntry.name);
|
|
2277
|
+
seen.add(remoteEntry.name);
|
|
2278
|
+
if (remoteEntry.override) batched.add(remoteEntry.name);
|
|
2279
|
+
}
|
|
2280
|
+
for (const remoteName of repeated) batched.delete(remoteName);
|
|
2281
|
+
removeCachedRemoteEntries(batched);
|
|
2282
|
+
return repeated;
|
|
2283
|
+
}
|
|
2145
2284
|
function addSharedExternal(remoteEntry, _sharedInfo, {
|
|
2146
2285
|
tag,
|
|
2147
2286
|
remote,
|
|
@@ -2150,15 +2289,12 @@ function createProcessRemoteEntries(config, ports) {
|
|
|
2150
2289
|
assertSameVersionCompatibility,
|
|
2151
2290
|
commit
|
|
2152
2291
|
}) {
|
|
2153
|
-
|
|
2292
|
+
if (scopeType !== "strict") cached2.dirty = true;
|
|
2293
|
+
const matchingVersion = findVersionForTag(cached2.versions, tag);
|
|
2154
2294
|
if (matchingVersion) {
|
|
2155
2295
|
assertSameVersionCompatibility(matchingVersion);
|
|
2156
|
-
|
|
2157
|
-
matchingVersion.host = true;
|
|
2158
|
-
matchingVersion.remotes.unshift(remote);
|
|
2159
|
-
} else matchingVersion.remotes.push(remote);
|
|
2296
|
+
addRemoteToVersion(matchingVersion, remote, !matchingVersion.host && !!remoteEntry?.host);
|
|
2160
2297
|
} else {
|
|
2161
|
-
if (scopeType !== "strict") cached2.dirty = true;
|
|
2162
2298
|
cached2.versions.push({
|
|
2163
2299
|
tag,
|
|
2164
2300
|
action: scopeType === "strict" ? "share" : "skip",
|
|
@@ -2170,19 +2306,154 @@ function createProcessRemoteEntries(config, ports) {
|
|
|
2170
2306
|
}
|
|
2171
2307
|
}
|
|
2172
2308
|
|
|
2309
|
+
// src/lib/core/2.app/steps/apply-winner.ts
|
|
2310
|
+
function versionAcceptance(external, isCompatible) {
|
|
2311
|
+
const demands = new Map(
|
|
2312
|
+
external.versions.map((v) => [v, versionDemands(v)])
|
|
2313
|
+
);
|
|
2314
|
+
return {
|
|
2315
|
+
accepts: (version, tag) => demands.get(version).every((d) => isCompatible(tag, d.requiredVersion)),
|
|
2316
|
+
objector: (version, tag) => demands.get(version).find((d) => d.strictVersion && !isCompatible(tag, d.requiredVersion))
|
|
2317
|
+
};
|
|
2318
|
+
}
|
|
2319
|
+
function createApplyWinner(config) {
|
|
2320
|
+
return function applyWinner(externalName, external, winner, isCompatible, acceptance) {
|
|
2321
|
+
if (external.versions.length > 1) {
|
|
2322
|
+
const { accepts, objector } = acceptance ?? versionAcceptance(external, isCompatible);
|
|
2323
|
+
const rebuilt = [];
|
|
2324
|
+
for (const v of external.versions) {
|
|
2325
|
+
rebuilt.push(v);
|
|
2326
|
+
if (accepts(v, winner.tag)) {
|
|
2327
|
+
v.action = "skip";
|
|
2328
|
+
continue;
|
|
2329
|
+
}
|
|
2330
|
+
const strict = objector(v, winner.tag);
|
|
2331
|
+
if (config.strict.strictExternalCompatibility && strict) {
|
|
2332
|
+
config.log.error(
|
|
2333
|
+
3,
|
|
2334
|
+
`[${strict.name}][${externalName}@${v.tag}] Is not compatible with requiredRange '${strict.requiredVersion}' of shared ${externalName}@${winner.tag}.`
|
|
2335
|
+
);
|
|
2336
|
+
throw new NFError(`External ${externalName}@${v.tag} could not be shared.`);
|
|
2337
|
+
}
|
|
2338
|
+
if (v === winner) continue;
|
|
2339
|
+
if (!strict) {
|
|
2340
|
+
v.action = "skip";
|
|
2341
|
+
continue;
|
|
2342
|
+
}
|
|
2343
|
+
const objecting = new Set(
|
|
2344
|
+
v.remotes.filter((r) => r.strictVersion && !isCompatible(winner.tag, r.requiredVersion))
|
|
2345
|
+
);
|
|
2346
|
+
if (objecting.size === v.remotes.length) {
|
|
2347
|
+
v.action = "scope";
|
|
2348
|
+
continue;
|
|
2349
|
+
}
|
|
2350
|
+
v.remotes = v.remotes.filter((r) => !objecting.has(r));
|
|
2351
|
+
v.action = "skip";
|
|
2352
|
+
rebuilt.push({ tag: v.tag, host: false, action: "scope", remotes: [...objecting] });
|
|
2353
|
+
}
|
|
2354
|
+
const merged = /* @__PURE__ */ new Map();
|
|
2355
|
+
external.versions = rebuilt.filter((v) => {
|
|
2356
|
+
const first = merged.get(`${v.tag}|${v.action}`);
|
|
2357
|
+
if (!first) {
|
|
2358
|
+
merged.set(`${v.tag}|${v.action}`, v);
|
|
2359
|
+
return true;
|
|
2360
|
+
}
|
|
2361
|
+
first.remotes.push(...v.remotes);
|
|
2362
|
+
return false;
|
|
2363
|
+
});
|
|
2364
|
+
}
|
|
2365
|
+
winner.action = "share";
|
|
2366
|
+
applyEntrypointCoveragePolicy(externalName, external);
|
|
2367
|
+
external.dirty = false;
|
|
2368
|
+
return external;
|
|
2369
|
+
};
|
|
2370
|
+
function applyEntrypointCoveragePolicy(externalName, external) {
|
|
2371
|
+
const { strictEntryPointCoverage } = config.strict;
|
|
2372
|
+
if (!strictEntryPointCoverage && !config.profile.scopeUncoveredEntrypoints) return;
|
|
2373
|
+
const tears = findTears(external);
|
|
2374
|
+
if (tears.length === 0) return;
|
|
2375
|
+
if (strictEntryPointCoverage) {
|
|
2376
|
+
const { version, remote, uncovered } = tears[0];
|
|
2377
|
+
config.log.error(
|
|
2378
|
+
3,
|
|
2379
|
+
`[${externalName}@${version.tag}][${remote.name}] Entrypoints not covered by the shared version: ${uncovered.join(", ")}.`
|
|
2380
|
+
);
|
|
2381
|
+
throw new NFError(
|
|
2382
|
+
`External ${externalName} could not be shared without tearing entrypoints.`
|
|
2383
|
+
);
|
|
2384
|
+
}
|
|
2385
|
+
scopeTornRemotes(externalName, external, tears);
|
|
2386
|
+
}
|
|
2387
|
+
function findTears(external) {
|
|
2388
|
+
const shared = external.versions.find((v) => v.action === "share");
|
|
2389
|
+
if (!shared) return [];
|
|
2390
|
+
const basis = versionEntries(shared);
|
|
2391
|
+
const tears = [];
|
|
2392
|
+
for (const version of external.versions) {
|
|
2393
|
+
if (version.action === "scope") continue;
|
|
2394
|
+
if (version === shared) continue;
|
|
2395
|
+
version.remotes.forEach((remote) => {
|
|
2396
|
+
if (remote.servedBy) return;
|
|
2397
|
+
const uncovered = uncoveredEntrypoints(remote, basis);
|
|
2398
|
+
if (uncovered.length > 0) tears.push({ version, remote, uncovered });
|
|
2399
|
+
});
|
|
2400
|
+
}
|
|
2401
|
+
return tears;
|
|
2402
|
+
}
|
|
2403
|
+
function scopeTornRemotes(externalName, external, tears) {
|
|
2404
|
+
const torn = new Set(tears.map((t) => t.remote));
|
|
2405
|
+
const demotedByTag = /* @__PURE__ */ new Map();
|
|
2406
|
+
for (const { version, remote, uncovered } of tears) {
|
|
2407
|
+
const group = demotedByTag.get(version.tag);
|
|
2408
|
+
if (group) group.push(remote);
|
|
2409
|
+
else demotedByTag.set(version.tag, [remote]);
|
|
2410
|
+
config.log.debug(
|
|
2411
|
+
3,
|
|
2412
|
+
`[${externalName}@${version.tag}][${remote.name}] Scoped: entrypoints not covered by the shared version: ${uncovered.join(", ")}.`
|
|
2413
|
+
);
|
|
2414
|
+
}
|
|
2415
|
+
for (const version of external.versions) {
|
|
2416
|
+
if (version.remotes.some((r) => torn.has(r))) {
|
|
2417
|
+
version.remotes = version.remotes.filter((r) => !torn.has(r));
|
|
2418
|
+
}
|
|
2419
|
+
}
|
|
2420
|
+
external.versions = external.versions.filter((v) => v.remotes.length > 0);
|
|
2421
|
+
for (const [tag, remotes] of demotedByTag) {
|
|
2422
|
+
const scoped = external.versions.find((v) => v.tag === tag && v.action === "scope");
|
|
2423
|
+
if (scoped) scoped.remotes.push(...remotes);
|
|
2424
|
+
else external.versions.push({ tag, host: false, action: "scope", remotes });
|
|
2425
|
+
}
|
|
2426
|
+
}
|
|
2427
|
+
}
|
|
2428
|
+
|
|
2173
2429
|
// src/lib/core/2.app/steps/determine-shared-externals.ts
|
|
2174
2430
|
function createDetermineSharedExternals(config, ports) {
|
|
2431
|
+
const applyWinner = createApplyWinner(config);
|
|
2175
2432
|
return () => {
|
|
2433
|
+
const memo = /* @__PURE__ */ new Map();
|
|
2434
|
+
const isCompatible = (tag, requiredVersion) => {
|
|
2435
|
+
const key = `${tag}|${requiredVersion}`;
|
|
2436
|
+
let hit = memo.get(key);
|
|
2437
|
+
if (hit === void 0) {
|
|
2438
|
+
hit = ports.versionCheck.isCompatible(tag, requiredVersion);
|
|
2439
|
+
memo.set(key, hit);
|
|
2440
|
+
}
|
|
2441
|
+
return hit;
|
|
2442
|
+
};
|
|
2443
|
+
const touched = /* @__PURE__ */ new Map();
|
|
2176
2444
|
for (const shareScope of ports.sharedExternalsRepo.getScopes()) {
|
|
2177
2445
|
const sharedExternals = ports.sharedExternalsRepo.getFromScope(shareScope);
|
|
2178
2446
|
try {
|
|
2179
|
-
|
|
2180
|
-
|
|
2447
|
+
const elected = /* @__PURE__ */ new Set();
|
|
2448
|
+
Object.entries(sharedExternals).filter(([_, e]) => e.dirty).forEach(([name, external]) => {
|
|
2449
|
+
ports.sharedExternalsRepo.addOrUpdate(
|
|
2181
2450
|
name,
|
|
2182
|
-
setVersionActions(name, external),
|
|
2451
|
+
setVersionActions(name, external, isCompatible),
|
|
2183
2452
|
shareScope
|
|
2184
|
-
)
|
|
2185
|
-
|
|
2453
|
+
);
|
|
2454
|
+
elected.add(name);
|
|
2455
|
+
});
|
|
2456
|
+
if (elected.size > 0) touched.set(shareScope, elected);
|
|
2186
2457
|
} catch (error) {
|
|
2187
2458
|
config.log.error(
|
|
2188
2459
|
3,
|
|
@@ -2200,22 +2471,25 @@ function createDetermineSharedExternals(config, ports) {
|
|
|
2200
2471
|
);
|
|
2201
2472
|
}
|
|
2202
2473
|
}
|
|
2203
|
-
return Promise.resolve();
|
|
2474
|
+
return Promise.resolve(touched);
|
|
2204
2475
|
};
|
|
2205
|
-
function uncoveredTears(external, winner) {
|
|
2206
|
-
const basis = winner
|
|
2476
|
+
function uncoveredTears(external, winner, accepts) {
|
|
2477
|
+
const basis = versionEntries(winner);
|
|
2207
2478
|
return external.versions.reduce((sum, v) => {
|
|
2208
2479
|
if (v === winner) return sum;
|
|
2209
|
-
if (!
|
|
2210
|
-
return
|
|
2480
|
+
if (!accepts(v, winner.tag)) return sum;
|
|
2481
|
+
return v.remotes.reduce(
|
|
2482
|
+
(n, r) => r.servedBy ? n : n + countUncoveredEntrypoints(r, basis),
|
|
2483
|
+
sum
|
|
2484
|
+
);
|
|
2211
2485
|
}, 0);
|
|
2212
2486
|
}
|
|
2213
|
-
function setVersionActions(externalName, external) {
|
|
2487
|
+
function setVersionActions(externalName, external, isCompatible) {
|
|
2214
2488
|
if (external.versions.length === 1) {
|
|
2215
|
-
external.versions[0]
|
|
2216
|
-
external.dirty = false;
|
|
2217
|
-
return external;
|
|
2489
|
+
return applyWinner(externalName, external, external.versions[0], isCompatible);
|
|
2218
2490
|
}
|
|
2491
|
+
const acceptance = versionAcceptance(external, isCompatible);
|
|
2492
|
+
const { accepts } = acceptance;
|
|
2219
2493
|
let sharedVersion = external.versions.find((v) => v.host);
|
|
2220
2494
|
if (!sharedVersion && config.profile.latestSharedExternal) {
|
|
2221
2495
|
sharedVersion = external.versions[0];
|
|
@@ -2223,13 +2497,39 @@ function createDetermineSharedExternals(config, ports) {
|
|
|
2223
2497
|
if (!sharedVersion) {
|
|
2224
2498
|
let leastExtraDownloads = Number.MAX_VALUE;
|
|
2225
2499
|
let leastTears = Number.MAX_VALUE;
|
|
2500
|
+
const selfServing = new Map(
|
|
2501
|
+
external.versions.map((v) => {
|
|
2502
|
+
const groups = /* @__PURE__ */ new Map();
|
|
2503
|
+
for (const remote of v.remotes) {
|
|
2504
|
+
if (remote.cached || !remote.strictVersion) continue;
|
|
2505
|
+
const group = groups.get(remote.requiredVersion);
|
|
2506
|
+
if (group) group.copies++;
|
|
2507
|
+
else
|
|
2508
|
+
groups.set(remote.requiredVersion, {
|
|
2509
|
+
requiredVersion: remote.requiredVersion,
|
|
2510
|
+
copies: 1
|
|
2511
|
+
});
|
|
2512
|
+
}
|
|
2513
|
+
return [v, [...groups.values()]];
|
|
2514
|
+
})
|
|
2515
|
+
);
|
|
2516
|
+
const costOf = (version, tag) => selfServing.get(version).reduce((n, g) => isCompatible(tag, g.requiredVersion) ? n : n + g.copies, 0);
|
|
2226
2517
|
external.versions.forEach((vA) => {
|
|
2227
|
-
const extraDownloads = external.versions.
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2518
|
+
const extraDownloads = external.versions.reduce(
|
|
2519
|
+
// A copy of the winner is never redirected, so it never self-serves however its own range
|
|
2520
|
+
// reads — see `applyWinner`, which does not split the winner either.
|
|
2521
|
+
(sum, vB) => vB === vA ? sum : sum + costOf(vB, vA.tag),
|
|
2522
|
+
0
|
|
2523
|
+
);
|
|
2524
|
+
if (extraDownloads < leastExtraDownloads) {
|
|
2232
2525
|
leastExtraDownloads = extraDownloads;
|
|
2526
|
+
leastTears = uncoveredTears(external, vA, accepts);
|
|
2527
|
+
sharedVersion = vA;
|
|
2528
|
+
return;
|
|
2529
|
+
}
|
|
2530
|
+
if (extraDownloads > leastExtraDownloads) return;
|
|
2531
|
+
const tears = uncoveredTears(external, vA, accepts);
|
|
2532
|
+
if (tears < leastTears) {
|
|
2233
2533
|
leastTears = tears;
|
|
2234
2534
|
sharedVersion = vA;
|
|
2235
2535
|
}
|
|
@@ -2238,40 +2538,302 @@ function createDetermineSharedExternals(config, ports) {
|
|
|
2238
2538
|
if (!sharedVersion) {
|
|
2239
2539
|
throw new NFError(`[${externalName}] Could not determine shared version!`);
|
|
2240
2540
|
}
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2541
|
+
return applyWinner(externalName, external, sharedVersion, isCompatible, acceptance);
|
|
2542
|
+
}
|
|
2543
|
+
}
|
|
2544
|
+
|
|
2545
|
+
// src/lib/core/2.app/steps/pooling/pool-views.ts
|
|
2546
|
+
function liveBuilds(members, islanded) {
|
|
2547
|
+
return walkBuilds(members, islanded, true);
|
|
2548
|
+
}
|
|
2549
|
+
function committedView(members) {
|
|
2550
|
+
const global = /* @__PURE__ */ new Map();
|
|
2551
|
+
forEachGlobalClaim(members, void 0, (specifier, tag, meta) => {
|
|
2552
|
+
if (!global.has(specifier))
|
|
2553
|
+
global.set(specifier, { tag, remote: meta.name, file: meta.entries[specifier] });
|
|
2554
|
+
});
|
|
2555
|
+
return { builds: walkBuilds(members, void 0, false), global };
|
|
2556
|
+
}
|
|
2557
|
+
function walkBuilds(members, islanded, skipScoped) {
|
|
2558
|
+
const builds = /* @__PURE__ */ new Map();
|
|
2559
|
+
for (const member of members) {
|
|
2560
|
+
const versions = member.external.versions;
|
|
2561
|
+
for (let v = 0; v < versions.length; v++) {
|
|
2562
|
+
const version = versions[v];
|
|
2563
|
+
if (skipScoped && version.action === "scope") continue;
|
|
2564
|
+
const remotes = version.remotes;
|
|
2565
|
+
for (let r = 0; r < remotes.length; r++) {
|
|
2566
|
+
const meta = remotes[r];
|
|
2567
|
+
if (islanded?.has(meta.name)) continue;
|
|
2568
|
+
let own = builds.get(meta.name);
|
|
2569
|
+
if (!own) {
|
|
2570
|
+
builds.set(
|
|
2571
|
+
meta.name,
|
|
2572
|
+
own = { coverage: /* @__PURE__ */ new Map(), tags: /* @__PURE__ */ new Map(), instance: /* @__PURE__ */ new Map() }
|
|
2573
|
+
);
|
|
2574
|
+
}
|
|
2575
|
+
if (!own.instance.has(member.name)) own.instance.set(member.name, version.tag);
|
|
2576
|
+
for (const specifier in meta.entries) {
|
|
2577
|
+
own.coverage.set(specifier, meta.entries[specifier]);
|
|
2578
|
+
if (!own.tags.has(specifier)) own.tags.set(specifier, version.tag);
|
|
2579
|
+
}
|
|
2245
2580
|
}
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2581
|
+
}
|
|
2582
|
+
}
|
|
2583
|
+
return builds;
|
|
2584
|
+
}
|
|
2585
|
+
function ownCopies(members, only) {
|
|
2586
|
+
const own = /* @__PURE__ */ new Map();
|
|
2587
|
+
for (const member of members) {
|
|
2588
|
+
for (const version of member.external.versions) {
|
|
2589
|
+
for (const meta of version.remotes) {
|
|
2590
|
+
if (only && !only.has(meta.name)) continue;
|
|
2591
|
+
let copies = own.get(meta.name);
|
|
2592
|
+
if (!copies) own.set(meta.name, copies = []);
|
|
2593
|
+
if (!copies.some((c) => c.member === member.name))
|
|
2594
|
+
copies.push({ member: member.name, tag: version.tag, entries: meta.entries });
|
|
2252
2595
|
}
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2596
|
+
}
|
|
2597
|
+
}
|
|
2598
|
+
return own;
|
|
2599
|
+
}
|
|
2600
|
+
function consumedMembers(members) {
|
|
2601
|
+
const consumed = /* @__PURE__ */ new Map();
|
|
2602
|
+
for (const member of members) {
|
|
2603
|
+
const versions = member.external.versions;
|
|
2604
|
+
for (let v = 0; v < versions.length; v++) {
|
|
2605
|
+
const remotes = versions[v].remotes;
|
|
2606
|
+
for (let r = 0; r < remotes.length; r++) {
|
|
2607
|
+
const name = remotes[r].name;
|
|
2608
|
+
const list = consumed.get(name);
|
|
2609
|
+
if (!list) consumed.set(name, [member.name]);
|
|
2610
|
+
else if (list[list.length - 1] !== member.name) list.push(member.name);
|
|
2611
|
+
}
|
|
2612
|
+
}
|
|
2613
|
+
}
|
|
2614
|
+
return consumed;
|
|
2615
|
+
}
|
|
2616
|
+
function consumedSpecifiers(members) {
|
|
2617
|
+
const consumed = /* @__PURE__ */ new Map();
|
|
2618
|
+
for (const member of members) {
|
|
2619
|
+
const versions = member.external.versions;
|
|
2620
|
+
for (let v = 0; v < versions.length; v++) {
|
|
2621
|
+
const remotes = versions[v].remotes;
|
|
2622
|
+
for (let r = 0; r < remotes.length; r++) {
|
|
2623
|
+
const meta = remotes[r];
|
|
2624
|
+
let own = consumed.get(meta.name);
|
|
2625
|
+
if (!own) consumed.set(meta.name, own = /* @__PURE__ */ new Set());
|
|
2626
|
+
for (const specifier in meta.entries) own.add(specifier);
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2629
|
+
}
|
|
2630
|
+
return consumed;
|
|
2631
|
+
}
|
|
2632
|
+
function coversWholePool(members, build, islanded) {
|
|
2633
|
+
const served = /* @__PURE__ */ new Set();
|
|
2634
|
+
const wanted = /* @__PURE__ */ new Set();
|
|
2635
|
+
for (const member of members) {
|
|
2636
|
+
for (const version of member.external.versions) {
|
|
2637
|
+
for (const meta of version.remotes) {
|
|
2638
|
+
if (islanded.has(meta.name)) continue;
|
|
2639
|
+
const into = meta.name === build ? served : wanted;
|
|
2640
|
+
for (const specifier in meta.entries) into.add(specifier);
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2644
|
+
for (const specifier of wanted) if (!served.has(specifier)) return false;
|
|
2645
|
+
return true;
|
|
2646
|
+
}
|
|
2647
|
+
function servingBuilds(members, islanded) {
|
|
2648
|
+
const serving = /* @__PURE__ */ new Map();
|
|
2649
|
+
for (const member of members) {
|
|
2650
|
+
const shared = member.external.versions.find((v) => v.action === "share");
|
|
2651
|
+
const basis = shared?.remotes.find((r) => !islanded.has(r.name));
|
|
2652
|
+
if (basis) serving.set(member.name, basis.name);
|
|
2653
|
+
}
|
|
2654
|
+
return serving;
|
|
2655
|
+
}
|
|
2656
|
+
function basisPerMember(members, islanded, dedupsElsewhere) {
|
|
2657
|
+
const basis = /* @__PURE__ */ new Map();
|
|
2658
|
+
for (const member of members) {
|
|
2659
|
+
const winner = member.external.versions.find((v) => v.action === "share");
|
|
2660
|
+
if (!winner) continue;
|
|
2661
|
+
const own = winner.remotes.find(
|
|
2662
|
+
(r) => !islanded?.has(r.name) && !dedupsElsewhere?.(r.name)
|
|
2663
|
+
);
|
|
2664
|
+
if (own) basis.set(member.name, own.name);
|
|
2665
|
+
}
|
|
2666
|
+
return basis;
|
|
2667
|
+
}
|
|
2668
|
+
function hostRemotes(members) {
|
|
2669
|
+
const hosts = /* @__PURE__ */ new Set();
|
|
2670
|
+
for (const member of members) {
|
|
2671
|
+
for (const version of member.external.versions) {
|
|
2672
|
+
if (version.host && version.remotes.length > 0) hosts.add(version.remotes[0].name);
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
return hosts;
|
|
2676
|
+
}
|
|
2677
|
+
function arrivalOrder(members) {
|
|
2678
|
+
const arrival = /* @__PURE__ */ new Map();
|
|
2679
|
+
for (const member of members) {
|
|
2680
|
+
for (const version of member.external.versions) {
|
|
2681
|
+
for (const meta of version.remotes) {
|
|
2682
|
+
if (!arrival.has(meta.name)) arrival.set(meta.name, arrival.size);
|
|
2683
|
+
}
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
return arrival;
|
|
2687
|
+
}
|
|
2688
|
+
function sharedTagPerSpecifier(members, islanded) {
|
|
2689
|
+
const shared = /* @__PURE__ */ new Map();
|
|
2690
|
+
forEachGlobalClaim(members, islanded, (specifier, tag) => {
|
|
2691
|
+
if (!shared.has(specifier)) shared.set(specifier, tag);
|
|
2692
|
+
});
|
|
2693
|
+
return shared;
|
|
2694
|
+
}
|
|
2695
|
+
function forEachGlobalClaim(members, islanded, visit) {
|
|
2696
|
+
const accepts = islanded ? (meta) => !islanded.has(meta.name) : void 0;
|
|
2697
|
+
const claim = (version) => forEachVersionEntry(version, accepts, (specifier, meta) => visit(specifier, version.tag, meta));
|
|
2698
|
+
for (const member of members) {
|
|
2699
|
+
const versions = member.external.versions;
|
|
2700
|
+
const winner = versions.find((v) => v.action === "share");
|
|
2701
|
+
if (winner) claim(winner);
|
|
2702
|
+
for (let v = 0; v < versions.length; v++) {
|
|
2703
|
+
if (versions[v].action === "skip") claim(versions[v]);
|
|
2704
|
+
}
|
|
2705
|
+
}
|
|
2706
|
+
}
|
|
2707
|
+
|
|
2708
|
+
// src/lib/core/2.app/steps/pooling/anchoring.ts
|
|
2709
|
+
function acceptanceTable(members, isCompatible) {
|
|
2710
|
+
const table = /* @__PURE__ */ new Map();
|
|
2711
|
+
for (const member of members) {
|
|
2712
|
+
const tags = [];
|
|
2713
|
+
for (const version of member.external.versions) tags.push(version.tag);
|
|
2714
|
+
for (const version of member.external.versions) {
|
|
2715
|
+
for (const meta of version.remotes) {
|
|
2716
|
+
let byMember = table.get(meta.name);
|
|
2717
|
+
if (!byMember) table.set(meta.name, byMember = /* @__PURE__ */ new Map());
|
|
2718
|
+
if (byMember.has(member.name)) continue;
|
|
2719
|
+
const accepted = /* @__PURE__ */ new Set();
|
|
2720
|
+
for (let t = 0; t < tags.length; t++) {
|
|
2721
|
+
if (isCompatible(tags[t], meta.requiredVersion)) accepted.add(tags[t]);
|
|
2269
2722
|
}
|
|
2270
|
-
|
|
2723
|
+
byMember.set(member.name, accepted);
|
|
2724
|
+
}
|
|
2271
2725
|
}
|
|
2272
|
-
external.dirty = false;
|
|
2273
|
-
return external;
|
|
2274
2726
|
}
|
|
2727
|
+
return table;
|
|
2728
|
+
}
|
|
2729
|
+
function covers(coverage2, consumed) {
|
|
2730
|
+
for (const specifier of consumed) if (!coverage2.has(specifier)) return false;
|
|
2731
|
+
return true;
|
|
2732
|
+
}
|
|
2733
|
+
function acceptsAll(acceptance, build, consumer, consumed) {
|
|
2734
|
+
const byMember = acceptance.get(consumer);
|
|
2735
|
+
if (!byMember) return false;
|
|
2736
|
+
for (let i = 0; i < consumed.length; i++) {
|
|
2737
|
+
const offered = build.get(consumed[i]);
|
|
2738
|
+
if (offered === void 0) return false;
|
|
2739
|
+
if (!byMember.get(consumed[i])?.has(offered)) return false;
|
|
2740
|
+
}
|
|
2741
|
+
return true;
|
|
2742
|
+
}
|
|
2743
|
+
function isWitnessed(specifiers, shared, builds) {
|
|
2744
|
+
const wanted = [...specifiers];
|
|
2745
|
+
for (const specifier of wanted) if (!shared.has(specifier)) return false;
|
|
2746
|
+
for (const [, build] of builds) {
|
|
2747
|
+
let matches2 = true;
|
|
2748
|
+
for (let i = 0; i < wanted.length; i++) {
|
|
2749
|
+
if (build.tags.get(wanted[i]) !== shared.get(wanted[i])) {
|
|
2750
|
+
matches2 = false;
|
|
2751
|
+
break;
|
|
2752
|
+
}
|
|
2753
|
+
}
|
|
2754
|
+
if (matches2) return true;
|
|
2755
|
+
}
|
|
2756
|
+
return false;
|
|
2757
|
+
}
|
|
2758
|
+
function explainSelfServe(remote, wants, specifiers, pool) {
|
|
2759
|
+
let closest;
|
|
2760
|
+
let fewest = Number.MAX_SAFE_INTEGER;
|
|
2761
|
+
let gap = wants[0] ?? "";
|
|
2762
|
+
for (const [build, view] of pool.builds) {
|
|
2763
|
+
if (build === remote) continue;
|
|
2764
|
+
let missing;
|
|
2765
|
+
let count = 0;
|
|
2766
|
+
for (const specifier of specifiers) {
|
|
2767
|
+
if (view.coverage.has(specifier)) continue;
|
|
2768
|
+
count++;
|
|
2769
|
+
missing ??= specifier;
|
|
2770
|
+
}
|
|
2771
|
+
if (count >= fewest) continue;
|
|
2772
|
+
fewest = count;
|
|
2773
|
+
closest = build;
|
|
2774
|
+
gap = missing ?? rejectedMember(view.instance, remote, wants, pool.acceptance) ?? gap;
|
|
2775
|
+
}
|
|
2776
|
+
return { gap, closest };
|
|
2777
|
+
}
|
|
2778
|
+
function rejectedMember(offered, consumer, wants, acceptance) {
|
|
2779
|
+
const accepts = acceptance.get(consumer);
|
|
2780
|
+
if (!accepts) return void 0;
|
|
2781
|
+
for (const member of wants) {
|
|
2782
|
+
const tag = offered.get(member);
|
|
2783
|
+
if (tag === void 0) return member;
|
|
2784
|
+
if (!accepts.get(member)?.has(tag)) return `${member}@${tag}`;
|
|
2785
|
+
}
|
|
2786
|
+
return void 0;
|
|
2787
|
+
}
|
|
2788
|
+
function assignAnchors(input) {
|
|
2789
|
+
const { builds, acceptance, consumedMembers: consumedMembers2, hosts, arrival } = input;
|
|
2790
|
+
const assignment = /* @__PURE__ */ new Map();
|
|
2791
|
+
const byPriority = (a, b) => (arrival.get(a) ?? Number.MAX_SAFE_INTEGER) - (arrival.get(b) ?? Number.MAX_SAFE_INTEGER) || a.localeCompare(b);
|
|
2792
|
+
const candidates = [...builds.keys()].sort(byPriority);
|
|
2793
|
+
const pending = new Set([...consumedMembers2.keys()].sort(byPriority));
|
|
2794
|
+
const anchored = /* @__PURE__ */ new Set();
|
|
2795
|
+
const canServe = (candidate, consumer) => {
|
|
2796
|
+
const build = builds.get(candidate);
|
|
2797
|
+
if (!covers(build.coverage, input.consumedSpecifiers.get(consumer) ?? [])) return false;
|
|
2798
|
+
return acceptsAll(acceptance, build.instance, consumer, consumedMembers2.get(consumer) ?? []);
|
|
2799
|
+
};
|
|
2800
|
+
const electAnchor = (anchor, served) => {
|
|
2801
|
+
pending.delete(anchor);
|
|
2802
|
+
assignment.set(anchor, void 0);
|
|
2803
|
+
for (const consumer of served) {
|
|
2804
|
+
pending.delete(consumer);
|
|
2805
|
+
anchored.add(consumer);
|
|
2806
|
+
assignment.set(consumer, anchor);
|
|
2807
|
+
}
|
|
2808
|
+
};
|
|
2809
|
+
for (const host of [...hosts].sort(byPriority)) {
|
|
2810
|
+
const served = [];
|
|
2811
|
+
if (builds.has(host)) {
|
|
2812
|
+
for (const consumer of pending) {
|
|
2813
|
+
if (consumer !== host && canServe(host, consumer)) served.push(consumer);
|
|
2814
|
+
}
|
|
2815
|
+
}
|
|
2816
|
+
electAnchor(host, served);
|
|
2817
|
+
}
|
|
2818
|
+
for (; ; ) {
|
|
2819
|
+
let best;
|
|
2820
|
+
let bestServed = [];
|
|
2821
|
+
for (const candidate of candidates) {
|
|
2822
|
+
if (anchored.has(candidate)) continue;
|
|
2823
|
+
const served = [];
|
|
2824
|
+
for (const consumer of pending) {
|
|
2825
|
+
if (consumer !== candidate && canServe(candidate, consumer)) served.push(consumer);
|
|
2826
|
+
}
|
|
2827
|
+
if (served.length > bestServed.length) {
|
|
2828
|
+
best = candidate;
|
|
2829
|
+
bestServed = served;
|
|
2830
|
+
}
|
|
2831
|
+
}
|
|
2832
|
+
if (best === void 0) break;
|
|
2833
|
+
electAnchor(best, bestServed);
|
|
2834
|
+
}
|
|
2835
|
+
for (const consumer of pending) assignment.set(consumer, void 0);
|
|
2836
|
+
return assignment;
|
|
2275
2837
|
}
|
|
2276
2838
|
|
|
2277
2839
|
// src/lib/core/2.app/steps/pooling/pool-graph.ts
|
|
@@ -2314,34 +2876,56 @@ function createDSU() {
|
|
|
2314
2876
|
}
|
|
2315
2877
|
var extNode = (name) => `ext\0${name}`;
|
|
2316
2878
|
var tagNode = (remote, tag) => `tag\0${remote}\0${tag}`;
|
|
2317
|
-
var scopeNode = (scope) => `scope\0${scope}`;
|
|
2879
|
+
var scopeNode = (remote, scope) => `scope\0${remote}\0${scope}`;
|
|
2318
2880
|
function autoScope(name, useAutoExternalPooling) {
|
|
2319
2881
|
return useAutoExternalPooling ? SCOPED_PACKAGE.exec(name)?.[1] : void 0;
|
|
2320
2882
|
}
|
|
2883
|
+
function owningPackage(name) {
|
|
2884
|
+
const depth = name.startsWith("@") ? 2 : 1;
|
|
2885
|
+
let cut = -1;
|
|
2886
|
+
for (let seen = 0; seen < depth; seen++) {
|
|
2887
|
+
cut = name.indexOf("/", cut + 1);
|
|
2888
|
+
if (cut === -1) return void 0;
|
|
2889
|
+
}
|
|
2890
|
+
return name.slice(0, cut);
|
|
2891
|
+
}
|
|
2321
2892
|
function groupByMembership(candidates, log) {
|
|
2322
2893
|
const dsu = createDSU();
|
|
2323
2894
|
const tagged = /* @__PURE__ */ new Set();
|
|
2324
|
-
const
|
|
2895
|
+
const joined = /* @__PURE__ */ new Set();
|
|
2896
|
+
const tagRules = /* @__PURE__ */ new Set();
|
|
2897
|
+
for (const candidate of candidates) {
|
|
2898
|
+
if (candidate.scope === void 0) continue;
|
|
2899
|
+
for (const edge of candidate.tags) tagRules.add(`${edge.remote}\0${candidate.scope}`);
|
|
2900
|
+
}
|
|
2325
2901
|
for (const candidate of candidates) {
|
|
2326
|
-
let joined = false;
|
|
2327
|
-
if (candidate.scope !== void 0) {
|
|
2328
|
-
dsu.union(extNode(candidate.name), scopeNode(candidate.scope));
|
|
2329
|
-
joined = true;
|
|
2330
|
-
}
|
|
2331
2902
|
for (const edge of candidate.tags) {
|
|
2332
2903
|
dsu.union(extNode(candidate.name), tagNode(edge.remote, edge.tag));
|
|
2333
2904
|
tagged.add(candidate.name);
|
|
2334
|
-
joined
|
|
2905
|
+
joined.add(candidate.name);
|
|
2906
|
+
}
|
|
2907
|
+
if (candidate.scope === void 0) continue;
|
|
2908
|
+
for (const remote of candidate.remotes) {
|
|
2909
|
+
if (tagRules.has(`${remote}\0${candidate.scope}`)) continue;
|
|
2910
|
+
dsu.union(extNode(candidate.name), scopeNode(remote, candidate.scope));
|
|
2911
|
+
joined.add(candidate.name);
|
|
2335
2912
|
}
|
|
2336
|
-
|
|
2913
|
+
}
|
|
2914
|
+
const declared = new Set(candidates.map((c) => c.name));
|
|
2915
|
+
for (const candidate of candidates) {
|
|
2916
|
+
const owner = owningPackage(candidate.name);
|
|
2917
|
+
if (owner !== void 0 && declared.has(owner))
|
|
2918
|
+
dsu.union(extNode(candidate.name), extNode(owner));
|
|
2337
2919
|
}
|
|
2338
2920
|
const byComponent = /* @__PURE__ */ new Map();
|
|
2339
|
-
for (const
|
|
2340
|
-
const root = dsu.component(extNode(
|
|
2341
|
-
|
|
2921
|
+
for (const candidate of candidates) {
|
|
2922
|
+
const root = dsu.component(extNode(candidate.name));
|
|
2923
|
+
const members = byComponent.get(root) ?? byComponent.set(root, []).get(root);
|
|
2924
|
+
members.push({ name: candidate.name, value: candidate.value });
|
|
2342
2925
|
}
|
|
2343
2926
|
const pools = [];
|
|
2344
2927
|
for (const members of byComponent.values()) {
|
|
2928
|
+
if (!members.some((m) => joined.has(m.name))) continue;
|
|
2345
2929
|
members.sort((a, b) => a.name.localeCompare(b.name));
|
|
2346
2930
|
if (members.length < 2) {
|
|
2347
2931
|
const only = members[0];
|
|
@@ -2369,6 +2953,7 @@ function buildPools(sharedExternals, useAutoExternalPooling, log) {
|
|
|
2369
2953
|
return tag ? [{ remote: r.name, tag }] : [];
|
|
2370
2954
|
})
|
|
2371
2955
|
),
|
|
2956
|
+
remotes: external.versions.flatMap((v) => v.remotes.map((r) => r.name)),
|
|
2372
2957
|
value: { name, external }
|
|
2373
2958
|
})
|
|
2374
2959
|
);
|
|
@@ -2376,28 +2961,131 @@ function buildPools(sharedExternals, useAutoExternalPooling, log) {
|
|
|
2376
2961
|
}
|
|
2377
2962
|
|
|
2378
2963
|
// src/lib/core/2.app/steps/pooling/pool.util.ts
|
|
2964
|
+
function lazy(make) {
|
|
2965
|
+
let value;
|
|
2966
|
+
return () => value ??= make();
|
|
2967
|
+
}
|
|
2379
2968
|
function remotesInPool(members) {
|
|
2380
2969
|
return [
|
|
2381
2970
|
...new Set(members.flatMap((m) => m.external.versions.flatMap((v) => v.remotes.map((r) => r.name))))
|
|
2382
2971
|
];
|
|
2383
2972
|
}
|
|
2973
|
+
function poolableScopes(config, repo) {
|
|
2974
|
+
const { useAutoExternalPooling } = config.feature;
|
|
2975
|
+
return {
|
|
2976
|
+
useAutoExternalPooling,
|
|
2977
|
+
scopes: repo.getScopes().filter(
|
|
2978
|
+
(scope) => repo.scopeType(scope) !== "strict" && (useAutoExternalPooling || repo.hasPoolTag(scope))
|
|
2979
|
+
)
|
|
2980
|
+
};
|
|
2981
|
+
}
|
|
2384
2982
|
|
|
2385
2983
|
// src/lib/core/2.app/steps/pooling/pool-shared-externals.ts
|
|
2386
2984
|
function islandedRemotes(members) {
|
|
2387
|
-
const islanded = /* @__PURE__ */ new
|
|
2985
|
+
const islanded = /* @__PURE__ */ new Map();
|
|
2388
2986
|
for (const member of members)
|
|
2389
2987
|
for (const version of member.external.versions)
|
|
2390
|
-
if (version.action === "scope")
|
|
2988
|
+
if (version.action === "scope") {
|
|
2989
|
+
for (const remote of version.remotes)
|
|
2990
|
+
if (!islanded.has(remote.name))
|
|
2991
|
+
islanded.set(remote.name, {
|
|
2992
|
+
kind: "incompatible",
|
|
2993
|
+
member: member.name,
|
|
2994
|
+
tag: version.tag
|
|
2995
|
+
});
|
|
2996
|
+
}
|
|
2391
2997
|
return islanded;
|
|
2392
2998
|
}
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2999
|
+
var basisFor = (members, islanded, serving) => basisPerMember(members, islanded, (remote) => {
|
|
3000
|
+
const build = serving.get(remote);
|
|
3001
|
+
return build !== void 0 && build !== remote;
|
|
3002
|
+
});
|
|
3003
|
+
function servedPerRemote(consumed, serving, basis) {
|
|
3004
|
+
const served = /* @__PURE__ */ new Map();
|
|
3005
|
+
for (const [remote, build] of serving) {
|
|
3006
|
+
const byMember = /* @__PURE__ */ new Map();
|
|
3007
|
+
for (const name of consumed.get(remote) ?? []) {
|
|
3008
|
+
if (basis.get(name) !== build) byMember.set(name, build);
|
|
3009
|
+
}
|
|
3010
|
+
if (byMember.size > 0) served.set(remote, byMember);
|
|
3011
|
+
}
|
|
3012
|
+
return served;
|
|
3013
|
+
}
|
|
3014
|
+
var anyAnchorStored = (members) => members.some((m) => m.external.versions.some((v) => v.remotes.some((r) => r.servedBy !== void 0)));
|
|
3015
|
+
function findTornRemotes(members, islanded, basis, served, hosts) {
|
|
3016
|
+
const { suspect, selfServed } = movedRemotes(members, islanded, basis, served, hosts);
|
|
3017
|
+
if (suspect.size === 0) return [];
|
|
3018
|
+
const builds = liveBuilds(members, islanded);
|
|
3019
|
+
const shared = sharedTagPerSpecifier(members, islanded);
|
|
3020
|
+
const own = ownCopies(members, suspect);
|
|
3021
|
+
const torn = [];
|
|
3022
|
+
for (const remote of suspect) {
|
|
3023
|
+
const copies = own.get(remote) ?? [];
|
|
3024
|
+
const mine = selfServed.get(remote);
|
|
3025
|
+
const anchors = served.get(remote);
|
|
3026
|
+
const ownTags = /* @__PURE__ */ new Map();
|
|
3027
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
3028
|
+
for (const copy of copies) {
|
|
3029
|
+
const from = mine?.has(copy.member) ? remote : anchors?.get(copy.member);
|
|
3030
|
+
for (const specifier in copy.entries) {
|
|
3031
|
+
if (!ownTags.has(specifier)) ownTags.set(specifier, copy.tag);
|
|
3032
|
+
const tag = from === remote ? copy.tag : from !== void 0 ? builds.get(from)?.tags.get(specifier) : shared.get(specifier);
|
|
3033
|
+
if (tag !== void 0 && !resolved.has(specifier)) resolved.set(specifier, tag);
|
|
3034
|
+
}
|
|
3035
|
+
}
|
|
3036
|
+
if (resolved.size === 0) continue;
|
|
3037
|
+
if (ships(ownTags, resolved)) continue;
|
|
3038
|
+
let witnessed = false;
|
|
3039
|
+
for (const [, build] of builds) {
|
|
3040
|
+
if (ships(build.tags, resolved)) {
|
|
3041
|
+
witnessed = true;
|
|
3042
|
+
break;
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
3045
|
+
if (!witnessed) {
|
|
3046
|
+
torn.push({
|
|
3047
|
+
remote,
|
|
3048
|
+
combination: [...resolved].map(([specifier, tag]) => `${specifier}@${tag}`).join(", ")
|
|
3049
|
+
});
|
|
2398
3050
|
}
|
|
2399
|
-
|
|
2400
|
-
|
|
3051
|
+
}
|
|
3052
|
+
return torn;
|
|
3053
|
+
}
|
|
3054
|
+
var ships = (build, resolved) => {
|
|
3055
|
+
if (!build) return false;
|
|
3056
|
+
for (const [specifier, tag] of resolved) if (build.get(specifier) !== tag) return false;
|
|
3057
|
+
return true;
|
|
3058
|
+
};
|
|
3059
|
+
function movedRemotes(members, islanded, basis, served, hosts) {
|
|
3060
|
+
const suspect = /* @__PURE__ */ new Set();
|
|
3061
|
+
const selfServed = /* @__PURE__ */ new Map();
|
|
3062
|
+
const add = (remote) => {
|
|
3063
|
+
if (!islanded.has(remote) && !hosts.has(remote)) suspect.add(remote);
|
|
3064
|
+
};
|
|
3065
|
+
for (const remote of served.keys()) add(remote);
|
|
3066
|
+
for (const member of members) {
|
|
3067
|
+
const unpublished = !basis.has(member.name);
|
|
3068
|
+
for (const version of member.external.versions) {
|
|
3069
|
+
const scoped = version.action === "scope";
|
|
3070
|
+
if (!unpublished && !scoped) continue;
|
|
3071
|
+
for (const meta of version.remotes) {
|
|
3072
|
+
add(meta.name);
|
|
3073
|
+
const servesItself = scoped || unpublished && served.get(meta.name)?.get(member.name) === void 0;
|
|
3074
|
+
if (!servesItself) continue;
|
|
3075
|
+
let mine = selfServed.get(meta.name);
|
|
3076
|
+
if (!mine) selfServed.set(meta.name, mine = /* @__PURE__ */ new Set());
|
|
3077
|
+
mine.add(member.name);
|
|
3078
|
+
}
|
|
3079
|
+
}
|
|
3080
|
+
}
|
|
3081
|
+
return { suspect, selfServed };
|
|
3082
|
+
}
|
|
3083
|
+
function createPoolSharedExternals(config, ports) {
|
|
3084
|
+
return (touched) => {
|
|
3085
|
+
const { useAutoExternalPooling, scopes } = poolableScopes(config, ports.sharedExternalsRepo);
|
|
3086
|
+
for (const scope of scopes) {
|
|
3087
|
+
const touchedInScope = touched?.get(scope);
|
|
3088
|
+
if (touched && !touchedInScope) continue;
|
|
2401
3089
|
const sharedExternals = ports.sharedExternalsRepo.getFromScope(scope);
|
|
2402
3090
|
try {
|
|
2403
3091
|
for (const [poolName, members] of buildPools(
|
|
@@ -2405,6 +3093,7 @@ function createPoolSharedExternals(config, ports) {
|
|
|
2405
3093
|
useAutoExternalPooling,
|
|
2406
3094
|
config.log
|
|
2407
3095
|
)) {
|
|
3096
|
+
if (touchedInScope && !members.some((m) => touchedInScope.has(m.name))) continue;
|
|
2408
3097
|
poolFamily(poolName, members, scope);
|
|
2409
3098
|
}
|
|
2410
3099
|
} catch (error) {
|
|
@@ -2425,45 +3114,138 @@ function createPoolSharedExternals(config, ports) {
|
|
|
2425
3114
|
const allRemotes = remotesInPool(members);
|
|
2426
3115
|
if (allRemotes.length < 2) return;
|
|
2427
3116
|
const islanded = islandedRemotes(members);
|
|
3117
|
+
const consumed = consumedMembers(members);
|
|
3118
|
+
const hosts = hostRemotes(members);
|
|
3119
|
+
const views = {
|
|
3120
|
+
consumedSpecifiers: lazy(() => consumedSpecifiers(members)),
|
|
3121
|
+
acceptance: lazy(() => acceptanceTable(members, ports.versionCheck.isCompatible)),
|
|
3122
|
+
arrival: lazy(() => arrivalOrder(members))
|
|
3123
|
+
};
|
|
2428
3124
|
config.log.debug(
|
|
2429
3125
|
3,
|
|
2430
|
-
`[${scope}][pool:${poolName}] ${members.length} members across ${allRemotes.length} remotes,
|
|
3126
|
+
`[${scope}][pool:${poolName}] ${members.length} members across ${allRemotes.length} remotes, incompatible={${[...islanded.keys()].join(", ") || "\u2205"}}
|
|
2431
3127
|
` + members.map((m) => ` - ${m.name}`).join("\n")
|
|
2432
3128
|
);
|
|
2433
|
-
|
|
3129
|
+
const assign = () => {
|
|
3130
|
+
const serving2 = assignServingBuilds(members, islanded, consumed, hosts, views);
|
|
3131
|
+
const basis2 = basisFor(members, islanded, serving2);
|
|
3132
|
+
return { serving: serving2, basis: basis2, served: servedPerRemote(consumed, serving2, basis2) };
|
|
3133
|
+
};
|
|
3134
|
+
let { serving, basis, served } = assign();
|
|
3135
|
+
if (islanded.size === 0 && serving.size === 0 && !anyAnchorStored(members)) return;
|
|
3136
|
+
for (; ; ) {
|
|
3137
|
+
const torn = findTornRemotes(members, islanded, basis, served, hosts);
|
|
3138
|
+
if (torn.length === 0) break;
|
|
3139
|
+
for (const { remote, combination } of torn)
|
|
3140
|
+
islanded.set(remote, { kind: "torn", combination });
|
|
3141
|
+
({ serving, basis, served } = assign());
|
|
3142
|
+
}
|
|
3143
|
+
const incompatible = [...islanded].filter(([, cause]) => cause.kind === "incompatible").map(([remote]) => remote);
|
|
3144
|
+
if (config.strict.strictExternalCompatibility && incompatible.length > 0) {
|
|
2434
3145
|
config.log.error(
|
|
2435
3146
|
3,
|
|
2436
|
-
`[${scope}][pool:${poolName}] version-incompatible remotes cannot be pooled: {${
|
|
3147
|
+
`[${scope}][pool:${poolName}] version-incompatible remotes cannot be pooled: {${incompatible.join(", ")}}.`
|
|
2437
3148
|
);
|
|
2438
3149
|
throw new NFError(`Could not pool '${poolName}' in scope ${scope}.`);
|
|
2439
3150
|
}
|
|
3151
|
+
for (const [remote, cause] of islanded) {
|
|
3152
|
+
const scoped = consumed.get(remote)?.length ?? 0;
|
|
3153
|
+
config.log.warn(3, `[${scope}][pool:${poolName}] ${islandWarning(remote, cause, scoped)}`);
|
|
3154
|
+
}
|
|
2440
3155
|
for (const member of members) {
|
|
2441
|
-
const rebuilt = rebuildMember(member, islanded);
|
|
2442
|
-
warnIfScopedOnly(poolName, member
|
|
3156
|
+
const rebuilt = rebuildMember(member, islanded, served, basis.get(member.name));
|
|
3157
|
+
warnIfScopedOnly(poolName, member, rebuilt, islanded, scope);
|
|
2443
3158
|
ports.sharedExternalsRepo.addOrUpdate(member.name, rebuilt, scope);
|
|
2444
3159
|
}
|
|
2445
3160
|
}
|
|
2446
|
-
function
|
|
3161
|
+
function assignServingBuilds(members, islanded, consumed, hosts, views) {
|
|
3162
|
+
for (; ; ) {
|
|
3163
|
+
const bases = servingBuilds(members, islanded);
|
|
3164
|
+
const distinct = new Set(bases.values());
|
|
3165
|
+
if (distinct.size === 1 && bases.size === members.length) {
|
|
3166
|
+
const sole = [...distinct][0];
|
|
3167
|
+
if (coversWholePool(members, sole, islanded)) return /* @__PURE__ */ new Map();
|
|
3168
|
+
}
|
|
3169
|
+
const builds = liveBuilds(members, islanded);
|
|
3170
|
+
const shared = sharedTagPerSpecifier(members, islanded);
|
|
3171
|
+
const consumedSpec = views.consumedSpecifiers();
|
|
3172
|
+
const needAnchor = /* @__PURE__ */ new Map();
|
|
3173
|
+
const needSpecifiers = /* @__PURE__ */ new Map();
|
|
3174
|
+
for (const [remote, wants] of consumed) {
|
|
3175
|
+
if (islanded.has(remote)) continue;
|
|
3176
|
+
if (isWitnessed(consumedSpec.get(remote) ?? [], shared, builds)) continue;
|
|
3177
|
+
needAnchor.set(remote, wants);
|
|
3178
|
+
needSpecifiers.set(remote, consumedSpec.get(remote) ?? /* @__PURE__ */ new Set());
|
|
3179
|
+
}
|
|
3180
|
+
if (needAnchor.size === 0) return /* @__PURE__ */ new Map();
|
|
3181
|
+
const acceptance = views.acceptance();
|
|
3182
|
+
const assignment = assignAnchors({
|
|
3183
|
+
builds,
|
|
3184
|
+
acceptance,
|
|
3185
|
+
consumedSpecifiers: needSpecifiers,
|
|
3186
|
+
consumedMembers: needAnchor,
|
|
3187
|
+
hosts,
|
|
3188
|
+
arrival: views.arrival()
|
|
3189
|
+
});
|
|
3190
|
+
const anchors = /* @__PURE__ */ new Set();
|
|
3191
|
+
for (const build of assignment.values()) if (build !== void 0) anchors.add(build);
|
|
3192
|
+
const serving = /* @__PURE__ */ new Map();
|
|
3193
|
+
let scoped = false;
|
|
3194
|
+
for (const [remote, wants] of needAnchor) {
|
|
3195
|
+
const assigned = assignment.get(remote);
|
|
3196
|
+
const build = assigned ?? (anchors.has(remote) || hosts.has(remote) ? remote : void 0);
|
|
3197
|
+
if (build === void 0) {
|
|
3198
|
+
islanded.set(remote, {
|
|
3199
|
+
kind: "uncovered",
|
|
3200
|
+
...explainSelfServe(remote, wants, needSpecifiers.get(remote), { builds, acceptance })
|
|
3201
|
+
});
|
|
3202
|
+
scoped = true;
|
|
3203
|
+
continue;
|
|
3204
|
+
}
|
|
3205
|
+
serving.set(remote, build);
|
|
3206
|
+
}
|
|
3207
|
+
if (!scoped) return serving;
|
|
3208
|
+
}
|
|
3209
|
+
}
|
|
3210
|
+
function warnIfScopedOnly(poolName, member, rebuilt, islanded, scope) {
|
|
2447
3211
|
if (rebuilt.versions.some((v) => v.action === "share")) return;
|
|
2448
|
-
const consumers = new Set(
|
|
3212
|
+
const consumers = new Set(
|
|
3213
|
+
rebuilt.versions.filter((v) => v.action === "scope").flatMap((v) => v.remotes.map((r) => r.name))
|
|
3214
|
+
).size;
|
|
2449
3215
|
if (consumers < 2) return;
|
|
3216
|
+
const provider = member.external.versions.find((v) => v.action === "share");
|
|
3217
|
+
if (provider?.remotes.some((r) => islanded.has(r.name))) return;
|
|
2450
3218
|
config.log.warn(
|
|
2451
3219
|
3,
|
|
2452
|
-
`[${scope}][pool:${poolName}] '${
|
|
3220
|
+
`[${scope}][pool:${poolName}] '${member.name}' is scoped-only \u2014 no coherent shared build provides it; ${consumers} remotes download their own copy.`
|
|
2453
3221
|
);
|
|
2454
3222
|
}
|
|
2455
|
-
function rebuildMember(member, islanded) {
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
)
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
3223
|
+
function rebuildMember(member, islanded, served, basis) {
|
|
3224
|
+
let scoped = [];
|
|
3225
|
+
let clean = [];
|
|
3226
|
+
for (const version of member.external.versions) {
|
|
3227
|
+
for (const meta of version.remotes) {
|
|
3228
|
+
const entry = {
|
|
3229
|
+
remote: meta.name,
|
|
3230
|
+
tag: version.tag,
|
|
3231
|
+
host: version.host,
|
|
3232
|
+
action: version.action,
|
|
3233
|
+
meta
|
|
3234
|
+
};
|
|
3235
|
+
(islanded.has(entry.remote) || entry.action === "scope" ? scoped : clean).push(entry);
|
|
3236
|
+
}
|
|
3237
|
+
}
|
|
3238
|
+
for (const entry of scoped) delete entry.meta.servedBy;
|
|
3239
|
+
for (const entry of clean) {
|
|
3240
|
+
const build = served.get(entry.remote)?.get(member.name);
|
|
3241
|
+
if (build !== void 0) entry.meta.servedBy = build;
|
|
3242
|
+
else delete entry.meta.servedBy;
|
|
3243
|
+
}
|
|
3244
|
+
if (basis === void 0) {
|
|
3245
|
+
scoped = [...scoped, ...clean.filter((e) => e.meta.servedBy === void 0)];
|
|
3246
|
+
clean = clean.filter((e) => e.meta.servedBy !== void 0).map((e) => ({ ...e, action: "skip" }));
|
|
3247
|
+
}
|
|
3248
|
+
const shareEntries = clean.filter((e) => e.action === "share").sort((a, b) => Number(b.remote === basis) - Number(a.remote === basis));
|
|
2467
3249
|
const shareVersion = shareEntries.length > 0 ? [
|
|
2468
3250
|
{
|
|
2469
3251
|
tag: shareEntries[0].tag,
|
|
@@ -2472,37 +3254,70 @@ function createPoolSharedExternals(config, ports) {
|
|
|
2472
3254
|
remotes: shareEntries.map((e) => e.meta)
|
|
2473
3255
|
}
|
|
2474
3256
|
] : [];
|
|
2475
|
-
const
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
const version = scopeByTag.get(e.tag) ?? {
|
|
2490
|
-
tag: e.tag,
|
|
2491
|
-
host: false,
|
|
2492
|
-
action: "scope",
|
|
2493
|
-
remotes: []
|
|
2494
|
-
};
|
|
2495
|
-
version.remotes.push(e.meta);
|
|
2496
|
-
scopeByTag.set(e.tag, version);
|
|
2497
|
-
}
|
|
3257
|
+
const byTag = (entries, action) => {
|
|
3258
|
+
const versions = /* @__PURE__ */ new Map();
|
|
3259
|
+
for (const entry of entries) {
|
|
3260
|
+
const version = versions.get(entry.tag) ?? {
|
|
3261
|
+
tag: entry.tag,
|
|
3262
|
+
host: entry.host,
|
|
3263
|
+
action,
|
|
3264
|
+
remotes: []
|
|
3265
|
+
};
|
|
3266
|
+
version.remotes.push(entry.meta);
|
|
3267
|
+
versions.set(entry.tag, version);
|
|
3268
|
+
}
|
|
3269
|
+
return [...versions.values()];
|
|
3270
|
+
};
|
|
2498
3271
|
return {
|
|
2499
3272
|
dirty: false,
|
|
2500
|
-
versions: [
|
|
3273
|
+
versions: [
|
|
3274
|
+
...shareVersion,
|
|
3275
|
+
...byTag(
|
|
3276
|
+
clean.filter((e) => e.action === "skip"),
|
|
3277
|
+
"skip"
|
|
3278
|
+
),
|
|
3279
|
+
...byTag(scoped, "scope")
|
|
3280
|
+
].sort((a, b) => ports.versionCheck.compare(b.tag, a.tag))
|
|
2501
3281
|
};
|
|
2502
3282
|
}
|
|
2503
3283
|
}
|
|
3284
|
+
function islandWarning(remote, cause, scoped) {
|
|
3285
|
+
switch (cause.kind) {
|
|
3286
|
+
case "incompatible":
|
|
3287
|
+
return `'${remote}' is islanded: the resolver scoped its '${cause.member}@${cause.tag}', so all ${scoped} members it imports are scoped for it.`;
|
|
3288
|
+
case "torn":
|
|
3289
|
+
return `'${remote}' serves its own family: the mapping would have handed it ${cause.combination}, which no build shipped together, so all ${scoped} members it imports are scoped for it.`;
|
|
3290
|
+
default: {
|
|
3291
|
+
const closest = cause.closest ? `closest is '${cause.closest}'` : "no other build in the pool serves any of it";
|
|
3292
|
+
return `'${remote}' serves its own family: no shared build offers every entrypoint it imports at a version it accepts \u2014 '${cause.gap}' is the gap, ${closest}. All ${scoped} members it imports are scoped for it.`;
|
|
3293
|
+
}
|
|
3294
|
+
}
|
|
3295
|
+
}
|
|
3296
|
+
|
|
3297
|
+
// src/lib/core/2.app/steps/pooling/mark-pools-for-reelection.ts
|
|
3298
|
+
function createMarkPoolsForReelection(config, ports) {
|
|
3299
|
+
return () => {
|
|
3300
|
+
const { useAutoExternalPooling, scopes } = poolableScopes(config, ports.sharedExternalsRepo);
|
|
3301
|
+
for (const scope of scopes) {
|
|
3302
|
+
const sharedExternals = ports.sharedExternalsRepo.getFromScope(scope);
|
|
3303
|
+
if (!Object.values(sharedExternals).some((external) => external.dirty)) continue;
|
|
3304
|
+
let spread = 0;
|
|
3305
|
+
for (const [, members] of buildPools(sharedExternals, useAutoExternalPooling)) {
|
|
3306
|
+
if (!members.some((m) => m.external.dirty)) continue;
|
|
3307
|
+
for (const member of members)
|
|
3308
|
+
if (!member.external.dirty) {
|
|
3309
|
+
member.external.dirty = true;
|
|
3310
|
+
spread++;
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
3313
|
+
if (spread > 0)
|
|
3314
|
+
config.log.debug(3, `[${scope}] ${spread} pool member(s) marked dirty for re-election.`);
|
|
3315
|
+
}
|
|
3316
|
+
return Promise.resolve();
|
|
3317
|
+
};
|
|
3318
|
+
}
|
|
2504
3319
|
|
|
2505
|
-
// node_modules/.pnpm/@softarc+native-federation@4.
|
|
3320
|
+
// node_modules/.pnpm/@softarc+native-federation@4.4.0_typescript@6.0.3/node_modules/@softarc/native-federation/dist/lib/domain/core/chunk.js
|
|
2506
3321
|
var CHUNK_PREFIX = "@nf-internal";
|
|
2507
3322
|
function toChunkImport(fileName) {
|
|
2508
3323
|
if (fileName.startsWith("./")) {
|
|
@@ -2563,9 +3378,10 @@ function createGenerateImportMap(config, ports) {
|
|
|
2563
3378
|
}
|
|
2564
3379
|
function processshareScope(importMap, shareScope, chunkBundles) {
|
|
2565
3380
|
const sharedExternals = ports.sharedExternalsRepo.getFromScope(shareScope);
|
|
3381
|
+
const index = buildServedIndex(sharedExternals);
|
|
2566
3382
|
for (const [externalName, external] of Object.entries(sharedExternals)) {
|
|
2567
3383
|
let override = void 0;
|
|
2568
|
-
|
|
3384
|
+
const cachedBefore = cachedFingerprint(external);
|
|
2569
3385
|
for (const version of external.versions) {
|
|
2570
3386
|
if (version.action === "scope") {
|
|
2571
3387
|
for (const remote of version.remotes) {
|
|
@@ -2581,37 +3397,53 @@ function createGenerateImportMap(config, ports) {
|
|
|
2581
3397
|
continue;
|
|
2582
3398
|
}
|
|
2583
3399
|
version.remotes[0].cached = true;
|
|
2584
|
-
let
|
|
2585
|
-
|
|
2586
|
-
if (version.action === "share") {
|
|
2587
|
-
registerBundleChunks(chunkBundles, source.name, source.bundle);
|
|
2588
|
-
} else if (version.action === "skip") {
|
|
3400
|
+
let serving = version;
|
|
3401
|
+
if (version.action === "skip") {
|
|
2589
3402
|
if (!override) {
|
|
2590
3403
|
override = findOverride(external, shareScope, externalName) ?? "NOT_AVAILABLE";
|
|
2591
3404
|
}
|
|
2592
3405
|
if (override !== "NOT_AVAILABLE") {
|
|
2593
|
-
|
|
2594
|
-
overrideScope = getScope2(shareScope, override.remotes[0].name, externalName);
|
|
2595
|
-
source = override.remotes[0];
|
|
2596
|
-
sourceScope = overrideScope;
|
|
2597
|
-
override.remotes[0].cached = true;
|
|
3406
|
+
serving = override;
|
|
2598
3407
|
version.remotes[0].cached = false;
|
|
2599
3408
|
}
|
|
2600
3409
|
}
|
|
2601
|
-
const
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
3410
|
+
const provided = versionEntries(serving);
|
|
3411
|
+
const mappings = [];
|
|
3412
|
+
for (const [packageName, provider] of provided) {
|
|
3413
|
+
const file = provider.entries[packageName];
|
|
3414
|
+
mappings.push({
|
|
3415
|
+
packageName,
|
|
3416
|
+
url: join(getScope2(shareScope, provider.name, externalName), file),
|
|
3417
|
+
name: provider.name,
|
|
3418
|
+
file
|
|
3419
|
+
});
|
|
3420
|
+
provider.cached = true;
|
|
3421
|
+
if (version.action === "share") {
|
|
3422
|
+
registerBundleChunks(chunkBundles, provider.name, provider.bundle);
|
|
3423
|
+
}
|
|
3424
|
+
}
|
|
2607
3425
|
version.remotes.forEach((r) => {
|
|
2608
3426
|
const rScope = getScope2(shareScope, r.name, externalName);
|
|
3427
|
+
if (index && r.servedBy) {
|
|
3428
|
+
const files = index.get(r.servedBy);
|
|
3429
|
+
const servedScope = getScope2(shareScope, r.servedBy, externalName);
|
|
3430
|
+
for (const specifier of Object.keys(r.entries)) {
|
|
3431
|
+
const source = files?.get(specifier);
|
|
3432
|
+
if (!source) continue;
|
|
3433
|
+
const url = join(servedScope, source.file);
|
|
3434
|
+
addToScope(importMap, rScope, { [specifier]: url });
|
|
3435
|
+
addIntegrity(importMap, url, r.servedBy, source.file);
|
|
3436
|
+
registerBundleChunks(chunkBundles, r.servedBy, source.bundle);
|
|
3437
|
+
source.meta.cached = true;
|
|
3438
|
+
}
|
|
3439
|
+
return;
|
|
3440
|
+
}
|
|
2609
3441
|
for (const m of mappings) {
|
|
2610
3442
|
addToScope(importMap, rScope, { [m.packageName]: m.url });
|
|
2611
3443
|
}
|
|
2612
3444
|
for (const [packageName, file] of Object.entries(r.entries)) {
|
|
2613
|
-
if (packageName
|
|
2614
|
-
if (config.strict.strictEntryPointCoverage) {
|
|
3445
|
+
if (provided.has(packageName)) continue;
|
|
3446
|
+
if (config.strict.strictEntryPointCoverage || config.profile.scopeUncoveredEntrypoints) {
|
|
2615
3447
|
warnUncoveredEntrypoint(shareScope, externalName, r.name, packageName);
|
|
2616
3448
|
continue;
|
|
2617
3449
|
}
|
|
@@ -2625,9 +3457,14 @@ function createGenerateImportMap(config, ports) {
|
|
|
2625
3457
|
addIntegrity(importMap, m.url, m.name, m.file);
|
|
2626
3458
|
}
|
|
2627
3459
|
}
|
|
2628
|
-
|
|
3460
|
+
if (cachedFingerprint(external) !== cachedBefore) {
|
|
3461
|
+
ports.sharedExternalsRepo.addOrUpdate(externalName, external, shareScope);
|
|
3462
|
+
}
|
|
2629
3463
|
}
|
|
2630
3464
|
}
|
|
3465
|
+
function cachedFingerprint(external) {
|
|
3466
|
+
return external.versions.map((v) => v.remotes.map((r) => r.cached ? 1 : 0).join("")).join("|");
|
|
3467
|
+
}
|
|
2631
3468
|
function findOverride(external, shareScope, externalName) {
|
|
2632
3469
|
const sharedVersions = external.versions.filter((v) => v.action === "share");
|
|
2633
3470
|
const scopedExternalName = `${shareScope}.${externalName}`;
|
|
@@ -2656,10 +3493,68 @@ function createGenerateImportMap(config, ports) {
|
|
|
2656
3493
|
}
|
|
2657
3494
|
config.log.warn(4, `ShareScope external ${scopedExternalName} has multiple shared versions.`);
|
|
2658
3495
|
}
|
|
3496
|
+
function buildServedIndex(externals) {
|
|
3497
|
+
let anyServed = false;
|
|
3498
|
+
for (const external of Object.values(externals)) {
|
|
3499
|
+
for (const version of external.versions) {
|
|
3500
|
+
if (version.remotes.some((r) => r.servedBy)) anyServed = true;
|
|
3501
|
+
}
|
|
3502
|
+
}
|
|
3503
|
+
if (!anyServed) return void 0;
|
|
3504
|
+
const index = /* @__PURE__ */ new Map();
|
|
3505
|
+
for (const external of Object.values(externals)) {
|
|
3506
|
+
for (const version of external.versions) {
|
|
3507
|
+
for (const remote of version.remotes) {
|
|
3508
|
+
let own = index.get(remote.name);
|
|
3509
|
+
if (!own) index.set(remote.name, own = /* @__PURE__ */ new Map());
|
|
3510
|
+
for (const [specifier, file] of Object.entries(remote.entries)) {
|
|
3511
|
+
if (!own.has(specifier))
|
|
3512
|
+
own.set(specifier, { file, bundle: remote.bundle, meta: remote });
|
|
3513
|
+
}
|
|
3514
|
+
}
|
|
3515
|
+
}
|
|
3516
|
+
}
|
|
3517
|
+
return index;
|
|
3518
|
+
}
|
|
3519
|
+
function collectServed(into, index, ctx, externalName, version) {
|
|
3520
|
+
for (const consumer of version.remotes) {
|
|
3521
|
+
if (!consumer.servedBy) continue;
|
|
3522
|
+
const files = index.get(consumer.servedBy);
|
|
3523
|
+
const scope = getScope2(ctx, consumer.name, externalName);
|
|
3524
|
+
for (const specifier of Object.keys(consumer.entries)) {
|
|
3525
|
+
const source = files?.get(specifier);
|
|
3526
|
+
if (!source) {
|
|
3527
|
+
config.log.warn(
|
|
3528
|
+
4,
|
|
3529
|
+
`[${ctx}][${externalName}][${consumer.name}] '${consumer.servedBy}' does not serve '${specifier}'.`
|
|
3530
|
+
);
|
|
3531
|
+
continue;
|
|
3532
|
+
}
|
|
3533
|
+
into.push({ scope, specifier, source, from: consumer.servedBy });
|
|
3534
|
+
}
|
|
3535
|
+
}
|
|
3536
|
+
}
|
|
3537
|
+
function flushServed(importMap, chunkBundles, served) {
|
|
3538
|
+
for (const { scope, specifier, source, from } of served) {
|
|
3539
|
+
const url = join(getScope2(GLOBAL_SCOPE, from), source.file);
|
|
3540
|
+
if (importMap.imports[specifier] === url) continue;
|
|
3541
|
+
addToScope(importMap, scope, { [specifier]: url });
|
|
3542
|
+
addIntegrity(importMap, url, from, source.file);
|
|
3543
|
+
registerBundleChunks(chunkBundles, from, source.bundle);
|
|
3544
|
+
source.meta.cached = true;
|
|
3545
|
+
}
|
|
3546
|
+
}
|
|
2659
3547
|
function addGlobalSharedExternals(importMap, chunkBundles) {
|
|
2660
3548
|
const sharedExternals = ports.sharedExternalsRepo.getFromScope();
|
|
3549
|
+
const index = buildServedIndex(sharedExternals);
|
|
3550
|
+
const served = [];
|
|
3551
|
+
const cachedBefore = /* @__PURE__ */ new Map();
|
|
2661
3552
|
for (const [externalName, external] of Object.entries(sharedExternals)) {
|
|
3553
|
+
cachedBefore.set(externalName, cachedFingerprint(external));
|
|
2662
3554
|
for (const version of external.versions) {
|
|
3555
|
+
if (index && version.action !== "scope") {
|
|
3556
|
+
collectServed(served, index, GLOBAL_SCOPE, externalName, version);
|
|
3557
|
+
}
|
|
2663
3558
|
if (version.action === "skip") continue;
|
|
2664
3559
|
if (version.action === "scope") {
|
|
2665
3560
|
for (const remote of version.remotes) {
|
|
@@ -2678,39 +3573,64 @@ function createGenerateImportMap(config, ports) {
|
|
|
2678
3573
|
notifyDuplicateGlobalExternal(externalName);
|
|
2679
3574
|
continue;
|
|
2680
3575
|
}
|
|
2681
|
-
|
|
2682
|
-
for (const [packageName, file] of Object.entries(version.remotes[0].entries)) {
|
|
2683
|
-
const url = join(scope, file);
|
|
2684
|
-
addToGlobal(importMap, { [packageName]: url });
|
|
2685
|
-
addIntegrity(importMap, url, version.remotes[0].name, file);
|
|
2686
|
-
}
|
|
2687
|
-
registerBundleChunks(chunkBundles, version.remotes[0].name, version.remotes[0].bundle);
|
|
2688
|
-
version.remotes[0].cached = true;
|
|
3576
|
+
mergeVersionEntries(importMap, chunkBundles, externalName, version);
|
|
2689
3577
|
}
|
|
2690
3578
|
for (const version of external.versions) {
|
|
2691
3579
|
if (version.action !== "skip") continue;
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
const scope = getScope2(GLOBAL_SCOPE, remote.name, externalName);
|
|
2700
|
-
const url = join(scope, file);
|
|
2701
|
-
addToGlobal(importMap, { [packageName]: url });
|
|
2702
|
-
addIntegrity(importMap, url, remote.name, file);
|
|
2703
|
-
registerBundleChunks(chunkBundles, remote.name, remote.bundle);
|
|
2704
|
-
remote.cached = true;
|
|
2705
|
-
}
|
|
3580
|
+
selfFillUncovered(importMap, chunkBundles, externalName, version.remotes);
|
|
3581
|
+
}
|
|
3582
|
+
}
|
|
3583
|
+
flushServed(importMap, chunkBundles, served);
|
|
3584
|
+
for (const [externalName, external] of Object.entries(sharedExternals)) {
|
|
3585
|
+
if (cachedFingerprint(external) !== cachedBefore.get(externalName)) {
|
|
3586
|
+
ports.sharedExternalsRepo.addOrUpdate(externalName, external);
|
|
2706
3587
|
}
|
|
2707
|
-
ports.sharedExternalsRepo.addOrUpdate(externalName, external);
|
|
2708
3588
|
}
|
|
2709
3589
|
return importMap;
|
|
2710
3590
|
}
|
|
3591
|
+
function mergeVersionEntries(importMap, chunkBundles, externalName, version) {
|
|
3592
|
+
const scopes = /* @__PURE__ */ new Map();
|
|
3593
|
+
for (const [packageName, remote] of versionEntries(version)) {
|
|
3594
|
+
if (importMap.imports[packageName]) {
|
|
3595
|
+
config.log.debug(
|
|
3596
|
+
4,
|
|
3597
|
+
`[${GLOBAL_SCOPE}][${externalName}][${remote.name}] Entrypoint '${packageName}' is already mapped by another external, keeping '${importMap.imports[packageName]}'.`
|
|
3598
|
+
);
|
|
3599
|
+
continue;
|
|
3600
|
+
}
|
|
3601
|
+
let scope = scopes.get(remote.name);
|
|
3602
|
+
if (scope === void 0) {
|
|
3603
|
+
scopes.set(remote.name, scope = getScope2(GLOBAL_SCOPE, remote.name, externalName));
|
|
3604
|
+
registerBundleChunks(chunkBundles, remote.name, remote.bundle);
|
|
3605
|
+
remote.cached = true;
|
|
3606
|
+
}
|
|
3607
|
+
const file = remote.entries[packageName];
|
|
3608
|
+
const url = join(scope, file);
|
|
3609
|
+
addToGlobal(importMap, { [packageName]: url });
|
|
3610
|
+
addIntegrity(importMap, url, remote.name, file);
|
|
3611
|
+
}
|
|
3612
|
+
}
|
|
3613
|
+
function selfFillUncovered(importMap, chunkBundles, externalName, remotes) {
|
|
3614
|
+
for (const remote of remotes) {
|
|
3615
|
+
if (remote.servedBy) continue;
|
|
3616
|
+
for (const [packageName, file] of Object.entries(remote.entries)) {
|
|
3617
|
+
if (importMap.imports[packageName]) continue;
|
|
3618
|
+
if (config.strict.strictEntryPointCoverage || config.profile.scopeUncoveredEntrypoints) {
|
|
3619
|
+
warnUncoveredEntrypoint(GLOBAL_SCOPE, externalName, remote.name, packageName);
|
|
3620
|
+
continue;
|
|
3621
|
+
}
|
|
3622
|
+
const scope = getScope2(GLOBAL_SCOPE, remote.name, externalName);
|
|
3623
|
+
const url = join(scope, file);
|
|
3624
|
+
addToGlobal(importMap, { [packageName]: url });
|
|
3625
|
+
addIntegrity(importMap, url, remote.name, file);
|
|
3626
|
+
registerBundleChunks(chunkBundles, remote.name, remote.bundle);
|
|
3627
|
+
remote.cached = true;
|
|
3628
|
+
}
|
|
3629
|
+
}
|
|
3630
|
+
}
|
|
2711
3631
|
function warnUncoveredEntrypoint(scope, externalName, remoteName, packageName) {
|
|
2712
3632
|
const msg = `[${scope}][${externalName}][${remoteName}] Entrypoint '${packageName}' is not covered by the shared version.`;
|
|
2713
|
-
if (config.strict.strictImportMap) {
|
|
3633
|
+
if (config.strict.strictEntryPointCoverage || config.strict.strictImportMap) {
|
|
2714
3634
|
config.log.error(4, msg);
|
|
2715
3635
|
throw new NFError("Could not create ImportMap.");
|
|
2716
3636
|
}
|
|
@@ -2899,18 +3819,24 @@ function createGetRemoteEntry(config, ports) {
|
|
|
2899
3819
|
// src/lib/core/2.app/steps/update-cache.ts
|
|
2900
3820
|
function createUpdateCache(config, ports) {
|
|
2901
3821
|
const storeRemoteEntry = createStoreRemoteEntry(config, ports, 8);
|
|
3822
|
+
const removeCachedRemoteEntries = createRemoveCachedRemoteEntries(ports);
|
|
2902
3823
|
return (remoteEntry) => {
|
|
2903
3824
|
try {
|
|
2904
3825
|
const actions = {};
|
|
3826
|
+
if (remoteEntry?.override) removeCachedRemoteEntries(/* @__PURE__ */ new Set([remoteEntry.name]));
|
|
2905
3827
|
storeRemoteEntry(remoteEntry, (entry, external, ctx) => {
|
|
2906
|
-
const { action,
|
|
3828
|
+
const { action, provided, sameVersion } = resolveSharedExternal(entry, external, ctx);
|
|
2907
3829
|
actions[external.packageName] = { action };
|
|
2908
|
-
if (action === "skip" &&
|
|
2909
|
-
actions[external.packageName].
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
3830
|
+
if (action === "skip" && provided) {
|
|
3831
|
+
actions[external.packageName].covered = Array.from(provided.keys());
|
|
3832
|
+
if (sameVersion) actions[external.packageName].sameVersion = true;
|
|
3833
|
+
if (external.shareScope) {
|
|
3834
|
+
actions[external.packageName].override = resolveOverrideEntries(
|
|
3835
|
+
entry,
|
|
3836
|
+
external,
|
|
3837
|
+
provided
|
|
3838
|
+
);
|
|
3839
|
+
}
|
|
2914
3840
|
}
|
|
2915
3841
|
});
|
|
2916
3842
|
return Promise.resolve({ entry: remoteEntry, actions });
|
|
@@ -2938,78 +3864,188 @@ function createUpdateCache(config, ports) {
|
|
|
2938
3864
|
}
|
|
2939
3865
|
config.log.warn(8, errorMsg);
|
|
2940
3866
|
}
|
|
2941
|
-
|
|
2942
|
-
|
|
3867
|
+
const provided = sharedVersion ? sharedInfo.shareScope ? versionEntries(sharedVersion) : committedEntries(sharedVersion) : void 0;
|
|
3868
|
+
const sameVersion = sharedVersion?.tag === tag;
|
|
3869
|
+
if (action === "skip" && provided && !sameVersion) {
|
|
3870
|
+
const uncovered = uncoveredEntrypoints(remote, provided);
|
|
3871
|
+
if (uncovered.length > 0) {
|
|
3872
|
+
const msg = `[${sharedInfo.shareScope ?? GLOBAL_SCOPE}][${remoteEntry.name}][${sharedInfo.packageName}] Entrypoints not covered by the shared version: ${uncovered.join(", ")}.`;
|
|
3873
|
+
if (config.strict.strictEntryPointCoverage) {
|
|
3874
|
+
config.log.error(8, msg);
|
|
3875
|
+
throw new NFError(`Could not process remote '${remoteEntry.name}'`);
|
|
3876
|
+
}
|
|
3877
|
+
if (config.profile.scopeUncoveredEntrypoints) {
|
|
3878
|
+
config.log.debug(8, msg);
|
|
3879
|
+
action = "scope";
|
|
3880
|
+
}
|
|
3881
|
+
}
|
|
2943
3882
|
}
|
|
2944
|
-
const matchingVersion = cached2.versions
|
|
2945
|
-
if (
|
|
3883
|
+
const matchingVersion = findVersionForTag(cached2.versions, tag);
|
|
3884
|
+
if (action === "scope") {
|
|
3885
|
+
remote.cached = true;
|
|
3886
|
+
const scoped = cached2.versions.find((v) => v.tag === tag && v.action === "scope");
|
|
3887
|
+
if (scoped) scoped.remotes.push(remote);
|
|
3888
|
+
else cached2.versions.push({ tag, action, host: false, remotes: [remote] });
|
|
3889
|
+
} else if (matchingVersion) {
|
|
2946
3890
|
assertSameVersionCompatibility(matchingVersion);
|
|
2947
|
-
matchingVersion
|
|
3891
|
+
addRemoteToVersion(matchingVersion, remote);
|
|
2948
3892
|
} else {
|
|
2949
3893
|
if (!sharedVersion) action = "share";
|
|
2950
3894
|
remote.cached = action !== "skip";
|
|
2951
3895
|
cached2.versions.push({ tag, action, host: false, remotes: [remote] });
|
|
2952
3896
|
}
|
|
2953
3897
|
commit();
|
|
2954
|
-
return { action,
|
|
2955
|
-
}
|
|
2956
|
-
function resolveOverrideEntries(remoteEntry, external,
|
|
2957
|
-
return
|
|
2958
|
-
(
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
3898
|
+
return { action, provided, sameVersion };
|
|
3899
|
+
}
|
|
3900
|
+
function resolveOverrideEntries(remoteEntry, external, provided) {
|
|
3901
|
+
return Object.fromEntries(
|
|
3902
|
+
Array.from(provided, ([packageName, provider]) => [
|
|
3903
|
+
packageName,
|
|
3904
|
+
join(
|
|
3905
|
+
providerScopeUrl(remoteEntry, external, provider.name),
|
|
3906
|
+
provider.entries[packageName]
|
|
3907
|
+
)
|
|
3908
|
+
])
|
|
3909
|
+
);
|
|
3910
|
+
}
|
|
3911
|
+
function providerScopeUrl(remoteEntry, external, providerName) {
|
|
3912
|
+
return ports.remoteInfoRepo.tryGet(providerName).map((remote) => remote.scopeUrl).orThrow(() => {
|
|
2965
3913
|
config.log.error(
|
|
2966
3914
|
8,
|
|
2967
3915
|
`[${external.shareScope ?? GLOBAL_SCOPE}][${remoteEntry.name}][${external.packageName}@${external.version}][override] Remote name not found in cache.`
|
|
2968
3916
|
);
|
|
2969
|
-
return new NFError(
|
|
2970
|
-
`Could not find override url from remote ${sharedVersion.remotes[0].name}`
|
|
2971
|
-
);
|
|
3917
|
+
return new NFError(`Could not find override url from remote ${providerName}`);
|
|
2972
3918
|
});
|
|
2973
3919
|
}
|
|
2974
3920
|
}
|
|
2975
3921
|
|
|
2976
3922
|
// src/lib/core/2.app/steps/pooling/pool-dynamic-externals.ts
|
|
2977
|
-
function createPoolDynamicExternals(config) {
|
|
3923
|
+
function createPoolDynamicExternals(config, ports) {
|
|
2978
3924
|
return ({ entry, actions }) => {
|
|
2979
3925
|
const { useAutoExternalPooling } = config.feature;
|
|
2980
|
-
|
|
2981
|
-
return Promise.resolve({ entry, actions });
|
|
2982
|
-
}
|
|
2983
|
-
const byScope = /* @__PURE__ */ new Map();
|
|
3926
|
+
const declared = /* @__PURE__ */ new Map();
|
|
2984
3927
|
for (const external of entry.shared ?? []) {
|
|
2985
3928
|
const name = external.packageName;
|
|
2986
3929
|
if (!external.singleton || !actions[name]) continue;
|
|
2987
3930
|
if (external.shareScope === STRICT_SCOPE) continue;
|
|
2988
|
-
const tag = external.pool?.trim();
|
|
2989
3931
|
const shareScope = external.shareScope ?? GLOBAL_SCOPE;
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
scope: autoScope(name, useAutoExternalPooling),
|
|
2994
|
-
tags: tag ? [{ remote: entry.name, tag }] : [],
|
|
2995
|
-
value: name
|
|
2996
|
-
});
|
|
2997
|
-
byScope.set(shareScope, candidates);
|
|
3932
|
+
let names = declared.get(shareScope);
|
|
3933
|
+
if (!names) declared.set(shareScope, names = /* @__PURE__ */ new Set());
|
|
3934
|
+
names.add(name);
|
|
2998
3935
|
}
|
|
3936
|
+
if (declared.size === 0) return Promise.resolve({ entry, actions });
|
|
2999
3937
|
const scope = (name) => {
|
|
3000
3938
|
actions[name].action = "scope";
|
|
3001
3939
|
delete actions[name].override;
|
|
3002
3940
|
};
|
|
3003
|
-
for (const
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3941
|
+
for (const [shareScope, names] of declared) {
|
|
3942
|
+
if (!useAutoExternalPooling && !ports.sharedExternalsRepo.hasPoolTag(shareScope)) continue;
|
|
3943
|
+
const committed = ports.sharedExternalsRepo.getFromScope(shareScope);
|
|
3944
|
+
for (const pool of buildPools(committed, useAutoExternalPooling).values()) {
|
|
3945
|
+
const mine = pool.filter((member) => names.has(member.name));
|
|
3946
|
+
if (mine.length === 0) continue;
|
|
3947
|
+
if (mine.some((member) => actions[member.name].action === "scope")) {
|
|
3948
|
+
mine.forEach((member) => scope(member.name));
|
|
3949
|
+
continue;
|
|
3950
|
+
}
|
|
3951
|
+
const asked = gateViews(entry.name, pool);
|
|
3952
|
+
const anchor = anchorFor(entry.name, asked);
|
|
3953
|
+
if (anchor === "witnessed") continue;
|
|
3954
|
+
if (anchor === void 0) {
|
|
3955
|
+
const reason = explainDynamic(entry.name, asked);
|
|
3956
|
+
const closest = reason.closest ? `closest is '${reason.closest}'` : "no committed build serves any of it";
|
|
3957
|
+
config.log.warn(
|
|
3958
|
+
8,
|
|
3959
|
+
`[${shareScope}] '${entry.name}' serves its own family: no committed build offers every entrypoint it imports at a version it accepts \u2014 '${reason.gap}' is the gap, ${closest}. All ${mine.length} members it imports are scoped for it.`
|
|
3960
|
+
);
|
|
3961
|
+
mine.forEach((member) => scope(member.name));
|
|
3962
|
+
continue;
|
|
3008
3963
|
}
|
|
3964
|
+
redirect(entry.name, anchor, pool, asked.view, actions, shareScope);
|
|
3009
3965
|
}
|
|
3010
3966
|
}
|
|
3011
3967
|
return Promise.resolve({ entry, actions });
|
|
3012
3968
|
};
|
|
3969
|
+
function gateViews(remote, pool) {
|
|
3970
|
+
return {
|
|
3971
|
+
pool,
|
|
3972
|
+
view: committedView(pool),
|
|
3973
|
+
wants: consumedMembers(pool).get(remote) ?? [],
|
|
3974
|
+
specifiers: consumedSpecifiers(pool).get(remote) ?? /* @__PURE__ */ new Set(),
|
|
3975
|
+
acceptance: lazy(() => acceptanceTable(pool, ports.versionCheck.isCompatible))
|
|
3976
|
+
};
|
|
3977
|
+
}
|
|
3978
|
+
function anchorFor(remote, { pool, view, wants, specifiers, acceptance }) {
|
|
3979
|
+
const shared = /* @__PURE__ */ new Map();
|
|
3980
|
+
for (const [specifier, source] of view.global) shared.set(specifier, source.tag);
|
|
3981
|
+
if (isWitnessed(specifiers, shared, view.builds)) return "witnessed";
|
|
3982
|
+
const basis = basisPerMember(pool);
|
|
3983
|
+
for (const build of candidateOrder(pool, view)) {
|
|
3984
|
+
if (build === remote) continue;
|
|
3985
|
+
const candidate = view.builds.get(build);
|
|
3986
|
+
if (!servesItsOwnFamily(build, pool, basis)) continue;
|
|
3987
|
+
if (!covers(candidate.coverage, specifiers)) continue;
|
|
3988
|
+
if (!acceptsAll(acceptance(), candidate.instance, remote, wants)) continue;
|
|
3989
|
+
return build;
|
|
3990
|
+
}
|
|
3991
|
+
return void 0;
|
|
3992
|
+
}
|
|
3993
|
+
function candidateOrder(pool, view) {
|
|
3994
|
+
const serving = /* @__PURE__ */ new Set();
|
|
3995
|
+
for (const source of view.global.values()) serving.add(source.remote);
|
|
3996
|
+
const hosts = hostRemotes(pool);
|
|
3997
|
+
const rank = (build) => serving.has(build) ? 0 : hosts.has(build) ? 1 : 2;
|
|
3998
|
+
return [...view.builds.keys()].sort((a, b) => rank(a) - rank(b) || a.localeCompare(b));
|
|
3999
|
+
}
|
|
4000
|
+
function servesItsOwnFamily(build, pool, basis) {
|
|
4001
|
+
let ships2 = 0;
|
|
4002
|
+
let winsAll = true;
|
|
4003
|
+
let allScoped = true;
|
|
4004
|
+
for (const member of pool) {
|
|
4005
|
+
for (const version of member.external.versions) {
|
|
4006
|
+
const meta = version.remotes.find((r) => r.name === build);
|
|
4007
|
+
if (!meta) continue;
|
|
4008
|
+
if (meta.servedBy !== void 0) return false;
|
|
4009
|
+
ships2++;
|
|
4010
|
+
if (version.action !== "scope") allScoped = false;
|
|
4011
|
+
if (basis.get(member.name) !== build) winsAll = false;
|
|
4012
|
+
}
|
|
4013
|
+
}
|
|
4014
|
+
return ships2 > 0 && (winsAll || allScoped);
|
|
4015
|
+
}
|
|
4016
|
+
function explainDynamic(remote, { view, wants, specifiers, acceptance }) {
|
|
4017
|
+
return explainSelfServe(remote, wants, specifiers, {
|
|
4018
|
+
builds: view.builds,
|
|
4019
|
+
acceptance: acceptance()
|
|
4020
|
+
});
|
|
4021
|
+
}
|
|
4022
|
+
function redirect(remote, anchor, pool, view, actions, shareScope) {
|
|
4023
|
+
const files = view.builds.get(anchor).coverage;
|
|
4024
|
+
const scopeUrl = ports.remoteInfoRepo.tryGet(anchor).get()?.scopeUrl;
|
|
4025
|
+
if (!scopeUrl) {
|
|
4026
|
+
config.log.warn(
|
|
4027
|
+
8,
|
|
4028
|
+
`[${shareScope}][${remote}] '${anchor}' is not in the cache, so its files cannot be mapped.`
|
|
4029
|
+
);
|
|
4030
|
+
return;
|
|
4031
|
+
}
|
|
4032
|
+
for (const member of pool) {
|
|
4033
|
+
const action = actions[member.name];
|
|
4034
|
+
if (!action || action.action !== "skip") continue;
|
|
4035
|
+
const own = member.external.versions.flatMap((v) => v.remotes).find((r) => r.name === remote);
|
|
4036
|
+
if (!own) continue;
|
|
4037
|
+
const specifiers = Object.keys(own.entries);
|
|
4038
|
+
if (specifiers.length === 0) continue;
|
|
4039
|
+
const override = {};
|
|
4040
|
+
for (const specifier of specifiers) {
|
|
4041
|
+
if (view.global.get(specifier)?.remote === anchor) continue;
|
|
4042
|
+
const file = files.get(specifier);
|
|
4043
|
+
if (file) override[specifier] = join(scopeUrl, file);
|
|
4044
|
+
}
|
|
4045
|
+
action.covered = specifiers;
|
|
4046
|
+
if (Object.keys(override).length > 0) action.override = override;
|
|
4047
|
+
}
|
|
4048
|
+
}
|
|
3013
4049
|
}
|
|
3014
4050
|
|
|
3015
4051
|
// src/lib/core/2.app/steps/convert-to-import-map.ts
|
|
@@ -3047,22 +4083,25 @@ function createConvertToImportMap(config, ports) {
|
|
|
3047
4083
|
return;
|
|
3048
4084
|
}
|
|
3049
4085
|
if (actions[external.packageName].action === "skip") {
|
|
3050
|
-
const override = actions[external.packageName]
|
|
3051
|
-
if (!external.shareScope) return;
|
|
4086
|
+
const { override, covered, sameVersion } = actions[external.packageName];
|
|
3052
4087
|
if (override) {
|
|
3053
4088
|
Object.entries(override).forEach(([packageName, url]) => {
|
|
3054
4089
|
addToScopes(remoteEntryScope, packageName, url, importMap);
|
|
3055
4090
|
});
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
4091
|
+
serveUncovered(
|
|
4092
|
+
remoteEntry,
|
|
4093
|
+
external,
|
|
4094
|
+
covered ?? Object.keys(override),
|
|
4095
|
+
remoteEntryScope,
|
|
4096
|
+
importMap,
|
|
4097
|
+
sameVersion
|
|
4098
|
+
);
|
|
4099
|
+
return;
|
|
4100
|
+
}
|
|
4101
|
+
if (!external.shareScope) {
|
|
4102
|
+
if (covered) {
|
|
4103
|
+
serveUncovered(remoteEntry, external, covered, remoteEntryScope, importMap, sameVersion);
|
|
4104
|
+
}
|
|
3066
4105
|
return;
|
|
3067
4106
|
}
|
|
3068
4107
|
log.error(
|
|
@@ -3129,9 +4168,22 @@ function createConvertToImportMap(config, ports) {
|
|
|
3129
4168
|
});
|
|
3130
4169
|
return importMap;
|
|
3131
4170
|
}
|
|
4171
|
+
function serveUncovered(remoteEntry, external, covered, remoteEntryScope, importMap, sameVersion = false) {
|
|
4172
|
+
const provided = new Set(covered);
|
|
4173
|
+
Object.entries(external.entries).forEach(([packageName, fileName]) => {
|
|
4174
|
+
if (provided.has(packageName)) return;
|
|
4175
|
+
if (!sameVersion && (config.strict.strictEntryPointCoverage || config.profile.scopeUncoveredEntrypoints)) {
|
|
4176
|
+
warnUncoveredEntrypoint(remoteEntry.name, external.packageName, packageName);
|
|
4177
|
+
return;
|
|
4178
|
+
}
|
|
4179
|
+
const url = join(remoteEntryScope, fileName);
|
|
4180
|
+
addToScopes(remoteEntryScope, packageName, url, importMap);
|
|
4181
|
+
addIntegrity(importMap, url, remoteEntry.integrity, fileName);
|
|
4182
|
+
});
|
|
4183
|
+
}
|
|
3132
4184
|
function warnUncoveredEntrypoint(remoteName, externalName, packageName) {
|
|
3133
4185
|
const msg = `[${remoteName}][${externalName}] Entrypoint '${packageName}' is not covered by the override.`;
|
|
3134
|
-
if (config.strict.strictImportMap) {
|
|
4186
|
+
if (config.strict.strictEntryPointCoverage || config.strict.strictImportMap) {
|
|
3135
4187
|
log.error(9, msg);
|
|
3136
4188
|
throw new NFError("Could not create ImportMap.");
|
|
3137
4189
|
}
|
|
@@ -3152,6 +4204,7 @@ var createInitDrivers = ({
|
|
|
3152
4204
|
}) => ({
|
|
3153
4205
|
getRemoteEntries: createGetRemoteEntries(config, adapters),
|
|
3154
4206
|
processRemoteEntries: createProcessRemoteEntries(config, adapters),
|
|
4207
|
+
markPoolsForReelection: createMarkPoolsForReelection(config, adapters),
|
|
3155
4208
|
determineSharedExternals: createDetermineSharedExternals(config, adapters),
|
|
3156
4209
|
poolSharedExternals: createPoolSharedExternals(config, adapters),
|
|
3157
4210
|
generateImportMap: createGenerateImportMap(config, adapters),
|
|
@@ -3159,7 +4212,7 @@ var createInitDrivers = ({
|
|
|
3159
4212
|
exposeModuleLoader: createExposeModuleLoader(config, adapters),
|
|
3160
4213
|
getRemoteEntry: createGetRemoteEntry(config, adapters),
|
|
3161
4214
|
updateCache: createUpdateCache(config, adapters),
|
|
3162
|
-
poolDynamicExternals: createPoolDynamicExternals(config),
|
|
4215
|
+
poolDynamicExternals: createPoolDynamicExternals(config, adapters),
|
|
3163
4216
|
convertToImportMap: createConvertToImportMap(config, adapters)
|
|
3164
4217
|
});
|
|
3165
4218
|
var INIT_FLOW_FACTORY = ({
|