@karaplay/file-coder 1.3.5 → 1.3.7

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.
@@ -0,0 +1,101 @@
1
+ # Bug Fix Summary - EMK to KAR Conversion
2
+
3
+ ## ปัญหาที่พบ (Problem Found)
4
+
5
+ เมื่อแปลงไฟล์ EMK ที่มี MIDI data เสียหายเป็น KAR ได้รับ error message ที่เป็น "undefined":
6
+
7
+ ```
8
+ Error: EMK to KAR conversion failed: undefined
9
+ ```
10
+
11
+ ## สาเหตุ (Root Cause)
12
+
13
+ 1. **Primary Issue**: Library `midi-file` throw string error แทนที่จะเป็น Error object
14
+ 2. **Code Issue**: ใน `src/emk-to-kar.ts` มีการ catch error และพยายามเข้าถึง `error.message` แต่เมื่อ error เป็น string จะไม่มี property `.message` จึงได้ค่า `undefined`
15
+ 3. **File Issue**: ไฟล์ `tests/emk/failed/failed_convert_emk_to_kar.emk` มี MIDI track 2 ที่ประกาศความยาว 1364 bytes แต่ข้อมูลจริงมี 1373 bytes (มากกว่า 9 bytes)
16
+
17
+ ## การแก้ไข (Solution)
18
+
19
+ แก้ไข error handling ใน `src/emk-to-kar.ts` เพื่อรองรับทั้ง Error object และ string error:
20
+
21
+ ```typescript
22
+ // Before (เดิม):
23
+ throw new Error(`EMK to KAR conversion failed: ${error.message}`);
24
+
25
+ // After (ใหม่):
26
+ const errorMessage = typeof error === 'string'
27
+ ? error
28
+ : error?.message || String(error) || 'Unknown error';
29
+
30
+ throw new Error(`EMK to KAR conversion failed: ${errorMessage}`);
31
+ ```
32
+
33
+ ## การทดสอบ (Testing)
34
+
35
+ เพิ่มไฟล์ทดสอบใหม่ `tests/emk-error-handling.test.ts` ที่มี 4 test cases:
36
+
37
+ 1. ✅ รองรับ corrupted MIDI data พร้อม error message ที่ชัดเจน
38
+ 2. ✅ รองรับ string errors จาก third-party libraries
39
+ 3. ✅ รองรับ missing input files
40
+ 4. ✅ ให้ error message ที่เป็นประโยชน์สำหรับ corrupted EMK structure
41
+
42
+ **ผลการทดสอบ: 135 tests passed** (รวม test cases ใหม่)
43
+
44
+ ## ผลลัพธ์ (Result)
45
+
46
+ ### Before (ก่อนแก้):
47
+ ```
48
+ Error: EMK to KAR conversion failed: undefined
49
+ ```
50
+
51
+ ### After (หลังแก้):
52
+ ```
53
+ Error: EMK to KAR conversion failed: Bad MIDI file. Expected 'MTrk', got: 'iF'
54
+ ```
55
+
56
+ ตอนนี้ error message บอกปัญหาได้ชัดเจนว่า MIDI file มีปัญหาตรงไหน
57
+
58
+ ## เวอร์ชันที่ปล่อย (Release)
59
+
60
+ - **Version**: 1.3.5
61
+ - **Published**: December 19, 2025
62
+ - **Package**: @karaplay/file-coder@1.3.5
63
+ - **Status**: ✅ Successfully published to npm
64
+
65
+ ## วิธีอัพเดท (How to Update)
66
+
67
+ ```bash
68
+ npm update @karaplay/file-coder
69
+ ```
70
+
71
+ หรือ
72
+
73
+ ```bash
74
+ npm install @karaplay/file-coder@1.3.5
75
+ ```
76
+
77
+ ## ไฟล์ที่แก้ไข (Files Modified)
78
+
79
+ 1. `src/emk-to-kar.ts` - ปรับปรุง error handling (2 locations)
80
+ 2. `tests/emk-error-handling.test.ts` - เพิ่ม test suite ใหม่
81
+ 3. `package.json` - อัพเดท version เป็น 1.3.5
82
+ 4. `RELEASE_v1.3.5.md` - เพิ่ม release notes
83
+
84
+ ## Technical Details
85
+
86
+ ไฟล์ `failed_convert_emk_to_kar.emk` มีโครงสร้างดังนี้:
87
+ - ✅ Decode EMK สำเร็จ
88
+ - ✅ มี MIDI, Lyric, Cursor data ครบถ้วน
89
+ - ❌ MIDI Track 2 มี length field ผิด (declare 1364 แต่จริง 1373)
90
+ - ❌ ทำให้ MIDI parser หา track ถัดไปไม่เจอ (เจอ 'iF' แทน 'MTrk')
91
+
92
+ นี่คือสถานการณ์จริงที่อาจเกิดขึ้นกับไฟล์ EMK ที่เสียหายหรือ encode ไม่ถูกต้อง
93
+
94
+ ## สรุป (Conclusion)
95
+
96
+ ✅ แก้ไข bug error handling สำเร็จ
97
+ ✅ เพิ่ม test coverage
98
+ ✅ ทุก tests ผ่านหมด (135/135)
99
+ ✅ Build สำเร็จ
100
+ ✅ Publish ไป npm สำเร็จ (v1.3.5)
101
+
@@ -0,0 +1,151 @@
1
+ # สรุปการแก้ไข Bug - EMK to KAR Conversion
2
+
3
+ ## 🎯 ปัญหาที่แท้จริง (The Real Issue)
4
+
5
+ คุณพูดถูกครับ! **ไฟล์ MIDI ไม่ได้เสียหาย** แต่มี **track length field ที่ผิด**
6
+
7
+ ### การวิเคราะห์:
8
+ ```
9
+ Track 2:
10
+ - Declared length: 1364 bytes
11
+ - Actual length: 1373 bytes
12
+ - Difference: +9 bytes
13
+
14
+ ทำให้ MIDI parser หา track ถัดไปที่ตำแหน่งผิด:
15
+ - คาดหวัง: position 1431 จะเจอ "MTrk"
16
+ - แต่เจอ: "iF" (ซึ่งเป็นข้อมูลภายใน track)
17
+ - ที่จริง: "MTrk" อยู่ที่ position 1440
18
+ ```
19
+
20
+ ## ✅ วิธีแก้ (Solution)
21
+
22
+ เพิ่มฟังก์ชัน `repairMidiTrackLengths()` ที่:
23
+
24
+ 1. **สแกนหา end-of-track marker** (`FF 2F 00`) ตำแหน่งจริง
25
+ 2. **คำนวณความยาวที่ถูกต้อง** จาก marker
26
+ 3. **สร้าง MIDI ใหม่** โดยแก้ไข track length fields
27
+ 4. **รายงานการแก้ไข** ผ่าน warnings
28
+
29
+ ### Code Implementation:
30
+
31
+ ```typescript
32
+ export function repairMidiTrackLengths(midiBuffer: Buffer): {
33
+ repaired: Buffer;
34
+ fixed: boolean;
35
+ corrections: number;
36
+ } {
37
+ // Scan each track for end-of-track marker
38
+ // Calculate actual length
39
+ // Rebuild MIDI with correct lengths
40
+ }
41
+ ```
42
+
43
+ ### การใช้งาน:
44
+
45
+ ```typescript
46
+ // แบบอัตโนมัติ (Auto-repair ใน convertEmkToKar)
47
+ const result = convertEmkToKar({
48
+ inputEmk: 'song.emk',
49
+ outputKar: 'song.kar'
50
+ });
51
+ // ✅ Success! warnings: ['Fixed 1 MIDI track length(s)']
52
+
53
+ // แบบ Manual
54
+ const repaired = repairMidiTrackLengths(midiBuffer);
55
+ if (repaired.fixed) {
56
+ console.log(`Fixed ${repaired.corrections} track(s)`);
57
+ }
58
+ ```
59
+
60
+ ## 📊 ผลการทดสอบ (Test Results)
61
+
62
+ ### Before (v1.3.5):
63
+ ```
64
+ ❌ Error: EMK to KAR conversion failed: Bad MIDI file. Expected 'MTrk', got: 'iF'
65
+ ```
66
+
67
+ ### After (v1.3.6):
68
+ ```
69
+ ✅ [1/3] Decoding EMK file
70
+ ✅ [1/3] ✓ Decoded to: MIDI, Lyric, Cursor
71
+ ✅ [2/3] Converting to KAR: 14 อีกครั้ง - โลโซ (Loso)
72
+ ✅ [3/3] ✓ KAR file created: 24,770 bytes
73
+
74
+ Result:
75
+ - Success: true
76
+ - Warnings: ['Fixed 1 MIDI track length(s)', ...]
77
+ - Output: Valid KAR file with 12 tracks
78
+ - Metadata: "14 อีกครั้ง " - "โลโซ (Loso)"
79
+ ```
80
+
81
+ ### All Tests:
82
+ - **136 tests passed** ✅
83
+ - Including:
84
+ - ✅ MIDI repair with incorrect lengths
85
+ - ✅ Don't modify correct MIDIs
86
+ - ✅ EMK to KAR with auto-repair
87
+ - ✅ Error handling
88
+ - ✅ Edge cases
89
+
90
+ ## 🔧 การเปลี่ยนแปลง (Changes)
91
+
92
+ ### ไฟล์ที่แก้ไข:
93
+ 1. **src/emk-to-kar.ts**
94
+ - เพิ่ม `repairMidiTrackLengths()` function (70+ lines)
95
+ - ใช้ repair function อัตโนมัติก่อน save MIDI
96
+ - ปรับปรุง error handling
97
+
98
+ 2. **src/index.ts**
99
+ - Export `repairMidiTrackLengths` เพื่อให้ใช้แบบ manual
100
+
101
+ 3. **tests/emk-error-handling.test.ts**
102
+ - อัพเดท tests ให้ cover repair functionality
103
+ - เพิ่ม test cases สำหรับ repair function
104
+
105
+ ### Version History:
106
+ - **v1.3.5**: Fixed error handling (string errors)
107
+ - **v1.3.6**: Added MIDI repair function ⭐
108
+
109
+ ## 📦 Publication
110
+
111
+ - **Package**: @karaplay/file-coder
112
+ - **Version**: 1.3.6
113
+ - **Status**: ✅ Successfully published to npm
114
+ - **Published**: December 19, 2025
115
+
116
+ ### ตรวจสอบ:
117
+ ```bash
118
+ $ npm view @karaplay/file-coder version
119
+ 1.3.6
120
+
121
+ $ npm view @karaplay/file-coder versions --json
122
+ [... "1.3.5", "1.3.6"]
123
+ ```
124
+
125
+ ## 🎓 สิ่งที่เรียนรู้ (Lessons Learned)
126
+
127
+ 1. **ไม่ใช่ทุกอย่างที่เป็น error จะเป็น bug**
128
+ - ก่อนหน้าคิดว่าไฟล์เสียหาย → แต่จริงๆ แค่ metadata ผิด
129
+ - MIDI data เองใช้งานได้ปกติ
130
+
131
+ 2. **การแก้ปัญหาต้องแก้ที่ root cause**
132
+ - แค่ปรับ error message ไม่พอ (v1.3.5)
133
+ - ต้อง **fix the actual problem** (v1.3.6)
134
+
135
+ 3. **Defensive programming**
136
+ - เพิ่ม auto-repair ทำให้ library robust ขึ้น
137
+ - User ไม่ต้องทำอะไรเอง
138
+
139
+ ## 🎉 สรุป (Summary)
140
+
141
+ | Aspect | Result |
142
+ |--------|--------|
143
+ | ปัญหา | MIDI track length ไม่ถูกต้อง ทำให้แปลงไม่ได้ |
144
+ | วิธีแก้ | เพิ่ม automatic MIDI repair function |
145
+ | Tests | 136/136 passed ✅ |
146
+ | Published | v1.3.6 ✅ |
147
+ | Breaking Changes | None |
148
+ | User Action Required | None (auto-repair) |
149
+
150
+ **คุณพูดถูกครับ - ไฟล์ไม่ได้เสียหาย มันแค่ต้องการการ "ซ่อมแซม" เล็กน้อย! ตอนนี้ library จะจัดการให้อัตโนมัติแล้ว** 🚀
151
+
@@ -0,0 +1,84 @@
1
+ # Release v1.3.4
2
+
3
+ **Release Date:** December 19, 2025
4
+
5
+ ## Bug Fixes
6
+
7
+ ### Fixed Error Handling for Corrupted MIDI Data
8
+
9
+ **Issue:** When converting EMK files with corrupted MIDI data, the error message was showing as "undefined" because the `midi-file` library throws string errors instead of Error objects.
10
+
11
+ **Root Cause:** The EMK to KAR conversion function was catching errors and trying to access `error.message`, but when third-party libraries throw string errors (not Error objects), the `.message` property is undefined.
12
+
13
+ **Solution:** Updated error handling in `convertEmkToKar` to properly handle both Error objects and string errors:
14
+
15
+ ```typescript
16
+ // Handle both Error objects and string errors (some libraries throw strings)
17
+ const errorMessage = typeof error === 'string'
18
+ ? error
19
+ : error?.message || String(error) || 'Unknown error';
20
+
21
+ throw new Error(`EMK to KAR conversion failed: ${errorMessage}`);
22
+ ```
23
+
24
+ **Impact:**
25
+ - ✅ Error messages are now always informative and actionable
26
+ - ✅ Users will see the actual MIDI parsing error (e.g., "Bad MIDI file. Expected 'MTrk', got: 'iF'")
27
+ - ✅ No more "undefined" error messages
28
+ - ✅ Better debugging for corrupted EMK files
29
+
30
+ ## Test Coverage
31
+
32
+ Added comprehensive test suite `emk-error-handling.test.ts` with 4 test cases:
33
+
34
+ 1. ✅ Handles corrupted MIDI data with proper error message
35
+ 2. ✅ Handles string errors from third-party libraries
36
+ 3. ✅ Handles missing input files with proper error
37
+ 4. ✅ Provides informative errors for corrupted EMK structure
38
+
39
+ **All 135 tests pass**, including the new error handling tests.
40
+
41
+ ## Example
42
+
43
+ **Before (v1.3.2):**
44
+ ```
45
+ Error: EMK to KAR conversion failed: undefined
46
+ ```
47
+
48
+ **After (v1.3.3):**
49
+ ```
50
+ Error: EMK to KAR conversion failed: Bad MIDI file. Expected 'MTrk', got: 'iF'
51
+ ```
52
+
53
+ ## Technical Details
54
+
55
+ ### The Corrupted File Case
56
+
57
+ The test file `tests/emk/failed/failed_convert_emk_to_kar.emk` contains:
58
+ - Valid EMK structure that decodes successfully
59
+ - MIDI data with 8 tracks (format 1, 96 ticks per beat)
60
+ - Track 2 has an incorrect length field (declares 1364 bytes but actually contains 1373 bytes)
61
+ - This causes the MIDI parser to look for the next track at the wrong position
62
+ - The parser encounters 'iF' (part of track data) instead of 'MTrk' (track header)
63
+
64
+ This is a real-world scenario that can occur with corrupted or improperly encoded EMK files.
65
+
66
+ ## Files Changed
67
+
68
+ - `src/emk-to-kar.ts` - Improved error handling
69
+ - `tests/emk-error-handling.test.ts` - New comprehensive test suite
70
+
71
+ ## Upgrade Notes
72
+
73
+ No breaking changes. This is a patch release that improves error messages only.
74
+
75
+ Upgrade with:
76
+ ```bash
77
+ npm update @karaplay/file-coder
78
+ ```
79
+
80
+ Or install specifically:
81
+ ```bash
82
+ npm install @karaplay/file-coder@1.3.3
83
+ ```
84
+
@@ -0,0 +1,84 @@
1
+ # Release v1.3.4
2
+
3
+ **Release Date:** December 19, 2025
4
+
5
+ ## Bug Fixes
6
+
7
+ ### Fixed Error Handling for Corrupted MIDI Data
8
+
9
+ **Issue:** When converting EMK files with corrupted MIDI data, the error message was showing as "undefined" because the `midi-file` library throws string errors instead of Error objects.
10
+
11
+ **Root Cause:** The EMK to KAR conversion function was catching errors and trying to access `error.message`, but when third-party libraries throw string errors (not Error objects), the `.message` property is undefined.
12
+
13
+ **Solution:** Updated error handling in `convertEmkToKar` to properly handle both Error objects and string errors:
14
+
15
+ ```typescript
16
+ // Handle both Error objects and string errors (some libraries throw strings)
17
+ const errorMessage = typeof error === 'string'
18
+ ? error
19
+ : error?.message || String(error) || 'Unknown error';
20
+
21
+ throw new Error(`EMK to KAR conversion failed: ${errorMessage}`);
22
+ ```
23
+
24
+ **Impact:**
25
+ - ✅ Error messages are now always informative and actionable
26
+ - ✅ Users will see the actual MIDI parsing error (e.g., "Bad MIDI file. Expected 'MTrk', got: 'iF'")
27
+ - ✅ No more "undefined" error messages
28
+ - ✅ Better debugging for corrupted EMK files
29
+
30
+ ## Test Coverage
31
+
32
+ Added comprehensive test suite `emk-error-handling.test.ts` with 4 test cases:
33
+
34
+ 1. ✅ Handles corrupted MIDI data with proper error message
35
+ 2. ✅ Handles string errors from third-party libraries
36
+ 3. ✅ Handles missing input files with proper error
37
+ 4. ✅ Provides informative errors for corrupted EMK structure
38
+
39
+ **All 135 tests pass**, including the new error handling tests.
40
+
41
+ ## Example
42
+
43
+ **Before (v1.3.2):**
44
+ ```
45
+ Error: EMK to KAR conversion failed: undefined
46
+ ```
47
+
48
+ **After (v1.3.3):**
49
+ ```
50
+ Error: EMK to KAR conversion failed: Bad MIDI file. Expected 'MTrk', got: 'iF'
51
+ ```
52
+
53
+ ## Technical Details
54
+
55
+ ### The Corrupted File Case
56
+
57
+ The test file `tests/emk/failed/failed_convert_emk_to_kar.emk` contains:
58
+ - Valid EMK structure that decodes successfully
59
+ - MIDI data with 8 tracks (format 1, 96 ticks per beat)
60
+ - Track 2 has an incorrect length field (declares 1364 bytes but actually contains 1373 bytes)
61
+ - This causes the MIDI parser to look for the next track at the wrong position
62
+ - The parser encounters 'iF' (part of track data) instead of 'MTrk' (track header)
63
+
64
+ This is a real-world scenario that can occur with corrupted or improperly encoded EMK files.
65
+
66
+ ## Files Changed
67
+
68
+ - `src/emk-to-kar.ts` - Improved error handling
69
+ - `tests/emk-error-handling.test.ts` - New comprehensive test suite
70
+
71
+ ## Upgrade Notes
72
+
73
+ No breaking changes. This is a patch release that improves error messages only.
74
+
75
+ Upgrade with:
76
+ ```bash
77
+ npm update @karaplay/file-coder
78
+ ```
79
+
80
+ Or install specifically:
81
+ ```bash
82
+ npm install @karaplay/file-coder@1.3.4
83
+ ```
84
+
@@ -0,0 +1,124 @@
1
+ # Release v1.3.6
2
+
3
+ **Release Date:** December 19, 2025
4
+
5
+ ## 🎉 Major Bug Fix: MIDI Track Length Repair
6
+
7
+ ### Problem
8
+ EMK files that were correctly encoded but contained MIDI data with incorrect track length fields would fail to convert to KAR format with the error:
9
+ ```
10
+ Error: EMK to KAR conversion failed: Bad MIDI file. Expected 'MTrk', got: 'iF'
11
+ ```
12
+
13
+ ### Root Cause
14
+ Some EMK files contain valid MIDI data, but the track length fields in the MIDI headers are incorrect. For example:
15
+ - Track 2 declares length = 1364 bytes
16
+ - Actual track data = 1373 bytes (9 bytes longer)
17
+ - The MIDI parser looks for the next track at the wrong position and fails
18
+
19
+ This is **not corrupted data** - the MIDI content itself is valid, just the metadata is wrong.
20
+
21
+ ### Solution
22
+ Added automatic MIDI repair function `repairMidiTrackLengths()` that:
23
+ 1. Scans MIDI tracks for the actual end-of-track marker (`FF 2F 00`)
24
+ 2. Calculates the correct track length
25
+ 3. Rebuilds the MIDI file with corrected length fields
26
+ 4. Reports the number of tracks fixed in warnings
27
+
28
+ The repair happens automatically during EMK to KAR conversion, so no user action required!
29
+
30
+ ### Example
31
+
32
+ **Before (v1.3.5)**:
33
+ ```javascript
34
+ const result = convertEmkToKar({
35
+ inputEmk: 'song.emk',
36
+ outputKar: 'song.kar'
37
+ });
38
+ // Error: Bad MIDI file. Expected 'MTrk', got: 'iF'
39
+ ```
40
+
41
+ **After (v1.3.6)**:
42
+ ```javascript
43
+ const result = convertEmkToKar({
44
+ inputEmk: 'song.emk',
45
+ outputKar: 'song.kar'
46
+ });
47
+ // ✅ Success!
48
+ // warnings: ['Fixed 1 MIDI track length(s)']
49
+ ```
50
+
51
+ ## New Features
52
+
53
+ ### 1. `repairMidiTrackLengths()` Function
54
+ Exported function for manually repairing MIDI files:
55
+
56
+ ```typescript
57
+ import { repairMidiTrackLengths } from '@karaplay/file-coder';
58
+
59
+ const midiBuffer = fs.readFileSync('song.mid');
60
+ const result = repairMidiTrackLengths(midiBuffer);
61
+
62
+ if (result.fixed) {
63
+ console.log(`Fixed ${result.corrections} track(s)`);
64
+ fs.writeFileSync('song_fixed.mid', result.repaired);
65
+ }
66
+ ```
67
+
68
+ ### 2. Enhanced Error Messages
69
+ Improved error handling from v1.3.5 to properly catch string errors from third-party libraries.
70
+
71
+ ## Files Changed
72
+
73
+ - `src/emk-to-kar.ts` - Added MIDI repair function and integration
74
+ - `src/index.ts` - Exported `repairMidiTrackLengths`
75
+ - `tests/emk-error-handling.test.ts` - Updated tests to verify repair functionality
76
+
77
+ ## Test Coverage
78
+
79
+ **136 tests passed**, including:
80
+ - ✅ MIDI repair with incorrect track lengths
81
+ - ✅ MIDI repair doesn't modify correct files
82
+ - ✅ EMK to KAR conversion with auto-repair
83
+ - ✅ Error handling for string errors
84
+ - ✅ Missing file handling
85
+
86
+ ## Technical Details
87
+
88
+ The repair function:
89
+ - Searches for end-of-track markers within declared length + 10% buffer
90
+ - Handles edge cases where files are truncated
91
+ - Preserves original file if no issues found
92
+ - Returns detailed information about fixes applied
93
+
94
+ ## Impact
95
+
96
+ This fix allows conversion of previously "failed" EMK files that actually contain valid data. The failed file at `tests/emk/failed/failed_convert_emk_to_kar.emk` now converts successfully:
97
+
98
+ ```
99
+ ✓ KAR file created: 24,770 bytes
100
+ ✓ Valid MIDI with 12 tracks
101
+ Metadata: "14 อีกครั้ง" - "โลโซ (Loso)"
102
+ ```
103
+
104
+ ## Upgrade Notes
105
+
106
+ **No breaking changes.** The repair happens automatically - existing code continues to work but now handles more files successfully.
107
+
108
+ ### Upgrade:
109
+ ```bash
110
+ npm install @karaplay/file-coder@1.3.6
111
+ ```
112
+
113
+ Or:
114
+ ```bash
115
+ npm update @karaplay/file-coder
116
+ ```
117
+
118
+ ## Summary
119
+
120
+ - 🐛 Fixed: EMK files with incorrect MIDI track lengths now convert successfully
121
+ - ✨ New: `repairMidiTrackLengths()` function for manual MIDI repair
122
+ - ✅ Tests: 136/136 passed
123
+ - 📦 Ready: Published to npm as v1.3.6
124
+
@@ -0,0 +1,69 @@
1
+ # Release v1.3.7
2
+
3
+ **Release Date:** December 19, 2025
4
+
5
+ ## Bug Fix: Package Export Path
6
+
7
+ ### Problem
8
+ Other packages (like `@karaplay/kar-player`) that imported `@karaplay/file-coder/dist/client` were getting a module not found error:
9
+
10
+ ```
11
+ Module not found: Package path ./dist/client is not exported from package
12
+ @karaplay/file-coder (see exports field in package.json)
13
+ ```
14
+
15
+ ### Root Cause
16
+ The package had an export for `./client` but not for `./dist/client`, even though some packages imported it using the full path.
17
+
18
+ ### Solution
19
+ Added explicit export path for `./dist/client` in package.json:
20
+
21
+ ```json
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "default": "./dist/index.js"
26
+ },
27
+ "./client": {
28
+ "types": "./dist/client.d.ts",
29
+ "default": "./dist/client.js"
30
+ },
31
+ "./dist/client": {
32
+ "types": "./dist/client.d.ts",
33
+ "default": "./dist/client.js"
34
+ }
35
+ }
36
+ ```
37
+
38
+ ### Impact
39
+ - ✅ Packages can now import using either `@karaplay/file-coder/client` or `@karaplay/file-coder/dist/client`
40
+ - ✅ Backward compatible - existing imports continue to work
41
+ - ✅ All 136 tests pass
42
+
43
+ ## Test Results
44
+ ```
45
+ Test Suites: 11 passed, 11 total
46
+ Tests: 136 passed, 136 total
47
+ ```
48
+
49
+ ## Changes
50
+ - **package.json**: Added `./dist/client` export path
51
+
52
+ ## Upgrade Notes
53
+ No breaking changes. Update with:
54
+
55
+ ```bash
56
+ npm install @karaplay/file-coder@1.3.7
57
+ ```
58
+
59
+ Or:
60
+
61
+ ```bash
62
+ npm update @karaplay/file-coder
63
+ ```
64
+
65
+ ## Version History
66
+ - v1.3.5: Fixed error handling for string errors
67
+ - v1.3.6: Added MIDI repair function for incorrect track lengths
68
+ - v1.3.7: Fixed package export path for `./dist/client` ⭐
69
+
@@ -2,6 +2,16 @@
2
2
  * EMK to KAR Workflow
