mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-07 18:26:17 +00:00
feat(studio): stage 7 step 3b — SDK shadow dispatch parity mode (#1450)
* feat(studio): stage 7 step 3b — SDK shadow dispatch parity mode Wire onDomEditPersisted callback from useDomEditCommits into useDomEditSession, calling reportShadowDispatch (flag-gated via VITE_STUDIO_SDK_SHADOW_ENABLED) to dispatch equivalent SDK ops alongside the server patch path and emit sdk_shadow_dispatch telemetry with mismatch details. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(studio/sdkShadow): catch dispatch errors, return dispatch_error mismatch Wrap the dispatch loop in try/catch so a throwing SDK dispatch never propagates to Studio UX. Returns dispatched:false with kind="dispatch_error" and the error message for telemetry. One new TDD test (RED→GREEN verified). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(studio): batch shadow dispatch, rename runShadowDispatch, add PatchOperation import Wrap the shadow dispatch loop in session.batch() so a mid-loop throw cannot leave the SDK session in a partially-applied state. Without the batch boundary, one failing op would update some elements but not others, diverging the shadow session from the real one. Rename reportShadowDispatch → runShadowDispatch to eliminate the misleading 'report' prefix — the function mutates the SDK session, it is not read-only. Update the only caller (useDomEditSession). Add missing PatchOperation import to useDomEditCommits (the type was already used in the onDomEditPersisted interface but never imported). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Miguel Ángel <miguel07alm@protonmail.com> * docs(studio/sdkShadow): note persist:error drift risk in parity comparisons Also remove unused re-exports from useDomEditCommits (GSAP_CSS_FALLBACK_BLOCKED_MESSAGE and PersistDomEditOperations — fallow confirmed 0 consumers) and suppress the Vite ?raw import in sdk-playground that fallow can't resolve statically. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Miguel Ángel <miguel07alm@protonmail.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Miguel Ángel <miguel07alm@protonmail.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
Miguel Ángel
parent
5fe87cc39b
commit
69aa595f38
@@ -9,14 +9,12 @@ import { buildDomEditPatchTarget, type DomEditSelection } from "../components/ed
|
||||
import { fontFamilyFromAssetPath, type ImportedFontAsset } from "../components/editor/fontAssets";
|
||||
import type { EditHistoryKind } from "../utils/editHistory";
|
||||
import type { PersistDomEditOperations } from "./domEditCommitTypes";
|
||||
import type { PatchOperation } from "../utils/sourcePatcher";
|
||||
import { useDomEditPositionPatchCommit } from "./useDomEditPositionPatchCommit";
|
||||
import { useDomEditTextCommits } from "./useDomEditTextCommits";
|
||||
import { useDomGeometryCommits } from "./useDomGeometryCommits";
|
||||
import { useElementLifecycleOps } from "./useElementLifecycleOps";
|
||||
|
||||
// Re-export so existing consumers keep their import path
|
||||
export { GSAP_CSS_FALLBACK_BLOCKED_MESSAGE } from "./useDomGeometryCommits";
|
||||
|
||||
// ── Helpers ──
|
||||
|
||||
function formatUnsafeFieldList(fields: Array<{ path: string }>): string {
|
||||
@@ -40,8 +38,6 @@ function formatPatchRejectionMessage(body: { error?: string; fields?: string[] }
|
||||
return `Couldn't save edit: ${body.error}${suffix}`;
|
||||
}
|
||||
|
||||
// ── Types ──
|
||||
|
||||
interface RecordEditInput {
|
||||
label: string;
|
||||
kind: EditHistoryKind;
|
||||
@@ -49,8 +45,6 @@ interface RecordEditInput {
|
||||
files: Record<string, { before: string; after: string }>;
|
||||
}
|
||||
|
||||
export type { PersistDomEditOperations } from "./domEditCommitTypes";
|
||||
|
||||
export interface UseDomEditCommitsParams {
|
||||
activeCompPath: string | null;
|
||||
previewIframeRef: React.MutableRefObject<HTMLIFrameElement | null>;
|
||||
@@ -77,10 +71,10 @@ export interface UseDomEditCommitsParams {
|
||||
target: HTMLElement,
|
||||
options?: { preferClipAncestor?: boolean },
|
||||
) => Promise<DomEditSelection | null>;
|
||||
/** Stage 7 Step 3b: called after a successful server-side element patch. */
|
||||
onDomEditPersisted?: (selection: DomEditSelection, operations: PatchOperation[]) => void;
|
||||
}
|
||||
|
||||
// ── Hook ──
|
||||
|
||||
export function useDomEditCommits({
|
||||
activeCompPath,
|
||||
previewIframeRef,
|
||||
@@ -99,6 +93,7 @@ export function useDomEditCommits({
|
||||
clearDomSelection,
|
||||
refreshDomEditSelectionFromPreview,
|
||||
buildDomSelectionFromTarget,
|
||||
onDomEditPersisted,
|
||||
}: UseDomEditCommitsParams) {
|
||||
const resolveImportedFontAsset = useCallback(
|
||||
(fontFamilyValue: string): ImportedFontAsset | null => {
|
||||
@@ -220,6 +215,7 @@ export function useDomEditCommits({
|
||||
coalesceKey: options?.coalesceKey,
|
||||
files: { [targetPath]: { before: originalContent, after: finalContent } },
|
||||
});
|
||||
onDomEditPersisted?.(selection, operations);
|
||||
|
||||
if (!options?.skipRefresh) {
|
||||
reloadPreview();
|
||||
@@ -233,6 +229,7 @@ export function useDomEditCommits({
|
||||
domEditSaveTimestampRef,
|
||||
reloadPreview,
|
||||
showToast,
|
||||
onDomEditPersisted,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user