-
-
Notifications
You must be signed in to change notification settings - Fork 2
docs: changelog updated version 0.0.2 #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
077d80f
e81ef2e
55633f5
f8fe036
3deb98a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,5 +2,6 @@ | |
| "trailingComma": "es5", | ||
| "tabWidth": 2, | ||
| "semi": true, | ||
| "singleQuote": true | ||
| "singleQuote": true, | ||
| "endOfLine": "lf" | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| # Changelog | ||
|
|
||
| All notable changes to this project will be documented in this file. | ||
|
|
||
| ## [0.0.2] - 2025-08-10 | ||
|
|
||
| ### Style | ||
|
|
||
| - Configure prettier to use lf line endings | ||
|
|
||
| ### Chore | ||
|
|
||
| - Support code lint and commit lint | ||
| - Add test lint | ||
| - Tsup config file confugured | ||
|
|
||
| ### Test | ||
|
|
||
| - Fix test error | ||
|
|
||
| ### Docs | ||
|
|
||
| - Add CONTRIBUTING.md guide | ||
| - Add DEVELOPER.md guide | ||
| - Update README.md with detailed project information | ||
| - Add horizontal rule to README | ||
|
|
||
| ### Features | ||
|
|
||
| - Migrate tsup configuration to tsup.config.ts | ||
| - Add React wrapper and example | ||
| - Update package metadata and dependencies | ||
| - Setup project structure and CI workflows | ||
|
|
||
| ### Bug Fixes | ||
|
|
||
| - Resolve race condition on initialization |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -59,55 +59,35 @@ export const InteractiveVideo: React.FC<InteractiveVideoProps> = ({ | |||||||||||||||||||||
| const uniqueIdRef = useRef<string>(generateUniqueId()); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||
| if (containerRef.current && !playerRef.current) { | ||||||||||||||||||||||
| const playerConfig: PlayerConfig = { | ||||||||||||||||||||||
| videoUrl, | ||||||||||||||||||||||
| ...restOptions, | ||||||||||||||||||||||
| }; | ||||||||||||||||||||||
| if (!containerRef.current) return; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| try { | ||||||||||||||||||||||
| setTimeout(() => { | ||||||||||||||||||||||
| if (containerRef.current) { | ||||||||||||||||||||||
| const player = new IVLabsPlayer(uniqueIdRef.current, playerConfig); | ||||||||||||||||||||||
| playerRef.current = player; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if (onAnalyticsEvent) { | ||||||||||||||||||||||
| player.on('PLAYER_LOADED', (payload?: AnalyticsPayload) => | ||||||||||||||||||||||
| onAnalyticsEvent('PLAYER_LOADED', payload) | ||||||||||||||||||||||
| ); | ||||||||||||||||||||||
| player.on('VIDEO_STARTED', (payload?: AnalyticsPayload) => | ||||||||||||||||||||||
| onAnalyticsEvent('VIDEO_STARTED', payload) | ||||||||||||||||||||||
| ); | ||||||||||||||||||||||
| player.on('VIDEO_PAUSED', (payload?: AnalyticsPayload) => | ||||||||||||||||||||||
| onAnalyticsEvent('VIDEO_PAUSED', payload) | ||||||||||||||||||||||
| ); | ||||||||||||||||||||||
| player.on('VIDEO_ENDED', (payload?: AnalyticsPayload) => | ||||||||||||||||||||||
| onAnalyticsEvent('VIDEO_ENDED', payload) | ||||||||||||||||||||||
| ); | ||||||||||||||||||||||
| player.on('CUE_TRIGGERED', (payload?: AnalyticsPayload) => | ||||||||||||||||||||||
| onAnalyticsEvent('CUE_TRIGGERED', payload) | ||||||||||||||||||||||
| ); | ||||||||||||||||||||||
| player.on('INTERACTION_COMPLETED', (payload?: AnalyticsPayload) => | ||||||||||||||||||||||
| onAnalyticsEvent('INTERACTION_COMPLETED', payload) | ||||||||||||||||||||||
| ); | ||||||||||||||||||||||
| player.on('ERROR', (payload?: AnalyticsPayload) => | ||||||||||||||||||||||
| onAnalyticsEvent('ERROR', payload) | ||||||||||||||||||||||
| ); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| const playerConfig: PlayerConfig = { | ||||||||||||||||||||||
| videoUrl, | ||||||||||||||||||||||
| ...restOptions, | ||||||||||||||||||||||
| }; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if (cues) { | ||||||||||||||||||||||
| player.loadCues(cues); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| try { | ||||||||||||||||||||||
| const player = new IVLabsPlayer(uniqueIdRef.current, playerConfig); | ||||||||||||||||||||||
| playerRef.current = player; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
Comment on lines
+62
to
72
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Avoid re-instantiating the player on every render; stabilize dependencies and callback. Including Apply these changes:
Diff within this block: - useEffect(() => {
- if (!containerRef.current) return;
-
- const playerConfig: PlayerConfig = {
- videoUrl,
- ...restOptions,
- };
-
- try {
- const player = new IVLabsPlayer(uniqueIdRef.current, playerConfig);
- playerRef.current = player;
-
- if (onAnalyticsEvent) {
- const events: AnalyticsEvent[] = [
- 'PLAYER_LOADED',
- 'VIDEO_STARTED',
- 'VIDEO_PAUSED',
- 'VIDEO_ENDED',
- 'CUE_TRIGGERED',
- 'INTERACTION_COMPLETED',
- 'ERROR',
- ];
- events.forEach((event) => {
- player.on(event, (payload?: AnalyticsPayload) =>
- onAnalyticsEvent(event, payload)
- );
- });
- }
- } catch (error) {
- console.error('Error initializing IVLabsPlayer:', error);
- }
-
- return () => {
- if (playerRef.current) {
- playerRef.current.destroy();
- playerRef.current = null;
- }
- };
- }, [videoUrl, onAnalyticsEvent, restOptions]);
+ useEffect(() => {
+ if (!containerRef.current) return;
+ try {
+ // Recreate only when videoUrl changes
+ if (playerRef.current) {
+ playerRef.current.destroy();
+ playerRef.current = null;
+ }
+ const playerConfig: PlayerConfig = { videoUrl, ...restOptions };
+ const player = new IVLabsPlayer(uniqueIdRef.current, playerConfig);
+ playerRef.current = player;
+
+ const events: AnalyticsEvent[] = [
+ 'PLAYER_LOADED',
+ 'VIDEO_STARTED',
+ 'VIDEO_PAUSED',
+ 'VIDEO_ENDED',
+ 'CUE_TRIGGERED',
+ 'INTERACTION_COMPLETED',
+ 'ERROR',
+ ];
+ events.forEach((event) => {
+ player.on(event, (payload?: AnalyticsPayload) => {
+ const cb = onAnalyticsRef.current;
+ if (cb) cb(event, payload);
+ });
+ });
+ } catch (error) {
+ console.error('Error initializing IVLabsPlayer:', error);
+ }
+ return () => {
+ if (playerRef.current) {
+ playerRef.current.destroy();
+ playerRef.current = null;
+ }
+ };
+ }, [videoUrl]);Additions required outside the selected range: // Keep the latest analytics callback without retriggering init effect
const onAnalyticsRef = useRef<typeof onAnalyticsEvent>(onAnalyticsEvent);
useEffect(() => {
onAnalyticsRef.current = onAnalyticsEvent;
}, [onAnalyticsEvent]);Rationale:
Also applies to: 73-87, 99-99 🤖 Prompt for AI Agents |
||||||||||||||||||||||
| if (translations) { | ||||||||||||||||||||||
| const locale = restOptions.locale || 'en'; | ||||||||||||||||||||||
| player.loadTranslations(locale, translations); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| }, 0); | ||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||
| console.error('Error initializing IVLabsPlayer:', error); | ||||||||||||||||||||||
| if (onAnalyticsEvent) { | ||||||||||||||||||||||
| const events: AnalyticsEvent[] = [ | ||||||||||||||||||||||
| 'PLAYER_LOADED', | ||||||||||||||||||||||
| 'VIDEO_STARTED', | ||||||||||||||||||||||
| 'VIDEO_PAUSED', | ||||||||||||||||||||||
| 'VIDEO_ENDED', | ||||||||||||||||||||||
| 'CUE_TRIGGERED', | ||||||||||||||||||||||
| 'INTERACTION_COMPLETED', | ||||||||||||||||||||||
| 'ERROR', | ||||||||||||||||||||||
| ]; | ||||||||||||||||||||||
| events.forEach((event) => { | ||||||||||||||||||||||
| player.on(event, (payload?: AnalyticsPayload) => | ||||||||||||||||||||||
| onAnalyticsEvent(event, payload) | ||||||||||||||||||||||
| ); | ||||||||||||||||||||||
| }); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||
| console.error('Error initializing IVLabsPlayer:', error); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| return () => { | ||||||||||||||||||||||
|
|
@@ -116,7 +96,20 @@ export const InteractiveVideo: React.FC<InteractiveVideoProps> = ({ | |||||||||||||||||||||
| playerRef.current = null; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| }; | ||||||||||||||||||||||
| }, [videoUrl, onAnalyticsEvent, cues, translations, restOptions]); | ||||||||||||||||||||||
| }, [videoUrl, onAnalyticsEvent, restOptions]); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||
| if (playerRef.current && cues) { | ||||||||||||||||||||||
| playerRef.current.loadCues(cues); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| }, [cues]); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
Comment on lines
+101
to
+106
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Ensure cues reload after player re-initialization. If the player is recreated (e.g., when - }, [cues]);
+ }, [cues, videoUrl]);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||
| if (playerRef.current && translations) { | ||||||||||||||||||||||
| const locale = restOptions.locale || 'en'; | ||||||||||||||||||||||
| playerRef.current.loadTranslations(locale, translations); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| }, [translations, restOptions.locale]); | ||||||||||||||||||||||
|
Comment on lines
+107
to
+112
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Ensure translations reload after player re-initialization and locale changes. Similarly, reload translations when the player is recreated. - }, [translations, restOptions.locale]);
+ }, [translations, restOptions.locale, videoUrl]);🤖 Prompt for AI Agents |
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| return ( | ||||||||||||||||||||||
| <div | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,16 +1,23 @@ | ||||||||||||||||||||||||||||||||||||
| import { defineConfig } from 'tsup'; | ||||||||||||||||||||||||||||||||||||
| import pkg from './package.json'; | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| export default defineConfig({ | ||||||||||||||||||||||||||||||||||||
| export default defineConfig((options) => ({ | ||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainJSON import in config may require TS settings; provide portable fallback. Importing package.json directly relies on resolveJsonModule (and compatible module resolution). If your env doesn’t guarantee this, prefer createRequire to avoid config-time import issues. Verification script (checks tsconfig flags): Optional portable change: -import pkg from './package.json';
+// Portable JSON access without relying on resolveJsonModule
+import { createRequire } from 'node:module';
+const require = createRequire(import.meta.url);
+const pkg = require('./package.json') as {
+ name: string;
+ version: string;
+ author?: string;
+ license?: string;
+};Nit: consider enabling sourcemaps for easier debugging: - clean: true,
+ clean: true,
+ sourcemap: true,Also applies to: 7-11, 13-13, 19-22, 23-23 🏁 Script executed: #!/bin/bash
set -euo pipefail
fd -t f 'tsconfig*.json' | while read -r f; do
echo "== $f =="
jq -r '.compilerOptions | {module, moduleResolution, resolveJsonModule, esModuleInterop}' "$f"
doneLength of output: 449 🏁 Script executed: #!/bin/bash
set -euo pipefail
# For each tsconfig*.json, print key compilerOptions fields
fd -t f 'tsconfig*.json' | while read -r f; do
echo "== $f =="
module=$(jq -r '.compilerOptions.module // "undefined"' "$f")
moduleResolution=$(jq -r '.compilerOptions.moduleResolution // "undefined"' "$f")
resolveJsonModule=$(jq -r '.compilerOptions.resolveJsonModule // false' "$f")
esModuleInterop=$(jq -r '.compilerOptions.esModuleInterop // false' "$f")
echo "module: $module"
echo "moduleResolution: $moduleResolution"
echo "resolveJsonModule: $resolveJsonModule"
echo "esModuleInterop: $esModuleInterop"
doneLength of output: 697 Enable portable JSON import in tsup.config.ts Your tsconfig.json currently has Locations to update:
Suggested changes: --- tsup.config.ts
@@ -1,7 +1,12
-import pkg from './package.json';
+// Portable JSON access without relying on resolveJsonModule
+import { createRequire } from 'node:module';
+const require = createRequire(import.meta.url);
+const pkg = require('./package.json') as {
+ name: string;
+ version: string;
+ author?: string;
+ license?: string;
+};
export default defineConfig((options) => ({
clean: true,
+ // Easier debugging of generated bundles
+ sourcemap: true,
// …
}));Alternatively, you can enable JSON imports by setting 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||
| entry: ['src/index.tsx'], | ||||||||||||||||||||||||||||||||||||
| format: ['esm', 'cjs'], | ||||||||||||||||||||||||||||||||||||
| outExtension({ format }) { | ||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||
| js: `.${format === 'esm' ? 'mjs' : 'cjs'}`, | ||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||
| dts: true, | ||||||||||||||||||||||||||||||||||||
| watch: options.watch, | ||||||||||||||||||||||||||||||||||||
| clean: true, | ||||||||||||||||||||||||||||||||||||
| banner: { | ||||||||||||||||||||||||||||||||||||
| js: `/** | ||||||||||||||||||||||||||||||||||||
| * ${pkg.name} v${pkg.version} | ||||||||||||||||||||||||||||||||||||
| * Author: ${pkg.author} | ||||||||||||||||||||||||||||||||||||
| * @license MIT | ||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||
| `, | ||||||||||||||||||||||||||||||||||||
| `, | ||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||
| })); | ||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Enforce LF consistently across OS (add .gitattributes).
Prettier will rewrite files to LF on save, but Git checkouts on Windows can still introduce CRLF. Add a repo-level .gitattributes to avoid churn.
Suggested .gitattributes:
Verification script to confirm presence/config:
🏁 Script executed:
Length of output: 163
Enforce LF line endings via .gitattributes
The
.gitattributesfile exists at the repo root but is currently empty. To avoid CRLF churn on Windows checkouts, please add the following content:Files needing update:
.gitattributes(repo root)Suggested diff:
🤖 Prompt for AI Agents