@hyperframes/studio-server 0.7.60 → 0.7.61

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.
Files changed (40) hide show
  1. package/dist/chunk-4ETS2LXI.js +192 -0
  2. package/dist/chunk-4ETS2LXI.js.map +1 -0
  3. package/dist/chunk-6XMC64FJ.js +584 -0
  4. package/dist/chunk-6XMC64FJ.js.map +1 -0
  5. package/dist/chunk-LVXVG4V6.js +282 -0
  6. package/dist/chunk-LVXVG4V6.js.map +1 -0
  7. package/dist/chunk-W2SBTCO2.js +32 -0
  8. package/dist/chunk-W2SBTCO2.js.map +1 -0
  9. package/dist/chunk-X62ASOGO.js +30 -0
  10. package/dist/chunk-X62ASOGO.js.map +1 -0
  11. package/dist/chunk-XVQX2JHE.js +422 -0
  12. package/dist/chunk-XVQX2JHE.js.map +1 -0
  13. package/dist/chunk-YBR7MXIO.js +459 -0
  14. package/dist/chunk-YBR7MXIO.js.map +1 -0
  15. package/dist/chunk-ZUW4PULZ.js +66 -0
  16. package/dist/chunk-ZUW4PULZ.js.map +1 -0
  17. package/dist/helpers/finiteMutation.js +4 -24
  18. package/dist/helpers/finiteMutation.js.map +1 -1
  19. package/dist/helpers/manualEditsRenderScript.js +5 -577
  20. package/dist/helpers/manualEditsRenderScript.js.map +1 -1
  21. package/dist/helpers/mediaCodecMap.d.ts +100 -0
  22. package/dist/helpers/mediaCodecMap.js +25 -0
  23. package/dist/helpers/mediaCodecMap.js.map +1 -0
  24. package/dist/helpers/mediaProxyPreview.d.ts +4 -0
  25. package/dist/helpers/mediaProxyPreview.js +17 -0
  26. package/dist/helpers/mediaProxyPreview.js.map +1 -0
  27. package/dist/helpers/proxyTranscoder.d.ts +61 -0
  28. package/dist/helpers/proxyTranscoder.js +30 -0
  29. package/dist/helpers/proxyTranscoder.js.map +1 -0
  30. package/dist/helpers/screenshotClip.js +3 -22
  31. package/dist/helpers/screenshotClip.js.map +1 -1
  32. package/dist/helpers/sourceMutation.js +9 -419
  33. package/dist/helpers/sourceMutation.js.map +1 -1
  34. package/dist/helpers/studioMotionRenderScript.js +4 -186
  35. package/dist/helpers/studioMotionRenderScript.js.map +1 -1
  36. package/dist/index.d.ts +6 -202
  37. package/dist/index.js +172 -1373
  38. package/dist/index.js.map +1 -1
  39. package/dist/mediaProxyPreview-CeshDUjE.d.ts +259 -0
  40. package/package.json +15 -3
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/helpers/manualEditsRenderScript.ts"],"sourcesContent":["// fallow-ignore-file code-duplication\nexport interface StudioManualEditsRenderScriptOptions {\n activeCompositionPath?: string | null;\n}\n\nexport const STUDIO_MANUAL_EDITS_PATH = \".hyperframes/studio-manual-edits.json\";\n\nexport function createStudioManualEditsRenderBodyScript(\n manifestContent: string,\n options: StudioManualEditsRenderScriptOptions = {},\n): string | null {\n if (!manifestContent.trim()) return null;\n return `(${studioManualEditsRenderRuntime.toString()})(${JSON.stringify(manifestContent)}, ${JSON.stringify(options.activeCompositionPath ?? null)});`;\n}\n\n/**\n * Returns a self-contained IIFE string that re-applies studio position edits\n * (translate, rotate) after every GSAP seek by querying data attributes baked\n * into the HTML. Works without a JSON manifest — positions are already inlined\n * as CSS custom properties on the elements.\n */\nexport function createStudioPositionSeekReapplyScript(): string {\n return `(${studioPositionSeekReapplyRuntime.toString()})();`;\n}\n\nfunction studioPositionSeekReapplyRuntime(): void {\n const OFFSET_X_PROP = \"--hf-studio-offset-x\";\n const OFFSET_Y_PROP = \"--hf-studio-offset-y\";\n const WIDTH_PROP = \"--hf-studio-width\";\n const HEIGHT_PROP = \"--hf-studio-height\";\n const ROTATION_PROP = \"--hf-studio-rotation\";\n const PATH_OFFSET_ATTR = \"data-hf-studio-path-offset\";\n const BOX_SIZE_ATTR = \"data-hf-studio-box-size\";\n const ROTATION_ATTR = \"data-hf-studio-rotation\";\n const ORIGINAL_TRANSLATE_ATTR = \"data-hf-studio-original-translate\";\n const ORIGINAL_ROTATE_ATTR = \"data-hf-studio-original-rotate\";\n const MOTION_ATTR = \"data-hf-studio-motion\";\n const MOTION_TL_KEY = \"studio-motion\";\n const WRAPPED_PROP = \"__hfStudioPositionSeekReapplyWrapped\";\n\n if (\n !document.querySelector(\"[\" + PATH_OFFSET_ATTR + '=\"true\"]') &&\n !document.querySelector(\"[\" + BOX_SIZE_ATTR + '=\"true\"]') &&\n !document.querySelector(\"[\" + ROTATION_ATTR + '=\"true\"]') &&\n !document.querySelector(\"[\" + MOTION_ATTR + \"]\")\n )\n return;\n\n const splitTopLevelWhitespace = (value: string): string[] => {\n const parts: string[] = [];\n let depth = 0;\n let current = \"\";\n for (const char of value.trim()) {\n if (char === \"(\") depth += 1;\n if (char === \")\") depth = Math.max(0, depth - 1);\n if (/\\s/.test(char) && depth === 0) {\n if (current) parts.push(current);\n current = \"\";\n } else {\n current += char;\n }\n }\n if (current) parts.push(current);\n return parts;\n };\n\n const composeTranslate = (element: HTMLElement, x: string, y: string): string => {\n const original = element.getAttribute(ORIGINAL_TRANSLATE_ATTR)?.trim();\n if (!original || original === \"none\") return x + \" \" + y;\n const parts = splitTopLevelWhitespace(original);\n if (parts.length === 1) return \"calc(\" + parts[0] + \" + \" + x + \") \" + y;\n if (parts.length >= 2) {\n const z = parts.length >= 3 ? \" \" + parts[2] : \"\";\n return \"calc(\" + parts[0] + \" + \" + x + \") calc(\" + parts[1] + \" + \" + y + \")\" + z;\n }\n return x + \" \" + y;\n };\n\n const isSimpleRotateAngle = (value: string): boolean =>\n /^-?(?:\\d+(?:\\.\\d+)?|\\.\\d+)(?:deg|rad|turn|grad)$/.test(value.trim());\n\n const composeRotation = (element: HTMLElement, rotationValue: string): string => {\n const original = element.getAttribute(ORIGINAL_ROTATE_ATTR)?.trim();\n if (!original || original === \"none\" || !isSimpleRotateAngle(original)) return rotationValue;\n return \"calc(\" + original + \" + \" + rotationValue + \")\";\n };\n\n let lastSeekTime = 0;\n let cachedMotionKey = \"\";\n\n const finiteNum = (v: unknown): number | null =>\n typeof v === \"number\" && Number.isFinite(v) ? v : null;\n\n const computeMotionKey = (motionEls: NodeListOf<Element>): string => {\n let key = \"\";\n for (let i = 0; i < motionEls.length; i++) {\n const json = (motionEls[i] as HTMLElement).getAttribute?.(MOTION_ATTR);\n if (json) key += (key ? \"\\n\" : \"\") + json;\n }\n return key;\n };\n\n const reapplyMotionTimeline = (): void => {\n const motionEls = document.querySelectorAll(\"[\" + MOTION_ATTR + \"]\");\n if (motionEls.length === 0) {\n cachedMotionKey = \"\";\n return;\n }\n const win = window as Window & {\n gsap?: {\n timeline?: (opts: Record<string, unknown>) => Record<string, unknown>;\n set?: (el: HTMLElement, vars: Record<string, unknown>) => void;\n registerPlugin?: (plugin: unknown) => void;\n };\n CustomEase?: { create?: (id: string, data: string) => void };\n __timelines?: Record<string, Record<string, unknown>>;\n };\n const gsap = win.gsap;\n if (!gsap || typeof gsap.timeline !== \"function\") return;\n win.__timelines = win.__timelines || {};\n\n // Cache the timeline keyed by the concatenated motion JSON strings.\n // On each seek, if the key hasn't changed, just seek the existing timeline\n // instead of rebuilding it (avoids kill+recreate on every frame).\n const motionKey = computeMotionKey(motionEls);\n const existing = win.__timelines[MOTION_TL_KEY];\n if (\n motionKey &&\n motionKey === cachedMotionKey &&\n existing &&\n typeof existing.totalTime === \"function\"\n ) {\n (existing.totalTime as (t: number, s: boolean) => void)(lastSeekTime, false);\n return;\n }\n\n if (existing && typeof existing.kill === \"function\") (existing.kill as () => void)();\n const tl = gsap.timeline({ paused: true, defaults: { overwrite: \"auto\" } });\n const fromTo = tl.fromTo as (\n el: HTMLElement,\n from: Record<string, unknown>,\n to: Record<string, unknown>,\n pos: number,\n ) => void;\n if (typeof fromTo !== \"function\") return;\n let applied = 0;\n for (let i = 0; i < motionEls.length; i++) {\n const el = motionEls[i] as HTMLElement;\n if (!(el instanceof HTMLElement)) continue;\n const json = el.getAttribute(MOTION_ATTR);\n if (!json) continue;\n try {\n const m = JSON.parse(json) as Record<string, unknown>;\n const start = finiteNum(m.start);\n const duration = finiteNum(m.duration);\n if (start == null || duration == null || duration <= 0) continue;\n const ease = typeof m.ease === \"string\" ? m.ease : \"none\";\n const from = (m.from && typeof m.from === \"object\" ? m.from : {}) as Record<\n string,\n unknown\n >;\n const to = (m.to && typeof m.to === \"object\" ? m.to : {}) as Record<string, unknown>;\n const customEase = m.customEase as { id?: string; data?: string } | null | undefined;\n let resolvedEase = ease;\n if (customEase?.id && customEase?.data && win.CustomEase?.create) {\n try {\n gsap.registerPlugin?.(win.CustomEase);\n win.CustomEase.create(customEase.id, customEase.data);\n resolvedEase = customEase.id;\n } catch {\n /* use default ease */\n }\n }\n fromTo.call(\n tl,\n el,\n { ...from },\n { ...to, duration, ease: resolvedEase, overwrite: \"auto\", immediateRender: false },\n start,\n );\n applied += 1;\n } catch {\n /* malformed JSON — skip */\n }\n }\n if (applied === 0) {\n cachedMotionKey = \"\";\n if (typeof (tl as { kill?: () => void }).kill === \"function\")\n (tl as { kill: () => void }).kill();\n return;\n }\n cachedMotionKey = motionKey;\n win.__timelines[MOTION_TL_KEY] = tl;\n if (typeof tl.pause === \"function\") (tl.pause as () => void)();\n if (typeof tl.totalTime === \"function\")\n (tl.totalTime as (t: number, s: boolean) => void)(lastSeekTime, false);\n };\n\n const stripGsapTranslateFromTransform = (el: HTMLElement): void => {\n const transform = el.style.getPropertyValue(\"transform\");\n if (!transform || transform === \"none\") return;\n const win = el.ownerDocument.defaultView as (Window & typeof globalThis) | null;\n const MatrixCtor = (win as unknown as { DOMMatrix?: typeof DOMMatrix })?.DOMMatrix;\n if (!MatrixCtor) return;\n try {\n const m = new MatrixCtor(transform);\n if (m.m41 === 0 && m.m42 === 0) return;\n m.m41 = 0;\n m.m42 = 0;\n if (m.is2D && m.a === 1 && m.b === 0 && m.c === 0 && m.d === 1) {\n el.style.removeProperty(\"transform\");\n } else {\n el.style.setProperty(\"transform\", m.toString());\n }\n } catch {\n /* non-parseable transform — leave as-is */\n }\n };\n\n const reapplyAll = (): void => {\n const offsetEls = document.querySelectorAll(\"[\" + PATH_OFFSET_ATTR + '=\"true\"]');\n for (let i = 0; i < offsetEls.length; i++) {\n const el = offsetEls[i] as HTMLElement;\n if (!(el instanceof HTMLElement)) continue;\n const x = el.style.getPropertyValue(OFFSET_X_PROP);\n const y = el.style.getPropertyValue(OFFSET_Y_PROP);\n if (x || y) {\n el.style.setProperty(\n \"translate\",\n composeTranslate(\n el,\n \"var(\" + OFFSET_X_PROP + \", 0px)\",\n \"var(\" + OFFSET_Y_PROP + \", 0px)\",\n ),\n );\n stripGsapTranslateFromTransform(el);\n }\n }\n const boxSizeEls = document.querySelectorAll(\"[\" + BOX_SIZE_ATTR + '=\"true\"]');\n for (let i = 0; i < boxSizeEls.length; i++) {\n const el = boxSizeEls[i] as HTMLElement;\n if (!(el instanceof HTMLElement)) continue;\n const w = el.style.getPropertyValue(WIDTH_PROP);\n const h = el.style.getPropertyValue(HEIGHT_PROP);\n if (w) el.style.setProperty(\"width\", w);\n if (h) el.style.setProperty(\"height\", h);\n }\n const rotEls = document.querySelectorAll(\"[\" + ROTATION_ATTR + '=\"true\"]');\n for (let i = 0; i < rotEls.length; i++) {\n const el = rotEls[i] as HTMLElement;\n if (!(el instanceof HTMLElement)) continue;\n const rot = el.style.getPropertyValue(ROTATION_PROP);\n if (rot) {\n el.style.setProperty(\"rotate\", composeRotation(el, \"var(\" + ROTATION_PROP + \", 0deg)\"));\n stripGsapTranslateFromTransform(el);\n }\n }\n reapplyMotionTimeline();\n };\n\n const runtimeWindow = window as Window & {\n __hf?: Record<string, unknown>;\n __player?: Record<string, unknown>;\n };\n\n const isWrapped = (fn: (time: number) => unknown): boolean =>\n Boolean((fn as unknown as Record<string, unknown>)[WRAPPED_PROP]);\n\n const markWrapped = (fn: (time: number) => unknown): void => {\n try {\n Object.defineProperty(fn, WRAPPED_PROP, {\n configurable: false,\n enumerable: false,\n value: true,\n });\n } catch {\n try {\n (fn as unknown as Record<string, unknown>)[WRAPPED_PROP] = true;\n } catch {\n /* ignore */\n }\n }\n };\n\n const wrapFn = (get: () => unknown, set: (fn: (time: number) => unknown) => void): boolean => {\n const fn = get();\n if (typeof fn !== \"function\") return false;\n const seek = fn as (time: number) => unknown;\n if (isWrapped(seek)) {\n reapplyAll();\n return true;\n }\n const wrapped = function (this: unknown, time: number): unknown {\n lastSeekTime = typeof time === \"number\" && Number.isFinite(time) ? Math.max(0, time) : 0;\n const result = seek.call(this, time);\n reapplyAll();\n return result;\n };\n markWrapped(wrapped);\n set(wrapped);\n reapplyAll();\n return true;\n };\n\n const wrapSeekFunctions = (): boolean => {\n const a = wrapFn(\n () => runtimeWindow.__hf?.[\"seek\"],\n (fn) => {\n if (runtimeWindow.__hf) runtimeWindow.__hf[\"seek\"] = fn;\n },\n );\n const b = wrapFn(\n () => runtimeWindow.__player?.[\"renderSeek\"],\n (fn) => {\n if (runtimeWindow.__player) runtimeWindow.__player[\"renderSeek\"] = fn;\n },\n );\n return a || b;\n };\n\n const installSeekTrap = (\n obj: Record<string, unknown> | undefined,\n key: string,\n getter: () => unknown,\n setter: (fn: (time: number) => unknown) => void,\n ): void => {\n if (!obj) return;\n try {\n let current = obj[key];\n Object.defineProperty(obj, key, {\n configurable: true,\n enumerable: true,\n get() {\n return current;\n },\n set(value: unknown) {\n current = value;\n if (typeof value === \"function\" && !isWrapped(value as (time: number) => unknown)) {\n wrapFn(getter, setter);\n }\n },\n });\n } catch {\n /* non-configurable — fall back to polling */\n }\n };\n\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", () => reapplyAll(), { once: true });\n } else {\n reapplyAll();\n }\n\n wrapSeekFunctions();\n installSeekTrap(\n runtimeWindow.__hf,\n \"seek\",\n () => runtimeWindow.__hf?.[\"seek\"],\n (fn) => {\n if (runtimeWindow.__hf) runtimeWindow.__hf[\"seek\"] = fn;\n },\n );\n installSeekTrap(\n runtimeWindow.__player as Record<string, unknown> | undefined,\n \"renderSeek\",\n () => runtimeWindow.__player?.[\"renderSeek\"],\n (fn) => {\n if (runtimeWindow.__player) runtimeWindow.__player[\"renderSeek\"] = fn;\n },\n );\n let remaining = 120;\n const interval = setInterval(() => {\n wrapSeekFunctions();\n remaining -= 1;\n if (remaining <= 0) clearInterval(interval);\n }, 50);\n}\n\nfunction studioManualEditsRenderRuntime(\n manifestContent: string,\n activeCompositionPath: string | null,\n): void {\n const OFFSET_X_PROP = \"--hf-studio-offset-x\";\n const OFFSET_Y_PROP = \"--hf-studio-offset-y\";\n const WIDTH_PROP = \"--hf-studio-width\";\n const HEIGHT_PROP = \"--hf-studio-height\";\n const ROTATION_PROP = \"--hf-studio-rotation\";\n const PATH_OFFSET_ATTR = \"data-hf-studio-path-offset\";\n const BOX_SIZE_ATTR = \"data-hf-studio-box-size\";\n const ROTATION_ATTR = \"data-hf-studio-rotation\";\n const ORIGINAL_TRANSLATE_ATTR = \"data-hf-studio-original-translate\";\n const ORIGINAL_ROTATE_ATTR = \"data-hf-studio-original-rotate\";\n const WRAPPED_SEEK_PROP = \"__hfStudioManualEditsWrapped\";\n const ROTATION_TRANSFORM_ORIGIN = \"center center\";\n\n const finiteNumber = (value: unknown): number | null =>\n typeof value === \"number\" && Number.isFinite(value) ? value : null;\n\n const objectRecord = (value: unknown): Record<string, unknown> | null =>\n value && typeof value === \"object\" ? (value as Record<string, unknown>) : null;\n\n const runtimeWindow = window as Window & {\n __hf?: { seek?: (time: number) => unknown };\n __hfStudioManualEditsApply?: () => number;\n __player?: { renderSeek?: (time: number) => unknown };\n };\n\n const parsedManifest = (() => {\n try {\n return objectRecord(JSON.parse(manifestContent));\n } catch {\n return null;\n }\n })();\n const manifestEdits = Array.isArray(parsedManifest?.edits) ? parsedManifest.edits : [];\n if (manifestEdits.length === 0) return;\n\n const sourceFileForElement = (element: HTMLElement): string => {\n let current: HTMLElement | null = element;\n while (current) {\n const sourceFile =\n current.getAttribute(\"data-composition-file\") ??\n current.getAttribute(\"data-composition-src\");\n if (sourceFile) return sourceFile;\n current = current.parentElement;\n }\n return activeCompositionPath ?? \"index.html\";\n };\n\n const elementMatchesSourceFile = (element: HTMLElement, sourceFile: string): boolean =>\n sourceFileForElement(element) === sourceFile;\n\n const styleUsesStudioOffset = (value: string): boolean =>\n value.includes(OFFSET_X_PROP) || value.includes(OFFSET_Y_PROP);\n\n const styleUsesStudioRotation = (value: string): boolean => value.includes(ROTATION_PROP);\n\n const splitTopLevelWhitespace = (value: string): string[] => {\n const parts: string[] = [];\n let depth = 0;\n let current = \"\";\n for (const char of value.trim()) {\n if (char === \"(\") depth += 1;\n if (char === \")\") depth = Math.max(0, depth - 1);\n if (/\\s/.test(char) && depth === 0) {\n if (current) parts.push(current);\n current = \"\";\n } else {\n current += char;\n }\n }\n if (current) parts.push(current);\n return parts;\n };\n\n const composeTranslate = (element: HTMLElement, x: string, y: string): string => {\n const original = element.getAttribute(ORIGINAL_TRANSLATE_ATTR)?.trim();\n if (!original || original === \"none\") return `${x} ${y}`;\n\n const parts = splitTopLevelWhitespace(original);\n if (parts.length === 1) return `calc(${parts[0]} + ${x}) ${y}`;\n if (parts.length === 2) return `calc(${parts[0]} + ${x}) calc(${parts[1]} + ${y})`;\n if (parts.length === 3) {\n return `calc(${parts[0]} + ${x}) calc(${parts[1]} + ${y}) ${parts[2]}`;\n }\n return `${x} ${y}`;\n };\n\n const readStyleOrComputed = (element: HTMLElement, property: string): string => {\n try {\n return (\n element.style.getPropertyValue(property) ||\n getComputedStyle(element).getPropertyValue(property)\n );\n } catch {\n return element.style.getPropertyValue(property);\n }\n };\n\n const readTransformLonghandBase = (\n element: HTMLElement,\n property: \"translate\" | \"rotate\",\n ): string => {\n const value = readStyleOrComputed(element, property).trim();\n return value === \"none\" ? \"\" : value;\n };\n\n const preparePathOffsetBase = (element: HTMLElement): void => {\n const currentTranslate = readTransformLonghandBase(element, \"translate\");\n const hasMarker = element.hasAttribute(PATH_OFFSET_ATTR);\n const wasResetByAnimation = !styleUsesStudioOffset(currentTranslate);\n if (!hasMarker) {\n element.setAttribute(ORIGINAL_TRANSLATE_ATTR, wasResetByAnimation ? currentTranslate : \"\");\n } else if (wasResetByAnimation) {\n element.setAttribute(ORIGINAL_TRANSLATE_ATTR, currentTranslate);\n }\n };\n\n const prepareRotationBase = (element: HTMLElement): void => {\n const currentRotate = readTransformLonghandBase(element, \"rotate\");\n const hasMarker = element.hasAttribute(ROTATION_ATTR);\n const wasResetByAnimation = !styleUsesStudioRotation(currentRotate);\n if (!hasMarker) {\n element.setAttribute(ORIGINAL_ROTATE_ATTR, wasResetByAnimation ? currentRotate : \"\");\n } else if (wasResetByAnimation) {\n element.setAttribute(ORIGINAL_ROTATE_ATTR, currentRotate);\n }\n };\n\n const querySelectorCandidates = (selector: string): HTMLElement[] => {\n const isCandidate = (element: Element): element is HTMLElement =>\n element instanceof HTMLElement;\n\n const className = selector.match(/^\\.([A-Za-z0-9_-]+)$/)?.[1];\n if (className) {\n return Array.from(document.getElementsByTagName(\"*\")).filter(\n (element): element is HTMLElement =>\n isCandidate(element) && element.classList.contains(className),\n );\n }\n\n if (/^[A-Za-z][A-Za-z0-9-]*$/.test(selector)) {\n return Array.from(document.getElementsByTagName(selector)).filter(isCandidate);\n }\n\n return Array.from(document.querySelectorAll(selector)).filter(isCandidate);\n };\n\n const resolveTarget = (edit: Record<string, unknown>): HTMLElement | null => {\n const targetRecord = objectRecord(edit.target);\n if (!targetRecord) return null;\n\n const sourceFile = typeof targetRecord.sourceFile === \"string\" ? targetRecord.sourceFile : \"\";\n if (!sourceFile) return null;\n\n const id = typeof targetRecord.id === \"string\" ? targetRecord.id : \"\";\n if (id) {\n const byId = document.getElementById(id);\n if (byId instanceof HTMLElement && elementMatchesSourceFile(byId, sourceFile)) return byId;\n\n const matchesById = [\n document.documentElement,\n ...Array.from(document.getElementsByTagName(\"*\")),\n ].filter(\n (element): element is HTMLElement =>\n element instanceof HTMLElement &&\n element.id === id &&\n elementMatchesSourceFile(element, sourceFile),\n );\n if (matchesById[0]) return matchesById[0];\n }\n\n const selector = typeof targetRecord.selector === \"string\" ? targetRecord.selector : \"\";\n if (!selector) return null;\n\n try {\n const matches = querySelectorCandidates(selector).filter((element) =>\n elementMatchesSourceFile(element, sourceFile),\n );\n const selectorIndex = finiteNumber(targetRecord.selectorIndex) ?? 0;\n return matches[Math.max(0, Math.floor(selectorIndex))] ?? null;\n } catch {\n return null;\n }\n };\n\n const roundRotationAngle = (angle: number): number => Math.round(angle * 10) / 10;\n\n const isSimpleRotateAngle = (value: string): boolean =>\n /^-?(?:\\d+(?:\\.\\d+)?|\\.\\d+)(?:deg|rad|turn|grad)$/.test(value.trim());\n\n const composeRotation = (element: HTMLElement, rotationValue: string): string => {\n const original = element.getAttribute(ORIGINAL_ROTATE_ATTR)?.trim();\n if (!original || original === \"none\" || !isSimpleRotateAngle(original)) {\n return rotationValue;\n }\n return `calc(${original} + ${rotationValue})`;\n };\n\n const applyPathOffset = (element: HTMLElement, edit: Record<string, unknown>): void => {\n const x = finiteNumber(edit.x);\n const y = finiteNumber(edit.y);\n if (x == null || y == null) return;\n preparePathOffsetBase(element);\n element.setAttribute(PATH_OFFSET_ATTR, \"true\");\n element.style.setProperty(OFFSET_X_PROP, `${Math.round(x)}px`);\n element.style.setProperty(OFFSET_Y_PROP, `${Math.round(y)}px`);\n element.style.setProperty(\n \"translate\",\n composeTranslate(element, `var(${OFFSET_X_PROP}, 0px)`, `var(${OFFSET_Y_PROP}, 0px)`),\n );\n };\n\n const readParentFlexBasisPixels = (\n element: HTMLElement,\n size: { width: number; height: number },\n ): number | null => {\n const parent = element.parentElement;\n if (!parent) return null;\n const styles = getComputedStyle(parent);\n if (styles.display !== \"flex\" && styles.display !== \"inline-flex\") return null;\n return Math.round(\n Math.max(1, styles.flexDirection.startsWith(\"column\") ? size.height : size.width),\n );\n };\n\n const applyBoxSize = (element: HTMLElement, edit: Record<string, unknown>): void => {\n const width = finiteNumber(edit.width);\n const height = finiteNumber(edit.height);\n if (width == null || height == null || width <= 0 || height <= 0) return;\n\n const rounded = {\n width: Math.round(Math.max(1, width)),\n height: Math.round(Math.max(1, height)),\n };\n element.setAttribute(BOX_SIZE_ATTR, \"true\");\n element.style.setProperty(WIDTH_PROP, `${rounded.width}px`);\n element.style.setProperty(HEIGHT_PROP, `${rounded.height}px`);\n element.style.setProperty(\"box-sizing\", \"border-box\");\n element.style.setProperty(\"width\", `${rounded.width}px`);\n element.style.setProperty(\"height\", `${rounded.height}px`);\n element.style.setProperty(\"min-width\", \"0px\");\n element.style.setProperty(\"min-height\", \"0px\");\n element.style.setProperty(\"max-width\", \"none\");\n element.style.setProperty(\"max-height\", \"none\");\n\n const flexBasis = readParentFlexBasisPixels(element, rounded);\n if (flexBasis != null) {\n element.style.setProperty(\"flex-basis\", `${flexBasis}px`);\n element.style.setProperty(\"flex-grow\", \"0\");\n element.style.setProperty(\"flex-shrink\", \"0\");\n }\n if (getComputedStyle(element).display === \"inline\") {\n element.style.setProperty(\"display\", \"inline-block\");\n }\n };\n\n const applyRotation = (element: HTMLElement, edit: Record<string, unknown>): void => {\n const angle = finiteNumber(edit.angle);\n if (angle == null) return;\n prepareRotationBase(element);\n element.setAttribute(ROTATION_ATTR, \"true\");\n element.style.setProperty(ROTATION_PROP, `${roundRotationAngle(angle)}deg`);\n element.style.setProperty(\"transform-origin\", ROTATION_TRANSFORM_ORIGIN);\n element.style.setProperty(\"rotate\", composeRotation(element, `var(${ROTATION_PROP}, 0deg)`));\n };\n\n const applyManifest = (): number => {\n let applied = 0;\n for (const edit of manifestEdits) {\n const editRecord = objectRecord(edit);\n if (!editRecord) continue;\n const element = resolveTarget(editRecord);\n if (!element) continue;\n if (editRecord.kind === \"path-offset\") applyPathOffset(element, editRecord);\n if (editRecord.kind === \"box-size\") applyBoxSize(element, editRecord);\n if (editRecord.kind === \"rotation\") applyRotation(element, editRecord);\n applied += 1;\n }\n return applied;\n };\n runtimeWindow.__hfStudioManualEditsApply = applyManifest;\n\n const markWrapped = (fn: (time: number) => unknown): void => {\n try {\n Object.defineProperty(fn, WRAPPED_SEEK_PROP, {\n configurable: false,\n enumerable: false,\n value: true,\n });\n } catch {\n try {\n (fn as unknown as Record<string, unknown>)[WRAPPED_SEEK_PROP] = true;\n } catch {\n // Ignore non-extensible functions.\n }\n }\n };\n\n const isWrapped = (fn: (time: number) => unknown): boolean =>\n Boolean((fn as unknown as Record<string, unknown>)[WRAPPED_SEEK_PROP]);\n\n const wrapFunction = (\n get: () => ((time: number) => unknown) | undefined,\n set: (fn: (time: number) => unknown) => void,\n ): boolean => {\n const fn = get();\n if (!fn) return false;\n const seek = fn as (time: number) => unknown;\n if (isWrapped(seek)) {\n applyManifest();\n return true;\n }\n\n const wrappedSeek = function (this: unknown, time: number): unknown {\n const result = seek.call(this, time);\n applyManifest();\n return result;\n };\n markWrapped(wrappedSeek);\n set(wrappedSeek);\n applyManifest();\n return true;\n };\n\n const wrapSeekFunctions = (): boolean => {\n const wrappedHfSeek = wrapFunction(\n () => runtimeWindow.__hf?.seek,\n (fn) => {\n if (runtimeWindow.__hf) runtimeWindow.__hf.seek = fn;\n },\n );\n const wrappedPlayerRenderSeek = wrapFunction(\n () => runtimeWindow.__player?.renderSeek,\n (fn) => {\n if (runtimeWindow.__player) runtimeWindow.__player.renderSeek = fn;\n },\n );\n return wrappedHfSeek || wrappedPlayerRenderSeek;\n };\n\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", () => applyManifest(), { once: true });\n } else {\n applyManifest();\n }\n\n wrapSeekFunctions();\n let remainingSeekWrapAttempts = 120;\n const seekWrapInterval = setInterval(() => {\n wrapSeekFunctions();\n remainingSeekWrapAttempts -= 1;\n if (remainingSeekWrapAttempts <= 0) clearInterval(seekWrapInterval);\n }, 50);\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,282 @@
1
+ // src/helpers/mediaCodecMap.ts
2
+ import { existsSync, statSync } from "fs";
3
+ import { relative, resolve, sep } from "path";
4
+ import { rewriteAssetPath } from "@hyperframes/parsers/asset-paths";
5
+ import {
6
+ cleanAssetUrl,
7
+ isRemoteOrInlineUrl,
8
+ maskNonScannableRanges,
9
+ resolveLocalAssetCandidates
10
+ } from "@hyperframes/parsers/asset-resolution";
11
+
12
+ // src/helpers/mediaMetadata.ts
13
+ import { execFile } from "child_process";
14
+ import { extname } from "path";
15
+ import { findFfBinary } from "@hyperframes/parsers/ff-binaries";
16
+ var execFileRunner = (command, args, options) => new Promise((resolvePromise) => {
17
+ execFile(
18
+ command,
19
+ args,
20
+ { timeout: options?.timeout, maxBuffer: options?.maxBuffer },
21
+ (error, stdout, stderr) => {
22
+ if (error && error.code === "ENOENT") {
23
+ resolvePromise({ status: null, stdout: "", stderr: "", error });
24
+ return;
25
+ }
26
+ if (error) {
27
+ const status = typeof error.code === "number" ? error.code : 1;
28
+ resolvePromise({ status, stdout: stdout ?? "", stderr: stderr ?? "" });
29
+ return;
30
+ }
31
+ resolvePromise({ status: 0, stdout: stdout ?? "", stderr: stderr ?? "" });
32
+ }
33
+ );
34
+ });
35
+ var VIDEO_EXT = /* @__PURE__ */ new Set([
36
+ ".mp4",
37
+ ".mov",
38
+ ".webm",
39
+ ".mkv",
40
+ ".avi",
41
+ ".m4v",
42
+ ".mxf",
43
+ ".mts",
44
+ ".m2ts",
45
+ ".ts"
46
+ ]);
47
+ var IMAGE_EXT = /* @__PURE__ */ new Set([".jpg", ".jpeg", ".png", ".webp", ".avif"]);
48
+ var AUDIO_EXT = /* @__PURE__ */ new Set([".mp3", ".wav", ".ogg", ".m4a", ".aac"]);
49
+ function lower(value) {
50
+ return value?.toLowerCase() ?? "";
51
+ }
52
+ function inferKindFromPath(path) {
53
+ const ext = extname(path).toLowerCase();
54
+ if (VIDEO_EXT.has(ext)) return "video";
55
+ if (IMAGE_EXT.has(ext)) return "image";
56
+ if (AUDIO_EXT.has(ext)) return "audio";
57
+ return "unknown";
58
+ }
59
+ function colorLabel(input) {
60
+ if (input.isHdr) {
61
+ if (input.hdrTransfer === "pq") return "HDR PQ";
62
+ if (input.hdrTransfer === "hlg") return "HDR HLG";
63
+ return "HDR";
64
+ }
65
+ if (input.colorPrimaries.includes("bt709") || input.colorSpace.includes("bt709") || input.colorTransfer.includes("bt709")) {
66
+ return "SDR Rec.709";
67
+ }
68
+ return "SDR/unknown";
69
+ }
70
+ var ALPHA_PIX_FMT_RE = /^(?:yuva|rgba|argb|bgra|abgr|gbrap|ya)/;
71
+ function pixelFormatHasAlpha(pixFmt) {
72
+ return pixFmt !== void 0 && ALPHA_PIX_FMT_RE.test(pixFmt.toLowerCase());
73
+ }
74
+ function classifyMediaColor(stream) {
75
+ const colorPrimaries = lower(stream?.color_primaries);
76
+ const colorSpace = lower(stream?.color_space);
77
+ const colorTransfer = lower(stream?.color_transfer);
78
+ const isHdr = colorPrimaries.includes("bt2020") || colorSpace.includes("bt2020") || colorTransfer === "smpte2084" || colorTransfer === "arib-std-b67";
79
+ const hdrTransfer = isHdr ? colorTransfer === "smpte2084" ? "pq" : colorTransfer === "arib-std-b67" ? "hlg" : "unknown" : null;
80
+ return {
81
+ dynamicRange: stream ? isHdr ? "hdr" : "sdr" : "unknown",
82
+ hdrTransfer,
83
+ label: stream ? colorLabel({ isHdr, hdrTransfer, colorPrimaries, colorSpace, colorTransfer }) : "Unknown",
84
+ isHdr,
85
+ codecName: stream?.codec_name,
86
+ profile: stream?.profile,
87
+ pixelFormat: stream?.pix_fmt,
88
+ colorSpace: stream?.color_space,
89
+ colorTransfer: stream?.color_transfer,
90
+ colorPrimaries: stream?.color_primaries,
91
+ bitsPerRawSample: stream?.bits_per_raw_sample
92
+ };
93
+ }
94
+ async function probeMediaMetadata(filePath, runner = execFileRunner) {
95
+ const kind = inferKindFromPath(filePath);
96
+ if (kind === "audio" || kind === "unknown") {
97
+ return { kind, color: classifyMediaColor(null) };
98
+ }
99
+ const ffprobePath = findFfBinary("ffprobe", { configuredMustExist: true }) ?? (runner === execFileRunner ? void 0 : "ffprobe");
100
+ if (!ffprobePath) {
101
+ return { kind, color: classifyMediaColor(null), probeError: "ffprobe unavailable" };
102
+ }
103
+ const result = await runner(
104
+ ffprobePath,
105
+ [
106
+ "-v",
107
+ "error",
108
+ "-show_entries",
109
+ "stream=codec_type,codec_name,profile,pix_fmt,color_space,color_transfer,color_primaries,bits_per_raw_sample:stream_disposition=attached_pic",
110
+ "-of",
111
+ "json",
112
+ filePath
113
+ ],
114
+ { timeout: 15e3, maxBuffer: 1024 * 1024 }
115
+ );
116
+ if (result.error?.code === "ENOENT") {
117
+ return { kind, color: classifyMediaColor(null), probeError: "ffprobe unavailable" };
118
+ }
119
+ if (result.status !== 0) {
120
+ return { kind, color: classifyMediaColor(null), probeError: "ffprobe failed" };
121
+ }
122
+ try {
123
+ const parsed = JSON.parse(String(result.stdout || "{}"));
124
+ const stream = parsed.streams?.find((item) => {
125
+ if (kind === "image") return item.codec_type === "video";
126
+ return item.codec_type === kind && item.disposition?.attached_pic !== 1;
127
+ });
128
+ return { kind, color: classifyMediaColor(stream) };
129
+ } catch {
130
+ return { kind, color: classifyMediaColor(null), probeError: "ffprobe returned invalid json" };
131
+ }
132
+ }
133
+
134
+ // src/helpers/mediaCodecMap.ts
135
+ var BROWSER_HOSTILE_CODECS = {
136
+ hevc: 'video/mp4; codecs="hvc1.1.6.L120.B0"',
137
+ prores: null,
138
+ av1: 'video/mp4; codecs="av01.0.08M.08"',
139
+ // VP9 is browser-dependent: Chrome generally decodes it while Safari
140
+ // support varies. Treat it as conditional so canPlayType keeps the
141
+ // original where supported and transparently proxies it where unsupported.
142
+ vp9: 'video/webm; codecs="vp09.00.10.08"'
143
+ };
144
+ var PROXY_VARIANT_CONFIG = {
145
+ h264: { extension: ".mp4", contentType: "video/mp4" },
146
+ vp9: { extension: ".webm", contentType: "video/webm" }
147
+ };
148
+ function isProxyVariant(value) {
149
+ return Object.hasOwn(PROXY_VARIANT_CONFIG, value);
150
+ }
151
+ function isProxyVariantRequest(value) {
152
+ return value === "auto" || isProxyVariant(value);
153
+ }
154
+ function proxyVariantFor(facts) {
155
+ return facts.hasAlpha ? "vp9" : "h264";
156
+ }
157
+ function resolveProxyVariantRequest(request, facts) {
158
+ const expected = proxyVariantFor(facts);
159
+ return request === "auto" || request === expected ? expected : null;
160
+ }
161
+ function decideMediaProxyEligibility(facts) {
162
+ if (!facts) return { eligible: false, reason: "unknown_codec" };
163
+ if (!facts.browserHostile) return { eligible: false, reason: "browser_safe_codec" };
164
+ if (facts.hasAlpha && facts.codecName === "vp9") {
165
+ return { eligible: false, reason: "proxy_target_codec" };
166
+ }
167
+ return { eligible: true };
168
+ }
169
+ function codecFactsFor(codecName, hasAlpha) {
170
+ const isHostile = Object.hasOwn(BROWSER_HOSTILE_CODECS, codecName);
171
+ return {
172
+ codecName,
173
+ browserHostile: isHostile,
174
+ representativeMime: isHostile ? BROWSER_HOSTILE_CODECS[codecName] ?? null : null,
175
+ hasAlpha
176
+ };
177
+ }
178
+ async function probeAssetCodec(filePath, runner) {
179
+ const metadata = runner ? await probeMediaMetadata(filePath, runner) : await probeMediaMetadata(filePath);
180
+ if (metadata.kind !== "video" || metadata.probeError) return null;
181
+ const codecName = metadata.color.codecName;
182
+ if (!codecName) return null;
183
+ return codecFactsFor(codecName, pixelFormatHasAlpha(metadata.color.pixelFormat));
184
+ }
185
+ function createMediaCodecProbeCache() {
186
+ return /* @__PURE__ */ new Map();
187
+ }
188
+ var defaultProbeCache = /* @__PURE__ */ new Map();
189
+ var MAX_PROBE_CACHE_ENTRIES = 512;
190
+ function rememberProbeResult(cache, filePath, result) {
191
+ if (!cache.has(filePath) && cache.size >= MAX_PROBE_CACHE_ENTRIES) {
192
+ const oldest = cache.keys().next().value;
193
+ if (oldest) cache.delete(oldest);
194
+ }
195
+ cache.delete(filePath);
196
+ cache.set(filePath, result);
197
+ }
198
+ async function probeAssetCodecCached(filePath, cache, runner) {
199
+ let stat;
200
+ try {
201
+ stat = statSync(filePath);
202
+ } catch {
203
+ return null;
204
+ }
205
+ const cached = cache.get(filePath);
206
+ if (cached && cached.mtimeMs === stat.mtimeMs && cached.size === stat.size) {
207
+ rememberProbeResult(cache, filePath, cached);
208
+ return cached.facts;
209
+ }
210
+ const facts = await probeAssetCodec(filePath, runner);
211
+ rememberProbeResult(cache, filePath, { mtimeMs: stat.mtimeMs, size: stat.size, facts });
212
+ return facts;
213
+ }
214
+ var VIDEO_SRC_RE = /<video\b[^>]*\bsrc\s*=\s*["']([^"']+)["'][^>]*>/gi;
215
+ function resolveExistingLocalAsset(projectDir, url) {
216
+ const projectRoot = resolve(projectDir);
217
+ const resolvedPath = resolveLocalAssetCandidates(projectRoot, url).find(
218
+ (candidate) => existsSync(candidate)
219
+ );
220
+ if (!resolvedPath) return null;
221
+ const rootRelative = relative(projectRoot, resolvedPath).split(sep).join("/");
222
+ return { resolvedPath, rootRelativePathname: `/${rootRelative}` };
223
+ }
224
+ function collectLocalVideoAssets(projectDir, htmlSources) {
225
+ const candidates = /* @__PURE__ */ new Map();
226
+ for (const { html, compSrcPath } of htmlSources) {
227
+ const scannable = maskNonScannableRanges(html);
228
+ const re = new RegExp(VIDEO_SRC_RE.source, VIDEO_SRC_RE.flags);
229
+ let match;
230
+ while ((match = re.exec(scannable)) !== null) {
231
+ const src = cleanAssetUrl(match[1] ?? "");
232
+ if (!src || isRemoteOrInlineUrl(src)) continue;
233
+ if (/^__[A-Z_]+__$/.test(src)) continue;
234
+ const rootRelativeSrc = compSrcPath ? rewriteAssetPath(compSrcPath, src) : src;
235
+ const resolved = resolveExistingLocalAsset(projectDir, rootRelativeSrc);
236
+ if (!resolved) continue;
237
+ candidates.set(resolved.resolvedPath, resolved.rootRelativePathname);
238
+ }
239
+ }
240
+ return candidates;
241
+ }
242
+ var PROBE_CONCURRENCY = 8;
243
+ async function scanProjectMediaCodecMap(projectDir, htmlSources, options = {}) {
244
+ const candidates = collectLocalVideoAssets(projectDir, htmlSources);
245
+ if (candidates.size === 0) return {};
246
+ const cache = options.cache ?? defaultProbeCache;
247
+ const entries = [...candidates.entries()];
248
+ const facts = new Array(entries.length).fill(null);
249
+ let nextIndex = 0;
250
+ const workerCount = Math.min(PROBE_CONCURRENCY, entries.length);
251
+ await Promise.all(
252
+ Array.from({ length: workerCount }, async () => {
253
+ while (nextIndex < entries.length) {
254
+ const index = nextIndex++;
255
+ const entry = entries[index];
256
+ if (!entry) break;
257
+ facts[index] = await probeAssetCodecCached(entry[0], cache, options.runner);
258
+ }
259
+ })
260
+ );
261
+ const map = {};
262
+ entries.forEach(([, pathname], index) => {
263
+ const entryFacts = facts[index];
264
+ if (entryFacts?.browserHostile) map[pathname] = entryFacts;
265
+ });
266
+ return map;
267
+ }
268
+
269
+ export {
270
+ probeMediaMetadata,
271
+ BROWSER_HOSTILE_CODECS,
272
+ PROXY_VARIANT_CONFIG,
273
+ isProxyVariant,
274
+ isProxyVariantRequest,
275
+ proxyVariantFor,
276
+ resolveProxyVariantRequest,
277
+ decideMediaProxyEligibility,
278
+ probeAssetCodec,
279
+ createMediaCodecProbeCache,
280
+ scanProjectMediaCodecMap
281
+ };
282
+ //# sourceMappingURL=chunk-LVXVG4V6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/helpers/mediaCodecMap.ts","../src/helpers/mediaMetadata.ts"],"sourcesContent":["import { existsSync, statSync } from \"node:fs\";\nimport { relative, resolve, sep } from \"node:path\";\nimport { rewriteAssetPath } from \"@hyperframes/parsers/asset-paths\";\nimport {\n cleanAssetUrl,\n isRemoteOrInlineUrl,\n maskNonScannableRanges,\n resolveLocalAssetCandidates,\n} from \"@hyperframes/parsers/asset-resolution\";\nimport { pixelFormatHasAlpha, probeMediaMetadata, type FfprobeRunner } from \"./mediaMetadata.js\";\n\n/**\n * One reusable answer to \"what codec is this asset, and is it browser-hostile?\",\n * built on top of `mediaMetadata.ts`'s ffprobe-backed prober so studio-server\n * probes each asset once instead of running a second prober.\n */\n\nexport interface AssetCodecFacts {\n codecName: string;\n browserHostile: boolean;\n /** Coarse `canPlayType()` input; `null` when not applicable (safe codec) or\n * when no representative mime exists (ProRes: browsers never decode it, so\n * the runtime always proxies rather than probing `canPlayType`). */\n representativeMime: string | null;\n /** Source carries an alpha channel (ffprobe pix_fmt). Alpha sources use a\n * VP9/WebM proxy so their transparency is preserved. */\n hasAlpha: boolean;\n}\n\n/** Server-root-relative URL pathname -> that asset's codec facts. */\nexport type MediaCodecMap = Record<string, AssetCodecFacts>;\n\n/**\n * Browser-hostile codec table v1. One exported constant so extending it is a\n * one-line change. `ffprobe` cannot emit exact RFC 6381 codec strings, so\n * these `representativeMime` values are deliberately coarse (a false\n * positive costs one proxy transcode, never correctness; a false negative is\n * rescued by the runtime's reactive zero-videoWidth swap).\n */\nexport const BROWSER_HOSTILE_CODECS: Record<string, string | null> = {\n hevc: 'video/mp4; codecs=\"hvc1.1.6.L120.B0\"',\n prores: null,\n av1: 'video/mp4; codecs=\"av01.0.08M.08\"',\n // VP9 is browser-dependent: Chrome generally decodes it while Safari\n // support varies. Treat it as conditional so canPlayType keeps the\n // original where supported and transparently proxies it where unsupported.\n vp9: 'video/webm; codecs=\"vp09.00.10.08\"',\n};\n\nexport type ProxyVariant = \"h264\" | \"vp9\";\nexport type ProxyVariantRequest = ProxyVariant | \"auto\";\n\nexport const PROXY_VARIANT_CONFIG: Record<\n ProxyVariant,\n { extension: \".mp4\" | \".webm\"; contentType: \"video/mp4\" | \"video/webm\" }\n> = {\n h264: { extension: \".mp4\", contentType: \"video/mp4\" },\n vp9: { extension: \".webm\", contentType: \"video/webm\" },\n};\n\nexport function isProxyVariant(value: string): value is ProxyVariant {\n return Object.hasOwn(PROXY_VARIANT_CONFIG, value);\n}\n\nexport function isProxyVariantRequest(value: string): value is ProxyVariantRequest {\n return value === \"auto\" || isProxyVariant(value);\n}\n\nexport function proxyVariantFor(facts: AssetCodecFacts): ProxyVariant {\n return facts.hasAlpha ? \"vp9\" : \"h264\";\n}\n\nexport function resolveProxyVariantRequest(\n request: ProxyVariantRequest,\n facts: AssetCodecFacts,\n): ProxyVariant | null {\n const expected = proxyVariantFor(facts);\n return request === \"auto\" || request === expected ? expected : null;\n}\n\nexport type MediaProxyIneligibilityReason =\n | \"browser_safe_codec\"\n | \"proxy_target_codec\"\n | \"unknown_codec\";\n\nexport type MediaProxyEligibility =\n | { eligible: true }\n | { eligible: false; reason: MediaProxyIneligibilityReason };\n\n/** Single policy gate shared by proactive scans and on-demand proxy routes. */\nexport function decideMediaProxyEligibility(facts: AssetCodecFacts | null): MediaProxyEligibility {\n if (!facts) return { eligible: false, reason: \"unknown_codec\" };\n if (!facts.browserHostile) return { eligible: false, reason: \"browser_safe_codec\" };\n if (facts.hasAlpha && facts.codecName === \"vp9\") {\n return { eligible: false, reason: \"proxy_target_codec\" };\n }\n return { eligible: true };\n}\n\nfunction codecFactsFor(codecName: string, hasAlpha: boolean): AssetCodecFacts {\n const isHostile = Object.hasOwn(BROWSER_HOSTILE_CODECS, codecName);\n return {\n codecName,\n browserHostile: isHostile,\n representativeMime: isHostile ? (BROWSER_HOSTILE_CODECS[codecName] ?? null) : null,\n hasAlpha,\n };\n}\n\n/**\n * Probe a single video asset. Best-effort: ffprobe missing, erroring, or\n * finding no video stream resolves to `null` (asset omitted by the caller),\n * never a throw. Async so a pool of probes runs concurrently (the default\n * runner is `execFile`-based).\n */\nexport async function probeAssetCodec(\n filePath: string,\n runner?: FfprobeRunner,\n): Promise<AssetCodecFacts | null> {\n const metadata = runner\n ? await probeMediaMetadata(filePath, runner)\n : await probeMediaMetadata(filePath);\n if (metadata.kind !== \"video\" || metadata.probeError) return null;\n const codecName = metadata.color.codecName;\n if (!codecName) return null;\n return codecFactsFor(codecName, pixelFormatHasAlpha(metadata.color.pixelFormat));\n}\n\ninterface CachedAssetProbe {\n mtimeMs: number;\n size: number;\n facts: AssetCodecFacts | null;\n}\n\n/** Per (path, mtime) probe cache. Construct one per project/server lifetime\n * and reuse it across scans; a fresh instance defeats the caching benefit. */\nexport type MediaCodecProbeCache = Map<string, CachedAssetProbe>;\n\nexport function createMediaCodecProbeCache(): MediaCodecProbeCache {\n return new Map();\n}\n\n// Used when a caller doesn't pass its own cache — still correct (probes every\n// time a fresh Map would), but callers that want the mtime-cache benefit\n// across repeated scans (the studio preview route, etc.) should construct\n// and hold their own cache via `createMediaCodecProbeCache`.\nconst defaultProbeCache: MediaCodecProbeCache = new Map();\nconst MAX_PROBE_CACHE_ENTRIES = 512;\n\nfunction rememberProbeResult(\n cache: MediaCodecProbeCache,\n filePath: string,\n result: CachedAssetProbe,\n): void {\n if (!cache.has(filePath) && cache.size >= MAX_PROBE_CACHE_ENTRIES) {\n const oldest = cache.keys().next().value;\n if (oldest) cache.delete(oldest);\n }\n // Refresh insertion order so frequently used assets remain resident.\n cache.delete(filePath);\n cache.set(filePath, result);\n}\n\nasync function probeAssetCodecCached(\n filePath: string,\n cache: MediaCodecProbeCache,\n runner?: FfprobeRunner,\n): Promise<AssetCodecFacts | null> {\n let stat: ReturnType<typeof statSync>;\n try {\n stat = statSync(filePath);\n } catch {\n return null;\n }\n const cached = cache.get(filePath);\n if (cached && cached.mtimeMs === stat.mtimeMs && cached.size === stat.size) {\n rememberProbeResult(cache, filePath, cached);\n return cached.facts;\n }\n const facts = await probeAssetCodec(filePath, runner);\n rememberProbeResult(cache, filePath, { mtimeMs: stat.mtimeMs, size: stat.size, facts });\n return facts;\n}\n\n/** Structurally compatible with `packages/lint/src/hevcPreviewLint.ts`'s\n * (unexported) `HtmlSourceLike`. */\nexport interface HtmlSourceLike {\n html: string;\n compSrcPath?: string;\n}\n\n// --- <video src> collection: shared primitives live in\n// @hyperframes/parsers/asset-resolution; the <video>-specific regex and the\n// pinned key derivation stay here.\nconst VIDEO_SRC_RE = /<video\\b[^>]*\\bsrc\\s*=\\s*[\"']([^\"']+)[\"'][^>]*>/gi;\n\n/**\n * Resolve a `<video src>` reference to an existing local file.\n *\n * `rootRelativePathname` is the map key format PINNED by this plan's Key\n * Technical Decisions: project-root-relative URL pathname, percent-decoded,\n * query-string-stripped, forward-slash separated, leading-slash prefixed\n * (e.g. \"/assets/videos/clip.mp4\"). This must match what the runtime derives\n * via `new URL(el.currentSrc || el.src, document.baseURI).pathname`, because\n * server-side scanning resolves filesystem paths while the DOM sees served\n * URLs — a documented prior source of this exact class of bug.\n */\nfunction resolveExistingLocalAsset(\n projectDir: string,\n url: string,\n): { resolvedPath: string; rootRelativePathname: string } | null {\n const projectRoot = resolve(projectDir);\n const resolvedPath = resolveLocalAssetCandidates(projectRoot, url).find((candidate) =>\n existsSync(candidate),\n );\n if (!resolvedPath) return null;\n const rootRelative = relative(projectRoot, resolvedPath).split(sep).join(\"/\");\n return { resolvedPath, rootRelativePathname: `/${rootRelative}` };\n}\n\n/**\n * Collects local `<video src>` references, resolved to their absolute path\n * and deduped by that path, keyed by the pinned root-relative URL pathname.\n */\n// fallow-ignore-next-line complexity\nfunction collectLocalVideoAssets(\n projectDir: string,\n htmlSources: HtmlSourceLike[],\n): Map<string, string> {\n const candidates = new Map<string, string>();\n\n for (const { html, compSrcPath } of htmlSources) {\n const scannable = maskNonScannableRanges(html);\n const re = new RegExp(VIDEO_SRC_RE.source, VIDEO_SRC_RE.flags);\n let match: RegExpExecArray | null;\n while ((match = re.exec(scannable)) !== null) {\n const src = cleanAssetUrl(match[1] ?? \"\");\n if (!src || isRemoteOrInlineUrl(src)) continue;\n if (/^__[A-Z_]+__$/.test(src)) continue;\n const rootRelativeSrc = compSrcPath ? rewriteAssetPath(compSrcPath, src) : src;\n const resolved = resolveExistingLocalAsset(projectDir, rootRelativeSrc);\n if (!resolved) continue;\n candidates.set(resolved.resolvedPath, resolved.rootRelativePathname);\n }\n }\n\n return candidates;\n}\n\n// Bounds concurrent ffprobe child processes for projects referencing many\n// videos, mirroring `PROBE_CONCURRENCY` in `hevcPreviewLint.ts`.\nconst PROBE_CONCURRENCY = 8;\n\nexport interface ScanProjectMediaCodecMapOptions {\n /** Persisted across calls by the caller for the mtime-cache benefit;\n * defaults to a shared module-level cache when omitted. */\n cache?: MediaCodecProbeCache;\n runner?: FfprobeRunner;\n}\n\n/**\n * Scans a project's composition HTML for local `<video src>` references and\n * returns the injection map: root-relative URL pathname -> codec facts.\n * Best-effort throughout — a video whose codec can't be determined (missing\n * ffprobe, probe error, no video stream) is simply omitted, never thrown.\n */\nexport async function scanProjectMediaCodecMap(\n projectDir: string,\n htmlSources: HtmlSourceLike[],\n options: ScanProjectMediaCodecMapOptions = {},\n): Promise<MediaCodecMap> {\n const candidates = collectLocalVideoAssets(projectDir, htmlSources);\n if (candidates.size === 0) return {};\n\n const cache = options.cache ?? defaultProbeCache;\n const entries = [...candidates.entries()]; // [resolvedPath, rootRelativePathname]\n const facts = new Array<AssetCodecFacts | null>(entries.length).fill(null);\n let nextIndex = 0;\n const workerCount = Math.min(PROBE_CONCURRENCY, entries.length);\n await Promise.all(\n Array.from({ length: workerCount }, async () => {\n while (nextIndex < entries.length) {\n const index = nextIndex++;\n const entry = entries[index];\n if (!entry) break;\n facts[index] = await probeAssetCodecCached(entry[0], cache, options.runner);\n }\n }),\n );\n\n const map: MediaCodecMap = {};\n entries.forEach(([, pathname], index) => {\n const entryFacts = facts[index];\n if (entryFacts?.browserHostile) map[pathname] = entryFacts;\n });\n return map;\n}\n","import { execFile } from \"node:child_process\";\nimport { extname } from \"node:path\";\nimport { findFfBinary } from \"@hyperframes/parsers/ff-binaries\";\n\nexport interface FfprobeRunResult {\n status: number | null;\n stdout: string | Buffer;\n stderr: string | Buffer;\n /** Spawn-level failure (covers both `NodeJS.ErrnoException` and\n * `ExecFileException`); only `code === \"ENOENT\"` is ever inspected. */\n error?: { code?: string | number | null | undefined };\n}\n\n/** Injectable ffprobe runner. May be synchronous (tests) or async (the\n * default `execFile`-based runner below), so cold scans can run many probes\n * concurrently off the event loop. */\nexport type FfprobeRunner = (\n command: string,\n args: string[],\n options?: { timeout?: number; maxBuffer?: number },\n) => FfprobeRunResult | Promise<FfprobeRunResult>;\n\n/** Default runner: genuinely async (`execFile`), unlike the previous\n * `spawnSync`-based one — a pool of concurrent probes actually parallelizes\n * (mirrors `execFileAsync` in packages/lint/src/hevcPreviewLint.ts). */\nconst execFileRunner: FfprobeRunner = (command, args, options) =>\n new Promise<FfprobeRunResult>((resolvePromise) => {\n execFile(\n command,\n args,\n { timeout: options?.timeout, maxBuffer: options?.maxBuffer },\n (error, stdout, stderr) => {\n if (error && error.code === \"ENOENT\") {\n resolvePromise({ status: null, stdout: \"\", stderr: \"\", error });\n return;\n }\n if (error) {\n // Nonzero exit / timeout / kill: report a nonzero status; callers\n // only distinguish \"ok\" (0) from \"failed\" from \"ENOENT\".\n const status = typeof error.code === \"number\" ? error.code : 1;\n resolvePromise({ status, stdout: stdout ?? \"\", stderr: stderr ?? \"\" });\n return;\n }\n resolvePromise({ status: 0, stdout: stdout ?? \"\", stderr: stderr ?? \"\" });\n },\n );\n });\n\nexport type MediaDynamicRange = \"hdr\" | \"sdr\" | \"unknown\";\nexport type MediaHdrTransfer = \"pq\" | \"hlg\" | \"unknown\";\n\nexport interface MediaColorMetadata {\n dynamicRange: MediaDynamicRange;\n hdrTransfer: MediaHdrTransfer | null;\n label: string;\n isHdr: boolean;\n codecName?: string;\n profile?: string;\n pixelFormat?: string;\n colorSpace?: string;\n colorTransfer?: string;\n colorPrimaries?: string;\n bitsPerRawSample?: string;\n}\n\nexport interface MediaMetadata {\n kind: \"video\" | \"image\" | \"audio\" | \"unknown\";\n color: MediaColorMetadata;\n probeError?: string;\n}\n\ninterface FfprobeStream {\n codec_type?: string;\n codec_name?: string;\n profile?: string;\n pix_fmt?: string;\n color_space?: string;\n color_transfer?: string;\n color_primaries?: string;\n bits_per_raw_sample?: string;\n disposition?: { attached_pic?: number };\n}\n\nconst VIDEO_EXT = new Set([\n \".mp4\",\n \".mov\",\n \".webm\",\n \".mkv\",\n \".avi\",\n \".m4v\",\n \".mxf\",\n \".mts\",\n \".m2ts\",\n \".ts\",\n]);\nconst IMAGE_EXT = new Set([\".jpg\", \".jpeg\", \".png\", \".webp\", \".avif\"]);\nconst AUDIO_EXT = new Set([\".mp3\", \".wav\", \".ogg\", \".m4a\", \".aac\"]);\n\nfunction lower(value: string | undefined): string {\n return value?.toLowerCase() ?? \"\";\n}\n\nfunction inferKindFromPath(path: string): MediaMetadata[\"kind\"] {\n const ext = extname(path).toLowerCase();\n if (VIDEO_EXT.has(ext)) return \"video\";\n if (IMAGE_EXT.has(ext)) return \"image\";\n if (AUDIO_EXT.has(ext)) return \"audio\";\n return \"unknown\";\n}\n\nfunction colorLabel(input: {\n isHdr: boolean;\n hdrTransfer: MediaHdrTransfer | null;\n colorPrimaries: string;\n colorSpace: string;\n colorTransfer: string;\n}): string {\n if (input.isHdr) {\n if (input.hdrTransfer === \"pq\") return \"HDR PQ\";\n if (input.hdrTransfer === \"hlg\") return \"HDR HLG\";\n return \"HDR\";\n }\n if (\n input.colorPrimaries.includes(\"bt709\") ||\n input.colorSpace.includes(\"bt709\") ||\n input.colorTransfer.includes(\"bt709\")\n ) {\n return \"SDR Rec.709\";\n }\n return \"SDR/unknown\";\n}\n\n// Conservative alpha-bearing pix_fmt list: yuva* (yuva420p, yuva444p10le...),\n// rgba/argb/bgra/abgr (packed RGB+alpha), gbrap* (planar GBR+alpha, ProRes\n// 4444 decodes to these), ya* (gray+alpha). Prefix match keeps bit-depth /\n// endianness suffixes covered.\nconst ALPHA_PIX_FMT_RE = /^(?:yuva|rgba|argb|bgra|abgr|gbrap|ya)/;\n\n/** True when an ffprobe `pix_fmt` carries an alpha component. */\nexport function pixelFormatHasAlpha(pixFmt: string | undefined): boolean {\n return pixFmt !== undefined && ALPHA_PIX_FMT_RE.test(pixFmt.toLowerCase());\n}\n\nexport function classifyMediaColor(stream: FfprobeStream | null | undefined): MediaColorMetadata {\n const colorPrimaries = lower(stream?.color_primaries);\n const colorSpace = lower(stream?.color_space);\n const colorTransfer = lower(stream?.color_transfer);\n const isHdr =\n colorPrimaries.includes(\"bt2020\") ||\n colorSpace.includes(\"bt2020\") ||\n colorTransfer === \"smpte2084\" ||\n colorTransfer === \"arib-std-b67\";\n const hdrTransfer: MediaHdrTransfer | null = isHdr\n ? colorTransfer === \"smpte2084\"\n ? \"pq\"\n : colorTransfer === \"arib-std-b67\"\n ? \"hlg\"\n : \"unknown\"\n : null;\n\n return {\n dynamicRange: stream ? (isHdr ? \"hdr\" : \"sdr\") : \"unknown\",\n hdrTransfer,\n label: stream\n ? colorLabel({ isHdr, hdrTransfer, colorPrimaries, colorSpace, colorTransfer })\n : \"Unknown\",\n isHdr,\n codecName: stream?.codec_name,\n profile: stream?.profile,\n pixelFormat: stream?.pix_fmt,\n colorSpace: stream?.color_space,\n colorTransfer: stream?.color_transfer,\n colorPrimaries: stream?.color_primaries,\n bitsPerRawSample: stream?.bits_per_raw_sample,\n };\n}\n\nexport async function probeMediaMetadata(\n filePath: string,\n runner: FfprobeRunner = execFileRunner,\n): Promise<MediaMetadata> {\n const kind = inferKindFromPath(filePath);\n if (kind === \"audio\" || kind === \"unknown\") {\n return { kind, color: classifyMediaColor(null) };\n }\n\n // The default runner degrades a missing ffprobe to \"unavailable\" without\n // spawning; injected runners own execution and receive the normal command.\n const ffprobePath =\n findFfBinary(\"ffprobe\", { configuredMustExist: true }) ??\n (runner === execFileRunner ? undefined : \"ffprobe\");\n if (!ffprobePath) {\n return { kind, color: classifyMediaColor(null), probeError: \"ffprobe unavailable\" };\n }\n\n const result = await runner(\n ffprobePath,\n [\n \"-v\",\n \"error\",\n \"-show_entries\",\n \"stream=codec_type,codec_name,profile,pix_fmt,color_space,color_transfer,color_primaries,bits_per_raw_sample:stream_disposition=attached_pic\",\n \"-of\",\n \"json\",\n filePath,\n ],\n { timeout: 15_000, maxBuffer: 1024 * 1024 },\n );\n\n if (result.error?.code === \"ENOENT\") {\n return { kind, color: classifyMediaColor(null), probeError: \"ffprobe unavailable\" };\n }\n if (result.status !== 0) {\n return { kind, color: classifyMediaColor(null), probeError: \"ffprobe failed\" };\n }\n\n try {\n const parsed = JSON.parse(String(result.stdout || \"{}\")) as { streams?: FfprobeStream[] };\n const stream = parsed.streams?.find((item) => {\n if (kind === \"image\") return item.codec_type === \"video\";\n return item.codec_type === kind && item.disposition?.attached_pic !== 1;\n });\n return { kind, color: classifyMediaColor(stream) };\n } catch {\n return { kind, color: classifyMediaColor(null), probeError: \"ffprobe returned invalid json\" };\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,32 @@
1
+ // src/helpers/screenshotClip.ts
2
+ function getElementScreenshotClip(selector, selectorIndex) {
3
+ let matches;
4
+ try {
5
+ matches = Array.from(document.querySelectorAll(selector)).filter(
6
+ (el2) => el2 instanceof HTMLElement
7
+ );
8
+ } catch {
9
+ return void 0;
10
+ }
11
+ const safeIndex = Math.max(0, Math.min(matches.length - 1, Math.floor(selectorIndex ?? 0)));
12
+ const el = matches[safeIndex] ?? null;
13
+ if (!(el instanceof HTMLElement)) return void 0;
14
+ const rect = el.getBoundingClientRect();
15
+ if (rect.width < 4 || rect.height < 4) return void 0;
16
+ const pad = 8;
17
+ const x = Math.max(0, rect.left - pad);
18
+ const y = Math.max(0, rect.top - pad);
19
+ const maxWidth = window.innerWidth - x;
20
+ const maxHeight = window.innerHeight - y;
21
+ return {
22
+ x,
23
+ y,
24
+ width: Math.max(1, Math.min(rect.width + pad * 2, maxWidth)),
25
+ height: Math.max(1, Math.min(rect.height + pad * 2, maxHeight))
26
+ };
27
+ }
28
+
29
+ export {
30
+ getElementScreenshotClip
31
+ };
32
+ //# sourceMappingURL=chunk-W2SBTCO2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/helpers/screenshotClip.ts"],"sourcesContent":["export interface ScreenshotClip {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport function getElementScreenshotClip(\n selector: string,\n selectorIndex?: number,\n): ScreenshotClip | undefined {\n // Guard against invalid CSS selectors (e.g. `#0` — a digit-leading id from\n // user HTML that upstream producers forgot to CSS.escape). querySelectorAll\n // throws SyntaxError on those, which bubbles out of page.evaluate and fails\n // the whole thumbnail. Returning undefined here falls back to a full-page\n // screenshot, so the user still sees a thumbnail instead of a broken image.\n let matches: HTMLElement[];\n try {\n matches = Array.from(document.querySelectorAll(selector)).filter(\n (el): el is HTMLElement => el instanceof HTMLElement,\n );\n } catch {\n return undefined;\n }\n const safeIndex = Math.max(0, Math.min(matches.length - 1, Math.floor(selectorIndex ?? 0)));\n const el = matches[safeIndex] ?? null;\n if (!(el instanceof HTMLElement)) return undefined;\n const rect = el.getBoundingClientRect();\n if (rect.width < 4 || rect.height < 4) return undefined;\n const pad = 8;\n const x = Math.max(0, rect.left - pad);\n const y = Math.max(0, rect.top - pad);\n const maxWidth = window.innerWidth - x;\n const maxHeight = window.innerHeight - y;\n return {\n x,\n y,\n width: Math.max(1, Math.min(rect.width + pad * 2, maxWidth)),\n height: Math.max(1, Math.min(rect.height + pad * 2, maxHeight)),\n };\n}\n"],"mappings":";AAOO,SAAS,yBACd,UACA,eAC4B;AAM5B,MAAI;AACJ,MAAI;AACF,cAAU,MAAM,KAAK,SAAS,iBAAiB,QAAQ,CAAC,EAAE;AAAA,MACxD,CAACA,QAA0BA,eAAc;AAAA,IAC3C;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACA,QAAM,YAAY,KAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,SAAS,GAAG,KAAK,MAAM,iBAAiB,CAAC,CAAC,CAAC;AAC1F,QAAM,KAAK,QAAQ,SAAS,KAAK;AACjC,MAAI,EAAE,cAAc,aAAc,QAAO;AACzC,QAAM,OAAO,GAAG,sBAAsB;AACtC,MAAI,KAAK,QAAQ,KAAK,KAAK,SAAS,EAAG,QAAO;AAC9C,QAAM,MAAM;AACZ,QAAM,IAAI,KAAK,IAAI,GAAG,KAAK,OAAO,GAAG;AACrC,QAAM,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,GAAG;AACpC,QAAM,WAAW,OAAO,aAAa;AACrC,QAAM,YAAY,OAAO,cAAc;AACvC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,QAAQ,MAAM,GAAG,QAAQ,CAAC;AAAA,IAC3D,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,SAAS,MAAM,GAAG,SAAS,CAAC;AAAA,EAChE;AACF;","names":["el"]}
@@ -0,0 +1,30 @@
1
+ // src/helpers/finiteMutation.ts
2
+ function findUnsafeMutationValues(value, path = "body", options = {}) {
3
+ if (value === null) {
4
+ return options.allowNullPath?.(path) ? [] : [{ path, reason: "null" }];
5
+ }
6
+ if (typeof value === "number") {
7
+ return Number.isFinite(value) ? [] : [{ path, reason: "non-finite-number" }];
8
+ }
9
+ if (!value || typeof value !== "object") return [];
10
+ if (Array.isArray(value)) {
11
+ return value.flatMap(
12
+ (item, index) => findUnsafeMutationValues(item, `${path}[${index}]`, options)
13
+ );
14
+ }
15
+ return Object.entries(value).flatMap(
16
+ ([key, item]) => findUnsafeMutationValues(item, `${path}.${key}`, options)
17
+ );
18
+ }
19
+ var DOM_PATCH_NULL_VALUE_PATH = /^body\.operations\[\d+\]\.value$/;
20
+ function findUnsafeDomPatchValues(value) {
21
+ return findUnsafeMutationValues(value, "body", {
22
+ allowNullPath: (path) => DOM_PATCH_NULL_VALUE_PATH.test(path)
23
+ });
24
+ }
25
+
26
+ export {
27
+ findUnsafeMutationValues,
28
+ findUnsafeDomPatchValues
29
+ };
30
+ //# sourceMappingURL=chunk-X62ASOGO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/helpers/finiteMutation.ts"],"sourcesContent":["export interface UnsafeMutationValue {\n path: string;\n reason: \"non-finite-number\" | \"null\";\n}\n\ninterface FindUnsafeMutationValuesOptions {\n allowNullPath?: (path: string) => boolean;\n}\n\nexport function findUnsafeMutationValues(\n value: unknown,\n path = \"body\",\n options: FindUnsafeMutationValuesOptions = {},\n): UnsafeMutationValue[] {\n if (value === null) {\n return options.allowNullPath?.(path) ? [] : [{ path, reason: \"null\" }];\n }\n if (typeof value === \"number\") {\n return Number.isFinite(value) ? [] : [{ path, reason: \"non-finite-number\" }];\n }\n if (!value || typeof value !== \"object\") return [];\n if (Array.isArray(value)) {\n return value.flatMap((item, index) =>\n findUnsafeMutationValues(item, `${path}[${index}]`, options),\n );\n }\n return Object.entries(value).flatMap(([key, item]) =>\n findUnsafeMutationValues(item, `${path}.${key}`, options),\n );\n}\n\nconst DOM_PATCH_NULL_VALUE_PATH = /^body\\.operations\\[\\d+\\]\\.value$/;\n\nexport function findUnsafeDomPatchValues(value: unknown): UnsafeMutationValue[] {\n return findUnsafeMutationValues(value, \"body\", {\n allowNullPath: (path) => DOM_PATCH_NULL_VALUE_PATH.test(path),\n });\n}\n"],"mappings":";AASO,SAAS,yBACd,OACA,OAAO,QACP,UAA2C,CAAC,GACrB;AACvB,MAAI,UAAU,MAAM;AAClB,WAAO,QAAQ,gBAAgB,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,QAAQ,OAAO,CAAC;AAAA,EACvE;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO,OAAO,SAAS,KAAK,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,QAAQ,oBAAoB,CAAC;AAAA,EAC7E;AACA,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO,CAAC;AACjD,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,WAAO,MAAM;AAAA,MAAQ,CAAC,MAAM,UAC1B,yBAAyB,MAAM,GAAG,IAAI,IAAI,KAAK,KAAK,OAAO;AAAA,IAC7D;AAAA,EACF;AACA,SAAO,OAAO,QAAQ,KAAK,EAAE;AAAA,IAAQ,CAAC,CAAC,KAAK,IAAI,MAC9C,yBAAyB,MAAM,GAAG,IAAI,IAAI,GAAG,IAAI,OAAO;AAAA,EAC1D;AACF;AAEA,IAAM,4BAA4B;AAE3B,SAAS,yBAAyB,OAAuC;AAC9E,SAAO,yBAAyB,OAAO,QAAQ;AAAA,IAC7C,eAAe,CAAC,SAAS,0BAA0B,KAAK,IAAI;AAAA,EAC9D,CAAC;AACH;","names":[]}