3
3
  * Complete pipeline: EMK file → decode → MIDI + LYR + CUR → convert → KAR file
4
4
  */
5
+ /**
6
+ * Repairs MIDI file with incorrect track lengths by finding actual end-of-track markers
7
+ * Some EMK files contain MIDI data with incorrect track length fields
8
+ * This function scans for FF 2F 00 (end of track) markers and corrects the lengths
9
+ */
10
+ export declare function repairMidiTrackLengths(midiBuffer: Buffer): {
11
+ repaired: Buffer;
12
+ fixed: boolean;
13
+ corrections: number;
14
+ };
5
15
  export interface EmkToKarOptions {
6
16
  inputEmk: string;
7
17
  outputKar: string;
@@ -37,6 +37,7 @@ var __importStar = (this && this.__importStar) || (function () {
37
37
  };
38
38
  })();
39
39
  Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.repairMidiTrackLengths = repairMidiTrackLengths;
40
41
  exports.convertEmkToKar = convertEmkToKar;
41
42
  exports.convertEmkToKarBatch = convertEmkToKarBatch;
42
43
  exports.validateThaiLyricReadability = validateThaiLyricReadability;
@@ -45,6 +46,78 @@ const path = __importStar(require("path"));
45
46
  const server_decode_1 = require("./emk/server-decode");
