@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
package/fesm2022/node.mjs
CHANGED
|
@@ -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) {
|
|
@@ -1288,19 +1288,30 @@ var createBrowser = (config) => {
|
|
|
1288
1288
|
// src/lib/core/3.adapters/checks/version.check.ts
|
|
1289
1289
|
var import_valid = __toESM(require_valid());
|
|
1290
1290
|
var import_satisfies = __toESM(require_satisfies());
|
|
1291
|
-
var
|
|
1291
|
+
var import_semver = __toESM(require_semver());
|
|
1292
1292
|
var import_min_version = __toESM(require_min_version());
|
|
1293
1293
|
var import_valid2 = __toESM(require_valid2());
|
|
1294
1294
|
var createVersionCheck = () => {
|
|
1295
|
+
const parsed = /* @__PURE__ */ new Map();
|
|
1296
|
+
const parse = (v) => {
|
|
1297
|
+
let hit = parsed.get(v);
|
|
1298
|
+
if (!hit) parsed.set(v, hit = new import_semver.default(v, true));
|
|
1299
|
+
return hit;
|
|
1300
|
+
};
|
|
1301
|
+
const satisfied = /* @__PURE__ */ new Map();
|
|
1295
1302
|
return {
|
|
1296
1303
|
isValidSemver: function(version) {
|
|
1297
1304
|
return (0, import_valid.default)(version) !== null;
|
|
1298
1305
|
},
|
|
1299
1306
|
isCompatible: function(version, range) {
|
|
1300
|
-
|
|
1307
|
+
let byVersion = satisfied.get(range);
|
|
1308
|
+
if (!byVersion) satisfied.set(range, byVersion = /* @__PURE__ */ new Map());
|
|
1309
|
+
let hit = byVersion.get(version);
|
|
1310
|
+
if (hit === void 0) byVersion.set(version, hit = (0, import_satisfies.default)(version, range));
|
|
1311
|
+
return hit;
|
|
1301
1312
|
},
|
|
1302
1313
|
compare: function(versionA, versionB) {
|
|
1303
|
-
return (
|
|
1314
|
+
return parse(versionA).compare(parse(versionB));
|
|
1304
1315
|
},
|
|
1305
1316
|
smallestVersion: function(versionRange) {
|
|
1306
1317
|
if (!(0, import_valid2.default)(versionRange)) return "0.0.0";
|
|
@@ -1313,7 +1324,7 @@ var createVersionCheck = () => {
|
|
|
1313
1324
|
// src/lib/core/native-federation.error.ts
|
|
1314
1325
|
var NFError = class extends Error {
|
|
1315
1326
|
constructor(message, cause) {
|
|
1316
|
-
super(message, cause);
|
|
1327
|
+
super(message, cause ? { cause } : void 0);
|
|
1317
1328
|
this.name = "NFError";
|
|
1318
1329
|
}
|
|
1319
1330
|
};
|
|
@@ -1395,14 +1406,94 @@ var createFsManifestProvider = () => {
|
|
|
1395
1406
|
};
|
|
1396
1407
|
};
|
|
1397
1408
|
|
|
1409
|
+
// src/lib/core/1.domain/remote-entry/mark-dense.ts
|
|
1410
|
+
function markDense(shared) {
|
|
1411
|
+
return shared.map((entry) => "entries" in entry ? { ...entry, dense: true } : entry);
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
// node_modules/.pnpm/@softarc+native-federation@4.9.0/node_modules/@softarc/native-federation/dist/lib/domain/core/chunk.js
|
|
1415
|
+
var CHUNK_PREFIX = "@nf-internal";
|
|
1416
|
+
var SCRIPT_EXTENSION = /\.(m|c)?js$/;
|
|
1417
|
+
function toChunkImport(fileName) {
|
|
1418
|
+
if (fileName.startsWith("./")) {
|
|
1419
|
+
fileName = fileName.slice(2);
|
|
1420
|
+
}
|
|
1421
|
+
const packageName = fileName.replace(SCRIPT_EXTENSION, "");
|
|
1422
|
+
return CHUNK_PREFIX + "/" + packageName;
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
// node_modules/.pnpm/@softarc+native-federation@4.9.0/node_modules/@softarc/native-federation/dist/lib/utils/normalize.js
|
|
1426
|
+
function inferPackageFromSecondary(secondary) {
|
|
1427
|
+
const parts = secondary.split("/");
|
|
1428
|
+
if (secondary.startsWith("@") && parts.length >= 2) {
|
|
1429
|
+
return parts[0] + "/" + parts[1];
|
|
1430
|
+
}
|
|
1431
|
+
return parts[0];
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
// node_modules/.pnpm/@softarc+native-federation@4.9.0/node_modules/@softarc/native-federation/dist/lib/core/output/densify-externals.js
|
|
1435
|
+
function isDense(entry) {
|
|
1436
|
+
return "entries" in entry;
|
|
1437
|
+
}
|
|
1438
|
+
function isFlatChunk(entry) {
|
|
1439
|
+
return entry.packageName.startsWith(CHUNK_PREFIX);
|
|
1440
|
+
}
|
|
1441
|
+
function densifyExternals(shared, declaredPackages) {
|
|
1442
|
+
const result = [];
|
|
1443
|
+
const groupIndex = /* @__PURE__ */ new Map();
|
|
1444
|
+
for (const entry of shared) {
|
|
1445
|
+
if (isDense(entry)) {
|
|
1446
|
+
result.push(entry);
|
|
1447
|
+
continue;
|
|
1448
|
+
}
|
|
1449
|
+
if (isFlatChunk(entry)) {
|
|
1450
|
+
const { outFileName: outFileName2, ...rest } = entry;
|
|
1451
|
+
result.push({ ...rest, entries: { [entry.packageName]: outFileName2 } });
|
|
1452
|
+
continue;
|
|
1453
|
+
}
|
|
1454
|
+
const { outFileName, packageName, dev, ...meta } = entry;
|
|
1455
|
+
const parent = declaredPackages.get(packageName) ?? inferPackageFromSecondary(packageName);
|
|
1456
|
+
const sig = JSON.stringify(meta, Object.keys(meta).sort());
|
|
1457
|
+
const key = parent + " " + sig;
|
|
1458
|
+
const existing = groupIndex.get(key);
|
|
1459
|
+
if (existing === void 0) {
|
|
1460
|
+
const dense = {
|
|
1461
|
+
...meta,
|
|
1462
|
+
packageName: parent,
|
|
1463
|
+
entries: { [packageName]: outFileName }
|
|
1464
|
+
};
|
|
1465
|
+
if (dev !== void 0) dense.dev = dev;
|
|
1466
|
+
groupIndex.set(key, result.length);
|
|
1467
|
+
result.push(dense);
|
|
1468
|
+
} else {
|
|
1469
|
+
result[existing].entries[packageName] = outFileName;
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
return result;
|
|
1473
|
+
}
|
|
1474
|
+
function toDenseSharedInfoFormat(shared) {
|
|
1475
|
+
return shared.map((external) => {
|
|
1476
|
+
if ("entries" in external) return external;
|
|
1477
|
+
const { outFileName, ...baseSharedInfoProps } = external;
|
|
1478
|
+
return {
|
|
1479
|
+
...baseSharedInfoProps,
|
|
1480
|
+
entries: { [external.packageName]: outFileName }
|
|
1481
|
+
};
|
|
1482
|
+
});
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
// src/lib/core/3.adapters/remote-entry/normalize-remote-entry.ts
|
|
1486
|
+
var normalizeRemoteEntry = (raw, remoteEntryUrl, config) => {
|
|
1487
|
+
const marked = markDense(raw.shared ?? []);
|
|
1488
|
+
const shared = config.feature.convertFlatSharedInfo ? densifyExternals(marked, /* @__PURE__ */ new Map()) : toDenseSharedInfoFormat(marked);
|
|
1489
|
+
const remoteEntry = { ...raw, shared };
|
|
1490
|
+
if (!remoteEntry.exposes) remoteEntry.exposes = [];
|
|
1491
|
+
if (!remoteEntry.url) remoteEntry.url = remoteEntryUrl;
|
|
1492
|
+
return remoteEntry;
|
|
1493
|
+
};
|
|
1494
|
+
|
|
1398
1495
|
// src/lib/node/adapters/fs-remote-entry-provider.ts
|
|
1399
|
-
var createFsRemoteEntryProvider = () => {
|
|
1400
|
-
const fillEmptyFields = (remoteEntryUrl) => (remoteEntry) => {
|
|
1401
|
-
if (!remoteEntry.exposes) remoteEntry.exposes = [];
|
|
1402
|
-
if (!remoteEntry.shared) remoteEntry.shared = [];
|
|
1403
|
-
if (!remoteEntry.url) remoteEntry.url = remoteEntryUrl;
|
|
1404
|
-
return remoteEntry;
|
|
1405
|
-
};
|
|
1496
|
+
var createFsRemoteEntryProvider = (config) => {
|
|
1406
1497
|
const formatError = (remoteEntryUrl) => (err) => {
|
|
1407
1498
|
if (err instanceof NFError) throw err;
|
|
1408
1499
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -1413,8 +1504,8 @@ var createFsRemoteEntryProvider = () => {
|
|
|
1413
1504
|
try {
|
|
1414
1505
|
const bytes = await readSourceBytes(remoteEntryUrl);
|
|
1415
1506
|
if (opts.integrity) await verifyIntegrity(bytes, opts.integrity);
|
|
1416
|
-
const
|
|
1417
|
-
return
|
|
1507
|
+
const raw = JSON.parse(new TextDecoder().decode(bytes));
|
|
1508
|
+
return normalizeRemoteEntry(raw, remoteEntryUrl, config);
|
|
1418
1509
|
} catch (err) {
|
|
1419
1510
|
return formatError(remoteEntryUrl)(err);
|
|
1420
1511
|
}
|
|
@@ -1435,7 +1526,8 @@ var STORAGE_KEYS = {
|
|
|
1435
1526
|
remotes: "remotes",
|
|
1436
1527
|
sharedExternals: "shared-externals",
|
|
1437
1528
|
scopedExternals: "scoped-externals",
|
|
1438
|
-
sharedChunks: "shared-chunks"
|
|
1529
|
+
sharedChunks: "shared-chunks",
|
|
1530
|
+
cacheState: "cache-state"
|
|
1439
1531
|
};
|
|
1440
1532
|
|
|
1441
1533
|
// src/lib/utils/path.ts
|
|
@@ -1497,7 +1589,7 @@ var Optional = class _Optional {
|
|
|
1497
1589
|
var createRemoteInfoRepository = (config) => {
|
|
1498
1590
|
const STORAGE = config.storage(STORAGE_KEYS.remotes, {});
|
|
1499
1591
|
if (config.clearStorage) STORAGE.clear();
|
|
1500
|
-
|
|
1592
|
+
let _cache = STORAGE.get() ?? {};
|
|
1501
1593
|
let _dirty = false;
|
|
1502
1594
|
return {
|
|
1503
1595
|
contains: function(remoteName) {
|
|
@@ -1531,6 +1623,11 @@ var createRemoteInfoRepository = (config) => {
|
|
|
1531
1623
|
STORAGE.set(_cache);
|
|
1532
1624
|
_dirty = false;
|
|
1533
1625
|
return this;
|
|
1626
|
+
},
|
|
1627
|
+
rollback: function() {
|
|
1628
|
+
_cache = STORAGE.get() ?? {};
|
|
1629
|
+
_dirty = false;
|
|
1630
|
+
return this;
|
|
1534
1631
|
}
|
|
1535
1632
|
};
|
|
1536
1633
|
};
|
|
@@ -1539,7 +1636,7 @@ var createRemoteInfoRepository = (config) => {
|
|
|
1539
1636
|
var createScopedExternalsRepository = (config) => {
|
|
1540
1637
|
const STORAGE = config.storage(STORAGE_KEYS.scopedExternals, {});
|
|
1541
1638
|
if (config.clearStorage) STORAGE.clear();
|
|
1542
|
-
|
|
1639
|
+
let _cache = STORAGE.get() ?? {};
|
|
1543
1640
|
let _dirty = false;
|
|
1544
1641
|
return {
|
|
1545
1642
|
addExternal: function(remoteName, external, version) {
|
|
@@ -1566,6 +1663,11 @@ var createScopedExternalsRepository = (config) => {
|
|
|
1566
1663
|
STORAGE.set(_cache);
|
|
1567
1664
|
_dirty = false;
|
|
1568
1665
|
return this;
|
|
1666
|
+
},
|
|
1667
|
+
rollback: function() {
|
|
1668
|
+
_cache = STORAGE.get() ?? {};
|
|
1669
|
+
_dirty = false;
|
|
1670
|
+
return this;
|
|
1569
1671
|
}
|
|
1570
1672
|
};
|
|
1571
1673
|
};
|
|
@@ -1574,39 +1676,48 @@ var createScopedExternalsRepository = (config) => {
|
|
|
1574
1676
|
var GLOBAL_SCOPE = "__GLOBAL__";
|
|
1575
1677
|
var STRICT_SCOPE = "strict";
|
|
1576
1678
|
|
|
1679
|
+
// src/lib/core/3.adapters/storage/cache-state.ts
|
|
1680
|
+
var createCacheState = (storage) => {
|
|
1681
|
+
const entry = storage(STORAGE_KEYS.cacheState, null);
|
|
1682
|
+
const read = () => {
|
|
1683
|
+
const stored = entry.get();
|
|
1684
|
+
if (typeof stored !== "object" || stored === null) return {};
|
|
1685
|
+
const { version, undecidedScopes } = stored;
|
|
1686
|
+
return {
|
|
1687
|
+
...typeof version === "string" ? { version } : {},
|
|
1688
|
+
...Array.isArray(undecidedScopes) ? { undecidedScopes: undecidedScopes.filter((s) => typeof s === "string") } : {}
|
|
1689
|
+
};
|
|
1690
|
+
};
|
|
1691
|
+
return {
|
|
1692
|
+
read,
|
|
1693
|
+
update: (fields) => void entry.set({ ...read(), ...fields })
|
|
1694
|
+
};
|
|
1695
|
+
};
|
|
1696
|
+
|
|
1577
1697
|
// src/lib/core/3.adapters/storage/shared-externals.repository.ts
|
|
1578
1698
|
var createSharedExternalsRepository = (config) => {
|
|
1579
1699
|
const STORAGE = config.storage(
|
|
1580
1700
|
STORAGE_KEYS.sharedExternals,
|
|
1581
1701
|
{ [GLOBAL_SCOPE]: {} }
|
|
1582
1702
|
);
|
|
1583
|
-
|
|
1584
|
-
const
|
|
1585
|
-
|
|
1703
|
+
const cacheState = createCacheState(config.storage);
|
|
1704
|
+
const storedUndecided = () => new Set(cacheState.read().undecidedScopes);
|
|
1705
|
+
if (config.clearStorage) {
|
|
1706
|
+
STORAGE.clear();
|
|
1707
|
+
cacheState.update({ undecidedScopes: [] });
|
|
1708
|
+
}
|
|
1709
|
+
let _cache = STORAGE.get() ?? { [GLOBAL_SCOPE]: {} };
|
|
1710
|
+
const _uncommitted = /* @__PURE__ */ new Set();
|
|
1711
|
+
let _undecided = storedUndecided();
|
|
1712
|
+
let _undecidedChanged = false;
|
|
1586
1713
|
return {
|
|
1587
|
-
// Read from the cache rather than remembered from this init's entries: a warm init may not refetch
|
|
1588
|
-
// the tagged remote at all, and pooling has to coordinate its pool anyway. Exits on the first hit.
|
|
1589
|
-
// Per share scope, because a pool never spans one: a tag in another scope is no reason to pool here.
|
|
1590
|
-
// Stored pool results count too, since a scope whose last tag left still has pool state to clear.
|
|
1591
|
-
hasPoolState: function(shareScope) {
|
|
1592
|
-
const scope = _cache[shareScope ?? GLOBAL_SCOPE];
|
|
1593
|
-
if (!scope) return false;
|
|
1594
|
-
for (const external of Object.values(scope)) {
|
|
1595
|
-
if (external.poolName !== void 0) return true;
|
|
1596
|
-
for (const version of external.versions)
|
|
1597
|
-
for (const remote of version.remotes)
|
|
1598
|
-
if (remote.pool?.trim() || remote.servedBy !== void 0 || remote.poolCause !== void 0)
|
|
1599
|
-
return true;
|
|
1600
|
-
}
|
|
1601
|
-
return false;
|
|
1602
|
-
},
|
|
1603
1714
|
getFromScope: function(shareScope) {
|
|
1604
1715
|
return { ..._cache[shareScope ?? GLOBAL_SCOPE] };
|
|
1605
1716
|
},
|
|
1606
1717
|
addOrUpdate: function(externalName, external, shareScope) {
|
|
1607
1718
|
if (!_cache[shareScope ?? GLOBAL_SCOPE]) _cache[shareScope ?? GLOBAL_SCOPE] = {};
|
|
1608
1719
|
_cache[shareScope ?? GLOBAL_SCOPE][externalName] = external;
|
|
1609
|
-
|
|
1720
|
+
_uncommitted.add(shareScope ?? GLOBAL_SCOPE);
|
|
1610
1721
|
return this;
|
|
1611
1722
|
},
|
|
1612
1723
|
getScopes: function(o = { includeGlobal: true }) {
|
|
@@ -1616,7 +1727,7 @@ var createSharedExternalsRepository = (config) => {
|
|
|
1616
1727
|
// Batched: one traversal of the graph per init instead of one per overridden remote.
|
|
1617
1728
|
removeFromAllScopes: function(remoteNames) {
|
|
1618
1729
|
if (remoteNames.size === 0) return;
|
|
1619
|
-
Object.
|
|
1730
|
+
Object.entries(_cache).forEach(([scopeName, scope]) => {
|
|
1620
1731
|
const removeExternals = [];
|
|
1621
1732
|
Object.entries(scope).forEach(([name, external]) => {
|
|
1622
1733
|
let removedCopy = false;
|
|
@@ -1632,12 +1743,12 @@ var createSharedExternalsRepository = (config) => {
|
|
|
1632
1743
|
if (keep !== remotes.length) {
|
|
1633
1744
|
remotes.length = keep;
|
|
1634
1745
|
removedCopy = true;
|
|
1635
|
-
|
|
1746
|
+
_uncommitted.add(scopeName);
|
|
1636
1747
|
if (host !== void 0 && remoteNames.has(host)) version.host = false;
|
|
1637
1748
|
}
|
|
1638
1749
|
if (remotes.length === 0) {
|
|
1639
1750
|
external.versions.splice(i, 1);
|
|
1640
|
-
|
|
1751
|
+
_uncommitted.add(scopeName);
|
|
1641
1752
|
}
|
|
1642
1753
|
}
|
|
1643
1754
|
if (removedCopy) {
|
|
@@ -1645,7 +1756,17 @@ var createSharedExternalsRepository = (config) => {
|
|
|
1645
1756
|
if (external.versions.length === 0) removeExternals.push(name);
|
|
1646
1757
|
}
|
|
1647
1758
|
});
|
|
1648
|
-
|
|
1759
|
+
const lostPools = /* @__PURE__ */ new Set();
|
|
1760
|
+
for (const name of removeExternals) {
|
|
1761
|
+
const poolName = scope[name].poolName;
|
|
1762
|
+
if (poolName !== void 0) lostPools.add(poolName);
|
|
1763
|
+
delete scope[name];
|
|
1764
|
+
}
|
|
1765
|
+
if (lostPools.size > 0) {
|
|
1766
|
+
for (const external of Object.values(scope))
|
|
1767
|
+
if (external.poolName !== void 0 && lostPools.has(external.poolName))
|
|
1768
|
+
external.dirty = true;
|
|
1769
|
+
}
|
|
1649
1770
|
});
|
|
1650
1771
|
},
|
|
1651
1772
|
scopeType: function(shareScope) {
|
|
@@ -1663,10 +1784,36 @@ var createSharedExternalsRepository = (config) => {
|
|
|
1663
1784
|
tryGet: function(external, shareScope) {
|
|
1664
1785
|
return Optional.of(_cache[shareScope ?? GLOBAL_SCOPE]?.[external]);
|
|
1665
1786
|
},
|
|
1787
|
+
uncommittedScopes: function() {
|
|
1788
|
+
return [..._uncommitted];
|
|
1789
|
+
},
|
|
1790
|
+
markUndecided: function(shareScope) {
|
|
1791
|
+
if (_undecided.has(shareScope)) return;
|
|
1792
|
+
_undecided.add(shareScope);
|
|
1793
|
+
_undecidedChanged = true;
|
|
1794
|
+
},
|
|
1795
|
+
isUndecided: function(shareScope) {
|
|
1796
|
+
return _undecided.has(shareScope);
|
|
1797
|
+
},
|
|
1798
|
+
markDecided: function(shareScope) {
|
|
1799
|
+
if (_undecided.delete(shareScope)) _undecidedChanged = true;
|
|
1800
|
+
},
|
|
1801
|
+
// Records before marks: should their write throw, the stored marks still send the next init to decide them. A
|
|
1802
|
+
// failed cache-state write after the records loses only this load's marks.
|
|
1666
1803
|
commit: function() {
|
|
1667
|
-
if (
|
|
1668
|
-
|
|
1669
|
-
|
|
1804
|
+
if (_uncommitted.size > 0) {
|
|
1805
|
+
STORAGE.set(_cache);
|
|
1806
|
+
_uncommitted.clear();
|
|
1807
|
+
}
|
|
1808
|
+
if (_undecidedChanged) cacheState.update({ undecidedScopes: [..._undecided] });
|
|
1809
|
+
_undecidedChanged = false;
|
|
1810
|
+
return this;
|
|
1811
|
+
},
|
|
1812
|
+
rollback: function() {
|
|
1813
|
+
_cache = STORAGE.get() ?? { [GLOBAL_SCOPE]: {} };
|
|
1814
|
+
_uncommitted.clear();
|
|
1815
|
+
_undecided = storedUndecided();
|
|
1816
|
+
_undecidedChanged = false;
|
|
1670
1817
|
return this;
|
|
1671
1818
|
}
|
|
1672
1819
|
};
|
|
@@ -1676,7 +1823,7 @@ var createSharedExternalsRepository = (config) => {
|
|
|
1676
1823
|
var createChunkRepository = (config) => {
|
|
1677
1824
|
const STORAGE = config.storage(STORAGE_KEYS.sharedChunks, {});
|
|
1678
1825
|
if (config.clearStorage) STORAGE.clear();
|
|
1679
|
-
|
|
1826
|
+
let _cache = STORAGE.get() ?? {};
|
|
1680
1827
|
let _dirty = false;
|
|
1681
1828
|
return {
|
|
1682
1829
|
addOrReplace: function(remoteName, bundleName, chunks) {
|
|
@@ -1701,6 +1848,11 @@ var createChunkRepository = (config) => {
|
|
|
1701
1848
|
STORAGE.set(_cache);
|
|
1702
1849
|
_dirty = false;
|
|
1703
1850
|
return this;
|
|
1851
|
+
},
|
|
1852
|
+
rollback: function() {
|
|
1853
|
+
_cache = STORAGE.get() ?? {};
|
|
1854
|
+
_dirty = false;
|
|
1855
|
+
return this;
|
|
1704
1856
|
}
|
|
1705
1857
|
};
|
|
1706
1858
|
};
|
|
@@ -1907,8 +2059,10 @@ var globalThisStorageEntry = (namespace) => (key, initialValue) => {
|
|
|
1907
2059
|
globalThisStorageEntry.type = "globalThis";
|
|
1908
2060
|
Object.freeze(globalThisStorageEntry);
|
|
1909
2061
|
|
|
2062
|
+
// src/lib/core/4.config/orchestrator-version.ts
|
|
2063
|
+
var ORCHESTRATOR_VERSION = true ? "4.9.0" : "dev";
|
|
2064
|
+
|
|
1910
2065
|
// src/lib/core/4.config/storage/publish-storage-info.ts
|
|
1911
|
-
var VERSION = true ? "4.7.0" : "dev";
|
|
1912
2066
|
var KEYS = Object.freeze(Object.values(STORAGE_KEYS));
|
|
1913
2067
|
var isStorageKey = (key) => KEYS.includes(key);
|
|
1914
2068
|
var createStorageInfo = ({
|
|
@@ -1917,7 +2071,12 @@ var createStorageInfo = ({
|
|
|
1917
2071
|
storage,
|
|
1918
2072
|
exposeGetter
|
|
1919
2073
|
}) => {
|
|
1920
|
-
const info = {
|
|
2074
|
+
const info = {
|
|
2075
|
+
version: ORCHESTRATOR_VERSION,
|
|
2076
|
+
type,
|
|
2077
|
+
namespace,
|
|
2078
|
+
keys: KEYS
|
|
2079
|
+
};
|
|
1921
2080
|
if (!exposeGetter) return Object.freeze(info);
|
|
1922
2081
|
return Object.freeze({
|
|
1923
2082
|
...info,
|
|
@@ -1938,19 +2097,65 @@ var publishStorageInfo = (options) => {
|
|
|
1938
2097
|
};
|
|
1939
2098
|
|
|
1940
2099
|
// src/lib/core/4.config/storage/storage.config.ts
|
|
1941
|
-
var
|
|
2100
|
+
var isOutdatedCache = (storage) => {
|
|
2101
|
+
const cacheState = createCacheState(storage);
|
|
2102
|
+
if (cacheState.read().version === ORCHESTRATOR_VERSION) return false;
|
|
2103
|
+
cacheState.update({ version: ORCHESTRATOR_VERSION, undecidedScopes: [] });
|
|
2104
|
+
return Object.values(STORAGE_KEYS).filter((key) => key !== STORAGE_KEYS.cacheState).some((key) => storage(key, null).get() !== null);
|
|
2105
|
+
};
|
|
2106
|
+
var guardWrites = (storage, log) => {
|
|
2107
|
+
let failed = false;
|
|
2108
|
+
const memory = /* @__PURE__ */ new Map();
|
|
2109
|
+
const write = (key, value, persist) => {
|
|
2110
|
+
if (!failed) {
|
|
2111
|
+
try {
|
|
2112
|
+
persist();
|
|
2113
|
+
return;
|
|
2114
|
+
} catch (error) {
|
|
2115
|
+
failed = true;
|
|
2116
|
+
try {
|
|
2117
|
+
storage(STORAGE_KEYS.cacheState, null).set(null);
|
|
2118
|
+
} catch {
|
|
2119
|
+
}
|
|
2120
|
+
log.warn(
|
|
2121
|
+
5,
|
|
2122
|
+
`Could not save '${key}' to storage; this page runs from memory and the next page starts without a cache.`,
|
|
2123
|
+
error
|
|
2124
|
+
);
|
|
2125
|
+
}
|
|
2126
|
+
}
|
|
2127
|
+
memory.set(key, cloneEntry(key, value));
|
|
2128
|
+
};
|
|
2129
|
+
return (key, initialValue) => {
|
|
2130
|
+
const inner = storage(key, initialValue);
|
|
2131
|
+
const entry = {
|
|
2132
|
+
get: () => memory.has(key) ? cloneEntry(key, memory.get(key)) : inner.get(),
|
|
2133
|
+
set: (value) => {
|
|
2134
|
+
write(key, value, () => void inner.set(value));
|
|
2135
|
+
return entry;
|
|
2136
|
+
},
|
|
2137
|
+
clear: () => {
|
|
2138
|
+
write(key, initialValue, () => void inner.clear());
|
|
2139
|
+
return entry;
|
|
2140
|
+
}
|
|
2141
|
+
};
|
|
2142
|
+
return entry;
|
|
2143
|
+
};
|
|
2144
|
+
};
|
|
2145
|
+
var createStorageConfig = (override, log) => {
|
|
1942
2146
|
const creator = override.storage ?? globalThisStorageEntry;
|
|
1943
2147
|
const namespace = override.storageNamespace ?? "__NATIVE_FEDERATION__";
|
|
1944
|
-
const storage = creator(namespace);
|
|
2148
|
+
const storage = guardWrites(creator(namespace), log);
|
|
1945
2149
|
publishStorageInfo({
|
|
1946
2150
|
type: creator.type ?? "custom",
|
|
1947
2151
|
namespace,
|
|
1948
2152
|
storage,
|
|
1949
2153
|
exposeGetter: override.exposeStorageGetter ?? true
|
|
1950
2154
|
});
|
|
2155
|
+
const outdated = isOutdatedCache(storage);
|
|
1951
2156
|
return {
|
|
1952
2157
|
storage,
|
|
1953
|
-
clearStorage: override.clearStorage ?? false
|
|
2158
|
+
clearStorage: (override.clearStorage ?? false) || outdated
|
|
1954
2159
|
};
|
|
1955
2160
|
};
|
|
1956
2161
|
|
|
@@ -1958,9 +2163,9 @@ var createStorageConfig = (override) => {
|
|
|
1958
2163
|
var defaultProfile = {
|
|
1959
2164
|
latestSharedExternal: false,
|
|
1960
2165
|
skipInvalidExternalVersions: false,
|
|
1961
|
-
scopeUncoveredEntrypoints: false,
|
|
1962
2166
|
overrideCachedRemotes: "init-only",
|
|
1963
|
-
overrideCachedRemotesIfURLMatches: false
|
|
2167
|
+
overrideCachedRemotesIfURLMatches: false,
|
|
2168
|
+
mergeManifests: true
|
|
1964
2169
|
};
|
|
1965
2170
|
|
|
1966
2171
|
// src/lib/core/4.config/mode/mode.config.ts
|
|
@@ -1970,15 +2175,13 @@ var createModeConfig = (override) => {
|
|
|
1970
2175
|
strictExternalCompatibility: override.strict,
|
|
1971
2176
|
strictExternalSameVersionCompatibility: override.strict,
|
|
1972
2177
|
strictExternalVersion: override.strict,
|
|
1973
|
-
strictImportMap: override.strict
|
|
1974
|
-
strictEntryPointCoverage: override.strict
|
|
2178
|
+
strictImportMap: override.strict
|
|
1975
2179
|
} : {
|
|
1976
2180
|
strictRemoteEntry: override.strict?.strictRemoteEntry ?? false,
|
|
1977
2181
|
strictExternalCompatibility: override.strict?.strictExternalCompatibility ?? false,
|
|
1978
2182
|
strictExternalSameVersionCompatibility: override.strict?.strictExternalSameVersionCompatibility ?? false,
|
|
1979
2183
|
strictExternalVersion: override.strict?.strictExternalVersion ?? false,
|
|
1980
|
-
strictImportMap: override.strict?.strictImportMap ?? false
|
|
1981
|
-
strictEntryPointCoverage: override.strict?.strictEntryPointCoverage ?? false
|
|
2184
|
+
strictImportMap: override.strict?.strictImportMap ?? false
|
|
1982
2185
|
};
|
|
1983
2186
|
return {
|
|
1984
2187
|
strict: strictnessConfig,
|
|
@@ -1990,13 +2193,16 @@ var createModeConfig = (override) => {
|
|
|
1990
2193
|
};
|
|
1991
2194
|
|
|
1992
2195
|
// src/lib/core/5.di/config.factory.ts
|
|
1993
|
-
var createConfigHandlers = (overrides) =>
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2196
|
+
var createConfigHandlers = (overrides) => {
|
|
2197
|
+
const logConfig = createLogConfig(overrides);
|
|
2198
|
+
return {
|
|
2199
|
+
...createImportMapConfig(overrides),
|
|
2200
|
+
...createHostConfig(overrides),
|
|
2201
|
+
...logConfig,
|
|
2202
|
+
...createStorageConfig(overrides, logConfig.log),
|
|
2203
|
+
...createModeConfig(overrides)
|
|
2204
|
+
};
|
|
2205
|
+
};
|
|
2000
2206
|
|
|
2001
2207
|
// src/lib/core/2.app/flows/init.flow.ts
|
|
2002
2208
|
var createInitFlow = ({
|
|
@@ -2004,7 +2210,7 @@ var createInitFlow = ({
|
|
|
2004
2210
|
adapters,
|
|
2005
2211
|
config
|
|
2006
2212
|
}) => {
|
|
2007
|
-
return (remotesOrManifestUrl) => flow.getRemoteEntries(remotesOrManifestUrl).then(flow.processRemoteEntries).then(flow.
|
|
2213
|
+
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) => ({
|
|
2008
2214
|
config,
|
|
2009
2215
|
adapters,
|
|
2010
2216
|
loadRemoteModule
|
|
@@ -2015,12 +2221,136 @@ var createInitFlow = ({
|
|
|
2015
2221
|
var createInitRemoteEntryFlow = ({
|
|
2016
2222
|
flow
|
|
2017
2223
|
}) => {
|
|
2018
|
-
const processDynamicRemoteEntry = (remoteEntry) => flow.updateCache(remoteEntry).then(flow.poolDynamicExternals).then(flow.convertToImportMap).then(flow.commitChanges);
|
|
2019
|
-
return (remoteEntryUrl, remote) => flow.getRemoteEntry(remoteEntryUrl, remote).then((entry) => entry.map(processDynamicRemoteEntry).orElse(Promise.resolve())).then(() => void 0)
|
|
2224
|
+
const processDynamicRemoteEntry = (remoteEntry) => flow.updateCache(remoteEntry).then(flow.poolDynamicExternals).then(flow.convertToImportMap).then((importMap) => flow.commitChanges(importMap, { markUndecided: true }));
|
|
2225
|
+
return (remoteEntryUrl, remote) => flow.getRemoteEntry(remoteEntryUrl, remote).then((entry) => entry.map(processDynamicRemoteEntry).orElse(Promise.resolve())).then(() => void 0).catch((error) => {
|
|
2226
|
+
const remoteName = typeof remote === "string" ? remote : remote?.name;
|
|
2227
|
+
return flow.rollbackChanges(`[dynamic-init][${remoteName ?? remoteEntryUrl}]`).then(() => Promise.reject(error));
|
|
2228
|
+
});
|
|
2020
2229
|
};
|
|
2021
2230
|
|
|
2231
|
+
// src/lib/core/2.app/steps/store-remote-entry.ts
|
|
2232
|
+
function createRemoveCachedRemoteEntries(ports) {
|
|
2233
|
+
return (remoteNames) => {
|
|
2234
|
+
if (remoteNames.size === 0) return;
|
|
2235
|
+
for (const remoteName of remoteNames) {
|
|
2236
|
+
ports.remoteInfoRepo.remove(remoteName);
|
|
2237
|
+
ports.scopedExternalsRepo.remove(remoteName);
|
|
2238
|
+
ports.sharedChunksRepo.remove(remoteName);
|
|
2239
|
+
}
|
|
2240
|
+
ports.sharedExternalsRepo.removeFromAllScopes(remoteNames);
|
|
2241
|
+
};
|
|
2242
|
+
}
|
|
2243
|
+
function createStoreRemoteEntry(config, ports, logStep) {
|
|
2244
|
+
return (remoteEntry, onSharedExternal) => {
|
|
2245
|
+
addRemoteInfoToStorage(remoteEntry);
|
|
2246
|
+
addExternalsToStorage(remoteEntry, onSharedExternal);
|
|
2247
|
+
addSharedChunksToStorage(remoteEntry);
|
|
2248
|
+
};
|
|
2249
|
+
function addRemoteInfoToStorage({ name, url, exposes, integrity }) {
|
|
2250
|
+
ports.remoteInfoRepo.addOrUpdate(name, {
|
|
2251
|
+
scopeUrl: getScope(url),
|
|
2252
|
+
exposes: Object.values(exposes ?? []).map((m) => ({
|
|
2253
|
+
moduleName: m.key,
|
|
2254
|
+
file: m.outFileName
|
|
2255
|
+
})),
|
|
2256
|
+
...integrity ? { integrity } : {}
|
|
2257
|
+
});
|
|
2258
|
+
}
|
|
2259
|
+
function addExternalsToStorage(remoteEntry, onSharedExternal) {
|
|
2260
|
+
remoteEntry.shared.forEach((external) => {
|
|
2261
|
+
const tag = resolveVersion(remoteEntry, external);
|
|
2262
|
+
if (tag === null) return;
|
|
2263
|
+
if (external.singleton) {
|
|
2264
|
+
if (external.requiredVersion && !ports.versionCheck.isCompatible(tag, external.requiredVersion))
|
|
2265
|
+
config.log.warn(
|
|
2266
|
+
logStep,
|
|
2267
|
+
`[${remoteEntry.name}][${external.packageName}] requiredVersion '${external.requiredVersion}' excludes its own version '${tag}'; '${tag}' is still accepted for it.`
|
|
2268
|
+
);
|
|
2269
|
+
onSharedExternal(remoteEntry, external, sharedExternalContext(remoteEntry, external, tag));
|
|
2270
|
+
} else {
|
|
2271
|
+
addScopedExternal(remoteEntry, external, tag);
|
|
2272
|
+
}
|
|
2273
|
+
});
|
|
2274
|
+
}
|
|
2275
|
+
function addSharedChunksToStorage(remoteEntry) {
|
|
2276
|
+
if (!remoteEntry.chunks) return;
|
|
2277
|
+
config.log.debug(
|
|
2278
|
+
logStep,
|
|
2279
|
+
`Adding chunks for remote "${remoteEntry.name}", bundles: [${Object.keys(remoteEntry.chunks).join(", ")}]`
|
|
2280
|
+
);
|
|
2281
|
+
Object.entries(remoteEntry.chunks).forEach(([bundleName, chunks]) => {
|
|
2282
|
+
ports.sharedChunksRepo.addOrReplace(remoteEntry.name, bundleName, chunks);
|
|
2283
|
+
});
|
|
2284
|
+
}
|
|
2285
|
+
function addScopedExternal(remoteEntry, sharedInfo, tag) {
|
|
2286
|
+
ports.scopedExternalsRepo.addExternal(remoteEntry.name, sharedInfo.packageName, {
|
|
2287
|
+
tag,
|
|
2288
|
+
bundle: sharedInfo.bundle,
|
|
2289
|
+
entries: sharedInfo.entries
|
|
2290
|
+
});
|
|
2291
|
+
}
|
|
2292
|
+
function resolveVersion(remoteEntry, external) {
|
|
2293
|
+
if (external.version && ports.versionCheck.isValidSemver(external.version)) {
|
|
2294
|
+
return external.version;
|
|
2295
|
+
}
|
|
2296
|
+
const errorMsg = `[${remoteEntry.name}][${external.packageName}] Version '${external.version}' is not a valid version.`;
|
|
2297
|
+
if (config.strict.strictExternalVersion) {
|
|
2298
|
+
config.log.error(logStep, errorMsg);
|
|
2299
|
+
throw new NFError(`Could not process remote '${remoteEntry.name}'`);
|
|
2300
|
+
}
|
|
2301
|
+
if (config.profile.skipInvalidExternalVersions) {
|
|
2302
|
+
config.log.warn(logStep, `${errorMsg} Skipping external.`);
|
|
2303
|
+
return null;
|
|
2304
|
+
}
|
|
2305
|
+
config.log.warn(logStep, errorMsg);
|
|
2306
|
+
return ports.versionCheck.smallestVersion(external.requiredVersion);
|
|
2307
|
+
}
|
|
2308
|
+
function sharedExternalContext(remoteEntry, sharedInfo, tag) {
|
|
2309
|
+
const scopeType = ports.sharedExternalsRepo.scopeType(sharedInfo.shareScope);
|
|
2310
|
+
const remote = {
|
|
2311
|
+
name: remoteEntry.name,
|
|
2312
|
+
bundle: sharedInfo.bundle,
|
|
2313
|
+
strictVersion: sharedInfo.strictVersion,
|
|
2314
|
+
cached: false,
|
|
2315
|
+
requiredVersion: scopeType === "strict" ? tag : sharedInfo.requiredVersion || tag,
|
|
2316
|
+
...sharedInfo.pool?.trim() ? { pool: sharedInfo.pool } : {},
|
|
2317
|
+
...sharedInfo.dense ? { dense: true } : {},
|
|
2318
|
+
entries: sharedInfo.entries
|
|
2319
|
+
};
|
|
2320
|
+
let stored;
|
|
2321
|
+
const readRecord = () => stored ??= ports.sharedExternalsRepo.tryGet(sharedInfo.packageName, sharedInfo.shareScope).get() ?? { dirty: false, versions: [] };
|
|
2322
|
+
return {
|
|
2323
|
+
tag,
|
|
2324
|
+
remote,
|
|
2325
|
+
readRecord,
|
|
2326
|
+
scopeType,
|
|
2327
|
+
assertSameVersionCompatibility(matchingVersion) {
|
|
2328
|
+
if (!remote.strictVersion) return;
|
|
2329
|
+
if (matchingVersion.remotes[0].requiredVersion === remote.requiredVersion) return;
|
|
2330
|
+
const errorMsg = `[${remoteEntry.name}][${sharedInfo.packageName}@${sharedInfo.version}] Required version-range '${remote.requiredVersion}' does not match cached version-range '${matchingVersion.remotes[0].requiredVersion}'`;
|
|
2331
|
+
if (config.strict.strictExternalSameVersionCompatibility) {
|
|
2332
|
+
config.log.error(logStep, errorMsg);
|
|
2333
|
+
throw new NFError(`Could not process remote '${remoteEntry.name}'`);
|
|
2334
|
+
}
|
|
2335
|
+
config.log.warn(logStep, errorMsg);
|
|
2336
|
+
},
|
|
2337
|
+
write() {
|
|
2338
|
+
ports.sharedExternalsRepo.addOrUpdate(
|
|
2339
|
+
sharedInfo.packageName,
|
|
2340
|
+
{
|
|
2341
|
+
...readRecord(),
|
|
2342
|
+
versions: readRecord().versions.sort((a, b) => ports.versionCheck.compare(b.tag, a.tag))
|
|
2343
|
+
},
|
|
2344
|
+
sharedInfo.shareScope
|
|
2345
|
+
);
|
|
2346
|
+
}
|
|
2347
|
+
};
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
|
|
2022
2351
|
// src/lib/core/2.app/steps/get-remote-entries.ts
|
|
2023
2352
|
function createGetRemoteEntries(config, ports) {
|
|
2353
|
+
const removeCachedRemoteEntries = createRemoveCachedRemoteEntries(ports);
|
|
2024
2354
|
return (remotesOrManifestUrl = {}) => {
|
|
2025
2355
|
const manifestPromise = config.manifestIntegrity ? ports.manifestProvider.provide(remotesOrManifestUrl, {
|
|
2026
2356
|
integrity: config.manifestIntegrity
|
|
@@ -2028,7 +2358,7 @@ function createGetRemoteEntries(config, ports) {
|
|
|
2028
2358
|
return manifestPromise.catch((e) => {
|
|
2029
2359
|
config.log.error(1, "Could not fetch manifest.", e);
|
|
2030
2360
|
return Promise.reject(new NFError("Failed to fetch manifest"));
|
|
2031
|
-
}).then(addHostRemoteEntry).then(fetchRemoteEntries).then(removeSkippedRemotes).then(checkForSSE);
|
|
2361
|
+
}).then(addHostRemoteEntry).then(dropUnlistedRemotes).then(fetchRemoteEntries).then(removeSkippedRemotes).then(checkForSSE);
|
|
2032
2362
|
};
|
|
2033
2363
|
function addHostRemoteEntry(manifest) {
|
|
2034
2364
|
if (!config.hostRemoteEntry) return manifest;
|
|
@@ -2038,6 +2368,26 @@ function createGetRemoteEntries(config, ports) {
|
|
|
2038
2368
|
[name]: integrity ? { url, integrity } : url
|
|
2039
2369
|
};
|
|
2040
2370
|
}
|
|
2371
|
+
function dropUnlistedRemotes(manifest) {
|
|
2372
|
+
if (config.profile.mergeManifests !== false) return manifest;
|
|
2373
|
+
const listedUrls = new Set(
|
|
2374
|
+
Object.values(manifest).map((descriptor) => normalizeEntry(descriptor).url)
|
|
2375
|
+
);
|
|
2376
|
+
const isListed = (remoteName, info) => Object.hasOwn(manifest, remoteName) || listedUrls.has(storedEntryUrl(info));
|
|
2377
|
+
const unlisted = new Set(
|
|
2378
|
+
Object.entries(ports.remoteInfoRepo.getAll()).filter(([remoteName, info]) => !isListed(remoteName, info)).map(([remoteName]) => remoteName)
|
|
2379
|
+
);
|
|
2380
|
+
if (unlisted.size > 0)
|
|
2381
|
+
config.log.debug(
|
|
2382
|
+
1,
|
|
2383
|
+
`Removing stored remotes the manifest doesn't list: ${[...unlisted].join(", ")}.`
|
|
2384
|
+
);
|
|
2385
|
+
removeCachedRemoteEntries(unlisted);
|
|
2386
|
+
return manifest;
|
|
2387
|
+
}
|
|
2388
|
+
function storedEntryUrl(info) {
|
|
2389
|
+
return join(info.scopeUrl, "remoteEntry.json");
|
|
2390
|
+
}
|
|
2041
2391
|
function normalizeEntry(descriptor) {
|
|
2042
2392
|
return typeof descriptor === "string" ? { url: descriptor } : descriptor;
|
|
2043
2393
|
}
|
|
@@ -2062,7 +2412,7 @@ function createGetRemoteEntries(config, ports) {
|
|
|
2062
2412
|
let isOverride = false;
|
|
2063
2413
|
let skip = false;
|
|
2064
2414
|
ports.remoteInfoRepo.tryGet(remoteName).ifPresent((cachedRemoteInfo) => {
|
|
2065
|
-
if (config.profile.overrideCachedRemotes !== "never" && (remoteEntryUrl !==
|
|
2415
|
+
if (config.profile.overrideCachedRemotes !== "never" && (remoteEntryUrl !== storedEntryUrl(cachedRemoteInfo) || config.profile.overrideCachedRemotesIfURLMatches)) {
|
|
2066
2416
|
config.log.debug(1, `Overriding existing remote '${remoteName}' with '${remoteEntryUrl}'.`);
|
|
2067
2417
|
isOverride = true;
|
|
2068
2418
|
} else {
|
|
@@ -2123,11 +2473,17 @@ function createGetRemoteEntries(config, ports) {
|
|
|
2123
2473
|
}
|
|
2124
2474
|
}
|
|
2125
2475
|
|
|
2476
|
+
// src/lib/utils/compare-strings.ts
|
|
2477
|
+
function compareStrings(a, b) {
|
|
2478
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
2479
|
+
}
|
|
2480
|
+
|
|
2126
2481
|
// src/lib/core/1.domain/externals/basis.ts
|
|
2127
2482
|
var coverage = (remote) => Object.keys(remote.entries).length;
|
|
2128
2483
|
function isBetterBasis(candidate, basis) {
|
|
2129
2484
|
if (basis.cached !== candidate.cached) return candidate.cached;
|
|
2130
|
-
|
|
2485
|
+
const byCoverage = coverage(candidate) - coverage(basis);
|
|
2486
|
+
return byCoverage === 0 ? compareStrings(candidate.name, basis.name) < 0 : byCoverage > 0;
|
|
2131
2487
|
}
|
|
2132
2488
|
function addRemoteToVersion(version, remote, isHost = false) {
|
|
2133
2489
|
if (isHost) {
|
|
@@ -2151,21 +2507,6 @@ function versionDemands(version) {
|
|
|
2151
2507
|
}
|
|
2152
2508
|
return Array.from(distinct.values());
|
|
2153
2509
|
}
|
|
2154
|
-
function findVersionForTag(versions, tag) {
|
|
2155
|
-
let scoped;
|
|
2156
|
-
for (const version of versions) {
|
|
2157
|
-
if (version.tag !== tag) continue;
|
|
2158
|
-
if (version.action !== "scope") return version;
|
|
2159
|
-
scoped ??= version;
|
|
2160
|
-
}
|
|
2161
|
-
return scoped;
|
|
2162
|
-
}
|
|
2163
|
-
function versionEntries(version) {
|
|
2164
|
-
return collectEntries(version, void 0);
|
|
2165
|
-
}
|
|
2166
|
-
function committedEntries(version) {
|
|
2167
|
-
return collectEntries(version, (remote) => remote.cached);
|
|
2168
|
-
}
|
|
2169
2510
|
function forEachVersionEntry(version, accepts, visit) {
|
|
2170
2511
|
for (const remote of version.remotes) {
|
|
2171
2512
|
if (remote.servedBy) continue;
|
|
@@ -2173,16 +2514,6 @@ function forEachVersionEntry(version, accepts, visit) {
|
|
|
2173
2514
|
for (const entrypoint in remote.entries) visit(entrypoint, remote);
|
|
2174
2515
|
}
|
|
2175
2516
|
}
|
|
2176
|
-
function collectEntries(version, accepts) {
|
|
2177
|
-
const entries = /* @__PURE__ */ new Map();
|
|
2178
|
-
forEachVersionEntry(version, accepts, (entrypoint, remote) => {
|
|
2179
|
-
if (!entries.has(entrypoint)) entries.set(entrypoint, remote);
|
|
2180
|
-
});
|
|
2181
|
-
return entries;
|
|
2182
|
-
}
|
|
2183
|
-
function uncoveredEntrypoints(remote, covered) {
|
|
2184
|
-
return Object.keys(remote.entries).filter((entrypoint) => !covered.has(entrypoint));
|
|
2185
|
-
}
|
|
2186
2517
|
function countUncoveredEntrypoints(remote, covered) {
|
|
2187
2518
|
let uncovered = 0;
|
|
2188
2519
|
for (const entrypoint in remote.entries) {
|
|
@@ -2191,118 +2522,87 @@ function countUncoveredEntrypoints(remote, covered) {
|
|
|
2191
2522
|
return uncovered;
|
|
2192
2523
|
}
|
|
2193
2524
|
|
|
2194
|
-
// src/lib/core/
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2525
|
+
// src/lib/core/1.domain/externals/rows.ts
|
|
2526
|
+
var byTag = (compare) => (a, b) => compare(b.tag, a.tag);
|
|
2527
|
+
var rowAt = (versions, tag, action) => versions.find((v) => v.tag === tag && v.action === action);
|
|
2528
|
+
function mergeRows(versions, lead) {
|
|
2529
|
+
const merged = /* @__PURE__ */ new Map();
|
|
2530
|
+
if (lead) merged.set(`${lead.tag}|${lead.action}`, lead);
|
|
2531
|
+
return versions.filter((v) => {
|
|
2532
|
+
const key = `${v.tag}|${v.action}`;
|
|
2533
|
+
const first = merged.get(key);
|
|
2534
|
+
if (first === v) return true;
|
|
2535
|
+
if (!first) {
|
|
2536
|
+
merged.set(key, v);
|
|
2537
|
+
return true;
|
|
2202
2538
|
}
|
|
2203
|
-
|
|
2204
|
-
|
|
2539
|
+
first.remotes.push(...v.remotes);
|
|
2540
|
+
return false;
|
|
2541
|
+
});
|
|
2205
2542
|
}
|
|
2206
|
-
function
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
function addRemoteInfoToStorage({ name, url, exposes, integrity }) {
|
|
2213
|
-
ports.remoteInfoRepo.addOrUpdate(name, {
|
|
2214
|
-
scopeUrl: getScope(url),
|
|
2215
|
-
exposes: Object.values(exposes ?? []).map((m) => ({
|
|
2216
|
-
moduleName: m.key,
|
|
2217
|
-
file: m.outFileName
|
|
2218
|
-
})),
|
|
2219
|
-
...integrity ? { integrity } : {}
|
|
2220
|
-
});
|
|
2221
|
-
}
|
|
2222
|
-
function addExternalsToStorage(remoteEntry, onSharedExternal) {
|
|
2223
|
-
remoteEntry.shared.forEach((external) => {
|
|
2224
|
-
const tag = resolveVersion(remoteEntry, external);
|
|
2225
|
-
if (tag === null) return;
|
|
2226
|
-
if (external.singleton) {
|
|
2227
|
-
onSharedExternal(remoteEntry, external, sharedExternalContext(remoteEntry, external, tag));
|
|
2228
|
-
} else {
|
|
2229
|
-
addScopedExternal(remoteEntry, external, tag);
|
|
2230
|
-
}
|
|
2231
|
-
});
|
|
2543
|
+
function findVersionForTag(versions, tag) {
|
|
2544
|
+
let scoped;
|
|
2545
|
+
for (const version of versions) {
|
|
2546
|
+
if (version.tag !== tag) continue;
|
|
2547
|
+
if (version.action !== "scope") return version;
|
|
2548
|
+
scoped ??= version;
|
|
2232
2549
|
}
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2550
|
+
return scoped;
|
|
2551
|
+
}
|
|
2552
|
+
function redirectRow(version, tag, acceptsTag) {
|
|
2553
|
+
const objecting = new Set(
|
|
2554
|
+
version.remotes.filter((r) => r.strictVersion && !acceptsTag(tag, version.tag, r.requiredVersion))
|
|
2555
|
+
);
|
|
2556
|
+
if (objecting.size === 0) {
|
|
2557
|
+
version.action = "skip";
|
|
2558
|
+
return [version];
|
|
2242
2559
|
}
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
bundle: sharedInfo.bundle,
|
|
2247
|
-
entries: sharedInfo.entries
|
|
2248
|
-
});
|
|
2560
|
+
if (objecting.size === version.remotes.length) {
|
|
2561
|
+
version.action = "scope";
|
|
2562
|
+
return [version];
|
|
2249
2563
|
}
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2564
|
+
version.remotes = version.remotes.filter((r) => !objecting.has(r));
|
|
2565
|
+
version.action = "skip";
|
|
2566
|
+
return [version, { tag: version.tag, host: false, action: "scope", remotes: [...objecting] }];
|
|
2567
|
+
}
|
|
2568
|
+
function scopeRemotes(versions, remotes) {
|
|
2569
|
+
if (remotes.length === 0) return versions;
|
|
2570
|
+
const turn = new Map(remotes.map((remote, i) => [remote, i]));
|
|
2571
|
+
const moves = /* @__PURE__ */ new Map();
|
|
2572
|
+
versions.forEach((source, at) => {
|
|
2573
|
+
if (source.action === "scope") return;
|
|
2574
|
+
const byTurn = /* @__PURE__ */ new Map();
|
|
2575
|
+
for (const copy of source.remotes) {
|
|
2576
|
+
const i = turn.get(copy.name);
|
|
2577
|
+
if (i === void 0) continue;
|
|
2578
|
+
const copies = byTurn.get(i);
|
|
2579
|
+
if (copies) copies.push(copy);
|
|
2580
|
+
else byTurn.set(i, [copy]);
|
|
2258
2581
|
}
|
|
2259
|
-
if (
|
|
2260
|
-
|
|
2261
|
-
|
|
2582
|
+
if (byTurn.size === 0) return;
|
|
2583
|
+
const hostTurn = source.host ? turn.get(source.remotes[0].name) : void 0;
|
|
2584
|
+
source.remotes = source.remotes.filter((r) => !turn.has(r.name));
|
|
2585
|
+
if (hostTurn !== void 0) source.host = false;
|
|
2586
|
+
const tagMoves = moves.get(source.tag) ?? [];
|
|
2587
|
+
for (const [i, copies] of byTurn)
|
|
2588
|
+
tagMoves.push({ turn: i, at, source, copies, host: i === hostTurn });
|
|
2589
|
+
moves.set(source.tag, tagMoves);
|
|
2590
|
+
});
|
|
2591
|
+
const rows = [...versions];
|
|
2592
|
+
for (const [tag, tagMoves] of moves) {
|
|
2593
|
+
tagMoves.sort((a, b) => a.turn - b.turn || a.at - b.at);
|
|
2594
|
+
let scoped = rowAt(rows, tag, "scope");
|
|
2595
|
+
if (!scoped) {
|
|
2596
|
+
scoped = { tag, host: false, action: "scope", remotes: [] };
|
|
2597
|
+
rows.splice(rows.indexOf(tagMoves[0].source) + 1, 0, scoped);
|
|
2262
2598
|
}
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
const remote = {
|
|
2269
|
-
name: remoteEntry.name,
|
|
2270
|
-
bundle: sharedInfo.bundle,
|
|
2271
|
-
strictVersion: sharedInfo.strictVersion,
|
|
2272
|
-
cached: false,
|
|
2273
|
-
requiredVersion: scopeType === "strict" ? tag : sharedInfo.requiredVersion || tag,
|
|
2274
|
-
...sharedInfo.pool?.trim() ? { pool: sharedInfo.pool } : {},
|
|
2275
|
-
entries: sharedInfo.entries
|
|
2276
|
-
};
|
|
2277
|
-
const cached2 = ports.sharedExternalsRepo.tryGet(sharedInfo.packageName, sharedInfo.shareScope).get() ?? { dirty: false, versions: [] };
|
|
2278
|
-
return {
|
|
2279
|
-
tag,
|
|
2280
|
-
remote,
|
|
2281
|
-
cached: cached2,
|
|
2282
|
-
scopeType,
|
|
2283
|
-
assertSameVersionCompatibility(matchingVersion) {
|
|
2284
|
-
if (!remote.strictVersion) return;
|
|
2285
|
-
if (matchingVersion.remotes[0].requiredVersion === remote.requiredVersion) return;
|
|
2286
|
-
const errorMsg = `[${remoteEntry.name}][${sharedInfo.packageName}@${sharedInfo.version}] Required version-range '${remote.requiredVersion}' does not match cached version-range '${matchingVersion.remotes[0].requiredVersion}'`;
|
|
2287
|
-
if (config.strict.strictExternalSameVersionCompatibility) {
|
|
2288
|
-
config.log.error(logStep, errorMsg);
|
|
2289
|
-
throw new NFError(`Could not process remote '${remoteEntry.name}'`);
|
|
2290
|
-
}
|
|
2291
|
-
config.log.warn(logStep, errorMsg);
|
|
2292
|
-
},
|
|
2293
|
-
commit() {
|
|
2294
|
-
ports.sharedExternalsRepo.addOrUpdate(
|
|
2295
|
-
sharedInfo.packageName,
|
|
2296
|
-
{
|
|
2297
|
-
dirty: cached2.dirty,
|
|
2298
|
-
...cached2.poolName !== void 0 && { poolName: cached2.poolName },
|
|
2299
|
-
versions: cached2.versions.sort((a, b) => ports.versionCheck.compare(b.tag, a.tag))
|
|
2300
|
-
},
|
|
2301
|
-
sharedInfo.shareScope
|
|
2302
|
-
);
|
|
2303
|
-
}
|
|
2304
|
-
};
|
|
2599
|
+
for (const { copies, host } of tagMoves)
|
|
2600
|
+
if (host) {
|
|
2601
|
+
scoped.host = true;
|
|
2602
|
+
scoped.remotes.unshift(...copies);
|
|
2603
|
+
} else scoped.remotes.push(...copies);
|
|
2305
2604
|
}
|
|
2605
|
+
return rows.filter((v) => v.remotes.length > 0);
|
|
2306
2606
|
}
|
|
2307
2607
|
|
|
2308
2608
|
// src/lib/core/2.app/steps/process-remote-entries.ts
|
|
@@ -2340,11 +2640,12 @@ function createProcessRemoteEntries(config, ports) {
|
|
|
2340
2640
|
function addSharedExternal(remoteEntry, _sharedInfo, {
|
|
2341
2641
|
tag,
|
|
2342
2642
|
remote,
|
|
2343
|
-
|
|
2643
|
+
readRecord,
|
|
2344
2644
|
scopeType,
|
|
2345
2645
|
assertSameVersionCompatibility,
|
|
2346
|
-
|
|
2646
|
+
write
|
|
2347
2647
|
}) {
|
|
2648
|
+
const cached2 = readRecord();
|
|
2348
2649
|
if (scopeType !== "strict") cached2.dirty = true;
|
|
2349
2650
|
const matchingVersion = findVersionForTag(cached2.versions, tag);
|
|
2350
2651
|
if (matchingVersion) {
|
|
@@ -2358,158 +2659,74 @@ function createProcessRemoteEntries(config, ports) {
|
|
|
2358
2659
|
remotes: [remote]
|
|
2359
2660
|
});
|
|
2360
2661
|
}
|
|
2361
|
-
|
|
2662
|
+
write();
|
|
2362
2663
|
}
|
|
2363
2664
|
}
|
|
2364
2665
|
|
|
2365
|
-
// src/lib/core/
|
|
2366
|
-
function
|
|
2666
|
+
// src/lib/core/1.domain/externals/compatibility.ts
|
|
2667
|
+
function createAcceptsTag(isCompatible, compare) {
|
|
2668
|
+
return (offered, ownTag, requiredVersion) => isCompatible(offered, requiredVersion) || offered === ownTag || compare(offered, ownTag) === 0;
|
|
2669
|
+
}
|
|
2670
|
+
function versionAcceptance(external, acceptsTag) {
|
|
2367
2671
|
const demands = new Map(
|
|
2368
2672
|
external.versions.map((v) => [v, versionDemands(v)])
|
|
2369
2673
|
);
|
|
2370
2674
|
return {
|
|
2371
|
-
accepts: (version, tag) => demands.get(version).every((d) =>
|
|
2372
|
-
objector: (version, tag) => demands.get(version).find((d) => d.strictVersion && !
|
|
2675
|
+
accepts: (version, tag) => demands.get(version).every((d) => acceptsTag(tag, version.tag, d.requiredVersion)),
|
|
2676
|
+
objector: (version, tag) => demands.get(version).find((d) => d.strictVersion && !acceptsTag(tag, version.tag, d.requiredVersion))
|
|
2373
2677
|
};
|
|
2374
2678
|
}
|
|
2679
|
+
|
|
2680
|
+
// src/lib/core/2.app/steps/apply-winner.ts
|
|
2681
|
+
function rejectIncompatible(config, copy, rejected, servedAt) {
|
|
2682
|
+
config.log.error(
|
|
2683
|
+
3,
|
|
2684
|
+
`[${copy.name}][${rejected}] Is not compatible with requiredRange '${copy.requiredVersion}' of shared ${servedAt}.`
|
|
2685
|
+
);
|
|
2686
|
+
throw new NFError(`External ${rejected} could not be shared.`);
|
|
2687
|
+
}
|
|
2375
2688
|
function createApplyWinner(config) {
|
|
2376
|
-
return function applyWinner(externalName, external, winner,
|
|
2689
|
+
return function applyWinner(externalName, external, winner, acceptsTag, acceptance) {
|
|
2377
2690
|
if (external.versions.length > 1) {
|
|
2378
|
-
const { accepts, objector } = acceptance ?? versionAcceptance(external, isCompatible);
|
|
2379
2691
|
const rebuilt = [];
|
|
2380
2692
|
for (const v of external.versions) {
|
|
2381
|
-
|
|
2382
|
-
if (
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
config.log.error(
|
|
2389
|
-
3,
|
|
2390
|
-
`[${strict.name}][${externalName}@${v.tag}] Is not compatible with requiredRange '${strict.requiredVersion}' of shared ${externalName}@${winner.tag}.`
|
|
2693
|
+
const objector = config.strict.strictExternalCompatibility && acceptance.objector(v, winner.tag);
|
|
2694
|
+
if (objector)
|
|
2695
|
+
rejectIncompatible(
|
|
2696
|
+
config,
|
|
2697
|
+
objector,
|
|
2698
|
+
`${externalName}@${v.tag}`,
|
|
2699
|
+
`${externalName}@${winner.tag}`
|
|
2391
2700
|
);
|
|
2392
|
-
|
|
2393
|
-
}
|
|
2394
|
-
if (v === winner) continue;
|
|
2395
|
-
if (!strict) {
|
|
2396
|
-
v.action = "skip";
|
|
2397
|
-
continue;
|
|
2398
|
-
}
|
|
2399
|
-
const objecting = new Set(
|
|
2400
|
-
v.remotes.filter((r) => r.strictVersion && !isCompatible(winner.tag, r.requiredVersion))
|
|
2401
|
-
);
|
|
2402
|
-
if (objecting.size === v.remotes.length) {
|
|
2403
|
-
v.action = "scope";
|
|
2404
|
-
continue;
|
|
2405
|
-
}
|
|
2406
|
-
v.remotes = v.remotes.filter((r) => !objecting.has(r));
|
|
2407
|
-
v.action = "skip";
|
|
2408
|
-
rebuilt.push({ tag: v.tag, host: false, action: "scope", remotes: [...objecting] });
|
|
2701
|
+
rebuilt.push(...redirectRow(v, winner.tag, acceptsTag));
|
|
2409
2702
|
}
|
|
2410
|
-
|
|
2411
|
-
external.versions = rebuilt.filter((v) => {
|
|
2412
|
-
const first = merged.get(`${v.tag}|${v.action}`);
|
|
2413
|
-
if (!first) {
|
|
2414
|
-
merged.set(`${v.tag}|${v.action}`, v);
|
|
2415
|
-
return true;
|
|
2416
|
-
}
|
|
2417
|
-
first.remotes.push(...v.remotes);
|
|
2418
|
-
return false;
|
|
2419
|
-
});
|
|
2703
|
+
external.versions = mergeRows(rebuilt, winner);
|
|
2420
2704
|
}
|
|
2421
2705
|
winner.action = "share";
|
|
2422
|
-
applyEntrypointCoveragePolicy(externalName, external);
|
|
2423
2706
|
external.dirty = false;
|
|
2424
2707
|
return external;
|
|
2425
2708
|
};
|
|
2426
|
-
function applyEntrypointCoveragePolicy(externalName, external) {
|
|
2427
|
-
const { strictEntryPointCoverage } = config.strict;
|
|
2428
|
-
if (!strictEntryPointCoverage && !config.profile.scopeUncoveredEntrypoints) return;
|
|
2429
|
-
const tears = findTears(external);
|
|
2430
|
-
if (tears.length === 0) return;
|
|
2431
|
-
if (strictEntryPointCoverage) {
|
|
2432
|
-
const { version, remote, uncovered } = tears[0];
|
|
2433
|
-
config.log.error(
|
|
2434
|
-
3,
|
|
2435
|
-
`[${externalName}@${version.tag}][${remote.name}] Entrypoints not covered by the shared version: ${uncovered.join(", ")}.`
|
|
2436
|
-
);
|
|
2437
|
-
throw new NFError(
|
|
2438
|
-
`External ${externalName} could not be shared without tearing entrypoints.`
|
|
2439
|
-
);
|
|
2440
|
-
}
|
|
2441
|
-
scopeTornRemotes(externalName, external, tears);
|
|
2442
|
-
}
|
|
2443
|
-
function findTears(external) {
|
|
2444
|
-
const shared = external.versions.find((v) => v.action === "share");
|
|
2445
|
-
if (!shared) return [];
|
|
2446
|
-
const basis = versionEntries(shared);
|
|
2447
|
-
const tears = [];
|
|
2448
|
-
for (const version of external.versions) {
|
|
2449
|
-
if (version.action === "scope") continue;
|
|
2450
|
-
if (version === shared) continue;
|
|
2451
|
-
version.remotes.forEach((remote) => {
|
|
2452
|
-
if (remote.servedBy) return;
|
|
2453
|
-
const uncovered = uncoveredEntrypoints(remote, basis);
|
|
2454
|
-
if (uncovered.length > 0) tears.push({ version, remote, uncovered });
|
|
2455
|
-
});
|
|
2456
|
-
}
|
|
2457
|
-
return tears;
|
|
2458
|
-
}
|
|
2459
|
-
function scopeTornRemotes(externalName, external, tears) {
|
|
2460
|
-
const torn = new Set(tears.map((t) => t.remote));
|
|
2461
|
-
const demotedByTag = /* @__PURE__ */ new Map();
|
|
2462
|
-
for (const { version, remote, uncovered } of tears) {
|
|
2463
|
-
const group = demotedByTag.get(version.tag);
|
|
2464
|
-
if (group) group.push(remote);
|
|
2465
|
-
else demotedByTag.set(version.tag, [remote]);
|
|
2466
|
-
config.log.debug(
|
|
2467
|
-
3,
|
|
2468
|
-
`[${externalName}@${version.tag}][${remote.name}] Scoped: entrypoints not covered by the shared version: ${uncovered.join(", ")}.`
|
|
2469
|
-
);
|
|
2470
|
-
}
|
|
2471
|
-
for (const version of external.versions) {
|
|
2472
|
-
if (version.remotes.some((r) => torn.has(r))) {
|
|
2473
|
-
version.remotes = version.remotes.filter((r) => !torn.has(r));
|
|
2474
|
-
}
|
|
2475
|
-
}
|
|
2476
|
-
external.versions = external.versions.filter((v) => v.remotes.length > 0);
|
|
2477
|
-
for (const [tag, remotes] of demotedByTag) {
|
|
2478
|
-
const scoped = external.versions.find((v) => v.tag === tag && v.action === "scope");
|
|
2479
|
-
if (scoped) scoped.remotes.push(...remotes);
|
|
2480
|
-
else external.versions.push({ tag, host: false, action: "scope", remotes });
|
|
2481
|
-
}
|
|
2482
|
-
}
|
|
2483
2709
|
}
|
|
2484
2710
|
|
|
2485
2711
|
// src/lib/core/2.app/steps/determine-shared-externals.ts
|
|
2486
2712
|
function createDetermineSharedExternals(config, ports) {
|
|
2487
2713
|
const applyWinner = createApplyWinner(config);
|
|
2488
2714
|
return () => {
|
|
2489
|
-
const
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
if (hit === void 0) {
|
|
2494
|
-
hit = ports.versionCheck.isCompatible(tag, requiredVersion);
|
|
2495
|
-
memo.set(key, hit);
|
|
2496
|
-
}
|
|
2497
|
-
return hit;
|
|
2498
|
-
};
|
|
2499
|
-
const touched = /* @__PURE__ */ new Map();
|
|
2715
|
+
const acceptsTag = createAcceptsTag(
|
|
2716
|
+
ports.versionCheck.isCompatible,
|
|
2717
|
+
ports.versionCheck.compare
|
|
2718
|
+
);
|
|
2500
2719
|
for (const shareScope of ports.sharedExternalsRepo.getScopes()) {
|
|
2720
|
+
if (ports.sharedExternalsRepo.scopeType(shareScope) === "strict") continue;
|
|
2501
2721
|
const sharedExternals = ports.sharedExternalsRepo.getFromScope(shareScope);
|
|
2502
2722
|
try {
|
|
2503
|
-
const elected = /* @__PURE__ */ new Set();
|
|
2504
2723
|
Object.entries(sharedExternals).filter(([_, e]) => e.dirty).forEach(([name, external]) => {
|
|
2505
2724
|
ports.sharedExternalsRepo.addOrUpdate(
|
|
2506
2725
|
name,
|
|
2507
|
-
setVersionActions(name, external,
|
|
2726
|
+
setVersionActions(name, external, acceptsTag),
|
|
2508
2727
|
shareScope
|
|
2509
2728
|
);
|
|
2510
|
-
elected.add(name);
|
|
2511
2729
|
});
|
|
2512
|
-
if (elected.size > 0) touched.set(shareScope, elected);
|
|
2513
2730
|
} catch (error) {
|
|
2514
2731
|
config.log.error(
|
|
2515
2732
|
3,
|
|
@@ -2527,24 +2744,22 @@ function createDetermineSharedExternals(config, ports) {
|
|
|
2527
2744
|
);
|
|
2528
2745
|
}
|
|
2529
2746
|
}
|
|
2530
|
-
return Promise.resolve(
|
|
2747
|
+
return Promise.resolve();
|
|
2531
2748
|
};
|
|
2532
2749
|
function uncoveredTears(external, winner, accepts) {
|
|
2533
|
-
const
|
|
2750
|
+
const covered = /* @__PURE__ */ new Set();
|
|
2751
|
+
forEachVersionEntry(winner, void 0, (entrypoint) => covered.add(entrypoint));
|
|
2534
2752
|
return external.versions.reduce((sum, v) => {
|
|
2535
2753
|
if (v === winner) return sum;
|
|
2536
2754
|
if (!accepts(v, winner.tag)) return sum;
|
|
2537
|
-
return v.remotes.reduce(
|
|
2538
|
-
(n, r) => r.servedBy ? n : n + countUncoveredEntrypoints(r, basis),
|
|
2539
|
-
sum
|
|
2540
|
-
);
|
|
2755
|
+
return v.remotes.reduce((n, r) => n + countUncoveredEntrypoints(r, covered), sum);
|
|
2541
2756
|
}, 0);
|
|
2542
2757
|
}
|
|
2543
|
-
function setVersionActions(externalName, external,
|
|
2758
|
+
function setVersionActions(externalName, external, acceptsTag) {
|
|
2759
|
+
const acceptance = versionAcceptance(external, acceptsTag);
|
|
2544
2760
|
if (external.versions.length === 1) {
|
|
2545
|
-
return applyWinner(externalName, external, external.versions[0],
|
|
2761
|
+
return applyWinner(externalName, external, external.versions[0], acceptsTag, acceptance);
|
|
2546
2762
|
}
|
|
2547
|
-
const acceptance = versionAcceptance(external, isCompatible);
|
|
2548
2763
|
const { accepts } = acceptance;
|
|
2549
2764
|
let sharedVersion = external.versions.find((v) => v.host);
|
|
2550
2765
|
if (!sharedVersion && config.profile.latestSharedExternal) {
|
|
@@ -2553,6 +2768,7 @@ function createDetermineSharedExternals(config, ports) {
|
|
|
2553
2768
|
if (!sharedVersion) {
|
|
2554
2769
|
let leastExtraDownloads = Number.MAX_VALUE;
|
|
2555
2770
|
let leastTears = Number.MAX_VALUE;
|
|
2771
|
+
let leaderShared = false;
|
|
2556
2772
|
const selfServing = new Map(
|
|
2557
2773
|
external.versions.map((v) => {
|
|
2558
2774
|
const groups = /* @__PURE__ */ new Map();
|
|
@@ -2569,24 +2785,25 @@ function createDetermineSharedExternals(config, ports) {
|
|
|
2569
2785
|
return [v, [...groups.values()]];
|
|
2570
2786
|
})
|
|
2571
2787
|
);
|
|
2572
|
-
const costOf = (version, tag) => selfServing.get(version).reduce(
|
|
2788
|
+
const costOf = (version, tag) => selfServing.get(version).reduce(
|
|
2789
|
+
(n, g) => acceptsTag(tag, version.tag, g.requiredVersion) ? n : n + g.copies,
|
|
2790
|
+
0
|
|
2791
|
+
);
|
|
2573
2792
|
external.versions.forEach((vA) => {
|
|
2574
|
-
const extraDownloads = external.versions.reduce(
|
|
2575
|
-
|
|
2576
|
-
// reads — see `applyWinner`, which does not split the winner either.
|
|
2577
|
-
(sum, vB) => vB === vA ? sum : sum + costOf(vB, vA.tag),
|
|
2578
|
-
0
|
|
2579
|
-
);
|
|
2793
|
+
const extraDownloads = external.versions.reduce((sum, vB) => sum + costOf(vB, vA.tag), 0);
|
|
2794
|
+
const alreadyShared = vA.action === "share" && !!vA.remotes[0]?.cached;
|
|
2580
2795
|
if (extraDownloads < leastExtraDownloads) {
|
|
2581
2796
|
leastExtraDownloads = extraDownloads;
|
|
2582
2797
|
leastTears = uncoveredTears(external, vA, accepts);
|
|
2798
|
+
leaderShared = alreadyShared;
|
|
2583
2799
|
sharedVersion = vA;
|
|
2584
2800
|
return;
|
|
2585
2801
|
}
|
|
2586
|
-
if (extraDownloads > leastExtraDownloads) return;
|
|
2802
|
+
if (extraDownloads > leastExtraDownloads || leaderShared) return;
|
|
2587
2803
|
const tears = uncoveredTears(external, vA, accepts);
|
|
2588
|
-
if (tears < leastTears) {
|
|
2804
|
+
if (alreadyShared || tears < leastTears) {
|
|
2589
2805
|
leastTears = tears;
|
|
2806
|
+
leaderShared = alreadyShared;
|
|
2590
2807
|
sharedVersion = vA;
|
|
2591
2808
|
}
|
|
2592
2809
|
});
|
|
@@ -2594,582 +2811,619 @@ function createDetermineSharedExternals(config, ports) {
|
|
|
2594
2811
|
if (!sharedVersion) {
|
|
2595
2812
|
throw new NFError(`[${externalName}] Could not determine shared version!`);
|
|
2596
2813
|
}
|
|
2597
|
-
return applyWinner(externalName, external, sharedVersion,
|
|
2814
|
+
return applyWinner(externalName, external, sharedVersion, acceptsTag, acceptance);
|
|
2598
2815
|
}
|
|
2599
2816
|
}
|
|
2600
2817
|
|
|
2601
|
-
// src/lib/
|
|
2602
|
-
function
|
|
2603
|
-
|
|
2818
|
+
// src/lib/utils/union-find.ts
|
|
2819
|
+
function unionFind() {
|
|
2820
|
+
const parent = /* @__PURE__ */ new Map();
|
|
2821
|
+
const find = (node) => {
|
|
2822
|
+
for (let up = parent.get(node); up !== void 0; up = parent.get(node)) {
|
|
2823
|
+
const grand = parent.get(up);
|
|
2824
|
+
if (grand === void 0) return up;
|
|
2825
|
+
parent.set(node, grand);
|
|
2826
|
+
node = grand;
|
|
2827
|
+
}
|
|
2828
|
+
return node;
|
|
2829
|
+
};
|
|
2830
|
+
const union = (a, b) => {
|
|
2831
|
+
const rootA = find(a);
|
|
2832
|
+
const rootB = find(b);
|
|
2833
|
+
if (rootA !== rootB) parent.set(rootB, rootA);
|
|
2834
|
+
};
|
|
2835
|
+
return { find, union };
|
|
2604
2836
|
}
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2837
|
+
|
|
2838
|
+
// src/lib/core/1.domain/externals/specifier.ts
|
|
2839
|
+
function npmPackageOf(name) {
|
|
2840
|
+
const depth = name.startsWith("@") ? 2 : 1;
|
|
2841
|
+
let cut = -1;
|
|
2842
|
+
for (let seen = 0; seen < depth; seen++) {
|
|
2843
|
+
cut = name.indexOf("/", cut + 1);
|
|
2844
|
+
if (cut === -1) return name;
|
|
2845
|
+
}
|
|
2846
|
+
return name.slice(0, cut);
|
|
2612
2847
|
}
|
|
2613
|
-
function
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
const
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
builds.set(
|
|
2627
|
-
meta.name,
|
|
2628
|
-
own = { coverage: /* @__PURE__ */ new Map(), tags: /* @__PURE__ */ new Map(), instance: /* @__PURE__ */ new Map() }
|
|
2629
|
-
);
|
|
2630
|
-
}
|
|
2631
|
-
if (!own.instance.has(member.name)) own.instance.set(member.name, version.tag);
|
|
2632
|
-
for (const specifier in meta.entries) {
|
|
2633
|
-
own.coverage.set(specifier, meta.entries[specifier]);
|
|
2634
|
-
if (!own.tags.has(specifier)) own.tags.set(specifier, version.tag);
|
|
2635
|
-
}
|
|
2636
|
-
}
|
|
2848
|
+
function packageOfIn(scope, loading = []) {
|
|
2849
|
+
if (!declaresLibrary(scope, loading)) return npmPackageOf;
|
|
2850
|
+
const { find, union } = unionFind();
|
|
2851
|
+
const shortest = /* @__PURE__ */ new Map();
|
|
2852
|
+
for (const [name, copy] of copiesIn(scope, loading)) {
|
|
2853
|
+
const anchor = anchorOf(name, copy);
|
|
2854
|
+
for (const specifier in copy.entries) {
|
|
2855
|
+
const best = shorter(
|
|
2856
|
+
shortest.get(find(anchor)) ?? anchor,
|
|
2857
|
+
shortest.get(find(specifier)) ?? specifier
|
|
2858
|
+
);
|
|
2859
|
+
union(anchor, specifier);
|
|
2860
|
+
shortest.set(find(anchor), best);
|
|
2637
2861
|
}
|
|
2638
2862
|
}
|
|
2639
|
-
return
|
|
2863
|
+
return (specifier) => {
|
|
2864
|
+
const npm = npmPackageOf(specifier);
|
|
2865
|
+
return shortest.get(find(specifier)) ?? shortest.get(find(npm)) ?? npm;
|
|
2866
|
+
};
|
|
2640
2867
|
}
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2868
|
+
var shorter = (a, b) => b.length < a.length || b.length === a.length && compareStrings(b, a) < 0 ? b : a;
|
|
2869
|
+
function declaresLibrary(scope, loading) {
|
|
2870
|
+
const isLibrary = (name, copies) => npmPackageOf(name) !== name && copies.some((copy) => copy.dense);
|
|
2871
|
+
return loading.some(([name, copy]) => isLibrary(name, [copy])) || Object.entries(scope).some(
|
|
2872
|
+
([name, external]) => external.versions.some((version) => isLibrary(name, version.remotes))
|
|
2873
|
+
);
|
|
2874
|
+
}
|
|
2875
|
+
var anchorOf = (name, copy) => copy.dense ? name : npmPackageOf(name);
|
|
2876
|
+
function* copiesIn(scope, loading) {
|
|
2877
|
+
yield* loading;
|
|
2878
|
+
for (const [name, external] of Object.entries(scope))
|
|
2879
|
+
for (const version of external.versions) for (const copy of version.remotes) yield [name, copy];
|
|
2880
|
+
}
|
|
2881
|
+
var SpecifierTags = class extends Map {
|
|
2882
|
+
constructor(packageOf, entries = []) {
|
|
2883
|
+
super();
|
|
2884
|
+
this.packageOf = packageOf;
|
|
2885
|
+
for (const [specifier, tag] of entries) this.set(specifier, tag);
|
|
2886
|
+
}
|
|
2887
|
+
packageOf;
|
|
2888
|
+
packages = /* @__PURE__ */ new Map();
|
|
2889
|
+
set(specifier, tag) {
|
|
2890
|
+
super.set(specifier, tag);
|
|
2891
|
+
const pkg = this.packageOf(specifier);
|
|
2892
|
+
if (pkg === specifier || !this.packages.has(pkg)) this.packages.set(pkg, tag);
|
|
2893
|
+
return this;
|
|
2894
|
+
}
|
|
2895
|
+
clear() {
|
|
2896
|
+
super.clear();
|
|
2897
|
+
this.packages.clear();
|
|
2898
|
+
}
|
|
2899
|
+
pinnedTag(specifier) {
|
|
2900
|
+
return this.get(specifier) ?? this.packages.get(this.packageOf(specifier));
|
|
2653
2901
|
}
|
|
2654
|
-
|
|
2902
|
+
};
|
|
2903
|
+
function groupByPackage(items, nameOf, packageOf) {
|
|
2904
|
+
const packages = /* @__PURE__ */ new Map();
|
|
2905
|
+
for (const item of items) {
|
|
2906
|
+
const pkg = packageOf(nameOf(item));
|
|
2907
|
+
const group = packages.get(pkg);
|
|
2908
|
+
if (group) group.push(item);
|
|
2909
|
+
else packages.set(pkg, [item]);
|
|
2910
|
+
}
|
|
2911
|
+
return packages;
|
|
2655
2912
|
}
|
|
2656
|
-
|
|
2657
|
-
|
|
2913
|
+
|
|
2914
|
+
// src/lib/core/1.domain/pooling/builds.ts
|
|
2915
|
+
function copiesByRemote(members) {
|
|
2916
|
+
const shipped = /* @__PURE__ */ new Map();
|
|
2658
2917
|
for (const member of members) {
|
|
2659
|
-
const
|
|
2660
|
-
for (
|
|
2661
|
-
const
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
if (!
|
|
2666
|
-
|
|
2918
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2919
|
+
for (const version of member.external.versions)
|
|
2920
|
+
for (const meta of version.remotes) {
|
|
2921
|
+
if (seen.has(meta.name)) continue;
|
|
2922
|
+
seen.add(meta.name);
|
|
2923
|
+
let copies = shipped.get(meta.name);
|
|
2924
|
+
if (!copies) shipped.set(meta.name, copies = []);
|
|
2925
|
+
copies.push({
|
|
2926
|
+
member: member.name,
|
|
2927
|
+
tag: version.tag,
|
|
2928
|
+
requiredVersion: meta.requiredVersion,
|
|
2929
|
+
strict: meta.strictVersion,
|
|
2930
|
+
host: version.host && meta === version.remotes[0],
|
|
2931
|
+
specifiers: Object.keys(meta.entries)
|
|
2932
|
+
});
|
|
2667
2933
|
}
|
|
2668
|
-
}
|
|
2669
2934
|
}
|
|
2670
|
-
return
|
|
2935
|
+
return shipped;
|
|
2671
2936
|
}
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2937
|
+
var specifierCount = (copies) => copies.reduce((n, copy) => n + copy.specifiers.length, 0);
|
|
2938
|
+
function buildOf(owner, copies, packageOf) {
|
|
2939
|
+
const tags = new SpecifierTags(packageOf);
|
|
2940
|
+
const tagByMember = /* @__PURE__ */ new Map();
|
|
2941
|
+
for (const copy of copies) {
|
|
2942
|
+
for (const specifier of copy.specifiers)
|
|
2943
|
+
if (!tags.has(specifier)) tags.set(specifier, copy.tag);
|
|
2944
|
+
tagByMember.set(copy.member, copy.tag);
|
|
2945
|
+
}
|
|
2946
|
+
return { owner, tags, tagByMember, host: copies.some((c) => c.host) };
|
|
2947
|
+
}
|
|
2948
|
+
|
|
2949
|
+
// src/lib/core/1.domain/pooling/rules.ts
|
|
2950
|
+
function agrees(copies, tags) {
|
|
2951
|
+
for (const copy of copies)
|
|
2952
|
+
for (const s of copy.specifiers) {
|
|
2953
|
+
const tag = tags.pinnedTag(s);
|
|
2954
|
+
if (tag !== void 0 && tag !== copy.tag) return false;
|
|
2684
2955
|
}
|
|
2685
|
-
|
|
2686
|
-
return consumed;
|
|
2956
|
+
return true;
|
|
2687
2957
|
}
|
|
2688
|
-
function
|
|
2689
|
-
const
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
for (const meta of version.remotes) {
|
|
2694
|
-
if (islanded.has(meta.name)) continue;
|
|
2695
|
-
const into = meta.name === build ? served : wanted;
|
|
2696
|
-
for (const specifier in meta.entries) into.add(specifier);
|
|
2697
|
-
}
|
|
2958
|
+
function serves(copies, tags, acceptsTag) {
|
|
2959
|
+
for (const copy of copies)
|
|
2960
|
+
for (const s of copy.specifiers) {
|
|
2961
|
+
const tag = tags.get(s);
|
|
2962
|
+
if (tag === void 0 || !acceptsTag(tag, copy.tag, copy.requiredVersion)) return false;
|
|
2698
2963
|
}
|
|
2699
|
-
}
|
|
2700
|
-
for (const specifier of wanted) if (!served.has(specifier)) return false;
|
|
2701
2964
|
return true;
|
|
2702
2965
|
}
|
|
2703
|
-
function
|
|
2704
|
-
const
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
const
|
|
2708
|
-
if (
|
|
2709
|
-
|
|
2710
|
-
|
|
2966
|
+
function unwitnessedGap(copies, tags, builds) {
|
|
2967
|
+
const specifiers = copies.flatMap((c) => c.specifiers);
|
|
2968
|
+
let gap = 0;
|
|
2969
|
+
for (const build of builds) {
|
|
2970
|
+
const miss = specifiers.findIndex((s) => build.tags.pinnedTag(s) !== tags.get(s));
|
|
2971
|
+
if (miss === -1) return void 0;
|
|
2972
|
+
gap = Math.max(gap, miss);
|
|
2973
|
+
}
|
|
2974
|
+
return specifiers[gap];
|
|
2711
2975
|
}
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2976
|
+
|
|
2977
|
+
// src/lib/core/1.domain/pooling/election.ts
|
|
2978
|
+
function elect(input) {
|
|
2979
|
+
const shipped = copiesByRemote(input.members);
|
|
2980
|
+
const builds = /* @__PURE__ */ new Map();
|
|
2981
|
+
for (const [owner, copies] of shipped) builds.set(owner, buildOf(owner, copies, input.packageOf));
|
|
2982
|
+
const pool = {
|
|
2983
|
+
...input,
|
|
2984
|
+
shipped,
|
|
2985
|
+
builds,
|
|
2986
|
+
packages: new Map(
|
|
2987
|
+
[...shipped].map(([owner, copies]) => [owner, packageCopies(owner, copies, input.packageOf)])
|
|
2988
|
+
),
|
|
2989
|
+
remotes: [...shipped.keys()],
|
|
2990
|
+
servesAt: (remote, tags) => serves(shipped.get(remote), tags, input.acceptsTag),
|
|
2991
|
+
agreesAt: (remote, tags) => agrees(shipped.get(remote), tags)
|
|
2992
|
+
};
|
|
2993
|
+
const hostRemote = pool.remotes.find((r) => builds.get(r).host);
|
|
2994
|
+
const state = roundOne(pool, hostRemote);
|
|
2995
|
+
formSubpools(pool, state);
|
|
2996
|
+
addExtensions(pool, state);
|
|
2997
|
+
promote(pool, state);
|
|
2998
|
+
while (settle(pool, state)) formSubpools(pool, state);
|
|
2999
|
+
const firstSeen = new Map(pool.remotes.map((r, i) => [r, i]));
|
|
3000
|
+
const self = state.pending.sort((a, b) => firstSeen.get(a) - firstSeen.get(b));
|
|
3001
|
+
return {
|
|
3002
|
+
winner: state.winner,
|
|
3003
|
+
winnerIsHost: hostRemote !== void 0,
|
|
3004
|
+
globalTags: state.globalTags,
|
|
3005
|
+
...placeRemotes(state.globalRemotes, state.subpools, self, (r) => missOf(pool, state, r))
|
|
3006
|
+
};
|
|
2723
3007
|
}
|
|
2724
|
-
function
|
|
2725
|
-
const
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
3008
|
+
function newer(pool, a, b) {
|
|
3009
|
+
for (const { name } of pool.members) {
|
|
3010
|
+
const tagA = a.tagByMember.get(name);
|
|
3011
|
+
const tagB = b.tagByMember.get(name);
|
|
3012
|
+
if (tagA === void 0 || tagB === void 0) continue;
|
|
3013
|
+
const d = pool.compare(tagA, tagB);
|
|
3014
|
+
if (d !== 0) return d;
|
|
3015
|
+
}
|
|
3016
|
+
return 0;
|
|
2732
3017
|
}
|
|
2733
|
-
function
|
|
2734
|
-
const
|
|
2735
|
-
|
|
2736
|
-
for (
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
}
|
|
3018
|
+
function rank(pool, candidates, keys) {
|
|
3019
|
+
const scored = [...candidates].sort((a, b) => compareStrings(a.build.owner, b.build.owner)).map((c) => ({ c, k: keys.map((key) => key(c)) }));
|
|
3020
|
+
scored.sort((a, b) => {
|
|
3021
|
+
for (let i = 0; i < keys.length; i++) {
|
|
3022
|
+
const d = b.k[i] - a.k[i];
|
|
3023
|
+
if (d !== 0) return d;
|
|
2740
3024
|
}
|
|
2741
|
-
|
|
2742
|
-
return arrival;
|
|
2743
|
-
}
|
|
2744
|
-
function sharedTagPerSpecifier(members, islanded) {
|
|
2745
|
-
const shared = /* @__PURE__ */ new Map();
|
|
2746
|
-
forEachGlobalClaim(members, islanded, (specifier, tag) => {
|
|
2747
|
-
if (!shared.has(specifier)) shared.set(specifier, tag);
|
|
3025
|
+
return newer(pool, b.c.build, a.c.build) || compareStrings(a.c.build.owner, b.c.build.owner);
|
|
2748
3026
|
});
|
|
2749
|
-
return
|
|
3027
|
+
return scored[0]?.c;
|
|
2750
3028
|
}
|
|
2751
|
-
function
|
|
2752
|
-
const
|
|
2753
|
-
const
|
|
2754
|
-
|
|
2755
|
-
const
|
|
2756
|
-
const
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
3029
|
+
function roundOne(pool, hostRemote) {
|
|
3030
|
+
const { remotes } = pool;
|
|
3031
|
+
const scored = /* @__PURE__ */ new Map();
|
|
3032
|
+
const round1 = (hostRemote ? [hostRemote] : remotes).map((owner) => {
|
|
3033
|
+
const build = pool.builds.get(owner);
|
|
3034
|
+
const key = JSON.stringify([[...build.tags], [...build.tagByMember]]);
|
|
3035
|
+
let score = scored.get(key);
|
|
3036
|
+
if (!score) {
|
|
3037
|
+
const served = new Set(remotes.filter((r) => pool.servesAt(r, build.tags)));
|
|
3038
|
+
const agreeing = remotes.filter((r) => !served.has(r) && pool.agreesAt(r, build.tags)).length;
|
|
3039
|
+
scored.set(key, score = { served: [...served], agreeing });
|
|
2760
3040
|
}
|
|
2761
|
-
|
|
3041
|
+
return { build, ...score };
|
|
3042
|
+
});
|
|
3043
|
+
const newerThan = (c) => round1.filter((o) => newer(pool, c.build, o.build) > 0).length;
|
|
3044
|
+
const round1Winner = rank(pool, round1, [
|
|
3045
|
+
...pool.latestFirst ? [newerThan] : [],
|
|
3046
|
+
(c) => c.served.length,
|
|
3047
|
+
(c) => c.agreeing,
|
|
3048
|
+
(c) => c.build.owner === pool.previousWinner ? 1 : 0
|
|
3049
|
+
]);
|
|
3050
|
+
const winner = round1Winner.build.owner;
|
|
3051
|
+
const globalTags = new SpecifierTags(pool.packageOf, round1Winner.build.tags);
|
|
3052
|
+
const globalRemotes = /* @__PURE__ */ new Set([winner, ...round1Winner.served]);
|
|
3053
|
+
const pending = remotes.filter((r) => !globalRemotes.has(r));
|
|
3054
|
+
return { winner, globalTags, globalRemotes, extensions: /* @__PURE__ */ new Set(), subpools: [], pending };
|
|
2762
3055
|
}
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
}
|
|
3056
|
+
function formSubpools(pool, state) {
|
|
3057
|
+
const servable = new Map(
|
|
3058
|
+
state.pending.map((owner) => {
|
|
3059
|
+
const build = pool.builds.get(owner);
|
|
3060
|
+
const served = state.pending.filter((r) => pool.servesAt(r, build.tags));
|
|
3061
|
+
return [owner, { build, served }];
|
|
3062
|
+
})
|
|
3063
|
+
);
|
|
3064
|
+
for (; ; ) {
|
|
3065
|
+
const stillPending = new Set(state.pending);
|
|
3066
|
+
const candidates = state.pending.map((owner) => {
|
|
3067
|
+
const { build, served } = servable.get(owner);
|
|
3068
|
+
return { build, served: served.filter((r) => stillPending.has(r)) };
|
|
3069
|
+
}).filter((c) => c.served.includes(c.build.owner) && c.served.length >= 2);
|
|
3070
|
+
const best = rank(pool, candidates, [(c) => c.served.length]);
|
|
3071
|
+
if (!best) break;
|
|
3072
|
+
state.subpools.push({ owner: best.build.owner, remotes: best.served });
|
|
3073
|
+
state.pending = state.pending.filter((r) => !best.served.includes(r));
|
|
2782
3074
|
}
|
|
2783
|
-
return table;
|
|
2784
3075
|
}
|
|
2785
|
-
function
|
|
2786
|
-
|
|
2787
|
-
|
|
3076
|
+
function promote(pool, state) {
|
|
3077
|
+
const { globalTags, globalRemotes } = state;
|
|
3078
|
+
const takesGlobal = (remote) => pool.servesAt(remote, globalTags) && unwitnessedGap(pool.shipped.get(remote), globalTags, pool.builds.values()) === void 0;
|
|
3079
|
+
for (const remote of state.pending) if (takesGlobal(remote)) globalRemotes.add(remote);
|
|
3080
|
+
state.pending = state.pending.filter((r) => !globalRemotes.has(r));
|
|
3081
|
+
for (const subpool of state.subpools) {
|
|
3082
|
+
const moved = subpool.remotes.filter((r) => r !== subpool.owner && takesGlobal(r));
|
|
3083
|
+
for (const remote of moved) globalRemotes.add(remote);
|
|
3084
|
+
subpool.remotes = subpool.remotes.filter((r) => !moved.includes(r));
|
|
3085
|
+
}
|
|
3086
|
+
state.subpools = state.subpools.filter((subpool) => {
|
|
3087
|
+
if (subpool.remotes.length >= 2) return true;
|
|
3088
|
+
if (takesGlobal(subpool.owner)) globalRemotes.add(subpool.owner);
|
|
3089
|
+
else state.pending.push(subpool.owner);
|
|
3090
|
+
return false;
|
|
3091
|
+
});
|
|
2788
3092
|
}
|
|
2789
|
-
function
|
|
2790
|
-
const
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
3093
|
+
function addExtensions(pool, state) {
|
|
3094
|
+
const { globalTags, globalRemotes } = state;
|
|
3095
|
+
const runsOn = (remote) => state.subpools.find((p) => p.remotes.includes(remote))?.owner ?? remote;
|
|
3096
|
+
const agreeing = pool.remotes.filter((r) => !globalRemotes.has(r) && pool.agreesAt(r, globalTags));
|
|
3097
|
+
const runsGlobally = (remote) => pool.agreesAt(runsOn(remote), globalTags);
|
|
3098
|
+
const offered = offers(pool, globalTags, agreeing.filter(runsGlobally));
|
|
3099
|
+
const fill = pool.builds.get(state.winner).host ? agreeing.filter((r) => !runsGlobally(r)) : [];
|
|
3100
|
+
for (const [pkg, offer] of offers(pool, globalTags, fill))
|
|
3101
|
+
if (!offered.has(pkg)) offered.set(pkg, offer);
|
|
3102
|
+
for (const [pkg, offer] of offered) {
|
|
3103
|
+
if (!offer) continue;
|
|
3104
|
+
state.extensions.add(pkg);
|
|
3105
|
+
for (const s of offer.specifiers) globalTags.set(s, offer.tag);
|
|
2796
3106
|
}
|
|
2797
|
-
return true;
|
|
2798
3107
|
}
|
|
2799
|
-
function
|
|
2800
|
-
const
|
|
2801
|
-
for (const
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
if (
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
}
|
|
3108
|
+
function packageCopies(owner, copies, packageOf) {
|
|
3109
|
+
const packages = /* @__PURE__ */ new Map();
|
|
3110
|
+
for (const copy of copies)
|
|
3111
|
+
for (const s of copy.specifiers) {
|
|
3112
|
+
const pkg = packageOf(s);
|
|
3113
|
+
const seen = packages.get(pkg);
|
|
3114
|
+
if (seen === void 0) packages.set(pkg, { owner, tag: copy.tag, specifiers: /* @__PURE__ */ new Set([s]) });
|
|
3115
|
+
else if (seen && seen.tag !== copy.tag) packages.set(pkg, null);
|
|
3116
|
+
else seen?.specifiers.add(s);
|
|
2809
3117
|
}
|
|
2810
|
-
|
|
2811
|
-
}
|
|
2812
|
-
return false;
|
|
3118
|
+
return packages;
|
|
2813
3119
|
}
|
|
2814
|
-
function
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
count++;
|
|
2825
|
-
missing ??= specifier;
|
|
2826
|
-
}
|
|
2827
|
-
if (count >= fewest) continue;
|
|
2828
|
-
fewest = count;
|
|
2829
|
-
closest = build;
|
|
2830
|
-
gap = missing ?? rejectedMember(view.instance, remote, wants, pool.acceptance) ?? gap;
|
|
2831
|
-
}
|
|
2832
|
-
return { gap, closest };
|
|
3120
|
+
function offers(pool, globalTags, remotes) {
|
|
3121
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
3122
|
+
for (const owner of remotes)
|
|
3123
|
+
for (const [pkg, copy] of pool.packages.get(owner))
|
|
3124
|
+
if (globalTags.pinnedTag(pkg) === void 0)
|
|
3125
|
+
candidates.set(pkg, [...candidates.get(pkg) ?? [], copy]);
|
|
3126
|
+
const offered = /* @__PURE__ */ new Map();
|
|
3127
|
+
for (const [pkg, copies] of candidates)
|
|
3128
|
+
offered.set(pkg, oneTag(copies) ? coveringCopy(copies) : null);
|
|
3129
|
+
return offered;
|
|
2833
3130
|
}
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
3131
|
+
var oneTag = (copies) => copies.every((c) => c !== null && c.tag === copies[0].tag);
|
|
3132
|
+
function coveringCopy(candidates) {
|
|
3133
|
+
const scored = candidates.map((c) => ({
|
|
3134
|
+
c,
|
|
3135
|
+
covers: candidates.filter((o) => contains(c.specifiers, o.specifiers)).length
|
|
3136
|
+
}));
|
|
3137
|
+
scored.sort(
|
|
3138
|
+
(a, b) => b.covers - a.covers || b.c.specifiers.size - a.c.specifiers.size || compareStrings(a.c.owner, b.c.owner)
|
|
3139
|
+
);
|
|
3140
|
+
return scored[0].c;
|
|
2843
3141
|
}
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
const
|
|
2847
|
-
|
|
2848
|
-
const candidates = [...builds.keys()].sort(byPriority);
|
|
2849
|
-
const pending = new Set([...consumedMembers2.keys()].sort(byPriority));
|
|
2850
|
-
const anchored = /* @__PURE__ */ new Set();
|
|
2851
|
-
const canServe = (candidate, consumer) => {
|
|
2852
|
-
const build = builds.get(candidate);
|
|
2853
|
-
if (!covers(build.coverage, input.consumedSpecifiers.get(consumer) ?? [])) return false;
|
|
2854
|
-
return acceptsAll(acceptance, build.instance, consumer, consumedMembers2.get(consumer) ?? []);
|
|
2855
|
-
};
|
|
2856
|
-
const electAnchor = (anchor, served) => {
|
|
2857
|
-
pending.delete(anchor);
|
|
2858
|
-
assignment.set(anchor, void 0);
|
|
2859
|
-
for (const consumer of served) {
|
|
2860
|
-
pending.delete(consumer);
|
|
2861
|
-
anchored.add(consumer);
|
|
2862
|
-
assignment.set(consumer, anchor);
|
|
2863
|
-
}
|
|
2864
|
-
};
|
|
2865
|
-
for (const host of [...hosts].sort(byPriority)) {
|
|
2866
|
-
const served = [];
|
|
2867
|
-
if (builds.has(host)) {
|
|
2868
|
-
for (const consumer of pending) {
|
|
2869
|
-
if (consumer !== host && canServe(host, consumer)) served.push(consumer);
|
|
2870
|
-
}
|
|
2871
|
-
}
|
|
2872
|
-
electAnchor(host, served);
|
|
2873
|
-
}
|
|
3142
|
+
var contains = (a, b) => [...b].every((s) => a.has(s));
|
|
3143
|
+
function settle(pool, state) {
|
|
3144
|
+
const { globalTags, globalRemotes, extensions } = state;
|
|
3145
|
+
let demoted = false;
|
|
2874
3146
|
for (; ; ) {
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
for (const
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
3147
|
+
const dropped = new Set([...extensions].filter((pkg) => !publishedWhole(pool, state, pkg)));
|
|
3148
|
+
if (dropped.size === 0) return demoted;
|
|
3149
|
+
for (const pkg of dropped) extensions.delete(pkg);
|
|
3150
|
+
const kept = [...globalTags].filter(([s]) => !dropped.has(pool.packageOf(s)));
|
|
3151
|
+
globalTags.clear();
|
|
3152
|
+
for (const [s, tag] of kept) globalTags.set(s, tag);
|
|
3153
|
+
for (const remote of globalRemotes)
|
|
3154
|
+
if (remote !== state.winner && !pool.servesAt(remote, globalTags)) {
|
|
3155
|
+
globalRemotes.delete(remote);
|
|
3156
|
+
const subpool = state.subpools.find(
|
|
3157
|
+
(p) => pool.servesAt(remote, pool.builds.get(p.owner).tags)
|
|
3158
|
+
);
|
|
3159
|
+
if (subpool) subpool.remotes.push(remote);
|
|
3160
|
+
else state.pending.push(remote);
|
|
3161
|
+
demoted = true;
|
|
2886
3162
|
}
|
|
2887
|
-
}
|
|
2888
|
-
if (best === void 0) break;
|
|
2889
|
-
electAnchor(best, bestServed);
|
|
2890
3163
|
}
|
|
2891
|
-
for (const consumer of pending) assignment.set(consumer, void 0);
|
|
2892
|
-
return assignment;
|
|
2893
3164
|
}
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
parent[x] = parent[parent[x]];
|
|
2913
|
-
x = parent[x];
|
|
2914
|
-
}
|
|
2915
|
-
return x;
|
|
2916
|
-
};
|
|
2917
|
-
return {
|
|
2918
|
-
union(a, b) {
|
|
2919
|
-
let rootA = findRoot(intern(a));
|
|
2920
|
-
let rootB = findRoot(intern(b));
|
|
2921
|
-
if (rootA === rootB) return;
|
|
2922
|
-
if (size[rootA] < size[rootB]) [rootA, rootB] = [rootB, rootA];
|
|
2923
|
-
parent[rootB] = rootA;
|
|
2924
|
-
size[rootA] = size[rootA] + size[rootB];
|
|
2925
|
-
},
|
|
2926
|
-
// Interns the key if unseen — an isolated key is its own component.
|
|
2927
|
-
component(key) {
|
|
2928
|
-
return findRoot(intern(key));
|
|
3165
|
+
function publishedWhole(pool, state, pkg) {
|
|
3166
|
+
const published = new Set([...state.globalTags.keys()].filter((s) => pool.packageOf(s) === pkg));
|
|
3167
|
+
const tag = state.globalTags.pinnedTag(pkg);
|
|
3168
|
+
return [...state.globalRemotes].some((remote) => {
|
|
3169
|
+
const copy = pool.packages.get(remote).get(pkg);
|
|
3170
|
+
return !!copy && copy.tag === tag && copy.specifiers.size === published.size && contains(copy.specifiers, published);
|
|
3171
|
+
});
|
|
3172
|
+
}
|
|
3173
|
+
function missOf(pool, state, remote) {
|
|
3174
|
+
const { globalTags } = state;
|
|
3175
|
+
const copies = pool.shipped.get(remote);
|
|
3176
|
+
let rejected;
|
|
3177
|
+
for (const copy of copies)
|
|
3178
|
+
for (const s of copy.specifiers) {
|
|
3179
|
+
const tag = globalTags.get(s);
|
|
3180
|
+
if (tag === void 0 || pool.acceptsTag(tag, copy.tag, copy.requiredVersion)) continue;
|
|
3181
|
+
if (copy.strict) return { cause: "incompatible", member: copy.member, tag, strict: true };
|
|
3182
|
+
rejected ??= { cause: "incompatible", member: copy.member, tag, strict: false };
|
|
2929
3183
|
}
|
|
2930
|
-
|
|
3184
|
+
if (rejected) return rejected;
|
|
3185
|
+
for (const copy of copies)
|
|
3186
|
+
for (const s of copy.specifiers) if (!globalTags.has(s)) return { cause: "uncovered", gap: s };
|
|
3187
|
+
const gap = unwitnessedGap(copies, globalTags, pool.builds.values());
|
|
3188
|
+
if (gap) return { cause: "uncovered", gap, unshipped: true };
|
|
3189
|
+
if (state.subpools.some((p) => p.owner === remote)) return void 0;
|
|
3190
|
+
throw new Error(`'${remote}' missed the global map with nothing it rejects or lacks.`);
|
|
3191
|
+
}
|
|
3192
|
+
function previousWinner(members) {
|
|
3193
|
+
const winners = new Set(members.flatMap((m) => m.external.poolWinner ?? []));
|
|
3194
|
+
const [winner] = winners;
|
|
3195
|
+
if (winners.size !== 1) return void 0;
|
|
3196
|
+
const ships = members.some(
|
|
3197
|
+
(m) => m.external.versions.some((v) => v.remotes.some((r) => r.name === winner))
|
|
3198
|
+
);
|
|
3199
|
+
return ships ? winner : void 0;
|
|
3200
|
+
}
|
|
3201
|
+
function placeRemotes(globalRemotes, subpools, self, missOf2) {
|
|
3202
|
+
const misses = /* @__PURE__ */ new Map();
|
|
3203
|
+
for (const remote of [...subpools.flatMap((p) => p.remotes), ...self])
|
|
3204
|
+
misses.set(remote, missOf2(remote));
|
|
3205
|
+
const placements = /* @__PURE__ */ new Map();
|
|
3206
|
+
for (const remote of globalRemotes) placements.set(remote, { kind: "global" });
|
|
3207
|
+
for (const { owner, remotes } of subpools)
|
|
3208
|
+
for (const remote of remotes) placements.set(remote, { kind: "subpool", owner });
|
|
3209
|
+
for (const remote of self)
|
|
3210
|
+
placements.set(remote, { kind: "self", cause: misses.get(remote).cause });
|
|
3211
|
+
return { placements, misses };
|
|
2931
3212
|
}
|
|
3213
|
+
|
|
3214
|
+
// src/lib/core/1.domain/pooling/membership.ts
|
|
2932
3215
|
var extNode = (name) => `ext\0${name}`;
|
|
2933
|
-
var
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
for (
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
3216
|
+
var labelNode = (label) => `label\0${label}`;
|
|
3217
|
+
var labelOf = (pool) => pool?.trim() || void 0;
|
|
3218
|
+
function labelsIn(sharedExternals) {
|
|
3219
|
+
const labelsOf = /* @__PURE__ */ new Map();
|
|
3220
|
+
for (const [name, external] of Object.entries(sharedExternals))
|
|
3221
|
+
labelsOf.set(
|
|
3222
|
+
name,
|
|
3223
|
+
external.versions.flatMap((v) => v.remotes.flatMap((r) => labelOf(r.pool) ?? []))
|
|
3224
|
+
);
|
|
3225
|
+
return labelsOf;
|
|
2942
3226
|
}
|
|
2943
|
-
function
|
|
2944
|
-
const
|
|
2945
|
-
const
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
}
|
|
2951
|
-
}
|
|
2952
|
-
const declared = new Set(candidates.map((c) => c.name));
|
|
2953
|
-
for (const candidate of candidates) {
|
|
2954
|
-
const owner = owningPackage(candidate.name);
|
|
2955
|
-
if (owner !== void 0 && declared.has(owner))
|
|
2956
|
-
dsu.union(extNode(candidate.name), extNode(owner));
|
|
3227
|
+
function labelledComponents(labelsOf, packageOf) {
|
|
3228
|
+
const { find, union } = unionFind();
|
|
3229
|
+
for (const [name, labels] of labelsOf)
|
|
3230
|
+
for (const label of labels) union(extNode(name), labelNode(label));
|
|
3231
|
+
for (const name of labelsOf.keys()) {
|
|
3232
|
+
const owner = packageOf(name);
|
|
3233
|
+
if (owner !== name) union(extNode(name), extNode(owner));
|
|
2957
3234
|
}
|
|
2958
3235
|
const byComponent = /* @__PURE__ */ new Map();
|
|
2959
|
-
for (const
|
|
2960
|
-
const root =
|
|
2961
|
-
const
|
|
2962
|
-
|
|
2963
|
-
}
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
3236
|
+
for (const name of labelsOf.keys()) {
|
|
3237
|
+
const root = find(extNode(name));
|
|
3238
|
+
const names = byComponent.get(root) ?? byComponent.set(root, []).get(root);
|
|
3239
|
+
names.push(name);
|
|
3240
|
+
}
|
|
3241
|
+
return [...byComponent.values()].filter((names) => names.some((n) => labelsOf.get(n).length > 0));
|
|
3242
|
+
}
|
|
3243
|
+
function buildPools(sharedExternals, packageOf = packageOfIn(sharedExternals)) {
|
|
3244
|
+
const labelsOf = labelsIn(sharedExternals);
|
|
3245
|
+
const pools = /* @__PURE__ */ new Map();
|
|
3246
|
+
const labelledAlone = [];
|
|
3247
|
+
for (const names of labelledComponents(labelsOf, packageOf)) {
|
|
3248
|
+
if (names.length < 2) labelledAlone.push(names[0]);
|
|
3249
|
+
else {
|
|
3250
|
+
const members = names.map((name) => ({ name, external: sharedExternals[name] }));
|
|
3251
|
+
pools.set(
|
|
3252
|
+
mostDeclaredLabel(members, labelsOf),
|
|
3253
|
+
members.sort((a, b) => compareStrings(a.name, b.name))
|
|
3254
|
+
);
|
|
2977
3255
|
}
|
|
2978
|
-
pools.push(members);
|
|
2979
|
-
}
|
|
2980
|
-
pools.sort((a, b) => a[0].name.localeCompare(b[0].name));
|
|
2981
|
-
const named = /* @__PURE__ */ new Map();
|
|
2982
|
-
for (const members of pools) {
|
|
2983
|
-
const label = mostDeclaredTag(members) ?? members[0].name;
|
|
2984
|
-
let name = label;
|
|
2985
|
-
for (let n = 2; named.has(name); n++) name = `${label}~${n}`;
|
|
2986
|
-
named.set(
|
|
2987
|
-
name,
|
|
2988
|
-
members.map((m) => m.value)
|
|
2989
|
-
);
|
|
2990
3256
|
}
|
|
2991
|
-
return
|
|
3257
|
+
return { pools, labelledAlone, packageOf };
|
|
3258
|
+
}
|
|
3259
|
+
function pooledPackagesWith(sharedExternals, copies, packageOf) {
|
|
3260
|
+
const labelsOf = labelsIn(sharedExternals);
|
|
3261
|
+
for (const { name, pool } of copies) {
|
|
3262
|
+
const labels = labelsOf.get(name) ?? [];
|
|
3263
|
+
const label = labelOf(pool);
|
|
3264
|
+
labelsOf.set(name, label === void 0 ? labels : [...labels, label]);
|
|
3265
|
+
}
|
|
3266
|
+
return new Set(
|
|
3267
|
+
labelledComponents(labelsOf, packageOf).filter((names) => names.length > 1).flatMap((names) => names.map(packageOf))
|
|
3268
|
+
);
|
|
2992
3269
|
}
|
|
2993
|
-
function
|
|
3270
|
+
function mostDeclaredLabel(members, labelsOf) {
|
|
2994
3271
|
const counts = /* @__PURE__ */ new Map();
|
|
2995
3272
|
for (const member of members)
|
|
2996
|
-
for (const
|
|
2997
|
-
let best;
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
if (count > top || count === top &&
|
|
3001
|
-
|
|
3273
|
+
for (const label of labelsOf.get(member.name)) counts.set(label, (counts.get(label) ?? 0) + 1);
|
|
3274
|
+
let best = "";
|
|
3275
|
+
let top = 0;
|
|
3276
|
+
for (const [label, count] of counts)
|
|
3277
|
+
if (count > top || count === top && compareStrings(label, best) < 0)
|
|
3278
|
+
[best, top] = [label, count];
|
|
3002
3279
|
return best;
|
|
3003
3280
|
}
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
const tag = r.pool?.trim();
|
|
3011
|
-
return tag ? [{ remote: r.name, tag }] : [];
|
|
3012
|
-
})
|
|
3013
|
-
),
|
|
3014
|
-
value: { name, external }
|
|
3015
|
-
})
|
|
3281
|
+
|
|
3282
|
+
// src/lib/core/1.domain/pooling/pool-state.ts
|
|
3283
|
+
function hasPoolResults(external) {
|
|
3284
|
+
if (external.poolName !== void 0 || external.poolWinner !== void 0) return true;
|
|
3285
|
+
return external.versions.some(
|
|
3286
|
+
(v) => v.remotes.some((r) => r.servedBy !== void 0 || r.poolCause !== void 0)
|
|
3016
3287
|
);
|
|
3017
|
-
|
|
3288
|
+
}
|
|
3289
|
+
function scopeHasPoolState(scope) {
|
|
3290
|
+
for (const name in scope) {
|
|
3291
|
+
const external = scope[name];
|
|
3292
|
+
if (hasPoolResults(external)) return true;
|
|
3293
|
+
for (const version of external.versions)
|
|
3294
|
+
for (const remote of version.remotes) if (remote.pool?.trim()) return true;
|
|
3295
|
+
}
|
|
3296
|
+
return false;
|
|
3018
3297
|
}
|
|
3019
3298
|
|
|
3020
|
-
// src/lib/core/
|
|
3021
|
-
function
|
|
3022
|
-
|
|
3023
|
-
|
|
3299
|
+
// src/lib/core/1.domain/pooling/records.ts
|
|
3300
|
+
function memberRecord(member, pool, compare) {
|
|
3301
|
+
const { globalTags, placements } = pool;
|
|
3302
|
+
let sharedTag = globalTags.get(member.name);
|
|
3303
|
+
for (const version of member.external.versions)
|
|
3304
|
+
for (const meta of version.remotes)
|
|
3305
|
+
for (const s in meta.entries) sharedTag ??= globalTags.get(s);
|
|
3306
|
+
const claimsGlobally = (name) => placements.get(name).kind === "global";
|
|
3307
|
+
const placed = [];
|
|
3308
|
+
let winnerRow;
|
|
3309
|
+
const place = (tag, action, meta) => {
|
|
3310
|
+
const row = { tag, host: false, action, remotes: [meta] };
|
|
3311
|
+
placed.push(row);
|
|
3312
|
+
if (meta.name !== pool.winner) return;
|
|
3313
|
+
winnerRow = row;
|
|
3314
|
+
row.host = pool.winnerIsHost;
|
|
3315
|
+
};
|
|
3316
|
+
for (const version of member.external.versions)
|
|
3317
|
+
for (const stored of version.remotes) {
|
|
3318
|
+
const { servedBy: _servedBy, poolCause: _poolCause, ...rest } = stored;
|
|
3319
|
+
const meta = { ...rest, cached: false };
|
|
3320
|
+
const placement = placements.get(meta.name);
|
|
3321
|
+
if (placement.kind === "global")
|
|
3322
|
+
place(version.tag, version.tag === sharedTag ? "share" : "skip", meta);
|
|
3323
|
+
else if (placement.kind === "subpool")
|
|
3324
|
+
place(version.tag, "skip", { ...meta, servedBy: placement.owner });
|
|
3325
|
+
else place(version.tag, "scope", { ...meta, poolCause: placement.cause });
|
|
3326
|
+
}
|
|
3327
|
+
const rows = mergeRows(placed, winnerRow);
|
|
3328
|
+
for (const row of rows)
|
|
3329
|
+
row.remotes.sort((a, b) => Number(!claimsGlobally(a.name)) - Number(!claimsGlobally(b.name)));
|
|
3330
|
+
const order = { share: 0, skip: 1, scope: 2 };
|
|
3331
|
+
const newest = byTag(compare);
|
|
3332
|
+
const versions = rows.sort((a, b) => newest(a, b) || order[a.action] - order[b.action]);
|
|
3333
|
+
return { dirty: false, poolName: pool.poolName, versions };
|
|
3024
3334
|
}
|
|
3025
|
-
function
|
|
3026
|
-
return
|
|
3027
|
-
...new Set(members.flatMap((m) => m.external.versions.flatMap((v) => v.remotes.map((r) => r.name))))
|
|
3028
|
-
];
|
|
3335
|
+
function movedRecord(external, remote, move, compare) {
|
|
3336
|
+
return withoutStaleServingBuild(moveCopy(external, remote, move, compare));
|
|
3029
3337
|
}
|
|
3030
|
-
function
|
|
3031
|
-
|
|
3338
|
+
function withoutStaleServingBuild(record) {
|
|
3339
|
+
const { servingBuild, ...rest } = record;
|
|
3340
|
+
if (servingBuild === void 0) return record;
|
|
3341
|
+
const shares = record.versions.some(
|
|
3342
|
+
(v) => v.action === "share" && v.remotes.some((r) => r.name === servingBuild)
|
|
3343
|
+
);
|
|
3344
|
+
return shares ? record : rest;
|
|
3032
3345
|
}
|
|
3033
|
-
function
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
const
|
|
3038
|
-
if (
|
|
3039
|
-
|
|
3040
|
-
const {
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
}
|
|
3346
|
+
function moveCopy(external, remote, move, compare) {
|
|
3347
|
+
if ("fromMap" in move) return recordFromMap(external, remote);
|
|
3348
|
+
const moved = [];
|
|
3349
|
+
const versions = external.versions.map((v) => {
|
|
3350
|
+
const copy = v.remotes.find((r) => r.name === remote);
|
|
3351
|
+
if (!copy) return v;
|
|
3352
|
+
const { servedBy: _servedBy, ...rest } = copy;
|
|
3353
|
+
const meta = { ...rest, cached: true, poolCause: move.cause };
|
|
3354
|
+
if (v.action === "scope")
|
|
3355
|
+
return { ...v, remotes: v.remotes.map((r) => r === copy ? meta : r) };
|
|
3356
|
+
moved.push({ tag: v.tag, meta });
|
|
3357
|
+
return { ...v, remotes: v.remotes.filter((r) => r !== copy) };
|
|
3358
|
+
}).filter((v) => v.remotes.length > 0);
|
|
3359
|
+
for (const { tag, meta } of moved) {
|
|
3360
|
+
const scoped = rowAt(versions, tag, "scope");
|
|
3361
|
+
if (!scoped) versions.push({ tag, action: "scope", host: false, remotes: [meta] });
|
|
3362
|
+
else versions[versions.indexOf(scoped)] = { ...scoped, remotes: [...scoped.remotes, meta] };
|
|
3363
|
+
}
|
|
3364
|
+
return { ...external, versions: versions.sort(byTag(compare)) };
|
|
3053
3365
|
}
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
return islanded;
|
|
3366
|
+
function recordFromMap(external, remote) {
|
|
3367
|
+
const opened = external.versions.find(
|
|
3368
|
+
(v) => v.action !== "skip" && v.remotes.some((r) => r.name === remote)
|
|
3369
|
+
);
|
|
3370
|
+
const meta = { ...opened.remotes.find((r) => r.name === remote), cached: false };
|
|
3371
|
+
const joined = rowAt(external.versions, opened.tag, "skip");
|
|
3372
|
+
const into = joined ? { ...joined, remotes: [...joined.remotes] } : { ...opened, action: "skip", remotes: [] };
|
|
3373
|
+
addRemoteToVersion(into, meta);
|
|
3374
|
+
const versions = external.versions.flatMap((v) => {
|
|
3375
|
+
if (v === joined) return [into];
|
|
3376
|
+
if (v !== opened) return [v];
|
|
3377
|
+
const left = { ...v, remotes: v.remotes.filter((r) => r.name !== remote) };
|
|
3378
|
+
return [...left.remotes.length > 0 ? [left] : [], ...joined ? [] : [into]];
|
|
3379
|
+
});
|
|
3380
|
+
return { ...external, versions };
|
|
3070
3381
|
}
|
|
3071
|
-
|
|
3072
|
-
const
|
|
3073
|
-
return
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
if (basis.get(name) !== build) byMember.set(name, build);
|
|
3081
|
-
}
|
|
3082
|
-
if (byMember.size > 0) served.set(remote, byMember);
|
|
3083
|
-
}
|
|
3084
|
-
return served;
|
|
3382
|
+
function withoutPoolResults(external) {
|
|
3383
|
+
const { poolName: _poolName, poolWinner: _poolWinner, ...rest } = external;
|
|
3384
|
+
return {
|
|
3385
|
+
...rest,
|
|
3386
|
+
versions: external.versions.map((v) => ({
|
|
3387
|
+
...v,
|
|
3388
|
+
remotes: v.remotes.map(({ servedBy: _servedBy, poolCause: _poolCause, ...meta }) => meta)
|
|
3389
|
+
}))
|
|
3390
|
+
};
|
|
3085
3391
|
}
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
);
|
|
3091
|
-
|
|
3092
|
-
const { suspect, selfServed } = movedRemotes(members, islanded, basis, served, hosts);
|
|
3093
|
-
if (suspect.size === 0) return [];
|
|
3094
|
-
const builds = liveBuilds(members, islanded);
|
|
3095
|
-
const shared = sharedTagPerSpecifier(members, islanded);
|
|
3096
|
-
const own = ownCopies(members, suspect);
|
|
3097
|
-
const torn = [];
|
|
3098
|
-
for (const remote of suspect) {
|
|
3099
|
-
const copies = own.get(remote) ?? [];
|
|
3100
|
-
const mine = selfServed.get(remote);
|
|
3101
|
-
const anchors = served.get(remote);
|
|
3102
|
-
const ownTags = /* @__PURE__ */ new Map();
|
|
3103
|
-
const resolved = /* @__PURE__ */ new Map();
|
|
3104
|
-
for (const copy of copies) {
|
|
3105
|
-
const from = mine?.has(copy.member) ? remote : anchors?.get(copy.member);
|
|
3106
|
-
for (const specifier in copy.entries) {
|
|
3107
|
-
if (!ownTags.has(specifier)) ownTags.set(specifier, copy.tag);
|
|
3108
|
-
const tag = from === remote ? copy.tag : from !== void 0 ? builds.get(from)?.tags.get(specifier) : shared.get(specifier);
|
|
3109
|
-
if (tag !== void 0 && !resolved.has(specifier)) resolved.set(specifier, tag);
|
|
3110
|
-
}
|
|
3111
|
-
}
|
|
3112
|
-
if (resolved.size === 0) continue;
|
|
3113
|
-
if (ships(ownTags, resolved)) continue;
|
|
3114
|
-
let witnessed = false;
|
|
3115
|
-
for (const [, build] of builds) {
|
|
3116
|
-
if (ships(build.tags, resolved)) {
|
|
3117
|
-
witnessed = true;
|
|
3118
|
-
break;
|
|
3119
|
-
}
|
|
3120
|
-
}
|
|
3121
|
-
if (!witnessed) {
|
|
3122
|
-
torn.push({
|
|
3123
|
-
remote,
|
|
3124
|
-
combination: [...resolved].map(([specifier, tag]) => `${specifier}@${tag}`).join(", ")
|
|
3125
|
-
});
|
|
3126
|
-
}
|
|
3127
|
-
}
|
|
3128
|
-
return torn;
|
|
3392
|
+
function renamedRecords(scope, pools) {
|
|
3393
|
+
const renamed = [];
|
|
3394
|
+
for (const [poolName, members] of pools)
|
|
3395
|
+
for (const { name } of members)
|
|
3396
|
+
if (scope[name].poolName !== poolName) renamed.push([name, { ...scope[name], poolName }]);
|
|
3397
|
+
return renamed;
|
|
3129
3398
|
}
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
};
|
|
3135
|
-
|
|
3136
|
-
const
|
|
3137
|
-
const
|
|
3138
|
-
const
|
|
3139
|
-
if (!
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
for (const member of members) {
|
|
3143
|
-
const unpublished = !basis.has(member.name);
|
|
3144
|
-
for (const version of member.external.versions) {
|
|
3145
|
-
const scoped = version.action === "scope";
|
|
3146
|
-
if (!unpublished && !scoped) continue;
|
|
3147
|
-
for (const meta of version.remotes) {
|
|
3148
|
-
add(meta.name);
|
|
3149
|
-
const servesItself = scoped || unpublished && served.get(meta.name)?.get(member.name) === void 0;
|
|
3150
|
-
if (!servesItself) continue;
|
|
3151
|
-
let mine = selfServed.get(meta.name);
|
|
3152
|
-
if (!mine) selfServed.set(meta.name, mine = /* @__PURE__ */ new Set());
|
|
3153
|
-
mine.add(member.name);
|
|
3154
|
-
}
|
|
3155
|
-
}
|
|
3156
|
-
}
|
|
3157
|
-
return { suspect, selfServed };
|
|
3399
|
+
|
|
3400
|
+
// src/lib/core/1.domain/pooling/plan.ts
|
|
3401
|
+
function planElection(scope, poolable) {
|
|
3402
|
+
if (!poolable || !Object.values(scope).some((external) => external.dirty) || !scopeHasPoolState(scope))
|
|
3403
|
+
return { pools: /* @__PURE__ */ new Map(), stripped: /* @__PURE__ */ new Map(), labelledAlone: [], packageOf: npmPackageOf };
|
|
3404
|
+
const { pools, labelledAlone, packageOf } = buildPools(scope);
|
|
3405
|
+
const pooled = new Set([...pools.values()].flatMap((members) => members.map((m) => m.name)));
|
|
3406
|
+
const stripped = /* @__PURE__ */ new Map();
|
|
3407
|
+
for (const [name, external] of Object.entries(scope))
|
|
3408
|
+
if (!pooled.has(name) && hasPoolResults(external))
|
|
3409
|
+
stripped.set(name, { ...withoutPoolResults(external), dirty: true });
|
|
3410
|
+
return { pools, stripped, labelledAlone, packageOf };
|
|
3158
3411
|
}
|
|
3412
|
+
|
|
3413
|
+
// src/lib/core/2.app/steps/pooling/pool-shared-externals.ts
|
|
3159
3414
|
function createPoolSharedExternals(config, ports) {
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
const sharedExternals =
|
|
3415
|
+
const { compare } = ports.versionCheck;
|
|
3416
|
+
return () => {
|
|
3417
|
+
const repo = ports.sharedExternalsRepo;
|
|
3418
|
+
for (const scope of repo.getScopes()) {
|
|
3419
|
+
const sharedExternals = repo.getFromScope(scope);
|
|
3165
3420
|
try {
|
|
3166
|
-
const
|
|
3167
|
-
|
|
3168
|
-
for (const [poolName, members] of pools)
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
syncPoolNames(sharedExternals, pools, ports.sharedExternalsRepo, scope, rebuilt);
|
|
3421
|
+
const plan = planElection(sharedExternals, repo.scopeType(scope) !== "strict");
|
|
3422
|
+
logPlan(plan, sharedExternals, scope);
|
|
3423
|
+
for (const [poolName, members] of plan.pools)
|
|
3424
|
+
for (const [name, record] of poolRecords(poolName, members, plan.packageOf, scope))
|
|
3425
|
+
repo.addOrUpdate(name, record, scope);
|
|
3426
|
+
for (const [name, external] of plan.stripped) repo.addOrUpdate(name, external, scope);
|
|
3173
3427
|
} catch (error) {
|
|
3174
3428
|
if (error instanceof NFError) return Promise.reject(error);
|
|
3175
3429
|
config.log.error(3, `[${scope}] failed to pool shared externals.`, {
|
|
@@ -3183,260 +3437,437 @@ function createPoolSharedExternals(config, ports) {
|
|
|
3183
3437
|
}
|
|
3184
3438
|
return Promise.resolve();
|
|
3185
3439
|
};
|
|
3186
|
-
function
|
|
3187
|
-
if (
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
ports.sharedExternalsRepo.addOrUpdate(
|
|
3194
|
-
member.name,
|
|
3195
|
-
rebuildMember(poolName, member, /* @__PURE__ */ new Map(), /* @__PURE__ */ new Map(), basis2.get(member.name)),
|
|
3196
|
-
scope
|
|
3197
|
-
);
|
|
3198
|
-
return true;
|
|
3199
|
-
}
|
|
3200
|
-
const islanded = islandedRemotes(members);
|
|
3201
|
-
const consumed = consumedMembers(members);
|
|
3202
|
-
const hosts = hostRemotes(members);
|
|
3203
|
-
const views = {
|
|
3204
|
-
consumedSpecifiers: lazy(() => consumedSpecifiers(members)),
|
|
3205
|
-
acceptance: lazy(() => acceptanceTable(members, ports.versionCheck.isCompatible)),
|
|
3206
|
-
arrival: lazy(() => arrivalOrder(members))
|
|
3207
|
-
};
|
|
3208
|
-
config.log.debug(
|
|
3209
|
-
3,
|
|
3210
|
-
`[${scope}][pool:${poolName}] ${members.length} members across ${allRemotes.length} remotes, incompatible={${[...islanded.keys()].join(", ") || "\u2205"}}
|
|
3211
|
-
` + members.map((m) => ` - ${m.name}`).join("\n")
|
|
3212
|
-
);
|
|
3213
|
-
const assign = () => {
|
|
3214
|
-
const serving2 = assignServingBuilds(members, islanded, consumed, hosts, views);
|
|
3215
|
-
const basis2 = basisFor(members, islanded, serving2);
|
|
3216
|
-
return { serving: serving2, basis: basis2, served: servedPerRemote(consumed, serving2, basis2) };
|
|
3217
|
-
};
|
|
3218
|
-
let { serving, basis, served } = assign();
|
|
3219
|
-
if (islanded.size === 0 && serving.size === 0 && !anyVerdictStored(members)) return false;
|
|
3220
|
-
for (; ; ) {
|
|
3221
|
-
const torn = findTornRemotes(members, islanded, basis, served, hosts);
|
|
3222
|
-
if (torn.length === 0) break;
|
|
3223
|
-
for (const { remote, combination } of torn)
|
|
3224
|
-
islanded.set(remote, { kind: "torn", combination });
|
|
3225
|
-
({ serving, basis, served } = assign());
|
|
3440
|
+
function logPlan(plan, sharedExternals, scope) {
|
|
3441
|
+
if (plan.pools.size > 0) {
|
|
3442
|
+
const dirty = Object.values(sharedExternals).filter((external) => external.dirty).length;
|
|
3443
|
+
config.log.debug(
|
|
3444
|
+
3,
|
|
3445
|
+
`[${scope}] re-electing ${plan.pools.size} pool(s): ${dirty} dirty external(s).`
|
|
3446
|
+
);
|
|
3226
3447
|
}
|
|
3227
|
-
|
|
3228
|
-
|
|
3448
|
+
if (plan.stripped.size > 0)
|
|
3449
|
+
config.log.debug(
|
|
3450
|
+
3,
|
|
3451
|
+
`[${scope}] ${plan.stripped.size} external(s) left every pool; cleared their pool state for re-election.`
|
|
3452
|
+
);
|
|
3453
|
+
for (const name of plan.labelledAlone)
|
|
3454
|
+
config.log.debug(
|
|
3455
|
+
3,
|
|
3456
|
+
`[${scope}] '${name}' has a 'pool' label that joins no other external; likely a typo or a missing sibling.`
|
|
3457
|
+
);
|
|
3458
|
+
}
|
|
3459
|
+
function poolRecords(poolName, members, packageOf, scope) {
|
|
3460
|
+
const election = elect({
|
|
3461
|
+
members,
|
|
3462
|
+
packageOf,
|
|
3463
|
+
acceptsTag: createAcceptsTag(ports.versionCheck.isCompatible, compare),
|
|
3464
|
+
compare,
|
|
3465
|
+
previousWinner: previousWinner(members),
|
|
3466
|
+
latestFirst: config.profile.latestSharedExternal
|
|
3467
|
+
});
|
|
3468
|
+
const placed = { ...election, poolName };
|
|
3469
|
+
report(poolName, members, placed, scope);
|
|
3470
|
+
return members.map((m) => [
|
|
3471
|
+
m.name,
|
|
3472
|
+
{ ...memberRecord(m, placed, compare), poolWinner: placed.winner }
|
|
3473
|
+
]);
|
|
3474
|
+
}
|
|
3475
|
+
function report(poolName, members, placed, scope) {
|
|
3476
|
+
const { misses } = placed;
|
|
3477
|
+
const rejecting = [...misses].filter(([, miss]) => miss?.cause === "incompatible" && miss.strict).map(([remote]) => remote);
|
|
3478
|
+
if (config.strict.strictExternalCompatibility && rejecting.length > 0) {
|
|
3229
3479
|
config.log.error(
|
|
3230
3480
|
3,
|
|
3231
|
-
`[${scope}][pool:${poolName}] version-incompatible remotes cannot be pooled: {${
|
|
3481
|
+
`[${scope}][pool:${poolName}] version-incompatible remotes cannot be pooled: {${rejecting.join(", ")}}.`
|
|
3232
3482
|
);
|
|
3233
3483
|
throw new NFError(`Could not pool '${poolName}' in scope ${scope}.`);
|
|
3234
3484
|
}
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
for (; ; ) {
|
|
3248
|
-
const bases = servingBuilds(members, islanded);
|
|
3249
|
-
const distinct = new Set(bases.values());
|
|
3250
|
-
if (distinct.size === 1 && bases.size === members.length) {
|
|
3251
|
-
const sole = [...distinct][0];
|
|
3252
|
-
if (coversWholePool(members, sole, islanded)) return /* @__PURE__ */ new Map();
|
|
3485
|
+
const subpoolSizes = /* @__PURE__ */ new Map();
|
|
3486
|
+
for (const placement of placed.placements.values())
|
|
3487
|
+
if (placement.kind === "subpool")
|
|
3488
|
+
subpoolSizes.set(placement.owner, (subpoolSizes.get(placement.owner) ?? 0) + 1);
|
|
3489
|
+
let shipped;
|
|
3490
|
+
for (const [remote, miss] of misses) {
|
|
3491
|
+
if (miss === void 0) {
|
|
3492
|
+
config.log.warn(
|
|
3493
|
+
3,
|
|
3494
|
+
`[${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.`
|
|
3495
|
+
);
|
|
3496
|
+
continue;
|
|
3253
3497
|
}
|
|
3254
|
-
|
|
3255
|
-
const
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3498
|
+
shipped ??= copiesByRemote(members);
|
|
3499
|
+
const counts = {
|
|
3500
|
+
imports: specifierCount(shipped.get(remote)),
|
|
3501
|
+
subpoolSize: subpoolSizes.get(remote) ?? 0
|
|
3502
|
+
};
|
|
3503
|
+
config.log.warn(
|
|
3504
|
+
3,
|
|
3505
|
+
`[${scope}][pool:${poolName}] ${missWarning(remote, miss, placed, counts)}`
|
|
3506
|
+
);
|
|
3507
|
+
}
|
|
3508
|
+
}
|
|
3509
|
+
}
|
|
3510
|
+
function missWarning(remote, miss, placed, counts) {
|
|
3511
|
+
const { imports, subpoolSize } = counts;
|
|
3512
|
+
const placement = placed.placements.get(remote);
|
|
3513
|
+
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.`;
|
|
3514
|
+
if (miss.cause === "incompatible")
|
|
3515
|
+
return `'${remote}' is islanded: its range rejects '${miss.member}@${miss.tag}' of the elected build '${placed.winner}'. ${where}`;
|
|
3516
|
+
if (miss.unshipped)
|
|
3517
|
+
return `'${remote}' serves its own family: no build shipped its entrypoints together at the elected versions (gap '${miss.gap}', closest '${placed.winner}'). ${where}`;
|
|
3518
|
+
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}`;
|
|
3519
|
+
}
|
|
3520
|
+
|
|
3521
|
+
// src/lib/core/1.domain/externals/serving.ts
|
|
3522
|
+
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);
|
|
3523
|
+
var packagesOf = (scope) => groupByPackage(Object.keys(scope), (name) => name, packageOfIn(scope));
|
|
3524
|
+
var isPooled = (externals) => externals.some(([, e]) => e.poolName !== void 0);
|
|
3525
|
+
function servingBuildOf(pkg, externals, accepts) {
|
|
3526
|
+
if (externals.length === 0) return void 0;
|
|
3527
|
+
const rootRows = shareRows(externals.find(([name]) => name === pkg)?.[1]).filter(
|
|
3528
|
+
(row) => row.remotes.some((copy) => pkg in copy.entries)
|
|
3529
|
+
);
|
|
3530
|
+
const rows = rootRows.length > 0 ? rootRows : externals.flatMap(([, e]) => shareRows(e));
|
|
3531
|
+
if (isPooled(externals)) return pooledBuild(externals, rows);
|
|
3532
|
+
const consumers = consumersOf(externals);
|
|
3533
|
+
const builds = buildsOf(rows, rootRows, consumers);
|
|
3534
|
+
const hosts = builds.filter((b) => b.host);
|
|
3535
|
+
const field = hosts.length > 0 ? hosts : builds;
|
|
3536
|
+
if (field.length <= 1) return field[0] && { remote: field[0].remote, tag: field[0].tag };
|
|
3537
|
+
return cheapestBuild(field, costTable(consumers, accepts));
|
|
3538
|
+
}
|
|
3539
|
+
function cheapestBuild(field, costOf) {
|
|
3540
|
+
let best;
|
|
3541
|
+
for (const b of field) {
|
|
3542
|
+
const { downloads, fallbacks } = costOf(b);
|
|
3543
|
+
const candidate = {
|
|
3544
|
+
remote: b.remote,
|
|
3545
|
+
tag: b.tag,
|
|
3546
|
+
host: b.host,
|
|
3547
|
+
rootBasis: b.rootBasis,
|
|
3548
|
+
downloads,
|
|
3549
|
+
fallbacks
|
|
3550
|
+
};
|
|
3551
|
+
if (!best || byServingRank(candidate, best) < 0) best = candidate;
|
|
3552
|
+
}
|
|
3553
|
+
const { remote, tag } = best;
|
|
3554
|
+
return { remote, tag };
|
|
3555
|
+
}
|
|
3556
|
+
function shareServingCopies(external, serving) {
|
|
3557
|
+
for (const row of external.versions) {
|
|
3558
|
+
const copy = row.remotes.find((c) => c.name === serving.remote);
|
|
3559
|
+
if (row.action !== "skip" || !copy || rowAt(external.versions, row.tag, "share")) continue;
|
|
3560
|
+
row.action = "share";
|
|
3561
|
+
if (row.remotes[0] !== copy) row.host = false;
|
|
3562
|
+
row.remotes = [copy, ...row.remotes.filter((c) => c !== copy)];
|
|
3563
|
+
}
|
|
3564
|
+
}
|
|
3565
|
+
function followServingBuild(external, serving, accepts) {
|
|
3566
|
+
let objector;
|
|
3567
|
+
const rebuilt = external.versions.flatMap((version) => {
|
|
3568
|
+
if (version.action !== "share" || version.tag === serving.tag || version.remotes[0].name === serving.remote)
|
|
3569
|
+
return [version];
|
|
3570
|
+
const rows = redirectRow(version, serving.tag, accepts);
|
|
3571
|
+
const scoped = rows.find((row) => row.action === "scope");
|
|
3572
|
+
if (scoped && !objector) objector = { copy: scoped.remotes[0], tag: scoped.tag };
|
|
3573
|
+
return rows;
|
|
3574
|
+
});
|
|
3575
|
+
external.versions = mergeRows(rebuilt);
|
|
3576
|
+
return { external, objector };
|
|
3577
|
+
}
|
|
3578
|
+
var sameTagOnly = (offered, ownTag) => offered === ownTag;
|
|
3579
|
+
var servedScopes = (scope, strict) => strict ? strictTagScopes(scope) : [scope];
|
|
3580
|
+
function strictTagScopes(scope) {
|
|
3581
|
+
const tagScopes = [];
|
|
3582
|
+
for (const [pkg, names] of packagesOf(scope)) {
|
|
3583
|
+
const byTag2 = /* @__PURE__ */ new Map();
|
|
3584
|
+
for (const name of names)
|
|
3585
|
+
for (const row of scope[name].versions) {
|
|
3586
|
+
let tagScope = byTag2.get(row.tag);
|
|
3587
|
+
if (!tagScope) byTag2.set(row.tag, tagScope = {});
|
|
3588
|
+
const external = tagScope[name] ??= { ...scope[name], versions: [] };
|
|
3589
|
+
external.versions.push({ ...row, remotes: [...row.remotes] });
|
|
3264
3590
|
}
|
|
3265
|
-
|
|
3266
|
-
const
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
consumedMembers: needAnchor,
|
|
3272
|
-
hosts,
|
|
3273
|
-
arrival: views.arrival()
|
|
3274
|
-
});
|
|
3275
|
-
const anchors = /* @__PURE__ */ new Set();
|
|
3276
|
-
for (const build of assignment.values()) if (build !== void 0) anchors.add(build);
|
|
3277
|
-
const serving = /* @__PURE__ */ new Map();
|
|
3278
|
-
let scoped = false;
|
|
3279
|
-
for (const [remote, wants] of needAnchor) {
|
|
3280
|
-
const assigned = assignment.get(remote);
|
|
3281
|
-
const build = assigned ?? (anchors.has(remote) || hosts.has(remote) ? remote : void 0);
|
|
3282
|
-
if (build === void 0) {
|
|
3283
|
-
islanded.set(remote, {
|
|
3284
|
-
kind: "uncovered",
|
|
3285
|
-
...explainSelfServe(remote, wants, needSpecifiers.get(remote), { builds, acceptance })
|
|
3286
|
-
});
|
|
3287
|
-
scoped = true;
|
|
3288
|
-
continue;
|
|
3289
|
-
}
|
|
3290
|
-
serving.set(remote, build);
|
|
3591
|
+
for (const [tag, tagScope] of byTag2) {
|
|
3592
|
+
const lead = [tagScope[pkg], ...Object.values(tagScope)].map((external) => external && rowAt(external.versions, tag, "share")).find((row) => row !== void 0);
|
|
3593
|
+
if (lead) {
|
|
3594
|
+
const serving = { remote: lead.remotes[0].name, tag };
|
|
3595
|
+
for (const external of Object.values(tagScope)) external.servingBuild = serving.remote;
|
|
3596
|
+
scopeFallbacks(Object.entries(tagScope), serving, sameTagOnly);
|
|
3291
3597
|
}
|
|
3292
|
-
|
|
3598
|
+
tagScopes.push(tagScope);
|
|
3293
3599
|
}
|
|
3294
3600
|
}
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3601
|
+
return tagScopes;
|
|
3602
|
+
}
|
|
3603
|
+
function shareRows(external) {
|
|
3604
|
+
return external?.versions.filter((v) => v.action === "share") ?? [];
|
|
3605
|
+
}
|
|
3606
|
+
function buildsOf(rows, rootRows, consumers) {
|
|
3607
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
3608
|
+
for (const row of rows)
|
|
3609
|
+
for (const copy of row.remotes) {
|
|
3610
|
+
const key = `${row.tag}|${copy.name}`;
|
|
3611
|
+
if (copy.servedBy || candidates.has(key) || shipsTwoTags(consumers.get(copy.name))) continue;
|
|
3612
|
+
const basis = copy === row.remotes[0];
|
|
3613
|
+
candidates.set(key, {
|
|
3614
|
+
remote: copy.name,
|
|
3615
|
+
tag: row.tag,
|
|
3616
|
+
host: basis && row.host,
|
|
3617
|
+
rootBasis: basis && rootRows.includes(row)
|
|
3618
|
+
});
|
|
3619
|
+
}
|
|
3620
|
+
return [...candidates.values()];
|
|
3621
|
+
}
|
|
3622
|
+
function pooledBuild(externals, rows) {
|
|
3623
|
+
const winner = externals.find(([, e]) => e.poolWinner !== void 0)?.[1].poolWinner;
|
|
3624
|
+
const shipped = rows.flatMap(
|
|
3625
|
+
(row) => row.remotes.filter((copy) => !copy.servedBy).map((copy) => ({ remote: copy.name, tag: row.tag }))
|
|
3626
|
+
);
|
|
3627
|
+
const own = shipped.find((c) => c.remote === winner);
|
|
3628
|
+
if (own) return own;
|
|
3629
|
+
const width = ({ remote, tag }) => externals.reduce((n, [, e]) => {
|
|
3630
|
+
const copy = shareRows(e).find((row) => row.tag === tag)?.remotes.find((c) => c.name === remote);
|
|
3631
|
+
return n + Object.keys(copy?.entries ?? {}).length;
|
|
3632
|
+
}, 0);
|
|
3633
|
+
return shipped.map((c) => ({ c, width: width(c) })).sort((a, b) => b.width - a.width || compareStrings(a.c.remote, b.c.remote))[0]?.c;
|
|
3634
|
+
}
|
|
3635
|
+
function consumersOf(externals) {
|
|
3636
|
+
const consumers = /* @__PURE__ */ new Map();
|
|
3637
|
+
for (const [, external] of externals)
|
|
3638
|
+
for (const row of external.versions)
|
|
3639
|
+
for (const copy of row.remotes) {
|
|
3640
|
+
const placed = consumers.get(copy.name);
|
|
3641
|
+
if (placed) placed.push({ row, copy });
|
|
3642
|
+
else consumers.set(copy.name, [{ row, copy }]);
|
|
3321
3643
|
}
|
|
3644
|
+
return consumers;
|
|
3645
|
+
}
|
|
3646
|
+
function costTable(consumers, accepts) {
|
|
3647
|
+
const scanned = /* @__PURE__ */ new Map();
|
|
3648
|
+
const keyed = /* @__PURE__ */ new Map();
|
|
3649
|
+
const tollFor = (build, surface) => {
|
|
3650
|
+
let atTag = scanned.get(build.tag);
|
|
3651
|
+
if (!atTag) scanned.set(build.tag, atTag = []);
|
|
3652
|
+
const known = atTag.find((t) => sameSurface(t.surface, surface));
|
|
3653
|
+
if (known) return known.toll;
|
|
3654
|
+
if (atTag.length < SCANNED_SURFACES_PER_TAG) {
|
|
3655
|
+
const toll2 = tollOf(consumers, surface, build.tag, accepts);
|
|
3656
|
+
atTag.push({ surface, toll: toll2 });
|
|
3657
|
+
return toll2;
|
|
3322
3658
|
}
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
clean = clean.filter((e) => e.meta.servedBy !== void 0).map((e) => ({ ...e, action: "skip" }));
|
|
3333
|
-
}
|
|
3334
|
-
for (const entry of scoped)
|
|
3335
|
-
entry.meta.poolCause = islanded.get(entry.remote)?.kind ?? "unshared";
|
|
3336
|
-
const shareEntries = clean.filter((e) => e.action === "share").sort((a, b) => Number(b.remote === basis) - Number(a.remote === basis));
|
|
3337
|
-
const shareVersion = shareEntries.length > 0 ? [
|
|
3338
|
-
{
|
|
3339
|
-
tag: shareEntries[0].tag,
|
|
3340
|
-
host: shareEntries[0].host,
|
|
3341
|
-
action: "share",
|
|
3342
|
-
remotes: shareEntries.map((e) => e.meta)
|
|
3343
|
-
}
|
|
3344
|
-
] : [];
|
|
3345
|
-
const byTag = (entries, action) => {
|
|
3346
|
-
const versions = /* @__PURE__ */ new Map();
|
|
3347
|
-
for (const entry of entries) {
|
|
3348
|
-
const version = versions.get(entry.tag) ?? {
|
|
3349
|
-
tag: entry.tag,
|
|
3350
|
-
host: entry.host,
|
|
3351
|
-
action,
|
|
3352
|
-
remotes: []
|
|
3353
|
-
};
|
|
3354
|
-
version.remotes.push(entry.meta);
|
|
3355
|
-
versions.set(entry.tag, version);
|
|
3356
|
-
}
|
|
3357
|
-
return [...versions.values()];
|
|
3358
|
-
};
|
|
3659
|
+
const key = [build.tag, ...[...surface].map(([s, tag]) => `${s}@${tag}`).sort()].join("\n");
|
|
3660
|
+
let toll = keyed.get(key);
|
|
3661
|
+
if (!toll) keyed.set(key, toll = tollOf(consumers, surface, build.tag, accepts));
|
|
3662
|
+
return toll;
|
|
3663
|
+
};
|
|
3664
|
+
return (build) => {
|
|
3665
|
+
const surface = surfaceOf(consumers, build);
|
|
3666
|
+
const toll = tollFor(build, surface);
|
|
3667
|
+
const others = (remotes) => remotes.size - Number(remotes.has(build.remote));
|
|
3359
3668
|
return {
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
versions: [
|
|
3363
|
-
...shareVersion,
|
|
3364
|
-
...byTag(
|
|
3365
|
-
clean.filter((e) => e.action === "skip"),
|
|
3366
|
-
"skip"
|
|
3367
|
-
),
|
|
3368
|
-
...byTag(scoped, "scope")
|
|
3369
|
-
].sort((a, b) => ports.versionCheck.compare(b.tag, a.tag))
|
|
3669
|
+
downloads: others(toll.downloads) + Number(!allCached(consumers.get(build.remote) ?? [])),
|
|
3670
|
+
fallbacks: others(toll.fallbacks)
|
|
3370
3671
|
};
|
|
3371
|
-
}
|
|
3672
|
+
};
|
|
3372
3673
|
}
|
|
3373
|
-
function
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
}
|
|
3383
|
-
}
|
|
3674
|
+
function tollOf(consumers, surface, tag, accepts) {
|
|
3675
|
+
const toll = { fallbacks: /* @__PURE__ */ new Set(), downloads: /* @__PURE__ */ new Set() };
|
|
3676
|
+
for (const [remote, placed] of consumers) {
|
|
3677
|
+
const fallback = fallsBack(placed, surface, tag, accepts);
|
|
3678
|
+
if (fallback) toll.fallbacks.add(remote);
|
|
3679
|
+
if (!allCached(placed) && (fallback || runsOffMap(placed, tag, accepts)))
|
|
3680
|
+
toll.downloads.add(remote);
|
|
3681
|
+
}
|
|
3682
|
+
return toll;
|
|
3384
3683
|
}
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3684
|
+
var allCached = (placed) => placed.every(({ copy }) => copy.cached);
|
|
3685
|
+
function fallbacksOf(externals, serving, accepts) {
|
|
3686
|
+
const consumers = consumersOf(externals);
|
|
3687
|
+
const surface = serving ? surfaceOf(consumers, serving) : /* @__PURE__ */ new Map();
|
|
3688
|
+
return [...consumers].filter(
|
|
3689
|
+
([remote, placed]) => remote !== serving?.remote && fallsBack(placed, surface, serving?.tag, accepts)
|
|
3690
|
+
).map(([remote]) => remote);
|
|
3691
|
+
}
|
|
3692
|
+
function scopeFallbacks(externals, serving, accepts) {
|
|
3693
|
+
const remotes = fallbacksOf(externals, serving, accepts);
|
|
3694
|
+
for (const [, external] of externals)
|
|
3695
|
+
external.versions = scopeRemotes(external.versions, remotes);
|
|
3696
|
+
}
|
|
3697
|
+
function strictObjectorOf(externals, serving, accepts) {
|
|
3698
|
+
const consumers = consumersOf(externals);
|
|
3699
|
+
const surface = surfaceOf(consumers, serving);
|
|
3700
|
+
for (const [name, external] of externals)
|
|
3701
|
+
for (const row of external.versions)
|
|
3702
|
+
for (const copy of row.remotes)
|
|
3703
|
+
if (copy.name !== serving.remote && rejectsServingTag({ row, copy }, surface, serving.tag, accepts) && !splitsPackage(consumers.get(copy.name), surface, serving.tag, accepts))
|
|
3704
|
+
return { external: name, copy, tag: row.tag };
|
|
3705
|
+
return void 0;
|
|
3706
|
+
}
|
|
3707
|
+
var SCANNED_SURFACES_PER_TAG = 8;
|
|
3708
|
+
function sameSurface(a, b) {
|
|
3709
|
+
if (a.size !== b.size) return false;
|
|
3710
|
+
for (const [specifier, tag] of a) if (b.get(specifier) !== tag) return false;
|
|
3711
|
+
return true;
|
|
3712
|
+
}
|
|
3713
|
+
function surfaceOf(consumers, serving) {
|
|
3714
|
+
const surface = /* @__PURE__ */ new Map();
|
|
3715
|
+
for (const p of consumers.get(serving.remote) ?? [])
|
|
3716
|
+
if (p.row.tag === serving.tag && onMap(p) || leadsShareRow(p)) {
|
|
3717
|
+
for (const s in p.copy.entries) if (!surface.has(s)) surface.set(s, p.row.tag);
|
|
3395
3718
|
}
|
|
3396
|
-
return
|
|
3719
|
+
return surface;
|
|
3720
|
+
}
|
|
3721
|
+
var leadsShareRow = ({ row, copy }) => row.action === "share" && row.remotes[0] === copy;
|
|
3722
|
+
var onMap = ({ row }) => row.action !== "scope";
|
|
3723
|
+
function splitsPackage(placed, surface, tag, accepts) {
|
|
3724
|
+
const uncovered = (p) => Object.keys(p.copy.entries).some((s) => {
|
|
3725
|
+
const servedAt = surface.get(s);
|
|
3726
|
+
return servedAt === void 0 || servedAt !== tag && rejectsTag(p, servedAt, accepts);
|
|
3727
|
+
});
|
|
3728
|
+
return placed.some(onMap) && (shipsTwoTags(placed) || placed.some((p) => !onMap(p) || uncovered(p)));
|
|
3729
|
+
}
|
|
3730
|
+
function loadSplitsPackage(pkg, copies, claims, accepts) {
|
|
3731
|
+
const root = claims.find(([specifier]) => specifier === pkg)?.[1];
|
|
3732
|
+
const servingTag = root?.tag ?? claims[0][1].tag;
|
|
3733
|
+
const surface = new Map(
|
|
3734
|
+
claims.map(([specifier, { tag }]) => [specifier, root ? tag : servingTag])
|
|
3735
|
+
);
|
|
3736
|
+
const placed = copies.map(({ tag, copy }) => ({
|
|
3737
|
+
row: { tag, action: "share", host: false, remotes: [copy] },
|
|
3738
|
+
copy
|
|
3739
|
+
}));
|
|
3740
|
+
return splitsPackage(placed, surface, servingTag, accepts);
|
|
3397
3741
|
}
|
|
3398
|
-
function
|
|
3742
|
+
function fallsBack(placed, surface, tag, accepts) {
|
|
3743
|
+
return splitsPackage(placed, surface, tag, accepts) || tag !== void 0 && placed.some((p) => rejectsServingTag(p, surface, tag, accepts));
|
|
3744
|
+
}
|
|
3745
|
+
function rejectsServingTag(p, surface, tag, accepts) {
|
|
3746
|
+
return onMap(p) && rejectsTag(p, tag, accepts) && Object.keys(p.copy.entries).some((s) => surface.get(s) === tag);
|
|
3747
|
+
}
|
|
3748
|
+
var rejectsTag = ({ row, copy }, tag, accepts) => copy.strictVersion && !accepts(tag, row.tag, copy.requiredVersion);
|
|
3749
|
+
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);
|
|
3750
|
+
function runsOffMap(placed, tag, accepts) {
|
|
3751
|
+
return placed.some((p) => !onMap(p) || rejectsTag(p, tag, accepts));
|
|
3752
|
+
}
|
|
3753
|
+
|
|
3754
|
+
// src/lib/core/2.app/steps/decide-serving-builds.ts
|
|
3755
|
+
function createDecideServingBuilds(config, ports) {
|
|
3399
3756
|
return () => {
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
const
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
}
|
|
3414
|
-
}
|
|
3415
|
-
for (const [name, external] of Object.entries(sharedExternals)) {
|
|
3416
|
-
if (pooled.has(name) || !clearPoolState(external)) continue;
|
|
3417
|
-
external.dirty = true;
|
|
3418
|
-
unpooled++;
|
|
3757
|
+
const accepts = createAcceptsTag(ports.versionCheck.isCompatible, ports.versionCheck.compare);
|
|
3758
|
+
const repo = ports.sharedExternalsRepo;
|
|
3759
|
+
const written = new Set(repo.uncommittedScopes());
|
|
3760
|
+
const needsDeciding = (shareScope) => written.has(shareScope) || repo.isUndecided(shareScope);
|
|
3761
|
+
try {
|
|
3762
|
+
for (const shareScope of repo.getScopes()) {
|
|
3763
|
+
if (repo.scopeType(shareScope) === "strict" || !needsDeciding(shareScope)) continue;
|
|
3764
|
+
const sharedExternals = repo.getFromScope(shareScope);
|
|
3765
|
+
for (const [pkg, names] of packagesOf(sharedExternals)) {
|
|
3766
|
+
const externals = names.map((name) => [name, sharedExternals[name]]);
|
|
3767
|
+
decidePackage(shareScope, pkg, externals, accepts);
|
|
3768
|
+
}
|
|
3769
|
+
repo.markDecided(shareScope);
|
|
3419
3770
|
}
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
config.log.debug(
|
|
3424
|
-
3,
|
|
3425
|
-
`[${scope}] ${unpooled} external(s) left every pool; cleared their pool state for re-election.`
|
|
3426
|
-
);
|
|
3771
|
+
return Promise.resolve();
|
|
3772
|
+
} catch (e) {
|
|
3773
|
+
return Promise.reject(e);
|
|
3427
3774
|
}
|
|
3428
|
-
return Promise.resolve();
|
|
3429
3775
|
};
|
|
3776
|
+
function decidePackage(shareScope, pkg, externals, accepts) {
|
|
3777
|
+
const serving = servingBuildOf(pkg, externals, accepts);
|
|
3778
|
+
const before = externals.map(([, external]) => shapeOf(external));
|
|
3779
|
+
const pooled = isPooled(externals);
|
|
3780
|
+
const toFollow = pooled ? void 0 : serving;
|
|
3781
|
+
if (!pooled) fallBack(pkg, externals, accepts, serving);
|
|
3782
|
+
externals.forEach(([name, external], i) => {
|
|
3783
|
+
const decided = withServingBuild(
|
|
3784
|
+
toFollow ? follow(pkg, name, external, toFollow, accepts) : external,
|
|
3785
|
+
serving?.remote
|
|
3786
|
+
);
|
|
3787
|
+
if (!sameShape(before[i], decided))
|
|
3788
|
+
ports.sharedExternalsRepo.addOrUpdate(name, decided, shareScope);
|
|
3789
|
+
});
|
|
3790
|
+
}
|
|
3791
|
+
function follow(pkg, name, external, serving, accepts) {
|
|
3792
|
+
const { external: followed, objector } = followServingBuild(external, serving, accepts);
|
|
3793
|
+
if (objector && config.strict.strictExternalCompatibility)
|
|
3794
|
+
rejectIncompatible(config, objector.copy, `${name}@${objector.tag}`, `${pkg}@${serving.tag}`);
|
|
3795
|
+
return followed;
|
|
3796
|
+
}
|
|
3797
|
+
function fallBack(pkg, externals, accepts, serving) {
|
|
3798
|
+
if (serving) {
|
|
3799
|
+
for (const [, external] of externals) shareServingCopies(external, serving);
|
|
3800
|
+
const objector = config.strict.strictExternalCompatibility && strictObjectorOf(externals, serving, accepts);
|
|
3801
|
+
if (objector)
|
|
3802
|
+
rejectIncompatible(
|
|
3803
|
+
config,
|
|
3804
|
+
objector.copy,
|
|
3805
|
+
`${objector.external}@${objector.tag}`,
|
|
3806
|
+
`${pkg}@${serving.tag}`
|
|
3807
|
+
);
|
|
3808
|
+
}
|
|
3809
|
+
scopeFallbacks(externals, serving, accepts);
|
|
3810
|
+
}
|
|
3430
3811
|
}
|
|
3812
|
+
function withServingBuild(external, servingBuild) {
|
|
3813
|
+
if (external.servingBuild === servingBuild) return external;
|
|
3814
|
+
const { servingBuild: _, ...rest } = external;
|
|
3815
|
+
return servingBuild ? { ...rest, servingBuild } : rest;
|
|
3816
|
+
}
|
|
3817
|
+
var shapeOf = (external) => ({
|
|
3818
|
+
servingBuild: external.servingBuild,
|
|
3819
|
+
rows: external.versions.map(
|
|
3820
|
+
({ tag, action, host, remotes }) => ({ tag, action, host, remotes: [...remotes] })
|
|
3821
|
+
)
|
|
3822
|
+
});
|
|
3823
|
+
var sameRow = (was, row) => Object.keys(was).every(
|
|
3824
|
+
(key) => key === "remotes" ? was.remotes.length === row.remotes.length && row.remotes.every((copy, j) => copy === was.remotes[j]) : was[key] === row[key]
|
|
3825
|
+
);
|
|
3826
|
+
var sameShape = (shape, external) => shape.servingBuild === external.servingBuild && shape.rows.length === external.versions.length && external.versions.every((row, i) => sameRow(shape.rows[i], row));
|
|
3431
3827
|
|
|
3432
|
-
//
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3828
|
+
// src/lib/core/1.domain/externals/claims.ts
|
|
3829
|
+
function claimTable(externals, publishes) {
|
|
3830
|
+
const table = { claims: /* @__PURE__ */ new Map(), duplicates: /* @__PURE__ */ new Set(), shareClaims: /* @__PURE__ */ new Map() };
|
|
3831
|
+
const ordered = [...externals];
|
|
3832
|
+
const claim = (into, external, version, accepts = publishes) => forEachVersionEntry(version, accepts, (specifier, copy) => {
|
|
3833
|
+
if (!into.has(specifier)) into.set(specifier, { external, tag: version.tag, copy });
|
|
3834
|
+
});
|
|
3835
|
+
const seedServingBuild = (name, external) => {
|
|
3836
|
+
const isServing = (copy) => copy.name === external.servingBuild && (!publishes || publishes(copy));
|
|
3837
|
+
for (const version of external.versions) {
|
|
3838
|
+
if (version.action !== "share") continue;
|
|
3839
|
+
claim(table.shareClaims, name, version, isServing);
|
|
3840
|
+
claim(table.claims, name, version, isServing);
|
|
3841
|
+
}
|
|
3842
|
+
};
|
|
3843
|
+
const claimShareRow = (name, external, version) => {
|
|
3844
|
+
const prior = table.claims.get(name);
|
|
3845
|
+
const duplicate = prior !== void 0 && prior.tag !== version.tag;
|
|
3846
|
+
if (duplicate && !(version.host && version.remotes[0].name === external.servingBuild))
|
|
3847
|
+
table.duplicates.add(version);
|
|
3848
|
+
if (external.servingBuild) return;
|
|
3849
|
+
claim(table.shareClaims, name, version);
|
|
3850
|
+
if (!duplicate && (!prior || prior.external === name)) claim(table.claims, name, version);
|
|
3851
|
+
};
|
|
3852
|
+
for (const [name, external] of ordered)
|
|
3853
|
+
if (external.servingBuild) seedServingBuild(name, external);
|
|
3854
|
+
for (const [name, external] of ordered)
|
|
3855
|
+
for (const version of external.versions)
|
|
3856
|
+
if (version.action === "share") claimShareRow(name, external, version);
|
|
3857
|
+
return table;
|
|
3858
|
+
}
|
|
3859
|
+
function committedClaims(externals, { shareScope, without }) {
|
|
3860
|
+
const publishes = (copy) => copy.name !== without && (shareScope !== GLOBAL_SCOPE || copy.cached);
|
|
3861
|
+
return claimTable(externals, publishes).claims;
|
|
3862
|
+
}
|
|
3863
|
+
function versionClaims(version, servingBuild) {
|
|
3864
|
+
const claims = /* @__PURE__ */ new Map();
|
|
3865
|
+
const claim = (specifier, copy) => {
|
|
3866
|
+
if (!claims.has(specifier)) claims.set(specifier, copy);
|
|
3867
|
+
};
|
|
3868
|
+
const accepts = servingBuild ? (copy) => copy.name === servingBuild : void 0;
|
|
3869
|
+
forEachVersionEntry(version, accepts, claim);
|
|
3870
|
+
return claims;
|
|
3440
3871
|
}
|
|
3441
3872
|
|
|
3442
3873
|
// src/lib/core/2.app/steps/generate-import-map.ts
|
|
@@ -3446,8 +3877,8 @@ function createGenerateImportMap(config, ports) {
|
|
|
3446
3877
|
const chunkBundles = {};
|
|
3447
3878
|
try {
|
|
3448
3879
|
addScopedExternals(importMap, chunkBundles);
|
|
3449
|
-
|
|
3450
|
-
|
|
3880
|
+
addNamedShareScopes(importMap, chunkBundles);
|
|
3881
|
+
addGlobalShareScope(importMap, chunkBundles);
|
|
3451
3882
|
addRemoteInfos(importMap, chunkBundles);
|
|
3452
3883
|
addChunkImports(importMap, chunkBundles);
|
|
3453
3884
|
return Promise.resolve(importMap);
|
|
@@ -3481,47 +3912,61 @@ function createGenerateImportMap(config, ports) {
|
|
|
3481
3912
|
}
|
|
3482
3913
|
return modules;
|
|
3483
3914
|
}
|
|
3484
|
-
function
|
|
3915
|
+
function addNamedShareScopes(importMap, chunkBundles) {
|
|
3485
3916
|
const shareScopes = ports.sharedExternalsRepo.getScopes({ includeGlobal: false });
|
|
3486
3917
|
for (const shareScope of shareScopes) {
|
|
3487
|
-
|
|
3918
|
+
const sharedExternals = ports.sharedExternalsRepo.getFromScope(shareScope);
|
|
3919
|
+
const cachedBefore = /* @__PURE__ */ new Map();
|
|
3920
|
+
for (const [externalName, external] of Object.entries(sharedExternals))
|
|
3921
|
+
cachedBefore.set(externalName, cachedFingerprint(external));
|
|
3922
|
+
const strict = ports.sharedExternalsRepo.scopeType(shareScope) === "strict";
|
|
3923
|
+
for (const served of servedScopes(sharedExternals, strict))
|
|
3924
|
+
addShareScope(importMap, shareScope, served, chunkBundles);
|
|
3925
|
+
for (const [externalName, external] of Object.entries(sharedExternals)) {
|
|
3926
|
+
if (cachedFingerprint(external) !== cachedBefore.get(externalName)) {
|
|
3927
|
+
ports.sharedExternalsRepo.addOrUpdate(externalName, external, shareScope);
|
|
3928
|
+
}
|
|
3929
|
+
}
|
|
3488
3930
|
}
|
|
3489
3931
|
return importMap;
|
|
3490
3932
|
}
|
|
3491
|
-
function
|
|
3492
|
-
const sharedExternals = ports.sharedExternalsRepo.getFromScope(shareScope);
|
|
3933
|
+
function addShareScope(importMap, shareScope, sharedExternals, chunkBundles) {
|
|
3493
3934
|
const index = buildServedIndex(sharedExternals);
|
|
3935
|
+
const claims = shareRowMappings(sharedExternals, shareScope);
|
|
3936
|
+
const claimedElsewhere = (externalName, specifier) => {
|
|
3937
|
+
const claim = claims.get(specifier);
|
|
3938
|
+
return claim?.external === externalName ? void 0 : claim;
|
|
3939
|
+
};
|
|
3494
3940
|
for (const [externalName, external] of Object.entries(sharedExternals)) {
|
|
3495
3941
|
let override = void 0;
|
|
3496
|
-
const cachedBefore = cachedFingerprint(external);
|
|
3497
3942
|
for (const version of external.versions) {
|
|
3498
3943
|
if (version.action === "scope") {
|
|
3499
|
-
|
|
3500
|
-
const remoteScope = getScope2(shareScope, remote.name, externalName);
|
|
3501
|
-
for (const [packageName, file] of Object.entries(remote.entries)) {
|
|
3502
|
-
const url = join(remoteScope, file);
|
|
3503
|
-
addToScope(importMap, remoteScope, { [packageName]: url });
|
|
3504
|
-
addIntegrity(importMap, url, remote.name, file);
|
|
3505
|
-
}
|
|
3506
|
-
registerBundleChunks(chunkBundles, remote.name, remote.bundle);
|
|
3507
|
-
remote.cached = true;
|
|
3508
|
-
}
|
|
3944
|
+
addScopeRow(importMap, chunkBundles, shareScope, externalName, version);
|
|
3509
3945
|
continue;
|
|
3510
3946
|
}
|
|
3511
|
-
version.remotes[0].cached = true;
|
|
3512
3947
|
let serving = version;
|
|
3513
3948
|
if (version.action === "skip") {
|
|
3514
3949
|
if (!override) {
|
|
3515
|
-
override = findOverride(
|
|
3950
|
+
override = findOverride(
|
|
3951
|
+
external,
|
|
3952
|
+
shareScope,
|
|
3953
|
+
externalName,
|
|
3954
|
+
(s) => Boolean(claimedElsewhere(externalName, s))
|
|
3955
|
+
) ?? "NOT_AVAILABLE";
|
|
3516
3956
|
}
|
|
3517
3957
|
if (override !== "NOT_AVAILABLE") {
|
|
3518
3958
|
serving = override;
|
|
3519
3959
|
version.remotes[0].cached = false;
|
|
3520
3960
|
}
|
|
3521
3961
|
}
|
|
3522
|
-
const provided =
|
|
3962
|
+
const provided = versionClaims(serving, external.servingBuild);
|
|
3523
3963
|
const mappings = [];
|
|
3524
3964
|
for (const [packageName, provider] of provided) {
|
|
3965
|
+
const claim = claimedElsewhere(externalName, packageName);
|
|
3966
|
+
if (claim) {
|
|
3967
|
+
mappings.push({ packageName, ...claim });
|
|
3968
|
+
continue;
|
|
3969
|
+
}
|
|
3525
3970
|
const file = provider.entries[packageName];
|
|
3526
3971
|
mappings.push({
|
|
3527
3972
|
packageName,
|
|
@@ -3534,56 +3979,60 @@ function createGenerateImportMap(config, ports) {
|
|
|
3534
3979
|
registerBundleChunks(chunkBundles, provider.name, provider.bundle);
|
|
3535
3980
|
}
|
|
3536
3981
|
}
|
|
3537
|
-
version.remotes.forEach((
|
|
3538
|
-
const
|
|
3539
|
-
if (index &&
|
|
3540
|
-
const files = index.get(
|
|
3541
|
-
const servedScope = getScope2(shareScope,
|
|
3542
|
-
for (const specifier of Object.keys(
|
|
3982
|
+
version.remotes.forEach((consumer) => {
|
|
3983
|
+
const consumerScope = getScope2(shareScope, consumer.name, externalName);
|
|
3984
|
+
if (index && consumer.servedBy) {
|
|
3985
|
+
const files = index.get(consumer.servedBy);
|
|
3986
|
+
const servedScope = getScope2(shareScope, consumer.servedBy, externalName);
|
|
3987
|
+
for (const specifier of Object.keys(consumer.entries)) {
|
|
3543
3988
|
const source = files?.get(specifier);
|
|
3544
3989
|
if (!source) continue;
|
|
3545
3990
|
const url = join(servedScope, source.file);
|
|
3546
|
-
addToScope(importMap,
|
|
3547
|
-
addIntegrity(importMap, url,
|
|
3548
|
-
registerBundleChunks(chunkBundles,
|
|
3991
|
+
addToScope(importMap, consumerScope, { [specifier]: url });
|
|
3992
|
+
addIntegrity(importMap, url, consumer.servedBy, source.file);
|
|
3993
|
+
registerBundleChunks(chunkBundles, consumer.servedBy, source.bundle);
|
|
3549
3994
|
source.meta.cached = true;
|
|
3550
3995
|
}
|
|
3551
3996
|
return;
|
|
3552
3997
|
}
|
|
3553
3998
|
for (const m of mappings) {
|
|
3554
|
-
addToScope(importMap,
|
|
3999
|
+
addToScope(importMap, consumerScope, { [m.packageName]: m.url });
|
|
3555
4000
|
}
|
|
3556
|
-
for (const
|
|
4001
|
+
for (const packageName of Object.keys(consumer.entries)) {
|
|
3557
4002
|
if (provided.has(packageName)) continue;
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
continue;
|
|
3561
|
-
}
|
|
3562
|
-
const url = join(rScope, file);
|
|
3563
|
-
addToScope(importMap, rScope, { [packageName]: url });
|
|
3564
|
-
addIntegrity(importMap, url, r.name, file);
|
|
3565
|
-
r.cached = true;
|
|
4003
|
+
const claim = claimedElsewhere(externalName, packageName);
|
|
4004
|
+
if (claim) addToScope(importMap, consumerScope, { [packageName]: claim.url });
|
|
3566
4005
|
}
|
|
3567
4006
|
});
|
|
3568
4007
|
for (const m of mappings) {
|
|
3569
4008
|
addIntegrity(importMap, m.url, m.name, m.file);
|
|
3570
4009
|
}
|
|
3571
4010
|
}
|
|
3572
|
-
|
|
3573
|
-
|
|
4011
|
+
}
|
|
4012
|
+
}
|
|
4013
|
+
function addScopeRow(importMap, chunkBundles, shareScope, externalName, version) {
|
|
4014
|
+
for (const remote of version.remotes) {
|
|
4015
|
+
const remoteScope = getScope2(shareScope, remote.name, externalName);
|
|
4016
|
+
for (const [packageName, file] of Object.entries(remote.entries)) {
|
|
4017
|
+
const url = join(remoteScope, file);
|
|
4018
|
+
addToScope(importMap, remoteScope, { [packageName]: url });
|
|
4019
|
+
addIntegrity(importMap, url, remote.name, file);
|
|
3574
4020
|
}
|
|
4021
|
+
registerBundleChunks(chunkBundles, remote.name, remote.bundle);
|
|
4022
|
+
remote.cached = true;
|
|
3575
4023
|
}
|
|
3576
4024
|
}
|
|
3577
4025
|
function cachedFingerprint(external) {
|
|
3578
4026
|
return external.versions.map((v) => v.remotes.map((r) => r.cached ? 1 : 0).join("")).join("|");
|
|
3579
4027
|
}
|
|
3580
|
-
function findOverride(external, shareScope, externalName) {
|
|
4028
|
+
function findOverride(external, shareScope, externalName, servedElsewhere) {
|
|
3581
4029
|
const sharedVersions = external.versions.filter((v) => v.action === "share");
|
|
3582
4030
|
const scopedExternalName = `${shareScope}.${externalName}`;
|
|
3583
4031
|
if (sharedVersions.length > 1) {
|
|
3584
4032
|
handleMultipleSharedVersions(scopedExternalName);
|
|
3585
4033
|
}
|
|
3586
|
-
|
|
4034
|
+
const servedByClaims = () => external.versions.filter((v) => v.action === "skip").every((v) => shipsOnly(v, servedElsewhere));
|
|
4035
|
+
if (sharedVersions.length < 1 && !servedByClaims()) {
|
|
3587
4036
|
if (config.strict.strictImportMap) {
|
|
3588
4037
|
config.log.error(4, `[${shareScope}][${externalName}] shareScope has no override version.`);
|
|
3589
4038
|
throw new NFError("Could not create ImportMap.");
|
|
@@ -3628,17 +4077,30 @@ function createGenerateImportMap(config, ports) {
|
|
|
3628
4077
|
}
|
|
3629
4078
|
return index;
|
|
3630
4079
|
}
|
|
3631
|
-
function
|
|
4080
|
+
function shareRowMappings(externals, shareScope) {
|
|
4081
|
+
const mappings = /* @__PURE__ */ new Map();
|
|
4082
|
+
for (const [specifier, { external, copy }] of claimTable(Object.entries(externals)).shareClaims) {
|
|
4083
|
+
const file = copy.entries[specifier];
|
|
4084
|
+
mappings.set(specifier, {
|
|
4085
|
+
url: join(getScope2(shareScope, copy.name, external), file),
|
|
4086
|
+
name: copy.name,
|
|
4087
|
+
file,
|
|
4088
|
+
external
|
|
4089
|
+
});
|
|
4090
|
+
}
|
|
4091
|
+
return mappings;
|
|
4092
|
+
}
|
|
4093
|
+
function collectServed(into, index, shareScope, externalName, version) {
|
|
3632
4094
|
for (const consumer of version.remotes) {
|
|
3633
4095
|
if (!consumer.servedBy) continue;
|
|
3634
4096
|
const files = index.get(consumer.servedBy);
|
|
3635
|
-
const scope = getScope2(
|
|
4097
|
+
const scope = getScope2(shareScope, consumer.name, externalName);
|
|
3636
4098
|
for (const specifier of Object.keys(consumer.entries)) {
|
|
3637
4099
|
const source = files?.get(specifier);
|
|
3638
4100
|
if (!source) {
|
|
3639
4101
|
config.log.warn(
|
|
3640
4102
|
4,
|
|
3641
|
-
`[${
|
|
4103
|
+
`[${shareScope}][${externalName}][${consumer.name}] '${consumer.servedBy}' does not serve '${specifier}'.`
|
|
3642
4104
|
);
|
|
3643
4105
|
continue;
|
|
3644
4106
|
}
|
|
@@ -3656,9 +4118,11 @@ function createGenerateImportMap(config, ports) {
|
|
|
3656
4118
|
source.meta.cached = true;
|
|
3657
4119
|
}
|
|
3658
4120
|
}
|
|
3659
|
-
function
|
|
4121
|
+
function addGlobalShareScope(importMap, chunkBundles) {
|
|
3660
4122
|
const sharedExternals = ports.sharedExternalsRepo.getFromScope();
|
|
3661
4123
|
const index = buildServedIndex(sharedExternals);
|
|
4124
|
+
const { claims, duplicates } = claimTable(Object.entries(sharedExternals));
|
|
4125
|
+
const claimed = claimsByCopy(claims);
|
|
3662
4126
|
const served = [];
|
|
3663
4127
|
const cachedBefore = /* @__PURE__ */ new Map();
|
|
3664
4128
|
for (const [externalName, external] of Object.entries(sharedExternals)) {
|
|
@@ -3669,27 +4133,14 @@ function createGenerateImportMap(config, ports) {
|
|
|
3669
4133
|
}
|
|
3670
4134
|
if (version.action === "skip") continue;
|
|
3671
4135
|
if (version.action === "scope") {
|
|
3672
|
-
|
|
3673
|
-
const remoteScope = getScope2(GLOBAL_SCOPE, remote.name, externalName);
|
|
3674
|
-
for (const [packageName, file] of Object.entries(remote.entries)) {
|
|
3675
|
-
const url = join(remoteScope, file);
|
|
3676
|
-
addToScope(importMap, remoteScope, { [packageName]: url });
|
|
3677
|
-
addIntegrity(importMap, url, remote.name, file);
|
|
3678
|
-
}
|
|
3679
|
-
remote.cached = true;
|
|
3680
|
-
registerBundleChunks(chunkBundles, remote.name, remote.bundle);
|
|
3681
|
-
}
|
|
4136
|
+
addScopeRow(importMap, chunkBundles, GLOBAL_SCOPE, externalName, version);
|
|
3682
4137
|
continue;
|
|
3683
4138
|
}
|
|
3684
|
-
if (
|
|
4139
|
+
if (duplicates.has(version)) {
|
|
3685
4140
|
notifyDuplicateGlobalExternal(externalName);
|
|
3686
4141
|
continue;
|
|
3687
4142
|
}
|
|
3688
|
-
|
|
3689
|
-
}
|
|
3690
|
-
for (const version of external.versions) {
|
|
3691
|
-
if (version.action !== "skip") continue;
|
|
3692
|
-
selfFillUncovered(importMap, chunkBundles, externalName, version.remotes);
|
|
4143
|
+
publishClaims(importMap, chunkBundles, externalName, version, claimed);
|
|
3693
4144
|
}
|
|
3694
4145
|
}
|
|
3695
4146
|
flushServed(importMap, chunkBundles, served);
|
|
@@ -3700,54 +4151,30 @@ function createGenerateImportMap(config, ports) {
|
|
|
3700
4151
|
}
|
|
3701
4152
|
return importMap;
|
|
3702
4153
|
}
|
|
3703
|
-
function
|
|
3704
|
-
const
|
|
3705
|
-
for (const [
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
`[${GLOBAL_SCOPE}][${externalName}][${remote.name}] Entrypoint '${packageName}' is already mapped by another external, keeping '${importMap.imports[packageName]}'.`
|
|
3710
|
-
);
|
|
3711
|
-
continue;
|
|
3712
|
-
}
|
|
3713
|
-
let scope = scopes.get(remote.name);
|
|
3714
|
-
if (scope === void 0) {
|
|
3715
|
-
scopes.set(remote.name, scope = getScope2(GLOBAL_SCOPE, remote.name, externalName));
|
|
3716
|
-
registerBundleChunks(chunkBundles, remote.name, remote.bundle);
|
|
3717
|
-
remote.cached = true;
|
|
3718
|
-
}
|
|
3719
|
-
const file = remote.entries[packageName];
|
|
3720
|
-
const url = join(scope, file);
|
|
3721
|
-
addToGlobal(importMap, { [packageName]: url });
|
|
3722
|
-
addIntegrity(importMap, url, remote.name, file);
|
|
4154
|
+
function claimsByCopy(claims) {
|
|
4155
|
+
const claimed = /* @__PURE__ */ new Map();
|
|
4156
|
+
for (const [specifier, { copy }] of claims) {
|
|
4157
|
+
const specifiers = claimed.get(copy);
|
|
4158
|
+
if (specifiers) specifiers.push(specifier);
|
|
4159
|
+
else claimed.set(copy, [specifier]);
|
|
3723
4160
|
}
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
const
|
|
4161
|
+
return claimed;
|
|
4162
|
+
}
|
|
4163
|
+
function publishClaims(importMap, chunkBundles, externalName, version, claimed) {
|
|
4164
|
+
for (const copy of version.remotes) {
|
|
4165
|
+
const specifiers = claimed.get(copy);
|
|
4166
|
+
if (!specifiers) continue;
|
|
4167
|
+
const scope = getScope2(GLOBAL_SCOPE, copy.name, externalName);
|
|
4168
|
+
registerBundleChunks(chunkBundles, copy.name, copy.bundle);
|
|
4169
|
+
copy.cached = true;
|
|
4170
|
+
for (const specifier of specifiers) {
|
|
4171
|
+
const file = copy.entries[specifier];
|
|
3735
4172
|
const url = join(scope, file);
|
|
3736
|
-
addToGlobal(importMap, { [
|
|
3737
|
-
addIntegrity(importMap, url,
|
|
3738
|
-
registerBundleChunks(chunkBundles, remote.name, remote.bundle);
|
|
3739
|
-
remote.cached = true;
|
|
4173
|
+
addToGlobal(importMap, { [specifier]: url });
|
|
4174
|
+
addIntegrity(importMap, url, copy.name, file);
|
|
3740
4175
|
}
|
|
3741
4176
|
}
|
|
3742
4177
|
}
|
|
3743
|
-
function warnUncoveredEntrypoint(scope, externalName, remoteName, packageName) {
|
|
3744
|
-
const msg = `[${scope}][${externalName}][${remoteName}] Entrypoint '${packageName}' is not covered by the shared version.`;
|
|
3745
|
-
if (config.strict.strictEntryPointCoverage || config.strict.strictImportMap) {
|
|
3746
|
-
config.log.error(4, msg);
|
|
3747
|
-
throw new NFError("Could not create ImportMap.");
|
|
3748
|
-
}
|
|
3749
|
-
config.log.warn(4, msg);
|
|
3750
|
-
}
|
|
3751
4178
|
function notifyDuplicateGlobalExternal(externalName) {
|
|
3752
4179
|
if (config.strict.strictImportMap) {
|
|
3753
4180
|
config.log.error(4, `[${externalName}] Shared external has multiple shared versions.`);
|
|
@@ -3821,15 +4248,30 @@ function createGenerateImportMap(config, ports) {
|
|
|
3821
4248
|
});
|
|
3822
4249
|
}
|
|
3823
4250
|
}
|
|
4251
|
+
function shipsOnly(version, served) {
|
|
4252
|
+
let only = true;
|
|
4253
|
+
forEachVersionEntry(version, void 0, (specifier) => {
|
|
4254
|
+
only &&= served(specifier);
|
|
4255
|
+
});
|
|
4256
|
+
return only;
|
|
4257
|
+
}
|
|
3824
4258
|
|
|
3825
4259
|
// src/lib/core/2.app/steps/commit-changes.ts
|
|
3826
4260
|
function createCommitChanges(config, ports) {
|
|
3827
|
-
return (importMap,
|
|
4261
|
+
return (importMap, { markUndecided = false, ...browserOpts } = {}) => Promise.resolve(importMap).then((map) => addToBrowser(map, browserOpts)).then(() => {
|
|
4262
|
+
if (markUndecided) markUndecidedScopes();
|
|
4263
|
+
persistRepositoryChanges();
|
|
4264
|
+
});
|
|
3828
4265
|
function addToBrowser(importMap, opts) {
|
|
3829
4266
|
ports.browser.setImportMapFn(importMap, opts);
|
|
3830
4267
|
config.log.debug(5, "Added import map to browser.", importMap);
|
|
3831
4268
|
return importMap;
|
|
3832
4269
|
}
|
|
4270
|
+
function markUndecidedScopes() {
|
|
4271
|
+
const repo = ports.sharedExternalsRepo;
|
|
4272
|
+
for (const shareScope of repo.uncommittedScopes())
|
|
4273
|
+
if (repo.scopeType(shareScope) !== "strict") repo.markUndecided(shareScope);
|
|
4274
|
+
}
|
|
3833
4275
|
function persistRepositoryChanges() {
|
|
3834
4276
|
ports.remoteInfoRepo.commit();
|
|
3835
4277
|
ports.scopedExternalsRepo.commit();
|
|
@@ -3839,6 +4281,29 @@ function createCommitChanges(config, ports) {
|
|
|
3839
4281
|
}
|
|
3840
4282
|
}
|
|
3841
4283
|
|
|
4284
|
+
// src/lib/core/2.app/steps/rollback-changes.ts
|
|
4285
|
+
var createStateDump = (config, ports) => (msg) => config.log.debug(0, msg, {
|
|
4286
|
+
remotes: { ...ports.remoteInfoRepo.getAll() },
|
|
4287
|
+
"shared-externals": ports.sharedExternalsRepo.getScopes({ includeGlobal: true }).reduce(
|
|
4288
|
+
(acc, scope) => ({ ...acc, [scope]: ports.sharedExternalsRepo.getFromScope(scope) }),
|
|
4289
|
+
{}
|
|
4290
|
+
),
|
|
4291
|
+
"scoped-externals": ports.scopedExternalsRepo.getAll()
|
|
4292
|
+
});
|
|
4293
|
+
function createRollbackChanges(config, ports) {
|
|
4294
|
+
const stateDump = createStateDump(config, ports);
|
|
4295
|
+
return (label) => Promise.resolve().then(() => {
|
|
4296
|
+
try {
|
|
4297
|
+
stateDump(`${label} STATE DUMP`);
|
|
4298
|
+
} finally {
|
|
4299
|
+
ports.remoteInfoRepo.rollback();
|
|
4300
|
+
ports.scopedExternalsRepo.rollback();
|
|
4301
|
+
ports.sharedExternalsRepo.rollback();
|
|
4302
|
+
ports.sharedChunksRepo.rollback();
|
|
4303
|
+
}
|
|
4304
|
+
});
|
|
4305
|
+
}
|
|
4306
|
+
|
|
3842
4307
|
// src/lib/core/2.app/steps/expose-module-loader.ts
|
|
3843
4308
|
function createExposeModuleLoader(config, ports) {
|
|
3844
4309
|
const loadRemoteModule = (remoteName, exposedModule) => {
|
|
@@ -3874,10 +4339,16 @@ var normalizeRemoteRef = (remote) => {
|
|
|
3874
4339
|
function createGetRemoteEntry(config, ports) {
|
|
3875
4340
|
return async (remoteEntryUrl, remote) => {
|
|
3876
4341
|
const { name: remoteName, integrity } = normalizeRemoteRef(remote);
|
|
3877
|
-
|
|
3878
|
-
|
|
4342
|
+
const knownAtUrl = findCachedRemoteAt(remoteEntryUrl);
|
|
4343
|
+
if (knownAtUrl) {
|
|
4344
|
+
config.log.debug(
|
|
4345
|
+
7,
|
|
4346
|
+
`Found remote '${knownAtUrl}' at '${remoteEntryUrl}' in storage, omitting fetch.`
|
|
4347
|
+
);
|
|
3879
4348
|
return Optional.empty();
|
|
3880
4349
|
}
|
|
4350
|
+
if (!!remoteName && ports.remoteInfoRepo.contains(remoteName))
|
|
4351
|
+
return warnInitialized(remoteName, remoteEntryUrl);
|
|
3881
4352
|
try {
|
|
3882
4353
|
const remoteEntry = integrity ? await ports.remoteEntryProvider.provide(remoteEntryUrl, { integrity }) : await ports.remoteEntryProvider.provide(remoteEntryUrl);
|
|
3883
4354
|
config.log.debug(
|
|
@@ -3892,10 +4363,8 @@ function createGetRemoteEntry(config, ports) {
|
|
|
3892
4363
|
}
|
|
3893
4364
|
config.log.warn(7, errorMsg + " Omitting expected name.");
|
|
3894
4365
|
}
|
|
3895
|
-
if (ports.remoteInfoRepo.contains(remoteEntry.name))
|
|
3896
|
-
remoteEntry.
|
|
3897
|
-
config.log.debug(7, `Overriding existing remote '${remoteName}' with '${remoteEntryUrl}'.`);
|
|
3898
|
-
}
|
|
4366
|
+
if (ports.remoteInfoRepo.contains(remoteEntry.name))
|
|
4367
|
+
return warnInitialized(remoteEntry.name, remoteEntryUrl);
|
|
3899
4368
|
return Optional.of(checkForSSE(remoteEntry));
|
|
3900
4369
|
} catch (error) {
|
|
3901
4370
|
config.log.error(
|
|
@@ -3908,10 +4377,18 @@ function createGetRemoteEntry(config, ports) {
|
|
|
3908
4377
|
);
|
|
3909
4378
|
}
|
|
3910
4379
|
};
|
|
3911
|
-
function
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
4380
|
+
function warnInitialized(name, remoteEntryUrl) {
|
|
4381
|
+
const initializedFrom = ports.remoteInfoRepo.tryGet(name).map((info) => join(info.scopeUrl, "remoteEntry.json")).get();
|
|
4382
|
+
config.log.warn(
|
|
4383
|
+
7,
|
|
4384
|
+
`[${name}] Already initialized from '${initializedFrom}', ignoring '${remoteEntryUrl}'.`
|
|
4385
|
+
);
|
|
4386
|
+
return Optional.empty();
|
|
4387
|
+
}
|
|
4388
|
+
function findCachedRemoteAt(remoteEntryUrl) {
|
|
4389
|
+
return Object.entries(ports.remoteInfoRepo.getAll()).find(
|
|
4390
|
+
([, info]) => join(info.scopeUrl, "remoteEntry.json") === remoteEntryUrl
|
|
4391
|
+
)?.[0];
|
|
3915
4392
|
}
|
|
3916
4393
|
function checkForSSE(entry) {
|
|
3917
4394
|
if (config.sse) {
|
|
@@ -3931,92 +4408,184 @@ function createGetRemoteEntry(config, ports) {
|
|
|
3931
4408
|
// src/lib/core/2.app/steps/update-cache.ts
|
|
3932
4409
|
function createUpdateCache(config, ports) {
|
|
3933
4410
|
const storeRemoteEntry = createStoreRemoteEntry(config, ports, 8);
|
|
3934
|
-
const
|
|
4411
|
+
const accepts = createAcceptsTag(
|
|
4412
|
+
(tag, range) => ports.versionCheck.isCompatible(tag, range),
|
|
4413
|
+
(a, b) => ports.versionCheck.compare(a, b)
|
|
4414
|
+
);
|
|
3935
4415
|
return (remoteEntry) => {
|
|
3936
4416
|
try {
|
|
4417
|
+
const pending = [];
|
|
4418
|
+
storeRemoteEntry(remoteEntry, (_, external, ctx) => pending.push({ external, ctx }));
|
|
4419
|
+
const decisions = decidePackages(remoteEntry, pending);
|
|
3937
4420
|
const actions = {};
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
const { action, provided, sameVersion } = resolveSharedExternal(entry, external, ctx);
|
|
3941
|
-
actions[external.packageName] = { action };
|
|
3942
|
-
if (action === "skip" && provided) {
|
|
3943
|
-
actions[external.packageName].covered = Array.from(provided.keys());
|
|
3944
|
-
if (sameVersion) actions[external.packageName].sameVersion = true;
|
|
3945
|
-
if (external.shareScope) {
|
|
3946
|
-
actions[external.packageName].override = resolveOverrideEntries(
|
|
3947
|
-
entry,
|
|
3948
|
-
external,
|
|
3949
|
-
provided
|
|
3950
|
-
);
|
|
3951
|
-
}
|
|
3952
|
-
}
|
|
3953
|
-
});
|
|
4421
|
+
for (const item of pending)
|
|
4422
|
+
actions[item.external.packageName] = applyDecision(remoteEntry, item, decisions.get(item));
|
|
3954
4423
|
return Promise.resolve({ entry: remoteEntry, actions });
|
|
3955
4424
|
} catch (error) {
|
|
3956
4425
|
return Promise.reject(error);
|
|
3957
4426
|
}
|
|
3958
4427
|
};
|
|
3959
|
-
function
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
commit
|
|
3966
|
-
}) {
|
|
3967
|
-
let action = scopeType === "strict" ? "share" : "skip";
|
|
3968
|
-
const sharedVersion = cached2.versions.find((c) => c.action === "share");
|
|
3969
|
-
const isCompatible = !sharedVersion || ports.versionCheck.isCompatible(sharedVersion.tag, remote.requiredVersion);
|
|
3970
|
-
if (action === "skip" && !isCompatible && remote.strictVersion) {
|
|
3971
|
-
action = "scope";
|
|
3972
|
-
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}'`;
|
|
3973
|
-
if (config.strict.strictExternalCompatibility) {
|
|
3974
|
-
config.log.error(8, errorMsg);
|
|
3975
|
-
throw new NFError(`Could not process remote '${remoteEntry.name}'`);
|
|
3976
|
-
}
|
|
3977
|
-
config.log.warn(8, errorMsg);
|
|
4428
|
+
function decidePackages(remoteEntry, pending) {
|
|
4429
|
+
const decisions = /* @__PURE__ */ new Map();
|
|
4430
|
+
const viewOf = loadViewOf(remoteEntry, pending);
|
|
4431
|
+
for (const group of pendingPerPackage(pending, viewOf)) {
|
|
4432
|
+
const decision = group[0].ctx.scopeType === "strict" ? { action: "share" } : decidePackage(remoteEntry, group, viewOf(group[0].external.shareScope));
|
|
4433
|
+
for (const item of group) decisions.set(item, decision);
|
|
3978
4434
|
}
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
4435
|
+
scopeOpenedPackages(decisions);
|
|
4436
|
+
return decisions;
|
|
4437
|
+
}
|
|
4438
|
+
function pendingPerPackage(pending, viewOf) {
|
|
4439
|
+
const packages = /* @__PURE__ */ new Map();
|
|
4440
|
+
for (const item of pending) {
|
|
4441
|
+
const { shareScope, packageName } = item.external;
|
|
4442
|
+
const pkg = item.ctx.scopeType === "strict" ? packageName : viewOf(shareScope).packageOf(packageName);
|
|
4443
|
+
const key = `${shareScope ?? GLOBAL_SCOPE}\0${pkg}`;
|
|
4444
|
+
const group = packages.get(key);
|
|
4445
|
+
if (group) group.push(item);
|
|
4446
|
+
else packages.set(key, [item]);
|
|
4447
|
+
}
|
|
4448
|
+
return [...packages.values()];
|
|
4449
|
+
}
|
|
4450
|
+
function loadViewOf(remoteEntry, pending) {
|
|
4451
|
+
const views = /* @__PURE__ */ new Map();
|
|
4452
|
+
return (shareScope) => {
|
|
4453
|
+
const scope = shareScope ?? GLOBAL_SCOPE;
|
|
4454
|
+
let view = views.get(scope);
|
|
4455
|
+
if (!view) {
|
|
4456
|
+
const record = ports.sharedExternalsRepo.getFromScope(shareScope);
|
|
4457
|
+
const claims = committedClaims(Object.entries(record), {
|
|
4458
|
+
shareScope: scope,
|
|
4459
|
+
without: remoteEntry.name
|
|
4460
|
+
});
|
|
4461
|
+
const packageOf = packageOfIn(record, loadingIn(pending, scope));
|
|
4462
|
+
const claimsIn = groupByPackage(claims, ([specifier]) => specifier, packageOf);
|
|
4463
|
+
let pooled;
|
|
4464
|
+
view = {
|
|
4465
|
+
packageOf,
|
|
4466
|
+
claims,
|
|
4467
|
+
claimsOf: (pkg) => claimsIn.get(pkg) ?? [],
|
|
4468
|
+
inPool: (pkg) => {
|
|
4469
|
+
pooled ??= pooledPackagesWith(record, labelledCopiesIn(pending, scope), packageOf);
|
|
4470
|
+
return pooled.has(pkg);
|
|
4471
|
+
}
|
|
4472
|
+
};
|
|
4473
|
+
views.set(scope, view);
|
|
3993
4474
|
}
|
|
4475
|
+
return view;
|
|
4476
|
+
};
|
|
4477
|
+
}
|
|
4478
|
+
function inScope(pending, scope) {
|
|
4479
|
+
return pending.filter(({ external }) => (external.shareScope ?? GLOBAL_SCOPE) === scope);
|
|
4480
|
+
}
|
|
4481
|
+
function loadingIn(pending, scope) {
|
|
4482
|
+
return inScope(pending, scope).map(({ external, ctx }) => [external.packageName, ctx.remote]);
|
|
4483
|
+
}
|
|
4484
|
+
function labelledCopiesIn(pending, scope) {
|
|
4485
|
+
return inScope(pending, scope).map(({ external, ctx }) => ({
|
|
4486
|
+
name: external.packageName,
|
|
4487
|
+
pool: ctx.remote.pool
|
|
4488
|
+
}));
|
|
4489
|
+
}
|
|
4490
|
+
function scopeOpenedPackages(decisions) {
|
|
4491
|
+
if (![...decisions.values()].some((d) => d.action === "scope" && d.partlyServed)) return;
|
|
4492
|
+
for (const [item, decision] of decisions)
|
|
4493
|
+
if (decision.action === "share" && item.ctx.scopeType !== "strict")
|
|
4494
|
+
decisions.set(item, { action: "scope", partlyServed: false });
|
|
4495
|
+
}
|
|
4496
|
+
function decidePackage(remoteEntry, group, view) {
|
|
4497
|
+
const pkg = view.packageOf(group[0].external.packageName);
|
|
4498
|
+
const claims = view.claimsOf(pkg);
|
|
4499
|
+
if (claims.length === 0) return { action: "share" };
|
|
4500
|
+
const specifiers = group.flatMap(({ external }) => Object.keys(external.entries));
|
|
4501
|
+
const builds = specifiers.every((specifier) => view.claims.has(specifier)) ? new Set(specifiers.map((specifier) => view.claims.get(specifier).copy.name)) : void 0;
|
|
4502
|
+
const rejections = group.flatMap((item) => rejectionsOf(item, view.claims));
|
|
4503
|
+
if (rejections.length > 0) {
|
|
4504
|
+
const copies = group.map(({ ctx }) => ({ tag: ctx.tag, copy: ctx.remote }));
|
|
4505
|
+
const splits = builds !== void 0 && builds.size > 1 || loadSplitsPackage(pkg, copies, claims, accepts);
|
|
4506
|
+
for (const rejection of refused(rejections, splits, view.inPool(pkg)))
|
|
4507
|
+
reportIncompatible(remoteEntry, rejection);
|
|
4508
|
+
return { action: "scope", partlyServed: false };
|
|
3994
4509
|
}
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4510
|
+
if (!builds || builds.size > 1) return { action: "scope", partlyServed: true };
|
|
4511
|
+
return { action: "skip", files: servingFiles(claims, builds) };
|
|
4512
|
+
}
|
|
4513
|
+
function servingFiles(claims, builds) {
|
|
4514
|
+
const files = /* @__PURE__ */ new Map();
|
|
4515
|
+
for (const [specifier, { copy }] of claims)
|
|
4516
|
+
if (builds.has(copy.name)) files.set(specifier, copy);
|
|
4517
|
+
return files;
|
|
4518
|
+
}
|
|
4519
|
+
function rejectionsOf(item, claims) {
|
|
4520
|
+
const { external, ctx } = item;
|
|
4521
|
+
if (!ctx.remote.strictVersion) return [];
|
|
4522
|
+
return Object.keys(external.entries).flatMap((specifier) => {
|
|
4523
|
+
const claim = claims.get(specifier);
|
|
4524
|
+
return claim && !accepts(claim.tag, ctx.tag, ctx.remote.requiredVersion) ? [{ item, specifier, claim }] : [];
|
|
4525
|
+
});
|
|
4526
|
+
}
|
|
4527
|
+
function refused(rejections, splits, pooled) {
|
|
4528
|
+
const first = /* @__PURE__ */ new Map();
|
|
4529
|
+
for (const rejection of rejections)
|
|
4530
|
+
if (!first.has(rejection.item) && (pooled || !splits || electionKeeps(rejection)))
|
|
4531
|
+
first.set(rejection.item, rejection);
|
|
4532
|
+
return [...first.values()];
|
|
4533
|
+
}
|
|
4534
|
+
function electionKeeps({ item: { external, ctx }, claim }) {
|
|
4535
|
+
if (claim.external !== external.packageName) return false;
|
|
4536
|
+
const versions = ports.sharedExternalsRepo.tryGet(claim.external, external.shareScope).get()?.versions ?? [];
|
|
4537
|
+
const strict = [
|
|
4538
|
+
{ tag: ctx.tag, copy: ctx.remote },
|
|
4539
|
+
...versions.flatMap(
|
|
4540
|
+
(v) => v.remotes.filter((r) => r.strictVersion).map((copy) => ({ tag: v.tag, copy }))
|
|
4541
|
+
)
|
|
4542
|
+
];
|
|
4543
|
+
const tags = [ctx.tag, ...versions.map((v) => v.tag)];
|
|
4544
|
+
if (!tags.some((tag) => strict.every((s) => accepts(tag, s.tag, s.copy.requiredVersion))))
|
|
4545
|
+
return true;
|
|
4546
|
+
const host = versions.find((v) => v.host);
|
|
4547
|
+
if (host) return host.tag === claim.tag;
|
|
4548
|
+
if (!config.profile.latestSharedExternal) return false;
|
|
4549
|
+
return tags.every((tag) => ports.versionCheck.compare(claim.tag, tag) >= 0);
|
|
4550
|
+
}
|
|
4551
|
+
function reportIncompatible(remoteEntry, { item: { external, ctx }, specifier, claim }) {
|
|
4552
|
+
const errorMsg = `[${external.shareScope ?? GLOBAL_SCOPE}][${remoteEntry.name}] ${specifier}@${ctx.tag} Is not compatible with existing ${specifier}@${claim.tag} requiredRange '${ctx.remote.requiredVersion}'`;
|
|
4553
|
+
if (config.strict.strictExternalCompatibility) {
|
|
4554
|
+
config.log.error(8, errorMsg);
|
|
4555
|
+
throw new NFError(`Could not process remote '${remoteEntry.name}'`);
|
|
4008
4556
|
}
|
|
4009
|
-
|
|
4010
|
-
return { action, provided, sameVersion };
|
|
4557
|
+
config.log.warn(8, errorMsg);
|
|
4011
4558
|
}
|
|
4012
|
-
function
|
|
4559
|
+
function applyDecision(remoteEntry, { external, ctx }, decision) {
|
|
4560
|
+
storeCopy(ctx, decision.action);
|
|
4561
|
+
if (decision.action !== "skip") return { action: decision.action };
|
|
4562
|
+
const covered = Object.keys(external.entries);
|
|
4563
|
+
if (!external.shareScope) return { action: "skip", covered };
|
|
4564
|
+
return {
|
|
4565
|
+
action: "skip",
|
|
4566
|
+
covered,
|
|
4567
|
+
override: overrideFrom(remoteEntry, external, decision.files)
|
|
4568
|
+
};
|
|
4569
|
+
}
|
|
4570
|
+
function storeCopy(ctx, action) {
|
|
4571
|
+
const { tag, remote } = ctx;
|
|
4572
|
+
const cached2 = ctx.readRecord();
|
|
4573
|
+
const shared = cached2.versions.find((v) => v.tag === tag && v.action === "share");
|
|
4574
|
+
if (shared && action !== "scope") ctx.assertSameVersionCompatibility(shared);
|
|
4575
|
+
remote.cached = action !== "skip";
|
|
4576
|
+
const row = action === "share" ? shared : cached2.versions.find((v) => v.tag === tag && v.action === action);
|
|
4577
|
+
const loaderServes = action === "share" && ctx.scopeType !== "strict";
|
|
4578
|
+
if (!row) cached2.versions.push({ tag, action, host: false, remotes: [remote] });
|
|
4579
|
+
else if (loaderServes) addRemoteToVersion(row, remote);
|
|
4580
|
+
else row.remotes.push(remote);
|
|
4581
|
+
if (loaderServes) cached2.servingBuild = remote.name;
|
|
4582
|
+
ctx.write();
|
|
4583
|
+
}
|
|
4584
|
+
function overrideFrom(remoteEntry, external, files) {
|
|
4013
4585
|
return Object.fromEntries(
|
|
4014
|
-
Array.from(
|
|
4015
|
-
|
|
4016
|
-
join(
|
|
4017
|
-
providerScopeUrl(remoteEntry, external, provider.name),
|
|
4018
|
-
provider.entries[packageName]
|
|
4019
|
-
)
|
|
4586
|
+
Array.from(files, ([specifier, copy]) => [
|
|
4587
|
+
specifier,
|
|
4588
|
+
join(providerScopeUrl(remoteEntry, external, copy.name), copy.entries[specifier])
|
|
4020
4589
|
])
|
|
4021
4590
|
);
|
|
4022
4591
|
}
|
|
@@ -4031,181 +4600,335 @@ function createUpdateCache(config, ports) {
|
|
|
4031
4600
|
}
|
|
4032
4601
|
}
|
|
4033
4602
|
|
|
4034
|
-
// src/lib/core/
|
|
4035
|
-
function
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
for (const
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
const
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4603
|
+
// src/lib/core/1.domain/pooling/gate.ts
|
|
4604
|
+
function committedView(members, shipped, recordOrder, {
|
|
4605
|
+
shareScope,
|
|
4606
|
+
without,
|
|
4607
|
+
packageOf
|
|
4608
|
+
}) {
|
|
4609
|
+
const global = /* @__PURE__ */ new Map();
|
|
4610
|
+
const claims = committedClaims(inRecordOrder(members, recordOrder), { shareScope, without });
|
|
4611
|
+
for (const [specifier, { tag, copy }] of claims)
|
|
4612
|
+
global.set(specifier, { tag, remote: copy.name, file: copy.entries[specifier] });
|
|
4613
|
+
const builds = /* @__PURE__ */ new Map();
|
|
4614
|
+
for (const [owner, copies] of shipped)
|
|
4615
|
+
if (owner !== without) builds.set(owner, buildOf(owner, copies, packageOf));
|
|
4616
|
+
const fileOf = subpoolFilesOf(members);
|
|
4617
|
+
return {
|
|
4618
|
+
packageOf,
|
|
4619
|
+
builds,
|
|
4620
|
+
global,
|
|
4621
|
+
runsOffMap: runsOffMapOf(members, global, builds, fileOf)
|
|
4622
|
+
};
|
|
4623
|
+
}
|
|
4624
|
+
function subpoolFilesOf(members) {
|
|
4625
|
+
const subpoolOwners = /* @__PURE__ */ new Set();
|
|
4626
|
+
for (const member of members)
|
|
4627
|
+
for (const version of member.external.versions)
|
|
4628
|
+
for (const { servedBy } of version.remotes) if (servedBy) subpoolOwners.add(servedBy);
|
|
4629
|
+
const fileOf = /* @__PURE__ */ new Map();
|
|
4630
|
+
for (const member of members)
|
|
4631
|
+
for (const version of member.external.versions)
|
|
4632
|
+
for (const { name, entries } of version.remotes) {
|
|
4633
|
+
if (!subpoolOwners.has(name)) continue;
|
|
4634
|
+
let files = fileOf.get(name);
|
|
4635
|
+
if (!files) fileOf.set(name, files = /* @__PURE__ */ new Map());
|
|
4636
|
+
for (const specifier in entries)
|
|
4637
|
+
if (!files.has(specifier)) files.set(specifier, entries[specifier]);
|
|
4638
|
+
}
|
|
4639
|
+
return fileOf;
|
|
4640
|
+
}
|
|
4641
|
+
function runsOffMapOf(members, global, builds, fileOf) {
|
|
4642
|
+
const runsOffMap2 = /* @__PURE__ */ new Map();
|
|
4643
|
+
for (const member of members)
|
|
4644
|
+
for (const version of member.external.versions)
|
|
4645
|
+
for (const meta of version.remotes) {
|
|
4646
|
+
const { servedBy } = meta;
|
|
4647
|
+
if (version.action === "share" && !servedBy) continue;
|
|
4648
|
+
let runs = runsOffMap2.get(meta.name);
|
|
4649
|
+
if (!runs) runsOffMap2.set(meta.name, runs = /* @__PURE__ */ new Map());
|
|
4650
|
+
for (const specifier in meta.entries) {
|
|
4651
|
+
if (version.action === "skip" && !servedBy && global.has(specifier)) continue;
|
|
4652
|
+
const tag = (servedBy ? builds.get(servedBy)?.tags.pinnedTag(specifier) : void 0) ?? version.tag;
|
|
4653
|
+
const file = servedBy && fileOf.get(servedBy)?.get(specifier);
|
|
4654
|
+
runs.set(
|
|
4655
|
+
specifier,
|
|
4656
|
+
file ? { tag, remote: servedBy, file } : { tag, remote: meta.name, file: meta.entries[specifier] }
|
|
4075
4657
|
);
|
|
4076
|
-
mine.forEach((member) => scope(member.name, "uncovered"));
|
|
4077
|
-
continue;
|
|
4078
4658
|
}
|
|
4079
|
-
for (const name of redirect(entry.name, anchor, pool, asked.view, actions, shareScope))
|
|
4080
|
-
verdicts.set(name, { servedBy: anchor });
|
|
4081
4659
|
}
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4660
|
+
return runsOffMap2;
|
|
4661
|
+
}
|
|
4662
|
+
function judgeRemote(copies, view, accepts) {
|
|
4663
|
+
const { rejected, missing } = scan(copies, view, accepts);
|
|
4664
|
+
if (rejected) return { cause: "incompatible", ...rejected };
|
|
4665
|
+
const globalTags = new SpecifierTags(
|
|
4666
|
+
view.packageOf,
|
|
4667
|
+
[...view.global].map(([s, { tag }]) => [s, tag])
|
|
4668
|
+
);
|
|
4669
|
+
const binding = offMapBinding(copies, view, globalTags);
|
|
4670
|
+
if (binding) return { cause: "uncovered", ...binding };
|
|
4671
|
+
if (servedSplit(copies, view)) return { cause: "uncovered", unshipped: true };
|
|
4672
|
+
if (agrees(copies, globalTags)) return "global";
|
|
4673
|
+
if (missing !== void 0) return { cause: "uncovered", specifier: missing };
|
|
4674
|
+
if (unwitnessedGap(copies, globalTags, view.builds.values()) === void 0) return "global";
|
|
4675
|
+
return { cause: "uncovered", unshipped: true };
|
|
4676
|
+
}
|
|
4677
|
+
function servedSplit(copies, view) {
|
|
4678
|
+
const loaded = new Set(copies.flatMap((copy) => copy.specifiers.map(view.packageOf)));
|
|
4679
|
+
const servedBy = /* @__PURE__ */ new Map();
|
|
4680
|
+
for (const [specifier, { remote }] of view.global) {
|
|
4681
|
+
const pkg = view.packageOf(specifier);
|
|
4682
|
+
if (!loaded.has(pkg)) continue;
|
|
4683
|
+
const first = servedBy.get(pkg);
|
|
4684
|
+
if (first === void 0) servedBy.set(pkg, remote);
|
|
4685
|
+
else if (first !== remote) return true;
|
|
4686
|
+
}
|
|
4687
|
+
return false;
|
|
4688
|
+
}
|
|
4689
|
+
function coverFromMap(remote, mine, view, actions, policy) {
|
|
4690
|
+
const files = [];
|
|
4691
|
+
for (const member of mine) {
|
|
4692
|
+
const action = actions[member.name];
|
|
4693
|
+
const copy = member.external.versions.flatMap((v) => v.remotes).find((r) => r.name === remote);
|
|
4694
|
+
if (!copy) continue;
|
|
4695
|
+
const mapped = mapFiles(copy, view, policy, action);
|
|
4696
|
+
if ("unmapped" in mapped) return mapped;
|
|
4697
|
+
files.push({ member, action, copy, ...mapped });
|
|
4698
|
+
}
|
|
4699
|
+
const reaches = reachesOf(remote, files, view);
|
|
4700
|
+
const bound = boundByFile(reaches, view);
|
|
4701
|
+
if (bound !== void 0) return { bound };
|
|
4702
|
+
const servedPackages = new Set([...view.global.keys()].map(view.packageOf));
|
|
4703
|
+
const gap = files.map((file) => gapOf(file, servedPackages, view.packageOf)).find((specifier) => specifier !== void 0);
|
|
4704
|
+
if (gap !== void 0) return { gap };
|
|
4705
|
+
return { covers: files.filter(covering).map(coverOf) };
|
|
4706
|
+
}
|
|
4707
|
+
function gapOf({ copy, covered }, servedPackages, packageOf) {
|
|
4708
|
+
const entrypoints = Object.keys(copy.entries);
|
|
4709
|
+
const missing = entrypoints.filter((specifier) => !covered.has(specifier));
|
|
4710
|
+
if (missing.length < entrypoints.length) return missing[0];
|
|
4711
|
+
return missing.find((specifier) => servedPackages.has(packageOf(specifier)));
|
|
4712
|
+
}
|
|
4713
|
+
function covering({ action, copy, covered }) {
|
|
4714
|
+
if (action.action === "skip") return true;
|
|
4715
|
+
const entrypoints = Object.keys(copy.entries);
|
|
4716
|
+
return entrypoints.length > 0 && entrypoints.every((specifier) => covered.has(specifier));
|
|
4717
|
+
}
|
|
4718
|
+
function coverOf({ member, action, copy, covered, override }) {
|
|
4719
|
+
const toSkip = action.action !== "skip" || covered.size > action.covered.length && member.external.versions.some((v) => v.action === "share" && v.remotes.includes(copy));
|
|
4720
|
+
return { name: member.name, toSkip, override };
|
|
4721
|
+
}
|
|
4722
|
+
function reachesOf(remote, files, view) {
|
|
4723
|
+
const reaches = /* @__PURE__ */ new Map();
|
|
4724
|
+
const fromMap = (specifier) => {
|
|
4725
|
+
const served = view.global.get(specifier);
|
|
4726
|
+
return served && { remote: served.remote, file: served.file };
|
|
4727
|
+
};
|
|
4728
|
+
for (const file of files) {
|
|
4729
|
+
const takesMap = covering(file);
|
|
4730
|
+
for (const [specifier, own] of Object.entries(file.copy.entries)) {
|
|
4731
|
+
if (!takesMap || !file.covered.has(specifier)) reaches.set(specifier, { remote, file: own });
|
|
4732
|
+
else {
|
|
4733
|
+
const reach = fromMap(specifier);
|
|
4734
|
+
if (reach) reaches.set(specifier, reach);
|
|
4086
4735
|
}
|
|
4087
|
-
syncPoolNames({ ...committed, ...written }, pools, ports.sharedExternalsRepo, shareScope);
|
|
4088
4736
|
}
|
|
4089
|
-
return Promise.resolve({ entry, actions });
|
|
4090
|
-
};
|
|
4091
|
-
function gateViews(remote, pool) {
|
|
4092
|
-
return {
|
|
4093
|
-
pool,
|
|
4094
|
-
view: committedView(pool),
|
|
4095
|
-
wants: consumedMembers(pool).get(remote) ?? [],
|
|
4096
|
-
specifiers: consumedSpecifiers(pool).get(remote) ?? /* @__PURE__ */ new Set(),
|
|
4097
|
-
acceptance: lazy(() => acceptanceTable(pool, ports.versionCheck.isCompatible))
|
|
4098
|
-
};
|
|
4099
4737
|
}
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
if (
|
|
4110
|
-
|
|
4111
|
-
|
|
4738
|
+
return reaches;
|
|
4739
|
+
}
|
|
4740
|
+
function boundByFile(reaches, view) {
|
|
4741
|
+
const servers = /* @__PURE__ */ new Set();
|
|
4742
|
+
for (const { remote } of reaches.values()) if (view.builds.has(remote)) servers.add(remote);
|
|
4743
|
+
const firstRun = /* @__PURE__ */ new Map();
|
|
4744
|
+
for (const build of servers)
|
|
4745
|
+
for (const specifier of view.builds.get(build).tags.keys()) {
|
|
4746
|
+
const served = view.runsOffMap.get(build)?.get(specifier) ?? view.global.get(specifier);
|
|
4747
|
+
if (served === void 0) continue;
|
|
4748
|
+
const reached = reaches.get(specifier) ?? firstRun.get(specifier);
|
|
4749
|
+
if (reached === void 0) {
|
|
4750
|
+
firstRun.set(specifier, served);
|
|
4751
|
+
if (view.builds.has(served.remote)) servers.add(served.remote);
|
|
4752
|
+
} else if (reached.remote !== served.remote || reached.file !== served.file)
|
|
4753
|
+
return { owner: build, specifier, tag: served.tag };
|
|
4112
4754
|
}
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
const
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
let allScoped = true;
|
|
4126
|
-
for (const member of pool) {
|
|
4127
|
-
for (const version of member.external.versions) {
|
|
4128
|
-
const meta = version.remotes.find((r) => r.name === build);
|
|
4129
|
-
if (!meta) continue;
|
|
4130
|
-
if (meta.servedBy !== void 0) return false;
|
|
4131
|
-
ships2++;
|
|
4132
|
-
if (version.action !== "scope") allScoped = false;
|
|
4133
|
-
if (basis.get(member.name) !== build) winsAll = false;
|
|
4134
|
-
}
|
|
4755
|
+
return void 0;
|
|
4756
|
+
}
|
|
4757
|
+
function mapFiles(copy, view, policy, action) {
|
|
4758
|
+
const covered = new Set(action.covered);
|
|
4759
|
+
const override = { ...action.override };
|
|
4760
|
+
for (const specifier in copy.entries) {
|
|
4761
|
+
const source = view.global.get(specifier);
|
|
4762
|
+
if (!source) continue;
|
|
4763
|
+
if (policy.shareScope !== GLOBAL_SCOPE) {
|
|
4764
|
+
const scopeUrl = policy.scopeUrlOf(source.remote);
|
|
4765
|
+
if (!scopeUrl) return { unmapped: source.remote };
|
|
4766
|
+
override[specifier] = join(scopeUrl, source.file);
|
|
4135
4767
|
}
|
|
4136
|
-
|
|
4137
|
-
}
|
|
4138
|
-
function explainDynamic(remote, { view, wants, specifiers, acceptance }) {
|
|
4139
|
-
return explainSelfServe(remote, wants, specifiers, {
|
|
4140
|
-
builds: view.builds,
|
|
4141
|
-
acceptance: acceptance()
|
|
4142
|
-
});
|
|
4768
|
+
covered.add(specifier);
|
|
4143
4769
|
}
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
);
|
|
4152
|
-
|
|
4770
|
+
return { covered, override };
|
|
4771
|
+
}
|
|
4772
|
+
function scan(copies, view, accepts) {
|
|
4773
|
+
let rejected;
|
|
4774
|
+
let missing;
|
|
4775
|
+
for (const copy of copies)
|
|
4776
|
+
for (const s of copy.specifiers) {
|
|
4777
|
+
const global = view.global.get(s);
|
|
4778
|
+
if (global === void 0) missing ??= s;
|
|
4779
|
+
else if (!accepts(global.tag, copy.tag, copy.requiredVersion))
|
|
4780
|
+
rejected ??= { specifier: s, tag: global.tag };
|
|
4153
4781
|
}
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
const file = files.get(specifier);
|
|
4167
|
-
if (file) override[specifier] = join(scopeUrl, file);
|
|
4168
|
-
}
|
|
4169
|
-
action.covered = specifiers;
|
|
4170
|
-
if (Object.keys(override).length > 0) action.override = override;
|
|
4171
|
-
if (basis.get(member.name) !== anchor) served.push(member.name);
|
|
4782
|
+
return { rejected, missing };
|
|
4783
|
+
}
|
|
4784
|
+
function offMapBinding(copies, view, globalTags) {
|
|
4785
|
+
const own = new SpecifierTags(
|
|
4786
|
+
view.packageOf,
|
|
4787
|
+
copies.flatMap((c) => c.specifiers.map((s) => [s, c.tag]))
|
|
4788
|
+
);
|
|
4789
|
+
const servers = /* @__PURE__ */ new Set();
|
|
4790
|
+
for (const copy of copies)
|
|
4791
|
+
for (const specifier of copy.specifiers) {
|
|
4792
|
+
const build = view.global.get(specifier)?.remote;
|
|
4793
|
+
if (build !== void 0) servers.add(build);
|
|
4172
4794
|
}
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
versions: external.versions.map((v) => ({
|
|
4180
|
-
...v,
|
|
4181
|
-
remotes: v.remotes.map(
|
|
4182
|
-
(r) => r.name === remote ? { ...r, servedBy: verdict.servedBy } : r
|
|
4183
|
-
)
|
|
4184
|
-
}))
|
|
4185
|
-
};
|
|
4795
|
+
const firstRun = new SpecifierTags(view.packageOf);
|
|
4796
|
+
for (const build of servers)
|
|
4797
|
+
for (const [specifier, { tag }] of view.runsOffMap.get(build) ?? []) {
|
|
4798
|
+
const reached = globalTags.pinnedTag(specifier) ?? own.pinnedTag(specifier) ?? firstRun.pinnedTag(specifier);
|
|
4799
|
+
if (reached === void 0) firstRun.set(specifier, tag);
|
|
4800
|
+
else if (reached !== tag) return { owner: build, specifier, tag };
|
|
4186
4801
|
}
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4802
|
+
return void 0;
|
|
4803
|
+
}
|
|
4804
|
+
function inRecordOrder(members, recordOrder) {
|
|
4805
|
+
const rank2 = new Map(recordOrder.map((name, i) => [name, i]));
|
|
4806
|
+
return [...members].sort((a, b) => rank2.get(a.name) - rank2.get(b.name)).map((m) => [m.name, m.external]);
|
|
4807
|
+
}
|
|
4808
|
+
|
|
4809
|
+
// src/lib/core/2.app/steps/pooling/pool-dynamic-externals.ts
|
|
4810
|
+
function createPoolDynamicExternals(config, ports) {
|
|
4811
|
+
const accepts = createAcceptsTag(
|
|
4812
|
+
(tag, range) => ports.versionCheck.isCompatible(tag, range),
|
|
4813
|
+
(a, b) => ports.versionCheck.compare(a, b)
|
|
4814
|
+
);
|
|
4815
|
+
const scopeUrlOf = (remote) => ports.remoteInfoRepo.tryGet(remote).get()?.scopeUrl;
|
|
4816
|
+
return ({ entry, actions }) => {
|
|
4817
|
+
for (const [scope, names] of poolableNames(entry, actions)) {
|
|
4818
|
+
const committed = ports.sharedExternalsRepo.getFromScope(scope);
|
|
4819
|
+
if (!scopeHasPoolState(committed)) continue;
|
|
4820
|
+
const { pools, packageOf } = buildPools(committed);
|
|
4821
|
+
const moves = judgeScope(
|
|
4822
|
+
entry.name,
|
|
4823
|
+
names,
|
|
4824
|
+
actions,
|
|
4825
|
+
pools,
|
|
4826
|
+
packageOf,
|
|
4827
|
+
Object.keys(committed),
|
|
4828
|
+
scope
|
|
4829
|
+
);
|
|
4830
|
+
writeMoves(entry.name, names, moves, committed, pools, scope);
|
|
4202
4831
|
}
|
|
4203
|
-
return {
|
|
4204
|
-
|
|
4205
|
-
|
|
4832
|
+
return Promise.resolve({ entry, actions: publicActions(actions) });
|
|
4833
|
+
};
|
|
4834
|
+
function judgeScope(remote, names, actions, pools, packageOf, recordOrder, scope) {
|
|
4835
|
+
const policy = { shareScope: scope, scopeUrlOf };
|
|
4836
|
+
const moves = /* @__PURE__ */ new Map();
|
|
4837
|
+
const selfServe = (members, cause) => {
|
|
4838
|
+
for (const { name } of members) {
|
|
4839
|
+
actions[name].action = "scope";
|
|
4840
|
+
delete actions[name].override;
|
|
4841
|
+
moves.set(name, { cause });
|
|
4842
|
+
}
|
|
4206
4843
|
};
|
|
4844
|
+
for (const pool of pools.values()) {
|
|
4845
|
+
const mine = pool.filter((member) => names.has(member.name));
|
|
4846
|
+
if (mine.length === 0) continue;
|
|
4847
|
+
const shipped = copiesByRemote(pool);
|
|
4848
|
+
const view = committedView(pool, shipped, recordOrder, {
|
|
4849
|
+
shareScope: scope,
|
|
4850
|
+
without: remote,
|
|
4851
|
+
packageOf
|
|
4852
|
+
});
|
|
4853
|
+
const own = shipped.get(remote) ?? [];
|
|
4854
|
+
const verdict = judgeRemote(own, view, accepts);
|
|
4855
|
+
if (verdict !== "global") {
|
|
4856
|
+
config.log.warn(8, `[${scope}] ${selfServeWarning(remote, verdict, specifierCount(own))}`);
|
|
4857
|
+
selfServe(mine, verdict.cause);
|
|
4858
|
+
continue;
|
|
4859
|
+
}
|
|
4860
|
+
const cover = coverFromMap(remote, mine, view, actions, policy);
|
|
4861
|
+
if (!("covers" in cover)) {
|
|
4862
|
+
if ("unmapped" in cover) warnUnmapped(scope, remote, cover.unmapped);
|
|
4863
|
+
else
|
|
4864
|
+
config.log.warn(
|
|
4865
|
+
8,
|
|
4866
|
+
`[${scope}] ${selfServeWarning(remote, coverMiss(cover), specifierCount(own))}`
|
|
4867
|
+
);
|
|
4868
|
+
selfServe(mine, "uncovered");
|
|
4869
|
+
continue;
|
|
4870
|
+
}
|
|
4871
|
+
for (const { name, toSkip, override } of cover.covers) {
|
|
4872
|
+
const action = actions[name];
|
|
4873
|
+
if (toSkip) {
|
|
4874
|
+
action.action = "skip";
|
|
4875
|
+
moves.set(name, { fromMap: true });
|
|
4876
|
+
}
|
|
4877
|
+
if (Object.keys(override).length > 0) action.override = override;
|
|
4878
|
+
}
|
|
4879
|
+
}
|
|
4880
|
+
return moves;
|
|
4881
|
+
}
|
|
4882
|
+
function writeMoves(remote, names, moves, committed, pools, scope) {
|
|
4883
|
+
const written = {};
|
|
4884
|
+
for (const [name, move] of moves)
|
|
4885
|
+
written[name] = movedRecord(committed[name], remote, move, ports.versionCheck.compare);
|
|
4886
|
+
for (const [name, record] of renamedRecords({ ...committed, ...written }, pools))
|
|
4887
|
+
written[name] = record;
|
|
4888
|
+
if (!config.strict.strictExternalCompatibility)
|
|
4889
|
+
for (const { name } of [...pools.values()].flat().filter((m) => names.has(m.name)))
|
|
4890
|
+
written[name] = { ...written[name] ?? committed[name], dirty: true };
|
|
4891
|
+
for (const [name, record] of Object.entries(written))
|
|
4892
|
+
ports.sharedExternalsRepo.addOrUpdate(name, record, scope);
|
|
4893
|
+
}
|
|
4894
|
+
function warnUnmapped(scope, remote, build) {
|
|
4895
|
+
config.log.warn(
|
|
4896
|
+
8,
|
|
4897
|
+
`[${scope}][${remote}] '${build}' is not in the cache, so its files cannot be mapped.`
|
|
4898
|
+
);
|
|
4207
4899
|
}
|
|
4208
4900
|
}
|
|
4901
|
+
function publicActions(actions) {
|
|
4902
|
+
for (const action of Object.values(actions)) delete action.covered;
|
|
4903
|
+
return actions;
|
|
4904
|
+
}
|
|
4905
|
+
function poolableNames(entry, actions) {
|
|
4906
|
+
const declared = /* @__PURE__ */ new Map();
|
|
4907
|
+
for (const external of entry.shared ?? []) {
|
|
4908
|
+
const name = external.packageName;
|
|
4909
|
+
if (!external.singleton || !actions[name]) continue;
|
|
4910
|
+
if (external.shareScope === STRICT_SCOPE) continue;
|
|
4911
|
+
const scope = external.shareScope ?? GLOBAL_SCOPE;
|
|
4912
|
+
let names = declared.get(scope);
|
|
4913
|
+
if (!names) declared.set(scope, names = /* @__PURE__ */ new Set());
|
|
4914
|
+
names.add(name);
|
|
4915
|
+
}
|
|
4916
|
+
return declared;
|
|
4917
|
+
}
|
|
4918
|
+
function coverMiss(cover) {
|
|
4919
|
+
if ("gap" in cover) return { cause: "uncovered", specifier: cover.gap };
|
|
4920
|
+
return { cause: "uncovered", ...cover.bound };
|
|
4921
|
+
}
|
|
4922
|
+
function selfServeWarning(remote, miss, imports) {
|
|
4923
|
+
const where = `All ${imports} of its entrypoints are scoped for it.`;
|
|
4924
|
+
if (miss.cause === "incompatible")
|
|
4925
|
+
return `'${remote}' is islanded: its range rejects '${miss.specifier}@${miss.tag}' of the committed map. ${where}`;
|
|
4926
|
+
if ("owner" in miss)
|
|
4927
|
+
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}`;
|
|
4928
|
+
if ("unshipped" in miss)
|
|
4929
|
+
return `'${remote}' serves its own family: no committed build shipped the map's combination for it. ${where}`;
|
|
4930
|
+
return `'${remote}' serves its own family: no committed build offers every entrypoint it imports at a version it accepts (gap '${miss.specifier}'). ${where}`;
|
|
4931
|
+
}
|
|
4209
4932
|
|
|
4210
4933
|
// src/lib/core/2.app/steps/convert-to-import-map.ts
|
|
4211
4934
|
function createConvertToImportMap(config, ports) {
|
|
@@ -4242,27 +4965,14 @@ function createConvertToImportMap(config, ports) {
|
|
|
4242
4965
|
return;
|
|
4243
4966
|
}
|
|
4244
4967
|
if (actions[external.packageName].action === "skip") {
|
|
4245
|
-
const { override
|
|
4968
|
+
const { override } = actions[external.packageName];
|
|
4246
4969
|
if (override) {
|
|
4247
4970
|
Object.entries(override).forEach(([packageName, url]) => {
|
|
4248
4971
|
addToScopes(remoteEntryScope, packageName, url, importMap);
|
|
4249
4972
|
});
|
|
4250
|
-
serveUncovered(
|
|
4251
|
-
remoteEntry,
|
|
4252
|
-
external,
|
|
4253
|
-
covered ?? Object.keys(override),
|
|
4254
|
-
remoteEntryScope,
|
|
4255
|
-
importMap,
|
|
4256
|
-
sameVersion
|
|
4257
|
-
);
|
|
4258
|
-
return;
|
|
4259
|
-
}
|
|
4260
|
-
if (!external.shareScope) {
|
|
4261
|
-
if (covered) {
|
|
4262
|
-
serveUncovered(remoteEntry, external, covered, remoteEntryScope, importMap, sameVersion);
|
|
4263
|
-
}
|
|
4264
4973
|
return;
|
|
4265
4974
|
}
|
|
4975
|
+
if (!external.shareScope) return;
|
|
4266
4976
|
log.error(
|
|
4267
4977
|
9,
|
|
4268
4978
|
`[${remoteEntry.name}][${external.packageName}] shareScope skip has no override.`
|
|
@@ -4327,27 +5037,6 @@ function createConvertToImportMap(config, ports) {
|
|
|
4327
5037
|
});
|
|
4328
5038
|
return importMap;
|
|
4329
5039
|
}
|
|
4330
|
-
function serveUncovered(remoteEntry, external, covered, remoteEntryScope, importMap, sameVersion = false) {
|
|
4331
|
-
const provided = new Set(covered);
|
|
4332
|
-
Object.entries(external.entries).forEach(([packageName, fileName]) => {
|
|
4333
|
-
if (provided.has(packageName)) return;
|
|
4334
|
-
if (!sameVersion && (config.strict.strictEntryPointCoverage || config.profile.scopeUncoveredEntrypoints)) {
|
|
4335
|
-
warnUncoveredEntrypoint(remoteEntry.name, external.packageName, packageName);
|
|
4336
|
-
return;
|
|
4337
|
-
}
|
|
4338
|
-
const url = join(remoteEntryScope, fileName);
|
|
4339
|
-
addToScopes(remoteEntryScope, packageName, url, importMap);
|
|
4340
|
-
addIntegrity(importMap, url, remoteEntry.integrity, fileName);
|
|
4341
|
-
});
|
|
4342
|
-
}
|
|
4343
|
-
function warnUncoveredEntrypoint(remoteName, externalName, packageName) {
|
|
4344
|
-
const msg = `[${remoteName}][${externalName}] Entrypoint '${packageName}' is not covered by the override.`;
|
|
4345
|
-
if (config.strict.strictEntryPointCoverage || config.strict.strictImportMap) {
|
|
4346
|
-
log.error(9, msg);
|
|
4347
|
-
throw new NFError("Could not create ImportMap.");
|
|
4348
|
-
}
|
|
4349
|
-
log.warn(9, msg);
|
|
4350
|
-
}
|
|
4351
5040
|
function addIntegrity(importMap, url, integrityMap, file) {
|
|
4352
5041
|
const hash = integrityMap?.[file];
|
|
4353
5042
|
if (!hash) return;
|
|
@@ -4363,11 +5052,12 @@ var createInitDrivers = ({
|
|
|
4363
5052
|
}) => ({
|
|
4364
5053
|
getRemoteEntries: createGetRemoteEntries(config, adapters),
|
|
4365
5054
|
processRemoteEntries: createProcessRemoteEntries(config, adapters),
|
|
4366
|
-
markPoolsForReelection: createMarkPoolsForReelection(config, adapters),
|
|
4367
5055
|
determineSharedExternals: createDetermineSharedExternals(config, adapters),
|
|
4368
5056
|
poolSharedExternals: createPoolSharedExternals(config, adapters),
|
|
5057
|
+
decideServingBuilds: createDecideServingBuilds(config, adapters),
|
|
4369
5058
|
generateImportMap: createGenerateImportMap(config, adapters),
|
|
4370
5059
|
commitChanges: createCommitChanges(config, adapters),
|
|
5060
|
+
rollbackChanges: createRollbackChanges(config, adapters),
|
|
4371
5061
|
exposeModuleLoader: createExposeModuleLoader(config, adapters),
|
|
4372
5062
|
getRemoteEntry: createGetRemoteEntry(config, adapters),
|
|
4373
5063
|
updateCache: createUpdateCache(config, adapters),
|
|
@@ -4387,14 +5077,6 @@ var INIT_FLOW_FACTORY = ({
|
|
|
4387
5077
|
};
|
|
4388
5078
|
|
|
4389
5079
|
// src/lib/core/5.di/federation-result.factory.ts
|
|
4390
|
-
var createStateDump = (config, adapters) => (msg) => config.log.debug(0, msg, {
|
|
4391
|
-
remotes: { ...adapters.remoteInfoRepo.getAll() },
|
|
4392
|
-
"shared-externals": adapters.sharedExternalsRepo.getScopes({ includeGlobal: true }).reduce(
|
|
4393
|
-
(acc, scope) => ({ ...acc, [scope]: adapters.sharedExternalsRepo.getFromScope(scope) }),
|
|
4394
|
-
{}
|
|
4395
|
-
),
|
|
4396
|
-
"scoped-externals": adapters.scopedExternalsRepo.getAll()
|
|
4397
|
-
});
|
|
4398
5080
|
var createFederationResult = ({
|
|
4399
5081
|
config,
|
|
4400
5082
|
adapters,
|
|
@@ -4402,11 +5084,8 @@ var createFederationResult = ({
|
|
|
4402
5084
|
initRemoteEntryFlow,
|
|
4403
5085
|
afterInitRemoteEntry
|
|
4404
5086
|
}) => {
|
|
4405
|
-
const stateDump = createStateDump(config, adapters);
|
|
4406
5087
|
const initRemoteEntry = async (remoteEntryUrl, remote) => {
|
|
4407
|
-
const remoteName = typeof remote === "string" ? remote : remote?.name;
|
|
4408
5088
|
return initRemoteEntryFlow(remoteEntryUrl, remote).catch((e) => {
|
|
4409
|
-
stateDump(`[dynamic-init][${remoteName ?? remoteEntryUrl}] STATE DUMP`);
|
|
4410
5089
|
if (config.strict.strictRemoteEntry) return Promise.reject(e);
|
|
4411
5090
|
else console.warn("Failed to initialize remote entry, continuing anyway.");
|
|
4412
5091
|
return Promise.resolve();
|
|
@@ -4554,7 +5233,9 @@ var resolveHostInstances = async (option, deps) => {
|
|
|
4554
5233
|
const entry = await deps.remoteEntryProvider.provide(url, { integrity });
|
|
4555
5234
|
const load = auto.load ?? ((specifier) => import(specifier));
|
|
4556
5235
|
const specifiers = [
|
|
4557
|
-
...new Set(
|
|
5236
|
+
...new Set(
|
|
5237
|
+
(entry.shared ?? []).filter((s) => s.singleton).flatMap((s) => Object.keys(s.entries))
|
|
5238
|
+
)
|
|
4558
5239
|
].filter((s) => auto.include ? matches(s, auto.include) : true).filter((s) => auto.exclude ? !matches(s, auto.exclude) : true);
|
|
4559
5240
|
const map = {};
|
|
4560
5241
|
for (const specifier of specifiers) {
|
|
@@ -4590,7 +5271,7 @@ var HOST_INSTANCES_GLOBAL = "__NF_HOST_INSTANCES__";
|
|
|
4590
5271
|
var buildNodeAdapters = (config) => ({
|
|
4591
5272
|
versionCheck: createVersionCheck(),
|
|
4592
5273
|
manifestProvider: createFsManifestProvider(),
|
|
4593
|
-
remoteEntryProvider: createFsRemoteEntryProvider(),
|
|
5274
|
+
remoteEntryProvider: createFsRemoteEntryProvider(config),
|
|
4594
5275
|
remoteInfoRepo: createRemoteInfoRepository(config),
|
|
4595
5276
|
scopedExternalsRepo: createScopedExternalsRepository(config),
|
|
4596
5277
|
sharedExternalsRepo: createSharedExternalsRepository(config),
|