mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
fix(ci): switch Windows install to hoisted linker; narrow FormData iter
Pushing further to actually get Windows render verification green, not just work around it. ## What's wrong on Windows Bun 1.3's default `isolated` linker creates nested workspace junctions under `packages/*/node_modules/` on Windows GHA runners. Those junctions don't materialize reliably — Node's `realpathSync` returns `EPERM` on stat, and ESM resolution returns `ERR_MODULE_NOT_FOUND`. Every Windows build since PR #748 has tripped this in one of three places: - `packages/producer/build.mjs` importing `esbuild` - `packages/producer/scripts/generate-font-data.ts` reading `@fontsource/*` - `packages/producer` running `tsc` to emit `.d.ts`s Long-running bun bugs: oven-sh/bun#23615, #18354, #10146. ## Fix **1. `--linker=hoisted` for the Windows install step** (workflow change, Windows only). Hoisted layout puts deps as real directories at the workspace root + workspace package node_modules. No junctions, no Windows-specific path quirks. Linux CI keeps the default isolated linker; the lockfile is linker-agnostic so `--frozen-lockfile` is still valid. **2. Source-level FormData narrowing in `packages/core/src/studio-api/routes/files.ts`** (needed because the hoisted layout exposes a `@types/node@25` typecheck issue that the isolated layout hides). With v25 + an `onmessage` global in scope, the ambient `FormData.entries()` infers `[string, string]` instead of `[string, File | string]`, so the `value instanceof File` check breaks at `TS2358`. Cast the iterator to a `[string, FileLike | string]` shape and narrow via `typeof value === "string"`. Identical runtime behavior; works under both v24 (isolated layout, what Linux CI sees) and v25 (hoisted, what Windows CI sees with this change). ## Verification - `bun install --frozen-lockfile` (isolated, default): full build green - `bun install --frozen-lockfile --linker=hoisted`: full build green, core typecheck passes, `@hyperframes/core` 853 tests pass - Format/lint clean on both layouts
This commit is contained in:
@@ -150,7 +150,16 @@ jobs:
|
||||
|
||||
- name: Install dependencies
|
||||
shell: pwsh
|
||||
run: bun install --frozen-lockfile
|
||||
# Force the pre-1.3 "hoisted" linker on Windows. Bun 1.3.x's default
|
||||
# "isolated" linker creates nested workspace junctions that don't
|
||||
# materialize reliably on Windows GHA runners — manifests as
|
||||
# `Cannot find package 'esbuild'` walking up from
|
||||
# `packages/producer/build.mjs` and `EPERM stat` on
|
||||
# `packages/producer/node_modules/@fontsource/*` from generators.
|
||||
# See oven-sh/bun#23615, #18354, #10146. Linux CI keeps isolated;
|
||||
# the lockfile is linker-agnostic so this flag is safe with
|
||||
# --frozen-lockfile.
|
||||
run: bun install --frozen-lockfile --linker=hoisted
|
||||
|
||||
- name: Build all packages
|
||||
shell: pwsh
|
||||
@@ -371,7 +380,16 @@ jobs:
|
||||
|
||||
- name: Install dependencies
|
||||
shell: pwsh
|
||||
run: bun install --frozen-lockfile
|
||||
# Force the pre-1.3 "hoisted" linker on Windows. Bun 1.3.x's default
|
||||
# "isolated" linker creates nested workspace junctions that don't
|
||||
# materialize reliably on Windows GHA runners — manifests as
|
||||
# `Cannot find package 'esbuild'` walking up from
|
||||
# `packages/producer/build.mjs` and `EPERM stat` on
|
||||
# `packages/producer/node_modules/@fontsource/*` from generators.
|
||||
# See oven-sh/bun#23615, #18354, #10146. Linux CI keeps isolated;
|
||||
# the lockfile is linker-agnostic so this flag is safe with
|
||||
# --frozen-lockfile.
|
||||
run: bun install --frozen-lockfile --linker=hoisted
|
||||
|
||||
- name: Build
|
||||
shell: pwsh
|
||||
|
||||
@@ -306,8 +306,21 @@ export function registerFileRoutes(api: Hono, adapter: StudioApiAdapter): void {
|
||||
const skipped: string[] = [];
|
||||
const invalid: Array<{ name: string; reason: string }> = [];
|
||||
|
||||
for (const [, value] of formData.entries()) {
|
||||
if (!(value instanceof File)) continue;
|
||||
// @types/node v25 narrows the ambient `FormData.entries()` to
|
||||
// `[string, string]` in workspaces where another dep declares an
|
||||
// `onmessage` global (it trips the worker branch of v25's conditional
|
||||
// File type). At runtime the value is still `File | string` — cast the
|
||||
// iterator so the rest of this block keeps type-checking on every
|
||||
// bun-install layout (hoisted on Windows surfaces this; isolated on
|
||||
// Linux happens to keep v24 in scope).
|
||||
type FileLike = {
|
||||
readonly name: string;
|
||||
readonly size: number;
|
||||
arrayBuffer(): Promise<ArrayBuffer>;
|
||||
};
|
||||
const entries = formData.entries() as unknown as Iterable<[string, FileLike | string]>;
|
||||
for (const [, value] of entries) {
|
||||
if (typeof value === "string") continue;
|
||||
|
||||
// Strip path separators — browsers may include directory components
|
||||
const name = value.name.split("/").pop()?.split("\\").pop() ?? "";
|
||||
|
||||
Reference in New Issue
Block a user