@hyperframes/studio-server 0.8.154 → 0.8.155

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,56 @@
1
+ // src/helpers/encoderOptions.ts
2
+ var CRF_MAX_BY_FORMAT = { mp4: 51, webm: 63 };
3
+ var VIDEO_BITRATE = /^\d+(\.\d+)?[kKmMgG]?$/;
4
+ var VIDEO_FRAME_FORMATS = ["auto", "jpg", "png"];
5
+ var HDR_MODES = ["auto", "force-hdr", "force-sdr"];
6
+ var isSet = (value) => value !== void 0 && value !== null;
7
+ function oneOf(value, allowed) {
8
+ return typeof value === "string" && allowed.includes(value);
9
+ }
10
+ function parseCrf(crf, format, max) {
11
+ if (typeof crf !== "number" || !Number.isInteger(crf) || crf < 0 || crf > max) {
12
+ return { ok: false, error: `crf must be an integer from 0 to ${max} for ${format}` };
13
+ }
14
+ return { ok: true, options: { crf } };
15
+ }
16
+ function parseVideoBitrate(videoBitrate) {
17
+ if (typeof videoBitrate !== "string" || !VIDEO_BITRATE.test(videoBitrate)) {
18
+ return { ok: false, error: 'videoBitrate must look like "10M", "2500k" or "8000000"' };
19
+ }
20
+ return { ok: true, options: { videoBitrate } };
21
+ }
22
+ function parseRateControl(body, format) {
23
+ const max = CRF_MAX_BY_FORMAT[format];
24
+ if (max === void 0) return { ok: true, options: {} };
25
+ if (isSet(body.crf) && isSet(body.videoBitrate)) {
26
+ return { ok: false, error: "use either crf or videoBitrate, not both" };
27
+ }
28
+ if (isSet(body.crf)) return parseCrf(body.crf, format, max);
29
+ if (isSet(body.videoBitrate)) return parseVideoBitrate(body.videoBitrate);
30
+ return { ok: true, options: {} };
31
+ }
32
+ function parseEncoderOptions(body, format) {
33
+ const rate = parseRateControl(body, format);
34
+ if (!rate.ok) return rate;
35
+ const options = { ...rate.options };
36
+ if (isSet(body.videoFrameFormat)) {
37
+ if (!oneOf(body.videoFrameFormat, VIDEO_FRAME_FORMATS)) {
38
+ return {
39
+ ok: false,
40
+ error: `videoFrameFormat must be one of ${VIDEO_FRAME_FORMATS.join(", ")}`
41
+ };
42
+ }
43
+ options.videoFrameFormat = body.videoFrameFormat;
44
+ }
45
+ if (isSet(body.hdrMode)) {
46
+ if (!oneOf(body.hdrMode, HDR_MODES)) {
47
+ return { ok: false, error: `hdrMode must be one of ${HDR_MODES.join(", ")}` };
48
+ }
49
+ options.hdrMode = body.hdrMode;
50
+ }
51
+ return { ok: true, options };
52
+ }
53
+
54
+ export {
55
+ parseEncoderOptions
56
+ };
@@ -0,0 +1,25 @@
1
+ declare const VIDEO_FRAME_FORMATS: readonly ["auto", "jpg", "png"];
2
+ declare const HDR_MODES: readonly ["auto", "force-hdr", "force-sdr"];
3
+ interface EncoderOptions {
4
+ crf?: number;
5
+ videoBitrate?: string;
6
+ videoFrameFormat?: (typeof VIDEO_FRAME_FORMATS)[number];
7
+ hdrMode?: (typeof HDR_MODES)[number];
8
+ }
9
+ interface EncoderOptionsBody {
10
+ crf?: unknown;
11
+ videoBitrate?: unknown;
12
+ videoFrameFormat?: unknown;
13
+ hdrMode?: unknown;
14
+ }
15
+ type Parsed = {
16
+ ok: true;
17
+ options: EncoderOptions;
18
+ } | {
19
+ ok: false;
20
+ error: string;
21
+ };
22
+ /** Explicit encoder overrides from a render request. MOV (ProRes) takes no rate control. */
23
+ declare function parseEncoderOptions(body: EncoderOptionsBody, format: string): Parsed;
24
+
25
+ export { type EncoderOptionsBody, parseEncoderOptions };
@@ -0,0 +1,6 @@
1
+ import {
2
+ parseEncoderOptions
3
+ } from "../chunk-GR4TX52A.js";
4
+ export {
5
+ parseEncoderOptions
6
+ };
@@ -1,5 +1,5 @@
1
1
  import '@hyperframes/core';
2
- export { a as PreviewApiAdapter, P as PreviewDocumentStore, i as injectMediaCodecMap, f as injectMediaCodecMapIntoHtml, g as isAutoProxyEnabled, p as proxyEtagSalt, r as resolvePreviewMediaCodecProbeCache } from '../mediaProxyPreview-DB1EEdxc.js';
2
+ export { a as PreviewApiAdapter, P as PreviewDocumentStore, i as injectMediaCodecMap, f as injectMediaCodecMapIntoHtml, g as isAutoProxyEnabled, p as proxyEtagSalt, r as resolvePreviewMediaCodecProbeCache } from '../mediaProxyPreview-J8vlAvrx.js';
3
3
  import './mediaCodecMap.js';
4
4
  import '@hyperframes/parsers';
