@hyperframes/studio-server 0.8.180 → 0.8.183

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.
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  PROXY_PARAMS_VERSION,
3
3
  resolveProxy
4
- } from "./chunk-QFJR3NIL.js";
4
+ } from "./chunk-D5RQMNZQ.js";
5
5
  import {
6
6
  createMediaCodecProbeCache,
7
7
  proxyVariantFor,
@@ -555,7 +555,8 @@ async function resolveProxy(projectDir, absoluteSourcePath, variant = "h264", bo
555
555
  if (options.priority) prioritize(entry.job);
556
556
  return joinJob(entry.promise, entry.job, options.signal);
557
557
  }
558
- async function resolveProxies(projectDir, sources) {
558
+ async function resolveProxies(projectDir, sources, onSettled = () => {
559
+ }) {
559
560
  const results = [];
560
561
  let next = 0;
561
562
  const worker = async () => {
@@ -568,6 +569,7 @@ async function resolveProxies(projectDir, sources) {
568
569
  (value) => ({ status: "fulfilled", value }),
569
570
  (reason) => ({ status: "rejected", reason })
570
571
  );
572
+ onSettled();
571
573
  }
572
574
  };
573
575
  const workers = Math.min(MAX_CONCURRENT_TRANSCODES, sources.length);
@@ -119,6 +119,10 @@ var HistoryBusyError = class extends Error {
119
119
  pid;
120
120
  url;
121
121
  };
122
+ var WINDOWS_BUSY = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "EACCES"]);
123
+ function busyOnWindows(error) {
124
+ return process.platform === "win32" && WINDOWS_BUSY.has(error.code ?? "");
125
+ }
122
126
  function alive(pid) {
123
127
  if (!Number.isInteger(pid) || pid <= 0) return false;
124
128
  try {
@@ -183,27 +187,36 @@ function servedBy(file, urlFile, pid) {
183
187
  return void 0;
184
188
  }
185
189
  }
190
+ function attemptClaim(file, urlFile, deadline) {
191
+ if (claim(file)) return "claimed";
192
+ const pid = ownerOf(file);
193
+ if (pid === null) return "retry";
194
+ if (!alive(pid) && evictDeadOwner(file)) return "retry";
195
+ if (Date.now() >= deadline) throw new HistoryBusyError(pid, servedBy(file, urlFile, pid));
196
+ return "wait";
197
+ }
186
198
  async function takeHistoryOwnership(home, waitMs, url) {
187
199
  const file = join(home, "owner.pid");
188
200
  const urlFile = join(home, "owner-url.json");
189
201
  const deadline = Date.now() + waitMs;
190
202
  mkdirSync(home, { recursive: true });
191
203
  for (; ; ) {
192
- if (claim(file)) {
193
- advertise(urlFile, url);
194
- let held = true;
195
- return () => {
196
- if (held && servedBy(file, urlFile, process.pid)) rmSync(urlFile, { force: true });
197
- if (held) releaseOwn(file);
198
- held = false;
199
- };
204
+ let next = "wait";
205
+ try {
206
+ next = attemptClaim(file, urlFile, deadline);
207
+ } catch (error) {
208
+ if (!busyOnWindows(error) || Date.now() >= deadline) throw error;
200
209
  }
201
- const pid = ownerOf(file);
202
- if (pid === null) continue;
203
- if (!alive(pid) && evictDeadOwner(file)) continue;
204
- if (Date.now() >= deadline) throw new HistoryBusyError(pid, servedBy(file, urlFile, pid));
205
- await new Promise((settle) => setTimeout(settle, 50));
206
- }
210
+ if (next === "claimed") break;
211
+ if (next === "wait") await new Promise((settle) => setTimeout(settle, 50));
212
+ }
213
+ advertise(urlFile, url);
214
+ let held = true;
215
+ return () => {
216
+ if (held && servedBy(file, urlFile, process.pid)) rmSync(urlFile, { force: true });
217
+ if (held) releaseOwn(file);
218
+ held = false;
219
+ };
207
220
  }
208
221
 
209
222
  // src/helpers/renderOutputs.ts
@@ -1,6 +1,7 @@
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-DIAid9-k.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-GMF-_zBh.js';
3
3
  import './mediaCodecMap.js';
4
+ import 'sharp';
4
5
  import '@hyperframes/parsers';
5
6
  import '@hyperframes/core/compiler';
6
7
  import '../projectHistory-ByC9sa3X.js';
@@ -4,8 +4,8 @@ import {
4
4
  isAutoProxyEnabled,
5
5
  proxyEtagSalt,
6
6
  resolvePreviewMediaCodecProbeCache
7
- } from "../chunk-7L3DUCM3.js";
8
- import "../chunk-QFJR3NIL.js";
7
+ } from "../chunk-436CO7P5.js";
8
+ import "../chunk-D5RQMNZQ.js";
9
9
  import "../chunk-E3VGIAMJ.js";
