@hyperframes/studio-server 0.8.203 → 0.8.205

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.
@@ -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,6 +1,6 @@
1
1
  import {
2
2
  parseEncoderOptions
3
- } from "../chunk-GR4TX52A.js";
3
+ } from "../chunk-2GPN2OSU.js";
4
4
  export {
5
5
  parseEncoderOptions
6
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-CdpmyC5i.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-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-CdpmyC5i.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-CdpmyC5i.js';
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-GR4TX52A.js";
27
+ } from "./chunk-2GPN2OSU.js";
28
28
  import {
29
29
  DEFAULT_HISTORY_ROOT,
30
30
  DELETED_VERSION,
@@ -4669,12 +4669,13 @@ import { streamSSE } from "hono/streaming";
4669
4669
  import { existsSync as existsSync6, lstatSync as lstatSync3, readFileSync as readFileSync8, unlinkSync as unlinkSync3, readdirSync as readdirSync3, statSync as statSync5 } from "fs";
4670
4670
  import { dirname as dirname5, join as join10 } from "path";
4671
4671
  import { VALID_CANVAS_RESOLUTIONS } from "@hyperframes/parsers";
4672
- import { formatRenderOutputTimestamp, parseFps } from "@hyperframes/core";
4672
+ import { formatRenderOutputTimestamp, parseFps, fpsToNumber } from "@hyperframes/core";
4673
4673
  var VALID_RESOLUTIONS = new Set(VALID_CANVAS_RESOLUTIONS);
4674
4674
  var RENDER_MIME = {
4675
4675
  ".mp4": "video/mp4",
4676
4676
  ".webm": "video/webm",
4677
- ".mov": "video/quicktime"
4677
+ ".mov": "video/quicktime",
4678
+ ".gif": "image/gif"
4678
4679
  };
4679
4680
  var RENDER_EXTENSIONS = Object.keys(RENDER_MIME);
4680
4681
  var RENDER_ARTIFACT_EXTENSIONS = [...RENDER_EXTENSIONS, ".meta.json"];
@@ -4724,11 +4725,17 @@ function registerRenderRoutes(api, adapter) {
4724
4725
  const project = await adapter.resolveProject(c.req.param("id"));
4725
4726
  if (!project) return c.json({ error: "not found" }, 404);
4726
4727
  const body = await c.req.json().catch(() => ({}));
4727
- const VALID_FORMATS = /* @__PURE__ */ new Set(["mp4", "webm", "mov"]);
4728
- const FORMAT_EXT = { mp4: ".mp4", webm: ".webm", mov: ".mov" };
4729
- const format = VALID_FORMATS.has(body.format ?? "") ? body.format : "mp4";
4728
+ const VALID_FORMATS = ["mp4", "webm", "mov", "gif"];
4729
+ const FORMAT_EXT = {
4730
+ mp4: ".mp4",
4731
+ webm: ".webm",
4732
+ mov: ".mov",
4733
+ gif: ".gif"
4734
+ };
4735
+ const format = VALID_FORMATS.find((value) => value === body.format) ?? "mp4";
4730
4736
  const fpsParse = body.fps === void 0 ? null : parseFps(body.fps);
4731
- const fps = fpsParse && fpsParse.ok ? fpsParse.value : { num: 30, den: 1 };
4737
+ const requestedFps = fpsParse && fpsParse.ok ? fpsParse.value : { num: 30, den: 1 };
4738
+ const fps = format === "gif" && fpsToNumber(requestedFps) > 30 ? { num: 30, den: 1 } : requestedFps;
4732
4739
  const quality = ["draft", "standard", "high"].includes(body.quality ?? "") ? body.quality : "standard";
4733
4740
  const outputResolution = VALID_RESOLUTIONS.has(body.resolution ?? "") ? body.resolution : void 0;
4734
4741
  let composition;
@@ -4903,12 +4910,12 @@ function registerRenderRoutes(api, adapter) {
4903
4910
  if (!project) return c.json({ error: "not found" }, 404);
4904
4911
  const rendersDir = adapter.rendersDir(project);
4905
4912
  if (!existsSync6(rendersDir)) return c.json({ renders: [] });
4906
- const files = readdirSync3(rendersDir).filter((f) => f.endsWith(".mp4") || f.endsWith(".webm") || f.endsWith(".mov")).flatMap((f) => {
4913
+ const files = readdirSync3(rendersDir).filter((f) => RENDER_EXTENSIONS.some((extension) => f.endsWith(extension))).flatMap((f) => {
4907
4914
  const fp = resolveWithinProject(rendersDir, f);
4908
4915
  return fp && !isPrivateProjectFile(project.dir, fp) ? [{ f, fp }] : [];
4909
4916
  }).map(({ f, fp }) => {
4910
4917
  const stat2 = statSync5(fp);
4911
- const rid = f.replace(/\.(mp4|webm|mov)$/, "");
4918
+ const rid = f.replace(/\.(mp4|webm|mov|gif)$/, "");
4912
4919
  const metaPath = join10(rendersDir, `${rid}.meta.json`);
4913
4920
  let status = "complete";
4914
4921
  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.203",
3
+ "version": "0.8.205",
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/core": "0.8.203",
88
- "@hyperframes/parsers": "0.8.203"
87
+ "@hyperframes/core": "0.8.205",
88
+ "@hyperframes/parsers": "0.8.205"
89
89
  },
90
90
  "devDependencies": {
91
91
  "@types/node": "^25.0.10",