@hyperframes/studio 0.7.89 → 0.7.92

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.
Files changed (86) hide show
  1. package/dist/assets/{hyperframes-player-DVTnBvSO.js → hyperframes-player-9qOa08Tv.js} +1 -1
  2. package/dist/assets/{index-Qvx7boWH.js → index-Bw4lNdtO.js} +1 -1
  3. package/dist/assets/{index-ulQEdWKo.js → index-CDTN2ZVa.js} +1 -1
  4. package/dist/assets/index-DIntkrQl.js +428 -0
  5. package/dist/index.d.ts +20 -16
  6. package/dist/index.html +1 -1
  7. package/dist/index.js +6495 -5429
  8. package/dist/index.js.map +1 -1
  9. package/package.json +7 -7
  10. package/src/components/StudioRightPanel.tsx +1 -1
  11. package/src/components/editor/GsapAnimationList.tsx +84 -0
  12. package/src/components/editor/GsapAnimationSection.test.tsx +100 -11
  13. package/src/components/editor/GsapAnimationSection.tsx +11 -41
  14. package/src/components/editor/PropertyPanel.tsx +1 -1
  15. package/src/components/editor/PropertyPanelFlat.tsx +29 -26
  16. package/src/components/editor/gsapAnimationCallbacks.ts +0 -10
  17. package/src/components/editor/propertyPanelFlatDescriptors.ts +20 -0
  18. package/src/components/editor/propertyPanelFlatMotionSection.test.tsx +56 -55
  19. package/src/components/editor/propertyPanelFlatMotionSection.tsx +9 -37
  20. package/src/components/editor/propertyPanelTypes.ts +1 -1
  21. package/src/components/nle/useTimelineEditCallbacks.test.tsx +78 -4
  22. package/src/components/nle/useTimelineEditCallbacks.ts +12 -7
  23. package/src/components/renders/useRenderQueue.ts +16 -3
  24. package/src/components/renders/useRenderQueueTelemetry.test.tsx +104 -0
  25. package/src/contexts/DomEditContext.tsx +1 -1
  26. package/src/hooks/useDomEditSession.test.tsx +1 -1
  27. package/src/hooks/useDomEditSession.ts +1 -1
  28. package/src/hooks/useGsapKeyframeOps.test.tsx +83 -5
  29. package/src/hooks/useGsapKeyframeOps.ts +20 -9
  30. package/src/player/components/BeatStrip.test.tsx +374 -0
  31. package/src/player/components/BeatStrip.tsx +295 -37
  32. package/src/player/components/KeyframeDiamondContextMenu.test.tsx +16 -1
  33. package/src/player/components/KeyframeDiamondContextMenu.tsx +6 -5
  34. package/src/player/components/Timeline.test.ts +2 -3
  35. package/src/player/components/Timeline.tsx +47 -48
  36. package/src/player/components/TimelineCanvas.tsx +14 -71
  37. package/src/player/components/TimelineClip.tsx +6 -3
  38. package/src/player/components/TimelineClipDiamonds.test.tsx +442 -18
  39. package/src/player/components/TimelineClipDiamonds.tsx +66 -211
  40. package/src/player/components/TimelineGestureOverlay.test.tsx +90 -0
  41. package/src/player/components/TimelineGestureOverlay.tsx +96 -0
  42. package/src/player/components/TimelineLanes.test.tsx +0 -1
  43. package/src/player/components/TimelineLanes.tsx +3 -2
  44. package/src/player/components/TimelineOverlays.test.ts +161 -0
  45. package/src/player/components/TimelineOverlays.tsx +104 -11
  46. package/src/player/components/timelineCallbacks.ts +1 -1
  47. package/src/player/components/timelineClipDragGestureLifecycle.test.ts +18 -3
  48. package/src/player/components/timelineClipDragGestureLifecycle.ts +199 -51
  49. package/src/player/components/timelineClipDragPreview.test.ts +33 -0
  50. package/src/player/components/timelineClipDragPreview.ts +18 -12
  51. package/src/player/components/timelineClipDragTypes.ts +12 -0
  52. package/src/player/components/timelineDiamondTypes.ts +5 -15
  53. package/src/player/components/timelineDragDrop.test.tsx +206 -0
  54. package/src/player/components/timelineDragDrop.ts +152 -30
  55. package/src/player/components/timelineLaneProps.ts +0 -1
  56. package/src/player/components/timelineMarquee.test.ts +73 -25
  57. package/src/player/components/timelineMarquee.ts +44 -16
  58. package/src/player/components/timelineTestViewport.ts +13 -0
  59. package/src/player/components/timelineViewModel.ts +4 -4
  60. package/src/player/components/useTimelineClipDrag.resize.test.tsx +219 -17
  61. package/src/player/components/useTimelineClipDrag.ts +112 -70
  62. package/src/player/components/useTimelineClipRenderWindow.ts +4 -4
  63. package/src/player/components/useTimelineKeyframeHandlers.test.tsx +43 -7
  64. package/src/player/components/useTimelineKeyframeHandlers.ts +465 -2
  65. package/src/player/components/useTimelineLaneMoveRefresh.ts +7 -0
  66. package/src/player/components/useTimelineRangeSelection.test.tsx +204 -0
  67. package/src/player/components/useTimelineRangeSelection.ts +202 -69
  68. package/src/player/components/useTimelineRangeSelectionScrub.test.tsx +3 -2
  69. package/src/player/components/useTimelineRowVirtualization.ts +11 -4
  70. package/src/player/components/useTrackGapMenu.test.tsx +64 -0
  71. package/src/player/components/useTrackGapMenu.ts +32 -9
  72. package/src/player/store/keyframeSlice.ts +59 -18
  73. package/src/player/store/playerStore.test.ts +76 -0
  74. package/src/player/store/playerStore.ts +19 -11
  75. package/src/telemetry/canary.test.ts +325 -0
  76. package/src/telemetry/canary.ts +268 -0
  77. package/src/telemetry/client.test.ts +8 -3
  78. package/src/telemetry/client.ts +13 -43
  79. package/src/telemetry/config.ts +16 -2
  80. package/src/telemetry/distinctId.test.ts +35 -0
  81. package/src/telemetry/distinctId.ts +11 -2
  82. package/src/telemetry/policy.test.ts +81 -0
  83. package/src/telemetry/policy.ts +104 -0
  84. package/src/utils/studioTelemetry.test.ts +76 -0
  85. package/src/utils/studioTelemetry.ts +14 -6
  86. package/dist/assets/index-CddKwfQ1.js +0 -428
