Skip to content

Commit d2fe92d

Browse files
committed
fix(build): the ui/auth dts guard is self-healing — one declarations-only re-emit before failing
rolldown-plugin-dts emits per-entry across parallel workers; on fresh CI checkouts the ui/auth emit has (rarely, non-deterministically) raced the better-near-auth dependency-types resolution and collapsed the plugin chain to `any` — red on the first GH attempt (PR #843's framework-integration), green on rerun with zero source delta. A release-gate guard that flakes taxes every future publish. The guard is now self-healing: on collapse it re-emits declarations only (tsdown --dts, serial, no JS bundle) and re-checks; the build goes red only on persistent collapse, which is a real regression. Recursion is recursion-proofed via an env flag the re-emit inherits.
1 parent a98e434 commit d2fe92d

1 file changed

Lines changed: 35 additions & 7 deletions

File tree

‎packages/everything-dev/tsdown.config.ts‎

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { execSync } from "node:child_process";
12
import { existsSync, readFileSync } from "node:fs";
23
import { chmod, readFile, writeFile } from "node:fs/promises";
34
import { createRequire } from "node:module";
@@ -60,6 +61,39 @@ assertWorkspaceDtsDependencies();
6061
* without declarations, so a source missing from the entry list ships a types
6162
* path that does not exist and every consumer's tsc fails with TS7016 (#839).
6263
*/
64+
// The dts emit is per-entry across parallel rolldown-plugin-dts workers; on
65+
// fresh CI checkouts the ui/auth emit has (rarely, non-deterministically)
66+
// raced the dependency-types resolution and collapsed the plugin chain to
67+
// `any` (2026-11-09: red on the first GH attempt, green on rerun with zero
68+
// source delta). The guard is therefore self-healing: one declarations-only
69+
// re-emit — serial, no JS bundle — before failing. The build only goes red
70+
// on persistent collapse, which is a real regression worth a human.
71+
async function assertAuthClientDtsTypes(): Promise<void> {
72+
const authDtsPath = join("dist", "ui", "auth.d.mts");
73+
const collapsed = async (): Promise<boolean> =>
74+
/declare function createAuthClient\(.*\): any;/.test(
75+
await readFile(authDtsPath, "utf-8").catch(() => ""),
76+
);
77+
if (!(await collapsed())) return;
78+
if (process.env.BOS_TS_DOWN_DTS_REEMIT) {
79+
throw new Error(
80+
"dist/ui/auth.d.mts emitted createAuthClient(): any after re-emit — the better-auth " +
81+
"plugin-chain inference collapsed persistently. Check that better-near-auth's dist " +
82+
"types are built and fresh.",
83+
);
84+
}
85+
console.warn("[tsdown] ui/auth dts collapsed to any — re-emitting declarations");
86+
process.env.BOS_TS_DOWN_DTS_REEMIT = "1";
87+
execSync("pnpm exec tsdown --dts", { stdio: "inherit", cwd: import.meta.dirname });
88+
if (await collapsed()) {
89+
throw new Error(
90+
"dist/ui/auth.d.mts emitted createAuthClient(): any after re-emit — the better-auth " +
91+
"plugin-chain inference collapsed persistently. Check that better-near-auth's dist " +
92+
"types are built and fresh.",
93+
);
94+
}
95+
}
96+
6397
function assertExportsDistTypesExist() {
6498
const manifest = JSON.parse(readFileSync(join(import.meta.dirname, "package.json"), "utf-8")) as {
6599
exports?: Record<string, unknown>;
@@ -177,13 +211,7 @@ export default defineConfig({
177211
},
178212
async onSuccess() {
179213
assertExportsDistTypesExist();
180-
const authDts = await readFile(join("dist", "ui", "auth.d.mts"), "utf-8").catch(() => "");
181-
if (/declare function createAuthClient\(.*\): any;/.test(authDts)) {
182-
throw new Error(
183-
"dist/ui/auth.d.mts emitted createAuthClient(): any — the better-auth plugin-chain " +
184-
"inference collapsed. Check that better-near-auth's dist types are built and fresh.",
185-
);
186-
}
214+
await assertAuthClientDtsTypes();
187215
for (const file of ["cli.mjs", "cli.cjs"]) {
188216
const filepath = join("dist", file);
189217
try {

0 commit comments

Comments
 (0)