hyperframes 0.4.13 → 0.4.14

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.
package/dist/cli.js CHANGED
@@ -54,7 +54,7 @@ var VERSION;
54
54
  var init_version = __esm({
55
55
  "src/version.ts"() {
56
56
  "use strict";
57
- VERSION = true ? "0.4.13" : "0.0.0-dev";
57
+ VERSION = true ? "0.4.14" : "0.0.0-dev";
58
58
  }
59
59
  });
60
60
 
@@ -4422,6 +4422,110 @@ var init_core = __esm({
4422
4422
  });
4423
4423
 
4424
4424
  // ../core/src/lint/rules/media.ts
4425
+ function escapeRegExp(value) {
4426
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4427
+ }
4428
+ function selectorTargetsManagedMedia(selector, mediaIds) {
4429
+ const normalized = selector.trim();
4430
+ if (!normalized) return false;
4431
+ if (/\b(video|audio)\b/i.test(normalized)) return true;
4432
+ for (const mediaId of mediaIds) {
4433
+ if (normalized.includes(`#${mediaId}`) || normalized.includes(`[id="${mediaId}"]`) || normalized.includes(`[id='${mediaId}']`)) {
4434
+ return true;
4435
+ }
4436
+ }
4437
+ return false;
4438
+ }
4439
+ function findImperativeMediaControlFindings(ctx) {
4440
+ const findings = [];
4441
+ const managedMediaIds = new Set(
4442
+ ctx.tags.filter((tag) => tag.name === "video" || tag.name === "audio").map((tag) => readAttr(tag.raw, "id")).filter((id) => Boolean(id))
4443
+ );
4444
+ if (managedMediaIds.size === 0 || ctx.scripts.length === 0) return findings;
4445
+ for (const script of ctx.scripts) {
4446
+ const mediaVars = /* @__PURE__ */ new Map();
4447
+ const assignmentPatterns = [
4448
+ /\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:document|window\.document)\.getElementById\(\s*["']([^"']+)["']\s*\)/g,
4449
+ /\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:document|window\.document)\.querySelector\(\s*["']([^"']+)["']\s*\)/g
4450
+ ];
4451
+ for (const pattern of assignmentPatterns) {
4452
+ let match;
4453
+ while ((match = pattern.exec(script.content)) !== null) {
4454
+ const variableName = match[1];
4455
+ const target = match[2];
4456
+ if (!variableName || !target) continue;
4457
+ if (managedMediaIds.has(target) || selectorTargetsManagedMedia(target, managedMediaIds)) {
4458
+ mediaVars.set(variableName, managedMediaIds.has(target) ? target : void 0);
4459
+ }
4460
+ }
4461
+ }
4462
+ const directIdPatterns = [
4463
+ {
4464
+ pattern: /\b(?:document|window\.document)\.getElementById\(\s*["']([^"']+)["']\s*\)\.play\s*\(/g,
4465
+ kind: "play()"
4466
+ },
4467
+ {
4468
+ pattern: /\b(?:document|window\.document)\.getElementById\(\s*["']([^"']+)["']\s*\)\.pause\s*\(/g,
4469
+ kind: "pause()"
4470
+ },
4471
+ {
4472
+ pattern: /\b(?:document|window\.document)\.getElementById\(\s*["']([^"']+)["']\s*\)\.currentTime\s*=/g,
4473
+ kind: "currentTime"
4474
+ },
4475
+ {
4476
+ pattern: /\b(?:document|window\.document)\.querySelector\(\s*["']([^"']+)["']\s*\)\.play\s*\(/g,
4477
+ kind: "play()"
4478
+ },
4479
+ {
4480
+ pattern: /\b(?:document|window\.document)\.querySelector\(\s*["']([^"']+)["']\s*\)\.pause\s*\(/g,
4481
+ kind: "pause()"
4482
+ },
4483
+ {
4484
+ pattern: /\b(?:document|window\.document)\.querySelector\(\s*["']([^"']+)["']\s*\)\.currentTime\s*=/g,
4485
+ kind: "currentTime"
4486
+ }
4487
+ ];
4488
+ for (const { pattern, kind } of directIdPatterns) {
4489
+ let match;
4490
+ while ((match = pattern.exec(script.content)) !== null) {
4491
+ const target = match[1];
4492
+ if (!target) continue;
4493
+ const elementId = managedMediaIds.has(target) ? target : selectorTargetsManagedMedia(target, managedMediaIds) ? void 0 : null;
4494
+ if (elementId === null) continue;
4495
+ findings.push({
4496
+ code: "imperative_media_control",
4497
+ severity: "error",
4498
+ message: `Inline <script> imperatively controls managed media via ${kind}. HyperFrames must own media play/pause/seek to keep preview, timeline, and renders deterministic.`,
4499
+ elementId: elementId || void 0,
4500
+ fixHint: "Remove imperative media play/pause/currentTime control. Express timing with data-start/data-duration and media offsets like data-media-start or data-playback-start instead.",
4501
+ snippet: truncateSnippet(match[0])
4502
+ });
4503
+ }
4504
+ }
4505
+ for (const [variableName, elementId] of mediaVars) {
4506
+ const escapedVar = escapeRegExp(variableName);
4507
+ const variablePatterns = [
4508
+ { pattern: new RegExp(`\\b${escapedVar}\\.play\\s*\\(`, "g"), kind: "play()" },
4509
+ { pattern: new RegExp(`\\b${escapedVar}\\.pause\\s*\\(`, "g"), kind: "pause()" },
4510
+ { pattern: new RegExp(`\\b${escapedVar}\\.currentTime\\s*=`, "g"), kind: "currentTime" }
4511
+ ];
4512
+ for (const { pattern, kind } of variablePatterns) {
4513
+ let match;
4514
+ while ((match = pattern.exec(script.content)) !== null) {
4515
+ findings.push({
4516
+ code: "imperative_media_control",
4517
+ severity: "error",
4518
+ message: `Inline <script> imperatively controls managed media via ${kind}. HyperFrames must own media play/pause/seek to keep preview, timeline, and renders deterministic.`,
4519
+ elementId,
4520
+ fixHint: "Remove imperative media play/pause/currentTime control. Express timing with data-start/data-duration and media offsets like data-media-start or data-playback-start instead.",
4521
+ snippet: truncateSnippet(match[0])
4522
+ });
4523
+ }
4524
+ }
4525
+ }
4526
+ }
4527
+ return findings;
4528
+ }
4425
4529
  var mediaRules;
4426
4530
  var init_media = __esm({
4427
4531
  "../core/src/lint/rules/media.ts"() {
@@ -4649,7 +4753,9 @@ var init_media = __esm({
4649
4753
  }
4650
4754
  }
4651
4755
  return findings;
4652
- }
4756
+ },
4757
+ // imperative_media_control
4758
+ findImperativeMediaControlFindings
4653
4759
  ];
4654
4760
  }
4655
4761
  });
