UNPKG

everything-dev

Version:

A consolidated product package for building Module Federation apps with oRPC APIs.

201 lines (199 loc) 8.25 kB
const require_runtime = require('./_virtual/_rolldown/runtime.cjs'); const require_merge = require('./merge.cjs'); const require_types = require('./types.cjs'); let node_fs = require("node:fs"); let node_path = require("node:path"); let node_crypto = require("node:crypto"); //#region src/shared-deps.ts function sha256(input) { return (0, node_crypto.createHash)("sha256").update(input).digest("hex"); } function extractSemverExact(input) { if (typeof input !== "string") return null; const match = input.match(/\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?/); return match ? match[0] : null; } function caretRange(version) { return `^${version}`; } function stableDepsObject(deps) { const keys = Object.keys(deps).sort((a, b) => a.localeCompare(b)); const out = {}; for (const key of keys) out[key] = deps[key]; return out; } function normalizeSharedDepConfig(config) { return { version: config.version, requiredVersion: config.requiredVersion ?? false, singleton: config.singleton ?? false, eager: config.eager ?? false, strictVersion: config.strictVersion ?? false, shareScope: config.shareScope ?? "default" }; } function getObject(value) { return require_merge.isPlainObject(value) ? value : void 0; } function getSharedDepsMap(value, source) { if (value === void 0) return void 0; if (!require_types.SharedDepMapSchema.safeParse(value).success) throw new Error(`Invalid shared dependency map at ${source}`); return value; } function writeFileIfChanged(filePath, nextContent) { try { if ((0, node_fs.readFileSync)(filePath, "utf-8") === nextContent) return false; } catch {} (0, node_fs.writeFileSync)(filePath, nextContent); return true; } function fingerprintResolved(deps) { return sha256(JSON.stringify(stableDepsObject(deps))); } function isSameSharedDepConfig(a, b) { const left = normalizeSharedDepConfig(a); const right = normalizeSharedDepConfig(b); return left.version === right.version && left.requiredVersion === right.requiredVersion && left.singleton === right.singleton && left.eager === right.eager && left.strictVersion === right.strictVersion && left.shareScope === right.shareScope; } function collectSharedDepRefs(bosConfig) { const refs = /* @__PURE__ */ new Map(); const app = getObject(bosConfig.app); const appUi = getObject(app?.ui); const appApi = getObject(app?.api); const appAuth = getObject(app?.auth); const plugins = getObject(bosConfig.plugins); if (appUi && "shared" in appUi) throw new Error("app.ui.shared is no longer supported. Move shared deps to app.api.shared, app.auth.shared, or plugins.*.shared."); const append = (source, shared) => { if (!shared) return; for (const [name, config] of Object.entries(shared)) { const existing = refs.get(name); if (!existing) { refs.set(name, [{ source, config }]); continue; } if (!isSameSharedDepConfig(existing[0].config, config)) { const previous = existing.map((ref) => ref.source).join(", "); throw new Error(`Conflicting shared dependency "${name}" between ${previous} and ${source}`); } existing.push({ source, config }); } }; append("app.api", getSharedDepsMap(appApi?.shared, "app.api.shared")); append("app.auth", getSharedDepsMap(appAuth?.shared, "app.auth.shared")); for (const [pluginId, plugin] of Object.entries(plugins ?? {})) { const pluginRecord = getObject(plugin); if (!pluginRecord) continue; const pluginUi = getObject(getObject(pluginRecord.app)?.ui); if (pluginUi && "shared" in pluginUi) throw new Error(`app.ui.shared is no longer supported in plugins.${pluginId}. Move shared deps to app.api.shared, app.auth.shared, or plugins.*.shared.`); append(`plugins.${pluginId}`, getSharedDepsMap(pluginRecord.shared, `plugins.${pluginId}.shared`)); } return Object.fromEntries(refs); } async function syncResolvedSharedDeps(opts) { const bosConfigPath = (0, node_path.join)(opts.configDir, "bos.config.json"); const resolvedConfigPath = (0, node_path.join)(opts.configDir, ".bos", "bos.resolved-config.json"); const packageJsonPath = (0, node_path.join)(opts.configDir, "package.json"); const generatedPath = (0, node_path.join)(opts.configDir, ".bos", "generated", "shared-deps.json"); const bosConfig = opts.bosConfig ?? JSON.parse((0, node_fs.readFileSync)(bosConfigPath, "utf-8")); if (!require_merge.isPlainObject(bosConfig)) throw new Error("bos.config.json must be an object"); const pkgJson = (0, node_fs.existsSync)(packageJsonPath) ? JSON.parse((0, node_fs.readFileSync)(packageJsonPath, "utf-8")) : {}; const originalBos = JSON.stringify(bosConfig); const originalPkg = JSON.stringify(pkgJson); const mode = opts.hostMode === "local" ? "catalog->bos" : "bos->catalog"; const refsByName = collectSharedDepRefs(bosConfig); const catalog = pkgJson.workspaces?.catalog ?? {}; const resolvedDeps = {}; for (const [name, refs] of Object.entries(refsByName)) { const first = refs[0]; if (!first) continue; const exactFromConfig = extractSemverExact(first.config.version) ?? extractSemverExact(first.config.requiredVersion); const exactFromCatalog = extractSemverExact(catalog[name]); const version = mode === "catalog->bos" ? exactFromCatalog ?? exactFromConfig : exactFromConfig ?? exactFromCatalog; if (!version) { const sources = refs.map((ref) => ref.source).join(", "); throw new Error(`Could not resolve exact version for shared dependency "${name}" from ${sources}`); } if (mode === "catalog->bos" && exactFromCatalog === null && exactFromConfig) catalog[name] = exactFromConfig; if (mode === "bos->catalog" && catalog[name] !== version) catalog[name] = version; for (const ref of refs) { ref.config.version = version; ref.config.requiredVersion = caretRange(version); ref.config.shareScope = ref.config.shareScope ?? "default"; } resolvedDeps[name] = { name, version, requiredVersion: caretRange(version), shareScope: first.config.shareScope ?? "default", singleton: first.config.singleton ?? false, eager: first.config.eager ?? false, strictVersion: first.config.strictVersion ?? false, sources: refs.map((ref) => ref.source).sort((a, b) => a.localeCompare(b)) }; } if (!pkgJson.workspaces) pkgJson.workspaces = { packages: [], catalog: {} }; pkgJson.workspaces.catalog = catalog; const nextBos = JSON.stringify(bosConfig); const nextPkg = JSON.stringify(pkgJson); const bosConfigChanged = nextBos !== originalBos; const catalogChanged = nextPkg !== originalPkg; if (bosConfigChanged) { const resolvedDir = (0, node_path.dirname)(resolvedConfigPath); if (!(0, node_fs.existsSync)(resolvedDir)) (0, node_fs.mkdirSync)(resolvedDir, { recursive: true }); const ordered = require_merge.rebuildOrderedConfig(bosConfig); const resolvedOutput = { _resolved: { env: opts.env ?? "development", resolvedAt: (/* @__PURE__ */ new Date()).toISOString(), extendsChain: opts.extendsChain ?? [], source: "shared-sync" }, ...ordered }; writeFileIfChanged(resolvedConfigPath, `${JSON.stringify(resolvedOutput, null, 2)}\n`); } if (catalogChanged) writeFileIfChanged(packageJsonPath, `${JSON.stringify(pkgJson, null, 2)}\n`); const stableResolvedDeps = stableDepsObject(resolvedDeps); const resolved = { deps: stableResolvedDeps, fingerprintSha256: fingerprintResolved(stableResolvedDeps) }; const nextGenerated = { schemaVersion: 1, kind: "everything-dev/shared-deps", generatedAt: (/* @__PURE__ */ new Date()).toISOString(), deps: stableResolvedDeps, fingerprintSha256: resolved.fingerprintSha256, inputs: { mode, hostMode: opts.hostMode } }; let prevFingerprint = null; try { prevFingerprint = JSON.parse((0, node_fs.readFileSync)(generatedPath, "utf-8"))?.fingerprintSha256 ?? null; } catch {} (0, node_fs.mkdirSync)((0, node_path.dirname)(generatedPath), { recursive: true }); writeFileIfChanged(generatedPath, `${JSON.stringify(nextGenerated, null, 2)}\n`); const generatedChanged = prevFingerprint !== nextGenerated.fingerprintSha256; return { mode, hostMode: opts.hostMode, bosConfigChanged, catalogChanged, generatedChanged, resolved }; } //#endregion exports.syncResolvedSharedDeps = syncResolvedSharedDeps; //# sourceMappingURL=shared-deps.cjs.map