@hyperframes/studio-server 0.9.25 → 0.9.27
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.
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
|
|
8
8
|
// src/history/projectHistory.ts
|
|
9
9
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
10
|
-
import { mkdir as mkdir2, readdir as readdir4, rm as rm3, rmdir, stat as stat2, writeFile } from "fs/promises";
|
|
10
|
+
import { mkdir as mkdir2, readdir as readdir4, rm as rm3, rmdir, stat as stat2, writeFile as writeFile2 } from "fs/promises";
|
|
11
11
|
import {
|
|
12
12
|
existsSync as existsSync3,
|
|
13
13
|
lstatSync as lstatSync4,
|
|
@@ -603,7 +603,17 @@ async function createProjectSignatureAsync(projectDir, excluding = /* @__PURE__
|
|
|
603
603
|
// src/history/blobStore.ts
|
|
604
604
|
import { createHash as createHash3, randomUUID as randomUUID3 } from "crypto";
|
|
605
605
|
import { constants, createReadStream, createWriteStream } from "fs";
|
|
606
|
-
import {
|
|
606
|
+
import {
|
|
607
|
+
chmod,
|
|
608
|
+
copyFile,
|
|
609
|
+
mkdir,
|
|
610
|
+
open,
|
|
611
|
+
readdir as readdir2,
|
|
612
|
+
readFile as readFile2,
|
|
613
|
+
rm,
|
|
614
|
+
stat,
|
|
615
|
+
writeFile
|
|
616
|
+
} from "fs/promises";
|
|
607
617
|
import { dirname, join as join2 } from "path";
|
|
608
618
|
import { pipeline } from "stream/promises";
|
|
609
619
|
import { atomicTempPath } from "@hyperframes/core/atomic-file";
|
|
@@ -642,6 +652,7 @@ async function stopServingAndClose(path) {
|
|
|
642
652
|
|
|
643
653
|
// src/history/blobStore.ts
|
|
644
654
|
var BLOB_HASH = /^[0-9a-f]{64}$/;
|
|
655
|
+
var READ_ONCE_AT_MOST_BYTES = 64 * 1024;
|
|
645
656
|
function blobPath(dir, hash) {
|
|
646
657
|
if (!BLOB_HASH.test(hash)) throw new Error("That is not a history blob.");
|
|
647
658
|
return join2(dir, hash.slice(0, 2), hash);
|
|
@@ -652,6 +663,15 @@ async function hashFile(path) {
|
|
|
652
663
|
for await (const chunk of createReadStream(path)) hash.update(chunk);
|
|
653
664
|
return hash.digest("hex");
|
|
654
665
|
}
|
|
666
|
+
async function readIfSmall(path) {
|
|
667
|
+
const handle = await open(path, "r");
|
|
668
|
+
try {
|
|
669
|
+
const { size, mode } = await handle.stat();
|
|
670
|
+
return size > READ_ONCE_AT_MOST_BYTES ? null : { bytes: await handle.readFile(), mode };
|
|
671
|
+
} finally {
|
|
672
|
+
await handle.close();
|
|
673
|
+
}
|
|
674
|
+
}
|
|
655
675
|
async function cloneOrStream(from, to) {
|
|
656
676
|
try {
|
|
657
677
|
await copyFile(from, to, constants.COPYFILE_FICLONE_FORCE);
|
|
@@ -734,8 +754,35 @@ async function openBlobStore(dir) {
|
|
|
734
754
|
asideSizes.delete(hash);
|
|
735
755
|
holds.delete(hash);
|
|
736
756
|
};
|
|
757
|
+
const file = (hash, size) => {
|
|
758
|
+
if (!sizes.has(hash)) total += size;
|
|
759
|
+
sizes.set(hash, size);
|
|
760
|
+
};
|
|
761
|
+
const withFolderMadeIfMissing = (folder, write) => write().catch(async (error) => {
|
|
762
|
+
if (error.code !== "ENOENT") throw error;
|
|
763
|
+
await mkdir(folder, { recursive: true });
|
|
764
|
+
await write();
|
|
765
|
+
});
|
|
766
|
+
const putBytes = async (bytes, mode) => {
|
|
767
|
+
const hash = createHash3("sha256").update(bytes).digest("hex");
|
|
768
|
+
if (sizes.has(hash)) return hash;
|
|
769
|
+
const temp = join2(dir, `incoming-${randomUUID3()}`);
|
|
770
|
+
try {
|
|
771
|
+
await withFolderMadeIfMissing(dir, () => writeFile(temp, bytes, { mode }));
|
|
772
|
+
await chmod(temp, mode & 4095);
|
|
773
|
+
const to = blobPath(dir, hash);
|
|
774
|
+
await withFolderMadeIfMissing(dirname(to), () => renameWithRetryAsync(temp, to));
|
|
775
|
+
} catch (error) {
|
|
776
|
+
await rm(temp, { force: true });
|
|
777
|
+
throw error;
|
|
778
|
+
}
|
|
779
|
+
file(hash, bytes.length);
|
|
780
|
+
return hash;
|
|
781
|
+
};
|
|
737
782
|
return {
|
|
738
783
|
async put(absPath) {
|
|
784
|
+
const small = await readIfSmall(absPath);
|
|
785
|
+
if (small) return putBytes(small.bytes, small.mode);
|
|
739
786
|
const temp = join2(dir, `incoming-${randomUUID3()}`);
|
|
740
787
|
await mkdir(dir, { recursive: true });
|
|
741
788
|
await cloneOrStream(absPath, temp).catch(async (error) => {
|
|
@@ -750,8 +797,7 @@ async function openBlobStore(dir) {
|
|
|
750
797
|
await mkdir(dirname(blobPath(dir, hash)), { recursive: true });
|
|
751
798
|
const size = (await stat(temp)).size;
|
|
752
799
|
await renameWithRetryAsync(temp, blobPath(dir, hash));
|
|
753
|
-
|
|
754
|
-
total += size;
|
|
800
|
+
file(hash, size);
|
|
755
801
|
return hash;
|
|
756
802
|
},
|
|
757
803
|
reference: (absPath) => hashFile(absPath),
|
|
@@ -1825,6 +1871,20 @@ var OUTSIDE = { kind: "outside", name: "Outside" };
|
|
|
1825
1871
|
var OUTSIDE_LABEL = "Changed outside the app";
|
|
1826
1872
|
var RACY_MS = 2e3;
|
|
1827
1873
|
var statKey = (file, sweptAt) => sweptAt - Math.max(file.mtimeMs, file.ctimeMs) < RACY_MS ? "" : `${file.size}:${file.mtimeMs}:${file.ctimeMs}`;
|
|
1874
|
+
var FIRST_COPY_SLOTS_IN_PROCESS = 4;
|
|
1875
|
+
var firstCopiesRunning = 0;
|
|
1876
|
+
var firstCopiesWaiting = [];
|
|
1877
|
+
async function inFirstCopySlot(copy) {
|
|
1878
|
+
if (firstCopiesRunning < FIRST_COPY_SLOTS_IN_PROCESS) firstCopiesRunning += 1;
|
|
1879
|
+
else await new Promise((yours) => firstCopiesWaiting.push(yours));
|
|
1880
|
+
try {
|
|
1881
|
+
return await copy();
|
|
1882
|
+
} finally {
|
|
1883
|
+
const next = firstCopiesWaiting.shift();
|
|
1884
|
+
if (next) next();
|
|
1885
|
+
else firstCopiesRunning -= 1;
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1828
1888
|
var MEDIA_LEDGER = ".media/manifest.jsonl";
|
|
1829
1889
|
var KEPT_HIDDEN_PATHS = /* @__PURE__ */ new Set([...STUDIO_SIGNATURE_MANIFEST_PATHS, MEDIA_LEDGER]);
|
|
1830
1890
|
function isHistoryPath(path) {
|
|
@@ -2061,7 +2121,7 @@ var Engine = class {
|
|
|
2061
2121
|
async storeBytes(bytes) {
|
|
2062
2122
|
const staged = join8(this.home, `overwrote-${randomUUID7()}`);
|
|
2063
2123
|
await mkdir2(this.home, { recursive: true });
|
|
2064
|
-
await
|
|
2124
|
+
await writeFile2(staged, bytes);
|
|
2065
2125
|
try {
|
|
2066
2126
|
await this.blobs.put(staged);
|
|
2067
2127
|
} finally {
|
|
@@ -2090,11 +2150,17 @@ var Engine = class {
|
|
|
2090
2150
|
async firstOpen() {
|
|
2091
2151
|
const sweptAt = this.now();
|
|
2092
2152
|
const files = historyFiles(this.dir);
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2153
|
+
const copied = files.filter((file) => file.size <= COPY_LATER_ABOVE_BYTES);
|
|
2154
|
+
const hashes = await Promise.allSettled(
|
|
2155
|
+
copied.map((file) => inFirstCopySlot(() => this.storeIfPresent(file.path)))
|
|
2156
|
+
);
|
|
2157
|
+
if (this.whereFolder() !== "here") throw this.replaced();
|
|
2158
|
+
copied.forEach((file, i) => {
|
|
2159
|
+
const result = hashes[i];
|
|
2160
|
+
if (result.status === "rejected") throw result.reason;
|
|
2161
|
+
if (result.value !== null)
|
|
2162
|
+
this.tracked.set(file.path, { hash: result.value, stat: statKey(file, sweptAt) });
|
|
2163
|
+
});
|
|
2098
2164
|
this.log.baseline = this.manifest();
|
|
2099
2165
|
this.log.keepsLedger = true;
|
|
2100
2166
|
this.persistLog();
|
package/dist/history/index.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -71,7 +71,7 @@ import {
|
|
|
71
71
|
retainSnapshotOutput,
|
|
72
72
|
serveWhileOpen,
|
|
73
73
|
settledFileTag
|
|
74
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-LVEVVTIB.js";
|
|
75
75
|
import {
|
|
76
76
|
clearElementScreenshotIsolation,
|
|
77
77
|
getElementScreenshotClip
|
|
@@ -849,13 +849,13 @@ import {
|
|
|
849
849
|
writeFileSync,
|
|
850
850
|
mkdirSync,
|
|
851
851
|
lstatSync,
|
|
852
|
-
mkdtempSync,
|
|
853
852
|
renameSync,
|
|
854
853
|
rmSync,
|
|
855
854
|
statSync
|
|
856
855
|
} from "fs";
|
|
857
856
|
import { dirname as dirname2, join as join3 } from "path";
|
|
858
857
|
import { findFfBinary } from "@hyperframes/parsers/ff-binaries";
|
|
858
|
+
import { createStagingDir } from "@hyperframes/core/atomic-file";
|
|
859
859
|
var SAMPLE_RATE = 4e3;
|
|
860
860
|
var PEAK_COUNT = 4e3;
|
|
861
861
|
var WAVEFORM_CACHE_VERSION = "v2";
|
|
@@ -947,7 +947,7 @@ function writeWaveformCache(cachePath, peaks) {
|
|
|
947
947
|
if (!isWaveformCacheDirectory(cacheDir)) {
|
|
948
948
|
throw new Error("Waveform cache must be a directory, not a symlink");
|
|
949
949
|
}
|
|
950
|
-
const stagingDir =
|
|
950
|
+
const stagingDir = createStagingDir(cacheDir, ".waveform-");
|
|
951
951
|
try {
|
|
952
952
|
const stagingPath = join3(stagingDir, "peaks.json");
|
|
953
953
|
writeFileSync(stagingPath, JSON.stringify(peaks), { flag: "wx" });
|
|
@@ -962,7 +962,7 @@ function writeWaveformCache(cachePath, peaks) {
|
|
|
962
962
|
|
|
963
963
|
// src/helpers/mediaValidation.ts
|
|
964
964
|
import { spawnSync } from "child_process";
|
|
965
|
-
import { mkdtempSync
|
|
965
|
+
import { mkdtempSync, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
966
966
|
import { tmpdir } from "os";
|
|
967
967
|
import { basename, join as join4 } from "path";
|
|
968
968
|
import { FFPROBE_PATH_ENV, findFfBinary as findFfBinary2 } from "@hyperframes/parsers/ff-binaries";
|
|
@@ -1016,7 +1016,7 @@ function checkStreams(stdout, isVideo, isAudio) {
|
|
|
1016
1016
|
}
|
|
1017
1017
|
}
|
|
1018
1018
|
function validateUploadedMediaBuffer(fileName, buffer, runner = defaultRunner) {
|
|
1019
|
-
const tempDir =
|
|
1019
|
+
const tempDir = mkdtempSync(join4(tmpdir(), "hyperframes-upload-"));
|
|
1020
1020
|
const tempPath = join4(tempDir, basename(fileName));
|
|
1021
1021
|
try {
|
|
1022
1022
|
writeFileSync2(tempPath, buffer);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/studio-server",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.27",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/heygen-com/hyperframes",
|
|
@@ -88,8 +88,8 @@
|
|
|
88
88
|
"linkedom": "^0.18.12",
|
|
89
89
|
"postcss": "^8.5.8",
|
|
90
90
|
"postcss-selector-parser": "^7.1.2",
|
|
91
|
-
"@hyperframes/core": "0.9.
|
|
92
|
-
"@hyperframes/parsers": "0.9.
|
|
91
|
+
"@hyperframes/core": "0.9.27",
|
|
92
|
+
"@hyperframes/parsers": "0.9.27"
|
|
93
93
|
},
|
|
94
94
|
"devDependencies": {
|
|
95
95
|
"@types/node": "^25.0.10",
|