fit-file-parser 5.2.1 → 6.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.
- package/CHANGELOG.md +35 -191
- package/PROFILE.md +43 -0
- package/README.md +126 -82
- package/dist/binary.d.ts +2 -0
- package/dist/binary.js +23 -6
- package/dist/cjs/binary.d.ts +2 -0
- package/dist/cjs/binary.js +23 -6
- package/dist/cjs/fit-parser.d.ts +5 -0
- package/dist/cjs/fit-parser.js +42 -4
- package/dist/cjs/fit.d.ts +0 -6
- package/dist/cjs/fit.js +4 -114
- package/dist/cjs/fit_types.d.ts +2 -1
- package/dist/cjs/profile-lookup.d.ts +19 -0
- package/dist/cjs/profile-lookup.js +150 -0
- package/dist/cjs/profile.d.ts +9 -0
- package/dist/{garmin_profile.generated.js → cjs/profile.js} +287 -8
- package/dist/cjs/raw-message-reader.d.ts +60 -0
- package/dist/cjs/raw-message-reader.js +377 -0
- package/dist/cjs/type_generator.js +1 -0
- package/dist/fit-parser.d.ts +5 -0
- package/dist/fit-parser.js +27 -3
- package/dist/fit.d.ts +0 -6
- package/dist/fit.js +3 -113
- package/dist/fit_types.d.ts +2 -1
- package/dist/profile-lookup.d.ts +19 -0
- package/dist/profile-lookup.js +140 -0
- package/dist/profile.d.ts +9 -0
- package/dist/{cjs/garmin_profile.generated.js → profile.js} +284 -11
- package/dist/raw-message-reader.d.ts +60 -0
- package/dist/raw-message-reader.js +368 -0
- package/dist/type_generator.js +1 -0
- package/package.json +38 -9
- package/dist/cjs/garmin_profile.generated.d.ts +0 -9
- package/dist/garmin_profile.generated.d.ts +0 -9
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Resolves a FIT manufacturer identifier to its canonical profile name. */
|
|
2
|
+
export declare function getFitManufacturerName(value: number | string | null | undefined): string | null;
|
|
3
|
+
/** Resolves a Garmin product identifier to its canonical profile name. */
|
|
4
|
+
export declare function getFitGarminProductName(value: number | string | null | undefined): string | null;
|
|
5
|
+
/** Resolves a FIT sport identifier to its canonical profile name. */
|
|
6
|
+
export declare function getFitSportName(value: number | string | null | undefined): string | null;
|
|
7
|
+
/** Resolves a FIT sub-sport identifier to its canonical profile name. */
|
|
8
|
+
export declare function getFitSubSportName(value: number | string | null | undefined): string | null;
|
|
9
|
+
/** Resolves a FIT sport name to its numeric profile identifier. */
|
|
10
|
+
export declare function getFitSportId(value: string | null | undefined): number | null;
|
|
11
|
+
/** Resolves a FIT sub-sport name to its numeric profile identifier. */
|
|
12
|
+
export declare function getFitSubSportId(value: string | null | undefined): number | null;
|
|
13
|
+
/** Resolves a FIT course-point name to its numeric profile identifier. */
|
|
14
|
+
export declare function getFitCoursePointId(value: string | null | undefined): number | null;
|
|
15
|
+
/**
|
|
16
|
+
* Resolves a Garmin product identifier to a human-readable device name.
|
|
17
|
+
* This does not alter parsed `product` or `product_name` fields.
|
|
18
|
+
*/
|
|
19
|
+
export declare function getFitGarminProductDisplayName(value: number | string | null | undefined): string | null;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { PROFILE_TYPES } from './profile.js';
|
|
2
|
+
function normalizeProfileName(value) {
|
|
3
|
+
return value.trim().toLowerCase().replace(/[\s_-]/g, '');
|
|
4
|
+
}
|
|
5
|
+
const FIT_PROFILE_MANUFACTURERS = PROFILE_TYPES.manufacturer;
|
|
6
|
+
const FIT_PROFILE_GARMIN_PRODUCTS = PROFILE_TYPES.garmin_product;
|
|
7
|
+
const FIT_PROFILE_SPORTS = PROFILE_TYPES.sport;
|
|
8
|
+
const FIT_PROFILE_SUB_SPORTS = PROFILE_TYPES.sub_sport;
|
|
9
|
+
const FIT_PROFILE_COURSE_POINTS = PROFILE_TYPES.course_point;
|
|
10
|
+
function createProfileIdMap(mapping) {
|
|
11
|
+
return new Map(Object.entries(mapping)
|
|
12
|
+
.filter((entry) => typeof entry[1] === 'string')
|
|
13
|
+
.map(([id, name]) => [normalizeProfileName(name), Number(id)]));
|
|
14
|
+
}
|
|
15
|
+
const FIT_PROFILE_SPORT_IDS = createProfileIdMap(FIT_PROFILE_SPORTS);
|
|
16
|
+
const FIT_PROFILE_SUB_SPORT_IDS = createProfileIdMap(FIT_PROFILE_SUB_SPORTS);
|
|
17
|
+
const FIT_PROFILE_COURSE_POINT_IDS = createProfileIdMap(FIT_PROFILE_COURSE_POINTS);
|
|
18
|
+
function getProfileName(mapping, value) {
|
|
19
|
+
if (value === null || value === undefined) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
if (typeof value !== 'number' && typeof value !== 'string') {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const normalizedValue = typeof value === 'string' ? value.trim() : value;
|
|
26
|
+
if (normalizedValue === '' || (typeof normalizedValue === 'string' && !/^\d+$/.test(normalizedValue))) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const id = Number(normalizedValue);
|
|
30
|
+
if (!Number.isSafeInteger(id) || id < 0) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const name = mapping[id];
|
|
34
|
+
return typeof name === 'string' ? name : null;
|
|
35
|
+
}
|
|
36
|
+
function getProfileId(mapping, value) {
|
|
37
|
+
var _a;
|
|
38
|
+
if (typeof value !== 'string') {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
const name = normalizeProfileName(value);
|
|
42
|
+
if (name === '') {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
return (_a = mapping.get(name)) !== null && _a !== void 0 ? _a : null;
|
|
46
|
+
}
|
|
47
|
+
/** Resolves a FIT manufacturer identifier to its canonical profile name. */
|
|
48
|
+
export function getFitManufacturerName(value) {
|
|
49
|
+
return getProfileName(FIT_PROFILE_MANUFACTURERS, value);
|
|
50
|
+
}
|
|
51
|
+
/** Resolves a Garmin product identifier to its canonical profile name. */
|
|
52
|
+
export function getFitGarminProductName(value) {
|
|
53
|
+
return getProfileName(FIT_PROFILE_GARMIN_PRODUCTS, value);
|
|
54
|
+
}
|
|
55
|
+
/** Resolves a FIT sport identifier to its canonical profile name. */
|
|
56
|
+
export function getFitSportName(value) {
|
|
57
|
+
return getProfileName(FIT_PROFILE_SPORTS, value);
|
|
58
|
+
}
|
|
59
|
+
/** Resolves a FIT sub-sport identifier to its canonical profile name. */
|
|
60
|
+
export function getFitSubSportName(value) {
|
|
61
|
+
return getProfileName(FIT_PROFILE_SUB_SPORTS, value);
|
|
62
|
+
}
|
|
63
|
+
/** Resolves a FIT sport name to its numeric profile identifier. */
|
|
64
|
+
export function getFitSportId(value) {
|
|
65
|
+
return getProfileId(FIT_PROFILE_SPORT_IDS, value);
|
|
66
|
+
}
|
|
67
|
+
/** Resolves a FIT sub-sport name to its numeric profile identifier. */
|
|
68
|
+
export function getFitSubSportId(value) {
|
|
69
|
+
return getProfileId(FIT_PROFILE_SUB_SPORT_IDS, value);
|
|
70
|
+
}
|
|
71
|
+
/** Resolves a FIT course-point name to its numeric profile identifier. */
|
|
72
|
+
export function getFitCoursePointId(value) {
|
|
73
|
+
return getProfileId(FIT_PROFILE_COURSE_POINT_IDS, value);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Resolves a Garmin product identifier to a human-readable device name.
|
|
77
|
+
* This does not alter parsed `product` or `product_name` fields.
|
|
78
|
+
*/
|
|
79
|
+
export function getFitGarminProductDisplayName(value) {
|
|
80
|
+
const name = getFitGarminProductName(value);
|
|
81
|
+
if (!name) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
// Preserve the established display spelling for the optical heart-rate product.
|
|
85
|
+
const displaySource = name === 'o_hr' ? 'o_h_r' : name;
|
|
86
|
+
const formatted = displaySource
|
|
87
|
+
.replace(/^fr(\d+)/i, 'Forerunner $1')
|
|
88
|
+
.replace(/^fenix(\d+)/i, 'Fenix $1')
|
|
89
|
+
.replace(/^edge(\d+)/i, 'Edge $1')
|
|
90
|
+
.replace(/^vivoactive/i, 'VivoActive')
|
|
91
|
+
.replace(/^vivosmart/i, 'VivoSmart')
|
|
92
|
+
.replace(/^vivofit/i, 'VivoFit')
|
|
93
|
+
.replace(/^vivomove/i, 'VivoMove')
|
|
94
|
+
.replace(/^vivosport/i, 'VivoSport')
|
|
95
|
+
.replace(/^approach([A-Z\d])/i, 'Approach $1')
|
|
96
|
+
.replace(/^marq([A-Z])/i, 'Marq $1')
|
|
97
|
+
.replace(/^hrm/i, 'HRM ')
|
|
98
|
+
.replace(/_/g, ' ')
|
|
99
|
+
.replace(/([a-z])([A-Z0-9])/g, '$1 $2')
|
|
100
|
+
.replace(/(\d)([a-z])/gi, '$1 $2');
|
|
101
|
+
return formatted
|
|
102
|
+
.split(' ')
|
|
103
|
+
.map((word) => {
|
|
104
|
+
const lower = word.toLowerCase();
|
|
105
|
+
if (lower === 'apac')
|
|
106
|
+
return 'APAC';
|
|
107
|
+
if (lower === 'xt')
|
|
108
|
+
return 'XT';
|
|
109
|
+
if (lower === 'lte')
|
|
110
|
+
return 'LTE';
|
|
111
|
+
if (lower === 'hr')
|
|
112
|
+
return 'HR';
|
|
113
|
+
if (lower === 'gps')
|
|
114
|
+
return 'GPS';
|
|
115
|
+
if (lower === 'mtb')
|
|
116
|
+
return 'MTB';
|
|
117
|
+
if (lower === 'ii')
|
|
118
|
+
return 'II';
|
|
119
|
+
if (lower === 'iii')
|
|
120
|
+
return 'III';
|
|
121
|
+
if (lower === 'm' && name.toLowerCase().includes('645m'))
|
|
122
|
+
return 'Music';
|
|
123
|
+
if (lower === 'jpn')
|
|
124
|
+
return 'Japan';
|
|
125
|
+
if (lower === 'chn')
|
|
126
|
+
return 'China';
|
|
127
|
+
if (lower === 'twn')
|
|
128
|
+
return 'Taiwan';
|
|
129
|
+
if (lower === 'kor')
|
|
130
|
+
return 'Korea';
|
|
131
|
+
if (lower === 'rus')
|
|
132
|
+
return 'Russia';
|
|
133
|
+
if (lower === 'sea')
|
|
134
|
+
return 'SEA';
|
|
135
|
+
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
136
|
+
})
|
|
137
|
+
.join(' ')
|
|
138
|
+
.replace(/Vivo Active/g, 'VivoActive')
|
|
139
|
+
.trim();
|
|
140
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Message } from './fit.js';
|
|
2
|
+
/**
|
|
3
|
+
* Static, community-maintained FIT interoperability profile.
|
|
4
|
+
*
|
|
5
|
+
* This table is ordinary project source maintained under the repository's MIT
|
|
6
|
+
* license. See PROFILE.md for the maintenance and verification policy.
|
|
7
|
+
*/
|
|
8
|
+
export declare const PROFILE_MESSAGES: Record<number, Message>;
|
|
9
|
+
export declare const PROFILE_TYPES: Record<string, Record<number, string | number>>;
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
type: 'Release',
|
|
9
|
-
};
|
|
10
|
-
exports.GARMIN_MESSAGES = {
|
|
1
|
+
/**
|
|
2
|
+
* Static, community-maintained FIT interoperability profile.
|
|
3
|
+
*
|
|
4
|
+
* This table is ordinary project source maintained under the repository's MIT
|
|
5
|
+
* license. See PROFILE.md for the maintenance and verification policy.
|
|
6
|
+
*/
|
|
7
|
+
export const PROFILE_MESSAGES = {
|
|
11
8
|
0: {
|
|
12
9
|
0: {
|
|
13
10
|
field: 'type',
|
|
@@ -2589,6 +2586,13 @@ exports.GARMIN_MESSAGES = {
|
|
|
2589
2586
|
offset: 0,
|
|
2590
2587
|
units: 'Breaths/min',
|
|
2591
2588
|
},
|
|
2589
|
+
178: {
|
|
2590
|
+
field: 'est_sweat_loss',
|
|
2591
|
+
type: 'uint16',
|
|
2592
|
+
scale: 1,
|
|
2593
|
+
offset: 0,
|
|
2594
|
+
units: 'ml',
|
|
2595
|
+
},
|
|
2592
2596
|
180: {
|
|
2593
2597
|
field: 'enhanced_min_respiration_rate',
|
|
2594
2598
|
type: 'uint16',
|
|
@@ -2643,6 +2647,13 @@ exports.GARMIN_MESSAGES = {
|
|
|
2643
2647
|
offset: 0,
|
|
2644
2648
|
units: 'Flow',
|
|
2645
2649
|
},
|
|
2650
|
+
188: {
|
|
2651
|
+
field: 'primary_benefit',
|
|
2652
|
+
type: 'uint8',
|
|
2653
|
+
scale: 1,
|
|
2654
|
+
offset: 0,
|
|
2655
|
+
units: '',
|
|
2656
|
+
},
|
|
2646
2657
|
192: {
|
|
2647
2658
|
field: 'workout_feel',
|
|
2648
2659
|
type: 'uint8',
|
|
@@ -2724,6 +2735,27 @@ exports.GARMIN_MESSAGES = {
|
|
|
2724
2735
|
offset: 0,
|
|
2725
2736
|
units: 'm',
|
|
2726
2737
|
},
|
|
2738
|
+
205: {
|
|
2739
|
+
field: 'beginning_potential_stamina',
|
|
2740
|
+
type: 'uint8',
|
|
2741
|
+
scale: 1,
|
|
2742
|
+
offset: 0,
|
|
2743
|
+
units: 'percent',
|
|
2744
|
+
},
|
|
2745
|
+
206: {
|
|
2746
|
+
field: 'ending_potential_stamina',
|
|
2747
|
+
type: 'uint8',
|
|
2748
|
+
scale: 1,
|
|
2749
|
+
offset: 0,
|
|
2750
|
+
units: 'percent',
|
|
2751
|
+
},
|
|
2752
|
+
207: {
|
|
2753
|
+
field: 'min_stamina',
|
|
2754
|
+
type: 'uint8',
|
|
2755
|
+
scale: 1,
|
|
2756
|
+
offset: 0,
|
|
2757
|
+
units: 'percent',
|
|
2758
|
+
},
|
|
2727
2759
|
208: {
|
|
2728
2760
|
field: 'avg_core_temperature',
|
|
2729
2761
|
type: 'uint16',
|
|
@@ -4422,6 +4454,13 @@ exports.GARMIN_MESSAGES = {
|
|
|
4422
4454
|
offset: 0,
|
|
4423
4455
|
units: 'm',
|
|
4424
4456
|
},
|
|
4457
|
+
90: {
|
|
4458
|
+
field: 'garmin_performance_condition',
|
|
4459
|
+
type: 'sint8',
|
|
4460
|
+
scale: 1,
|
|
4461
|
+
offset: 0,
|
|
4462
|
+
units: '',
|
|
4463
|
+
},
|
|
4425
4464
|
91: {
|
|
4426
4465
|
field: 'absolute_pressure',
|
|
4427
4466
|
type: 'uint32',
|
|
@@ -4629,6 +4668,20 @@ exports.GARMIN_MESSAGES = {
|
|
|
4629
4668
|
offset: 0,
|
|
4630
4669
|
units: 'percent',
|
|
4631
4670
|
},
|
|
4671
|
+
137: {
|
|
4672
|
+
field: 'potential_stamina',
|
|
4673
|
+
type: 'uint8',
|
|
4674
|
+
scale: 1,
|
|
4675
|
+
offset: 0,
|
|
4676
|
+
units: 'percent',
|
|
4677
|
+
},
|
|
4678
|
+
138: {
|
|
4679
|
+
field: 'stamina',
|
|
4680
|
+
type: 'uint8',
|
|
4681
|
+
scale: 1,
|
|
4682
|
+
offset: 0,
|
|
4683
|
+
units: 'percent',
|
|
4684
|
+
},
|
|
4632
4685
|
139: {
|
|
4633
4686
|
field: 'core_temperature',
|
|
4634
4687
|
type: 'uint16',
|
|
@@ -4959,6 +5012,13 @@ exports.GARMIN_MESSAGES = {
|
|
|
4959
5012
|
offset: 0,
|
|
4960
5013
|
units: '',
|
|
4961
5014
|
},
|
|
5015
|
+
24: {
|
|
5016
|
+
field: 'ant_id',
|
|
5017
|
+
type: 'uint32z',
|
|
5018
|
+
scale: 1,
|
|
5019
|
+
offset: 0,
|
|
5020
|
+
units: '',
|
|
5021
|
+
},
|
|
4962
5022
|
25: {
|
|
4963
5023
|
field: 'source_type',
|
|
4964
5024
|
type: 'source_type',
|
|
@@ -6401,6 +6461,107 @@ exports.GARMIN_MESSAGES = {
|
|
|
6401
6461
|
},
|
|
6402
6462
|
name: 'hrv',
|
|
6403
6463
|
},
|
|
6464
|
+
79: {
|
|
6465
|
+
0: {
|
|
6466
|
+
field: 'vo2_max',
|
|
6467
|
+
type: 'uint16',
|
|
6468
|
+
scale: 292.57142857142856,
|
|
6469
|
+
offset: 0,
|
|
6470
|
+
units: 'ml/kg/min',
|
|
6471
|
+
},
|
|
6472
|
+
1: {
|
|
6473
|
+
field: 'age',
|
|
6474
|
+
type: 'uint8',
|
|
6475
|
+
scale: 1,
|
|
6476
|
+
offset: 0,
|
|
6477
|
+
units: 'years',
|
|
6478
|
+
},
|
|
6479
|
+
2: {
|
|
6480
|
+
field: 'height',
|
|
6481
|
+
type: 'uint8',
|
|
6482
|
+
scale: 100,
|
|
6483
|
+
offset: 0,
|
|
6484
|
+
units: 'm',
|
|
6485
|
+
},
|
|
6486
|
+
3: {
|
|
6487
|
+
field: 'weight',
|
|
6488
|
+
type: 'uint16',
|
|
6489
|
+
scale: 10,
|
|
6490
|
+
offset: 0,
|
|
6491
|
+
units: 'kg',
|
|
6492
|
+
},
|
|
6493
|
+
4: {
|
|
6494
|
+
field: 'gender',
|
|
6495
|
+
type: 'gender',
|
|
6496
|
+
scale: 1,
|
|
6497
|
+
offset: 0,
|
|
6498
|
+
units: '',
|
|
6499
|
+
},
|
|
6500
|
+
6: {
|
|
6501
|
+
field: 'max_heart_rate',
|
|
6502
|
+
type: 'uint8',
|
|
6503
|
+
scale: 1,
|
|
6504
|
+
offset: 0,
|
|
6505
|
+
units: 'bpm',
|
|
6506
|
+
},
|
|
6507
|
+
8: {
|
|
6508
|
+
field: 'remaining_recovery_time',
|
|
6509
|
+
type: 'uint16',
|
|
6510
|
+
scale: 1,
|
|
6511
|
+
offset: 0,
|
|
6512
|
+
units: '',
|
|
6513
|
+
},
|
|
6514
|
+
11: {
|
|
6515
|
+
field: 'lthr',
|
|
6516
|
+
type: 'uint16',
|
|
6517
|
+
scale: 1,
|
|
6518
|
+
offset: 0,
|
|
6519
|
+
units: 'bpm',
|
|
6520
|
+
},
|
|
6521
|
+
12: {
|
|
6522
|
+
field: 'ltpower',
|
|
6523
|
+
type: 'uint16',
|
|
6524
|
+
scale: 1,
|
|
6525
|
+
offset: 0,
|
|
6526
|
+
units: 'watts',
|
|
6527
|
+
},
|
|
6528
|
+
13: {
|
|
6529
|
+
field: 'ltspeed',
|
|
6530
|
+
type: 'uint16',
|
|
6531
|
+
scale: 1000,
|
|
6532
|
+
offset: 0,
|
|
6533
|
+
units: 'm/s',
|
|
6534
|
+
},
|
|
6535
|
+
16: {
|
|
6536
|
+
field: 'start_of_activity',
|
|
6537
|
+
type: 'date_time',
|
|
6538
|
+
scale: 1,
|
|
6539
|
+
offset: 0,
|
|
6540
|
+
units: '',
|
|
6541
|
+
},
|
|
6542
|
+
19: {
|
|
6543
|
+
field: 'first_vo2_max',
|
|
6544
|
+
type: 'uint32',
|
|
6545
|
+
scale: 18724.571428571428,
|
|
6546
|
+
offset: 0,
|
|
6547
|
+
units: 'ml/kg/min',
|
|
6548
|
+
},
|
|
6549
|
+
35: {
|
|
6550
|
+
field: 'end_of_previous_activity',
|
|
6551
|
+
type: 'date_time',
|
|
6552
|
+
scale: 1,
|
|
6553
|
+
offset: 0,
|
|
6554
|
+
units: '',
|
|
6555
|
+
},
|
|
6556
|
+
253: {
|
|
6557
|
+
field: 'timestamp',
|
|
6558
|
+
type: 'date_time',
|
|
6559
|
+
scale: 1,
|
|
6560
|
+
offset: 0,
|
|
6561
|
+
units: '',
|
|
6562
|
+
},
|
|
6563
|
+
name: 'user_metrics',
|
|
6564
|
+
},
|
|
6404
6565
|
80: {
|
|
6405
6566
|
0: {
|
|
6406
6567
|
field: 'fractional_timestamp',
|
|
@@ -7256,6 +7417,93 @@ exports.GARMIN_MESSAGES = {
|
|
|
7256
7417
|
},
|
|
7257
7418
|
name: 'hr',
|
|
7258
7419
|
},
|
|
7420
|
+
140: {
|
|
7421
|
+
1: {
|
|
7422
|
+
field: 'new_max_heart_rate',
|
|
7423
|
+
type: 'uint8',
|
|
7424
|
+
scale: 1,
|
|
7425
|
+
offset: 0,
|
|
7426
|
+
units: 'bpm',
|
|
7427
|
+
},
|
|
7428
|
+
4: {
|
|
7429
|
+
field: 'aerobic_training_effect',
|
|
7430
|
+
type: 'uint8',
|
|
7431
|
+
scale: 10,
|
|
7432
|
+
offset: 0,
|
|
7433
|
+
units: '',
|
|
7434
|
+
},
|
|
7435
|
+
7: {
|
|
7436
|
+
field: 'vo2_max',
|
|
7437
|
+
type: 'uint32',
|
|
7438
|
+
scale: 18724.571428571428,
|
|
7439
|
+
offset: 0,
|
|
7440
|
+
units: 'ml/kg/min',
|
|
7441
|
+
},
|
|
7442
|
+
9: {
|
|
7443
|
+
field: 'recovery_time',
|
|
7444
|
+
type: 'uint16',
|
|
7445
|
+
scale: 1,
|
|
7446
|
+
offset: 0,
|
|
7447
|
+
units: 'min',
|
|
7448
|
+
},
|
|
7449
|
+
11: {
|
|
7450
|
+
field: 'sport',
|
|
7451
|
+
type: 'sport',
|
|
7452
|
+
scale: 1,
|
|
7453
|
+
offset: 0,
|
|
7454
|
+
units: '',
|
|
7455
|
+
},
|
|
7456
|
+
20: {
|
|
7457
|
+
field: 'anaerobic_training_effect',
|
|
7458
|
+
type: 'uint8',
|
|
7459
|
+
scale: 10,
|
|
7460
|
+
offset: 0,
|
|
7461
|
+
units: '',
|
|
7462
|
+
},
|
|
7463
|
+
29: {
|
|
7464
|
+
field: 'first_vo2_max',
|
|
7465
|
+
type: 'uint32',
|
|
7466
|
+
scale: 18724.571428571428,
|
|
7467
|
+
offset: 0,
|
|
7468
|
+
units: 'ml/kg/min',
|
|
7469
|
+
},
|
|
7470
|
+
41: {
|
|
7471
|
+
field: 'primary_benefit',
|
|
7472
|
+
type: 'uint8',
|
|
7473
|
+
scale: 1,
|
|
7474
|
+
offset: 0,
|
|
7475
|
+
units: '',
|
|
7476
|
+
},
|
|
7477
|
+
60: {
|
|
7478
|
+
field: 'total_ascent',
|
|
7479
|
+
type: 'uint16',
|
|
7480
|
+
scale: 1,
|
|
7481
|
+
offset: 0,
|
|
7482
|
+
units: 'm',
|
|
7483
|
+
},
|
|
7484
|
+
61: {
|
|
7485
|
+
field: 'total_descent',
|
|
7486
|
+
type: 'uint16',
|
|
7487
|
+
scale: 1,
|
|
7488
|
+
offset: 0,
|
|
7489
|
+
units: 'm',
|
|
7490
|
+
},
|
|
7491
|
+
62: {
|
|
7492
|
+
field: 'avg_power',
|
|
7493
|
+
type: 'uint16',
|
|
7494
|
+
scale: 1,
|
|
7495
|
+
offset: 0,
|
|
7496
|
+
units: 'watts',
|
|
7497
|
+
},
|
|
7498
|
+
63: {
|
|
7499
|
+
field: 'avg_heart_rate',
|
|
7500
|
+
type: 'uint8',
|
|
7501
|
+
scale: 1,
|
|
7502
|
+
offset: 0,
|
|
7503
|
+
units: 'bpm',
|
|
7504
|
+
},
|
|
7505
|
+
name: 'activity_metrics',
|
|
7506
|
+
},
|
|
7259
7507
|
142: {
|
|
7260
7508
|
0: {
|
|
7261
7509
|
field: 'event',
|
|
@@ -11790,6 +12038,27 @@ exports.GARMIN_MESSAGES = {
|
|
|
11790
12038
|
offset: 0,
|
|
11791
12039
|
units: 's',
|
|
11792
12040
|
},
|
|
12041
|
+
107: {
|
|
12042
|
+
field: 'beginning_potential_stamina',
|
|
12043
|
+
type: 'uint8',
|
|
12044
|
+
scale: 1,
|
|
12045
|
+
offset: 0,
|
|
12046
|
+
units: 'percent',
|
|
12047
|
+
},
|
|
12048
|
+
108: {
|
|
12049
|
+
field: 'ending_potential_stamina',
|
|
12050
|
+
type: 'uint8',
|
|
12051
|
+
scale: 1,
|
|
12052
|
+
offset: 0,
|
|
12053
|
+
units: 'percent',
|
|
12054
|
+
},
|
|
12055
|
+
109: {
|
|
12056
|
+
field: 'min_stamina',
|
|
12057
|
+
type: 'uint8',
|
|
12058
|
+
scale: 1,
|
|
12059
|
+
offset: 0,
|
|
12060
|
+
units: 'percent',
|
|
12061
|
+
},
|
|
11793
12062
|
110: {
|
|
11794
12063
|
field: 'total_moving_time',
|
|
11795
12064
|
type: 'uint32',
|
|
@@ -13035,7 +13304,7 @@ exports.GARMIN_MESSAGES = {
|
|
|
13035
13304
|
name: 'sleep_disruption_overnight_severity',
|
|
13036
13305
|
},
|
|
13037
13306
|
};
|
|
13038
|
-
|
|
13307
|
+
export const PROFILE_TYPES = {
|
|
13039
13308
|
activity: {
|
|
13040
13309
|
0: 'manual',
|
|
13041
13310
|
1: 'auto_multi_sport',
|
|
@@ -15765,6 +16034,7 @@ exports.GARMIN_TYPES = {
|
|
|
15765
16034
|
55: 'monitoring',
|
|
15766
16035
|
72: 'training_file',
|
|
15767
16036
|
78: 'hrv',
|
|
16037
|
+
79: 'user_metrics',
|
|
15768
16038
|
80: 'ant_rx',
|
|
15769
16039
|
81: 'ant_tx',
|
|
15770
16040
|
82: 'ant_channel_id',
|
|
@@ -15777,6 +16047,7 @@ exports.GARMIN_TYPES = {
|
|
|
15777
16047
|
129: 'weather_alert',
|
|
15778
16048
|
131: 'cadence_zone',
|
|
15779
16049
|
132: 'hr',
|
|
16050
|
+
140: 'activity_metrics',
|
|
15780
16051
|
142: 'segment_lap',
|
|
15781
16052
|
145: 'memo_glob',
|
|
15782
16053
|
148: 'segment_id',
|
|
@@ -17205,6 +17476,8 @@ exports.GARMIN_TYPES = {
|
|
|
17205
17476
|
125: 'rally',
|
|
17206
17477
|
126: 'pool_triathlon',
|
|
17207
17478
|
127: 'e_bike_enduro',
|
|
17479
|
+
153: 'mountain_enduro',
|
|
17480
|
+
154: 'mountain_downhill',
|
|
17208
17481
|
254: 'all',
|
|
17209
17482
|
},
|
|
17210
17483
|
supported_exd_screen_layouts: {
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export type FitMessageReaderErrorCode = 'invalid_input' | 'input_limit' | 'invalid_header' | 'invalid_crc' | 'invalid_structure';
|
|
2
|
+
export type FitMessageReaderIssueCode = 'invalid_timestamp';
|
|
3
|
+
export interface FitRawField {
|
|
4
|
+
fieldNumber: number;
|
|
5
|
+
size: number;
|
|
6
|
+
baseType: number;
|
|
7
|
+
bytes: Uint8Array;
|
|
8
|
+
}
|
|
9
|
+
export interface FitRawDeveloperField {
|
|
10
|
+
fieldNumber: number;
|
|
11
|
+
size: number;
|
|
12
|
+
developerDataIndex: number;
|
|
13
|
+
bytes: Uint8Array;
|
|
14
|
+
}
|
|
15
|
+
export interface FitRawMessage {
|
|
16
|
+
globalMessageNumber: number;
|
|
17
|
+
messageIndex: number;
|
|
18
|
+
littleEndian: boolean;
|
|
19
|
+
/** Native FIT timestamp in seconds since the FIT epoch, when available. */
|
|
20
|
+
timestamp?: number;
|
|
21
|
+
/** Reconstructed native timestamp when the record used a compressed header. */
|
|
22
|
+
compressedTimestamp?: number;
|
|
23
|
+
fields: FitRawField[];
|
|
24
|
+
developerFields: FitRawDeveloperField[];
|
|
25
|
+
}
|
|
26
|
+
export interface FitMessageReaderIssue {
|
|
27
|
+
code: FitMessageReaderIssueCode;
|
|
28
|
+
globalMessageNumber: number;
|
|
29
|
+
messageIndex: number;
|
|
30
|
+
}
|
|
31
|
+
export interface FitMessageReaderResult {
|
|
32
|
+
protocolVersion: number;
|
|
33
|
+
profileVersion: number;
|
|
34
|
+
messages: FitRawMessage[];
|
|
35
|
+
issues: FitMessageReaderIssue[];
|
|
36
|
+
}
|
|
37
|
+
export interface FitMessageReaderOptions {
|
|
38
|
+
/** Retain only these global message numbers. Omit to retain every message. */
|
|
39
|
+
messageNumbers?: readonly number[];
|
|
40
|
+
/** Reject larger inputs before allocating retained message data. */
|
|
41
|
+
maxInputBytes?: number;
|
|
42
|
+
}
|
|
43
|
+
/** Error thrown when the strict raw-message reader rejects a FIT input. */
|
|
44
|
+
export declare class FitMessageReaderError extends Error {
|
|
45
|
+
readonly code: FitMessageReaderErrorCode;
|
|
46
|
+
constructor(code: FitMessageReaderErrorCode);
|
|
47
|
+
}
|
|
48
|
+
/** Returns the five-bit FIT base-type identifier, or null for reserved/unknown values. */
|
|
49
|
+
export declare function getFitBaseTypeId(baseType: number): number | null;
|
|
50
|
+
/** Reads an unsigned one-, two-, or four-byte raw FIT field. */
|
|
51
|
+
export declare function readFitUnsignedField(field: FitRawField | undefined, expectedBaseType: number, size: 1 | 2 | 4, littleEndian: boolean): number | undefined;
|
|
52
|
+
/** Reads UTF-8 bytes, removes trailing NUL padding, and preserves interior NUL separators. */
|
|
53
|
+
export declare function readFitStringField(field: FitRawField | undefined): string | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* Strictly validates a FIT file and retains raw fields for selected messages.
|
|
56
|
+
* This entry point does not load the semantic FIT profile or format field values.
|
|
57
|
+
*/
|
|
58
|
+
export declare function readFitMessages(input: ArrayBuffer | Uint8Array, options?: FitMessageReaderOptions): FitMessageReaderResult;
|
|
59
|
+
/** Converts a native FIT timestamp to a JavaScript epoch millisecond value. */
|
|
60
|
+
export declare function fitTimestampToUnixMilliseconds(timestamp: number): number;
|