@hyperframes/core 0.6.95 → 0.6.96
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/compiler/htmlBundler.d.ts.map +1 -1
- package/dist/compiler/htmlBundler.js +10 -7
- package/dist/compiler/htmlBundler.js.map +1 -1
- package/dist/generated/runtime-inline.js +1 -1
- package/dist/generated/runtime-inline.js.map +1 -1
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +21 -21
- package/dist/hyperframe.runtime.mjs +21 -21
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/media/gif.d.ts.map +1 -1
- package/dist/media/gif.js +9 -2
- package/dist/media/gif.js.map +1 -1
- package/dist/safePath.d.ts +24 -0
- package/dist/safePath.d.ts.map +1 -0
- package/dist/safePath.js +58 -0
- package/dist/safePath.js.map +1 -0
- package/dist/studio-api/helpers/backupJournal.d.ts +9 -0
- package/dist/studio-api/helpers/backupJournal.d.ts.map +1 -0
- package/dist/studio-api/helpers/backupJournal.js +81 -0
- package/dist/studio-api/helpers/backupJournal.js.map +1 -0
- package/dist/studio-api/helpers/finiteMutation.d.ts +11 -0
- package/dist/studio-api/helpers/finiteMutation.d.ts.map +1 -0
- package/dist/studio-api/helpers/finiteMutation.js +21 -0
- package/dist/studio-api/helpers/finiteMutation.js.map +1 -0
- package/dist/studio-api/helpers/safePath.d.ts +9 -2
- package/dist/studio-api/helpers/safePath.d.ts.map +1 -1
- package/dist/studio-api/helpers/safePath.js +21 -8
- package/dist/studio-api/helpers/safePath.js.map +1 -1
- package/dist/studio-api/routes/files.d.ts.map +1 -1
- package/dist/studio-api/routes/files.js +82 -10
- package/dist/studio-api/routes/files.js.map +1 -1
- package/dist/studio-api/routes/lint.d.ts.map +1 -1
- package/dist/studio-api/routes/lint.js +2 -2
- package/dist/studio-api/routes/lint.js.map +1 -1
- package/dist/studio-api/routes/projects.js +2 -2
- package/dist/studio-api/routes/projects.js.map +1 -1
- package/dist/studio-api/routes/render.d.ts.map +1 -1
- package/dist/studio-api/routes/render.js +6 -2
- package/dist/studio-api/routes/render.js.map +1 -1
- package/package.json +5 -1
package/dist/index.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export { getHyperframeRuntimeScript } from "./generated/runtime-inline";
|
|
|
22
22
|
export { buildHyperframesRuntimeScript, type HyperframesRuntimeBuildOptions, } from "./inline-scripts/hyperframesRuntime.engine";
|
|
23
23
|
export { MEDIA_VISUAL_STYLE_PROPERTIES, copyMediaVisualStyles, quantizeTimeToFrame, type MediaVisualStyleProperty, } from "./inline-scripts/parityContract";
|
|
24
24
|
export { redactTelemetryString } from "./telemetryRedaction";
|
|
25
|
+
export { isSafePath } from "./safePath";
|
|
25
26
|
export type { HyperframePickerApi, HyperframePickerBoundingBox, HyperframePickerElementInfo, } from "./inline-scripts/pickerApi";
|
|
26
27
|
export type { FrameAdapter, FrameAdapterContext } from "./adapters/types";
|
|
27
28
|
export type { GSAPTimelineLike, CreateGSAPFrameAdapterOptions } from "./adapters/gsap";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,aAAa,EACb,WAAW,EACX,KAAK,EACL,eAAe,EACf,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,0BAA0B,EAC1B,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,GAAG,EACH,QAAQ,EACR,cAAc,EACd,SAAS,EACT,cAAc,EACd,SAAS,EACT,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,QAAQ,EACR,kBAAkB,EAClB,gBAAgB,EAChB,SAAS,EACT,iBAAiB,EACjB,uBAAuB,EACvB,uBAAuB,EACvB,cAAc,EACd,cAAc,EACd,aAAa,EACb,eAAe,EACf,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,YAAY,GACb,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,uBAAuB,EACvB,QAAQ,EACR,mBAAmB,EACnB,KAAK,EACL,WAAW,EACX,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,0BAA0B,EAC1B,aAAa,EACb,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,cAAc,GACf,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EACL,QAAQ,EACR,WAAW,EACX,mBAAmB,EACnB,YAAY,EACZ,WAAW,EACX,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAM/B,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErF,OAAO,EACL,uBAAuB,EACvB,yBAAyB,EACzB,uBAAuB,EACvB,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,yBAAyB,CAAC;AAEjC,YAAY,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE5E,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,gBAAgB,EAChB,qBAAqB,EACrB,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,sBAAsB,CAAC;AAG9B,YAAY,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,yBAAyB,GAC1B,MAAM,0BAA0B,CAAC;AAGlC,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,cAAc,EACd,wBAAwB,GACzB,MAAM,2BAA2B,CAAC;AAGnC,YAAY,EACV,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACnF,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,wBAAwB,EAAE,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGjF,OAAO,EACL,4BAA4B,EAC5B,2BAA2B,EAC3B,2BAA2B,EAC3B,KAAK,yBAAyB,GAC/B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,0BAA0B,EAC1B,yBAAyB,EACzB,0BAA0B,EAC1B,KAAK,uBAAuB,GAC7B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EACL,6BAA6B,EAC7B,KAAK,8BAA8B,GACpC,MAAM,4CAA4C,CAAC;AACpD,OAAO,EACL,6BAA6B,EAC7B,qBAAqB,EACrB,mBAAmB,EACnB,KAAK,wBAAwB,GAC9B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,YAAY,EACV,mBAAmB,EACnB,2BAA2B,EAC3B,2BAA2B,GAC5B,MAAM,4BAA4B,CAAC;AAGpC,YAAY,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC1E,YAAY,EAAE,gBAAgB,EAAE,6BAA6B,EAAE,MAAM,iBAAiB,CAAC;AACvF,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAGzD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGrE,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAGzD,OAAO,EACL,iBAAiB,EACjB,6BAA6B,EAC7B,KAAK,uBAAuB,GAC7B,MAAM,gCAAgC,CAAC;AAGxC,YAAY,EACV,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,sBAAsB,EACtB,mBAAmB,EACnB,YAAY,EACZ,WAAW,EACX,SAAS,EACT,aAAa,EACb,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,UAAU,EACV,UAAU,EACV,cAAc,EACd,aAAa,EACb,WAAW,EACX,eAAe,GAChB,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -18,6 +18,7 @@ export { getHyperframeRuntimeScript } from "./generated/runtime-inline";
|
|
|
18
18
|
export { buildHyperframesRuntimeScript, } from "./inline-scripts/hyperframesRuntime.engine";
|
|
19
19
|
export { MEDIA_VISUAL_STYLE_PROPERTIES, copyMediaVisualStyles, quantizeTimeToFrame, } from "./inline-scripts/parityContract";
|
|
20
20
|
export { redactTelemetryString } from "./telemetryRedaction";
|
|
21
|
+
export { isSafePath } from "./safePath";
|
|
21
22
|
export { createGSAPFrameAdapter } from "./adapters/gsap";
|
|
22
23
|
// Text measurement
|
|
23
24
|
export { fitTextFontSize } from "./text/index.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAuCA,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,uBAAuB,EACvB,QAAQ,EACR,mBAAmB,EACnB,KAAK,EACL,WAAW,EACX,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,0BAA0B,EAC1B,aAAa,EACb,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,cAAc,GACf,MAAM,cAAc,CAAC;AAEtB,YAAY;AACZ,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EACL,QAAQ,EACR,WAAW,EACX,mBAAmB,EACnB,YAAY,EACZ,WAAW,EACX,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAQ/B,OAAO,EACL,uBAAuB,EACvB,yBAAyB,EACzB,uBAAuB,EACvB,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,yBAAyB,CAAC;AAIjC,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,gBAAgB,EAChB,qBAAqB,EACrB,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,sBAAsB,CAAC;AAK9B,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,yBAAyB,GAC1B,MAAM,0BAA0B,CAAC;AAUlC,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,cAAc,EACd,wBAAwB,GACzB,MAAM,2BAA2B,CAAC;AASnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACnF,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,wBAAwB,EAA4B,MAAM,aAAa,CAAC;AAEjF,iBAAiB;AACjB,OAAO,EACL,4BAA4B,EAC5B,2BAA2B,EAC3B,2BAA2B,GAE5B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,0BAA0B,EAC1B,yBAAyB,EACzB,0BAA0B,GAE3B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EACL,6BAA6B,GAE9B,MAAM,4CAA4C,CAAC;AACpD,OAAO,EACL,6BAA6B,EAC7B,qBAAqB,EACrB,mBAAmB,GAEpB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAuCA,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,uBAAuB,EACvB,QAAQ,EACR,mBAAmB,EACnB,KAAK,EACL,WAAW,EACX,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,0BAA0B,EAC1B,aAAa,EACb,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,cAAc,GACf,MAAM,cAAc,CAAC;AAEtB,YAAY;AACZ,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EACL,QAAQ,EACR,WAAW,EACX,mBAAmB,EACnB,YAAY,EACZ,WAAW,EACX,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAQ/B,OAAO,EACL,uBAAuB,EACvB,yBAAyB,EACzB,uBAAuB,EACvB,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,yBAAyB,CAAC;AAIjC,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,gBAAgB,EAChB,qBAAqB,EACrB,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,sBAAsB,CAAC;AAK9B,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,yBAAyB,GAC1B,MAAM,0BAA0B,CAAC;AAUlC,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,cAAc,EACd,wBAAwB,GACzB,MAAM,2BAA2B,CAAC;AASnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACnF,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,wBAAwB,EAA4B,MAAM,aAAa,CAAC;AAEjF,iBAAiB;AACjB,OAAO,EACL,4BAA4B,EAC5B,2BAA2B,EAC3B,2BAA2B,GAE5B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,0BAA0B,EAC1B,yBAAyB,EACzB,0BAA0B,GAE3B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EACL,6BAA6B,GAE9B,MAAM,4CAA4C,CAAC;AACpD,OAAO,EACL,6BAA6B,EAC7B,qBAAqB,EACrB,mBAAmB,GAEpB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAUxC,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,mBAAmB;AACnB,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAGlD,qCAAqC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEzD,2CAA2C;AAC3C,OAAO,EACL,iBAAiB,EACjB,6BAA6B,GAE9B,MAAM,gCAAgC,CAAC;AAiBxC,OAAO,EACL,UAAU,EACV,UAAU,EACV,cAAc,EACd,aAAa,EACb,WAAW,EACX,eAAe,GAChB,MAAM,qBAAqB,CAAC"}
|
package/dist/media/gif.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gif.d.ts","sourceRoot":"","sources":["../../src/media/gif.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,uFAAuF;IACvF,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;CACnB;
|
|
1
|
+
{"version":3,"file":"gif.d.ts","sourceRoot":"","sources":["../../src/media/gif.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,uFAAuF;IACvF,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAqED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,UAAU,GAAG,mBAAmB,GAAG,IAAI,CAuFtF"}
|
package/dist/media/gif.js
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
const BROWSER_MIN_DELAY_CENTISECONDS = 10;
|
|
2
|
+
function normalizeDelayCentiseconds(delay) {
|
|
3
|
+
// Chrome clamps GIF frame delays <= 1cs to 10cs (100ms); mirror browser playback timing.
|
|
4
|
+
if (delay <= 1)
|
|
5
|
+
return BROWSER_MIN_DELAY_CENTISECONDS;
|
|
6
|
+
return Math.max(0, delay);
|
|
7
|
+
}
|
|
1
8
|
function readAscii(bytes, start, length) {
|
|
2
9
|
if (start + length > bytes.length)
|
|
3
10
|
return "";
|
|
@@ -88,7 +95,7 @@ export function parseAnimatedGifMetadata(bytes) {
|
|
|
88
95
|
const delay = readU16LE(bytes, pos + 2);
|
|
89
96
|
if (delay == null)
|
|
90
97
|
return null;
|
|
91
|
-
delaysCentiseconds.push(delay);
|
|
98
|
+
delaysCentiseconds.push(normalizeDelayCentiseconds(delay));
|
|
92
99
|
pos += 1 + blockSize;
|
|
93
100
|
if (bytes[pos] !== 0)
|
|
94
101
|
return null;
|
|
@@ -130,7 +137,7 @@ export function parseAnimatedGifMetadata(bytes) {
|
|
|
130
137
|
}
|
|
131
138
|
return null;
|
|
132
139
|
}
|
|
133
|
-
const durationSeconds = delaysCentiseconds.reduce((total, delay) => total +
|
|
140
|
+
const durationSeconds = delaysCentiseconds.reduce((total, delay) => total + delay, 0) / 100;
|
|
134
141
|
return {
|
|
135
142
|
width,
|
|
136
143
|
height,
|
package/dist/media/gif.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gif.js","sourceRoot":"","sources":["../../src/media/gif.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"gif.js","sourceRoot":"","sources":["../../src/media/gif.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reject paths that escape the `base` directory — including via symlinks.
|
|
3
|
+
*
|
|
4
|
+
* `path.resolve()` collapses `.`/`..` but does NOT dereference symlinks, so a
|
|
5
|
+
* plain prefix check (`resolved.startsWith(base + sep)`) can be defeated by a
|
|
6
|
+
* symlink that lives *inside* `base` but points outside it (e.g.
|
|
7
|
+
* `base/link -> /etc`). A downstream `readFileSync`/`writeFileSync`/`statSync`
|
|
8
|
+
* then follows that link to a file outside `base`. To close this we canonicalize
|
|
9
|
+
* both sides with `realpathSync` before comparing.
|
|
10
|
+
*
|
|
11
|
+
* The target may not exist yet (e.g. creating a new file), so we canonicalize the
|
|
12
|
+
* deepest *existing* ancestor and re-attach the trailing not-yet-existing
|
|
13
|
+
* segments. Segments that don't exist cannot be symlinks at check time, so they
|
|
14
|
+
* can't redirect the path outside `base` right now. (A symlink swapped in between
|
|
15
|
+
* this check and the subsequent fs call is an inherent TOCTOU race this helper
|
|
16
|
+
* does not, and cannot by itself, defend against.)
|
|
17
|
+
*
|
|
18
|
+
* Lives at the package root rather than under `studio-api/` because callers span
|
|
19
|
+
* layers — `studio-api` routes, the `compiler`, the CLI, and the engine — and
|
|
20
|
+
* `compiler` sits below `studio-api` in the dependency graph, so it cannot import
|
|
21
|
+
* from there without a backwards edge.
|
|
22
|
+
*/
|
|
23
|
+
export declare function isSafePath(base: string, resolved: string): boolean;
|
|
24
|
+
//# sourceMappingURL=safePath.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safePath.d.ts","sourceRoot":"","sources":["../src/safePath.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAgClE"}
|
package/dist/safePath.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { resolve, sep, join, dirname, basename } from "node:path";
|
|
2
|
+
import { realpathSync } from "node:fs";
|
|
3
|
+
/**
|
|
4
|
+
* Reject paths that escape the `base` directory — including via symlinks.
|
|
5
|
+
*
|
|
6
|
+
* `path.resolve()` collapses `.`/`..` but does NOT dereference symlinks, so a
|
|
7
|
+
* plain prefix check (`resolved.startsWith(base + sep)`) can be defeated by a
|
|
8
|
+
* symlink that lives *inside* `base` but points outside it (e.g.
|
|
9
|
+
* `base/link -> /etc`). A downstream `readFileSync`/`writeFileSync`/`statSync`
|
|
10
|
+
* then follows that link to a file outside `base`. To close this we canonicalize
|
|
11
|
+
* both sides with `realpathSync` before comparing.
|
|
12
|
+
*
|
|
13
|
+
* The target may not exist yet (e.g. creating a new file), so we canonicalize the
|
|
14
|
+
* deepest *existing* ancestor and re-attach the trailing not-yet-existing
|
|
15
|
+
* segments. Segments that don't exist cannot be symlinks at check time, so they
|
|
16
|
+
* can't redirect the path outside `base` right now. (A symlink swapped in between
|
|
17
|
+
* this check and the subsequent fs call is an inherent TOCTOU race this helper
|
|
18
|
+
* does not, and cannot by itself, defend against.)
|
|
19
|
+
*
|
|
20
|
+
* Lives at the package root rather than under `studio-api/` because callers span
|
|
21
|
+
* layers — `studio-api` routes, the `compiler`, the CLI, and the engine — and
|
|
22
|
+
* `compiler` sits below `studio-api` in the dependency graph, so it cannot import
|
|
23
|
+
* from there without a backwards edge.
|
|
24
|
+
*/
|
|
25
|
+
export function isSafePath(base, resolved) {
|
|
26
|
+
let baseReal;
|
|
27
|
+
try {
|
|
28
|
+
baseReal = realpathSync(resolve(base));
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// Base must exist and be resolvable; fail closed if not.
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
const target = resolve(resolved);
|
|
35
|
+
const trailing = [];
|
|
36
|
+
let probe = target;
|
|
37
|
+
for (;;) {
|
|
38
|
+
let ancestorReal;
|
|
39
|
+
try {
|
|
40
|
+
ancestorReal = realpathSync(probe);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
const parent = dirname(probe);
|
|
44
|
+
if (parent === probe)
|
|
45
|
+
return false; // walked past the filesystem root
|
|
46
|
+
trailing.push(basename(probe));
|
|
47
|
+
probe = parent;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
// Copy before reverse(): the array is only consumed once today, but a future
|
|
51
|
+
// edit that loops would otherwise silently misorder the rebuilt segments.
|
|
52
|
+
const targetReal = trailing.length
|
|
53
|
+
? join(ancestorReal, ...[...trailing].reverse())
|
|
54
|
+
: ancestorReal;
|
|
55
|
+
return targetReal === baseReal || targetReal.startsWith(baseReal + sep);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=safePath.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safePath.js","sourceRoot":"","sources":["../src/safePath.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,QAAgB;IACvD,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,yDAAyD;QACzD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,KAAK,GAAG,MAAM,CAAC;IAEnB,SAAS,CAAC;QACR,IAAI,YAAoB,CAAC;QACzB,IAAI,CAAC;YACH,YAAY,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QACrC,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;YAC9B,IAAI,MAAM,KAAK,KAAK;gBAAE,OAAO,KAAK,CAAC,CAAC,kCAAkC;YACtE,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;YAC/B,KAAK,GAAG,MAAM,CAAC;YACf,SAAS;QACX,CAAC;QAED,6EAA6E;QAC7E,0EAA0E;QAC1E,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM;YAChC,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAC;YAChD,CAAC,CAAC,YAAY,CAAC;QACjB,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,UAAU,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC;IAC1E,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface BackupJournalResult {
|
|
2
|
+
backupPath: string | null;
|
|
3
|
+
error?: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function backupPathForResponse(projectDir: string, backupPath: string | null): string | null;
|
|
6
|
+
export declare function snapshotBeforeWrite(projectDir: string, absPath: string, options?: {
|
|
7
|
+
keepPerFile?: number;
|
|
8
|
+
}): BackupJournalResult;
|
|
9
|
+
//# sourceMappingURL=backupJournal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backupJournal.d.ts","sourceRoot":"","sources":["../../../src/studio-api/helpers/backupJournal.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAUD,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GAAG,IAAI,GACxB,MAAM,GAAG,IAAI,CAKf;AAED,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GACrC,mBAAmB,CA0BrB"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { mkdirSync, readdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { Buffer } from "node:buffer";
|
|
3
|
+
import { join, relative } from "node:path";
|
|
4
|
+
import { isSafePath } from "./safePath.js";
|
|
5
|
+
const DEFAULT_KEEP_PER_FILE = 10;
|
|
6
|
+
function backupKeyForPath(path) {
|
|
7
|
+
return Buffer.from(path, "utf-8").toString("base64url");
|
|
8
|
+
}
|
|
9
|
+
function timestampPrefix() {
|
|
10
|
+
return new Date().toISOString().replace(/[:.]/g, "-");
|
|
11
|
+
}
|
|
12
|
+
export function backupPathForResponse(projectDir, backupPath) {
|
|
13
|
+
if (!backupPath)
|
|
14
|
+
return null;
|
|
15
|
+
const rel = relative(projectDir, backupPath);
|
|
16
|
+
if (!rel || rel.startsWith(".."))
|
|
17
|
+
return null;
|
|
18
|
+
return rel.split("\\").join("/");
|
|
19
|
+
}
|
|
20
|
+
export function snapshotBeforeWrite(projectDir, absPath, options = {}) {
|
|
21
|
+
if (!isSafePath(projectDir, absPath))
|
|
22
|
+
return { backupPath: null };
|
|
23
|
+
try {
|
|
24
|
+
const content = readFileSync(absPath);
|
|
25
|
+
const relativePath = relative(projectDir, absPath);
|
|
26
|
+
const backupDir = join(projectDir, ".hyperframes", "backup");
|
|
27
|
+
mkdirSync(backupDir, { recursive: true });
|
|
28
|
+
const backupKey = backupKeyForPath(relativePath);
|
|
29
|
+
const backupPath = nextBackupPath(backupDir, backupKey);
|
|
30
|
+
writeFileSync(backupPath, content);
|
|
31
|
+
pruneBackups(backupDir, backupKey, options.keepPerFile ?? DEFAULT_KEEP_PER_FILE);
|
|
32
|
+
return { backupPath };
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
if (error &&
|
|
36
|
+
typeof error === "object" &&
|
|
37
|
+
"code" in error &&
|
|
38
|
+
(error.code === "ENOENT" || error.code === "EISDIR")) {
|
|
39
|
+
return { backupPath: null };
|
|
40
|
+
}
|
|
41
|
+
return { backupPath: null, error: error instanceof Error ? error.message : String(error) };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function nextBackupPath(backupDir, backupKey) {
|
|
45
|
+
const base = `${timestampPrefix()}-${backupKey}`;
|
|
46
|
+
let candidate = join(backupDir, base);
|
|
47
|
+
let counter = 2;
|
|
48
|
+
while (true) {
|
|
49
|
+
try {
|
|
50
|
+
readFileSync(candidate);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
54
|
+
return candidate;
|
|
55
|
+
}
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
candidate = join(backupDir, `${base}-${counter}`);
|
|
59
|
+
counter += 1;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function pruneBackups(backupDir, backupKey, keepPerFile) {
|
|
63
|
+
const keep = Math.max(1, Math.floor(keepPerFile));
|
|
64
|
+
const suffix = `-${backupKey}`;
|
|
65
|
+
const numberedSuffix = new RegExp(`-${backupKey}-\\d+$`);
|
|
66
|
+
const matches = readdirSync(backupDir)
|
|
67
|
+
.filter((name) => name.endsWith(suffix) || numberedSuffix.test(name))
|
|
68
|
+
.map((name) => join(backupDir, name))
|
|
69
|
+
.sort((a, b) => {
|
|
70
|
+
return b.localeCompare(a);
|
|
71
|
+
});
|
|
72
|
+
for (const file of matches.slice(keep)) {
|
|
73
|
+
try {
|
|
74
|
+
unlinkSync(file);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// Backup pruning is best-effort and must not block the user's write.
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=backupJournal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backupJournal.js","sourceRoot":"","sources":["../../../src/studio-api/helpers/backupJournal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface UnsafeMutationValue {
|
|
2
|
+
path: string;
|
|
3
|
+
reason: "non-finite-number" | "null";
|
|
4
|
+
}
|
|
5
|
+
interface FindUnsafeMutationValuesOptions {
|
|
6
|
+
allowNullPath?: (path: string) => boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function findUnsafeMutationValues(value: unknown, path?: string, options?: FindUnsafeMutationValuesOptions): UnsafeMutationValue[];
|
|
9
|
+
export declare function findUnsafeDomPatchValues(value: unknown): UnsafeMutationValue[];
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=finiteMutation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finiteMutation.d.ts","sourceRoot":"","sources":["../../../src/studio-api/helpers/finiteMutation.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,mBAAmB,GAAG,MAAM,CAAC;CACtC;AAED,UAAU,+BAA+B;IACvC,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CAC3C;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,OAAO,EACd,IAAI,SAAS,EACb,OAAO,GAAE,+BAAoC,GAC5C,mBAAmB,EAAE,CAgBvB;AAID,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,EAAE,CAI9E"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export function findUnsafeMutationValues(value, path = "body", options = {}) {
|
|
2
|
+
if (value === null) {
|
|
3
|
+
return options.allowNullPath?.(path) ? [] : [{ path, reason: "null" }];
|
|
4
|
+
}
|
|
5
|
+
if (typeof value === "number") {
|
|
6
|
+
return Number.isFinite(value) ? [] : [{ path, reason: "non-finite-number" }];
|
|
7
|
+
}
|
|
8
|
+
if (!value || typeof value !== "object")
|
|
9
|
+
return [];
|
|
10
|
+
if (Array.isArray(value)) {
|
|
11
|
+
return value.flatMap((item, index) => findUnsafeMutationValues(item, `${path}[${index}]`, options));
|
|
12
|
+
}
|
|
13
|
+
return Object.entries(value).flatMap(([key, item]) => findUnsafeMutationValues(item, `${path}.${key}`, options));
|
|
14
|
+
}
|
|
15
|
+
const DOM_PATCH_NULL_VALUE_PATH = /^body\.operations\[\d+\]\.value$/;
|
|
16
|
+
export function findUnsafeDomPatchValues(value) {
|
|
17
|
+
return findUnsafeMutationValues(value, "body", {
|
|
18
|
+
allowNullPath: (path) => DOM_PATCH_NULL_VALUE_PATH.test(path),
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=finiteMutation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finiteMutation.js","sourceRoot":"","sources":["../../../src/studio-api/helpers/finiteMutation.ts"],"names":[],"mappings":"AASA,MAAM,UAAU,wBAAwB,CACtC,KAAc,EACd,IAAI,GAAG,MAAM,EACb,UAA2C,EAAE;IAE7C,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,OAAO,OAAO,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC,CAAC;IAC/E,CAAC;IACD,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IACnD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CACnC,wBAAwB,CAAC,IAAI,EAAE,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,OAAO,CAAC,CAC7D,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,CACnD,wBAAwB,CAAC,IAAI,EAAE,GAAG,IAAI,IAAI,GAAG,EAAE,EAAE,OAAO,CAAC,CAC1D,CAAC;AACJ,CAAC;AAED,MAAM,yBAAyB,GAAG,kCAAkC,CAAC;AAErE,MAAM,UAAU,wBAAwB,CAAC,KAAc;IACrD,OAAO,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE;QAC7C,aAAa,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC;KAC9D,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export { isSafePath } from "../../safePath.js";
|
|
2
|
+
/**
|
|
3
|
+
* True when any directory segment of a relative path is a dot-directory or
|
|
4
|
+
* node_modules. Projects that vendor tooling assets under dot-directories
|
|
5
|
+
* (.hyperframes/, .cache/, …) ship example/preset HTML that must not surface
|
|
6
|
+
* as project compositions or studio lint targets (#1384). The file tree is
|
|
7
|
+
* deliberately not filtered — this only gates discovery.
|
|
8
|
+
*/
|
|
9
|
+
export declare function isInHiddenOrVendorDir(relPath: string): boolean;
|
|
3
10
|
/** Recursively walk a directory and return relative file paths. */
|
|
4
11
|
export declare function walkDir(dir: string, prefix?: string): string[];
|
|
5
12
|
//# sourceMappingURL=safePath.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safePath.d.ts","sourceRoot":"","sources":["../../../src/studio-api/helpers/safePath.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"safePath.d.ts","sourceRoot":"","sources":["../../../src/studio-api/helpers/safePath.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAQ/C;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAG9D;AAED,mEAAmE;AACnE,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,SAAK,GAAG,MAAM,EAAE,CAY1D"}
|
|
@@ -1,18 +1,31 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { join } from "node:path";
|
|
2
2
|
import { readdirSync } from "node:fs";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
3
|
+
// `isSafePath` lives at the package root so non-studio-api layers (compiler,
|
|
4
|
+
// CLI, engine) can share it without a backwards dependency on studio-api.
|
|
5
|
+
// Re-exported here for back-compat with existing `../helpers/safePath.js` imports.
|
|
6
|
+
export { isSafePath } from "../../safePath.js";
|
|
8
7
|
const IGNORE_DIRS = new Set([".thumbnails", "node_modules", ".git"]);
|
|
8
|
+
function shouldIgnoreDir(rel) {
|
|
9
|
+
return rel === ".hyperframes/backup";
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* True when any directory segment of a relative path is a dot-directory or
|
|
13
|
+
* node_modules. Projects that vendor tooling assets under dot-directories
|
|
14
|
+
* (.hyperframes/, .cache/, …) ship example/preset HTML that must not surface
|
|
15
|
+
* as project compositions or studio lint targets (#1384). The file tree is
|
|
16
|
+
* deliberately not filtered — this only gates discovery.
|
|
17
|
+
*/
|
|
18
|
+
export function isInHiddenOrVendorDir(relPath) {
|
|
19
|
+
const segments = relPath.split("/");
|
|
20
|
+
return segments.slice(0, -1).some((seg) => seg.startsWith(".") || seg === "node_modules");
|
|
21
|
+
}
|
|
9
22
|
/** Recursively walk a directory and return relative file paths. */
|
|
10
23
|
export function walkDir(dir, prefix = "") {
|
|
11
24
|
const files = [];
|
|
12
25
|
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
13
|
-
if (IGNORE_DIRS.has(entry.name))
|
|
14
|
-
continue;
|
|
15
26
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
27
|
+
if (IGNORE_DIRS.has(entry.name) || shouldIgnoreDir(rel))
|
|
28
|
+
continue;
|
|
16
29
|
if (entry.isDirectory()) {
|
|
17
30
|
files.push(...walkDir(join(dir, entry.name), rel));
|
|
18
31
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safePath.js","sourceRoot":"","sources":["../../../src/studio-api/helpers/safePath.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"safePath.js","sourceRoot":"","sources":["../../../src/studio-api/helpers/safePath.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEtC,6EAA6E;AAC7E,0EAA0E;AAC1E,mFAAmF;AACnF,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,aAAa,EAAE,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC;AAErE,SAAS,eAAe,CAAC,GAAW;IAClC,OAAO,GAAG,KAAK,qBAAqB,CAAC;AACvC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAe;IACnD,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpC,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,KAAK,cAAc,CAAC,CAAC;AAC5F,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,OAAO,CAAC,GAAW,EAAE,MAAM,GAAG,EAAE;IAC9C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAC9D,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;QAC5D,IAAI,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,eAAe,CAAC,GAAG,CAAC;YAAE,SAAS;QAClE,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QACrD,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../../src/studio-api/routes/files.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAcjC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../../src/studio-api/routes/files.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAcjC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAuyBpD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,gBAAgB,GAAG,IAAI,CA2Y7E"}
|
|
@@ -5,6 +5,8 @@ import { isAudioFile } from "../helpers/mime.js";
|
|
|
5
5
|
import { generateWaveformCache } from "../helpers/waveform.js";
|
|
6
6
|
import { validateUploadedMediaBuffer } from "../helpers/mediaValidation.js";
|
|
7
7
|
import { isSafePath } from "../helpers/safePath.js";
|
|
8
|
+
import { backupPathForResponse, snapshotBeforeWrite } from "../helpers/backupJournal.js";
|
|
9
|
+
import { findUnsafeDomPatchValues, findUnsafeMutationValues, } from "../helpers/finiteMutation.js";
|
|
8
10
|
import { removeElementFromHtml, patchElementInHtml, probeElementInSource, splitElementInHtml, } from "../helpers/sourceMutation.js";
|
|
9
11
|
import { parseHTML } from "linkedom";
|
|
10
12
|
/** Resolve project + safe absolute path for any project-scoped route. */
|
|
@@ -34,12 +36,28 @@ function resolveFileMutationContext(c, adapter, operation) {
|
|
|
34
36
|
return resolveProjectPath(c, adapter, (id) => `/projects/${id}/file-mutations/${operation}/`);
|
|
35
37
|
}
|
|
36
38
|
/** Write `next` to `absPath` only if it differs from `original`, returning a standardized change response. */
|
|
37
|
-
function writeIfChanged(c, absPath, original, next) {
|
|
39
|
+
function writeIfChanged(c, projectDir, filePath, absPath, original, next) {
|
|
38
40
|
if (next === original) {
|
|
39
|
-
return c.json({ ok: true, changed: false, content: original });
|
|
41
|
+
return c.json({ ok: true, changed: false, content: original, path: filePath });
|
|
40
42
|
}
|
|
43
|
+
const backup = snapshotBeforeWrite(projectDir, absPath);
|
|
44
|
+
if (backup.error)
|
|
45
|
+
console.warn(`Failed to create backup for ${filePath}: ${backup.error}`);
|
|
41
46
|
writeFileSync(absPath, next, "utf-8");
|
|
42
|
-
return c.json({
|
|
47
|
+
return c.json({
|
|
48
|
+
ok: true,
|
|
49
|
+
changed: true,
|
|
50
|
+
content: next,
|
|
51
|
+
path: filePath,
|
|
52
|
+
backupPath: backupPathForResponse(projectDir, backup.backupPath),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function rejectUnsafeMutationValues(c, unsafeFields) {
|
|
56
|
+
return c.json({
|
|
57
|
+
error: "mutation contains unsafe values",
|
|
58
|
+
fields: unsafeFields.map((field) => field.path),
|
|
59
|
+
unsafeValues: unsafeFields,
|
|
60
|
+
}, 400);
|
|
43
61
|
}
|
|
44
62
|
/**
|
|
45
63
|
* Parse the request body and validate that `target` is present.
|
|
@@ -483,8 +501,15 @@ export function registerFileRoutes(api, adapter) {
|
|
|
483
501
|
return res.error;
|
|
484
502
|
ensureDir(res.absPath);
|
|
485
503
|
const body = await c.req.text();
|
|
504
|
+
const backup = snapshotBeforeWrite(res.project.dir, res.absPath);
|
|
505
|
+
if (backup.error)
|
|
506
|
+
console.warn(`Failed to create backup for ${res.filePath}: ${backup.error}`);
|
|
486
507
|
writeFileSync(res.absPath, body, "utf-8");
|
|
487
|
-
return c.json({
|
|
508
|
+
return c.json({
|
|
509
|
+
ok: true,
|
|
510
|
+
path: res.filePath,
|
|
511
|
+
backupPath: backupPathForResponse(res.project.dir, backup.backupPath),
|
|
512
|
+
});
|
|
488
513
|
});
|
|
489
514
|
// ── Create (fail if exists) ──
|
|
490
515
|
api.post("/projects/:id/files/*", async (c) => {
|
|
@@ -505,13 +530,19 @@ export function registerFileRoutes(api, adapter) {
|
|
|
505
530
|
if ("error" in res)
|
|
506
531
|
return res.error;
|
|
507
532
|
const stat = statSync(res.absPath);
|
|
533
|
+
const backup = snapshotBeforeWrite(res.project.dir, res.absPath);
|
|
534
|
+
if (backup.error)
|
|
535
|
+
console.warn(`Failed to create backup for ${res.filePath}: ${backup.error}`);
|
|
508
536
|
if (stat.isDirectory()) {
|
|
509
537
|
rmSync(res.absPath, { recursive: true });
|
|
510
538
|
}
|
|
511
539
|
else {
|
|
512
540
|
unlinkSync(res.absPath);
|
|
513
541
|
}
|
|
514
|
-
return c.json({
|
|
542
|
+
return c.json({
|
|
543
|
+
ok: true,
|
|
544
|
+
backupPath: backupPathForResponse(res.project.dir, backup.backupPath),
|
|
545
|
+
});
|
|
515
546
|
});
|
|
516
547
|
api.post("/projects/:id/file-mutations/remove-element/*", async (c) => {
|
|
517
548
|
const ctx = await resolveFileMutationContext(c, adapter, "remove-element");
|
|
@@ -524,7 +555,7 @@ export function registerFileRoutes(api, adapter) {
|
|
|
524
555
|
if ("error" in parsed)
|
|
525
556
|
return parsed.error;
|
|
526
557
|
const originalContent = readFileSync(ctx.absPath, "utf-8");
|
|
527
|
-
return writeIfChanged(c, ctx.absPath, originalContent, removeElementFromHtml(originalContent, parsed.target));
|
|
558
|
+
return writeIfChanged(c, ctx.project.dir, ctx.filePath, ctx.absPath, originalContent, removeElementFromHtml(originalContent, parsed.target));
|
|
528
559
|
});
|
|
529
560
|
api.post("/projects/:id/file-mutations/split-element/*", async (c) => {
|
|
530
561
|
const ctx = await resolveFileMutationContext(c, adapter, "split-element");
|
|
@@ -545,10 +576,20 @@ export function registerFileRoutes(api, adapter) {
|
|
|
545
576
|
}
|
|
546
577
|
const result = splitElementInHtml(originalContent, parsed.target, parsed.body.splitTime, parsed.body.newId);
|
|
547
578
|
if (!result.matched) {
|
|
548
|
-
return c.json({ ok: false, changed: false, content: originalContent });
|
|
579
|
+
return c.json({ ok: false, changed: false, content: originalContent, path: ctx.filePath });
|
|
549
580
|
}
|
|
581
|
+
const backup = snapshotBeforeWrite(ctx.project.dir, ctx.absPath);
|
|
582
|
+
if (backup.error)
|
|
583
|
+
console.warn(`Failed to create backup for ${ctx.filePath}: ${backup.error}`);
|
|
550
584
|
writeFileSync(ctx.absPath, result.html, "utf-8");
|
|
551
|
-
return c.json({
|
|
585
|
+
return c.json({
|
|
586
|
+
ok: true,
|
|
587
|
+
changed: true,
|
|
588
|
+
content: result.html,
|
|
589
|
+
newId: result.newId,
|
|
590
|
+
path: ctx.filePath,
|
|
591
|
+
backupPath: backupPathForResponse(ctx.project.dir, backup.backupPath),
|
|
592
|
+
});
|
|
552
593
|
});
|
|
553
594
|
api.post("/projects/:id/file-mutations/patch-element/*", async (c) => {
|
|
554
595
|
const ctx = await resolveFileMutationContext(c, adapter, "patch-element");
|
|
@@ -560,6 +601,10 @@ export function registerFileRoutes(api, adapter) {
|
|
|
560
601
|
if (!Array.isArray(parsed.body.operations) || parsed.body.operations.length === 0) {
|
|
561
602
|
return c.json({ error: "target and operations required" }, 400);
|
|
562
603
|
}
|
|
604
|
+
const unsafeFields = findUnsafeDomPatchValues(parsed.body);
|
|
605
|
+
if (unsafeFields.length > 0) {
|
|
606
|
+
return rejectUnsafeMutationValues(c, unsafeFields);
|
|
607
|
+
}
|
|
563
608
|
let originalContent;
|
|
564
609
|
try {
|
|
565
610
|
originalContent = readFileSync(ctx.absPath, "utf-8");
|
|
@@ -569,10 +614,26 @@ export function registerFileRoutes(api, adapter) {
|
|
|
569
614
|
}
|
|
570
615
|
const { html: patched, matched } = patchElementInHtml(originalContent, parsed.target, parsed.body.operations);
|
|
571
616
|
if (patched === originalContent) {
|
|
572
|
-
return c.json({
|
|
617
|
+
return c.json({
|
|
618
|
+
ok: true,
|
|
619
|
+
changed: false,
|
|
620
|
+
matched,
|
|
621
|
+
content: originalContent,
|
|
622
|
+
path: ctx.filePath,
|
|
623
|
+
});
|
|
573
624
|
}
|
|
625
|
+
const backup = snapshotBeforeWrite(ctx.project.dir, ctx.absPath);
|
|
626
|
+
if (backup.error)
|
|
627
|
+
console.warn(`Failed to create backup for ${ctx.filePath}: ${backup.error}`);
|
|
574
628
|
writeFileSync(ctx.absPath, patched, "utf-8");
|
|
575
|
-
return c.json({
|
|
629
|
+
return c.json({
|
|
630
|
+
ok: true,
|
|
631
|
+
changed: true,
|
|
632
|
+
matched,
|
|
633
|
+
content: patched,
|
|
634
|
+
path: ctx.filePath,
|
|
635
|
+
backupPath: backupPathForResponse(ctx.project.dir, backup.backupPath),
|
|
636
|
+
});
|
|
576
637
|
});
|
|
577
638
|
api.post("/projects/:id/file-mutations/probe-element/*", async (c) => {
|
|
578
639
|
const ctx = await resolveFileMutationContext(c, adapter, "probe-element");
|
|
@@ -687,6 +748,10 @@ export function registerFileRoutes(api, adapter) {
|
|
|
687
748
|
if (!body || !body.type) {
|
|
688
749
|
return c.json({ error: "mutation type required" }, 400);
|
|
689
750
|
}
|
|
751
|
+
const unsafeFields = findUnsafeMutationValues(body);
|
|
752
|
+
if (unsafeFields.length > 0) {
|
|
753
|
+
return rejectUnsafeMutationValues(c, unsafeFields);
|
|
754
|
+
}
|
|
690
755
|
let html = readFileSync(res.absPath, "utf-8");
|
|
691
756
|
let block = extractGsapScriptBlock(html);
|
|
692
757
|
if (!block && (body.type === "add" || body.type === "add-with-keyframes")) {
|
|
@@ -721,7 +786,12 @@ export function registerFileRoutes(api, adapter) {
|
|
|
721
786
|
const newScript = typeof result === "string" ? result : result.script;
|
|
722
787
|
const changed = newScript !== block.scriptText;
|
|
723
788
|
const newHtml = changed ? block.replaceScript(newScript) : html;
|
|
789
|
+
let backupPath = null;
|
|
724
790
|
if (changed) {
|
|
791
|
+
const backup = snapshotBeforeWrite(res.project.dir, res.absPath);
|
|
792
|
+
if (backup.error)
|
|
793
|
+
console.warn(`Failed to create backup for ${res.filePath}: ${backup.error}`);
|
|
794
|
+
backupPath = backupPathForResponse(res.project.dir, backup.backupPath);
|
|
725
795
|
writeFileSync(res.absPath, newHtml, "utf-8");
|
|
726
796
|
}
|
|
727
797
|
const { parseGsapScript } = await loadGsapParser();
|
|
@@ -733,6 +803,8 @@ export function registerFileRoutes(api, adapter) {
|
|
|
733
803
|
before: html,
|
|
734
804
|
after: newHtml,
|
|
735
805
|
scriptText: newScript,
|
|
806
|
+
path: res.filePath,
|
|
807
|
+
backupPath,
|
|
736
808
|
};
|
|
737
809
|
if (typeof result !== "string" && result.skippedSelectors.length > 0) {
|
|
738
810
|
responsePayload.skippedSelectors = result.skippedSelectors;
|