@hyperframes/studio-server 0.8.207 → 0.8.208

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.
@@ -20,7 +20,7 @@ import {
20
20
  } from "fs";
21
21
  import { homedir } from "os";
22
22
  import { dirname as dirname5, isAbsolute as isAbsolute5, join as join8, relative as relative5, resolve as resolve7, sep as sep5 } from "path";
23
- import { replaceFileAtomically as replaceFileAtomically5 } from "@hyperframes/core/atomic-file";
23
+ import { replaceFileAtomically as replaceFileAtomically6 } from "@hyperframes/core/atomic-file";
24
24
 
25
25
  // src/helpers/fileVersion.ts
26
26
  import { createHash, randomUUID } from "crypto";
@@ -103,22 +103,15 @@ var consumeFileWriteReceipt = identifyFileWrite;
103
103
  // src/helpers/renderOutputs.ts
104
104
  import { readFileSync as readFileSync2 } from "fs";
105
105
  import { isAbsolute, relative, resolve, sep } from "path";
106
- import { replaceFileAtomically } from "@hyperframes/core/atomic-file";
106
+ import { replaceFileAtomically as replaceFileAtomically2 } from "@hyperframes/core/atomic-file";
107
107
 
108
108
  // src/history/ownerLock.ts
109
109
  import { spawnSync } from "child_process";
110
110
  import { randomUUID as randomUUID2 } from "crypto";
