@hyperframes/studio-server 0.8.190 → 0.8.192
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-YIMSBQIO.js → chunk-B4NDV4NM.js} +169 -45
- package/dist/{chunk-ERQWOZ7E.js → chunk-QZWVJKLI.js} +9 -1
- package/dist/helpers/loudness.js +1 -1
- package/dist/history/index.d.ts +11 -1
- package/dist/history/index.js +3 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -2
- package/package.json +3 -3
|
@@ -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 readdir3, rm as rm3, rmdir, writeFile } from "fs/promises";
|
|
10
|
+
import { mkdir as mkdir2, readdir as readdir3, rm as rm3, rmdir, stat as stat2, writeFile } from "fs/promises";
|
|
11
11
|
import {
|
|
12
12
|
existsSync as existsSync3,
|
|
13
13
|
lstatSync as lstatSync4,
|
|
@@ -37,9 +37,9 @@ function hashVersion(hex) {
|
|
|
37
37
|
function hashOfVersion(version) {
|
|
38
38
|
return /^"sha256:([0-9a-f]{64})"$/.exec(version)?.[1];
|
|
39
39
|
}
|
|
40
|
-
function settledFileTag(
|
|
41
|
-
if (now -
|
|
42
|
-
return [
|
|
40
|
+
function settledFileTag(stat4, now = Date.now()) {
|
|
41
|
+
if (now - stat4.ctimeMs < 3e3) return null;
|
|
42
|
+
return [stat4.ino, stat4.ctimeMs, stat4.size].map((n) => n.toString(36)).join("-");
|
|
43
43
|
}
|
|
44
44
|
function createWriteToken(requestToken) {
|
|
45
45
|
const token = requestToken?.trim();
|
|
@@ -345,8 +345,8 @@ function signatureEntryStat(projectDir, entry, file, outputs) {
|
|
|
345
345
|
if (isSkippedEntry(entry) || !isPathWithin(projectDir, file)) return null;
|
|
346
346
|
if (isRenderOutput(projectDir, file, outputs)) return null;
|
|
347
347
|
try {
|
|
348
|
-
const
|
|
349
|
-
return
|
|
348
|
+
const stat4 = lstatSync(file);
|
|
349
|
+
return stat4.isSymbolicLink() ? null : stat4;
|
|
350
350
|
} catch {
|
|
351
351
|
return null;
|
|
352
352
|
}
|
|
@@ -360,17 +360,17 @@ function collectProjectSignatureFiles(projectDir, dir, files, outputs = readRend
|
|
|
360
360
|
}
|
|
361
361
|
for (const entry of entries) {
|
|
362
362
|
const file = resolve2(dir, entry);
|
|
363
|
-
const
|
|
364
|
-
if (!
|
|
365
|
-
if (
|
|
363
|
+
const stat4 = signatureEntryStat(projectDir, entry, file, outputs);
|
|
364
|
+
if (!stat4) continue;
|
|
365
|
+
if (stat4.isDirectory()) {
|
|
366
366
|
collectProjectSignatureFiles(projectDir, file, files, outputs);
|
|
367
|
-
} else if (
|
|
367
|
+
} else if (stat4.isFile()) {
|
|
368
368
|
files.push({
|
|
369
369
|
file,
|
|
370
|
-
mtimeMs:
|
|
371
|
-
ctimeMs:
|
|
372
|
-
size:
|
|
373
|
-
textContentEligible: isTextContentEligible(file,
|
|
370
|
+
mtimeMs: stat4.mtimeMs,
|
|
371
|
+
ctimeMs: stat4.ctimeMs,
|
|
372
|
+
size: stat4.size,
|
|
373
|
+
textContentEligible: isTextContentEligible(file, stat4.size)
|
|
374
374
|
});
|
|
375
375
|
}
|
|
376
376
|
}
|
|
@@ -380,19 +380,19 @@ function collectProjectSignatureManifestFiles(projectDir, files) {
|
|
|
380
380
|
for (const manifestPath of STUDIO_SIGNATURE_MANIFEST_PATHS) {
|
|
381
381
|
const file = resolve2(projectDir, manifestPath);
|
|
382
382
|
if (seen.has(file) || !isPathWithin(projectDir, file)) continue;
|
|
383
|
-
let
|
|
383
|
+
let stat4;
|
|
384
384
|
try {
|
|
385
|
-
|
|
385
|
+
stat4 = lstatSync(file);
|
|
386
386
|
} catch {
|
|
387
387
|
continue;
|
|
388
388
|
}
|
|
389
|
-
if (
|
|
389
|
+
if (stat4.isSymbolicLink() || !stat4.isFile()) continue;
|
|
390
390
|
files.push({
|
|
391
391
|
file,
|
|
392
|
-
mtimeMs:
|
|
393
|
-
ctimeMs:
|
|
394
|
-
size:
|
|
395
|
-
textContentEligible: isTextContentEligible(file,
|
|
392
|
+
mtimeMs: stat4.mtimeMs,
|
|
393
|
+
ctimeMs: stat4.ctimeMs,
|
|
394
|
+
size: stat4.size,
|
|
395
|
+
textContentEligible: isTextContentEligible(file, stat4.size)
|
|
396
396
|
});
|
|
397
397
|
seen.add(file);
|
|
398
398
|
}
|
|
@@ -540,11 +540,21 @@ async function openBlobStore(dir) {
|
|
|
540
540
|
total += size;
|
|
541
541
|
return hash;
|
|
542
542
|
},
|
|
543
|
+
reference: (absPath) => hashFile(absPath),
|
|
543
544
|
has: (hash) => sizes.has(hash),
|
|
544
545
|
read: async (hash) => readBlob(dir, hash),
|
|
545
546
|
writeTo: async (hash, absPath, beforeReplace) => cloneOrCopy(pathOf(hash), absPath, beforeReplace),
|
|
546
547
|
bytes: () => total,
|
|
547
548
|
size: (hash) => sizes.get(hash) ?? 0,
|
|
549
|
+
async drop(hashes) {
|
|
550
|
+
for (const hash of hashes) {
|
|
551
|
+
const size = sizes.get(hash);
|
|
552
|
+
if (size === void 0) continue;
|
|
553
|
+
await rm(pathOf(hash), { force: true });
|
|
554
|
+
sizes.delete(hash);
|
|
555
|
+
total -= size;
|
|
556
|
+
}
|
|
557
|
+
},
|
|
548
558
|
async prune(keep) {
|
|
549
559
|
for (const [hash, size] of sizes) {
|
|
550
560
|
if (keep.has(hash)) continue;
|
|
@@ -556,6 +566,42 @@ async function openBlobStore(dir) {
|
|
|
556
566
|
};
|
|
557
567
|
}
|
|
558
568
|
|
|
569
|
+
// src/history/uncopied.ts
|
|
570
|
+
import { extname as extname2 } from "path";
|
|
571
|
+
var MEDIA_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
572
|
+
".mp4",
|
|
573
|
+
".mov",
|
|
574
|
+
".m4v",
|
|
575
|
+
".webm",
|
|
576
|
+
".mkv",
|
|
577
|
+
".avi",
|
|
578
|
+
".mxf",
|
|
579
|
+
".m2ts",
|
|
580
|
+
".mp3",
|
|
581
|
+
".wav",
|
|
582
|
+
".aac",
|
|
583
|
+
".m4a",
|
|
584
|
+
".flac",
|
|
585
|
+
".ogg",
|
|
586
|
+
".opus"
|
|
587
|
+
]);
|
|
588
|
+
var COPY_NOTHING_ABOVE_BYTES = 64 * 1024 ** 2;
|
|
589
|
+
var isUncopied = (path, size) => size > COPY_NOTHING_ABOVE_BYTES || MEDIA_EXTENSIONS.has(extname2(path).toLowerCase());
|
|
590
|
+
function uncopiedOnlyHashes(log, sizeOf) {
|
|
591
|
+
const copied = /* @__PURE__ */ new Set();
|
|
592
|
+
const uncopied = /* @__PURE__ */ new Set();
|
|
593
|
+
const note = (path, hash) => {
|
|
594
|
+
if (hash) (isUncopied(path, sizeOf(hash)) ? uncopied : copied).add(hash);
|
|
595
|
+
};
|
|
596
|
+
for (const [path, hash] of log.baseline) note(path, hash);
|
|
597
|
+
for (const entry of log.entries)
|
|
598
|
+
for (const file of entry.files) {
|
|
599
|
+
note(file.path, file.before);
|
|
600
|
+
note(file.path, file.after);
|
|
601
|
+
}
|
|
602
|
+
return [...uncopied].filter((hash) => !copied.has(hash));
|
|
603
|
+
}
|
|
604
|
+
|
|
559
605
|
// src/history/pruneHistories.ts
|
|
560
606
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
561
607
|
import { readdirSync as readdirSync2, readFileSync as readFileSync5, renameSync as renameSync3, statSync as statSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
@@ -740,13 +786,13 @@ function projectGone(dir, id, dev, tempDir) {
|
|
|
740
786
|
}
|
|
741
787
|
function diskStillHere(dir, dev, tempDir) {
|
|
742
788
|
let at = dir;
|
|
743
|
-
let
|
|
744
|
-
while (!
|
|
789
|
+
let stat4 = statSync3(at, { throwIfNoEntry: false });
|
|
790
|
+
while (!stat4) {
|
|
745
791
|
if (dirname2(at) === at) return false;
|
|
746
792
|
at = dirname2(at);
|
|
747
|
-
|
|
793
|
+
stat4 = statSync3(at, { throwIfNoEntry: false });
|
|
748
794
|
}
|
|
749
|
-
if (typeof dev === "number") return
|
|
795
|
+
if (typeof dev === "number") return stat4.dev === dev;
|
|
750
796
|
return at === dir || isSafePath(tempDir, at);
|
|
751
797
|
}
|
|
752
798
|
function lastUsed(home) {
|
|
@@ -866,12 +912,12 @@ function stillPendingAfterUnlink(item) {
|
|
|
866
912
|
let descriptor;
|
|
867
913
|
try {
|
|
868
914
|
descriptor = openSync(item.path, constants2.O_RDONLY | constants2.O_NOFOLLOW);
|
|
869
|
-
const
|
|
870
|
-
if (!
|
|
915
|
+
const stat4 = fstatSync(descriptor);
|
|
916
|
+
if (!stat4.isFile() || stat4.isSymbolicLink()) return false;
|
|
871
917
|
const hash = createHash4("sha256").update(readFileSync6(descriptor)).digest("hex");
|
|
872
918
|
if (hash !== item.hash) return false;
|
|
873
919
|
const current = lstatSync2(item.path);
|
|
874
|
-
if (current.dev !==
|
|
920
|
+
if (current.dev !== stat4.dev || current.ino !== stat4.ino) return false;
|
|
875
921
|
unlinkSync(item.path);
|
|
876
922
|
return false;
|
|
877
923
|
} catch (error) {
|
|
@@ -988,8 +1034,8 @@ function ownerPid(owner) {
|
|
|
988
1034
|
const pid = owner.pid;
|
|
989
1035
|
return typeof pid === "number" && Number.isSafeInteger(pid) && pid > 0 ? pid : null;
|
|
990
1036
|
}
|
|
991
|
-
function ordinaryOwner(
|
|
992
|
-
return
|
|
1037
|
+
function ordinaryOwner(stat4) {
|
|
1038
|
+
return stat4.isFile() && stat4.nlink === 1;
|
|
993
1039
|
}
|
|
994
1040
|
function sameOwnerFile(before, current) {
|
|
995
1041
|
return current.dev === before.dev && current.ino === before.ino;
|
|
@@ -1063,8 +1109,8 @@ function runsOnDisk(root) {
|
|
|
1063
1109
|
return entries.filter((entry) => entry.isDirectory() && UUID.test(entry.name)).flatMap((entry) => {
|
|
1064
1110
|
const path = join6(root, entry.name);
|
|
1065
1111
|
try {
|
|
1066
|
-
const
|
|
1067
|
-
return [{ path, stat:
|
|
1112
|
+
const stat4 = lstatSync3(path);
|
|
1113
|
+
return [{ path, stat: stat4 }];
|
|
1068
1114
|
} catch {
|
|
1069
1115
|
return [];
|
|
1070
1116
|
}
|
|
@@ -1078,10 +1124,10 @@ function planSnapshotCleanup(project, state, now = Date.now()) {
|
|
|
1078
1124
|
const runs = runsOnDisk(root);
|
|
1079
1125
|
for (const run of runs.slice(0, SNAPSHOT_RUNS_TO_KEEP)) keep.add(run.path);
|
|
1080
1126
|
const pending = [];
|
|
1081
|
-
for (const { path, stat:
|
|
1082
|
-
if (keep.has(path) || now -
|
|
1127
|
+
for (const { path, stat: stat4 } of runs) {
|
|
1128
|
+
if (keep.has(path) || now - stat4.mtimeMs < SNAPSHOT_GRACE_MS || liveOwner(path)) continue;
|
|
1083
1129
|
try {
|
|
1084
|
-
const run = { path, dev:
|
|
1130
|
+
const run = { path, dev: stat4.dev, ino: stat4.ino, mtimeMs: stat4.mtimeMs };
|
|
1085
1131
|
if (!unchangedRun(project, run)) continue;
|
|
1086
1132
|
pending.push(run);
|
|
1087
1133
|
retireReferences(records2, root, path);
|
|
@@ -1726,6 +1772,7 @@ var Engine = class {
|
|
|
1726
1772
|
);
|
|
1727
1773
|
if (!log) return this.firstOpen();
|
|
1728
1774
|
this.log = withoutHiddenPaths(log);
|
|
1775
|
+
await this.reclaimUncopied();
|
|
1729
1776
|
if (!this.log.keepsLedger) await this.takeInUnnamedLedger();
|
|
1730
1777
|
const cache = this.readStatCache();
|
|
1731
1778
|
const last = this.log.entries.at(-1)?.id ?? START;
|
|
@@ -1739,6 +1786,10 @@ var Engine = class {
|
|
|
1739
1786
|
this.reopenClosedWindow();
|
|
1740
1787
|
await this.settleAll();
|
|
1741
1788
|
}
|
|
1789
|
+
/** Copies an older version took of files that are no longer copied; text and small files are never touched. */
|
|
1790
|
+
async reclaimUncopied() {
|
|
1791
|
+
await this.blobs.drop(uncopiedOnlyHashes(this.log, (hash) => this.blobs.size(hash)));
|
|
1792
|
+
}
|
|
1742
1793
|
hearWrites() {
|
|
1743
1794
|
const realDir = realFilePath(this.dir);
|
|
1744
1795
|
this.stopHearing = onFileOverwritten((absPath, version, bytes) => {
|
|
@@ -1753,7 +1804,8 @@ var Engine = class {
|
|
|
1753
1804
|
chainBackFrom(this.overwritten.get(path), replaced).set(after, replaced)
|
|
1754
1805
|
);
|
|
1755
1806
|
this.queue(async () => {
|
|
1756
|
-
if (!this.blobs.has(replaced)
|
|
1807
|
+
if (!this.blobs.has(replaced) && !isUncopied(path, bytes.length))
|
|
1808
|
+
await this.storeBytes(bytes);
|
|
1757
1809
|
}).catch((error) => this.options.onError?.(error));
|
|
1758
1810
|
});
|
|
1759
1811
|
}
|
|
@@ -1832,7 +1884,8 @@ var Engine = class {
|
|
|
1832
1884
|
}
|
|
1833
1885
|
async recordAdopted(file, sweptAt, stored) {
|
|
1834
1886
|
if (stored === null || this.whereFolder() !== "here") return;
|
|
1835
|
-
const
|
|
1887
|
+
const kept = this.blobs.has(stored) || isUncopied(file.path, file.size);
|
|
1888
|
+
const hash = kept ? stored : await this.storeIfPresent(file.path);
|
|
1836
1889
|
if (hash === null) return;
|
|
1837
1890
|
const change = { path: file.path, before: null, after: hash };
|
|
1838
1891
|
const found = this.overwrittenBy(change, void 0, /* @__PURE__ */ new Set());
|
|
@@ -1908,22 +1961,24 @@ var Engine = class {
|
|
|
1908
1961
|
/** The file's hash once copied in; null when it was removed before the copy (the next sweep records that). */
|
|
1909
1962
|
async storeIfPresent(path) {
|
|
1910
1963
|
try {
|
|
1911
|
-
|
|
1964
|
+
const abs = join8(this.dir, path);
|
|
1965
|
+
const { size } = await stat2(abs);
|
|
1966
|
+
return await (isUncopied(path, size) ? this.blobs.reference(abs) : this.blobs.put(abs));
|
|
1912
1967
|
} catch (error) {
|
|
1913
1968
|
if (error.code === "ENOENT") return null;
|
|
1914
1969
|
throw error;
|
|
1915
1970
|
}
|
|
1916
1971
|
}
|
|
1917
|
-
async observe(path,
|
|
1972
|
+
async observe(path, stat4, at) {
|
|
1918
1973
|
const known = this.tracked.get(path) ?? { hash: null, stat: null };
|
|
1919
|
-
if (
|
|
1974
|
+
if (stat4 && known.stat === stat4) return false;
|
|
1920
1975
|
const heard = this.overwritten.get(path);
|
|
1921
1976
|
const hash = await this.storeIfPresent(path);
|
|
1922
1977
|
if (hash === null || this.whereFolder() !== "here") return false;
|
|
1923
|
-
this.tracked.set(path, { hash, stat:
|
|
1978
|
+
this.tracked.set(path, { hash, stat: stat4 });
|
|
1924
1979
|
this.forgetWritesBefore(path, hash, heard);
|
|
1925
1980
|
if (known.hash !== hash) await this.record(path, known.hash, hash, at);
|
|
1926
|
-
return known.hash !== hash || known.stat !==
|
|
1981
|
+
return known.hash !== hash || known.stat !== stat4;
|
|
1927
1982
|
}
|
|
1928
1983
|
async record(path, before, after, at) {
|
|
1929
1984
|
const endedBeforeThisWrite = this.windows.filter((open) => !takesWrite(open, at));
|
|
@@ -2221,9 +2276,9 @@ var Engine = class {
|
|
|
2221
2276
|
const parts = path.split("/");
|
|
2222
2277
|
for (let depth = 1; depth <= parts.length; depth += 1) {
|
|
2223
2278
|
const at = parts.slice(0, depth).join("/");
|
|
2224
|
-
const
|
|
2225
|
-
if (!
|
|
2226
|
-
if (at === path || !
|
|
2279
|
+
const stat4 = lstatSync4(join8(this.dir, at), { throwIfNoEntry: false });
|
|
2280
|
+
if (!stat4) return void 0;
|
|
2281
|
+
if (at === path || !stat4.isDirectory()) return { at, stat: stat4 };
|
|
2227
2282
|
}
|
|
2228
2283
|
return void 0;
|
|
2229
2284
|
}
|
|
@@ -2242,6 +2297,11 @@ var Engine = class {
|
|
|
2242
2297
|
async writeAs(who, label, target, extra) {
|
|
2243
2298
|
this.assertWritable();
|
|
2244
2299
|
const changes = [...target].filter(([path, hash]) => (this.tracked.get(path)?.hash ?? null) !== hash).sort(([, a], [, b]) => Number(a !== null) - Number(b !== null));
|
|
2300
|
+
const gone = changes.find(([, hash]) => hash !== null && !this.blobs.has(hash));
|
|
2301
|
+
if (gone)
|
|
2302
|
+
throw new Error(
|
|
2303
|
+
`An earlier version of ${gone[0]} is not kept, so this cannot be brought back.`
|
|
2304
|
+
);
|
|
2245
2305
|
const deleted = new Set(changes.filter(([, hash]) => hash === null).map(([path]) => path));
|
|
2246
2306
|
const blocked = changes.filter(([, hash]) => hash !== null).map(([path]) => this.inTheWay(path, deleted)).find(Boolean);
|
|
2247
2307
|
if (blocked) throw new Error(`${blocked} is in the way; move or delete it, then try again.`);
|
|
@@ -2408,6 +2468,9 @@ var Engine = class {
|
|
|
2408
2468
|
if ((await readdir3(dest).catch(missingIsEmpty)).length > 0)
|
|
2409
2469
|
throw new Error(`Checkout writes into an empty folder only: ${dest}`);
|
|
2410
2470
|
const files = manifestAround(this.log, entryId, side);
|
|
2471
|
+
for (const [path, hash] of files)
|
|
2472
|
+
if (!this.blobs.has(hash))
|
|
2473
|
+
throw new Error(`The version of ${path} from then is not kept.`);
|
|
2411
2474
|
try {
|
|
2412
2475
|
for (const [path, hash] of files) await this.blobs.writeTo(hash, join8(dest, path));
|
|
2413
2476
|
} catch (error) {
|
|
@@ -2513,6 +2576,66 @@ function readProjectHistory(options) {
|
|
|
2513
2576
|
};
|
|
2514
2577
|
}
|
|
2515
2578
|
|
|
2579
|
+
// src/history/reclaimUncopied.ts
|
|
2580
|
+
import { readdirSync as readdirSync5 } from "fs";
|
|
2581
|
+
import { rm as rm4, stat as stat3 } from "fs/promises";
|
|
2582
|
+
import { join as join9 } from "path";
|
|
2583
|
+
function historyIds(historyRoot) {
|
|
2584
|
+
try {
|
|
2585
|
+
return readdirSync5(historyRoot).filter(isHistoryId);
|
|
2586
|
+
} catch {
|
|
2587
|
+
return [];
|
|
2588
|
+
}
|
|
2589
|
+
}
|
|
2590
|
+
function namedHashes(log) {
|
|
2591
|
+
const hashes = new Set(log.baseline.values());
|
|
2592
|
+
for (const entry of log.entries) {
|
|
2593
|
+
for (const file of entry.files) {
|
|
2594
|
+
if (file.before) hashes.add(file.before);
|
|
2595
|
+
if (file.after) hashes.add(file.after);
|
|
2596
|
+
}
|
|
2597
|
+
}
|
|
2598
|
+
return hashes;
|
|
2599
|
+
}
|
|
2600
|
+
async function blobSizes(blobs, hashes) {
|
|
2601
|
+
const sizes = /* @__PURE__ */ new Map();
|
|
2602
|
+
for (const hash of hashes)
|
|
2603
|
+
sizes.set(hash, (await stat3(blobPath(blobs, hash)).catch(() => null))?.size ?? 0);
|
|
2604
|
+
return sizes;
|
|
2605
|
+
}
|
|
2606
|
+
async function reclaimOne(home, dryRun) {
|
|
2607
|
+
const log = readLog(join9(home, "log.jsonl"), () => {
|
|
2608
|
+
});
|
|
2609
|
+
if (!log) return 0;
|
|
2610
|
+
const blobs = join9(home, "blobs");
|
|
2611
|
+
const sizes = await blobSizes(blobs, namedHashes(log));
|
|
2612
|
+
let bytes = 0;
|
|
2613
|
+
for (const hash of uncopiedOnlyHashes(log, (known) => sizes.get(known) ?? 0)) {
|
|
2614
|
+
const size = sizes.get(hash) ?? 0;
|
|
2615
|
+
if (size === 0) continue;
|
|
2616
|
+
bytes += size;
|
|
2617
|
+
if (!dryRun) await rm4(blobPath(blobs, hash), { force: true });
|
|
2618
|
+
}
|
|
2619
|
+
return bytes;
|
|
2620
|
+
}
|
|
2621
|
+
async function reclaimUncopiedBlobs(historyRoot, { dryRun = false, onError } = {}) {
|
|
2622
|
+
const reclaimed = [];
|
|
2623
|
+
for (const id of historyIds(historyRoot)) {
|
|
2624
|
+
const home = join9(historyRoot, id);
|
|
2625
|
+
let release;
|
|
2626
|
+
try {
|
|
2627
|
+
release = await takeHistoryOwnership(home, 0);
|
|
2628
|
+
const bytes = await reclaimOne(home, dryRun);
|
|
2629
|
+
if (bytes > 0) reclaimed.push({ id, bytes });
|
|
2630
|
+
} catch (error) {
|
|
2631
|
+
if (!(error instanceof HistoryBusyError)) onError?.(error);
|
|
2632
|
+
} finally {
|
|
2633
|
+
release?.();
|
|
2634
|
+
}
|
|
2635
|
+
}
|
|
2636
|
+
return reclaimed;
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2516
2639
|
// src/history/historyCache.ts
|
|
2517
2640
|
function historyCache(open) {
|
|
2518
2641
|
const histories = /* @__PURE__ */ new Map();
|
|
@@ -2571,5 +2694,6 @@ export {
|
|
|
2571
2694
|
HistoryClosedError,
|
|
2572
2695
|
openProjectHistory,
|
|
2573
2696
|
readProjectHistory,
|
|
2697
|
+
reclaimUncopiedBlobs,
|
|
2574
2698
|
historyCache
|
|
2575
2699
|
};
|
|
@@ -8,6 +8,7 @@ import { isAbsolute, relative, resolve } from "path";
|
|
|
8
8
|
import { promisify } from "util";
|
|
9
9
|
import { isAudibleVideoElement } from "@hyperframes/core/audible-video";
|
|
10
10
|
import { formatAudioGain, MAX_AUDIO_GAIN_DB } from "@hyperframes/core/audio-gain";
|
|
11
|
+
import { decodeAuthoredAttribute } from "@hyperframes/parsers";
|
|
11
12
|
import { findFfBinary } from "@hyperframes/parsers/ff-binaries";
|
|
12
13
|
import { readMediaOffsetSeconds } from "@hyperframes/parsers/media-duration";
|
|
13
14
|
|
|
@@ -46,7 +47,14 @@ function attributeFromMatch(match, absoluteOffset) {
|
|
|
46
47
|
const whole = match[0];
|
|
47
48
|
const localValueStart = attributeValueStart(whole);
|
|
48
49
|
const valueStart = absoluteOffset + match.index + localValueStart;
|
|
49
|
-
return [
|
|
50
|
+
return [
|
|
51
|
+
name,
|
|
52
|
+
{
|
|
53
|
+
value: decodeAuthoredAttribute(value),
|
|
54
|
+
valueStart,
|
|
55
|
+
valueEnd: valueStart + value.length
|
|
56
|
+
}
|
|
57
|
+
];
|
|
50
58
|
}
|
|
51
59
|
function matchedAttributeValue(match) {
|
|
52
60
|
return match[2] ?? match[3] ?? match[4];
|
package/dist/helpers/loudness.js
CHANGED
package/dist/history/index.d.ts
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import { P as ProjectHistory, f as HistoryTarget, g as HistoryWho } from '../projectHistory-ByC9sa3X.js';
|
|
2
2
|
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, h as HistoryWindow, M as MAX_WINDOW_IDLE_MS, i as ProjectHistoryOptions, j as ProjectHistoryView, U as UNDO_MODES, k as UndoMode, o as openProjectHistory, r as readProjectHistory } from '../projectHistory-ByC9sa3X.js';
|
|
3
3
|
|
|
4
|
+
interface ReclaimedHistory {
|
|
5
|
+
id: string;
|
|
6
|
+
bytes: number;
|
|
7
|
+
}
|
|
8
|
+
/** Drops the media copies older versions left in every history no running process holds; the same rule as on open. */
|
|
9
|
+
declare function reclaimUncopiedBlobs(historyRoot: string, { dryRun, onError }?: {
|
|
10
|
+
dryRun?: boolean;
|
|
11
|
+
onError?: (error: unknown) => void;
|
|
12
|
+
}): Promise<ReclaimedHistory[]>;
|
|
13
|
+
|
|
4
14
|
declare class HistoryBusyError extends Error {
|
|
5
15
|
readonly pid: number;
|
|
6
16
|
readonly url?: string | undefined;
|
|
@@ -138,4 +148,4 @@ declare function registerRenderOutput(projectDir: string, output: string): Promi
|
|
|
138
148
|
/** Explicit outputs remain user evidence even when reusing a managed UUID folder. */
|
|
139
149
|
declare function retainSnapshotOutput(project: string, path: string): void;
|
|
140
150
|
|
|
141
|
-
export { type ArtifactCapture, type ArtifactInput, type ArtifactRecord, HistoryBusyError, HistoryIdError, HistoryTarget, HistoryWho, ProjectHistory, type ProjectHistoryRecord, type PrunedHistory, type RenderRecord, type VideoState, artifactDirectory, beginArtifactCapture, finishSnapshotRun, forgetRecordedArtifacts, historyCache, listProjectHistories, pruneGoneProjectHistories, recordArtifact, recordArtifacts, recordRenderSuccess, registerRenderOutput, retainSnapshotOutput };
|
|
151
|
+
export { type ArtifactCapture, type ArtifactInput, type ArtifactRecord, HistoryBusyError, HistoryIdError, HistoryTarget, HistoryWho, ProjectHistory, type ProjectHistoryRecord, type PrunedHistory, type ReclaimedHistory, type RenderRecord, type VideoState, artifactDirectory, beginArtifactCapture, finishSnapshotRun, forgetRecordedArtifacts, historyCache, listProjectHistories, pruneGoneProjectHistories, reclaimUncopiedBlobs, recordArtifact, recordArtifacts, recordRenderSuccess, registerRenderOutput, retainSnapshotOutput };
|
package/dist/history/index.js
CHANGED
|
@@ -15,12 +15,13 @@ import {
|
|
|
15
15
|
openProjectHistory,
|
|
16
16
|
pruneGoneProjectHistories,
|
|
17
17
|
readProjectHistory,
|
|
18
|
+
reclaimUncopiedBlobs,
|
|
18
19
|
recordArtifact,
|
|
19
20
|
recordArtifacts,
|
|
20
21
|
recordRenderSuccess,
|
|
21
22
|
registerRenderOutput,
|
|
22
23
|
retainSnapshotOutput
|
|
23
|
-
} from "../chunk-
|
|
24
|
+
} from "../chunk-B4NDV4NM.js";
|
|
24
25
|
import "../chunk-QF7MFJJU.js";
|
|
25
26
|
import "../chunk-SVQFE44C.js";
|
|
26
27
|
import "../chunk-L3HJVTQE.js";
|
|
@@ -41,6 +42,7 @@ export {
|
|
|
41
42
|
openProjectHistory,
|
|
42
43
|
pruneGoneProjectHistories,
|
|
43
44
|
readProjectHistory,
|
|
45
|
+
reclaimUncopiedBlobs,
|
|
44
46
|
recordArtifact,
|
|
45
47
|
recordArtifacts,
|
|
46
48
|
recordRenderSuccess,
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Hono } from 'hono';
|
|
|
2
2
|
import { S as StudioApiAdapter, P as PreviewDocumentStore, M as MediaProcessingJobState } from './mediaProxyPreview-CAiGJucG.js';
|
|
3
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-CAiGJucG.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
|
-
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';
|
|
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';
|
|
7
7
|
export { walkDir } from './helpers/safePath.js';
|
|
8
8
|
export { stampProjectHfIds } from './helpers/hfIdPersist.js';
|
package/dist/index.js
CHANGED
|
@@ -51,6 +51,7 @@ import {
|
|
|
51
51
|
openProjectHistory,
|
|
52
52
|
pruneGoneProjectHistories,
|
|
53
53
|
readProjectHistory,
|
|
54
|
+
reclaimUncopiedBlobs,
|
|
54
55
|
recordArtifact,
|
|
55
56
|
recordArtifacts,
|
|
56
57
|
recordFileWriteReceipt,
|
|
@@ -60,7 +61,7 @@ import {
|
|
|
60
61
|
resolveProjectSignature,
|
|
61
62
|
retainSnapshotOutput,
|
|
62
63
|
settledFileTag
|
|
63
|
-
} from "./chunk-
|
|
64
|
+
} from "./chunk-B4NDV4NM.js";
|
|
64
65
|
import {
|
|
65
66
|
clearElementScreenshotIsolation,
|
|
66
67
|
getElementScreenshotClip
|
|
@@ -74,7 +75,7 @@ import {
|
|
|
74
75
|
requestedProjectPath,
|
|
75
76
|
requiredFfmpeg,
|
|
76
77
|
resolveLocalAudioPath
|
|
77
|
-
} from "./chunk-
|
|
78
|
+
} from "./chunk-QZWVJKLI.js";
|
|
78
79
|
import {
|
|
79
80
|
injectMediaCodecMap,
|
|
80
81
|
isAutoProxyEnabled,
|
|
@@ -6807,6 +6808,7 @@ export {
|
|
|
6807
6808
|
patchElementInHtml,
|
|
6808
6809
|
pruneGoneProjectHistories,
|
|
6809
6810
|
readProjectHistory,
|
|
6811
|
+
reclaimUncopiedBlobs,
|
|
6810
6812
|
recordArtifact,
|
|
6811
6813
|
recordArtifacts,
|
|
6812
6814
|
recordRenderSuccess,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/studio-server",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.192",
|
|
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/
|
|
88
|
-
"@hyperframes/
|
|
87
|
+
"@hyperframes/core": "0.8.192",
|
|
88
|
+
"@hyperframes/parsers": "0.8.192"
|
|
89
89
|
},
|
|
90
90
|
"devDependencies": {
|
|
91
91
|
"@types/node": "^25.0.10",
|