Skip to content

Commit 5acedf0

Browse files
committed
fix(ci): type-check drift — bun-only fs/promises.exists + floating resolution
The workflow failed on 'Module "fs/promises" has no exported member "exists"' while every local run passed. Root cause chain: 1. bun install --force re-resolved dependencies in CI. Nothing pins @types/node (no lockfile — gitignored by policy; every path to it is a floating "*": @types/pidusage and bun-types both declare "*"), so CI silently typechecked against whatever @types/node was registry-latest that day. Reproduced locally: 22.20.2 fails the old import, 26.4.1 passes — that's the local-vs-CI split. 2. With stock @types/node winning the fs/promises module declaration, the Bun-only exists extension stopped typechecking. Fixes, layered: - tests/log-manager.test.ts: existsSync from node:fs — typed by both @types/node and bun-types, identical behavior (the only fs/promises Bun-extension import in the repo; everything else is stock Node API) - @types/node pinned as a direct devDependency (22.20.2 — exactly what CI was resolving): a direct dep overrides the floating "*" transitives - workflow: bun install --frozen-lockfile — the correct CI posture; installs exactly what exists when a lockfile is present, instead of re-resolving daily - devDeps pinned: @types/bun ^1.4.2, bun-types ^1.4.2 (no more floating "latest" tag) Verified: tsc clean under BOTH @types/node 26.4.1 and 22.20.2; the workflow's exact bun 1.3.9 + frozen install + tsc in a pristine copy; log-manager 10/10; full suite 597/597.
1 parent c6099f0 commit 5acedf0

3 files changed

Lines changed: 17 additions & 6 deletions

File tree

.github/workflows/test.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,13 @@ jobs:
3131
run: bun --version
3232

3333
# Install dependencies
34+
# --frozen-lockfile: install EXACTLY the committed bun.lock. The old
35+
# `--force` re-resolved from the registry on every run, letting
36+
# floating transitives (e.g. @types/node via @types/pidusage's "*")
37+
# drift to whatever was "latest" that day — the moving target behind
38+
# the "fs/promises has no exported member 'exists'" CI failure.
3439
- name: Install dependencies
35-
run: bun install --force
40+
run: bun install --frozen-lockfile
3641

3742
# Type check (TS)
3843
- name: Type check

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,10 @@
7474
"pidusage": "^4.0.1"
7575
},
7676
"devDependencies": {
77-
"@types/bun": "^1.3.14",
77+
"@types/bun": "^1.4.2",
78+
"@types/node": "22.20.2",
7879
"@types/pidusage": "^2.0.5",
79-
"bun-types": "latest",
80+
"bun-types": "^1.4.2",
8081
"typescript": "^5.9.3"
8182
}
8283
}

tests/log-manager.test.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { describe, test, expect, beforeEach, afterEach } from "bun:test";
2-
import { mkdir, rm, writeFile, readFile, exists, readdir } from "fs/promises";
2+
import { mkdir, rm, writeFile, readFile, readdir } from "fs/promises";
3+
// NB: no `exists` here — fs/promises.exists is a BUN-ONLY extension. When
4+
// tsc resolves fs/promises against stock @types/node (CI's install can
5+
// re-resolve it transitively), the import stops typechecking. existsSync
6+
// is typed by both @types/node and bun-types and behaves identically here.
7+
import { existsSync } from "node:fs";
38
import { join } from "path";
49
import { tmpdir } from "os";
510

@@ -19,15 +24,15 @@ describe("Log File Management", () => {
1924
const logFile = join(LOG_DIR, "app-out.log");
2025
await writeFile(logFile, "");
2126

22-
const fileExists = await exists(logFile);
27+
const fileExists = existsSync(logFile);
2328
expect(fileExists).toBe(true);
2429
});
2530

2631
test("should create stderr log file", async () => {
2732
const logFile = join(LOG_DIR, "app-error.log");
2833
await writeFile(logFile, "");
2934

30-
const fileExists = await exists(logFile);
35+
const fileExists = existsSync(logFile);
3136
expect(fileExists).toBe(true);
3237
});
3338

0 commit comments

Comments
 (0)