111
- import {
112
- linkSync,
113
- mkdirSync,
114
- readFileSync,
115
- renameSync,
116
- rmSync,
117
- statSync,
118
- writeFileSync
119
- } from "fs";
111
+ import { linkSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from "fs";
120
112
  import { uptime } from "os";
121
113
  import { join } from "path";
114
+ import { replaceFileAtomically } from "@hyperframes/core/atomic-file";
122
115
  var HistoryBusyError = class extends Error {
123
116
  constructor(pid, url) {
124
117
  super(`This project's history is open in another process (pid ${pid}).`);
@@ -258,9 +251,7 @@ function evictDeadOwner(file) {
258
251
  }
259
252
  function advertise(urlFile, url) {
260
253
  if (!url) return rmSync(urlFile, { force: true });
261
- const draft = `${urlFile}-${process.pid}-${randomUUID2()}.tmp`;
262
- writeFileSync(draft, JSON.stringify({ pid: process.pid, url }));
263
- renameSync(draft, urlFile);
254
+ replaceFileAtomically(urlFile, JSON.stringify({ pid: process.pid, url }));
264
255
  }
265
256
  function servedBy(file, urlFile, pid) {
266
257
  try {
@@ -294,7 +285,12 @@ async function takeHistoryOwnership(home, waitMs, url) {
294
285
  if (next === "claimed") break;
295
286
  if (next === "wait") await new Promise((settle) => setTimeout(settle, 50));
296
287
  }
297
- advertise(urlFile, url);
288
+ try {
289
+ advertise(urlFile, url);
290
+ } catch (error) {
291
+ releaseOwn(file);
292
+ throw error;
293
+ }
298
294
  let held = true;
299
295
  return () => {
300
296
  if (held && servedBy(file, urlFile, process.pid)) rmSync(urlFile, { force: true });
@@ -344,7 +340,7 @@ async function registerRenderOutput(projectDir, output) {
344
340
  const release = await takeHistoryOwnership(lock, 5e3);
345
341
  try {
346
342
  const paths = [.../* @__PURE__ */ new Set([...readRenderOutputs(projectDir), path])].sort();
347
- replaceFileAtomically(registry, JSON.stringify({ version: 1, paths }) + "\n", 420);
343
+ replaceFileAtomically2(registry, JSON.stringify({ version: 1, paths }) + "\n", 420);
348
344
  } finally {
349
345
  release();
350
346
  }
@@ -528,7 +524,7 @@ function createProjectSignature(projectDir, excluding = /* @__PURE__ */ new Set(
528
524
 
529
525
  // src/history/blobStore.ts
530
526
  import { createHash as createHash3, randomUUID as randomUUID3 } from "crypto";
531
- import { constants, createReadStream, createWriteStream, renameSync as renameSync2 } from "fs";
527
+ import { constants, createReadStream, createWriteStream, renameSync } from "fs";
532
528
  import { copyFile, mkdir, readdir, readFile, rename, rm, stat } from "fs/promises";
533
529
  import { dirname, join as join2 } from "path";
534
530
  import { pipeline } from "stream/promises";
@@ -558,7 +554,7 @@ async function cloneOrCopy(from, to, beforeReplace) {
558
554
  try {
559
555
  await copyFile(from, temp, constants.COPYFILE_FICLONE);
560
556
  beforeReplace?.();
561
- renameSync2(temp, to);
557
+ renameSync(temp, to);
562
558
  } catch (error) {
563
559
  await rm(temp, { force: true });
564
560
  throw error;
@@ -703,7 +699,7 @@ function uncopiedOnlyHashes(log, sizeOf) {
703
699
 
704
700
  // src/history/pruneHistories.ts
705
701
  import { randomUUID as randomUUID5 } from "crypto";
706
- import { readdirSync as readdirSync2, readFileSync as readFileSync5, renameSync as renameSync3, statSync as statSync3, writeFileSync as writeFileSync3 } from "fs";
702
+ import { readdirSync as readdirSync2, readFileSync as readFileSync5, renameSync as renameSync2, statSync as statSync3, writeFileSync as writeFileSync3 } from "fs";
707
703
  import { lstat, readdir as readdir2, rm as rm2 } from "fs/promises";
708
704
  import { tmpdir } from "os";
709
705
  import { dirname as dirname2, join as join4 } from "path";
@@ -712,7 +708,7 @@ import { dirname as dirname2, join as join4 } from "path";
712
708
  import { randomUUID as randomUUID4 } from "crypto";
713
709
  import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync4, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
714
710
  import { basename, join as join3, resolve as resolve3 } from "path";
715
- import { replaceFileAtomically as replaceFileAtomically2 } from "@hyperframes/core/atomic-file";
711
+ import { replaceFileAtomically as replaceFileAtomically3 } from "@hyperframes/core/atomic-file";
716
712
  var ID_PATH = join3(".hyperframes", "history-id");
717
713
  var ID_SHAPE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
718
714
  var isHistoryId = (name) => ID_SHAPE.test(name);
@@ -775,7 +771,7 @@ var HistoryIdError = class extends Error {
775
771
  function recordProject(historyDir, dir, folder) {
776
772
  const record = { dir, ino: folder.ino, born: folder.birthtimeMs, dev: folder.dev };
777
773
  mkdirSync2(historyDir, { recursive: true });
778
- replaceFileAtomically2(join3(historyDir, "project.json"), JSON.stringify(record), 420);
774
+ replaceFileAtomically3(join3(historyDir, "project.json"), JSON.stringify(record), 420);
779
775
  }
780
776
 
781
777
  // src/history/pruneHistories.ts
@@ -867,7 +863,7 @@ function recheckAndMoveAway(historyRoot, id, { now, dryRun, tempDir }) {
867
863
  if (projectDir === null) return null;
868
864
  if (dryRun) return { projectDir, trash: null };
869
865
  const trash = join4(historyRoot, `${PRUNED_PREFIX}${id}-${randomUUID5()}`);
870
- renameSync3(home, trash);
866
+ renameSync2(home, trash);
871
867
  return { projectDir, trash };
872
868
  }
873
869
  function abandonedProject(home, id, now, tempDir) {
@@ -926,9 +922,9 @@ function pruneGoneProjectHistoriesDaily(historyRoot, now, { onError, budgetMs }
926
922
 
927
923
  // src/history/videoState.ts
928
924
  import { createHash as createHash5, randomUUID as randomUUID6 } from "crypto";
929
- import { createReadStream as createReadStream2, existsSync as existsSync2, readFileSync as readFileSync8, renameSync as renameSync4, statSync as statSync4 } from "fs";
925
+ import { createReadStream as createReadStream2, existsSync as existsSync2, readFileSync as readFileSync8, renameSync as renameSync3, statSync as statSync4 } from "fs";
930
926
  import { isAbsolute as isAbsolute4, join as join7, resolve as resolve6 } from "path";
931
- import { replaceFileAtomically as replaceFileAtomically3 } from "@hyperframes/core/atomic-file";
927
+ import { replaceFileAtomically as replaceFileAtomically4 } from "@hyperframes/core/atomic-file";
932
928
 
933
929
  // src/history/artifactCleanup.ts
934
930
  import { createHash as createHash4 } from "crypto";
@@ -1327,11 +1323,11 @@ async function updateState(dir, update) {
1327
1323
  state = readState(dir);
1328
1324
  } catch (error) {
1329
1325
  if (!(error instanceof SyntaxError)) throw error;
1330
- renameSync4(statePath(dir), `${statePath(dir)}.invalid-${randomUUID6()}`);
1326
+ renameSync3(statePath(dir), `${statePath(dir)}.invalid-${randomUUID6()}`);
1331
1327
  state = emptyState();
1332
1328
  }
1333
1329
  update(state);
1334
- replaceFileAtomically3(statePath(dir), JSON.stringify(state, null, 2) + "\n", 420);
1330
+ replaceFileAtomically4(statePath(dir), JSON.stringify(state, null, 2) + "\n", 420);
1335
1331
  } finally {
1336
1332
  release();
1337
1333
  }
@@ -1534,7 +1530,7 @@ async function finishSnapshotRun(projectDir, path) {
1534
1530
  // src/history/historyLog.ts
1535
1531
  import { closeSync as closeSync3, constants as constants4, mkdirSync as mkdirSync4, openSync as openSync3, readFileSync as readFileSync9, writeSync as writeSync2 } from "fs";
1536
1532
  import { dirname as dirname4 } from "path";
1537
- import { replaceFileAtomically as replaceFileAtomically4 } from "@hyperframes/core/atomic-file";
1533
+ import { replaceFileAtomically as replaceFileAtomically5 } from "@hyperframes/core/atomic-file";
1538
1534
  var START = "start";
1539
1535
  function parseRecord(line) {
1540
1536
  try {
@@ -1596,7 +1592,7 @@ function writeLog(file, log) {
1596
1592
  ...[...log.pins].map((id) => ({ type: "pin", id, pinned: true }))
1597
1593
  ];
1598
1594
  mkdirSync4(dirname4(file), { recursive: true });
1599
- replaceFileAtomically4(file, records2.map((r) => `${JSON.stringify(r)}
1595
+ replaceFileAtomically5(file, records2.map((r) => `${JSON.stringify(r)}
1600
1596
  `).join(""), 420);
1601
1597
  }
1602
1598
  function applyEntry(manifest2, entry, side) {
@@ -1966,7 +1962,7 @@ var Engine = class {
1966
1962
  const file = join8(this.home, "adopting.json");
1967
1963
  if (!this.adopting.size) return rmSync3(file, { force: true });
1968
1964
  mkdirSync5(this.home, { recursive: true });
1969
- replaceFileAtomically5(file, JSON.stringify([...this.adopting.keys()]), 420);
1965
+ replaceFileAtomically6(file, JSON.stringify([...this.adopting.keys()]), 420);
1970
1966
  }
1971
1967
  async adopt(file, sweptAt) {
1972
1968
  try {
@@ -2018,7 +2014,7 @@ var Engine = class {
2018
2014
  saveStatCache() {
2019
2015
  const files = JSON.stringify(Object.fromEntries(this.tracked));
2020
2016
  mkdirSync5(this.home, { recursive: true });
2021
- replaceFileAtomically5(join8(this.home, "stat.json"), files, 420);
2017
+ replaceFileAtomically6(join8(this.home, "stat.json"), files, 420);
2022
2018
  }
2023
2019
  /**
2024
2020
  * Takes in every write since the last sweep and files each change to its writer. ponytail: always the whole
@@ -22,7 +22,7 @@ import {
22
22
  recordRenderSuccess,
23
23
  registerRenderOutput,
24
24
  retainSnapshotOutput
25
- } from "../chunk-OSZE5WT3.js";
25
+ } from "../chunk-WAMZ2Z5O.js";
26
26
  import "../chunk-QF7MFJJU.js";
27
27
  import "../chunk-SVQFE44C.js";
28
28
  import "../chunk-L3HJVTQE.js";
package/dist/index.js CHANGED
@@ -62,7 +62,7 @@ import {
62
62
  resolveProjectSignature,
63
63
  retainSnapshotOutput,
64
64
  settledFileTag
65
- } from "./chunk-OSZE5WT3.js";
65
+ } from "./chunk-WAMZ2Z5O.js";
66
66
  import {
67
67
  clearElementScreenshotIsolation,
68
68
  getElementScreenshotClip
@@ -3902,8 +3902,51 @@ import {
3902
3902
  normalizeGsapBaseUrl,
3903
3903
  normalizeGsapLocalRoot
3904
3904
  } from "@hyperframes/core/gsap-cdn";
3905
- import { findStartTags as findStartTags3, injectTagsAtHeadStart } from "@hyperframes/core/compiler/html-document";
3905
+ import { findStartTags as findStartTags4, injectTagsAtHeadStart as injectTagsAtHeadStart2 } from "@hyperframes/core/compiler/html-document";
3906
3906
  import { isWithinProjectRoot } from "@hyperframes/parsers/asset-resolution";
3907
+
3908
+ // src/helpers/rootImportMap.ts
3909
+ import { findStartTags as findStartTags2, injectTagsAtHeadStart } from "@hyperframes/core/compiler/html-document";
3910
+ var ROOT_PATH = /^\/(?!\/)/;
3911
+ var IMPORT_MAP_TYPE = /\btype\s*=\s*["']?importmap["']?(?=[\s/>])/i;
3912
+ function findImportMap(html) {
3913
+ for (const at of findStartTags2(html, "script")) {
3914
+ const open2 = /^<script\b[^>]*>/i.exec(html.slice(at));
3915
+ if (!open2 || !IMPORT_MAP_TYPE.test(open2[0])) continue;
3916
+ const start = at + open2[0].length;
3917
+ const end = html.toLowerCase().indexOf("</script", start);
3918
+ if (end !== -1) return { start, end, json: html.slice(start, end) };
3919
+ }
3920
+ return null;
3921
+ }
3922
+ function withRootImportMap(html, base) {
3923
+ const ours = { "/": base, [base]: base };
3924
+ const own = findImportMap(html);
3925
+ if (!own)
3926
+ return injectTagsAtHeadStart(
3927
+ html,
3928
+ `<script type="importmap">${JSON.stringify({ imports: ours })}</script>`
3929
+ );
3930
+ let map;
3931
+ try {
3932
+ map = JSON.parse(own.json);
3933
+ } catch {
3934
+ return html;
3935
+ }
3936
+ if (!map || typeof map !== "object") return html;
3937
+ const under = (path) => ROOT_PATH.test(path) && !path.startsWith(base) ? base + path.slice(1) : path;
3938
+ const moved = (entries = {}) => Object.fromEntries(
3939
+ Object.entries(entries).map(([key, target]) => [key, under(String(target))])
3940
+ );
3941
+ const merged = { ...map, imports: { ...ours, ...moved(map.imports) } };
3942
+ if (map.scopes)
3943
+ merged.scopes = Object.fromEntries(
3944
+ Object.entries(map.scopes).map(([scope, entries]) => [under(scope), moved(entries)])
3945
+ );
3946
+ return html.slice(0, own.start) + JSON.stringify(merged) + html.slice(own.end);
3947
+ }
3948
+
3949
+ // src/routes/preview.ts
3907
3950
  import { ensureHfIds as ensureHfIds2 } from "@hyperframes/parsers/hf-ids";
3908
3951
 
3909
3952
  // src/helpers/previewReads.ts
@@ -4037,7 +4080,7 @@ function injectPreviewVariables(html, values) {
4037
4080
  }
4038
4081
 
4039
4082
  // src/helpers/lazyPreviewImages.ts
4040
- import { findStartTags as findStartTags2 } from "@hyperframes/core/compiler/html-document";
4083
+ import { findStartTags as findStartTags3 } from "@hyperframes/core/compiler/html-document";
4041
4084
  import { parseHTML as parseHTML6 } from "linkedom";
4042
4085
  import { STUDIO_PREVIEW_LAZY_ATTR } from "@hyperframes/core/studio-preview-mark";
4043
4086
  function startsAfterZero(el) {
@@ -4050,7 +4093,7 @@ var hasLoading = (img) => Array.from(img.attributes).some((attr) => attr.name.to
4050
4093
  function lazyPreviewImages(html) {
4051
4094
  if (!/<!doctype|<html[\s>]/i.test(html)) return html;
4052
4095
  const images = [...parseHTML6(html).document.querySelectorAll("img")];
4053
- const tags = findStartTags2(html, "img");
4096
+ const tags = findStartTags3(html, "img");
4054
4097
  if (tags.length !== images.length) return html;
4055
4098
  const parts = [];
4056
4099
  let from = 0;
@@ -4136,7 +4179,7 @@ function injectMotionPathPluginIfNeeded(html, baseUrl) {
4136
4179
  }
4137
4180
  function findGsapCoreScript(html) {
4138
4181
  const scripts = [...parseHTML7(html).document.querySelectorAll("script")];
4139
- const starts = findStartTags3(html, "script");
4182
+ const starts = findStartTags4(html, "script");
4140
4183
  if (starts.length !== scripts.length) return null;
4141
4184
  const at = scripts.findIndex(
4142
4185
  (script) => isGsapCoreUrl(lowerCaseAttributes(script).get("src") ?? "")
@@ -4242,16 +4285,16 @@ var PREVIEW_CAPTURE_PARAM = "hf-capture";
4242
4285
  var EARLY_ERRORS_SCRIPT = `<script>(function(){var seen=window.${STUDIO_PREVIEW_ERRORS}=[];
4243
4286
  addEventListener("error",function(e){seen.push(e.message||String(e))});})();</script>`;
4244
4287
  function injectStudioPreviewAugmentations(html, adapter, projectDir, activeCompositionPath, options) {
4245
- const marked = options.capture ? injectTagsAtHeadStart(
4288
+ const marked = options.capture ? injectTagsAtHeadStart2(
4246
4289
  html,
4247
4290
  `<meta name="${STUDIO_PREVIEW_MARK_META}" content="${STUDIO_PREVIEW_CAPTURE_MODE}">`
4248
- ) : injectTagsAtHeadStart(
4291
+ ) : injectTagsAtHeadStart2(
4249
4292
  lazyPreviewImages(html),
4250
4293
  `<meta name="${STUDIO_PREVIEW_MARK_META}">${EARLY_ERRORS_SCRIPT}`
4251
4294
  );
4252
4295
  const withFallback = injectGsapCdnFallback(
4253
4296
  injectProjectSignature(
4254
- injectTagsAtHeadStart(
4297
+ injectTagsAtHeadStart2(
4255
4298
  marked,
4256
4299
  `<meta name="${GSAP_BASE_URL_META}" content="${escapeGsapUrl(options.gsapBaseUrl)}">`
4257
4300
  ),
@@ -4307,7 +4350,11 @@ var PREVIEW_BUNDLE_OPTIONS = {
4307
4350
  sceneParts: true
4308
4351
  };
4309
4352
  var previewBaseHref = (projectId) => `/api/projects/${encodeURIComponent(projectId)}/preview/`;
4310
- var withPreviewBase = (html, projectId) => hasBaseElement(html) ? html : injectTagsAtHeadStart(html, `<base href="${previewBaseHref(projectId)}">`);
4353
+ var withPreviewBase = (html, projectId) => {
4354
+ const base = previewBaseHref(projectId);
4355
+ const mapped = withRootImportMap(html, base);
4356
+ return hasBaseElement(mapped) ? mapped : injectTagsAtHeadStart2(mapped, `<base href="${base}">`);
4357
+ };
4311
4358
  function resolvePreviewGsapBaseUrl(adapter) {
4312
4359
  const configured = process.env.HYPERFRAMES_GSAP_BASE_URL;
4313
4360
  if (configured?.trim() || !adapter.gsapLocalRoot) {
@@ -4482,6 +4529,7 @@ ${etag}`;
4482
4529
  gsapBaseUrl
4483
4530
  );
4484
4531
  if (!html) return c.text("not found", 404);
4532
+ html = withRootImportMap(html, baseHref);
4485
4533
  recordPreviewReferences(project.dir, html);
4486
4534
  html = ensureHfIds2(await transformPreviewHtml(html, adapter, project, compPath));
4487
4535
  html = injectStudioPreviewAugmentations(html, adapter, project.dir, compPath, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperframes/studio-server",
3
- "version": "0.8.207",
3
+ "version": "0.8.208",
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.207",
88
- "@hyperframes/parsers": "0.8.207"
87
+ "@hyperframes/core": "0.8.208",
88
+ "@hyperframes/parsers": "0.8.208"
89
89
  },
90
90
  "devDependencies": {
91
91
  "@types/node": "^25.0.10",