mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-05 17:30:50 +00:00
* feat(sdk,studio): populate animationIds; shadow GSAP update/delete Closes the GSAP shadow gaps. The server's animationId was assumed to live in a separate id-space — it does not: the studio-api read path (T6e) and the SDK both derive tween ids as targetSelector-method-position from the same acorn parser, so server ids are dispatchable in the SDK as-is. SDK: populate ElementSnapshot.animationIds (was a hardcoded stub) from parseGsapScriptAcornForWrite().located, resolving each tween's targetSelector to element hf-ids. Makes the snapshot truthful and enables real GSAP parity. Studio: shadow deleteGsapAnimation (removeGsapTween) and updateGsapMeta (setGsapTween) using the server animationId directly. GSAP add/remove parity now verifies via animationIds (present after add, gone after remove). set is existence-only — the SDK still has no per-tween property reader (value fidelity would need serialize()-script round-trip diffing). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(studio): GSAP value fidelity via serialize round-trip diff Closes the last shadow gap: GSAP value fidelity. Existence parity confirmed a tween was created/removed but not that its values (duration/ease/position/ properties) matched the server, since the SDK has no per-tween property reader. runShadowGsapFidelity opens a fresh SDK doc from the server's pre-op file (result.before), applies the same typed op, serializes, and structurally diffs the SDK's GSAP script against the server's resulting script (result.scriptText). Both are re-parsed via parseGsapScriptAcorn, so formatting/whitespace never produces false positives — only real value drift does. gsapFidelityMismatches reports per-field drift and tween presence/absence. Wired at the commitMutation chokepoint (the only place with the server's before+after scripts); handlers pass the typed ShadowGsapOp via CommitMutationOptions.shadowGsapOp. Emits sdk_shadow_dispatch op:gsap_fidelity. Complements the existing live existence shadow (op:gsap). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(studio,sdk): address shadow code-review findings - gsapFidelityMismatches: canonical comparison (sort property keys, numeric- coerce position/duration/values). Server (addAnimationToScript) and SDK (gsapWriterAcorn) are different writers; non-canonical compare flagged key-order / number-vs-string differences as false value drift. - document.ts buildAnimationIdMap: memoize the acorn parse by script text (single-entry). getElements() invalidates on every dispatch, so shadow's frequent dispatches were re-parsing the full GSAP AST each rebuild. Selector resolution still runs per-call (depends on live DOM). - runShadowGsapFidelity: early-bail when serverScript/beforeHtml is empty — skip the costly openComposition. - useSafeGsapCommitMutation: import the shared CommitMutationOptions/ CommitMutation instead of a stale local duplicate (was missing shadowGsapOp). - align extractGsapScript marker set across sdkShadow.ts and document.ts (gsap || __timelines || ScrollTrigger) so both pick the same script. Tests: +2 canonical-compare cases (key-order, number-vs-string → no drift). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(studio,sdk): fallow gate for #1474 (fidelity diff + test clones) - suppress moderate CRAP on gsapFidelityMismatches and the runShadowGsapTween parity arrow (comparison/parity functions are inherently branchy) - suppress two pre-existing test clones in session.test.ts surfaced by the added animationIds tests (TestPreviewAdapter stub, selectionchange setup) Rebased onto the updated #1473 (no-persist shadow session); inherits the persist-race fix and prior fallow suppressions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(studio): extract GSAP fidelity to its own module (file-size gate) sdkShadow.ts hit 602 lines (CI File size check: max 600). Move the GSAP value-fidelity diff (gsapFidelityMismatches, runShadowGsapFidelity, and their private helpers) into sdkShadowGsapFidelity.ts; re-export from sdkShadow.ts so the import surface is unchanged. sdkShadow.ts now 430 lines. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(studio,sdk): address #1474 review feedback - CodeQL js/bad-tag-filter: the GSAP <script> extraction + test regexes now match </script\s*> (whitespace-before-close variant). 3 alerts resolved. - Wiring (Miguel): extract resolveGsapFidelityArgs — a pure, narrowing gate for the commitMutation chokepoint (no non-null assertions) — and unit-test the fire/skip conditions (session, op, before, scriptText). Replaces the inline guard so the wiring decision is covered without rendering the hook. - Property-handler scope (Rames): comment at the chokepoint documenting that only meta-level ops (add/update-meta/delete) carry shadowGsapOp today; per-property and keyframe handlers are a deliberate follow-up. Also why scriptText can be null. - Test coverage (Rames): multi-tween-per-element and shared-selector cross-element animationIds cases. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(studio): CodeQL js/bad-tag-filter — match </script[^>]*> close tags `</script\s*>` still tripped CodeQL on attribute-junk closes like `</script foo>` (HTML5 ignores junk before `>`). Widen the close-tag match to `</script[^>]*>` in the GSAP-script extraction and the test regexes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
54 lines
1.8 KiB
TypeScript
54 lines
1.8 KiB
TypeScript
import { useCallback } from "react";
|
|
import type { DomEditSelection } from "../components/editor/domEditingTypes";
|
|
import { getStudioSaveErrorMessage, trackStudioSaveFailure } from "../utils/studioSaveDiagnostics";
|
|
import type { CommitMutation, CommitMutationOptions } from "./gsapScriptCommitTypes";
|
|
|
|
type TrackGsapSaveFailure = (
|
|
error: unknown,
|
|
selection: DomEditSelection,
|
|
mutation: Record<string, unknown>,
|
|
label?: string,
|
|
) => void;
|
|
|
|
function getGsapMutationType(mutation: Record<string, unknown>): string {
|
|
return typeof mutation.type === "string" ? mutation.type : "gsap";
|
|
}
|
|
|
|
export function useGsapSaveFailureTelemetry(activeCompPath: string | null): TrackGsapSaveFailure {
|
|
return useCallback(
|
|
(error, selection, mutation, label) => {
|
|
trackStudioSaveFailure({
|
|
source: "gsap_commit",
|
|
error,
|
|
filePath: selection.sourceFile ?? activeCompPath ?? "index.html",
|
|
mutationType: getGsapMutationType(mutation),
|
|
label,
|
|
targetId: selection.id,
|
|
targetSelector: selection.selector,
|
|
targetSourceFile: selection.sourceFile,
|
|
});
|
|
},
|
|
[activeCompPath],
|
|
);
|
|
}
|
|
|
|
export function useSafeGsapCommitMutation(
|
|
commitMutation: CommitMutation,
|
|
trackGsapSaveFailure: TrackGsapSaveFailure,
|
|
showToast?: (message: string, tone?: "error" | "info") => void,
|
|
) {
|
|
return useCallback(
|
|
(
|
|
selection: DomEditSelection,
|
|
mutation: Record<string, unknown>,
|
|
options: CommitMutationOptions,
|
|
) => {
|
|
void commitMutation(selection, mutation, options).catch((error) => {
|
|
trackGsapSaveFailure(error, selection, mutation, options.label);
|
|
showToast?.(`Couldn't save animation: ${getStudioSaveErrorMessage(error)}`, "error");
|
|
});
|
|
},
|
|
[commitMutation, trackGsapSaveFailure, showToast],
|
|
);
|
|
}
|