fit-file-parser 3.0.0 → 3.0.2
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/dist/cjs/fit-parser.js +13 -1
- package/dist/cjs/fit.js +359 -0
- package/dist/cjs/fit_types.d.ts +54 -2
- package/dist/cjs/type_generator.js +4 -0
- package/dist/fit-parser.js +13 -1
- package/dist/fit.js +359 -0
- package/dist/fit_types.d.ts +54 -2
- package/dist/type_generator.js +4 -0
- package/package.json +9 -2
- package/.agent/rules/fit-parser-dev.md +0 -35
- package/.agent/skills/add-fit-message/SKILL.md +0 -29
- package/.agent/workflows/fit-workflows.md +0 -28
- package/.editorconfig +0 -3
- package/.github/workflows/ci.yml +0 -40
- package/.vscode/extensions.json +0 -6
- package/.vscode/launch.json +0 -27
- package/.vscode/tasks.json +0 -34
- package/INVESTIGATING.md +0 -50
- package/check_ids.js +0 -24
- package/check_jump_fields.js +0 -46
- package/codegen/codegen.ts +0 -9
- package/eslint.config.js +0 -20
- package/find_field.js +0 -23
- package/find_field_esm.js +0 -28
- package/inspect_parser.ts +0 -34
- package/output.txt +0 -154
- package/scan_jumps.js +0 -29
- package/scripts/deep_probe.js +0 -74
- package/scripts/inspect_fit.js +0 -69
- package/tsconfig.cjs.json +0 -8
- package/tsconfig.json +0 -16
- package/vitest.config.js +0 -8
package/dist/fit.js
CHANGED
|
@@ -1773,6 +1773,27 @@ export const FIT = {
|
|
|
1773
1773
|
offset: 0,
|
|
1774
1774
|
units: 'kcal',
|
|
1775
1775
|
},
|
|
1776
|
+
205: {
|
|
1777
|
+
field: 'beginning_potential_stamina',
|
|
1778
|
+
type: 'uint8',
|
|
1779
|
+
scale: 1,
|
|
1780
|
+
offset: 0,
|
|
1781
|
+
units: 'percent',
|
|
1782
|
+
},
|
|
1783
|
+
206: {
|
|
1784
|
+
field: 'ending_potential_stamina',
|
|
1785
|
+
type: 'uint8',
|
|
1786
|
+
scale: 1,
|
|
1787
|
+
offset: 0,
|
|
1788
|
+
units: 'percent',
|
|
1789
|
+
},
|
|
1790
|
+
207: {
|
|
1791
|
+
field: 'min_stamina',
|
|
1792
|
+
type: 'uint8',
|
|
1793
|
+
scale: 1,
|
|
1794
|
+
offset: 0,
|
|
1795
|
+
units: 'percent',
|
|
1796
|
+
},
|
|
1776
1797
|
214: {
|
|
1777
1798
|
field: 'avg_grit',
|
|
1778
1799
|
type: 'float32',
|
|
@@ -3001,6 +3022,292 @@ export const FIT = {
|
|
|
3001
3022
|
offset: 0,
|
|
3002
3023
|
units: 'percent',
|
|
3003
3024
|
},
|
|
3025
|
+
137: {
|
|
3026
|
+
field: 'potential_stamina',
|
|
3027
|
+
type: 'uint8',
|
|
3028
|
+
scale: 1,
|
|
3029
|
+
offset: 0,
|
|
3030
|
+
units: 'percent',
|
|
3031
|
+
},
|
|
3032
|
+
138: {
|
|
3033
|
+
field: 'stamina',
|
|
3034
|
+
type: 'uint8',
|
|
3035
|
+
scale: 1,
|
|
3036
|
+
offset: 0,
|
|
3037
|
+
units: 'percent',
|
|
3038
|
+
},
|
|
3039
|
+
},
|
|
3040
|
+
312: {
|
|
3041
|
+
name: 'split',
|
|
3042
|
+
254: {
|
|
3043
|
+
field: 'message_index',
|
|
3044
|
+
type: 'message_index',
|
|
3045
|
+
scale: null,
|
|
3046
|
+
offset: 0,
|
|
3047
|
+
units: '',
|
|
3048
|
+
},
|
|
3049
|
+
0: {
|
|
3050
|
+
field: 'split_type',
|
|
3051
|
+
type: 'split_type',
|
|
3052
|
+
scale: null,
|
|
3053
|
+
offset: 0,
|
|
3054
|
+
units: '',
|
|
3055
|
+
},
|
|
3056
|
+
1: {
|
|
3057
|
+
field: 'total_elapsed_time',
|
|
3058
|
+
type: 'uint32',
|
|
3059
|
+
scale: 1000,
|
|
3060
|
+
offset: 0,
|
|
3061
|
+
units: 's',
|
|
3062
|
+
},
|
|
3063
|
+
2: {
|
|
3064
|
+
field: 'total_timer_time',
|
|
3065
|
+
type: 'uint32',
|
|
3066
|
+
scale: 1000,
|
|
3067
|
+
offset: 0,
|
|
3068
|
+
units: 's',
|
|
3069
|
+
},
|
|
3070
|
+
3: {
|
|
3071
|
+
field: 'total_distance',
|
|
3072
|
+
type: 'uint32',
|
|
3073
|
+
scale: 100,
|
|
3074
|
+
offset: 0,
|
|
3075
|
+
units: 'm',
|
|
3076
|
+
},
|
|
3077
|
+
4: {
|
|
3078
|
+
field: 'avg_speed',
|
|
3079
|
+
type: 'uint32',
|
|
3080
|
+
scale: 1000,
|
|
3081
|
+
offset: 0,
|
|
3082
|
+
units: 'm/s',
|
|
3083
|
+
},
|
|
3084
|
+
9: {
|
|
3085
|
+
field: 'start_time',
|
|
3086
|
+
type: 'date_time',
|
|
3087
|
+
scale: null,
|
|
3088
|
+
offset: 0,
|
|
3089
|
+
units: '',
|
|
3090
|
+
},
|
|
3091
|
+
13: {
|
|
3092
|
+
field: 'total_ascent',
|
|
3093
|
+
type: 'uint16',
|
|
3094
|
+
scale: null,
|
|
3095
|
+
offset: 0,
|
|
3096
|
+
units: 'm',
|
|
3097
|
+
},
|
|
3098
|
+
14: {
|
|
3099
|
+
field: 'total_descent',
|
|
3100
|
+
type: 'uint16',
|
|
3101
|
+
scale: null,
|
|
3102
|
+
offset: 0,
|
|
3103
|
+
units: 'm',
|
|
3104
|
+
},
|
|
3105
|
+
21: {
|
|
3106
|
+
field: 'start_position_lat',
|
|
3107
|
+
type: 'sint32',
|
|
3108
|
+
scale: null,
|
|
3109
|
+
offset: 0,
|
|
3110
|
+
units: 'semicircles',
|
|
3111
|
+
},
|
|
3112
|
+
22: {
|
|
3113
|
+
field: 'start_position_long',
|
|
3114
|
+
type: 'sint32',
|
|
3115
|
+
scale: null,
|
|
3116
|
+
offset: 0,
|
|
3117
|
+
units: 'semicircles',
|
|
3118
|
+
},
|
|
3119
|
+
23: {
|
|
3120
|
+
field: 'end_position_lat',
|
|
3121
|
+
type: 'sint32',
|
|
3122
|
+
scale: null,
|
|
3123
|
+
offset: 0,
|
|
3124
|
+
units: 'semicircles',
|
|
3125
|
+
},
|
|
3126
|
+
24: {
|
|
3127
|
+
field: 'end_position_long',
|
|
3128
|
+
type: 'sint32',
|
|
3129
|
+
scale: null,
|
|
3130
|
+
offset: 0,
|
|
3131
|
+
units: 'semicircles',
|
|
3132
|
+
},
|
|
3133
|
+
25: {
|
|
3134
|
+
field: 'max_speed',
|
|
3135
|
+
type: 'uint32',
|
|
3136
|
+
scale: 1000,
|
|
3137
|
+
offset: 0,
|
|
3138
|
+
units: 'm/s',
|
|
3139
|
+
},
|
|
3140
|
+
26: {
|
|
3141
|
+
field: 'avg_vert_speed',
|
|
3142
|
+
type: 'sint32',
|
|
3143
|
+
scale: 1000,
|
|
3144
|
+
offset: 0,
|
|
3145
|
+
units: 'm/s',
|
|
3146
|
+
},
|
|
3147
|
+
27: {
|
|
3148
|
+
field: 'end_time',
|
|
3149
|
+
type: 'date_time',
|
|
3150
|
+
scale: null,
|
|
3151
|
+
offset: 0,
|
|
3152
|
+
units: '',
|
|
3153
|
+
},
|
|
3154
|
+
28: {
|
|
3155
|
+
field: 'total_calories',
|
|
3156
|
+
type: 'uint32',
|
|
3157
|
+
scale: null,
|
|
3158
|
+
offset: 0,
|
|
3159
|
+
units: 'kcal',
|
|
3160
|
+
},
|
|
3161
|
+
74: {
|
|
3162
|
+
field: 'start_elevation',
|
|
3163
|
+
type: 'uint32',
|
|
3164
|
+
scale: 5,
|
|
3165
|
+
offset: -500,
|
|
3166
|
+
units: 'm',
|
|
3167
|
+
},
|
|
3168
|
+
78: {
|
|
3169
|
+
field: 'active_time',
|
|
3170
|
+
type: 'uint32',
|
|
3171
|
+
scale: 1000,
|
|
3172
|
+
offset: 0,
|
|
3173
|
+
units: 's',
|
|
3174
|
+
},
|
|
3175
|
+
107: {
|
|
3176
|
+
field: 'beginning_potential_stamina',
|
|
3177
|
+
type: 'uint8',
|
|
3178
|
+
scale: 1,
|
|
3179
|
+
offset: 0,
|
|
3180
|
+
units: 'percent',
|
|
3181
|
+
},
|
|
3182
|
+
108: {
|
|
3183
|
+
field: 'ending_potential_stamina',
|
|
3184
|
+
type: 'uint8',
|
|
3185
|
+
scale: 1,
|
|
3186
|
+
offset: 0,
|
|
3187
|
+
units: 'percent',
|
|
3188
|
+
},
|
|
3189
|
+
109: {
|
|
3190
|
+
field: 'min_stamina',
|
|
3191
|
+
type: 'uint8',
|
|
3192
|
+
scale: 1,
|
|
3193
|
+
offset: 0,
|
|
3194
|
+
units: 'percent',
|
|
3195
|
+
},
|
|
3196
|
+
110: {
|
|
3197
|
+
field: 'total_moving_time',
|
|
3198
|
+
type: 'uint32',
|
|
3199
|
+
scale: 1000,
|
|
3200
|
+
offset: 0,
|
|
3201
|
+
units: 's',
|
|
3202
|
+
},
|
|
3203
|
+
},
|
|
3204
|
+
313: {
|
|
3205
|
+
name: 'split_summary',
|
|
3206
|
+
254: {
|
|
3207
|
+
field: 'message_index',
|
|
3208
|
+
type: 'message_index',
|
|
3209
|
+
scale: null,
|
|
3210
|
+
offset: 0,
|
|
3211
|
+
units: '',
|
|
3212
|
+
},
|
|
3213
|
+
0: {
|
|
3214
|
+
field: 'split_type',
|
|
3215
|
+
type: 'split_type',
|
|
3216
|
+
scale: null,
|
|
3217
|
+
offset: 0,
|
|
3218
|
+
units: '',
|
|
3219
|
+
},
|
|
3220
|
+
3: {
|
|
3221
|
+
field: 'num_splits',
|
|
3222
|
+
type: 'uint16',
|
|
3223
|
+
scale: null,
|
|
3224
|
+
offset: 0,
|
|
3225
|
+
units: '',
|
|
3226
|
+
},
|
|
3227
|
+
4: {
|
|
3228
|
+
field: 'total_timer_time',
|
|
3229
|
+
type: 'uint32',
|
|
3230
|
+
scale: 1000,
|
|
3231
|
+
offset: 0,
|
|
3232
|
+
units: 's',
|
|
3233
|
+
},
|
|
3234
|
+
5: {
|
|
3235
|
+
field: 'total_distance',
|
|
3236
|
+
type: 'uint32',
|
|
3237
|
+
scale: 100,
|
|
3238
|
+
offset: 0,
|
|
3239
|
+
units: 'm',
|
|
3240
|
+
},
|
|
3241
|
+
6: {
|
|
3242
|
+
field: 'avg_speed',
|
|
3243
|
+
type: 'uint32',
|
|
3244
|
+
scale: 1000,
|
|
3245
|
+
offset: 0,
|
|
3246
|
+
units: 'm/s',
|
|
3247
|
+
},
|
|
3248
|
+
7: {
|
|
3249
|
+
field: 'max_speed',
|
|
3250
|
+
type: 'uint32',
|
|
3251
|
+
scale: 1000,
|
|
3252
|
+
offset: 0,
|
|
3253
|
+
units: 'm/s',
|
|
3254
|
+
},
|
|
3255
|
+
8: {
|
|
3256
|
+
field: 'total_ascent',
|
|
3257
|
+
type: 'uint16',
|
|
3258
|
+
scale: null,
|
|
3259
|
+
offset: 0,
|
|
3260
|
+
units: 'm',
|
|
3261
|
+
},
|
|
3262
|
+
9: {
|
|
3263
|
+
field: 'total_descent',
|
|
3264
|
+
type: 'uint16',
|
|
3265
|
+
scale: null,
|
|
3266
|
+
offset: 0,
|
|
3267
|
+
units: 'm',
|
|
3268
|
+
},
|
|
3269
|
+
10: {
|
|
3270
|
+
field: 'avg_heart_rate',
|
|
3271
|
+
type: 'uint8',
|
|
3272
|
+
scale: null,
|
|
3273
|
+
offset: 0,
|
|
3274
|
+
units: 'bpm',
|
|
3275
|
+
},
|
|
3276
|
+
11: {
|
|
3277
|
+
field: 'max_heart_rate',
|
|
3278
|
+
type: 'uint8',
|
|
3279
|
+
scale: null,
|
|
3280
|
+
offset: 0,
|
|
3281
|
+
units: 'bpm',
|
|
3282
|
+
},
|
|
3283
|
+
12: {
|
|
3284
|
+
field: 'avg_vert_speed',
|
|
3285
|
+
type: 'sint32',
|
|
3286
|
+
scale: 1000,
|
|
3287
|
+
offset: 0,
|
|
3288
|
+
units: 'm/s',
|
|
3289
|
+
},
|
|
3290
|
+
13: {
|
|
3291
|
+
field: 'total_calories',
|
|
3292
|
+
type: 'uint32',
|
|
3293
|
+
scale: null,
|
|
3294
|
+
offset: 0,
|
|
3295
|
+
units: 'kcal',
|
|
3296
|
+
},
|
|
3297
|
+
65: {
|
|
3298
|
+
field: 'active_time',
|
|
3299
|
+
type: 'uint32',
|
|
3300
|
+
scale: 1000,
|
|
3301
|
+
offset: 0,
|
|
3302
|
+
units: 's',
|
|
3303
|
+
},
|
|
3304
|
+
77: {
|
|
3305
|
+
field: 'total_moving_time',
|
|
3306
|
+
type: 'uint32',
|
|
3307
|
+
scale: 1000,
|
|
3308
|
+
offset: 0,
|
|
3309
|
+
units: 's',
|
|
3310
|
+
},
|
|
3004
3311
|
},
|
|
3005
3312
|
285: {
|
|
3006
3313
|
name: 'jump',
|
|
@@ -5082,6 +5389,8 @@ export const FIT = {
|
|
|
5082
5389
|
264: 'exercise_title',
|
|
5083
5390
|
268: 'dive_summary',
|
|
5084
5391
|
285: 'jump',
|
|
5392
|
+
312: 'split',
|
|
5393
|
+
313: 'split_summary',
|
|
5085
5394
|
317: 'climb_pro',
|
|
5086
5395
|
319: 'tank_update',
|
|
5087
5396
|
323: 'tank_summary',
|
|
@@ -5837,6 +6146,33 @@ export const FIT = {
|
|
|
5837
6146
|
23: 'u_turn',
|
|
5838
6147
|
24: 'segment_start',
|
|
5839
6148
|
25: 'segment_end',
|
|
6149
|
+
27: 'campsite',
|
|
6150
|
+
28: 'aid_station',
|
|
6151
|
+
29: 'rest_area',
|
|
6152
|
+
30: 'general_distance',
|
|
6153
|
+
31: 'service',
|
|
6154
|
+
32: 'energy_gel',
|
|
6155
|
+
33: 'sports_drink',
|
|
6156
|
+
34: 'mile_marker',
|
|
6157
|
+
35: 'checkpoint',
|
|
6158
|
+
36: 'shelter',
|
|
6159
|
+
37: 'meeting_spot',
|
|
6160
|
+
38: 'overlook',
|
|
6161
|
+
39: 'toilet',
|
|
6162
|
+
40: 'shower',
|
|
6163
|
+
41: 'gear',
|
|
6164
|
+
42: 'sharp_curve',
|
|
6165
|
+
43: 'steep_incline',
|
|
6166
|
+
44: 'tunnel',
|
|
6167
|
+
45: 'bridge',
|
|
6168
|
+
46: 'obstacle',
|
|
6169
|
+
47: 'crossing',
|
|
6170
|
+
48: 'store',
|
|
6171
|
+
49: 'transition',
|
|
6172
|
+
50: 'navaid',
|
|
6173
|
+
51: 'transport',
|
|
6174
|
+
52: 'alert',
|
|
6175
|
+
53: 'info',
|
|
5840
6176
|
},
|
|
5841
6177
|
manufacturer: {
|
|
5842
6178
|
0: 0,
|
|
@@ -6598,6 +6934,29 @@ export const FIT = {
|
|
|
6598
6934
|
0: 'starred',
|
|
6599
6935
|
1: 'suggested',
|
|
6600
6936
|
},
|
|
6937
|
+
split_type: {
|
|
6938
|
+
1: 'ascent_split',
|
|
6939
|
+
2: 'descent_split',
|
|
6940
|
+
3: 'interval_active',
|
|
6941
|
+
4: 'interval_rest',
|
|
6942
|
+
5: 'interval_warmup',
|
|
6943
|
+
6: 'interval_cooldown',
|
|
6944
|
+
7: 'interval_recovery',
|
|
6945
|
+
8: 'interval_other',
|
|
6946
|
+
9: 'climb_active',
|
|
6947
|
+
10: 'climb_rest',
|
|
6948
|
+
11: 'surf_active',
|
|
6949
|
+
12: 'run_active',
|
|
6950
|
+
13: 'run_rest',
|
|
6951
|
+
14: 'workout_round',
|
|
6952
|
+
17: 'rwd_run',
|
|
6953
|
+
18: 'rwd_walk',
|
|
6954
|
+
21: 'windsurf_active',
|
|
6955
|
+
22: 'rwd_stand',
|
|
6956
|
+
23: 'transition',
|
|
6957
|
+
28: 'ski_lift_split',
|
|
6958
|
+
29: 'ski_run_split',
|
|
6959
|
+
},
|
|
6601
6960
|
source_type: {
|
|
6602
6961
|
0: 'ant',
|
|
6603
6962
|
1: 'antplus',
|
package/dist/fit_types.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export interface MessageIndex {
|
|
|
16
16
|
selected: boolean;
|
|
17
17
|
}
|
|
18
18
|
export type File = 'device' | 'settings' | 'sport' | 'activity' | 'workout' | 'course' | 'schedules' | 'weight' | 'totals' | 'goals' | 'blood_pressure' | 'monitoring_a' | 'activity_summary' | 'monitoring_daily' | 'monitoring_b' | 'segment' | 'segment_list' | 'exd_configuration' | 'mfg_range_min' | 'mfg_range_max';
|
|
19
|
-
export type MesgNum = 'file_id' | 'capabilities' | 'device_settings' | 'user_profile' | 'hrm_profile' | 'sdm_profile' | 'bike_profile' | 'zones_target' | 'hr_zone' | 'power_zone' | 'met_zone' | 'sport' | 'goal' | 'session' | 'lap' | 'record' | 'event' | 'device_info' | 'workout' | 'workout_step' | 'schedule' | 'weight_scale' | 'course' | 'course_point' | 'totals' | 'activity' | 'software' | 'file_capabilities' | 'mesg_capabilities' | 'field_capabilities' | 'file_creator' | 'blood_pressure' | 'speed_zone' | 'monitoring' | 'training_file' | 'hrv' | 'user_metrics' | 'ant_rx' | 'ant_tx' | 'ant_channel_id' | 'length' | 'monitoring_info' | 'pad' | 'slave_device' | 'connectivity' | 'weather_conditions' | 'weather_alert' | 'cadence_zone' | 'hr' | 'activity_metrics' | 'segment_lap' | 'memo_glob' | 'segment_id' | 'segment_leaderboard_entry' | 'segment_point' | 'segment_file' | 'workout_session' | 'watchface_settings' | 'gps_metadata' | 'camera_event' | 'timestamp_correlation' | 'gyroscope_data' | 'accelerometer_data' | 'three_d_sensor_calibration' | 'video_frame' | 'obdii_data' | 'nmea_sentence' | 'aviation_attitude' | 'video' | 'video_title' | 'video_description' | 'video_clip' | 'exd_screen_configuration' | 'exd_data_field_configuration' | 'exd_data_concept_configuration' | 'field_description' | 'developer_data_id' | 'magnetometer_data' | 'barometer_data' | 'one_d_sensor_calibration' | 'time_in_zone' | 'set' | 'stress_level' | 'dive_settings' | 'dive_gas' | 'dive_alarm' | 'exercise_title' | 'dive_summary' | 'jump' | 'climb_pro' | 'tank_update' | 'tank_summary' | 'o_hr_settings' | 'mfg_range_min' | 'mfg_range_max' | 'definition';
|
|
19
|
+
export type MesgNum = 'file_id' | 'capabilities' | 'device_settings' | 'user_profile' | 'hrm_profile' | 'sdm_profile' | 'bike_profile' | 'zones_target' | 'hr_zone' | 'power_zone' | 'met_zone' | 'sport' | 'goal' | 'session' | 'lap' | 'record' | 'event' | 'device_info' | 'workout' | 'workout_step' | 'schedule' | 'weight_scale' | 'course' | 'course_point' | 'totals' | 'activity' | 'software' | 'file_capabilities' | 'mesg_capabilities' | 'field_capabilities' | 'file_creator' | 'blood_pressure' | 'speed_zone' | 'monitoring' | 'training_file' | 'hrv' | 'user_metrics' | 'ant_rx' | 'ant_tx' | 'ant_channel_id' | 'length' | 'monitoring_info' | 'pad' | 'slave_device' | 'connectivity' | 'weather_conditions' | 'weather_alert' | 'cadence_zone' | 'hr' | 'activity_metrics' | 'segment_lap' | 'memo_glob' | 'segment_id' | 'segment_leaderboard_entry' | 'segment_point' | 'segment_file' | 'workout_session' | 'watchface_settings' | 'gps_metadata' | 'camera_event' | 'timestamp_correlation' | 'gyroscope_data' | 'accelerometer_data' | 'three_d_sensor_calibration' | 'video_frame' | 'obdii_data' | 'nmea_sentence' | 'aviation_attitude' | 'video' | 'video_title' | 'video_description' | 'video_clip' | 'exd_screen_configuration' | 'exd_data_field_configuration' | 'exd_data_concept_configuration' | 'field_description' | 'developer_data_id' | 'magnetometer_data' | 'barometer_data' | 'one_d_sensor_calibration' | 'time_in_zone' | 'set' | 'stress_level' | 'dive_settings' | 'dive_gas' | 'dive_alarm' | 'exercise_title' | 'dive_summary' | 'jump' | 'split' | 'split_summary' | 'climb_pro' | 'tank_update' | 'tank_summary' | 'o_hr_settings' | 'mfg_range_min' | 'mfg_range_max' | 'definition';
|
|
20
20
|
export type Checksum = 'clear' | 'ok';
|
|
21
21
|
export type FileFlags = '0' | 'read' | 'write' | 'erase';
|
|
22
22
|
export type MesgCount = 'num_per_file' | 'max_per_file' | 'max_per_file_type';
|
|
@@ -69,7 +69,7 @@ export type Goal = 'time' | 'distance' | 'calories' | 'frequency' | 'steps' | 'a
|
|
|
69
69
|
export type GoalRecurrence = 'off' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'custom';
|
|
70
70
|
export type GoalSource = 'auto' | 'community' | 'user';
|
|
71
71
|
export type Schedule = 'workout' | 'course';
|
|
72
|
-
export type CoursePoint = 'generic' | 'summit' | 'valley' | 'water' | 'food' | 'danger' | 'left' | 'right' | 'straight' | 'first_aid' | 'fourth_category' | 'third_category' | 'second_category' | 'first_category' | 'hors_category' | 'sprint' | 'left_fork' | 'right_fork' | 'middle_fork' | 'slight_left' | 'sharp_left' | 'slight_right' | 'sharp_right' | 'u_turn' | 'segment_start' | 'segment_end';
|
|
72
|
+
export type CoursePoint = 'generic' | 'summit' | 'valley' | 'water' | 'food' | 'danger' | 'left' | 'right' | 'straight' | 'first_aid' | 'fourth_category' | 'third_category' | 'second_category' | 'first_category' | 'hors_category' | 'sprint' | 'left_fork' | 'right_fork' | 'middle_fork' | 'slight_left' | 'sharp_left' | 'slight_right' | 'sharp_right' | 'u_turn' | 'segment_start' | 'segment_end' | 'campsite' | 'aid_station' | 'rest_area' | 'general_distance' | 'service' | 'energy_gel' | 'sports_drink' | 'mile_marker' | 'checkpoint' | 'shelter' | 'meeting_spot' | 'overlook' | 'toilet' | 'shower' | 'gear' | 'sharp_curve' | 'steep_incline' | 'tunnel' | 'bridge' | 'obstacle' | 'crossing' | 'store' | 'transition' | 'navaid' | 'transport' | 'alert' | 'info';
|
|
73
73
|
export type Manufacturer = '0' | 'garmin' | 'garmin_fr405_antfs' | 'zephyr' | 'dayton' | 'idt' | 'srm' | 'quarq' | 'ibike' | 'saris' | 'spark_hk' | 'tanita' | 'echowell' | 'dynastream_oem' | 'nautilus' | 'dynastream' | 'timex' | 'metrigear' | 'xelic' | 'beurer' | 'cardiosport' | 'a_and_d' | 'hmm' | 'suunto' | 'thita_elektronik' | 'gpulse' | 'clean_mobile' | 'pedal_brain' | 'peaksware' | 'saxonar' | 'lemond_fitness' | 'dexcom' | 'wahoo_fitness' | 'octane_fitness' | 'archinoetics' | 'the_hurt_box' | 'citizen_systems' | 'magellan' | 'osynce' | 'holux' | 'concept2' | 'one_giant_leap' | 'ace_sensor' | 'brim_brothers' | 'xplova' | 'perception_digital' | 'bf1systems' | 'pioneer' | 'spantec' | 'metalogics' | '4iiiis' | 'seiko_epson' | 'seiko_epson_oem' | 'ifor_powell' | 'maxwell_guider' | 'star_trac' | 'breakaway' | 'alatech_technology_ltd' | 'mio_technology_europe' | 'rotor' | 'geonaute' | 'id_bike' | 'specialized' | 'wtek' | 'physical_enterprises' | 'north_pole_engineering' | 'bkool' | 'cateye' | 'stages_cycling' | 'sigmasport' | 'tomtom' | 'peripedal' | 'wattbike' | 'moxy' | 'ciclosport' | 'powerbahn' | 'acorn_projects_aps' | 'lifebeam' | 'bontrager' | 'wellgo' | 'scosche' | 'magura' | 'woodway' | 'elite' | 'nielsen_kellerman' | 'dk_city' | 'tacx' | 'direction_technology' | 'magtonic' | '1partcarbon' | 'inside_ride_technologies' | 'sound_of_motion' | 'stryd' | 'icg' | 'mipulse' | 'bsx_athletics' | 'look' | 'campagnolo_srl' | 'body_bike_smart' | 'praxisworks' | 'limits_technology' | 'topaction_technology' | 'cosinuss' | 'fitcare' | 'magene' | 'giant_manufacturing_co' | 'tigrasport' | 'salutron' | 'technogym' | 'bryton_sensors' | 'latitude_limited' | 'soaring_technology' | 'igpsport' | 'thinkrider' | 'gopher_sport' | 'waterrower' | 'orangetheory' | 'inpeak' | 'kinetic' | 'johnson_health_tech' | 'polar_electro' | 'seesense' | 'nci_technology' | 'development' | 'healthandlife' | 'lezyne' | 'scribe_labs' | 'zwift' | 'watteam' | 'recon' | 'favero_electronics' | 'dynovelo' | 'strava' | 'precor' | 'bryton' | 'sram' | 'navman' | 'cobi' | 'spivi' | 'mio_magellan' | 'evesports' | 'sensitivus_gauge' | 'podoon' | 'life_time_fitness' | 'falco_e_motors' | 'minoura' | 'cycliq' | 'luxottica' | 'trainer_road' | 'the_sufferfest' | 'fullspeedahead' | 'virtualtraining' | 'feedbacksports' | 'omata' | 'vdo' | 'magneticdays' | 'hammerhead' | 'kinetic_by_kurt' | 'shapelog' | 'dabuziduo' | 'jetblack' | 'coros' | 'virtugo' | 'velosense' | 'actigraphcorp';
|
|
74
74
|
export type GarminProduct = 'hrm_bike' | 'hrm1' | 'axh01' | 'axb01' | 'axb02' | 'hrm2ss' | 'dsi_alf02' | 'hrm3ss' | 'hrm_run_single_byte_product_id' | 'bsm' | 'bcm' | 'axs01' | 'hrm_tri_single_byte_product_id' | 'fr225_single_byte_product_id' | 'fr301_china' | 'fr301_japan' | 'fr301_korea' | 'fr301_taiwan' | 'fr405' | 'fr50' | 'fr405_japan' | 'fr60' | 'dsi_alf01' | 'fr310xt' | 'edge500' | 'fr110' | 'edge800' | 'edge500_taiwan' | 'edge500_japan' | 'chirp' | 'fr110_japan' | 'edge200' | 'fr910xt' | 'edge800_taiwan' | 'edge800_japan' | 'alf04' | 'fr610' | 'fr210_japan' | 'vector_ss' | 'vector_cp' | 'edge800_china' | 'edge500_china' | 'fr610_japan' | 'edge500_korea' | 'fr70' | 'fr310xt_4t' | 'amx' | 'fr10' | 'edge800_korea' | 'swim' | 'fr910xt_china' | 'fenix' | 'edge200_taiwan' | 'edge510' | 'edge810' | 'tempe' | 'fr910xt_japan' | 'fr620' | 'fr220' | 'fr910xt_korea' | 'fr10_japan' | 'edge810_japan' | 'virb_elite' | 'edge_touring' | 'edge510_japan' | 'hrm_tri' | 'hrm_run' | 'fr920xt' | 'edge510_asia' | 'edge810_china' | 'edge810_taiwan' | 'edge1000' | 'vivo_fit' | 'virb_remote' | 'vivo_ki' | 'fr15' | 'vivo_active' | 'edge510_korea' | 'fr620_japan' | 'fr620_china' | 'fr220_japan' | 'fr220_china' | 'approach_s6' | 'vivo_smart' | 'fenix2' | 'epix' | 'fenix3' | 'edge1000_taiwan' | 'edge1000_japan' | 'fr15_japan' | 'edge520' | 'edge1000_china' | 'fr620_russia' | 'fr220_russia' | 'vector_s' | 'edge1000_korea' | 'fr920xt_taiwan' | 'fr920xt_china' | 'fr920xt_japan' | 'virbx' | 'vivo_smart_apac' | 'etrex_touch' | 'edge25' | 'fr25' | 'vivo_fit2' | 'fr225' | 'fr630' | 'fr230' | 'fr735xt' | 'vivo_active_apac' | 'vector_2' | 'vector_2s' | 'virbxe' | 'fr620_taiwan' | 'fr220_taiwan' | 'truswing' | 'fenix3_china' | 'fenix3_twn' | 'varia_headlight' | 'varia_taillight_old' | 'edge_explore_1000' | 'fr225_asia' | 'varia_radar_taillight' | 'varia_radar_display' | 'edge20' | 'd2_bravo' | 'approach_s20' | 'varia_remote' | 'hrm4_run' | 'vivo_active_hr' | 'vivo_smart_hr' | 'vivo_move' | 'varia_vision' | 'vivo_fit3' | 'fenix3_hr' | 'virb_ultra_30' | 'index_smart_scale' | 'fr235' | 'fenix3_chronos' | 'oregon7xx' | 'rino7xx' | 'nautix' | 'edge_820' | 'edge_explore_820' | 'fenix5s' | 'd2_bravo_titanium' | 'varia_ut800' | 'running_dynamics_pod' | 'fenix5x' | 'vivo_fit_jr' | 'fr935' | 'fenix5' | 'descent' | 'sdm4' | 'edge_remote' | 'training_center' | 'connectiq_simulator' | 'android_antplus_plugin' | 'connect';
|
|
75
75
|
export type AntplusDeviceType = 'antfs' | 'bike_power' | 'environment_sensor_legacy' | 'multi_sport_speed_distance' | 'control' | 'fitness_equipment' | 'blood_pressure' | 'geocache_node' | 'light_electric_vehicle' | 'env_sensor' | 'racquet' | 'control_hub' | 'muscle_oxygen' | 'shifting' | 'bike_light_main' | 'bike_light_shared' | 'exd' | 'bike_radar' | 'bike_aero' | 'weight_scale' | 'heart_rate' | 'bike_speed_cadence' | 'bike_cadence' | 'bike_speed' | 'stride_speed_distance';
|
|
@@ -105,6 +105,7 @@ export type SegmentLapStatus = 'end' | 'fail';
|
|
|
105
105
|
export type SegmentLeaderboardType = 'overall' | 'personal_best' | 'connections' | 'group' | 'challenger' | 'kom' | 'qom' | 'pr' | 'goal' | 'rival' | 'club_leader';
|
|
106
106
|
export type SegmentDeleteStatus = 'do_not_delete' | 'delete_one' | 'delete_all';
|
|
107
107
|
export type SegmentSelectionType = 'starred' | 'suggested';
|
|
108
|
+
export type SplitType = 'ascent_split' | 'descent_split' | 'interval_active' | 'interval_rest' | 'interval_warmup' | 'interval_cooldown' | 'interval_recovery' | 'interval_other' | 'climb_active' | 'climb_rest' | 'surf_active' | 'run_active' | 'run_rest' | 'workout_round' | 'rwd_run' | 'rwd_walk' | 'windsurf_active' | 'rwd_stand' | 'transition' | 'ski_lift_split' | 'ski_run_split';
|
|
108
109
|
export type SourceType = 'ant' | 'antplus' | 'bluetooth' | 'bluetooth_low_energy' | 'wifi' | 'local';
|
|
109
110
|
export type DisplayOrientation = 'auto' | 'portrait' | 'landscape' | 'portrait_flipped' | 'landscape_flipped';
|
|
110
111
|
export type WorkoutEquipment = 'none' | 'swim_fins' | 'swim_kickboard' | 'swim_paddles' | 'swim_pull_buoy' | 'swim_snorkel';
|
|
@@ -465,6 +466,9 @@ export interface ParsedSession {
|
|
|
465
466
|
workout_feel?: number;
|
|
466
467
|
workout_rpe?: number;
|
|
467
468
|
resting_calories?: number;
|
|
469
|
+
beginning_potential_stamina?: number;
|
|
470
|
+
ending_potential_stamina?: number;
|
|
471
|
+
min_stamina?: number;
|
|
468
472
|
timestamp: string;
|
|
469
473
|
message_index?: MessageIndex;
|
|
470
474
|
laps?: ParsedLap[];
|
|
@@ -648,6 +652,8 @@ export interface ParsedRecord {
|
|
|
648
652
|
n2_load?: number;
|
|
649
653
|
grit?: number;
|
|
650
654
|
flow?: number;
|
|
655
|
+
potential_stamina?: number;
|
|
656
|
+
stamina?: number;
|
|
651
657
|
timestamp: string;
|
|
652
658
|
}
|
|
653
659
|
export interface ParsedEvent {
|
|
@@ -762,6 +768,8 @@ export interface ParsedActivity {
|
|
|
762
768
|
developer_data_ids?: ParsedDeveloperDataId[];
|
|
763
769
|
field_descriptions?: ParsedFieldDescription[];
|
|
764
770
|
sports?: ParsedSport[];
|
|
771
|
+
splits?: ParsedSplit[];
|
|
772
|
+
split_summaries?: ParsedSplitSummary[];
|
|
765
773
|
}
|
|
766
774
|
export interface ParsedSoftware {
|
|
767
775
|
version?: number;
|
|
@@ -1010,6 +1018,48 @@ export interface ParsedJump {
|
|
|
1010
1018
|
enhanced_speed?: number;
|
|
1011
1019
|
timestamp: string;
|
|
1012
1020
|
}
|
|
1021
|
+
export interface ParsedSplit {
|
|
1022
|
+
split_type?: SplitType;
|
|
1023
|
+
total_elapsed_time?: number;
|
|
1024
|
+
total_timer_time?: number;
|
|
1025
|
+
total_distance?: number;
|
|
1026
|
+
avg_speed?: number;
|
|
1027
|
+
start_time: string;
|
|
1028
|
+
total_ascent?: number;
|
|
1029
|
+
total_descent?: number;
|
|
1030
|
+
start_position_lat?: number;
|
|
1031
|
+
start_position_long?: number;
|
|
1032
|
+
end_position_lat?: number;
|
|
1033
|
+
end_position_long?: number;
|
|
1034
|
+
max_speed?: number;
|
|
1035
|
+
avg_vert_speed?: number;
|
|
1036
|
+
end_time?: string;
|
|
1037
|
+
total_calories?: number;
|
|
1038
|
+
start_elevation?: number;
|
|
1039
|
+
active_time?: number;
|
|
1040
|
+
beginning_potential_stamina?: number;
|
|
1041
|
+
ending_potential_stamina?: number;
|
|
1042
|
+
min_stamina?: number;
|
|
1043
|
+
total_moving_time?: number;
|
|
1044
|
+
message_index?: MessageIndex;
|
|
1045
|
+
}
|
|
1046
|
+
export interface ParsedSplitSummary {
|
|
1047
|
+
split_type?: SplitType;
|
|
1048
|
+
num_splits?: number;
|
|
1049
|
+
total_timer_time?: number;
|
|
1050
|
+
total_distance?: number;
|
|
1051
|
+
avg_speed?: number;
|
|
1052
|
+
max_speed?: number;
|
|
1053
|
+
total_ascent?: number;
|
|
1054
|
+
total_descent?: number;
|
|
1055
|
+
avg_heart_rate?: number;
|
|
1056
|
+
max_heart_rate?: number;
|
|
1057
|
+
avg_vert_speed?: number;
|
|
1058
|
+
total_calories?: number;
|
|
1059
|
+
active_time?: number;
|
|
1060
|
+
total_moving_time?: number;
|
|
1061
|
+
message_index?: MessageIndex;
|
|
1062
|
+
}
|
|
1013
1063
|
export interface ParsedTankUpdate {
|
|
1014
1064
|
sensor?: number;
|
|
1015
1065
|
pressure?: number;
|
|
@@ -1054,6 +1104,8 @@ export interface ParsedFit {
|
|
|
1054
1104
|
tank_updates?: ParsedTankUpdate[];
|
|
1055
1105
|
tank_summaries?: ParsedTankSummary[];
|
|
1056
1106
|
jumps?: ParsedJump[];
|
|
1107
|
+
splits?: ParsedSplit[];
|
|
1108
|
+
split_summaries?: ParsedSplitSummary[];
|
|
1057
1109
|
time_in_zone?: ParsedTimeInZone[];
|
|
1058
1110
|
activity_metrics?: ParsedActivityMetrics[];
|
|
1059
1111
|
user_metrics?: ParsedUserMetrics[];
|
package/dist/type_generator.js
CHANGED
|
@@ -160,6 +160,8 @@ function generateAdditionalFields(msg) {
|
|
|
160
160
|
developer_data_ids: 'parsed_developer_data_id',
|
|
161
161
|
field_descriptions: 'parsed_field_description',
|
|
162
162
|
sports: 'parsed_sport',
|
|
163
|
+
splits: 'parsed_split',
|
|
164
|
+
split_summaries: 'parsed_split_summary',
|
|
163
165
|
};
|
|
164
166
|
return Object.keys(props).map(prop => generateArrayProperty(prop, ts.factory.createTypeReferenceNode(snakeToCamel(props[prop]))));
|
|
165
167
|
}
|
|
@@ -189,6 +191,8 @@ export function generateFitType() {
|
|
|
189
191
|
tank_updates: 'parsed_tank_update',
|
|
190
192
|
tank_summaries: 'parsed_tank_summary',
|
|
191
193
|
jumps: 'parsed_jump',
|
|
194
|
+
splits: 'parsed_split',
|
|
195
|
+
split_summaries: 'parsed_split_summary',
|
|
192
196
|
time_in_zone: 'parsed_time_in_zone',
|
|
193
197
|
activity_metrics: 'parsed_activity_metrics',
|
|
194
198
|
user_metrics: 'parsed_user_metrics',
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fit-file-parser",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "3.0.
|
|
4
|
+
"version": "3.0.2",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "Parse your .FIT files easily, directly from JS (Garmin, Polar, Suunto)",
|
|
7
7
|
"author": {
|
|
@@ -32,6 +32,13 @@
|
|
|
32
32
|
"garmin",
|
|
33
33
|
"parse"
|
|
34
34
|
],
|
|
35
|
+
"files": [
|
|
36
|
+
"dist/",
|
|
37
|
+
"README.md",
|
|
38
|
+
"LICENSE",
|
|
39
|
+
"CHANGELOG.md",
|
|
40
|
+
"CONTRIBUTORS.md"
|
|
41
|
+
],
|
|
35
42
|
"exports": {
|
|
36
43
|
".": {
|
|
37
44
|
"types": "./dist/fit-parser.d.ts",
|
|
@@ -75,4 +82,4 @@
|
|
|
75
82
|
"typescript": "^5.9.3",
|
|
76
83
|
"vitest": "^4.0.13"
|
|
77
84
|
}
|
|
78
|
-
}
|
|
85
|
+
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# FIT Parser Development Rules
|
|
2
|
-
|
|
3
|
-
You are working on the `fit-parser` library. Follow these rules strictly to ensure correctness and stability.
|
|
4
|
-
|
|
5
|
-
## Core Principles
|
|
6
|
-
|
|
7
|
-
1. **Trust the Official SDK**:
|
|
8
|
-
* Always verify Message IDs and Field IDs against the Official Garmin FIT SDK (`@garmin/fitsdk`).
|
|
9
|
-
* **NEVER** guess or reuse existing IDs if they seem wrong (e.g., Message 140 vs 285).
|
|
10
|
-
* If `@garmin/fitsdk` is available in `node_modules`, use it as the source of truth.
|
|
11
|
-
|
|
12
|
-
2. **Investigation First**:
|
|
13
|
-
* If a field is missing, use `npm run inspect <file>` or `npm run probe <file> <value>` BEFORE modifying code.
|
|
14
|
-
* Confirm the field exists in the file and identify its raw value.
|
|
15
|
-
|
|
16
|
-
3. **Testing is Mandatory**:
|
|
17
|
-
* Every new message or field definition MUST have a corresponding test case in `test/`.
|
|
18
|
-
* Test against real FIT files whenever possible (use `examples/` directory).
|
|
19
|
-
* Use `npm run test` to verify changes.
|
|
20
|
-
|
|
21
|
-
4. **Code Generation**:
|
|
22
|
-
* `src/fit_types.ts` is AUTO-GENERATED.
|
|
23
|
-
* If you modify `src/fit.ts`, you **MUST** run `npm run codegen` to update types.
|
|
24
|
-
* Do not edit `src/fit_types.ts` manually.
|
|
25
|
-
|
|
26
|
-
## Workflow checklist
|
|
27
|
-
|
|
28
|
-
When adding a new message or fixing a field:
|
|
29
|
-
|
|
30
|
-
- [ ] Locate official Message ID in Garmin SDK
|
|
31
|
-
- [ ] Locate Field IDs and Types in Garmin SDK
|
|
32
|
-
- [ ] Update `src/fit.ts` with new definition
|
|
33
|
-
- [ ] Run `npm run codegen`
|
|
34
|
-
- [ ] Add/Update test in `test/`
|
|
35
|
-
- [ ] Run `npm run build && npm run test`
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: add-fit-message
|
|
3
|
-
description: Add a new FIT message or update an existing one
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Add/Update FIT Message
|
|
7
|
-
|
|
8
|
-
## Prerequisites
|
|
9
|
-
|
|
10
|
-
- Identify Message ID (e.g., 285 for Jump)
|
|
11
|
-
- Identify Field IDs and Types from Garmin SDK
|
|
12
|
-
|
|
13
|
-
## Steps
|
|
14
|
-
|
|
15
|
-
1. **Modify `src/fit.ts`** - Add message definition
|
|
16
|
-
2. **Run `npm run codegen`** - Updates `src/fit_types.ts`
|
|
17
|
-
3. **Add Test** - Create test in `test/`
|
|
18
|
-
4. **Verify** - Run `npm run build && npm run test`
|
|
19
|
-
|
|
20
|
-
## Example Entry
|
|
21
|
-
|
|
22
|
-
```typescript
|
|
23
|
-
285: {
|
|
24
|
-
name: 'jump',
|
|
25
|
-
253: { field: 'timestamp', type: 'date_time', scale: null, offset: 0, units: 's' },
|
|
26
|
-
0: { field: 'distance', type: 'float32', scale: null, offset: 0, units: 'm' },
|
|
27
|
-
5: { field: 'position_lat', type: 'sint32', scale: null, offset: 0, units: 'semicircles' },
|
|
28
|
-
}
|
|
29
|
-
```
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: common fit-parser development workflows
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Inspect FIT File
|
|
6
|
-
|
|
7
|
-
// turbo
|
|
8
|
-
1. node scripts/inspect_fit.js <path_to_fit_file> [message_key]
|
|
9
|
-
|
|
10
|
-
# Probe FIT File for Value
|
|
11
|
-
|
|
12
|
-
// turbo
|
|
13
|
-
1. node scripts/deep_probe.js <path_to_fit_file> <value> [tolerance]
|
|
14
|
-
|
|
15
|
-
# Run Tests
|
|
16
|
-
|
|
17
|
-
// turbo
|
|
18
|
-
1. npm run build && npm run test
|
|
19
|
-
|
|
20
|
-
# Add New Message
|
|
21
|
-
|
|
22
|
-
1. Locate Message ID in `@garmin/fitsdk/src/profile.js`
|
|
23
|
-
2. Update `src/fit.ts` with message definition
|
|
24
|
-
// turbo
|
|
25
|
-
3. npm run codegen
|
|
26
|
-
4. Add test in `test/`
|
|
27
|
-
// turbo
|
|
28
|
-
5. npm run build && npm run test
|
package/.editorconfig
DELETED