@softarc/native-federation-orchestrator 4.8.0 → 4.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/fesm2022/@softarc/native-federation-orchestrator.mjs +399 -235
  2. package/fesm2022/@softarc/native-federation-orchestrator.mjs.map +3 -3
  3. package/fesm2022/module-federation.mjs +78 -21
  4. package/fesm2022/module-federation.mjs.map +3 -3
  5. package/fesm2022/node.mjs +468 -238
  6. package/fesm2022/node.mjs.map +3 -3
  7. package/fesm2022/options.mjs +4 -2
  8. package/fesm2022/options.mjs.map +2 -2
  9. package/package.json +1 -1
  10. package/quickstart.mjs +14 -14
  11. package/types/lib/core/1.domain/externals/claims.d.ts +1 -2
  12. package/types/lib/core/1.domain/externals/serving.d.ts +2 -2
  13. package/types/lib/core/1.domain/externals/specifier.d.ts +11 -6
  14. package/types/lib/core/1.domain/externals/version.contract.d.ts +1 -0
  15. package/types/lib/core/1.domain/pooling/builds.d.ts +2 -2
  16. package/types/lib/core/1.domain/pooling/election.d.ts +2 -1
  17. package/types/lib/core/1.domain/pooling/gate.d.ts +4 -2
  18. package/types/lib/core/1.domain/pooling/membership.d.ts +4 -2
  19. package/types/lib/core/1.domain/pooling/plan.d.ts +2 -0
  20. package/types/lib/core/1.domain/remote-entry/mark-dense.d.ts +2 -0
  21. package/types/lib/core/1.domain/remote-entry/remote-entry.contract.d.ts +5 -2
  22. package/types/lib/core/2.app/config/mode.contract.d.ts +1 -0
  23. package/types/lib/core/2.app/steps/get-remote-entries.d.ts +1 -1
  24. package/types/lib/core/2.app/steps/store-remote-entry.d.ts +3 -3
  25. package/types/lib/core/3.adapters/remote-entry/normalize-remote-entry.d.ts +4 -0
  26. package/types/lib/core/4.config/storage/storage.config.d.ts +2 -1
  27. package/types/lib/node/adapters/fs-remote-entry-provider.d.ts +2 -1
  28. package/types/lib/utils/union-find.d.ts +4 -0
package/fesm2022/node.mjs CHANGED
@@ -1406,14 +1406,94 @@ var createFsManifestProvider = () => {
1406
1406
  };
1407
1407
  };
1408
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
+
1409
1495
  // src/lib/node/adapters/fs-remote-entry-provider.ts
