@softarc/native-federation-orchestrator 4.7.0 → 4.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/@softarc/native-federation-orchestrator.mjs +2099 -1484
- 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 +256 -32
- package/fesm2022/module-federation.mjs.map +3 -3
- package/fesm2022/node.mjs +2168 -1487
- package/fesm2022/node.mjs.map +4 -4
- package/fesm2022/options.mjs +5 -5
- 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/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 +21 -0
- package/types/lib/core/1.domain/externals/compatibility.d.ts +9 -0
- package/types/lib/core/1.domain/externals/external.contract.d.ts +3 -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 +18 -0
- package/types/lib/core/1.domain/externals/version.contract.d.ts +2 -1
- package/types/lib/core/1.domain/pooling/builds.d.ts +20 -0
- package/types/lib/core/1.domain/pooling/election.d.ts +41 -0
- package/types/lib/core/1.domain/pooling/gate.d.ts +64 -0
- package/types/lib/core/1.domain/pooling/membership.d.ts +19 -0
- package/types/lib/core/1.domain/pooling/plan.d.ts +11 -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/mark-dense.d.ts +2 -0
- package/types/lib/core/1.domain/remote-entry/remote-entry.contract.d.ts +5 -4
- package/types/lib/core/2.app/config/mode.contract.d.ts +9 -4
- package/types/lib/core/2.app/config/storage.contract.d.ts +6 -1
- 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/get-remote-entries.d.ts +1 -1
- 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 +5 -5
- package/types/lib/core/3.adapters/remote-entry/normalize-remote-entry.d.ts +4 -0
- package/types/lib/core/3.adapters/storage/cache-state.d.ts +5 -0
- package/types/lib/core/4.config/orchestrator-version.d.ts +1 -0
- package/types/lib/core/4.config/storage/storage.config.d.ts +3 -2
- package/types/lib/core/5.di/federation-result.factory.d.ts +1 -1
- package/types/lib/node/adapters/fs-remote-entry-provider.d.ts +2 -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/utils/union-find.d.ts +4 -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 -25
- 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 -19
- package/types/lib/testing/handlers/log.handler.d.ts +0 -3
- package/types/lib/testing/pooling/no-tear.d.ts +0 -37
- package/types/lib/testing/pooling/tag-by-npm-scope.d.ts +0 -9
|
@@ -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
|
};
|
|
@@ -1322,8 +1325,129 @@ function getScope(path) {
|
|
|
1322
1325
|
return `${parts.join("/")}/`;
|
|
1323
1326
|
}
|
|
1324
1327
|
|
|
1328
|
+
// src/lib/core/2.app/steps/store-remote-entry.ts
|
|
1329
|
+
function createRemoveCachedRemoteEntries(ports) {
|
|
1330
|
+
return (remoteNames) => {
|
|
1331
|
+
if (remoteNames.size === 0) return;
|
|
1332
|
+
for (const remoteName of remoteNames) {
|
|
1333
|
+
ports.remoteInfoRepo.remove(remoteName);
|
|
1334
|
+
ports.scopedExternalsRepo.remove(remoteName);
|
|
1335
|
+
ports.sharedChunksRepo.remove(remoteName);
|
|
1336
|
+
}
|
|
1337
|
+
ports.sharedExternalsRepo.removeFromAllScopes(remoteNames);
|
|
1338
|
+
};
|
|
1339
|
+
}
|
|
1340
|
+
function createStoreRemoteEntry(config, ports, logStep) {
|
|
1341
|
+
return (remoteEntry, onSharedExternal) => {
|
|
1342
|
+
addRemoteInfoToStorage(remoteEntry);
|
|
1343
|
+
addExternalsToStorage(remoteEntry, onSharedExternal);
|
|
1344
|
+
addSharedChunksToStorage(remoteEntry);
|
|
1345
|
+
};
|
|
1346
|
+
function addRemoteInfoToStorage({ name, url, exposes, integrity }) {
|
|
1347
|
+
ports.remoteInfoRepo.addOrUpdate(name, {
|
|
1348
|
+
scopeUrl: getScope(url),
|
|
1349
|
+
exposes: Object.values(exposes ?? []).map((m) => ({
|
|
1350
|
+
moduleName: m.key,
|
|
1351
|
+
file: m.outFileName
|
|
1352
|
+
})),
|
|
1353
|
+
...integrity ? { integrity } : {}
|
|
1354
|
+
});
|
|
1355
|
+
}
|
|
1356
|
+
function addExternalsToStorage(remoteEntry, onSharedExternal) {
|
|
1357
|
+
remoteEntry.shared.forEach((external) => {
|
|
1358
|
+
const tag = resolveVersion(remoteEntry, external);
|
|
1359
|
+
if (tag === null) return;
|
|
1360
|
+
if (external.singleton) {
|
|
1361
|
+
if (external.requiredVersion && !ports.versionCheck.isCompatible(tag, external.requiredVersion))
|
|
1362
|
+
config.log.warn(
|
|
1363
|
+
logStep,
|
|
1364
|
+
`[${remoteEntry.name}][${external.packageName}] requiredVersion '${external.requiredVersion}' excludes its own version '${tag}'; '${tag}' is still accepted for it.`
|
|
1365
|
+
);
|
|
1366
|
+
onSharedExternal(remoteEntry, external, sharedExternalContext(remoteEntry, external, tag));
|
|
1367
|
+
} else {
|
|
1368
|
+
addScopedExternal(remoteEntry, external, tag);
|
|
1369
|
+
}
|
|
1370
|
+
});
|
|
1371
|
+
}
|
|
1372
|
+
function addSharedChunksToStorage(remoteEntry) {
|
|
1373
|
+
if (!remoteEntry.chunks) return;
|
|
1374
|
+
config.log.debug(
|
|
1375
|
+
logStep,
|
|
1376
|
+
`Adding chunks for remote "${remoteEntry.name}", bundles: [${Object.keys(remoteEntry.chunks).join(", ")}]`
|
|
1377
|
+
);
|
|
1378
|
+
Object.entries(remoteEntry.chunks).forEach(([bundleName, chunks]) => {
|
|
1379
|
+
ports.sharedChunksRepo.addOrReplace(remoteEntry.name, bundleName, chunks);
|
|
1380
|
+
});
|
|
1381
|
+
}
|
|
1382
|
+
function addScopedExternal(remoteEntry, sharedInfo, tag) {
|
|
1383
|
+
ports.scopedExternalsRepo.addExternal(remoteEntry.name, sharedInfo.packageName, {
|
|
1384
|
+
tag,
|
|
1385
|
+
bundle: sharedInfo.bundle,
|
|
1386
|
+
entries: sharedInfo.entries
|
|
1387
|
+
});
|
|
1388
|
+
}
|
|
1389
|
+
function resolveVersion(remoteEntry, external) {
|
|
1390
|
+
if (external.version && ports.versionCheck.isValidSemver(external.version)) {
|
|
1391
|
+
return external.version;
|
|
1392
|
+
}
|
|
1393
|
+
const errorMsg = `[${remoteEntry.name}][${external.packageName}] Version '${external.version}' is not a valid version.`;
|
|
1394
|
+
if (config.strict.strictExternalVersion) {
|
|
1395
|
+
config.log.error(logStep, errorMsg);
|
|
1396
|
+
throw new NFError(`Could not process remote '${remoteEntry.name}'`);
|
|
1397
|
+
}
|
|
1398
|
+
if (config.profile.skipInvalidExternalVersions) {
|
|
1399
|
+
config.log.warn(logStep, `${errorMsg} Skipping external.`);
|
|
1400
|
+
return null;
|
|
1401
|
+
}
|
|
1402
|
+
config.log.warn(logStep, errorMsg);
|
|
1403
|
+
return ports.versionCheck.smallestVersion(external.requiredVersion);
|
|
1404
|
+
}
|
|
1405
|
+
function sharedExternalContext(remoteEntry, sharedInfo, tag) {
|
|
1406
|
+
const scopeType = ports.sharedExternalsRepo.scopeType(sharedInfo.shareScope);
|
|
1407
|
+
const remote = {
|
|
1408
|
+
name: remoteEntry.name,
|
|
1409
|
+
bundle: sharedInfo.bundle,
|
|
1410
|
+
strictVersion: sharedInfo.strictVersion,
|
|
1411
|
+
cached: false,
|
|
1412
|
+
requiredVersion: scopeType === "strict" ? tag : sharedInfo.requiredVersion || tag,
|
|
1413
|
+
...sharedInfo.pool?.trim() ? { pool: sharedInfo.pool } : {},
|
|
1414
|
+
...sharedInfo.dense ? { dense: true } : {},
|
|
1415
|
+
entries: sharedInfo.entries
|
|
1416
|
+
};
|
|
1417
|
+
let stored;
|
|
1418
|
+
const readRecord = () => stored ??= ports.sharedExternalsRepo.tryGet(sharedInfo.packageName, sharedInfo.shareScope).get() ?? { dirty: false, versions: [] };
|
|
1419
|
+
return {
|
|
1420
|
+
tag,
|
|
1421
|
+
remote,
|
|
1422
|
+
readRecord,
|
|
1423
|
+
scopeType,
|
|
1424
|
+
assertSameVersionCompatibility(matchingVersion) {
|
|
1425
|
+
if (!remote.strictVersion) return;
|
|
1426
|
+
if (matchingVersion.remotes[0].requiredVersion === remote.requiredVersion) return;
|
|
1427
|
+
const errorMsg = `[${remoteEntry.name}][${sharedInfo.packageName}@${sharedInfo.version}] Required version-range '${remote.requiredVersion}' does not match cached version-range '${matchingVersion.remotes[0].requiredVersion}'`;
|
|
1428
|
+
if (config.strict.strictExternalSameVersionCompatibility) {
|
|
1429
|
+
config.log.error(logStep, errorMsg);
|
|
1430
|
+
throw new NFError(`Could not process remote '${remoteEntry.name}'`);
|
|
1431
|
+
}
|
|
1432
|
+
config.log.warn(logStep, errorMsg);
|
|
1433
|
+
},
|
|
1434
|
+
write() {
|
|
1435
|
+
ports.sharedExternalsRepo.addOrUpdate(
|
|
1436
|
+
sharedInfo.packageName,
|
|
1437
|
+
{
|
|
1438
|
+
...readRecord(),
|
|
1439
|
+
versions: readRecord().versions.sort((a, b) => ports.versionCheck.compare(b.tag, a.tag))
|
|
1440
|
+
},
|
|
1441
|
+
sharedInfo.shareScope
|
|
1442
|
+
);
|
|
1443
|
+
}
|
|
1444
|
+
};
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1325
1448
|
// src/lib/core/2.app/steps/get-remote-entries.ts
|
|
1326
1449
|
function createGetRemoteEntries(config, ports) {
|
|
1450
|
+
const removeCachedRemoteEntries = createRemoveCachedRemoteEntries(ports);
|
|
1327
1451
|
return (remotesOrManifestUrl = {}) => {
|
|
1328
1452
|
const manifestPromise = config.manifestIntegrity ? ports.manifestProvider.provide(remotesOrManifestUrl, {
|
|
1329
1453
|
integrity: config.manifestIntegrity
|
|
@@ -1331,7 +1455,7 @@ function createGetRemoteEntries(config, ports) {
|
|
|
1331
1455
|
return manifestPromise.catch((e) => {
|
|
1332
1456
|
config.log.error(1, "Could not fetch manifest.", e);
|
|
1333
1457
|
return Promise.reject(new NFError("Failed to fetch manifest"));
|
|
1334
|
-
}).then(addHostRemoteEntry).then(fetchRemoteEntries).then(removeSkippedRemotes).then(checkForSSE);
|
|
1458
|
+
}).then(addHostRemoteEntry).then(dropUnlistedRemotes).then(fetchRemoteEntries).then(removeSkippedRemotes).then(checkForSSE);
|
|
1335
1459
|
};
|
|
1336
1460
|
function addHostRemoteEntry(manifest) {
|
|
1337
1461
|
if (!config.hostRemoteEntry) return manifest;
|
|
@@ -1341,6 +1465,26 @@ function createGetRemoteEntries(config, ports) {
|
|
|
1341
1465
|
[name]: integrity ? { url, integrity } : url
|
|
1342
1466
|
};
|
|
1343
1467
|
}
|
|
1468
|
+
function dropUnlistedRemotes(manifest) {
|
|
1469
|
+
if (config.profile.mergeManifests !== false) return manifest;
|
|
1470
|
+
const listedUrls = new Set(
|
|
1471
|
+
Object.values(manifest).map((descriptor) => normalizeEntry(descriptor).url)
|
|
1472
|
+
);
|
|
1473
|
+
const isListed = (remoteName, info) => Object.hasOwn(manifest, remoteName) || listedUrls.has(storedEntryUrl(info));
|
|
1474
|
+
const unlisted = new Set(
|
|
1475
|
+
Object.entries(ports.remoteInfoRepo.getAll()).filter(([remoteName, info]) => !isListed(remoteName, info)).map(([remoteName]) => remoteName)
|
|
1476
|
+
);
|
|
1477
|
+
if (unlisted.size > 0)
|
|
1478
|
+
config.log.debug(
|
|
1479
|
+
1,
|
|
1480
|
+
`Removing stored remotes the manifest doesn't list: ${[...unlisted].join(", ")}.`
|
|
1481
|
+
);
|
|
1482
|
+
removeCachedRemoteEntries(unlisted);
|
|
1483
|
+
return manifest;
|
|
1484
|
+
}
|
|
1485
|
+
function storedEntryUrl(info) {
|
|
1486
|
+
return join(info.scopeUrl, "remoteEntry.json");
|
|
1487
|
+
}
|
|
1344
1488
|
function normalizeEntry(descriptor) {
|
|
1345
1489
|
return typeof descriptor === "string" ? { url: descriptor } : descriptor;
|
|
1346
1490
|
}
|
|
@@ -1365,7 +1509,7 @@ function createGetRemoteEntries(config, ports) {
|
|
|
1365
1509
|
let isOverride = false;
|
|
1366
1510
|
let skip = false;
|
|
1367
1511
|
ports.remoteInfoRepo.tryGet(remoteName).ifPresent((cachedRemoteInfo) => {
|
|
1368
|
-
if (config.profile.overrideCachedRemotes !== "never" && (remoteEntryUrl !==
|
|
1512
|
+
if (config.profile.overrideCachedRemotes !== "never" && (remoteEntryUrl !== storedEntryUrl(cachedRemoteInfo) || config.profile.overrideCachedRemotesIfURLMatches)) {
|
|
1369
1513
|
config.log.debug(1, `Overriding existing remote '${remoteName}' with '${remoteEntryUrl}'.`);
|
|
1370
1514
|
isOverride = true;
|
|
1371
1515
|
} else {
|
|
@@ -1426,11 +1570,17 @@ function createGetRemoteEntries(config, ports) {
|
|
|
1426
1570
|
}
|
|
1427
1571
|
}
|
|
1428
1572
|
|
|
1573
|
+
// src/lib/utils/compare-strings.ts
|
|
1574
|
+
function compareStrings(a, b) {
|
|
1575
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1429
1578
|
// src/lib/core/1.domain/externals/basis.ts
|
|
1430
1579
|
var coverage = (remote) => Object.keys(remote.entries).length;
|
|
1431
1580
|
function isBetterBasis(candidate, basis) {
|
|
1432
1581
|
if (basis.cached !== candidate.cached) return candidate.cached;
|
|
1433
|
-
|
|
1582
|
+
const byCoverage = coverage(candidate) - coverage(basis);
|
|
1583
|
+
return byCoverage === 0 ? compareStrings(candidate.name, basis.name) < 0 : byCoverage > 0;
|
|
1434
1584
|
}
|
|
1435
1585
|
function addRemoteToVersion(version, remote, isHost = false) {
|
|
1436
1586
|
if (isHost) {
|
|
@@ -1454,21 +1604,6 @@ function versionDemands(version) {
|
|
|
1454
1604
|
}
|
|
1455
1605
|
return Array.from(distinct.values());
|
|
1456
1606
|
}
|
|
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
1607
|
function forEachVersionEntry(version, accepts, visit) {
|
|
1473
1608
|
for (const remote of version.remotes) {
|
|
1474
1609
|
if (remote.servedBy) continue;
|
|
@@ -1476,16 +1611,6 @@ function forEachVersionEntry(version, accepts, visit) {
|
|
|
1476
1611
|
for (const entrypoint in remote.entries) visit(entrypoint, remote);
|
|
1477
1612
|
}
|
|
1478
1613
|
}
|
|
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
1614
|
function countUncoveredEntrypoints(remote, covered) {
|
|
1490
1615
|
let uncovered = 0;
|
|
1491
1616
|
for (const entrypoint in remote.entries) {
|
|
@@ -1494,118 +1619,87 @@ function countUncoveredEntrypoints(remote, covered) {
|
|
|
1494
1619
|
return uncovered;
|
|
1495
1620
|
}
|
|
1496
1621
|
|
|
1497
|
-
// src/lib/core/
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1622
|
+
// src/lib/core/1.domain/externals/rows.ts
|
|
1623
|
+
var byTag = (compare) => (a, b) => compare(b.tag, a.tag);
|
|
1624
|
+
var rowAt = (versions, tag, action) => versions.find((v) => v.tag === tag && v.action === action);
|
|
1625
|
+
function mergeRows(versions, lead) {
|
|
1626
|
+
const merged = /* @__PURE__ */ new Map();
|
|
1627
|
+
if (lead) merged.set(`${lead.tag}|${lead.action}`, lead);
|
|
1628
|
+
return versions.filter((v) => {
|
|
1629
|
+
const key = `${v.tag}|${v.action}`;
|
|
1630
|
+
const first = merged.get(key);
|
|
1631
|
+
if (first === v) return true;
|
|
1632
|
+
if (!first) {
|
|
1633
|
+
merged.set(key, v);
|
|
1634
|
+
return true;
|
|
1505
1635
|
}
|
|
1506
|
-
|
|
1507
|
-
|
|
1636
|
+
first.remotes.push(...v.remotes);
|
|
1637
|
+
return false;
|
|
1638
|
+
});
|
|
1508
1639
|
}
|
|
1509
|
-
function
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
function addRemoteInfoToStorage({ name, url, exposes, integrity }) {
|
|
1516
|
-
ports.remoteInfoRepo.addOrUpdate(name, {
|
|
1517
|
-
scopeUrl: getScope(url),
|
|
1518
|
-
exposes: Object.values(exposes ?? []).map((m) => ({
|
|
1519
|
-
moduleName: m.key,
|
|
1520
|
-
file: m.outFileName
|
|
1521
|
-
})),
|
|
1522
|
-
...integrity ? { integrity } : {}
|
|
1523
|
-
});
|
|
1524
|
-
}
|
|
1525
|
-
function addExternalsToStorage(remoteEntry, onSharedExternal) {
|
|
1526
|
-
remoteEntry.shared.forEach((external) => {
|
|
1527
|
-
const tag = resolveVersion(remoteEntry, external);
|
|
1528
|
-
if (tag === null) return;
|
|
1529
|
-
if (external.singleton) {
|
|
1530
|
-
onSharedExternal(remoteEntry, external, sharedExternalContext(remoteEntry, external, tag));
|
|
1531
|
-
} else {
|
|
1532
|
-
addScopedExternal(remoteEntry, external, tag);
|
|
1533
|
-
}
|
|
1534
|
-
});
|
|
1640
|
+
function findVersionForTag(versions, tag) {
|
|
1641
|
+
let scoped;
|
|
1642
|
+
for (const version of versions) {
|
|
1643
|
+
if (version.tag !== tag) continue;
|
|
1644
|
+
if (version.action !== "scope") return version;
|
|
1645
|
+
scoped ??= version;
|
|
1535
1646
|
}
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1647
|
+
return scoped;
|
|
1648
|
+
}
|
|
1649
|
+
function redirectRow(version, tag, acceptsTag) {
|
|
1650
|
+
const objecting = new Set(
|
|
1651
|
+
version.remotes.filter((r) => r.strictVersion && !acceptsTag(tag, version.tag, r.requiredVersion))
|
|
1652
|
+
);
|
|
1653
|
+
if (objecting.size === 0) {
|
|
1654
|
+
version.action = "skip";
|
|
1655
|
+
return [version];
|
|
1545
1656
|
}
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
bundle: sharedInfo.bundle,
|
|
1550
|
-
entries: sharedInfo.entries
|
|
1551
|
-
});
|
|
1657
|
+
if (objecting.size === version.remotes.length) {
|
|
1658
|
+
version.action = "scope";
|
|
1659
|
+
return [version];
|
|
1552
1660
|
}
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1661
|
+
version.remotes = version.remotes.filter((r) => !objecting.has(r));
|
|
1662
|
+
version.action = "skip";
|
|
1663
|
+
return [version, { tag: version.tag, host: false, action: "scope", remotes: [...objecting] }];
|
|
1664
|
+
}
|
|
1665
|
+
function scopeRemotes(versions, remotes) {
|
|
1666
|
+
if (remotes.length === 0) return versions;
|
|
1667
|
+
const turn = new Map(remotes.map((remote, i) => [remote, i]));
|
|
1668
|
+
const moves = /* @__PURE__ */ new Map();
|
|
1669
|
+
versions.forEach((source, at) => {
|
|
1670
|
+
if (source.action === "scope") return;
|
|
1671
|
+
const byTurn = /* @__PURE__ */ new Map();
|
|
1672
|
+
for (const copy of source.remotes) {
|
|
1673
|
+
const i = turn.get(copy.name);
|
|
1674
|
+
if (i === void 0) continue;
|
|
1675
|
+
const copies = byTurn.get(i);
|
|
1676
|
+
if (copies) copies.push(copy);
|
|
1677
|
+
else byTurn.set(i, [copy]);
|
|
1561
1678
|
}
|
|
1562
|
-
if (
|
|
1563
|
-
|
|
1564
|
-
|
|
1679
|
+
if (byTurn.size === 0) return;
|
|
1680
|
+
const hostTurn = source.host ? turn.get(source.remotes[0].name) : void 0;
|
|
1681
|
+
source.remotes = source.remotes.filter((r) => !turn.has(r.name));
|
|
1682
|
+
if (hostTurn !== void 0) source.host = false;
|
|
1683
|
+
const tagMoves = moves.get(source.tag) ?? [];
|
|
1684
|
+
for (const [i, copies] of byTurn)
|
|
1685
|
+
tagMoves.push({ turn: i, at, source, copies, host: i === hostTurn });
|
|
1686
|
+
moves.set(source.tag, tagMoves);
|
|
1687
|
+
});
|
|
1688
|
+
const rows = [...versions];
|
|
1689
|
+
for (const [tag, tagMoves] of moves) {
|
|
1690
|
+
tagMoves.sort((a, b) => a.turn - b.turn || a.at - b.at);
|
|
1691
|
+
let scoped = rowAt(rows, tag, "scope");
|
|
1692
|
+
if (!scoped) {
|
|
1693
|
+
scoped = { tag, host: false, action: "scope", remotes: [] };
|
|
1694
|
+
rows.splice(rows.indexOf(tagMoves[0].source) + 1, 0, scoped);
|
|
1565
1695
|
}
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
const remote = {
|
|
1572
|
-
name: remoteEntry.name,
|
|
1573
|
-
bundle: sharedInfo.bundle,
|
|
1574
|
-
strictVersion: sharedInfo.strictVersion,
|
|
1575
|
-
cached: false,
|
|
1576
|
-
requiredVersion: scopeType === "strict" ? tag : sharedInfo.requiredVersion || tag,
|
|
1577
|
-
...sharedInfo.pool?.trim() ? { pool: sharedInfo.pool } : {},
|
|
1578
|
-
entries: sharedInfo.entries
|
|
1579
|
-
};
|
|
1580
|
-
const cached = ports.sharedExternalsRepo.tryGet(sharedInfo.packageName, sharedInfo.shareScope).get() ?? { dirty: false, versions: [] };
|
|
1581
|
-
return {
|
|
1582
|
-
tag,
|
|
1583
|
-
remote,
|
|
1584
|
-
cached,
|
|
1585
|
-
scopeType,
|
|
1586
|
-
assertSameVersionCompatibility(matchingVersion) {
|
|
1587
|
-
if (!remote.strictVersion) return;
|
|
1588
|
-
if (matchingVersion.remotes[0].requiredVersion === remote.requiredVersion) return;
|
|
1589
|
-
const errorMsg = `[${remoteEntry.name}][${sharedInfo.packageName}@${sharedInfo.version}] Required version-range '${remote.requiredVersion}' does not match cached version-range '${matchingVersion.remotes[0].requiredVersion}'`;
|
|
1590
|
-
if (config.strict.strictExternalSameVersionCompatibility) {
|
|
1591
|
-
config.log.error(logStep, errorMsg);
|
|
1592
|
-
throw new NFError(`Could not process remote '${remoteEntry.name}'`);
|
|
1593
|
-
}
|
|
1594
|
-
config.log.warn(logStep, errorMsg);
|
|
1595
|
-
},
|
|
1596
|
-
commit() {
|
|
1597
|
-
ports.sharedExternalsRepo.addOrUpdate(
|
|
1598
|
-
sharedInfo.packageName,
|
|
1599
|
-
{
|
|
1600
|
-
dirty: cached.dirty,
|
|
1601
|
-
...cached.poolName !== void 0 && { poolName: cached.poolName },
|
|
1602
|
-
versions: cached.versions.sort((a, b) => ports.versionCheck.compare(b.tag, a.tag))
|
|
1603
|
-
},
|
|
1604
|
-
sharedInfo.shareScope
|
|
1605
|
-
);
|
|
1606
|
-
}
|
|
1607
|
-
};
|
|
1696
|
+
for (const { copies, host } of tagMoves)
|
|
1697
|
+
if (host) {
|
|
1698
|
+
scoped.host = true;
|
|
1699
|
+
scoped.remotes.unshift(...copies);
|
|
1700
|
+
} else scoped.remotes.push(...copies);
|
|
1608
1701
|
}
|
|
1702
|
+
return rows.filter((v) => v.remotes.length > 0);
|
|
1609
1703
|
}
|
|
1610
1704
|
|
|
1611
1705
|
// src/lib/core/2.app/steps/process-remote-entries.ts
|
|
@@ -1643,11 +1737,12 @@ function createProcessRemoteEntries(config, ports) {
|
|
|
1643
1737
|
function addSharedExternal(remoteEntry, _sharedInfo, {
|
|
1644
1738
|
tag,
|
|
1645
1739
|
remote,
|
|
1646
|
-
|
|
1740
|
+
readRecord,
|
|
1647
1741
|
scopeType,
|
|
1648
1742
|
assertSameVersionCompatibility,
|
|
1649
|
-
|
|
1743
|
+
write
|
|
1650
1744
|
}) {
|
|
1745
|
+
const cached = readRecord();
|
|
1651
1746
|
if (scopeType !== "strict") cached.dirty = true;
|
|
1652
1747
|
const matchingVersion = findVersionForTag(cached.versions, tag);
|
|
1653
1748
|
if (matchingVersion) {
|
|
@@ -1661,7 +1756,7 @@ function createProcessRemoteEntries(config, ports) {
|
|
|
1661
1756
|
remotes: [remote]
|
|
1662
1757
|
});
|
|
1663
1758
|
}
|
|
1664
|
-
|
|
1759
|
+
write();
|
|
1665
1760
|
}
|
|
1666
1761
|
}
|
|
1667
1762
|
|
|
@@ -1669,154 +1764,70 @@ function createProcessRemoteEntries(config, ports) {
|
|
|
1669
1764
|
var GLOBAL_SCOPE = "__GLOBAL__";
|
|
1670
1765
|
var STRICT_SCOPE = "strict";
|
|
1671
1766
|
|
|
1672
|
-
// src/lib/core/
|
|
1673
|
-
function
|
|
1767
|
+
// src/lib/core/1.domain/externals/compatibility.ts
|
|
1768
|
+
function createAcceptsTag(isCompatible, compare) {
|
|
1769
|
+
return (offered, ownTag, requiredVersion) => isCompatible(offered, requiredVersion) || offered === ownTag || compare(offered, ownTag) === 0;
|
|
1770
|
+
}
|
|
1771
|
+
function versionAcceptance(external, acceptsTag) {
|
|
1674
1772
|
const demands = new Map(
|
|
1675
1773
|
external.versions.map((v) => [v, versionDemands(v)])
|
|
1676
1774
|
);
|
|
1677
1775
|
return {
|
|
1678
|
-
accepts: (version, tag) => demands.get(version).every((d) =>
|
|
1679
|
-
objector: (version, tag) => demands.get(version).find((d) => d.strictVersion && !
|
|
1776
|
+
accepts: (version, tag) => demands.get(version).every((d) => acceptsTag(tag, version.tag, d.requiredVersion)),
|
|
1777
|
+
objector: (version, tag) => demands.get(version).find((d) => d.strictVersion && !acceptsTag(tag, version.tag, d.requiredVersion))
|
|
1680
1778
|
};
|
|
1681
1779
|
}
|
|
1780
|
+
|
|
1781
|
+
// src/lib/core/2.app/steps/apply-winner.ts
|
|
1782
|
+
function rejectIncompatible(config, copy, rejected, servedAt) {
|
|
1783
|
+
config.log.error(
|
|
1784
|
+
3,
|
|
1785
|
+
`[${copy.name}][${rejected}] Is not compatible with requiredRange '${copy.requiredVersion}' of shared ${servedAt}.`
|
|
1786
|
+
);
|
|
1787
|
+
throw new NFError(`External ${rejected} could not be shared.`);
|
|
1788
|
+
}
|
|
1682
1789
|
function createApplyWinner(config) {
|
|
1683
|
-
return function applyWinner(externalName, external, winner,
|
|
1790
|
+
return function applyWinner(externalName, external, winner, acceptsTag, acceptance) {
|
|
1684
1791
|
if (external.versions.length > 1) {
|
|
1685
|
-
const { accepts, objector } = acceptance ?? versionAcceptance(external, isCompatible);
|
|
1686
1792
|
const rebuilt = [];
|
|
1687
1793
|
for (const v of external.versions) {
|
|
1688
|
-
|
|
1689
|
-
if (
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
config.log.error(
|
|
1696
|
-
3,
|
|
1697
|
-
`[${strict.name}][${externalName}@${v.tag}] Is not compatible with requiredRange '${strict.requiredVersion}' of shared ${externalName}@${winner.tag}.`
|
|
1794
|
+
const objector = config.strict.strictExternalCompatibility && acceptance.objector(v, winner.tag);
|
|
1795
|
+
if (objector)
|
|
1796
|
+
rejectIncompatible(
|
|
1797
|
+
config,
|
|
1798
|
+
objector,
|
|
1799
|
+
`${externalName}@${v.tag}`,
|
|
1800
|
+
`${externalName}@${winner.tag}`
|
|
1698
1801
|
);
|
|
1699
|
-
|
|
1700
|
-
}
|
|
1701
|
-
if (v === winner) continue;
|
|
1702
|
-
if (!strict) {
|
|
1703
|
-
v.action = "skip";
|
|
1704
|
-
continue;
|
|
1705
|
-
}
|
|
1706
|
-
const objecting = new Set(
|
|
1707
|
-
v.remotes.filter((r) => r.strictVersion && !isCompatible(winner.tag, r.requiredVersion))
|
|
1708
|
-
);
|
|
1709
|
-
if (objecting.size === v.remotes.length) {
|
|
1710
|
-
v.action = "scope";
|
|
1711
|
-
continue;
|
|
1712
|
-
}
|
|
1713
|
-
v.remotes = v.remotes.filter((r) => !objecting.has(r));
|
|
1714
|
-
v.action = "skip";
|
|
1715
|
-
rebuilt.push({ tag: v.tag, host: false, action: "scope", remotes: [...objecting] });
|
|
1802
|
+
rebuilt.push(...redirectRow(v, winner.tag, acceptsTag));
|
|
1716
1803
|
}
|
|
1717
|
-
|
|
1718
|
-
external.versions = rebuilt.filter((v) => {
|
|
1719
|
-
const first = merged.get(`${v.tag}|${v.action}`);
|
|
1720
|
-
if (!first) {
|
|
1721
|
-
merged.set(`${v.tag}|${v.action}`, v);
|
|
1722
|
-
return true;
|
|
1723
|
-
}
|
|
1724
|
-
first.remotes.push(...v.remotes);
|
|
1725
|
-
return false;
|
|
1726
|
-
});
|
|
1804
|
+
external.versions = mergeRows(rebuilt, winner);
|
|
1727
1805
|
}
|
|
1728
1806
|
winner.action = "share";
|
|
1729
|
-
applyEntrypointCoveragePolicy(externalName, external);
|
|
1730
1807
|
external.dirty = false;
|
|
1731
1808
|
return external;
|
|
1732
1809
|
};
|
|
1733
|
-
function applyEntrypointCoveragePolicy(externalName, external) {
|
|
1734
|
-
const { strictEntryPointCoverage } = config.strict;
|
|
1735
|
-
if (!strictEntryPointCoverage && !config.profile.scopeUncoveredEntrypoints) return;
|
|
1736
|
-
const tears = findTears(external);
|
|
1737
|
-
if (tears.length === 0) return;
|
|
1738
|
-
if (strictEntryPointCoverage) {
|
|
1739
|
-
const { version, remote, uncovered } = tears[0];
|
|
1740
|
-
config.log.error(
|
|
1741
|
-
3,
|
|
1742
|
-
`[${externalName}@${version.tag}][${remote.name}] Entrypoints not covered by the shared version: ${uncovered.join(", ")}.`
|
|
1743
|
-
);
|
|
1744
|
-
throw new NFError(
|
|
1745
|
-
`External ${externalName} could not be shared without tearing entrypoints.`
|
|
1746
|
-
);
|
|
1747
|
-
}
|
|
1748
|
-
scopeTornRemotes(externalName, external, tears);
|
|
1749
|
-
}
|
|
1750
|
-
function findTears(external) {
|
|
1751
|
-
const shared = external.versions.find((v) => v.action === "share");
|
|
1752
|
-
if (!shared) return [];
|
|
1753
|
-
const basis = versionEntries(shared);
|
|
1754
|
-
const tears = [];
|
|
1755
|
-
for (const version of external.versions) {
|
|
1756
|
-
if (version.action === "scope") continue;
|
|
1757
|
-
if (version === shared) continue;
|
|
1758
|
-
version.remotes.forEach((remote) => {
|
|
1759
|
-
if (remote.servedBy) return;
|
|
1760
|
-
const uncovered = uncoveredEntrypoints(remote, basis);
|
|
1761
|
-
if (uncovered.length > 0) tears.push({ version, remote, uncovered });
|
|
1762
|
-
});
|
|
1763
|
-
}
|
|
1764
|
-
return tears;
|
|
1765
|
-
}
|
|
1766
|
-
function scopeTornRemotes(externalName, external, tears) {
|
|
1767
|
-
const torn = new Set(tears.map((t) => t.remote));
|
|
1768
|
-
const demotedByTag = /* @__PURE__ */ new Map();
|
|
1769
|
-
for (const { version, remote, uncovered } of tears) {
|
|
1770
|
-
const group = demotedByTag.get(version.tag);
|
|
1771
|
-
if (group) group.push(remote);
|
|
1772
|
-
else demotedByTag.set(version.tag, [remote]);
|
|
1773
|
-
config.log.debug(
|
|
1774
|
-
3,
|
|
1775
|
-
`[${externalName}@${version.tag}][${remote.name}] Scoped: entrypoints not covered by the shared version: ${uncovered.join(", ")}.`
|
|
1776
|
-
);
|
|
1777
|
-
}
|
|
1778
|
-
for (const version of external.versions) {
|
|
1779
|
-
if (version.remotes.some((r) => torn.has(r))) {
|
|
1780
|
-
version.remotes = version.remotes.filter((r) => !torn.has(r));
|
|
1781
|
-
}
|
|
1782
|
-
}
|
|
1783
|
-
external.versions = external.versions.filter((v) => v.remotes.length > 0);
|
|
1784
|
-
for (const [tag, remotes] of demotedByTag) {
|
|
1785
|
-
const scoped = external.versions.find((v) => v.tag === tag && v.action === "scope");
|
|
1786
|
-
if (scoped) scoped.remotes.push(...remotes);
|
|
1787
|
-
else external.versions.push({ tag, host: false, action: "scope", remotes });
|
|
1788
|
-
}
|
|
1789
|
-
}
|
|
1790
1810
|
}
|
|
1791
1811
|
|
|
1792
1812
|
// src/lib/core/2.app/steps/determine-shared-externals.ts
|
|
1793
1813
|
function createDetermineSharedExternals(config, ports) {
|
|
1794
1814
|
const applyWinner = createApplyWinner(config);
|
|
1795
1815
|
return () => {
|
|
1796
|
-
const
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
if (hit === void 0) {
|
|
1801
|
-
hit = ports.versionCheck.isCompatible(tag, requiredVersion);
|
|
1802
|
-
memo.set(key, hit);
|
|
1803
|
-
}
|
|
1804
|
-
return hit;
|
|
1805
|
-
};
|
|
1806
|
-
const touched = /* @__PURE__ */ new Map();
|
|
1816
|
+
const acceptsTag = createAcceptsTag(
|
|
1817
|
+
ports.versionCheck.isCompatible,
|
|
1818
|
+
ports.versionCheck.compare
|
|
1819
|
+
);
|
|
1807
1820
|
for (const shareScope of ports.sharedExternalsRepo.getScopes()) {
|
|
1821
|
+
if (ports.sharedExternalsRepo.scopeType(shareScope) === "strict") continue;
|
|
1808
1822
|
const sharedExternals = ports.sharedExternalsRepo.getFromScope(shareScope);
|
|
1809
1823
|
try {
|
|
1810
|
-
const elected = /* @__PURE__ */ new Set();
|
|
1811
1824
|
Object.entries(sharedExternals).filter(([_, e]) => e.dirty).forEach(([name, external]) => {
|
|
1812
1825
|
ports.sharedExternalsRepo.addOrUpdate(
|
|
1813
1826
|
name,
|
|
1814
|
-
setVersionActions(name, external,
|
|
1827
|
+
setVersionActions(name, external, acceptsTag),
|
|
1815
1828
|
shareScope
|
|
1816
1829
|
);
|
|
1817
|
-
elected.add(name);
|
|
1818
1830
|
});
|
|
1819
|
-
if (elected.size > 0) touched.set(shareScope, elected);
|
|
1820
1831
|
} catch (error) {
|
|
1821
1832
|
config.log.error(
|
|
1822
1833
|
3,
|
|
@@ -1834,24 +1845,22 @@ function createDetermineSharedExternals(config, ports) {
|
|
|
1834
1845
|
);
|
|
1835
1846
|
}
|
|
1836
1847
|
}
|
|
1837
|
-
return Promise.resolve(
|
|
1848
|
+
return Promise.resolve();
|
|
1838
1849
|
};
|
|
1839
1850
|
function uncoveredTears(external, winner, accepts) {
|
|
1840
|
-
const
|
|
1851
|
+
const covered = /* @__PURE__ */ new Set();
|
|
1852
|
+
forEachVersionEntry(winner, void 0, (entrypoint) => covered.add(entrypoint));
|
|
1841
1853
|
return external.versions.reduce((sum, v) => {
|
|
1842
1854
|
if (v === winner) return sum;
|
|
1843
1855
|
if (!accepts(v, winner.tag)) return sum;
|
|
1844
|
-
return v.remotes.reduce(
|
|
1845
|
-
(n, r) => r.servedBy ? n : n + countUncoveredEntrypoints(r, basis),
|
|
1846
|
-
sum
|
|
1847
|
-
);
|
|
1856
|
+
return v.remotes.reduce((n, r) => n + countUncoveredEntrypoints(r, covered), sum);
|
|
1848
1857
|
}, 0);
|
|
1849
1858
|
}
|
|
1850
|
-
function setVersionActions(externalName, external,
|
|
1859
|
+
function setVersionActions(externalName, external, acceptsTag) {
|
|
1860
|
+
const acceptance = versionAcceptance(external, acceptsTag);
|
|
1851
1861
|
if (external.versions.length === 1) {
|
|
1852
|
-
return applyWinner(externalName, external, external.versions[0],
|
|
1862
|
+
return applyWinner(externalName, external, external.versions[0], acceptsTag, acceptance);
|
|
1853
1863
|
}
|
|
1854
|
-
const acceptance = versionAcceptance(external, isCompatible);
|
|
1855
1864
|
const { accepts } = acceptance;
|
|
1856
1865
|
let sharedVersion = external.versions.find((v) => v.host);
|
|
1857
1866
|
if (!sharedVersion && config.profile.latestSharedExternal) {
|
|
@@ -1860,6 +1869,7 @@ function createDetermineSharedExternals(config, ports) {
|
|
|
1860
1869
|
if (!sharedVersion) {
|
|
1861
1870
|
let leastExtraDownloads = Number.MAX_VALUE;
|
|
1862
1871
|
let leastTears = Number.MAX_VALUE;
|
|
1872
|
+
let leaderShared = false;
|
|
1863
1873
|
const selfServing = new Map(
|
|
1864
1874
|
external.versions.map((v) => {
|
|
1865
1875
|
const groups = /* @__PURE__ */ new Map();
|
|
@@ -1876,24 +1886,25 @@ function createDetermineSharedExternals(config, ports) {
|
|
|
1876
1886
|
return [v, [...groups.values()]];
|
|
1877
1887
|
})
|
|
1878
1888
|
);
|
|
1879
|
-
const costOf = (version, tag) => selfServing.get(version).reduce(
|
|
1889
|
+
const costOf = (version, tag) => selfServing.get(version).reduce(
|
|
1890
|
+
(n, g) => acceptsTag(tag, version.tag, g.requiredVersion) ? n : n + g.copies,
|
|
1891
|
+
0
|
|
1892
|
+
);
|
|
1880
1893
|
external.versions.forEach((vA) => {
|
|
1881
|
-
const extraDownloads = external.versions.reduce(
|
|
1882
|
-
|
|
1883
|
-
// reads — see `applyWinner`, which does not split the winner either.
|
|
1884
|
-
(sum, vB) => vB === vA ? sum : sum + costOf(vB, vA.tag),
|
|
1885
|
-
0
|
|
1886
|
-
);
|
|
1894
|
+
const extraDownloads = external.versions.reduce((sum, vB) => sum + costOf(vB, vA.tag), 0);
|
|
1895
|
+
const alreadyShared = vA.action === "share" && !!vA.remotes[0]?.cached;
|
|
1887
1896
|
if (extraDownloads < leastExtraDownloads) {
|
|
1888
1897
|
leastExtraDownloads = extraDownloads;
|
|
1889
1898
|
leastTears = uncoveredTears(external, vA, accepts);
|
|
1899
|
+
leaderShared = alreadyShared;
|
|
1890
1900
|
sharedVersion = vA;
|
|
1891
1901
|
return;
|
|
1892
1902
|
}
|
|
1893
|
-
if (extraDownloads > leastExtraDownloads) return;
|
|
1903
|
+
if (extraDownloads > leastExtraDownloads || leaderShared) return;
|
|
1894
1904
|
const tears = uncoveredTears(external, vA, accepts);
|
|
1895
|
-
if (tears < leastTears) {
|
|
1905
|
+
if (alreadyShared || tears < leastTears) {
|
|
1896
1906
|
leastTears = tears;
|
|
1907
|
+
leaderShared = alreadyShared;
|
|
1897
1908
|
sharedVersion = vA;
|
|
1898
1909
|
}
|
|
1899
1910
|
});
|
|
@@ -1901,582 +1912,619 @@ function createDetermineSharedExternals(config, ports) {
|
|
|
1901
1912
|
if (!sharedVersion) {
|
|
1902
1913
|
throw new NFError(`[${externalName}] Could not determine shared version!`);
|
|
1903
1914
|
}
|
|
1904
|
-
return applyWinner(externalName, external, sharedVersion,
|
|
1915
|
+
return applyWinner(externalName, external, sharedVersion, acceptsTag, acceptance);
|
|
1905
1916
|
}
|
|
1906
1917
|
}
|
|
1907
1918
|
|
|
1908
|
-
// src/lib/
|
|
1909
|
-
function
|
|
1910
|
-
|
|
1919
|
+
// src/lib/utils/union-find.ts
|
|
1920
|
+
function unionFind() {
|
|
1921
|
+
const parent = /* @__PURE__ */ new Map();
|
|
1922
|
+
const find = (node) => {
|
|
1923
|
+
for (let up = parent.get(node); up !== void 0; up = parent.get(node)) {
|
|
1924
|
+
const grand = parent.get(up);
|
|
1925
|
+
if (grand === void 0) return up;
|
|
1926
|
+
parent.set(node, grand);
|
|
1927
|
+
node = grand;
|
|
1928
|
+
}
|
|
1929
|
+
return node;
|
|
1930
|
+
};
|
|
1931
|
+
const union = (a, b) => {
|
|
1932
|
+
const rootA = find(a);
|
|
1933
|
+
const rootB = find(b);
|
|
1934
|
+
if (rootA !== rootB) parent.set(rootB, rootA);
|
|
1935
|
+
};
|
|
1936
|
+
return { find, union };
|
|
1911
1937
|
}
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1938
|
+
|
|
1939
|
+
// src/lib/core/1.domain/externals/specifier.ts
|
|
1940
|
+
function npmPackageOf(name) {
|
|
1941
|
+
const depth = name.startsWith("@") ? 2 : 1;
|
|
1942
|
+
let cut = -1;
|
|
1943
|
+
for (let seen = 0; seen < depth; seen++) {
|
|
1944
|
+
cut = name.indexOf("/", cut + 1);
|
|
1945
|
+
if (cut === -1) return name;
|
|
1946
|
+
}
|
|
1947
|
+
return name.slice(0, cut);
|
|
1919
1948
|
}
|
|
1920
|
-
function
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
const
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
builds.set(
|
|
1934
|
-
meta.name,
|
|
1935
|
-
own = { coverage: /* @__PURE__ */ new Map(), tags: /* @__PURE__ */ new Map(), instance: /* @__PURE__ */ new Map() }
|
|
1936
|
-
);
|
|
1937
|
-
}
|
|
1938
|
-
if (!own.instance.has(member.name)) own.instance.set(member.name, version.tag);
|
|
1939
|
-
for (const specifier in meta.entries) {
|
|
1940
|
-
own.coverage.set(specifier, meta.entries[specifier]);
|
|
1941
|
-
if (!own.tags.has(specifier)) own.tags.set(specifier, version.tag);
|
|
1942
|
-
}
|
|
1943
|
-
}
|
|
1949
|
+
function packageOfIn(scope, loading = []) {
|
|
1950
|
+
if (!declaresLibrary(scope, loading)) return npmPackageOf;
|
|
1951
|
+
const { find, union } = unionFind();
|
|
1952
|
+
const shortest = /* @__PURE__ */ new Map();
|
|
1953
|
+
for (const [name, copy] of copiesIn(scope, loading)) {
|
|
1954
|
+
const anchor = anchorOf(name, copy);
|
|
1955
|
+
for (const specifier in copy.entries) {
|
|
1956
|
+
const best = shorter(
|
|
1957
|
+
shortest.get(find(anchor)) ?? anchor,
|
|
1958
|
+
shortest.get(find(specifier)) ?? specifier
|
|
1959
|
+
);
|
|
1960
|
+
union(anchor, specifier);
|
|
1961
|
+
shortest.set(find(anchor), best);
|
|
1944
1962
|
}
|
|
1945
1963
|
}
|
|
1946
|
-
return
|
|
1964
|
+
return (specifier) => {
|
|
1965
|
+
const npm = npmPackageOf(specifier);
|
|
1966
|
+
return shortest.get(find(specifier)) ?? shortest.get(find(npm)) ?? npm;
|
|
1967
|
+
};
|
|
1947
1968
|
}
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1969
|
+
var shorter = (a, b) => b.length < a.length || b.length === a.length && compareStrings(b, a) < 0 ? b : a;
|
|
1970
|
+
function declaresLibrary(scope, loading) {
|
|
1971
|
+
const isLibrary = (name, copies) => npmPackageOf(name) !== name && copies.some((copy) => copy.dense);
|
|
1972
|
+
return loading.some(([name, copy]) => isLibrary(name, [copy])) || Object.entries(scope).some(
|
|
1973
|
+
([name, external]) => external.versions.some((version) => isLibrary(name, version.remotes))
|
|
1974
|
+
);
|
|
1975
|
+
}
|
|
1976
|
+
var anchorOf = (name, copy) => copy.dense ? name : npmPackageOf(name);
|
|
1977
|
+
function* copiesIn(scope, loading) {
|
|
1978
|
+
yield* loading;
|
|
1979
|
+
for (const [name, external] of Object.entries(scope))
|
|
1980
|
+
for (const version of external.versions) for (const copy of version.remotes) yield [name, copy];
|
|
1981
|
+
}
|
|
1982
|
+
var SpecifierTags = class extends Map {
|
|
1983
|
+
constructor(packageOf, entries = []) {
|
|
1984
|
+
super();
|
|
1985
|
+
this.packageOf = packageOf;
|
|
1986
|
+
for (const [specifier, tag] of entries) this.set(specifier, tag);
|
|
1987
|
+
}
|
|
1988
|
+
packageOf;
|
|
1989
|
+
packages = /* @__PURE__ */ new Map();
|
|
1990
|
+
set(specifier, tag) {
|
|
1991
|
+
super.set(specifier, tag);
|
|
1992
|
+
const pkg = this.packageOf(specifier);
|
|
1993
|
+
if (pkg === specifier || !this.packages.has(pkg)) this.packages.set(pkg, tag);
|
|
1994
|
+
return this;
|
|
1995
|
+
}
|
|
1996
|
+
clear() {
|
|
1997
|
+
super.clear();
|
|
1998
|
+
this.packages.clear();
|
|
1999
|
+
}
|
|
2000
|
+
pinnedTag(specifier) {
|
|
2001
|
+
return this.get(specifier) ?? this.packages.get(this.packageOf(specifier));
|
|
1960
2002
|
}
|
|
1961
|
-
|
|
2003
|
+
};
|
|
2004
|
+
function groupByPackage(items, nameOf, packageOf) {
|
|
2005
|
+
const packages = /* @__PURE__ */ new Map();
|
|
2006
|
+
for (const item of items) {
|
|
2007
|
+
const pkg = packageOf(nameOf(item));
|
|
2008
|
+
const group = packages.get(pkg);
|
|
2009
|
+
if (group) group.push(item);
|
|
2010
|
+
else packages.set(pkg, [item]);
|
|
2011
|
+
}
|
|
2012
|
+
return packages;
|
|
1962
2013
|
}
|
|
1963
|
-
|
|
1964
|
-
|
|
2014
|
+
|
|
2015
|
+
// src/lib/core/1.domain/pooling/builds.ts
|
|
2016
|
+
function copiesByRemote(members) {
|
|
2017
|
+
const shipped = /* @__PURE__ */ new Map();
|
|
1965
2018
|
for (const member of members) {
|
|
1966
|
-
const
|
|
1967
|
-
for (
|
|
1968
|
-
const
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
if (!
|
|
1973
|
-
|
|
2019
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2020
|
+
for (const version of member.external.versions)
|
|
2021
|
+
for (const meta of version.remotes) {
|
|
2022
|
+
if (seen.has(meta.name)) continue;
|
|
2023
|
+
seen.add(meta.name);
|
|
2024
|
+
let copies = shipped.get(meta.name);
|
|
2025
|
+
if (!copies) shipped.set(meta.name, copies = []);
|
|
2026
|
+
copies.push({
|
|
2027
|
+
member: member.name,
|
|
2028
|
+
tag: version.tag,
|
|
2029
|
+
requiredVersion: meta.requiredVersion,
|
|
2030
|
+
strict: meta.strictVersion,
|
|
2031
|
+
host: version.host && meta === version.remotes[0],
|
|
2032
|
+
specifiers: Object.keys(meta.entries)
|
|
2033
|
+
});
|
|
1974
2034
|
}
|
|
1975
|
-
}
|
|
1976
2035
|
}
|
|
1977
|
-
return
|
|
2036
|
+
return shipped;
|
|
1978
2037
|
}
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
2038
|
+
var specifierCount = (copies) => copies.reduce((n, copy) => n + copy.specifiers.length, 0);
|
|
2039
|
+
function buildOf(owner, copies, packageOf) {
|
|
2040
|
+
const tags = new SpecifierTags(packageOf);
|
|
2041
|
+
const tagByMember = /* @__PURE__ */ new Map();
|
|
2042
|
+
for (const copy of copies) {
|
|
2043
|
+
for (const specifier of copy.specifiers)
|
|
2044
|
+
if (!tags.has(specifier)) tags.set(specifier, copy.tag);
|
|
2045
|
+
tagByMember.set(copy.member, copy.tag);
|
|
2046
|
+
}
|
|
2047
|
+
return { owner, tags, tagByMember, host: copies.some((c) => c.host) };
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
// src/lib/core/1.domain/pooling/rules.ts
|
|
2051
|
+
function agrees(copies, tags) {
|
|
2052
|
+
for (const copy of copies)
|
|
2053
|
+
for (const s of copy.specifiers) {
|
|
2054
|
+
const tag = tags.pinnedTag(s);
|
|
2055
|
+
if (tag !== void 0 && tag !== copy.tag) return false;
|
|
1991
2056
|
}
|
|
1992
|
-
|
|
1993
|
-
return consumed;
|
|
2057
|
+
return true;
|
|
1994
2058
|
}
|
|
1995
|
-
function
|
|
1996
|
-
const
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
for (const meta of version.remotes) {
|
|
2001
|
-
if (islanded.has(meta.name)) continue;
|
|
2002
|
-
const into = meta.name === build ? served : wanted;
|
|
2003
|
-
for (const specifier in meta.entries) into.add(specifier);
|
|
2004
|
-
}
|
|
2059
|
+
function serves(copies, tags, acceptsTag) {
|
|
2060
|
+
for (const copy of copies)
|
|
2061
|
+
for (const s of copy.specifiers) {
|
|
2062
|
+
const tag = tags.get(s);
|
|
2063
|
+
if (tag === void 0 || !acceptsTag(tag, copy.tag, copy.requiredVersion)) return false;
|
|
2005
2064
|
}
|
|
2006
|
-
}
|
|
2007
|
-
for (const specifier of wanted) if (!served.has(specifier)) return false;
|
|
2008
2065
|
return true;
|
|
2009
2066
|
}
|
|
2010
|
-
function
|
|
2011
|
-
const
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
const
|
|
2015
|
-
if (
|
|
2016
|
-
|
|
2017
|
-
|
|
2067
|
+
function unwitnessedGap(copies, tags, builds) {
|
|
2068
|
+
const specifiers = copies.flatMap((c) => c.specifiers);
|
|
2069
|
+
let gap = 0;
|
|
2070
|
+
for (const build of builds) {
|
|
2071
|
+
const miss = specifiers.findIndex((s) => build.tags.pinnedTag(s) !== tags.get(s));
|
|
2072
|
+
if (miss === -1) return void 0;
|
|
2073
|
+
gap = Math.max(gap, miss);
|
|
2074
|
+
}
|
|
2075
|
+
return specifiers[gap];
|
|
2018
2076
|
}
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2077
|
+
|
|
2078
|
+
// src/lib/core/1.domain/pooling/election.ts
|
|
2079
|
+
function elect(input) {
|
|
2080
|
+
const shipped = copiesByRemote(input.members);
|
|
2081
|
+
const builds = /* @__PURE__ */ new Map();
|
|
2082
|
+
for (const [owner, copies] of shipped) builds.set(owner, buildOf(owner, copies, input.packageOf));
|
|
2083
|
+
const pool = {
|
|
2084
|
+
...input,
|
|
2085
|
+
shipped,
|
|
2086
|
+
builds,
|
|
2087
|
+
packages: new Map(
|
|
2088
|
+
[...shipped].map(([owner, copies]) => [owner, packageCopies(owner, copies, input.packageOf)])
|
|
2089
|
+
),
|
|
2090
|
+
remotes: [...shipped.keys()],
|
|
2091
|
+
servesAt: (remote, tags) => serves(shipped.get(remote), tags, input.acceptsTag),
|
|
2092
|
+
agreesAt: (remote, tags) => agrees(shipped.get(remote), tags)
|
|
2093
|
+
};
|
|
2094
|
+
const hostRemote = pool.remotes.find((r) => builds.get(r).host);
|
|
2095
|
+
const state = roundOne(pool, hostRemote);
|
|
2096
|
+
formSubpools(pool, state);
|
|
2097
|
+
addExtensions(pool, state);
|
|
2098
|
+
promote(pool, state);
|
|
2099
|
+
while (settle(pool, state)) formSubpools(pool, state);
|
|
2100
|
+
const firstSeen = new Map(pool.remotes.map((r, i) => [r, i]));
|
|
2101
|
+
const self = state.pending.sort((a, b) => firstSeen.get(a) - firstSeen.get(b));
|
|
2102
|
+
return {
|
|
2103
|
+
winner: state.winner,
|
|
2104
|
+
winnerIsHost: hostRemote !== void 0,
|
|
2105
|
+
globalTags: state.globalTags,
|
|
2106
|
+
...placeRemotes(state.globalRemotes, state.subpools, self, (r) => missOf(pool, state, r))
|
|
2107
|
+
};
|
|
2030
2108
|
}
|
|
2031
|
-
function
|
|
2032
|
-
const
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2109
|
+
function newer(pool, a, b) {
|
|
2110
|
+
for (const { name } of pool.members) {
|
|
2111
|
+
const tagA = a.tagByMember.get(name);
|
|
2112
|
+
const tagB = b.tagByMember.get(name);
|
|
2113
|
+
if (tagA === void 0 || tagB === void 0) continue;
|
|
2114
|
+
const d = pool.compare(tagA, tagB);
|
|
2115
|
+
if (d !== 0) return d;
|
|
2116
|
+
}
|
|
2117
|
+
return 0;
|
|
2039
2118
|
}
|
|
2040
|
-
function
|
|
2041
|
-
const
|
|
2042
|
-
|
|
2043
|
-
for (
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
}
|
|
2119
|
+
function rank(pool, candidates, keys) {
|
|
2120
|
+
const scored = [...candidates].sort((a, b) => compareStrings(a.build.owner, b.build.owner)).map((c) => ({ c, k: keys.map((key) => key(c)) }));
|
|
2121
|
+
scored.sort((a, b) => {
|
|
2122
|
+
for (let i = 0; i < keys.length; i++) {
|
|
2123
|
+
const d = b.k[i] - a.k[i];
|
|
2124
|
+
if (d !== 0) return d;
|
|
2047
2125
|
}
|
|
2048
|
-
|
|
2049
|
-
return arrival;
|
|
2050
|
-
}
|
|
2051
|
-
function sharedTagPerSpecifier(members, islanded) {
|
|
2052
|
-
const shared = /* @__PURE__ */ new Map();
|
|
2053
|
-
forEachGlobalClaim(members, islanded, (specifier, tag) => {
|
|
2054
|
-
if (!shared.has(specifier)) shared.set(specifier, tag);
|
|
2126
|
+
return newer(pool, b.c.build, a.c.build) || compareStrings(a.c.build.owner, b.c.build.owner);
|
|
2055
2127
|
});
|
|
2056
|
-
return
|
|
2128
|
+
return scored[0]?.c;
|
|
2057
2129
|
}
|
|
2058
|
-
function
|
|
2059
|
-
const
|
|
2060
|
-
const
|
|
2061
|
-
|
|
2062
|
-
const
|
|
2063
|
-
const
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2130
|
+
function roundOne(pool, hostRemote) {
|
|
2131
|
+
const { remotes } = pool;
|
|
2132
|
+
const scored = /* @__PURE__ */ new Map();
|
|
2133
|
+
const round1 = (hostRemote ? [hostRemote] : remotes).map((owner) => {
|
|
2134
|
+
const build = pool.builds.get(owner);
|
|
2135
|
+
const key = JSON.stringify([[...build.tags], [...build.tagByMember]]);
|
|
2136
|
+
let score = scored.get(key);
|
|
2137
|
+
if (!score) {
|
|
2138
|
+
const served = new Set(remotes.filter((r) => pool.servesAt(r, build.tags)));
|
|
2139
|
+
const agreeing = remotes.filter((r) => !served.has(r) && pool.agreesAt(r, build.tags)).length;
|
|
2140
|
+
scored.set(key, score = { served: [...served], agreeing });
|
|
2067
2141
|
}
|
|
2068
|
-
|
|
2142
|
+
return { build, ...score };
|
|
2143
|
+
});
|
|
2144
|
+
const newerThan = (c) => round1.filter((o) => newer(pool, c.build, o.build) > 0).length;
|
|
2145
|
+
const round1Winner = rank(pool, round1, [
|
|
2146
|
+
...pool.latestFirst ? [newerThan] : [],
|
|
2147
|
+
(c) => c.served.length,
|
|
2148
|
+
(c) => c.agreeing,
|
|
2149
|
+
(c) => c.build.owner === pool.previousWinner ? 1 : 0
|
|
2150
|
+
]);
|
|
2151
|
+
const winner = round1Winner.build.owner;
|
|
2152
|
+
const globalTags = new SpecifierTags(pool.packageOf, round1Winner.build.tags);
|
|
2153
|
+
const globalRemotes = /* @__PURE__ */ new Set([winner, ...round1Winner.served]);
|
|
2154
|
+
const pending = remotes.filter((r) => !globalRemotes.has(r));
|
|
2155
|
+
return { winner, globalTags, globalRemotes, extensions: /* @__PURE__ */ new Set(), subpools: [], pending };
|
|
2069
2156
|
}
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
}
|
|
2157
|
+
function formSubpools(pool, state) {
|
|
2158
|
+
const servable = new Map(
|
|
2159
|
+
state.pending.map((owner) => {
|
|
2160
|
+
const build = pool.builds.get(owner);
|
|
2161
|
+
const served = state.pending.filter((r) => pool.servesAt(r, build.tags));
|
|
2162
|
+
return [owner, { build, served }];
|
|
2163
|
+
})
|
|
2164
|
+
);
|
|
2165
|
+
for (; ; ) {
|
|
2166
|
+
const stillPending = new Set(state.pending);
|
|
2167
|
+
const candidates = state.pending.map((owner) => {
|
|
2168
|
+
const { build, served } = servable.get(owner);
|
|
2169
|
+
return { build, served: served.filter((r) => stillPending.has(r)) };
|
|
2170
|
+
}).filter((c) => c.served.includes(c.build.owner) && c.served.length >= 2);
|
|
2171
|
+
const best = rank(pool, candidates, [(c) => c.served.length]);
|
|
2172
|
+
if (!best) break;
|
|
2173
|
+
state.subpools.push({ owner: best.build.owner, remotes: best.served });
|
|
2174
|
+
state.pending = state.pending.filter((r) => !best.served.includes(r));
|
|
2089
2175
|
}
|
|
2090
|
-
return table;
|
|
2091
2176
|
}
|
|
2092
|
-
function
|
|
2093
|
-
|
|
2094
|
-
|
|
2177
|
+
function promote(pool, state) {
|
|
2178
|
+
const { globalTags, globalRemotes } = state;
|
|
2179
|
+
const takesGlobal = (remote) => pool.servesAt(remote, globalTags) && unwitnessedGap(pool.shipped.get(remote), globalTags, pool.builds.values()) === void 0;
|
|
2180
|
+
for (const remote of state.pending) if (takesGlobal(remote)) globalRemotes.add(remote);
|
|
2181
|
+
state.pending = state.pending.filter((r) => !globalRemotes.has(r));
|
|
2182
|
+
for (const subpool of state.subpools) {
|
|
2183
|
+
const moved = subpool.remotes.filter((r) => r !== subpool.owner && takesGlobal(r));
|
|
2184
|
+
for (const remote of moved) globalRemotes.add(remote);
|
|
2185
|
+
subpool.remotes = subpool.remotes.filter((r) => !moved.includes(r));
|
|
2186
|
+
}
|
|
2187
|
+
state.subpools = state.subpools.filter((subpool) => {
|
|
2188
|
+
if (subpool.remotes.length >= 2) return true;
|
|
2189
|
+
if (takesGlobal(subpool.owner)) globalRemotes.add(subpool.owner);
|
|
2190
|
+
else state.pending.push(subpool.owner);
|
|
2191
|
+
return false;
|
|
2192
|
+
});
|
|
2095
2193
|
}
|
|
2096
|
-
function
|
|
2097
|
-
const
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2194
|
+
function addExtensions(pool, state) {
|
|
2195
|
+
const { globalTags, globalRemotes } = state;
|
|
2196
|
+
const runsOn = (remote) => state.subpools.find((p) => p.remotes.includes(remote))?.owner ?? remote;
|
|
2197
|
+
const agreeing = pool.remotes.filter((r) => !globalRemotes.has(r) && pool.agreesAt(r, globalTags));
|
|
2198
|
+
const runsGlobally = (remote) => pool.agreesAt(runsOn(remote), globalTags);
|
|
2199
|
+
const offered = offers(pool, globalTags, agreeing.filter(runsGlobally));
|
|
2200
|
+
const fill = pool.builds.get(state.winner).host ? agreeing.filter((r) => !runsGlobally(r)) : [];
|
|
2201
|
+
for (const [pkg, offer] of offers(pool, globalTags, fill))
|
|
2202
|
+
if (!offered.has(pkg)) offered.set(pkg, offer);
|
|
2203
|
+
for (const [pkg, offer] of offered) {
|
|
2204
|
+
if (!offer) continue;
|
|
2205
|
+
state.extensions.add(pkg);
|
|
2206
|
+
for (const s of offer.specifiers) globalTags.set(s, offer.tag);
|
|
2103
2207
|
}
|
|
2104
|
-
return true;
|
|
2105
2208
|
}
|
|
2106
|
-
function
|
|
2107
|
-
const
|
|
2108
|
-
for (const
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
if (
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
}
|
|
2209
|
+
function packageCopies(owner, copies, packageOf) {
|
|
2210
|
+
const packages = /* @__PURE__ */ new Map();
|
|
2211
|
+
for (const copy of copies)
|
|
2212
|
+
for (const s of copy.specifiers) {
|
|
2213
|
+
const pkg = packageOf(s);
|
|
2214
|
+
const seen = packages.get(pkg);
|
|
2215
|
+
if (seen === void 0) packages.set(pkg, { owner, tag: copy.tag, specifiers: /* @__PURE__ */ new Set([s]) });
|
|
2216
|
+
else if (seen && seen.tag !== copy.tag) packages.set(pkg, null);
|
|
2217
|
+
else seen?.specifiers.add(s);
|
|
2116
2218
|
}
|
|
2117
|
-
|
|
2118
|
-
}
|
|
2119
|
-
return false;
|
|
2219
|
+
return packages;
|
|
2120
2220
|
}
|
|
2121
|
-
function
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
count++;
|
|
2132
|
-
missing ??= specifier;
|
|
2133
|
-
}
|
|
2134
|
-
if (count >= fewest) continue;
|
|
2135
|
-
fewest = count;
|
|
2136
|
-
closest = build;
|
|
2137
|
-
gap = missing ?? rejectedMember(view.instance, remote, wants, pool.acceptance) ?? gap;
|
|
2138
|
-
}
|
|
2139
|
-
return { gap, closest };
|
|
2221
|
+
function offers(pool, globalTags, remotes) {
|
|
2222
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
2223
|
+
for (const owner of remotes)
|
|
2224
|
+
for (const [pkg, copy] of pool.packages.get(owner))
|
|
2225
|
+
if (globalTags.pinnedTag(pkg) === void 0)
|
|
2226
|
+
candidates.set(pkg, [...candidates.get(pkg) ?? [], copy]);
|
|
2227
|
+
const offered = /* @__PURE__ */ new Map();
|
|
2228
|
+
for (const [pkg, copies] of candidates)
|
|
2229
|
+
offered.set(pkg, oneTag(copies) ? coveringCopy(copies) : null);
|
|
2230
|
+
return offered;
|
|
2140
2231
|
}
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2232
|
+
var oneTag = (copies) => copies.every((c) => c !== null && c.tag === copies[0].tag);
|
|
2233
|
+
function coveringCopy(candidates) {
|
|
2234
|
+
const scored = candidates.map((c) => ({
|
|
2235
|
+
c,
|
|
2236
|
+
covers: candidates.filter((o) => contains(c.specifiers, o.specifiers)).length
|
|
2237
|
+
}));
|
|
2238
|
+
scored.sort(
|
|
2239
|
+
(a, b) => b.covers - a.covers || b.c.specifiers.size - a.c.specifiers.size || compareStrings(a.c.owner, b.c.owner)
|
|
2240
|
+
);
|
|
2241
|
+
return scored[0].c;
|
|
2150
2242
|
}
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
const
|
|
2154
|
-
|
|
2155
|
-
const candidates = [...builds.keys()].sort(byPriority);
|
|
2156
|
-
const pending = new Set([...consumedMembers2.keys()].sort(byPriority));
|
|
2157
|
-
const anchored = /* @__PURE__ */ new Set();
|
|
2158
|
-
const canServe = (candidate, consumer) => {
|
|
2159
|
-
const build = builds.get(candidate);
|
|
2160
|
-
if (!covers(build.coverage, input.consumedSpecifiers.get(consumer) ?? [])) return false;
|
|
2161
|
-
return acceptsAll(acceptance, build.instance, consumer, consumedMembers2.get(consumer) ?? []);
|
|
2162
|
-
};
|
|
2163
|
-
const electAnchor = (anchor, served) => {
|
|
2164
|
-
pending.delete(anchor);
|
|
2165
|
-
assignment.set(anchor, void 0);
|
|
2166
|
-
for (const consumer of served) {
|
|
2167
|
-
pending.delete(consumer);
|
|
2168
|
-
anchored.add(consumer);
|
|
2169
|
-
assignment.set(consumer, anchor);
|
|
2170
|
-
}
|
|
2171
|
-
};
|
|
2172
|
-
for (const host of [...hosts].sort(byPriority)) {
|
|
2173
|
-
const served = [];
|
|
2174
|
-
if (builds.has(host)) {
|
|
2175
|
-
for (const consumer of pending) {
|
|
2176
|
-
if (consumer !== host && canServe(host, consumer)) served.push(consumer);
|
|
2177
|
-
}
|
|
2178
|
-
}
|
|
2179
|
-
electAnchor(host, served);
|
|
2180
|
-
}
|
|
2243
|
+
var contains = (a, b) => [...b].every((s) => a.has(s));
|
|
2244
|
+
function settle(pool, state) {
|
|
2245
|
+
const { globalTags, globalRemotes, extensions } = state;
|
|
2246
|
+
let demoted = false;
|
|
2181
2247
|
for (; ; ) {
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
for (const
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2248
|
+
const dropped = new Set([...extensions].filter((pkg) => !publishedWhole(pool, state, pkg)));
|
|
2249
|
+
if (dropped.size === 0) return demoted;
|
|
2250
|
+
for (const pkg of dropped) extensions.delete(pkg);
|
|
2251
|
+
const kept = [...globalTags].filter(([s]) => !dropped.has(pool.packageOf(s)));
|
|
2252
|
+
globalTags.clear();
|
|
2253
|
+
for (const [s, tag] of kept) globalTags.set(s, tag);
|
|
2254
|
+
for (const remote of globalRemotes)
|
|
2255
|
+
if (remote !== state.winner && !pool.servesAt(remote, globalTags)) {
|
|
2256
|
+
globalRemotes.delete(remote);
|
|
2257
|
+
const subpool = state.subpools.find(
|
|
2258
|
+
(p) => pool.servesAt(remote, pool.builds.get(p.owner).tags)
|
|
2259
|
+
);
|
|
2260
|
+
if (subpool) subpool.remotes.push(remote);
|
|
2261
|
+
else state.pending.push(remote);
|
|
2262
|
+
demoted = true;
|
|
2193
2263
|
}
|
|
2194
|
-
}
|
|
2195
|
-
if (best === void 0) break;
|
|
2196
|
-
electAnchor(best, bestServed);
|
|
2197
2264
|
}
|
|
2198
|
-
for (const consumer of pending) assignment.set(consumer, void 0);
|
|
2199
|
-
return assignment;
|
|
2200
2265
|
}
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
parent[x] = parent[parent[x]];
|
|
2220
|
-
x = parent[x];
|
|
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));
|
|
2266
|
+
function publishedWhole(pool, state, pkg) {
|
|
2267
|
+
const published = new Set([...state.globalTags.keys()].filter((s) => pool.packageOf(s) === pkg));
|
|
2268
|
+
const tag = state.globalTags.pinnedTag(pkg);
|
|
2269
|
+
return [...state.globalRemotes].some((remote) => {
|
|
2270
|
+
const copy = pool.packages.get(remote).get(pkg);
|
|
2271
|
+
return !!copy && copy.tag === tag && copy.specifiers.size === published.size && contains(copy.specifiers, published);
|
|
2272
|
+
});
|
|
2273
|
+
}
|
|
2274
|
+
function missOf(pool, state, remote) {
|
|
2275
|
+
const { globalTags } = state;
|
|
2276
|
+
const copies = pool.shipped.get(remote);
|
|
2277
|
+
let rejected;
|
|
2278
|
+
for (const copy of copies)
|
|
2279
|
+
for (const s of copy.specifiers) {
|
|
2280
|
+
const tag = globalTags.get(s);
|
|
2281
|
+
if (tag === void 0 || pool.acceptsTag(tag, copy.tag, copy.requiredVersion)) continue;
|
|
2282
|
+
if (copy.strict) return { cause: "incompatible", member: copy.member, tag, strict: true };
|
|
2283
|
+
rejected ??= { cause: "incompatible", member: copy.member, tag, strict: false };
|
|
2236
2284
|
}
|
|
2237
|
-
|
|
2285
|
+
if (rejected) return rejected;
|
|
2286
|
+
for (const copy of copies)
|
|
2287
|
+
for (const s of copy.specifiers) if (!globalTags.has(s)) return { cause: "uncovered", gap: s };
|
|
2288
|
+
const gap = unwitnessedGap(copies, globalTags, pool.builds.values());
|
|
2289
|
+
if (gap) return { cause: "uncovered", gap, unshipped: true };
|
|
2290
|
+
if (state.subpools.some((p) => p.owner === remote)) return void 0;
|
|
2291
|
+
throw new Error(`'${remote}' missed the global map with nothing it rejects or lacks.`);
|
|
2238
2292
|
}
|
|
2293
|
+
function previousWinner(members) {
|
|
2294
|
+
const winners = new Set(members.flatMap((m) => m.external.poolWinner ?? []));
|
|
2295
|
+
const [winner] = winners;
|
|
2296
|
+
if (winners.size !== 1) return void 0;
|
|
2297
|
+
const ships = members.some(
|
|
2298
|
+
(m) => m.external.versions.some((v) => v.remotes.some((r) => r.name === winner))
|
|
2299
|
+
);
|
|
2300
|
+
return ships ? winner : void 0;
|
|
2301
|
+
}
|
|
2302
|
+
function placeRemotes(globalRemotes, subpools, self, missOf2) {
|
|
2303
|
+
const misses = /* @__PURE__ */ new Map();
|
|
2304
|
+
for (const remote of [...subpools.flatMap((p) => p.remotes), ...self])
|
|
2305
|
+
misses.set(remote, missOf2(remote));
|
|
2306
|
+
const placements = /* @__PURE__ */ new Map();
|
|
2307
|
+
for (const remote of globalRemotes) placements.set(remote, { kind: "global" });
|
|
2308
|
+
for (const { owner, remotes } of subpools)
|
|
2309
|
+
for (const remote of remotes) placements.set(remote, { kind: "subpool", owner });
|
|
2310
|
+
for (const remote of self)
|
|
2311
|
+
placements.set(remote, { kind: "self", cause: misses.get(remote).cause });
|
|
2312
|
+
return { placements, misses };
|
|
2313
|
+
}
|
|
2314
|
+
|
|
2315
|
+
// src/lib/core/1.domain/pooling/membership.ts
|
|
2239
2316
|
var extNode = (name) => `ext\0${name}`;
|
|
2240
|
-
var
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
for (
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2317
|
+
var labelNode = (label) => `label\0${label}`;
|
|
2318
|
+
var labelOf = (pool) => pool?.trim() || void 0;
|
|
2319
|
+
function labelsIn(sharedExternals) {
|
|
2320
|
+
const labelsOf = /* @__PURE__ */ new Map();
|
|
2321
|
+
for (const [name, external] of Object.entries(sharedExternals))
|
|
2322
|
+
labelsOf.set(
|
|
2323
|
+
name,
|
|
2324
|
+
external.versions.flatMap((v) => v.remotes.flatMap((r) => labelOf(r.pool) ?? []))
|
|
2325
|
+
);
|
|
2326
|
+
return labelsOf;
|
|
2249
2327
|
}
|
|
2250
|
-
function
|
|
2251
|
-
const
|
|
2252
|
-
const
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
}
|
|
2258
|
-
}
|
|
2259
|
-
const declared = new Set(candidates.map((c) => c.name));
|
|
2260
|
-
for (const candidate of candidates) {
|
|
2261
|
-
const owner = owningPackage(candidate.name);
|
|
2262
|
-
if (owner !== void 0 && declared.has(owner))
|
|
2263
|
-
dsu.union(extNode(candidate.name), extNode(owner));
|
|
2328
|
+
function labelledComponents(labelsOf, packageOf) {
|
|
2329
|
+
const { find, union } = unionFind();
|
|
2330
|
+
for (const [name, labels] of labelsOf)
|
|
2331
|
+
for (const label of labels) union(extNode(name), labelNode(label));
|
|
2332
|
+
for (const name of labelsOf.keys()) {
|
|
2333
|
+
const owner = packageOf(name);
|
|
2334
|
+
if (owner !== name) union(extNode(name), extNode(owner));
|
|
2264
2335
|
}
|
|
2265
2336
|
const byComponent = /* @__PURE__ */ new Map();
|
|
2266
|
-
for (const
|
|
2267
|
-
const root =
|
|
2268
|
-
const
|
|
2269
|
-
|
|
2270
|
-
}
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2337
|
+
for (const name of labelsOf.keys()) {
|
|
2338
|
+
const root = find(extNode(name));
|
|
2339
|
+
const names = byComponent.get(root) ?? byComponent.set(root, []).get(root);
|
|
2340
|
+
names.push(name);
|
|
2341
|
+
}
|
|
2342
|
+
return [...byComponent.values()].filter((names) => names.some((n) => labelsOf.get(n).length > 0));
|
|
2343
|
+
}
|
|
2344
|
+
function buildPools(sharedExternals, packageOf = packageOfIn(sharedExternals)) {
|
|
2345
|
+
const labelsOf = labelsIn(sharedExternals);
|
|
2346
|
+
const pools = /* @__PURE__ */ new Map();
|
|
2347
|
+
const labelledAlone = [];
|
|
2348
|
+
for (const names of labelledComponents(labelsOf, packageOf)) {
|
|
2349
|
+
if (names.length < 2) labelledAlone.push(names[0]);
|
|
2350
|
+
else {
|
|
2351
|
+
const members = names.map((name) => ({ name, external: sharedExternals[name] }));
|
|
2352
|
+
pools.set(
|
|
2353
|
+
mostDeclaredLabel(members, labelsOf),
|
|
2354
|
+
members.sort((a, b) => compareStrings(a.name, b.name))
|
|
2355
|
+
);
|
|
2284
2356
|
}
|
|
2285
|
-
pools.push(members);
|
|
2286
|
-
}
|
|
2287
|
-
pools.sort((a, b) => a[0].name.localeCompare(b[0].name));
|
|
2288
|
-
const named = /* @__PURE__ */ new Map();
|
|
2289
|
-
for (const members of pools) {
|
|
2290
|
-
const label = mostDeclaredTag(members) ?? members[0].name;
|
|
2291
|
-
let name = label;
|
|
2292
|
-
for (let n = 2; named.has(name); n++) name = `${label}~${n}`;
|
|
2293
|
-
named.set(
|
|
2294
|
-
name,
|
|
2295
|
-
members.map((m) => m.value)
|
|
2296
|
-
);
|
|
2297
2357
|
}
|
|
2298
|
-
return
|
|
2358
|
+
return { pools, labelledAlone, packageOf };
|
|
2299
2359
|
}
|
|
2300
|
-
function
|
|
2360
|
+
function pooledPackagesWith(sharedExternals, copies, packageOf) {
|
|
2361
|
+
const labelsOf = labelsIn(sharedExternals);
|
|
2362
|
+
for (const { name, pool } of copies) {
|
|
2363
|
+
const labels = labelsOf.get(name) ?? [];
|
|
2364
|
+
const label = labelOf(pool);
|
|
2365
|
+
labelsOf.set(name, label === void 0 ? labels : [...labels, label]);
|
|
2366
|
+
}
|
|
2367
|
+
return new Set(
|
|
2368
|
+
labelledComponents(labelsOf, packageOf).filter((names) => names.length > 1).flatMap((names) => names.map(packageOf))
|
|
2369
|
+
);
|
|
2370
|
+
}
|
|
2371
|
+
function mostDeclaredLabel(members, labelsOf) {
|
|
2301
2372
|
const counts = /* @__PURE__ */ new Map();
|
|
2302
2373
|
for (const member of members)
|
|
2303
|
-
for (const
|
|
2304
|
-
let best;
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
if (count > top || count === top &&
|
|
2308
|
-
|
|
2374
|
+
for (const label of labelsOf.get(member.name)) counts.set(label, (counts.get(label) ?? 0) + 1);
|
|
2375
|
+
let best = "";
|
|
2376
|
+
let top = 0;
|
|
2377
|
+
for (const [label, count] of counts)
|
|
2378
|
+
if (count > top || count === top && compareStrings(label, best) < 0)
|
|
2379
|
+
[best, top] = [label, count];
|
|
2309
2380
|
return best;
|
|
2310
2381
|
}
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
const tag = r.pool?.trim();
|
|
2318
|
-
return tag ? [{ remote: r.name, tag }] : [];
|
|
2319
|
-
})
|
|
2320
|
-
),
|
|
2321
|
-
value: { name, external }
|
|
2322
|
-
})
|
|
2382
|
+
|
|
2383
|
+
// src/lib/core/1.domain/pooling/pool-state.ts
|
|
2384
|
+
function hasPoolResults(external) {
|
|
2385
|
+
if (external.poolName !== void 0 || external.poolWinner !== void 0) return true;
|
|
2386
|
+
return external.versions.some(
|
|
2387
|
+
(v) => v.remotes.some((r) => r.servedBy !== void 0 || r.poolCause !== void 0)
|
|
2323
2388
|
);
|
|
2324
|
-
|
|
2389
|
+
}
|
|
2390
|
+
function scopeHasPoolState(scope) {
|
|
2391
|
+
for (const name in scope) {
|
|
2392
|
+
const external = scope[name];
|
|
2393
|
+
if (hasPoolResults(external)) return true;
|
|
2394
|
+
for (const version of external.versions)
|
|
2395
|
+
for (const remote of version.remotes) if (remote.pool?.trim()) return true;
|
|
2396
|
+
}
|
|
2397
|
+
return false;
|
|
2325
2398
|
}
|
|
2326
2399
|
|
|
2327
|
-
// src/lib/core/
|
|
2328
|
-
function
|
|
2329
|
-
|
|
2330
|
-
|
|
2400
|
+
// src/lib/core/1.domain/pooling/records.ts
|
|
2401
|
+
function memberRecord(member, pool, compare) {
|
|
2402
|
+
const { globalTags, placements } = pool;
|
|
2403
|
+
let sharedTag = globalTags.get(member.name);
|
|
2404
|
+
for (const version of member.external.versions)
|
|
2405
|
+
for (const meta of version.remotes)
|
|
2406
|
+
for (const s in meta.entries) sharedTag ??= globalTags.get(s);
|
|
2407
|
+
const claimsGlobally = (name) => placements.get(name).kind === "global";
|
|
2408
|
+
const placed = [];
|
|
2409
|
+
let winnerRow;
|
|
2410
|
+
const place = (tag, action, meta) => {
|
|
2411
|
+
const row = { tag, host: false, action, remotes: [meta] };
|
|
2412
|
+
placed.push(row);
|
|
2413
|
+
if (meta.name !== pool.winner) return;
|
|
2414
|
+
winnerRow = row;
|
|
2415
|
+
row.host = pool.winnerIsHost;
|
|
2416
|
+
};
|
|
2417
|
+
for (const version of member.external.versions)
|
|
2418
|
+
for (const stored of version.remotes) {
|
|
2419
|
+
const { servedBy: _servedBy, poolCause: _poolCause, ...rest } = stored;
|
|
2420
|
+
const meta = { ...rest, cached: false };
|
|
2421
|
+
const placement = placements.get(meta.name);
|
|
2422
|
+
if (placement.kind === "global")
|
|
2423
|
+
place(version.tag, version.tag === sharedTag ? "share" : "skip", meta);
|
|
2424
|
+
else if (placement.kind === "subpool")
|
|
2425
|
+
place(version.tag, "skip", { ...meta, servedBy: placement.owner });
|
|
2426
|
+
else place(version.tag, "scope", { ...meta, poolCause: placement.cause });
|
|
2427
|
+
}
|
|
2428
|
+
const rows = mergeRows(placed, winnerRow);
|
|
2429
|
+
for (const row of rows)
|
|
2430
|
+
row.remotes.sort((a, b) => Number(!claimsGlobally(a.name)) - Number(!claimsGlobally(b.name)));
|
|
2431
|
+
const order = { share: 0, skip: 1, scope: 2 };
|
|
2432
|
+
const newest = byTag(compare);
|
|
2433
|
+
const versions = rows.sort((a, b) => newest(a, b) || order[a.action] - order[b.action]);
|
|
2434
|
+
return { dirty: false, poolName: pool.poolName, versions };
|
|
2331
2435
|
}
|
|
2332
|
-
function
|
|
2333
|
-
return
|
|
2334
|
-
...new Set(members.flatMap((m) => m.external.versions.flatMap((v) => v.remotes.map((r) => r.name))))
|
|
2335
|
-
];
|
|
2436
|
+
function movedRecord(external, remote, move, compare) {
|
|
2437
|
+
return withoutStaleServingBuild(moveCopy(external, remote, move, compare));
|
|
2336
2438
|
}
|
|
2337
|
-
function
|
|
2338
|
-
|
|
2439
|
+
function withoutStaleServingBuild(record) {
|
|
2440
|
+
const { servingBuild, ...rest } = record;
|
|
2441
|
+
if (servingBuild === void 0) return record;
|
|
2442
|
+
const shares = record.versions.some(
|
|
2443
|
+
(v) => v.action === "share" && v.remotes.some((r) => r.name === servingBuild)
|
|
2444
|
+
);
|
|
2445
|
+
return shares ? record : rest;
|
|
2339
2446
|
}
|
|
2340
|
-
function
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
const
|
|
2345
|
-
if (
|
|
2346
|
-
|
|
2347
|
-
const {
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
}
|
|
2447
|
+
function moveCopy(external, remote, move, compare) {
|
|
2448
|
+
if ("fromMap" in move) return recordFromMap(external, remote);
|
|
2449
|
+
const moved = [];
|
|
2450
|
+
const versions = external.versions.map((v) => {
|
|
2451
|
+
const copy = v.remotes.find((r) => r.name === remote);
|
|
2452
|
+
if (!copy) return v;
|
|
2453
|
+
const { servedBy: _servedBy, ...rest } = copy;
|
|
2454
|
+
const meta = { ...rest, cached: true, poolCause: move.cause };
|
|
2455
|
+
if (v.action === "scope")
|
|
2456
|
+
return { ...v, remotes: v.remotes.map((r) => r === copy ? meta : r) };
|
|
2457
|
+
moved.push({ tag: v.tag, meta });
|
|
2458
|
+
return { ...v, remotes: v.remotes.filter((r) => r !== copy) };
|
|
2459
|
+
}).filter((v) => v.remotes.length > 0);
|
|
2460
|
+
for (const { tag, meta } of moved) {
|
|
2461
|
+
const scoped = rowAt(versions, tag, "scope");
|
|
2462
|
+
if (!scoped) versions.push({ tag, action: "scope", host: false, remotes: [meta] });
|
|
2463
|
+
else versions[versions.indexOf(scoped)] = { ...scoped, remotes: [...scoped.remotes, meta] };
|
|
2464
|
+
}
|
|
2465
|
+
return { ...external, versions: versions.sort(byTag(compare)) };
|
|
2360
2466
|
}
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
return islanded;
|
|
2467
|
+
function recordFromMap(external, remote) {
|
|
2468
|
+
const opened = external.versions.find(
|
|
2469
|
+
(v) => v.action !== "skip" && v.remotes.some((r) => r.name === remote)
|
|
2470
|
+
);
|
|
2471
|
+
const meta = { ...opened.remotes.find((r) => r.name === remote), cached: false };
|
|
2472
|
+
const joined = rowAt(external.versions, opened.tag, "skip");
|
|
2473
|
+
const into = joined ? { ...joined, remotes: [...joined.remotes] } : { ...opened, action: "skip", remotes: [] };
|
|
2474
|
+
addRemoteToVersion(into, meta);
|
|
2475
|
+
const versions = external.versions.flatMap((v) => {
|
|
2476
|
+
if (v === joined) return [into];
|
|
2477
|
+
if (v !== opened) return [v];
|
|
2478
|
+
const left = { ...v, remotes: v.remotes.filter((r) => r.name !== remote) };
|
|
2479
|
+
return [...left.remotes.length > 0 ? [left] : [], ...joined ? [] : [into]];
|
|
2480
|
+
});
|
|
2481
|
+
return { ...external, versions };
|
|
2377
2482
|
}
|
|
2378
|
-
|
|
2379
|
-
const
|
|
2380
|
-
return
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
if (basis.get(name) !== build) byMember.set(name, build);
|
|
2388
|
-
}
|
|
2389
|
-
if (byMember.size > 0) served.set(remote, byMember);
|
|
2390
|
-
}
|
|
2391
|
-
return served;
|
|
2483
|
+
function withoutPoolResults(external) {
|
|
2484
|
+
const { poolName: _poolName, poolWinner: _poolWinner, ...rest } = external;
|
|
2485
|
+
return {
|
|
2486
|
+
...rest,
|
|
2487
|
+
versions: external.versions.map((v) => ({
|
|
2488
|
+
...v,
|
|
2489
|
+
remotes: v.remotes.map(({ servedBy: _servedBy, poolCause: _poolCause, ...meta }) => meta)
|
|
2490
|
+
}))
|
|
2491
|
+
};
|
|
2392
2492
|
}
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
);
|
|
2398
|
-
|
|
2399
|
-
const { suspect, selfServed } = movedRemotes(members, islanded, basis, served, hosts);
|
|
2400
|
-
if (suspect.size === 0) return [];
|
|
2401
|
-
const builds = liveBuilds(members, islanded);
|
|
2402
|
-
const shared = sharedTagPerSpecifier(members, islanded);
|
|
2403
|
-
const own = ownCopies(members, suspect);
|
|
2404
|
-
const torn = [];
|
|
2405
|
-
for (const remote of suspect) {
|
|
2406
|
-
const copies = own.get(remote) ?? [];
|
|
2407
|
-
const mine = selfServed.get(remote);
|
|
2408
|
-
const anchors = served.get(remote);
|
|
2409
|
-
const ownTags = /* @__PURE__ */ new Map();
|
|
2410
|
-
const resolved = /* @__PURE__ */ new Map();
|
|
2411
|
-
for (const copy of copies) {
|
|
2412
|
-
const from = mine?.has(copy.member) ? remote : anchors?.get(copy.member);
|
|
2413
|
-
for (const specifier in copy.entries) {
|
|
2414
|
-
if (!ownTags.has(specifier)) ownTags.set(specifier, copy.tag);
|
|
2415
|
-
const tag = from === remote ? copy.tag : from !== void 0 ? builds.get(from)?.tags.get(specifier) : shared.get(specifier);
|
|
2416
|
-
if (tag !== void 0 && !resolved.has(specifier)) resolved.set(specifier, tag);
|
|
2417
|
-
}
|
|
2418
|
-
}
|
|
2419
|
-
if (resolved.size === 0) continue;
|
|
2420
|
-
if (ships(ownTags, resolved)) continue;
|
|
2421
|
-
let witnessed = false;
|
|
2422
|
-
for (const [, build] of builds) {
|
|
2423
|
-
if (ships(build.tags, resolved)) {
|
|
2424
|
-
witnessed = true;
|
|
2425
|
-
break;
|
|
2426
|
-
}
|
|
2427
|
-
}
|
|
2428
|
-
if (!witnessed) {
|
|
2429
|
-
torn.push({
|
|
2430
|
-
remote,
|
|
2431
|
-
combination: [...resolved].map(([specifier, tag]) => `${specifier}@${tag}`).join(", ")
|
|
2432
|
-
});
|
|
2433
|
-
}
|
|
2434
|
-
}
|
|
2435
|
-
return torn;
|
|
2493
|
+
function renamedRecords(scope, pools) {
|
|
2494
|
+
const renamed = [];
|
|
2495
|
+
for (const [poolName, members] of pools)
|
|
2496
|
+
for (const { name } of members)
|
|
2497
|
+
if (scope[name].poolName !== poolName) renamed.push([name, { ...scope[name], poolName }]);
|
|
2498
|
+
return renamed;
|
|
2436
2499
|
}
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
};
|
|
2442
|
-
|
|
2443
|
-
const
|
|
2444
|
-
const
|
|
2445
|
-
const
|
|
2446
|
-
if (!
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
for (const member of members) {
|
|
2450
|
-
const unpublished = !basis.has(member.name);
|
|
2451
|
-
for (const version of member.external.versions) {
|
|
2452
|
-
const scoped = version.action === "scope";
|
|
2453
|
-
if (!unpublished && !scoped) continue;
|
|
2454
|
-
for (const meta of version.remotes) {
|
|
2455
|
-
add(meta.name);
|
|
2456
|
-
const servesItself = scoped || unpublished && served.get(meta.name)?.get(member.name) === void 0;
|
|
2457
|
-
if (!servesItself) continue;
|
|
2458
|
-
let mine = selfServed.get(meta.name);
|
|
2459
|
-
if (!mine) selfServed.set(meta.name, mine = /* @__PURE__ */ new Set());
|
|
2460
|
-
mine.add(member.name);
|
|
2461
|
-
}
|
|
2462
|
-
}
|
|
2463
|
-
}
|
|
2464
|
-
return { suspect, selfServed };
|
|
2500
|
+
|
|
2501
|
+
// src/lib/core/1.domain/pooling/plan.ts
|
|
2502
|
+
function planElection(scope, poolable) {
|
|
2503
|
+
if (!poolable || !Object.values(scope).some((external) => external.dirty) || !scopeHasPoolState(scope))
|
|
2504
|
+
return { pools: /* @__PURE__ */ new Map(), stripped: /* @__PURE__ */ new Map(), labelledAlone: [], packageOf: npmPackageOf };
|
|
2505
|
+
const { pools, labelledAlone, packageOf } = buildPools(scope);
|
|
2506
|
+
const pooled = new Set([...pools.values()].flatMap((members) => members.map((m) => m.name)));
|
|
2507
|
+
const stripped = /* @__PURE__ */ new Map();
|
|
2508
|
+
for (const [name, external] of Object.entries(scope))
|
|
2509
|
+
if (!pooled.has(name) && hasPoolResults(external))
|
|
2510
|
+
stripped.set(name, { ...withoutPoolResults(external), dirty: true });
|
|
2511
|
+
return { pools, stripped, labelledAlone, packageOf };
|
|
2465
2512
|
}
|
|
2513
|
+
|
|
2514
|
+
// src/lib/core/2.app/steps/pooling/pool-shared-externals.ts
|
|
2466
2515
|
function createPoolSharedExternals(config, ports) {
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
const sharedExternals =
|
|
2516
|
+
const { compare } = ports.versionCheck;
|
|
2517
|
+
return () => {
|
|
2518
|
+
const repo = ports.sharedExternalsRepo;
|
|
2519
|
+
for (const scope of repo.getScopes()) {
|
|
2520
|
+
const sharedExternals = repo.getFromScope(scope);
|
|
2472
2521
|
try {
|
|
2473
|
-
const
|
|
2474
|
-
|
|
2475
|
-
for (const [poolName, members] of pools)
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
syncPoolNames(sharedExternals, pools, ports.sharedExternalsRepo, scope, rebuilt);
|
|
2522
|
+
const plan = planElection(sharedExternals, repo.scopeType(scope) !== "strict");
|
|
2523
|
+
logPlan(plan, sharedExternals, scope);
|
|
2524
|
+
for (const [poolName, members] of plan.pools)
|
|
2525
|
+
for (const [name, record] of poolRecords(poolName, members, plan.packageOf, scope))
|
|
2526
|
+
repo.addOrUpdate(name, record, scope);
|
|
2527
|
+
for (const [name, external] of plan.stripped) repo.addOrUpdate(name, external, scope);
|
|
2480
2528
|
} catch (error) {
|
|
2481
2529
|
if (error instanceof NFError) return Promise.reject(error);
|
|
2482
2530
|
config.log.error(3, `[${scope}] failed to pool shared externals.`, {
|
|
@@ -2490,253 +2538,440 @@ function createPoolSharedExternals(config, ports) {
|
|
|
2490
2538
|
}
|
|
2491
2539
|
return Promise.resolve();
|
|
2492
2540
|
};
|
|
2493
|
-
function
|
|
2494
|
-
if (
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
ports.sharedExternalsRepo.addOrUpdate(
|
|
2501
|
-
member.name,
|
|
2502
|
-
rebuildMember(poolName, member, /* @__PURE__ */ new Map(), /* @__PURE__ */ new Map(), basis2.get(member.name)),
|
|
2503
|
-
scope
|
|
2504
|
-
);
|
|
2505
|
-
return true;
|
|
2506
|
-
}
|
|
2507
|
-
const islanded = islandedRemotes(members);
|
|
2508
|
-
const consumed = consumedMembers(members);
|
|
2509
|
-
const hosts = hostRemotes(members);
|
|
2510
|
-
const views = {
|
|
2511
|
-
consumedSpecifiers: lazy(() => consumedSpecifiers(members)),
|
|
2512
|
-
acceptance: lazy(() => acceptanceTable(members, ports.versionCheck.isCompatible)),
|
|
2513
|
-
arrival: lazy(() => arrivalOrder(members))
|
|
2514
|
-
};
|
|
2515
|
-
config.log.debug(
|
|
2516
|
-
3,
|
|
2517
|
-
`[${scope}][pool:${poolName}] ${members.length} members across ${allRemotes.length} remotes, incompatible={${[...islanded.keys()].join(", ") || "\u2205"}}
|
|
2518
|
-
` + members.map((m) => ` - ${m.name}`).join("\n")
|
|
2519
|
-
);
|
|
2520
|
-
const assign = () => {
|
|
2521
|
-
const serving2 = assignServingBuilds(members, islanded, consumed, hosts, views);
|
|
2522
|
-
const basis2 = basisFor(members, islanded, serving2);
|
|
2523
|
-
return { serving: serving2, basis: basis2, served: servedPerRemote(consumed, serving2, basis2) };
|
|
2524
|
-
};
|
|
2525
|
-
let { serving, basis, served } = assign();
|
|
2526
|
-
if (islanded.size === 0 && serving.size === 0 && !anyVerdictStored(members)) return false;
|
|
2527
|
-
for (; ; ) {
|
|
2528
|
-
const torn = findTornRemotes(members, islanded, basis, served, hosts);
|
|
2529
|
-
if (torn.length === 0) break;
|
|
2530
|
-
for (const { remote, combination } of torn)
|
|
2531
|
-
islanded.set(remote, { kind: "torn", combination });
|
|
2532
|
-
({ serving, basis, served } = assign());
|
|
2541
|
+
function logPlan(plan, sharedExternals, scope) {
|
|
2542
|
+
if (plan.pools.size > 0) {
|
|
2543
|
+
const dirty = Object.values(sharedExternals).filter((external) => external.dirty).length;
|
|
2544
|
+
config.log.debug(
|
|
2545
|
+
3,
|
|
2546
|
+
`[${scope}] re-electing ${plan.pools.size} pool(s): ${dirty} dirty external(s).`
|
|
2547
|
+
);
|
|
2533
2548
|
}
|
|
2534
|
-
|
|
2535
|
-
|
|
2549
|
+
if (plan.stripped.size > 0)
|
|
2550
|
+
config.log.debug(
|
|
2551
|
+
3,
|
|
2552
|
+
`[${scope}] ${plan.stripped.size} external(s) left every pool; cleared their pool state for re-election.`
|
|
2553
|
+
);
|
|
2554
|
+
for (const name of plan.labelledAlone)
|
|
2555
|
+
config.log.debug(
|
|
2556
|
+
3,
|
|
2557
|
+
`[${scope}] '${name}' has a 'pool' label that joins no other external; likely a typo or a missing sibling.`
|
|
2558
|
+
);
|
|
2559
|
+
}
|
|
2560
|
+
function poolRecords(poolName, members, packageOf, scope) {
|
|
2561
|
+
const election = elect({
|
|
2562
|
+
members,
|
|
2563
|
+
packageOf,
|
|
2564
|
+
acceptsTag: createAcceptsTag(ports.versionCheck.isCompatible, compare),
|
|
2565
|
+
compare,
|
|
2566
|
+
previousWinner: previousWinner(members),
|
|
2567
|
+
latestFirst: config.profile.latestSharedExternal
|
|
2568
|
+
});
|
|
2569
|
+
const placed = { ...election, poolName };
|
|
2570
|
+
report(poolName, members, placed, scope);
|
|
2571
|
+
return members.map((m) => [
|
|
2572
|
+
m.name,
|
|
2573
|
+
{ ...memberRecord(m, placed, compare), poolWinner: placed.winner }
|
|
2574
|
+
]);
|
|
2575
|
+
}
|
|
2576
|
+
function report(poolName, members, placed, scope) {
|
|
2577
|
+
const { misses } = placed;
|
|
2578
|
+
const rejecting = [...misses].filter(([, miss]) => miss?.cause === "incompatible" && miss.strict).map(([remote]) => remote);
|
|
2579
|
+
if (config.strict.strictExternalCompatibility && rejecting.length > 0) {
|
|
2536
2580
|
config.log.error(
|
|
2537
2581
|
3,
|
|
2538
|
-
`[${scope}][pool:${poolName}] version-incompatible remotes cannot be pooled: {${
|
|
2582
|
+
`[${scope}][pool:${poolName}] version-incompatible remotes cannot be pooled: {${rejecting.join(", ")}}.`
|
|
2539
2583
|
);
|
|
2540
2584
|
throw new NFError(`Could not pool '${poolName}' in scope ${scope}.`);
|
|
2541
2585
|
}
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
for (; ; ) {
|
|
2555
|
-
const bases = servingBuilds(members, islanded);
|
|
2556
|
-
const distinct = new Set(bases.values());
|
|
2557
|
-
if (distinct.size === 1 && bases.size === members.length) {
|
|
2558
|
-
const sole = [...distinct][0];
|
|
2559
|
-
if (coversWholePool(members, sole, islanded)) return /* @__PURE__ */ new Map();
|
|
2560
|
-
}
|
|
2561
|
-
const builds = liveBuilds(members, islanded);
|
|
2562
|
-
const shared = sharedTagPerSpecifier(members, islanded);
|
|
2563
|
-
const consumedSpec = views.consumedSpecifiers();
|
|
2564
|
-
const needAnchor = /* @__PURE__ */ new Map();
|
|
2565
|
-
const needSpecifiers = /* @__PURE__ */ new Map();
|
|
2566
|
-
for (const [remote, wants] of consumed) {
|
|
2567
|
-
if (islanded.has(remote)) continue;
|
|
2568
|
-
if (isWitnessed(consumedSpec.get(remote) ?? [], shared, builds)) continue;
|
|
2569
|
-
needAnchor.set(remote, wants);
|
|
2570
|
-
needSpecifiers.set(remote, consumedSpec.get(remote) ?? /* @__PURE__ */ new Set());
|
|
2571
|
-
}
|
|
2572
|
-
if (needAnchor.size === 0) return /* @__PURE__ */ new Map();
|
|
2573
|
-
const acceptance = views.acceptance();
|
|
2574
|
-
const assignment = assignAnchors({
|
|
2575
|
-
builds,
|
|
2576
|
-
acceptance,
|
|
2577
|
-
consumedSpecifiers: needSpecifiers,
|
|
2578
|
-
consumedMembers: needAnchor,
|
|
2579
|
-
hosts,
|
|
2580
|
-
arrival: views.arrival()
|
|
2581
|
-
});
|
|
2582
|
-
const anchors = /* @__PURE__ */ new Set();
|
|
2583
|
-
for (const build of assignment.values()) if (build !== void 0) anchors.add(build);
|
|
2584
|
-
const serving = /* @__PURE__ */ new Map();
|
|
2585
|
-
let scoped = false;
|
|
2586
|
-
for (const [remote, wants] of needAnchor) {
|
|
2587
|
-
const assigned = assignment.get(remote);
|
|
2588
|
-
const build = assigned ?? (anchors.has(remote) || hosts.has(remote) ? remote : void 0);
|
|
2589
|
-
if (build === void 0) {
|
|
2590
|
-
islanded.set(remote, {
|
|
2591
|
-
kind: "uncovered",
|
|
2592
|
-
...explainSelfServe(remote, wants, needSpecifiers.get(remote), { builds, acceptance })
|
|
2593
|
-
});
|
|
2594
|
-
scoped = true;
|
|
2595
|
-
continue;
|
|
2596
|
-
}
|
|
2597
|
-
serving.set(remote, build);
|
|
2586
|
+
const subpoolSizes = /* @__PURE__ */ new Map();
|
|
2587
|
+
for (const placement of placed.placements.values())
|
|
2588
|
+
if (placement.kind === "subpool")
|
|
2589
|
+
subpoolSizes.set(placement.owner, (subpoolSizes.get(placement.owner) ?? 0) + 1);
|
|
2590
|
+
let shipped;
|
|
2591
|
+
for (const [remote, miss] of misses) {
|
|
2592
|
+
if (miss === void 0) {
|
|
2593
|
+
config.log.warn(
|
|
2594
|
+
3,
|
|
2595
|
+
`[${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.`
|
|
2596
|
+
);
|
|
2597
|
+
continue;
|
|
2598
2598
|
}
|
|
2599
|
-
|
|
2599
|
+
shipped ??= copiesByRemote(members);
|
|
2600
|
+
const counts = {
|
|
2601
|
+
imports: specifierCount(shipped.get(remote)),
|
|
2602
|
+
subpoolSize: subpoolSizes.get(remote) ?? 0
|
|
2603
|
+
};
|
|
2604
|
+
config.log.warn(
|
|
2605
|
+
3,
|
|
2606
|
+
`[${scope}][pool:${poolName}] ${missWarning(remote, miss, placed, counts)}`
|
|
2607
|
+
);
|
|
2600
2608
|
}
|
|
2601
2609
|
}
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2610
|
+
}
|
|
2611
|
+
function missWarning(remote, miss, placed, counts) {
|
|
2612
|
+
const { imports, subpoolSize } = counts;
|
|
2613
|
+
const placement = placed.placements.get(remote);
|
|
2614
|
+
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.`;
|
|
2615
|
+
if (miss.cause === "incompatible")
|
|
2616
|
+
return `'${remote}' is islanded: its range rejects '${miss.member}@${miss.tag}' of the elected build '${placed.winner}'. ${where}`;
|
|
2617
|
+
if (miss.unshipped)
|
|
2618
|
+
return `'${remote}' serves its own family: no build shipped its entrypoints together at the elected versions (gap '${miss.gap}', closest '${placed.winner}'). ${where}`;
|
|
2619
|
+
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}`;
|
|
2620
|
+
}
|
|
2621
|
+
|
|
2622
|
+
// src/lib/core/1.domain/externals/serving.ts
|
|
2623
|
+
var byServingRank = (a, b) => Number(b.host) - Number(a.host) || a.downloads - b.downloads || a.fallbacks - b.fallbacks || Number(b.rootBasis) - Number(a.rootBasis) || compareStrings(a.remote, b.remote);
|
|
2624
|
+
var packagesOf = (scope) => groupByPackage(Object.keys(scope), (name) => name, packageOfIn(scope));
|
|
2625
|
+
var isPooled = (externals) => externals.some(([, e]) => e.poolName !== void 0);
|
|
2626
|
+
function servingBuildOf(pkg, externals, accepts) {
|
|
2627
|
+
if (externals.length === 0) return void 0;
|
|
2628
|
+
const rootRows = shareRows(externals.find(([name]) => name === pkg)?.[1]).filter(
|
|
2629
|
+
(row) => row.remotes.some((copy) => pkg in copy.entries)
|
|
2630
|
+
);
|
|
2631
|
+
const rows = rootRows.length > 0 ? rootRows : externals.flatMap(([, e]) => shareRows(e));
|
|
2632
|
+
if (isPooled(externals)) return pooledBuild(externals, rows);
|
|
2633
|
+
const consumers = consumersOf(externals);
|
|
2634
|
+
const builds = buildsOf(rows, rootRows, consumers);
|
|
2635
|
+
const hosts = builds.filter((b) => b.host);
|
|
2636
|
+
const field = hosts.length > 0 ? hosts : builds;
|
|
2637
|
+
if (field.length <= 1) return field[0] && { remote: field[0].remote, tag: field[0].tag };
|
|
2638
|
+
return cheapestBuild(field, costTable(consumers, accepts));
|
|
2639
|
+
}
|
|
2640
|
+
function cheapestBuild(field, costOf) {
|
|
2641
|
+
let best;
|
|
2642
|
+
for (const b of field) {
|
|
2643
|
+
const { downloads, fallbacks } = costOf(b);
|
|
2644
|
+
const candidate = {
|
|
2645
|
+
remote: b.remote,
|
|
2646
|
+
tag: b.tag,
|
|
2647
|
+
host: b.host,
|
|
2648
|
+
rootBasis: b.rootBasis,
|
|
2649
|
+
downloads,
|
|
2650
|
+
fallbacks
|
|
2651
|
+
};
|
|
2652
|
+
if (!best || byServingRank(candidate, best) < 0) best = candidate;
|
|
2614
2653
|
}
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2654
|
+
const { remote, tag } = best;
|
|
2655
|
+
return { remote, tag };
|
|
2656
|
+
}
|
|
2657
|
+
function shareServingCopies(external, serving) {
|
|
2658
|
+
for (const row of external.versions) {
|
|
2659
|
+
const copy = row.remotes.find((c) => c.name === serving.remote);
|
|
2660
|
+
if (row.action !== "skip" || !copy || rowAt(external.versions, row.tag, "share")) continue;
|
|
2661
|
+
row.action = "share";
|
|
2662
|
+
if (row.remotes[0] !== copy) row.host = false;
|
|
2663
|
+
row.remotes = [copy, ...row.remotes.filter((c) => c !== copy)];
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
function followServingBuild(external, serving, accepts) {
|
|
2667
|
+
let objector;
|
|
2668
|
+
const rebuilt = external.versions.flatMap((version) => {
|
|
2669
|
+
if (version.action !== "share" || version.tag === serving.tag || version.remotes[0].name === serving.remote)
|
|
2670
|
+
return [version];
|
|
2671
|
+
const rows = redirectRow(version, serving.tag, accepts);
|
|
2672
|
+
const scoped = rows.find((row) => row.action === "scope");
|
|
2673
|
+
if (scoped && !objector) objector = { copy: scoped.remotes[0], tag: scoped.tag };
|
|
2674
|
+
return rows;
|
|
2675
|
+
});
|
|
2676
|
+
external.versions = mergeRows(rebuilt);
|
|
2677
|
+
return { external, objector };
|
|
2678
|
+
}
|
|
2679
|
+
var sameTagOnly = (offered, ownTag) => offered === ownTag;
|
|
2680
|
+
var servedScopes = (scope, strict) => strict ? strictTagScopes(scope) : [scope];
|
|
2681
|
+
function strictTagScopes(scope) {
|
|
2682
|
+
const tagScopes = [];
|
|
2683
|
+
for (const [pkg, names] of packagesOf(scope)) {
|
|
2684
|
+
const byTag2 = /* @__PURE__ */ new Map();
|
|
2685
|
+
for (const name of names)
|
|
2686
|
+
for (const row of scope[name].versions) {
|
|
2687
|
+
let tagScope = byTag2.get(row.tag);
|
|
2688
|
+
if (!tagScope) byTag2.set(row.tag, tagScope = {});
|
|
2689
|
+
const external = tagScope[name] ??= { ...scope[name], versions: [] };
|
|
2690
|
+
external.versions.push({ ...row, remotes: [...row.remotes] });
|
|
2628
2691
|
}
|
|
2692
|
+
for (const [tag, tagScope] of byTag2) {
|
|
2693
|
+
const lead = [tagScope[pkg], ...Object.values(tagScope)].map((external) => external && rowAt(external.versions, tag, "share")).find((row) => row !== void 0);
|
|
2694
|
+
if (lead) {
|
|
2695
|
+
const serving = { remote: lead.remotes[0].name, tag };
|
|
2696
|
+
for (const external of Object.values(tagScope)) external.servingBuild = serving.remote;
|
|
2697
|
+
scopeFallbacks(Object.entries(tagScope), serving, sameTagOnly);
|
|
2698
|
+
}
|
|
2699
|
+
tagScopes.push(tagScope);
|
|
2629
2700
|
}
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2701
|
+
}
|
|
2702
|
+
return tagScopes;
|
|
2703
|
+
}
|
|
2704
|
+
function shareRows(external) {
|
|
2705
|
+
return external?.versions.filter((v) => v.action === "share") ?? [];
|
|
2706
|
+
}
|
|
2707
|
+
function buildsOf(rows, rootRows, consumers) {
|
|
2708
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
2709
|
+
for (const row of rows)
|
|
2710
|
+
for (const copy of row.remotes) {
|
|
2711
|
+
const key = `${row.tag}|${copy.name}`;
|
|
2712
|
+
if (copy.servedBy || candidates.has(key) || shipsTwoTags(consumers.get(copy.name))) continue;
|
|
2713
|
+
const basis = copy === row.remotes[0];
|
|
2714
|
+
candidates.set(key, {
|
|
2715
|
+
remote: copy.name,
|
|
2716
|
+
tag: row.tag,
|
|
2717
|
+
host: basis && row.host,
|
|
2718
|
+
rootBasis: basis && rootRows.includes(row)
|
|
2719
|
+
});
|
|
2640
2720
|
}
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2721
|
+
return [...candidates.values()];
|
|
2722
|
+
}
|
|
2723
|
+
function pooledBuild(externals, rows) {
|
|
2724
|
+
const winner = externals.find(([, e]) => e.poolWinner !== void 0)?.[1].poolWinner;
|
|
2725
|
+
const shipped = rows.flatMap(
|
|
2726
|
+
(row) => row.remotes.filter((copy) => !copy.servedBy).map((copy) => ({ remote: copy.name, tag: row.tag }))
|
|
2727
|
+
);
|
|
2728
|
+
const own = shipped.find((c) => c.remote === winner);
|
|
2729
|
+
if (own) return own;
|
|
2730
|
+
const width = ({ remote, tag }) => externals.reduce((n, [, e]) => {
|
|
2731
|
+
const copy = shareRows(e).find((row) => row.tag === tag)?.remotes.find((c) => c.name === remote);
|
|
2732
|
+
return n + Object.keys(copy?.entries ?? {}).length;
|
|
2733
|
+
}, 0);
|
|
2734
|
+
return shipped.map((c) => ({ c, width: width(c) })).sort((a, b) => b.width - a.width || compareStrings(a.c.remote, b.c.remote))[0]?.c;
|
|
2735
|
+
}
|
|
2736
|
+
function consumersOf(externals) {
|
|
2737
|
+
const consumers = /* @__PURE__ */ new Map();
|
|
2738
|
+
for (const [, external] of externals)
|
|
2739
|
+
for (const row of external.versions)
|
|
2740
|
+
for (const copy of row.remotes) {
|
|
2741
|
+
const placed = consumers.get(copy.name);
|
|
2742
|
+
if (placed) placed.push({ row, copy });
|
|
2743
|
+
else consumers.set(copy.name, [{ row, copy }]);
|
|
2663
2744
|
}
|
|
2664
|
-
|
|
2665
|
-
|
|
2745
|
+
return consumers;
|
|
2746
|
+
}
|
|
2747
|
+
function costTable(consumers, accepts) {
|
|
2748
|
+
const scanned = /* @__PURE__ */ new Map();
|
|
2749
|
+
const keyed = /* @__PURE__ */ new Map();
|
|
2750
|
+
const tollFor = (build, surface) => {
|
|
2751
|
+
let atTag = scanned.get(build.tag);
|
|
2752
|
+
if (!atTag) scanned.set(build.tag, atTag = []);
|
|
2753
|
+
const known = atTag.find((t) => sameSurface(t.surface, surface));
|
|
2754
|
+
if (known) return known.toll;
|
|
2755
|
+
if (atTag.length < SCANNED_SURFACES_PER_TAG) {
|
|
2756
|
+
const toll2 = tollOf(consumers, surface, build.tag, accepts);
|
|
2757
|
+
atTag.push({ surface, toll: toll2 });
|
|
2758
|
+
return toll2;
|
|
2759
|
+
}
|
|
2760
|
+
const key = [build.tag, ...[...surface].map(([s, tag]) => `${s}@${tag}`).sort()].join("\n");
|
|
2761
|
+
let toll = keyed.get(key);
|
|
2762
|
+
if (!toll) keyed.set(key, toll = tollOf(consumers, surface, build.tag, accepts));
|
|
2763
|
+
return toll;
|
|
2764
|
+
};
|
|
2765
|
+
return (build) => {
|
|
2766
|
+
const surface = surfaceOf(consumers, build);
|
|
2767
|
+
const toll = tollFor(build, surface);
|
|
2768
|
+
const others = (remotes) => remotes.size - Number(remotes.has(build.remote));
|
|
2666
2769
|
return {
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
versions: [
|
|
2670
|
-
...shareVersion,
|
|
2671
|
-
...byTag(
|
|
2672
|
-
clean.filter((e) => e.action === "skip"),
|
|
2673
|
-
"skip"
|
|
2674
|
-
),
|
|
2675
|
-
...byTag(scoped, "scope")
|
|
2676
|
-
].sort((a, b) => ports.versionCheck.compare(b.tag, a.tag))
|
|
2770
|
+
downloads: others(toll.downloads) + Number(!allCached(consumers.get(build.remote) ?? [])),
|
|
2771
|
+
fallbacks: others(toll.fallbacks)
|
|
2677
2772
|
};
|
|
2678
|
-
}
|
|
2773
|
+
};
|
|
2679
2774
|
}
|
|
2680
|
-
function
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
}
|
|
2690
|
-
}
|
|
2775
|
+
function tollOf(consumers, surface, tag, accepts) {
|
|
2776
|
+
const toll = { fallbacks: /* @__PURE__ */ new Set(), downloads: /* @__PURE__ */ new Set() };
|
|
2777
|
+
for (const [remote, placed] of consumers) {
|
|
2778
|
+
const fallback = fallsBack(placed, surface, tag, accepts);
|
|
2779
|
+
if (fallback) toll.fallbacks.add(remote);
|
|
2780
|
+
if (!allCached(placed) && (fallback || runsOffMap(placed, tag, accepts)))
|
|
2781
|
+
toll.downloads.add(remote);
|
|
2782
|
+
}
|
|
2783
|
+
return toll;
|
|
2691
2784
|
}
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2785
|
+
var allCached = (placed) => placed.every(({ copy }) => copy.cached);
|
|
2786
|
+
function fallbacksOf(externals, serving, accepts) {
|
|
2787
|
+
const consumers = consumersOf(externals);
|
|
2788
|
+
const surface = serving ? surfaceOf(consumers, serving) : /* @__PURE__ */ new Map();
|
|
2789
|
+
return [...consumers].filter(
|
|
2790
|
+
([remote, placed]) => remote !== serving?.remote && fallsBack(placed, surface, serving?.tag, accepts)
|
|
2791
|
+
).map(([remote]) => remote);
|
|
2792
|
+
}
|
|
2793
|
+
function scopeFallbacks(externals, serving, accepts) {
|
|
2794
|
+
const remotes = fallbacksOf(externals, serving, accepts);
|
|
2795
|
+
for (const [, external] of externals)
|
|
2796
|
+
external.versions = scopeRemotes(external.versions, remotes);
|
|
2797
|
+
}
|
|
2798
|
+
function strictObjectorOf(externals, serving, accepts) {
|
|
2799
|
+
const consumers = consumersOf(externals);
|
|
2800
|
+
const surface = surfaceOf(consumers, serving);
|
|
2801
|
+
for (const [name, external] of externals)
|
|
2802
|
+
for (const row of external.versions)
|
|
2803
|
+
for (const copy of row.remotes)
|
|
2804
|
+
if (copy.name !== serving.remote && rejectsServingTag({ row, copy }, surface, serving.tag, accepts) && !splitsPackage(consumers.get(copy.name), surface, serving.tag, accepts))
|
|
2805
|
+
return { external: name, copy, tag: row.tag };
|
|
2806
|
+
return void 0;
|
|
2807
|
+
}
|
|
2808
|
+
var SCANNED_SURFACES_PER_TAG = 8;
|
|
2809
|
+
function sameSurface(a, b) {
|
|
2810
|
+
if (a.size !== b.size) return false;
|
|
2811
|
+
for (const [specifier, tag] of a) if (b.get(specifier) !== tag) return false;
|
|
2812
|
+
return true;
|
|
2813
|
+
}
|
|
2814
|
+
function surfaceOf(consumers, serving) {
|
|
2815
|
+
const surface = /* @__PURE__ */ new Map();
|
|
2816
|
+
for (const p of consumers.get(serving.remote) ?? [])
|
|
2817
|
+
if (p.row.tag === serving.tag && onMap(p) || leadsShareRow(p)) {
|
|
2818
|
+
for (const s in p.copy.entries) if (!surface.has(s)) surface.set(s, p.row.tag);
|
|
2702
2819
|
}
|
|
2703
|
-
return
|
|
2820
|
+
return surface;
|
|
2821
|
+
}
|
|
2822
|
+
var leadsShareRow = ({ row, copy }) => row.action === "share" && row.remotes[0] === copy;
|
|
2823
|
+
var onMap = ({ row }) => row.action !== "scope";
|
|
2824
|
+
function splitsPackage(placed, surface, tag, accepts) {
|
|
2825
|
+
const uncovered = (p) => Object.keys(p.copy.entries).some((s) => {
|
|
2826
|
+
const servedAt = surface.get(s);
|
|
2827
|
+
return servedAt === void 0 || servedAt !== tag && rejectsTag(p, servedAt, accepts);
|
|
2828
|
+
});
|
|
2829
|
+
return placed.some(onMap) && (shipsTwoTags(placed) || placed.some((p) => !onMap(p) || uncovered(p)));
|
|
2704
2830
|
}
|
|
2705
|
-
function
|
|
2831
|
+
function loadSplitsPackage(pkg, copies, claims, accepts) {
|
|
2832
|
+
const root = claims.find(([specifier]) => specifier === pkg)?.[1];
|
|
2833
|
+
const servingTag = root?.tag ?? claims[0][1].tag;
|
|
2834
|
+
const surface = new Map(
|
|
2835
|
+
claims.map(([specifier, { tag }]) => [specifier, root ? tag : servingTag])
|
|
2836
|
+
);
|
|
2837
|
+
const placed = copies.map(({ tag, copy }) => ({
|
|
2838
|
+
row: { tag, action: "share", host: false, remotes: [copy] },
|
|
2839
|
+
copy
|
|
2840
|
+
}));
|
|
2841
|
+
return splitsPackage(placed, surface, servingTag, accepts);
|
|
2842
|
+
}
|
|
2843
|
+
function fallsBack(placed, surface, tag, accepts) {
|
|
2844
|
+
return splitsPackage(placed, surface, tag, accepts) || tag !== void 0 && placed.some((p) => rejectsServingTag(p, surface, tag, accepts));
|
|
2845
|
+
}
|
|
2846
|
+
function rejectsServingTag(p, surface, tag, accepts) {
|
|
2847
|
+
return onMap(p) && rejectsTag(p, tag, accepts) && Object.keys(p.copy.entries).some((s) => surface.get(s) === tag);
|
|
2848
|
+
}
|
|
2849
|
+
var rejectsTag = ({ row, copy }, tag, accepts) => copy.strictVersion && !accepts(tag, row.tag, copy.requiredVersion);
|
|
2850
|
+
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);
|
|
2851
|
+
function runsOffMap(placed, tag, accepts) {
|
|
2852
|
+
return placed.some((p) => !onMap(p) || rejectsTag(p, tag, accepts));
|
|
2853
|
+
}
|
|
2854
|
+
|
|
2855
|
+
// src/lib/core/2.app/steps/decide-serving-builds.ts
|
|
2856
|
+
function createDecideServingBuilds(config, ports) {
|
|
2706
2857
|
return () => {
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
const
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
}
|
|
2721
|
-
}
|
|
2722
|
-
for (const [name, external] of Object.entries(sharedExternals)) {
|
|
2723
|
-
if (pooled.has(name) || !clearPoolState(external)) continue;
|
|
2724
|
-
external.dirty = true;
|
|
2725
|
-
unpooled++;
|
|
2858
|
+
const accepts = createAcceptsTag(ports.versionCheck.isCompatible, ports.versionCheck.compare);
|
|
2859
|
+
const repo = ports.sharedExternalsRepo;
|
|
2860
|
+
const written = new Set(repo.uncommittedScopes());
|
|
2861
|
+
const needsDeciding = (shareScope) => written.has(shareScope) || repo.isUndecided(shareScope);
|
|
2862
|
+
try {
|
|
2863
|
+
for (const shareScope of repo.getScopes()) {
|
|
2864
|
+
if (repo.scopeType(shareScope) === "strict" || !needsDeciding(shareScope)) continue;
|
|
2865
|
+
const sharedExternals = repo.getFromScope(shareScope);
|
|
2866
|
+
for (const [pkg, names] of packagesOf(sharedExternals)) {
|
|
2867
|
+
const externals = names.map((name) => [name, sharedExternals[name]]);
|
|
2868
|
+
decidePackage(shareScope, pkg, externals, accepts);
|
|
2869
|
+
}
|
|
2870
|
+
repo.markDecided(shareScope);
|
|
2726
2871
|
}
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2872
|
+
return Promise.resolve();
|
|
2873
|
+
} catch (e) {
|
|
2874
|
+
return Promise.reject(e);
|
|
2875
|
+
}
|
|
2876
|
+
};
|
|
2877
|
+
function decidePackage(shareScope, pkg, externals, accepts) {
|
|
2878
|
+
const serving = servingBuildOf(pkg, externals, accepts);
|
|
2879
|
+
const before = externals.map(([, external]) => shapeOf(external));
|
|
2880
|
+
const pooled = isPooled(externals);
|
|
2881
|
+
const toFollow = pooled ? void 0 : serving;
|
|
2882
|
+
if (!pooled) fallBack(pkg, externals, accepts, serving);
|
|
2883
|
+
externals.forEach(([name, external], i) => {
|
|
2884
|
+
const decided = withServingBuild(
|
|
2885
|
+
toFollow ? follow(pkg, name, external, toFollow, accepts) : external,
|
|
2886
|
+
serving?.remote
|
|
2887
|
+
);
|
|
2888
|
+
if (!sameShape(before[i], decided))
|
|
2889
|
+
ports.sharedExternalsRepo.addOrUpdate(name, decided, shareScope);
|
|
2890
|
+
});
|
|
2891
|
+
}
|
|
2892
|
+
function follow(pkg, name, external, serving, accepts) {
|
|
2893
|
+
const { external: followed, objector } = followServingBuild(external, serving, accepts);
|
|
2894
|
+
if (objector && config.strict.strictExternalCompatibility)
|
|
2895
|
+
rejectIncompatible(config, objector.copy, `${name}@${objector.tag}`, `${pkg}@${serving.tag}`);
|
|
2896
|
+
return followed;
|
|
2897
|
+
}
|
|
2898
|
+
function fallBack(pkg, externals, accepts, serving) {
|
|
2899
|
+
if (serving) {
|
|
2900
|
+
for (const [, external] of externals) shareServingCopies(external, serving);
|
|
2901
|
+
const objector = config.strict.strictExternalCompatibility && strictObjectorOf(externals, serving, accepts);
|
|
2902
|
+
if (objector)
|
|
2903
|
+
rejectIncompatible(
|
|
2904
|
+
config,
|
|
2905
|
+
objector.copy,
|
|
2906
|
+
`${objector.external}@${objector.tag}`,
|
|
2907
|
+
`${pkg}@${serving.tag}`
|
|
2733
2908
|
);
|
|
2734
2909
|
}
|
|
2735
|
-
|
|
2910
|
+
scopeFallbacks(externals, serving, accepts);
|
|
2911
|
+
}
|
|
2912
|
+
}
|
|
2913
|
+
function withServingBuild(external, servingBuild) {
|
|
2914
|
+
if (external.servingBuild === servingBuild) return external;
|
|
2915
|
+
const { servingBuild: _, ...rest } = external;
|
|
2916
|
+
return servingBuild ? { ...rest, servingBuild } : rest;
|
|
2917
|
+
}
|
|
2918
|
+
var shapeOf = (external) => ({
|
|
2919
|
+
servingBuild: external.servingBuild,
|
|
2920
|
+
rows: external.versions.map(
|
|
2921
|
+
({ tag, action, host, remotes }) => ({ tag, action, host, remotes: [...remotes] })
|
|
2922
|
+
)
|
|
2923
|
+
});
|
|
2924
|
+
var sameRow = (was, row) => Object.keys(was).every(
|
|
2925
|
+
(key) => key === "remotes" ? was.remotes.length === row.remotes.length && row.remotes.every((copy, j) => copy === was.remotes[j]) : was[key] === row[key]
|
|
2926
|
+
);
|
|
2927
|
+
var sameShape = (shape, external) => shape.servingBuild === external.servingBuild && shape.rows.length === external.versions.length && external.versions.every((row, i) => sameRow(shape.rows[i], row));
|
|
2928
|
+
|
|
2929
|
+
// src/lib/core/1.domain/externals/claims.ts
|
|
2930
|
+
function claimTable(externals, publishes) {
|
|
2931
|
+
const table = { claims: /* @__PURE__ */ new Map(), duplicates: /* @__PURE__ */ new Set(), shareClaims: /* @__PURE__ */ new Map() };
|
|
2932
|
+
const ordered = [...externals];
|
|
2933
|
+
const claim = (into, external, version, accepts = publishes) => forEachVersionEntry(version, accepts, (specifier, copy) => {
|
|
2934
|
+
if (!into.has(specifier)) into.set(specifier, { external, tag: version.tag, copy });
|
|
2935
|
+
});
|
|
2936
|
+
const seedServingBuild = (name, external) => {
|
|
2937
|
+
const isServing = (copy) => copy.name === external.servingBuild && (!publishes || publishes(copy));
|
|
2938
|
+
for (const version of external.versions) {
|
|
2939
|
+
if (version.action !== "share") continue;
|
|
2940
|
+
claim(table.shareClaims, name, version, isServing);
|
|
2941
|
+
claim(table.claims, name, version, isServing);
|
|
2942
|
+
}
|
|
2943
|
+
};
|
|
2944
|
+
const claimShareRow = (name, external, version) => {
|
|
2945
|
+
const prior = table.claims.get(name);
|
|
2946
|
+
const duplicate = prior !== void 0 && prior.tag !== version.tag;
|
|
2947
|
+
if (duplicate && !(version.host && version.remotes[0].name === external.servingBuild))
|
|
2948
|
+
table.duplicates.add(version);
|
|
2949
|
+
if (external.servingBuild) return;
|
|
2950
|
+
claim(table.shareClaims, name, version);
|
|
2951
|
+
if (!duplicate && (!prior || prior.external === name)) claim(table.claims, name, version);
|
|
2952
|
+
};
|
|
2953
|
+
for (const [name, external] of ordered)
|
|
2954
|
+
if (external.servingBuild) seedServingBuild(name, external);
|
|
2955
|
+
for (const [name, external] of ordered)
|
|
2956
|
+
for (const version of external.versions)
|
|
2957
|
+
if (version.action === "share") claimShareRow(name, external, version);
|
|
2958
|
+
return table;
|
|
2959
|
+
}
|
|
2960
|
+
function committedClaims(externals, { shareScope, without }) {
|
|
2961
|
+
const publishes = (copy) => copy.name !== without && (shareScope !== GLOBAL_SCOPE || copy.cached);
|
|
2962
|
+
return claimTable(externals, publishes).claims;
|
|
2963
|
+
}
|
|
2964
|
+
function versionClaims(version, servingBuild) {
|
|
2965
|
+
const claims = /* @__PURE__ */ new Map();
|
|
2966
|
+
const claim = (specifier, copy) => {
|
|
2967
|
+
if (!claims.has(specifier)) claims.set(specifier, copy);
|
|
2736
2968
|
};
|
|
2969
|
+
const accepts = servingBuild ? (copy) => copy.name === servingBuild : void 0;
|
|
2970
|
+
forEachVersionEntry(version, accepts, claim);
|
|
2971
|
+
return claims;
|
|
2737
2972
|
}
|
|
2738
2973
|
|
|
2739
|
-
// node_modules/.pnpm/@softarc+native-federation@4.
|
|
2974
|
+
// node_modules/.pnpm/@softarc+native-federation@4.9.0/node_modules/@softarc/native-federation/dist/lib/domain/core/build-notification-options.contract.js
|
|
2740
2975
|
var BuildNotificationType = /* @__PURE__ */ ((BuildNotificationType2) => {
|
|
2741
2976
|
BuildNotificationType2["COMPLETED"] = "federation-rebuild-complete";
|
|
2742
2977
|
BuildNotificationType2["ERROR"] = "federation-rebuild-error";
|
|
@@ -2744,13 +2979,14 @@ var BuildNotificationType = /* @__PURE__ */ ((BuildNotificationType2) => {
|
|
|
2744
2979
|
return BuildNotificationType2;
|
|
2745
2980
|
})(BuildNotificationType || {});
|
|
2746
2981
|
|
|
2747
|
-
// node_modules/.pnpm/@softarc+native-federation@4.
|
|
2982
|
+
// node_modules/.pnpm/@softarc+native-federation@4.9.0/node_modules/@softarc/native-federation/dist/lib/domain/core/chunk.js
|
|
2748
2983
|
var CHUNK_PREFIX = "@nf-internal";
|
|
2984
|
+
var SCRIPT_EXTENSION = /\.(m|c)?js$/;
|
|
2749
2985
|
function toChunkImport(fileName) {
|
|
2750
2986
|
if (fileName.startsWith("./")) {
|
|
2751
2987
|
fileName = fileName.slice(2);
|
|
2752
2988
|
}
|
|
2753
|
-
const packageName = fileName.replace(
|
|
2989
|
+
const packageName = fileName.replace(SCRIPT_EXTENSION, "");
|
|
2754
2990
|
return CHUNK_PREFIX + "/" + packageName;
|
|
2755
2991
|
}
|
|
2756
2992
|
|
|
@@ -2761,8 +2997,8 @@ function createGenerateImportMap(config, ports) {
|
|
|
2761
2997
|
const chunkBundles = {};
|
|
2762
2998
|
try {
|
|
2763
2999
|
addScopedExternals(importMap, chunkBundles);
|
|
2764
|
-
|
|
2765
|
-
|
|
3000
|
+
addNamedShareScopes(importMap, chunkBundles);
|
|
3001
|
+
addGlobalShareScope(importMap, chunkBundles);
|
|
2766
3002
|
addRemoteInfos(importMap, chunkBundles);
|
|
2767
3003
|
addChunkImports(importMap, chunkBundles);
|
|
2768
3004
|
return Promise.resolve(importMap);
|
|
@@ -2796,47 +3032,61 @@ function createGenerateImportMap(config, ports) {
|
|
|
2796
3032
|
}
|
|
2797
3033
|
return modules;
|
|
2798
3034
|
}
|
|
2799
|
-
function
|
|
3035
|
+
function addNamedShareScopes(importMap, chunkBundles) {
|
|
2800
3036
|
const shareScopes = ports.sharedExternalsRepo.getScopes({ includeGlobal: false });
|
|
2801
3037
|
for (const shareScope of shareScopes) {
|
|
2802
|
-
|
|
3038
|
+
const sharedExternals = ports.sharedExternalsRepo.getFromScope(shareScope);
|
|
3039
|
+
const cachedBefore = /* @__PURE__ */ new Map();
|
|
3040
|
+
for (const [externalName, external] of Object.entries(sharedExternals))
|
|
3041
|
+
cachedBefore.set(externalName, cachedFingerprint(external));
|
|
3042
|
+
const strict = ports.sharedExternalsRepo.scopeType(shareScope) === "strict";
|
|
3043
|
+
for (const served of servedScopes(sharedExternals, strict))
|
|
3044
|
+
addShareScope(importMap, shareScope, served, chunkBundles);
|
|
3045
|
+
for (const [externalName, external] of Object.entries(sharedExternals)) {
|
|
3046
|
+
if (cachedFingerprint(external) !== cachedBefore.get(externalName)) {
|
|
3047
|
+
ports.sharedExternalsRepo.addOrUpdate(externalName, external, shareScope);
|
|
3048
|
+
}
|
|
3049
|
+
}
|
|
2803
3050
|
}
|
|
2804
3051
|
return importMap;
|
|
2805
3052
|
}
|
|
2806
|
-
function
|
|
2807
|
-
const sharedExternals = ports.sharedExternalsRepo.getFromScope(shareScope);
|
|
3053
|
+
function addShareScope(importMap, shareScope, sharedExternals, chunkBundles) {
|
|
2808
3054
|
const index = buildServedIndex(sharedExternals);
|
|
3055
|
+
const claims = shareRowMappings(sharedExternals, shareScope);
|
|
3056
|
+
const claimedElsewhere = (externalName, specifier) => {
|
|
3057
|
+
const claim = claims.get(specifier);
|
|
3058
|
+
return claim?.external === externalName ? void 0 : claim;
|
|
3059
|
+
};
|
|
2809
3060
|
for (const [externalName, external] of Object.entries(sharedExternals)) {
|
|
2810
3061
|
let override = void 0;
|
|
2811
|
-
const cachedBefore = cachedFingerprint(external);
|
|
2812
3062
|
for (const version of external.versions) {
|
|
2813
3063
|
if (version.action === "scope") {
|
|
2814
|
-
|
|
2815
|
-
const remoteScope = getScope2(shareScope, remote.name, externalName);
|
|
2816
|
-
for (const [packageName, file] of Object.entries(remote.entries)) {
|
|
2817
|
-
const url = join(remoteScope, file);
|
|
2818
|
-
addToScope(importMap, remoteScope, { [packageName]: url });
|
|
2819
|
-
addIntegrity(importMap, url, remote.name, file);
|
|
2820
|
-
}
|
|
2821
|
-
registerBundleChunks(chunkBundles, remote.name, remote.bundle);
|
|
2822
|
-
remote.cached = true;
|
|
2823
|
-
}
|
|
3064
|
+
addScopeRow(importMap, chunkBundles, shareScope, externalName, version);
|
|
2824
3065
|
continue;
|
|
2825
3066
|
}
|
|
2826
|
-
version.remotes[0].cached = true;
|
|
2827
3067
|
let serving = version;
|
|
2828
3068
|
if (version.action === "skip") {
|
|
2829
3069
|
if (!override) {
|
|
2830
|
-
override = findOverride(
|
|
3070
|
+
override = findOverride(
|
|
3071
|
+
external,
|
|
3072
|
+
shareScope,
|
|
3073
|
+
externalName,
|
|
3074
|
+
(s) => Boolean(claimedElsewhere(externalName, s))
|
|
3075
|
+
) ?? "NOT_AVAILABLE";
|
|
2831
3076
|
}
|
|
2832
3077
|
if (override !== "NOT_AVAILABLE") {
|
|
2833
3078
|
serving = override;
|
|
2834
3079
|
version.remotes[0].cached = false;
|
|
2835
3080
|
}
|
|
2836
3081
|
}
|
|
2837
|
-
const provided =
|
|
3082
|
+
const provided = versionClaims(serving, external.servingBuild);
|
|
2838
3083
|
const mappings = [];
|
|
2839
3084
|
for (const [packageName, provider] of provided) {
|
|
3085
|
+
const claim = claimedElsewhere(externalName, packageName);
|
|
3086
|
+
if (claim) {
|
|
3087
|
+
mappings.push({ packageName, ...claim });
|
|
3088
|
+
continue;
|
|
3089
|
+
}
|
|
2840
3090
|
const file = provider.entries[packageName];
|
|
2841
3091
|
mappings.push({
|
|
2842
3092
|
packageName,
|
|
@@ -2849,56 +3099,60 @@ function createGenerateImportMap(config, ports) {
|
|
|
2849
3099
|
registerBundleChunks(chunkBundles, provider.name, provider.bundle);
|
|
2850
3100
|
}
|
|
2851
3101
|
}
|
|
2852
|
-
version.remotes.forEach((
|
|
2853
|
-
const
|
|
2854
|
-
if (index &&
|
|
2855
|
-
const files = index.get(
|
|
2856
|
-
const servedScope = getScope2(shareScope,
|
|
2857
|
-
for (const specifier of Object.keys(
|
|
3102
|
+
version.remotes.forEach((consumer) => {
|
|
3103
|
+
const consumerScope = getScope2(shareScope, consumer.name, externalName);
|
|
3104
|
+
if (index && consumer.servedBy) {
|
|
3105
|
+
const files = index.get(consumer.servedBy);
|
|
3106
|
+
const servedScope = getScope2(shareScope, consumer.servedBy, externalName);
|
|
3107
|
+
for (const specifier of Object.keys(consumer.entries)) {
|
|
2858
3108
|
const source = files?.get(specifier);
|
|
2859
3109
|
if (!source) continue;
|
|
2860
3110
|
const url = join(servedScope, source.file);
|
|
2861
|
-
addToScope(importMap,
|
|
2862
|
-
addIntegrity(importMap, url,
|
|
2863
|
-
registerBundleChunks(chunkBundles,
|
|
3111
|
+
addToScope(importMap, consumerScope, { [specifier]: url });
|
|
3112
|
+
addIntegrity(importMap, url, consumer.servedBy, source.file);
|
|
3113
|
+
registerBundleChunks(chunkBundles, consumer.servedBy, source.bundle);
|
|
2864
3114
|
source.meta.cached = true;
|
|
2865
3115
|
}
|
|
2866
3116
|
return;
|
|
2867
3117
|
}
|
|
2868
3118
|
for (const m of mappings) {
|
|
2869
|
-
addToScope(importMap,
|
|
3119
|
+
addToScope(importMap, consumerScope, { [m.packageName]: m.url });
|
|
2870
3120
|
}
|
|
2871
|
-
for (const
|
|
3121
|
+
for (const packageName of Object.keys(consumer.entries)) {
|
|
2872
3122
|
if (provided.has(packageName)) continue;
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
continue;
|
|
2876
|
-
}
|
|
2877
|
-
const url = join(rScope, file);
|
|
2878
|
-
addToScope(importMap, rScope, { [packageName]: url });
|
|
2879
|
-
addIntegrity(importMap, url, r.name, file);
|
|
2880
|
-
r.cached = true;
|
|
3123
|
+
const claim = claimedElsewhere(externalName, packageName);
|
|
3124
|
+
if (claim) addToScope(importMap, consumerScope, { [packageName]: claim.url });
|
|
2881
3125
|
}
|
|
2882
3126
|
});
|
|
2883
3127
|
for (const m of mappings) {
|
|
2884
3128
|
addIntegrity(importMap, m.url, m.name, m.file);
|
|
2885
3129
|
}
|
|
2886
3130
|
}
|
|
2887
|
-
|
|
2888
|
-
|
|
3131
|
+
}
|
|
3132
|
+
}
|
|
3133
|
+
function addScopeRow(importMap, chunkBundles, shareScope, externalName, version) {
|
|
3134
|
+
for (const remote of version.remotes) {
|
|
3135
|
+
const remoteScope = getScope2(shareScope, remote.name, externalName);
|
|
3136
|
+
for (const [packageName, file] of Object.entries(remote.entries)) {
|
|
3137
|
+
const url = join(remoteScope, file);
|
|
3138
|
+
addToScope(importMap, remoteScope, { [packageName]: url });
|
|
3139
|
+
addIntegrity(importMap, url, remote.name, file);
|
|
2889
3140
|
}
|
|
3141
|
+
registerBundleChunks(chunkBundles, remote.name, remote.bundle);
|
|
3142
|
+
remote.cached = true;
|
|
2890
3143
|
}
|
|
2891
3144
|
}
|
|
2892
3145
|
function cachedFingerprint(external) {
|
|
2893
3146
|
return external.versions.map((v) => v.remotes.map((r) => r.cached ? 1 : 0).join("")).join("|");
|
|
2894
3147
|
}
|
|
2895
|
-
function findOverride(external, shareScope, externalName) {
|
|
3148
|
+
function findOverride(external, shareScope, externalName, servedElsewhere) {
|
|
2896
3149
|
const sharedVersions = external.versions.filter((v) => v.action === "share");
|
|
2897
3150
|
const scopedExternalName = `${shareScope}.${externalName}`;
|
|
2898
3151
|
if (sharedVersions.length > 1) {
|
|
2899
3152
|
handleMultipleSharedVersions(scopedExternalName);
|
|
2900
3153
|
}
|
|
2901
|
-
|
|
3154
|
+
const servedByClaims = () => external.versions.filter((v) => v.action === "skip").every((v) => shipsOnly(v, servedElsewhere));
|
|
3155
|
+
if (sharedVersions.length < 1 && !servedByClaims()) {
|
|
2902
3156
|
if (config.strict.strictImportMap) {
|
|
2903
3157
|
config.log.error(4, `[${shareScope}][${externalName}] shareScope has no override version.`);
|
|
2904
3158
|
throw new NFError("Could not create ImportMap.");
|
|
@@ -2943,17 +3197,30 @@ function createGenerateImportMap(config, ports) {
|
|
|
2943
3197
|
}
|
|
2944
3198
|
return index;
|
|
2945
3199
|
}
|
|
2946
|
-
function
|
|
3200
|
+
function shareRowMappings(externals, shareScope) {
|
|
3201
|
+
const mappings = /* @__PURE__ */ new Map();
|
|
3202
|
+
for (const [specifier, { external, copy }] of claimTable(Object.entries(externals)).shareClaims) {
|
|
3203
|
+
const file = copy.entries[specifier];
|
|
3204
|
+
mappings.set(specifier, {
|
|
3205
|
+
url: join(getScope2(shareScope, copy.name, external), file),
|
|
3206
|
+
name: copy.name,
|
|
3207
|
+
file,
|
|
3208
|
+
external
|
|
3209
|
+
});
|
|
3210
|
+
}
|
|
3211
|
+
return mappings;
|
|
3212
|
+
}
|
|
3213
|
+
function collectServed(into, index, shareScope, externalName, version) {
|
|
2947
3214
|
for (const consumer of version.remotes) {
|
|
2948
3215
|
if (!consumer.servedBy) continue;
|
|
2949
3216
|
const files = index.get(consumer.servedBy);
|
|
2950
|
-
const scope = getScope2(
|
|
3217
|
+
const scope = getScope2(shareScope, consumer.name, externalName);
|
|
2951
3218
|
for (const specifier of Object.keys(consumer.entries)) {
|
|
2952
3219
|
const source = files?.get(specifier);
|
|
2953
3220
|
if (!source) {
|
|
2954
3221
|
config.log.warn(
|
|
2955
3222
|
4,
|
|
2956
|
-
`[${
|
|
3223
|
+
`[${shareScope}][${externalName}][${consumer.name}] '${consumer.servedBy}' does not serve '${specifier}'.`
|
|
2957
3224
|
);
|
|
2958
3225
|
continue;
|
|
2959
3226
|
}
|
|
@@ -2971,9 +3238,11 @@ function createGenerateImportMap(config, ports) {
|
|
|
2971
3238
|
source.meta.cached = true;
|
|
2972
3239
|
}
|
|
2973
3240
|
}
|
|
2974
|
-
function
|
|
3241
|
+
function addGlobalShareScope(importMap, chunkBundles) {
|
|
2975
3242
|
const sharedExternals = ports.sharedExternalsRepo.getFromScope();
|
|
2976
3243
|
const index = buildServedIndex(sharedExternals);
|
|
3244
|
+
const { claims, duplicates } = claimTable(Object.entries(sharedExternals));
|
|
3245
|
+
const claimed = claimsByCopy(claims);
|
|
2977
3246
|
const served = [];
|
|
2978
3247
|
const cachedBefore = /* @__PURE__ */ new Map();
|
|
2979
3248
|
for (const [externalName, external] of Object.entries(sharedExternals)) {
|
|
@@ -2984,27 +3253,14 @@ function createGenerateImportMap(config, ports) {
|
|
|
2984
3253
|
}
|
|
2985
3254
|
if (version.action === "skip") continue;
|
|
2986
3255
|
if (version.action === "scope") {
|
|
2987
|
-
|
|
2988
|
-
const remoteScope = getScope2(GLOBAL_SCOPE, remote.name, externalName);
|
|
2989
|
-
for (const [packageName, file] of Object.entries(remote.entries)) {
|
|
2990
|
-
const url = join(remoteScope, file);
|
|
2991
|
-
addToScope(importMap, remoteScope, { [packageName]: url });
|
|
2992
|
-
addIntegrity(importMap, url, remote.name, file);
|
|
2993
|
-
}
|
|
2994
|
-
remote.cached = true;
|
|
2995
|
-
registerBundleChunks(chunkBundles, remote.name, remote.bundle);
|
|
2996
|
-
}
|
|
3256
|
+
addScopeRow(importMap, chunkBundles, GLOBAL_SCOPE, externalName, version);
|
|
2997
3257
|
continue;
|
|
2998
3258
|
}
|
|
2999
|
-
if (
|
|
3259
|
+
if (duplicates.has(version)) {
|
|
3000
3260
|
notifyDuplicateGlobalExternal(externalName);
|
|
3001
3261
|
continue;
|
|
3002
3262
|
}
|
|
3003
|
-
|
|
3004
|
-
}
|
|
3005
|
-
for (const version of external.versions) {
|
|
3006
|
-
if (version.action !== "skip") continue;
|
|
3007
|
-
selfFillUncovered(importMap, chunkBundles, externalName, version.remotes);
|
|
3263
|
+
publishClaims(importMap, chunkBundles, externalName, version, claimed);
|
|
3008
3264
|
}
|
|
3009
3265
|
}
|
|
3010
3266
|
flushServed(importMap, chunkBundles, served);
|
|
@@ -3015,54 +3271,30 @@ function createGenerateImportMap(config, ports) {
|
|
|
3015
3271
|
}
|
|
3016
3272
|
return importMap;
|
|
3017
3273
|
}
|
|
3018
|
-
function
|
|
3019
|
-
const
|
|
3020
|
-
for (const [
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
`[${GLOBAL_SCOPE}][${externalName}][${remote.name}] Entrypoint '${packageName}' is already mapped by another external, keeping '${importMap.imports[packageName]}'.`
|
|
3025
|
-
);
|
|
3026
|
-
continue;
|
|
3027
|
-
}
|
|
3028
|
-
let scope = scopes.get(remote.name);
|
|
3029
|
-
if (scope === void 0) {
|
|
3030
|
-
scopes.set(remote.name, scope = getScope2(GLOBAL_SCOPE, remote.name, externalName));
|
|
3031
|
-
registerBundleChunks(chunkBundles, remote.name, remote.bundle);
|
|
3032
|
-
remote.cached = true;
|
|
3033
|
-
}
|
|
3034
|
-
const file = remote.entries[packageName];
|
|
3035
|
-
const url = join(scope, file);
|
|
3036
|
-
addToGlobal(importMap, { [packageName]: url });
|
|
3037
|
-
addIntegrity(importMap, url, remote.name, file);
|
|
3274
|
+
function claimsByCopy(claims) {
|
|
3275
|
+
const claimed = /* @__PURE__ */ new Map();
|
|
3276
|
+
for (const [specifier, { copy }] of claims) {
|
|
3277
|
+
const specifiers = claimed.get(copy);
|
|
3278
|
+
if (specifiers) specifiers.push(specifier);
|
|
3279
|
+
else claimed.set(copy, [specifier]);
|
|
3038
3280
|
}
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
const
|
|
3281
|
+
return claimed;
|
|
3282
|
+
}
|
|
3283
|
+
function publishClaims(importMap, chunkBundles, externalName, version, claimed) {
|
|
3284
|
+
for (const copy of version.remotes) {
|
|
3285
|
+
const specifiers = claimed.get(copy);
|
|
3286
|
+
if (!specifiers) continue;
|
|
3287
|
+
const scope = getScope2(GLOBAL_SCOPE, copy.name, externalName);
|
|
3288
|
+
registerBundleChunks(chunkBundles, copy.name, copy.bundle);
|
|
3289
|
+
copy.cached = true;
|
|
3290
|
+
for (const specifier of specifiers) {
|
|
3291
|
+
const file = copy.entries[specifier];
|
|
3050
3292
|
const url = join(scope, file);
|
|
3051
|
-
addToGlobal(importMap, { [
|
|
3052
|
-
addIntegrity(importMap, url,
|
|
3053
|
-
registerBundleChunks(chunkBundles, remote.name, remote.bundle);
|
|
3054
|
-
remote.cached = true;
|
|
3293
|
+
addToGlobal(importMap, { [specifier]: url });
|
|
3294
|
+
addIntegrity(importMap, url, copy.name, file);
|
|
3055
3295
|
}
|
|
3056
3296
|
}
|
|
3057
3297
|
}
|
|
3058
|
-
function warnUncoveredEntrypoint(scope, externalName, remoteName, packageName) {
|
|
3059
|
-
const msg = `[${scope}][${externalName}][${remoteName}] Entrypoint '${packageName}' is not covered by the shared version.`;
|
|
3060
|
-
if (config.strict.strictEntryPointCoverage || config.strict.strictImportMap) {
|
|
3061
|
-
config.log.error(4, msg);
|
|
3062
|
-
throw new NFError("Could not create ImportMap.");
|
|
3063
|
-
}
|
|
3064
|
-
config.log.warn(4, msg);
|
|
3065
|
-
}
|
|
3066
3298
|
function notifyDuplicateGlobalExternal(externalName) {
|
|
3067
3299
|
if (config.strict.strictImportMap) {
|
|
3068
3300
|
config.log.error(4, `[${externalName}] Shared external has multiple shared versions.`);
|
|
@@ -3136,15 +3368,30 @@ function createGenerateImportMap(config, ports) {
|
|
|
3136
3368
|
});
|
|
3137
3369
|
}
|
|
3138
3370
|
}
|
|
3371
|
+
function shipsOnly(version, served) {
|
|
3372
|
+
let only = true;
|
|
3373
|
+
forEachVersionEntry(version, void 0, (specifier) => {
|
|
3374
|
+
only &&= served(specifier);
|
|
3375
|
+
});
|
|
3376
|
+
return only;
|
|
3377
|
+
}
|
|
3139
3378
|
|
|
3140
3379
|
// src/lib/core/2.app/steps/commit-changes.ts
|
|
3141
3380
|
function createCommitChanges(config, ports) {
|
|
3142
|
-
return (importMap,
|
|
3381
|
+
return (importMap, { markUndecided = false, ...browserOpts } = {}) => Promise.resolve(importMap).then((map) => addToBrowser(map, browserOpts)).then(() => {
|
|
3382
|
+
if (markUndecided) markUndecidedScopes();
|
|
3383
|
+
persistRepositoryChanges();
|
|
3384
|
+
});
|
|
3143
3385
|
function addToBrowser(importMap, opts) {
|
|
3144
3386
|
ports.browser.setImportMapFn(importMap, opts);
|
|
3145
3387
|
config.log.debug(5, "Added import map to browser.", importMap);
|
|
3146
3388
|
return importMap;
|
|
3147
3389
|
}
|
|
3390
|
+
function markUndecidedScopes() {
|
|
3391
|
+
const repo = ports.sharedExternalsRepo;
|
|
3392
|
+
for (const shareScope of repo.uncommittedScopes())
|
|
3393
|
+
if (repo.scopeType(shareScope) !== "strict") repo.markUndecided(shareScope);
|
|
3394
|
+
}
|
|
3148
3395
|
function persistRepositoryChanges() {
|
|
3149
3396
|
ports.remoteInfoRepo.commit();
|
|
3150
3397
|
ports.scopedExternalsRepo.commit();
|
|
@@ -3154,6 +3401,29 @@ function createCommitChanges(config, ports) {
|
|
|
3154
3401
|
}
|
|
3155
3402
|
}
|
|
3156
3403
|
|
|
3404
|
+
// src/lib/core/2.app/steps/rollback-changes.ts
|
|
3405
|
+
var createStateDump = (config, ports) => (msg) => config.log.debug(0, msg, {
|
|
3406
|
+
remotes: { ...ports.remoteInfoRepo.getAll() },
|
|
3407
|
+
"shared-externals": ports.sharedExternalsRepo.getScopes({ includeGlobal: true }).reduce(
|
|
3408
|
+
(acc, scope) => ({ ...acc, [scope]: ports.sharedExternalsRepo.getFromScope(scope) }),
|
|
3409
|
+
{}
|
|
3410
|
+
),
|
|
3411
|
+
"scoped-externals": ports.scopedExternalsRepo.getAll()
|
|
3412
|
+
});
|
|
3413
|
+
function createRollbackChanges(config, ports) {
|
|
3414
|
+
const stateDump = createStateDump(config, ports);
|
|
3415
|
+
return (label) => Promise.resolve().then(() => {
|
|
3416
|
+
try {
|
|
3417
|
+
stateDump(`${label} STATE DUMP`);
|
|
3418
|
+
} finally {
|
|
3419
|
+
ports.remoteInfoRepo.rollback();
|
|
3420
|
+
ports.scopedExternalsRepo.rollback();
|
|
3421
|
+
ports.sharedExternalsRepo.rollback();
|
|
3422
|
+
ports.sharedChunksRepo.rollback();
|
|
3423
|
+
}
|
|
3424
|
+
});
|
|
3425
|
+
}
|
|
3426
|
+
|
|
3157
3427
|
// src/lib/core/2.app/steps/expose-module-loader.ts
|
|
3158
3428
|
function createExposeModuleLoader(config, ports) {
|
|
3159
3429
|
const loadRemoteModule = (remoteName, exposedModule) => {
|
|
@@ -3228,10 +3498,16 @@ var normalizeRemoteRef = (remote) => {
|
|
|
3228
3498
|
function createGetRemoteEntry(config, ports) {
|
|
3229
3499
|
return async (remoteEntryUrl, remote) => {
|
|
3230
3500
|
const { name: remoteName, integrity } = normalizeRemoteRef(remote);
|
|
3231
|
-
|
|
3232
|
-
|
|
3501
|
+
const knownAtUrl = findCachedRemoteAt(remoteEntryUrl);
|
|
3502
|
+
if (knownAtUrl) {
|
|
3503
|
+
config.log.debug(
|
|
3504
|
+
7,
|
|
3505
|
+
`Found remote '${knownAtUrl}' at '${remoteEntryUrl}' in storage, omitting fetch.`
|
|
3506
|
+
);
|
|
3233
3507
|
return Optional.empty();
|
|
3234
3508
|
}
|
|
3509
|
+
if (!!remoteName && ports.remoteInfoRepo.contains(remoteName))
|
|
3510
|
+
return warnInitialized(remoteName, remoteEntryUrl);
|
|
3235
3511
|
try {
|
|
3236
3512
|
const remoteEntry = integrity ? await ports.remoteEntryProvider.provide(remoteEntryUrl, { integrity }) : await ports.remoteEntryProvider.provide(remoteEntryUrl);
|
|
3237
3513
|
config.log.debug(
|
|
@@ -3246,10 +3522,8 @@ function createGetRemoteEntry(config, ports) {
|
|
|
3246
3522
|
}
|
|
3247
3523
|
config.log.warn(7, errorMsg + " Omitting expected name.");
|
|
3248
3524
|
}
|
|
3249
|
-
if (ports.remoteInfoRepo.contains(remoteEntry.name))
|
|
3250
|
-
remoteEntry.
|
|
3251
|
-
config.log.debug(7, `Overriding existing remote '${remoteName}' with '${remoteEntryUrl}'.`);
|
|
3252
|
-
}
|
|
3525
|
+
if (ports.remoteInfoRepo.contains(remoteEntry.name))
|
|
3526
|
+
return warnInitialized(remoteEntry.name, remoteEntryUrl);
|
|
3253
3527
|
return Optional.of(checkForSSE(remoteEntry));
|
|
3254
3528
|
} catch (error) {
|
|
3255
3529
|
config.log.error(
|
|
@@ -3262,10 +3536,18 @@ function createGetRemoteEntry(config, ports) {
|
|
|
3262
3536
|
);
|
|
3263
3537
|
}
|
|
3264
3538
|
};
|
|
3265
|
-
function
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3539
|
+
function warnInitialized(name, remoteEntryUrl) {
|
|
3540
|
+
const initializedFrom = ports.remoteInfoRepo.tryGet(name).map((info) => join(info.scopeUrl, "remoteEntry.json")).get();
|
|
3541
|
+
config.log.warn(
|
|
3542
|
+
7,
|
|
3543
|
+
`[${name}] Already initialized from '${initializedFrom}', ignoring '${remoteEntryUrl}'.`
|
|
3544
|
+
);
|
|
3545
|
+
return Optional.empty();
|
|
3546
|
+
}
|
|
3547
|
+
function findCachedRemoteAt(remoteEntryUrl) {
|
|
3548
|
+
return Object.entries(ports.remoteInfoRepo.getAll()).find(
|
|
3549
|
+
([, info]) => join(info.scopeUrl, "remoteEntry.json") === remoteEntryUrl
|
|
3550
|
+
)?.[0];
|
|
3269
3551
|
}
|
|
3270
3552
|
function checkForSSE(entry) {
|
|
3271
3553
|
if (config.sse) {
|
|
@@ -3285,92 +3567,184 @@ function createGetRemoteEntry(config, ports) {
|
|
|
3285
3567
|
// src/lib/core/2.app/steps/update-cache.ts
|
|
3286
3568
|
function createUpdateCache(config, ports) {
|
|
3287
3569
|
const storeRemoteEntry = createStoreRemoteEntry(config, ports, 8);
|
|
3288
|
-
const
|
|
3570
|
+
const accepts = createAcceptsTag(
|
|
3571
|
+
(tag, range) => ports.versionCheck.isCompatible(tag, range),
|
|
3572
|
+
(a, b) => ports.versionCheck.compare(a, b)
|
|
3573
|
+
);
|
|
3289
3574
|
return (remoteEntry) => {
|
|
3290
3575
|
try {
|
|
3576
|
+
const pending = [];
|
|
3577
|
+
storeRemoteEntry(remoteEntry, (_, external, ctx) => pending.push({ external, ctx }));
|
|
3578
|
+
const decisions = decidePackages(remoteEntry, pending);
|
|
3291
3579
|
const actions = {};
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
const { action, provided, sameVersion } = resolveSharedExternal(entry, external, ctx);
|
|
3295
|
-
actions[external.packageName] = { action };
|
|
3296
|
-
if (action === "skip" && provided) {
|
|
3297
|
-
actions[external.packageName].covered = Array.from(provided.keys());
|
|
3298
|
-
if (sameVersion) actions[external.packageName].sameVersion = true;
|
|
3299
|
-
if (external.shareScope) {
|
|
3300
|
-
actions[external.packageName].override = resolveOverrideEntries(
|
|
3301
|
-
entry,
|
|
3302
|
-
external,
|
|
3303
|
-
provided
|
|
3304
|
-
);
|
|
3305
|
-
}
|
|
3306
|
-
}
|
|
3307
|
-
});
|
|
3580
|
+
for (const item of pending)
|
|
3581
|
+
actions[item.external.packageName] = applyDecision(remoteEntry, item, decisions.get(item));
|
|
3308
3582
|
return Promise.resolve({ entry: remoteEntry, actions });
|
|
3309
3583
|
} catch (error) {
|
|
3310
3584
|
return Promise.reject(error);
|
|
3311
3585
|
}
|
|
3312
3586
|
};
|
|
3313
|
-
function
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
commit
|
|
3320
|
-
}) {
|
|
3321
|
-
let action = scopeType === "strict" ? "share" : "skip";
|
|
3322
|
-
const sharedVersion = cached.versions.find((c) => c.action === "share");
|
|
3323
|
-
const isCompatible = !sharedVersion || ports.versionCheck.isCompatible(sharedVersion.tag, remote.requiredVersion);
|
|
3324
|
-
if (action === "skip" && !isCompatible && remote.strictVersion) {
|
|
3325
|
-
action = "scope";
|
|
3326
|
-
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}'`;
|
|
3327
|
-
if (config.strict.strictExternalCompatibility) {
|
|
3328
|
-
config.log.error(8, errorMsg);
|
|
3329
|
-
throw new NFError(`Could not process remote '${remoteEntry.name}'`);
|
|
3330
|
-
}
|
|
3331
|
-
config.log.warn(8, errorMsg);
|
|
3587
|
+
function decidePackages(remoteEntry, pending) {
|
|
3588
|
+
const decisions = /* @__PURE__ */ new Map();
|
|
3589
|
+
const viewOf = loadViewOf(remoteEntry, pending);
|
|
3590
|
+
for (const group of pendingPerPackage(pending, viewOf)) {
|
|
3591
|
+
const decision = group[0].ctx.scopeType === "strict" ? { action: "share" } : decidePackage(remoteEntry, group, viewOf(group[0].external.shareScope));
|
|
3592
|
+
for (const item of group) decisions.set(item, decision);
|
|
3332
3593
|
}
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3594
|
+
scopeOpenedPackages(decisions);
|
|
3595
|
+
return decisions;
|
|
3596
|
+
}
|
|
3597
|
+
function pendingPerPackage(pending, viewOf) {
|
|
3598
|
+
const packages = /* @__PURE__ */ new Map();
|
|
3599
|
+
for (const item of pending) {
|
|
3600
|
+
const { shareScope, packageName } = item.external;
|
|
3601
|
+
const pkg = item.ctx.scopeType === "strict" ? packageName : viewOf(shareScope).packageOf(packageName);
|
|
3602
|
+
const key = `${shareScope ?? GLOBAL_SCOPE}\0${pkg}`;
|
|
3603
|
+
const group = packages.get(key);
|
|
3604
|
+
if (group) group.push(item);
|
|
3605
|
+
else packages.set(key, [item]);
|
|
3606
|
+
}
|
|
3607
|
+
return [...packages.values()];
|
|
3608
|
+
}
|
|
3609
|
+
function loadViewOf(remoteEntry, pending) {
|
|
3610
|
+
const views = /* @__PURE__ */ new Map();
|
|
3611
|
+
return (shareScope) => {
|
|
3612
|
+
const scope = shareScope ?? GLOBAL_SCOPE;
|
|
3613
|
+
let view = views.get(scope);
|
|
3614
|
+
if (!view) {
|
|
3615
|
+
const record = ports.sharedExternalsRepo.getFromScope(shareScope);
|
|
3616
|
+
const claims = committedClaims(Object.entries(record), {
|
|
3617
|
+
shareScope: scope,
|
|
3618
|
+
without: remoteEntry.name
|
|
3619
|
+
});
|
|
3620
|
+
const packageOf = packageOfIn(record, loadingIn(pending, scope));
|
|
3621
|
+
const claimsIn = groupByPackage(claims, ([specifier]) => specifier, packageOf);
|
|
3622
|
+
let pooled;
|
|
3623
|
+
view = {
|
|
3624
|
+
packageOf,
|
|
3625
|
+
claims,
|
|
3626
|
+
claimsOf: (pkg) => claimsIn.get(pkg) ?? [],
|
|
3627
|
+
inPool: (pkg) => {
|
|
3628
|
+
pooled ??= pooledPackagesWith(record, labelledCopiesIn(pending, scope), packageOf);
|
|
3629
|
+
return pooled.has(pkg);
|
|
3630
|
+
}
|
|
3631
|
+
};
|
|
3632
|
+
views.set(scope, view);
|
|
3347
3633
|
}
|
|
3634
|
+
return view;
|
|
3635
|
+
};
|
|
3636
|
+
}
|
|
3637
|
+
function inScope(pending, scope) {
|
|
3638
|
+
return pending.filter(({ external }) => (external.shareScope ?? GLOBAL_SCOPE) === scope);
|
|
3639
|
+
}
|
|
3640
|
+
function loadingIn(pending, scope) {
|
|
3641
|
+
return inScope(pending, scope).map(({ external, ctx }) => [external.packageName, ctx.remote]);
|
|
3642
|
+
}
|
|
3643
|
+
function labelledCopiesIn(pending, scope) {
|
|
3644
|
+
return inScope(pending, scope).map(({ external, ctx }) => ({
|
|
3645
|
+
name: external.packageName,
|
|
3646
|
+
pool: ctx.remote.pool
|
|
3647
|
+
}));
|
|
3648
|
+
}
|
|
3649
|
+
function scopeOpenedPackages(decisions) {
|
|
3650
|
+
if (![...decisions.values()].some((d) => d.action === "scope" && d.partlyServed)) return;
|
|
3651
|
+
for (const [item, decision] of decisions)
|
|
3652
|
+
if (decision.action === "share" && item.ctx.scopeType !== "strict")
|
|
3653
|
+
decisions.set(item, { action: "scope", partlyServed: false });
|
|
3654
|
+
}
|
|
3655
|
+
function decidePackage(remoteEntry, group, view) {
|
|
3656
|
+
const pkg = view.packageOf(group[0].external.packageName);
|
|
3657
|
+
const claims = view.claimsOf(pkg);
|
|
3658
|
+
if (claims.length === 0) return { action: "share" };
|
|
3659
|
+
const specifiers = group.flatMap(({ external }) => Object.keys(external.entries));
|
|
3660
|
+
const builds = specifiers.every((specifier) => view.claims.has(specifier)) ? new Set(specifiers.map((specifier) => view.claims.get(specifier).copy.name)) : void 0;
|
|
3661
|
+
const rejections = group.flatMap((item) => rejectionsOf(item, view.claims));
|
|
3662
|
+
if (rejections.length > 0) {
|
|
3663
|
+
const copies = group.map(({ ctx }) => ({ tag: ctx.tag, copy: ctx.remote }));
|
|
3664
|
+
const splits = builds !== void 0 && builds.size > 1 || loadSplitsPackage(pkg, copies, claims, accepts);
|
|
3665
|
+
for (const rejection of refused(rejections, splits, view.inPool(pkg)))
|
|
3666
|
+
reportIncompatible(remoteEntry, rejection);
|
|
3667
|
+
return { action: "scope", partlyServed: false };
|
|
3348
3668
|
}
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3669
|
+
if (!builds || builds.size > 1) return { action: "scope", partlyServed: true };
|
|
3670
|
+
return { action: "skip", files: servingFiles(claims, builds) };
|
|
3671
|
+
}
|
|
3672
|
+
function servingFiles(claims, builds) {
|
|
3673
|
+
const files = /* @__PURE__ */ new Map();
|
|
3674
|
+
for (const [specifier, { copy }] of claims)
|
|
3675
|
+
if (builds.has(copy.name)) files.set(specifier, copy);
|
|
3676
|
+
return files;
|
|
3677
|
+
}
|
|
3678
|
+
function rejectionsOf(item, claims) {
|
|
3679
|
+
const { external, ctx } = item;
|
|
3680
|
+
if (!ctx.remote.strictVersion) return [];
|
|
3681
|
+
return Object.keys(external.entries).flatMap((specifier) => {
|
|
3682
|
+
const claim = claims.get(specifier);
|
|
3683
|
+
return claim && !accepts(claim.tag, ctx.tag, ctx.remote.requiredVersion) ? [{ item, specifier, claim }] : [];
|
|
3684
|
+
});
|
|
3685
|
+
}
|
|
3686
|
+
function refused(rejections, splits, pooled) {
|
|
3687
|
+
const first = /* @__PURE__ */ new Map();
|
|
3688
|
+
for (const rejection of rejections)
|
|
3689
|
+
if (!first.has(rejection.item) && (pooled || !splits || electionKeeps(rejection)))
|
|
3690
|
+
first.set(rejection.item, rejection);
|
|
3691
|
+
return [...first.values()];
|
|
3692
|
+
}
|
|
3693
|
+
function electionKeeps({ item: { external, ctx }, claim }) {
|
|
3694
|
+
if (claim.external !== external.packageName) return false;
|
|
3695
|
+
const versions = ports.sharedExternalsRepo.tryGet(claim.external, external.shareScope).get()?.versions ?? [];
|
|
3696
|
+
const strict = [
|
|
3697
|
+
{ tag: ctx.tag, copy: ctx.remote },
|
|
3698
|
+
...versions.flatMap(
|
|
3699
|
+
(v) => v.remotes.filter((r) => r.strictVersion).map((copy) => ({ tag: v.tag, copy }))
|
|
3700
|
+
)
|
|
3701
|
+
];
|
|
3702
|
+
const tags = [ctx.tag, ...versions.map((v) => v.tag)];
|
|
3703
|
+
if (!tags.some((tag) => strict.every((s) => accepts(tag, s.tag, s.copy.requiredVersion))))
|
|
3704
|
+
return true;
|
|
3705
|
+
const host = versions.find((v) => v.host);
|
|
3706
|
+
if (host) return host.tag === claim.tag;
|
|
3707
|
+
if (!config.profile.latestSharedExternal) return false;
|
|
3708
|
+
return tags.every((tag) => ports.versionCheck.compare(claim.tag, tag) >= 0);
|
|
3709
|
+
}
|
|
3710
|
+
function reportIncompatible(remoteEntry, { item: { external, ctx }, specifier, claim }) {
|
|
3711
|
+
const errorMsg = `[${external.shareScope ?? GLOBAL_SCOPE}][${remoteEntry.name}] ${specifier}@${ctx.tag} Is not compatible with existing ${specifier}@${claim.tag} requiredRange '${ctx.remote.requiredVersion}'`;
|
|
3712
|
+
if (config.strict.strictExternalCompatibility) {
|
|
3713
|
+
config.log.error(8, errorMsg);
|
|
3714
|
+
throw new NFError(`Could not process remote '${remoteEntry.name}'`);
|
|
3362
3715
|
}
|
|
3363
|
-
|
|
3364
|
-
|
|
3716
|
+
config.log.warn(8, errorMsg);
|
|
3717
|
+
}
|
|
3718
|
+
function applyDecision(remoteEntry, { external, ctx }, decision) {
|
|
3719
|
+
storeCopy(ctx, decision.action);
|
|
3720
|
+
if (decision.action !== "skip") return { action: decision.action };
|
|
3721
|
+
const covered = Object.keys(external.entries);
|
|
3722
|
+
if (!external.shareScope) return { action: "skip", covered };
|
|
3723
|
+
return {
|
|
3724
|
+
action: "skip",
|
|
3725
|
+
covered,
|
|
3726
|
+
override: overrideFrom(remoteEntry, external, decision.files)
|
|
3727
|
+
};
|
|
3365
3728
|
}
|
|
3366
|
-
function
|
|
3729
|
+
function storeCopy(ctx, action) {
|
|
3730
|
+
const { tag, remote } = ctx;
|
|
3731
|
+
const cached = ctx.readRecord();
|
|
3732
|
+
const shared = cached.versions.find((v) => v.tag === tag && v.action === "share");
|
|
3733
|
+
if (shared && action !== "scope") ctx.assertSameVersionCompatibility(shared);
|
|
3734
|
+
remote.cached = action !== "skip";
|
|
3735
|
+
const row = action === "share" ? shared : cached.versions.find((v) => v.tag === tag && v.action === action);
|
|
3736
|
+
const loaderServes = action === "share" && ctx.scopeType !== "strict";
|
|
3737
|
+
if (!row) cached.versions.push({ tag, action, host: false, remotes: [remote] });
|
|
3738
|
+
else if (loaderServes) addRemoteToVersion(row, remote);
|
|
3739
|
+
else row.remotes.push(remote);
|
|
3740
|
+
if (loaderServes) cached.servingBuild = remote.name;
|
|
3741
|
+
ctx.write();
|
|
3742
|
+
}
|
|
3743
|
+
function overrideFrom(remoteEntry, external, files) {
|
|
3367
3744
|
return Object.fromEntries(
|
|
3368
|
-
Array.from(
|
|
3369
|
-
|
|
3370
|
-
join(
|
|
3371
|
-
providerScopeUrl(remoteEntry, external, provider.name),
|
|
3372
|
-
provider.entries[packageName]
|
|
3373
|
-
)
|
|
3745
|
+
Array.from(files, ([specifier, copy]) => [
|
|
3746
|
+
specifier,
|
|
3747
|
+
join(providerScopeUrl(remoteEntry, external, copy.name), copy.entries[specifier])
|
|
3374
3748
|
])
|
|
3375
3749
|
);
|
|
3376
3750
|
}
|
|
@@ -3385,181 +3759,335 @@ function createUpdateCache(config, ports) {
|
|
|
3385
3759
|
}
|
|
3386
3760
|
}
|
|
3387
3761
|
|
|
3388
|
-
// src/lib/core/
|
|
3389
|
-
function
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
for (const
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
const
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3762
|
+
// src/lib/core/1.domain/pooling/gate.ts
|
|
3763
|
+
function committedView(members, shipped, recordOrder, {
|
|
3764
|
+
shareScope,
|
|
3765
|
+
without,
|
|
3766
|
+
packageOf
|
|
3767
|
+
}) {
|
|
3768
|
+
const global = /* @__PURE__ */ new Map();
|
|
3769
|
+
const claims = committedClaims(inRecordOrder(members, recordOrder), { shareScope, without });
|
|
3770
|
+
for (const [specifier, { tag, copy }] of claims)
|
|
3771
|
+
global.set(specifier, { tag, remote: copy.name, file: copy.entries[specifier] });
|
|
3772
|
+
const builds = /* @__PURE__ */ new Map();
|
|
3773
|
+
for (const [owner, copies] of shipped)
|
|
3774
|
+
if (owner !== without) builds.set(owner, buildOf(owner, copies, packageOf));
|
|
3775
|
+
const fileOf = subpoolFilesOf(members);
|
|
3776
|
+
return {
|
|
3777
|
+
packageOf,
|
|
3778
|
+
builds,
|
|
3779
|
+
global,
|
|
3780
|
+
runsOffMap: runsOffMapOf(members, global, builds, fileOf)
|
|
3781
|
+
};
|
|
3782
|
+
}
|
|
3783
|
+
function subpoolFilesOf(members) {
|
|
3784
|
+
const subpoolOwners = /* @__PURE__ */ new Set();
|
|
3785
|
+
for (const member of members)
|
|
3786
|
+
for (const version of member.external.versions)
|
|
3787
|
+
for (const { servedBy } of version.remotes) if (servedBy) subpoolOwners.add(servedBy);
|
|
3788
|
+
const fileOf = /* @__PURE__ */ new Map();
|
|
3789
|
+
for (const member of members)
|
|
3790
|
+
for (const version of member.external.versions)
|
|
3791
|
+
for (const { name, entries } of version.remotes) {
|
|
3792
|
+
if (!subpoolOwners.has(name)) continue;
|
|
3793
|
+
let files = fileOf.get(name);
|
|
3794
|
+
if (!files) fileOf.set(name, files = /* @__PURE__ */ new Map());
|
|
3795
|
+
for (const specifier in entries)
|
|
3796
|
+
if (!files.has(specifier)) files.set(specifier, entries[specifier]);
|
|
3797
|
+
}
|
|
3798
|
+
return fileOf;
|
|
3799
|
+
}
|
|
3800
|
+
function runsOffMapOf(members, global, builds, fileOf) {
|
|
3801
|
+
const runsOffMap2 = /* @__PURE__ */ new Map();
|
|
3802
|
+
for (const member of members)
|
|
3803
|
+
for (const version of member.external.versions)
|
|
3804
|
+
for (const meta of version.remotes) {
|
|
3805
|
+
const { servedBy } = meta;
|
|
3806
|
+
if (version.action === "share" && !servedBy) continue;
|
|
3807
|
+
let runs = runsOffMap2.get(meta.name);
|
|
3808
|
+
if (!runs) runsOffMap2.set(meta.name, runs = /* @__PURE__ */ new Map());
|
|
3809
|
+
for (const specifier in meta.entries) {
|
|
3810
|
+
if (version.action === "skip" && !servedBy && global.has(specifier)) continue;
|
|
3811
|
+
const tag = (servedBy ? builds.get(servedBy)?.tags.pinnedTag(specifier) : void 0) ?? version.tag;
|
|
3812
|
+
const file = servedBy && fileOf.get(servedBy)?.get(specifier);
|
|
3813
|
+
runs.set(
|
|
3814
|
+
specifier,
|
|
3815
|
+
file ? { tag, remote: servedBy, file } : { tag, remote: meta.name, file: meta.entries[specifier] }
|
|
3429
3816
|
);
|
|
3430
|
-
mine.forEach((member) => scope(member.name, "uncovered"));
|
|
3431
|
-
continue;
|
|
3432
3817
|
}
|
|
3433
|
-
for (const name of redirect(entry.name, anchor, pool, asked.view, actions, shareScope))
|
|
3434
|
-
verdicts.set(name, { servedBy: anchor });
|
|
3435
3818
|
}
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3819
|
+
return runsOffMap2;
|
|
3820
|
+
}
|
|
3821
|
+
function judgeRemote(copies, view, accepts) {
|
|
3822
|
+
const { rejected, missing } = scan(copies, view, accepts);
|
|
3823
|
+
if (rejected) return { cause: "incompatible", ...rejected };
|
|
3824
|
+
const globalTags = new SpecifierTags(
|
|
3825
|
+
view.packageOf,
|
|
3826
|
+
[...view.global].map(([s, { tag }]) => [s, tag])
|
|
3827
|
+
);
|
|
3828
|
+
const binding = offMapBinding(copies, view, globalTags);
|
|
3829
|
+
if (binding) return { cause: "uncovered", ...binding };
|
|
3830
|
+
if (servedSplit(copies, view)) return { cause: "uncovered", unshipped: true };
|
|
3831
|
+
if (agrees(copies, globalTags)) return "global";
|
|
3832
|
+
if (missing !== void 0) return { cause: "uncovered", specifier: missing };
|
|
3833
|
+
if (unwitnessedGap(copies, globalTags, view.builds.values()) === void 0) return "global";
|
|
3834
|
+
return { cause: "uncovered", unshipped: true };
|
|
3835
|
+
}
|
|
3836
|
+
function servedSplit(copies, view) {
|
|
3837
|
+
const loaded = new Set(copies.flatMap((copy) => copy.specifiers.map(view.packageOf)));
|
|
3838
|
+
const servedBy = /* @__PURE__ */ new Map();
|
|
3839
|
+
for (const [specifier, { remote }] of view.global) {
|
|
3840
|
+
const pkg = view.packageOf(specifier);
|
|
3841
|
+
if (!loaded.has(pkg)) continue;
|
|
3842
|
+
const first = servedBy.get(pkg);
|
|
3843
|
+
if (first === void 0) servedBy.set(pkg, remote);
|
|
3844
|
+
else if (first !== remote) return true;
|
|
3845
|
+
}
|
|
3846
|
+
return false;
|
|
3847
|
+
}
|
|
3848
|
+
function coverFromMap(remote, mine, view, actions, policy) {
|
|
3849
|
+
const files = [];
|
|
3850
|
+
for (const member of mine) {
|
|
3851
|
+
const action = actions[member.name];
|
|
3852
|
+
const copy = member.external.versions.flatMap((v) => v.remotes).find((r) => r.name === remote);
|
|
3853
|
+
if (!copy) continue;
|
|
3854
|
+
const mapped = mapFiles(copy, view, policy, action);
|
|
3855
|
+
if ("unmapped" in mapped) return mapped;
|
|
3856
|
+
files.push({ member, action, copy, ...mapped });
|
|
3857
|
+
}
|
|
3858
|
+
const reaches = reachesOf(remote, files, view);
|
|
3859
|
+
const bound = boundByFile(reaches, view);
|
|
3860
|
+
if (bound !== void 0) return { bound };
|
|
3861
|
+
const servedPackages = new Set([...view.global.keys()].map(view.packageOf));
|
|
3862
|
+
const gap = files.map((file) => gapOf(file, servedPackages, view.packageOf)).find((specifier) => specifier !== void 0);
|
|
3863
|
+
if (gap !== void 0) return { gap };
|
|
3864
|
+
return { covers: files.filter(covering).map(coverOf) };
|
|
3865
|
+
}
|
|
3866
|
+
function gapOf({ copy, covered }, servedPackages, packageOf) {
|
|
3867
|
+
const entrypoints = Object.keys(copy.entries);
|
|
3868
|
+
const missing = entrypoints.filter((specifier) => !covered.has(specifier));
|
|
3869
|
+
if (missing.length < entrypoints.length) return missing[0];
|
|
3870
|
+
return missing.find((specifier) => servedPackages.has(packageOf(specifier)));
|
|
3871
|
+
}
|
|
3872
|
+
function covering({ action, copy, covered }) {
|
|
3873
|
+
if (action.action === "skip") return true;
|
|
3874
|
+
const entrypoints = Object.keys(copy.entries);
|
|
3875
|
+
return entrypoints.length > 0 && entrypoints.every((specifier) => covered.has(specifier));
|
|
3876
|
+
}
|
|
3877
|
+
function coverOf({ member, action, copy, covered, override }) {
|
|
3878
|
+
const toSkip = action.action !== "skip" || covered.size > action.covered.length && member.external.versions.some((v) => v.action === "share" && v.remotes.includes(copy));
|
|
3879
|
+
return { name: member.name, toSkip, override };
|
|
3880
|
+
}
|
|
3881
|
+
function reachesOf(remote, files, view) {
|
|
3882
|
+
const reaches = /* @__PURE__ */ new Map();
|
|
3883
|
+
const fromMap = (specifier) => {
|
|
3884
|
+
const served = view.global.get(specifier);
|
|
3885
|
+
return served && { remote: served.remote, file: served.file };
|
|
3886
|
+
};
|
|
3887
|
+
for (const file of files) {
|
|
3888
|
+
const takesMap = covering(file);
|
|
3889
|
+
for (const [specifier, own] of Object.entries(file.copy.entries)) {
|
|
3890
|
+
if (!takesMap || !file.covered.has(specifier)) reaches.set(specifier, { remote, file: own });
|
|
3891
|
+
else {
|
|
3892
|
+
const reach = fromMap(specifier);
|
|
3893
|
+
if (reach) reaches.set(specifier, reach);
|
|
3440
3894
|
}
|
|
3441
|
-
syncPoolNames({ ...committed, ...written }, pools, ports.sharedExternalsRepo, shareScope);
|
|
3442
3895
|
}
|
|
3443
|
-
return Promise.resolve({ entry, actions });
|
|
3444
|
-
};
|
|
3445
|
-
function gateViews(remote, pool) {
|
|
3446
|
-
return {
|
|
3447
|
-
pool,
|
|
3448
|
-
view: committedView(pool),
|
|
3449
|
-
wants: consumedMembers(pool).get(remote) ?? [],
|
|
3450
|
-
specifiers: consumedSpecifiers(pool).get(remote) ?? /* @__PURE__ */ new Set(),
|
|
3451
|
-
acceptance: lazy(() => acceptanceTable(pool, ports.versionCheck.isCompatible))
|
|
3452
|
-
};
|
|
3453
3896
|
}
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
if (
|
|
3464
|
-
|
|
3465
|
-
|
|
3897
|
+
return reaches;
|
|
3898
|
+
}
|
|
3899
|
+
function boundByFile(reaches, view) {
|
|
3900
|
+
const servers = /* @__PURE__ */ new Set();
|
|
3901
|
+
for (const { remote } of reaches.values()) if (view.builds.has(remote)) servers.add(remote);
|
|
3902
|
+
const firstRun = /* @__PURE__ */ new Map();
|
|
3903
|
+
for (const build of servers)
|
|
3904
|
+
for (const specifier of view.builds.get(build).tags.keys()) {
|
|
3905
|
+
const served = view.runsOffMap.get(build)?.get(specifier) ?? view.global.get(specifier);
|
|
3906
|
+
if (served === void 0) continue;
|
|
3907
|
+
const reached = reaches.get(specifier) ?? firstRun.get(specifier);
|
|
3908
|
+
if (reached === void 0) {
|
|
3909
|
+
firstRun.set(specifier, served);
|
|
3910
|
+
if (view.builds.has(served.remote)) servers.add(served.remote);
|
|
3911
|
+
} else if (reached.remote !== served.remote || reached.file !== served.file)
|
|
3912
|
+
return { owner: build, specifier, tag: served.tag };
|
|
3466
3913
|
}
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
const
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
let allScoped = true;
|
|
3480
|
-
for (const member of pool) {
|
|
3481
|
-
for (const version of member.external.versions) {
|
|
3482
|
-
const meta = version.remotes.find((r) => r.name === build);
|
|
3483
|
-
if (!meta) continue;
|
|
3484
|
-
if (meta.servedBy !== void 0) return false;
|
|
3485
|
-
ships2++;
|
|
3486
|
-
if (version.action !== "scope") allScoped = false;
|
|
3487
|
-
if (basis.get(member.name) !== build) winsAll = false;
|
|
3488
|
-
}
|
|
3914
|
+
return void 0;
|
|
3915
|
+
}
|
|
3916
|
+
function mapFiles(copy, view, policy, action) {
|
|
3917
|
+
const covered = new Set(action.covered);
|
|
3918
|
+
const override = { ...action.override };
|
|
3919
|
+
for (const specifier in copy.entries) {
|
|
3920
|
+
const source = view.global.get(specifier);
|
|
3921
|
+
if (!source) continue;
|
|
3922
|
+
if (policy.shareScope !== GLOBAL_SCOPE) {
|
|
3923
|
+
const scopeUrl = policy.scopeUrlOf(source.remote);
|
|
3924
|
+
if (!scopeUrl) return { unmapped: source.remote };
|
|
3925
|
+
override[specifier] = join(scopeUrl, source.file);
|
|
3489
3926
|
}
|
|
3490
|
-
|
|
3491
|
-
}
|
|
3492
|
-
function explainDynamic(remote, { view, wants, specifiers, acceptance }) {
|
|
3493
|
-
return explainSelfServe(remote, wants, specifiers, {
|
|
3494
|
-
builds: view.builds,
|
|
3495
|
-
acceptance: acceptance()
|
|
3496
|
-
});
|
|
3927
|
+
covered.add(specifier);
|
|
3497
3928
|
}
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
);
|
|
3506
|
-
|
|
3929
|
+
return { covered, override };
|
|
3930
|
+
}
|
|
3931
|
+
function scan(copies, view, accepts) {
|
|
3932
|
+
let rejected;
|
|
3933
|
+
let missing;
|
|
3934
|
+
for (const copy of copies)
|
|
3935
|
+
for (const s of copy.specifiers) {
|
|
3936
|
+
const global = view.global.get(s);
|
|
3937
|
+
if (global === void 0) missing ??= s;
|
|
3938
|
+
else if (!accepts(global.tag, copy.tag, copy.requiredVersion))
|
|
3939
|
+
rejected ??= { specifier: s, tag: global.tag };
|
|
3507
3940
|
}
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
const file = files.get(specifier);
|
|
3521
|
-
if (file) override[specifier] = join(scopeUrl, file);
|
|
3522
|
-
}
|
|
3523
|
-
action.covered = specifiers;
|
|
3524
|
-
if (Object.keys(override).length > 0) action.override = override;
|
|
3525
|
-
if (basis.get(member.name) !== anchor) served.push(member.name);
|
|
3941
|
+
return { rejected, missing };
|
|
3942
|
+
}
|
|
3943
|
+
function offMapBinding(copies, view, globalTags) {
|
|
3944
|
+
const own = new SpecifierTags(
|
|
3945
|
+
view.packageOf,
|
|
3946
|
+
copies.flatMap((c) => c.specifiers.map((s) => [s, c.tag]))
|
|
3947
|
+
);
|
|
3948
|
+
const servers = /* @__PURE__ */ new Set();
|
|
3949
|
+
for (const copy of copies)
|
|
3950
|
+
for (const specifier of copy.specifiers) {
|
|
3951
|
+
const build = view.global.get(specifier)?.remote;
|
|
3952
|
+
if (build !== void 0) servers.add(build);
|
|
3526
3953
|
}
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
versions: external.versions.map((v) => ({
|
|
3534
|
-
...v,
|
|
3535
|
-
remotes: v.remotes.map(
|
|
3536
|
-
(r) => r.name === remote ? { ...r, servedBy: verdict.servedBy } : r
|
|
3537
|
-
)
|
|
3538
|
-
}))
|
|
3539
|
-
};
|
|
3954
|
+
const firstRun = new SpecifierTags(view.packageOf);
|
|
3955
|
+
for (const build of servers)
|
|
3956
|
+
for (const [specifier, { tag }] of view.runsOffMap.get(build) ?? []) {
|
|
3957
|
+
const reached = globalTags.pinnedTag(specifier) ?? own.pinnedTag(specifier) ?? firstRun.pinnedTag(specifier);
|
|
3958
|
+
if (reached === void 0) firstRun.set(specifier, tag);
|
|
3959
|
+
else if (reached !== tag) return { owner: build, specifier, tag };
|
|
3540
3960
|
}
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3961
|
+
return void 0;
|
|
3962
|
+
}
|
|
3963
|
+
function inRecordOrder(members, recordOrder) {
|
|
3964
|
+
const rank2 = new Map(recordOrder.map((name, i) => [name, i]));
|
|
3965
|
+
return [...members].sort((a, b) => rank2.get(a.name) - rank2.get(b.name)).map((m) => [m.name, m.external]);
|
|
3966
|
+
}
|
|
3967
|
+
|
|
3968
|
+
// src/lib/core/2.app/steps/pooling/pool-dynamic-externals.ts
|
|
3969
|
+
function createPoolDynamicExternals(config, ports) {
|
|
3970
|
+
const accepts = createAcceptsTag(
|
|
3971
|
+
(tag, range) => ports.versionCheck.isCompatible(tag, range),
|
|
3972
|
+
(a, b) => ports.versionCheck.compare(a, b)
|
|
3973
|
+
);
|
|
3974
|
+
const scopeUrlOf = (remote) => ports.remoteInfoRepo.tryGet(remote).get()?.scopeUrl;
|
|
3975
|
+
return ({ entry, actions }) => {
|
|
3976
|
+
for (const [scope, names] of poolableNames(entry, actions)) {
|
|
3977
|
+
const committed = ports.sharedExternalsRepo.getFromScope(scope);
|
|
3978
|
+
if (!scopeHasPoolState(committed)) continue;
|
|
3979
|
+
const { pools, packageOf } = buildPools(committed);
|
|
3980
|
+
const moves = judgeScope(
|
|
3981
|
+
entry.name,
|
|
3982
|
+
names,
|
|
3983
|
+
actions,
|
|
3984
|
+
pools,
|
|
3985
|
+
packageOf,
|
|
3986
|
+
Object.keys(committed),
|
|
3987
|
+
scope
|
|
3988
|
+
);
|
|
3989
|
+
writeMoves(entry.name, names, moves, committed, pools, scope);
|
|
3556
3990
|
}
|
|
3557
|
-
return {
|
|
3558
|
-
|
|
3559
|
-
|
|
3991
|
+
return Promise.resolve({ entry, actions: publicActions(actions) });
|
|
3992
|
+
};
|
|
3993
|
+
function judgeScope(remote, names, actions, pools, packageOf, recordOrder, scope) {
|
|
3994
|
+
const policy = { shareScope: scope, scopeUrlOf };
|
|
3995
|
+
const moves = /* @__PURE__ */ new Map();
|
|
3996
|
+
const selfServe = (members, cause) => {
|
|
3997
|
+
for (const { name } of members) {
|
|
3998
|
+
actions[name].action = "scope";
|
|
3999
|
+
delete actions[name].override;
|
|
4000
|
+
moves.set(name, { cause });
|
|
4001
|
+
}
|
|
3560
4002
|
};
|
|
4003
|
+
for (const pool of pools.values()) {
|
|
4004
|
+
const mine = pool.filter((member) => names.has(member.name));
|
|
4005
|
+
if (mine.length === 0) continue;
|
|
4006
|
+
const shipped = copiesByRemote(pool);
|
|
4007
|
+
const view = committedView(pool, shipped, recordOrder, {
|
|
4008
|
+
shareScope: scope,
|
|
4009
|
+
without: remote,
|
|
4010
|
+
packageOf
|
|
4011
|
+
});
|
|
4012
|
+
const own = shipped.get(remote) ?? [];
|
|
4013
|
+
const verdict = judgeRemote(own, view, accepts);
|
|
4014
|
+
if (verdict !== "global") {
|
|
4015
|
+
config.log.warn(8, `[${scope}] ${selfServeWarning(remote, verdict, specifierCount(own))}`);
|
|
4016
|
+
selfServe(mine, verdict.cause);
|
|
4017
|
+
continue;
|
|
4018
|
+
}
|
|
4019
|
+
const cover = coverFromMap(remote, mine, view, actions, policy);
|
|
4020
|
+
if (!("covers" in cover)) {
|
|
4021
|
+
if ("unmapped" in cover) warnUnmapped(scope, remote, cover.unmapped);
|
|
4022
|
+
else
|
|
4023
|
+
config.log.warn(
|
|
4024
|
+
8,
|
|
4025
|
+
`[${scope}] ${selfServeWarning(remote, coverMiss(cover), specifierCount(own))}`
|
|
4026
|
+
);
|
|
4027
|
+
selfServe(mine, "uncovered");
|
|
4028
|
+
continue;
|
|
4029
|
+
}
|
|
4030
|
+
for (const { name, toSkip, override } of cover.covers) {
|
|
4031
|
+
const action = actions[name];
|
|
4032
|
+
if (toSkip) {
|
|
4033
|
+
action.action = "skip";
|
|
4034
|
+
moves.set(name, { fromMap: true });
|
|
4035
|
+
}
|
|
4036
|
+
if (Object.keys(override).length > 0) action.override = override;
|
|
4037
|
+
}
|
|
4038
|
+
}
|
|
4039
|
+
return moves;
|
|
4040
|
+
}
|
|
4041
|
+
function writeMoves(remote, names, moves, committed, pools, scope) {
|
|
4042
|
+
const written = {};
|
|
4043
|
+
for (const [name, move] of moves)
|
|
4044
|
+
written[name] = movedRecord(committed[name], remote, move, ports.versionCheck.compare);
|
|
4045
|
+
for (const [name, record] of renamedRecords({ ...committed, ...written }, pools))
|
|
4046
|
+
written[name] = record;
|
|
4047
|
+
if (!config.strict.strictExternalCompatibility)
|
|
4048
|
+
for (const { name } of [...pools.values()].flat().filter((m) => names.has(m.name)))
|
|
4049
|
+
written[name] = { ...written[name] ?? committed[name], dirty: true };
|
|
4050
|
+
for (const [name, record] of Object.entries(written))
|
|
4051
|
+
ports.sharedExternalsRepo.addOrUpdate(name, record, scope);
|
|
4052
|
+
}
|
|
4053
|
+
function warnUnmapped(scope, remote, build) {
|
|
4054
|
+
config.log.warn(
|
|
4055
|
+
8,
|
|
4056
|
+
`[${scope}][${remote}] '${build}' is not in the cache, so its files cannot be mapped.`
|
|
4057
|
+
);
|
|
3561
4058
|
}
|
|
3562
4059
|
}
|
|
4060
|
+
function publicActions(actions) {
|
|
4061
|
+
for (const action of Object.values(actions)) delete action.covered;
|
|
4062
|
+
return actions;
|
|
4063
|
+
}
|
|
4064
|
+
function poolableNames(entry, actions) {
|
|
4065
|
+
const declared = /* @__PURE__ */ new Map();
|
|
4066
|
+
for (const external of entry.shared ?? []) {
|
|
4067
|
+
const name = external.packageName;
|
|
4068
|
+
if (!external.singleton || !actions[name]) continue;
|
|
4069
|
+
if (external.shareScope === STRICT_SCOPE) continue;
|
|
4070
|
+
const scope = external.shareScope ?? GLOBAL_SCOPE;
|
|
4071
|
+
let names = declared.get(scope);
|
|
4072
|
+
if (!names) declared.set(scope, names = /* @__PURE__ */ new Set());
|
|
4073
|
+
names.add(name);
|
|
4074
|
+
}
|
|
4075
|
+
return declared;
|
|
4076
|
+
}
|
|
4077
|
+
function coverMiss(cover) {
|
|
4078
|
+
if ("gap" in cover) return { cause: "uncovered", specifier: cover.gap };
|
|
4079
|
+
return { cause: "uncovered", ...cover.bound };
|
|
4080
|
+
}
|
|
4081
|
+
function selfServeWarning(remote, miss, imports) {
|
|
4082
|
+
const where = `All ${imports} of its entrypoints are scoped for it.`;
|
|
4083
|
+
if (miss.cause === "incompatible")
|
|
4084
|
+
return `'${remote}' is islanded: its range rejects '${miss.specifier}@${miss.tag}' of the committed map. ${where}`;
|
|
4085
|
+
if ("owner" in miss)
|
|
4086
|
+
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}`;
|
|
4087
|
+
if ("unshipped" in miss)
|
|
4088
|
+
return `'${remote}' serves its own family: no committed build shipped the map's combination for it. ${where}`;
|
|
4089
|
+
return `'${remote}' serves its own family: no committed build offers every entrypoint it imports at a version it accepts (gap '${miss.specifier}'). ${where}`;
|
|
4090
|
+
}
|
|
3563
4091
|
|
|
3564
4092
|
// src/lib/core/2.app/steps/convert-to-import-map.ts
|
|
3565
4093
|
function createConvertToImportMap(config, ports) {
|
|
@@ -3596,27 +4124,14 @@ function createConvertToImportMap(config, ports) {
|
|
|
3596
4124
|
return;
|
|
3597
4125
|
}
|
|
3598
4126
|
if (actions[external.packageName].action === "skip") {
|
|
3599
|
-
const { override
|
|
4127
|
+
const { override } = actions[external.packageName];
|
|
3600
4128
|
if (override) {
|
|
3601
4129
|
Object.entries(override).forEach(([packageName, url]) => {
|
|
3602
4130
|
addToScopes(remoteEntryScope, packageName, url, importMap);
|
|
3603
4131
|
});
|
|
3604
|
-
serveUncovered(
|
|
3605
|
-
remoteEntry,
|
|
3606
|
-
external,
|
|
3607
|
-
covered ?? Object.keys(override),
|
|
3608
|
-
remoteEntryScope,
|
|
3609
|
-
importMap,
|
|
3610
|
-
sameVersion
|
|
3611
|
-
);
|
|
3612
|
-
return;
|
|
3613
|
-
}
|
|
3614
|
-
if (!external.shareScope) {
|
|
3615
|
-
if (covered) {
|
|
3616
|
-
serveUncovered(remoteEntry, external, covered, remoteEntryScope, importMap, sameVersion);
|
|
3617
|
-
}
|
|
3618
4132
|
return;
|
|
3619
4133
|
}
|
|
4134
|
+
if (!external.shareScope) return;
|
|
3620
4135
|
log.error(
|
|
3621
4136
|
9,
|
|
3622
4137
|
`[${remoteEntry.name}][${external.packageName}] shareScope skip has no override.`
|
|
@@ -3681,27 +4196,6 @@ function createConvertToImportMap(config, ports) {
|
|
|
3681
4196
|
});
|
|
3682
4197
|
return importMap;
|
|
3683
4198
|
}
|
|
3684
|
-
function serveUncovered(remoteEntry, external, covered, remoteEntryScope, importMap, sameVersion = false) {
|
|
3685
|
-
const provided = new Set(covered);
|
|
3686
|
-
Object.entries(external.entries).forEach(([packageName, fileName]) => {
|
|
3687
|
-
if (provided.has(packageName)) return;
|
|
3688
|
-
if (!sameVersion && (config.strict.strictEntryPointCoverage || config.profile.scopeUncoveredEntrypoints)) {
|
|
3689
|
-
warnUncoveredEntrypoint(remoteEntry.name, external.packageName, packageName);
|
|
3690
|
-
return;
|
|
3691
|
-
}
|
|
3692
|
-
const url = join(remoteEntryScope, fileName);
|
|
3693
|
-
addToScopes(remoteEntryScope, packageName, url, importMap);
|
|
3694
|
-
addIntegrity(importMap, url, remoteEntry.integrity, fileName);
|
|
3695
|
-
});
|
|
3696
|
-
}
|
|
3697
|
-
function warnUncoveredEntrypoint(remoteName, externalName, packageName) {
|
|
3698
|
-
const msg = `[${remoteName}][${externalName}] Entrypoint '${packageName}' is not covered by the override.`;
|
|
3699
|
-
if (config.strict.strictEntryPointCoverage || config.strict.strictImportMap) {
|
|
3700
|
-
log.error(9, msg);
|
|
3701
|
-
throw new NFError("Could not create ImportMap.");
|
|
3702
|
-
}
|
|
3703
|
-
log.warn(9, msg);
|
|
3704
|
-
}
|
|
3705
4199
|
function addIntegrity(importMap, url, integrityMap, file) {
|
|
3706
4200
|
const hash = integrityMap?.[file];
|
|
3707
4201
|
if (!hash) return;
|
|
@@ -3717,11 +4211,12 @@ var createInitDrivers = ({
|
|
|
3717
4211
|
}) => ({
|
|
3718
4212
|
getRemoteEntries: createGetRemoteEntries(config, adapters),
|
|
3719
4213
|
processRemoteEntries: createProcessRemoteEntries(config, adapters),
|
|
3720
|
-
markPoolsForReelection: createMarkPoolsForReelection(config, adapters),
|
|
3721
4214
|
determineSharedExternals: createDetermineSharedExternals(config, adapters),
|
|
3722
4215
|
poolSharedExternals: createPoolSharedExternals(config, adapters),
|
|
4216
|
+
decideServingBuilds: createDecideServingBuilds(config, adapters),
|
|
3723
4217
|
generateImportMap: createGenerateImportMap(config, adapters),
|
|
3724
4218
|
commitChanges: createCommitChanges(config, adapters),
|
|
4219
|
+
rollbackChanges: createRollbackChanges(config, adapters),
|
|
3725
4220
|
exposeModuleLoader: createExposeModuleLoader(config, adapters),
|
|
3726
4221
|
getRemoteEntry: createGetRemoteEntry(config, adapters),
|
|
3727
4222
|
updateCache: createUpdateCache(config, adapters),
|
|
@@ -3751,19 +4246,30 @@ var createBrowser = (config) => {
|
|
|
3751
4246
|
// src/lib/core/3.adapters/checks/version.check.ts
|
|
3752
4247
|
var import_valid = __toESM(require_valid());
|
|
3753
4248
|
var import_satisfies = __toESM(require_satisfies());
|
|
3754
|
-
var
|
|
4249
|
+
var import_semver = __toESM(require_semver());
|
|
3755
4250
|
var import_min_version = __toESM(require_min_version());
|
|
3756
4251
|
var import_valid2 = __toESM(require_valid2());
|
|
3757
4252
|
var createVersionCheck = () => {
|
|
4253
|
+
const parsed = /* @__PURE__ */ new Map();
|
|
4254
|
+
const parse = (v) => {
|
|
4255
|
+
let hit = parsed.get(v);
|
|
4256
|
+
if (!hit) parsed.set(v, hit = new import_semver.default(v, true));
|
|
4257
|
+
return hit;
|
|
4258
|
+
};
|
|
4259
|
+
const satisfied = /* @__PURE__ */ new Map();
|
|
3758
4260
|
return {
|
|
3759
4261
|
isValidSemver: function(version) {
|
|
3760
4262
|
return (0, import_valid.default)(version) !== null;
|
|
3761
4263
|
},
|
|
3762
4264
|
isCompatible: function(version, range) {
|
|
3763
|
-
|
|
4265
|
+
let byVersion = satisfied.get(range);
|
|
4266
|
+
if (!byVersion) satisfied.set(range, byVersion = /* @__PURE__ */ new Map());
|
|
4267
|
+
let hit = byVersion.get(version);
|
|
4268
|
+
if (hit === void 0) byVersion.set(version, hit = (0, import_satisfies.default)(version, range));
|
|
4269
|
+
return hit;
|
|
3764
4270
|
},
|
|
3765
4271
|
compare: function(versionA, versionB) {
|
|
3766
|
-
return (
|
|
4272
|
+
return parse(versionA).compare(parse(versionB));
|
|
3767
4273
|
},
|
|
3768
4274
|
smallestVersion: function(versionRange) {
|
|
3769
4275
|
if (!(0, import_valid2.default)(versionRange)) return "0.0.0";
|
|
@@ -3836,7 +4342,12 @@ var createManifestProvider = () => {
|
|
|
3836
4342
|
};
|
|
3837
4343
|
};
|
|
3838
4344
|
|
|
3839
|
-
//
|
|
4345
|
+
// src/lib/core/1.domain/remote-entry/mark-dense.ts
|
|
4346
|
+
function markDense(shared) {
|
|
4347
|
+
return shared.map((entry) => "entries" in entry ? { ...entry, dense: true } : entry);
|
|
4348
|
+
}
|
|
4349
|
+
|
|
4350
|
+
// node_modules/.pnpm/@softarc+native-federation@4.9.0/node_modules/@softarc/native-federation/dist/lib/utils/normalize.js
|
|
3840
4351
|
function inferPackageFromSecondary(secondary) {
|
|
3841
4352
|
const parts = secondary.split("/");
|
|
3842
4353
|
if (secondary.startsWith("@") && parts.length >= 2) {
|
|
@@ -3845,14 +4356,14 @@ function inferPackageFromSecondary(secondary) {
|
|
|
3845
4356
|
return parts[0];
|
|
3846
4357
|
}
|
|
3847
4358
|
|
|
3848
|
-
// node_modules/.pnpm/@softarc+native-federation@4.
|
|
4359
|
+
// node_modules/.pnpm/@softarc+native-federation@4.9.0/node_modules/@softarc/native-federation/dist/lib/core/output/densify-externals.js
|
|
3849
4360
|
function isDense(entry) {
|
|
3850
4361
|
return "entries" in entry;
|
|
3851
4362
|
}
|
|
3852
4363
|
function isFlatChunk(entry) {
|
|
3853
4364
|
return entry.packageName.startsWith(CHUNK_PREFIX);
|
|
3854
4365
|
}
|
|
3855
|
-
function densifyExternals(shared) {
|
|
4366
|
+
function densifyExternals(shared, declaredPackages) {
|
|
3856
4367
|
const result = [];
|
|
3857
4368
|
const groupIndex = /* @__PURE__ */ new Map();
|
|
3858
4369
|
for (const entry of shared) {
|
|
@@ -3866,7 +4377,7 @@ function densifyExternals(shared) {
|
|
|
3866
4377
|
continue;
|
|
3867
4378
|
}
|
|
3868
4379
|
const { outFileName, packageName, dev, ...meta } = entry;
|
|
3869
|
-
const parent = inferPackageFromSecondary(packageName);
|
|
4380
|
+
const parent = declaredPackages.get(packageName) ?? inferPackageFromSecondary(packageName);
|
|
3870
4381
|
const sig = JSON.stringify(meta, Object.keys(meta).sort());
|
|
3871
4382
|
const key = parent + " " + sig;
|
|
3872
4383
|
const existing = groupIndex.get(key);
|
|
@@ -3896,6 +4407,16 @@ function toDenseSharedInfoFormat(shared) {
|
|
|
3896
4407
|
});
|
|
3897
4408
|
}
|
|
3898
4409
|
|
|
4410
|
+
// src/lib/core/3.adapters/remote-entry/normalize-remote-entry.ts
|
|
4411
|
+
var normalizeRemoteEntry = (raw, remoteEntryUrl, config) => {
|
|
4412
|
+
const marked = markDense(raw.shared ?? []);
|
|
4413
|
+
const shared = config.feature.convertFlatSharedInfo ? densifyExternals(marked, /* @__PURE__ */ new Map()) : toDenseSharedInfoFormat(marked);
|
|
4414
|
+
const remoteEntry = { ...raw, shared };
|
|
4415
|
+
if (!remoteEntry.exposes) remoteEntry.exposes = [];
|
|
4416
|
+
if (!remoteEntry.url) remoteEntry.url = remoteEntryUrl;
|
|
4417
|
+
return remoteEntry;
|
|
4418
|
+
};
|
|
4419
|
+
|
|
3899
4420
|
// src/lib/core/3.adapters/http/remote-entry-provider.ts
|
|
3900
4421
|
var createRemoteEntryProvider = (config) => {
|
|
3901
4422
|
const ensureOk = (response) => {
|
|
@@ -3903,16 +4424,6 @@ var createRemoteEntryProvider = (config) => {
|
|
|
3903
4424
|
return Promise.reject(new Error(`${response.status} - ${response.statusText}`));
|
|
3904
4425
|
return response;
|
|
3905
4426
|
};
|
|
3906
|
-
const fillEmptyFields = (remoteEntryUrl) => (remoteEntry) => {
|
|
3907
|
-
if (!remoteEntry.exposes) remoteEntry.exposes = [];
|
|
3908
|
-
if (!remoteEntry.shared) remoteEntry.shared = [];
|
|
3909
|
-
if (!remoteEntry.url) remoteEntry.url = remoteEntryUrl;
|
|
3910
|
-
return remoteEntry;
|
|
3911
|
-
};
|
|
3912
|
-
const normalizeRemoteEntry = (raw) => {
|
|
3913
|
-
const shared = config.feature.convertFlatSharedInfo ? densifyExternals(raw.shared ?? []) : toDenseSharedInfoFormat(raw.shared ?? []);
|
|
3914
|
-
return { ...raw, shared };
|
|
3915
|
-
};
|
|
3916
4427
|
const formatError = (remoteEntryUrl) => (err) => {
|
|
3917
4428
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3918
4429
|
throw new NFError(`Fetch of '${remoteEntryUrl}' returned ${msg}`);
|
|
@@ -3925,7 +4436,7 @@ var createRemoteEntryProvider = (config) => {
|
|
|
3925
4436
|
await verifyIntegrity(bytes, opts.integrity);
|
|
3926
4437
|
return JSON.parse(new TextDecoder().decode(bytes));
|
|
3927
4438
|
};
|
|
3928
|
-
return fetch(remoteEntryUrl).then(ensureOk).then(parse).then(normalizeRemoteEntry
|
|
4439
|
+
return fetch(remoteEntryUrl).then(ensureOk).then(parse).then((raw) => normalizeRemoteEntry(raw, remoteEntryUrl, config)).catch(formatError(remoteEntryUrl));
|
|
3929
4440
|
}
|
|
3930
4441
|
};
|
|
3931
4442
|
};
|
|
@@ -3935,14 +4446,15 @@ var STORAGE_KEYS = {
|
|
|
3935
4446
|
remotes: "remotes",
|
|
3936
4447
|
sharedExternals: "shared-externals",
|
|
3937
4448
|
scopedExternals: "scoped-externals",
|
|
3938
|
-
sharedChunks: "shared-chunks"
|
|
4449
|
+
sharedChunks: "shared-chunks",
|
|
4450
|
+
cacheState: "cache-state"
|
|
3939
4451
|
};
|
|
3940
4452
|
|
|
3941
4453
|
// src/lib/core/3.adapters/storage/remote-info.repository.ts
|
|
3942
4454
|
var createRemoteInfoRepository = (config) => {
|
|
3943
4455
|
const STORAGE = config.storage(STORAGE_KEYS.remotes, {});
|
|
3944
4456
|
if (config.clearStorage) STORAGE.clear();
|
|
3945
|
-
|
|
4457
|
+
let _cache = STORAGE.get() ?? {};
|
|
3946
4458
|
let _dirty = false;
|
|
3947
4459
|
return {
|
|
3948
4460
|
contains: function(remoteName) {
|
|
@@ -3976,6 +4488,11 @@ var createRemoteInfoRepository = (config) => {
|
|
|
3976
4488
|
STORAGE.set(_cache);
|
|
3977
4489
|
_dirty = false;
|
|
3978
4490
|
return this;
|
|
4491
|
+
},
|
|
4492
|
+
rollback: function() {
|
|
4493
|
+
_cache = STORAGE.get() ?? {};
|
|
4494
|
+
_dirty = false;
|
|
4495
|
+
return this;
|
|
3979
4496
|
}
|
|
3980
4497
|
};
|
|
3981
4498
|
};
|
|
@@ -3984,7 +4501,7 @@ var createRemoteInfoRepository = (config) => {
|
|
|
3984
4501
|
var createScopedExternalsRepository = (config) => {
|
|
3985
4502
|
const STORAGE = config.storage(STORAGE_KEYS.scopedExternals, {});
|
|
3986
4503
|
if (config.clearStorage) STORAGE.clear();
|
|
3987
|
-
|
|
4504
|
+
let _cache = STORAGE.get() ?? {};
|
|
3988
4505
|
let _dirty = false;
|
|
3989
4506
|
return {
|
|
3990
4507
|
addExternal: function(remoteName, external, version) {
|
|
@@ -4011,43 +4528,57 @@ var createScopedExternalsRepository = (config) => {
|
|
|
4011
4528
|
STORAGE.set(_cache);
|
|
4012
4529
|
_dirty = false;
|
|
4013
4530
|
return this;
|
|
4531
|
+
},
|
|
4532
|
+
rollback: function() {
|
|
4533
|
+
_cache = STORAGE.get() ?? {};
|
|
4534
|
+
_dirty = false;
|
|
4535
|
+
return this;
|
|
4014
4536
|
}
|
|
4015
4537
|
};
|
|
4016
4538
|
};
|
|
4017
4539
|
|
|
4540
|
+
// src/lib/core/3.adapters/storage/cache-state.ts
|
|
4541
|
+
var createCacheState = (storage) => {
|
|
4542
|
+
const entry = storage(STORAGE_KEYS.cacheState, null);
|
|
4543
|
+
const read = () => {
|
|
4544
|
+
const stored = entry.get();
|
|
4545
|
+
if (typeof stored !== "object" || stored === null) return {};
|
|
4546
|
+
const { version, undecidedScopes } = stored;
|
|
4547
|
+
return {
|
|
4548
|
+
...typeof version === "string" ? { version } : {},
|
|
4549
|
+
...Array.isArray(undecidedScopes) ? { undecidedScopes: undecidedScopes.filter((s) => typeof s === "string") } : {}
|
|
4550
|
+
};
|
|
4551
|
+
};
|
|
4552
|
+
return {
|
|
4553
|
+
read,
|
|
4554
|
+
update: (fields) => void entry.set({ ...read(), ...fields })
|
|
4555
|
+
};
|
|
4556
|
+
};
|
|
4557
|
+
|
|
4018
4558
|
// src/lib/core/3.adapters/storage/shared-externals.repository.ts
|
|
4019
4559
|
var createSharedExternalsRepository = (config) => {
|
|
4020
4560
|
const STORAGE = config.storage(
|
|
4021
4561
|
STORAGE_KEYS.sharedExternals,
|
|
4022
4562
|
{ [GLOBAL_SCOPE]: {} }
|
|
4023
4563
|
);
|
|
4024
|
-
|
|
4025
|
-
const
|
|
4026
|
-
|
|
4564
|
+
const cacheState = createCacheState(config.storage);
|
|
4565
|
+
const storedUndecided = () => new Set(cacheState.read().undecidedScopes);
|
|
4566
|
+
if (config.clearStorage) {
|
|
4567
|
+
STORAGE.clear();
|
|
4568
|
+
cacheState.update({ undecidedScopes: [] });
|
|
4569
|
+
}
|
|
4570
|
+
let _cache = STORAGE.get() ?? { [GLOBAL_SCOPE]: {} };
|
|
4571
|
+
const _uncommitted = /* @__PURE__ */ new Set();
|
|
4572
|
+
let _undecided = storedUndecided();
|
|
4573
|
+
let _undecidedChanged = false;
|
|
4027
4574
|
return {
|
|
4028
|
-
// Read from the cache rather than remembered from this init's entries: a warm init may not refetch
|
|
4029
|
-
// the tagged remote at all, and pooling has to coordinate its pool anyway. Exits on the first hit.
|
|
4030
|
-
// Per share scope, because a pool never spans one: a tag in another scope is no reason to pool here.
|
|
4031
|
-
// Stored pool results count too, since a scope whose last tag left still has pool state to clear.
|
|
4032
|
-
hasPoolState: function(shareScope) {
|
|
4033
|
-
const scope = _cache[shareScope ?? GLOBAL_SCOPE];
|
|
4034
|
-
if (!scope) return false;
|
|
4035
|
-
for (const external of Object.values(scope)) {
|
|
4036
|
-
if (external.poolName !== void 0) return true;
|
|
4037
|
-
for (const version of external.versions)
|
|
4038
|
-
for (const remote of version.remotes)
|
|
4039
|
-
if (remote.pool?.trim() || remote.servedBy !== void 0 || remote.poolCause !== void 0)
|
|
4040
|
-
return true;
|
|
4041
|
-
}
|
|
4042
|
-
return false;
|
|
4043
|
-
},
|
|
4044
4575
|
getFromScope: function(shareScope) {
|
|
4045
4576
|
return { ..._cache[shareScope ?? GLOBAL_SCOPE] };
|
|
4046
4577
|
},
|
|
4047
4578
|
addOrUpdate: function(externalName, external, shareScope) {
|
|
4048
4579
|
if (!_cache[shareScope ?? GLOBAL_SCOPE]) _cache[shareScope ?? GLOBAL_SCOPE] = {};
|
|
4049
4580
|
_cache[shareScope ?? GLOBAL_SCOPE][externalName] = external;
|
|
4050
|
-
|
|
4581
|
+
_uncommitted.add(shareScope ?? GLOBAL_SCOPE);
|
|
4051
4582
|
return this;
|
|
4052
4583
|
},
|
|
4053
4584
|
getScopes: function(o = { includeGlobal: true }) {
|
|
@@ -4057,7 +4588,7 @@ var createSharedExternalsRepository = (config) => {
|
|
|
4057
4588
|
// Batched: one traversal of the graph per init instead of one per overridden remote.
|
|
4058
4589
|
removeFromAllScopes: function(remoteNames) {
|
|
4059
4590
|
if (remoteNames.size === 0) return;
|
|
4060
|
-
Object.
|
|
4591
|
+
Object.entries(_cache).forEach(([scopeName, scope]) => {
|
|
4061
4592
|
const removeExternals = [];
|
|
4062
4593
|
Object.entries(scope).forEach(([name, external]) => {
|
|
4063
4594
|
let removedCopy = false;
|
|
@@ -4073,12 +4604,12 @@ var createSharedExternalsRepository = (config) => {
|
|
|
4073
4604
|
if (keep !== remotes.length) {
|
|
4074
4605
|
remotes.length = keep;
|
|
4075
4606
|
removedCopy = true;
|
|
4076
|
-
|
|
4607
|
+
_uncommitted.add(scopeName);
|
|
4077
4608
|
if (host !== void 0 && remoteNames.has(host)) version.host = false;
|
|
4078
4609
|
}
|
|
4079
4610
|
if (remotes.length === 0) {
|
|
4080
4611
|
external.versions.splice(i, 1);
|
|
4081
|
-
|
|
4612
|
+
_uncommitted.add(scopeName);
|
|
4082
4613
|
}
|
|
4083
4614
|
}
|
|
4084
4615
|
if (removedCopy) {
|
|
@@ -4086,7 +4617,17 @@ var createSharedExternalsRepository = (config) => {
|
|
|
4086
4617
|
if (external.versions.length === 0) removeExternals.push(name);
|
|
4087
4618
|
}
|
|
4088
4619
|
});
|
|
4089
|
-
|
|
4620
|
+
const lostPools = /* @__PURE__ */ new Set();
|
|
4621
|
+
for (const name of removeExternals) {
|
|
4622
|
+
const poolName = scope[name].poolName;
|
|
4623
|
+
if (poolName !== void 0) lostPools.add(poolName);
|
|
4624
|
+
delete scope[name];
|
|
4625
|
+
}
|
|
4626
|
+
if (lostPools.size > 0) {
|
|
4627
|
+
for (const external of Object.values(scope))
|
|
4628
|
+
if (external.poolName !== void 0 && lostPools.has(external.poolName))
|
|
4629
|
+
external.dirty = true;
|
|
4630
|
+
}
|
|
4090
4631
|
});
|
|
4091
4632
|
},
|
|
4092
4633
|
scopeType: function(shareScope) {
|
|
@@ -4104,10 +4645,36 @@ var createSharedExternalsRepository = (config) => {
|
|
|
4104
4645
|
tryGet: function(external, shareScope) {
|
|
4105
4646
|
return Optional.of(_cache[shareScope ?? GLOBAL_SCOPE]?.[external]);
|
|
4106
4647
|
},
|
|
4648
|
+
uncommittedScopes: function() {
|
|
4649
|
+
return [..._uncommitted];
|
|
4650
|
+
},
|
|
4651
|
+
markUndecided: function(shareScope) {
|
|
4652
|
+
if (_undecided.has(shareScope)) return;
|
|
4653
|
+
_undecided.add(shareScope);
|
|
4654
|
+
_undecidedChanged = true;
|
|
4655
|
+
},
|
|
4656
|
+
isUndecided: function(shareScope) {
|
|
4657
|
+
return _undecided.has(shareScope);
|
|
4658
|
+
},
|
|
4659
|
+
markDecided: function(shareScope) {
|
|
4660
|
+
if (_undecided.delete(shareScope)) _undecidedChanged = true;
|
|
4661
|
+
},
|
|
4662
|
+
// Records before marks: should their write throw, the stored marks still send the next init to decide them. A
|
|
4663
|
+
// failed cache-state write after the records loses only this load's marks.
|
|
4107
4664
|
commit: function() {
|
|
4108
|
-
if (
|
|
4109
|
-
|
|
4110
|
-
|
|
4665
|
+
if (_uncommitted.size > 0) {
|
|
4666
|
+
STORAGE.set(_cache);
|
|
4667
|
+
_uncommitted.clear();
|
|
4668
|
+
}
|
|
4669
|
+
if (_undecidedChanged) cacheState.update({ undecidedScopes: [..._undecided] });
|
|
4670
|
+
_undecidedChanged = false;
|
|
4671
|
+
return this;
|
|
4672
|
+
},
|
|
4673
|
+
rollback: function() {
|
|
4674
|
+
_cache = STORAGE.get() ?? { [GLOBAL_SCOPE]: {} };
|
|
4675
|
+
_uncommitted.clear();
|
|
4676
|
+
_undecided = storedUndecided();
|
|
4677
|
+
_undecidedChanged = false;
|
|
4111
4678
|
return this;
|
|
4112
4679
|
}
|
|
4113
4680
|
};
|
|
@@ -4224,7 +4791,7 @@ var createSSEHandler = (config) => {
|
|
|
4224
4791
|
var createChunkRepository = (config) => {
|
|
4225
4792
|
const STORAGE = config.storage(STORAGE_KEYS.sharedChunks, {});
|
|
4226
4793
|
if (config.clearStorage) STORAGE.clear();
|
|
4227
|
-
|
|
4794
|
+
let _cache = STORAGE.get() ?? {};
|
|
4228
4795
|
let _dirty = false;
|
|
4229
4796
|
return {
|
|
4230
4797
|
addOrReplace: function(remoteName, bundleName, chunks) {
|
|
@@ -4249,6 +4816,11 @@ var createChunkRepository = (config) => {
|
|
|
4249
4816
|
STORAGE.set(_cache);
|
|
4250
4817
|
_dirty = false;
|
|
4251
4818
|
return this;
|
|
4819
|
+
},
|
|
4820
|
+
rollback: function() {
|
|
4821
|
+
_cache = STORAGE.get() ?? {};
|
|
4822
|
+
_dirty = false;
|
|
4823
|
+
return this;
|
|
4252
4824
|
}
|
|
4253
4825
|
};
|
|
4254
4826
|
};
|
|
@@ -4471,8 +5043,10 @@ var globalThisStorageEntry = (namespace) => (key, initialValue) => {
|
|
|
4471
5043
|
globalThisStorageEntry.type = "globalThis";
|
|
4472
5044
|
Object.freeze(globalThisStorageEntry);
|
|
4473
5045
|
|
|
5046
|
+
// src/lib/core/4.config/orchestrator-version.ts
|
|
5047
|
+
var ORCHESTRATOR_VERSION = true ? "4.9.0" : "dev";
|
|
5048
|
+
|
|
4474
5049
|
// src/lib/core/4.config/storage/publish-storage-info.ts
|
|
4475
|
-
var VERSION = true ? "4.7.0" : "dev";
|
|
4476
5050
|
var KEYS = Object.freeze(Object.values(STORAGE_KEYS));
|
|
4477
5051
|
var isStorageKey = (key) => KEYS.includes(key);
|
|
4478
5052
|
var createStorageInfo = ({
|
|
@@ -4481,7 +5055,12 @@ var createStorageInfo = ({
|
|
|
4481
5055
|
storage,
|
|
4482
5056
|
exposeGetter
|
|
4483
5057
|
}) => {
|
|
4484
|
-
const info = {
|
|
5058
|
+
const info = {
|
|
5059
|
+
version: ORCHESTRATOR_VERSION,
|
|
5060
|
+
type,
|
|
5061
|
+
namespace,
|
|
5062
|
+
keys: KEYS
|
|
5063
|
+
};
|
|
4485
5064
|
if (!exposeGetter) return Object.freeze(info);
|
|
4486
5065
|
return Object.freeze({
|
|
4487
5066
|
...info,
|
|
@@ -4502,19 +5081,65 @@ var publishStorageInfo = (options) => {
|
|
|
4502
5081
|
};
|
|
4503
5082
|
|
|
4504
5083
|
// src/lib/core/4.config/storage/storage.config.ts
|
|
4505
|
-
var
|
|
5084
|
+
var isOutdatedCache = (storage) => {
|
|
5085
|
+
const cacheState = createCacheState(storage);
|
|
5086
|
+
if (cacheState.read().version === ORCHESTRATOR_VERSION) return false;
|
|
5087
|
+
cacheState.update({ version: ORCHESTRATOR_VERSION, undecidedScopes: [] });
|
|
5088
|
+
return Object.values(STORAGE_KEYS).filter((key) => key !== STORAGE_KEYS.cacheState).some((key) => storage(key, null).get() !== null);
|
|
5089
|
+
};
|
|
5090
|
+
var guardWrites = (storage, log) => {
|
|
5091
|
+
let failed = false;
|
|
5092
|
+
const memory = /* @__PURE__ */ new Map();
|
|
5093
|
+
const write = (key, value, persist) => {
|
|
5094
|
+
if (!failed) {
|
|
5095
|
+
try {
|
|
5096
|
+
persist();
|
|
5097
|
+
return;
|
|
5098
|
+
} catch (error) {
|
|
5099
|
+
failed = true;
|
|
5100
|
+
try {
|
|
5101
|
+
storage(STORAGE_KEYS.cacheState, null).set(null);
|
|
5102
|
+
} catch {
|
|
5103
|
+
}
|
|
5104
|
+
log.warn(
|
|
5105
|
+
5,
|
|
5106
|
+
`Could not save '${key}' to storage; this page runs from memory and the next page starts without a cache.`,
|
|
5107
|
+
error
|
|
5108
|
+
);
|
|
5109
|
+
}
|
|
5110
|
+
}
|
|
5111
|
+
memory.set(key, cloneEntry(key, value));
|
|
5112
|
+
};
|
|
5113
|
+
return (key, initialValue) => {
|
|
5114
|
+
const inner = storage(key, initialValue);
|
|
5115
|
+
const entry = {
|
|
5116
|
+
get: () => memory.has(key) ? cloneEntry(key, memory.get(key)) : inner.get(),
|
|
5117
|
+
set: (value) => {
|
|
5118
|
+
write(key, value, () => void inner.set(value));
|
|
5119
|
+
return entry;
|
|
5120
|
+
},
|
|
5121
|
+
clear: () => {
|
|
5122
|
+
write(key, initialValue, () => void inner.clear());
|
|
5123
|
+
return entry;
|
|
5124
|
+
}
|
|
5125
|
+
};
|
|
5126
|
+
return entry;
|
|
5127
|
+
};
|
|
5128
|
+
};
|
|
5129
|
+
var createStorageConfig = (override, log) => {
|
|
4506
5130
|
const creator = override.storage ?? globalThisStorageEntry;
|
|
4507
5131
|
const namespace = override.storageNamespace ?? "__NATIVE_FEDERATION__";
|
|
4508
|
-
const storage = creator(namespace);
|
|
5132
|
+
const storage = guardWrites(creator(namespace), log);
|
|
4509
5133
|
publishStorageInfo({
|
|
4510
5134
|
type: creator.type ?? "custom",
|
|
4511
5135
|
namespace,
|
|
4512
5136
|
storage,
|
|
4513
5137
|
exposeGetter: override.exposeStorageGetter ?? true
|
|
4514
5138
|
});
|
|
5139
|
+
const outdated = isOutdatedCache(storage);
|
|
4515
5140
|
return {
|
|
4516
5141
|
storage,
|
|
4517
|
-
clearStorage: override.clearStorage ?? false
|
|
5142
|
+
clearStorage: (override.clearStorage ?? false) || outdated
|
|
4518
5143
|
};
|
|
4519
5144
|
};
|
|
4520
5145
|
|
|
@@ -4522,9 +5147,9 @@ var createStorageConfig = (override) => {
|
|
|
4522
5147
|
var defaultProfile = {
|
|
4523
5148
|
latestSharedExternal: false,
|
|
4524
5149
|
skipInvalidExternalVersions: false,
|
|
4525
|
-
scopeUncoveredEntrypoints: false,
|
|
4526
5150
|
overrideCachedRemotes: "init-only",
|
|
4527
|
-
overrideCachedRemotesIfURLMatches: false
|
|
5151
|
+
overrideCachedRemotesIfURLMatches: false,
|
|
5152
|
+
mergeManifests: true
|
|
4528
5153
|
};
|
|
4529
5154
|
|
|
4530
5155
|
// src/lib/core/4.config/mode/mode.config.ts
|
|
@@ -4534,15 +5159,13 @@ var createModeConfig = (override) => {
|
|
|
4534
5159
|
strictExternalCompatibility: override.strict,
|
|
4535
5160
|
strictExternalSameVersionCompatibility: override.strict,
|
|
4536
5161
|
strictExternalVersion: override.strict,
|
|
4537
|
-
strictImportMap: override.strict
|
|
4538
|
-
strictEntryPointCoverage: override.strict
|
|
5162
|
+
strictImportMap: override.strict
|
|
4539
5163
|
} : {
|
|
4540
5164
|
strictRemoteEntry: override.strict?.strictRemoteEntry ?? false,
|
|
4541
5165
|
strictExternalCompatibility: override.strict?.strictExternalCompatibility ?? false,
|
|
4542
5166
|
strictExternalSameVersionCompatibility: override.strict?.strictExternalSameVersionCompatibility ?? false,
|
|
4543
5167
|
strictExternalVersion: override.strict?.strictExternalVersion ?? false,
|
|
4544
|
-
strictImportMap: override.strict?.strictImportMap ?? false
|
|
4545
|
-
strictEntryPointCoverage: override.strict?.strictEntryPointCoverage ?? false
|
|
5168
|
+
strictImportMap: override.strict?.strictImportMap ?? false
|
|
4546
5169
|
};
|
|
4547
5170
|
return {
|
|
4548
5171
|
strict: strictnessConfig,
|
|
@@ -4554,23 +5177,18 @@ var createModeConfig = (override) => {
|
|
|
4554
5177
|
};
|
|
4555
5178
|
|
|
4556
5179
|
// src/lib/core/5.di/config.factory.ts
|
|
4557
|
-
var createConfigHandlers = (overrides) =>
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
5180
|
+
var createConfigHandlers = (overrides) => {
|
|
5181
|
+
const logConfig = createLogConfig(overrides);
|
|
5182
|
+
return {
|
|
5183
|
+
...createImportMapConfig(overrides),
|
|
5184
|
+
...createHostConfig(overrides),
|
|
5185
|
+
...logConfig,
|
|
5186
|
+
...createStorageConfig(overrides, logConfig.log),
|
|
5187
|
+
...createModeConfig(overrides)
|
|
5188
|
+
};
|
|
5189
|
+
};
|
|
4564
5190
|
|
|
4565
5191
|
// src/lib/core/5.di/federation-result.factory.ts
|
|
4566
|
-
var createStateDump = (config, adapters) => (msg) => config.log.debug(0, msg, {
|
|
4567
|
-
remotes: { ...adapters.remoteInfoRepo.getAll() },
|
|
4568
|
-
"shared-externals": adapters.sharedExternalsRepo.getScopes({ includeGlobal: true }).reduce(
|
|
4569
|
-
(acc, scope) => ({ ...acc, [scope]: adapters.sharedExternalsRepo.getFromScope(scope) }),
|
|
4570
|
-
{}
|
|
4571
|
-
),
|
|
4572
|
-
"scoped-externals": adapters.scopedExternalsRepo.getAll()
|
|
4573
|
-
});
|
|
4574
5192
|
var createFederationResult = ({
|
|
4575
5193
|
config,
|
|
4576
5194
|
adapters,
|
|
@@ -4578,11 +5196,8 @@ var createFederationResult = ({
|
|
|
4578
5196
|
initRemoteEntryFlow,
|
|
4579
5197
|
afterInitRemoteEntry
|
|
4580
5198
|
}) => {
|
|
4581
|
-
const stateDump = createStateDump(config, adapters);
|
|
4582
5199
|
const initRemoteEntry = async (remoteEntryUrl, remote) => {
|
|
4583
|
-
const remoteName = typeof remote === "string" ? remote : remote?.name;
|
|
4584
5200
|
return initRemoteEntryFlow(remoteEntryUrl, remote).catch((e) => {
|
|
4585
|
-
stateDump(`[dynamic-init][${remoteName ?? remoteEntryUrl}] STATE DUMP`);
|
|
4586
5201
|
if (config.strict.strictRemoteEntry) return Promise.reject(e);
|
|
4587
5202
|
else console.warn("Failed to initialize remote entry, continuing anyway.");
|
|
4588
5203
|
return Promise.resolve();
|