10
10
  import "../chunk-QF7MFJJU.js";
11
11
  import "../chunk-SVQFE44C.js";
@@ -71,7 +71,7 @@ declare function resolveProxy(projectDir: string, absoluteSourcePath: string, va
71
71
  declare function resolveProxies(projectDir: string, sources: ReadonlyArray<{
72
72
  sourcePath: string;
73
73
  variant: ProxyVariant;
74
- }>): Promise<PromiseSettledResult<string>[]>;
74
+ }>, onSettled?: () => void): Promise<PromiseSettledResult<string>[]>;
75
75
  interface ResolveProxyOptions {
76
76
  priority?: boolean;
77
77
  signal?: AbortSignal;
@@ -16,7 +16,7 @@ import {
16
16
  resolveProxies,
17
17
  resolveProxy,
18
18
  waitForProxy
19
- } from "../chunk-QFJR3NIL.js";
19
+ } from "../chunk-D5RQMNZQ.js";
20
20
  import "../chunk-E3VGIAMJ.js";
21
21
  import "../chunk-QF7MFJJU.js";
22
22
  import "../chunk-SVQFE44C.js";
@@ -20,7 +20,7 @@ import {
20
20
  recordRenderSuccess,
21
21
  registerRenderOutput,
22
22
  retainSnapshotOutput
23
- } from "../chunk-6PE5OD32.js";
23
+ } from "../chunk-XM2TJIF5.js";
24
24
  import "../chunk-QF7MFJJU.js";
25
25
  import "../chunk-SVQFE44C.js";
26
26
  import "../chunk-L3HJVTQE.js";
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-DIAid9-k.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-DIAid9-k.js';
2
+ import { S as StudioApiAdapter, P as PreviewDocumentStore, M as MediaProcessingJobState } from './mediaProxyPreview-GMF-_zBh.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-GMF-_zBh.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-ByC9sa3X.js';
5
5
  export { ArtifactCapture, ArtifactInput, ArtifactRecord, HistoryBusyError, HistoryIdError, ProjectHistoryRecord, PrunedHistory, RenderRecord, VideoState, artifactDirectory, beginArtifactCapture, finishSnapshotRun, forgetRecordedArtifacts, historyCache, listProjectHistories, pruneGoneProjectHistories, recordArtifact, recordArtifacts, recordRenderSuccess, registerRenderOutput, retainSnapshotOutput } from './history/index.js';
6
6
  export { CACHE_DIR_NAME as PROXY_CACHE_DIR_NAME } from './helpers/proxyTranscoder.js';
