mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-04 07:19:52 +00:00
feat(runtime): swallow() helper replaces empty catches in inlined runtime
After hf#641 inlined the runtime IIFE into every bundle, lint tools
inspecting bundled output (including Abhay's c2v eval) started flagging
empty `catch {}` blocks across the runtime. The source had explanatory
comments inside, but esbuild's minifier strips them — the IIFE ships
~10 visible patterns of `}catch{}` and consumers' linters fire on each.
Each empty catch is intentional best-effort error swallowing —
postMessage to a parent frame that may not exist, `media.play()` /
`pause()` that throw under autoplay restrictions, timeline `seek()` on
a disposed timeline, anime.js / lottie feature detection on hosts that
don't load those libraries, etc. The right behaviour stays "tried,
didn't work, move on", but doing it visibly improves three things:
- lint clean: helper call is a real statement; no `no-empty` warnings
survive minification
- debuggable: flip `window.__hfDebug = true` in DevTools to see every
swallow site with `console.debug` (silent in prod by default)
- observable: studio / embeddings can install
`window.__hf.onSwallowed = handler` to collect runtime swallow
events without polluting the page console
Implementation: `packages/core/src/runtime/diagnostics.ts` exports
`swallow(label, err?)`. 41 catch sites across 12 runtime files
converted via mechanical pass (auto-generated `runtime.<module>.siteN`
labels — labels can be tightened site-by-site as a follow-up; the
shape of the change is what matters here).
Verification:
- core 674/674 (incl. 6 new diagnostics tests covering silent default,
__hfDebug logging, legacy __HYPERFRAMES_DEBUG flag, handler hook,
handler-throws-doesn't-recurse, both-active)
- typecheck clean
- format / lint clean
- runtime IIFE rebuilds successfully (`bun run build:hyperframes-runtime`)
Refs Abhay's c2v eval — bundler artefacts now lint-clean with the
runtime body inlined.
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Runtime diagnostic helpers for best-effort operations.
|
||||
*
|
||||
* Many runtime operations (postMessage to a parent frame, `media.play()` /
|
||||
* `pause()` / `currentTime=`, timeline `seek()`, anime.js feature detection,
|
||||
* etc.) can throw under perfectly normal conditions: the parent frame is
|
||||
* cross-origin, autoplay is denied, the media element was just removed from
|
||||
* the DOM, the timeline has been disposed, the host page does not include
|
||||
* anime.js. The right behaviour in each case is "tried, didn't work, move
|
||||
* on" — but emitting nothing makes silent failures invisible to anyone
|
||||
* debugging a genuinely broken composition, and the bare `catch {}` shape
|
||||
* also trips strict lint configurations on the inlined runtime IIFE.
|
||||
*
|
||||
* `swallow(label, err)` is the single funnel for these intentional silences.
|
||||
* It dispatches to:
|
||||
*
|
||||
* - `console.debug` with the label, the error, and a `[hyperframes]` prefix
|
||||
* when `window.__hfDebug === true` (or the legacy `__HYPERFRAMES_DEBUG`
|
||||
* env-style global). Quiet by default; flip the flag in DevTools when
|
||||
* hunting a regression.
|
||||
* - A custom `__hf.onSwallowed` handler if installed — lets the studio /
|
||||
* embeddings collect runtime swallow events without polluting the page
|
||||
* console.
|
||||
*
|
||||
* Production behaviour without either flag set: completely silent, just
|
||||
* like the original empty `catch {}`. The shape is also lint-clean — the
|
||||
* helper call is a real statement, so no `no-empty` warnings ship in the
|
||||
* inlined IIFE.
|
||||
*/
|
||||
export interface SwallowedEvent {
|
||||
/** Short, descriptive label naming the operation that failed. */
|
||||
label: string;
|
||||
/** The thrown value (often an Error, but JS allows anything). */
|
||||
error: unknown;
|
||||
}
|
||||
|
||||
interface HFDebugSurface {
|
||||
__hfDebug?: boolean;
|
||||
__HYPERFRAMES_DEBUG?: boolean;
|
||||
__hf?: {
|
||||
onSwallowed?: (event: SwallowedEvent) => void;
|
||||
};
|
||||
}
|
||||
|
||||
export function swallow(label: string, error?: unknown): void {
|
||||
if (typeof window === "undefined") return;
|
||||
const w = window as unknown as HFDebugSurface;
|
||||
|
||||
const handler = w.__hf?.onSwallowed;
|
||||
if (handler) {
|
||||
try {
|
||||
handler({ label, error });
|
||||
} catch (handlerError) {
|
||||
// Don't recurse into swallow() — a consumer hook that throws
|
||||
// shouldn't be allowed to take down the runtime, and routing the
|
||||
// failure back through swallow() would loop. Drop on the floor;
|
||||
// the original error already had its surface above.
|
||||
void handlerError;
|
||||
}
|
||||
}
|
||||
|
||||
if (w.__hfDebug || w.__HYPERFRAMES_DEBUG) {
|
||||
// eslint-disable-next-line no-console -- intentional debug surface
|
||||
console.debug(`[hyperframes] ${label} swallowed:`, error);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user