mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-07 18:26:17 +00:00
feat(producer): support entryFile for rendering individual compositions (#42)
## Changes
- Add optional `entryFile` parameter to render API endpoints (`/v1/render` and `/v1/render-stream`)
- Enable rendering individual sub-compositions by extracting them from index.html context when the entry file is a `<template>` wrapper
- Change base64 audio/video linting from detecting "fabricated" media to prohibiting all inline base64 media
- Add manifest path resolution for bundled producer deployments
## API Changes
- `RenderConfig` — new optional `entryFile` field for specifying HTML file to render
- `server.ts` — parses `entryFile` from request body, validates file exists in project directory
- `executeRenderJob` — uses `entryFile` instead of hardcoded `"index.html"`
## Template Extraction
- `extractStandaloneEntryFromIndex` — extracts sub-composition hosts from index.html and creates standalone render context
- Handles `<template>` entry files by finding matching `data-composition-src` in index.html and isolating that host
- Resets `data-start` to 0 for standalone rendering
## Linting Updates
- Change rule #3.7 from detecting "fabricated" base64 media to prohibiting all inline base64 audio/video
- Lower detection threshold from 100+ to 20+ base64 characters
- All base64 media now triggers error severity with clearer messaging about file size bloat
## Usage
```json
POST /v1/render-stream
{ "projectDir": "/path/to/project", "entryFile": "compositions/intro.html" }
```
Omit `entryFile` for default behavior (renders `index.html`).
This commit is contained in:
@@ -69,6 +69,7 @@ interface RenderInput {
|
||||
workers?: number;
|
||||
useGpu: boolean;
|
||||
debug: boolean;
|
||||
entryFile?: string;
|
||||
}
|
||||
|
||||
interface PreparedRenderInput {
|
||||
@@ -91,7 +92,12 @@ function parseRenderOptions(body: Record<string, unknown>): Omit<RenderInput, "p
|
||||
? body.output
|
||||
: null;
|
||||
|
||||
return { outputPath, fps, quality, workers, useGpu, debug };
|
||||
const entryFile =
|
||||
typeof body.entryFile === "string" && body.entryFile.trim().length > 0
|
||||
? body.entryFile.trim()
|
||||
: undefined;
|
||||
|
||||
return { outputPath, fps, quality, workers, useGpu, debug, entryFile };
|
||||
}
|
||||
|
||||
async function prepareRenderBody(
|
||||
@@ -104,8 +110,9 @@ async function prepareRenderBody(
|
||||
if (!existsSync(absProjectDir) || !statSync(absProjectDir).isDirectory()) {
|
||||
return { error: `Project directory not found: ${absProjectDir}` };
|
||||
}
|
||||
if (!existsSync(resolve(absProjectDir, "index.html"))) {
|
||||
return { error: `No index.html in project directory: ${absProjectDir}` };
|
||||
const entry = options.entryFile || "index.html";
|
||||
if (!existsSync(resolve(absProjectDir, entry))) {
|
||||
return { error: `Entry file "${entry}" not found in project directory: ${absProjectDir}` };
|
||||
}
|
||||
return { prepared: { input: { projectDir: absProjectDir, ...options } } };
|
||||
}
|
||||
@@ -317,6 +324,7 @@ export function createRenderHandlers(options: HandlerOptions = {}): RenderHandle
|
||||
workers: input.workers,
|
||||
useGpu: input.useGpu,
|
||||
debug: input.debug,
|
||||
entryFile: input.entryFile,
|
||||
logger: log,
|
||||
});
|
||||
|
||||
@@ -428,6 +436,7 @@ export function createRenderHandlers(options: HandlerOptions = {}): RenderHandle
|
||||
workers: input.workers,
|
||||
useGpu: input.useGpu,
|
||||
debug: input.debug,
|
||||
entryFile: input.entryFile,
|
||||
logger: log,
|
||||
});
|
||||
const abortController = new AbortController();
|
||||
|
||||
Reference in New Issue
Block a user