46
47
  const ncntokar_1 = require("./ncntokar");
47
48
  const iconv = __importStar(require("iconv-lite"));
49
+ /**
50
+ * Repairs MIDI file with incorrect track lengths by finding actual end-of-track markers
51
+ * Some EMK files contain MIDI data with incorrect track length fields
52
+ * This function scans for FF 2F 00 (end of track) markers and corrects the lengths
53
+ */
54
+ function repairMidiTrackLengths(midiBuffer) {
55
+ // Check if it's a valid MIDI file
56
+ if (midiBuffer.length < 14 || midiBuffer.subarray(0, 4).toString('ascii') !== 'MThd') {
57
+ return { repaired: midiBuffer, fixed: false, corrections: 0 };
58
+ }
59
+ const headerLength = midiBuffer.readUInt32BE(4);
60
+ if (headerLength !== 6) {
61
+ return { repaired: midiBuffer, fixed: false, corrections: 0 };
62
+ }
63
+ const numTracks = midiBuffer.readUInt16BE(10);
64
+ let corrections = 0;
65
+ const chunks = [];
66
+ // Copy header
67
+ chunks.push(midiBuffer.subarray(0, 14));
68
+ let pos = 14;
69
+ for (let trackIdx = 0; trackIdx < numTracks && pos < midiBuffer.length - 8; trackIdx++) {
70
+ const chunkType = midiBuffer.subarray(pos, pos + 4).toString('ascii');
71
+ if (chunkType !== 'MTrk') {
72
+ // Invalid chunk, return original
73
+ return { repaired: midiBuffer, fixed: false, corrections };
74
+ }
75
+ const declaredLength = midiBuffer.readUInt32BE(pos + 4);
76
+ const trackDataStart = pos + 8;
77
+ // Search for end of track marker (FF 2F 00)
78
+ // Search within declared length + extra buffer (some EMK files have incorrect track lengths)
79
+ let actualEndPos = -1;
80
+ const extraBuffer = Math.max(100, Math.floor(declaredLength * 0.1)); // 10% or 100 bytes, whichever is larger
81
+ const searchLimit = Math.min(trackDataStart + declaredLength + extraBuffer, midiBuffer.length - 2);
82
+ for (let i = trackDataStart; i < searchLimit; i++) {
83
+ if (midiBuffer[i] === 0xFF && midiBuffer[i + 1] === 0x2F && midiBuffer[i + 2] === 0x00) {
84
+ actualEndPos = i + 3; // Include the 3 bytes of end marker
85
+ break;
86
+ }
87
+ }
88
+ if (actualEndPos === -1) {
89
+ // No end marker found, use declared length
90
+ chunks.push(midiBuffer.subarray(pos, trackDataStart + declaredLength));
91
+ pos = trackDataStart + declaredLength;
92
+ continue;
93
+ }
94
+ const actualLength = actualEndPos - trackDataStart;
95
+ if (actualLength !== declaredLength) {
96
+ // Need to fix the length
97
+ corrections++;
98
+ // Create new track chunk with correct length
99
+ const trackHeader = Buffer.alloc(8);
100
+ trackHeader.write('MTrk', 0, 'ascii');
101
+ trackHeader.writeUInt32BE(actualLength, 4);
102
+ chunks.push(trackHeader);
103
+ chunks.push(midiBuffer.subarray(trackDataStart, actualEndPos));
104
+ pos = actualEndPos;
105
+ }
106
+ else {
107
+ // Length is correct
108
+ chunks.push(midiBuffer.subarray(pos, trackDataStart + declaredLength));
109
+ pos = trackDataStart + declaredLength;
110
+ }
111
+ }
112
+ if (corrections > 0) {
113
+ return {
114
+ repaired: Buffer.concat(chunks),
115
+ fixed: true,
116
+ corrections
117
+ };
118
+ }
119
+ return { repaired: midiBuffer, fixed: false, corrections: 0 };
120
+ }
48
121
  /**
49
122
  * Complete workflow: Converts EMK file directly to KAR file
50
123
  *
@@ -83,6 +156,12 @@ function convertEmkToKar(options) {
83
156
  throw new Error('Lyric data not found in EMK file');
84
157
  if (!decoded.cursor)
85
158
  throw new Error('Cursor data not found in EMK file');
159
+ // Repair MIDI track lengths if needed (some EMK files have incorrect track length fields)
160
+ const repairResult = repairMidiTrackLengths(decoded.midi);
161
+ if (repairResult.fixed) {
162
+ warnings.push(`Fixed ${repairResult.corrections} MIDI track length(s)`);
163
+ decoded.midi = repairResult.repaired;
164
+ }
86
165
  // Write intermediate files
87
166
  fs.writeFileSync(midiFile, decoded.midi);
88
167
  // Lyric is already in TIS-620 encoding from EMK decoder, write as-is
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  */
5
5
  export { convertNcnToKar, convertWithDefaults, parseLyricFile, buildKaraokeTrack, buildMetadataTracks, readFileTextTIS620, splitLinesKeepEndings, trimLineEndings, metaEvent, endOfTrack, ensureReadableFile, ensureOutputDoesNotExist, CursorReader, type ConversionOptions, type SongMetadata } from './ncntokar';