@@ -0,0 +1,76 @@
1
+ // @vitest-environment happy-dom
2
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
3
+
4
+ // The `studio:*` path predates telemetry/config.ts and shipped its own
5
+ // opt-out key and its own send loop, so it sat outside both contracts the
6
+ // canary work established: the documented opt-out did not silence it, and its
7
+ // events carried no cohort assignment. These pin both.
8
+
9
+ vi.mock("../telemetry/canary", () => ({
10
+ canaryEventProperties: () => ({ "$feature/canary-test-one": "true" }),
11
+ }));
12
+
13
+ // One shared policy now governs this transport, telemetry/client.ts and
14
+ // canary enrolment. Exercised directly here so each case names the control
15
+ // under test rather than relying on ambient import.meta.env.
16
+ const policyState = { allowed: true };
17
+ vi.mock("../telemetry/policy", () => ({
18
+ browserTelemetryAllowed: () => policyState.allowed,
19
+ }));
20
+
21
+ describe("studioTelemetry — shared opt-out and canary properties", () => {
22
+ let trackStudioEvent: typeof import("./studioTelemetry").trackStudioEvent;
23
+ let fetchMock: ReturnType<typeof vi.fn>;
24
+
25
+ beforeEach(async () => {
26
+ policyState.allowed = true;
27
+ localStorage.clear();
28
+ vi.resetModules();
29
+ vi.useFakeTimers();
30
+ fetchMock = vi.fn(() => Promise.resolve({ ok: true } as Response));
31
+ vi.stubGlobal("fetch", fetchMock);
32
+ ({ trackStudioEvent } = await import("./studioTelemetry"));
33
+ });
34
+
35
+ afterEach(() => {
36
+ vi.useRealTimers();
37
+ vi.unstubAllGlobals();
38
+ });
39
+
40
+ /** Drain the queue and return the events the batch would have sent. */
41
+ async function sentEvents(): Promise<Array<Record<string, unknown>>> {
42
+ await vi.runOnlyPendingTimersAsync();
43
+ if (fetchMock.mock.calls.length === 0) return [];
44
+ const body = fetchMock.mock.calls[0]?.[1] as { body?: string } | undefined;
45
+ const parsed = JSON.parse(body?.body ?? "{}") as { batch?: Array<Record<string, unknown>> };
46
+ return parsed.batch ?? [];
47
+ }
48
+
49
+ // Every control the shared policy enforces — documented key, legacy key,
50
+ // navigator.doNotTrack, VITE_HYPERFRAMES_NO_TELEMETRY, Vite dev mode, API
51
+ // key eligibility. Before the policy was shared this transport honoured
52
+ // only the legacy key, so all of the others still emitted `studio:*`.
53
+ it("sends nothing when the shared policy refuses", async () => {
54
+ policyState.allowed = false;
55
+ trackStudioEvent("thing_happened");
56
+ expect(await sentEvents()).toHaveLength(0);
57
+ expect(fetchMock).not.toHaveBeenCalled();
58
+ });
59
+
60
+ it("attaches canary assignments to every event", async () => {
61
+ trackStudioEvent("thing_happened");
62
+ const events = await sentEvents();
63
+ expect(events).toHaveLength(1);
64
+ expect(events[0]?.["properties"]).toMatchObject({
65
+ "$feature/canary-test-one": "true",
66
+ });
67
+ });
68
+
69
+ it("lets an explicit property win over the canary mixin", async () => {
70
+ trackStudioEvent("thing_happened", { "$feature/canary-test-one": "false" });
71
+ const events = await sentEvents();
72
+ expect(events[0]?.["properties"]).toMatchObject({
73
+ "$feature/canary-test-one": "false",
74
+ });
75
+ });
76
+ });
@@ -1,4 +1,6 @@
1
1
  import { resolveStudioDistinctId } from "../telemetry/distinctId";
