hyperframes 0.8.133 → 0.8.135
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/{add-KIAMI737.js → add-7E2GRDW5.js} +16 -16
- package/dist/{animatedGifPrep-P2T6YM7Z.js → animatedGifPrep-3AKQSXPU.js} +7 -7
- package/dist/{asset-KRQ4APXQ.js → asset-43SXDTJI.js} +2 -2
- package/dist/{assetCataloger-VBLPHX24.js → assetCataloger-KBN5LNK4.js} +3 -3
- package/dist/{auth-M4XWYQDV.js → auth-BWQ4HPK7.js} +2 -2
- package/dist/{autoUpdate-J7LNL4BP.js → autoUpdate-JTHQKHG5.js} +2 -2
- package/dist/{backgroundChecks-LLNHXZPY.js → backgroundChecks-H43RKGRE.js} +3 -3
- package/dist/backgroundChecksWorker.js +3 -3
- package/dist/{batchRender-FT7AP7XH.js → batchRender-VFXGGGJG.js} +4 -4
- package/dist/{beats-NOF2NADU.js → beats-HAOQC7GJ.js} +13 -13
- package/dist/{benchmark-XVHUNNCM.js → benchmark-ANUXIEPD.js} +13 -13
- package/dist/{browser-URZ3PY73.js → browser-HEICRDNT.js} +10 -10
- package/dist/{bundleWithLocalizedFonts-5QOPOB5D.js → bundleWithLocalizedFonts-5ATL25BF.js} +2 -2
- package/dist/{capture-RLZA6EMR.js → capture-DYBK5LGE.js} +10 -10
- package/dist/{capture-SZZ4IYJK.js → capture-UEJG6BUX.js} +2 -2
- package/dist/{catalog-EJBGGESW.js → catalog-2F5L72ZT.js} +16 -16
- package/dist/{check-RXLKRRB2.js → check-WZ5QMBBF.js} +33 -33
- package/dist/{checkBrowser-DNUQDCGD.js → checkBrowser-FXVVADP6.js} +32 -32
- package/dist/{chunk-MWB3ZIFM.js → chunk-2BJCQN7K.js} +1 -1
- package/dist/{chunk-LYNI3FOL.js → chunk-32QEFPDS.js} +1 -1
- package/dist/{chunk-4NWOGZZS.js → chunk-374QQGBQ.js} +26 -3
- package/dist/{chunk-QC4FJVLM.js → chunk-37EDNWLQ.js} +1 -1
- package/dist/{chunk-KBJUXVOJ.js → chunk-3NCZ2SCH.js} +3 -3
- package/dist/{chunk-IUZFXWSV.js → chunk-4AXZWUQ6.js} +1 -1
- package/dist/{chunk-3ZP5DXE7.js → chunk-527WRFUQ.js} +1 -1
- package/dist/{chunk-ZMXUQLI2.js → chunk-5ALWCRBU.js} +47 -25
- package/dist/{chunk-JEFU7IHM.js → chunk-AV7FBRWP.js} +2 -2
- package/dist/{chunk-2YN64IN5.js → chunk-BHOKLX4F.js} +2 -2
- package/dist/{chunk-HRUGC23L.js → chunk-BSU7EOWJ.js} +1 -1
- package/dist/{chunk-FCSIGXXP.js → chunk-BWJ27MQP.js} +1 -1
- package/dist/{chunk-PDAMK4Q5.js → chunk-D2KNWIQ6.js} +1 -1
- package/dist/{chunk-RMHUQGRK.js → chunk-GK5W3SIJ.js} +4 -4
- package/dist/{chunk-GK3QVRBM.js → chunk-GN6GW6IP.js} +9 -9
- package/dist/{chunk-6CTIGJY7.js → chunk-H4UIYRZZ.js} +2 -2
- package/dist/{chunk-DIFXJN2V.js → chunk-HNUHWAHR.js} +1 -1
- package/dist/{chunk-S55PCW5S.js → chunk-I54AADBN.js} +1 -1
- package/dist/{chunk-5OZGQCAB.js → chunk-KZ7B3XK7.js} +1 -1
- package/dist/{chunk-7JZ4FXP2.js → chunk-KZJPREW7.js} +1 -1
- package/dist/{chunk-ARR5QKPH.js → chunk-LKCICE2T.js} +10 -10
- package/dist/{chunk-YQZNILVH.js → chunk-LO7L5PJ3.js} +5 -5
- package/dist/{chunk-S7NPLFWV.js → chunk-LYJNFBD6.js} +792 -671
- package/dist/{chunk-7XKF2OB5.js → chunk-N3DZEPNT.js} +1 -1
- package/dist/{chunk-K2FTXJYH.js → chunk-N3KRRPL7.js} +81 -24
- package/dist/{chunk-ETWKKKJI.js → chunk-NDKVPWBH.js} +3 -3
- package/dist/{chunk-XS4EJSKU.js → chunk-OSSVNAI5.js} +1 -1
- package/dist/{chunk-AVUUN2XD.js → chunk-OZUQF4NB.js} +5 -4
- package/dist/{chunk-Z6B37SNM.js → chunk-PGFP4FLW.js} +12 -158
- package/dist/{chunk-SF4GTH2H.js → chunk-PULS7UW7.js} +2 -2
- package/dist/{chunk-A2Z4Z4VL.js → chunk-RTURM45Q.js} +1 -1
- package/dist/{chunk-TCLGPL65.js → chunk-RVG35AL2.js} +2 -2
- package/dist/{chunk-HKGEEUZV.js → chunk-SMWYGLTD.js} +7 -7
- package/dist/chunk-SRXQEQWZ.js +3742 -0
- package/dist/{chunk-K2EQN4VU.js → chunk-T5LPCY6I.js} +1 -1
- package/dist/{chunk-MAWC5PUQ.js → chunk-TKSAWNNI.js} +3 -3
- package/dist/{chunk-Q7IU7MOR.js → chunk-V26IB6L2.js} +2 -2
- package/dist/{chunk-CWPVM2QV.js → chunk-V2J2ZWPR.js} +2 -2
- package/dist/{chunk-ZJUKFZ2P.js → chunk-VDQCNWQI.js} +2 -2
- package/dist/{chunk-CFKU7HTK.js → chunk-VNC6YQOC.js} +1 -1
- package/dist/{chunk-WPHMNO44.js → chunk-WJFCDDP7.js} +1 -1
- package/dist/{chunk-VTUOQTFU.js → chunk-WVRNPWVW.js} +1 -1
- package/dist/{chunk-7HG4BFIN.js → chunk-XE6S5CE6.js} +1 -1
- package/dist/{chunk-U7CKZ7BR.js → chunk-XFKPUKL7.js} +4 -4
- package/dist/{chunk-UEZXMWG3.js → chunk-XSWKLDVC.js} +2 -2
- package/dist/{chunk-64TQHBM7.js → chunk-XZVPQYLU.js} +5 -5
- package/dist/{chunk-LHSR3M4M.js → chunk-Z3EFUXL5.js} +2 -2
- package/dist/{chunk-MJ5XLLXY.js → chunk-Z3KAYWE5.js} +3 -3
- package/dist/{clean-XMQXSQI5.js → clean-SZMPUNNQ.js} +17 -17
- package/dist/cli.js +51 -51
- package/dist/{cloud-BAC5KWSE.js → cloud-L7RFQB5E.js} +4 -4
- package/dist/{cloudrun-AJUTHUEA.js → cloudrun-FA4XHPZS.js} +5 -5
- package/dist/{compare-QAV6WNL4.js → compare-DN5GHUAZ.js} +27 -27
- package/dist/{compiler-QO36EXLS.js → compiler-XZ654ZH2.js} +13 -11
- package/dist/{component-HAJPPCFF.js → component-RYYGPCCC.js} +3 -3
- package/dist/{compositions-A5PN3ILU.js → compositions-TF42YRGQ.js} +12 -12
- package/dist/{delete-L5LYQF6D.js → delete-KYGP772F.js} +2 -2
- package/dist/{deterministicFonts-HAEMV4TM.js → deterministicFonts-U2EXY2KQ.js} +2 -2
- package/dist/{dist-S3PJNPXQ.js → dist-HVJAGLHF.js} +5 -3
- package/dist/{dist-FNNGCKFS.js → dist-QS5WEGBE.js} +1 -1
- package/dist/{doctor-VAALU6RK.js → doctor-AWERBYTS.js} +11 -11
- package/dist/{events-53SD6Z6G.js → events-QMT3TXJ2.js} +10 -10
- package/dist/{events-FSZQPLB5.js → events-W4AILK4F.js} +9 -9
- package/dist/{feedback-HVIGQIBA.js → feedback-KNKJFGOK.js} +11 -11
- package/dist/{figma-OMHCIFA6.js → figma-D76N4WD7.js} +3 -3
- package/dist/fontLocalizeCli.js +10 -10
- package/dist/{get-VVCHOTHZ.js → get-JHNZVDVT.js} +2 -2
- package/dist/{gpuPolicy-2ZUZE5D6.js → gpuPolicy-ON3RMSWD.js} +7 -7
- package/dist/{grade-compare-VEQUV7SJ.js → grade-compare-22SRAVPO.js} +27 -27
- package/dist/{gsapParser-DIYYX6JT.js → gsapParser-2OL54XZ5.js} +61 -23
- package/dist/{gsapParserAcorn-E3GEIRZB.js → gsapParserAcorn-VXZ3ZIF2.js} +5 -3
- package/dist/{help-VWAFVPC6.js → help-CKKLDL3G.js} +1 -1
- package/dist/{history-NYADNWVR.js → history-44SS2VJQ.js} +17 -17
- package/dist/hyperframe-runtime.js +49 -49
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +49 -49
- package/dist/hyperframes-player.global.js +1 -1
- package/dist/{info-42A4ZXQZ.js → info-A2CXIT7G.js} +12 -12
- package/dist/{init-YUGOYCN6.js → init-6D2GNNON.js} +23 -23
- package/dist/{inspect-C66X5KGK.js → inspect-QLYCCDHV.js} +28 -28
- package/dist/{installer-K6O5WF44.js → installer-DDJVY4TO.js} +5 -5
- package/dist/{keyframes-CC4SVYGQ.js → keyframes-TBS3BUZ5.js} +13 -16
- package/dist/{lambda-D7UMN4DJ.js → lambda-LPLYOEYY.js} +6 -6
- package/dist/{layout-OBTKALAB.js → layout-YLBD2653.js} +28 -28
- package/dist/{lint-CDJ4BIB5.js → lint-6XERRN4E.js} +13 -13
- package/dist/{lintProject-OHBBM3DJ.js → lintProject-EPVG2EFE.js} +1 -1
- package/dist/{list-AMHMJLVP.js → list-DPVTICQX.js} +2 -2
- package/dist/{login-3FHM5JUX.js → login-FJJH3ZPU.js} +4 -4
- package/dist/{media-treatment-SGIJZZSW.js → media-treatment-CQWZZRHR.js} +13 -13
- package/dist/{models-C4E4IWJD.js → models-54NL5PRB.js} +8 -8
- package/dist/{motionShot-S4MIGMT5.js → motionShot-BSI4U6X7.js} +13 -13
- package/dist/{normalize-audio-U4QNHC3R.js → normalize-audio-2QQBNTAW.js} +12 -12
- package/dist/{open-DRIBRDFD.js → open-YCWBIUNN.js} +11 -11
- package/dist/{pipeline-TNGWUZQC.js → pipeline-P7QRGI5H.js} +7 -7
- package/dist/{play-NOBUJING.js → play-5OX76SR5.js} +22 -22
- package/dist/{preflight-SMNV6RW2.js → preflight-X3XFRJPQ.js} +8 -8
- package/dist/{present-Q4Q4V6JJ.js → present-UFG6NPCO.js} +18 -18
- package/dist/{preview-SEH3BNYZ.js → preview-AGS4TAWM.js} +18 -18
- package/dist/{producer-ECLEN5RP.js → producer-KQNJKM7F.js} +1 -1
- package/dist/{projectConfig-HYJMJ5BY.js → projectConfig-EAAQYRMP.js} +7 -7
- package/dist/{publication-HQ5Y3KBM.js → publication-H3G346EX.js} +3 -3
- package/dist/{publish-VHDYQASC.js → publish-NEGKIS35.js} +9 -9
- package/dist/{remove-background-W2YX2NVH.js → remove-background-HU4S4HH5.js} +8 -8
- package/dist/{render-AO5VX3YI.js → render-F3CNO2IE.js} +4 -4
- package/dist/{render-ZJYL6ZPT.js → render-KEZFDRDA.js} +22 -22
- package/dist/{render-XVKTOY2L.js → render-POQI3EKS.js} +13 -13
- package/dist/{render-batch-YH7CTWNY.js → render-batch-63CBIJYR.js} +4 -4
- package/dist/{renderCancellation-JPIHE47X.js → renderCancellation-FT3JJ7GB.js} +7 -7
- package/dist/renderSetupWorker.js +1 -1
- package/dist/{resolver-IZ647GBZ.js → resolver-YJJKOGQF.js} +5 -5
- package/dist/{sherpa-KKLNW6U2.js → sherpa-3BQDMJPJ.js} +8 -8
- package/dist/{skills-IIHWUS56.js → skills-L7SZ45NC.js} +12 -12
- package/dist/{skillsUpdateCheck-HG5HOSBY.js → skillsUpdateCheck-HP3GJFBP.js} +3 -3
- package/dist/{snapshot-SRSWE7B2.js → snapshot-CYB2PZPW.js} +28 -28
- package/dist/{src-PVYUYV3M.js → src-CUR36DBE.js} +8 -6
- package/dist/{src-6YQBJGWR.js → src-ZPAJ44CP.js} +9 -9
- package/dist/{staticProjectServer-7EU666GS.js → staticProjectServer-U5DMWKWA.js} +16 -16
- package/dist/{status-YM52BQ6S.js → status-6CGT2PJT.js} +7 -7
- package/dist/studio/assets/{hyperframes-player-Cjcwveg0.js → hyperframes-player-DFv9heE6.js} +1 -1
- package/dist/studio/assets/{index-CwgWmfgx.js → index-Buy06mZy.js} +1 -1
- package/dist/studio/assets/{index-ME-Z5jh6.js → index-CTp4loy9.js} +1 -1
- package/dist/studio/assets/{index-Dj21zXWA.js → index-N_4Ij4X6.js} +184 -183
- package/dist/studio/assets/{index-D11atkBt.css → index-syMK0_9C.css} +1 -1
- package/dist/studio/{chunk-5VSXRGIX.js → chunk-NM7BXNZ7.js} +1 -1
- package/dist/studio/chunk-NM7BXNZ7.js.map +1 -0
- package/dist/studio/{chunk-FOEID72M.js → chunk-QRLKWENQ.js} +2 -2
- package/dist/studio/index.d.ts +3 -1
- package/dist/studio/index.html +2 -2
- package/dist/studio/index.js +911 -691
- package/dist/studio/index.js.map +1 -1
- package/dist/studio/player.js +2 -2
- package/dist/studio/styles.css +1 -1
- package/dist/studio/ui.d.ts +3 -2
- package/dist/studio/ui.js +1 -1
- package/dist/{studio-api-PNQZRPX5.js → studio-api-KMBTUYG5.js} +10 -10
- package/dist/{studioServer-SKEFBCNM.js → studioServer-LOJ6IOWA.js} +42 -42
- package/dist/{system-EZYZNUFD.js → system-3BTZGJNK.js} +7 -7
- package/dist/{telemetry-TN6HXCPW.js → telemetry-MCEZ5JYB.js} +10 -10
- package/dist/{timeline-Y6RJY467.js → timeline-XWH4I5CF.js} +17 -17
- package/dist/{tokens-HWMQVD2T.js → tokens-6UTTSLVN.js} +2 -2
- package/dist/{transcribe-BNSJRR4M.js → transcribe-HC35FL6W.js} +8 -8
- package/dist/{transcribe-PZP553TY.js → transcribe-S3NI7SYU.js} +13 -13
- package/dist/{updateCheck-2HHCJUTZ.js → updateCheck-3YAKEXSX.js} +2 -2
- package/dist/{upgrade-Y55PMAGH.js → upgrade-JQPBH5RY.js} +2 -2
- package/dist/{urlDownloader-H6WRI2UE.js → urlDownloader-A5TT3AFE.js} +6 -6
- package/dist/{validate-BFYU5VTW.js → validate-BLUPV5H5.js} +17 -17
- package/dist/{video-FGSGKRSV.js → video-USXMJDEZ.js} +7 -7
- package/package.json +1 -1
- package/dist/chunk-HWKCIWQT.js +0 -3578
- package/dist/studio/chunk-5VSXRGIX.js.map +0 -1
- /package/dist/studio/{chunk-FOEID72M.js.map → chunk-QRLKWENQ.js.map} +0 -0
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
splitElementInHtml,
|
|
22
22
|
unwrapElementsFromHtml,
|
|
23
23
|
wrapElementsInHtml
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-GK5W3SIJ.js";
|
|
25
25
|
import {
|
|
26
26
|
atomicTempPath,
|
|
27
27
|
createFileAtomically,
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
measureAudio,
|
|
35
35
|
requiredFfmpeg,
|
|
36
36
|
resolveLocalAudioPath
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-37EDNWLQ.js";
|
|
38
38
|
import {
|
|
39
39
|
PROXY_PARAMS_VERSION,
|
|
40
40
|
PROXY_PENDING_RETRY_AFTER_SECONDS,
|
|
@@ -60,11 +60,11 @@ import {
|
|
|
60
60
|
shouldPrewarmProxy,
|
|
61
61
|
waitForProxy,
|
|
62
62
|
walkDir
|
|
63
|
-
} from "./chunk-
|
|
63
|
+
} from "./chunk-RVG35AL2.js";
|
|
64
64
|
import {
|
|
65
65
|
findTimelineScript,
|
|
66
66
|
parseGsapScriptAcorn
|
|
67
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-374QQGBQ.js";
|
|
68
68
|
import {
|
|
69
69
|
STUDIO_MANUAL_EDITS_PATH
|
|
70
70
|
} from "./chunk-KC5XXX3X.js";
|
|
@@ -81,20 +81,20 @@ import {
|
|
|
81
81
|
motionPathPluginUrl,
|
|
82
82
|
parseFps,
|
|
83
83
|
sameInstant
|
|
84
|
-
} from "./chunk-
|
|
84
|
+
} from "./chunk-BHOKLX4F.js";
|
|
85
85
|
import {
|
|
86
86
|
MagicString,
|
|
87
87
|
VALID_CANVAS_RESOLUTIONS,
|
|
88
88
|
unrollComputedTimeline
|
|
89
|
-
} from "./chunk-
|
|
89
|
+
} from "./chunk-OZUQF4NB.js";
|
|
90
90
|
import {
|
|
91
|
-
AFTER_FONTS_SCRIPT_TYPE,
|
|
92
91
|
addScenePartsManifest,
|
|
93
|
-
deferScriptsUntilFonts,
|
|
94
92
|
ensureHfIds
|
|
95
|
-
} from "./chunk-
|
|
93
|
+
} from "./chunk-PGFP4FLW.js";
|
|
96
94
|
import {
|
|
95
|
+
AFTER_FONTS_SCRIPT_TYPE,
|
|
97
96
|
RUNTIME_BOOTSTRAP_ATTR,
|
|
97
|
+
deferScriptsUntilFonts,
|
|
98
98
|
findStartTags,
|
|
99
99
|
hasCompositionOutsideTemplates,
|
|
100
100
|
injectTagsAtHeadStart,
|
|
@@ -104,7 +104,7 @@ import {
|
|
|
104
104
|
resolveRateSpec,
|
|
105
105
|
sourceTimeAt,
|
|
106
106
|
stripEmbeddedRuntimeScripts
|
|
107
|
-
} from "./chunk-
|
|
107
|
+
} from "./chunk-SRXQEQWZ.js";
|
|
108
108
|
import {
|
|
109
109
|
ProjectRootMissingError,
|
|
110
110
|
folderGone,
|
|
@@ -117,7 +117,7 @@ import {
|
|
|
117
117
|
import {
|
|
118
118
|
isWithinProjectRoot,
|
|
119
119
|
readProjectFile
|
|
120
|
-
} from "./chunk-
|
|
120
|
+
} from "./chunk-VDQCNWQI.js";
|
|
121
121
|
import {
|
|
122
122
|
FFPROBE_PATH_ENV,
|
|
123
123
|
findFfBinary
|
|
@@ -2227,10 +2227,10 @@ import { join as join6 } from "path";
|
|
|
2227
2227
|
import { bodyLimit } from "hono/body-limit";
|
|
2228
2228
|
import {
|
|
2229
2229
|
closeSync as closeSync3,
|
|
2230
|
-
existsSync as
|
|
2230
|
+
existsSync as existsSync4,
|
|
2231
2231
|
lstatSync as lstatSync22,
|
|
2232
2232
|
openSync as openSync3,
|
|
2233
|
-
readFileSync as
|
|
2233
|
+
readFileSync as readFileSync52,
|
|
2234
2234
|
readlinkSync,
|
|
2235
2235
|
unlinkSync as unlinkSync2,
|
|
2236
2236
|
rmSync as rmSync3,
|
|
@@ -2240,10 +2240,17 @@ import {
|
|
|
2240
2240
|
readdirSync as readdirSync22,
|
|
2241
2241
|
realpathSync as realpathSync2
|
|
2242
2242
|
} from "fs";
|
|
2243
|
-
import { resolve as resolve22, dirname as dirname32, join as
|
|
2243
|
+
import { resolve as resolve22, dirname as dirname32, join as join62 } from "path";
|
|
2244
|
+
import { readFileSync as readFileSync23 } from "fs";
|
|
2245
|
+
import { createHash as createHash4 } from "crypto";
|
|
2246
|
+
import { existsSync as existsSync3, readFileSync as readFileSync7 } from "fs";
|
|
2247
|
+
import { join as join23 } from "path";
|
|
2248
|
+
import { existsSync as existsSync22 } from "fs";
|
|
2249
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
2250
|
+
import { dirname as dirname5, relative as relative3, resolve as resolve5, sep as sep3 } from "path";
|
|
2244
2251
|
import { spawn } from "child_process";
|
|
2245
2252
|
import {
|
|
2246
|
-
existsSync as
|
|
2253
|
+
existsSync as existsSync32,
|
|
2247
2254
|
writeFileSync as writeFileSync4,
|
|
2248
2255
|
mkdirSync as mkdirSync5,
|
|
2249
2256
|
lstatSync as lstatSync3,
|
|
@@ -2252,15 +2259,15 @@ import {
|
|
|
2252
2259
|
rmSync as rmSync4,
|
|
2253
2260
|
statSync as statSync4
|
|
2254
2261
|
} from "fs";
|
|
2255
|
-
import { dirname as
|
|
2262
|
+
import { dirname as dirname23, join as join32 } from "path";
|
|
2256
2263
|
import { spawnSync } from "child_process";
|
|
2257
2264
|
import { mkdtempSync as mkdtempSync2, rmSync as rmSync22, writeFileSync as writeFileSync23 } from "fs";
|
|
2258
2265
|
import { tmpdir as tmpdir2 } from "os";
|
|
2259
|
-
import { basename as basename2, join as
|
|
2260
|
-
import { readdirSync as readdirSync4, readFileSync as
|
|
2266
|
+
import { basename as basename2, join as join42 } from "path";
|
|
2267
|
+
import { readdirSync as readdirSync4, readFileSync as readFileSync32, unlinkSync, writeFileSync as writeFileSync32 } from "fs";
|
|
2261
2268
|
import { Buffer as Buffer2 } from "buffer";
|
|
2262
|
-
import { join as
|
|
2263
|
-
import { readFileSync as
|
|
2269
|
+
import { join as join52, relative as relative22 } from "path";
|
|
2270
|
+
import { readFileSync as readFileSync42, statSync as statSync22 } from "fs";
|
|
2264
2271
|
|
|
2265
2272
|
// ../parsers/dist/gsapConstants.js
|
|
2266
2273
|
var PROPERTY_GROUPS = {
|
|
@@ -2335,23 +2342,43 @@ function knownStart(animation) {
|
|
|
2335
2342
|
if (animation.resolvedStart !== void 0) return animation.resolvedStart;
|
|
2336
2343
|
return typeof animation.position === "number" ? animation.position : void 0;
|
|
2337
2344
|
}
|
|
2338
|
-
|
|
2345
|
+
var tweenSignature = (a) => JSON.stringify([a.targetSelector, a.method, a.position, a.duration, a.properties, a.keyframes]);
|
|
2346
|
+
function holdScope(before, previous) {
|
|
2347
|
+
const kept = new Set(previous?.map(tweenSignature));
|
|
2348
|
+
const held = /* @__PURE__ */ new Map();
|
|
2349
|
+
for (const a of before.filter((b) => b.method === "set" && b.properties?.data === "hf-hold")) {
|
|
2350
|
+
const props = held.get(a.targetSelector) ?? /* @__PURE__ */ new Map();
|
|
2351
|
+
for (const [property, value] of Object.entries(a.properties)) props.set(property, value);
|
|
2352
|
+
held.set(a.targetSelector, props);
|
|
2353
|
+
}
|
|
2354
|
+
return {
|
|
2355
|
+
touched: (a) => previous !== null && !kept.has(tweenSignature(a)),
|
|
2356
|
+
held: (selector) => held.get(selector) ?? /* @__PURE__ */ new Map()
|
|
2357
|
+
};
|
|
2358
|
+
}
|
|
2359
|
+
function keyframeHoldForAnimation(animation, animations, scope) {
|
|
2339
2360
|
if (!animation.keyframes) return null;
|
|
2340
|
-
const start = knownStart(animation)
|
|
2341
|
-
|
|
2361
|
+
const start = knownStart(animation);
|
|
2362
|
+
const lone = animation.keyframes.keyframes.length === 1;
|
|
2363
|
+
if (start === void 0 || !(start > 1e-3) && !lone) return null;
|
|
2342
2364
|
const atStart = animation.keyframes.keyframes.find((keyframe) => keyframe.percentage === 0);
|
|
2343
2365
|
if (!atStart) return null;
|
|
2344
2366
|
const earlier = animations.filter((other) => {
|
|
2345
2367
|
const otherStart = knownStart(other);
|
|
2346
2368
|
return other !== animation && !other.global && other.targetSelector === animation.targetSelector && otherStart !== void 0 && otherStart < start - 1e-3;
|
|
2347
2369
|
});
|
|
2348
|
-
const
|
|
2370
|
+
const touched = scope.touched(animation);
|
|
2371
|
+
const pinned = scope.held(animation.targetSelector);
|
|
2372
|
+
const kept = (property, value) => touched ? pinned.has(property) : pinned.get(property) === value;
|
|
2373
|
+
const pins = (group, property, value) => group === "position" && start > 1e-3 || (group === "position" || group === "size") && (lone && touched || kept(property, value));
|
|
2374
|
+
const hold = {};
|
|
2349
2375
|
for (const [property, value] of Object.entries(atStart.properties)) {
|
|
2350
|
-
if (classifyPropertyGroup2(property)
|
|
2376
|
+
if (!pins(classifyPropertyGroup2(property), property, value) || typeof value !== "number")
|
|
2377
|
+
continue;
|
|
2351
2378
|
if (earlier.some((other) => writesProperty(other, property))) continue;
|
|
2352
|
-
|
|
2379
|
+
hold[property] = value;
|
|
2353
2380
|
}
|
|
2354
|
-
return Object.keys(
|
|
2381
|
+
return Object.keys(hold).length > 0 ? hold : null;
|
|
2355
2382
|
}
|
|
2356
2383
|
function authorsKeyframes(anim) {
|
|
2357
2384
|
return anim.keyframes !== void 0 || anim.hasUnresolvedKeyframes === true;
|
|
@@ -2394,6 +2421,10 @@ function buildArcPath(coords, curviness, autoRotate, isCubic) {
|
|
|
2394
2421
|
}
|
|
2395
2422
|
return { arcPath: { enabled: true, autoRotate, segments }, waypoints };
|
|
2396
2423
|
}
|
|
2424
|
+
function plainPercentKey(percentage) {
|
|
2425
|
+
const text2 = Math.abs(percentage) < 1e-6 ? percentage.toFixed(20).replace(/\.?0+$/, "") : String(percentage);
|
|
2426
|
+
return `${text2}%`;
|
|
2427
|
+
}
|
|
2397
2428
|
var CSS_IDENTITY = {
|
|
2398
2429
|
opacity: 1,
|
|
2399
2430
|
autoAlpha: 1,
|
|
@@ -3333,9 +3364,6 @@ function tweenCallToAnimation(call, scope, source, identifierBindings) {
|
|
|
3333
3364
|
properties[key] = val;
|
|
3334
3365
|
}
|
|
3335
3366
|
}
|
|
3336
|
-
if (keyframesData && typeof vars.easeEach === "string") {
|
|
3337
|
-
keyframesData.easeEach = vars.easeEach;
|
|
3338
|
-
}
|
|
3339
3367
|
if (motionPathResult) {
|
|
3340
3368
|
const { waypoints } = motionPathResult;
|
|
3341
3369
|
if (!keyframesData) {
|
|
@@ -4311,7 +4339,7 @@ function convertArrayKeyframesToObject(script, target) {
|
|
|
4311
4339
|
if (!timing) return script;
|
|
4312
4340
|
const entries = els.map((el, i) => {
|
|
4313
4341
|
const { duration: _duration, ...record } = records[i];
|
|
4314
|
-
return `${JSON.stringify(
|
|
4342
|
+
return `${JSON.stringify(plainPercentKey(timing.percentages[i]))}: ${recordToCode(record)}`;
|
|
4315
4343
|
});
|
|
4316
4344
|
const ms = new MagicString(script);
|
|
4317
4345
|
ms.overwrite(
|
|
@@ -4373,7 +4401,13 @@ function addKeyframeToScript(script, animationId, percentage, properties, ease,
|
|
|
4373
4401
|
ms.overwrite(existing.prop.value.start, existing.prop.value.end, recordToCode(targetRecord));
|
|
4374
4402
|
}
|
|
4375
4403
|
} else {
|
|
4376
|
-
insertNewKeyframe(
|
|
4404
|
+
insertNewKeyframe(
|
|
4405
|
+
ms,
|
|
4406
|
+
kfNode,
|
|
4407
|
+
percentage,
|
|
4408
|
+
plainPercentKey(percentage),
|
|
4409
|
+
recordToCode(targetRecord)
|
|
4410
|
+
);
|
|
4377
4411
|
}
|
|
4378
4412
|
for (const [prop, rec] of [...endpointOverwrites, ...backfillOverwrites]) {
|
|
4379
4413
|
ms.overwrite(prop.value.start, prop.value.end, recordToCode(rec));
|
|
@@ -4472,7 +4506,12 @@ function moveKeyframeInScript(script, animationId, fromPercentage, toPercentage)
|
|
|
4472
4506
|
}
|
|
4473
4507
|
entries.push({ pct: toPercentage, record: valueNodeToRecord(match.prop.value, src) });
|
|
4474
4508
|
entries.sort((a, b) => a.pct - b.pct);
|
|
4475
|
-
const
|
|
4509
|
+
const pctProps = new Set(percentagePropsOf(kfNode));
|
|
4510
|
+
const kept = (kfNode.properties ?? []).filter((p) => !pctProps.has(p)).map((p) => src.slice(p.start, p.end));
|
|
4511
|
+
const body = [
|
|
4512
|
+
...entries.map((e) => `${JSON.stringify(plainPercentKey(e.pct))}: ${recordToCode(e.record)}`),
|
|
4513
|
+
...kept
|
|
4514
|
+
].join(", ");
|
|
4476
4515
|
const ms = new MagicString(src);
|
|
4477
4516
|
ms.overwrite(kfNode.start, kfNode.end, `{ ${body} }`);
|
|
4478
4517
|
return ms.toString();
|
|
@@ -4491,7 +4530,7 @@ function resizeKeyframedTweenInScript(script, animationId, newPosition, newDurat
|
|
|
4491
4530
|
}
|
|
4492
4531
|
const ms = new MagicString(src);
|
|
4493
4532
|
for (const { keyNode, to } of edits) {
|
|
4494
|
-
ms.overwrite(keyNode.start, keyNode.end, JSON.stringify(
|
|
4533
|
+
ms.overwrite(keyNode.start, keyNode.end, JSON.stringify(plainPercentKey(to)));
|
|
4495
4534
|
}
|
|
4496
4535
|
overwritePosition(ms, target.call, newPosition);
|
|
4497
4536
|
upsertProp(ms, target.call.varsArg, "duration", newDuration);
|
|
@@ -4594,7 +4633,7 @@ function buildKeyframeObjectCode(keyframes, easeEach) {
|
|
|
4594
4633
|
const props = Object.entries(kf.properties).map(([k, v]) => `${safeKey(k)}: ${valueToCode(v)}`);
|
|
4595
4634
|
if (kf.ease) props.push(`ease: ${valueToCode(kf.ease)}`);
|
|
4596
4635
|
if (kf.auto) props.push(`_auto: 1`);
|
|
4597
|
-
return `${JSON.stringify(
|
|
4636
|
+
return `${JSON.stringify(plainPercentKey(kf.percentage))}: { ${props.join(", ")} }`;
|
|
4598
4637
|
});
|
|
4599
4638
|
if (easeEach) entries.push(`easeEach: ${valueToCode(easeEach)}`);
|
|
4600
4639
|
return `{ ${entries.join(", ")} }`;
|
|
@@ -4748,7 +4787,8 @@ function addGroupAnimToScript(script, anim, propSet) {
|
|
|
4748
4787
|
pos,
|
|
4749
4788
|
anim.duration ?? 0.5,
|
|
4750
4789
|
groupKeyframes,
|
|
4751
|
-
anim.keyframes.
|
|
4790
|
+
anim.keyframes.ease ?? anim.ease,
|
|
4791
|
+
anim.keyframes.easeEach
|
|
4752
4792
|
);
|
|
4753
4793
|
}
|
|
4754
4794
|
const groupProperties = filterGroupProperties(anim.properties, propSet);
|
|
@@ -5021,15 +5061,20 @@ function removeStudioHoldSets(script, parsed) {
|
|
|
5021
5061
|
for (const hold of staleHolds) removeCallFromMagicString(ms, hold.call, script);
|
|
5022
5062
|
return ms.toString();
|
|
5023
5063
|
}
|
|
5024
|
-
function syncPositionHoldsBeforeKeyframes(script) {
|
|
5064
|
+
function syncPositionHoldsBeforeKeyframes(script, previous) {
|
|
5025
5065
|
const parsed = parseGsapScriptAcornForWrite(script);
|
|
5026
5066
|
if (!parsed) return script;
|
|
5067
|
+
const tweensOf = (text2) => parseGsapScriptAcornForWrite(text2)?.located.map((entry) => entry.animation) ?? null;
|
|
5068
|
+
const scope = holdScope(
|
|
5069
|
+
parsed.located.map((entry) => entry.animation),
|
|
5070
|
+
previous === void 0 ? null : tweensOf(previous)
|
|
5071
|
+
);
|
|
5027
5072
|
let result = removeStudioHoldSets(script, parsed);
|
|
5028
5073
|
const current = parseGsapScriptAcornForWrite(result);
|
|
5029
5074
|
if (!current) return result;
|
|
5030
5075
|
const animations = current.located.map((entry) => entry.animation);
|
|
5031
5076
|
for (const animation of animations) {
|
|
5032
|
-
const position =
|
|
5077
|
+
const position = keyframeHoldForAnimation(animation, animations, scope);
|
|
5033
5078
|
if (!position) continue;
|
|
5034
5079
|
result = insertInheritedStateSetInScript(result, animation.targetSelector, 0, {
|
|
5035
5080
|
...position,
|
|
@@ -5038,6 +5083,62 @@ function syncPositionHoldsBeforeKeyframes(script) {
|
|
|
5038
5083
|
}
|
|
5039
5084
|
return result;
|
|
5040
5085
|
}
|
|
5086
|
+
var roundPct = (pct) => Math.round(pct * 1e3) / 1e3;
|
|
5087
|
+
var LINEAR_RUN = /* @__PURE__ */ new Set(["none", "linear"]);
|
|
5088
|
+
var PLACED_BY_TIMELINE = /\.(?:add|addLabel|addPause|call|repeat|yoyo|duration|timeScale)\s*\(|\b(?:repeat|yoyo)\s*:/;
|
|
5089
|
+
function linearPercentageKeys(animation) {
|
|
5090
|
+
const data = animation.keyframes;
|
|
5091
|
+
if (data?.format !== "percentage" || data.fromMotionPath || animation.arcPath) return null;
|
|
5092
|
+
if (animation.durationUnresolved || !LINEAR_RUN.has(animation.ease || "none")) return null;
|
|
5093
|
+
return data.keyframes;
|
|
5094
|
+
}
|
|
5095
|
+
var loops = (animation) => Boolean(animation.extras?.repeat || animation.extras?.yoyo);
|
|
5096
|
+
function trimmableKeyframes(animation) {
|
|
5097
|
+
const keyframes = loops(animation) ? null : linearPercentageKeys(animation);
|
|
5098
|
+
const { duration, position } = animation;
|
|
5099
|
+
if (!keyframes || typeof position !== "number" || typeof duration !== "number") return null;
|
|
5100
|
+
return duration > 0 ? { keyframes, duration, position } : null;
|
|
5101
|
+
}
|
|
5102
|
+
function trailingSpanTrim(animation) {
|
|
5103
|
+
const tween = trimmableKeyframes(animation);
|
|
5104
|
+
if (!tween) return null;
|
|
5105
|
+
const last = Math.max(...tween.keyframes.map((keyframe) => keyframe.percentage));
|
|
5106
|
+
if (tween.keyframes.length < 2 || !(last > 0) || last >= 99.999) return null;
|
|
5107
|
+
return {
|
|
5108
|
+
position: tween.position,
|
|
5109
|
+
duration: Math.round(tween.duration * last * 10) / 1e3,
|
|
5110
|
+
pctRemap: tween.keyframes.map(({ percentage: from }) => ({
|
|
5111
|
+
from,
|
|
5112
|
+
to: roundPct(from / last * 100)
|
|
5113
|
+
}))
|
|
5114
|
+
};
|
|
5115
|
+
}
|
|
5116
|
+
function trimTrailingKeyframeSpans(previous, script) {
|
|
5117
|
+
if (script === previous) return script;
|
|
5118
|
+
const located = parseGsapScriptAcornForWrite(script)?.located ?? [];
|
|
5119
|
+
const placedAfter = ({ animation: a }) => !a.global && (a.implicitPosition || typeof a.position !== "number");
|
|
5120
|
+
if (PLACED_BY_TIMELINE.test(script) || located.some(placedAfter)) return script;
|
|
5121
|
+
const trims = located.flatMap((entry) => {
|
|
5122
|
+
const trim = trailingSpanTrim(entry.animation);
|
|
5123
|
+
return trim ? [{ entry, trim }] : [];
|
|
5124
|
+
});
|
|
5125
|
+
if (!trims.length) return script;
|
|
5126
|
+
const source = (text2, { call }) => `${call.method}${text2.slice(call.node.arguments[0]?.start, call.node.end)}`;
|
|
5127
|
+
const previousTweens = parseGsapScriptAcornForWrite(previous)?.located ?? [];
|
|
5128
|
+
const untouched = new Set(previousTweens.map((entry) => source(previous, entry)));
|
|
5129
|
+
let result = script;
|
|
5130
|
+
for (const { entry, trim } of trims) {
|
|
5131
|
+
if (untouched.has(source(script, entry))) continue;
|
|
5132
|
+
result = resizeKeyframedTweenInScript(
|
|
5133
|
+
result,
|
|
5134
|
+
entry.id,
|
|
5135
|
+
trim.position,
|
|
5136
|
+
trim.duration,
|
|
5137
|
+
trim.pctRemap
|
|
5138
|
+
);
|
|
5139
|
+
}
|
|
5140
|
+
return result;
|
|
5141
|
+
}
|
|
5041
5142
|
function computeForwardBaselines(matching, splitTime) {
|
|
5042
5143
|
const before = [];
|
|
5043
5144
|
const acc = {};
|
|
@@ -5330,31 +5431,26 @@ function unrollDynamicAnimations(script, animationId, elements) {
|
|
|
5330
5431
|
}
|
|
5331
5432
|
|
|
5332
5433
|
// ../studio-server/dist/index.js
|
|
5333
|
-
import { existsSync as
|
|
5334
|
-
import { randomUUID as randomUUID7 } from "crypto";
|
|
5335
|
-
import { dirname as dirname23, relative as relative22, resolve as resolve5, sep as sep3 } from "path";
|
|
5336
|
-
import { createReadStream as createReadStream2, existsSync as existsSync5, readFileSync as readFileSync52, statSync as statSync42 } from "fs";
|
|
5434
|
+
import { createReadStream as createReadStream2, existsSync as existsSync5, readFileSync as readFileSync62, statSync as statSync42 } from "fs";
|
|
5337
5435
|
import { Readable } from "stream";
|
|
5338
5436
|
import { join as join8, resolve as resolve42 } from "path";
|
|
5339
|
-
import { createHash as
|
|
5437
|
+
import { createHash as createHash23 } from "crypto";
|
|
5340
5438
|
|
|
5341
5439
|
// ../core/dist/studioPreviewMark.js
|
|
5342
5440
|
var STUDIO_PREVIEW_MARK_META = "hyperframes-studio-preview";
|
|
5343
5441
|
var STUDIO_PREVIEW_LAZY_ATTR = "data-hf-preview-lazy";
|
|
5344
5442
|
|
|
5345
5443
|
// ../studio-server/dist/index.js
|
|
5346
|
-
import { existsSync as existsSync42, readFileSync as readFileSync42 } from "fs";
|
|
5347
|
-
import { join as join62 } from "path";
|
|
5348
5444
|
import { readlinkSync as readlinkSync2 } from "fs";
|
|
5349
5445
|
import { dirname as dirname42, join as join7, parse as parse2, relative as relative32, resolve as resolve32 } from "path";
|
|
5350
|
-
import { readFileSync as
|
|
5446
|
+
import { readFileSync as readFileSync72 } from "fs";
|
|
5351
5447
|
import { join as join9 } from "path";
|
|
5352
5448
|
import { streamSSE } from "hono/streaming";
|
|
5353
|
-
import { existsSync as existsSync6, readFileSync as
|
|
5449
|
+
import { existsSync as existsSync6, readFileSync as readFileSync8, unlinkSync as unlinkSync3, readdirSync as readdirSync32, statSync as statSync5 } from "fs";
|
|
5354
5450
|
import { join as join10 } from "path";
|
|
5355
5451
|
import { HTTPException } from "hono/http-exception";
|
|
5356
5452
|
import { open, stat as stat2 } from "fs/promises";
|
|
5357
|
-
import { createHash as
|
|
5453
|
+
import { createHash as createHash32 } from "crypto";
|
|
5358
5454
|
import {
|
|
5359
5455
|
closeSync as closeSync22,
|
|
5360
5456
|
fstatSync as fstatSync22,
|
|
@@ -5369,8 +5465,6 @@ import {
|
|
|
5369
5465
|
} from "fs";
|
|
5370
5466
|
import { join as join11 } from "path";
|
|
5371
5467
|
import { createHash as createHash42, randomUUID as randomUUID22 } from "crypto";
|
|
5372
|
-
import { readFileSync as readFileSync8 } from "fs";
|
|
5373
|
-
import { createHash as createHash32 } from "crypto";
|
|
5374
5468
|
import { existsSync as existsSync7, readFileSync as readFileSync10, statSync as statSync7 } from "fs";
|
|
5375
5469
|
import { join as join12, resolve as resolve52 } from "path";
|
|
5376
5470
|
import { execFile } from "child_process";
|
|
@@ -5477,339 +5571,175 @@ function getMimeType(path) {
|
|
|
5477
5571
|
function isAudioFile(name) {
|
|
5478
5572
|
return (getMimeType(name) ?? "").startsWith("audio/");
|
|
5479
5573
|
}
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
if (abs > max) max = abs;
|
|
5499
|
-
}
|
|
5500
|
-
peaks.push(max);
|
|
5574
|
+
function rewriteRelativePaths(root, compPath, projectDir) {
|
|
5575
|
+
const assetExists = (path) => existsSync3(join23(projectDir, path));
|
|
5576
|
+
rewriteAssetPaths(
|
|
5577
|
+
root.querySelectorAll("[src], [href]"),
|
|
5578
|
+
compPath,
|
|
5579
|
+
(el, attr) => el.getAttribute(attr),
|
|
5580
|
+
(el, attr, value) => el.setAttribute(attr, value),
|
|
5581
|
+
assetExists
|
|
5582
|
+
);
|
|
5583
|
+
rewriteInlineStyleAssetUrls(
|
|
5584
|
+
root.querySelectorAll("[style]"),
|
|
5585
|
+
compPath,
|
|
5586
|
+
(el) => el.getAttribute("style"),
|
|
5587
|
+
(el, value) => el.setAttribute("style", value),
|
|
5588
|
+
assetExists
|
|
5589
|
+
);
|
|
5590
|
+
for (const styleEl of root.querySelectorAll("style")) {
|
|
5591
|
+
styleEl.textContent = rewriteCssAssetUrls(styleEl.textContent || "", compPath, assetExists);
|
|
5501
5592
|
}
|
|
5502
|
-
const maxPeak = Math.max(...peaks, 1e-3);
|
|
5503
|
-
return peaks.map((p) => p / maxPeak);
|
|
5504
|
-
}
|
|
5505
|
-
function decodeAudioPeaks(audioPath) {
|
|
5506
|
-
return new Promise((resolvePromise, reject) => {
|
|
5507
|
-
const proc = spawn(
|
|
5508
|
-
findFfBinary("ffmpeg") ?? "ffmpeg",
|
|
5509
|
-
[
|
|
5510
|
-
"-i",
|
|
5511
|
-
audioPath,
|
|
5512
|
-
"-af",
|
|
5513
|
-
"atrim=start_sample=1152",
|
|
5514
|
-
"-f",
|
|
5515
|
-
"f32le",
|
|
5516
|
-
"-ac",
|
|
5517
|
-
"1",
|
|
5518
|
-
"-ar",
|
|
5519
|
-
String(SAMPLE_RATE),
|
|
5520
|
-
"-vn",
|
|
5521
|
-
"pipe:1"
|
|
5522
|
-
],
|
|
5523
|
-
{ stdio: ["ignore", "pipe", "ignore"], windowsHide: true }
|
|
5524
|
-
);
|
|
5525
|
-
const chunks = [];
|
|
5526
|
-
proc.stdout?.on("data", (chunk) => chunks.push(chunk));
|
|
5527
|
-
proc.on("close", (code) => {
|
|
5528
|
-
if (code !== 0 && chunks.length === 0) {
|
|
5529
|
-
reject(new Error(`ffmpeg exited with code ${code}`));
|
|
5530
|
-
return;
|
|
5531
|
-
}
|
|
5532
|
-
const buf = Buffer.concat(chunks);
|
|
5533
|
-
const numSamples = Math.floor(buf.length / 4);
|
|
5534
|
-
if (numSamples === 0) {
|
|
5535
|
-
reject(new Error("ffmpeg produced no audio samples"));
|
|
5536
|
-
return;
|
|
5537
|
-
}
|
|
5538
|
-
const ab = buf.buffer.slice(buf.byteOffset, buf.byteOffset + numSamples * 4);
|
|
5539
|
-
resolvePromise(computePeaks(new Float32Array(ab), PEAK_COUNT));
|
|
5540
|
-
});
|
|
5541
|
-
proc.on("error", reject);
|
|
5542
|
-
});
|
|
5543
|
-
}
|
|
5544
|
-
async function generateWaveformCache(projectDir, assetPath) {
|
|
5545
|
-
const audioPath = join23(projectDir, assetPath);
|
|
5546
|
-
if (!existsSync4(audioPath)) return;
|
|
5547
|
-
const stats = statSync4(audioPath);
|
|
5548
|
-
const cacheDir = join23(projectDir, ".waveform-cache");
|
|
5549
|
-
const cachePath = join23(cacheDir, buildWaveformCacheKey(assetPath, stats));
|
|
5550
|
-
if (isWaveformCacheDirectory(cacheDir) && existsSync4(cachePath)) return;
|
|
5551
|
-
const peaks = await decodeAudioPeaks(audioPath);
|
|
5552
|
-
writeWaveformCache(cachePath, peaks);
|
|
5553
5593
|
}
|
|
5554
|
-
function
|
|
5555
|
-
return
|
|
5594
|
+
function escapeLeadingDigitIdent(id) {
|
|
5595
|
+
return `\\${id.charCodeAt(0).toString(16)} ${id.slice(1)}`;
|
|
5556
5596
|
}
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
if (
|
|
5563
|
-
}
|
|
5564
|
-
if (!isWaveformCacheDirectory(cacheDir)) {
|
|
5565
|
-
throw new Error("Waveform cache must be a directory, not a symlink");
|
|
5597
|
+
var REGEXP_SPECIALS = /[.*+?^${}()|[\]\\]/g;
|
|
5598
|
+
function fixDigitLeadingIdSelectors(root) {
|
|
5599
|
+
const digitIds = /* @__PURE__ */ new Set();
|
|
5600
|
+
for (const el of root.querySelectorAll("[id]")) {
|
|
5601
|
+
const id = el.getAttribute("id");
|
|
5602
|
+
if (id && /^\d/.test(id)) digitIds.add(id);
|
|
5566
5603
|
}
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
try {
|
|
5574
|
-
rmSync4(stagingDir, { recursive: true, force: true });
|
|
5575
|
-
} catch {
|
|
5604
|
+
if (digitIds.size === 0) return;
|
|
5605
|
+
for (const styleEl of root.querySelectorAll("style")) {
|
|
5606
|
+
let css = styleEl.textContent || "";
|
|
5607
|
+
for (const id of digitIds) {
|
|
5608
|
+
const pattern = new RegExp(`#${id.replace(REGEXP_SPECIALS, "\\$&")}(?![\\w-])`, "g");
|
|
5609
|
+
css = css.replace(pattern, `#${escapeLeadingDigitIdent(id)}`);
|
|
5576
5610
|
}
|
|
5611
|
+
styleEl.textContent = css;
|
|
5577
5612
|
}
|
|
5578
5613
|
}
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
const isVideo = VIDEO_EXT.test(filePath);
|
|
5585
|
-
const isAudio = AUDIO_EXT.test(filePath);
|
|
5586
|
-
if (!isVideo && !isAudio) {
|
|
5587
|
-
return { ok: true };
|
|
5588
|
-
}
|
|
5589
|
-
const ffprobe = findFfBinary("ffprobe") ?? (runner === defaultRunner ? void 0 : "ffprobe");
|
|
5590
|
-
if (!ffprobe) return { ok: true, unchecked: FFPROBE_MISSING };
|
|
5591
|
-
const result = runner(
|
|
5592
|
-
ffprobe,
|
|
5593
|
-
["-v", "error", "-show_entries", "stream=codec_type", "-of", "json", "--", filePath],
|
|
5594
|
-
{ windowsHide: true }
|
|
5595
|
-
);
|
|
5596
|
-
if (result.error && process.env[FFPROBE_PATH_ENV]?.trim()) {
|
|
5597
|
-
return {
|
|
5598
|
-
ok: false,
|
|
5599
|
-
reason: `${FFPROBE_PATH_ENV} names "${ffprobe}", which cannot run: fix it or unset it`
|
|
5600
|
-
};
|
|
5601
|
-
}
|
|
5602
|
-
if (result.error?.code === "ENOENT") {
|
|
5603
|
-
return { ok: true, unchecked: FFPROBE_MISSING };
|
|
5604
|
-
}
|
|
5605
|
-
if (result.status !== 0) {
|
|
5606
|
-
return { ok: false, reason: "ffprobe failed to read the media file" };
|
|
5614
|
+
function extractFullDocumentParts(rawHtml, compPath, projectDir) {
|
|
5615
|
+
const { document: doc } = parseHTML(rawHtml);
|
|
5616
|
+
const rewriteTargets = [doc.head, doc.body].filter(Boolean);
|
|
5617
|
+
for (const target of rewriteTargets) {
|
|
5618
|
+
rewriteRelativePaths(target, compPath, projectDir);
|
|
5607
5619
|
}
|
|
5608
|
-
|
|
5620
|
+
fixDigitLeadingIdSelectors(doc);
|
|
5621
|
+
const headContent = doc.head?.innerHTML ?? "";
|
|
5622
|
+
const bodyContent = doc.body?.innerHTML ?? "";
|
|
5623
|
+
const htmlEl = doc.documentElement;
|
|
5624
|
+
const htmlAttrs = extractElementAttrs(htmlEl);
|
|
5625
|
+
const bodyAttrs = doc.body ? extractElementAttrs(doc.body) : "";
|
|
5626
|
+
return { headContent, bodyContent, htmlAttrs, bodyAttrs };
|
|
5609
5627
|
}
|
|
5610
|
-
function
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5628
|
+
function extractTemplateInnerHtml(rawComp) {
|
|
5629
|
+
const { document: doc } = parseHTML(rawComp);
|
|
5630
|
+
const template = doc.querySelector("template");
|
|
5631
|
+
return template ? template.innerHTML : null;
|
|
5632
|
+
}
|
|
5633
|
+
function escapeAttrValue(value) {
|
|
5634
|
+
return value.replace(/&/g, "&").replace(/"/g, """);
|
|
5635
|
+
}
|
|
5636
|
+
function extractElementAttrs(el) {
|
|
5637
|
+
const parts = [];
|
|
5638
|
+
for (let i = 0; i < el.attributes.length; i++) {
|
|
5639
|
+
const attr = el.attributes[i];
|
|
5640
|
+
if (attr.value === "") {
|
|
5641
|
+
parts.push(attr.name);
|
|
5642
|
+
} else {
|
|
5643
|
+
parts.push(`${attr.name}="${escapeAttrValue(attr.value)}"`);
|
|
5621
5644
|
}
|
|
5622
|
-
return { ok: true };
|
|
5623
|
-
} catch {
|
|
5624
|
-
return { ok: false, reason: "ffprobe returned unreadable media metadata" };
|
|
5625
5645
|
}
|
|
5646
|
+
return parts.join(" ");
|
|
5626
5647
|
}
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5648
|
+
var NON_RENDERED_TAGS = /* @__PURE__ */ new Set(["SCRIPT", "STYLE", "LINK", "META", "TEMPLATE", "NOSCRIPT"]);
|
|
5649
|
+
function promoteTemplateCompositionId(rawComp, body) {
|
|
5650
|
+
let templateCompositionId;
|
|
5651
|
+
for (const tag of rawComp.matchAll(/<template\b[^>]*/gi)) {
|
|
5652
|
+
const id = /\bdata-composition-id\s*=\s*["']([^"']+)["']/i.exec(tag[0] ?? "")?.[1];
|
|
5653
|
+
if (id) {
|
|
5654
|
+
templateCompositionId = id;
|
|
5655
|
+
break;
|
|
5656
|
+
}
|
|
5635
5657
|
}
|
|
5658
|
+
if (!templateCompositionId) return;
|
|
5659
|
+
if (body.querySelector("[data-composition-id]")) return;
|
|
5660
|
+
const root = Array.from(body.children).find((el) => !NON_RENDERED_TAGS.has(el.tagName));
|
|
5661
|
+
root?.setAttribute("data-composition-id", templateCompositionId);
|
|
5636
5662
|
}
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5663
|
+
function tagRootCompositionFile(bodyHtml, compPath) {
|
|
5664
|
+
const match = bodyHtml.match(/<[a-zA-Z][^>]*\bdata-composition-id=/);
|
|
5665
|
+
if (match?.index == null) return bodyHtml;
|
|
5666
|
+
const tagEnd = bodyHtml.indexOf(">", match.index);
|
|
5667
|
+
if (tagEnd === -1) return bodyHtml;
|
|
5668
|
+
if (bodyHtml.slice(match.index, tagEnd).includes("data-composition-file")) return bodyHtml;
|
|
5669
|
+
return bodyHtml.slice(0, tagEnd) + ` data-composition-file="${compPath}"` + bodyHtml.slice(tagEnd);
|
|
5640
5670
|
}
|
|
5641
|
-
function
|
|
5642
|
-
return (
|
|
5671
|
+
function rootHeadContent(rootHtml) {
|
|
5672
|
+
return rootHtml.match(/<head[^>]*>([\s\S]*?)<\/head>/i)?.[1] ?? "";
|
|
5643
5673
|
}
|
|
5644
|
-
function
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
const
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
}
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
while (true) {
|
|
5675
|
-
try {
|
|
5676
|
-
readFileSync7(candidate);
|
|
5677
|
-
} catch (error) {
|
|
5678
|
-
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
5679
|
-
return candidate;
|
|
5680
|
-
}
|
|
5681
|
-
throw error;
|
|
5682
|
-
}
|
|
5683
|
-
candidate = join42(backupDir, `${base}-${counter}`);
|
|
5684
|
-
counter += 1;
|
|
5685
|
-
}
|
|
5686
|
-
}
|
|
5687
|
-
function pruneBackups(backupDir, backupKey, keepPerFile) {
|
|
5688
|
-
const keep = Math.max(1, Math.floor(keepPerFile));
|
|
5689
|
-
const suffix = `-${backupKey}`;
|
|
5690
|
-
const numberedSuffix = new RegExp(`-${backupKey}-\\d+$`);
|
|
5691
|
-
const matches = readdirSync4(backupDir).filter((name) => name.endsWith(suffix) || numberedSuffix.test(name)).map((name) => join42(backupDir, name)).sort((a, b) => {
|
|
5692
|
-
return b.localeCompare(a);
|
|
5693
|
-
});
|
|
5694
|
-
for (const file of matches.slice(keep)) {
|
|
5695
|
-
try {
|
|
5696
|
-
unlinkSync(file);
|
|
5697
|
-
} catch {
|
|
5698
|
-
}
|
|
5699
|
-
}
|
|
5700
|
-
}
|
|
5701
|
-
var PROJECT_DIR_MISSING = { error: "not found", why: "project_dir_missing" };
|
|
5702
|
-
var projectDirMissing = (c) => c.json(PROJECT_DIR_MISSING, 404);
|
|
5703
|
-
function replaceWithProjectDirMissing(c, hostHeaders) {
|
|
5704
|
-
hostHeaders.delete("content-type");
|
|
5705
|
-
c.res = void 0;
|
|
5706
|
-
c.res = Response.json(PROJECT_DIR_MISSING, { status: 404, headers: hostHeaders });
|
|
5707
|
-
}
|
|
5708
|
-
function applyFileMutations(projectDir, mutations, requestToken, writeFile2 = (path, content) => replaceFileAtomically(path, content, statSync22(path).mode)) {
|
|
5709
|
-
const prepared = mutations.map((mutation) => ({
|
|
5710
|
-
...mutation,
|
|
5711
|
-
before: mutation.before ?? readFileSync23(mutation.absPath, "utf-8")
|
|
5712
|
-
}));
|
|
5713
|
-
const results = [];
|
|
5714
|
-
const attempted = [];
|
|
5715
|
-
for (const mutation of prepared)
|
|
5716
|
-
assertExpectedVersion(mutation, readFileSync23(mutation.absPath, "utf-8"));
|
|
5717
|
-
try {
|
|
5718
|
-
for (const mutation of prepared) {
|
|
5719
|
-
results.push(applyOneMutation(projectDir, mutation, requestToken, writeFile2, attempted));
|
|
5720
|
-
}
|
|
5721
|
-
return results;
|
|
5722
|
-
} catch (error) {
|
|
5723
|
-
const rollbackErrors = [];
|
|
5724
|
-
for (const mutation of attempted.reverse()) {
|
|
5725
|
-
try {
|
|
5726
|
-
if (!mutation.written || readFileSync23(mutation.absPath, "utf-8") === mutation.after)
|
|
5727
|
-
writeFile2(mutation.absPath, mutation.before, "utf-8");
|
|
5728
|
-
clearFileWriteReceipt(mutation.absPath, mutation.version, mutation.writeToken);
|
|
5729
|
-
} catch (rollbackError) {
|
|
5730
|
-
rollbackErrors.push(rollbackError);
|
|
5731
|
-
}
|
|
5732
|
-
}
|
|
5733
|
-
if (rollbackErrors.length > 0) {
|
|
5734
|
-
throw new AggregateError(
|
|
5735
|
-
[error, ...rollbackErrors],
|
|
5736
|
-
"File mutation failed and rollback did not complete"
|
|
5737
|
-
);
|
|
5738
|
-
}
|
|
5739
|
-
throw error;
|
|
5674
|
+
function buildSubCompositionHtml(projectDir, compPath, runtimeUrl, baseHref, rawOverride) {
|
|
5675
|
+
const compFile = join23(projectDir, compPath);
|
|
5676
|
+
if (!existsSync3(compFile)) return null;
|
|
5677
|
+
const rawComp = rawOverride ?? readFileSync7(compFile, "utf-8");
|
|
5678
|
+
let compHeadContent = "";
|
|
5679
|
+
let rewrittenContent;
|
|
5680
|
+
let htmlAttrs = "";
|
|
5681
|
+
let bodyAttrs = "";
|
|
5682
|
+
const templateInner = extractTemplateInnerHtml(rawComp);
|
|
5683
|
+
if (templateInner != null) {
|
|
5684
|
+
const { document: contentDoc } = parseHTML(
|
|
5685
|
+
`<!DOCTYPE html><html><head></head><body>${templateInner}</body></html>`
|
|
5686
|
+
);
|
|
5687
|
+
rewriteRelativePaths(contentDoc, compPath, projectDir);
|
|
5688
|
+
fixDigitLeadingIdSelectors(contentDoc);
|
|
5689
|
+
promoteTemplateCompositionId(rawComp, contentDoc.body);
|
|
5690
|
+
rewrittenContent = contentDoc.body.innerHTML || templateInner;
|
|
5691
|
+
} else if (isFullHtmlDocument(rawComp)) {
|
|
5692
|
+
const parts = extractFullDocumentParts(rawComp, compPath, projectDir);
|
|
5693
|
+
compHeadContent = parts.headContent;
|
|
5694
|
+
rewrittenContent = parts.bodyContent;
|
|
5695
|
+
htmlAttrs = parts.htmlAttrs;
|
|
5696
|
+
bodyAttrs = parts.bodyAttrs;
|
|
5697
|
+
} else {
|
|
5698
|
+
const { document: contentDoc } = parseHTML(
|
|
5699
|
+
`<!DOCTYPE html><html><head></head><body>${rawComp}</body></html>`
|
|
5700
|
+
);
|
|
5701
|
+
rewriteRelativePaths(contentDoc, compPath, projectDir);
|
|
5702
|
+
fixDigitLeadingIdSelectors(contentDoc);
|
|
5703
|
+
rewrittenContent = contentDoc.body.innerHTML || rawComp;
|
|
5740
5704
|
}
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5705
|
+
rewrittenContent = stripEmbeddedRuntimeScripts(rewrittenContent);
|
|
5706
|
+
const { document: scriptsDoc } = parseHTML(
|
|
5707
|
+
`<!DOCTYPE html><html><head></head><body>${rewrittenContent}</body></html>`
|
|
5708
|
+
);
|
|
5709
|
+
deferScriptsUntilFonts(scriptsDoc);
|
|
5710
|
+
rewrittenContent = scriptsDoc.body.innerHTML;
|
|
5711
|
+
rewrittenContent = tagRootCompositionFile(rewrittenContent, compPath);
|
|
5712
|
+
const indexPath = join23(projectDir, "index.html");
|
|
5713
|
+
let headContent = "";
|
|
5714
|
+
if (existsSync3(indexPath)) headContent = rootHeadContent(readFileSync7(indexPath, "utf-8"));
|
|
5715
|
+
if (baseHref && !hasBaseElement(headContent)) {
|
|
5716
|
+
headContent = `<base href="${baseHref}">
|
|
5717
|
+
${headContent}`;
|
|
5754
5718
|
}
|
|
5755
|
-
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
writeFile2(mutation.absPath, mutation.after, "utf-8");
|
|
5764
|
-
attempt.written = true;
|
|
5765
|
-
recordFileWriteReceipt(mutation.absPath, {
|
|
5766
|
-
path: mutation.sourceFile,
|
|
5767
|
-
version,
|
|
5768
|
-
writeToken,
|
|
5769
|
-
overwrote: before
|
|
5770
|
-
});
|
|
5771
|
-
return {
|
|
5772
|
-
...mutation,
|
|
5773
|
-
before,
|
|
5774
|
-
changed: true,
|
|
5775
|
-
backupPath: backupPathForResponse(projectDir, backup.backupPath),
|
|
5776
|
-
version,
|
|
5777
|
-
writeToken
|
|
5778
|
-
};
|
|
5779
|
-
}
|
|
5780
|
-
var FileChangedError = class extends Error {
|
|
5781
|
-
constructor(sourceFile) {
|
|
5782
|
-
super("file changed since the timeline was read");
|
|
5783
|
-
this.sourceFile = sourceFile;
|
|
5719
|
+
if (compHeadContent) headContent += `
|
|
5720
|
+
${compHeadContent}`;
|
|
5721
|
+
headContent = stripEmbeddedRuntimeScripts(headContent);
|
|
5722
|
+
headContent += `
|
|
5723
|
+
<script ${RUNTIME_BOOTSTRAP_ATTR}="1" src="${runtimeUrl}"></script>`;
|
|
5724
|
+
if (!headContent.includes("gsap")) {
|
|
5725
|
+
headContent += `
|
|
5726
|
+
<script src="${gsapCdnDist()}gsap.min.js"></script>`;
|
|
5784
5727
|
}
|
|
5785
|
-
|
|
5786
|
-
};
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
}
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
|
|
5728
|
+
const htmlOpen = htmlAttrs ? `<html ${htmlAttrs}>` : "<html>";
|
|
5729
|
+
const bodyOpen = bodyAttrs ? `<body ${bodyAttrs}>` : "<body>";
|
|
5730
|
+
return `<!DOCTYPE html>
|
|
5731
|
+
${htmlOpen}
|
|
5732
|
+
<head>
|
|
5733
|
+
${headContent}
|
|
5734
|
+
</head>
|
|
5735
|
+
${bodyOpen}
|
|
5736
|
+
<script>window.__timelines=window.__timelines||{};</script>
|
|
5737
|
+
${rewrittenContent}
|
|
5738
|
+
</body>
|
|
5739
|
+
</html>`;
|
|
5795
5740
|
}
|
|
5796
|
-
function
|
|
5797
|
-
|
|
5798
|
-
const block = FONT_STYLE_RE.exec(html);
|
|
5799
|
-
if (block) {
|
|
5800
|
-
const next = `${(block[2] ?? "").trim()}
|
|
5801
|
-
${css}`.trim();
|
|
5802
|
-
return html.replace(block[0], () => `<style data-hf-studio-fonts="true">
|
|
5803
|
-
${next}
|
|
5804
|
-
</style>`);
|
|
5805
|
-
}
|
|
5806
|
-
const styleTag = `<style data-hf-studio-fonts="true">
|
|
5807
|
-
${css}
|
|
5808
|
-
</style>`;
|
|
5809
|
-
if (/<\/head>/i.test(html)) return html.replace(/<\/head>/i, () => ` ${styleTag}
|
|
5810
|
-
</head>`);
|
|
5811
|
-
return `${styleTag}
|
|
5812
|
-
${html}`;
|
|
5741
|
+
function hasBaseElement(html) {
|
|
5742
|
+
return parseHTML(html).document.querySelector("base") !== null;
|
|
5813
5743
|
}
|
|
5814
5744
|
var CompositionInsertionError = class extends Error {
|
|
5815
5745
|
constructor(message, status) {
|
|
@@ -5875,7 +5805,7 @@ function canonicalDependency(projectDir, ownerAbs, sourcePath) {
|
|
|
5875
5805
|
validateSourcePath(sourcePath);
|
|
5876
5806
|
return canonicalProjectPath(
|
|
5877
5807
|
projectDir,
|
|
5878
|
-
resolveWithinProject(projectDir,
|
|
5808
|
+
resolveWithinProject(projectDir, relative3(projectDir, resolve5(dirname5(ownerAbs), sourcePath)))
|
|
5879
5809
|
);
|
|
5880
5810
|
}
|
|
5881
5811
|
function validateDependencyGraph(projectDir, targetAbs, sourceAbs) {
|
|
@@ -5948,7 +5878,7 @@ function uniqueHostId(root, base) {
|
|
|
5948
5878
|
return `${base}_${suffix}`;
|
|
5949
5879
|
}
|
|
5950
5880
|
function relativeSourcePath(targetAbs, sourceAbs) {
|
|
5951
|
-
return
|
|
5881
|
+
return relative3(dirname5(targetAbs), sourceAbs).split(sep3).join("/");
|
|
5952
5882
|
}
|
|
5953
5883
|
function insertCompositionIntoSource(input) {
|
|
5954
5884
|
const targetAbs = canonicalProjectFile(input.projectDir, input.targetPath);
|
|
@@ -6001,7 +5931,443 @@ function insertCompositionIntoSource(input) {
|
|
|
6001
5931
|
const name = root.hasAttribute("data-duration") ? "data-duration" : "data-composition-duration";
|
|
6002
5932
|
root.setAttribute(name, String(Math.round((input.start + duration) * 100) / 100));
|
|
6003
5933
|
}
|
|
6004
|
-
return { html: document2.toString(), hostId, track, duration };
|
|
5934
|
+
return { html: document2.toString(), hostId, track, duration };
|
|
5935
|
+
}
|
|
5936
|
+
var ROOT_COMPOSITION = "index.html";
|
|
5937
|
+
var COMPOSITION_SRC = /\bdata-composition-src\s*=\s*(["'])(.*?)\1/g;
|
|
5938
|
+
function projectReader(projectDir) {
|
|
5939
|
+
const sources = /* @__PURE__ */ new Map();
|
|
5940
|
+
return (compPath) => {
|
|
5941
|
+
if (!sources.has(compPath)) {
|
|
5942
|
+
const file = resolveWithinProject(projectDir, compPath);
|
|
5943
|
+
let source = null;
|
|
5944
|
+
try {
|
|
5945
|
+
source = file ? readFileSync23(file, "utf-8") : null;
|
|
5946
|
+
} catch {
|
|
5947
|
+
}
|
|
5948
|
+
sources.set(compPath, source);
|
|
5949
|
+
}
|
|
5950
|
+
return sources.get(compPath) ?? null;
|
|
5951
|
+
};
|
|
5952
|
+
}
|
|
5953
|
+
function normalizeSource(src) {
|
|
5954
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(src) || src.startsWith("//")) return null;
|
|
5955
|
+
const path = src.split(/[?#]/)[0]?.replace(/^\.?\//, "") ?? "";
|
|
5956
|
+
return path || null;
|
|
5957
|
+
}
|
|
5958
|
+
function closureOf(read, compPath) {
|
|
5959
|
+
const closure = /* @__PURE__ */ new Set();
|
|
5960
|
+
const visit = (path) => {
|
|
5961
|
+
if (closure.has(path)) return;
|
|
5962
|
+
closure.add(path);
|
|
5963
|
+
for (const match of (read(path) ?? "").matchAll(COMPOSITION_SRC)) {
|
|
5964
|
+
const mounted = normalizeSource(match[2] ?? "");
|
|
5965
|
+
if (mounted) visit(mounted);
|
|
5966
|
+
}
|
|
5967
|
+
};
|
|
5968
|
+
visit(compPath);
|
|
5969
|
+
return closure;
|
|
5970
|
+
}
|
|
5971
|
+
function lengthIsTimeline(projectDir, compPath) {
|
|
5972
|
+
const read = projectReader(projectDir);
|
|
5973
|
+
const documents = /* @__PURE__ */ new Map();
|
|
5974
|
+
const elements = (path, selector) => {
|
|
5975
|
+
let document2 = documents.get(path);
|
|
5976
|
+
if (!document2) documents.set(path, document2 = parseHTML(read(path) ?? "").document);
|
|
5977
|
+
return descendants(document2, selector);
|
|
5978
|
+
};
|
|
5979
|
+
const comp = normalizeSource(compPath) ?? compPath;
|
|
5980
|
+
const unsized = (path) => {
|
|
5981
|
+
const [root] = elements(path, "[data-composition-id]");
|
|
5982
|
+
return Boolean(root && !root.hasAttribute("data-duration"));
|
|
5983
|
+
};
|
|
5984
|
+
if (unsized(ROOT_COMPOSITION)) return true;
|
|
5985
|
+
const hosts = [...closureOf(read, ROOT_COMPOSITION)].flatMap(
|
|
5986
|
+
(path) => elements(path, "[data-composition-src]").filter(
|
|
5987
|
+
(host) => normalizeSource(host.getAttribute("data-composition-src") ?? "") === comp
|
|
5988
|
+
)
|
|
5989
|
+
);
|
|
5990
|
+
if (comp === ROOT_COMPOSITION || hosts.length === 0) return unsized(comp);
|
|
5991
|
+
return hosts.some(
|
|
5992
|
+
(host) => !host.hasAttribute("data-duration") && !host.hasAttribute("data-end")
|
|
5993
|
+
);
|
|
5994
|
+
}
|
|
5995
|
+
var inputSignatures = /* @__PURE__ */ new Map();
|
|
5996
|
+
var rootMemos = /* @__PURE__ */ new Map();
|
|
5997
|
+
var sha1 = (text2) => createHash4("sha1").update(text2).digest("hex");
|
|
5998
|
+
function rootHashes(read) {
|
|
5999
|
+
const source = read(ROOT_COMPOSITION) ?? "";
|
|
6000
|
+
return { root: sha1(source), head: sha1(rootHeadContent(source)) };
|
|
6001
|
+
}
|
|
6002
|
+
function compositionInputSignature(projectDir, compPath, projectSignature) {
|
|
6003
|
+
const key = `${projectDir}\0${compPath}`;
|
|
6004
|
+
const known = inputSignatures.get(key);
|
|
6005
|
+
if (known?.projectSignature === projectSignature) return known.inputSignature;
|
|
6006
|
+
const read = projectReader(projectDir);
|
|
6007
|
+
const comp = normalizeSource(compPath) ?? compPath;
|
|
6008
|
+
const inputs = closureOf(read, comp).add(ROOT_COMPOSITION);
|
|
6009
|
+
const excluded = new Set(
|
|
6010
|
+
[...closureOf(read, ROOT_COMPOSITION)].filter((path) => !inputs.has(path))
|
|
6011
|
+
);
|
|
6012
|
+
let inputSignature;
|
|
6013
|
+
if (comp === ROOT_COMPOSITION) {
|
|
6014
|
+
inputSignature = createProjectSignature(projectDir, excluded);
|
|
6015
|
+
} else {
|
|
6016
|
+
const hashes = rootHashes(read);
|
|
6017
|
+
if (!rootMemos.has(projectDir)) rootMemos.set(projectDir, { ...hashes, affected: null });
|
|
6018
|
+
inputSignature = `${createProjectSignature(projectDir, excluded.add(ROOT_COMPOSITION))}:${hashes.head}`;
|
|
6019
|
+
}
|
|
6020
|
+
inputSignatures.set(key, { projectSignature, inputSignature });
|
|
6021
|
+
return inputSignature;
|
|
6022
|
+
}
|
|
6023
|
+
function compositionsAffectedBy(projectDir, changedPath) {
|
|
6024
|
+
const changed = changedPath.replace(/\\/g, "/");
|
|
6025
|
+
const read = projectReader(projectDir);
|
|
6026
|
+
if (changed === ROOT_COMPOSITION) {
|
|
6027
|
+
const now = rootHashes(read);
|
|
6028
|
+
const memo = rootMemos.get(projectDir);
|
|
6029
|
+
if (memo?.root === now.root) return memo.affected;
|
|
6030
|
+
const affected = memo?.head === now.head ? [ROOT_COMPOSITION] : null;
|
|
6031
|
+
rootMemos.set(projectDir, { ...now, affected });
|
|
6032
|
+
return affected;
|
|
6033
|
+
}
|
|
6034
|
+
const mounted = closureOf(read, ROOT_COMPOSITION);
|
|
6035
|
+
if (!mounted.has(changed)) return null;
|
|
6036
|
+
return [...mounted].filter((path) => closureOf(read, path).has(changed));
|
|
6037
|
+
}
|
|
6038
|
+
var SAMPLE_RATE = 4e3;
|
|
6039
|
+
var PEAK_COUNT = 4e3;
|
|
6040
|
+
var WAVEFORM_CACHE_VERSION = "v2";
|
|
6041
|
+
function buildWaveformCacheKey(assetPath, fingerprint) {
|
|
6042
|
+
const name = assetPath.replace(/[/\\]/g, "_");
|
|
6043
|
+
if (!fingerprint) return `${WAVEFORM_CACHE_VERSION}_${name}.json`;
|
|
6044
|
+
const stamp = `${fingerprint.size}-${Math.round(fingerprint.mtimeMs)}`;
|
|
6045
|
+
return `${WAVEFORM_CACHE_VERSION}_${name}_${stamp}.json`;
|
|
6046
|
+
}
|
|
6047
|
+
function computePeaks(floats, count) {
|
|
6048
|
+
const step = floats.length / count;
|
|
6049
|
+
const peaks = [];
|
|
6050
|
+
for (let i = 0; i < count; i++) {
|
|
6051
|
+
const start = Math.floor(i * step);
|
|
6052
|
+
const end = Math.min(Math.floor((i + 1) * step), floats.length);
|
|
6053
|
+
let max = 0;
|
|
6054
|
+
for (let j = start; j < end; j++) {
|
|
6055
|
+
const abs = Math.abs(floats[j] ?? 0);
|
|
6056
|
+
if (abs > max) max = abs;
|
|
6057
|
+
}
|
|
6058
|
+
peaks.push(max);
|
|
6059
|
+
}
|
|
6060
|
+
const maxPeak = Math.max(...peaks, 1e-3);
|
|
6061
|
+
return peaks.map((p) => p / maxPeak);
|
|
6062
|
+
}
|
|
6063
|
+
function decodeAudioPeaks(audioPath) {
|
|
6064
|
+
return new Promise((resolvePromise, reject) => {
|
|
6065
|
+
const proc = spawn(
|
|
6066
|
+
findFfBinary("ffmpeg") ?? "ffmpeg",
|
|
6067
|
+
[
|
|
6068
|
+
"-i",
|
|
6069
|
+
audioPath,
|
|
6070
|
+
"-af",
|
|
6071
|
+
"atrim=start_sample=1152",
|
|
6072
|
+
"-f",
|
|
6073
|
+
"f32le",
|
|
6074
|
+
"-ac",
|
|
6075
|
+
"1",
|
|
6076
|
+
"-ar",
|
|
6077
|
+
String(SAMPLE_RATE),
|
|
6078
|
+
"-vn",
|
|
6079
|
+
"pipe:1"
|
|
6080
|
+
],
|
|
6081
|
+
{ stdio: ["ignore", "pipe", "ignore"], windowsHide: true }
|
|
6082
|
+
);
|
|
6083
|
+
const chunks = [];
|
|
6084
|
+
proc.stdout?.on("data", (chunk) => chunks.push(chunk));
|
|
6085
|
+
proc.on("close", (code) => {
|
|
6086
|
+
if (code !== 0 && chunks.length === 0) {
|
|
6087
|
+
reject(new Error(`ffmpeg exited with code ${code}`));
|
|
6088
|
+
return;
|
|
6089
|
+
}
|
|
6090
|
+
const buf = Buffer.concat(chunks);
|
|
6091
|
+
const numSamples = Math.floor(buf.length / 4);
|
|
6092
|
+
if (numSamples === 0) {
|
|
6093
|
+
reject(new Error("ffmpeg produced no audio samples"));
|
|
6094
|
+
return;
|
|
6095
|
+
}
|
|
6096
|
+
const ab = buf.buffer.slice(buf.byteOffset, buf.byteOffset + numSamples * 4);
|
|
6097
|
+
resolvePromise(computePeaks(new Float32Array(ab), PEAK_COUNT));
|
|
6098
|
+
});
|
|
6099
|
+
proc.on("error", reject);
|
|
6100
|
+
});
|
|
6101
|
+
}
|
|
6102
|
+
async function generateWaveformCache(projectDir, assetPath) {
|
|
6103
|
+
const audioPath = join32(projectDir, assetPath);
|
|
6104
|
+
if (!existsSync32(audioPath)) return;
|
|
6105
|
+
const stats = statSync4(audioPath);
|
|
6106
|
+
const cacheDir = join32(projectDir, ".waveform-cache");
|
|
6107
|
+
const cachePath = join32(cacheDir, buildWaveformCacheKey(assetPath, stats));
|
|
6108
|
+
if (isWaveformCacheDirectory(cacheDir) && existsSync32(cachePath)) return;
|
|
6109
|
+
const peaks = await decodeAudioPeaks(audioPath);
|
|
6110
|
+
writeWaveformCache(cachePath, peaks);
|
|
6111
|
+
}
|
|
6112
|
+
function isWaveformCacheDirectory(cacheDir) {
|
|
6113
|
+
return lstatSync3(cacheDir, { throwIfNoEntry: false })?.isDirectory() ?? false;
|
|
6114
|
+
}
|
|
6115
|
+
function writeWaveformCache(cachePath, peaks) {
|
|
6116
|
+
const cacheDir = dirname23(cachePath);
|
|
6117
|
+
try {
|
|
6118
|
+
mkdirSync5(cacheDir, { mode: 448 });
|
|
6119
|
+
} catch (error) {
|
|
6120
|
+
if (!(error instanceof Error && "code" in error && error.code === "EEXIST")) throw error;
|
|
6121
|
+
}
|
|
6122
|
+
if (!isWaveformCacheDirectory(cacheDir)) {
|
|
6123
|
+
throw new Error("Waveform cache must be a directory, not a symlink");
|
|
6124
|
+
}
|
|
6125
|
+
const stagingDir = mkdtempSync(join32(cacheDir, ".waveform-"));
|
|
6126
|
+
try {
|
|
6127
|
+
const stagingPath = join32(stagingDir, "peaks.json");
|
|
6128
|
+
writeFileSync4(stagingPath, JSON.stringify(peaks), { flag: "wx" });
|
|
6129
|
+
renameSync3(stagingPath, cachePath);
|
|
6130
|
+
} finally {
|
|
6131
|
+
try {
|
|
6132
|
+
rmSync4(stagingDir, { recursive: true, force: true });
|
|
6133
|
+
} catch {
|
|
6134
|
+
}
|
|
6135
|
+
}
|
|
6136
|
+
}
|
|
6137
|
+
var VIDEO_EXT = /\.(mp4|webm|mov|mkv|avi|m4v|mxf|mts|m2ts|ts)$/i;
|
|
6138
|
+
var AUDIO_EXT = /\.(mp3|wav|ogg|m4a|aac|flac)$/i;
|
|
6139
|
+
var defaultRunner = spawnSync;
|
|
6140
|
+
var FFPROBE_MISSING = "not checked: ffprobe was not found. Install FFmpeg or set HYPERFRAMES_FFPROBE_PATH.";
|
|
6141
|
+
function validateUploadedMedia(filePath, runner = defaultRunner) {
|
|
6142
|
+
const isVideo = VIDEO_EXT.test(filePath);
|
|
6143
|
+
const isAudio = AUDIO_EXT.test(filePath);
|
|
6144
|
+
if (!isVideo && !isAudio) {
|
|
6145
|
+
return { ok: true };
|
|
6146
|
+
}
|
|
6147
|
+
const ffprobe = findFfBinary("ffprobe") ?? (runner === defaultRunner ? void 0 : "ffprobe");
|
|
6148
|
+
if (!ffprobe) return { ok: true, unchecked: FFPROBE_MISSING };
|
|
6149
|
+
const result = runner(
|
|
6150
|
+
ffprobe,
|
|
6151
|
+
["-v", "error", "-show_entries", "stream=codec_type", "-of", "json", "--", filePath],
|
|
6152
|
+
{ windowsHide: true }
|
|
6153
|
+
);
|
|
6154
|
+
if (result.error && process.env[FFPROBE_PATH_ENV]?.trim()) {
|
|
6155
|
+
return {
|
|
6156
|
+
ok: false,
|
|
6157
|
+
reason: `${FFPROBE_PATH_ENV} names "${ffprobe}", which cannot run: fix it or unset it`
|
|
6158
|
+
};
|
|
6159
|
+
}
|
|
6160
|
+
if (result.error?.code === "ENOENT") {
|
|
6161
|
+
return { ok: true, unchecked: FFPROBE_MISSING };
|
|
6162
|
+
}
|
|
6163
|
+
if (result.status !== 0) {
|
|
6164
|
+
return { ok: false, reason: "ffprobe failed to read the media file" };
|
|
6165
|
+
}
|
|
6166
|
+
return checkStreams(String(result.stdout || "{}"), isVideo, isAudio);
|
|
6167
|
+
}
|
|
6168
|
+
function checkStreams(stdout, isVideo, isAudio) {
|
|
6169
|
+
try {
|
|
6170
|
+
const parsed = JSON.parse(stdout);
|
|
6171
|
+
const streams = parsed.streams ?? [];
|
|
6172
|
+
const hasVideo = streams.some((stream) => stream.codec_type === "video");
|
|
6173
|
+
const hasAudio = streams.some((stream) => stream.codec_type === "audio");
|
|
6174
|
+
if (isVideo && !hasVideo) {
|
|
6175
|
+
return { ok: false, reason: "no supported video stream found" };
|
|
6176
|
+
}
|
|
6177
|
+
if (isAudio && !hasAudio) {
|
|
6178
|
+
return { ok: false, reason: "no supported audio stream found" };
|
|
6179
|
+
}
|
|
6180
|
+
return { ok: true };
|
|
6181
|
+
} catch {
|
|
6182
|
+
return { ok: false, reason: "ffprobe returned unreadable media metadata" };
|
|
6183
|
+
}
|
|
6184
|
+
}
|
|
6185
|
+
function validateUploadedMediaBuffer(fileName, buffer, runner = defaultRunner) {
|
|
6186
|
+
const tempDir = mkdtempSync2(join42(tmpdir2(), "hyperframes-upload-"));
|
|
6187
|
+
const tempPath = join42(tempDir, basename2(fileName));
|
|
6188
|
+
try {
|
|
6189
|
+
writeFileSync23(tempPath, buffer);
|
|
6190
|
+
return validateUploadedMedia(tempPath, runner);
|
|
6191
|
+
} finally {
|
|
6192
|
+
rmSync22(tempDir, { recursive: true, force: true });
|
|
6193
|
+
}
|
|
6194
|
+
}
|
|
6195
|
+
var DEFAULT_KEEP_PER_FILE = 10;
|
|
6196
|
+
function backupKeyForPath(path) {
|
|
6197
|
+
return Buffer2.from(path, "utf-8").toString("base64url");
|
|
6198
|
+
}
|
|
6199
|
+
function timestampPrefix() {
|
|
6200
|
+
return (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
6201
|
+
}
|
|
6202
|
+
function backupPathForResponse(projectDir, backupPath) {
|
|
6203
|
+
if (!backupPath) return null;
|
|
6204
|
+
const rel = relative22(projectDir, backupPath);
|
|
6205
|
+
if (!rel || rel.startsWith("..")) return null;
|
|
6206
|
+
return rel.split("\\").join("/");
|
|
6207
|
+
}
|
|
6208
|
+
function snapshotBeforeWrite(projectDir, absPath, options = {}) {
|
|
6209
|
+
if (!isSafePath(projectDir, absPath)) return { backupPath: null };
|
|
6210
|
+
try {
|
|
6211
|
+
const content = readFileSync32(absPath);
|
|
6212
|
+
const relativePath = relative22(projectDir, absPath);
|
|
6213
|
+
const backupDir = join52(projectDir, ".hyperframes", "backup");
|
|
6214
|
+
mkdirWithinProject(projectDir, backupDir);
|
|
6215
|
+
const backupKey = backupKeyForPath(relativePath);
|
|
6216
|
+
const backupPath = nextBackupPath(backupDir, backupKey);
|
|
6217
|
+
writeFileSync32(backupPath, content);
|
|
6218
|
+
pruneBackups(backupDir, backupKey, options.keepPerFile ?? DEFAULT_KEEP_PER_FILE);
|
|
6219
|
+
return { backupPath };
|
|
6220
|
+
} catch (error) {
|
|
6221
|
+
if (isProjectRootMissing(error)) throw error;
|
|
6222
|
+
if (error && typeof error === "object" && "code" in error && (error.code === "ENOENT" || error.code === "EISDIR")) {
|
|
6223
|
+
return { backupPath: null };
|
|
6224
|
+
}
|
|
6225
|
+
return { backupPath: null, error: error instanceof Error ? error.message : String(error) };
|
|
6226
|
+
}
|
|
6227
|
+
}
|
|
6228
|
+
function nextBackupPath(backupDir, backupKey) {
|
|
6229
|
+
const base = `${timestampPrefix()}-${backupKey}`;
|
|
6230
|
+
let candidate = join52(backupDir, base);
|
|
6231
|
+
let counter = 2;
|
|
6232
|
+
while (true) {
|
|
6233
|
+
try {
|
|
6234
|
+
readFileSync32(candidate);
|
|
6235
|
+
} catch (error) {
|
|
6236
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
6237
|
+
return candidate;
|
|
6238
|
+
}
|
|
6239
|
+
throw error;
|
|
6240
|
+
}
|
|
6241
|
+
candidate = join52(backupDir, `${base}-${counter}`);
|
|
6242
|
+
counter += 1;
|
|
6243
|
+
}
|
|
6244
|
+
}
|
|
6245
|
+
function pruneBackups(backupDir, backupKey, keepPerFile) {
|
|
6246
|
+
const keep = Math.max(1, Math.floor(keepPerFile));
|
|
6247
|
+
const suffix = `-${backupKey}`;
|
|
6248
|
+
const numberedSuffix = new RegExp(`-${backupKey}-\\d+$`);
|
|
6249
|
+
const matches = readdirSync4(backupDir).filter((name) => name.endsWith(suffix) || numberedSuffix.test(name)).map((name) => join52(backupDir, name)).sort((a, b) => {
|
|
6250
|
+
return b.localeCompare(a);
|
|
6251
|
+
});
|
|
6252
|
+
for (const file of matches.slice(keep)) {
|
|
6253
|
+
try {
|
|
6254
|
+
unlinkSync(file);
|
|
6255
|
+
} catch {
|
|
6256
|
+
}
|
|
6257
|
+
}
|
|
6258
|
+
}
|
|
6259
|
+
var PROJECT_DIR_MISSING = { error: "not found", why: "project_dir_missing" };
|
|
6260
|
+
var projectDirMissing = (c) => c.json(PROJECT_DIR_MISSING, 404);
|
|
6261
|
+
function replaceWithProjectDirMissing(c, hostHeaders) {
|
|
6262
|
+
hostHeaders.delete("content-type");
|
|
6263
|
+
c.res = void 0;
|
|
6264
|
+
c.res = Response.json(PROJECT_DIR_MISSING, { status: 404, headers: hostHeaders });
|
|
6265
|
+
}
|
|
6266
|
+
function applyFileMutations(projectDir, mutations, requestToken, writeFile2 = (path, content) => replaceFileAtomically(path, content, statSync22(path).mode)) {
|
|
6267
|
+
const prepared = mutations.map((mutation) => ({
|
|
6268
|
+
...mutation,
|
|
6269
|
+
before: mutation.before ?? readFileSync42(mutation.absPath, "utf-8")
|
|
6270
|
+
}));
|
|
6271
|
+
const results = [];
|
|
6272
|
+
const attempted = [];
|
|
6273
|
+
for (const mutation of prepared)
|
|
6274
|
+
assertExpectedVersion(mutation, readFileSync42(mutation.absPath, "utf-8"));
|
|
6275
|
+
try {
|
|
6276
|
+
for (const mutation of prepared) {
|
|
6277
|
+
results.push(applyOneMutation(projectDir, mutation, requestToken, writeFile2, attempted));
|
|
6278
|
+
}
|
|
6279
|
+
return results;
|
|
6280
|
+
} catch (error) {
|
|
6281
|
+
const rollbackErrors = [];
|
|
6282
|
+
for (const mutation of attempted.reverse()) {
|
|
6283
|
+
try {
|
|
6284
|
+
if (!mutation.written || readFileSync42(mutation.absPath, "utf-8") === mutation.after)
|
|
6285
|
+
writeFile2(mutation.absPath, mutation.before, "utf-8");
|
|
6286
|
+
clearFileWriteReceipt(mutation.absPath, mutation.version, mutation.writeToken);
|
|
6287
|
+
} catch (rollbackError) {
|
|
6288
|
+
rollbackErrors.push(rollbackError);
|
|
6289
|
+
}
|
|
6290
|
+
}
|
|
6291
|
+
if (rollbackErrors.length > 0) {
|
|
6292
|
+
throw new AggregateError(
|
|
6293
|
+
[error, ...rollbackErrors],
|
|
6294
|
+
"File mutation failed and rollback did not complete"
|
|
6295
|
+
);
|
|
6296
|
+
}
|
|
6297
|
+
throw error;
|
|
6298
|
+
}
|
|
6299
|
+
}
|
|
6300
|
+
function applyOneMutation(projectDir, mutation, requestToken, writeFile2, attempted) {
|
|
6301
|
+
const current = readFileSync42(mutation.absPath, "utf-8");
|
|
6302
|
+
assertExpectedVersion(mutation, current);
|
|
6303
|
+
if (mutation.after === mutation.before) {
|
|
6304
|
+
return {
|
|
6305
|
+
...mutation,
|
|
6306
|
+
before: current,
|
|
6307
|
+
changed: false,
|
|
6308
|
+
backupPath: null,
|
|
6309
|
+
version: fileContentVersion(mutation.before),
|
|
6310
|
+
writeToken: null
|
|
6311
|
+
};
|
|
6312
|
+
}
|
|
6313
|
+
const backup = snapshotBeforeWrite(projectDir, mutation.absPath);
|
|
6314
|
+
if (backup.error) throw new Error(`backup failed: ${backup.error}`);
|
|
6315
|
+
assertExpectedVersion(mutation, readFileSync42(mutation.absPath, "utf-8"));
|
|
6316
|
+
const before = current;
|
|
6317
|
+
const version = fileContentVersion(mutation.after);
|
|
6318
|
+
const writeToken = createWriteToken(requestToken);
|
|
6319
|
+
const attempt = { ...mutation, before, version, writeToken, written: false };
|
|
6320
|
+
attempted.push(attempt);
|
|
6321
|
+
writeFile2(mutation.absPath, mutation.after, "utf-8");
|
|
6322
|
+
attempt.written = true;
|
|
6323
|
+
recordFileWriteReceipt(mutation.absPath, {
|
|
6324
|
+
path: mutation.sourceFile,
|
|
6325
|
+
version,
|
|
6326
|
+
writeToken,
|
|
6327
|
+
overwrote: before
|
|
6328
|
+
});
|
|
6329
|
+
return {
|
|
6330
|
+
...mutation,
|
|
6331
|
+
before,
|
|
6332
|
+
changed: true,
|
|
6333
|
+
backupPath: backupPathForResponse(projectDir, backup.backupPath),
|
|
6334
|
+
version,
|
|
6335
|
+
writeToken
|
|
6336
|
+
};
|
|
6337
|
+
}
|
|
6338
|
+
var FileChangedError = class extends Error {
|
|
6339
|
+
constructor(sourceFile) {
|
|
6340
|
+
super("file changed since the timeline was read");
|
|
6341
|
+
this.sourceFile = sourceFile;
|
|
6342
|
+
}
|
|
6343
|
+
sourceFile;
|
|
6344
|
+
};
|
|
6345
|
+
function assertExpectedVersion(mutation, current) {
|
|
6346
|
+
const stale = mutation.expectedVersion === void 0 ? current !== mutation.before : fileContentVersion(current) !== mutation.expectedVersion;
|
|
6347
|
+
if (stale) throw new FileChangedError(mutation.sourceFile);
|
|
6348
|
+
}
|
|
6349
|
+
var FONT_STYLE_RE = /<style\b[^>]*data-hf-studio-fonts=(["'])true\1[^>]*>([\s\S]*?)<\/style>/i;
|
|
6350
|
+
var ONE_FONT_FACE_RULE = /^@font-face \{(?:[^{}<"'\\]|"(?:[^"\\<\n\r\f]|\\[^<\n\r\f])*"|'(?:[^'\\<\n\r\f]|\\[^<\n\r\f])*')*\}$/;
|
|
6351
|
+
function isStudioFontFaceCss(css) {
|
|
6352
|
+
return typeof css === "string" && ONE_FONT_FACE_RULE.test(css);
|
|
6353
|
+
}
|
|
6354
|
+
function ensureStudioFontFaceCss(html, css) {
|
|
6355
|
+
if (html.includes(css)) return html;
|
|
6356
|
+
const block = FONT_STYLE_RE.exec(html);
|
|
6357
|
+
if (block) {
|
|
6358
|
+
const next = `${(block[2] ?? "").trim()}
|
|
6359
|
+
${css}`.trim();
|
|
6360
|
+
return html.replace(block[0], () => `<style data-hf-studio-fonts="true">
|
|
6361
|
+
${next}
|
|
6362
|
+
</style>`);
|
|
6363
|
+
}
|
|
6364
|
+
const styleTag = `<style data-hf-studio-fonts="true">
|
|
6365
|
+
${css}
|
|
6366
|
+
</style>`;
|
|
6367
|
+
if (/<\/head>/i.test(html)) return html.replace(/<\/head>/i, () => ` ${styleTag}
|
|
6368
|
+
</head>`);
|
|
6369
|
+
return `${styleTag}
|
|
6370
|
+
${html}`;
|
|
6005
6371
|
}
|
|
6006
6372
|
var differential = (family) => ({
|
|
6007
6373
|
family,
|
|
@@ -6070,7 +6436,7 @@ function requestSubPath(url, route) {
|
|
|
6070
6436
|
return decodeURIComponent(segments.slice(start + routeSegments.length).join("/"));
|
|
6071
6437
|
}
|
|
6072
6438
|
async function loadGsapParser() {
|
|
6073
|
-
return import("./gsapParser-
|
|
6439
|
+
return import("./gsapParser-2OL54XZ5.js");
|
|
6074
6440
|
}
|
|
6075
6441
|
function isDanglingSymlinkInProject(projectDir, lexicalPath) {
|
|
6076
6442
|
if (!isSafePath(projectDir, dirname32(lexicalPath))) return false;
|
|
@@ -6110,7 +6476,7 @@ async function resolveProjectPath(c, adapter, route, opts) {
|
|
|
6110
6476
|
}
|
|
6111
6477
|
return { error: c.json({ error: "forbidden", why: "outside_project" }, 403) };
|
|
6112
6478
|
}
|
|
6113
|
-
if (opts?.mustExist && !
|
|
6479
|
+
if (opts?.mustExist && !existsSync4(absPath)) {
|
|
6114
6480
|
return { error: c.json({ error: "not found" }, 404) };
|
|
6115
6481
|
}
|
|
6116
6482
|
return { project, filePath, absPath };
|
|
@@ -6176,7 +6542,7 @@ function projectHtmlIds(projectDir) {
|
|
|
6176
6542
|
if (!rel.endsWith(".html") || isInHiddenOrVendorDir(rel)) continue;
|
|
6177
6543
|
let html;
|
|
6178
6544
|
try {
|
|
6179
|
-
html =
|
|
6545
|
+
html = readFileSync52(join62(projectDir, rel), "utf-8");
|
|
6180
6546
|
} catch {
|
|
6181
6547
|
continue;
|
|
6182
6548
|
}
|
|
@@ -6205,7 +6571,7 @@ function foldAndCommitElementPatchBatches(projectDir, batches, writeFile2, reque
|
|
|
6205
6571
|
resolvedPaths.add(absPath);
|
|
6206
6572
|
let before;
|
|
6207
6573
|
try {
|
|
6208
|
-
before =
|
|
6574
|
+
before = readFileSync52(absPath, "utf-8");
|
|
6209
6575
|
} catch {
|
|
6210
6576
|
return { error: "not-found", sourceFile: batch.sourceFile };
|
|
6211
6577
|
}
|
|
@@ -6261,7 +6627,7 @@ function commitElementPatchBatchesWithReceipts(c, projectDir, batches) {
|
|
|
6261
6627
|
);
|
|
6262
6628
|
}
|
|
6263
6629
|
function writeFileWithReceipt(c, filePath, absPath, html) {
|
|
6264
|
-
const overwrote =
|
|
6630
|
+
const overwrote = readFileSync52(absPath);
|
|
6265
6631
|
replaceFileAtomically(absPath, html, statSync32(absPath).mode);
|
|
6266
6632
|
const version = fileContentVersion(html);
|
|
6267
6633
|
const writeToken = createWriteToken(c.req.header("X-Hyperframes-Write-Token"));
|
|
@@ -6271,7 +6637,7 @@ function writeFileWithReceipt(c, filePath, absPath, html) {
|
|
|
6271
6637
|
function writeMutationResult(c, projectDir, filePath, absPath, html, original) {
|
|
6272
6638
|
const backup = snapshotBeforeWrite(projectDir, absPath);
|
|
6273
6639
|
if (backup.error) return c.json({ error: `backup failed: ${backup.error}` }, 500);
|
|
6274
|
-
if (
|
|
6640
|
+
if (readFileSync52(absPath, "utf-8") !== original) {
|
|
6275
6641
|
return c.json({ error: "file changed", conflict: true, path: filePath }, 409);
|
|
6276
6642
|
}
|
|
6277
6643
|
const { version } = writeFileWithReceipt(c, filePath, absPath, html);
|
|
@@ -6326,7 +6692,7 @@ function generateCopyPath(projectDir, originalPath) {
|
|
|
6326
6692
|
const cleanBase = copyMatch ? base.slice(0, -copyMatch[0].length) : base;
|
|
6327
6693
|
let num = copyMatch ? copyMatch[1] ? parseInt(copyMatch[1]) + 1 : 2 : 1;
|
|
6328
6694
|
let candidate = num === 1 ? `${cleanBase} (copy)${ext}` : `${cleanBase} (copy ${num})${ext}`;
|
|
6329
|
-
while (
|
|
6695
|
+
while (existsSync4(resolve22(projectDir, candidate))) {
|
|
6330
6696
|
num++;
|
|
6331
6697
|
candidate = `${cleanBase} (copy ${num})${ext}`;
|
|
6332
6698
|
}
|
|
@@ -6335,7 +6701,7 @@ function generateCopyPath(projectDir, originalPath) {
|
|
|
6335
6701
|
function walkFiles(dir, filter) {
|
|
6336
6702
|
const results = [];
|
|
6337
6703
|
for (const entry of readableEntries(dir)) {
|
|
6338
|
-
const full2 =
|
|
6704
|
+
const full2 = join62(dir, entry.name);
|
|
6339
6705
|
if (entry.isDirectory()) {
|
|
6340
6706
|
if (entry.name === "node_modules" || entry.name === ".thumbnails" || entry.name === "renders" || entry.name === ".transcode-cache")
|
|
6341
6707
|
continue;
|
|
@@ -6360,7 +6726,7 @@ function readableEntries(dir) {
|
|
|
6360
6726
|
}
|
|
6361
6727
|
function readableText(file) {
|
|
6362
6728
|
try {
|
|
6363
|
-
return
|
|
6729
|
+
return readFileSync52(file, "utf-8");
|
|
6364
6730
|
} catch (error) {
|
|
6365
6731
|
if (skippable(error)) return null;
|
|
6366
6732
|
throw error;
|
|
@@ -6418,7 +6784,7 @@ function occurrences(text2, part) {
|
|
|
6418
6784
|
}
|
|
6419
6785
|
function projectPaths(root, dir = root, prefix = "", ancestors = /* @__PURE__ */ new Set()) {
|
|
6420
6786
|
return readableEntries(dir).flatMap((entry) => {
|
|
6421
|
-
const [path, full2] = [`${prefix}${entry.name}`,
|
|
6787
|
+
const [path, full2] = [`${prefix}${entry.name}`, join62(dir, entry.name)];
|
|
6422
6788
|
const real = entry.name === "node_modules" ? null : directoryReal(entry, full2);
|
|
6423
6789
|
if (real === null || ancestors.has(real) || !isSafePath(root, full2)) return [path];
|
|
6424
6790
|
return [path, ...projectPaths(root, full2, `${path}/`, /* @__PURE__ */ new Set([...ancestors, real]))];
|
|
@@ -6726,12 +7092,12 @@ function containsRawGsapExpression(value) {
|
|
|
6726
7092
|
return Object.values(value).some(containsRawGsapExpression);
|
|
6727
7093
|
}
|
|
6728
7094
|
async function prepareGsapMutationScript(c, res, firstMutation) {
|
|
6729
|
-
const beforeHtml =
|
|
7095
|
+
const beforeHtml = readFileSync52(res.absPath, "utf-8");
|
|
6730
7096
|
let html = beforeHtml;
|
|
6731
7097
|
let block = extractGsapScriptBlock(html);
|
|
6732
7098
|
if (!block && (firstMutation.type === "add" || firstMutation.type === "add-with-keyframes")) {
|
|
6733
7099
|
const compId = html.match(/data-composition-id="([^"]+)"/)?.[1] ?? "main";
|
|
6734
|
-
const { GSAP_CDN } = await import("./dist-
|
|
7100
|
+
const { GSAP_CDN } = await import("./dist-HVJAGLHF.js");
|
|
6735
7101
|
const bootstrap = [
|
|
6736
7102
|
`<script src="${GSAP_CDN}"></script>`,
|
|
6737
7103
|
"<script>",
|
|
@@ -6801,6 +7167,7 @@ async function applyGsapMutations(c, res, mutations) {
|
|
|
6801
7167
|
const prepared = await prepareGsapMutationScript(c, res, firstMutation);
|
|
6802
7168
|
if (prepared instanceof Response) return prepared;
|
|
6803
7169
|
const { html, beforeHtml, block } = prepared;
|
|
7170
|
+
let lengthIsAuthored;
|
|
6804
7171
|
const initialScript = block.scriptText;
|
|
6805
7172
|
const skippedSelectors = /* @__PURE__ */ new Set();
|
|
6806
7173
|
const respond = (data, status) => status ? c.json(data, status) : c.json(data);
|
|
@@ -6832,7 +7199,9 @@ async function applyGsapMutations(c, res, mutations) {
|
|
|
6832
7199
|
for (const selector of result.skippedSelectors) skippedSelectors.add(selector);
|
|
6833
7200
|
}
|
|
6834
7201
|
if (HOLD_SYNC_MUTATION_TYPES.has(mutation.type)) {
|
|
6835
|
-
|
|
7202
|
+
lengthIsAuthored ??= !lengthIsTimeline(res.project.dir, res.filePath);
|
|
7203
|
+
if (lengthIsAuthored) newScript = trimTrailingKeyframeSpans(previousScript, newScript);
|
|
7204
|
+
newScript = writer === "acorn" ? syncPositionHoldsBeforeKeyframes(newScript, previousScript) : (await loadGsapParser()).syncPositionHoldsBeforeKeyframes(newScript, previousScript);
|
|
6836
7205
|
}
|
|
6837
7206
|
mutationChanges.push(newScript !== previousScript);
|
|
6838
7207
|
block.scriptText = newScript;
|
|
@@ -6840,7 +7209,7 @@ async function applyGsapMutations(c, res, mutations) {
|
|
|
6840
7209
|
const changed = block.scriptText !== initialScript;
|
|
6841
7210
|
const newHtml = changed ? block.replaceScript(block.scriptText) : html;
|
|
6842
7211
|
let backupPath = null;
|
|
6843
|
-
if (
|
|
7212
|
+
if (readFileSync52(res.absPath, "utf-8") !== beforeHtml) {
|
|
6844
7213
|
return c.json({ error: "file changed during GSAP mutation", conflict: true }, 409);
|
|
6845
7214
|
}
|
|
6846
7215
|
if (changed) {
|
|
@@ -7531,7 +7900,7 @@ async function foldAtomicCutFile(c, file, absPath, before, writer) {
|
|
|
7531
7900
|
for (const selector of result.skippedSelectors) skippedSelectors.add(selector);
|
|
7532
7901
|
}
|
|
7533
7902
|
if (script !== block.scriptText) {
|
|
7534
|
-
script = writer === "acorn" ? syncPositionHoldsBeforeKeyframes(script) : (await loadGsapParser()).syncPositionHoldsBeforeKeyframes(script);
|
|
7903
|
+
script = writer === "acorn" ? syncPositionHoldsBeforeKeyframes(script, block.scriptText) : (await loadGsapParser()).syncPositionHoldsBeforeKeyframes(script, block.scriptText);
|
|
7535
7904
|
after = block.replaceScript(script);
|
|
7536
7905
|
}
|
|
7537
7906
|
}
|
|
@@ -7570,9 +7939,9 @@ async function processUploadedFiles(formData, targetDir, projectDir) {
|
|
|
7570
7939
|
const base = dotIdx > 0 ? name.slice(0, dotIdx) : name;
|
|
7571
7940
|
const MAX_COPY_INDEX = 1e4;
|
|
7572
7941
|
let n = 1;
|
|
7573
|
-
if (
|
|
7942
|
+
if (existsSync4(finalPath)) {
|
|
7574
7943
|
n = 2;
|
|
7575
|
-
while (n < MAX_COPY_INDEX &&
|
|
7944
|
+
while (n < MAX_COPY_INDEX && existsSync4(resolve22(targetDir, `${base} (${n})${ext}`))) n++;
|
|
7576
7945
|
if (n >= MAX_COPY_INDEX) {
|
|
7577
7946
|
skipped.push(name);
|
|
7578
7947
|
continue;
|
|
@@ -7606,7 +7975,7 @@ async function processUploadedFiles(formData, targetDir, projectDir) {
|
|
|
7606
7975
|
if (n >= MAX_COPY_INDEX) skipped.push(name);
|
|
7607
7976
|
continue;
|
|
7608
7977
|
}
|
|
7609
|
-
const relativePath = subDir ?
|
|
7978
|
+
const relativePath = subDir ? join62(subDir, finalName) : finalName;
|
|
7610
7979
|
uploaded.push(relativePath);
|
|
7611
7980
|
if (validation.unchecked) unchecked.push({ name: finalName, reason: validation.unchecked });
|
|
7612
7981
|
if (isAudioFile(finalName)) {
|
|
@@ -7639,7 +8008,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
7639
8008
|
if (stat22.size > MAX_TEXT_READ_BYTES) {
|
|
7640
8009
|
return c.json({ error: "too large to read as text", why: "too_large" }, 413);
|
|
7641
8010
|
}
|
|
7642
|
-
const content =
|
|
8011
|
+
const content = readFileSync52(fd);
|
|
7643
8012
|
const version = fileContentVersion(content);
|
|
7644
8013
|
c.header("ETag", version);
|
|
7645
8014
|
if (content.subarray(0, GIT_BINARY_SNIFF_BYTES).includes(0)) {
|
|
@@ -7664,7 +8033,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
7664
8033
|
if (expectedVersion === null && !createOnly) {
|
|
7665
8034
|
let currentContent = null;
|
|
7666
8035
|
try {
|
|
7667
|
-
currentContent =
|
|
8036
|
+
currentContent = readFileSync52(res.absPath);
|
|
7668
8037
|
} catch (error) {
|
|
7669
8038
|
if (!error || typeof error !== "object" || !("code" in error) || error.code !== "ENOENT") {
|
|
7670
8039
|
throw error;
|
|
@@ -7690,7 +8059,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
7690
8059
|
if (!error || typeof error !== "object" || !("code" in error) || error.code !== "EEXIST") {
|
|
7691
8060
|
throw error;
|
|
7692
8061
|
}
|
|
7693
|
-
const currentContent =
|
|
8062
|
+
const currentContent = readFileSync52(res.absPath);
|
|
7694
8063
|
return c.json(
|
|
7695
8064
|
{
|
|
7696
8065
|
error: "file conflict",
|
|
@@ -7720,7 +8089,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
7720
8089
|
);
|
|
7721
8090
|
}
|
|
7722
8091
|
try {
|
|
7723
|
-
const currentContent =
|
|
8092
|
+
const currentContent = readFileSync52(fd);
|
|
7724
8093
|
overwrote = currentContent;
|
|
7725
8094
|
const currentVersion = fileContentVersion(currentContent);
|
|
7726
8095
|
if (expectedVersion !== currentVersion) {
|
|
@@ -7796,7 +8165,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
7796
8165
|
}
|
|
7797
8166
|
let before;
|
|
7798
8167
|
try {
|
|
7799
|
-
before =
|
|
8168
|
+
before = readFileSync52(ctx.absPath, "utf-8");
|
|
7800
8169
|
} catch (error) {
|
|
7801
8170
|
if (!error || typeof error !== "object" || !("code" in error) || error.code !== "ENOENT") {
|
|
7802
8171
|
throw error;
|
|
@@ -7825,7 +8194,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
7825
8194
|
}
|
|
7826
8195
|
const backup = snapshotBeforeWrite(ctx.project.dir, ctx.absPath);
|
|
7827
8196
|
if (backup.error) return c.json({ error: `backup failed: ${backup.error}` }, 500);
|
|
7828
|
-
const current =
|
|
8197
|
+
const current = readFileSync52(ctx.absPath, "utf-8");
|
|
7829
8198
|
if (current !== before) {
|
|
7830
8199
|
const currentVersion2 = fileContentVersion(current);
|
|
7831
8200
|
return c.json({ error: "file conflict", currentVersion: currentVersion2, currentContent: current }, 409);
|
|
@@ -7853,12 +8222,12 @@ function registerFileRoutes(api, adapter) {
|
|
|
7853
8222
|
api.post("/projects/:id/file-mutations/remove-element/*", async (c) => {
|
|
7854
8223
|
const ctx = await resolveFileMutationContext(c, adapter, "remove-element");
|
|
7855
8224
|
if ("error" in ctx) return ctx.error;
|
|
7856
|
-
if (!
|
|
8225
|
+
if (!existsSync4(ctx.absPath)) {
|
|
7857
8226
|
return c.json({ error: "not found" }, 404);
|
|
7858
8227
|
}
|
|
7859
8228
|
const parsed = await parseMutationBody(c);
|
|
7860
8229
|
if ("error" in parsed) return parsed.error;
|
|
7861
|
-
const originalContent =
|
|
8230
|
+
const originalContent = readFileSync52(ctx.absPath, "utf-8");
|
|
7862
8231
|
return writeIfChanged(
|
|
7863
8232
|
c,
|
|
7864
8233
|
ctx.project.dir,
|
|
@@ -7871,7 +8240,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
7871
8240
|
api.post("/projects/:id/file-mutations/remove-elements/*", async (c) => {
|
|
7872
8241
|
const ctx = await resolveFileMutationContext(c, adapter, "remove-elements");
|
|
7873
8242
|
if ("error" in ctx) return ctx.error;
|
|
7874
|
-
if (!
|
|
8243
|
+
if (!existsSync4(ctx.absPath)) {
|
|
7875
8244
|
return c.json({ error: "not found" }, 404);
|
|
7876
8245
|
}
|
|
7877
8246
|
const body = await c.req.json().catch(() => null);
|
|
@@ -7879,7 +8248,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
7879
8248
|
if (!Array.isArray(targets) || targets.length === 0) {
|
|
7880
8249
|
return c.json({ error: "targets required" }, 400);
|
|
7881
8250
|
}
|
|
7882
|
-
const originalContent =
|
|
8251
|
+
const originalContent = readFileSync52(ctx.absPath, "utf-8");
|
|
7883
8252
|
return writeIfChanged(
|
|
7884
8253
|
c,
|
|
7885
8254
|
ctx.project.dir,
|
|
@@ -7915,7 +8284,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
7915
8284
|
seen.add(absPath);
|
|
7916
8285
|
let before;
|
|
7917
8286
|
try {
|
|
7918
|
-
before =
|
|
8287
|
+
before = readFileSync52(absPath, "utf-8");
|
|
7919
8288
|
} catch {
|
|
7920
8289
|
return c.json({ error: `not found: ${file.path}` }, 404);
|
|
7921
8290
|
}
|
|
@@ -7942,7 +8311,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
7942
8311
|
prepared.push(folded);
|
|
7943
8312
|
}
|
|
7944
8313
|
for (const file of prepared) {
|
|
7945
|
-
const current =
|
|
8314
|
+
const current = readFileSync52(file.absPath, "utf-8");
|
|
7946
8315
|
if (current !== file.before) {
|
|
7947
8316
|
return c.json(
|
|
7948
8317
|
{
|
|
@@ -7985,7 +8354,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
7985
8354
|
const conflicts = [];
|
|
7986
8355
|
for (const file of written.reverse()) {
|
|
7987
8356
|
try {
|
|
7988
|
-
const current =
|
|
8357
|
+
const current = readFileSync52(file.absPath, "utf-8");
|
|
7989
8358
|
if (current !== file.after) {
|
|
7990
8359
|
conflicts.push(file.path);
|
|
7991
8360
|
continue;
|
|
@@ -8033,7 +8402,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
8033
8402
|
const fallbackTiming = typeof parsed.body.elementStart === "number" && typeof parsed.body.elementDuration === "number" ? { start: parsed.body.elementStart, duration: parsed.body.elementDuration } : void 0;
|
|
8034
8403
|
let originalContent;
|
|
8035
8404
|
try {
|
|
8036
|
-
originalContent =
|
|
8405
|
+
originalContent = readFileSync52(ctx.absPath, "utf-8");
|
|
8037
8406
|
} catch {
|
|
8038
8407
|
return c.json({ error: "not found" }, 404);
|
|
8039
8408
|
}
|
|
@@ -8095,7 +8464,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
8095
8464
|
for (let attempt = 1; ; attempt += 1) {
|
|
8096
8465
|
let originalContent;
|
|
8097
8466
|
try {
|
|
8098
|
-
originalContent =
|
|
8467
|
+
originalContent = readFileSync52(ctx.absPath, "utf-8");
|
|
8099
8468
|
} catch {
|
|
8100
8469
|
return c.json({ error: "not found" }, 404);
|
|
8101
8470
|
}
|
|
@@ -8207,7 +8576,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
8207
8576
|
}
|
|
8208
8577
|
let originalContent;
|
|
8209
8578
|
try {
|
|
8210
|
-
originalContent =
|
|
8579
|
+
originalContent = readFileSync52(ctx.absPath, "utf-8");
|
|
8211
8580
|
} catch {
|
|
8212
8581
|
return c.json({ error: "not found" }, 404);
|
|
8213
8582
|
}
|
|
@@ -8263,7 +8632,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
8263
8632
|
).map((entry) => ({ target: entry.target, track: entry.track }));
|
|
8264
8633
|
let originalContent;
|
|
8265
8634
|
try {
|
|
8266
|
-
originalContent =
|
|
8635
|
+
originalContent = readFileSync52(ctx.absPath, "utf-8");
|
|
8267
8636
|
} catch {
|
|
8268
8637
|
return c.json({ error: "not found" }, 404);
|
|
8269
8638
|
}
|
|
@@ -8292,7 +8661,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
8292
8661
|
if ("error" in parsed) return parsed.error;
|
|
8293
8662
|
let content;
|
|
8294
8663
|
try {
|
|
8295
|
-
content =
|
|
8664
|
+
content = readFileSync52(ctx.absPath, "utf-8");
|
|
8296
8665
|
} catch {
|
|
8297
8666
|
return c.json({ exists: false });
|
|
8298
8667
|
}
|
|
@@ -8306,7 +8675,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
8306
8675
|
if (!Array.isArray(body?.targets)) return c.json({ error: "targets required" }, 400);
|
|
8307
8676
|
let content;
|
|
8308
8677
|
try {
|
|
8309
|
-
content =
|
|
8678
|
+
content = readFileSync52(ctx.absPath, "utf-8");
|
|
8310
8679
|
} catch {
|
|
8311
8680
|
return c.json({ exists: body.targets.map(() => false) });
|
|
8312
8681
|
}
|
|
@@ -8323,7 +8692,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
8323
8692
|
if (!newAbs) {
|
|
8324
8693
|
return c.json({ error: "forbidden" }, 403);
|
|
8325
8694
|
}
|
|
8326
|
-
if (
|
|
8695
|
+
if (existsSync4(newAbs)) {
|
|
8327
8696
|
return c.json({ error: "already exists" }, 409);
|
|
8328
8697
|
}
|
|
8329
8698
|
const isDirectory = statSync32(res.absPath, { throwIfNoEntry: false })?.isDirectory() ?? false;
|
|
@@ -8340,7 +8709,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
8340
8709
|
return c.json({ error: "path required" }, 400);
|
|
8341
8710
|
}
|
|
8342
8711
|
const srcAbs = resolveWithinProject(project.dir, body.path);
|
|
8343
|
-
if (!srcAbs || !
|
|
8712
|
+
if (!srcAbs || !existsSync4(srcAbs)) {
|
|
8344
8713
|
return c.json({ error: "not found" }, 404);
|
|
8345
8714
|
}
|
|
8346
8715
|
const copyPath = generateCopyPath(project.dir, body.path);
|
|
@@ -8350,7 +8719,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
8350
8719
|
}
|
|
8351
8720
|
ensureDir(project.dir, destAbs);
|
|
8352
8721
|
try {
|
|
8353
|
-
createFileAtomically(destAbs,
|
|
8722
|
+
createFileAtomically(destAbs, readFileSync52(srcAbs));
|
|
8354
8723
|
} catch (error) {
|
|
8355
8724
|
if (!error || typeof error !== "object" || !("code" in error) || error.code !== "EEXIST") {
|
|
8356
8725
|
throw error;
|
|
@@ -8394,7 +8763,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
8394
8763
|
mustExist: true
|
|
8395
8764
|
});
|
|
8396
8765
|
if ("error" in res) return res.error;
|
|
8397
|
-
const html =
|
|
8766
|
+
const html = readFileSync52(res.absPath, "utf-8");
|
|
8398
8767
|
const etag = `${fileContentVersion(html).slice(0, -1)}:gsap-animations:v1"`;
|
|
8399
8768
|
const headers = { ETag: etag, "Cache-Control": "no-cache" };
|
|
8400
8769
|
if (c.req.header("If-None-Match") === etag) return new Response(null, { status: 304, headers });
|
|
@@ -8451,7 +8820,7 @@ function registerFileRoutes(api, adapter) {
|
|
|
8451
8820
|
if (!body || typeof body.expected !== "string" || typeof body.restore !== "string") {
|
|
8452
8821
|
return c.json({ error: "expected and restore contents required" }, 400);
|
|
8453
8822
|
}
|
|
8454
|
-
const current =
|
|
8823
|
+
const current = readFileSync52(res.absPath, "utf-8");
|
|
8455
8824
|
if (current !== body.expected) {
|
|
8456
8825
|
return c.json({ ok: true, restored: false, conflict: true });
|
|
8457
8826
|
}
|
|
@@ -8459,176 +8828,6 @@ function registerFileRoutes(api, adapter) {
|
|
|
8459
8828
|
return c.json({ ok: true, restored: true, conflict: false });
|
|
8460
8829
|
});
|
|
8461
8830
|
}
|
|
8462
|
-
function rewriteRelativePaths(root, compPath, projectDir) {
|
|
8463
|
-
const assetExists = (path) => existsSync42(join62(projectDir, path));
|
|
8464
|
-
rewriteAssetPaths(
|
|
8465
|
-
root.querySelectorAll("[src], [href]"),
|
|
8466
|
-
compPath,
|
|
8467
|
-
(el, attr) => el.getAttribute(attr),
|
|
8468
|
-
(el, attr, value) => el.setAttribute(attr, value),
|
|
8469
|
-
assetExists
|
|
8470
|
-
);
|
|
8471
|
-
rewriteInlineStyleAssetUrls(
|
|
8472
|
-
root.querySelectorAll("[style]"),
|
|
8473
|
-
compPath,
|
|
8474
|
-
(el) => el.getAttribute("style"),
|
|
8475
|
-
(el, value) => el.setAttribute("style", value),
|
|
8476
|
-
assetExists
|
|
8477
|
-
);
|
|
8478
|
-
for (const styleEl of root.querySelectorAll("style")) {
|
|
8479
|
-
styleEl.textContent = rewriteCssAssetUrls(styleEl.textContent || "", compPath, assetExists);
|
|
8480
|
-
}
|
|
8481
|
-
}
|
|
8482
|
-
function escapeLeadingDigitIdent(id) {
|
|
8483
|
-
return `\\${id.charCodeAt(0).toString(16)} ${id.slice(1)}`;
|
|
8484
|
-
}
|
|
8485
|
-
var REGEXP_SPECIALS = /[.*+?^${}()|[\]\\]/g;
|
|
8486
|
-
function fixDigitLeadingIdSelectors(root) {
|
|
8487
|
-
const digitIds = /* @__PURE__ */ new Set();
|
|
8488
|
-
for (const el of root.querySelectorAll("[id]")) {
|
|
8489
|
-
const id = el.getAttribute("id");
|
|
8490
|
-
if (id && /^\d/.test(id)) digitIds.add(id);
|
|
8491
|
-
}
|
|
8492
|
-
if (digitIds.size === 0) return;
|
|
8493
|
-
for (const styleEl of root.querySelectorAll("style")) {
|
|
8494
|
-
let css = styleEl.textContent || "";
|
|
8495
|
-
for (const id of digitIds) {
|
|
8496
|
-
const pattern = new RegExp(`#${id.replace(REGEXP_SPECIALS, "\\$&")}(?![\\w-])`, "g");
|
|
8497
|
-
css = css.replace(pattern, `#${escapeLeadingDigitIdent(id)}`);
|
|
8498
|
-
}
|
|
8499
|
-
styleEl.textContent = css;
|
|
8500
|
-
}
|
|
8501
|
-
}
|
|
8502
|
-
function extractFullDocumentParts(rawHtml, compPath, projectDir) {
|
|
8503
|
-
const { document: doc } = parseHTML(rawHtml);
|
|
8504
|
-
const rewriteTargets = [doc.head, doc.body].filter(Boolean);
|
|
8505
|
-
for (const target of rewriteTargets) {
|
|
8506
|
-
rewriteRelativePaths(target, compPath, projectDir);
|
|
8507
|
-
}
|
|
8508
|
-
fixDigitLeadingIdSelectors(doc);
|
|
8509
|
-
const headContent = doc.head?.innerHTML ?? "";
|
|
8510
|
-
const bodyContent = doc.body?.innerHTML ?? "";
|
|
8511
|
-
const htmlEl = doc.documentElement;
|
|
8512
|
-
const htmlAttrs = extractElementAttrs(htmlEl);
|
|
8513
|
-
const bodyAttrs = doc.body ? extractElementAttrs(doc.body) : "";
|
|
8514
|
-
return { headContent, bodyContent, htmlAttrs, bodyAttrs };
|
|
8515
|
-
}
|
|
8516
|
-
function extractTemplateInnerHtml(rawComp) {
|
|
8517
|
-
const { document: doc } = parseHTML(rawComp);
|
|
8518
|
-
const template = doc.querySelector("template");
|
|
8519
|
-
return template ? template.innerHTML : null;
|
|
8520
|
-
}
|
|
8521
|
-
function escapeAttrValue(value) {
|
|
8522
|
-
return value.replace(/&/g, "&").replace(/"/g, """);
|
|
8523
|
-
}
|
|
8524
|
-
function extractElementAttrs(el) {
|
|
8525
|
-
const parts = [];
|
|
8526
|
-
for (let i = 0; i < el.attributes.length; i++) {
|
|
8527
|
-
const attr = el.attributes[i];
|
|
8528
|
-
if (attr.value === "") {
|
|
8529
|
-
parts.push(attr.name);
|
|
8530
|
-
} else {
|
|
8531
|
-
parts.push(`${attr.name}="${escapeAttrValue(attr.value)}"`);
|
|
8532
|
-
}
|
|
8533
|
-
}
|
|
8534
|
-
return parts.join(" ");
|
|
8535
|
-
}
|
|
8536
|
-
var NON_RENDERED_TAGS = /* @__PURE__ */ new Set(["SCRIPT", "STYLE", "LINK", "META", "TEMPLATE", "NOSCRIPT"]);
|
|
8537
|
-
function promoteTemplateCompositionId(rawComp, body) {
|
|
8538
|
-
let templateCompositionId;
|
|
8539
|
-
for (const tag of rawComp.matchAll(/<template\b[^>]*/gi)) {
|
|
8540
|
-
const id = /\bdata-composition-id\s*=\s*["']([^"']+)["']/i.exec(tag[0] ?? "")?.[1];
|
|
8541
|
-
if (id) {
|
|
8542
|
-
templateCompositionId = id;
|
|
8543
|
-
break;
|
|
8544
|
-
}
|
|
8545
|
-
}
|
|
8546
|
-
if (!templateCompositionId) return;
|
|
8547
|
-
if (body.querySelector("[data-composition-id]")) return;
|
|
8548
|
-
const root = Array.from(body.children).find((el) => !NON_RENDERED_TAGS.has(el.tagName));
|
|
8549
|
-
root?.setAttribute("data-composition-id", templateCompositionId);
|
|
8550
|
-
}
|
|
8551
|
-
function tagRootCompositionFile(bodyHtml, compPath) {
|
|
8552
|
-
const match = bodyHtml.match(/<[a-zA-Z][^>]*\bdata-composition-id=/);
|
|
8553
|
-
if (match?.index == null) return bodyHtml;
|
|
8554
|
-
const tagEnd = bodyHtml.indexOf(">", match.index);
|
|
8555
|
-
if (tagEnd === -1) return bodyHtml;
|
|
8556
|
-
if (bodyHtml.slice(match.index, tagEnd).includes("data-composition-file")) return bodyHtml;
|
|
8557
|
-
return bodyHtml.slice(0, tagEnd) + ` data-composition-file="${compPath}"` + bodyHtml.slice(tagEnd);
|
|
8558
|
-
}
|
|
8559
|
-
function rootHeadContent(rootHtml) {
|
|
8560
|
-
return rootHtml.match(/<head[^>]*>([\s\S]*?)<\/head>/i)?.[1] ?? "";
|
|
8561
|
-
}
|
|
8562
|
-
function buildSubCompositionHtml(projectDir, compPath, runtimeUrl, baseHref, rawOverride) {
|
|
8563
|
-
const compFile = join62(projectDir, compPath);
|
|
8564
|
-
if (!existsSync42(compFile)) return null;
|
|
8565
|
-
const rawComp = rawOverride ?? readFileSync42(compFile, "utf-8");
|
|
8566
|
-
let compHeadContent = "";
|
|
8567
|
-
let rewrittenContent;
|
|
8568
|
-
let htmlAttrs = "";
|
|
8569
|
-
let bodyAttrs = "";
|
|
8570
|
-
const templateInner = extractTemplateInnerHtml(rawComp);
|
|
8571
|
-
if (templateInner != null) {
|
|
8572
|
-
const { document: contentDoc } = parseHTML(
|
|
8573
|
-
`<!DOCTYPE html><html><head></head><body>${templateInner}</body></html>`
|
|
8574
|
-
);
|
|
8575
|
-
rewriteRelativePaths(contentDoc, compPath, projectDir);
|
|
8576
|
-
fixDigitLeadingIdSelectors(contentDoc);
|
|
8577
|
-
promoteTemplateCompositionId(rawComp, contentDoc.body);
|
|
8578
|
-
rewrittenContent = contentDoc.body.innerHTML || templateInner;
|
|
8579
|
-
} else if (isFullHtmlDocument(rawComp)) {
|
|
8580
|
-
const parts = extractFullDocumentParts(rawComp, compPath, projectDir);
|
|
8581
|
-
compHeadContent = parts.headContent;
|
|
8582
|
-
rewrittenContent = parts.bodyContent;
|
|
8583
|
-
htmlAttrs = parts.htmlAttrs;
|
|
8584
|
-
bodyAttrs = parts.bodyAttrs;
|
|
8585
|
-
} else {
|
|
8586
|
-
const { document: contentDoc } = parseHTML(
|
|
8587
|
-
`<!DOCTYPE html><html><head></head><body>${rawComp}</body></html>`
|
|
8588
|
-
);
|
|
8589
|
-
rewriteRelativePaths(contentDoc, compPath, projectDir);
|
|
8590
|
-
fixDigitLeadingIdSelectors(contentDoc);
|
|
8591
|
-
rewrittenContent = contentDoc.body.innerHTML || rawComp;
|
|
8592
|
-
}
|
|
8593
|
-
rewrittenContent = stripEmbeddedRuntimeScripts(rewrittenContent);
|
|
8594
|
-
const { document: scriptsDoc } = parseHTML(
|
|
8595
|
-
`<!DOCTYPE html><html><head></head><body>${rewrittenContent}</body></html>`
|
|
8596
|
-
);
|
|
8597
|
-
deferScriptsUntilFonts(scriptsDoc);
|
|
8598
|
-
rewrittenContent = scriptsDoc.body.innerHTML;
|
|
8599
|
-
rewrittenContent = tagRootCompositionFile(rewrittenContent, compPath);
|
|
8600
|
-
const indexPath = join62(projectDir, "index.html");
|
|
8601
|
-
let headContent = "";
|
|
8602
|
-
if (existsSync42(indexPath)) headContent = rootHeadContent(readFileSync42(indexPath, "utf-8"));
|
|
8603
|
-
if (baseHref && !hasBaseElement(headContent)) {
|
|
8604
|
-
headContent = `<base href="${baseHref}">
|
|
8605
|
-
${headContent}`;
|
|
8606
|
-
}
|
|
8607
|
-
if (compHeadContent) headContent += `
|
|
8608
|
-
${compHeadContent}`;
|
|
8609
|
-
headContent = stripEmbeddedRuntimeScripts(headContent);
|
|
8610
|
-
headContent += `
|
|
8611
|
-
<script ${RUNTIME_BOOTSTRAP_ATTR}="1" src="${runtimeUrl}"></script>`;
|
|
8612
|
-
if (!headContent.includes("gsap")) {
|
|
8613
|
-
headContent += `
|
|
8614
|
-
<script src="${gsapCdnDist()}gsap.min.js"></script>`;
|
|
8615
|
-
}
|
|
8616
|
-
const htmlOpen = htmlAttrs ? `<html ${htmlAttrs}>` : "<html>";
|
|
8617
|
-
const bodyOpen = bodyAttrs ? `<body ${bodyAttrs}>` : "<body>";
|
|
8618
|
-
return `<!DOCTYPE html>
|
|
8619
|
-
${htmlOpen}
|
|
8620
|
-
<head>
|
|
8621
|
-
${headContent}
|
|
8622
|
-
</head>
|
|
8623
|
-
${bodyOpen}
|
|
8624
|
-
<script>window.__timelines=window.__timelines||{};</script>
|
|
8625
|
-
${rewrittenContent}
|
|
8626
|
-
</body>
|
|
8627
|
-
</html>`;
|
|
8628
|
-
}
|
|
8629
|
-
function hasBaseElement(html) {
|
|
8630
|
-
return parseHTML(html).document.querySelector("base") !== null;
|
|
8631
|
-
}
|
|
8632
8831
|
var ALWAYS_AFFECTS = ["hyperframes.json", ...STUDIO_SIGNATURE_MANIFEST_PATHS];
|
|
8633
8832
|
var REFERENCE = /\b(?:src|href|poster|data-composition-src)\s*=\s*(?:"([^"\n]*)"|'([^'\n]*)')|url\(\s*(?:"([^"\n]*)"|'([^'\n]*)'|([^"'\s)]+))/gi;
|
|
8634
8833
|
var pathKey = process.platform === "darwin" || process.platform === "win32" ? (path) => resolve32(path).toLowerCase() : (path) => resolve32(path);
|
|
@@ -8763,7 +8962,7 @@ function readStudioMotionManifestContent(projectDir) {
|
|
|
8763
8962
|
const manifestPath = join8(projectDir, STUDIO_MOTION_PATH);
|
|
8764
8963
|
if (!existsSync5(manifestPath)) return "";
|
|
8765
8964
|
try {
|
|
8766
|
-
return
|
|
8965
|
+
return readFileSync62(manifestPath, "utf-8");
|
|
8767
8966
|
} catch {
|
|
8768
8967
|
return "";
|
|
8769
8968
|
}
|
|
@@ -8905,7 +9104,7 @@ function parsePreviewVariablesParam(raw) {
|
|
|
8905
9104
|
}
|
|
8906
9105
|
function variablesEtagSalt(raw) {
|
|
8907
9106
|
if (!raw) return "";
|
|
8908
|
-
return `:vars:${
|
|
9107
|
+
return `:vars:${createHash23("sha1").update(raw).digest("hex").slice(0, 12)}`;
|
|
8909
9108
|
}
|
|
8910
9109
|
function previewVariablesFromRequest(rawVariables) {
|
|
8911
9110
|
const parse22 = parsePreviewVariablesParam(rawVariables);
|
|
@@ -8945,13 +9144,13 @@ function resolveProjectMainHtml(projectDir, projectId) {
|
|
|
8945
9144
|
recordPreviewRead(projectDir, blockHtmlPath);
|
|
8946
9145
|
if (existsSync5(indexPath)) {
|
|
8947
9146
|
return {
|
|
8948
|
-
html:
|
|
9147
|
+
html: readFileSync62(indexPath, "utf-8"),
|
|
8949
9148
|
compositionPath: "index.html"
|
|
8950
9149
|
};
|
|
8951
9150
|
}
|
|
8952
9151
|
if (existsSync5(blockHtmlPath)) {
|
|
8953
9152
|
return {
|
|
8954
|
-
html:
|
|
9153
|
+
html: readFileSync62(blockHtmlPath, "utf-8"),
|
|
8955
9154
|
compositionPath: `${projectId}.html`
|
|
8956
9155
|
};
|
|
8957
9156
|
}
|
|
@@ -9082,7 +9281,7 @@ ${etag}`;
|
|
|
9082
9281
|
function pinSubCompHfIds(compFile, compPath) {
|
|
9083
9282
|
if (!/\.html?$/i.test(compPath)) return void 0;
|
|
9084
9283
|
try {
|
|
9085
|
-
return ensureHfIds(
|
|
9284
|
+
return ensureHfIds(readFileSync62(compFile, "utf-8"));
|
|
9086
9285
|
} catch {
|
|
9087
9286
|
return null;
|
|
9088
9287
|
}
|
|
@@ -9101,7 +9300,7 @@ ${etag}`;
|
|
|
9101
9300
|
if (!compFile || !existsSync5(compFile) || !statSync42(compFile).isFile()) {
|
|
9102
9301
|
return c.text("not found", 404);
|
|
9103
9302
|
}
|
|
9104
|
-
const compPathHash =
|
|
9303
|
+
const compPathHash = createHash23("sha1").update(compPath).digest("hex");
|
|
9105
9304
|
const capture = c.req.query(PREVIEW_CAPTURE_PARAM) !== void 0;
|
|
9106
9305
|
const etag = `"comp:v2:${compPathHash}:${signature}${variablesEtagSalt(vars.raw)}${capture ? ":capture" : ""}"`;
|
|
9107
9306
|
const ifNoneMatch = c.req.header("If-None-Match");
|
|
@@ -9193,7 +9392,7 @@ ${etag}`;
|
|
|
9193
9392
|
recordProxyRequest();
|
|
9194
9393
|
servedContentType = PROXY_VARIANT_CONFIG[proxyVariant].contentType;
|
|
9195
9394
|
}
|
|
9196
|
-
const textBuffer = isText ? Buffer.from(
|
|
9395
|
+
const textBuffer = isText ? Buffer.from(readFileSync62(file, "utf-8"), "utf-8") : null;
|
|
9197
9396
|
const totalSize = textBuffer ? textBuffer.length : statSync42(servedPath).size;
|
|
9198
9397
|
const bodyFor = (start, end) => textBuffer ? new Uint8Array(textBuffer.subarray(start, end + 1)) : (
|
|
9199
9398
|
// Node's web stream type and the DOM one do not overlap for tsc on
|
|
@@ -9252,7 +9451,7 @@ async function lintUncoveredHtml(adapter, projectDir, htmlFiles, coveredFiles) {
|
|
|
9252
9451
|
const findings = [];
|
|
9253
9452
|
for (const file of htmlFiles) {
|
|
9254
9453
|
if (coveredFiles.has(file)) continue;
|
|
9255
|
-
const content =
|
|
9454
|
+
const content = readFileSync72(join9(projectDir, file), "utf-8");
|
|
9256
9455
|
const result = await adapter.lint(content, { filePath: file, isSubComposition: true });
|
|
9257
9456
|
for (const finding of result?.findings ?? []) {
|
|
9258
9457
|
findings.push({ ...finding, file });
|
|
@@ -9418,7 +9617,7 @@ function registerRenderRoutes(api, adapter) {
|
|
|
9418
9617
|
}
|
|
9419
9618
|
const contentType = renderContentType(job.outputPath);
|
|
9420
9619
|
const filename = job.outputPath.split("/").pop() ?? `render.mp4`;
|
|
9421
|
-
const content =
|
|
9620
|
+
const content = readFileSync8(job.outputPath);
|
|
9422
9621
|
return new Response(content, {
|
|
9423
9622
|
headers: {
|
|
9424
9623
|
"Content-Type": contentType,
|
|
@@ -9436,7 +9635,7 @@ function registerRenderRoutes(api, adapter) {
|
|
|
9436
9635
|
}
|
|
9437
9636
|
const contentType = renderContentType(job.outputPath);
|
|
9438
9637
|
const filename = job.outputPath.split("/").pop() ?? `render.mp4`;
|
|
9439
|
-
const content =
|
|
9638
|
+
const content = readFileSync8(job.outputPath);
|
|
9440
9639
|
return new Response(content, {
|
|
9441
9640
|
headers: {
|
|
9442
9641
|
"Content-Type": contentType,
|
|
@@ -9469,7 +9668,7 @@ function registerRenderRoutes(api, adapter) {
|
|
|
9469
9668
|
if (!fp) return c.json({ error: "forbidden" }, 403);
|
|
9470
9669
|
if (!existsSync6(fp)) return c.json({ error: "not found" }, 404);
|
|
9471
9670
|
const contentType = renderContentType(fp);
|
|
9472
|
-
const content =
|
|
9671
|
+
const content = readFileSync8(fp);
|
|
9473
9672
|
return new Response(content, {
|
|
9474
9673
|
headers: {
|
|
9475
9674
|
"Content-Type": contentType,
|
|
@@ -9494,7 +9693,7 @@ function registerRenderRoutes(api, adapter) {
|
|
|
9494
9693
|
let audioLoweredDb;
|
|
9495
9694
|
if (existsSync6(metaPath)) {
|
|
9496
9695
|
try {
|
|
9497
|
-
const meta = JSON.parse(
|
|
9696
|
+
const meta = JSON.parse(readFileSync8(metaPath, "utf-8"));
|
|
9498
9697
|
if (meta.status === "failed" && !existsSync6(fp)) status = "failed";
|
|
9499
9698
|
if (meta.durationMs) durationMs = meta.durationMs;
|
|
9500
9699
|
if (typeof meta.audioLoweredDb === "number") audioLoweredDb = meta.audioLoweredDb;
|
|
@@ -9702,7 +9901,7 @@ function registerImageThumbnailRoutes(api, adapter) {
|
|
|
9702
9901
|
api.get("/projects/:id/image-thumbnail/*", async (c) => {
|
|
9703
9902
|
try {
|
|
9704
9903
|
const { path, info } = await resolveSource(adapter, c.req.param("id"), c.req.url);
|
|
9705
|
-
const key =
|
|
9904
|
+
const key = createHash32("sha256").update(JSON.stringify([path, info.dev, info.ino, info.size, info.mtimeMs, info.ctimeMs])).digest("hex");
|
|
9706
9905
|
const etag = `"${key}"`;
|
|
9707
9906
|
c.header("ETag", etag);
|
|
9708
9907
|
c.header("Cache-Control", "private, no-cache");
|
|
@@ -9727,84 +9926,6 @@ function registerImageThumbnailRoutes(api, adapter) {
|
|
|
9727
9926
|
}
|
|
9728
9927
|
});
|
|
9729
9928
|
}
|
|
9730
|
-
var ROOT_COMPOSITION = "index.html";
|
|
9731
|
-
var COMPOSITION_SRC = /\bdata-composition-src\s*=\s*(["'])(.*?)\1/g;
|
|
9732
|
-
function projectReader(projectDir) {
|
|
9733
|
-
const sources = /* @__PURE__ */ new Map();
|
|
9734
|
-
return (compPath) => {
|
|
9735
|
-
if (!sources.has(compPath)) {
|
|
9736
|
-
const file = resolveWithinProject(projectDir, compPath);
|
|
9737
|
-
let source = null;
|
|
9738
|
-
try {
|
|
9739
|
-
source = file ? readFileSync8(file, "utf-8") : null;
|
|
9740
|
-
} catch {
|
|
9741
|
-
}
|
|
9742
|
-
sources.set(compPath, source);
|
|
9743
|
-
}
|
|
9744
|
-
return sources.get(compPath) ?? null;
|
|
9745
|
-
};
|
|
9746
|
-
}
|
|
9747
|
-
function normalizeSource(src) {
|
|
9748
|
-
if (/^[a-z][a-z0-9+.-]*:/i.test(src) || src.startsWith("//")) return null;
|
|
9749
|
-
const path = src.split(/[?#]/)[0]?.replace(/^\.?\//, "") ?? "";
|
|
9750
|
-
return path || null;
|
|
9751
|
-
}
|
|
9752
|
-
function closureOf(read, compPath) {
|
|
9753
|
-
const closure = /* @__PURE__ */ new Set();
|
|
9754
|
-
const visit = (path) => {
|
|
9755
|
-
if (closure.has(path)) return;
|
|
9756
|
-
closure.add(path);
|
|
9757
|
-
for (const match of (read(path) ?? "").matchAll(COMPOSITION_SRC)) {
|
|
9758
|
-
const mounted = normalizeSource(match[2] ?? "");
|
|
9759
|
-
if (mounted) visit(mounted);
|
|
9760
|
-
}
|
|
9761
|
-
};
|
|
9762
|
-
visit(compPath);
|
|
9763
|
-
return closure;
|
|
9764
|
-
}
|
|
9765
|
-
var inputSignatures = /* @__PURE__ */ new Map();
|
|
9766
|
-
var rootMemos = /* @__PURE__ */ new Map();
|
|
9767
|
-
var sha1 = (text2) => createHash32("sha1").update(text2).digest("hex");
|
|
9768
|
-
function rootHashes(read) {
|
|
9769
|
-
const source = read(ROOT_COMPOSITION) ?? "";
|
|
9770
|
-
return { root: sha1(source), head: sha1(rootHeadContent(source)) };
|
|
9771
|
-
}
|
|
9772
|
-
function compositionInputSignature(projectDir, compPath, projectSignature) {
|
|
9773
|
-
const key = `${projectDir}\0${compPath}`;
|
|
9774
|
-
const known = inputSignatures.get(key);
|
|
9775
|
-
if (known?.projectSignature === projectSignature) return known.inputSignature;
|
|
9776
|
-
const read = projectReader(projectDir);
|
|
9777
|
-
const comp = normalizeSource(compPath) ?? compPath;
|
|
9778
|
-
const inputs = closureOf(read, comp).add(ROOT_COMPOSITION);
|
|
9779
|
-
const excluded = new Set(
|
|
9780
|
-
[...closureOf(read, ROOT_COMPOSITION)].filter((path) => !inputs.has(path))
|
|
9781
|
-
);
|
|
9782
|
-
let inputSignature;
|
|
9783
|
-
if (comp === ROOT_COMPOSITION) {
|
|
9784
|
-
inputSignature = createProjectSignature(projectDir, excluded);
|
|
9785
|
-
} else {
|
|
9786
|
-
const hashes = rootHashes(read);
|
|
9787
|
-
if (!rootMemos.has(projectDir)) rootMemos.set(projectDir, { ...hashes, affected: null });
|
|
9788
|
-
inputSignature = `${createProjectSignature(projectDir, excluded.add(ROOT_COMPOSITION))}:${hashes.head}`;
|
|
9789
|
-
}
|
|
9790
|
-
inputSignatures.set(key, { projectSignature, inputSignature });
|
|
9791
|
-
return inputSignature;
|
|
9792
|
-
}
|
|
9793
|
-
function compositionsAffectedBy(projectDir, changedPath) {
|
|
9794
|
-
const changed = changedPath.replace(/\\/g, "/");
|
|
9795
|
-
const read = projectReader(projectDir);
|
|
9796
|
-
if (changed === ROOT_COMPOSITION) {
|
|
9797
|
-
const now = rootHashes(read);
|
|
9798
|
-
const memo = rootMemos.get(projectDir);
|
|
9799
|
-
if (memo?.root === now.root) return memo.affected;
|
|
9800
|
-
const affected = memo?.head === now.head ? [ROOT_COMPOSITION] : null;
|
|
9801
|
-
rootMemos.set(projectDir, { ...now, affected });
|
|
9802
|
-
return affected;
|
|
9803
|
-
}
|
|
9804
|
-
const mounted = closureOf(read, ROOT_COMPOSITION);
|
|
9805
|
-
if (!mounted.has(changed)) return null;
|
|
9806
|
-
return [...mounted].filter((path) => closureOf(read, path).has(changed));
|
|
9807
|
-
}
|
|
9808
9929
|
var THUMBNAIL_CACHE_VERSION = "v5";
|
|
9809
9930
|
var THUMBNAIL_MAX_OUTPUT_WIDTH = 240;
|
|
9810
9931
|
var THUMBNAIL_MAX_OUTPUT_HEIGHT = 135;
|
|
@@ -11381,12 +11502,12 @@ export {
|
|
|
11381
11502
|
createStudioMotionRenderBodyScript,
|
|
11382
11503
|
MIME_TYPES,
|
|
11383
11504
|
getMimeType,
|
|
11505
|
+
buildSubCompositionHtml,
|
|
11506
|
+
compositionsAffectedBy,
|
|
11384
11507
|
applyFileMutations,
|
|
11385
11508
|
requestSubPath,
|
|
11386
|
-
buildSubCompositionHtml,
|
|
11387
11509
|
affectsPreview,
|
|
11388
11510
|
PREVIEW_BUNDLE_OPTIONS,
|
|
11389
|
-
compositionsAffectedBy,
|
|
11390
11511
|
createStudioApi,
|
|
11391
11512
|
duplicateElementInHtml,
|
|
11392
11513
|
createPreviewDocumentStore,
|