@hyperframes/sdk 0.8.200 → 0.8.202

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.
@@ -17,6 +17,7 @@ import type { ParsedDocument } from "./model.js";
17
17
  */
18
18
  export declare function applyOverrideSet(parsed: ParsedDocument, overrides: OverrideSet): void;
19
19
  export declare function isElementSnapshotOverride(key: string, value: OverrideSet[string]): value is Record<string, unknown> & {
20
+ html: string;
20
21
  siblingIndex: number;
21
22
  };
22
23
  interface ApplyOptions {
@@ -102,6 +102,10 @@ export function applyOverrideSet(parsed, overrides) {
102
102
  const path = keyToPath(key);
103
103
  if (!path)
104
104
  continue;
105
+ if (value !== null &&
106
+ /^\/elements\/[^/]+$/.test(path) &&
107
+ !isElementSnapshotOverride(key, value))
108
+ continue;
105
109
  if (value === null) {
106
110
  patches.push({ op: "remove", path });
107
111
  }
@@ -127,7 +131,9 @@ export function applyOverrideSet(parsed, overrides) {
127
131
  export function isElementSnapshotOverride(key, value) {
128
132
  if (value === null || typeof value !== "object")
129
133
  return false;
130
- return /^\/elements\/[^/]+$/.test(keyToPath(key) ?? "") && typeof value.siblingIndex === "number";
134
+ return (/^\/elements\/[^/]+$/.test(keyToPath(key) ?? "") &&
135
+ typeof value.html === "string" &&
136
+ typeof value.siblingIndex === "number");
131
137
  }
132
138
  function restoreOverridePositions(parsed, overrides) {
133
139
  const positions = [];
@@ -45,10 +45,7 @@ export declare function styleSheetPath(): string;
45
45
  * Returns null for paths that don't correspond to override-set entries.
46
46
  */
47
47
  export declare function pathToKey(path: string): string | null;
48
- /**
49
- * Inverse of pathToKey — maps an override-set key back to its RFC 6902 path.
50
- * Used to replay a stored override-set onto a fresh base document (T3 init).
51
- */
48
+ /** Map a stored override key to its RFC 6902 path when reopening a base document. */
52
49
  export declare function keyToPath(key: string): string | null;
53
50
  export declare function buildPatchEvent(forward: readonly JsonPatchOp[], inverse: readonly JsonPatchOp[], origin: unknown, opTypes: readonly string[]): PatchEvent;
54
51
  export declare function patchAdd(path: string, value: unknown): JsonPatchOp;
@@ -129,31 +129,41 @@ export function pathToKey(path) {
129
129
  return "style.css";
130
130
  return null;
131
131
  }
132
- /**
133
- * Inverse of pathToKey — maps an override-set key back to its RFC 6902 path.
134
- * Used to replay a stored override-set onto a fresh base document (T3 init).
135
- */
136
- // Exhaustive key-family dispatcher — same shape as apply-patches.ts parsePath.
132
+ // Exhaustive element-key dispatch keeps both ID grammars on the same path rules.
137
133
  // fallow-ignore-next-line complexity
134
+ function elementKeyToPath(key, allowDots = false) {
135
+ const separator = /\.(style|attr|timing|hold)\./.exec(key);
136
+ if (!separator) {
137
+ const id = key.endsWith(".text") ? key.slice(0, -5) : "";
138
+ return id && (allowDots || !id.includes(".")) ? textPath(id) : null;
139
+ }
140
+ const id = key.slice(0, separator.index);
141
+ const prop = key.slice(separator.index + separator[0].length);
142
+ if (!id || !prop || (!allowDots && id.includes(".")))
143
+ return null;
144
+ switch (separator[1]) {
145
+ case "style":
146
+ return stylePath(id, prop);
147
+ case "attr":
148
+ // Attribute names are already RFC 6902-encoded by pathToKey.
149
+ return `/elements/${escapeIdForPath(id)}/attributes/${prop}`;
150
+ case "timing":
151
+ if (prop === "start" || prop === "end" || prop === "duration" || prop === "trackIndex")
152
+ return timingPath(id, prop);
153
+ return null;
154
+ case "hold":
155
+ if (prop === "start" || prop === "end" || prop === "fill")
156
+ return holdPath(id, prop);
157
+ return null;
158
+ default:
159
+ return null;
160
+ }
161
+ }
162
+ /** Map a stored override key to its RFC 6902 path when reopening a base document. */
138
163
  export function keyToPath(key) {
139
- const style = /^([^.]+)\.style\.(.+)$/.exec(key);
140
- if (style?.[1] && style[2])
141
- return stylePath(style[1], style[2]);
142
- const text = /^([^.]+)\.text$/.exec(key);
143
- if (text?.[1])
144
- return textPath(text[1]);
145
- const attr = /^([^.]+)\.attr\.(.+)$/.exec(key);
146
- // The attr name segment in the key is already RFC 6902-encoded (pathToKey stored it verbatim).
147
- // The id may be a scoped id (contains "/") so we must escape it, but must NOT re-escape
148
- // the already-encoded attr segment. Reconstruct manually.
149
- if (attr?.[1] && attr[2])
150
- return `/elements/${escapeIdForPath(attr[1])}/attributes/${attr[2]}`;
151
- const timing = /^([^.]+)\.timing\.(start|end|duration|trackIndex)$/.exec(key);
152
- if (timing?.[1])
153
- return timingPath(timing[1], timing[2]);
154
- const hold = /^([^.]+)\.hold\.(start|end|fill)$/.exec(key);
155
- if (hold?.[1])
156
- return holdPath(hold[1], hold[2]);
164
+ const element = elementKeyToPath(key);
165
+ if (element)
166
+ return element;
157
167
  const varDecl = /^varDecl\.(.+)$/.exec(key);
158
168
  if (varDecl?.[1])
159
169
  return variableDeclPath(varDecl[1]);
@@ -167,10 +177,8 @@ export function keyToPath(key) {
167
177
  return gsapScriptPath();
168
178
  if (key === "style.css")
169
179
  return styleSheetPath();
170
- // Bare element id — removal marker key.
171
- if (!key.includes("."))
172
- return elementPath(key);
173
- return null;
180
+ // Existing namespaces keep precedence over the dotted-ID fallback.
181
+ return elementKeyToPath(key, true) ?? elementPath(key);
174
182
  }
175
183
  // ─── Patch event builder ──────────────────────────────────────────────────────
176
184
  export function buildPatchEvent(forward, inverse, origin, opTypes) {
package/dist/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { CompositionVariable, VariableValidationIssue } from "@hyperframes/core/variables";
1
+ import type { CompositionVariable, FontValue, ImageValue, VariableValidationIssue } from "@hyperframes/core/variables";
2
2
  /**
3
3
  * Cross-referenced variable usage for a whole composition: the per-script
4
4
  * static scans merged and compared against the declared schema.
@@ -321,25 +321,7 @@ export interface ElasticHold {
321
321
  end: number;
322
322
  fill: "freeze" | "loop";
323
323
  }
324
- /**
325
- * Object value for a `font` variable (LOCKED §7 — object-valued, never a CSS string).
326
- * `name` is the CSS font-family value; `source` is the stylesheet URL to load.
327
- */
328
- export interface FontValue {
329
- name: string;
330
- source: string;
331
- }
332
- /**
333
- * Object value for an `image` variable (LOCKED §7 — object-valued, never a CSS string).
334
- * `url` is the image src. Add explicit optional fields here as consumers need them —
335
- * an open `[key: string]: unknown` index signature was dropped because it let any
336
- * `{url}`-shaped object through and swallowed key typos.
337
- */
338
- export interface ImageValue {
339
- url: string;
340
- alt?: string;
341
- fit?: "cover" | "contain" | "fill" | "none" | "scale-down";
342
- }
324
+ export type { FontValue, ImageValue } from "@hyperframes/core/variables";
343
325
  export interface GsapTweenSpec {
344
326
  method: "from" | "to" | "fromTo" | "set";
345
327
  position?: number | string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperframes/sdk",
3
- "version": "0.8.200",
3
+ "version": "0.8.202",
4
4
  "description": "Headless, framework-neutral HyperFrames composition editing engine",
5
5
  "repository": {
6
6
  "type": "git",
@@ -44,8 +44,8 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "linkedom": "^0.18.12",
47
- "@hyperframes/parsers": "0.8.200",
48
- "@hyperframes/core": "0.8.200"
47
+ "@hyperframes/core": "0.8.202",
48
+ "@hyperframes/parsers": "0.8.202"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@types/node": "^25.0.10",