import * as _hyperframes_core from '@hyperframes/core'; import { RegistryItem } from '@hyperframes/core'; import { CanvasResolution } from '@hyperframes/parsers'; import { MediaCodecProbeCache, HtmlSourceLike } from './helpers/mediaCodecMap.js'; /** Resolved info about a single project. */ interface ResolvedProject { id: string; dir: string; title?: string; sessionId?: string; } /** Observable render job state, polled by the SSE progress handler. */ interface RenderJobState { id: string; status: "rendering" | "complete" | "failed" | "cancelled"; progress: number; stage?: string; outputPath: string; error?: string; /** * Optional abort hook set by the adapter. The cancel route calls this to * stop an in-flight render; adapters that can't abort may omit it (the * route still marks the job cancelled so the SSE stream terminates). */ cancel?: () => void; } interface MediaProcessingJobState { id: string; status: "processing" | "complete" | "failed"; progress: number; stage?: string; inputAssetPath: string; outputAssetPath: string; outputPath: string; backgroundOutputAssetPath?: string; backgroundOutputPath?: string; error?: string; provider?: string; framesProcessed?: number; durationSeconds?: number; avgMsPerFrame?: number; } /** Lint result from the core linter. */ interface LintResult { findings: Array<{ code?: string; severity: string; message: string; file?: string; fixHint?: string; }>; } interface ProjectLintResult { results: Array<{ file: string; result: LintResult; }>; } interface StudioSelectionTextField { key: string; label: string; value: string; tagName: string; source: "self" | "child" | "text-node"; } interface StudioSelectionSnapshot { schemaVersion: 1; projectId: string; compositionPath: string; sourceFile: string; currentTime: number; target: { id?: string | null; hfId?: string; selector?: string; selectorIndex?: number; }; label: string; tagName: string; boundingBox: { x: number; y: number; width: number; height: number; }; textContent: string | null; dataAttributes: Record; inlineStyles: Record; computedStyles: Record; textFields: StudioSelectionTextField[]; capabilities: Record; thumbnailUrl: string; } interface StudioSelectionResponse { selection: StudioSelectionSnapshot | null; updatedAt: string | null; } /** * Adapter interface — injected by each consumer to handle host-specific behavior. * The shared API module calls these methods; each host (vite dev, CLI embedded) * provides its own implementation. */ interface StudioApiAdapter { /** List all available projects. */ listProjects(): Promise | ResolvedProject[]; /** Resolve a project ID (or session ID) to its directory. Returns null if not found. */ resolveProject(id: string): Promise | ResolvedProject | null; /** Bundle a project directory into a single HTML string. Returns null if unavailable. */ bundle(projectDir: string): Promise; /** Optional: cached signature for project files that should invalidate preview frame caches. */ getProjectSignature?: (projectDir: string) => string; /** Lint a single HTML string. */ lint(html: string, opts?: { filePath?: string; }): Promise | LintResult; /** * Lint the complete project, including relationships between files. Official * adapters provide this; the single-file method remains as a compatibility * fallback for third-party adapters compiled against older releases. */ lintProject?: (projectDir: string) => Promise | ProjectLintResult; /** URL to the hyperframe runtime JS (injected into preview HTML). */ runtimeUrl: string; /** * Optional: post-process preview HTML before Studio augments it. * Useful when preview must mirror render-time compilation steps. */ transformPreviewHtml?: (opts: { html: string; project: ResolvedProject; activeCompositionPath: string; }) => Promise | string; /** Directory where render output files are stored. */ rendersDir(project: ResolvedProject): string; /** * Start a render job. The adapter owns the async execution and must * update the returned RenderJobState object reactively. */ startRender(opts: { project: ResolvedProject; outputPath: string; format: "mp4" | "webm" | "mov"; /** * Frame rate as an exact rational. The HTTP layer (POST * `/projects/:id/render`) accepts either a JSON number (integer fps, * `30`) or a JSON string (ffmpeg-style rational, `"30000/1001"`); the * route normalizes both into `Fps` before invoking the adapter, so * adapter implementations only ever see the rational form. */ fps: _hyperframes_core.Fps; quality: string; jobId: string; /** * The triggering browser profile has telemetry disabled (localStorage * opt-out, DNT, dev build...). The CLI cannot observe any of that, so the * browser has to say so — without it the server emitted render outcomes * for a user who had opted out, under the CLI's own policy. */ telemetryOptOut?: boolean; /** * Optional output resolution preset. See `resolveDeviceScaleFactor` in * the producer for the integer-scale + aspect + HDR constraints. */ outputResolution?: CanvasResolution; /** Entry file relative to projectDir (e.g. "compositions/intro.html"). Defaults to index.html. */ composition?: string; /** * Composition-variable overrides ({variableId: value}), forwarded to the * producer's RenderConfig.variables and injected as window.__hfVariables — * the same channel `hyperframes render --variables` uses. */ variables?: Record; /** * Telemetry id of the browser user who triggered the render. Lets the * adapter attribute the server-emitted render_complete/render_error to * that user so the studio render funnel is joinable. Undefined for older * clients → falls back to the install's anonymous id. */ distinctId?: string; }): RenderJobState; startBackgroundRemoval?: (opts: { project: ResolvedProject; inputPath: string; inputAssetPath: string; outputPath: string; outputAssetPath: string; backgroundOutputPath?: string; backgroundOutputAssetPath?: string; quality: "fast" | "balanced" | "best"; device?: "auto" | "cpu" | "coreml" | "cuda"; jobId: string; }) => MediaProcessingJobState; /** Optional: generate a thumbnail at the route's explicit output dimensions. */ generateThumbnail?: (opts: { project: ResolvedProject; compPath: string; seekTime: number; width: number; height: number; outputWidth: number; outputHeight: number; previewUrl: string; selector?: string; format?: "jpeg" | "png"; selectorIndex?: number; signal: AbortSignal; }) => Promise; /** Optional: resolve session ID to project (multi-project mode). */ resolveSession?: (sessionId: string) => Promise<{ projectId: string; title: string; } | null>; /** Optional: list all registry items (blocks + components) for the catalog. */ listRegistryCatalog?(): Promise; /** Optional: install a registry item into a project directory. */ installRegistryBlock?(opts: { project: ResolvedProject; blockName: string; }): Promise<{ written: string[]; block: RegistryItem; }>; } /** * Transparent-media-proxy wiring shared by `routes/preview.ts` * (docs/plans/2026-07-14-002-feat-transparent-media-proxies-plan.md, unit U3). * Split out of the route module to keep it under the repo's 600-line file cap. */ /** * Preview-route-local adapter surface for the auto-proxy feature. Both * fields are optional so any existing `StudioApiAdapter` value remains * structurally assignable without editing the shared interface: * `autoProxy` defaults to true (on) when omitted — a later unit wires the * CLI `--no-proxy` flag / `hyperframes.json` setting through it; * `mediaCodecProbeCache` lets a host share one probe cache across * preview/play/static-server surfaces instead of each constructing its own. */ type PreviewApiAdapter = StudioApiAdapter & { autoProxy?: boolean; mediaCodecProbeCache?: MediaCodecProbeCache; }; declare function isAutoProxyEnabled(adapter: PreviewApiAdapter): boolean; /** One probe cache per server instance — construct once in `registerPreviewRoutes` * and reuse across every request so the mtime-cache benefit in * `scanProjectMediaCodecMap` actually applies. A host that wants to share the * cache across other surfaces (play, static project server) can pass its own * via `adapter.mediaCodecProbeCache`. */ declare function resolvePreviewMediaCodecProbeCache(adapter: PreviewApiAdapter): MediaCodecProbeCache; /** * ETag salt for `?hf-proxy=` asset requests, mirroring `variablesEtagSalt` in * preview.ts: salted by the raw param value plus the transcoder's params * version, so a future proxy-recipe change (which bumps `PROXY_PARAMS_VERSION`) * or a different proxy variant invalidates cached 304s without needing to * touch the proxy file itself. */ declare function proxyEtagSalt(raw: string | undefined): string; /** * Injects `window.__HF_MEDIA_CODEC_MAP__` (the U1 codec-facts scan) into * served composition HTML, and fire-and-forget pre-warms `resolveProxy` for * every browser-hostile entry so an element's proactive swap usually hits a * warm cache (KTD: protects the per-origin connection budget under held * responses). No second concurrency limiter here — the transcoder's own * global bound throttles both pre-warm and element-triggered calls. * Pre-warm failures are swallowed; an actual `?hf-proxy=` request surfaces * them as a 502. Alpha-bearing entries pre-warm their VP8/WebM variant. * * The single shared implementation for every auto-proxy surface — the studio * preview route (via `injectMediaCodecMap` below) and the CLI's composition / * static project servers (via the `./media-proxy-preview` subpath export). * Empty maps leave HTML untouched, preserving the normal no-hostile-media * preview path. On-demand proxy requests enforce the same eligibility gate. */ declare function injectMediaCodecMapIntoHtml(html: string, projectDir: string, htmlSources: HtmlSourceLike[], probeCache?: MediaCodecProbeCache): Promise; /** * Adapter-aware wrapper used by the studio preview routes: skipped entirely * (no scan, no injection) when auto-proxy is off for this adapter. */ declare function injectMediaCodecMap(html: string, adapter: PreviewApiAdapter, projectDir: string, compSrcPath: string, probeCache: MediaCodecProbeCache): Promise; export { type LintResult as L, type MediaProcessingJobState as M, type PreviewApiAdapter as P, type RenderJobState as R, type StudioApiAdapter as S, type ResolvedProject as a, type StudioSelectionResponse as b, type StudioSelectionSnapshot as c, type StudioSelectionTextField as d, injectMediaCodecMapIntoHtml as e, isAutoProxyEnabled as f, injectMediaCodecMap as i, proxyEtagSalt as p, resolvePreviewMediaCodecProbeCache as r };