6
6
  export { readKarFile, validateKarFile, extractLyricsFromKar, type KarFileInfo, type KarTrack } from './kar-reader';
7
- export { convertEmkToKar, convertEmkToKarBatch, validateThaiLyricReadability, type EmkToKarOptions, type EmkToKarResult } from './emk-to-kar';
7
+ export { convertEmkToKar, convertEmkToKarBatch, validateThaiLyricReadability, repairMidiTrackLengths, type EmkToKarOptions, type EmkToKarResult } from './emk-to-kar';
8
8
  export { decodeEmk as decodeEmkServer, parseSongInfo as parseSongInfoServer, xorDecrypt as xorDecryptServer, looksLikeText as looksLikeTextServer, type DecodedEmkParts as DecodedEmkPartsServer } from './emk/server-decode';
9
9
  export { decodeEmk as decodeEmkClient, parseSongInfo as parseSongInfoClient, xorDecrypt as xorDecryptClient, looksLikeText as looksLikeTextClient, type DecodedEmkParts as DecodedEmkPartsClient } from './emk/client-decoder';
10
10
  export { convertNcnToKarBrowser, parseLyricBuffer, buildKaraokeTrackBrowser, buildMetadataTracksBrowser, fileToBuffer, downloadBuffer, type BrowserConversionOptions, type BrowserConversionResult, } from './ncntokar.browser';
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * Supports .emk (Extreme Karaoke), .kar (MIDI karaoke), and NCN format conversions
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.readKarFileFromBrowser = exports.extractLyricsFromKarBuffer = exports.validateKarBuffer = exports.readKarBuffer = exports.validateThaiLyricReadabilityBrowser = exports.convertEmkFilesBatch = exports.convertEmkFileToKar = exports.convertEmkToKarBrowser = exports.downloadBuffer = exports.fileToBuffer = exports.buildMetadataTracksBrowser = exports.buildKaraokeTrackBrowser = exports.parseLyricBuffer = exports.convertNcnToKarBrowser = exports.looksLikeTextClient = exports.xorDecryptClient = exports.parseSongInfoClient = exports.decodeEmkClient = exports.looksLikeTextServer = exports.xorDecryptServer = exports.parseSongInfoServer = exports.decodeEmkServer = exports.validateThaiLyricReadability = exports.convertEmkToKarBatch = exports.convertEmkToKar = exports.extractLyricsFromKar = exports.validateKarFile = exports.readKarFile = exports.CursorReader = exports.ensureOutputDoesNotExist = exports.ensureReadableFile = exports.endOfTrack = exports.metaEvent = exports.trimLineEndings = exports.splitLinesKeepEndings = exports.readFileTextTIS620 = exports.buildMetadataTracks = exports.buildKaraokeTrack = exports.parseLyricFile = exports.convertWithDefaults = exports.convertNcnToKar = void 0;
7
+ exports.readKarFileFromBrowser = exports.extractLyricsFromKarBuffer = exports.validateKarBuffer = exports.readKarBuffer = exports.validateThaiLyricReadabilityBrowser = exports.convertEmkFilesBatch = exports.convertEmkFileToKar = exports.convertEmkToKarBrowser = exports.downloadBuffer = exports.fileToBuffer = exports.buildMetadataTracksBrowser = exports.buildKaraokeTrackBrowser = exports.parseLyricBuffer = exports.convertNcnToKarBrowser = exports.looksLikeTextClient = exports.xorDecryptClient = exports.parseSongInfoClient = exports.decodeEmkClient = exports.looksLikeTextServer = exports.xorDecryptServer = exports.parseSongInfoServer = exports.decodeEmkServer = exports.repairMidiTrackLengths = exports.validateThaiLyricReadability = exports.convertEmkToKarBatch = exports.convertEmkToKar = exports.extractLyricsFromKar = exports.validateKarFile = exports.readKarFile = exports.CursorReader = exports.ensureOutputDoesNotExist = exports.ensureReadableFile = exports.endOfTrack = exports.metaEvent = exports.trimLineEndings = exports.splitLinesKeepEndings = exports.readFileTextTIS620 = exports.buildMetadataTracks = exports.buildKaraokeTrack = exports.parseLyricFile = exports.convertWithDefaults = exports.convertNcnToKar = void 0;
8
8
  // NCN to KAR converter exports
