@rixl/media-core 1.0.2 → 1.1.1

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 (172) hide show
  1. package/README.md +74 -84
  2. package/dist/chunks/B-QvSqjj.js +1 -0
  3. package/dist/chunks/B2DDE32u.js +1 -0
  4. package/dist/chunks/DMkwQjgA.js +1 -0
  5. package/dist/index.d.ts +1906 -82
  6. package/dist/index.js +6 -73
  7. package/package.json +13 -6
  8. package/dist/api/analytics.d.ts +0 -16
  9. package/dist/api/analytics.js +0 -227
  10. package/dist/api/feed.js +0 -52
  11. package/dist/api/heatmap.d.ts +0 -6
  12. package/dist/api/heatmap.js +0 -28
  13. package/dist/api/hot-segments.d.ts +0 -7
  14. package/dist/api/hot-segments.js +0 -20
  15. package/dist/api/image.js +0 -11
  16. package/dist/api/rixl-client.d.ts +0 -3
  17. package/dist/api/rixl-client.js +0 -14
  18. package/dist/api/upload.d.ts +0 -76
  19. package/dist/api/upload.js +0 -150
  20. package/dist/api/video.js +0 -11
  21. package/dist/lib/analytics-builders.d.ts +0 -59
  22. package/dist/lib/analytics-builders.js +0 -88
  23. package/dist/lib/analytics-initialize.d.ts +0 -1
  24. package/dist/lib/analytics-initialize.js +0 -59
  25. package/dist/lib/analytics-utils.d.ts +0 -43
  26. package/dist/lib/analytics-utils.js +0 -85
  27. package/dist/lib/analytics-wire.js +0 -153
  28. package/dist/lib/buffer-progress.d.ts +0 -20
  29. package/dist/lib/buffer-progress.js +0 -37
  30. package/dist/lib/caption-styles.d.ts +0 -20
  31. package/dist/lib/caption-styles.js +0 -56
  32. package/dist/lib/caption-utils.d.ts +0 -80
  33. package/dist/lib/caption-utils.js +0 -111
  34. package/dist/lib/chapter-utils.d.ts +0 -102
  35. package/dist/lib/chapter-utils.js +0 -147
  36. package/dist/lib/click-disambiguation.d.ts +0 -44
  37. package/dist/lib/click-disambiguation.js +0 -80
  38. package/dist/lib/click-outside.d.ts +0 -68
  39. package/dist/lib/click-outside.js +0 -64
  40. package/dist/lib/colors.d.ts +0 -6
  41. package/dist/lib/colors.js +0 -16
  42. package/dist/lib/content-analytics.d.ts +0 -27
  43. package/dist/lib/content-analytics.js +0 -38
  44. package/dist/lib/environment-effects.d.ts +0 -89
  45. package/dist/lib/environment-effects.js +0 -139
  46. package/dist/lib/feed-autoscroll.d.ts +0 -10
  47. package/dist/lib/feed-autoscroll.js +0 -13
  48. package/dist/lib/feed-container-height.d.ts +0 -7
  49. package/dist/lib/feed-container-height.js +0 -11
  50. package/dist/lib/feed-description-overflow.d.ts +0 -1
  51. package/dist/lib/feed-description-overflow.js +0 -9
  52. package/dist/lib/feed-dwell.d.ts +0 -2
  53. package/dist/lib/feed-dwell.js +0 -8
  54. package/dist/lib/feed-loop.d.ts +0 -10
  55. package/dist/lib/feed-loop.js +0 -21
  56. package/dist/lib/feed-scroll.d.ts +0 -11
  57. package/dist/lib/feed-scroll.js +0 -19
  58. package/dist/lib/feed-transforms.d.ts +0 -5
  59. package/dist/lib/feed-transforms.js +0 -30
  60. package/dist/lib/filter-undefined.js +0 -11
  61. package/dist/lib/fullscreen-utils.d.ts +0 -1
  62. package/dist/lib/fullscreen-utils.js +0 -7
  63. package/dist/lib/hls-buffer-flush.js +0 -46
  64. package/dist/lib/hls-error-recovery.d.ts +0 -35
  65. package/dist/lib/hls-error-recovery.js +0 -75
  66. package/dist/lib/hls-event-handlers.js +0 -61
  67. package/dist/lib/hls-loader.js +0 -23
  68. package/dist/lib/hls-setup.d.ts +0 -72
  69. package/dist/lib/hls-setup.js +0 -144
  70. package/dist/lib/hls-utils.d.ts +0 -31
  71. package/dist/lib/hls-utils.js +0 -34
  72. package/dist/lib/image-render.d.ts +0 -29
  73. package/dist/lib/image-render.js +0 -63
  74. package/dist/lib/keyboard-config.d.ts +0 -66
  75. package/dist/lib/keyboard-config.js +0 -127
  76. package/dist/lib/keyboard-utils.d.ts +0 -4
  77. package/dist/lib/keyboard-utils.js +0 -11
  78. package/dist/lib/lifecycle-effects.d.ts +0 -67
  79. package/dist/lib/lifecycle-effects.js +0 -78
  80. package/dist/lib/loading-debounce.d.ts +0 -26
  81. package/dist/lib/loading-debounce.js +0 -38
  82. package/dist/lib/numbers.d.ts +0 -6
  83. package/dist/lib/numbers.js +0 -36
  84. package/dist/lib/pip-utils.d.ts +0 -16
  85. package/dist/lib/pip-utils.js +0 -32
  86. package/dist/lib/playback-handlers.d.ts +0 -33
  87. package/dist/lib/playback-handlers.js +0 -51
  88. package/dist/lib/playback-slider.d.ts +0 -23
  89. package/dist/lib/playback-slider.js +0 -24
  90. package/dist/lib/player-labels.d.ts +0 -23
  91. package/dist/lib/player-labels.js +0 -132
  92. package/dist/lib/player-menu-labels.d.ts +0 -80
  93. package/dist/lib/player-menu-labels.js +0 -829
  94. package/dist/lib/player-ui-actions.d.ts +0 -10
  95. package/dist/lib/player-ui-actions.js +0 -58
  96. package/dist/lib/progress-fraction.d.ts +0 -11
  97. package/dist/lib/progress-fraction.js +0 -20
  98. package/dist/lib/progress-persist.d.ts +0 -28
  99. package/dist/lib/progress-persist.js +0 -54
  100. package/dist/lib/segment-analytics.d.ts +0 -20
  101. package/dist/lib/segment-analytics.js +0 -29
  102. package/dist/lib/subtitle-logic.d.ts +0 -31
  103. package/dist/lib/subtitle-logic.js +0 -75
  104. package/dist/lib/subtitle-utils.d.ts +0 -16
  105. package/dist/lib/subtitle-utils.js +0 -37
  106. package/dist/lib/time.d.ts +0 -1
  107. package/dist/lib/time.js +0 -17
  108. package/dist/lib/track-persistence.d.ts +0 -4
  109. package/dist/lib/track-persistence.js +0 -35
  110. package/dist/lib/video-preload-config.d.ts +0 -34
  111. package/dist/lib/video-preload-config.js +0 -41
  112. package/dist/lib/video-spinner.d.ts +0 -25
  113. package/dist/lib/video-spinner.js +0 -35
  114. package/dist/lib/video-stats.d.ts +0 -28
  115. package/dist/lib/video-stats.js +0 -44
  116. package/dist/lib/volume-utils.d.ts +0 -59
  117. package/dist/lib/volume-utils.js +0 -55
  118. package/dist/progressbar.d.ts +0 -10
  119. package/dist/progressbar.js +0 -125
  120. package/dist/store/analytics-context-store.d.ts +0 -4
  121. package/dist/store/analytics-context-store.js +0 -13
  122. package/dist/store/analytics-device-store.d.ts +0 -8
  123. package/dist/store/analytics-device-store.js +0 -44
  124. package/dist/store/analytics-session-store.d.ts +0 -8
  125. package/dist/store/analytics-session-store.js +0 -40
  126. package/dist/store/analytics-store.d.ts +0 -30
  127. package/dist/store/analytics-store.js +0 -88
  128. package/dist/store/controls-store.d.ts +0 -16
  129. package/dist/store/controls-store.js +0 -53
  130. package/dist/store/feed-cache-store.d.ts +0 -24
  131. package/dist/store/feed-cache-store.js +0 -165
  132. package/dist/store/feed-interaction-store.d.ts +0 -17
  133. package/dist/store/feed-interaction-store.js +0 -32
  134. package/dist/store/feed-store.d.ts +0 -16
  135. package/dist/store/feed-store.js +0 -38
  136. package/dist/store/generic-store.js +0 -24
  137. package/dist/store/image-store.d.ts +0 -2
  138. package/dist/store/image-store.js +0 -8
  139. package/dist/store/player-container-element-store.d.ts +0 -10
  140. package/dist/store/player-container-element-store.js +0 -38
  141. package/dist/store/player-global-actions.js +0 -53
  142. package/dist/store/player-media-element-store.d.ts +0 -10
  143. package/dist/store/player-media-element-store.js +0 -38
  144. package/dist/store/player-store-actions.js +0 -197
  145. package/dist/store/player-store.d.ts +0 -94
  146. package/dist/store/player-store.js +0 -127
  147. package/dist/store/player-track-actions.js +0 -44
  148. package/dist/store/postStore.d.ts +0 -20
  149. package/dist/store/postStore.js +0 -112
  150. package/dist/store/settings/constants.d.ts +0 -15
  151. package/dist/store/settings/constants.js +0 -47
  152. package/dist/store/settings/defaults.d.ts +0 -2
  153. package/dist/store/settings/defaults.js +0 -24
  154. package/dist/store/settings/storage.d.ts +0 -3
  155. package/dist/store/settings/storage.js +0 -28
  156. package/dist/store/settings/store.d.ts +0 -32
  157. package/dist/store/settings/store.js +0 -59
  158. package/dist/store/settings/types.d.ts +0 -27
  159. package/dist/store/settings/validation.d.ts +0 -7
  160. package/dist/store/settings/validation.js +0 -55
  161. package/dist/store/settings-menu-store.d.ts +0 -19
  162. package/dist/store/settings-menu-store.js +0 -30
  163. package/dist/store/video-store.d.ts +0 -2
  164. package/dist/store/video-store.js +0 -8
  165. package/dist/types/analytics.d.ts +0 -113
  166. package/dist/types/feed.d.ts +0 -21
  167. package/dist/types/file.d.ts +0 -12
  168. package/dist/types/heatmap.d.ts +0 -5
  169. package/dist/types/hot-segments.d.ts +0 -9
  170. package/dist/types/image.d.ts +0 -9
  171. package/dist/types/uuid.d.ts +0 -1
  172. package/dist/types/video.d.ts +0 -22