1410
- var createFsRemoteEntryProvider = () => {
1411
- const fillEmptyFields = (remoteEntryUrl) => (remoteEntry) => {
1412
- if (!remoteEntry.exposes) remoteEntry.exposes = [];
1413
- if (!remoteEntry.shared) remoteEntry.shared = [];
1414
- if (!remoteEntry.url) remoteEntry.url = remoteEntryUrl;
1415
- return remoteEntry;
1416
- };
1496
+ var createFsRemoteEntryProvider = (config) => {
1417
1497
  const formatError = (remoteEntryUrl) => (err) => {
1418
1498
  if (err instanceof NFError) throw err;
1419
1499
  const msg = err instanceof Error ? err.message : String(err);
@@ -1424,8 +1504,8 @@ var createFsRemoteEntryProvider = () => {
1424
1504
  try {
1425
1505
  const bytes = await readSourceBytes(remoteEntryUrl);
1426
1506
  if (opts.integrity) await verifyIntegrity(bytes, opts.integrity);
1427
- const parsed = JSON.parse(new TextDecoder().decode(bytes));
1428
- return fillEmptyFields(remoteEntryUrl)(parsed);
1507
+ const raw = JSON.parse(new TextDecoder().decode(bytes));
1508
+ return normalizeRemoteEntry(raw, remoteEntryUrl, config);
1429
1509
  } catch (err) {
1430
1510
  return formatError(remoteEntryUrl)(err);
1431
1511
  }
@@ -1980,7 +2060,7 @@ globalThisStorageEntry.type = "globalThis";
1980
2060
  Object.freeze(globalThisStorageEntry);
1981
2061
 
1982
2062
  // src/lib/core/4.config/orchestrator-version.ts
1983
- var ORCHESTRATOR_VERSION = true ? "4.8.0" : "dev";
2063
+ var ORCHESTRATOR_VERSION = true ? "4.9.0" : "dev";
1984
2064
 
1985
2065
  // src/lib/core/4.config/storage/publish-storage-info.ts
1986
2066
  var KEYS = Object.freeze(Object.values(STORAGE_KEYS));
@@ -2023,10 +2103,49 @@ var isOutdatedCache = (storage) => {
2023
2103
  cacheState.update({ version: ORCHESTRATOR_VERSION, undecidedScopes: [] });
2024
2104
  return Object.values(STORAGE_KEYS).filter((key) => key !== STORAGE_KEYS.cacheState).some((key) => storage(key, null).get() !== null);
2025
2105
  };
2026
- var createStorageConfig = (override) => {
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) => {
2027
2146
  const creator = override.storage ?? globalThisStorageEntry;
2028
2147
  const namespace = override.storageNamespace ?? "__NATIVE_FEDERATION__";
2029
- const storage = creator(namespace);
2148
+ const storage = guardWrites(creator(namespace), log);
2030
2149
  publishStorageInfo({
2031
2150
  type: creator.type ?? "custom",
2032
2151
  namespace,
@@ -2045,7 +2164,8 @@ var defaultProfile = {
2045
2164
  latestSharedExternal: false,
2046
2165
  skipInvalidExternalVersions: false,
2047
2166
  overrideCachedRemotes: "init-only",
2048
- overrideCachedRemotesIfURLMatches: false
2167
+ overrideCachedRemotesIfURLMatches: false,
2168
+ mergeManifests: true
2049
2169
  };
2050
2170
 
2051
2171
  // src/lib/core/4.config/mode/mode.config.ts
@@ -2073,13 +2193,16 @@ var createModeConfig = (override) => {
2073
2193
  };
2074
2194
 
2075
2195
  // src/lib/core/5.di/config.factory.ts
2076
- var createConfigHandlers = (overrides) => ({
2077
- ...createImportMapConfig(overrides),
2078
- ...createHostConfig(overrides),
2079
- ...createLogConfig(overrides),
2080
- ...createStorageConfig(overrides),
2081
- ...createModeConfig(overrides)
2082
- });
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
+ };
2083
2206
 
2084
2207
  // src/lib/core/2.app/flows/init.flow.ts
2085
2208
  var createInitFlow = ({
@@ -2105,8 +2228,129 @@ var createInitRemoteEntryFlow = ({
2105
2228
  });
2106
2229
  };
2107
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
+
2108
2351
  // src/lib/core/2.app/steps/get-remote-entries.ts
2109
2352
  function createGetRemoteEntries(config, ports) {
2353
+ const removeCachedRemoteEntries = createRemoveCachedRemoteEntries(ports);
2110
2354
  return (remotesOrManifestUrl = {}) => {
2111
2355
  const manifestPromise = config.manifestIntegrity ? ports.manifestProvider.provide(remotesOrManifestUrl, {
2112
2356
  integrity: config.manifestIntegrity
@@ -2114,7 +2358,7 @@ function createGetRemoteEntries(config, ports) {
2114
2358
  return manifestPromise.catch((e) => {
2115
2359
  config.log.error(1, "Could not fetch manifest.", e);
2116
2360
  return Promise.reject(new NFError("Failed to fetch manifest"));
2117
- }).then(addHostRemoteEntry).then(fetchRemoteEntries).then(removeSkippedRemotes).then(checkForSSE);
2361
+ }).then(addHostRemoteEntry).then(dropUnlistedRemotes).then(fetchRemoteEntries).then(removeSkippedRemotes).then(checkForSSE);
2118
2362
  };
2119
2363
  function addHostRemoteEntry(manifest) {
2120
2364
  if (!config.hostRemoteEntry) return manifest;
@@ -2124,6 +2368,26 @@ function createGetRemoteEntries(config, ports) {
2124
2368
  [name]: integrity ? { url, integrity } : url
2125
2369
  };
2126
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
+ }
2127
2391
  function normalizeEntry(descriptor) {
2128
2392
  return typeof descriptor === "string" ? { url: descriptor } : descriptor;
2129
2393
  }
@@ -2148,7 +2412,7 @@ function createGetRemoteEntries(config, ports) {
2148
2412
  let isOverride = false;
2149
2413
  let skip = false;
2150
2414
  ports.remoteInfoRepo.tryGet(remoteName).ifPresent((cachedRemoteInfo) => {
2151
- if (config.profile.overrideCachedRemotes !== "never" && (remoteEntryUrl !== join(cachedRemoteInfo.scopeUrl, "remoteEntry.json") || config.profile.overrideCachedRemotesIfURLMatches)) {
2415
+ if (config.profile.overrideCachedRemotes !== "never" && (remoteEntryUrl !== storedEntryUrl(cachedRemoteInfo) || config.profile.overrideCachedRemotesIfURLMatches)) {
2152
2416
  config.log.debug(1, `Overriding existing remote '${remoteName}' with '${remoteEntryUrl}'.`);
2153
2417
  isOverride = true;
2154
2418
  } else {
@@ -2341,125 +2605,6 @@ function scopeRemotes(versions, remotes) {
2341
2605
  return rows.filter((v) => v.remotes.length > 0);
2342
2606
  }
2343
2607
 
2344
- // src/lib/core/2.app/steps/store-remote-entry.ts
2345
- function createRemoveCachedRemoteEntries(ports) {
2346
- return (remoteNames) => {
2347
- if (remoteNames.size === 0) return;
2348
- for (const remoteName of remoteNames) {
2349
- ports.remoteInfoRepo.remove(remoteName);
2350
- ports.scopedExternalsRepo.remove(remoteName);
2351
- ports.sharedChunksRepo.remove(remoteName);
2352
- }
2353
- ports.sharedExternalsRepo.removeFromAllScopes(remoteNames);
2354
- };
2355
- }
2356
- function createStoreRemoteEntry(config, ports, logStep) {
2357
- return (remoteEntry, onSharedExternal) => {
2358
- addRemoteInfoToStorage(remoteEntry);
2359
- addExternalsToStorage(remoteEntry, onSharedExternal);
2360
- addSharedChunksToStorage(remoteEntry);
2361
- };
2362
- function addRemoteInfoToStorage({ name, url, exposes, integrity }) {
2363
- ports.remoteInfoRepo.addOrUpdate(name, {
2364
- scopeUrl: getScope(url),
2365
- exposes: Object.values(exposes ?? []).map((m) => ({
2366
- moduleName: m.key,
2367
- file: m.outFileName
2368
- })),
2369
- ...integrity ? { integrity } : {}
2370
- });
2371
- }
2372
- function addExternalsToStorage(remoteEntry, onSharedExternal) {
2373
- remoteEntry.shared.forEach((external) => {
2374
- const tag = resolveVersion(remoteEntry, external);
2375
- if (tag === null) return;
2376
- if (external.singleton) {
2377
- if (external.requiredVersion && !ports.versionCheck.isCompatible(tag, external.requiredVersion))
2378
- config.log.warn(
2379
- logStep,
2380
- `[${remoteEntry.name}][${external.packageName}] requiredVersion '${external.requiredVersion}' excludes its own version '${tag}'; '${tag}' is still accepted for it.`
2381
- );
2382
- onSharedExternal(remoteEntry, external, sharedExternalContext(remoteEntry, external, tag));
2383
- } else {
2384
- addScopedExternal(remoteEntry, external, tag);
2385
- }
2386
- });
2387
- }
2388
- function addSharedChunksToStorage(remoteEntry) {
2389
- if (!remoteEntry.chunks) return;
2390
- config.log.debug(
2391
- logStep,
2392
- `Adding chunks for remote "${remoteEntry.name}", bundles: [${Object.keys(remoteEntry.chunks).join(", ")}]`
2393
- );
2394
- Object.entries(remoteEntry.chunks).forEach(([bundleName, chunks]) => {
2395
- ports.sharedChunksRepo.addOrReplace(remoteEntry.name, bundleName, chunks);
2396
- });
2397
- }
2398
- function addScopedExternal(remoteEntry, sharedInfo, tag) {
2399
- ports.scopedExternalsRepo.addExternal(remoteEntry.name, sharedInfo.packageName, {
2400
- tag,
2401
- bundle: sharedInfo.bundle,
2402
- entries: sharedInfo.entries
2403
- });
2404
- }
2405
- function resolveVersion(remoteEntry, external) {
2406
- if (external.version && ports.versionCheck.isValidSemver(external.version)) {
2407
- return external.version;
2408
- }
2409
- const errorMsg = `[${remoteEntry.name}][${external.packageName}] Version '${external.version}' is not a valid version.`;
2410
- if (config.strict.strictExternalVersion) {
2411
- config.log.error(logStep, errorMsg);
2412
- throw new NFError(`Could not process remote '${remoteEntry.name}'`);
2413
- }
2414
- if (config.profile.skipInvalidExternalVersions) {
2415
- config.log.warn(logStep, `${errorMsg} Skipping external.`);
2416
- return null;
2417
- }
2418
- config.log.warn(logStep, errorMsg);
2419
- return ports.versionCheck.smallestVersion(external.requiredVersion);
2420
- }
2421
- function sharedExternalContext(remoteEntry, sharedInfo, tag) {
2422
- const scopeType = ports.sharedExternalsRepo.scopeType(sharedInfo.shareScope);
2423
- const remote = {
2424
- name: remoteEntry.name,
2425
- bundle: sharedInfo.bundle,
2426
- strictVersion: sharedInfo.strictVersion,
2427
- cached: false,
2428
- requiredVersion: scopeType === "strict" ? tag : sharedInfo.requiredVersion || tag,
2429
- ...sharedInfo.pool?.trim() ? { pool: sharedInfo.pool } : {},
2430
- entries: sharedInfo.entries
2431
- };
2432
- let stored;
2433
- const readRecord = () => stored ??= ports.sharedExternalsRepo.tryGet(sharedInfo.packageName, sharedInfo.shareScope).get() ?? { dirty: false, versions: [] };
2434
- return {
2435
- tag,
2436
- remote,
2437
- readRecord,
2438
- scopeType,
2439
- assertSameVersionCompatibility(matchingVersion) {
2440
- if (!remote.strictVersion) return;
2441
- if (matchingVersion.remotes[0].requiredVersion === remote.requiredVersion) return;
2442
- const errorMsg = `[${remoteEntry.name}][${sharedInfo.packageName}@${sharedInfo.version}] Required version-range '${remote.requiredVersion}' does not match cached version-range '${matchingVersion.remotes[0].requiredVersion}'`;
2443
- if (config.strict.strictExternalSameVersionCompatibility) {
2444
- config.log.error(logStep, errorMsg);
2445
- throw new NFError(`Could not process remote '${remoteEntry.name}'`);
2446
- }
2447
- config.log.warn(logStep, errorMsg);
2448
- },
2449
- write() {
2450
- ports.sharedExternalsRepo.addOrUpdate(
2451
- sharedInfo.packageName,
2452
- {
2453
- ...readRecord(),
2454
- versions: readRecord().versions.sort((a, b) => ports.versionCheck.compare(b.tag, a.tag))
2455
- },
2456
- sharedInfo.shareScope
2457
- );
2458
- }
2459
- };
2460
- }
2461
- }
2462
-
2463
2608
  // src/lib/core/2.app/steps/process-remote-entries.ts
2464
2609
  function createProcessRemoteEntries(config, ports) {
2465
2610
  const storeRemoteEntry = createStoreRemoteEntry(config, ports, 2);
@@ -2623,6 +2768,7 @@ function createDetermineSharedExternals(config, ports) {
2623
2768
  if (!sharedVersion) {
2624
2769
  let leastExtraDownloads = Number.MAX_VALUE;
2625
2770
  let leastTears = Number.MAX_VALUE;
2771
+ let leaderShared = false;
2626
2772
  const selfServing = new Map(
2627
2773
  external.versions.map((v) => {
2628
2774
  const groups = /* @__PURE__ */ new Map();
@@ -2645,16 +2791,19 @@ function createDetermineSharedExternals(config, ports) {
2645
2791
  );
2646
2792
  external.versions.forEach((vA) => {
2647
2793
  const extraDownloads = external.versions.reduce((sum, vB) => sum + costOf(vB, vA.tag), 0);
2794
+ const alreadyShared = vA.action === "share" && !!vA.remotes[0]?.cached;
2648
2795
  if (extraDownloads < leastExtraDownloads) {
2649
2796
  leastExtraDownloads = extraDownloads;
2650
2797
  leastTears = uncoveredTears(external, vA, accepts);
2798
+ leaderShared = alreadyShared;
2651
2799
  sharedVersion = vA;
2652
2800
  return;
2653
2801
  }
2654
- if (extraDownloads > leastExtraDownloads) return;
2802
+ if (extraDownloads > leastExtraDownloads || leaderShared) return;
2655
2803
  const tears = uncoveredTears(external, vA, accepts);
2656
- if (tears < leastTears) {
2804
+ if (alreadyShared || tears < leastTears) {
2657
2805
  leastTears = tears;
2806
+ leaderShared = alreadyShared;
2658
2807
  sharedVersion = vA;
2659
2808
  }
2660
2809
  });
@@ -2666,28 +2815,81 @@ function createDetermineSharedExternals(config, ports) {
2666
2815
  }
2667
2816
  }
2668
2817
 
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 };
2836
+ }
2837
+
2669
2838
  // src/lib/core/1.domain/externals/specifier.ts
2670
- function owningPackage(name) {
2839
+ function npmPackageOf(name) {
2671
2840
  const depth = name.startsWith("@") ? 2 : 1;
2672
2841
  let cut = -1;
2673
2842
  for (let seen = 0; seen < depth; seen++) {
2674
2843
  cut = name.indexOf("/", cut + 1);
2675
- if (cut === -1) return void 0;
2844
+ if (cut === -1) return name;
2676
2845
  }
2677
2846
  return name.slice(0, cut);
2678
2847
  }
2679
- var packageOf = (name) => owningPackage(name) ?? name;
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);
2861
+ }
2862
+ }
2863
+ return (specifier) => {
2864
+ const npm = npmPackageOf(specifier);
2865
+ return shortest.get(find(specifier)) ?? shortest.get(find(npm)) ?? npm;
2866
+ };
2867
+ }
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
+ }
2680
2881
  var SpecifierTags = class extends Map {
2681
- packages = /* @__PURE__ */ new Map();
2682
- constructor(entries = []) {
2882
+ constructor(packageOf, entries = []) {
2683
2883
  super();
2884
+ this.packageOf = packageOf;
2684
2885
  for (const [specifier, tag] of entries) this.set(specifier, tag);
2685
2886
  }
2887
+ packageOf;
2888
+ packages = /* @__PURE__ */ new Map();
2686
2889
  set(specifier, tag) {
2687
2890
  super.set(specifier, tag);
2688
- const pkg = owningPackage(specifier);
2689
- if (pkg === void 0) this.packages.set(specifier, tag);
2690
- else if (!this.packages.has(pkg)) this.packages.set(pkg, tag);
2891
+ const pkg = this.packageOf(specifier);
2892
+ if (pkg === specifier || !this.packages.has(pkg)) this.packages.set(pkg, tag);
2691
2893
  return this;
2692
2894
  }
2693
2895
  clear() {
@@ -2695,10 +2897,10 @@ var SpecifierTags = class extends Map {
2695
2897
  this.packages.clear();
2696
2898
  }
2697
2899
  pinnedTag(specifier) {
2698
- return this.get(specifier) ?? this.packages.get(owningPackage(specifier) ?? specifier);
2900
+ return this.get(specifier) ?? this.packages.get(this.packageOf(specifier));
2699
2901
  }
2700
2902
  };
2701
- function groupByPackage(items, nameOf) {
2903
+ function groupByPackage(items, nameOf, packageOf) {
2702
2904
  const packages = /* @__PURE__ */ new Map();
2703
2905
  for (const item of items) {
2704
2906
  const pkg = packageOf(nameOf(item));
@@ -2733,8 +2935,8 @@ function copiesByRemote(members) {
2733
2935
  return shipped;
2734
2936
  }
2735
2937
  var specifierCount = (copies) => copies.reduce((n, copy) => n + copy.specifiers.length, 0);
2736
- function buildOf(owner, copies) {
2737
- const tags = new SpecifierTags();
2938
+ function buildOf(owner, copies, packageOf) {
2939
+ const tags = new SpecifierTags(packageOf);
2738
2940
  const tagByMember = /* @__PURE__ */ new Map();
2739
2941
  for (const copy of copies) {
2740
2942
  for (const specifier of copy.specifiers)
@@ -2776,12 +2978,14 @@ function unwitnessedGap(copies, tags, builds) {
2776
2978
  function elect(input) {
2777
2979
  const shipped = copiesByRemote(input.members);
2778
2980
  const builds = /* @__PURE__ */ new Map();
2779
- for (const [owner, copies] of shipped) builds.set(owner, buildOf(owner, copies));
2981
+ for (const [owner, copies] of shipped) builds.set(owner, buildOf(owner, copies, input.packageOf));
2780
2982
  const pool = {
2781
2983
  ...input,
2782
2984
  shipped,
2783
2985
  builds,
2784
- packages: new Map([...shipped].map(([owner, copies]) => [owner, packageCopies(owner, copies)])),
2986
+ packages: new Map(
2987
+ [...shipped].map(([owner, copies]) => [owner, packageCopies(owner, copies, input.packageOf)])
2988
+ ),
2785
2989
  remotes: [...shipped.keys()],
2786
2990
  servesAt: (remote, tags) => serves(shipped.get(remote), tags, input.acceptsTag),
2787
2991
  agreesAt: (remote, tags) => agrees(shipped.get(remote), tags)
@@ -2844,7 +3048,7 @@ function roundOne(pool, hostRemote) {
2844
3048
  (c) => c.build.owner === pool.previousWinner ? 1 : 0
2845
3049
  ]);
2846
3050
  const winner = round1Winner.build.owner;
2847
- const globalTags = new SpecifierTags(round1Winner.build.tags);
3051
+ const globalTags = new SpecifierTags(pool.packageOf, round1Winner.build.tags);
2848
3052
  const globalRemotes = /* @__PURE__ */ new Set([winner, ...round1Winner.served]);
2849
3053
  const pending = remotes.filter((r) => !globalRemotes.has(r));
2850
3054
  return { winner, globalTags, globalRemotes, extensions: /* @__PURE__ */ new Set(), subpools: [], pending };
@@ -2901,7 +3105,7 @@ function addExtensions(pool, state) {
2901
3105
  for (const s of offer.specifiers) globalTags.set(s, offer.tag);
2902
3106
  }
2903
3107
  }
2904
- function packageCopies(owner, copies) {
3108
+ function packageCopies(owner, copies, packageOf) {
2905
3109
  const packages = /* @__PURE__ */ new Map();
2906
3110
  for (const copy of copies)
2907
3111
  for (const s of copy.specifiers) {
@@ -2943,7 +3147,7 @@ function settle(pool, state) {
2943
3147
  const dropped = new Set([...extensions].filter((pkg) => !publishedWhole(pool, state, pkg)));
2944
3148
  if (dropped.size === 0) return demoted;
2945
3149
  for (const pkg of dropped) extensions.delete(pkg);
2946
- const kept = [...globalTags].filter(([s]) => !dropped.has(packageOf(s)));
3150
+ const kept = [...globalTags].filter(([s]) => !dropped.has(pool.packageOf(s)));
2947
3151
  globalTags.clear();
2948
3152
  for (const [s, tag] of kept) globalTags.set(s, tag);
2949
3153
  for (const remote of globalRemotes)
@@ -2959,7 +3163,7 @@ function settle(pool, state) {
2959
3163
  }
2960
3164
  }
2961
3165
  function publishedWhole(pool, state, pkg) {
2962
- const published = new Set([...state.globalTags.keys()].filter((s) => packageOf(s) === pkg));
3166
+ const published = new Set([...state.globalTags.keys()].filter((s) => pool.packageOf(s) === pkg));
2963
3167
  const tag = state.globalTags.pinnedTag(pkg);
2964
3168
  return [...state.globalRemotes].some((remote) => {
2965
3169
  const copy = pool.packages.get(remote).get(pkg);
@@ -3008,24 +3212,6 @@ function placeRemotes(globalRemotes, subpools, self, missOf2) {
3008
3212
  }
3009
3213
 
3010
3214
  // src/lib/core/1.domain/pooling/membership.ts
3011
- function unionFind() {
3012
- const parent = /* @__PURE__ */ new Map();
3013
- const find = (node) => {
3014
- for (let up = parent.get(node); up !== void 0; up = parent.get(node)) {
3015
- const grand = parent.get(up);
3016
- if (grand === void 0) return up;
3017
- parent.set(node, grand);
3018
- node = grand;
3019
- }
3020
- return node;
3021
- };
3022
- const union = (a, b) => {
3023
- const rootA = find(a);
3024
- const rootB = find(b);
3025
- if (rootA !== rootB) parent.set(rootB, rootA);
3026
- };
3027
- return { find, union };
3028
- }
3029
3215
  var extNode = (name) => `ext\0${name}`;
3030
3216
  var labelNode = (label) => `label\0${label}`;
3031
3217
  var labelOf = (pool) => pool?.trim() || void 0;
@@ -3038,13 +3224,13 @@ function labelsIn(sharedExternals) {
3038
3224
  );
3039
3225
  return labelsOf;
3040
3226
  }
3041
- function labelledComponents(labelsOf) {
3227
+ function labelledComponents(labelsOf, packageOf) {
3042
3228
  const { find, union } = unionFind();
3043
3229
  for (const [name, labels] of labelsOf)
3044
3230
  for (const label of labels) union(extNode(name), labelNode(label));
3045
3231
  for (const name of labelsOf.keys()) {
3046
- const owner = owningPackage(name);
3047
- if (owner !== void 0) union(extNode(name), extNode(owner));
3232
+ const owner = packageOf(name);
3233
+ if (owner !== name) union(extNode(name), extNode(owner));
3048
3234
  }
3049
3235
  const byComponent = /* @__PURE__ */ new Map();
3050
3236
  for (const name of labelsOf.keys()) {
@@ -3054,11 +3240,11 @@ function labelledComponents(labelsOf) {
3054
3240
  }
3055
3241
  return [...byComponent.values()].filter((names) => names.some((n) => labelsOf.get(n).length > 0));
3056
3242
  }
3057
- function buildPools(sharedExternals) {
3243
+ function buildPools(sharedExternals, packageOf = packageOfIn(sharedExternals)) {
3058
3244
  const labelsOf = labelsIn(sharedExternals);
3059
3245
  const pools = /* @__PURE__ */ new Map();
3060
3246
  const labelledAlone = [];
3061
- for (const names of labelledComponents(labelsOf)) {
3247
+ for (const names of labelledComponents(labelsOf, packageOf)) {
3062
3248
  if (names.length < 2) labelledAlone.push(names[0]);
3063
3249
  else {
3064
3250
  const members = names.map((name) => ({ name, external: sharedExternals[name] }));
@@ -3068,9 +3254,9 @@ function buildPools(sharedExternals) {
3068
3254
  );
3069
3255
  }
3070
3256
  }
3071
- return { pools, labelledAlone };
3257
+ return { pools, labelledAlone, packageOf };
3072
3258
  }
3073
- function pooledPackagesWith(sharedExternals, copies) {
3259
+ function pooledPackagesWith(sharedExternals, copies, packageOf) {
3074
3260
  const labelsOf = labelsIn(sharedExternals);
3075
3261
  for (const { name, pool } of copies) {
3076
3262
  const labels = labelsOf.get(name) ?? [];
@@ -3078,7 +3264,7 @@ function pooledPackagesWith(sharedExternals, copies) {
3078
3264
  labelsOf.set(name, label === void 0 ? labels : [...labels, label]);
3079
3265
  }
3080
3266
  return new Set(
3081
- labelledComponents(labelsOf).filter((names) => names.length > 1).flatMap((names) => names.map(packageOf))
3267
+ labelledComponents(labelsOf, packageOf).filter((names) => names.length > 1).flatMap((names) => names.map(packageOf))
3082
3268
  );
3083
3269
  }
3084
3270
  function mostDeclaredLabel(members, labelsOf) {
@@ -3214,14 +3400,14 @@ function renamedRecords(scope, pools) {
3214
3400
  // src/lib/core/1.domain/pooling/plan.ts
3215
3401
  function planElection(scope, poolable) {
3216
3402
  if (!poolable || !Object.values(scope).some((external) => external.dirty) || !scopeHasPoolState(scope))
3217
- return { pools: /* @__PURE__ */ new Map(), stripped: /* @__PURE__ */ new Map(), labelledAlone: [] };
3218
- const { pools, labelledAlone } = buildPools(scope);
3403
+ return { pools: /* @__PURE__ */ new Map(), stripped: /* @__PURE__ */ new Map(), labelledAlone: [], packageOf: npmPackageOf };
3404
+ const { pools, labelledAlone, packageOf } = buildPools(scope);
3219
3405
  const pooled = new Set([...pools.values()].flatMap((members) => members.map((m) => m.name)));
3220
3406
  const stripped = /* @__PURE__ */ new Map();
3221
3407
  for (const [name, external] of Object.entries(scope))
3222
3408
  if (!pooled.has(name) && hasPoolResults(external))
3223
3409
  stripped.set(name, { ...withoutPoolResults(external), dirty: true });
3224
- return { pools, stripped, labelledAlone };
3410
+ return { pools, stripped, labelledAlone, packageOf };
3225
3411
  }
3226
3412
 
3227
3413
  // src/lib/core/2.app/steps/pooling/pool-shared-externals.ts
@@ -3235,7 +3421,7 @@ function createPoolSharedExternals(config, ports) {
3235
3421
  const plan = planElection(sharedExternals, repo.scopeType(scope) !== "strict");
3236
3422
  logPlan(plan, sharedExternals, scope);
3237
3423
  for (const [poolName, members] of plan.pools)
3238
- for (const [name, record] of poolRecords(poolName, members, scope))
3424
+ for (const [name, record] of poolRecords(poolName, members, plan.packageOf, scope))
3239
3425
  repo.addOrUpdate(name, record, scope);
3240
3426
  for (const [name, external] of plan.stripped) repo.addOrUpdate(name, external, scope);
3241
3427
  } catch (error) {
@@ -3270,9 +3456,10 @@ function createPoolSharedExternals(config, ports) {
3270
3456
  `[${scope}] '${name}' has a 'pool' label that joins no other external; likely a typo or a missing sibling.`
3271
3457
  );
3272
3458
  }
3273
- function poolRecords(poolName, members, scope) {
3459
+ function poolRecords(poolName, members, packageOf, scope) {
3274
3460
  const election = elect({
3275
3461
  members,
3462
+ packageOf,
3276
3463
  acceptsTag: createAcceptsTag(ports.versionCheck.isCompatible, compare),
3277
3464
  compare,
3278
3465
  previousWinner: previousWinner(members),
@@ -3333,12 +3520,13 @@ function missWarning(remote, miss, placed, counts) {
3333
3520
 
3334
3521
  // src/lib/core/1.domain/externals/serving.ts
3335
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);
3336
- var packagesOf = (scope) => groupByPackage(Object.keys(scope), (name) => name);
3523
+ var packagesOf = (scope) => groupByPackage(Object.keys(scope), (name) => name, packageOfIn(scope));
3337
3524
  var isPooled = (externals) => externals.some(([, e]) => e.poolName !== void 0);
3338
- function servingBuildOf(externals, accepts) {
3525
+ function servingBuildOf(pkg, externals, accepts) {
3339
3526
  if (externals.length === 0) return void 0;
3340
- const pkg = packageOf(externals[0][0]);
3341
- const rootRows = shareRows(externals.find(([name]) => name === pkg)?.[1]);
3527
+ const rootRows = shareRows(externals.find(([name]) => name === pkg)?.[1]).filter(
3528
+ (row) => row.remotes.some((copy) => pkg in copy.entries)
3529
+ );
3342
3530
  const rows = rootRows.length > 0 ? rootRows : externals.flatMap(([, e]) => shareRows(e));
3343
3531
  if (isPooled(externals)) return pooledBuild(externals, rows);
3344
3532
  const consumers = consumersOf(externals);
@@ -3539,8 +3727,8 @@ function splitsPackage(placed, surface, tag, accepts) {
3539
3727
  });
3540
3728
  return placed.some(onMap) && (shipsTwoTags(placed) || placed.some((p) => !onMap(p) || uncovered(p)));
3541
3729
  }
3542
- function loadSplitsPackage(copies, claims, accepts) {
3543
- const root = claims.find(([specifier]) => specifier === packageOf(specifier))?.[1];
3730
+ function loadSplitsPackage(pkg, copies, claims, accepts) {
3731
+ const root = claims.find(([specifier]) => specifier === pkg)?.[1];
3544
3732
  const servingTag = root?.tag ?? claims[0][1].tag;
3545
3733
  const surface = new Map(
3546
3734
  claims.map(([specifier, { tag }]) => [specifier, root ? tag : servingTag])
@@ -3586,7 +3774,7 @@ function createDecideServingBuilds(config, ports) {
3586
3774
  }
3587
3775
  };
3588
3776
  function decidePackage(shareScope, pkg, externals, accepts) {
3589
- const serving = servingBuildOf(externals, accepts);
3777
+ const serving = servingBuildOf(pkg, externals, accepts);
3590
3778
  const before = externals.map(([, external]) => shapeOf(external));
3591
3779
  const pooled = isPooled(externals);
3592
3780
  const toFollow = pooled ? void 0 : serving;
@@ -3672,7 +3860,6 @@ function committedClaims(externals, { shareScope, without }) {
3672
3860
  const publishes = (copy) => copy.name !== without && (shareScope !== GLOBAL_SCOPE || copy.cached);
3673
3861
  return claimTable(externals, publishes).claims;
3674
3862
  }
3675
- var claimsByPackage = (claims) => groupByPackage(claims, ([specifier]) => specifier);
3676
3863
  function versionClaims(version, servingBuild) {
3677
3864
  const claims = /* @__PURE__ */ new Map();
3678
3865
  const claim = (specifier, copy) => {
@@ -3683,16 +3870,6 @@ function versionClaims(version, servingBuild) {
3683
3870
  return claims;
3684
3871
  }
3685
3872
 
3686
- // node_modules/.pnpm/@softarc+native-federation@4.8.0/node_modules/@softarc/native-federation/dist/lib/domain/core/chunk.js
3687
- var CHUNK_PREFIX = "@nf-internal";
3688
- function toChunkImport(fileName) {
3689
- if (fileName.startsWith("./")) {
3690
- fileName = fileName.slice(2);
3691
- }
3692
- const packageName = fileName.replace(/.(m|c)?js$/, "");
3693
- return CHUNK_PREFIX + "/" + packageName;
3694
- }
3695
-
3696
3873
  // src/lib/core/2.app/steps/generate-import-map.ts
3697
3874
  function createGenerateImportMap(config, ports) {
3698
3875
  return () => {
@@ -4251,18 +4428,19 @@ function createUpdateCache(config, ports) {
4251
4428
  function decidePackages(remoteEntry, pending) {
4252
4429
  const decisions = /* @__PURE__ */ new Map();
4253
4430
  const viewOf = loadViewOf(remoteEntry, pending);
4254
- for (const group of pendingPerPackage(pending)) {
4431
+ for (const group of pendingPerPackage(pending, viewOf)) {
4255
4432
  const decision = group[0].ctx.scopeType === "strict" ? { action: "share" } : decidePackage(remoteEntry, group, viewOf(group[0].external.shareScope));
4256
4433
  for (const item of group) decisions.set(item, decision);
4257
4434
  }
4258
4435
  scopeOpenedPackages(decisions);
4259
4436
  return decisions;
4260
4437
  }
4261
- function pendingPerPackage(pending) {
4438
+ function pendingPerPackage(pending, viewOf) {
4262
4439
  const packages = /* @__PURE__ */ new Map();
4263
4440
  for (const item of pending) {
4264
4441
  const { shareScope, packageName } = item.external;
4265
- const key = `${shareScope ?? GLOBAL_SCOPE}\0${packageOf(packageName)}`;
4442
+ const pkg = item.ctx.scopeType === "strict" ? packageName : viewOf(shareScope).packageOf(packageName);
4443
+ const key = `${shareScope ?? GLOBAL_SCOPE}\0${pkg}`;
4266
4444
  const group = packages.get(key);
4267
4445
  if (group) group.push(item);
4268
4446
  else packages.set(key, [item]);
@@ -4280,20 +4458,34 @@ function createUpdateCache(config, ports) {
4280
4458
  shareScope: scope,
4281
4459
  without: remoteEntry.name
4282
4460
  });
4283
- const claimsIn = claimsByPackage(claims);
4461
+ const packageOf = packageOfIn(record, loadingIn(pending, scope));
4462
+ const claimsIn = groupByPackage(claims, ([specifier]) => specifier, packageOf);
4284
4463
  let pooled;
4285
4464
  view = {
4465
+ packageOf,
4286
4466
  claims,
4287
4467
  claimsOf: (pkg) => claimsIn.get(pkg) ?? [],
4288
- inPool: (pkg) => (pooled ??= pooledPackagesWith(record, copiesIn(pending, scope))).has(pkg)
4468
+ inPool: (pkg) => {
4469
+ pooled ??= pooledPackagesWith(record, labelledCopiesIn(pending, scope), packageOf);
4470
+ return pooled.has(pkg);
4471
+ }
4289
4472
  };
4290
4473
  views.set(scope, view);
4291
4474
  }
4292
4475
  return view;
4293
4476
  };
4294
4477
  }
4295
- function copiesIn(pending, scope) {
4296
- return pending.filter(({ external }) => (external.shareScope ?? GLOBAL_SCOPE) === scope).map(({ external, ctx }) => ({ name: external.packageName, pool: ctx.remote.pool }));
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
+ }));
4297
4489
  }
4298
4490
  function scopeOpenedPackages(decisions) {
4299
4491
  if (![...decisions.values()].some((d) => d.action === "scope" && d.partlyServed)) return;
@@ -4302,15 +4494,16 @@ function createUpdateCache(config, ports) {
4302
4494
  decisions.set(item, { action: "scope", partlyServed: false });
4303
4495
  }
4304
4496
  function decidePackage(remoteEntry, group, view) {
4305
- const pkg = packageOf(group[0].external.packageName);
4497
+ const pkg = view.packageOf(group[0].external.packageName);
4306
4498
  const claims = view.claimsOf(pkg);
4307
4499
  if (claims.length === 0) return { action: "share" };
4308
4500
  const specifiers = group.flatMap(({ external }) => Object.keys(external.entries));
4309
4501
  const builds = specifiers.every((specifier) => view.claims.has(specifier)) ? new Set(specifiers.map((specifier) => view.claims.get(specifier).copy.name)) : void 0;
4310
4502
  const rejections = group.flatMap((item) => rejectionsOf(item, view.claims));
4311
4503
  if (rejections.length > 0) {
4312
- const fromTwoBuilds = builds !== void 0 && builds.size > 1;
4313
- for (const rejection of refused(group, rejections, fromTwoBuilds, claims, view.inPool(pkg)))
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)))
4314
4507
  reportIncompatible(remoteEntry, rejection);
4315
4508
  return { action: "scope", partlyServed: false };
4316
4509
  }
@@ -4331,9 +4524,7 @@ function createUpdateCache(config, ports) {
4331
4524
  return claim && !accepts(claim.tag, ctx.tag, ctx.remote.requiredVersion) ? [{ item, specifier, claim }] : [];
4332
4525
  });
4333
4526
  }
4334
- function refused(group, rejections, fromTwoBuilds, claims, pooled) {
4335
- const copies = group.map(({ ctx }) => ({ tag: ctx.tag, copy: ctx.remote }));
4336
- const splits = fromTwoBuilds || loadSplitsPackage(copies, claims, accepts);
4527
+ function refused(rejections, splits, pooled) {
4337
4528
  const first = /* @__PURE__ */ new Map();
4338
4529
  for (const rejection of rejections)
4339
4530
  if (!first.has(rejection.item) && (pooled || !splits || electionKeeps(rejection)))
@@ -4410,16 +4601,25 @@ function createUpdateCache(config, ports) {
4410
4601
  }
4411
4602
 
4412
4603
  // src/lib/core/1.domain/pooling/gate.ts
4413
- function committedView(members, shipped, recordOrder, { shareScope, without }) {
4604
+ function committedView(members, shipped, recordOrder, {
4605
+ shareScope,
4606
+ without,
4607
+ packageOf
4608
+ }) {
4414
4609
  const global = /* @__PURE__ */ new Map();
4415
4610
  const claims = committedClaims(inRecordOrder(members, recordOrder), { shareScope, without });
4416
4611
  for (const [specifier, { tag, copy }] of claims)
4417
4612
  global.set(specifier, { tag, remote: copy.name, file: copy.entries[specifier] });
4418
4613
  const builds = /* @__PURE__ */ new Map();
4419
4614
  for (const [owner, copies] of shipped)
4420
- if (owner !== without) builds.set(owner, buildOf(owner, copies));
4615
+ if (owner !== without) builds.set(owner, buildOf(owner, copies, packageOf));
4421
4616
  const fileOf = subpoolFilesOf(members);
4422
- return { builds, global, runsOffMap: runsOffMapOf(members, global, builds, fileOf) };
4617
+ return {
4618
+ packageOf,
4619
+ builds,
4620
+ global,
4621
+ runsOffMap: runsOffMapOf(members, global, builds, fileOf)
4622
+ };
4423
4623
  }
4424
4624
  function subpoolFilesOf(members) {
4425
4625
  const subpoolOwners = /* @__PURE__ */ new Set();
@@ -4462,14 +4662,30 @@ function runsOffMapOf(members, global, builds, fileOf) {
4462
4662
  function judgeRemote(copies, view, accepts) {
4463
4663
  const { rejected, missing } = scan(copies, view, accepts);
4464
4664
  if (rejected) return { cause: "incompatible", ...rejected };
4465
- const globalTags = new SpecifierTags([...view.global].map(([s, { tag }]) => [s, tag]));
4665
+ const globalTags = new SpecifierTags(
4666
+ view.packageOf,
4667
+ [...view.global].map(([s, { tag }]) => [s, tag])
4668
+ );
4466
4669
  const binding = offMapBinding(copies, view, globalTags);
4467
4670
  if (binding) return { cause: "uncovered", ...binding };
4671
+ if (servedSplit(copies, view)) return { cause: "uncovered", unshipped: true };
4468
4672
  if (agrees(copies, globalTags)) return "global";
4469
4673
  if (missing !== void 0) return { cause: "uncovered", specifier: missing };
4470
4674
  if (unwitnessedGap(copies, globalTags, view.builds.values()) === void 0) return "global";
4471
4675
  return { cause: "uncovered", unshipped: true };
4472
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
+ }
4473
4689
  function coverFromMap(remote, mine, view, actions, policy) {
4474
4690
  const files = [];
4475
4691
  for (const member of mine) {
@@ -4483,12 +4699,12 @@ function coverFromMap(remote, mine, view, actions, policy) {
4483
4699
  const reaches = reachesOf(remote, files, view);
4484
4700
  const bound = boundByFile(reaches, view);
4485
4701
  if (bound !== void 0) return { bound };
4486
- const servedPackages = new Set([...view.global.keys()].map(packageOf));
4487
- const gap = files.map((file) => gapOf(file, servedPackages)).find((specifier) => specifier !== void 0);
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);
4488
4704
  if (gap !== void 0) return { gap };
4489
4705
  return { covers: files.filter(covering).map(coverOf) };
4490
4706
  }
4491
- function gapOf({ copy, covered }, servedPackages) {
4707
+ function gapOf({ copy, covered }, servedPackages, packageOf) {
4492
4708
  const entrypoints = Object.keys(copy.entries);
4493
4709
  const missing = entrypoints.filter((specifier) => !covered.has(specifier));
4494
4710
  if (missing.length < entrypoints.length) return missing[0];
@@ -4566,14 +4782,17 @@ function scan(copies, view, accepts) {
4566
4782
  return { rejected, missing };
4567
4783
  }
4568
4784
  function offMapBinding(copies, view, globalTags) {
4569
- const own = new SpecifierTags(copies.flatMap((c) => c.specifiers.map((s) => [s, c.tag])));
4785
+ const own = new SpecifierTags(
4786
+ view.packageOf,
4787
+ copies.flatMap((c) => c.specifiers.map((s) => [s, c.tag]))
4788
+ );
4570
4789
  const servers = /* @__PURE__ */ new Set();
4571
4790
  for (const copy of copies)
4572
4791
  for (const specifier of copy.specifiers) {
4573
4792
  const build = view.global.get(specifier)?.remote;
4574
4793
  if (build !== void 0) servers.add(build);
4575
4794
  }
4576
- const firstRun = new SpecifierTags();
4795
+ const firstRun = new SpecifierTags(view.packageOf);
4577
4796
  for (const build of servers)
4578
4797
  for (const [specifier, { tag }] of view.runsOffMap.get(build) ?? []) {
4579
4798
  const reached = globalTags.pinnedTag(specifier) ?? own.pinnedTag(specifier) ?? firstRun.pinnedTag(specifier);
@@ -4598,13 +4817,21 @@ function createPoolDynamicExternals(config, ports) {
4598
4817
  for (const [scope, names] of poolableNames(entry, actions)) {
4599
4818
  const committed = ports.sharedExternalsRepo.getFromScope(scope);
4600
4819
  if (!scopeHasPoolState(committed)) continue;
4601
- const { pools } = buildPools(committed);
4602
- const moves = judgeScope(entry.name, names, actions, pools, Object.keys(committed), scope);
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
+ );
4603
4830
  writeMoves(entry.name, names, moves, committed, pools, scope);
4604
4831
  }
4605
4832
  return Promise.resolve({ entry, actions: publicActions(actions) });
4606
4833
  };
4607
- function judgeScope(remote, names, actions, pools, recordOrder, scope) {
4834
+ function judgeScope(remote, names, actions, pools, packageOf, recordOrder, scope) {
4608
4835
  const policy = { shareScope: scope, scopeUrlOf };
4609
4836
  const moves = /* @__PURE__ */ new Map();
4610
4837
  const selfServe = (members, cause) => {
@@ -4620,7 +4847,8 @@ function createPoolDynamicExternals(config, ports) {
4620
4847
  const shipped = copiesByRemote(pool);
4621
4848
  const view = committedView(pool, shipped, recordOrder, {
4622
4849
  shareScope: scope,
4623
- without: remote
4850
+ without: remote,
4851
+ packageOf
4624
4852
  });
4625
4853
  const own = shipped.get(remote) ?? [];
4626
4854
  const verdict = judgeRemote(own, view, accepts);
@@ -5005,7 +5233,9 @@ var resolveHostInstances = async (option, deps) => {
5005
5233
  const entry = await deps.remoteEntryProvider.provide(url, { integrity });
5006
5234
  const load = auto.load ?? ((specifier) => import(specifier));
5007
5235
  const specifiers = [
5008
- ...new Set((entry.shared ?? []).filter((s) => s.singleton).map((s) => s.packageName))
5236
+ ...new Set(
5237
+ (entry.shared ?? []).filter((s) => s.singleton).flatMap((s) => Object.keys(s.entries))
5238
+ )
5009
5239
  ].filter((s) => auto.include ? matches(s, auto.include) : true).filter((s) => auto.exclude ? !matches(s, auto.exclude) : true);
5010
5240
  const map = {};
5011
5241
  for (const specifier of specifiers) {
@@ -5041,7 +5271,7 @@ var HOST_INSTANCES_GLOBAL = "__NF_HOST_INSTANCES__";
5041
5271
  var buildNodeAdapters = (config) => ({
5042
5272
  versionCheck: createVersionCheck(),
5043
5273
  manifestProvider: createFsManifestProvider(),
5044
- remoteEntryProvider: createFsRemoteEntryProvider(),
5274
+ remoteEntryProvider: createFsRemoteEntryProvider(config),
5045
5275
  remoteInfoRepo: createRemoteInfoRepository(config),
5046
5276
  scopedExternalsRepo: createScopedExternalsRepository(config),
5047
5277
  sharedExternalsRepo: createSharedExternalsRepository(config),