@hyperframes/studio 0.8.18 → 0.8.20

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.
@@ -1 +1 @@
1
- import{g as P}from"./index-F-PUkOVc.js";function j(c,d){for(var s=0;s<d.length;s++){const a=d[s];if(typeof a!="string"&&!Array.isArray(a)){for(const i in a)if(i!=="default"&&!(i in c)){const l=Object.getOwnPropertyDescriptor(a,i);l&&Object.defineProperty(c,i,l.get?l:{enumerable:!0,get:()=>a[i]})}}}return Object.freeze(Object.defineProperty(c,Symbol.toStringTag,{value:"Module"}))}var v={},w;function k(){if(w)return v;w=1,Object.defineProperty(v,"__esModule",{value:!0}),v.default=d;var c=window.OfflineAudioContext||window.webkitOfflineAudioContext;function d(e){var r=a(e);return r.start(0),[i,y,O(e.sampleRate),s].reduce(function(t,o){return o(t)},r.buffer.getChannelData(0))}function s(e){return e.sort(function(r,t){return t.count-r.count}).splice(0,5)[0].tempo}function a(e){var r=e.length,t=e.numberOfChannels,o=e.sampleRate,n=new c(t,r,o),u=n.createBufferSource();u.buffer=e;var f=n.createBiquadFilter();return f.type="lowpass",u.connect(f),f.connect(n.destination),u}function i(e){for(var r=[],t=.9,o=.3,n=15;r.length<n&&t>=o;)r=l(e,t),t-=.05;if(r.length<n)throw new Error("Could not find enough samples for a reliable detection.");return r}function l(e,r){for(var t=[],o=0,n=e.length;o<n;o+=1)e[o]>r&&(t.push(o),o+=1e4);return t}function y(e){var r=[];return e.forEach(function(t,o){for(var n=function(x){var g=e[o+x]-t,_=r.some(function(h){if(h.interval===g)return h.count+=1});_||r.push({interval:g,count:1})},u=0;u<10;u+=1)n(u)}),r}function O(e){return function(r){var t=[];return r.forEach(function(o){if(o.interval!==0){for(var n=60/(o.interval/e);n<90;)n*=2;for(;n>180;)n/=2;n=Math.round(n);var u=t.some(function(f){if(f.tempo===n)return f.count+=o.count});u||t.push({tempo:n,count:o.count})}}),t}}return v}var p,b;function q(){return b||(b=1,p=k().default),p}var m=q();const A=P(m),D=j({__proto__:null,default:A},[m]);export{D as i};
1
+ import{g as P}from"./index-CBSKXKAr.js";function j(c,d){for(var s=0;s<d.length;s++){const a=d[s];if(typeof a!="string"&&!Array.isArray(a)){for(const i in a)if(i!=="default"&&!(i in c)){const l=Object.getOwnPropertyDescriptor(a,i);l&&Object.defineProperty(c,i,l.get?l:{enumerable:!0,get:()=>a[i]})}}}return Object.freeze(Object.defineProperty(c,Symbol.toStringTag,{value:"Module"}))}var v={},w;function k(){if(w)return v;w=1,Object.defineProperty(v,"__esModule",{value:!0}),v.default=d;var c=window.OfflineAudioContext||window.webkitOfflineAudioContext;function d(e){var r=a(e);return r.start(0),[i,y,O(e.sampleRate),s].reduce(function(t,o){return o(t)},r.buffer.getChannelData(0))}function s(e){return e.sort(function(r,t){return t.count-r.count}).splice(0,5)[0].tempo}function a(e){var r=e.length,t=e.numberOfChannels,o=e.sampleRate,n=new c(t,r,o),u=n.createBufferSource();u.buffer=e;var f=n.createBiquadFilter();return f.type="lowpass",u.connect(f),f.connect(n.destination),u}function i(e){for(var r=[],t=.9,o=.3,n=15;r.length<n&&t>=o;)r=l(e,t),t-=.05;if(r.length<n)throw new Error("Could not find enough samples for a reliable detection.");return r}function l(e,r){for(var t=[],o=0,n=e.length;o<n;o+=1)e[o]>r&&(t.push(o),o+=1e4);return t}function y(e){var r=[];return e.forEach(function(t,o){for(var n=function(x){var g=e[o+x]-t,_=r.some(function(h){if(h.interval===g)return h.count+=1});_||r.push({interval:g,count:1})},u=0;u<10;u+=1)n(u)}),r}function O(e){return function(r){var t=[];return r.forEach(function(o){if(o.interval!==0){for(var n=60/(o.interval/e);n<90;)n*=2;for(;n>180;)n/=2;n=Math.round(n);var u=t.some(function(f){if(f.tempo===n)return f.count+=o.count});u||t.push({tempo:n,count:o.count})}}),t}}return v}var p,b;function q(){return b||(b=1,p=k().default),p}var m=q();const A=P(m),D=j({__proto__:null,default:A},[m]);export{D as i};
package/dist/index.html CHANGED
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
6
6
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
7
7
  <title>HyperFrames Studio</title>
