everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
177 lines (175 loc) • 7.5 kB
JavaScript
import { Finding } from "../domain.mjs";
import { fileExists, readText } from "../fs.mjs";
import { readFileSync } from "node:fs";
import { Effect } from "effect";
import { readFile } from "node:fs/promises";
//#region src/services/scaffold/upgrade-audit/checks/compose-seam.ts
/**
* Compose-seam guard — replays the host's SSR composition collision locally:
* our core ui manifest (which claims /login) composed with the deployed
* auth-ui manifest (which ships _public/login plus a device-login subtree).
*
* every-plugin's constructTree handles the collision by design ("core ui
* wins; shadowed route skipped") but pre-fix releases mark the shadowed
* children without splicing them out of `pending`, so the loop exits
* non-empty and throws a false "unresolvable parentage" — the prod boot
* failure this guard watches for. Run with: pnpm compose-seam [--live]
*/
const UI_MANIFEST_PATH = "ui/src/manifest.gen.json";
const AUTH_FIXTURE_PATH = "fixtures/compose-seam/auth-ui.manifest.gen.json";
const AUTH_MANIFEST_URL = "https://cdn.everything.dev/bundles/dev.everything.near/everything.dev/auth-ui/manifest.gen.json";
const AUTH_PLUGIN_KEY = "auth";
const CORE_UI_KEY = "ui";
const SHADOW_LOG_MARKER = "core ui wins; shadowed route skipped";
/** Pure — "unresolvable parentage" after a shadow log is the known cascade bug. */
const classifyComposeError = (message, shadowedARoute) => {
if (message.includes("path collision:")) return "path-collision";
if (message.includes("unresolvable parentage") && shadowedARoute) return "cascade-bug";
return "compose-failed";
};
/** Pure — every manifest route id needs a loader or constructTree refuses. */
const stubRouteConfigLoaders = (manifest) => Object.fromEntries(manifest.routes.map((record) => [record.id, async () => ({})]));
const uiClaimsLogin = (manifest) => manifest.routes.some((record) => record.id === "_public/login" && record.path === "/login");
const captureConsole = async (fn) => {
const lines = [];
const original = console.log;
console.log = (...args) => {
lines.push(args.map(String).join(" "));
};
let result;
let error;
try {
result = await fn();
} catch (cause) {
error = cause;
} finally {
console.log = original;
}
return {
lines,
result,
error
};
};
/**
* Runs the real composer (or an injected stand-in) over the two manifests.
* The auth manifest's /login tree is the collision shape; classification
* only — never throws.
*/
const runComposeProbe = async (uiManifest, authManifest, constructTree) => {
const claimsLogin = uiClaimsLogin(uiManifest);
const manifests = /* @__PURE__ */ new Map([["ui", uiManifest], [AUTH_PLUGIN_KEY, authManifest]]);
try {
const { lines, result, error } = await captureConsole(() => constructTree({
name: "compose-seam-probe",
plugins: [{
key: "ui",
mfName: "ui"
}, {
key: AUTH_PLUGIN_KEY,
mfName: AUTH_PLUGIN_KEY
}],
resolve: async (ref) => {
const manifest = manifests.get(ref.key);
if (!manifest) throw new Error(`probe has no manifest for "${ref.key}"`);
return {
key: ref.key,
manifest,
routeConfig: { routeConfigLoaders: stubRouteConfigLoaders(manifest) }
};
}
}));
if (error === void 0) return {
seam: "ok",
composeLog: lines,
mountCounts: result?.mountCounts,
uiClaimsLogin: claimsLogin
};
const message = error instanceof Error ? error.message : String(error);
const shadowedARoute = lines.some((line) => line.includes(SHADOW_LOG_MARKER));
return {
seam: classifyComposeError(message, shadowedARoute),
composeLog: lines,
error: message,
uiClaimsLogin: claimsLogin
};
} catch (cause) {
return {
seam: "compose-failed",
composeLog: [],
error: cause instanceof Error ? cause.message : String(cause),
uiClaimsLogin: claimsLogin
};
}
};
const loadManifest = (source, label) => Effect.try({
try: () => {
const parsed = JSON.parse(source);
if (!Array.isArray(parsed.routes) || typeof parsed.name !== "string") throw new Error("not a plugin manifest (name/routes missing)");
return parsed;
},
catch: (error) => /* @__PURE__ */ new Error(`${label}: ${String(error)}`)
});
/** Reads both manifests and runs the probe; succeeds even when compose fails. */
const probeComposeSeam = (projectDir, options) => Effect.gen(function* () {
if (!(yield* fileExists(projectDir, "ui/src/manifest.gen.json"))) return {
seam: "absent-ui-manifest",
composeLog: [],
uiClaimsLogin: false
};
const uiManifest = yield* loadManifest(yield* readText(projectDir, UI_MANIFEST_PATH), UI_MANIFEST_PATH);
let authSource;
if (options?.live) authSource = yield* Effect.tryPromise({
try: async () => {
const response = await fetch(AUTH_MANIFEST_URL);
if (!response.ok) throw new Error(`${response.status} ${response.statusText}`);
return await response.text();
},
catch: (error) => /* @__PURE__ */ new Error(`failed to fetch deployed auth-ui manifest: ${String(error)}`)
});
else authSource = yield* Effect.tryPromise({
try: () => readFile(new URL(`../${AUTH_FIXTURE_PATH}`, import.meta.url), "utf-8"),
catch: (error) => /* @__PURE__ */ new Error(`failed to load the committed auth-ui fixture: ${String(error)}`)
});
const authManifest = yield* loadManifest(authSource, "auth-ui manifest");
const { constructTree } = yield* Effect.tryPromise({
try: () => import("every-plugin/ui/manifest"),
catch: (error) => /* @__PURE__ */ new Error(`failed to load every-plugin's composer: ${String(error)}`)
});
return yield* Effect.tryPromise({
try: () => runComposeProbe(uiManifest, authManifest, constructTree),
catch: (error) => /* @__PURE__ */ new Error(`compose probe failed: ${String(error)}`)
});
});
const readEveryPluginVersion = (projectDir) => Effect.sync(() => {
try {
const source = readFileSync(`${projectDir}/node_modules/every-plugin/package.json`, "utf-8");
return JSON.parse(source).version ?? "unknown";
} catch {
return "unknown";
}
});
/** Pure — probe outcome → audit findings. */
const composeFindings = (probe, everyPluginVersion) => {
if (probe.seam === "ok") return [];
if (probe.seam === "absent-ui-manifest") return [new Finding({
check: "compose-seam",
path: UI_MANIFEST_PATH,
severity: "warn",
message: "ui/src/manifest.gen.json is absent — run `pnpm types:gen`; the compose probe needs the generated manifest"
})];
const messages = {
"cascade-bug": `every-plugin ${everyPluginVersion} still throws a false "unresolvable parentage" for the /login shadow cascade (constructTree marks shadowed children without splicing them out of pending) — prod boot SSR composition fails with this. Bump everything-dev/every-plugin to the release with the cascade-splice fix, then redeploy`,
"path-collision": `the composer treats the /login shadow as a hard path collision instead of "core ui wins" — shadow handling regressed; check every-plugin ${everyPluginVersion} constructTree against the auth-ui manifest`,
"compose-failed": `compose probe failed: ${probe.error ?? "unknown error"}`
};
return [new Finding({
check: "compose-seam",
path: "ui/src/manifest.gen.json + auth-ui manifest",
severity: "blocker",
message: messages[probe.seam]
})];
};
//#endregion
export { AUTH_FIXTURE_PATH, AUTH_MANIFEST_URL, AUTH_PLUGIN_KEY, SHADOW_LOG_MARKER, UI_MANIFEST_PATH, classifyComposeError, composeFindings, probeComposeSeam, readEveryPluginVersion, runComposeProbe, stubRouteConfigLoaders, uiClaimsLogin };
//# sourceMappingURL=compose-seam.mjs.map