@softarc/native-federation-orchestrator 4.6.1 → 4.8.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 +1880 -1281
- package/fesm2022/@softarc/native-federation-orchestrator.mjs.map +4 -4
- package/fesm2022/audit.mjs +1 -1
- package/fesm2022/audit.mjs.map +2 -2
- package/fesm2022/module-federation.mjs +199 -32
- package/fesm2022/module-federation.mjs.map +3 -3
- package/fesm2022/node.mjs +1867 -1257
- package/fesm2022/node.mjs.map +4 -4
- package/fesm2022/options.mjs +7 -3
- package/fesm2022/options.mjs.map +2 -2
- package/fesm2022/registry.mjs +1 -1
- package/fesm2022/registry.mjs.map +2 -2
- package/fesm2022/sdk.mjs +1 -1
- package/fesm2022/sdk.mjs.map +2 -2
- package/init-registry.mjs +1 -1
- package/node-loader/loader.mjs +7 -4
- package/node-loader/loader.mjs.map +2 -2
- package/package.json +9 -1
- package/quickstart.mjs +14 -15
- package/types/lib/core/1.domain/externals/basis.d.ts +2 -15
- package/types/lib/core/1.domain/externals/claims.d.ts +22 -0
- package/types/lib/core/1.domain/externals/compatibility.d.ts +9 -0
- package/types/lib/core/1.domain/externals/external.contract.d.ts +4 -0
- package/types/lib/core/1.domain/externals/rows.d.ts +9 -0
- package/types/lib/core/1.domain/externals/serving.d.ts +52 -0
- package/types/lib/core/1.domain/externals/specifier.d.ts +13 -0
- package/types/lib/core/1.domain/externals/version.contract.d.ts +2 -0
- package/types/lib/core/1.domain/pooling/builds.d.ts +20 -0
- package/types/lib/core/1.domain/pooling/election.d.ts +40 -0
- package/types/lib/core/1.domain/pooling/gate.d.ts +62 -0
- package/types/lib/core/1.domain/pooling/membership.d.ts +17 -0
- package/types/lib/core/1.domain/pooling/plan.d.ts +9 -0
- package/types/lib/core/1.domain/pooling/pool-state.d.ts +4 -0
- package/types/lib/core/1.domain/pooling/records.d.ts +16 -0
- package/types/lib/core/1.domain/pooling/rules.d.ts +6 -0
- package/types/lib/core/1.domain/remote-entry/load-actions.contract.d.ts +4 -0
- package/types/lib/core/1.domain/remote-entry/remote-entry.contract.d.ts +0 -2
- package/types/lib/core/2.app/config/index.d.ts +2 -1
- package/types/lib/core/2.app/config/mode.contract.d.ts +8 -5
- package/types/lib/core/2.app/config/orchestrator-global.contract.d.ts +15 -0
- package/types/lib/core/2.app/config/storage.contract.d.ts +19 -2
- package/types/lib/core/2.app/driver-ports/init/drivers.contract.d.ts +4 -2
- package/types/lib/core/2.app/driver-ports/init/for-committing-changes.port.d.ts +1 -0
- package/types/lib/core/2.app/driver-ports/init/for-deciding-serving-builds.port.d.ts +1 -0
- package/types/lib/core/2.app/driver-ports/init/for-determining-shared-externals.port.d.ts +1 -8
- package/types/lib/core/2.app/driver-ports/init/for-pooling-dynamic-externals.port.d.ts +2 -1
- package/types/lib/core/2.app/driver-ports/init/for-pooling-shared-externals.port.d.ts +1 -3
- package/types/lib/core/2.app/driver-ports/init/for-rolling-back-changes.port.d.ts +1 -0
- package/types/lib/core/2.app/driver-ports/init/for-updating-cache.d.ts +3 -2
- package/types/lib/core/2.app/driver-ports/init/index.d.ts +2 -0
- package/types/lib/core/2.app/driving-ports/for-remote-info-storage.port.d.ts +1 -0
- package/types/lib/core/2.app/driving-ports/for-scoped-externals-storage.port.d.ts +1 -0
- 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 +5 -1
- package/types/lib/core/2.app/steps/apply-winner.d.ts +6 -13
- package/types/lib/core/2.app/steps/decide-serving-builds.d.ts +5 -0
- package/types/lib/core/2.app/steps/pooling/pool-shared-externals.d.ts +0 -29
- package/types/lib/core/2.app/steps/rollback-changes.d.ts +5 -0
- package/types/lib/core/2.app/steps/store-remote-entry.d.ts +2 -2
- package/types/lib/core/3.adapters/storage/cache-state.d.ts +5 -0
- package/types/lib/core/3.adapters/storage/chunk.repository.d.ts +1 -1
- package/types/lib/core/3.adapters/storage/remote-info.repository.d.ts +1 -1
- package/types/lib/core/3.adapters/storage/scoped-externals.repository.d.ts +1 -1
- package/types/lib/core/3.adapters/storage/shared-externals.repository.d.ts +1 -1
- package/types/lib/core/4.config/orchestrator-version.d.ts +1 -0
- package/types/lib/core/4.config/storage/publish-storage-info.d.ts +9 -0
- package/types/lib/core/4.config/storage/storage.config.d.ts +1 -1
- package/types/lib/core/5.di/federation-result.factory.d.ts +1 -1
- package/types/lib/sdk.index.d.ts +4 -0
- package/types/lib/utils/compare-strings.d.ts +2 -0
- package/types/lib/utils/deep-readonly.d.ts +3 -0
- package/types/lib/core/2.app/driver-ports/init/for-marking-pools-for-reelection.port.d.ts +0 -6
- package/types/lib/core/2.app/steps/pooling/anchoring.d.ts +0 -69
- package/types/lib/core/2.app/steps/pooling/mark-pools-for-reelection.d.ts +0 -5
- package/types/lib/core/2.app/steps/pooling/pool-graph.d.ts +0 -30
- package/types/lib/core/2.app/steps/pooling/pool-views.d.ts +0 -63
- package/types/lib/core/2.app/steps/pooling/pool.types.d.ts +0 -35
- package/types/lib/core/2.app/steps/pooling/pool.util.d.ts +0 -18
- package/types/lib/testing/handlers/log.handler.d.ts +0 -3
- package/types/lib/testing/pooling/no-tear.d.ts +0 -37
|
@@ -223,7 +223,7 @@ var require_semver = __commonJS({
|
|
|
223
223
|
}
|
|
224
224
|
return true;
|
|
225
225
|
};
|
|
226
|
-
var
|
|
226
|
+
var SemVer2 = class _SemVer {
|
|
227
227
|
constructor(version, options) {
|
|
228
228
|
options = parseOptions(options);
|
|
229
229
|
if (version instanceof _SemVer) {
|
|
@@ -490,7 +490,7 @@ var require_semver = __commonJS({
|
|
|
490
490
|
return this;
|
|
491
491
|
}
|
|
492
492
|
};
|
|
493
|
-
module.exports =
|
|
493
|
+
module.exports = SemVer2;
|
|
494
494
|
}
|
|
495
495
|
});
|
|
496
496
|
|
|
@@ -498,13 +498,13 @@ var require_semver = __commonJS({
|
|
|
498
498
|
var require_parse = __commonJS({
|
|
499
499
|
"node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/parse.js"(exports, module) {
|
|
500
500
|
"use strict";
|
|
501
|
-
var
|
|
501
|
+
var SemVer2 = require_semver();
|
|
502
502
|
var parse = (version, options, throwErrors = false) => {
|
|
503
|
-
if (version instanceof
|
|
503
|
+
if (version instanceof SemVer2) {
|
|
504
504
|
return version;
|
|
505
505
|
}
|
|
506
506
|
try {
|
|
507
|
-
return new
|
|
507
|
+
return new SemVer2(version, options);
|
|
508
508
|
} catch (er) {
|
|
509
509
|
if (!throwErrors) {
|
|
510
510
|
return null;
|
|
@@ -571,8 +571,8 @@ var require_lrucache = __commonJS({
|
|
|
571
571
|
var require_compare = __commonJS({
|
|
572
572
|
"node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/compare.js"(exports, module) {
|
|
573
573
|
"use strict";
|
|
574
|
-
var
|
|
575
|
-
var compare = (a, b, loose) => new
|
|
574
|
+
var SemVer2 = require_semver();
|
|
575
|
+
var compare = (a, b, loose) => new SemVer2(a, loose).compare(new SemVer2(b, loose));
|
|
576
576
|
module.exports = compare;
|
|
577
577
|
}
|
|
578
578
|
});
|
|
@@ -730,7 +730,7 @@ var require_comparator = __commonJS({
|
|
|
730
730
|
if (!m[2]) {
|
|
731
731
|
this.semver = ANY;
|
|
732
732
|
} else {
|
|
733
|
-
this.semver = new
|
|
733
|
+
this.semver = new SemVer2(m[2], this.options.loose);
|
|
734
734
|
}
|
|
735
735
|
}
|
|
736
736
|
toString() {
|
|
@@ -743,7 +743,7 @@ var require_comparator = __commonJS({
|
|
|
743
743
|
}
|
|
744
744
|
if (typeof version === "string") {
|
|
745
745
|
try {
|
|
746
|
-
version = new
|
|
746
|
+
version = new SemVer2(version, this.options);
|
|
747
747
|
} catch (er) {
|
|
748
748
|
return false;
|
|
749
749
|
}
|
|
@@ -795,7 +795,7 @@ var require_comparator = __commonJS({
|
|
|
795
795
|
var { safeRe: re, t } = require_re();
|
|
796
796
|
var cmp = require_cmp();
|
|
797
797
|
var debug = require_debug();
|
|
798
|
-
var
|
|
798
|
+
var SemVer2 = require_semver();
|
|
799
799
|
var Range = require_range();
|
|
800
800
|
}
|
|
801
801
|
});
|
|
@@ -931,7 +931,7 @@ var require_range = __commonJS({
|
|
|
931
931
|
}
|
|
932
932
|
if (typeof version === "string") {
|
|
933
933
|
try {
|
|
934
|
-
version = new
|
|
934
|
+
version = new SemVer2(version, this.options);
|
|
935
935
|
} catch (er) {
|
|
936
936
|
return false;
|
|
937
937
|
}
|
|
@@ -950,7 +950,7 @@ var require_range = __commonJS({
|
|
|
950
950
|
var parseOptions = require_parse_options();
|
|
951
951
|
var Comparator = require_comparator();
|
|
952
952
|
var debug = require_debug();
|
|
953
|
-
var
|
|
953
|
+
var SemVer2 = require_semver();
|
|
954
954
|
var {
|
|
955
955
|
safeRe: re,
|
|
956
956
|
src,
|
|
@@ -1206,16 +1206,16 @@ var require_satisfies = __commonJS({
|
|
|
1206
1206
|
var require_min_version = __commonJS({
|
|
1207
1207
|
"node_modules/.pnpm/semver@7.8.5/node_modules/semver/ranges/min-version.js"(exports, module) {
|
|
1208
1208
|
"use strict";
|
|
1209
|
-
var
|
|
1209
|
+
var SemVer2 = require_semver();
|
|
1210
1210
|
var Range = require_range();
|
|
1211
1211
|
var gt = require_gt();
|
|
1212
1212
|
var minVersion = (range, loose) => {
|
|
1213
1213
|
range = new Range(range, loose);
|
|
1214
|
-
let minver = new
|
|
1214
|
+
let minver = new SemVer2("0.0.0");
|
|
1215
1215
|
if (range.test(minver)) {
|
|
1216
1216
|
return minver;
|
|
1217
1217
|
}
|
|
1218
|
-
minver = new
|
|
1218
|
+
minver = new SemVer2("0.0.0-0");
|
|
1219
1219
|
if (range.test(minver)) {
|
|
1220
1220
|
return minver;
|
|
1221
1221
|
}
|
|
@@ -1224,7 +1224,7 @@ var require_min_version = __commonJS({
|
|
|
1224
1224
|
const comparators = range.set[i];
|
|
1225
1225
|
let setMin = null;
|
|
1226
1226
|
comparators.forEach((comparator) => {
|
|
1227
|
-
const compver = new
|
|
1227
|
+
const compver = new SemVer2(comparator.semver.version);
|
|
1228
1228
|
switch (comparator.operator) {
|
|
1229
1229
|
case ">":
|
|
1230
1230
|
if (compver.prerelease.length === 0) {
|
|
@@ -1283,7 +1283,7 @@ var createInitFlow = ({
|
|
|
1283
1283
|
adapters,
|
|
1284
1284
|
config
|
|
1285
1285
|
}) => {
|
|
1286
|
-
return (remotesOrManifestUrl) => flow.getRemoteEntries(remotesOrManifestUrl).then(flow.processRemoteEntries).then(flow.
|
|
1286
|
+
return (remotesOrManifestUrl) => flow.getRemoteEntries(remotesOrManifestUrl).then(flow.processRemoteEntries).then(flow.poolSharedExternals).then(flow.determineSharedExternals).then(flow.decideServingBuilds).then(flow.generateImportMap).then((importMap) => flow.commitChanges(importMap, { override: true })).then(flow.exposeModuleLoader).then((loadRemoteModule) => ({
|
|
1287
1287
|
config,
|
|
1288
1288
|
adapters,
|
|
1289
1289
|
loadRemoteModule
|
|
@@ -1294,14 +1294,17 @@ var createInitFlow = ({
|
|
|
1294
1294
|
var createInitRemoteEntryFlow = ({
|
|
1295
1295
|
flow
|
|
1296
1296
|
}) => {
|
|
1297
|
-
const processDynamicRemoteEntry = (remoteEntry) => flow.updateCache(remoteEntry).then(flow.poolDynamicExternals).then(flow.convertToImportMap).then(flow.commitChanges);
|
|
1298
|
-
return (remoteEntryUrl, remote) => flow.getRemoteEntry(remoteEntryUrl, remote).then((entry) => entry.map(processDynamicRemoteEntry).orElse(Promise.resolve())).then(() => void 0)
|
|
1297
|
+
const processDynamicRemoteEntry = (remoteEntry) => flow.updateCache(remoteEntry).then(flow.poolDynamicExternals).then(flow.convertToImportMap).then((importMap) => flow.commitChanges(importMap, { markUndecided: true }));
|
|
1298
|
+
return (remoteEntryUrl, remote) => flow.getRemoteEntry(remoteEntryUrl, remote).then((entry) => entry.map(processDynamicRemoteEntry).orElse(Promise.resolve())).then(() => void 0).catch((error) => {
|
|
1299
|
+
const remoteName = typeof remote === "string" ? remote : remote?.name;
|
|
1300
|
+
return flow.rollbackChanges(`[dynamic-init][${remoteName ?? remoteEntryUrl}]`).then(() => Promise.reject(error));
|
|
1301
|
+
});
|
|
1299
1302
|
};
|
|
1300
1303
|
|
|
1301
1304
|
// src/lib/core/native-federation.error.ts
|
|
1302
1305
|
var NFError = class extends Error {
|
|
1303
1306
|
constructor(message, cause) {
|
|
1304
|
-
super(message, cause);
|
|
1307
|
+
super(message, cause ? { cause } : void 0);
|
|
1305
1308
|
this.name = "NFError";
|
|
1306
1309
|
}
|
|
1307
1310
|
};
|
|
@@ -1426,11 +1429,17 @@ function createGetRemoteEntries(config, ports) {
|
|
|
1426
1429
|
}
|
|
1427
1430
|
}
|
|
1428
1431
|
|
|
1432
|
+
// src/lib/utils/compare-strings.ts
|
|
1433
|
+
function compareStrings(a, b) {
|
|
1434
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1429
1437
|
// src/lib/core/1.domain/externals/basis.ts
|
|
1430
1438
|
var coverage = (remote) => Object.keys(remote.entries).length;
|
|
1431
1439
|
function isBetterBasis(candidate, basis) {
|
|
1432
1440
|
if (basis.cached !== candidate.cached) return candidate.cached;
|
|
1433
|
-
|
|
1441
|
+
const byCoverage = coverage(candidate) - coverage(basis);
|
|
1442
|
+
return byCoverage === 0 ? compareStrings(candidate.name, basis.name) < 0 : byCoverage > 0;
|
|
1434
1443
|
}
|
|
1435
1444
|
function addRemoteToVersion(version, remote, isHost = false) {
|
|
1436
1445
|
if (isHost) {
|
|
@@ -1454,21 +1463,6 @@ function versionDemands(version) {
|
|
|
1454
1463
|
}
|
|
1455
1464
|
return Array.from(distinct.values());
|
|
1456
1465
|
}
|
|
1457
|
-
function findVersionForTag(versions, tag) {
|
|
1458
|
-
let scoped;
|
|
1459
|
-
for (const version of versions) {
|
|
1460
|
-
if (version.tag !== tag) continue;
|
|
1461
|
-
if (version.action !== "scope") return version;
|
|
1462
|
-
scoped ??= version;
|
|
1463
|
-
}
|
|
1464
|
-
return scoped;
|
|
1465
|
-
}
|
|
1466
|
-
function versionEntries(version) {
|
|
1467
|
-
return collectEntries(version, void 0);
|
|
1468
|
-
}
|
|
1469
|
-
function committedEntries(version) {
|
|
1470
|
-
return collectEntries(version, (remote) => remote.cached);
|
|
1471
|
-
}
|
|
1472
1466
|
function forEachVersionEntry(version, accepts, visit) {
|
|
1473
1467
|
for (const remote of version.remotes) {
|
|
1474
1468
|
if (remote.servedBy) continue;
|
|
@@ -1476,16 +1470,6 @@ function forEachVersionEntry(version, accepts, visit) {
|
|
|
1476
1470
|
for (const entrypoint in remote.entries) visit(entrypoint, remote);
|
|
1477
1471
|
}
|
|
1478
1472
|
}
|
|
1479
|
-
function collectEntries(version, accepts) {
|
|
1480
|
-
const entries = /* @__PURE__ */ new Map();
|
|
1481
|
-
forEachVersionEntry(version, accepts, (entrypoint, remote) => {
|
|
1482
|
-
if (!entries.has(entrypoint)) entries.set(entrypoint, remote);
|
|
1483
|
-
});
|
|
1484
|
-
return entries;
|
|
1485
|
-
}
|
|
1486
|
-
function uncoveredEntrypoints(remote, covered) {
|
|
1487
|
-
return Object.keys(remote.entries).filter((entrypoint) => !covered.has(entrypoint));
|
|
1488
|
-
}
|
|
1489
1473
|
function countUncoveredEntrypoints(remote, covered) {
|
|
1490
1474
|
let uncovered = 0;
|
|
1491
1475
|
for (const entrypoint in remote.entries) {
|
|
@@ -1494,6 +1478,89 @@ function countUncoveredEntrypoints(remote, covered) {
|
|
|
1494
1478
|
return uncovered;
|
|
1495
1479
|
}
|
|
1496
1480
|
|
|
1481
|
+
// src/lib/core/1.domain/externals/rows.ts
|
|
1482
|
+
var byTag = (compare) => (a, b) => compare(b.tag, a.tag);
|
|
1483
|
+
var rowAt = (versions, tag, action) => versions.find((v) => v.tag === tag && v.action === action);
|
|
1484
|
+
function mergeRows(versions, lead) {
|
|
1485
|
+
const merged = /* @__PURE__ */ new Map();
|
|
1486
|
+
if (lead) merged.set(`${lead.tag}|${lead.action}`, lead);
|
|
1487
|
+
return versions.filter((v) => {
|
|
1488
|
+
const key = `${v.tag}|${v.action}`;
|
|
1489
|
+
const first = merged.get(key);
|
|
1490
|
+
if (first === v) return true;
|
|
1491
|
+
if (!first) {
|
|
1492
|
+
merged.set(key, v);
|
|
1493
|
+
return true;
|
|
1494
|
+
}
|
|
1495
|
+
first.remotes.push(...v.remotes);
|
|
1496
|
+
return false;
|
|
1497
|
+
});
|
|
1498
|
+
}
|
|
1499
|
+
function findVersionForTag(versions, tag) {
|
|
1500
|
+
let scoped;
|
|
1501
|
+
for (const version of versions) {
|
|
1502
|
+
if (version.tag !== tag) continue;
|
|
1503
|
+
if (version.action !== "scope") return version;
|
|
1504
|
+
scoped ??= version;
|
|
1505
|
+
}
|
|
1506
|
+
return scoped;
|
|
1507
|
+
}
|
|
1508
|
+
function redirectRow(version, tag, acceptsTag) {
|
|
1509
|
+
const objecting = new Set(
|
|
1510
|
+
version.remotes.filter((r) => r.strictVersion && !acceptsTag(tag, version.tag, r.requiredVersion))
|
|
1511
|
+
);
|
|
1512
|
+
if (objecting.size === 0) {
|
|
1513
|
+
version.action = "skip";
|
|
1514
|
+
return [version];
|
|
1515
|
+
}
|
|
1516
|
+
if (objecting.size === version.remotes.length) {
|
|
1517
|
+
version.action = "scope";
|
|
1518
|
+
return [version];
|
|
1519
|
+
}
|
|
1520
|
+
version.remotes = version.remotes.filter((r) => !objecting.has(r));
|
|
1521
|
+
version.action = "skip";
|
|
1522
|
+
return [version, { tag: version.tag, host: false, action: "scope", remotes: [...objecting] }];
|
|
1523
|
+
}
|
|
1524
|
+
function scopeRemotes(versions, remotes) {
|
|
1525
|
+
if (remotes.length === 0) return versions;
|
|
1526
|
+
const turn = new Map(remotes.map((remote, i) => [remote, i]));
|
|
1527
|
+
const moves = /* @__PURE__ */ new Map();
|
|
1528
|
+
versions.forEach((source, at) => {
|
|
1529
|
+
if (source.action === "scope") return;
|
|
1530
|
+
const byTurn = /* @__PURE__ */ new Map();
|
|
1531
|
+
for (const copy of source.remotes) {
|
|
1532
|
+
const i = turn.get(copy.name);
|
|
1533
|
+
if (i === void 0) continue;
|
|
1534
|
+
const copies = byTurn.get(i);
|
|
1535
|
+
if (copies) copies.push(copy);
|
|
1536
|
+
else byTurn.set(i, [copy]);
|
|
1537
|
+
}
|
|
1538
|
+
if (byTurn.size === 0) return;
|
|
1539
|
+
const hostTurn = source.host ? turn.get(source.remotes[0].name) : void 0;
|
|
1540
|
+
source.remotes = source.remotes.filter((r) => !turn.has(r.name));
|
|
1541
|
+
if (hostTurn !== void 0) source.host = false;
|
|
1542
|
+
const tagMoves = moves.get(source.tag) ?? [];
|
|
1543
|
+
for (const [i, copies] of byTurn)
|
|
1544
|
+
tagMoves.push({ turn: i, at, source, copies, host: i === hostTurn });
|
|
1545
|
+
moves.set(source.tag, tagMoves);
|
|
1546
|
+
});
|
|
1547
|
+
const rows = [...versions];
|
|
1548
|
+
for (const [tag, tagMoves] of moves) {
|
|
1549
|
+
tagMoves.sort((a, b) => a.turn - b.turn || a.at - b.at);
|
|
1550
|
+
let scoped = rowAt(rows, tag, "scope");
|
|
1551
|
+
if (!scoped) {
|
|
1552
|
+
scoped = { tag, host: false, action: "scope", remotes: [] };
|
|
1553
|
+
rows.splice(rows.indexOf(tagMoves[0].source) + 1, 0, scoped);
|
|
1554
|
+
}
|
|
1555
|
+
for (const { copies, host } of tagMoves)
|
|
1556
|
+
if (host) {
|
|
1557
|
+
scoped.host = true;
|
|
1558
|
+
scoped.remotes.unshift(...copies);
|
|
1559
|
+
} else scoped.remotes.push(...copies);
|
|
1560
|
+
}
|
|
1561
|
+
return rows.filter((v) => v.remotes.length > 0);
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1497
1564
|
// src/lib/core/2.app/steps/store-remote-entry.ts
|
|
1498
1565
|
function createRemoveCachedRemoteEntries(ports) {
|
|
1499
1566
|
return (remoteNames) => {
|
|
@@ -1527,6 +1594,11 @@ function createStoreRemoteEntry(config, ports, logStep) {
|
|
|
1527
1594
|
const tag = resolveVersion(remoteEntry, external);
|
|
1528
1595
|
if (tag === null) return;
|
|
1529
1596
|
if (external.singleton) {
|
|
1597
|
+
if (external.requiredVersion && !ports.versionCheck.isCompatible(tag, external.requiredVersion))
|
|
1598
|
+
config.log.warn(
|
|
1599
|
+
logStep,
|
|
1600
|
+
`[${remoteEntry.name}][${external.packageName}] requiredVersion '${external.requiredVersion}' excludes its own version '${tag}'; '${tag}' is still accepted for it.`
|
|
1601
|
+
);
|
|
1530
1602
|
onSharedExternal(remoteEntry, external, sharedExternalContext(remoteEntry, external, tag));
|
|
1531
1603
|
} else {
|
|
1532
1604
|
addScopedExternal(remoteEntry, external, tag);
|
|
@@ -1577,11 +1649,12 @@ function createStoreRemoteEntry(config, ports, logStep) {
|
|
|
1577
1649
|
...sharedInfo.pool?.trim() ? { pool: sharedInfo.pool } : {},
|
|
1578
1650
|
entries: sharedInfo.entries
|
|
1579
1651
|
};
|
|
1580
|
-
|
|
1652
|
+
let stored;
|
|
1653
|
+
const readRecord = () => stored ??= ports.sharedExternalsRepo.tryGet(sharedInfo.packageName, sharedInfo.shareScope).get() ?? { dirty: false, versions: [] };
|
|
1581
1654
|
return {
|
|
1582
1655
|
tag,
|
|
1583
1656
|
remote,
|
|
1584
|
-
|
|
1657
|
+
readRecord,
|
|
1585
1658
|
scopeType,
|
|
1586
1659
|
assertSameVersionCompatibility(matchingVersion) {
|
|
1587
1660
|
if (!remote.strictVersion) return;
|
|
@@ -1593,12 +1666,12 @@ function createStoreRemoteEntry(config, ports, logStep) {
|
|
|
1593
1666
|
}
|
|
1594
1667
|
config.log.warn(logStep, errorMsg);
|
|
1595
1668
|
},
|
|
1596
|
-
|
|
1669
|
+
write() {
|
|
1597
1670
|
ports.sharedExternalsRepo.addOrUpdate(
|
|
1598
1671
|
sharedInfo.packageName,
|
|
1599
1672
|
{
|
|
1600
|
-
|
|
1601
|
-
versions:
|
|
1673
|
+
...readRecord(),
|
|
1674
|
+
versions: readRecord().versions.sort((a, b) => ports.versionCheck.compare(b.tag, a.tag))
|
|
1602
1675
|
},
|
|
1603
1676
|
sharedInfo.shareScope
|
|
1604
1677
|
);
|
|
@@ -1642,11 +1715,12 @@ function createProcessRemoteEntries(config, ports) {
|
|
|
1642
1715
|
function addSharedExternal(remoteEntry, _sharedInfo, {
|
|
1643
1716
|
tag,
|
|
1644
1717
|
remote,
|
|
1645
|
-
|
|
1718
|
+
readRecord,
|
|
1646
1719
|
scopeType,
|
|
1647
1720
|
assertSameVersionCompatibility,
|
|
1648
|
-
|
|
1721
|
+
write
|
|
1649
1722
|
}) {
|
|
1723
|
+
const cached = readRecord();
|
|
1650
1724
|
if (scopeType !== "strict") cached.dirty = true;
|
|
1651
1725
|
const matchingVersion = findVersionForTag(cached.versions, tag);
|
|
1652
1726
|
if (matchingVersion) {
|
|
@@ -1660,7 +1734,7 @@ function createProcessRemoteEntries(config, ports) {
|
|
|
1660
1734
|
remotes: [remote]
|
|
1661
1735
|
});
|
|
1662
1736
|
}
|
|
1663
|
-
|
|
1737
|
+
write();
|
|
1664
1738
|
}
|
|
1665
1739
|
}
|
|
1666
1740
|
|
|
@@ -1668,154 +1742,70 @@ function createProcessRemoteEntries(config, ports) {
|
|
|
1668
1742
|
var GLOBAL_SCOPE = "__GLOBAL__";
|
|
1669
1743
|
var STRICT_SCOPE = "strict";
|
|
1670
1744
|
|
|
1671
|
-
// src/lib/core/
|
|
1672
|
-
function
|
|
1745
|
+
// src/lib/core/1.domain/externals/compatibility.ts
|
|
1746
|
+
function createAcceptsTag(isCompatible, compare) {
|
|
1747
|
+
return (offered, ownTag, requiredVersion) => isCompatible(offered, requiredVersion) || offered === ownTag || compare(offered, ownTag) === 0;
|
|
1748
|
+
}
|
|
1749
|
+
function versionAcceptance(external, acceptsTag) {
|
|
1673
1750
|
const demands = new Map(
|
|
1674
1751
|
external.versions.map((v) => [v, versionDemands(v)])
|
|
1675
1752
|
);
|
|
1676
1753
|
return {
|
|
1677
|
-
accepts: (version, tag) => demands.get(version).every((d) =>
|
|
1678
|
-
objector: (version, tag) => demands.get(version).find((d) => d.strictVersion && !
|
|
1754
|
+
accepts: (version, tag) => demands.get(version).every((d) => acceptsTag(tag, version.tag, d.requiredVersion)),
|
|
1755
|
+
objector: (version, tag) => demands.get(version).find((d) => d.strictVersion && !acceptsTag(tag, version.tag, d.requiredVersion))
|
|
1679
1756
|
};
|
|
1680
1757
|
}
|
|
1758
|
+
|
|
1759
|
+
// src/lib/core/2.app/steps/apply-winner.ts
|
|
1760
|
+
function rejectIncompatible(config, copy, rejected, servedAt) {
|
|
1761
|
+
config.log.error(
|
|
1762
|
+
3,
|
|
1763
|
+
`[${copy.name}][${rejected}] Is not compatible with requiredRange '${copy.requiredVersion}' of shared ${servedAt}.`
|
|
1764
|
+
);
|
|
1765
|
+
throw new NFError(`External ${rejected} could not be shared.`);
|
|
1766
|
+
}
|
|
1681
1767
|
function createApplyWinner(config) {
|
|
1682
|
-
return function applyWinner(externalName, external, winner,
|
|
1768
|
+
return function applyWinner(externalName, external, winner, acceptsTag, acceptance) {
|
|
1683
1769
|
if (external.versions.length > 1) {
|
|
1684
|
-
const { accepts, objector } = acceptance ?? versionAcceptance(external, isCompatible);
|
|
1685
1770
|
const rebuilt = [];
|
|
1686
1771
|
for (const v of external.versions) {
|
|
1687
|
-
|
|
1688
|
-
if (
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
config.log.error(
|
|
1695
|
-
3,
|
|
1696
|
-
`[${strict.name}][${externalName}@${v.tag}] Is not compatible with requiredRange '${strict.requiredVersion}' of shared ${externalName}@${winner.tag}.`
|
|
1772
|
+
const objector = config.strict.strictExternalCompatibility && acceptance.objector(v, winner.tag);
|
|
1773
|
+
if (objector)
|
|
1774
|
+
rejectIncompatible(
|
|
1775
|
+
config,
|
|
1776
|
+
objector,
|
|
1777
|
+
`${externalName}@${v.tag}`,
|
|
1778
|
+
`${externalName}@${winner.tag}`
|
|
1697
1779
|
);
|
|
1698
|
-
|
|
1699
|
-
}
|
|
1700
|
-
if (v === winner) continue;
|
|
1701
|
-
if (!strict) {
|
|
1702
|
-
v.action = "skip";
|
|
1703
|
-
continue;
|
|
1704
|
-
}
|
|
1705
|
-
const objecting = new Set(
|
|
1706
|
-
v.remotes.filter((r) => r.strictVersion && !isCompatible(winner.tag, r.requiredVersion))
|
|
1707
|
-
);
|
|
1708
|
-
if (objecting.size === v.remotes.length) {
|
|
1709
|
-
v.action = "scope";
|
|
1710
|
-
continue;
|
|
1711
|
-
}
|
|
1712
|
-
v.remotes = v.remotes.filter((r) => !objecting.has(r));
|
|
1713
|
-
v.action = "skip";
|
|
1714
|
-
rebuilt.push({ tag: v.tag, host: false, action: "scope", remotes: [...objecting] });
|
|
1780
|
+
rebuilt.push(...redirectRow(v, winner.tag, acceptsTag));
|
|
1715
1781
|
}
|
|
1716
|
-
|
|
1717
|
-
external.versions = rebuilt.filter((v) => {
|
|
1718
|
-
const first = merged.get(`${v.tag}|${v.action}`);
|
|
1719
|
-
if (!first) {
|
|
1720
|
-
merged.set(`${v.tag}|${v.action}`, v);
|
|
1721
|
-
return true;
|
|
1722
|
-
}
|
|
1723
|
-
first.remotes.push(...v.remotes);
|
|
1724
|
-
return false;
|
|
1725
|
-
});
|
|
1782
|
+
external.versions = mergeRows(rebuilt, winner);
|
|
1726
1783
|
}
|
|
1727
1784
|
winner.action = "share";
|
|
1728
|
-
applyEntrypointCoveragePolicy(externalName, external);
|
|
1729
1785
|
external.dirty = false;
|
|
1730
1786
|
return external;
|
|
1731
1787
|
};
|
|
1732
|
-
function applyEntrypointCoveragePolicy(externalName, external) {
|
|
1733
|
-
const { strictEntryPointCoverage } = config.strict;
|
|
1734
|
-
if (!strictEntryPointCoverage && !config.profile.scopeUncoveredEntrypoints) return;
|
|
1735
|
-
const tears = findTears(external);
|
|
1736
|
-
if (tears.length === 0) return;
|
|
1737
|
-
if (strictEntryPointCoverage) {
|
|
1738
|
-
const { version, remote, uncovered } = tears[0];
|
|
1739
|
-
config.log.error(
|
|
1740
|
-
3,
|
|
1741
|
-
`[${externalName}@${version.tag}][${remote.name}] Entrypoints not covered by the shared version: ${uncovered.join(", ")}.`
|
|
1742
|
-
);
|
|
1743
|
-
throw new NFError(
|
|
1744
|
-
`External ${externalName} could not be shared without tearing entrypoints.`
|
|
1745
|
-
);
|
|
1746
|
-
}
|
|
1747
|
-
scopeTornRemotes(externalName, external, tears);
|
|
1748
|
-
}
|
|
1749
|
-
function findTears(external) {
|
|
1750
|
-
const shared = external.versions.find((v) => v.action === "share");
|
|
1751
|
-
if (!shared) return [];
|
|
1752
|
-
const basis = versionEntries(shared);
|
|
1753
|
-
const tears = [];
|
|
1754
|
-
for (const version of external.versions) {
|
|
1755
|
-
if (version.action === "scope") continue;
|
|
1756
|
-
if (version === shared) continue;
|
|
1757
|
-
version.remotes.forEach((remote) => {
|
|
1758
|
-
if (remote.servedBy) return;
|
|
1759
|
-
const uncovered = uncoveredEntrypoints(remote, basis);
|
|
1760
|
-
if (uncovered.length > 0) tears.push({ version, remote, uncovered });
|
|
1761
|
-
});
|
|
1762
|
-
}
|
|
1763
|
-
return tears;
|
|
1764
|
-
}
|
|
1765
|
-
function scopeTornRemotes(externalName, external, tears) {
|
|
1766
|
-
const torn = new Set(tears.map((t) => t.remote));
|
|
1767
|
-
const demotedByTag = /* @__PURE__ */ new Map();
|
|
1768
|
-
for (const { version, remote, uncovered } of tears) {
|
|
1769
|
-
const group = demotedByTag.get(version.tag);
|
|
1770
|
-
if (group) group.push(remote);
|
|
1771
|
-
else demotedByTag.set(version.tag, [remote]);
|
|
1772
|
-
config.log.debug(
|
|
1773
|
-
3,
|
|
1774
|
-
`[${externalName}@${version.tag}][${remote.name}] Scoped: entrypoints not covered by the shared version: ${uncovered.join(", ")}.`
|
|
1775
|
-
);
|
|
1776
|
-
}
|
|
1777
|
-
for (const version of external.versions) {
|
|
1778
|
-
if (version.remotes.some((r) => torn.has(r))) {
|
|
1779
|
-
version.remotes = version.remotes.filter((r) => !torn.has(r));
|
|
1780
|
-
}
|
|
1781
|
-
}
|
|
1782
|
-
external.versions = external.versions.filter((v) => v.remotes.length > 0);
|
|
1783
|
-
for (const [tag, remotes] of demotedByTag) {
|
|
1784
|
-
const scoped = external.versions.find((v) => v.tag === tag && v.action === "scope");
|
|
1785
|
-
if (scoped) scoped.remotes.push(...remotes);
|
|
1786
|
-
else external.versions.push({ tag, host: false, action: "scope", remotes });
|
|
1787
|
-
}
|
|
1788
|
-
}
|
|
1789
1788
|
}
|
|
1790
1789
|
|
|
1791
1790
|
// src/lib/core/2.app/steps/determine-shared-externals.ts
|
|
1792
1791
|
function createDetermineSharedExternals(config, ports) {
|
|
1793
1792
|
const applyWinner = createApplyWinner(config);
|
|
1794
1793
|
return () => {
|
|
1795
|
-
const
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
if (hit === void 0) {
|
|
1800
|
-
hit = ports.versionCheck.isCompatible(tag, requiredVersion);
|
|
1801
|
-
memo.set(key, hit);
|
|
1802
|
-
}
|
|
1803
|
-
return hit;
|
|
1804
|
-
};
|
|
1805
|
-
const touched = /* @__PURE__ */ new Map();
|
|
1794
|
+
const acceptsTag = createAcceptsTag(
|
|
1795
|
+
ports.versionCheck.isCompatible,
|
|
1796
|
+
ports.versionCheck.compare
|
|
1797
|
+
);
|
|
1806
1798
|
for (const shareScope of ports.sharedExternalsRepo.getScopes()) {
|
|
1799
|
+
if (ports.sharedExternalsRepo.scopeType(shareScope) === "strict") continue;
|
|
1807
1800
|
const sharedExternals = ports.sharedExternalsRepo.getFromScope(shareScope);
|
|
1808
1801
|
try {
|
|
1809
|
-
const elected = /* @__PURE__ */ new Set();
|
|
1810
1802
|
Object.entries(sharedExternals).filter(([_, e]) => e.dirty).forEach(([name, external]) => {
|
|
1811
1803
|
ports.sharedExternalsRepo.addOrUpdate(
|
|
1812
1804
|
name,
|
|
1813
|
-
setVersionActions(name, external,
|
|
1805
|
+
setVersionActions(name, external, acceptsTag),
|
|
1814
1806
|
shareScope
|
|
1815
1807
|
);
|
|
1816
|
-
elected.add(name);
|
|
1817
1808
|
});
|
|
1818
|
-
if (elected.size > 0) touched.set(shareScope, elected);
|
|
1819
1809
|
} catch (error) {
|
|
1820
1810
|
config.log.error(
|
|
1821
1811
|
3,
|
|
@@ -1833,24 +1823,22 @@ function createDetermineSharedExternals(config, ports) {
|
|
|
1833
1823
|
);
|
|
1834
1824
|
}
|
|
1835
1825
|
}
|
|
1836
|
-
return Promise.resolve(
|
|
1826
|
+
return Promise.resolve();
|
|
1837
1827
|
};
|
|
1838
1828
|
function uncoveredTears(external, winner, accepts) {
|
|
1839
|
-
const
|
|
1829
|
+
const covered = /* @__PURE__ */ new Set();
|
|
1830
|
+
forEachVersionEntry(winner, void 0, (entrypoint) => covered.add(entrypoint));
|
|
1840
1831
|
return external.versions.reduce((sum, v) => {
|
|
1841
1832
|
if (v === winner) return sum;
|
|
1842
1833
|
if (!accepts(v, winner.tag)) return sum;
|
|
1843
|
-
return v.remotes.reduce(
|
|
1844
|
-
(n, r) => r.servedBy ? n : n + countUncoveredEntrypoints(r, basis),
|
|
1845
|
-
sum
|
|
1846
|
-
);
|
|
1834
|
+
return v.remotes.reduce((n, r) => n + countUncoveredEntrypoints(r, covered), sum);
|
|
1847
1835
|
}, 0);
|
|
1848
1836
|
}
|
|
1849
|
-
function setVersionActions(externalName, external,
|
|
1837
|
+
function setVersionActions(externalName, external, acceptsTag) {
|
|
1838
|
+
const acceptance = versionAcceptance(external, acceptsTag);
|
|
1850
1839
|
if (external.versions.length === 1) {
|
|
1851
|
-
return applyWinner(externalName, external, external.versions[0],
|
|
1840
|
+
return applyWinner(externalName, external, external.versions[0], acceptsTag, acceptance);
|
|
1852
1841
|
}
|
|
1853
|
-
const acceptance = versionAcceptance(external, isCompatible);
|
|
1854
1842
|
const { accepts } = acceptance;
|
|
1855
1843
|
let sharedVersion = external.versions.find((v) => v.host);
|
|
1856
1844
|
if (!sharedVersion && config.profile.latestSharedExternal) {
|
|
@@ -1875,14 +1863,12 @@ function createDetermineSharedExternals(config, ports) {
|
|
|
1875
1863
|
return [v, [...groups.values()]];
|
|
1876
1864
|
})
|
|
1877
1865
|
);
|
|
1878
|
-
const costOf = (version, tag) => selfServing.get(version).reduce(
|
|
1866
|
+
const costOf = (version, tag) => selfServing.get(version).reduce(
|
|
1867
|
+
(n, g) => acceptsTag(tag, version.tag, g.requiredVersion) ? n : n + g.copies,
|
|
1868
|
+
0
|
|
1869
|
+
);
|
|
1879
1870
|
external.versions.forEach((vA) => {
|
|
1880
|
-
const extraDownloads = external.versions.reduce(
|
|
1881
|
-
// A copy of the winner is never redirected, so it never self-serves however its own range
|
|
1882
|
-
// reads — see `applyWinner`, which does not split the winner either.
|
|
1883
|
-
(sum, vB) => vB === vA ? sum : sum + costOf(vB, vA.tag),
|
|
1884
|
-
0
|
|
1885
|
-
);
|
|
1871
|
+
const extraDownloads = external.versions.reduce((sum, vB) => sum + costOf(vB, vA.tag), 0);
|
|
1886
1872
|
if (extraDownloads < leastExtraDownloads) {
|
|
1887
1873
|
leastExtraDownloads = extraDownloads;
|
|
1888
1874
|
leastTears = uncoveredTears(external, vA, accepts);
|
|
@@ -1900,564 +1886,582 @@ function createDetermineSharedExternals(config, ports) {
|
|
|
1900
1886
|
if (!sharedVersion) {
|
|
1901
1887
|
throw new NFError(`[${externalName}] Could not determine shared version!`);
|
|
1902
1888
|
}
|
|
1903
|
-
return applyWinner(externalName, external, sharedVersion,
|
|
1889
|
+
return applyWinner(externalName, external, sharedVersion, acceptsTag, acceptance);
|
|
1904
1890
|
}
|
|
1905
1891
|
}
|
|
1906
1892
|
|
|
1907
|
-
// src/lib/core/
|
|
1908
|
-
function
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
});
|
|
1917
|
-
return { builds: walkBuilds(members, void 0, false), global };
|
|
1893
|
+
// src/lib/core/1.domain/externals/specifier.ts
|
|
1894
|
+
function owningPackage(name) {
|
|
1895
|
+
const depth = name.startsWith("@") ? 2 : 1;
|
|
1896
|
+
let cut = -1;
|
|
1897
|
+
for (let seen = 0; seen < depth; seen++) {
|
|
1898
|
+
cut = name.indexOf("/", cut + 1);
|
|
1899
|
+
if (cut === -1) return void 0;
|
|
1900
|
+
}
|
|
1901
|
+
return name.slice(0, cut);
|
|
1918
1902
|
}
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
own.coverage.set(specifier, meta.entries[specifier]);
|
|
1940
|
-
if (!own.tags.has(specifier)) own.tags.set(specifier, version.tag);
|
|
1941
|
-
}
|
|
1942
|
-
}
|
|
1943
|
-
}
|
|
1903
|
+
var packageOf = (name) => owningPackage(name) ?? name;
|
|
1904
|
+
var SpecifierTags = class extends Map {
|
|
1905
|
+
packages = /* @__PURE__ */ new Map();
|
|
1906
|
+
constructor(entries = []) {
|
|
1907
|
+
super();
|
|
1908
|
+
for (const [specifier, tag] of entries) this.set(specifier, tag);
|
|
1909
|
+
}
|
|
1910
|
+
set(specifier, tag) {
|
|
1911
|
+
super.set(specifier, tag);
|
|
1912
|
+
const pkg = owningPackage(specifier);
|
|
1913
|
+
if (pkg === void 0) this.packages.set(specifier, tag);
|
|
1914
|
+
else if (!this.packages.has(pkg)) this.packages.set(pkg, tag);
|
|
1915
|
+
return this;
|
|
1916
|
+
}
|
|
1917
|
+
clear() {
|
|
1918
|
+
super.clear();
|
|
1919
|
+
this.packages.clear();
|
|
1920
|
+
}
|
|
1921
|
+
pinnedTag(specifier) {
|
|
1922
|
+
return this.get(specifier) ?? this.packages.get(owningPackage(specifier) ?? specifier);
|
|
1944
1923
|
}
|
|
1945
|
-
|
|
1924
|
+
};
|
|
1925
|
+
function groupByPackage(items, nameOf) {
|
|
1926
|
+
const packages = /* @__PURE__ */ new Map();
|
|
1927
|
+
for (const item of items) {
|
|
1928
|
+
const pkg = packageOf(nameOf(item));
|
|
1929
|
+
const group = packages.get(pkg);
|
|
1930
|
+
if (group) group.push(item);
|
|
1931
|
+
else packages.set(pkg, [item]);
|
|
1932
|
+
}
|
|
1933
|
+
return packages;
|
|
1946
1934
|
}
|
|
1947
|
-
|
|
1948
|
-
|
|
1935
|
+
|
|
1936
|
+
// src/lib/core/1.domain/pooling/builds.ts
|
|
1937
|
+
function copiesByRemote(members) {
|
|
1938
|
+
const shipped = /* @__PURE__ */ new Map();
|
|
1949
1939
|
for (const member of members) {
|
|
1950
|
-
|
|
1940
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1941
|
+
for (const version of member.external.versions)
|
|
1951
1942
|
for (const meta of version.remotes) {
|
|
1952
|
-
if (
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
if (!copies.
|
|
1956
|
-
|
|
1943
|
+
if (seen.has(meta.name)) continue;
|
|
1944
|
+
seen.add(meta.name);
|
|
1945
|
+
let copies = shipped.get(meta.name);
|
|
1946
|
+
if (!copies) shipped.set(meta.name, copies = []);
|
|
1947
|
+
copies.push({
|
|
1948
|
+
member: member.name,
|
|
1949
|
+
tag: version.tag,
|
|
1950
|
+
requiredVersion: meta.requiredVersion,
|
|
1951
|
+
strict: meta.strictVersion,
|
|
1952
|
+
host: version.host && meta === version.remotes[0],
|
|
1953
|
+
specifiers: Object.keys(meta.entries)
|
|
1954
|
+
});
|
|
1957
1955
|
}
|
|
1958
|
-
}
|
|
1959
1956
|
}
|
|
1960
|
-
return
|
|
1957
|
+
return shipped;
|
|
1961
1958
|
}
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
else if (list[list.length - 1] !== member.name) list.push(member.name);
|
|
1973
|
-
}
|
|
1974
|
-
}
|
|
1975
|
-
}
|
|
1976
|
-
return consumed;
|
|
1959
|
+
var specifierCount = (copies) => copies.reduce((n, copy) => n + copy.specifiers.length, 0);
|
|
1960
|
+
function buildOf(owner, copies) {
|
|
1961
|
+
const tags = new SpecifierTags();
|
|
1962
|
+
const tagByMember = /* @__PURE__ */ new Map();
|
|
1963
|
+
for (const copy of copies) {
|
|
1964
|
+
for (const specifier of copy.specifiers)
|
|
1965
|
+
if (!tags.has(specifier)) tags.set(specifier, copy.tag);
|
|
1966
|
+
tagByMember.set(copy.member, copy.tag);
|
|
1967
|
+
}
|
|
1968
|
+
return { owner, tags, tagByMember, host: copies.some((c) => c.host) };
|
|
1977
1969
|
}
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
for (
|
|
1983
|
-
const
|
|
1984
|
-
|
|
1985
|
-
const meta = remotes[r];
|
|
1986
|
-
let own = consumed.get(meta.name);
|
|
1987
|
-
if (!own) consumed.set(meta.name, own = /* @__PURE__ */ new Set());
|
|
1988
|
-
for (const specifier in meta.entries) own.add(specifier);
|
|
1989
|
-
}
|
|
1970
|
+
|
|
1971
|
+
// src/lib/core/1.domain/pooling/rules.ts
|
|
1972
|
+
function agrees(copies, tags) {
|
|
1973
|
+
for (const copy of copies)
|
|
1974
|
+
for (const s of copy.specifiers) {
|
|
1975
|
+
const tag = tags.pinnedTag(s);
|
|
1976
|
+
if (tag !== void 0 && tag !== copy.tag) return false;
|
|
1990
1977
|
}
|
|
1991
|
-
|
|
1992
|
-
return consumed;
|
|
1978
|
+
return true;
|
|
1993
1979
|
}
|
|
1994
|
-
function
|
|
1995
|
-
const
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
for (const meta of version.remotes) {
|
|
2000
|
-
if (islanded.has(meta.name)) continue;
|
|
2001
|
-
const into = meta.name === build ? served : wanted;
|
|
2002
|
-
for (const specifier in meta.entries) into.add(specifier);
|
|
2003
|
-
}
|
|
1980
|
+
function serves(copies, tags, acceptsTag) {
|
|
1981
|
+
for (const copy of copies)
|
|
1982
|
+
for (const s of copy.specifiers) {
|
|
1983
|
+
const tag = tags.get(s);
|
|
1984
|
+
if (tag === void 0 || !acceptsTag(tag, copy.tag, copy.requiredVersion)) return false;
|
|
2004
1985
|
}
|
|
2005
|
-
}
|
|
2006
|
-
for (const specifier of wanted) if (!served.has(specifier)) return false;
|
|
2007
1986
|
return true;
|
|
2008
1987
|
}
|
|
2009
|
-
function
|
|
2010
|
-
const
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
const
|
|
2014
|
-
if (
|
|
2015
|
-
|
|
2016
|
-
|
|
1988
|
+
function unwitnessedGap(copies, tags, builds) {
|
|
1989
|
+
const specifiers = copies.flatMap((c) => c.specifiers);
|
|
1990
|
+
let gap = 0;
|
|
1991
|
+
for (const build of builds) {
|
|
1992
|
+
const miss = specifiers.findIndex((s) => build.tags.pinnedTag(s) !== tags.get(s));
|
|
1993
|
+
if (miss === -1) return void 0;
|
|
1994
|
+
gap = Math.max(gap, miss);
|
|
1995
|
+
}
|
|
1996
|
+
return specifiers[gap];
|
|
2017
1997
|
}
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
1998
|
+
|
|
1999
|
+
// src/lib/core/1.domain/pooling/election.ts
|
|
2000
|
+
function elect(input) {
|
|
2001
|
+
const shipped = copiesByRemote(input.members);
|
|
2002
|
+
const builds = /* @__PURE__ */ new Map();
|
|
2003
|
+
for (const [owner, copies] of shipped) builds.set(owner, buildOf(owner, copies));
|
|
2004
|
+
const pool = {
|
|
2005
|
+
...input,
|
|
2006
|
+
shipped,
|
|
2007
|
+
builds,
|
|
2008
|
+
packages: new Map([...shipped].map(([owner, copies]) => [owner, packageCopies(owner, copies)])),
|
|
2009
|
+
remotes: [...shipped.keys()],
|
|
2010
|
+
servesAt: (remote, tags) => serves(shipped.get(remote), tags, input.acceptsTag),
|
|
2011
|
+
agreesAt: (remote, tags) => agrees(shipped.get(remote), tags)
|
|
2012
|
+
};
|
|
2013
|
+
const hostRemote = pool.remotes.find((r) => builds.get(r).host);
|
|
2014
|
+
const state = roundOne(pool, hostRemote);
|
|
2015
|
+
formSubpools(pool, state);
|
|
2016
|
+
addExtensions(pool, state);
|
|
2017
|
+
promote(pool, state);
|
|
2018
|
+
while (settle(pool, state)) formSubpools(pool, state);
|
|
2019
|
+
const firstSeen = new Map(pool.remotes.map((r, i) => [r, i]));
|
|
2020
|
+
const self = state.pending.sort((a, b) => firstSeen.get(a) - firstSeen.get(b));
|
|
2021
|
+
return {
|
|
2022
|
+
winner: state.winner,
|
|
2023
|
+
winnerIsHost: hostRemote !== void 0,
|
|
2024
|
+
globalTags: state.globalTags,
|
|
2025
|
+
...placeRemotes(state.globalRemotes, state.subpools, self, (r) => missOf(pool, state, r))
|
|
2026
|
+
};
|
|
2029
2027
|
}
|
|
2030
|
-
function
|
|
2031
|
-
const
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2028
|
+
function newer(pool, a, b) {
|
|
2029
|
+
for (const { name } of pool.members) {
|
|
2030
|
+
const tagA = a.tagByMember.get(name);
|
|
2031
|
+
const tagB = b.tagByMember.get(name);
|
|
2032
|
+
if (tagA === void 0 || tagB === void 0) continue;
|
|
2033
|
+
const d = pool.compare(tagA, tagB);
|
|
2034
|
+
if (d !== 0) return d;
|
|
2035
|
+
}
|
|
2036
|
+
return 0;
|
|
2037
|
+
}
|
|
2038
|
+
function rank(pool, candidates, keys) {
|
|
2039
|
+
const scored = [...candidates].sort((a, b) => compareStrings(a.build.owner, b.build.owner)).map((c) => ({ c, k: keys.map((key) => key(c)) }));
|
|
2040
|
+
scored.sort((a, b) => {
|
|
2041
|
+
for (let i = 0; i < keys.length; i++) {
|
|
2042
|
+
const d = b.k[i] - a.k[i];
|
|
2043
|
+
if (d !== 0) return d;
|
|
2035
2044
|
}
|
|
2036
|
-
|
|
2037
|
-
|
|
2045
|
+
return newer(pool, b.c.build, a.c.build) || compareStrings(a.c.build.owner, b.c.build.owner);
|
|
2046
|
+
});
|
|
2047
|
+
return scored[0]?.c;
|
|
2038
2048
|
}
|
|
2039
|
-
function
|
|
2040
|
-
const
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2049
|
+
function roundOne(pool, hostRemote) {
|
|
2050
|
+
const { remotes } = pool;
|
|
2051
|
+
const scored = /* @__PURE__ */ new Map();
|
|
2052
|
+
const round1 = (hostRemote ? [hostRemote] : remotes).map((owner) => {
|
|
2053
|
+
const build = pool.builds.get(owner);
|
|
2054
|
+
const key = JSON.stringify([[...build.tags], [...build.tagByMember]]);
|
|
2055
|
+
let score = scored.get(key);
|
|
2056
|
+
if (!score) {
|
|
2057
|
+
const served = new Set(remotes.filter((r) => pool.servesAt(r, build.tags)));
|
|
2058
|
+
const agreeing = remotes.filter((r) => !served.has(r) && pool.agreesAt(r, build.tags)).length;
|
|
2059
|
+
scored.set(key, score = { served: [...served], agreeing });
|
|
2046
2060
|
}
|
|
2061
|
+
return { build, ...score };
|
|
2062
|
+
});
|
|
2063
|
+
const newerThan = (c) => round1.filter((o) => newer(pool, c.build, o.build) > 0).length;
|
|
2064
|
+
const round1Winner = rank(pool, round1, [
|
|
2065
|
+
...pool.latestFirst ? [newerThan] : [],
|
|
2066
|
+
(c) => c.served.length,
|
|
2067
|
+
(c) => c.agreeing,
|
|
2068
|
+
(c) => c.build.owner === pool.previousWinner ? 1 : 0
|
|
2069
|
+
]);
|
|
2070
|
+
const winner = round1Winner.build.owner;
|
|
2071
|
+
const globalTags = new SpecifierTags(round1Winner.build.tags);
|
|
2072
|
+
const globalRemotes = /* @__PURE__ */ new Set([winner, ...round1Winner.served]);
|
|
2073
|
+
const pending = remotes.filter((r) => !globalRemotes.has(r));
|
|
2074
|
+
return { winner, globalTags, globalRemotes, extensions: /* @__PURE__ */ new Set(), subpools: [], pending };
|
|
2075
|
+
}
|
|
2076
|
+
function formSubpools(pool, state) {
|
|
2077
|
+
const servable = new Map(
|
|
2078
|
+
state.pending.map((owner) => {
|
|
2079
|
+
const build = pool.builds.get(owner);
|
|
2080
|
+
const served = state.pending.filter((r) => pool.servesAt(r, build.tags));
|
|
2081
|
+
return [owner, { build, served }];
|
|
2082
|
+
})
|
|
2083
|
+
);
|
|
2084
|
+
for (; ; ) {
|
|
2085
|
+
const stillPending = new Set(state.pending);
|
|
2086
|
+
const candidates = state.pending.map((owner) => {
|
|
2087
|
+
const { build, served } = servable.get(owner);
|
|
2088
|
+
return { build, served: served.filter((r) => stillPending.has(r)) };
|
|
2089
|
+
}).filter((c) => c.served.includes(c.build.owner) && c.served.length >= 2);
|
|
2090
|
+
const best = rank(pool, candidates, [(c) => c.served.length]);
|
|
2091
|
+
if (!best) break;
|
|
2092
|
+
state.subpools.push({ owner: best.build.owner, remotes: best.served });
|
|
2093
|
+
state.pending = state.pending.filter((r) => !best.served.includes(r));
|
|
2047
2094
|
}
|
|
2048
|
-
return arrival;
|
|
2049
2095
|
}
|
|
2050
|
-
function
|
|
2051
|
-
const
|
|
2052
|
-
|
|
2053
|
-
|
|
2096
|
+
function promote(pool, state) {
|
|
2097
|
+
const { globalTags, globalRemotes } = state;
|
|
2098
|
+
const takesGlobal = (remote) => pool.servesAt(remote, globalTags) && unwitnessedGap(pool.shipped.get(remote), globalTags, pool.builds.values()) === void 0;
|
|
2099
|
+
for (const remote of state.pending) if (takesGlobal(remote)) globalRemotes.add(remote);
|
|
2100
|
+
state.pending = state.pending.filter((r) => !globalRemotes.has(r));
|
|
2101
|
+
for (const subpool of state.subpools) {
|
|
2102
|
+
const moved = subpool.remotes.filter((r) => r !== subpool.owner && takesGlobal(r));
|
|
2103
|
+
for (const remote of moved) globalRemotes.add(remote);
|
|
2104
|
+
subpool.remotes = subpool.remotes.filter((r) => !moved.includes(r));
|
|
2105
|
+
}
|
|
2106
|
+
state.subpools = state.subpools.filter((subpool) => {
|
|
2107
|
+
if (subpool.remotes.length >= 2) return true;
|
|
2108
|
+
if (takesGlobal(subpool.owner)) globalRemotes.add(subpool.owner);
|
|
2109
|
+
else state.pending.push(subpool.owner);
|
|
2110
|
+
return false;
|
|
2054
2111
|
});
|
|
2055
|
-
return shared;
|
|
2056
2112
|
}
|
|
2057
|
-
function
|
|
2058
|
-
const
|
|
2059
|
-
const
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2113
|
+
function addExtensions(pool, state) {
|
|
2114
|
+
const { globalTags, globalRemotes } = state;
|
|
2115
|
+
const runsOn = (remote) => state.subpools.find((p) => p.remotes.includes(remote))?.owner ?? remote;
|
|
2116
|
+
const agreeing = pool.remotes.filter((r) => !globalRemotes.has(r) && pool.agreesAt(r, globalTags));
|
|
2117
|
+
const runsGlobally = (remote) => pool.agreesAt(runsOn(remote), globalTags);
|
|
2118
|
+
const offered = offers(pool, globalTags, agreeing.filter(runsGlobally));
|
|
2119
|
+
const fill = pool.builds.get(state.winner).host ? agreeing.filter((r) => !runsGlobally(r)) : [];
|
|
2120
|
+
for (const [pkg, offer] of offers(pool, globalTags, fill))
|
|
2121
|
+
if (!offered.has(pkg)) offered.set(pkg, offer);
|
|
2122
|
+
for (const [pkg, offer] of offered) {
|
|
2123
|
+
if (!offer) continue;
|
|
2124
|
+
state.extensions.add(pkg);
|
|
2125
|
+
for (const s of offer.specifiers) globalTags.set(s, offer.tag);
|
|
2067
2126
|
}
|
|
2068
2127
|
}
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
let byMember = table.get(meta.name);
|
|
2079
|
-
if (!byMember) table.set(meta.name, byMember = /* @__PURE__ */ new Map());
|
|
2080
|
-
if (byMember.has(member.name)) continue;
|
|
2081
|
-
const accepted = /* @__PURE__ */ new Set();
|
|
2082
|
-
for (let t = 0; t < tags.length; t++) {
|
|
2083
|
-
if (isCompatible(tags[t], meta.requiredVersion)) accepted.add(tags[t]);
|
|
2084
|
-
}
|
|
2085
|
-
byMember.set(member.name, accepted);
|
|
2086
|
-
}
|
|
2128
|
+
function packageCopies(owner, copies) {
|
|
2129
|
+
const packages = /* @__PURE__ */ new Map();
|
|
2130
|
+
for (const copy of copies)
|
|
2131
|
+
for (const s of copy.specifiers) {
|
|
2132
|
+
const pkg = packageOf(s);
|
|
2133
|
+
const seen = packages.get(pkg);
|
|
2134
|
+
if (seen === void 0) packages.set(pkg, { owner, tag: copy.tag, specifiers: /* @__PURE__ */ new Set([s]) });
|
|
2135
|
+
else if (seen && seen.tag !== copy.tag) packages.set(pkg, null);
|
|
2136
|
+
else seen?.specifiers.add(s);
|
|
2087
2137
|
}
|
|
2088
|
-
|
|
2089
|
-
return table;
|
|
2138
|
+
return packages;
|
|
2090
2139
|
}
|
|
2091
|
-
function
|
|
2092
|
-
|
|
2093
|
-
|
|
2140
|
+
function offers(pool, globalTags, remotes) {
|
|
2141
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
2142
|
+
for (const owner of remotes)
|
|
2143
|
+
for (const [pkg, copy] of pool.packages.get(owner))
|
|
2144
|
+
if (globalTags.pinnedTag(pkg) === void 0)
|
|
2145
|
+
candidates.set(pkg, [...candidates.get(pkg) ?? [], copy]);
|
|
2146
|
+
const offered = /* @__PURE__ */ new Map();
|
|
2147
|
+
for (const [pkg, copies] of candidates)
|
|
2148
|
+
offered.set(pkg, oneTag(copies) ? coveringCopy(copies) : null);
|
|
2149
|
+
return offered;
|
|
2094
2150
|
}
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2151
|
+
var oneTag = (copies) => copies.every((c) => c !== null && c.tag === copies[0].tag);
|
|
2152
|
+
function coveringCopy(candidates) {
|
|
2153
|
+
const scored = candidates.map((c) => ({
|
|
2154
|
+
c,
|
|
2155
|
+
covers: candidates.filter((o) => contains(c.specifiers, o.specifiers)).length
|
|
2156
|
+
}));
|
|
2157
|
+
scored.sort(
|
|
2158
|
+
(a, b) => b.covers - a.covers || b.c.specifiers.size - a.c.specifiers.size || compareStrings(a.c.owner, b.c.owner)
|
|
2159
|
+
);
|
|
2160
|
+
return scored[0].c;
|
|
2104
2161
|
}
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2162
|
+
var contains = (a, b) => [...b].every((s) => a.has(s));
|
|
2163
|
+
function settle(pool, state) {
|
|
2164
|
+
const { globalTags, globalRemotes, extensions } = state;
|
|
2165
|
+
let demoted = false;
|
|
2166
|
+
for (; ; ) {
|
|
2167
|
+
const dropped = new Set([...extensions].filter((pkg) => !publishedWhole(pool, state, pkg)));
|
|
2168
|
+
if (dropped.size === 0) return demoted;
|
|
2169
|
+
for (const pkg of dropped) extensions.delete(pkg);
|
|
2170
|
+
const kept = [...globalTags].filter(([s]) => !dropped.has(packageOf(s)));
|
|
2171
|
+
globalTags.clear();
|
|
2172
|
+
for (const [s, tag] of kept) globalTags.set(s, tag);
|
|
2173
|
+
for (const remote of globalRemotes)
|
|
2174
|
+
if (remote !== state.winner && !pool.servesAt(remote, globalTags)) {
|
|
2175
|
+
globalRemotes.delete(remote);
|
|
2176
|
+
const subpool = state.subpools.find(
|
|
2177
|
+
(p) => pool.servesAt(remote, pool.builds.get(p.owner).tags)
|
|
2178
|
+
);
|
|
2179
|
+
if (subpool) subpool.remotes.push(remote);
|
|
2180
|
+
else state.pending.push(remote);
|
|
2181
|
+
demoted = true;
|
|
2114
2182
|
}
|
|
2115
|
-
}
|
|
2116
|
-
if (matches) return true;
|
|
2117
2183
|
}
|
|
2118
|
-
return false;
|
|
2119
2184
|
}
|
|
2120
|
-
function
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2185
|
+
function publishedWhole(pool, state, pkg) {
|
|
2186
|
+
const published = new Set([...state.globalTags.keys()].filter((s) => packageOf(s) === pkg));
|
|
2187
|
+
const tag = state.globalTags.pinnedTag(pkg);
|
|
2188
|
+
return [...state.globalRemotes].some((remote) => {
|
|
2189
|
+
const copy = pool.packages.get(remote).get(pkg);
|
|
2190
|
+
return !!copy && copy.tag === tag && copy.specifiers.size === published.size && contains(copy.specifiers, published);
|
|
2191
|
+
});
|
|
2192
|
+
}
|
|
2193
|
+
function missOf(pool, state, remote) {
|
|
2194
|
+
const { globalTags } = state;
|
|
2195
|
+
const copies = pool.shipped.get(remote);
|
|
2196
|
+
let rejected;
|
|
2197
|
+
for (const copy of copies)
|
|
2198
|
+
for (const s of copy.specifiers) {
|
|
2199
|
+
const tag = globalTags.get(s);
|
|
2200
|
+
if (tag === void 0 || pool.acceptsTag(tag, copy.tag, copy.requiredVersion)) continue;
|
|
2201
|
+
if (copy.strict) return { cause: "incompatible", member: copy.member, tag, strict: true };
|
|
2202
|
+
rejected ??= { cause: "incompatible", member: copy.member, tag, strict: false };
|
|
2132
2203
|
}
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
}
|
|
2138
|
-
|
|
2204
|
+
if (rejected) return rejected;
|
|
2205
|
+
for (const copy of copies)
|
|
2206
|
+
for (const s of copy.specifiers) if (!globalTags.has(s)) return { cause: "uncovered", gap: s };
|
|
2207
|
+
const gap = unwitnessedGap(copies, globalTags, pool.builds.values());
|
|
2208
|
+
if (gap) return { cause: "uncovered", gap, unshipped: true };
|
|
2209
|
+
if (state.subpools.some((p) => p.owner === remote)) return void 0;
|
|
2210
|
+
throw new Error(`'${remote}' missed the global map with nothing it rejects or lacks.`);
|
|
2139
2211
|
}
|
|
2140
|
-
function
|
|
2141
|
-
const
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
return void 0;
|
|
2212
|
+
function previousWinner(members) {
|
|
2213
|
+
const winners = new Set(members.flatMap((m) => m.external.poolWinner ?? []));
|
|
2214
|
+
const [winner] = winners;
|
|
2215
|
+
if (winners.size !== 1) return void 0;
|
|
2216
|
+
const ships = members.some(
|
|
2217
|
+
(m) => m.external.versions.some((v) => v.remotes.some((r) => r.name === winner))
|
|
2218
|
+
);
|
|
2219
|
+
return ships ? winner : void 0;
|
|
2149
2220
|
}
|
|
2150
|
-
function
|
|
2151
|
-
const
|
|
2152
|
-
const
|
|
2153
|
-
|
|
2154
|
-
const
|
|
2155
|
-
const
|
|
2156
|
-
const
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
};
|
|
2162
|
-
const electAnchor = (anchor, served) => {
|
|
2163
|
-
pending.delete(anchor);
|
|
2164
|
-
assignment.set(anchor, void 0);
|
|
2165
|
-
for (const consumer of served) {
|
|
2166
|
-
pending.delete(consumer);
|
|
2167
|
-
anchored.add(consumer);
|
|
2168
|
-
assignment.set(consumer, anchor);
|
|
2169
|
-
}
|
|
2170
|
-
};
|
|
2171
|
-
for (const host of [...hosts].sort(byPriority)) {
|
|
2172
|
-
const served = [];
|
|
2173
|
-
if (builds.has(host)) {
|
|
2174
|
-
for (const consumer of pending) {
|
|
2175
|
-
if (consumer !== host && canServe(host, consumer)) served.push(consumer);
|
|
2176
|
-
}
|
|
2177
|
-
}
|
|
2178
|
-
electAnchor(host, served);
|
|
2179
|
-
}
|
|
2180
|
-
for (; ; ) {
|
|
2181
|
-
let best;
|
|
2182
|
-
let bestServed = [];
|
|
2183
|
-
for (const candidate of candidates) {
|
|
2184
|
-
if (anchored.has(candidate)) continue;
|
|
2185
|
-
const served = [];
|
|
2186
|
-
for (const consumer of pending) {
|
|
2187
|
-
if (consumer !== candidate && canServe(candidate, consumer)) served.push(consumer);
|
|
2188
|
-
}
|
|
2189
|
-
if (served.length > bestServed.length) {
|
|
2190
|
-
best = candidate;
|
|
2191
|
-
bestServed = served;
|
|
2192
|
-
}
|
|
2193
|
-
}
|
|
2194
|
-
if (best === void 0) break;
|
|
2195
|
-
electAnchor(best, bestServed);
|
|
2196
|
-
}
|
|
2197
|
-
for (const consumer of pending) assignment.set(consumer, void 0);
|
|
2198
|
-
return assignment;
|
|
2221
|
+
function placeRemotes(globalRemotes, subpools, self, missOf2) {
|
|
2222
|
+
const misses = /* @__PURE__ */ new Map();
|
|
2223
|
+
for (const remote of [...subpools.flatMap((p) => p.remotes), ...self])
|
|
2224
|
+
misses.set(remote, missOf2(remote));
|
|
2225
|
+
const placements = /* @__PURE__ */ new Map();
|
|
2226
|
+
for (const remote of globalRemotes) placements.set(remote, { kind: "global" });
|
|
2227
|
+
for (const { owner, remotes } of subpools)
|
|
2228
|
+
for (const remote of remotes) placements.set(remote, { kind: "subpool", owner });
|
|
2229
|
+
for (const remote of self)
|
|
2230
|
+
placements.set(remote, { kind: "self", cause: misses.get(remote).cause });
|
|
2231
|
+
return { placements, misses };
|
|
2199
2232
|
}
|
|
2200
2233
|
|
|
2201
|
-
// src/lib/core/
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
const
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
id = parent.length;
|
|
2211
|
-
ids.set(key, id);
|
|
2212
|
-
parent.push(id);
|
|
2213
|
-
size.push(1);
|
|
2234
|
+
// src/lib/core/1.domain/pooling/membership.ts
|
|
2235
|
+
function unionFind() {
|
|
2236
|
+
const parent = /* @__PURE__ */ new Map();
|
|
2237
|
+
const find = (node) => {
|
|
2238
|
+
for (let up = parent.get(node); up !== void 0; up = parent.get(node)) {
|
|
2239
|
+
const grand = parent.get(up);
|
|
2240
|
+
if (grand === void 0) return up;
|
|
2241
|
+
parent.set(node, grand);
|
|
2242
|
+
node = grand;
|
|
2214
2243
|
}
|
|
2215
|
-
return
|
|
2244
|
+
return node;
|
|
2216
2245
|
};
|
|
2217
|
-
const
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
}
|
|
2222
|
-
return x;
|
|
2223
|
-
};
|
|
2224
|
-
return {
|
|
2225
|
-
union(a, b) {
|
|
2226
|
-
let rootA = findRoot(intern(a));
|
|
2227
|
-
let rootB = findRoot(intern(b));
|
|
2228
|
-
if (rootA === rootB) return;
|
|
2229
|
-
if (size[rootA] < size[rootB]) [rootA, rootB] = [rootB, rootA];
|
|
2230
|
-
parent[rootB] = rootA;
|
|
2231
|
-
size[rootA] = size[rootA] + size[rootB];
|
|
2232
|
-
},
|
|
2233
|
-
// Interns the key if unseen — an isolated key is its own component.
|
|
2234
|
-
component(key) {
|
|
2235
|
-
return findRoot(intern(key));
|
|
2236
|
-
}
|
|
2246
|
+
const union = (a, b) => {
|
|
2247
|
+
const rootA = find(a);
|
|
2248
|
+
const rootB = find(b);
|
|
2249
|
+
if (rootA !== rootB) parent.set(rootB, rootA);
|
|
2237
2250
|
};
|
|
2251
|
+
return { find, union };
|
|
2238
2252
|
}
|
|
2239
2253
|
var extNode = (name) => `ext\0${name}`;
|
|
2240
|
-
var
|
|
2241
|
-
var
|
|
2242
|
-
function
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
if (cut === -1) return void 0;
|
|
2251
|
-
}
|
|
2252
|
-
return name.slice(0, cut);
|
|
2254
|
+
var labelNode = (label) => `label\0${label}`;
|
|
2255
|
+
var labelOf = (pool) => pool?.trim() || void 0;
|
|
2256
|
+
function labelsIn(sharedExternals) {
|
|
2257
|
+
const labelsOf = /* @__PURE__ */ new Map();
|
|
2258
|
+
for (const [name, external] of Object.entries(sharedExternals))
|
|
2259
|
+
labelsOf.set(
|
|
2260
|
+
name,
|
|
2261
|
+
external.versions.flatMap((v) => v.remotes.flatMap((r) => labelOf(r.pool) ?? []))
|
|
2262
|
+
);
|
|
2263
|
+
return labelsOf;
|
|
2253
2264
|
}
|
|
2254
|
-
function
|
|
2255
|
-
const
|
|
2256
|
-
const
|
|
2257
|
-
|
|
2258
|
-
const
|
|
2259
|
-
|
|
2260
|
-
if (
|
|
2261
|
-
for (const edge of candidate.tags) tagRules.add(`${edge.remote}\0${candidate.scope}`);
|
|
2262
|
-
}
|
|
2263
|
-
for (const candidate of candidates) {
|
|
2264
|
-
for (const edge of candidate.tags) {
|
|
2265
|
-
dsu.union(extNode(candidate.name), tagNode(edge.remote, edge.tag));
|
|
2266
|
-
tagged.add(candidate.name);
|
|
2267
|
-
joined.add(candidate.name);
|
|
2268
|
-
}
|
|
2269
|
-
if (candidate.scope === void 0) continue;
|
|
2270
|
-
for (const remote of candidate.remotes) {
|
|
2271
|
-
if (tagRules.has(`${remote}\0${candidate.scope}`)) continue;
|
|
2272
|
-
dsu.union(extNode(candidate.name), scopeNode(remote, candidate.scope));
|
|
2273
|
-
joined.add(candidate.name);
|
|
2274
|
-
}
|
|
2275
|
-
}
|
|
2276
|
-
const declared = new Set(candidates.map((c) => c.name));
|
|
2277
|
-
for (const candidate of candidates) {
|
|
2278
|
-
const owner = owningPackage(candidate.name);
|
|
2279
|
-
if (owner !== void 0 && declared.has(owner))
|
|
2280
|
-
dsu.union(extNode(candidate.name), extNode(owner));
|
|
2265
|
+
function labelledComponents(labelsOf) {
|
|
2266
|
+
const { find, union } = unionFind();
|
|
2267
|
+
for (const [name, labels] of labelsOf)
|
|
2268
|
+
for (const label of labels) union(extNode(name), labelNode(label));
|
|
2269
|
+
for (const name of labelsOf.keys()) {
|
|
2270
|
+
const owner = owningPackage(name);
|
|
2271
|
+
if (owner !== void 0) union(extNode(name), extNode(owner));
|
|
2281
2272
|
}
|
|
2282
2273
|
const byComponent = /* @__PURE__ */ new Map();
|
|
2283
|
-
for (const
|
|
2284
|
-
const root =
|
|
2285
|
-
const
|
|
2286
|
-
|
|
2287
|
-
}
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2274
|
+
for (const name of labelsOf.keys()) {
|
|
2275
|
+
const root = find(extNode(name));
|
|
2276
|
+
const names = byComponent.get(root) ?? byComponent.set(root, []).get(root);
|
|
2277
|
+
names.push(name);
|
|
2278
|
+
}
|
|
2279
|
+
return [...byComponent.values()].filter((names) => names.some((n) => labelsOf.get(n).length > 0));
|
|
2280
|
+
}
|
|
2281
|
+
function buildPools(sharedExternals) {
|
|
2282
|
+
const labelsOf = labelsIn(sharedExternals);
|
|
2283
|
+
const pools = /* @__PURE__ */ new Map();
|
|
2284
|
+
const labelledAlone = [];
|
|
2285
|
+
for (const names of labelledComponents(labelsOf)) {
|
|
2286
|
+
if (names.length < 2) labelledAlone.push(names[0]);
|
|
2287
|
+
else {
|
|
2288
|
+
const members = names.map((name) => ({ name, external: sharedExternals[name] }));
|
|
2289
|
+
pools.set(
|
|
2290
|
+
mostDeclaredLabel(members, labelsOf),
|
|
2291
|
+
members.sort((a, b) => compareStrings(a.name, b.name))
|
|
2292
|
+
);
|
|
2301
2293
|
}
|
|
2302
|
-
pools.push(members);
|
|
2303
2294
|
}
|
|
2304
|
-
pools
|
|
2305
|
-
return new Map(pools.map((members) => [members[0].name, members.map((m) => m.value)]));
|
|
2295
|
+
return { pools, labelledAlone };
|
|
2306
2296
|
}
|
|
2307
|
-
function
|
|
2308
|
-
const
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
})
|
|
2317
|
-
),
|
|
2318
|
-
remotes: external.versions.flatMap((v) => v.remotes.map((r) => r.name)),
|
|
2319
|
-
value: { name, external }
|
|
2320
|
-
})
|
|
2297
|
+
function pooledPackagesWith(sharedExternals, copies) {
|
|
2298
|
+
const labelsOf = labelsIn(sharedExternals);
|
|
2299
|
+
for (const { name, pool } of copies) {
|
|
2300
|
+
const labels = labelsOf.get(name) ?? [];
|
|
2301
|
+
const label = labelOf(pool);
|
|
2302
|
+
labelsOf.set(name, label === void 0 ? labels : [...labels, label]);
|
|
2303
|
+
}
|
|
2304
|
+
return new Set(
|
|
2305
|
+
labelledComponents(labelsOf).filter((names) => names.length > 1).flatMap((names) => names.map(packageOf))
|
|
2321
2306
|
);
|
|
2322
|
-
|
|
2307
|
+
}
|
|
2308
|
+
function mostDeclaredLabel(members, labelsOf) {
|
|
2309
|
+
const counts = /* @__PURE__ */ new Map();
|
|
2310
|
+
for (const member of members)
|
|
2311
|
+
for (const label of labelsOf.get(member.name)) counts.set(label, (counts.get(label) ?? 0) + 1);
|
|
2312
|
+
let best = "";
|
|
2313
|
+
let top = 0;
|
|
2314
|
+
for (const [label, count] of counts)
|
|
2315
|
+
if (count > top || count === top && compareStrings(label, best) < 0)
|
|
2316
|
+
[best, top] = [label, count];
|
|
2317
|
+
return best;
|
|
2323
2318
|
}
|
|
2324
2319
|
|
|
2325
|
-
// src/lib/core/
|
|
2326
|
-
function
|
|
2327
|
-
|
|
2328
|
-
return (
|
|
2320
|
+
// src/lib/core/1.domain/pooling/pool-state.ts
|
|
2321
|
+
function hasPoolResults(external) {
|
|
2322
|
+
if (external.poolName !== void 0 || external.poolWinner !== void 0) return true;
|
|
2323
|
+
return external.versions.some(
|
|
2324
|
+
(v) => v.remotes.some((r) => r.servedBy !== void 0 || r.poolCause !== void 0)
|
|
2325
|
+
);
|
|
2329
2326
|
}
|
|
2330
|
-
function
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2327
|
+
function scopeHasPoolState(scope) {
|
|
2328
|
+
for (const name in scope) {
|
|
2329
|
+
const external = scope[name];
|
|
2330
|
+
if (hasPoolResults(external)) return true;
|
|
2331
|
+
for (const version of external.versions)
|
|
2332
|
+
for (const remote of version.remotes) if (remote.pool?.trim()) return true;
|
|
2333
|
+
}
|
|
2334
|
+
return false;
|
|
2334
2335
|
}
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
)
|
|
2336
|
+
|
|
2337
|
+
// src/lib/core/1.domain/pooling/records.ts
|
|
2338
|
+
function memberRecord(member, pool, compare) {
|
|
2339
|
+
const { globalTags, placements } = pool;
|
|
2340
|
+
let sharedTag = globalTags.get(member.name);
|
|
2341
|
+
for (const version of member.external.versions)
|
|
2342
|
+
for (const meta of version.remotes)
|
|
2343
|
+
for (const s in meta.entries) sharedTag ??= globalTags.get(s);
|
|
2344
|
+
const claimsGlobally = (name) => placements.get(name).kind === "global";
|
|
2345
|
+
const placed = [];
|
|
2346
|
+
let winnerRow;
|
|
2347
|
+
const place = (tag, action, meta) => {
|
|
2348
|
+
const row = { tag, host: false, action, remotes: [meta] };
|
|
2349
|
+
placed.push(row);
|
|
2350
|
+
if (meta.name !== pool.winner) return;
|
|
2351
|
+
winnerRow = row;
|
|
2352
|
+
row.host = pool.winnerIsHost;
|
|
2342
2353
|
};
|
|
2354
|
+
for (const version of member.external.versions)
|
|
2355
|
+
for (const stored of version.remotes) {
|
|
2356
|
+
const { servedBy: _servedBy, poolCause: _poolCause, ...rest } = stored;
|
|
2357
|
+
const meta = { ...rest, cached: false };
|
|
2358
|
+
const placement = placements.get(meta.name);
|
|
2359
|
+
if (placement.kind === "global")
|
|
2360
|
+
place(version.tag, version.tag === sharedTag ? "share" : "skip", meta);
|
|
2361
|
+
else if (placement.kind === "subpool")
|
|
2362
|
+
place(version.tag, "skip", { ...meta, servedBy: placement.owner });
|
|
2363
|
+
else place(version.tag, "scope", { ...meta, poolCause: placement.cause });
|
|
2364
|
+
}
|
|
2365
|
+
const rows = mergeRows(placed, winnerRow);
|
|
2366
|
+
for (const row of rows)
|
|
2367
|
+
row.remotes.sort((a, b) => Number(!claimsGlobally(a.name)) - Number(!claimsGlobally(b.name)));
|
|
2368
|
+
const order = { share: 0, skip: 1, scope: 2 };
|
|
2369
|
+
const newest = byTag(compare);
|
|
2370
|
+
const versions = rows.sort((a, b) => newest(a, b) || order[a.action] - order[b.action]);
|
|
2371
|
+
return { dirty: false, poolName: pool.poolName, versions };
|
|
2343
2372
|
}
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
function islandedRemotes(members) {
|
|
2347
|
-
const islanded = /* @__PURE__ */ new Map();
|
|
2348
|
-
for (const member of members)
|
|
2349
|
-
for (const version of member.external.versions)
|
|
2350
|
-
if (version.action === "scope") {
|
|
2351
|
-
for (const remote of version.remotes)
|
|
2352
|
-
if (!islanded.has(remote.name))
|
|
2353
|
-
islanded.set(remote.name, {
|
|
2354
|
-
kind: "incompatible",
|
|
2355
|
-
member: member.name,
|
|
2356
|
-
tag: version.tag
|
|
2357
|
-
});
|
|
2358
|
-
}
|
|
2359
|
-
return islanded;
|
|
2373
|
+
function movedRecord(external, remote, move, compare) {
|
|
2374
|
+
return withoutStaleServingBuild(moveCopy(external, remote, move, compare));
|
|
2360
2375
|
}
|
|
2361
|
-
|
|
2362
|
-
const
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
const byMember = /* @__PURE__ */ new Map();
|
|
2369
|
-
for (const name of consumed.get(remote) ?? []) {
|
|
2370
|
-
if (basis.get(name) !== build) byMember.set(name, build);
|
|
2371
|
-
}
|
|
2372
|
-
if (byMember.size > 0) served.set(remote, byMember);
|
|
2373
|
-
}
|
|
2374
|
-
return served;
|
|
2376
|
+
function withoutStaleServingBuild(record) {
|
|
2377
|
+
const { servingBuild, ...rest } = record;
|
|
2378
|
+
if (servingBuild === void 0) return record;
|
|
2379
|
+
const shares = record.versions.some(
|
|
2380
|
+
(v) => v.action === "share" && v.remotes.some((r) => r.name === servingBuild)
|
|
2381
|
+
);
|
|
2382
|
+
return shares ? record : rest;
|
|
2375
2383
|
}
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
const
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
if (tag !== void 0 && !resolved.has(specifier)) resolved.set(specifier, tag);
|
|
2396
|
-
}
|
|
2397
|
-
}
|
|
2398
|
-
if (resolved.size === 0) continue;
|
|
2399
|
-
if (ships(ownTags, resolved)) continue;
|
|
2400
|
-
let witnessed = false;
|
|
2401
|
-
for (const [, build] of builds) {
|
|
2402
|
-
if (ships(build.tags, resolved)) {
|
|
2403
|
-
witnessed = true;
|
|
2404
|
-
break;
|
|
2405
|
-
}
|
|
2406
|
-
}
|
|
2407
|
-
if (!witnessed) {
|
|
2408
|
-
torn.push({
|
|
2409
|
-
remote,
|
|
2410
|
-
combination: [...resolved].map(([specifier, tag]) => `${specifier}@${tag}`).join(", ")
|
|
2411
|
-
});
|
|
2412
|
-
}
|
|
2413
|
-
}
|
|
2414
|
-
return torn;
|
|
2384
|
+
function moveCopy(external, remote, move, compare) {
|
|
2385
|
+
if ("fromMap" in move) return recordFromMap(external, remote);
|
|
2386
|
+
const moved = [];
|
|
2387
|
+
const versions = external.versions.map((v) => {
|
|
2388
|
+
const copy = v.remotes.find((r) => r.name === remote);
|
|
2389
|
+
if (!copy) return v;
|
|
2390
|
+
const { servedBy: _servedBy, ...rest } = copy;
|
|
2391
|
+
const meta = { ...rest, cached: true, poolCause: move.cause };
|
|
2392
|
+
if (v.action === "scope")
|
|
2393
|
+
return { ...v, remotes: v.remotes.map((r) => r === copy ? meta : r) };
|
|
2394
|
+
moved.push({ tag: v.tag, meta });
|
|
2395
|
+
return { ...v, remotes: v.remotes.filter((r) => r !== copy) };
|
|
2396
|
+
}).filter((v) => v.remotes.length > 0);
|
|
2397
|
+
for (const { tag, meta } of moved) {
|
|
2398
|
+
const scoped = rowAt(versions, tag, "scope");
|
|
2399
|
+
if (!scoped) versions.push({ tag, action: "scope", host: false, remotes: [meta] });
|
|
2400
|
+
else versions[versions.indexOf(scoped)] = { ...scoped, remotes: [...scoped.remotes, meta] };
|
|
2401
|
+
}
|
|
2402
|
+
return { ...external, versions: versions.sort(byTag(compare)) };
|
|
2415
2403
|
}
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
};
|
|
2421
|
-
|
|
2422
|
-
const
|
|
2423
|
-
|
|
2424
|
-
const
|
|
2425
|
-
if (
|
|
2404
|
+
function recordFromMap(external, remote) {
|
|
2405
|
+
const opened = external.versions.find(
|
|
2406
|
+
(v) => v.action !== "skip" && v.remotes.some((r) => r.name === remote)
|
|
2407
|
+
);
|
|
2408
|
+
const meta = { ...opened.remotes.find((r) => r.name === remote), cached: false };
|
|
2409
|
+
const joined = rowAt(external.versions, opened.tag, "skip");
|
|
2410
|
+
const into = joined ? { ...joined, remotes: [...joined.remotes] } : { ...opened, action: "skip", remotes: [] };
|
|
2411
|
+
addRemoteToVersion(into, meta);
|
|
2412
|
+
const versions = external.versions.flatMap((v) => {
|
|
2413
|
+
if (v === joined) return [into];
|
|
2414
|
+
if (v !== opened) return [v];
|
|
2415
|
+
const left = { ...v, remotes: v.remotes.filter((r) => r.name !== remote) };
|
|
2416
|
+
return [...left.remotes.length > 0 ? [left] : [], ...joined ? [] : [into]];
|
|
2417
|
+
});
|
|
2418
|
+
return { ...external, versions };
|
|
2419
|
+
}
|
|
2420
|
+
function withoutPoolResults(external) {
|
|
2421
|
+
const { poolName: _poolName, poolWinner: _poolWinner, ...rest } = external;
|
|
2422
|
+
return {
|
|
2423
|
+
...rest,
|
|
2424
|
+
versions: external.versions.map((v) => ({
|
|
2425
|
+
...v,
|
|
2426
|
+
remotes: v.remotes.map(({ servedBy: _servedBy, poolCause: _poolCause, ...meta }) => meta)
|
|
2427
|
+
}))
|
|
2426
2428
|
};
|
|
2427
|
-
for (const remote of served.keys()) add(remote);
|
|
2428
|
-
for (const member of members) {
|
|
2429
|
-
const unpublished = !basis.has(member.name);
|
|
2430
|
-
for (const version of member.external.versions) {
|
|
2431
|
-
const scoped = version.action === "scope";
|
|
2432
|
-
if (!unpublished && !scoped) continue;
|
|
2433
|
-
for (const meta of version.remotes) {
|
|
2434
|
-
add(meta.name);
|
|
2435
|
-
const servesItself = scoped || unpublished && served.get(meta.name)?.get(member.name) === void 0;
|
|
2436
|
-
if (!servesItself) continue;
|
|
2437
|
-
let mine = selfServed.get(meta.name);
|
|
2438
|
-
if (!mine) selfServed.set(meta.name, mine = /* @__PURE__ */ new Set());
|
|
2439
|
-
mine.add(member.name);
|
|
2440
|
-
}
|
|
2441
|
-
}
|
|
2442
|
-
}
|
|
2443
|
-
return { suspect, selfServed };
|
|
2444
2429
|
}
|
|
2430
|
+
function renamedRecords(scope, pools) {
|
|
2431
|
+
const renamed = [];
|
|
2432
|
+
for (const [poolName, members] of pools)
|
|
2433
|
+
for (const { name } of members)
|
|
2434
|
+
if (scope[name].poolName !== poolName) renamed.push([name, { ...scope[name], poolName }]);
|
|
2435
|
+
return renamed;
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2438
|
+
// src/lib/core/1.domain/pooling/plan.ts
|
|
2439
|
+
function planElection(scope, poolable) {
|
|
2440
|
+
if (!poolable || !Object.values(scope).some((external) => external.dirty) || !scopeHasPoolState(scope))
|
|
2441
|
+
return { pools: /* @__PURE__ */ new Map(), stripped: /* @__PURE__ */ new Map(), labelledAlone: [] };
|
|
2442
|
+
const { pools, labelledAlone } = buildPools(scope);
|
|
2443
|
+
const pooled = new Set([...pools.values()].flatMap((members) => members.map((m) => m.name)));
|
|
2444
|
+
const stripped = /* @__PURE__ */ new Map();
|
|
2445
|
+
for (const [name, external] of Object.entries(scope))
|
|
2446
|
+
if (!pooled.has(name) && hasPoolResults(external))
|
|
2447
|
+
stripped.set(name, { ...withoutPoolResults(external), dirty: true });
|
|
2448
|
+
return { pools, stripped, labelledAlone };
|
|
2449
|
+
}
|
|
2450
|
+
|
|
2451
|
+
// src/lib/core/2.app/steps/pooling/pool-shared-externals.ts
|
|
2445
2452
|
function createPoolSharedExternals(config, ports) {
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
const sharedExternals = ports.sharedExternalsRepo.getFromScope(scope);
|
|
2453
|
+
const { compare } = ports.versionCheck;
|
|
2454
|
+
return () => {
|
|
2455
|
+
const repo = ports.sharedExternalsRepo;
|
|
2456
|
+
for (const scope of repo.getScopes()) {
|
|
2457
|
+
const sharedExternals = repo.getFromScope(scope);
|
|
2452
2458
|
try {
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
poolFamily(poolName, members, scope);
|
|
2460
|
-
}
|
|
2459
|
+
const plan = planElection(sharedExternals, repo.scopeType(scope) !== "strict");
|
|
2460
|
+
logPlan(plan, sharedExternals, scope);
|
|
2461
|
+
for (const [poolName, members] of plan.pools)
|
|
2462
|
+
for (const [name, record] of poolRecords(poolName, members, scope))
|
|
2463
|
+
repo.addOrUpdate(name, record, scope);
|
|
2464
|
+
for (const [name, external] of plan.stripped) repo.addOrUpdate(name, external, scope);
|
|
2461
2465
|
} catch (error) {
|
|
2462
2466
|
if (error instanceof NFError) return Promise.reject(error);
|
|
2463
2467
|
config.log.error(3, `[${scope}] failed to pool shared externals.`, {
|
|
@@ -2471,215 +2475,439 @@ function createPoolSharedExternals(config, ports) {
|
|
|
2471
2475
|
}
|
|
2472
2476
|
return Promise.resolve();
|
|
2473
2477
|
};
|
|
2474
|
-
function
|
|
2475
|
-
if (
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
const views = {
|
|
2482
|
-
consumedSpecifiers: lazy(() => consumedSpecifiers(members)),
|
|
2483
|
-
acceptance: lazy(() => acceptanceTable(members, ports.versionCheck.isCompatible)),
|
|
2484
|
-
arrival: lazy(() => arrivalOrder(members))
|
|
2485
|
-
};
|
|
2486
|
-
config.log.debug(
|
|
2487
|
-
3,
|
|
2488
|
-
`[${scope}][pool:${poolName}] ${members.length} members across ${allRemotes.length} remotes, incompatible={${[...islanded.keys()].join(", ") || "\u2205"}}
|
|
2489
|
-
` + members.map((m) => ` - ${m.name}`).join("\n")
|
|
2490
|
-
);
|
|
2491
|
-
const assign = () => {
|
|
2492
|
-
const serving2 = assignServingBuilds(members, islanded, consumed, hosts, views);
|
|
2493
|
-
const basis2 = basisFor(members, islanded, serving2);
|
|
2494
|
-
return { serving: serving2, basis: basis2, served: servedPerRemote(consumed, serving2, basis2) };
|
|
2495
|
-
};
|
|
2496
|
-
let { serving, basis, served } = assign();
|
|
2497
|
-
if (islanded.size === 0 && serving.size === 0 && !anyAnchorStored(members)) return;
|
|
2498
|
-
for (; ; ) {
|
|
2499
|
-
const torn = findTornRemotes(members, islanded, basis, served, hosts);
|
|
2500
|
-
if (torn.length === 0) break;
|
|
2501
|
-
for (const { remote, combination } of torn)
|
|
2502
|
-
islanded.set(remote, { kind: "torn", combination });
|
|
2503
|
-
({ serving, basis, served } = assign());
|
|
2478
|
+
function logPlan(plan, sharedExternals, scope) {
|
|
2479
|
+
if (plan.pools.size > 0) {
|
|
2480
|
+
const dirty = Object.values(sharedExternals).filter((external) => external.dirty).length;
|
|
2481
|
+
config.log.debug(
|
|
2482
|
+
3,
|
|
2483
|
+
`[${scope}] re-electing ${plan.pools.size} pool(s): ${dirty} dirty external(s).`
|
|
2484
|
+
);
|
|
2504
2485
|
}
|
|
2505
|
-
|
|
2506
|
-
|
|
2486
|
+
if (plan.stripped.size > 0)
|
|
2487
|
+
config.log.debug(
|
|
2488
|
+
3,
|
|
2489
|
+
`[${scope}] ${plan.stripped.size} external(s) left every pool; cleared their pool state for re-election.`
|
|
2490
|
+
);
|
|
2491
|
+
for (const name of plan.labelledAlone)
|
|
2492
|
+
config.log.debug(
|
|
2493
|
+
3,
|
|
2494
|
+
`[${scope}] '${name}' has a 'pool' label that joins no other external; likely a typo or a missing sibling.`
|
|
2495
|
+
);
|
|
2496
|
+
}
|
|
2497
|
+
function poolRecords(poolName, members, scope) {
|
|
2498
|
+
const election = elect({
|
|
2499
|
+
members,
|
|
2500
|
+
acceptsTag: createAcceptsTag(ports.versionCheck.isCompatible, compare),
|
|
2501
|
+
compare,
|
|
2502
|
+
previousWinner: previousWinner(members),
|
|
2503
|
+
latestFirst: config.profile.latestSharedExternal
|
|
2504
|
+
});
|
|
2505
|
+
const placed = { ...election, poolName };
|
|
2506
|
+
report(poolName, members, placed, scope);
|
|
2507
|
+
return members.map((m) => [
|
|
2508
|
+
m.name,
|
|
2509
|
+
{ ...memberRecord(m, placed, compare), poolWinner: placed.winner }
|
|
2510
|
+
]);
|
|
2511
|
+
}
|
|
2512
|
+
function report(poolName, members, placed, scope) {
|
|
2513
|
+
const { misses } = placed;
|
|
2514
|
+
const rejecting = [...misses].filter(([, miss]) => miss?.cause === "incompatible" && miss.strict).map(([remote]) => remote);
|
|
2515
|
+
if (config.strict.strictExternalCompatibility && rejecting.length > 0) {
|
|
2507
2516
|
config.log.error(
|
|
2508
2517
|
3,
|
|
2509
|
-
`[${scope}][pool:${poolName}] version-incompatible remotes cannot be pooled: {${
|
|
2518
|
+
`[${scope}][pool:${poolName}] version-incompatible remotes cannot be pooled: {${rejecting.join(", ")}}.`
|
|
2510
2519
|
);
|
|
2511
2520
|
throw new NFError(`Could not pool '${poolName}' in scope ${scope}.`);
|
|
2512
2521
|
}
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
const bases = servingBuilds(members, islanded);
|
|
2526
|
-
const distinct = new Set(bases.values());
|
|
2527
|
-
if (distinct.size === 1 && bases.size === members.length) {
|
|
2528
|
-
const sole = [...distinct][0];
|
|
2529
|
-
if (coversWholePool(members, sole, islanded)) return /* @__PURE__ */ new Map();
|
|
2530
|
-
}
|
|
2531
|
-
const builds = liveBuilds(members, islanded);
|
|
2532
|
-
const shared = sharedTagPerSpecifier(members, islanded);
|
|
2533
|
-
const consumedSpec = views.consumedSpecifiers();
|
|
2534
|
-
const needAnchor = /* @__PURE__ */ new Map();
|
|
2535
|
-
const needSpecifiers = /* @__PURE__ */ new Map();
|
|
2536
|
-
for (const [remote, wants] of consumed) {
|
|
2537
|
-
if (islanded.has(remote)) continue;
|
|
2538
|
-
if (isWitnessed(consumedSpec.get(remote) ?? [], shared, builds)) continue;
|
|
2539
|
-
needAnchor.set(remote, wants);
|
|
2540
|
-
needSpecifiers.set(remote, consumedSpec.get(remote) ?? /* @__PURE__ */ new Set());
|
|
2541
|
-
}
|
|
2542
|
-
if (needAnchor.size === 0) return /* @__PURE__ */ new Map();
|
|
2543
|
-
const acceptance = views.acceptance();
|
|
2544
|
-
const assignment = assignAnchors({
|
|
2545
|
-
builds,
|
|
2546
|
-
acceptance,
|
|
2547
|
-
consumedSpecifiers: needSpecifiers,
|
|
2548
|
-
consumedMembers: needAnchor,
|
|
2549
|
-
hosts,
|
|
2550
|
-
arrival: views.arrival()
|
|
2551
|
-
});
|
|
2552
|
-
const anchors = /* @__PURE__ */ new Set();
|
|
2553
|
-
for (const build of assignment.values()) if (build !== void 0) anchors.add(build);
|
|
2554
|
-
const serving = /* @__PURE__ */ new Map();
|
|
2555
|
-
let scoped = false;
|
|
2556
|
-
for (const [remote, wants] of needAnchor) {
|
|
2557
|
-
const assigned = assignment.get(remote);
|
|
2558
|
-
const build = assigned ?? (anchors.has(remote) || hosts.has(remote) ? remote : void 0);
|
|
2559
|
-
if (build === void 0) {
|
|
2560
|
-
islanded.set(remote, {
|
|
2561
|
-
kind: "uncovered",
|
|
2562
|
-
...explainSelfServe(remote, wants, needSpecifiers.get(remote), { builds, acceptance })
|
|
2563
|
-
});
|
|
2564
|
-
scoped = true;
|
|
2565
|
-
continue;
|
|
2566
|
-
}
|
|
2567
|
-
serving.set(remote, build);
|
|
2522
|
+
const subpoolSizes = /* @__PURE__ */ new Map();
|
|
2523
|
+
for (const placement of placed.placements.values())
|
|
2524
|
+
if (placement.kind === "subpool")
|
|
2525
|
+
subpoolSizes.set(placement.owner, (subpoolSizes.get(placement.owner) ?? 0) + 1);
|
|
2526
|
+
let shipped;
|
|
2527
|
+
for (const [remote, miss] of misses) {
|
|
2528
|
+
if (miss === void 0) {
|
|
2529
|
+
config.log.warn(
|
|
2530
|
+
3,
|
|
2531
|
+
`[${scope}][pool:${poolName}] '${remote}' keeps subpool '${remote}': the elected build would serve it, but ${subpoolSizes.get(remote) - 1} other remote(s) in it need its build.`
|
|
2532
|
+
);
|
|
2533
|
+
continue;
|
|
2568
2534
|
}
|
|
2569
|
-
|
|
2535
|
+
shipped ??= copiesByRemote(members);
|
|
2536
|
+
const counts = {
|
|
2537
|
+
imports: specifierCount(shipped.get(remote)),
|
|
2538
|
+
subpoolSize: subpoolSizes.get(remote) ?? 0
|
|
2539
|
+
};
|
|
2540
|
+
config.log.warn(
|
|
2541
|
+
3,
|
|
2542
|
+
`[${scope}][pool:${poolName}] ${missWarning(remote, miss, placed, counts)}`
|
|
2543
|
+
);
|
|
2570
2544
|
}
|
|
2571
2545
|
}
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2546
|
+
}
|
|
2547
|
+
function missWarning(remote, miss, placed, counts) {
|
|
2548
|
+
const { imports, subpoolSize } = counts;
|
|
2549
|
+
const placement = placed.placements.get(remote);
|
|
2550
|
+
const where = placement.kind === "subpool" && placement.owner !== remote ? `It runs in subpool '${placement.owner}' for all ${imports} of its entrypoints.` : subpoolSize > 1 ? `Its build serves subpool '${remote}': its ${imports} entrypoints and ${subpoolSize - 1} other remote(s).` : `All ${imports} of its entrypoints are scoped for it.`;
|
|
2551
|
+
if (miss.cause === "incompatible")
|
|
2552
|
+
return `'${remote}' is islanded: its range rejects '${miss.member}@${miss.tag}' of the elected build '${placed.winner}'. ${where}`;
|
|
2553
|
+
if (miss.unshipped)
|
|
2554
|
+
return `'${remote}' serves its own family: no build shipped its entrypoints together at the elected versions (gap '${miss.gap}', closest '${placed.winner}'). ${where}`;
|
|
2555
|
+
return `'${remote}' serves its own family: no elected build offers every entrypoint it imports at a version it accepts (gap '${miss.gap}', closest '${placed.winner}'). ${where}`;
|
|
2556
|
+
}
|
|
2557
|
+
|
|
2558
|
+
// src/lib/core/1.domain/externals/serving.ts
|
|
2559
|
+
var byServingRank = (a, b) => Number(b.host) - Number(a.host) || a.downloads - b.downloads || a.fallbacks - b.fallbacks || Number(b.rootBasis) - Number(a.rootBasis) || compareStrings(a.remote, b.remote);
|
|
2560
|
+
var packagesOf = (scope) => groupByPackage(Object.keys(scope), (name) => name);
|
|
2561
|
+
var isPooled = (externals) => externals.some(([, e]) => e.poolName !== void 0);
|
|
2562
|
+
function servingBuildOf(externals, accepts) {
|
|
2563
|
+
if (externals.length === 0) return void 0;
|
|
2564
|
+
const pkg = packageOf(externals[0][0]);
|
|
2565
|
+
const rootRows = shareRows(externals.find(([name]) => name === pkg)?.[1]);
|
|
2566
|
+
const rows = rootRows.length > 0 ? rootRows : externals.flatMap(([, e]) => shareRows(e));
|
|
2567
|
+
if (isPooled(externals)) return pooledBuild(externals, rows);
|
|
2568
|
+
const consumers = consumersOf(externals);
|
|
2569
|
+
const builds = buildsOf(rows, rootRows, consumers);
|
|
2570
|
+
const hosts = builds.filter((b) => b.host);
|
|
2571
|
+
const field = hosts.length > 0 ? hosts : builds;
|
|
2572
|
+
if (field.length <= 1) return field[0] && { remote: field[0].remote, tag: field[0].tag };
|
|
2573
|
+
return cheapestBuild(field, costTable(consumers, accepts));
|
|
2574
|
+
}
|
|
2575
|
+
function cheapestBuild(field, costOf) {
|
|
2576
|
+
let best;
|
|
2577
|
+
for (const b of field) {
|
|
2578
|
+
const { downloads, fallbacks } = costOf(b);
|
|
2579
|
+
const candidate = {
|
|
2580
|
+
remote: b.remote,
|
|
2581
|
+
tag: b.tag,
|
|
2582
|
+
host: b.host,
|
|
2583
|
+
rootBasis: b.rootBasis,
|
|
2584
|
+
downloads,
|
|
2585
|
+
fallbacks
|
|
2586
|
+
};
|
|
2587
|
+
if (!best || byServingRank(candidate, best) < 0) best = candidate;
|
|
2584
2588
|
}
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2589
|
+
const { remote, tag } = best;
|
|
2590
|
+
return { remote, tag };
|
|
2591
|
+
}
|
|
2592
|
+
function shareServingCopies(external, serving) {
|
|
2593
|
+
for (const row of external.versions) {
|
|
2594
|
+
const copy = row.remotes.find((c) => c.name === serving.remote);
|
|
2595
|
+
if (row.action !== "skip" || !copy || rowAt(external.versions, row.tag, "share")) continue;
|
|
2596
|
+
row.action = "share";
|
|
2597
|
+
if (row.remotes[0] !== copy) row.host = false;
|
|
2598
|
+
row.remotes = [copy, ...row.remotes.filter((c) => c !== copy)];
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
function followServingBuild(external, serving, accepts) {
|
|
2602
|
+
let objector;
|
|
2603
|
+
const rebuilt = external.versions.flatMap((version) => {
|
|
2604
|
+
if (version.action !== "share" || version.tag === serving.tag || version.remotes[0].name === serving.remote)
|
|
2605
|
+
return [version];
|
|
2606
|
+
const rows = redirectRow(version, serving.tag, accepts);
|
|
2607
|
+
const scoped = rows.find((row) => row.action === "scope");
|
|
2608
|
+
if (scoped && !objector) objector = { copy: scoped.remotes[0], tag: scoped.tag };
|
|
2609
|
+
return rows;
|
|
2610
|
+
});
|
|
2611
|
+
external.versions = mergeRows(rebuilt);
|
|
2612
|
+
return { external, objector };
|
|
2613
|
+
}
|
|
2614
|
+
var sameTagOnly = (offered, ownTag) => offered === ownTag;
|
|
2615
|
+
var servedScopes = (scope, strict) => strict ? strictTagScopes(scope) : [scope];
|
|
2616
|
+
function strictTagScopes(scope) {
|
|
2617
|
+
const tagScopes = [];
|
|
2618
|
+
for (const [pkg, names] of packagesOf(scope)) {
|
|
2619
|
+
const byTag2 = /* @__PURE__ */ new Map();
|
|
2620
|
+
for (const name of names)
|
|
2621
|
+
for (const row of scope[name].versions) {
|
|
2622
|
+
let tagScope = byTag2.get(row.tag);
|
|
2623
|
+
if (!tagScope) byTag2.set(row.tag, tagScope = {});
|
|
2624
|
+
const external = tagScope[name] ??= { ...scope[name], versions: [] };
|
|
2625
|
+
external.versions.push({ ...row, remotes: [...row.remotes] });
|
|
2598
2626
|
}
|
|
2627
|
+
for (const [tag, tagScope] of byTag2) {
|
|
2628
|
+
const lead = [tagScope[pkg], ...Object.values(tagScope)].map((external) => external && rowAt(external.versions, tag, "share")).find((row) => row !== void 0);
|
|
2629
|
+
if (lead) {
|
|
2630
|
+
const serving = { remote: lead.remotes[0].name, tag };
|
|
2631
|
+
for (const external of Object.values(tagScope)) external.servingBuild = serving.remote;
|
|
2632
|
+
scopeFallbacks(Object.entries(tagScope), serving, sameTagOnly);
|
|
2633
|
+
}
|
|
2634
|
+
tagScopes.push(tagScope);
|
|
2599
2635
|
}
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2636
|
+
}
|
|
2637
|
+
return tagScopes;
|
|
2638
|
+
}
|
|
2639
|
+
function shareRows(external) {
|
|
2640
|
+
return external?.versions.filter((v) => v.action === "share") ?? [];
|
|
2641
|
+
}
|
|
2642
|
+
function buildsOf(rows, rootRows, consumers) {
|
|
2643
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
2644
|
+
for (const row of rows)
|
|
2645
|
+
for (const copy of row.remotes) {
|
|
2646
|
+
const key = `${row.tag}|${copy.name}`;
|
|
2647
|
+
if (copy.servedBy || candidates.has(key) || shipsTwoTags(consumers.get(copy.name))) continue;
|
|
2648
|
+
const basis = copy === row.remotes[0];
|
|
2649
|
+
candidates.set(key, {
|
|
2650
|
+
remote: copy.name,
|
|
2651
|
+
tag: row.tag,
|
|
2652
|
+
host: basis && row.host,
|
|
2653
|
+
rootBasis: basis && rootRows.includes(row)
|
|
2654
|
+
});
|
|
2609
2655
|
}
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2656
|
+
return [...candidates.values()];
|
|
2657
|
+
}
|
|
2658
|
+
function pooledBuild(externals, rows) {
|
|
2659
|
+
const winner = externals.find(([, e]) => e.poolWinner !== void 0)?.[1].poolWinner;
|
|
2660
|
+
const shipped = rows.flatMap(
|
|
2661
|
+
(row) => row.remotes.filter((copy) => !copy.servedBy).map((copy) => ({ remote: copy.name, tag: row.tag }))
|
|
2662
|
+
);
|
|
2663
|
+
const own = shipped.find((c) => c.remote === winner);
|
|
2664
|
+
if (own) return own;
|
|
2665
|
+
const width = ({ remote, tag }) => externals.reduce((n, [, e]) => {
|
|
2666
|
+
const copy = shareRows(e).find((row) => row.tag === tag)?.remotes.find((c) => c.name === remote);
|
|
2667
|
+
return n + Object.keys(copy?.entries ?? {}).length;
|
|
2668
|
+
}, 0);
|
|
2669
|
+
return shipped.map((c) => ({ c, width: width(c) })).sort((a, b) => b.width - a.width || compareStrings(a.c.remote, b.c.remote))[0]?.c;
|
|
2670
|
+
}
|
|
2671
|
+
function consumersOf(externals) {
|
|
2672
|
+
const consumers = /* @__PURE__ */ new Map();
|
|
2673
|
+
for (const [, external] of externals)
|
|
2674
|
+
for (const row of external.versions)
|
|
2675
|
+
for (const copy of row.remotes) {
|
|
2676
|
+
const placed = consumers.get(copy.name);
|
|
2677
|
+
if (placed) placed.push({ row, copy });
|
|
2678
|
+
else consumers.set(copy.name, [{ row, copy }]);
|
|
2630
2679
|
}
|
|
2631
|
-
|
|
2632
|
-
|
|
2680
|
+
return consumers;
|
|
2681
|
+
}
|
|
2682
|
+
function costTable(consumers, accepts) {
|
|
2683
|
+
const scanned = /* @__PURE__ */ new Map();
|
|
2684
|
+
const keyed = /* @__PURE__ */ new Map();
|
|
2685
|
+
const tollFor = (build, surface) => {
|
|
2686
|
+
let atTag = scanned.get(build.tag);
|
|
2687
|
+
if (!atTag) scanned.set(build.tag, atTag = []);
|
|
2688
|
+
const known = atTag.find((t) => sameSurface(t.surface, surface));
|
|
2689
|
+
if (known) return known.toll;
|
|
2690
|
+
if (atTag.length < SCANNED_SURFACES_PER_TAG) {
|
|
2691
|
+
const toll2 = tollOf(consumers, surface, build.tag, accepts);
|
|
2692
|
+
atTag.push({ surface, toll: toll2 });
|
|
2693
|
+
return toll2;
|
|
2694
|
+
}
|
|
2695
|
+
const key = [build.tag, ...[...surface].map(([s, tag]) => `${s}@${tag}`).sort()].join("\n");
|
|
2696
|
+
let toll = keyed.get(key);
|
|
2697
|
+
if (!toll) keyed.set(key, toll = tollOf(consumers, surface, build.tag, accepts));
|
|
2698
|
+
return toll;
|
|
2699
|
+
};
|
|
2700
|
+
return (build) => {
|
|
2701
|
+
const surface = surfaceOf(consumers, build);
|
|
2702
|
+
const toll = tollFor(build, surface);
|
|
2703
|
+
const others = (remotes) => remotes.size - Number(remotes.has(build.remote));
|
|
2633
2704
|
return {
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
...shareVersion,
|
|
2637
|
-
...byTag(
|
|
2638
|
-
clean.filter((e) => e.action === "skip"),
|
|
2639
|
-
"skip"
|
|
2640
|
-
),
|
|
2641
|
-
...byTag(scoped, "scope")
|
|
2642
|
-
].sort((a, b) => ports.versionCheck.compare(b.tag, a.tag))
|
|
2705
|
+
downloads: others(toll.downloads) + Number(!allCached(consumers.get(build.remote) ?? [])),
|
|
2706
|
+
fallbacks: others(toll.fallbacks)
|
|
2643
2707
|
};
|
|
2708
|
+
};
|
|
2709
|
+
}
|
|
2710
|
+
function tollOf(consumers, surface, tag, accepts) {
|
|
2711
|
+
const toll = { fallbacks: /* @__PURE__ */ new Set(), downloads: /* @__PURE__ */ new Set() };
|
|
2712
|
+
for (const [remote, placed] of consumers) {
|
|
2713
|
+
const fallback = fallsBack(placed, surface, tag, accepts);
|
|
2714
|
+
if (fallback) toll.fallbacks.add(remote);
|
|
2715
|
+
if (!allCached(placed) && (fallback || runsOffMap(placed, tag, accepts)))
|
|
2716
|
+
toll.downloads.add(remote);
|
|
2717
|
+
}
|
|
2718
|
+
return toll;
|
|
2719
|
+
}
|
|
2720
|
+
var allCached = (placed) => placed.every(({ copy }) => copy.cached);
|
|
2721
|
+
function fallbacksOf(externals, serving, accepts) {
|
|
2722
|
+
const consumers = consumersOf(externals);
|
|
2723
|
+
const surface = serving ? surfaceOf(consumers, serving) : /* @__PURE__ */ new Map();
|
|
2724
|
+
return [...consumers].filter(
|
|
2725
|
+
([remote, placed]) => remote !== serving?.remote && fallsBack(placed, surface, serving?.tag, accepts)
|
|
2726
|
+
).map(([remote]) => remote);
|
|
2727
|
+
}
|
|
2728
|
+
function scopeFallbacks(externals, serving, accepts) {
|
|
2729
|
+
const remotes = fallbacksOf(externals, serving, accepts);
|
|
2730
|
+
for (const [, external] of externals)
|
|
2731
|
+
external.versions = scopeRemotes(external.versions, remotes);
|
|
2732
|
+
}
|
|
2733
|
+
function strictObjectorOf(externals, serving, accepts) {
|
|
2734
|
+
const consumers = consumersOf(externals);
|
|
2735
|
+
const surface = surfaceOf(consumers, serving);
|
|
2736
|
+
for (const [name, external] of externals)
|
|
2737
|
+
for (const row of external.versions)
|
|
2738
|
+
for (const copy of row.remotes)
|
|
2739
|
+
if (copy.name !== serving.remote && rejectsServingTag({ row, copy }, surface, serving.tag, accepts) && !splitsPackage(consumers.get(copy.name), surface, serving.tag, accepts))
|
|
2740
|
+
return { external: name, copy, tag: row.tag };
|
|
2741
|
+
return void 0;
|
|
2742
|
+
}
|
|
2743
|
+
var SCANNED_SURFACES_PER_TAG = 8;
|
|
2744
|
+
function sameSurface(a, b) {
|
|
2745
|
+
if (a.size !== b.size) return false;
|
|
2746
|
+
for (const [specifier, tag] of a) if (b.get(specifier) !== tag) return false;
|
|
2747
|
+
return true;
|
|
2748
|
+
}
|
|
2749
|
+
function surfaceOf(consumers, serving) {
|
|
2750
|
+
const surface = /* @__PURE__ */ new Map();
|
|
2751
|
+
for (const p of consumers.get(serving.remote) ?? [])
|
|
2752
|
+
if (p.row.tag === serving.tag && onMap(p) || leadsShareRow(p)) {
|
|
2753
|
+
for (const s in p.copy.entries) if (!surface.has(s)) surface.set(s, p.row.tag);
|
|
2754
|
+
}
|
|
2755
|
+
return surface;
|
|
2756
|
+
}
|
|
2757
|
+
var leadsShareRow = ({ row, copy }) => row.action === "share" && row.remotes[0] === copy;
|
|
2758
|
+
var onMap = ({ row }) => row.action !== "scope";
|
|
2759
|
+
function splitsPackage(placed, surface, tag, accepts) {
|
|
2760
|
+
const uncovered = (p) => Object.keys(p.copy.entries).some((s) => {
|
|
2761
|
+
const servedAt = surface.get(s);
|
|
2762
|
+
return servedAt === void 0 || servedAt !== tag && rejectsTag(p, servedAt, accepts);
|
|
2763
|
+
});
|
|
2764
|
+
return placed.some(onMap) && (shipsTwoTags(placed) || placed.some((p) => !onMap(p) || uncovered(p)));
|
|
2765
|
+
}
|
|
2766
|
+
function loadSplitsPackage(copies, claims, accepts) {
|
|
2767
|
+
const root = claims.find(([specifier]) => specifier === packageOf(specifier))?.[1];
|
|
2768
|
+
const servingTag = root?.tag ?? claims[0][1].tag;
|
|
2769
|
+
const surface = new Map(
|
|
2770
|
+
claims.map(([specifier, { tag }]) => [specifier, root ? tag : servingTag])
|
|
2771
|
+
);
|
|
2772
|
+
const placed = copies.map(({ tag, copy }) => ({
|
|
2773
|
+
row: { tag, action: "share", host: false, remotes: [copy] },
|
|
2774
|
+
copy
|
|
2775
|
+
}));
|
|
2776
|
+
return splitsPackage(placed, surface, servingTag, accepts);
|
|
2777
|
+
}
|
|
2778
|
+
function fallsBack(placed, surface, tag, accepts) {
|
|
2779
|
+
return splitsPackage(placed, surface, tag, accepts) || tag !== void 0 && placed.some((p) => rejectsServingTag(p, surface, tag, accepts));
|
|
2780
|
+
}
|
|
2781
|
+
function rejectsServingTag(p, surface, tag, accepts) {
|
|
2782
|
+
return onMap(p) && rejectsTag(p, tag, accepts) && Object.keys(p.copy.entries).some((s) => surface.get(s) === tag);
|
|
2783
|
+
}
|
|
2784
|
+
var rejectsTag = ({ row, copy }, tag, accepts) => copy.strictVersion && !accepts(tag, row.tag, copy.requiredVersion);
|
|
2785
|
+
var shipsTwoTags = (placed) => !placed.some((p) => p.row.host && p.row.remotes[0] === p.copy) && placed.some((p) => p.row.tag !== placed[0].row.tag);
|
|
2786
|
+
function runsOffMap(placed, tag, accepts) {
|
|
2787
|
+
return placed.some((p) => !onMap(p) || rejectsTag(p, tag, accepts));
|
|
2788
|
+
}
|
|
2789
|
+
|
|
2790
|
+
// src/lib/core/2.app/steps/decide-serving-builds.ts
|
|
2791
|
+
function createDecideServingBuilds(config, ports) {
|
|
2792
|
+
return () => {
|
|
2793
|
+
const accepts = createAcceptsTag(ports.versionCheck.isCompatible, ports.versionCheck.compare);
|
|
2794
|
+
const repo = ports.sharedExternalsRepo;
|
|
2795
|
+
const written = new Set(repo.uncommittedScopes());
|
|
2796
|
+
const needsDeciding = (shareScope) => written.has(shareScope) || repo.isUndecided(shareScope);
|
|
2797
|
+
try {
|
|
2798
|
+
for (const shareScope of repo.getScopes()) {
|
|
2799
|
+
if (repo.scopeType(shareScope) === "strict" || !needsDeciding(shareScope)) continue;
|
|
2800
|
+
const sharedExternals = repo.getFromScope(shareScope);
|
|
2801
|
+
for (const [pkg, names] of packagesOf(sharedExternals)) {
|
|
2802
|
+
const externals = names.map((name) => [name, sharedExternals[name]]);
|
|
2803
|
+
decidePackage(shareScope, pkg, externals, accepts);
|
|
2804
|
+
}
|
|
2805
|
+
repo.markDecided(shareScope);
|
|
2806
|
+
}
|
|
2807
|
+
return Promise.resolve();
|
|
2808
|
+
} catch (e) {
|
|
2809
|
+
return Promise.reject(e);
|
|
2810
|
+
}
|
|
2811
|
+
};
|
|
2812
|
+
function decidePackage(shareScope, pkg, externals, accepts) {
|
|
2813
|
+
const serving = servingBuildOf(externals, accepts);
|
|
2814
|
+
const before = externals.map(([, external]) => shapeOf(external));
|
|
2815
|
+
const pooled = isPooled(externals);
|
|
2816
|
+
const toFollow = pooled ? void 0 : serving;
|
|
2817
|
+
if (!pooled) fallBack(pkg, externals, accepts, serving);
|
|
2818
|
+
externals.forEach(([name, external], i) => {
|
|
2819
|
+
const decided = withServingBuild(
|
|
2820
|
+
toFollow ? follow(pkg, name, external, toFollow, accepts) : external,
|
|
2821
|
+
serving?.remote
|
|
2822
|
+
);
|
|
2823
|
+
if (!sameShape(before[i], decided))
|
|
2824
|
+
ports.sharedExternalsRepo.addOrUpdate(name, decided, shareScope);
|
|
2825
|
+
});
|
|
2644
2826
|
}
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
const
|
|
2654
|
-
|
|
2827
|
+
function follow(pkg, name, external, serving, accepts) {
|
|
2828
|
+
const { external: followed, objector } = followServingBuild(external, serving, accepts);
|
|
2829
|
+
if (objector && config.strict.strictExternalCompatibility)
|
|
2830
|
+
rejectIncompatible(config, objector.copy, `${name}@${objector.tag}`, `${pkg}@${serving.tag}`);
|
|
2831
|
+
return followed;
|
|
2832
|
+
}
|
|
2833
|
+
function fallBack(pkg, externals, accepts, serving) {
|
|
2834
|
+
if (serving) {
|
|
2835
|
+
for (const [, external] of externals) shareServingCopies(external, serving);
|
|
2836
|
+
const objector = config.strict.strictExternalCompatibility && strictObjectorOf(externals, serving, accepts);
|
|
2837
|
+
if (objector)
|
|
2838
|
+
rejectIncompatible(
|
|
2839
|
+
config,
|
|
2840
|
+
objector.copy,
|
|
2841
|
+
`${objector.external}@${objector.tag}`,
|
|
2842
|
+
`${pkg}@${serving.tag}`
|
|
2843
|
+
);
|
|
2655
2844
|
}
|
|
2845
|
+
scopeFallbacks(externals, serving, accepts);
|
|
2656
2846
|
}
|
|
2657
2847
|
}
|
|
2848
|
+
function withServingBuild(external, servingBuild) {
|
|
2849
|
+
if (external.servingBuild === servingBuild) return external;
|
|
2850
|
+
const { servingBuild: _, ...rest } = external;
|
|
2851
|
+
return servingBuild ? { ...rest, servingBuild } : rest;
|
|
2852
|
+
}
|
|
2853
|
+
var shapeOf = (external) => ({
|
|
2854
|
+
servingBuild: external.servingBuild,
|
|
2855
|
+
rows: external.versions.map(
|
|
2856
|
+
({ tag, action, host, remotes }) => ({ tag, action, host, remotes: [...remotes] })
|
|
2857
|
+
)
|
|
2858
|
+
});
|
|
2859
|
+
var sameRow = (was, row) => Object.keys(was).every(
|
|
2860
|
+
(key) => key === "remotes" ? was.remotes.length === row.remotes.length && row.remotes.every((copy, j) => copy === was.remotes[j]) : was[key] === row[key]
|
|
2861
|
+
);
|
|
2862
|
+
var sameShape = (shape, external) => shape.servingBuild === external.servingBuild && shape.rows.length === external.versions.length && external.versions.every((row, i) => sameRow(shape.rows[i], row));
|
|
2658
2863
|
|
|
2659
|
-
// src/lib/core/
|
|
2660
|
-
function
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
spread++;
|
|
2673
|
-
}
|
|
2674
|
-
}
|
|
2675
|
-
if (spread > 0)
|
|
2676
|
-
config.log.debug(3, `[${scope}] ${spread} pool member(s) marked dirty for re-election.`);
|
|
2864
|
+
// src/lib/core/1.domain/externals/claims.ts
|
|
2865
|
+
function claimTable(externals, publishes) {
|
|
2866
|
+
const table = { claims: /* @__PURE__ */ new Map(), duplicates: /* @__PURE__ */ new Set(), shareClaims: /* @__PURE__ */ new Map() };
|
|
2867
|
+
const ordered = [...externals];
|
|
2868
|
+
const claim = (into, external, version, accepts = publishes) => forEachVersionEntry(version, accepts, (specifier, copy) => {
|
|
2869
|
+
if (!into.has(specifier)) into.set(specifier, { external, tag: version.tag, copy });
|
|
2870
|
+
});
|
|
2871
|
+
const seedServingBuild = (name, external) => {
|
|
2872
|
+
const isServing = (copy) => copy.name === external.servingBuild && (!publishes || publishes(copy));
|
|
2873
|
+
for (const version of external.versions) {
|
|
2874
|
+
if (version.action !== "share") continue;
|
|
2875
|
+
claim(table.shareClaims, name, version, isServing);
|
|
2876
|
+
claim(table.claims, name, version, isServing);
|
|
2677
2877
|
}
|
|
2678
|
-
return Promise.resolve();
|
|
2679
2878
|
};
|
|
2879
|
+
const claimShareRow = (name, external, version) => {
|
|
2880
|
+
const prior = table.claims.get(name);
|
|
2881
|
+
const duplicate = prior !== void 0 && prior.tag !== version.tag;
|
|
2882
|
+
if (duplicate && !(version.host && version.remotes[0].name === external.servingBuild))
|
|
2883
|
+
table.duplicates.add(version);
|
|
2884
|
+
if (external.servingBuild) return;
|
|
2885
|
+
claim(table.shareClaims, name, version);
|
|
2886
|
+
if (!duplicate && (!prior || prior.external === name)) claim(table.claims, name, version);
|
|
2887
|
+
};
|
|
2888
|
+
for (const [name, external] of ordered)
|
|
2889
|
+
if (external.servingBuild) seedServingBuild(name, external);
|
|
2890
|
+
for (const [name, external] of ordered)
|
|
2891
|
+
for (const version of external.versions)
|
|
2892
|
+
if (version.action === "share") claimShareRow(name, external, version);
|
|
2893
|
+
return table;
|
|
2894
|
+
}
|
|
2895
|
+
function committedClaims(externals, { shareScope, without }) {
|
|
2896
|
+
const publishes = (copy) => copy.name !== without && (shareScope !== GLOBAL_SCOPE || copy.cached);
|
|
2897
|
+
return claimTable(externals, publishes).claims;
|
|
2898
|
+
}
|
|
2899
|
+
var claimsByPackage = (claims) => groupByPackage(claims, ([specifier]) => specifier);
|
|
2900
|
+
function versionClaims(version, servingBuild) {
|
|
2901
|
+
const claims = /* @__PURE__ */ new Map();
|
|
2902
|
+
const claim = (specifier, copy) => {
|
|
2903
|
+
if (!claims.has(specifier)) claims.set(specifier, copy);
|
|
2904
|
+
};
|
|
2905
|
+
const accepts = servingBuild ? (copy) => copy.name === servingBuild : void 0;
|
|
2906
|
+
forEachVersionEntry(version, accepts, claim);
|
|
2907
|
+
return claims;
|
|
2680
2908
|
}
|
|
2681
2909
|
|
|
2682
|
-
// node_modules/.pnpm/@softarc+native-federation@4.
|
|
2910
|
+
// node_modules/.pnpm/@softarc+native-federation@4.8.0/node_modules/@softarc/native-federation/dist/lib/domain/core/build-notification-options.contract.js
|
|
2683
2911
|
var BuildNotificationType = /* @__PURE__ */ ((BuildNotificationType2) => {
|
|
2684
2912
|
BuildNotificationType2["COMPLETED"] = "federation-rebuild-complete";
|
|
2685
2913
|
BuildNotificationType2["ERROR"] = "federation-rebuild-error";
|
|
@@ -2687,7 +2915,7 @@ var BuildNotificationType = /* @__PURE__ */ ((BuildNotificationType2) => {
|
|
|
2687
2915
|
return BuildNotificationType2;
|
|
2688
2916
|
})(BuildNotificationType || {});
|
|
2689
2917
|
|
|
2690
|
-
// node_modules/.pnpm/@softarc+native-federation@4.
|
|
2918
|
+
// node_modules/.pnpm/@softarc+native-federation@4.8.0/node_modules/@softarc/native-federation/dist/lib/domain/core/chunk.js
|
|
2691
2919
|
var CHUNK_PREFIX = "@nf-internal";
|
|
2692
2920
|
function toChunkImport(fileName) {
|
|
2693
2921
|
if (fileName.startsWith("./")) {
|
|
@@ -2704,8 +2932,8 @@ function createGenerateImportMap(config, ports) {
|
|
|
2704
2932
|
const chunkBundles = {};
|
|
2705
2933
|
try {
|
|
2706
2934
|
addScopedExternals(importMap, chunkBundles);
|
|
2707
|
-
|
|
2708
|
-
|
|
2935
|
+
addNamedShareScopes(importMap, chunkBundles);
|
|
2936
|
+
addGlobalShareScope(importMap, chunkBundles);
|
|
2709
2937
|
addRemoteInfos(importMap, chunkBundles);
|
|
2710
2938
|
addChunkImports(importMap, chunkBundles);
|
|
2711
2939
|
return Promise.resolve(importMap);
|
|
@@ -2739,47 +2967,61 @@ function createGenerateImportMap(config, ports) {
|
|
|
2739
2967
|
}
|
|
2740
2968
|
return modules;
|
|
2741
2969
|
}
|
|
2742
|
-
function
|
|
2970
|
+
function addNamedShareScopes(importMap, chunkBundles) {
|
|
2743
2971
|
const shareScopes = ports.sharedExternalsRepo.getScopes({ includeGlobal: false });
|
|
2744
2972
|
for (const shareScope of shareScopes) {
|
|
2745
|
-
|
|
2973
|
+
const sharedExternals = ports.sharedExternalsRepo.getFromScope(shareScope);
|
|
2974
|
+
const cachedBefore = /* @__PURE__ */ new Map();
|
|
2975
|
+
for (const [externalName, external] of Object.entries(sharedExternals))
|
|
2976
|
+
cachedBefore.set(externalName, cachedFingerprint(external));
|
|
2977
|
+
const strict = ports.sharedExternalsRepo.scopeType(shareScope) === "strict";
|
|
2978
|
+
for (const served of servedScopes(sharedExternals, strict))
|
|
2979
|
+
addShareScope(importMap, shareScope, served, chunkBundles);
|
|
2980
|
+
for (const [externalName, external] of Object.entries(sharedExternals)) {
|
|
2981
|
+
if (cachedFingerprint(external) !== cachedBefore.get(externalName)) {
|
|
2982
|
+
ports.sharedExternalsRepo.addOrUpdate(externalName, external, shareScope);
|
|
2983
|
+
}
|
|
2984
|
+
}
|
|
2746
2985
|
}
|
|
2747
2986
|
return importMap;
|
|
2748
2987
|
}
|
|
2749
|
-
function
|
|
2750
|
-
const sharedExternals = ports.sharedExternalsRepo.getFromScope(shareScope);
|
|
2988
|
+
function addShareScope(importMap, shareScope, sharedExternals, chunkBundles) {
|
|
2751
2989
|
const index = buildServedIndex(sharedExternals);
|
|
2990
|
+
const claims = shareRowMappings(sharedExternals, shareScope);
|
|
2991
|
+
const claimedElsewhere = (externalName, specifier) => {
|
|
2992
|
+
const claim = claims.get(specifier);
|
|
2993
|
+
return claim?.external === externalName ? void 0 : claim;
|
|
2994
|
+
};
|
|
2752
2995
|
for (const [externalName, external] of Object.entries(sharedExternals)) {
|
|
2753
2996
|
let override = void 0;
|
|
2754
|
-
const cachedBefore = cachedFingerprint(external);
|
|
2755
2997
|
for (const version of external.versions) {
|
|
2756
2998
|
if (version.action === "scope") {
|
|
2757
|
-
|
|
2758
|
-
const remoteScope = getScope2(shareScope, remote.name, externalName);
|
|
2759
|
-
for (const [packageName, file] of Object.entries(remote.entries)) {
|
|
2760
|
-
const url = join(remoteScope, file);
|
|
2761
|
-
addToScope(importMap, remoteScope, { [packageName]: url });
|
|
2762
|
-
addIntegrity(importMap, url, remote.name, file);
|
|
2763
|
-
}
|
|
2764
|
-
registerBundleChunks(chunkBundles, remote.name, remote.bundle);
|
|
2765
|
-
remote.cached = true;
|
|
2766
|
-
}
|
|
2999
|
+
addScopeRow(importMap, chunkBundles, shareScope, externalName, version);
|
|
2767
3000
|
continue;
|
|
2768
3001
|
}
|
|
2769
|
-
version.remotes[0].cached = true;
|
|
2770
3002
|
let serving = version;
|
|
2771
3003
|
if (version.action === "skip") {
|
|
2772
3004
|
if (!override) {
|
|
2773
|
-
override = findOverride(
|
|
3005
|
+
override = findOverride(
|
|
3006
|
+
external,
|
|
3007
|
+
shareScope,
|
|
3008
|
+
externalName,
|
|
3009
|
+
(s) => Boolean(claimedElsewhere(externalName, s))
|
|
3010
|
+
) ?? "NOT_AVAILABLE";
|
|
2774
3011
|
}
|
|
2775
3012
|
if (override !== "NOT_AVAILABLE") {
|
|
2776
3013
|
serving = override;
|
|
2777
3014
|
version.remotes[0].cached = false;
|
|
2778
3015
|
}
|
|
2779
3016
|
}
|
|
2780
|
-
const provided =
|
|
3017
|
+
const provided = versionClaims(serving, external.servingBuild);
|
|
2781
3018
|
const mappings = [];
|
|
2782
3019
|
for (const [packageName, provider] of provided) {
|
|
3020
|
+
const claim = claimedElsewhere(externalName, packageName);
|
|
3021
|
+
if (claim) {
|
|
3022
|
+
mappings.push({ packageName, ...claim });
|
|
3023
|
+
continue;
|
|
3024
|
+
}
|
|
2783
3025
|
const file = provider.entries[packageName];
|
|
2784
3026
|
mappings.push({
|
|
2785
3027
|
packageName,
|
|
@@ -2792,56 +3034,60 @@ function createGenerateImportMap(config, ports) {
|
|
|
2792
3034
|
registerBundleChunks(chunkBundles, provider.name, provider.bundle);
|
|
2793
3035
|
}
|
|
2794
3036
|
}
|
|
2795
|
-
version.remotes.forEach((
|
|
2796
|
-
const
|
|
2797
|
-
if (index &&
|
|
2798
|
-
const files = index.get(
|
|
2799
|
-
const servedScope = getScope2(shareScope,
|
|
2800
|
-
for (const specifier of Object.keys(
|
|
3037
|
+
version.remotes.forEach((consumer) => {
|
|
3038
|
+
const consumerScope = getScope2(shareScope, consumer.name, externalName);
|
|
3039
|
+
if (index && consumer.servedBy) {
|
|
3040
|
+
const files = index.get(consumer.servedBy);
|
|
3041
|
+
const servedScope = getScope2(shareScope, consumer.servedBy, externalName);
|
|
3042
|
+
for (const specifier of Object.keys(consumer.entries)) {
|
|
2801
3043
|
const source = files?.get(specifier);
|
|
2802
3044
|
if (!source) continue;
|
|
2803
3045
|
const url = join(servedScope, source.file);
|
|
2804
|
-
addToScope(importMap,
|
|
2805
|
-
addIntegrity(importMap, url,
|
|
2806
|
-
registerBundleChunks(chunkBundles,
|
|
3046
|
+
addToScope(importMap, consumerScope, { [specifier]: url });
|
|
3047
|
+
addIntegrity(importMap, url, consumer.servedBy, source.file);
|
|
3048
|
+
registerBundleChunks(chunkBundles, consumer.servedBy, source.bundle);
|
|
2807
3049
|
source.meta.cached = true;
|
|
2808
3050
|
}
|
|
2809
3051
|
return;
|
|
2810
3052
|
}
|
|
2811
3053
|
for (const m of mappings) {
|
|
2812
|
-
addToScope(importMap,
|
|
3054
|
+
addToScope(importMap, consumerScope, { [m.packageName]: m.url });
|
|
2813
3055
|
}
|
|
2814
|
-
for (const
|
|
3056
|
+
for (const packageName of Object.keys(consumer.entries)) {
|
|
2815
3057
|
if (provided.has(packageName)) continue;
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
continue;
|
|
2819
|
-
}
|
|
2820
|
-
const url = join(rScope, file);
|
|
2821
|
-
addToScope(importMap, rScope, { [packageName]: url });
|
|
2822
|
-
addIntegrity(importMap, url, r.name, file);
|
|
2823
|
-
r.cached = true;
|
|
3058
|
+
const claim = claimedElsewhere(externalName, packageName);
|
|
3059
|
+
if (claim) addToScope(importMap, consumerScope, { [packageName]: claim.url });
|
|
2824
3060
|
}
|
|
2825
3061
|
});
|
|
2826
3062
|
for (const m of mappings) {
|
|
2827
3063
|
addIntegrity(importMap, m.url, m.name, m.file);
|
|
2828
3064
|
}
|
|
2829
3065
|
}
|
|
2830
|
-
|
|
2831
|
-
|
|
3066
|
+
}
|
|
3067
|
+
}
|
|
3068
|
+
function addScopeRow(importMap, chunkBundles, shareScope, externalName, version) {
|
|
3069
|
+
for (const remote of version.remotes) {
|
|
3070
|
+
const remoteScope = getScope2(shareScope, remote.name, externalName);
|
|
3071
|
+
for (const [packageName, file] of Object.entries(remote.entries)) {
|
|
3072
|
+
const url = join(remoteScope, file);
|
|
3073
|
+
addToScope(importMap, remoteScope, { [packageName]: url });
|
|
3074
|
+
addIntegrity(importMap, url, remote.name, file);
|
|
2832
3075
|
}
|
|
3076
|
+
registerBundleChunks(chunkBundles, remote.name, remote.bundle);
|
|
3077
|
+
remote.cached = true;
|
|
2833
3078
|
}
|
|
2834
3079
|
}
|
|
2835
3080
|
function cachedFingerprint(external) {
|
|
2836
3081
|
return external.versions.map((v) => v.remotes.map((r) => r.cached ? 1 : 0).join("")).join("|");
|
|
2837
3082
|
}
|
|
2838
|
-
function findOverride(external, shareScope, externalName) {
|
|
3083
|
+
function findOverride(external, shareScope, externalName, servedElsewhere) {
|
|
2839
3084
|
const sharedVersions = external.versions.filter((v) => v.action === "share");
|
|
2840
3085
|
const scopedExternalName = `${shareScope}.${externalName}`;
|
|
2841
3086
|
if (sharedVersions.length > 1) {
|
|
2842
3087
|
handleMultipleSharedVersions(scopedExternalName);
|
|
2843
3088
|
}
|
|
2844
|
-
|
|
3089
|
+
const servedByClaims = () => external.versions.filter((v) => v.action === "skip").every((v) => shipsOnly(v, servedElsewhere));
|
|
3090
|
+
if (sharedVersions.length < 1 && !servedByClaims()) {
|
|
2845
3091
|
if (config.strict.strictImportMap) {
|
|
2846
3092
|
config.log.error(4, `[${shareScope}][${externalName}] shareScope has no override version.`);
|
|
2847
3093
|
throw new NFError("Could not create ImportMap.");
|
|
@@ -2886,17 +3132,30 @@ function createGenerateImportMap(config, ports) {
|
|
|
2886
3132
|
}
|
|
2887
3133
|
return index;
|
|
2888
3134
|
}
|
|
2889
|
-
function
|
|
3135
|
+
function shareRowMappings(externals, shareScope) {
|
|
3136
|
+
const mappings = /* @__PURE__ */ new Map();
|
|
3137
|
+
for (const [specifier, { external, copy }] of claimTable(Object.entries(externals)).shareClaims) {
|
|
3138
|
+
const file = copy.entries[specifier];
|
|
3139
|
+
mappings.set(specifier, {
|
|
3140
|
+
url: join(getScope2(shareScope, copy.name, external), file),
|
|
3141
|
+
name: copy.name,
|
|
3142
|
+
file,
|
|
3143
|
+
external
|
|
3144
|
+
});
|
|
3145
|
+
}
|
|
3146
|
+
return mappings;
|
|
3147
|
+
}
|
|
3148
|
+
function collectServed(into, index, shareScope, externalName, version) {
|
|
2890
3149
|
for (const consumer of version.remotes) {
|
|
2891
3150
|
if (!consumer.servedBy) continue;
|
|
2892
3151
|
const files = index.get(consumer.servedBy);
|
|
2893
|
-
const scope = getScope2(
|
|
3152
|
+
const scope = getScope2(shareScope, consumer.name, externalName);
|
|
2894
3153
|
for (const specifier of Object.keys(consumer.entries)) {
|
|
2895
3154
|
const source = files?.get(specifier);
|
|
2896
3155
|
if (!source) {
|
|
2897
3156
|
config.log.warn(
|
|
2898
3157
|
4,
|
|
2899
|
-
`[${
|
|
3158
|
+
`[${shareScope}][${externalName}][${consumer.name}] '${consumer.servedBy}' does not serve '${specifier}'.`
|
|
2900
3159
|
);
|
|
2901
3160
|
continue;
|
|
2902
3161
|
}
|
|
@@ -2914,9 +3173,11 @@ function createGenerateImportMap(config, ports) {
|
|
|
2914
3173
|
source.meta.cached = true;
|
|
2915
3174
|
}
|
|
2916
3175
|
}
|
|
2917
|
-
function
|
|
3176
|
+
function addGlobalShareScope(importMap, chunkBundles) {
|
|
2918
3177
|
const sharedExternals = ports.sharedExternalsRepo.getFromScope();
|
|
2919
3178
|
const index = buildServedIndex(sharedExternals);
|
|
3179
|
+
const { claims, duplicates } = claimTable(Object.entries(sharedExternals));
|
|
3180
|
+
const claimed = claimsByCopy(claims);
|
|
2920
3181
|
const served = [];
|
|
2921
3182
|
const cachedBefore = /* @__PURE__ */ new Map();
|
|
2922
3183
|
for (const [externalName, external] of Object.entries(sharedExternals)) {
|
|
@@ -2927,27 +3188,14 @@ function createGenerateImportMap(config, ports) {
|
|
|
2927
3188
|
}
|
|
2928
3189
|
if (version.action === "skip") continue;
|
|
2929
3190
|
if (version.action === "scope") {
|
|
2930
|
-
|
|
2931
|
-
const remoteScope = getScope2(GLOBAL_SCOPE, remote.name, externalName);
|
|
2932
|
-
for (const [packageName, file] of Object.entries(remote.entries)) {
|
|
2933
|
-
const url = join(remoteScope, file);
|
|
2934
|
-
addToScope(importMap, remoteScope, { [packageName]: url });
|
|
2935
|
-
addIntegrity(importMap, url, remote.name, file);
|
|
2936
|
-
}
|
|
2937
|
-
remote.cached = true;
|
|
2938
|
-
registerBundleChunks(chunkBundles, remote.name, remote.bundle);
|
|
2939
|
-
}
|
|
3191
|
+
addScopeRow(importMap, chunkBundles, GLOBAL_SCOPE, externalName, version);
|
|
2940
3192
|
continue;
|
|
2941
3193
|
}
|
|
2942
|
-
if (
|
|
3194
|
+
if (duplicates.has(version)) {
|
|
2943
3195
|
notifyDuplicateGlobalExternal(externalName);
|
|
2944
3196
|
continue;
|
|
2945
3197
|
}
|
|
2946
|
-
|
|
2947
|
-
}
|
|
2948
|
-
for (const version of external.versions) {
|
|
2949
|
-
if (version.action !== "skip") continue;
|
|
2950
|
-
selfFillUncovered(importMap, chunkBundles, externalName, version.remotes);
|
|
3198
|
+
publishClaims(importMap, chunkBundles, externalName, version, claimed);
|
|
2951
3199
|
}
|
|
2952
3200
|
}
|
|
2953
3201
|
flushServed(importMap, chunkBundles, served);
|
|
@@ -2958,54 +3206,30 @@ function createGenerateImportMap(config, ports) {
|
|
|
2958
3206
|
}
|
|
2959
3207
|
return importMap;
|
|
2960
3208
|
}
|
|
2961
|
-
function
|
|
2962
|
-
const
|
|
2963
|
-
for (const [
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
`[${GLOBAL_SCOPE}][${externalName}][${remote.name}] Entrypoint '${packageName}' is already mapped by another external, keeping '${importMap.imports[packageName]}'.`
|
|
2968
|
-
);
|
|
2969
|
-
continue;
|
|
2970
|
-
}
|
|
2971
|
-
let scope = scopes.get(remote.name);
|
|
2972
|
-
if (scope === void 0) {
|
|
2973
|
-
scopes.set(remote.name, scope = getScope2(GLOBAL_SCOPE, remote.name, externalName));
|
|
2974
|
-
registerBundleChunks(chunkBundles, remote.name, remote.bundle);
|
|
2975
|
-
remote.cached = true;
|
|
2976
|
-
}
|
|
2977
|
-
const file = remote.entries[packageName];
|
|
2978
|
-
const url = join(scope, file);
|
|
2979
|
-
addToGlobal(importMap, { [packageName]: url });
|
|
2980
|
-
addIntegrity(importMap, url, remote.name, file);
|
|
3209
|
+
function claimsByCopy(claims) {
|
|
3210
|
+
const claimed = /* @__PURE__ */ new Map();
|
|
3211
|
+
for (const [specifier, { copy }] of claims) {
|
|
3212
|
+
const specifiers = claimed.get(copy);
|
|
3213
|
+
if (specifiers) specifiers.push(specifier);
|
|
3214
|
+
else claimed.set(copy, [specifier]);
|
|
2981
3215
|
}
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
const
|
|
3216
|
+
return claimed;
|
|
3217
|
+
}
|
|
3218
|
+
function publishClaims(importMap, chunkBundles, externalName, version, claimed) {
|
|
3219
|
+
for (const copy of version.remotes) {
|
|
3220
|
+
const specifiers = claimed.get(copy);
|
|
3221
|
+
if (!specifiers) continue;
|
|
3222
|
+
const scope = getScope2(GLOBAL_SCOPE, copy.name, externalName);
|
|
3223
|
+
registerBundleChunks(chunkBundles, copy.name, copy.bundle);
|
|
3224
|
+
copy.cached = true;
|
|
3225
|
+
for (const specifier of specifiers) {
|
|
3226
|
+
const file = copy.entries[specifier];
|
|
2993
3227
|
const url = join(scope, file);
|
|
2994
|
-
addToGlobal(importMap, { [
|
|
2995
|
-
addIntegrity(importMap, url,
|
|
2996
|
-
registerBundleChunks(chunkBundles, remote.name, remote.bundle);
|
|
2997
|
-
remote.cached = true;
|
|
3228
|
+
addToGlobal(importMap, { [specifier]: url });
|
|
3229
|
+
addIntegrity(importMap, url, copy.name, file);
|
|
2998
3230
|
}
|
|
2999
3231
|
}
|
|
3000
3232
|
}
|
|
3001
|
-
function warnUncoveredEntrypoint(scope, externalName, remoteName, packageName) {
|
|
3002
|
-
const msg = `[${scope}][${externalName}][${remoteName}] Entrypoint '${packageName}' is not covered by the shared version.`;
|
|
3003
|
-
if (config.strict.strictEntryPointCoverage || config.strict.strictImportMap) {
|
|
3004
|
-
config.log.error(4, msg);
|
|
3005
|
-
throw new NFError("Could not create ImportMap.");
|
|
3006
|
-
}
|
|
3007
|
-
config.log.warn(4, msg);
|
|
3008
|
-
}
|
|
3009
3233
|
function notifyDuplicateGlobalExternal(externalName) {
|
|
3010
3234
|
if (config.strict.strictImportMap) {
|
|
3011
3235
|
config.log.error(4, `[${externalName}] Shared external has multiple shared versions.`);
|
|
@@ -3079,15 +3303,30 @@ function createGenerateImportMap(config, ports) {
|
|
|
3079
3303
|
});
|
|
3080
3304
|
}
|
|
3081
3305
|
}
|
|
3306
|
+
function shipsOnly(version, served) {
|
|
3307
|
+
let only = true;
|
|
3308
|
+
forEachVersionEntry(version, void 0, (specifier) => {
|
|
3309
|
+
only &&= served(specifier);
|
|
3310
|
+
});
|
|
3311
|
+
return only;
|
|
3312
|
+
}
|
|
3082
3313
|
|
|
3083
3314
|
// src/lib/core/2.app/steps/commit-changes.ts
|
|
3084
3315
|
function createCommitChanges(config, ports) {
|
|
3085
|
-
return (importMap,
|
|
3316
|
+
return (importMap, { markUndecided = false, ...browserOpts } = {}) => Promise.resolve(importMap).then((map) => addToBrowser(map, browserOpts)).then(() => {
|
|
3317
|
+
if (markUndecided) markUndecidedScopes();
|
|
3318
|
+
persistRepositoryChanges();
|
|
3319
|
+
});
|
|
3086
3320
|
function addToBrowser(importMap, opts) {
|
|
3087
3321
|
ports.browser.setImportMapFn(importMap, opts);
|
|
3088
3322
|
config.log.debug(5, "Added import map to browser.", importMap);
|
|
3089
3323
|
return importMap;
|
|
3090
3324
|
}
|
|
3325
|
+
function markUndecidedScopes() {
|
|
3326
|
+
const repo = ports.sharedExternalsRepo;
|
|
3327
|
+
for (const shareScope of repo.uncommittedScopes())
|
|
3328
|
+
if (repo.scopeType(shareScope) !== "strict") repo.markUndecided(shareScope);
|
|
3329
|
+
}
|
|
3091
3330
|
function persistRepositoryChanges() {
|
|
3092
3331
|
ports.remoteInfoRepo.commit();
|
|
3093
3332
|
ports.scopedExternalsRepo.commit();
|
|
@@ -3097,6 +3336,29 @@ function createCommitChanges(config, ports) {
|
|
|
3097
3336
|
}
|
|
3098
3337
|
}
|
|
3099
3338
|
|
|
3339
|
+
// src/lib/core/2.app/steps/rollback-changes.ts
|
|
3340
|
+
var createStateDump = (config, ports) => (msg) => config.log.debug(0, msg, {
|
|
3341
|
+
remotes: { ...ports.remoteInfoRepo.getAll() },
|
|
3342
|
+
"shared-externals": ports.sharedExternalsRepo.getScopes({ includeGlobal: true }).reduce(
|
|
3343
|
+
(acc, scope) => ({ ...acc, [scope]: ports.sharedExternalsRepo.getFromScope(scope) }),
|
|
3344
|
+
{}
|
|
3345
|
+
),
|
|
3346
|
+
"scoped-externals": ports.scopedExternalsRepo.getAll()
|
|
3347
|
+
});
|
|
3348
|
+
function createRollbackChanges(config, ports) {
|
|
3349
|
+
const stateDump = createStateDump(config, ports);
|
|
3350
|
+
return (label) => Promise.resolve().then(() => {
|
|
3351
|
+
try {
|
|
3352
|
+
stateDump(`${label} STATE DUMP`);
|
|
3353
|
+
} finally {
|
|
3354
|
+
ports.remoteInfoRepo.rollback();
|
|
3355
|
+
ports.scopedExternalsRepo.rollback();
|
|
3356
|
+
ports.sharedExternalsRepo.rollback();
|
|
3357
|
+
ports.sharedChunksRepo.rollback();
|
|
3358
|
+
}
|
|
3359
|
+
});
|
|
3360
|
+
}
|
|
3361
|
+
|
|
3100
3362
|
// src/lib/core/2.app/steps/expose-module-loader.ts
|
|
3101
3363
|
function createExposeModuleLoader(config, ports) {
|
|
3102
3364
|
const loadRemoteModule = (remoteName, exposedModule) => {
|
|
@@ -3171,10 +3433,16 @@ var normalizeRemoteRef = (remote) => {
|
|
|
3171
3433
|
function createGetRemoteEntry(config, ports) {
|
|
3172
3434
|
return async (remoteEntryUrl, remote) => {
|
|
3173
3435
|
const { name: remoteName, integrity } = normalizeRemoteRef(remote);
|
|
3174
|
-
|
|
3175
|
-
|
|
3436
|
+
const knownAtUrl = findCachedRemoteAt(remoteEntryUrl);
|
|
3437
|
+
if (knownAtUrl) {
|
|
3438
|
+
config.log.debug(
|
|
3439
|
+
7,
|
|
3440
|
+
`Found remote '${knownAtUrl}' at '${remoteEntryUrl}' in storage, omitting fetch.`
|
|
3441
|
+
);
|
|
3176
3442
|
return Optional.empty();
|
|
3177
3443
|
}
|
|
3444
|
+
if (!!remoteName && ports.remoteInfoRepo.contains(remoteName))
|
|
3445
|
+
return warnInitialized(remoteName, remoteEntryUrl);
|
|
3178
3446
|
try {
|
|
3179
3447
|
const remoteEntry = integrity ? await ports.remoteEntryProvider.provide(remoteEntryUrl, { integrity }) : await ports.remoteEntryProvider.provide(remoteEntryUrl);
|
|
3180
3448
|
config.log.debug(
|
|
@@ -3189,10 +3457,8 @@ function createGetRemoteEntry(config, ports) {
|
|
|
3189
3457
|
}
|
|
3190
3458
|
config.log.warn(7, errorMsg + " Omitting expected name.");
|
|
3191
3459
|
}
|
|
3192
|
-
if (ports.remoteInfoRepo.contains(remoteEntry.name))
|
|
3193
|
-
remoteEntry.
|
|
3194
|
-
config.log.debug(7, `Overriding existing remote '${remoteName}' with '${remoteEntryUrl}'.`);
|
|
3195
|
-
}
|
|
3460
|
+
if (ports.remoteInfoRepo.contains(remoteEntry.name))
|
|
3461
|
+
return warnInitialized(remoteEntry.name, remoteEntryUrl);
|
|
3196
3462
|
return Optional.of(checkForSSE(remoteEntry));
|
|
3197
3463
|
} catch (error) {
|
|
3198
3464
|
config.log.error(
|
|
@@ -3205,10 +3471,18 @@ function createGetRemoteEntry(config, ports) {
|
|
|
3205
3471
|
);
|
|
3206
3472
|
}
|
|
3207
3473
|
};
|
|
3208
|
-
function
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3474
|
+
function warnInitialized(name, remoteEntryUrl) {
|
|
3475
|
+
const initializedFrom = ports.remoteInfoRepo.tryGet(name).map((info) => join(info.scopeUrl, "remoteEntry.json")).get();
|
|
3476
|
+
config.log.warn(
|
|
3477
|
+
7,
|
|
3478
|
+
`[${name}] Already initialized from '${initializedFrom}', ignoring '${remoteEntryUrl}'.`
|
|
3479
|
+
);
|
|
3480
|
+
return Optional.empty();
|
|
3481
|
+
}
|
|
3482
|
+
function findCachedRemoteAt(remoteEntryUrl) {
|
|
3483
|
+
return Object.entries(ports.remoteInfoRepo.getAll()).find(
|
|
3484
|
+
([, info]) => join(info.scopeUrl, "remoteEntry.json") === remoteEntryUrl
|
|
3485
|
+
)?.[0];
|
|
3212
3486
|
}
|
|
3213
3487
|
function checkForSSE(entry) {
|
|
3214
3488
|
if (config.sse) {
|
|
@@ -3228,92 +3502,170 @@ function createGetRemoteEntry(config, ports) {
|
|
|
3228
3502
|
// src/lib/core/2.app/steps/update-cache.ts
|
|
3229
3503
|
function createUpdateCache(config, ports) {
|
|
3230
3504
|
const storeRemoteEntry = createStoreRemoteEntry(config, ports, 8);
|
|
3231
|
-
const
|
|
3505
|
+
const accepts = createAcceptsTag(
|
|
3506
|
+
(tag, range) => ports.versionCheck.isCompatible(tag, range),
|
|
3507
|
+
(a, b) => ports.versionCheck.compare(a, b)
|
|
3508
|
+
);
|
|
3232
3509
|
return (remoteEntry) => {
|
|
3233
3510
|
try {
|
|
3511
|
+
const pending = [];
|
|
3512
|
+
storeRemoteEntry(remoteEntry, (_, external, ctx) => pending.push({ external, ctx }));
|
|
3513
|
+
const decisions = decidePackages(remoteEntry, pending);
|
|
3234
3514
|
const actions = {};
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
const { action, provided, sameVersion } = resolveSharedExternal(entry, external, ctx);
|
|
3238
|
-
actions[external.packageName] = { action };
|
|
3239
|
-
if (action === "skip" && provided) {
|
|
3240
|
-
actions[external.packageName].covered = Array.from(provided.keys());
|
|
3241
|
-
if (sameVersion) actions[external.packageName].sameVersion = true;
|
|
3242
|
-
if (external.shareScope) {
|
|
3243
|
-
actions[external.packageName].override = resolveOverrideEntries(
|
|
3244
|
-
entry,
|
|
3245
|
-
external,
|
|
3246
|
-
provided
|
|
3247
|
-
);
|
|
3248
|
-
}
|
|
3249
|
-
}
|
|
3250
|
-
});
|
|
3515
|
+
for (const item of pending)
|
|
3516
|
+
actions[item.external.packageName] = applyDecision(remoteEntry, item, decisions.get(item));
|
|
3251
3517
|
return Promise.resolve({ entry: remoteEntry, actions });
|
|
3252
3518
|
} catch (error) {
|
|
3253
3519
|
return Promise.reject(error);
|
|
3254
3520
|
}
|
|
3255
3521
|
};
|
|
3256
|
-
function
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
commit
|
|
3263
|
-
}) {
|
|
3264
|
-
let action = scopeType === "strict" ? "share" : "skip";
|
|
3265
|
-
const sharedVersion = cached.versions.find((c) => c.action === "share");
|
|
3266
|
-
const isCompatible = !sharedVersion || ports.versionCheck.isCompatible(sharedVersion.tag, remote.requiredVersion);
|
|
3267
|
-
if (action === "skip" && !isCompatible && remote.strictVersion) {
|
|
3268
|
-
action = "scope";
|
|
3269
|
-
const errorMsg = `[${sharedInfo.shareScope ?? GLOBAL_SCOPE}][${remoteEntry.name}] ${sharedInfo.packageName}@${sharedInfo.version} Is not compatible with existing ${sharedInfo.packageName}@${sharedVersion.tag} requiredRange '${sharedVersion.remotes[0]?.requiredVersion}'`;
|
|
3270
|
-
if (config.strict.strictExternalCompatibility) {
|
|
3271
|
-
config.log.error(8, errorMsg);
|
|
3272
|
-
throw new NFError(`Could not process remote '${remoteEntry.name}'`);
|
|
3273
|
-
}
|
|
3274
|
-
config.log.warn(8, errorMsg);
|
|
3522
|
+
function decidePackages(remoteEntry, pending) {
|
|
3523
|
+
const decisions = /* @__PURE__ */ new Map();
|
|
3524
|
+
const viewOf = loadViewOf(remoteEntry, pending);
|
|
3525
|
+
for (const group of pendingPerPackage(pending)) {
|
|
3526
|
+
const decision = group[0].ctx.scopeType === "strict" ? { action: "share" } : decidePackage(remoteEntry, group, viewOf(group[0].external.shareScope));
|
|
3527
|
+
for (const item of group) decisions.set(item, decision);
|
|
3275
3528
|
}
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3529
|
+
scopeOpenedPackages(decisions);
|
|
3530
|
+
return decisions;
|
|
3531
|
+
}
|
|
3532
|
+
function pendingPerPackage(pending) {
|
|
3533
|
+
const packages = /* @__PURE__ */ new Map();
|
|
3534
|
+
for (const item of pending) {
|
|
3535
|
+
const { shareScope, packageName } = item.external;
|
|
3536
|
+
const key = `${shareScope ?? GLOBAL_SCOPE}\0${packageOf(packageName)}`;
|
|
3537
|
+
const group = packages.get(key);
|
|
3538
|
+
if (group) group.push(item);
|
|
3539
|
+
else packages.set(key, [item]);
|
|
3540
|
+
}
|
|
3541
|
+
return [...packages.values()];
|
|
3542
|
+
}
|
|
3543
|
+
function loadViewOf(remoteEntry, pending) {
|
|
3544
|
+
const views = /* @__PURE__ */ new Map();
|
|
3545
|
+
return (shareScope) => {
|
|
3546
|
+
const scope = shareScope ?? GLOBAL_SCOPE;
|
|
3547
|
+
let view = views.get(scope);
|
|
3548
|
+
if (!view) {
|
|
3549
|
+
const record = ports.sharedExternalsRepo.getFromScope(shareScope);
|
|
3550
|
+
const claims = committedClaims(Object.entries(record), {
|
|
3551
|
+
shareScope: scope,
|
|
3552
|
+
without: remoteEntry.name
|
|
3553
|
+
});
|
|
3554
|
+
const claimsIn = claimsByPackage(claims);
|
|
3555
|
+
let pooled;
|
|
3556
|
+
view = {
|
|
3557
|
+
claims,
|
|
3558
|
+
claimsOf: (pkg) => claimsIn.get(pkg) ?? [],
|
|
3559
|
+
inPool: (pkg) => (pooled ??= pooledPackagesWith(record, copiesIn(pending, scope))).has(pkg)
|
|
3560
|
+
};
|
|
3561
|
+
views.set(scope, view);
|
|
3290
3562
|
}
|
|
3563
|
+
return view;
|
|
3564
|
+
};
|
|
3565
|
+
}
|
|
3566
|
+
function copiesIn(pending, scope) {
|
|
3567
|
+
return pending.filter(({ external }) => (external.shareScope ?? GLOBAL_SCOPE) === scope).map(({ external, ctx }) => ({ name: external.packageName, pool: ctx.remote.pool }));
|
|
3568
|
+
}
|
|
3569
|
+
function scopeOpenedPackages(decisions) {
|
|
3570
|
+
if (![...decisions.values()].some((d) => d.action === "scope" && d.partlyServed)) return;
|
|
3571
|
+
for (const [item, decision] of decisions)
|
|
3572
|
+
if (decision.action === "share" && item.ctx.scopeType !== "strict")
|
|
3573
|
+
decisions.set(item, { action: "scope", partlyServed: false });
|
|
3574
|
+
}
|
|
3575
|
+
function decidePackage(remoteEntry, group, view) {
|
|
3576
|
+
const pkg = packageOf(group[0].external.packageName);
|
|
3577
|
+
const claims = view.claimsOf(pkg);
|
|
3578
|
+
if (claims.length === 0) return { action: "share" };
|
|
3579
|
+
const specifiers = group.flatMap(({ external }) => Object.keys(external.entries));
|
|
3580
|
+
const builds = specifiers.every((specifier) => view.claims.has(specifier)) ? new Set(specifiers.map((specifier) => view.claims.get(specifier).copy.name)) : void 0;
|
|
3581
|
+
const rejections = group.flatMap((item) => rejectionsOf(item, view.claims));
|
|
3582
|
+
if (rejections.length > 0) {
|
|
3583
|
+
const fromTwoBuilds = builds !== void 0 && builds.size > 1;
|
|
3584
|
+
for (const rejection of refused(group, rejections, fromTwoBuilds, claims, view.inPool(pkg)))
|
|
3585
|
+
reportIncompatible(remoteEntry, rejection);
|
|
3586
|
+
return { action: "scope", partlyServed: false };
|
|
3291
3587
|
}
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3588
|
+
if (!builds || builds.size > 1) return { action: "scope", partlyServed: true };
|
|
3589
|
+
return { action: "skip", files: servingFiles(claims, builds) };
|
|
3590
|
+
}
|
|
3591
|
+
function servingFiles(claims, builds) {
|
|
3592
|
+
const files = /* @__PURE__ */ new Map();
|
|
3593
|
+
for (const [specifier, { copy }] of claims)
|
|
3594
|
+
if (builds.has(copy.name)) files.set(specifier, copy);
|
|
3595
|
+
return files;
|
|
3596
|
+
}
|
|
3597
|
+
function rejectionsOf(item, claims) {
|
|
3598
|
+
const { external, ctx } = item;
|
|
3599
|
+
if (!ctx.remote.strictVersion) return [];
|
|
3600
|
+
return Object.keys(external.entries).flatMap((specifier) => {
|
|
3601
|
+
const claim = claims.get(specifier);
|
|
3602
|
+
return claim && !accepts(claim.tag, ctx.tag, ctx.remote.requiredVersion) ? [{ item, specifier, claim }] : [];
|
|
3603
|
+
});
|
|
3604
|
+
}
|
|
3605
|
+
function refused(group, rejections, fromTwoBuilds, claims, pooled) {
|
|
3606
|
+
const copies = group.map(({ ctx }) => ({ tag: ctx.tag, copy: ctx.remote }));
|
|
3607
|
+
const splits = fromTwoBuilds || loadSplitsPackage(copies, claims, accepts);
|
|
3608
|
+
const first = /* @__PURE__ */ new Map();
|
|
3609
|
+
for (const rejection of rejections)
|
|
3610
|
+
if (!first.has(rejection.item) && (pooled || !splits || electionKeeps(rejection)))
|
|
3611
|
+
first.set(rejection.item, rejection);
|
|
3612
|
+
return [...first.values()];
|
|
3613
|
+
}
|
|
3614
|
+
function electionKeeps({ item: { external, ctx }, claim }) {
|
|
3615
|
+
if (claim.external !== external.packageName) return false;
|
|
3616
|
+
const versions = ports.sharedExternalsRepo.tryGet(claim.external, external.shareScope).get()?.versions ?? [];
|
|
3617
|
+
const strict = [
|
|
3618
|
+
{ tag: ctx.tag, copy: ctx.remote },
|
|
3619
|
+
...versions.flatMap(
|
|
3620
|
+
(v) => v.remotes.filter((r) => r.strictVersion).map((copy) => ({ tag: v.tag, copy }))
|
|
3621
|
+
)
|
|
3622
|
+
];
|
|
3623
|
+
const tags = [ctx.tag, ...versions.map((v) => v.tag)];
|
|
3624
|
+
if (!tags.some((tag) => strict.every((s) => accepts(tag, s.tag, s.copy.requiredVersion))))
|
|
3625
|
+
return true;
|
|
3626
|
+
const host = versions.find((v) => v.host);
|
|
3627
|
+
if (host) return host.tag === claim.tag;
|
|
3628
|
+
if (!config.profile.latestSharedExternal) return false;
|
|
3629
|
+
return tags.every((tag) => ports.versionCheck.compare(claim.tag, tag) >= 0);
|
|
3630
|
+
}
|
|
3631
|
+
function reportIncompatible(remoteEntry, { item: { external, ctx }, specifier, claim }) {
|
|
3632
|
+
const errorMsg = `[${external.shareScope ?? GLOBAL_SCOPE}][${remoteEntry.name}] ${specifier}@${ctx.tag} Is not compatible with existing ${specifier}@${claim.tag} requiredRange '${ctx.remote.requiredVersion}'`;
|
|
3633
|
+
if (config.strict.strictExternalCompatibility) {
|
|
3634
|
+
config.log.error(8, errorMsg);
|
|
3635
|
+
throw new NFError(`Could not process remote '${remoteEntry.name}'`);
|
|
3305
3636
|
}
|
|
3306
|
-
|
|
3307
|
-
|
|
3637
|
+
config.log.warn(8, errorMsg);
|
|
3638
|
+
}
|
|
3639
|
+
function applyDecision(remoteEntry, { external, ctx }, decision) {
|
|
3640
|
+
storeCopy(ctx, decision.action);
|
|
3641
|
+
if (decision.action !== "skip") return { action: decision.action };
|
|
3642
|
+
const covered = Object.keys(external.entries);
|
|
3643
|
+
if (!external.shareScope) return { action: "skip", covered };
|
|
3644
|
+
return {
|
|
3645
|
+
action: "skip",
|
|
3646
|
+
covered,
|
|
3647
|
+
override: overrideFrom(remoteEntry, external, decision.files)
|
|
3648
|
+
};
|
|
3308
3649
|
}
|
|
3309
|
-
function
|
|
3650
|
+
function storeCopy(ctx, action) {
|
|
3651
|
+
const { tag, remote } = ctx;
|
|
3652
|
+
const cached = ctx.readRecord();
|
|
3653
|
+
const shared = cached.versions.find((v) => v.tag === tag && v.action === "share");
|
|
3654
|
+
if (shared && action !== "scope") ctx.assertSameVersionCompatibility(shared);
|
|
3655
|
+
remote.cached = action !== "skip";
|
|
3656
|
+
const row = action === "share" ? shared : cached.versions.find((v) => v.tag === tag && v.action === action);
|
|
3657
|
+
const loaderServes = action === "share" && ctx.scopeType !== "strict";
|
|
3658
|
+
if (!row) cached.versions.push({ tag, action, host: false, remotes: [remote] });
|
|
3659
|
+
else if (loaderServes) addRemoteToVersion(row, remote);
|
|
3660
|
+
else row.remotes.push(remote);
|
|
3661
|
+
if (loaderServes) cached.servingBuild = remote.name;
|
|
3662
|
+
ctx.write();
|
|
3663
|
+
}
|
|
3664
|
+
function overrideFrom(remoteEntry, external, files) {
|
|
3310
3665
|
return Object.fromEntries(
|
|
3311
|
-
Array.from(
|
|
3312
|
-
|
|
3313
|
-
join(
|
|
3314
|
-
providerScopeUrl(remoteEntry, external, provider.name),
|
|
3315
|
-
provider.entries[packageName]
|
|
3316
|
-
)
|
|
3666
|
+
Array.from(files, ([specifier, copy]) => [
|
|
3667
|
+
specifier,
|
|
3668
|
+
join(providerScopeUrl(remoteEntry, external, copy.name), copy.entries[specifier])
|
|
3317
3669
|
])
|
|
3318
3670
|
);
|
|
3319
3671
|
}
|
|
@@ -3328,134 +3680,298 @@ function createUpdateCache(config, ports) {
|
|
|
3328
3680
|
}
|
|
3329
3681
|
}
|
|
3330
3682
|
|
|
3331
|
-
// src/lib/core/
|
|
3332
|
-
function
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
const
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
for (const
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3683
|
+
// src/lib/core/1.domain/pooling/gate.ts
|
|
3684
|
+
function committedView(members, shipped, recordOrder, { shareScope, without }) {
|
|
3685
|
+
const global = /* @__PURE__ */ new Map();
|
|
3686
|
+
const claims = committedClaims(inRecordOrder(members, recordOrder), { shareScope, without });
|
|
3687
|
+
for (const [specifier, { tag, copy }] of claims)
|
|
3688
|
+
global.set(specifier, { tag, remote: copy.name, file: copy.entries[specifier] });
|
|
3689
|
+
const builds = /* @__PURE__ */ new Map();
|
|
3690
|
+
for (const [owner, copies] of shipped)
|
|
3691
|
+
if (owner !== without) builds.set(owner, buildOf(owner, copies));
|
|
3692
|
+
const fileOf = subpoolFilesOf(members);
|
|
3693
|
+
return { builds, global, runsOffMap: runsOffMapOf(members, global, builds, fileOf) };
|
|
3694
|
+
}
|
|
3695
|
+
function subpoolFilesOf(members) {
|
|
3696
|
+
const subpoolOwners = /* @__PURE__ */ new Set();
|
|
3697
|
+
for (const member of members)
|
|
3698
|
+
for (const version of member.external.versions)
|
|
3699
|
+
for (const { servedBy } of version.remotes) if (servedBy) subpoolOwners.add(servedBy);
|
|
3700
|
+
const fileOf = /* @__PURE__ */ new Map();
|
|
3701
|
+
for (const member of members)
|
|
3702
|
+
for (const version of member.external.versions)
|
|
3703
|
+
for (const { name, entries } of version.remotes) {
|
|
3704
|
+
if (!subpoolOwners.has(name)) continue;
|
|
3705
|
+
let files = fileOf.get(name);
|
|
3706
|
+
if (!files) fileOf.set(name, files = /* @__PURE__ */ new Map());
|
|
3707
|
+
for (const specifier in entries)
|
|
3708
|
+
if (!files.has(specifier)) files.set(specifier, entries[specifier]);
|
|
3709
|
+
}
|
|
3710
|
+
return fileOf;
|
|
3711
|
+
}
|
|
3712
|
+
function runsOffMapOf(members, global, builds, fileOf) {
|
|
3713
|
+
const runsOffMap2 = /* @__PURE__ */ new Map();
|
|
3714
|
+
for (const member of members)
|
|
3715
|
+
for (const version of member.external.versions)
|
|
3716
|
+
for (const meta of version.remotes) {
|
|
3717
|
+
const { servedBy } = meta;
|
|
3718
|
+
if (version.action === "share" && !servedBy) continue;
|
|
3719
|
+
let runs = runsOffMap2.get(meta.name);
|
|
3720
|
+
if (!runs) runsOffMap2.set(meta.name, runs = /* @__PURE__ */ new Map());
|
|
3721
|
+
for (const specifier in meta.entries) {
|
|
3722
|
+
if (version.action === "skip" && !servedBy && global.has(specifier)) continue;
|
|
3723
|
+
const tag = (servedBy ? builds.get(servedBy)?.tags.pinnedTag(specifier) : void 0) ?? version.tag;
|
|
3724
|
+
const file = servedBy && fileOf.get(servedBy)?.get(specifier);
|
|
3725
|
+
runs.set(
|
|
3726
|
+
specifier,
|
|
3727
|
+
file ? { tag, remote: servedBy, file } : { tag, remote: meta.name, file: meta.entries[specifier] }
|
|
3369
3728
|
);
|
|
3370
|
-
mine.forEach((member) => scope(member.name));
|
|
3371
|
-
continue;
|
|
3372
3729
|
}
|
|
3373
|
-
redirect(entry.name, anchor, pool, asked.view, actions, shareScope);
|
|
3374
3730
|
}
|
|
3375
|
-
|
|
3376
|
-
|
|
3731
|
+
return runsOffMap2;
|
|
3732
|
+
}
|
|
3733
|
+
function judgeRemote(copies, view, accepts) {
|
|
3734
|
+
const { rejected, missing } = scan(copies, view, accepts);
|
|
3735
|
+
if (rejected) return { cause: "incompatible", ...rejected };
|
|
3736
|
+
const globalTags = new SpecifierTags([...view.global].map(([s, { tag }]) => [s, tag]));
|
|
3737
|
+
const binding = offMapBinding(copies, view, globalTags);
|
|
3738
|
+
if (binding) return { cause: "uncovered", ...binding };
|
|
3739
|
+
if (agrees(copies, globalTags)) return "global";
|
|
3740
|
+
if (missing !== void 0) return { cause: "uncovered", specifier: missing };
|
|
3741
|
+
if (unwitnessedGap(copies, globalTags, view.builds.values()) === void 0) return "global";
|
|
3742
|
+
return { cause: "uncovered", unshipped: true };
|
|
3743
|
+
}
|
|
3744
|
+
function coverFromMap(remote, mine, view, actions, policy) {
|
|
3745
|
+
const files = [];
|
|
3746
|
+
for (const member of mine) {
|
|
3747
|
+
const action = actions[member.name];
|
|
3748
|
+
const copy = member.external.versions.flatMap((v) => v.remotes).find((r) => r.name === remote);
|
|
3749
|
+
if (!copy) continue;
|
|
3750
|
+
const mapped = mapFiles(copy, view, policy, action);
|
|
3751
|
+
if ("unmapped" in mapped) return mapped;
|
|
3752
|
+
files.push({ member, action, copy, ...mapped });
|
|
3753
|
+
}
|
|
3754
|
+
const reaches = reachesOf(remote, files, view);
|
|
3755
|
+
const bound = boundByFile(reaches, view);
|
|
3756
|
+
if (bound !== void 0) return { bound };
|
|
3757
|
+
const servedPackages = new Set([...view.global.keys()].map(packageOf));
|
|
3758
|
+
const gap = files.map((file) => gapOf(file, servedPackages)).find((specifier) => specifier !== void 0);
|
|
3759
|
+
if (gap !== void 0) return { gap };
|
|
3760
|
+
return { covers: files.filter(covering).map(coverOf) };
|
|
3761
|
+
}
|
|
3762
|
+
function gapOf({ copy, covered }, servedPackages) {
|
|
3763
|
+
const entrypoints = Object.keys(copy.entries);
|
|
3764
|
+
const missing = entrypoints.filter((specifier) => !covered.has(specifier));
|
|
3765
|
+
if (missing.length < entrypoints.length) return missing[0];
|
|
3766
|
+
return missing.find((specifier) => servedPackages.has(packageOf(specifier)));
|
|
3767
|
+
}
|
|
3768
|
+
function covering({ action, copy, covered }) {
|
|
3769
|
+
if (action.action === "skip") return true;
|
|
3770
|
+
const entrypoints = Object.keys(copy.entries);
|
|
3771
|
+
return entrypoints.length > 0 && entrypoints.every((specifier) => covered.has(specifier));
|
|
3772
|
+
}
|
|
3773
|
+
function coverOf({ member, action, copy, covered, override }) {
|
|
3774
|
+
const toSkip = action.action !== "skip" || covered.size > action.covered.length && member.external.versions.some((v) => v.action === "share" && v.remotes.includes(copy));
|
|
3775
|
+
return { name: member.name, toSkip, override };
|
|
3776
|
+
}
|
|
3777
|
+
function reachesOf(remote, files, view) {
|
|
3778
|
+
const reaches = /* @__PURE__ */ new Map();
|
|
3779
|
+
const fromMap = (specifier) => {
|
|
3780
|
+
const served = view.global.get(specifier);
|
|
3781
|
+
return served && { remote: served.remote, file: served.file };
|
|
3377
3782
|
};
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
};
|
|
3386
|
-
}
|
|
3387
|
-
function anchorFor(remote, { pool, view, wants, specifiers, acceptance }) {
|
|
3388
|
-
const shared = /* @__PURE__ */ new Map();
|
|
3389
|
-
for (const [specifier, source] of view.global) shared.set(specifier, source.tag);
|
|
3390
|
-
if (isWitnessed(specifiers, shared, view.builds)) return "witnessed";
|
|
3391
|
-
const basis = basisPerMember(pool);
|
|
3392
|
-
for (const build of candidateOrder(pool, view)) {
|
|
3393
|
-
if (build === remote) continue;
|
|
3394
|
-
const candidate = view.builds.get(build);
|
|
3395
|
-
if (!servesItsOwnFamily(build, pool, basis)) continue;
|
|
3396
|
-
if (!covers(candidate.coverage, specifiers)) continue;
|
|
3397
|
-
if (!acceptsAll(acceptance(), candidate.instance, remote, wants)) continue;
|
|
3398
|
-
return build;
|
|
3399
|
-
}
|
|
3400
|
-
return void 0;
|
|
3401
|
-
}
|
|
3402
|
-
function candidateOrder(pool, view) {
|
|
3403
|
-
const serving = /* @__PURE__ */ new Set();
|
|
3404
|
-
for (const source of view.global.values()) serving.add(source.remote);
|
|
3405
|
-
const hosts = hostRemotes(pool);
|
|
3406
|
-
const rank = (build) => serving.has(build) ? 0 : hosts.has(build) ? 1 : 2;
|
|
3407
|
-
return [...view.builds.keys()].sort((a, b) => rank(a) - rank(b) || a.localeCompare(b));
|
|
3408
|
-
}
|
|
3409
|
-
function servesItsOwnFamily(build, pool, basis) {
|
|
3410
|
-
let ships2 = 0;
|
|
3411
|
-
let winsAll = true;
|
|
3412
|
-
let allScoped = true;
|
|
3413
|
-
for (const member of pool) {
|
|
3414
|
-
for (const version of member.external.versions) {
|
|
3415
|
-
const meta = version.remotes.find((r) => r.name === build);
|
|
3416
|
-
if (!meta) continue;
|
|
3417
|
-
if (meta.servedBy !== void 0) return false;
|
|
3418
|
-
ships2++;
|
|
3419
|
-
if (version.action !== "scope") allScoped = false;
|
|
3420
|
-
if (basis.get(member.name) !== build) winsAll = false;
|
|
3783
|
+
for (const file of files) {
|
|
3784
|
+
const takesMap = covering(file);
|
|
3785
|
+
for (const [specifier, own] of Object.entries(file.copy.entries)) {
|
|
3786
|
+
if (!takesMap || !file.covered.has(specifier)) reaches.set(specifier, { remote, file: own });
|
|
3787
|
+
else {
|
|
3788
|
+
const reach = fromMap(specifier);
|
|
3789
|
+
if (reach) reaches.set(specifier, reach);
|
|
3421
3790
|
}
|
|
3422
3791
|
}
|
|
3423
|
-
return ships2 > 0 && (winsAll || allScoped);
|
|
3424
3792
|
}
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3793
|
+
return reaches;
|
|
3794
|
+
}
|
|
3795
|
+
function boundByFile(reaches, view) {
|
|
3796
|
+
const servers = /* @__PURE__ */ new Set();
|
|
3797
|
+
for (const { remote } of reaches.values()) if (view.builds.has(remote)) servers.add(remote);
|
|
3798
|
+
const firstRun = /* @__PURE__ */ new Map();
|
|
3799
|
+
for (const build of servers)
|
|
3800
|
+
for (const specifier of view.builds.get(build).tags.keys()) {
|
|
3801
|
+
const served = view.runsOffMap.get(build)?.get(specifier) ?? view.global.get(specifier);
|
|
3802
|
+
if (served === void 0) continue;
|
|
3803
|
+
const reached = reaches.get(specifier) ?? firstRun.get(specifier);
|
|
3804
|
+
if (reached === void 0) {
|
|
3805
|
+
firstRun.set(specifier, served);
|
|
3806
|
+
if (view.builds.has(served.remote)) servers.add(served.remote);
|
|
3807
|
+
} else if (reached.remote !== served.remote || reached.file !== served.file)
|
|
3808
|
+
return { owner: build, specifier, tag: served.tag };
|
|
3809
|
+
}
|
|
3810
|
+
return void 0;
|
|
3811
|
+
}
|
|
3812
|
+
function mapFiles(copy, view, policy, action) {
|
|
3813
|
+
const covered = new Set(action.covered);
|
|
3814
|
+
const override = { ...action.override };
|
|
3815
|
+
for (const specifier in copy.entries) {
|
|
3816
|
+
const source = view.global.get(specifier);
|
|
3817
|
+
if (!source) continue;
|
|
3818
|
+
if (policy.shareScope !== GLOBAL_SCOPE) {
|
|
3819
|
+
const scopeUrl = policy.scopeUrlOf(source.remote);
|
|
3820
|
+
if (!scopeUrl) return { unmapped: source.remote };
|
|
3821
|
+
override[specifier] = join(scopeUrl, source.file);
|
|
3822
|
+
}
|
|
3823
|
+
covered.add(specifier);
|
|
3430
3824
|
}
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
);
|
|
3439
|
-
|
|
3825
|
+
return { covered, override };
|
|
3826
|
+
}
|
|
3827
|
+
function scan(copies, view, accepts) {
|
|
3828
|
+
let rejected;
|
|
3829
|
+
let missing;
|
|
3830
|
+
for (const copy of copies)
|
|
3831
|
+
for (const s of copy.specifiers) {
|
|
3832
|
+
const global = view.global.get(s);
|
|
3833
|
+
if (global === void 0) missing ??= s;
|
|
3834
|
+
else if (!accepts(global.tag, copy.tag, copy.requiredVersion))
|
|
3835
|
+
rejected ??= { specifier: s, tag: global.tag };
|
|
3440
3836
|
}
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
const
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3837
|
+
return { rejected, missing };
|
|
3838
|
+
}
|
|
3839
|
+
function offMapBinding(copies, view, globalTags) {
|
|
3840
|
+
const own = new SpecifierTags(copies.flatMap((c) => c.specifiers.map((s) => [s, c.tag])));
|
|
3841
|
+
const servers = /* @__PURE__ */ new Set();
|
|
3842
|
+
for (const copy of copies)
|
|
3843
|
+
for (const specifier of copy.specifiers) {
|
|
3844
|
+
const build = view.global.get(specifier)?.remote;
|
|
3845
|
+
if (build !== void 0) servers.add(build);
|
|
3846
|
+
}
|
|
3847
|
+
const firstRun = new SpecifierTags();
|
|
3848
|
+
for (const build of servers)
|
|
3849
|
+
for (const [specifier, { tag }] of view.runsOffMap.get(build) ?? []) {
|
|
3850
|
+
const reached = globalTags.pinnedTag(specifier) ?? own.pinnedTag(specifier) ?? firstRun.pinnedTag(specifier);
|
|
3851
|
+
if (reached === void 0) firstRun.set(specifier, tag);
|
|
3852
|
+
else if (reached !== tag) return { owner: build, specifier, tag };
|
|
3853
|
+
}
|
|
3854
|
+
return void 0;
|
|
3855
|
+
}
|
|
3856
|
+
function inRecordOrder(members, recordOrder) {
|
|
3857
|
+
const rank2 = new Map(recordOrder.map((name, i) => [name, i]));
|
|
3858
|
+
return [...members].sort((a, b) => rank2.get(a.name) - rank2.get(b.name)).map((m) => [m.name, m.external]);
|
|
3859
|
+
}
|
|
3860
|
+
|
|
3861
|
+
// src/lib/core/2.app/steps/pooling/pool-dynamic-externals.ts
|
|
3862
|
+
function createPoolDynamicExternals(config, ports) {
|
|
3863
|
+
const accepts = createAcceptsTag(
|
|
3864
|
+
(tag, range) => ports.versionCheck.isCompatible(tag, range),
|
|
3865
|
+
(a, b) => ports.versionCheck.compare(a, b)
|
|
3866
|
+
);
|
|
3867
|
+
const scopeUrlOf = (remote) => ports.remoteInfoRepo.tryGet(remote).get()?.scopeUrl;
|
|
3868
|
+
return ({ entry, actions }) => {
|
|
3869
|
+
for (const [scope, names] of poolableNames(entry, actions)) {
|
|
3870
|
+
const committed = ports.sharedExternalsRepo.getFromScope(scope);
|
|
3871
|
+
if (!scopeHasPoolState(committed)) continue;
|
|
3872
|
+
const { pools } = buildPools(committed);
|
|
3873
|
+
const moves = judgeScope(entry.name, names, actions, pools, Object.keys(committed), scope);
|
|
3874
|
+
writeMoves(entry.name, names, moves, committed, pools, scope);
|
|
3875
|
+
}
|
|
3876
|
+
return Promise.resolve({ entry, actions: publicActions(actions) });
|
|
3877
|
+
};
|
|
3878
|
+
function judgeScope(remote, names, actions, pools, recordOrder, scope) {
|
|
3879
|
+
const policy = { shareScope: scope, scopeUrlOf };
|
|
3880
|
+
const moves = /* @__PURE__ */ new Map();
|
|
3881
|
+
const selfServe = (members, cause) => {
|
|
3882
|
+
for (const { name } of members) {
|
|
3883
|
+
actions[name].action = "scope";
|
|
3884
|
+
delete actions[name].override;
|
|
3885
|
+
moves.set(name, { cause });
|
|
3886
|
+
}
|
|
3887
|
+
};
|
|
3888
|
+
for (const pool of pools.values()) {
|
|
3889
|
+
const mine = pool.filter((member) => names.has(member.name));
|
|
3890
|
+
if (mine.length === 0) continue;
|
|
3891
|
+
const shipped = copiesByRemote(pool);
|
|
3892
|
+
const view = committedView(pool, shipped, recordOrder, {
|
|
3893
|
+
shareScope: scope,
|
|
3894
|
+
without: remote
|
|
3895
|
+
});
|
|
3896
|
+
const own = shipped.get(remote) ?? [];
|
|
3897
|
+
const verdict = judgeRemote(own, view, accepts);
|
|
3898
|
+
if (verdict !== "global") {
|
|
3899
|
+
config.log.warn(8, `[${scope}] ${selfServeWarning(remote, verdict, specifierCount(own))}`);
|
|
3900
|
+
selfServe(mine, verdict.cause);
|
|
3901
|
+
continue;
|
|
3902
|
+
}
|
|
3903
|
+
const cover = coverFromMap(remote, mine, view, actions, policy);
|
|
3904
|
+
if (!("covers" in cover)) {
|
|
3905
|
+
if ("unmapped" in cover) warnUnmapped(scope, remote, cover.unmapped);
|
|
3906
|
+
else
|
|
3907
|
+
config.log.warn(
|
|
3908
|
+
8,
|
|
3909
|
+
`[${scope}] ${selfServeWarning(remote, coverMiss(cover), specifierCount(own))}`
|
|
3910
|
+
);
|
|
3911
|
+
selfServe(mine, "uncovered");
|
|
3912
|
+
continue;
|
|
3913
|
+
}
|
|
3914
|
+
for (const { name, toSkip, override } of cover.covers) {
|
|
3915
|
+
const action = actions[name];
|
|
3916
|
+
if (toSkip) {
|
|
3917
|
+
action.action = "skip";
|
|
3918
|
+
moves.set(name, { fromMap: true });
|
|
3919
|
+
}
|
|
3920
|
+
if (Object.keys(override).length > 0) action.override = override;
|
|
3453
3921
|
}
|
|
3454
|
-
action.covered = specifiers;
|
|
3455
|
-
if (Object.keys(override).length > 0) action.override = override;
|
|
3456
3922
|
}
|
|
3923
|
+
return moves;
|
|
3924
|
+
}
|
|
3925
|
+
function writeMoves(remote, names, moves, committed, pools, scope) {
|
|
3926
|
+
const written = {};
|
|
3927
|
+
for (const [name, move] of moves)
|
|
3928
|
+
written[name] = movedRecord(committed[name], remote, move, ports.versionCheck.compare);
|
|
3929
|
+
for (const [name, record] of renamedRecords({ ...committed, ...written }, pools))
|
|
3930
|
+
written[name] = record;
|
|
3931
|
+
if (!config.strict.strictExternalCompatibility)
|
|
3932
|
+
for (const { name } of [...pools.values()].flat().filter((m) => names.has(m.name)))
|
|
3933
|
+
written[name] = { ...written[name] ?? committed[name], dirty: true };
|
|
3934
|
+
for (const [name, record] of Object.entries(written))
|
|
3935
|
+
ports.sharedExternalsRepo.addOrUpdate(name, record, scope);
|
|
3936
|
+
}
|
|
3937
|
+
function warnUnmapped(scope, remote, build) {
|
|
3938
|
+
config.log.warn(
|
|
3939
|
+
8,
|
|
3940
|
+
`[${scope}][${remote}] '${build}' is not in the cache, so its files cannot be mapped.`
|
|
3941
|
+
);
|
|
3457
3942
|
}
|
|
3458
3943
|
}
|
|
3944
|
+
function publicActions(actions) {
|
|
3945
|
+
for (const action of Object.values(actions)) delete action.covered;
|
|
3946
|
+
return actions;
|
|
3947
|
+
}
|
|
3948
|
+
function poolableNames(entry, actions) {
|
|
3949
|
+
const declared = /* @__PURE__ */ new Map();
|
|
3950
|
+
for (const external of entry.shared ?? []) {
|
|
3951
|
+
const name = external.packageName;
|
|
3952
|
+
if (!external.singleton || !actions[name]) continue;
|
|
3953
|
+
if (external.shareScope === STRICT_SCOPE) continue;
|
|
3954
|
+
const scope = external.shareScope ?? GLOBAL_SCOPE;
|
|
3955
|
+
let names = declared.get(scope);
|
|
3956
|
+
if (!names) declared.set(scope, names = /* @__PURE__ */ new Set());
|
|
3957
|
+
names.add(name);
|
|
3958
|
+
}
|
|
3959
|
+
return declared;
|
|
3960
|
+
}
|
|
3961
|
+
function coverMiss(cover) {
|
|
3962
|
+
if ("gap" in cover) return { cause: "uncovered", specifier: cover.gap };
|
|
3963
|
+
return { cause: "uncovered", ...cover.bound };
|
|
3964
|
+
}
|
|
3965
|
+
function selfServeWarning(remote, miss, imports) {
|
|
3966
|
+
const where = `All ${imports} of its entrypoints are scoped for it.`;
|
|
3967
|
+
if (miss.cause === "incompatible")
|
|
3968
|
+
return `'${remote}' is islanded: its range rejects '${miss.specifier}@${miss.tag}' of the committed map. ${where}`;
|
|
3969
|
+
if ("owner" in miss)
|
|
3970
|
+
return `'${remote}' serves its own family: committed build '${miss.owner}', whose files it would reach, resolves '${miss.specifier}' to another file than it would. ${where}`;
|
|
3971
|
+
if ("unshipped" in miss)
|
|
3972
|
+
return `'${remote}' serves its own family: no committed build shipped the map's combination for it. ${where}`;
|
|
3973
|
+
return `'${remote}' serves its own family: no committed build offers every entrypoint it imports at a version it accepts (gap '${miss.specifier}'). ${where}`;
|
|
3974
|
+
}
|
|
3459
3975
|
|
|
3460
3976
|
// src/lib/core/2.app/steps/convert-to-import-map.ts
|
|
3461
3977
|
function createConvertToImportMap(config, ports) {
|
|
@@ -3492,27 +4008,14 @@ function createConvertToImportMap(config, ports) {
|
|
|
3492
4008
|
return;
|
|
3493
4009
|
}
|
|
3494
4010
|
if (actions[external.packageName].action === "skip") {
|
|
3495
|
-
const { override
|
|
4011
|
+
const { override } = actions[external.packageName];
|
|
3496
4012
|
if (override) {
|
|
3497
4013
|
Object.entries(override).forEach(([packageName, url]) => {
|
|
3498
4014
|
addToScopes(remoteEntryScope, packageName, url, importMap);
|
|
3499
4015
|
});
|
|
3500
|
-
serveUncovered(
|
|
3501
|
-
remoteEntry,
|
|
3502
|
-
external,
|
|
3503
|
-
covered ?? Object.keys(override),
|
|
3504
|
-
remoteEntryScope,
|
|
3505
|
-
importMap,
|
|
3506
|
-
sameVersion
|
|
3507
|
-
);
|
|
3508
|
-
return;
|
|
3509
|
-
}
|
|
3510
|
-
if (!external.shareScope) {
|
|
3511
|
-
if (covered) {
|
|
3512
|
-
serveUncovered(remoteEntry, external, covered, remoteEntryScope, importMap, sameVersion);
|
|
3513
|
-
}
|
|
3514
4016
|
return;
|
|
3515
4017
|
}
|
|
4018
|
+
if (!external.shareScope) return;
|
|
3516
4019
|
log.error(
|
|
3517
4020
|
9,
|
|
3518
4021
|
`[${remoteEntry.name}][${external.packageName}] shareScope skip has no override.`
|
|
@@ -3577,27 +4080,6 @@ function createConvertToImportMap(config, ports) {
|
|
|
3577
4080
|
});
|
|
3578
4081
|
return importMap;
|
|
3579
4082
|
}
|
|
3580
|
-
function serveUncovered(remoteEntry, external, covered, remoteEntryScope, importMap, sameVersion = false) {
|
|
3581
|
-
const provided = new Set(covered);
|
|
3582
|
-
Object.entries(external.entries).forEach(([packageName, fileName]) => {
|
|
3583
|
-
if (provided.has(packageName)) return;
|
|
3584
|
-
if (!sameVersion && (config.strict.strictEntryPointCoverage || config.profile.scopeUncoveredEntrypoints)) {
|
|
3585
|
-
warnUncoveredEntrypoint(remoteEntry.name, external.packageName, packageName);
|
|
3586
|
-
return;
|
|
3587
|
-
}
|
|
3588
|
-
const url = join(remoteEntryScope, fileName);
|
|
3589
|
-
addToScopes(remoteEntryScope, packageName, url, importMap);
|
|
3590
|
-
addIntegrity(importMap, url, remoteEntry.integrity, fileName);
|
|
3591
|
-
});
|
|
3592
|
-
}
|
|
3593
|
-
function warnUncoveredEntrypoint(remoteName, externalName, packageName) {
|
|
3594
|
-
const msg = `[${remoteName}][${externalName}] Entrypoint '${packageName}' is not covered by the override.`;
|
|
3595
|
-
if (config.strict.strictEntryPointCoverage || config.strict.strictImportMap) {
|
|
3596
|
-
log.error(9, msg);
|
|
3597
|
-
throw new NFError("Could not create ImportMap.");
|
|
3598
|
-
}
|
|
3599
|
-
log.warn(9, msg);
|
|
3600
|
-
}
|
|
3601
4083
|
function addIntegrity(importMap, url, integrityMap, file) {
|
|
3602
4084
|
const hash = integrityMap?.[file];
|
|
3603
4085
|
if (!hash) return;
|
|
@@ -3613,11 +4095,12 @@ var createInitDrivers = ({
|
|
|
3613
4095
|
}) => ({
|
|
3614
4096
|
getRemoteEntries: createGetRemoteEntries(config, adapters),
|
|
3615
4097
|
processRemoteEntries: createProcessRemoteEntries(config, adapters),
|
|
3616
|
-
markPoolsForReelection: createMarkPoolsForReelection(config, adapters),
|
|
3617
4098
|
determineSharedExternals: createDetermineSharedExternals(config, adapters),
|
|
3618
4099
|
poolSharedExternals: createPoolSharedExternals(config, adapters),
|
|
4100
|
+
decideServingBuilds: createDecideServingBuilds(config, adapters),
|
|
3619
4101
|
generateImportMap: createGenerateImportMap(config, adapters),
|
|
3620
4102
|
commitChanges: createCommitChanges(config, adapters),
|
|
4103
|
+
rollbackChanges: createRollbackChanges(config, adapters),
|
|
3621
4104
|
exposeModuleLoader: createExposeModuleLoader(config, adapters),
|
|
3622
4105
|
getRemoteEntry: createGetRemoteEntry(config, adapters),
|
|
3623
4106
|
updateCache: createUpdateCache(config, adapters),
|
|
@@ -3647,19 +4130,30 @@ var createBrowser = (config) => {
|
|
|
3647
4130
|
// src/lib/core/3.adapters/checks/version.check.ts
|
|
3648
4131
|
var import_valid = __toESM(require_valid());
|
|
3649
4132
|
var import_satisfies = __toESM(require_satisfies());
|
|
3650
|
-
var
|
|
4133
|
+
var import_semver = __toESM(require_semver());
|
|
3651
4134
|
var import_min_version = __toESM(require_min_version());
|
|
3652
4135
|
var import_valid2 = __toESM(require_valid2());
|
|
3653
4136
|
var createVersionCheck = () => {
|
|
4137
|
+
const parsed = /* @__PURE__ */ new Map();
|
|
4138
|
+
const parse = (v) => {
|
|
4139
|
+
let hit = parsed.get(v);
|
|
4140
|
+
if (!hit) parsed.set(v, hit = new import_semver.default(v, true));
|
|
4141
|
+
return hit;
|
|
4142
|
+
};
|
|
4143
|
+
const satisfied = /* @__PURE__ */ new Map();
|
|
3654
4144
|
return {
|
|
3655
4145
|
isValidSemver: function(version) {
|
|
3656
4146
|
return (0, import_valid.default)(version) !== null;
|
|
3657
4147
|
},
|
|
3658
4148
|
isCompatible: function(version, range) {
|
|
3659
|
-
|
|
4149
|
+
let byVersion = satisfied.get(range);
|
|
4150
|
+
if (!byVersion) satisfied.set(range, byVersion = /* @__PURE__ */ new Map());
|
|
4151
|
+
let hit = byVersion.get(version);
|
|
4152
|
+
if (hit === void 0) byVersion.set(version, hit = (0, import_satisfies.default)(version, range));
|
|
4153
|
+
return hit;
|
|
3660
4154
|
},
|
|
3661
4155
|
compare: function(versionA, versionB) {
|
|
3662
|
-
return (
|
|
4156
|
+
return parse(versionA).compare(parse(versionB));
|
|
3663
4157
|
},
|
|
3664
4158
|
smallestVersion: function(versionRange) {
|
|
3665
4159
|
if (!(0, import_valid2.default)(versionRange)) return "0.0.0";
|
|
@@ -3732,7 +4226,7 @@ var createManifestProvider = () => {
|
|
|
3732
4226
|
};
|
|
3733
4227
|
};
|
|
3734
4228
|
|
|
3735
|
-
// node_modules/.pnpm/@softarc+native-federation@4.
|
|
4229
|
+
// node_modules/.pnpm/@softarc+native-federation@4.8.0/node_modules/@softarc/native-federation/dist/lib/utils/normalize.js
|
|
3736
4230
|
function inferPackageFromSecondary(secondary) {
|
|
3737
4231
|
const parts = secondary.split("/");
|
|
3738
4232
|
if (secondary.startsWith("@") && parts.length >= 2) {
|
|
@@ -3741,7 +4235,7 @@ function inferPackageFromSecondary(secondary) {
|
|
|
3741
4235
|
return parts[0];
|
|
3742
4236
|
}
|
|
3743
4237
|
|
|
3744
|
-
// node_modules/.pnpm/@softarc+native-federation@4.
|
|
4238
|
+
// node_modules/.pnpm/@softarc+native-federation@4.8.0/node_modules/@softarc/native-federation/dist/lib/core/output/densify-externals.js
|
|
3745
4239
|
function isDense(entry) {
|
|
3746
4240
|
return "entries" in entry;
|
|
3747
4241
|
}
|
|
@@ -3757,37 +4251,26 @@ function densifyExternals(shared) {
|
|
|
3757
4251
|
continue;
|
|
3758
4252
|
}
|
|
3759
4253
|
if (isFlatChunk(entry)) {
|
|
3760
|
-
const { outFileName, ...rest } = entry;
|
|
3761
|
-
result.push({ ...rest, entries: { [entry.packageName]:
|
|
4254
|
+
const { outFileName: outFileName2, ...rest } = entry;
|
|
4255
|
+
result.push({ ...rest, entries: { [entry.packageName]: outFileName2 } });
|
|
3762
4256
|
continue;
|
|
3763
4257
|
}
|
|
3764
|
-
const
|
|
3765
|
-
const
|
|
3766
|
-
|
|
3767
|
-
strictVersion: entry.strictVersion,
|
|
3768
|
-
requiredVersion: entry.requiredVersion,
|
|
3769
|
-
version: entry.version,
|
|
3770
|
-
shareScope: entry.shareScope
|
|
3771
|
-
});
|
|
4258
|
+
const { outFileName, packageName, dev, ...meta } = entry;
|
|
4259
|
+
const parent = inferPackageFromSecondary(packageName);
|
|
4260
|
+
const sig = JSON.stringify(meta, Object.keys(meta).sort());
|
|
3772
4261
|
const key = parent + " " + sig;
|
|
3773
4262
|
const existing = groupIndex.get(key);
|
|
3774
4263
|
if (existing === void 0) {
|
|
3775
4264
|
const dense = {
|
|
3776
|
-
|
|
3777
|
-
strictVersion: entry.strictVersion,
|
|
3778
|
-
requiredVersion: entry.requiredVersion,
|
|
4265
|
+
...meta,
|
|
3779
4266
|
packageName: parent,
|
|
3780
|
-
entries: { [
|
|
4267
|
+
entries: { [packageName]: outFileName }
|
|
3781
4268
|
};
|
|
3782
|
-
if (
|
|
3783
|
-
if (entry.shareScope !== void 0) dense.shareScope = entry.shareScope;
|
|
3784
|
-
if (entry.bundle !== void 0) dense.bundle = entry.bundle;
|
|
3785
|
-
if (entry.pool !== void 0) dense.pool = entry.pool;
|
|
3786
|
-
if (entry.dev !== void 0) dense.dev = entry.dev;
|
|
4269
|
+
if (dev !== void 0) dense.dev = dev;
|
|
3787
4270
|
groupIndex.set(key, result.length);
|
|
3788
4271
|
result.push(dense);
|
|
3789
4272
|
} else {
|
|
3790
|
-
result[existing].entries[
|
|
4273
|
+
result[existing].entries[packageName] = outFileName;
|
|
3791
4274
|
}
|
|
3792
4275
|
}
|
|
3793
4276
|
return result;
|
|
@@ -3837,11 +4320,20 @@ var createRemoteEntryProvider = (config) => {
|
|
|
3837
4320
|
};
|
|
3838
4321
|
};
|
|
3839
4322
|
|
|
4323
|
+
// src/lib/core/2.app/config/storage.contract.ts
|
|
4324
|
+
var STORAGE_KEYS = {
|
|
4325
|
+
remotes: "remotes",
|
|
4326
|
+
sharedExternals: "shared-externals",
|
|
4327
|
+
scopedExternals: "scoped-externals",
|
|
4328
|
+
sharedChunks: "shared-chunks",
|
|
4329
|
+
cacheState: "cache-state"
|
|
4330
|
+
};
|
|
4331
|
+
|
|
3840
4332
|
// src/lib/core/3.adapters/storage/remote-info.repository.ts
|
|
3841
4333
|
var createRemoteInfoRepository = (config) => {
|
|
3842
|
-
const STORAGE = config.storage(
|
|
4334
|
+
const STORAGE = config.storage(STORAGE_KEYS.remotes, {});
|
|
3843
4335
|
if (config.clearStorage) STORAGE.clear();
|
|
3844
|
-
|
|
4336
|
+
let _cache = STORAGE.get() ?? {};
|
|
3845
4337
|
let _dirty = false;
|
|
3846
4338
|
return {
|
|
3847
4339
|
contains: function(remoteName) {
|
|
@@ -3875,15 +4367,20 @@ var createRemoteInfoRepository = (config) => {
|
|
|
3875
4367
|
STORAGE.set(_cache);
|
|
3876
4368
|
_dirty = false;
|
|
3877
4369
|
return this;
|
|
4370
|
+
},
|
|
4371
|
+
rollback: function() {
|
|
4372
|
+
_cache = STORAGE.get() ?? {};
|
|
4373
|
+
_dirty = false;
|
|
4374
|
+
return this;
|
|
3878
4375
|
}
|
|
3879
4376
|
};
|
|
3880
4377
|
};
|
|
3881
4378
|
|
|
3882
4379
|
// src/lib/core/3.adapters/storage/scoped-externals.repository.ts
|
|
3883
4380
|
var createScopedExternalsRepository = (config) => {
|
|
3884
|
-
const STORAGE = config.storage(
|
|
4381
|
+
const STORAGE = config.storage(STORAGE_KEYS.scopedExternals, {});
|
|
3885
4382
|
if (config.clearStorage) STORAGE.clear();
|
|
3886
|
-
|
|
4383
|
+
let _cache = STORAGE.get() ?? {};
|
|
3887
4384
|
let _dirty = false;
|
|
3888
4385
|
return {
|
|
3889
4386
|
addExternal: function(remoteName, external, version) {
|
|
@@ -3910,38 +4407,57 @@ var createScopedExternalsRepository = (config) => {
|
|
|
3910
4407
|
STORAGE.set(_cache);
|
|
3911
4408
|
_dirty = false;
|
|
3912
4409
|
return this;
|
|
4410
|
+
},
|
|
4411
|
+
rollback: function() {
|
|
4412
|
+
_cache = STORAGE.get() ?? {};
|
|
4413
|
+
_dirty = false;
|
|
4414
|
+
return this;
|
|
3913
4415
|
}
|
|
3914
4416
|
};
|
|
3915
4417
|
};
|
|
3916
4418
|
|
|
4419
|
+
// src/lib/core/3.adapters/storage/cache-state.ts
|
|
4420
|
+
var createCacheState = (storage) => {
|
|
4421
|
+
const entry = storage(STORAGE_KEYS.cacheState, null);
|
|
4422
|
+
const read = () => {
|
|
4423
|
+
const stored = entry.get();
|
|
4424
|
+
if (typeof stored !== "object" || stored === null) return {};
|
|
4425
|
+
const { version, undecidedScopes } = stored;
|
|
4426
|
+
return {
|
|
4427
|
+
...typeof version === "string" ? { version } : {},
|
|
4428
|
+
...Array.isArray(undecidedScopes) ? { undecidedScopes: undecidedScopes.filter((s) => typeof s === "string") } : {}
|
|
4429
|
+
};
|
|
4430
|
+
};
|
|
4431
|
+
return {
|
|
4432
|
+
read,
|
|
4433
|
+
update: (fields) => void entry.set({ ...read(), ...fields })
|
|
4434
|
+
};
|
|
4435
|
+
};
|
|
4436
|
+
|
|
3917
4437
|
// src/lib/core/3.adapters/storage/shared-externals.repository.ts
|
|
3918
4438
|
var createSharedExternalsRepository = (config) => {
|
|
3919
4439
|
const STORAGE = config.storage(
|
|
3920
|
-
|
|
4440
|
+
STORAGE_KEYS.sharedExternals,
|
|
3921
4441
|
{ [GLOBAL_SCOPE]: {} }
|
|
3922
4442
|
);
|
|
3923
|
-
|
|
3924
|
-
const
|
|
3925
|
-
|
|
4443
|
+
const cacheState = createCacheState(config.storage);
|
|
4444
|
+
const storedUndecided = () => new Set(cacheState.read().undecidedScopes);
|
|
4445
|
+
if (config.clearStorage) {
|
|
4446
|
+
STORAGE.clear();
|
|
4447
|
+
cacheState.update({ undecidedScopes: [] });
|
|
4448
|
+
}
|
|
4449
|
+
let _cache = STORAGE.get() ?? { [GLOBAL_SCOPE]: {} };
|
|
4450
|
+
const _uncommitted = /* @__PURE__ */ new Set();
|
|
4451
|
+
let _undecided = storedUndecided();
|
|
4452
|
+
let _undecidedChanged = false;
|
|
3926
4453
|
return {
|
|
3927
|
-
// Read from the cache rather than remembered from this init's entries: a warm init may not refetch
|
|
3928
|
-
// the tagged remote at all, and pooling has to coordinate its pool anyway. Exits on the first hit.
|
|
3929
|
-
// Per share scope, because a pool never spans one: a tag in another scope is no reason to pool here.
|
|
3930
|
-
hasPoolTag: function(shareScope) {
|
|
3931
|
-
const scope = _cache[shareScope ?? GLOBAL_SCOPE];
|
|
3932
|
-
if (!scope) return false;
|
|
3933
|
-
for (const external of Object.values(scope))
|
|
3934
|
-
for (const version of external.versions)
|
|
3935
|
-
for (const remote of version.remotes) if (remote.pool?.trim()) return true;
|
|
3936
|
-
return false;
|
|
3937
|
-
},
|
|
3938
4454
|
getFromScope: function(shareScope) {
|
|
3939
4455
|
return { ..._cache[shareScope ?? GLOBAL_SCOPE] };
|
|
3940
4456
|
},
|
|
3941
4457
|
addOrUpdate: function(externalName, external, shareScope) {
|
|
3942
4458
|
if (!_cache[shareScope ?? GLOBAL_SCOPE]) _cache[shareScope ?? GLOBAL_SCOPE] = {};
|
|
3943
4459
|
_cache[shareScope ?? GLOBAL_SCOPE][externalName] = external;
|
|
3944
|
-
|
|
4460
|
+
_uncommitted.add(shareScope ?? GLOBAL_SCOPE);
|
|
3945
4461
|
return this;
|
|
3946
4462
|
},
|
|
3947
4463
|
getScopes: function(o = { includeGlobal: true }) {
|
|
@@ -3951,7 +4467,7 @@ var createSharedExternalsRepository = (config) => {
|
|
|
3951
4467
|
// Batched: one traversal of the graph per init instead of one per overridden remote.
|
|
3952
4468
|
removeFromAllScopes: function(remoteNames) {
|
|
3953
4469
|
if (remoteNames.size === 0) return;
|
|
3954
|
-
Object.
|
|
4470
|
+
Object.entries(_cache).forEach(([scopeName, scope]) => {
|
|
3955
4471
|
const removeExternals = [];
|
|
3956
4472
|
Object.entries(scope).forEach(([name, external]) => {
|
|
3957
4473
|
let removedCopy = false;
|
|
@@ -3967,12 +4483,12 @@ var createSharedExternalsRepository = (config) => {
|
|
|
3967
4483
|
if (keep !== remotes.length) {
|
|
3968
4484
|
remotes.length = keep;
|
|
3969
4485
|
removedCopy = true;
|
|
3970
|
-
|
|
4486
|
+
_uncommitted.add(scopeName);
|
|
3971
4487
|
if (host !== void 0 && remoteNames.has(host)) version.host = false;
|
|
3972
4488
|
}
|
|
3973
4489
|
if (remotes.length === 0) {
|
|
3974
4490
|
external.versions.splice(i, 1);
|
|
3975
|
-
|
|
4491
|
+
_uncommitted.add(scopeName);
|
|
3976
4492
|
}
|
|
3977
4493
|
}
|
|
3978
4494
|
if (removedCopy) {
|
|
@@ -3980,7 +4496,17 @@ var createSharedExternalsRepository = (config) => {
|
|
|
3980
4496
|
if (external.versions.length === 0) removeExternals.push(name);
|
|
3981
4497
|
}
|
|
3982
4498
|
});
|
|
3983
|
-
|
|
4499
|
+
const lostPools = /* @__PURE__ */ new Set();
|
|
4500
|
+
for (const name of removeExternals) {
|
|
4501
|
+
const poolName = scope[name].poolName;
|
|
4502
|
+
if (poolName !== void 0) lostPools.add(poolName);
|
|
4503
|
+
delete scope[name];
|
|
4504
|
+
}
|
|
4505
|
+
if (lostPools.size > 0) {
|
|
4506
|
+
for (const external of Object.values(scope))
|
|
4507
|
+
if (external.poolName !== void 0 && lostPools.has(external.poolName))
|
|
4508
|
+
external.dirty = true;
|
|
4509
|
+
}
|
|
3984
4510
|
});
|
|
3985
4511
|
},
|
|
3986
4512
|
scopeType: function(shareScope) {
|
|
@@ -3998,10 +4524,36 @@ var createSharedExternalsRepository = (config) => {
|
|
|
3998
4524
|
tryGet: function(external, shareScope) {
|
|
3999
4525
|
return Optional.of(_cache[shareScope ?? GLOBAL_SCOPE]?.[external]);
|
|
4000
4526
|
},
|
|
4527
|
+
uncommittedScopes: function() {
|
|
4528
|
+
return [..._uncommitted];
|
|
4529
|
+
},
|
|
4530
|
+
markUndecided: function(shareScope) {
|
|
4531
|
+
if (_undecided.has(shareScope)) return;
|
|
4532
|
+
_undecided.add(shareScope);
|
|
4533
|
+
_undecidedChanged = true;
|
|
4534
|
+
},
|
|
4535
|
+
isUndecided: function(shareScope) {
|
|
4536
|
+
return _undecided.has(shareScope);
|
|
4537
|
+
},
|
|
4538
|
+
markDecided: function(shareScope) {
|
|
4539
|
+
if (_undecided.delete(shareScope)) _undecidedChanged = true;
|
|
4540
|
+
},
|
|
4541
|
+
// Records before marks: should their write throw, the stored marks still send the next init to decide them. A
|
|
4542
|
+
// failed cache-state write after the records loses only this load's marks.
|
|
4001
4543
|
commit: function() {
|
|
4002
|
-
if (
|
|
4003
|
-
|
|
4004
|
-
|
|
4544
|
+
if (_uncommitted.size > 0) {
|
|
4545
|
+
STORAGE.set(_cache);
|
|
4546
|
+
_uncommitted.clear();
|
|
4547
|
+
}
|
|
4548
|
+
if (_undecidedChanged) cacheState.update({ undecidedScopes: [..._undecided] });
|
|
4549
|
+
_undecidedChanged = false;
|
|
4550
|
+
return this;
|
|
4551
|
+
},
|
|
4552
|
+
rollback: function() {
|
|
4553
|
+
_cache = STORAGE.get() ?? { [GLOBAL_SCOPE]: {} };
|
|
4554
|
+
_uncommitted.clear();
|
|
4555
|
+
_undecided = storedUndecided();
|
|
4556
|
+
_undecidedChanged = false;
|
|
4005
4557
|
return this;
|
|
4006
4558
|
}
|
|
4007
4559
|
};
|
|
@@ -4116,9 +4668,9 @@ var createSSEHandler = (config) => {
|
|
|
4116
4668
|
|
|
4117
4669
|
// src/lib/core/3.adapters/storage/chunk.repository.ts
|
|
4118
4670
|
var createChunkRepository = (config) => {
|
|
4119
|
-
const STORAGE = config.storage(
|
|
4671
|
+
const STORAGE = config.storage(STORAGE_KEYS.sharedChunks, {});
|
|
4120
4672
|
if (config.clearStorage) STORAGE.clear();
|
|
4121
|
-
|
|
4673
|
+
let _cache = STORAGE.get() ?? {};
|
|
4122
4674
|
let _dirty = false;
|
|
4123
4675
|
return {
|
|
4124
4676
|
addOrReplace: function(remoteName, bundleName, chunks) {
|
|
@@ -4143,6 +4695,11 @@ var createChunkRepository = (config) => {
|
|
|
4143
4695
|
STORAGE.set(_cache);
|
|
4144
4696
|
_dirty = false;
|
|
4145
4697
|
return this;
|
|
4698
|
+
},
|
|
4699
|
+
rollback: function() {
|
|
4700
|
+
_cache = STORAGE.get() ?? {};
|
|
4701
|
+
_dirty = false;
|
|
4702
|
+
return this;
|
|
4146
4703
|
}
|
|
4147
4704
|
};
|
|
4148
4705
|
};
|
|
@@ -4362,18 +4919,74 @@ var globalThisStorageEntry = (namespace) => (key, initialValue) => {
|
|
|
4362
4919
|
};
|
|
4363
4920
|
return entry;
|
|
4364
4921
|
};
|
|
4922
|
+
globalThisStorageEntry.type = "globalThis";
|
|
4923
|
+
Object.freeze(globalThisStorageEntry);
|
|
4924
|
+
|
|
4925
|
+
// src/lib/core/4.config/orchestrator-version.ts
|
|
4926
|
+
var ORCHESTRATOR_VERSION = true ? "4.8.0" : "dev";
|
|
4927
|
+
|
|
4928
|
+
// src/lib/core/4.config/storage/publish-storage-info.ts
|
|
4929
|
+
var KEYS = Object.freeze(Object.values(STORAGE_KEYS));
|
|
4930
|
+
var isStorageKey = (key) => KEYS.includes(key);
|
|
4931
|
+
var createStorageInfo = ({
|
|
4932
|
+
type,
|
|
4933
|
+
namespace,
|
|
4934
|
+
storage,
|
|
4935
|
+
exposeGetter
|
|
4936
|
+
}) => {
|
|
4937
|
+
const info = {
|
|
4938
|
+
version: ORCHESTRATOR_VERSION,
|
|
4939
|
+
type,
|
|
4940
|
+
namespace,
|
|
4941
|
+
keys: KEYS
|
|
4942
|
+
};
|
|
4943
|
+
if (!exposeGetter) return Object.freeze(info);
|
|
4944
|
+
return Object.freeze({
|
|
4945
|
+
...info,
|
|
4946
|
+
// Cloned again because custom storages may hand out live references.
|
|
4947
|
+
get: (key) => isStorageKey(key) ? cloneEntry(key, storage(key, void 0).get()) : void 0
|
|
4948
|
+
});
|
|
4949
|
+
};
|
|
4950
|
+
var publishStorageInfo = (options) => {
|
|
4951
|
+
try {
|
|
4952
|
+
globalThis.__NF_ORCHESTRATOR__ = Object.freeze({
|
|
4953
|
+
storage: Object.freeze({
|
|
4954
|
+
...globalThis.__NF_ORCHESTRATOR__?.storage,
|
|
4955
|
+
[options.namespace]: createStorageInfo(options)
|
|
4956
|
+
})
|
|
4957
|
+
});
|
|
4958
|
+
} catch {
|
|
4959
|
+
}
|
|
4960
|
+
};
|
|
4365
4961
|
|
|
4366
4962
|
// src/lib/core/4.config/storage/storage.config.ts
|
|
4367
|
-
var
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
});
|
|
4963
|
+
var isOutdatedCache = (storage) => {
|
|
4964
|
+
const cacheState = createCacheState(storage);
|
|
4965
|
+
if (cacheState.read().version === ORCHESTRATOR_VERSION) return false;
|
|
4966
|
+
cacheState.update({ version: ORCHESTRATOR_VERSION, undecidedScopes: [] });
|
|
4967
|
+
return Object.values(STORAGE_KEYS).filter((key) => key !== STORAGE_KEYS.cacheState).some((key) => storage(key, null).get() !== null);
|
|
4968
|
+
};
|
|
4969
|
+
var createStorageConfig = (override) => {
|
|
4970
|
+
const creator = override.storage ?? globalThisStorageEntry;
|
|
4971
|
+
const namespace = override.storageNamespace ?? "__NATIVE_FEDERATION__";
|
|
4972
|
+
const storage = creator(namespace);
|
|
4973
|
+
publishStorageInfo({
|
|
4974
|
+
type: creator.type ?? "custom",
|
|
4975
|
+
namespace,
|
|
4976
|
+
storage,
|
|
4977
|
+
exposeGetter: override.exposeStorageGetter ?? true
|
|
4978
|
+
});
|
|
4979
|
+
const outdated = isOutdatedCache(storage);
|
|
4980
|
+
return {
|
|
4981
|
+
storage,
|
|
4982
|
+
clearStorage: (override.clearStorage ?? false) || outdated
|
|
4983
|
+
};
|
|
4984
|
+
};
|
|
4371
4985
|
|
|
4372
4986
|
// src/lib/core/4.config/mode/default.profile.ts
|
|
4373
4987
|
var defaultProfile = {
|
|
4374
4988
|
latestSharedExternal: false,
|
|
4375
4989
|
skipInvalidExternalVersions: false,
|
|
4376
|
-
scopeUncoveredEntrypoints: false,
|
|
4377
4990
|
overrideCachedRemotes: "init-only",
|
|
4378
4991
|
overrideCachedRemotesIfURLMatches: false
|
|
4379
4992
|
};
|
|
@@ -4385,22 +4998,19 @@ var createModeConfig = (override) => {
|
|
|
4385
4998
|
strictExternalCompatibility: override.strict,
|
|
4386
4999
|
strictExternalSameVersionCompatibility: override.strict,
|
|
4387
5000
|
strictExternalVersion: override.strict,
|
|
4388
|
-
strictImportMap: override.strict
|
|
4389
|
-
strictEntryPointCoverage: override.strict
|
|
5001
|
+
strictImportMap: override.strict
|
|
4390
5002
|
} : {
|
|
4391
5003
|
strictRemoteEntry: override.strict?.strictRemoteEntry ?? false,
|
|
4392
5004
|
strictExternalCompatibility: override.strict?.strictExternalCompatibility ?? false,
|
|
4393
5005
|
strictExternalSameVersionCompatibility: override.strict?.strictExternalSameVersionCompatibility ?? false,
|
|
4394
5006
|
strictExternalVersion: override.strict?.strictExternalVersion ?? false,
|
|
4395
|
-
strictImportMap: override.strict?.strictImportMap ?? false
|
|
4396
|
-
strictEntryPointCoverage: override.strict?.strictEntryPointCoverage ?? false
|
|
5007
|
+
strictImportMap: override.strict?.strictImportMap ?? false
|
|
4397
5008
|
};
|
|
4398
5009
|
return {
|
|
4399
5010
|
strict: strictnessConfig,
|
|
4400
5011
|
profile: { ...defaultProfile, ...override.profile ?? {} },
|
|
4401
5012
|
feature: {
|
|
4402
|
-
convertFlatSharedInfo: override.feature?.convertFlatSharedInfo ?? false
|
|
4403
|
-
useAutoExternalPooling: override.feature?.useAutoExternalPooling ?? false
|
|
5013
|
+
convertFlatSharedInfo: override.feature?.convertFlatSharedInfo ?? false
|
|
4404
5014
|
}
|
|
4405
5015
|
};
|
|
4406
5016
|
};
|
|
@@ -4415,14 +5025,6 @@ var createConfigHandlers = (overrides) => ({
|
|
|
4415
5025
|
});
|
|
4416
5026
|
|
|
4417
5027
|
// src/lib/core/5.di/federation-result.factory.ts
|
|
4418
|
-
var createStateDump = (config, adapters) => (msg) => config.log.debug(0, msg, {
|
|
4419
|
-
remotes: { ...adapters.remoteInfoRepo.getAll() },
|
|
4420
|
-
"shared-externals": adapters.sharedExternalsRepo.getScopes({ includeGlobal: true }).reduce(
|
|
4421
|
-
(acc, scope) => ({ ...acc, [scope]: adapters.sharedExternalsRepo.getFromScope(scope) }),
|
|
4422
|
-
{}
|
|
4423
|
-
),
|
|
4424
|
-
"scoped-externals": adapters.scopedExternalsRepo.getAll()
|
|
4425
|
-
});
|
|
4426
5028
|
var createFederationResult = ({
|
|
4427
5029
|
config,
|
|
4428
5030
|
adapters,
|
|
@@ -4430,11 +5032,8 @@ var createFederationResult = ({
|
|
|
4430
5032
|
initRemoteEntryFlow,
|
|
4431
5033
|
afterInitRemoteEntry
|
|
4432
5034
|
}) => {
|
|
4433
|
-
const stateDump = createStateDump(config, adapters);
|
|
4434
5035
|
const initRemoteEntry = async (remoteEntryUrl, remote) => {
|
|
4435
|
-
const remoteName = typeof remote === "string" ? remote : remote?.name;
|
|
4436
5036
|
return initRemoteEntryFlow(remoteEntryUrl, remote).catch((e) => {
|
|
4437
|
-
stateDump(`[dynamic-init][${remoteName ?? remoteEntryUrl}] STATE DUMP`);
|
|
4438
5037
|
if (config.strict.strictRemoteEntry) return Promise.reject(e);
|
|
4439
5038
|
else console.warn("Failed to initialize remote entry, continuing anyway.");
|
|
4440
5039
|
return Promise.resolve();
|