8
- <script type="module" crossorigin src="/assets/index-F-PUkOVc.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-CBSKXKAr.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-yGhfxxoL.css">
10
10
  </head>
11
11
  <body>
package/dist/index.js CHANGED
@@ -16306,6 +16306,9 @@ function buildStudioSaveFailureProperties(input) {
16306
16306
  function trackStudioSaveFailure(input) {
16307
16307
  trackStudioEvent("save_failure", buildStudioSaveFailureProperties(input));
16308
16308
  }
16309
+ function trackStudioEditBlocked(input) {
16310
+ trackStudioEvent("edit_blocked", buildStudioSaveFailureProperties(input));
16311
+ }
16309
16312
  async function createStudioSaveHttpError(response, fallbackMessage, options = {}) {
16310
16313
  let body = "";
16311
16314
  try {
@@ -16693,7 +16696,16 @@ async function studioExpectedFileVersion(versions, path, expectedContent) {
16693
16696
  return versions.get(path);
16694
16697
  }
16695
16698
  function createStudioWriteToken() {
16696
- return globalThis.crypto.randomUUID();
16699
+ const webCrypto = globalThis.crypto;
16700
+ if (typeof webCrypto?.randomUUID === "function") return webCrypto.randomUUID();
16701
+ if (typeof webCrypto?.getRandomValues !== "function") {
16702
+ throw new Error("Web Crypto getRandomValues is required for Studio write identity");
16703
+ }
16704
+ const bytes = webCrypto.getRandomValues(new Uint8Array(16));
16705
+ bytes[6] = bytes[6] & 15 | 64;
16706
+ bytes[8] = bytes[8] & 63 | 128;
16707
+ const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
16708
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
16697
16709
  }
16698
16710
  function studioWriteHeaders() {
16699
16711
  const token = createStudioWriteToken();
@@ -60693,7 +60705,7 @@ function writeHiddenIds(projectId, ids) {
60693
60705
  } catch {
60694
60706
  }
60695
60707
  }
60696
- function useRenderQueue(projectId) {
60708
+ function useRenderQueue(projectId, activeCompPathRef) {
60697
60709
  const [jobs, setJobs] = useState94([]);
60698
60710
  const [loadError, setLoadError] = useState94(null);
60699
60711
  const [actionError, setActionError] = useState94(null);
@@ -60769,7 +60781,7 @@ function useRenderQueue(projectId) {
60769
60781
  const quality = opts.quality ?? "standard";
60770
60782
  const format = opts.format ?? "mp4";
60771
60783
  const resolution = opts.resolution;
60772
- const composition = opts.composition;
60784
+ const composition = opts.composition ?? activeCompPathRef.current ?? void 0;
60773
60785
  trackStudioRenderStart({
60774
60786
  fps,
60775
60787
  quality,
@@ -60884,7 +60896,7 @@ function useRenderQueue(projectId) {
60884
60896
  };
60885
60897
  return jobId;
60886
60898
  },
60887
- [projectId, closeActiveEventSource, addSessionJob, ffmpeg, ffmpegMissing]
60899
+ [projectId, activeCompPathRef, closeActiveEventSource, addSessionJob, ffmpeg, ffmpegMissing]
60888
60900
  );
60889
60901
  const cancelRender = useCallback80(
60890
60902
  async (jobId) => {
@@ -62928,6 +62940,7 @@ function useFileTree({ projectId, projectIdRef }) {
62928
62940
 
62929
62941
  // src/hooks/useEditorSave.ts
62930
62942
  import { useCallback as useCallback87, useRef as useRef112 } from "react";
62943
+ var FAILURE_BURST_MS = 5e3;
62931
62944
  function useEditorSave({
62932
62945
  editingPathRef,
62933
62946
  projectIdRef,
@@ -62940,18 +62953,32 @@ function useEditorSave({
62940
62953
  }) {
62941
62954
  const saveRafRef = useRef112(null);
62942
62955
  const refreshRafRef = useRef112(null);
62943
- const lastFailureToastAtRef = useRef112(0);
62956
+ const lastFailureToastAtRef = useRef112(null);
62957
+ const lastFailureReportRef = useRef112(null);
62944
62958
  const pendingCandidateRef = useRef112(null);
62945
62959
  const inFlightRef = useRef112(null);
62946
62960
  const inFlightCandidateRef = useRef112(null);
62947
62961
  const reportFailure = useCallback87(
62948
62962
  (path, error) => {
62949
- trackStudioEvent("save_failure", {
62963
+ const now2 = Date.now();
62964
+ const properties = buildStudioSaveFailureProperties({
62950
62965
  source: "code_editor",
62951
- error_message: error instanceof Error ? error.message : "unknown"
62966
+ error,
62967
+ filePath: path
62952
62968
  });
62953
- const now2 = Date.now();
62954
- if (now2 - lastFailureToastAtRef.current > 5e3) {
62969
+ const errorName = error instanceof Error ? error.name : typeof error;
62970
+ const fingerprint = JSON.stringify([
62971
+ path,
62972
+ errorName,
62973
+ properties.error_message,
62974
+ properties.status_code
62975
+ ]);
62976
+ const previous = lastFailureReportRef.current;
62977
+ if (previous === null || previous.fingerprint !== fingerprint || now2 - previous.emittedAt >= FAILURE_BURST_MS) {
62978
+ trackStudioSaveFailure({ source: "code_editor", error, filePath: path });
62979
+ lastFailureReportRef.current = { fingerprint, emittedAt: now2 };
62980
+ }
62981
+ if (lastFailureToastAtRef.current === null || now2 - lastFailureToastAtRef.current >= FAILURE_BURST_MS) {
62955
62982
  lastFailureToastAtRef.current = now2;
62956
62983
  showToast(
62957
62984
  `Couldn't save ${path} \u2014 your latest edits are NOT persisted. Check the preview server; editing again retries the save.`,
@@ -62974,6 +63001,7 @@ function useEditorSave({
62974
63001
  recordEdit
62975
63002
  }).then(() => {
62976
63003
  if (pendingCandidateRef.current === candidate) pendingCandidateRef.current = null;
63004
+ lastFailureReportRef.current = null;
62977
63005
  if (refreshRafRef.current != null) cancelAnimationFrame(refreshRafRef.current);
62978
63006
  refreshRafRef.current = requestAnimationFrame(() => setRefreshKey((k) => k + 1));
62979
63007
  return { status: "clean" };
@@ -70189,7 +70217,8 @@ import { useCallback as useCallback117 } from "react";
70189
70217
  function useGsapInteractionFailureTelemetry(activeCompPath, showToast) {
70190
70218
  return useCallback117(
70191
70219
  (error, selection, mutationType, label) => {
70192
- trackStudioSaveFailure({
70220
+ const report = isGsapEditBlockedError(error) ? trackStudioEditBlocked : trackStudioSaveFailure;
70221
+ report({
70193
70222
  source: "gsap_commit",
70194
70223
  error,
70195
70224
  filePath: selection?.sourceFile ?? activeCompPath ?? "index.html",
@@ -81852,13 +81881,7 @@ var RenderQueue = memo49(function RenderQueue2({
81852
81881
  // src/components/renders/RenderQueuePanel.tsx
81853
81882
  import { jsx as jsx194 } from "react/jsx-runtime";
81854
81883
  var RenderQueuePanel = memo50(function RenderQueuePanel2() {
81855
- const {
81856
- projectId,
81857
- activeCompPath,
81858
- compositionDimensions,
81859
- waitForPendingDomEditSaves,
81860
- renderQueue
81861
- } = useStudioShellContext();
81884
+ const { projectId, compositionDimensions, waitForPendingDomEditSaves, renderQueue } = useStudioShellContext();
81862
81885
  return /* @__PURE__ */ jsx194(
81863
81886
  RenderQueue,
81864
81887
  {
@@ -81876,13 +81899,11 @@ var RenderQueuePanel = memo50(function RenderQueuePanel2() {
81876
81899
  onRecheckFfmpeg: renderQueue.recheckFfmpeg,
81877
81900
  onStartRender: async (format, quality, resolution, fps) => {
81878
81901
  await waitForPendingDomEditSaves();
81879
- const composition = activeCompPath && activeCompPath !== "index.html" ? activeCompPath : void 0;
81880
81902
  await renderQueue.startRender({
81881
81903
  fps,
81882
81904
  quality,
81883
81905
  format,
81884
81906
  resolution,
81885
- composition,
81886
81907
  // Render what the user is previewing: active variable overrides
81887
81908
  // from the Variables panel ride along (undefined = defaults).
81888
81909
  variables: usePreviewVariablesStore.getState().values ?? void 0
@@ -87215,7 +87236,7 @@ function StudioApp() {
87215
87236
  const activeCompPathRef = useRef170(activeCompPath);
87216
87237
  activeCompPathRef.current = activeCompPath;
87217
87238
  const leftSidebarRef = useRef170(null);
87218
- const renderQueue = useRenderQueue(projectId);
87239
+ const renderQueue = useRenderQueue(projectId, activeCompPathRef);
87219
87240
  const captionEditMode = useCaptionStore((s) => s.isEditMode);
87220
87241
  const captionHasSelection = useCaptionStore((s) => s.selectedSegmentIds.size > 0);
87221
87242
  const captionSync = useCaptionSync(projectId);