@@ -1,44 +0,0 @@
1
- // src/lib/video-stats.ts
2
- function getDroppedFrames(video) {
3
- if (!("getVideoPlaybackQuality" in video)) return 0;
4
- return video.getVideoPlaybackQuality().droppedVideoFrames;
5
- }
6
- function getBufferHealth(video) {
7
- if (video.buffered.length === 0) return 0;
8
- const currentTime = video.currentTime;
9
- for (let i = 0; i < video.buffered.length; i++) if (video.buffered.start(i) <= currentTime && video.buffered.end(i) >= currentTime) return Math.max(0, video.buffered.end(i) - currentTime);
10
- return 0;
11
- }
12
- function getOptimalRes(input) {
13
- const levelIndex = input.hlsAutoLevelEnabled ? input.hlsAutoLevelCapping : input.hlsCurrentLevel;
14
- if (levelIndex < 0 || levelIndex >= input.hlsLevels.length) return null;
15
- const level = input.hlsLevels[levelIndex];
16
- return level ? {
17
- width: level.width,
18
- height: level.height
19
- } : null;
20
- }
21
- function collectVideoStats(input) {
22
- const { video } = input;
23
- if (!video) return {
24
- droppedFrames: 0,
25
- volume: 0,
26
- networkSpeed: 0,
27
- bufferHealth: 0,
28
- currentRes: null,
29
- optimalRes: null
30
- };
31
- return {
32
- droppedFrames: getDroppedFrames(video),
33
- volume: Math.round(video.volume * 100),
34
- networkSpeed: input.hlsBandwidthEstimate ?? 0,
35
- bufferHealth: getBufferHealth(video),
36
- currentRes: video.videoWidth > 0 ? {
37
- width: video.videoWidth,
38
- height: video.videoHeight
39
- } : null,
40
- optimalRes: getOptimalRes(input)
41
- };
42
- }
43
-
44
- export { collectVideoStats, getBufferHealth, getDroppedFrames };
@@ -1,59 +0,0 @@
1
- /**
2
- * Volume and mute utility functions
3
- * Pure functions for volume calculations and mute state logic
4
- */
5
- /**
6
- * Calculate the volume to set, ensuring it's never 0 when unmuting
7
- * @param currentVolume - The current volume from settings (0-1)
8
- * @param defaultVolume - The default volume to use if current is 0 (default: 1.0)
9
- * @returns The volume to set (0-1)
10
- */
11
- export declare function calculateVolumeToSet(currentVolume: number, defaultVolume?: number): number;
12
- /**
13
- * Determine if video should be muted based on player state and interaction state
14
- * @param playerMuted - Whether the current player is muted
15
- * @param isFeed - Whether this is a feed video
16
- * @param feedInteracted - Whether user has interacted with the feed
17
- * @param playerInteracted - Whether user has interacted with the player
18
- * @returns Whether the video should be muted
19
- */
20
- interface MuteCheckParams {
21
- playerMuted: boolean;
22
- playerInteracted: boolean;
23
- }
24
- export declare function shouldBeMuted({ playerMuted, playerInteracted }: MuteCheckParams): boolean;
25
- /**
26
- * Get the volume to restore when unmuting, with a minimum threshold
27
- * @param currentVolume - The current volume (0-1)
28
- * @param previousVolume - The previously saved volume before muting (0-1)
29
- * @param minVolume - The minimum volume to restore to (default: 0.1)
30
- * @returns The volume to restore (0-1)
31
- */
32
- export declare function getRestoredVolume(currentVolume: number, previousVolume: number, minVolume?: number): number;
33
- /**
34
- * Clamp volume to valid range (0-1)
35
- * @param volume - The volume to clamp
36
- * @returns Volume clamped to 0-1 range
37
- */
38
- export declare function clampVolume(volume: number): number;
39
- /**
40
- * Check if volume is effectively muted (0 or very close to 0)
41
- * @param volume - The volume to check
42
- * @param threshold - The threshold below which volume is considered muted (default: 0.01)
43
- * @returns Whether volume is effectively muted
44
- */
45
- export declare function isEffectivelyMuted(volume: number, threshold?: number): boolean;
46
- interface MousePointerLike {
47
- clientX: number;
48
- }
49
- interface TouchPointerLike {
50
- touches: ArrayLike<MousePointerLike>;
51
- }
52
- /** clientX of a mouse or touch event (first touch) — shared by the volume sliders. */
53
- export declare function getPointerClientX(event: MousePointerLike | TouchPointerLike): number;
54
- /** Map a pointer position over a slider rect to a clamped 0-1 volume. */
55
- export declare function getVolumeFromPointer(rect: {
56
- left: number;
57
- width: number;
58
- }, clientX: number): number;
59
- export {};
@@ -1,55 +0,0 @@
1
- // src/lib/volume-utils.ts
2
- /**
3
- * Volume and mute utility functions
4
- * Pure functions for volume calculations and mute state logic
5
- */
6
- /**
7
- * Calculate the volume to set, ensuring it's never 0 when unmuting
8
- * @param currentVolume - The current volume from settings (0-1)
9
- * @param defaultVolume - The default volume to use if current is 0 (default: 1.0)
10
- * @returns The volume to set (0-1)
11
- */
12
- function calculateVolumeToSet(currentVolume, defaultVolume = 1) {
13
- return currentVolume > 0 ? currentVolume : defaultVolume;
14
- }
15
- function shouldBeMuted({ playerMuted, playerInteracted }) {
16
- return playerMuted || !playerInteracted;
17
- }
18
- /**
19
- * Get the volume to restore when unmuting, with a minimum threshold
20
- * @param currentVolume - The current volume (0-1)
21
- * @param previousVolume - The previously saved volume before muting (0-1)
22
- * @param minVolume - The minimum volume to restore to (default: 0.1)
23
- * @returns The volume to restore (0-1)
24
- */
25
- function getRestoredVolume(currentVolume, previousVolume, minVolume = .1) {
26
- if (currentVolume === 0) return Math.max(minVolume, previousVolume);
27
- return currentVolume;
28
- }
29
- /**
30
- * Clamp volume to valid range (0-1)
31
- * @param volume - The volume to clamp
32
- * @returns Volume clamped to 0-1 range
33
- */
34
- function clampVolume(volume) {
35
- return Math.max(0, Math.min(1, volume));
36
- }
37
- /**
38
- * Check if volume is effectively muted (0 or very close to 0)
39
- * @param volume - The volume to check
40
- * @param threshold - The threshold below which volume is considered muted (default: 0.01)
41
- * @returns Whether volume is effectively muted
42
- */
43
- function isEffectivelyMuted(volume, threshold = .01) {
44
- return volume < threshold;
45
- }
46
- /** clientX of a mouse or touch event (first touch) — shared by the volume sliders. */
47
- function getPointerClientX(event) {
48
- return "touches" in event ? event.touches[0].clientX : event.clientX;
49
- }
50
- /** Map a pointer position over a slider rect to a clamped 0-1 volume. */
51
- function getVolumeFromPointer(rect, clientX) {
52
- return clampVolume((clientX - rect.left) / rect.width);
53
- }
54
-
55
- export { calculateVolumeToSet, clampVolume, getPointerClientX, getRestoredVolume, getVolumeFromPointer, isEffectivelyMuted, shouldBeMuted };
@@ -1,10 +0,0 @@
1
- export interface ProgressBarProps {
2
- video: HTMLVideoElement;
3
- onDraggingChange?: (isDragging: boolean) => void;
4
- onProgressChange?: (progress: number) => void;
5
- }
6
- export interface ProgressBarControls {
7
- handleDragStart: (event: MouseEvent | TouchEvent) => void;
8
- destroy: () => void;
9
- }
10
- export declare const initProgressBar: ({ video, onDraggingChange, onProgressChange }: ProgressBarProps) => ProgressBarControls;
@@ -1,125 +0,0 @@
1
- // src/progressbar.ts
2
- const SWIPE_DISTANCE_THRESHOLD = 15;
3
- const SWIPE_TIME_THRESHOLD = 200;
4
- const manageListeners = (action, events, handler) => events.forEach((e) => window[`${action}EventListener`](e, handler));
5
- const clamp01 = (value) => Math.min(Math.max(value, 0), 1);
6
- const getClientX = (event) => {
7
- if ("touches" in event) return event.touches[0]?.clientX ?? event.changedTouches?.[0]?.clientX ?? 0;
8
- return event.clientX;
9
- };
10
- const createProgressBarState = (video) => ({
11
- isDragging: false,
12
- progress: Number.isFinite(video.duration) && video.duration > 0 ? video.currentTime / video.duration : 0,
13
- initialRect: null,
14
- initialClientX: null,
15
- initialProgress: 0,
16
- startTime: 0,
17
- hasMoved: false
18
- });
19
- const setProgress = (state, value, onProgressChange) => {
20
- state.progress = Number(value.toFixed(6));
21
- onProgressChange?.(state.progress);
22
- };
23
- const setDragging = (state, value, onDraggingChange) => {
24
- state.isDragging = value;
25
- onDraggingChange?.(value);
26
- };
27
- const shouldStartDragging = (state, clientX) => {
28
- if (state.initialClientX === null) return false;
29
- const distanceMoved = Math.abs(clientX - state.initialClientX);
30
- const timeElapsed = Date.now() - state.startTime;
31
- return distanceMoved >= SWIPE_DISTANCE_THRESHOLD || timeElapsed >= SWIPE_TIME_THRESHOLD;
32
- };
33
- const startDragging = (state, clientX, onDraggingChange) => {
34
- state.hasMoved = true;
35
- setDragging(state, true, onDraggingChange);
36
- state.initialClientX = clientX;
37
- state.initialProgress = state.progress;
38
- };
39
- const getDragProgress = (state, clientX) => {
40
- if (!state.initialRect) return null;
41
- const offset = (clientX - (state.initialClientX ?? state.initialRect.left)) / state.initialRect.width;
42
- const baseProgress = state.initialClientX ? state.initialProgress : 0;
43
- return clamp01(offset + baseProgress);
44
- };
45
- const getClickProgress = (state) => {
46
- if (!state.initialRect || state.initialClientX === null) return null;
47
- return clamp01((state.initialClientX - state.initialRect.left) / state.initialRect.width);
48
- };
49
- const resetDragState = (state, onDraggingChange) => {
50
- setDragging(state, false, onDraggingChange);
51
- state.hasMoved = false;
52
- state.initialRect = null;
53
- state.initialClientX = null;
54
- };
55
- const createTimeUpdateHandler = (state, video, onProgressChange) => () => {
56
- if (state.isDragging) return;
57
- const progress = Number.isFinite(video.duration) && video.duration > 0 ? video.currentTime / video.duration : 0;
58
- setProgress(state, progress, onProgressChange);
59
- };
60
- const createMoveHandler = (state, onDraggingChange, onProgressChange) => (event) => {
61
- const clientX = getClientX(event);
62
- if (!state.isDragging) {
63
- if (!shouldStartDragging(state, clientX)) return;
64
- startDragging(state, clientX, onDraggingChange);
65
- }
66
- const newProgress = getDragProgress(state, clientX);
67
- if (newProgress === null) return;
68
- setProgress(state, newProgress, onProgressChange);
69
- };
70
- const createEndHandler = ({ state, video, onDraggingChange, onProgressChange, removeListeners }) => () => {
71
- const clickProgress = !state.hasMoved ? getClickProgress(state) : null;
72
- const hasValidDuration = Number.isFinite(video.duration) && video.duration > 0;
73
- if (clickProgress !== null) {
74
- setProgress(state, clickProgress, onProgressChange);
75
- if (hasValidDuration) video.currentTime = clickProgress * video.duration;
76
- } else if (state.isDragging && hasValidDuration) video.currentTime = state.progress * video.duration;
77
- resetDragState(state, onDraggingChange);
78
- removeListeners();
79
- };
80
- const createDragStartHandler = (state, handleMove, handleEnd) => (event) => {
81
- state.initialRect = event.currentTarget.getBoundingClientRect();
82
- state.startTime = Date.now();
83
- state.hasMoved = false;
84
- state.initialClientX = getClientX(event);
85
- manageListeners("add", ["mousemove", "touchmove"], handleMove);
86
- manageListeners("add", [
87
- "mouseup",
88
- "touchend",
89
- "blur"
90
- ], handleEnd);
91
- };
92
- const initProgressBar = ({ video, onDraggingChange, onProgressChange }) => {
93
- const state = createProgressBarState(video);
94
- onDraggingChange?.(false);
95
- onProgressChange?.(state.progress);
96
- const handleTimeUpdate = createTimeUpdateHandler(state, video, onProgressChange);
97
- const handleMove = createMoveHandler(state, onDraggingChange, onProgressChange);
98
- let handleEnd;
99
- const removeListeners = () => {
100
- manageListeners("remove", ["mousemove", "touchmove"], handleMove);
101
- manageListeners("remove", [
102
- "mouseup",
103
- "touchend",
104
- "blur"
105
- ], handleEnd);
106
- };
107
- handleEnd = createEndHandler({
108
- state,
109
- video,
110
- onDraggingChange,
111
- onProgressChange,
112
- removeListeners
113
- });
114
- const handleDragStart = createDragStartHandler(state, handleMove, handleEnd);
115
- video.addEventListener("timeupdate", handleTimeUpdate);
116
- return {
117
- handleDragStart,
118
- destroy: () => {
119
- handleEnd();
120
- video.removeEventListener("timeupdate", handleTimeUpdate);
121
- }
122
- };
123
- };
124
-
125
- export { initProgressBar };
@@ -1,4 +0,0 @@
1
- import { AnalyticsContext } from "../types/analytics.js";
2
- import { WritableAtom } from "nanostores";
3
- export declare const analyticsContextStore: WritableAtom<AnalyticsContext>;
4
- export declare function setAnalyticsContext(context: Partial<AnalyticsContext>): void;
@@ -1,13 +0,0 @@
1
- import { atom } from "nanostores";
2
-
3
- // src/store/analytics-context-store.ts
4
- const initialContext = {};
5
- const analyticsContextStore = atom(initialContext);
6
- function setAnalyticsContext(context) {
7
- analyticsContextStore.set({
8
- ...analyticsContextStore.get(),
9
- ...context
10
- });
11
- }
12
-
13
- export { analyticsContextStore, setAnalyticsContext };
@@ -1,8 +0,0 @@
1
- import { WritableAtom } from "nanostores";
2
- interface DeviceState {
3
- deviceId: string | undefined;
4
- }
5
- export declare const analyticsDeviceStore: WritableAtom<DeviceState>;
6
- export declare function getOrCreateDeviceId(): string;
7
- export declare function setDeviceId(deviceId: string): void;
8
- export {};
@@ -1,44 +0,0 @@
1
- import { atom } from "nanostores";
2
-
3
- // src/store/analytics-device-store.ts
4
- const STORAGE_KEY = "rixl_analytics_device_id";
5
- const initialState = { deviceId: void 0 };
6
- const analyticsDeviceStore = atom(initialState);
7
- function generateDeviceId() {
8
- const cryptoApi = globalThis.crypto;
9
- if (cryptoApi?.randomUUID) return cryptoApi.randomUUID();
10
- return `${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`;
11
- }
12
- function getStoredDeviceId() {
13
- if (typeof localStorage === "undefined" || !localStorage) return;
14
- try {
15
- return localStorage.getItem(STORAGE_KEY) ?? void 0;
16
- } catch {
17
- return;
18
- }
19
- }
20
- function setStoredDeviceId(deviceId) {
21
- if (typeof localStorage === "undefined" || !localStorage) return;
22
- try {
23
- localStorage.setItem(STORAGE_KEY, deviceId);
24
- } catch {}
25
- }
26
- function getOrCreateDeviceId() {
27
- const state = analyticsDeviceStore.get();
28
- if (state.deviceId) return state.deviceId;
29
- const stored = getStoredDeviceId();
30
- if (stored) {
31
- analyticsDeviceStore.set({ deviceId: stored });
32
- return stored;
33
- }
34
- const generated = generateDeviceId();
35
- setStoredDeviceId(generated);
36
- analyticsDeviceStore.set({ deviceId: generated });
37
- return generated;
38
- }
39
- function setDeviceId(deviceId) {
40
- setStoredDeviceId(deviceId);
41
- analyticsDeviceStore.set({ deviceId });
42
- }
43
-
44
- export { analyticsDeviceStore, getOrCreateDeviceId, setDeviceId };
@@ -1,8 +0,0 @@
1
- import { WritableAtom } from "nanostores";
2
- interface SessionState {
3
- sessionId: string | undefined;
4
- started: boolean;
5
- }
6
- export declare const analyticsSessionStore: WritableAtom<SessionState>;
7
- export declare function getOrCreateSessionId(): string;
8
- export {};
@@ -1,40 +0,0 @@
1
- import { atom } from "nanostores";
2
-
3
- // src/store/analytics-session-store.ts
4
- const initialState = {
5
- sessionId: void 0,
6
- started: false
7
- };
8
- const analyticsSessionStore = atom(initialState);
9
- function generateSessionId() {
10
- const cryptoApi = globalThis.crypto;
11
- if (cryptoApi?.randomUUID) return cryptoApi.randomUUID();
12
- return `s-${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`;
13
- }
14
- function getOrCreateSessionId() {
15
- const state = analyticsSessionStore.get();
16
- if (state.sessionId) return state.sessionId;
17
- const sessionId = generateSessionId();
18
- analyticsSessionStore.set({
19
- ...state,
20
- sessionId
21
- });
22
- return sessionId;
23
- }
24
- function hasSessionStarted() {
25
- return analyticsSessionStore.get().started;
26
- }
27
- function markSessionStarted() {
28
- analyticsSessionStore.set({
29
- ...analyticsSessionStore.get(),
30
- started: true
31
- });
32
- }
33
- function resetSession() {
34
- analyticsSessionStore.set({
35
- sessionId: void 0,
36
- started: false
37
- });
38
- }
39
-
40
- export { analyticsSessionStore, getOrCreateSessionId, hasSessionStarted, markSessionStarted, resetSession };
@@ -1,30 +0,0 @@
1
- import { Segment } from "../types/analytics.js";
2
- import { WritableAtom } from "nanostores";
3
- interface CurrentSegment {
4
- start_ms: number;
5
- speed: number;
6
- }
7
- interface AnalyticsState {
8
- segments: Map<string, Segment[]>;
9
- currentSegment: Map<string, CurrentSegment | null>;
10
- }
11
- export declare const analyticsStore: WritableAtom<AnalyticsState>;
12
- export declare const analyticsStoreActions: {
13
- /**
14
- * Start tracking a new segment
15
- */
16
- startSegment(playerId: string, positionMs: number, speed: number): void;
17
- /**
18
- * End the current segment being tracked
19
- */
20
- endSegment(playerId: string, positionMs: number): void;
21
- /**
22
- * Get segments including the current in-progress segment
23
- */
24
- getSegmentsWithCurrent(playerId: string, currentPositionMs: number): Segment[];
25
- /**
26
- * Clear all segments for a player
27
- */
28
- clearSegments(playerId: string): void;
29
- };
30
- export {};
@@ -1,88 +0,0 @@
1
- import { atom } from "nanostores";
2
-
3
- // src/store/analytics-store.ts
4
- const analyticsStore = atom({
5
- segments: /* @__PURE__ */ new Map(),
6
- currentSegment: /* @__PURE__ */ new Map()
7
- });
8
- const analyticsStoreActions = {
9
- /**
10
- * Start tracking a new segment
11
- */
12
- startSegment(playerId, positionMs, speed) {
13
- if (analyticsStore.get().currentSegment.get(playerId)) this.endSegment(playerId, positionMs);
14
- const updatedState = analyticsStore.get();
15
- const newCurrentSegment = new Map(updatedState.currentSegment);
16
- newCurrentSegment.set(playerId, {
17
- start_ms: positionMs,
18
- speed
19
- });
20
- analyticsStore.set({
21
- ...updatedState,
22
- currentSegment: newCurrentSegment
23
- });
24
- },
25
- /**
26
- * End the current segment being tracked
27
- */
28
- endSegment(playerId, positionMs) {
29
- const state = analyticsStore.get();
30
- const currentSegment = state.currentSegment.get(playerId);
31
- if (!currentSegment) return;
32
- if (positionMs - currentSegment.start_ms > 100) {
33
- const segment = {
34
- start_ms: Math.round(currentSegment.start_ms),
35
- end_ms: Math.round(positionMs),
36
- speed: currentSegment.speed
37
- };
38
- const newSegments = new Map(state.segments);
39
- const playerSegments = newSegments.get(playerId) || [];
40
- newSegments.set(playerId, [...playerSegments, segment]);
41
- const newCurrentSegment = new Map(state.currentSegment);
42
- newCurrentSegment.set(playerId, null);
43
- analyticsStore.set({
44
- ...state,
45
- segments: newSegments,
46
- currentSegment: newCurrentSegment
47
- });
48
- } else {
49
- const newCurrentSegment = new Map(state.currentSegment);
50
- newCurrentSegment.set(playerId, null);
51
- analyticsStore.set({
52
- ...state,
53
- currentSegment: newCurrentSegment
54
- });
55
- }
56
- },
57
- /**
58
- * Get segments including the current in-progress segment
59
- */
60
- getSegmentsWithCurrent(playerId, currentPositionMs) {
61
- const state = analyticsStore.get();
62
- const segments = [...state.segments.get(playerId) || []];
63
- const currentSegment = state.currentSegment.get(playerId);
64
- if (currentSegment && currentPositionMs - currentSegment.start_ms > 100) segments.push({
65
- start_ms: Math.round(currentSegment.start_ms),
66
- end_ms: Math.round(currentPositionMs),
67
- speed: currentSegment.speed
68
- });
69
- return segments;
70
- },
71
- /**
72
- * Clear all segments for a player
73
- */
74
- clearSegments(playerId) {
75
- const state = analyticsStore.get();
76
- const newSegments = new Map(state.segments);
77
- newSegments.delete(playerId);
78
- const newCurrentSegment = new Map(state.currentSegment);
79
- newCurrentSegment.delete(playerId);
80
- analyticsStore.set({
81
- ...state,
82
- segments: newSegments,
83
- currentSegment: newCurrentSegment
84
- });
85
- }
86
- };
87
-
88
- export { analyticsStore, analyticsStoreActions };
@@ -1,16 +0,0 @@
1
- import { UUID } from "../types/uuid.js";
2
- import { MapStore } from "nanostores";
3
- export interface ControlsState {
4
- visible: boolean;
5
- hideTimeout: ReturnType<typeof setTimeout> | null;
6
- }
7
- interface ControlsStore {
8
- state: Map<UUID, MapStore<ControlsState>>;
9
- get: (id: UUID) => MapStore<ControlsState>;
10
- deleteControls: (id: UUID) => void;
11
- setVisible: (id: UUID, visible: boolean) => void;
12
- showControls: (id: UUID, autoHideMs?: number) => void;
13
- hideControls: (id: UUID) => void;
14
- }
15
- export declare const controlsStore: ControlsStore;
16
- export {};
@@ -1,53 +0,0 @@
1
- import { map } from "nanostores";
2
-
3
- // src/store/controls-store.ts
4
- const initialControls = {
5
- visible: false,
6
- hideTimeout: null
7
- };
8
- const controlsStore = {
9
- state: /* @__PURE__ */ new Map(),
10
- get: (id) => {
11
- let controls = controlsStore.state.get(id);
12
- if (!controls) {
13
- controls = map({ ...initialControls });
14
- controlsStore.state.set(id, controls);
15
- }
16
- return controls;
17
- },
18
- deleteControls: (id) => {
19
- const controls = controlsStore.state.get(id);
20
- if (controls) {
21
- const state = controls.get();
22
- if (state.hideTimeout) clearTimeout(state.hideTimeout);
23
- }
24
- controlsStore.state.delete(id);
25
- },
26
- setVisible: (id, visible) => {
27
- const controls = controlsStore.get(id);
28
- const currentState = controls.get();
29
- if (currentState.hideTimeout) clearTimeout(currentState.hideTimeout);
30
- controls.setKey("visible", visible);
31
- controls.setKey("hideTimeout", null);
32
- },
33
- showControls: (id, autoHideMs) => {
34
- const controls = controlsStore.get(id);
35
- const currentState = controls.get();
36
- if (currentState.hideTimeout) clearTimeout(currentState.hideTimeout);
37
- let hideTimeout = null;
38
- if (autoHideMs !== void 0 && autoHideMs > 0) hideTimeout = setTimeout(() => {
39
- controlsStore.setVisible(id, false);
40
- }, autoHideMs);
41
- controls.setKey("visible", true);
42
- controls.setKey("hideTimeout", hideTimeout);
43
- },
44
- hideControls: (id) => {
45
- const controls = controlsStore.get(id);
46
- const currentState = controls.get();
47
- if (currentState.hideTimeout) clearTimeout(currentState.hideTimeout);
48
- controls.setKey("visible", false);
49
- controls.setKey("hideTimeout", null);
50
- }
51
- };
52
-
53
- export { controlsStore };
@@ -1,24 +0,0 @@
1
- import { FeedPost } from "../types/feed.js";
2
- import { WritableAtom } from "nanostores";
3
- interface FeedCacheState {
4
- cachedPosts: FeedPost[];
5
- isLoadingFromCache: boolean;
6
- }
7
- export declare const feedCacheAtom: WritableAtom<FeedCacheState>;
8
- interface FeedCacheStore {
9
- currentFeedId: string | undefined;
10
- loadCache: (feedId?: string) => FeedPost[];
11
- /**
12
- * Append posts to the cache. Pass the feed the posts came from and the batch
13
- * is refused if the cache has since moved to another feed.
14
- */
15
- saveNewPosts: (newPosts: FeedPost[], feedId?: string) => void;
16
- removePost: (postId: string) => void;
17
- clearCache: () => void;
18
- getCacheStats: () => {
19
- size: number;
20
- timestamp: number | null;
21
- };
22
- }
23
- export declare const feedCacheStore: FeedCacheStore;
24
- export {};