9
9
  var ncntokar_1 = require("./ncntokar");
10
10
  Object.defineProperty(exports, "convertNcnToKar", { enumerable: true, get: function () { return ncntokar_1.convertNcnToKar; } });
@@ -30,6 +30,7 @@ var emk_to_kar_1 = require("./emk-to-kar");
30
30
  Object.defineProperty(exports, "convertEmkToKar", { enumerable: true, get: function () { return emk_to_kar_1.convertEmkToKar; } });
31
31
  Object.defineProperty(exports, "convertEmkToKarBatch", { enumerable: true, get: function () { return emk_to_kar_1.convertEmkToKarBatch; } });
32
32
  Object.defineProperty(exports, "validateThaiLyricReadability", { enumerable: true, get: function () { return emk_to_kar_1.validateThaiLyricReadability; } });
33
+ Object.defineProperty(exports, "repairMidiTrackLengths", { enumerable: true, get: function () { return emk_to_kar_1.repairMidiTrackLengths; } });
33
34
  // EMK server-side decoder exports
34
35
  var server_decode_1 = require("./emk/server-decode");
35
36
  Object.defineProperty(exports, "decodeEmkServer", { enumerable: true, get: function () { return server_decode_1.decodeEmk; } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@karaplay/file-coder",
3
- "version": "1.3.5",
3
+ "version": "1.3.7",
4
4
  "description": "A comprehensive library for encoding/decoding karaoke files (.emk, .kar, MIDI) with Next.js support. Convert EMK to KAR, read/write karaoke files, full browser and server support.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -15,6 +15,10 @@
15
15
  "./client": {
16
16
  "types": "./dist/client.d.ts",
17
17
  "default": "./dist/client.js"
18
+ },
19
+ "./dist/client": {
20
+ "types": "./dist/client.d.ts",
21
+ "default": "./dist/client.js"
18
22
  }
19
23
  },
20
24
  "scripts": {