@@ -29622,7 +29728,6 @@ __export(src_exports2, {
29622
29728
  getEncoderPreset: () => getEncoderPreset,
29623
29729
  getFrameAtTime: () => getFrameAtTime,
29624
29730
  getHdrEncoderColorParams: () => getHdrEncoderColorParams,
29625
- getSrgbToHdrLut: () => getSrgbToHdrLut,
29626
29731
  getSystemResources: () => getSystemResources,
29627
29732
  groupIntoLayers: () => groupIntoLayers,
29628
29733
  hdrToLinear: () => hdrToLinear,
@@ -33095,8 +33200,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
33095
33200
  )
33096
33201
  });
33097
33202
  }
33098
- for (let layerIdx = 0; layerIdx < layers.length; layerIdx++) {
33099
- const layer = layers[layerIdx];
33203
+ for (const [layerIdx, layer] of layers.entries()) {
33100
33204
  if (layer.type === "hdr") {
33101
33205
  const before2 = shouldLog ? countNonZeroRgb482(canvas) : 0;
33102
33206
  const isHdrImage = nativeHdrImageIds.has(layer.element.id);
@@ -34675,7 +34779,7 @@ function createStudioServer(options) {
34675
34779
  });
34676
34780
  app.get("/api/runtime.js", (c2) => {
34677
34781
  const serve4 = async () => {
34678
- const runtimeSource = existsSync31(runtimePath) ? readFileSync23(runtimePath, "utf-8") : await loadRuntimeSourceFallback();
34782
+ const runtimeSource = await loadRuntimeSourceFallback() ?? (existsSync31(runtimePath) ? readFileSync23(runtimePath, "utf-8") : null);
34679
34783
  if (!runtimeSource) return c2.text("runtime not available", 404);
34680
34784
  return c2.body(runtimeSource, 200, {
34681
34785
  "Content-Type": "text/javascript",