2
+ import { browserTelemetryAllowed } from "../telemetry/policy";
3
+ import { canaryEventProperties } from "../telemetry/canary";
2
4
 
3
5
  // PostHog public ingest key — write-only, safe to ship in the client bundle
4
6
  const POSTHOG_API_KEY = "phc_zjjbX0PnWxERXrMHhkEJWj9A9BhGVLRReICgsfTMmpx";
@@ -26,12 +28,15 @@ function getDistinctId(): string {
26
28
  return resolveStudioDistinctId();
27
29
  }
28
30
 
31
+ /**
32
+ * This path predates telemetry/config.ts and enforced only its own
33
+ * localStorage key, so `navigator.doNotTrack`, VITE_HYPERFRAMES_NO_TELEMETRY,
34
+ * Vite dev mode and the documented `hyperframes-studio:telemetryDisabled` all
35
+ * failed to silence `studio:*` events. Now one shared policy governs every
36
+ * transport — including the legacy key, which it still honours.
37
+ */
29
38
  function isEnabled(): boolean {
30
- try {
31
- return localStorage.getItem("hf-studio-telemetry-opt-out") !== "1";
32
- } catch {
33
- return true;
34
- }
39
+ return browserTelemetryAllowed();
35
40
  }
36
41
 
37
42
  function getSessionProperties(): EventProperties {
@@ -56,7 +61,10 @@ export function trackStudioEvent(event: string, properties: EventProperties = {}
56
61
 
57
62
  queue.push({
58
63
  event: `studio:${event}`,
59
- properties: { ...getSessionProperties(), ...properties },
64
+ // Canary assignments on every event, matching the CLI and the newer
65
+ // studio client — "every telemetry event carries the assignment" has to
66
+ // include this path or a cohort breakdown silently omits `studio:*`.
67
+ properties: { ...getSessionProperties(), ...canaryEventProperties(), ...properties },
60
68
  timestamp: new Date().toISOString(),
61
69
  });
62
70