@hyperframes/studio-server 0.8.204 → 0.8.206
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.
- package/dist/{chunk-GR4TX52A.js → chunk-2GPN2OSU.js} +6 -0
- package/dist/helpers/encoderOptions.d.ts +2 -0
- package/dist/helpers/encoderOptions.js +1 -1
- package/dist/helpers/mediaProxyPreview.d.ts +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +20 -11
- package/dist/{mediaProxyPreview-CdpmyC5i.d.ts → mediaProxyPreview-DeICCYb5.d.ts} +2 -1
- package/package.json +3 -3
|
@@ -33,6 +33,12 @@ function parseEncoderOptions(body, format) {
|
|
|
33
33
|
const rate = parseRateControl(body, format);
|
|
34
34
|
if (!rate.ok) return rate;
|
|
35
35
|
const options = { ...rate.options };
|
|
36
|
+
if (isSet(body.gifLoop)) {
|
|
37
|
+
if (typeof body.gifLoop !== "number" || !Number.isInteger(body.gifLoop) || body.gifLoop < 0 || body.gifLoop > 65535) {
|
|
38
|
+
return { ok: false, error: "gifLoop must be an integer from 0 to 65535" };
|
|
39
|
+
}
|
|
40
|
+
if (format === "gif") options.gifLoop = body.gifLoop;
|
|
41
|
+
}
|
|
36
42
|
if (isSet(body.videoFrameFormat)) {
|
|
37
43
|
if (!oneOf(body.videoFrameFormat, VIDEO_FRAME_FORMATS)) {
|
|
38
44
|
return {
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
declare const VIDEO_FRAME_FORMATS: readonly ["auto", "jpg", "png"];
|
|
2
2
|
declare const HDR_MODES: readonly ["auto", "force-hdr", "force-sdr"];
|
|
3
3
|
interface EncoderOptions {
|
|
4
|
+
gifLoop?: number;
|
|
4
5
|
crf?: number;
|
|
5
6
|
videoBitrate?: string;
|
|
6
7
|
videoFrameFormat?: (typeof VIDEO_FRAME_FORMATS)[number];
|
|
7
8
|
hdrMode?: (typeof HDR_MODES)[number];
|
|
8
9
|
}
|
|
9
10
|
interface EncoderOptionsBody {
|
|
11
|
+
gifLoop?: unknown;
|
|
10
12
|
crf?: unknown;
|
|
11
13
|
videoBitrate?: unknown;
|
|
12
14
|
videoFrameFormat?: unknown;
|
|
@@ -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-
|
|
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-DeICCYb5.js';
|
|
3
3
|
import './mediaCodecMap.js';
|
|
4
4
|
import 'sharp';
|
|
5
5
|
import '@hyperframes/parsers';
|
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-
|
|
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-
|
|
2
|
+
import { S as StudioApiAdapter, P as PreviewDocumentStore, M as MediaProcessingJobState } from './mediaProxyPreview-DeICCYb5.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-DeICCYb5.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 HistoryRefusedError, f as HistoryResult, g as HistoryTarget, h as HistoryWho, i as HistoryWindow, M as MAX_WINDOW_IDLE_MS, P as ProjectHistory, j as ProjectHistoryOptions, k as ProjectHistoryView, U as UNDO_MODES, l as UndoMode, o as openProjectHistory, r as readProjectHistory } from './projectHistory-C18HDvac.js';
|
|
5
5
|
export { ArtifactCapture, ArtifactInput, ArtifactRecord, HistoryBusyError, HistoryIdError, ProjectHistoryRecord, PrunedHistory, ReclaimedHistory, RenderRecord, VideoState, artifactDirectory, beginArtifactCapture, finishSnapshotRun, forgetRecordedArtifacts, historyCache, listProjectHistories, pruneGoneProjectHistories, reclaimUncopiedBlobs, recordArtifact, recordArtifacts, recordRenderSuccess, registerRenderOutput, retainSnapshotOutput } from './history/index.js';
|
|
6
6
|
export { CACHE_DIR_NAME as PROXY_CACHE_DIR_NAME } from './helpers/proxyTranscoder.js';
|
package/dist/index.js
CHANGED
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
} from "./chunk-FJBJJURY.js";
|
|
25
25
|
import {
|
|
26
26
|
parseEncoderOptions
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-2GPN2OSU.js";
|
|
28
28
|
import {
|
|
29
29
|
DEFAULT_HISTORY_ROOT,
|
|
30
30
|
DELETED_VERSION,
|
|
@@ -3871,6 +3871,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
3871
3871
|
// src/routes/preview.ts
|
|
3872
3872
|
import { parseHTML as parseHTML7 } from "linkedom";
|
|
3873
3873
|
import { createReadStream, existsSync as existsSync5, readFileSync as readFileSync6, statSync as statSync4 } from "fs";
|
|
3874
|
+
import { stripSdrPngColourTags } from "@hyperframes/core/compiler/png-colour-tags";
|
|
3874
3875
|
import { Readable } from "stream";
|
|
3875
3876
|
import { join as join8, resolve as resolve4 } from "path";
|
|
3876
3877
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -4567,8 +4568,9 @@ ${etag}`;
|
|
|
4567
4568
|
servedContentType = PROXY_VARIANT_CONFIG[proxyVariant].contentType;
|
|
4568
4569
|
}
|
|
4569
4570
|
const textBuffer = isText ? Buffer.from(readFileSync6(file, "utf-8"), "utf-8") : null;
|
|
4570
|
-
const
|
|
4571
|
-
const
|
|
4571
|
+
const heldBuffer = textBuffer ?? (contentType === "image/png" ? stripSdrPngColourTags(readFileSync6(file)) : null);
|
|
4572
|
+
const totalSize = heldBuffer ? heldBuffer.length : statSync4(servedPath).size;
|
|
4573
|
+
const bodyFor = (start, end) => heldBuffer ? new Uint8Array(heldBuffer.subarray(start, end + 1)) : (
|
|
4572
4574
|
// Node's web stream type and the DOM one do not overlap for tsc on
|
|
4573
4575
|
// every platform's lib set; the double cast is the documented bridge.
|
|
4574
4576
|
Readable.toWeb(
|
|
@@ -4669,12 +4671,13 @@ import { streamSSE } from "hono/streaming";
|
|
|
4669
4671
|
import { existsSync as existsSync6, lstatSync as lstatSync3, readFileSync as readFileSync8, unlinkSync as unlinkSync3, readdirSync as readdirSync3, statSync as statSync5 } from "fs";
|
|
4670
4672
|
import { dirname as dirname5, join as join10 } from "path";
|
|
4671
4673
|
import { VALID_CANVAS_RESOLUTIONS } from "@hyperframes/parsers";
|
|
4672
|
-
import { formatRenderOutputTimestamp, parseFps } from "@hyperframes/core";
|
|
4674
|
+
import { formatRenderOutputTimestamp, parseFps, fpsToNumber } from "@hyperframes/core";
|
|
4673
4675
|
var VALID_RESOLUTIONS = new Set(VALID_CANVAS_RESOLUTIONS);
|
|
4674
4676
|
var RENDER_MIME = {
|
|
4675
4677
|
".mp4": "video/mp4",
|
|
4676
4678
|
".webm": "video/webm",
|
|
4677
|
-
".mov": "video/quicktime"
|
|
4679
|
+
".mov": "video/quicktime",
|
|
4680
|
+
".gif": "image/gif"
|
|
4678
4681
|
};
|
|
4679
4682
|
var RENDER_EXTENSIONS = Object.keys(RENDER_MIME);
|
|
4680
4683
|
var RENDER_ARTIFACT_EXTENSIONS = [...RENDER_EXTENSIONS, ".meta.json"];
|
|
@@ -4724,11 +4727,17 @@ function registerRenderRoutes(api, adapter) {
|
|
|
4724
4727
|
const project = await adapter.resolveProject(c.req.param("id"));
|
|
4725
4728
|
if (!project) return c.json({ error: "not found" }, 404);
|
|
4726
4729
|
const body = await c.req.json().catch(() => ({}));
|
|
4727
|
-
const VALID_FORMATS =
|
|
4728
|
-
const FORMAT_EXT = {
|
|
4729
|
-
|
|
4730
|
+
const VALID_FORMATS = ["mp4", "webm", "mov", "gif"];
|
|
4731
|
+
const FORMAT_EXT = {
|
|
4732
|
+
mp4: ".mp4",
|
|
4733
|
+
webm: ".webm",
|
|
4734
|
+
mov: ".mov",
|
|
4735
|
+
gif: ".gif"
|
|
4736
|
+
};
|
|
4737
|
+
const format = VALID_FORMATS.find((value) => value === body.format) ?? "mp4";
|
|
4730
4738
|
const fpsParse = body.fps === void 0 ? null : parseFps(body.fps);
|
|
4731
|
-
const
|
|
4739
|
+
const requestedFps = fpsParse && fpsParse.ok ? fpsParse.value : { num: 30, den: 1 };
|
|
4740
|
+
const fps = format === "gif" && fpsToNumber(requestedFps) > 30 ? { num: 30, den: 1 } : requestedFps;
|
|
4732
4741
|
const quality = ["draft", "standard", "high"].includes(body.quality ?? "") ? body.quality : "standard";
|
|
4733
4742
|
const outputResolution = VALID_RESOLUTIONS.has(body.resolution ?? "") ? body.resolution : void 0;
|
|
4734
4743
|
let composition;
|
|
@@ -4903,12 +4912,12 @@ function registerRenderRoutes(api, adapter) {
|
|
|
4903
4912
|
if (!project) return c.json({ error: "not found" }, 404);
|
|
4904
4913
|
const rendersDir = adapter.rendersDir(project);
|
|
4905
4914
|
if (!existsSync6(rendersDir)) return c.json({ renders: [] });
|
|
4906
|
-
const files = readdirSync3(rendersDir).filter((f) =>
|
|
4915
|
+
const files = readdirSync3(rendersDir).filter((f) => RENDER_EXTENSIONS.some((extension) => f.endsWith(extension))).flatMap((f) => {
|
|
4907
4916
|
const fp = resolveWithinProject(rendersDir, f);
|
|
4908
4917
|
return fp && !isPrivateProjectFile(project.dir, fp) ? [{ f, fp }] : [];
|
|
4909
4918
|
}).map(({ f, fp }) => {
|
|
4910
4919
|
const stat2 = statSync5(fp);
|
|
4911
|
-
const rid = f.replace(/\.(mp4|webm|mov)$/, "");
|
|
4920
|
+
const rid = f.replace(/\.(mp4|webm|mov|gif)$/, "");
|
|
4912
4921
|
const metaPath = join10(rendersDir, `${rid}.meta.json`);
|
|
4913
4922
|
let status = "complete";
|
|
4914
4923
|
let durationMs;
|
|
@@ -154,7 +154,7 @@ interface StudioApiAdapter {
|
|
|
154
154
|
startRender(opts: {
|
|
155
155
|
project: ResolvedProject;
|
|
156
156
|
outputPath: string;
|
|
157
|
-
format: "mp4" | "webm" | "mov";
|
|
157
|
+
format: "mp4" | "webm" | "mov" | "gif";
|
|
158
158
|
/**
|
|
159
159
|
* Frame rate as an exact rational. The HTTP layer (POST
|
|
160
160
|
* `/projects/:id/render`) accepts either a JSON number (integer fps,
|
|
@@ -164,6 +164,7 @@ interface StudioApiAdapter {
|
|
|
164
164
|
*/
|
|
165
165
|
fps: _hyperframes_core.Fps;
|
|
166
166
|
quality: string;
|
|
167
|
+
gifLoop?: number;
|
|
167
168
|
crf?: number;
|
|
168
169
|
videoBitrate?: string;
|
|
169
170
|
videoFrameFormat?: "auto" | "jpg" | "png";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/studio-server",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.206",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/heygen-com/hyperframes",
|
|
@@ -84,8 +84,8 @@
|
|
|
84
84
|
"linkedom": "^0.18.12",
|
|
85
85
|
"postcss": "^8.5.8",
|
|
86
86
|
"postcss-selector-parser": "^7.1.2",
|
|
87
|
-
"@hyperframes/parsers": "0.8.
|
|
88
|
-
"@hyperframes/core": "0.8.
|
|
87
|
+
"@hyperframes/parsers": "0.8.206",
|
|
88
|
+
"@hyperframes/core": "0.8.206"
|
|
89
89
|
},
|
|
90
90
|
"devDependencies": {
|
|
91
91
|
"@types/node": "^25.0.10",
|