mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-10 22:20:14 +00:00
feat(sdk): ws-3 — reorderElements op (batch z-index update) (#1502)
* feat(sdk): ws-3 — reorderElements op (batch z-index update) Adds the reorderElements EditOp: each entry sets inline zIndex on one element. Last-write-wins per target so a duplicated target collapses to a single zIndex patch. Positioning is unchanged — z-index only takes effect on non-static elements, so the caller must ensure the target is positioned. Also fixes single-dispatch undo to reverse the inverse patch list (parity with batch()): an op emitting multiple patches whose undo order matters — a duplicated reorderElements target, an aliased multi-target, or a nested parent+child removeElement — must undo in reverse application order, or undo lands on an intermediate value / drops a subtree. validateOp resolves every entry target (E_TARGET_NOT_FOUND for unknown ids; empty entries is a clean no-op). Tests cover set/inverse/validate/duplicate-target. Rebuilt standalone on main (reorderElements only depends on handleSetStyle). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(sdk): remove unused HTTP persist adapter The HTTP PersistAdapter (createHttpAdapter) was dead weight after the studio cutover went single-writer (ws-4): Studio's writeProjectFile is the sole writer and useSdkSession opens with no persist queue, so the adapter's write/flush/ listVersions/loadFrom were never used — only read() was, to fetch the composition source. Replace those two read() calls with a direct optional fetch (GET /files/<path>?optional=1) and drop the adapter + its export-map entries. Saved for later re-introduction (when a non-Studio SDK host needs server-backed persist) at docs/hyperframes/plans/sdk-http-adapter/ (outside the repo). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(studio): resolver shadow for z-index reorder targets The z-index reorder commit takes the server path (no SDK persist), but the resolver-shadow tripwire is decoupled from cutover — so it should still record whether the SDK resolves each reordered element (reorderElements' targets), the same as timing/delete already do before their cutover gate. This gives wild resolver-parity telemetry on z-index targets before z-index reorder is cut over. Threads an onReorderShadow callback (sdkSession-bound, mirrors onTrySdkDelete) from useDomEditSession → useDomEditCommits → useElementLifecycleOps, called with the reordered elements' hf-ids in handleDomZIndexReorderCommit. Read-only, divergence-only, never throws — same contract as recordResolverParity elsewhere. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(studio): guard project-file read path against traversal (CodeQL CSRF) readProjectFileOptional interpolated a user-influenced composition path into the fetch URL, which CodeQL flagged as client-side request forgery. Reject NUL/`..` up front (mirrors the existing guard in timelineEditingHelpers) and encodeURIComponent the projectId too, so both values stay confined to single segments of the same-origin URL. Unsafe path → undefined (graceful for the optional read). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
de87f3932e
commit
28bfe09f21
@@ -28,6 +28,8 @@ interface UseElementLifecycleOpsParams {
|
||||
clearDomSelection: () => void;
|
||||
/** Route delete through SDK when session resolves the hf-id; returns true if handled. */
|
||||
onTrySdkDelete?: (hfId: string, originalContent: string, targetPath: string) => Promise<boolean>;
|
||||
/** Resolver-shadow tripwire for the reordered targets (telemetry-only, decoupled from cutover). */
|
||||
onReorderShadow?: (targets: string[]) => void;
|
||||
/** Resync the SDK session after a server-fallback delete. */
|
||||
forceReloadSdkSession?: () => void;
|
||||
commitPositionPatchToHtml: (
|
||||
@@ -49,6 +51,7 @@ export function useElementLifecycleOps({
|
||||
reloadPreview,
|
||||
clearDomSelection,
|
||||
onTrySdkDelete,
|
||||
onReorderShadow,
|
||||
forceReloadSdkSession,
|
||||
commitPositionPatchToHtml,
|
||||
onElementDeleted,
|
||||
@@ -168,6 +171,11 @@ export function useElementLifecycleOps({
|
||||
}>,
|
||||
) => {
|
||||
if (entries.length === 0) return;
|
||||
// Resolver shadow (telemetry-only, decoupled from cutover): record whether
|
||||
// the SDK resolves each reordered element — the reorderElements op's targets.
|
||||
onReorderShadow?.(
|
||||
entries.map((e) => readHfId(e.element)).filter((id): id is string => id != null),
|
||||
);
|
||||
const coalesceKey = `z-reorder:${entries.map((e) => e.id ?? e.selector ?? e.element.getAttribute("data-hf-id") ?? "el").join(":")}`;
|
||||
for (let i = 0; i < entries.length; i++) {
|
||||
const entry = entries[i];
|
||||
@@ -202,7 +210,7 @@ export function useElementLifecycleOps({
|
||||
).catch(() => undefined);
|
||||
}
|
||||
},
|
||||
[commitPositionPatchToHtml],
|
||||
[commitPositionPatchToHtml, onReorderShadow],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user