UNPKG

everything-dev

Version:

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

549 lines (547 loc) • 20.9 kB
const require_runtime = require('../_virtual/_rolldown/runtime.cjs'); const require_load = require('../services/resolution/load.cjs'); const require_theme = require('../utils/theme.cjs'); const require_catalog = require('../services/workspace/catalog.cjs'); const require_services_resolution_session = require('../services/resolution/session.cjs'); const require_services_federation_service = require('../services/federation/service.cjs'); const require_artifacts = require('../services/codegen/artifacts.cjs'); const require_workspace = require('../services/workspace/workspace.cjs'); const require_framework_version = require('../services/framework-version.cjs'); const require_build_train = require('../services/workspace/build-train.cjs'); const require_manifest = require('../services/platform/manifest.cjs'); const require_published = require('../services/registry/published.cjs'); const require_upgrade = require('../services/scaffold/upgrade.cjs'); const require_index = require('../services/scaffold/upgrade-audit/index.cjs'); let node_fs = require("node:fs"); let node_path = require("node:path"); let effect = require("effect"); let node_child_process = require("node:child_process"); let node_process = require("node:process"); node_process = require_runtime.__toESM(node_process, 1); let every_plugin_ui_manifest_generator = require("every-plugin/ui/manifest-generator"); //#region src/handlers/upgrade.ts function registerUpgrade(builder) { return { upgrade: builder.upgrade.effect(function* (_opts, input) { return yield* effect.Effect.tryPromise({ try: async () => { const configPath = require_load.findConfigPath(); if (!configPath) return { status: "error", packages: [], error: `${require_load.MISSING_CONFIG_MESSAGE} in current directory` }; const projectDir = (0, node_path.resolve)((0, node_path.dirname)(configPath)); if (input.from === "v1") { if (require_index.isV2Tree(projectDir)) return { status: "already-upgraded", packages: [], notes: ["bos.app.ts present — this tree is already on the v2 train; nothing to audit or apply"] }; if (input.maintain && input.maintain.length > 0) { const migrated = []; const notes = []; for (const step of input.maintain) { const result = await require_index.maintainV1Tree(projectDir, step, input.dryRun); for (const path of result.writes) migrated.push(`${step}: wrote ${path}`); for (const path of result.deletes) migrated.push(`${step}: deleted ${path}`); for (const note of result.notes) notes.push(`${step}: ${note}`); } return { status: input.dryRun ? "dry-run" : "upgraded", packages: [], migrated, notes }; } if (input.audit) { const outcome = await require_index.auditV1Tree(projectDir); const auditResult = { tier: outcome.tier, findings: outcome.findings, manifest: outcome.manifest }; return outcome.gateBlocked ? { status: "gate-blocked", packages: [], audit: auditResult, blockers: outcome.findings.filter((f) => f.severity === "blocker") } : { status: "audit", packages: [], audit: auditResult }; } const outcome = await require_index.applyV1Tree(projectDir, input.dryRun); if (!outcome.ok) return { status: "gate-blocked", packages: [], blockers: outcome.blockers }; return { status: input.dryRun ? "dry-run" : "upgraded", packages: [], migrated: outcome.outcome.migrated, notes: outcome.outcome.notes }; } return await require_upgrade.upgradeTemplate(projectDir, input); }, catch: (error) => ({ status: "error", packages: [], error: error instanceof Error ? error.message : "Unknown error" }) }); }), typesGen: builder.typesGen.effect(function* (_opts, input) { return yield* effect.Effect.tryPromise({ try: async () => { const configPath = require_load.findConfigPath(); if (!configPath) return { status: "error", generated: [], fetched: [], skipped: [], failed: [], error: `${require_load.MISSING_CONFIG_MESSAGE} in current directory` }; const projectDir = (0, node_path.resolve)((0, node_path.dirname)(configPath)); const env = input.env ?? (node_process.default.env.NODE_ENV === "production" ? "production" : "development"); const refreshed = await require_services_resolution_session.openResolution({ cwd: projectDir, env, remotePlugins: input.remotePlugins }); if (!refreshed?.config || !refreshed.runtime) return { status: "error", generated: [], fetched: [], skipped: [], failed: [], error: "Failed to load the authored config" }; const runtime = refreshed.runtime; const resolvedConfig = refreshed.config; if (input.dryRun) { const pluginEntries = Object.entries(runtime.plugins ?? {}); const fetched = []; const skipped = []; const hasLocalApiWorkspace = (0, node_fs.existsSync)((0, node_path.join)(projectDir, "api", "src")); if (runtime.api.source !== "local") fetched.push(`api remote (${runtime.api.url})`); else { const path = runtime.api.localPath ? ` (${(0, node_path.relative)(projectDir, runtime.api.localPath)})` : ""; skipped.push(`api local${path}`); } if (runtime.auth) { if (runtime.auth.source !== "local") fetched.push(`auth remote (${runtime.auth.url})`); else { const path = runtime.auth.localPath ? ` (${(0, node_path.relative)(projectDir, runtime.auth.localPath)})` : ""; skipped.push(`auth local${path}`); } } for (const [key, plugin] of pluginEntries) if (plugin.url && plugin.source !== "local") fetched.push(`${key} remote (${plugin.url})`); else if (plugin.localPath) skipped.push(`${key} local (${(0, node_path.relative)(projectDir, plugin.localPath)})`); else skipped.push(`${key} no URL resolved`); const generated = [ "ui/src/lib/api-types.gen.ts", "ui/src/lib/auth-types.gen.ts", ".bos/bos.resolved-config.json" ]; if (hasLocalApiWorkspace) generated.push("api/src/lib/plugins-types.gen.ts", "api/src/lib/auth-types.gen.ts"); if ((0, node_fs.existsSync)((0, node_path.join)(projectDir, "host", "src"))) generated.push("host/src/lib/auth-types.gen.ts"); for (const [_key, plugin] of pluginEntries) { const localPath = plugin.localPath; if (!localPath) continue; const pluginSrc = (0, node_path.join)(localPath, "src", "lib", "plugins-client.gen.ts"); if ((0, node_fs.existsSync)(pluginSrc)) generated.push((0, node_path.relative)(projectDir, pluginSrc)); } if (runtime.auth?.localPath) { const authSrc = (0, node_path.join)(runtime.auth.localPath, "src", "lib", "plugins-client.gen.ts"); if ((0, node_fs.existsSync)(authSrc)) generated.push((0, node_path.relative)(projectDir, authSrc)); } return { status: "success", generated, fetched, skipped, failed: [] }; } const artifacts = await require_artifacts.generateCodeArtifacts(projectDir, resolvedConfig, { env, extendsChain: [...refreshed.chain], runtimeConfig: runtime, forceRouteTree: true }); const hasLocalApiWorkspace = (0, node_fs.existsSync)((0, node_path.join)(projectDir, "api", "src")); const generated = ["ui/src/lib/api-types.gen.ts"]; if (hasLocalApiWorkspace) generated.push("api/src/lib/plugins-types.gen.ts", "api/src/lib/auth-types.gen.ts"); if (runtime.auth && (runtime.auth.source !== "local" || runtime.auth.localPath)) generated.push("ui/src/lib/auth-types.gen.ts"); if ((0, node_fs.existsSync)((0, node_path.join)(projectDir, "host", "src"))) generated.push("host/src/lib/auth-types.gen.ts"); for (const [_key, plugin] of Object.entries(runtime.plugins ?? {})) { const localPath = plugin.localPath; if (!localPath) continue; const pluginSrc = (0, node_path.join)(localPath, "src", "lib", "plugins-client.gen.ts"); if ((0, node_fs.existsSync)(pluginSrc)) generated.push((0, node_path.relative)(projectDir, pluginSrc)); } if (runtime.auth?.localPath) { const authSrc = (0, node_path.join)(runtime.auth.localPath, "src", "lib", "plugins-client.gen.ts"); if ((0, node_fs.existsSync)(authSrc)) generated.push((0, node_path.relative)(projectDir, authSrc)); } const contractStatus = artifacts?.contractStatus ?? []; const fetched = []; const skipped = []; const failed = []; for (const entry of contractStatus) if (entry.source === "remote") fetched.push(entry.url ? `${entry.key} remote (${entry.url})` : entry.key); else if (entry.source === "local") { const path = entry.localPath ? ` (${(0, node_path.relative)(projectDir, entry.localPath)})` : ""; skipped.push(`${entry.key} local${path}`); } else if (entry.source === "skipped") skipped.push(`${entry.key} no URL resolved`); else if (entry.source === "failed") { const detail = entry.error ? `: ${entry.error}` : ""; failed.push(`${entry.key}${detail}`); } return { status: "success", generated: [...generated, ".bos/bos.resolved-config.json"], fetched, skipped, failed }; }, catch: (error) => ({ status: "error", generated: [], fetched: [], skipped: [], failed: [], error: error instanceof Error ? error.message : "Unknown error" }) }); }), typecheck: builder.typecheck.effect(function* (_opts, input) { return yield* effect.Effect.tryPromise({ try: async () => { const configPath = require_load.findConfigPath(); if (!configPath) return { status: "error", checked: [], skipped: [], results: [], error: `${require_load.MISSING_CONFIG_MESSAGE} in current directory` }; const projectDir = (0, node_path.resolve)((0, node_path.dirname)(configPath)); const refreshed = await require_services_resolution_session.openResolution({ cwd: projectDir }); if (!refreshed?.config || !refreshed.runtime) return { status: "error", checked: [], skipped: [], results: [], error: "Failed to load the authored config" }; const runtime = refreshed.runtime; const resolvedConfig = refreshed.config; await require_artifacts.generateCodeArtifacts(projectDir, resolvedConfig, { env: node_process.default.env.NODE_ENV === "production" ? "production" : "development", extendsChain: [...refreshed.chain], runtimeConfig: runtime }); const workspaceEntries = []; const skipped = []; const appTargets = [ { key: "host", label: "host", target: runtime.host }, { key: "ui", label: "ui", target: runtime.ui }, { key: "api", label: "api", target: runtime.api } ]; if (runtime.auth) appTargets.push({ key: "auth", label: "auth", target: runtime.auth }); for (const entry of appTargets) if (entry.target?.source === "local" && entry.target.localPath && (0, node_fs.existsSync)((0, node_path.join)(entry.target.localPath, "tsconfig.json"))) workspaceEntries.push({ key: entry.key, label: entry.label, dir: entry.target.localPath }); else skipped.push({ key: entry.key, label: entry.label }); for (const [key, plugin] of Object.entries(runtime.plugins ?? {})) { const label = `plugins/${key}`; const localPath = plugin.source === "local" ? plugin.localPath : void 0; if (localPath && (0, node_fs.existsSync)((0, node_path.join)(localPath, "tsconfig.json"))) workspaceEntries.push({ key, label, dir: localPath }); else skipped.push({ key, label }); if (localPath && (0, node_fs.existsSync)((0, node_path.join)(localPath, "ui", "tsconfig.json"))) workspaceEntries.push({ key, label: `${label}/ui`, dir: localPath, ui: true }); } const selected = require_build_train.selectWorkspaceTargets(input.packages, resolvedConfig); const targets = input.packages === "all" ? workspaceEntries : workspaceEntries.filter((entry) => selected.includes(entry.key)); const skippedEntries = input.packages === "all" ? skipped : skipped.filter((entry) => selected.includes(entry.key)); const checked = []; const results = []; for (const entry of targets) { if (entry.ui && !(0, node_fs.existsSync)((0, node_path.join)(entry.dir, "ui", "src", "routeTree.gen.ts"))) try { await (0, every_plugin_ui_manifest_generator.generateUiManifest)({ workspaceRoot: (0, node_path.join)(entry.dir, "ui"), pluginName: entry.key, emitRouteTree: true }); } catch (error) { checked.push(entry.label); results.push({ workspace: entry.label, passed: false, error: `routeTree materialization failed: ${error instanceof Error ? error.message : String(error)}` }); continue; } const packageJsonPath = (0, node_path.join)(entry.dir, "package.json"); let args = entry.ui ? [ "exec", "tsc", "--noEmit", "-p", "ui/tsconfig.json" ] : [ "exec", "tsc", "--noEmit" ]; if ((0, node_fs.existsSync)(packageJsonPath)) try { const pkg = JSON.parse((0, node_fs.readFileSync)(packageJsonPath, "utf-8")); const scriptName = entry.ui ? "typecheck:ui" : "typecheck"; if (pkg.scripts?.[scriptName]) args = ["run", scriptName]; } catch {} console.log(`\n ${require_theme.colors.dim("Checking")} ${require_theme.colors.cyan(entry.label)}`); const child = (0, node_child_process.spawnSync)("pnpm", args, { cwd: entry.dir, stdio: "inherit" }); const passed = child.status === 0; checked.push(entry.label); results.push({ workspace: entry.label, passed, error: passed ? void 0 : `typecheck failed (exit code ${child.status ?? "n/a"})` }); } return { status: "success", checked, skipped: skippedEntries.map((entry) => entry.label), results }; }, catch: (error) => ({ status: "error", checked: [], skipped: [], results: [], error: error instanceof Error ? error.message : "Unknown error" }) }); }), mfCheck: builder.mfCheck.effect(function* (_opts, input) { const platformManifest = yield* require_manifest.PlatformManifestService; return yield* effect.Effect.promise(async () => { let authored = null; try { authored = await require_load.readAuthoredConfigInput(); } catch (e) { return { status: "fail", hostVersion: null, hostReachable: false, hostReason: e instanceof Error ? e.message : String(e), remotes: [] }; } if (!authored) { const account = node_process.default.env.BOS_ACCOUNT; const gateway = node_process.default.env.BOS_GATEWAY; if (!account || !gateway) return { status: "fail", hostVersion: null, hostReachable: false, hostReason: require_load.MISSING_CONFIG_MESSAGE, remotes: [] }; try { authored = await require_published.resolvePublishedConfig(account, gateway); } catch (e) { return { status: "fail", hostVersion: null, hostReachable: false, hostReason: e instanceof Error ? e.message : String(e), remotes: [] }; } if (!authored) return { status: "fail", hostVersion: null, hostReachable: false, hostReason: `No config found at bos://${account}/${gateway} — verify BOS_ACCOUNT/BOS_GATEWAY and that the config has been published.`, remotes: [] }; } const report = await require_services_federation_service.checkFederationCompat(authored, { timeoutMs: input.timeoutMs }); const ui = await require_services_federation_service.checkUiCompositionCompat(authored, { timeoutMs: input.timeoutMs }); let platform; try { const configPath = require_load.findConfigPath(); if (configPath) { const projectDir = (0, node_path.resolve)((0, node_path.dirname)(configPath)); const resolved = await platformManifest.resolvePlatformManifest({ configDir: projectDir, localConfig: authored }); if (resolved) { const root = require_workspace.findWorkspaceRoot(projectDir)?.dir ?? projectDir; const violations = platformManifest.checkPlatformCompat(resolved.manifest, { platformVersion: require_framework_version.readInstalledFrameworkVersion(projectDir, "everything-dev"), catalog: require_catalog.readWorkspaceCatalog(root) }); platform = { ok: violations.length === 0, violations }; } } } catch (e) { platform = { ok: false, violations: [{ kind: "minChild", message: `platform manifest resolution failed: ${e instanceof Error ? e.message : String(e)}` }] }; } return { status: report.ok && (platform?.ok ?? true) ? "ok" : "fail", hostVersion: report.hostVersion, hostReachable: report.hostReachable, hostReason: report.hostReason, remotes: report.remotes, ...ui.slots.length > 0 ? { ui: { ok: ui.ok, slots: ui.slots } } : {}, ...platform ? { platform } : {} }; }); }), platformManifest: builder.platformManifest.effect(function* (_opts, input) { const platformManifest = yield* require_manifest.PlatformManifestService; return yield* effect.Effect.promise(async () => { const inImage = platformManifest.readInImagePlatformManifest(); if (inImage) return { status: "ok", version: inImage.frameworkVersion, source: "in-image", ...input.check ? { compat: { ok: true, violations: [] } } : {} }; const configPath = require_load.findConfigPath(); if (!configPath) return { status: "absent", version: null, error: `${require_load.MISSING_CONFIG_MESSAGE} — and the in-image platform manifest is absent (non-framework image)` }; const projectDir = (0, node_path.resolve)((0, node_path.dirname)(configPath)); try { const authoredConfig = await require_load.readAuthoredConfigInput() ?? {}; let resolved; let drift; try { resolved = await platformManifest.resolvePlatformManifest({ configDir: projectDir, localConfig: authoredConfig }); } catch (pinError) { const latest = await platformManifest.resolvePlatformManifest({ configDir: projectDir, localConfig: { ...authoredConfig, platform: void 0 } }); if (!latest) throw pinError; resolved = latest; const pinned = typeof authoredConfig.platform === "string" ? authoredConfig.platform : void 0; drift = pinned ? { pinned, published: latest.manifest.frameworkVersion } : void 0; } if (!resolved) return { status: "absent", version: null }; if (drift) return { status: "fail", version: drift.published, source: `bos://${resolved.source.account}/${resolved.source.gateway}`, drift, error: `parent platform is ${drift.published} (published at bos://${resolved.source.account}/${resolved.source.gateway}), you pinned ${drift.pinned} — run \`bos upgrade\` to realign` }; const base = { status: "ok", version: resolved.manifest.frameworkVersion, source: `bos://${resolved.source.account}/${resolved.source.gateway}`, fromCache: resolved.fromCache }; if (!input.check) return base; const root = require_workspace.findWorkspaceRoot(projectDir)?.dir ?? projectDir; const violations = platformManifest.checkPlatformCompat(resolved.manifest, { platformVersion: require_framework_version.readInstalledFrameworkVersion(projectDir, "everything-dev"), catalog: require_catalog.readWorkspaceCatalog(root) }); return { ...base, compat: { ok: violations.length === 0, violations } }; } catch (e) { return { status: "fail", version: null, error: e instanceof Error ? e.message : String(e) }; } }); }) }; } //#endregion exports.registerUpgrade = registerUpgrade; //# sourceMappingURL=upgrade.cjs.map