@@ -14,6 +14,7 @@ export { STUDIO_MOTION_PATH, StudioMotionRenderScriptOptions, createStudioMotion
14
14
  export { decodeWellFormedEscapes } from '@hyperframes/parsers/asset-paths';
15
15
  export { isSafePath } from '@hyperframes/core/safe-path';
16
16
  import '@hyperframes/core';
17
+ import 'sharp';
17
18
  import '@hyperframes/parsers';
18
19
  import '@hyperframes/core/compiler';
19
20
  import './helpers/mediaCodecMap.js';
package/dist/index.js CHANGED
@@ -60,7 +60,7 @@ import {
60
60
  resolveProjectSignature,
61
61
  retainSnapshotOutput,
62
62
  settledFileTag
63
- } from "./chunk-6PE5OD32.js";
63
+ } from "./chunk-XM2TJIF5.js";
64
64
  import {
65
65
  clearElementScreenshotIsolation,
66
66
  getElementScreenshotClip
@@ -80,7 +80,7 @@ import {
80
80
  isAutoProxyEnabled,
81
81
  proxyEtagSalt,
82
82
  resolvePreviewMediaCodecProbeCache
83
- } from "./chunk-7L3DUCM3.js";
83
+ } from "./chunk-436CO7P5.js";
84
84
  import {
85
85
  CACHE_DIR_NAME,
86
86
  PROXY_PENDING_RETRY_AFTER_SECONDS,
@@ -91,7 +91,7 @@ import {
91
91
  proxyActivityMark,
92
92
  resolveProxy,
93
93
  waitForProxy
94
- } from "./chunk-QFJR3NIL.js";
94
+ } from "./chunk-D5RQMNZQ.js";
95
95
  import {
96
96
  PROXY_VARIANT_CONFIG,
97
97
  decideMediaProxyEligibility,
@@ -200,11 +200,11 @@ import { resolve as resolve2, dirname as dirname3, join as join6, sep as sep2 }
200
200
 
201
201
  // src/helpers/mime.ts
202
202
  var MIME_TYPES = {
203
- ".html": "text/html",
204
- ".css": "text/css",
205
- ".js": "text/javascript",
206
- ".mjs": "text/javascript",
207
- ".json": "application/json",
203
+ ".html": "text/html; charset=utf-8",
204
+ ".css": "text/css; charset=utf-8",
205
+ ".js": "text/javascript; charset=utf-8",
206
+ ".mjs": "text/javascript; charset=utf-8",
207
+ ".json": "application/json; charset=utf-8",
208
208
  ".svg": "image/svg+xml",
209
209
  ".png": "image/png",
210
210
  ".jpg": "image/jpeg",
@@ -4948,18 +4948,18 @@ var thumbnailGenerationCoordinator = new ThumbnailGenerationCoordinator(1);
4948
4948
  // src/routes/imageThumbnail.ts
4949
4949
  var MAX_SOURCE_BYTES = 64 * 1024 * 1024;
4950
4950
  var MAX_CACHE_BYTES = 8 * 1024 * 1024;
4951
- var sharpLoad;
4952
- function loadSharp() {
4953
- sharpLoad ??= import("sharp").then(
4954
- (module) => module.default,
4955
- (error) => {
4956
- console.warn("[Studio] JPEG thumbnails are off: sharp could not load:", error);
4957
- throw error;
4958
- }
4959
- );
4960
- return sharpLoad;
4951
+ function retryingSharpLoader(adapter) {
4952
+ let loaded;
4953
+ let warned = false;
4954
+ const load = () => adapter.loadSharp?.() ?? import("sharp").then((module) => module.default);
4955
+ return () => loaded ??= load().catch((error) => {
4956
+ loaded = void 0;
4957
+ if (!warned) console.warn("[Studio] JPEG thumbnails are off: sharp could not load:", error);
4958
+ warned = true;
4959
+ throw error;
4960
+ });
4961
4961
  }
4962
- async function generateThumbnail(path, signal) {
4962
+ async function generateThumbnail(loadSharp, path, signal) {
4963
4963
  const sharp = await loadSharp();
4964
4964
  const file = await open(path, "r");
4965
4965
  try {
@@ -5000,6 +5000,7 @@ async function resolveSource(adapter, id, url) {
5000
5000
  }
5001
5001
  function registerImageThumbnailRoutes(api, adapter) {
5002
5002
  const coordinator = new ThumbnailGenerationCoordinator(2);
5003
+ const loadSharp = retryingSharpLoader(adapter);
5003
5004
  const cache = /* @__PURE__ */ new Map();
5004
5005
  let cacheBytes = 0;
5005
5006
  const remember = (key, image) => {
@@ -5028,7 +5029,7 @@ function registerImageThumbnailRoutes(api, adapter) {
5028
5029
  else {
5029
5030
  if (coordinator.protectedKeys().size >= 32) return c.text("thumbnail queue full", 429);
5030
5031
  result = await coordinator.acquire(key, c.req.raw.signal, async (signal) => {
5031
- const image = await generateThumbnail(path, signal);
5032
+ const image = await generateThumbnail(loadSharp, path, signal);
5032
5033
  remember(key, image);
5033
5034
  return image;
5034
5035
  }) ?? void 0;
@@ -1,5 +1,6 @@
1
1
  import * as _hyperframes_core from '@hyperframes/core';
2
2
  import { RegistryItem, PreviewProxyBox } from '@hyperframes/core';
3
+ import * as sharp from 'sharp';
3
4
  import { CanvasResolution } from '@hyperframes/parsers';
4
5
  import { BundleOptions } from '@hyperframes/core/compiler';
5
6
  import { P as ProjectHistory } from './projectHistory-ByC9sa3X.js';
@@ -119,6 +120,7 @@ interface StudioApiAdapter {
119
120
  /** Optional: a cached `createProjectSignature(dir)`; preview caching checks builds against it. */
120
121
  getProjectSignature?: (projectDir: string) => string;
121
122
  invalidateProjectSignature?: (projectDir: string) => void;
123
+ loadSharp?: () => Promise<typeof sharp.default>;
122
124
  /** Lint a single HTML string. */
123
125
  lint(html: string, opts?: {
124
126
  filePath?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperframes/studio-server",
3
- "version": "0.8.180",
3
+ "version": "0.8.183",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/heygen-com/hyperframes",
@@ -84,9 +84,8 @@
84
84
  "linkedom": "^0.18.12",
85
85
  "postcss": "^8.5.8",
86
86
  "postcss-selector-parser": "^7.1.2",
87
- "sharp": "^0.35.0",
88
- "@hyperframes/core": "0.8.180",
89
- "@hyperframes/parsers": "0.8.180"
87
+ "@hyperframes/core": "0.8.183",
88
+ "@hyperframes/parsers": "0.8.183"
90
89
  },
91
90
  "devDependencies": {
92
91
  "@types/node": "^25.0.10",
@@ -95,6 +94,9 @@
95
94
  "typescript": "^5.0.0",
96
95
  "vitest": "^4.1.11"
97
96
  },
97
+ "optionalDependencies": {
98
+ "sharp": "^0.35.0"
99
+ },
98
100
  "scripts": {
99
101
  "build": "tsup",
100
102
  "test": "vitest run",