5
5
  import '@hyperframes/core/compiler';
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Hono } from 'hono';
2
- import { S as StudioApiAdapter, P as PreviewDocumentStore, M as MediaProcessingJobState } from './mediaProxyPreview-DB1EEdxc.js';
3
- export { L as LintResult, a as PreviewApiAdapter, R as RenderJobState, b as ResolvedProject, c as StudioSelectionResponse, d as StudioSelectionSnapshot, e as StudioSelectionTextField } from './mediaProxyPreview-DB1EEdxc.js';
2
+ import { S as StudioApiAdapter, P as PreviewDocumentStore, M as MediaProcessingJobState } from './mediaProxyPreview-J8vlAvrx.js';
3
+ export { L as LintResult, a as PreviewApiAdapter, R as RenderJobState, b as ResolvedProject, c as StudioSelectionResponse, d as StudioSelectionSnapshot, e as StudioSelectionTextField } from './mediaProxyPreview-J8vlAvrx.js';
4
4
  export { C as ClosedWindow, D as DEFAULT_HISTORY_ROOT, S as HISTORY_START, H as HistoryClosedError, a as HistoryEntry, b as HistoryEntrySide, c as HistoryFileChange, d as HistoryListItem, e as HistoryResult, f as HistoryTarget, g as HistoryWho, h as HistoryWindow, M as MAX_WINDOW_IDLE_MS, P as ProjectHistory, i as ProjectHistoryOptions, j as ProjectHistoryView, U as UNDO_MODES, k as UndoMode, o as openProjectHistory, r as readProjectHistory } from './projectHistory-C5dpCjPU.js';
5
5
  export { ArtifactCapture, ArtifactInput, ArtifactRecord, HistoryBusyError, HistoryIdError, ProjectHistoryRecord, PrunedHistory, RenderRecord, VideoState, artifactDirectory, beginArtifactCapture, forgetRecordedArtifacts, historyCache, listProjectHistories, pruneGoneProjectHistories, recordArtifact, recordArtifacts, recordRenderSuccess, registerRenderOutput } from './history/index.js';
6
6
  export { CACHE_DIR_NAME as PROXY_CACHE_DIR_NAME } from './helpers/proxyTranscoder.js';
package/dist/index.js CHANGED
@@ -22,6 +22,9 @@ import {
22
22
  isCompositionSource,
23
23
  stampProjectHfIds
24
24
  } from "./chunk-6RICWA3B.js";
25
+ import {
26
+ parseEncoderOptions
27
+ } from "./chunk-GR4TX52A.js";
25
28
  import {
26
29
  DEFAULT_HISTORY_ROOT,
27
30
  DELETED_VERSION,
@@ -4634,6 +4637,8 @@ function registerRenderRoutes(api, adapter) {
4634
4637
  }
4635
4638
  variables = body.variables;
4636
4639
  }
4640
+ const encoder = parseEncoderOptions(body, format);
4641
+ if (!encoder.ok) return c.json({ error: encoder.error }, 400);
4637
4642
  const now = /* @__PURE__ */ new Date();
4638
4643
  const jobId = `${project.id}_${formatRenderOutputTimestamp(now)}`;
4639
4644
  const rendersDir = adapter.rendersDir(project);
@@ -4650,6 +4655,7 @@ function registerRenderRoutes(api, adapter) {
4650
4655
  outputResolution,
4651
4656
  composition,
4652
4657
  variables,
4658
+ ...encoder.options,
4653
4659
  useGpu: body.gpu === true && format === "mp4",
4654
4660
  distinctId: typeof body.telemetryDistinctId === "string" ? body.telemetryDistinctId : void 0,
4655
4661
  telemetryOptOut: body.telemetryOptOut === true
@@ -161,6 +161,10 @@ interface StudioApiAdapter {
161
161
  */
162
162
  fps: _hyperframes_core.Fps;
163
163
  quality: string;
164
+ crf?: number;
165
+ videoBitrate?: string;
166
+ videoFrameFormat?: "auto" | "jpg" | "png";
167
+ hdrMode?: "auto" | "force-hdr" | "force-sdr";
164
168
  jobId: string;
165
169
  /**
166
170
  * The triggering browser profile has telemetry disabled (localStorage
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperframes/studio-server",
3
- "version": "0.8.154",
3
+ "version": "0.8.155",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/heygen-com/hyperframes",
@@ -70,6 +70,10 @@
70
70
  "./media-proxy-preview": {
71
71
  "import": "./dist/helpers/mediaProxyPreview.js",
72
72
  "types": "./dist/helpers/mediaProxyPreview.d.ts"
73
+ },
74
+ "./encoder-options": {
75
+ "import": "./dist/helpers/encoderOptions.js",
76
+ "types": "./dist/helpers/encoderOptions.d.ts"
73
77
  }
74
78
  },
75
79
  "publishConfig": {
@@ -81,8 +85,8 @@
81
85
  "postcss": "^8.5.8",
82
86
  "postcss-selector-parser": "^7.1.2",
83
87
  "sharp": "^0.35.0",
84
- "@hyperframes/core": "0.8.154",
85
- "@hyperframes/parsers": "0.8.154"
88
+ "@hyperframes/core": "0.8.155",
89
+ "@hyperframes/parsers": "0.8.155"
86
90
  },
87
91
  "devDependencies": {
88
92
  "@types/node": "^25.0.10",