fit-file-parser 6.1.2 → 6.2.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 +56 -0
- package/PROFILE.md +23 -0
- package/README.md +72 -5
- package/dist/binary.js +30 -17
- package/dist/cjs/binary.js +30 -17
- package/dist/cjs/fit-parser.d.ts +11 -0
- package/dist/cjs/fit-parser.js +112 -6
- package/dist/cjs/fit_types.d.ts +23 -1
- package/dist/cjs/profile.js +166 -0
- package/dist/cjs/type_generator.js +1 -0
- package/dist/fit-parser.d.ts +11 -0
- package/dist/fit-parser.js +112 -6
- package/dist/fit_types.d.ts +23 -1
- package/dist/profile.js +166 -0
- package/dist/type_generator.js +1 -0
- package/package.json +14 -5
package/dist/cjs/fit-parser.js
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
2
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
12
|
exports.readFitUnsignedField = exports.readFitStringField = exports.readFitMessages = exports.getFitBaseTypeId = exports.fitTimestampToUnixMilliseconds = exports.FitMessageReaderError = exports.getFitSubSportName = exports.getFitSubSportId = exports.getFitSportName = exports.getFitSportId = exports.getFitManufacturerName = exports.getFitGarminProductName = exports.getFitGarminProductDisplayName = exports.getFitCoursePointId = exports.FitEncoder = exports.FitBaseType = void 0;
|
|
4
13
|
const binary_js_1 = require("./binary.js");
|
|
@@ -22,21 +31,31 @@ Object.defineProperty(exports, "getFitBaseTypeId", { enumerable: true, get: func
|
|
|
22
31
|
Object.defineProperty(exports, "readFitMessages", { enumerable: true, get: function () { return raw_message_reader_js_1.readFitMessages; } });
|
|
23
32
|
Object.defineProperty(exports, "readFitStringField", { enumerable: true, get: function () { return raw_message_reader_js_1.readFitStringField; } });
|
|
24
33
|
Object.defineProperty(exports, "readFitUnsignedField", { enumerable: true, get: function () { return raw_message_reader_js_1.readFitUnsignedField; } });
|
|
34
|
+
function hasFitHeader(blob, start) {
|
|
35
|
+
const headerLength = blob[start];
|
|
36
|
+
return blob.length - start >= headerLength
|
|
37
|
+
&& (headerLength === 12 || headerLength === 14)
|
|
38
|
+
&& blob[start + 8] === 0x2E
|
|
39
|
+
&& blob[start + 9] === 0x46
|
|
40
|
+
&& blob[start + 10] === 0x49
|
|
41
|
+
&& blob[start + 11] === 0x54;
|
|
42
|
+
}
|
|
25
43
|
class FitParser {
|
|
26
44
|
constructor(options = {}) {
|
|
27
|
-
var _a, _b, _c, _d;
|
|
45
|
+
var _a, _b, _c, _d, _e;
|
|
28
46
|
this.options = {
|
|
29
47
|
force: options.force != null ? options.force : true,
|
|
48
|
+
strict: (_a = options.strict) !== null && _a !== void 0 ? _a : false,
|
|
30
49
|
speedUnit: options.speedUnit || 'm/s',
|
|
31
50
|
lengthUnit: options.lengthUnit || 'm',
|
|
32
51
|
temperatureUnit: options.temperatureUnit || 'celsius',
|
|
33
52
|
elapsedRecordField: options.elapsedRecordField || false,
|
|
34
53
|
pressureUnit: options.pressureUnit || 'bar',
|
|
35
54
|
mode: options.mode || 'list',
|
|
36
|
-
includeRawDeveloperFields: (
|
|
37
|
-
includeRawMessages: (
|
|
38
|
-
includeUnmappedMessages: (
|
|
39
|
-
rawMessagesOnly: (
|
|
55
|
+
includeRawDeveloperFields: (_b = options.includeRawDeveloperFields) !== null && _b !== void 0 ? _b : false,
|
|
56
|
+
includeRawMessages: (_c = options.includeRawMessages) !== null && _c !== void 0 ? _c : false,
|
|
57
|
+
includeUnmappedMessages: (_d = options.includeUnmappedMessages) !== null && _d !== void 0 ? _d : false,
|
|
58
|
+
rawMessagesOnly: (_e = options.rawMessagesOnly) !== null && _e !== void 0 ? _e : false,
|
|
40
59
|
};
|
|
41
60
|
}
|
|
42
61
|
parseAsync(content) {
|
|
@@ -51,7 +70,81 @@ class FitParser {
|
|
|
51
70
|
});
|
|
52
71
|
});
|
|
53
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Parses FIT files in input order with independent decoder state. Uses the
|
|
75
|
+
* same force and strict policies as parseAsync; strict mode rejects trailing
|
|
76
|
+
* bytes, while the default ignores a non-FIT suffix after parsed files.
|
|
77
|
+
* Rejects with an Error when any file cannot be parsed.
|
|
78
|
+
*/
|
|
79
|
+
parseFilesAsync(content) {
|
|
80
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
81
|
+
const blob = content instanceof ArrayBuffer
|
|
82
|
+
? new Uint8Array(content)
|
|
83
|
+
: new Uint8Array(content.buffer, content.byteOffset, content.byteLength);
|
|
84
|
+
const results = [];
|
|
85
|
+
let start = 0;
|
|
86
|
+
do {
|
|
87
|
+
const remaining = blob.length - start;
|
|
88
|
+
const headerLength = blob[start];
|
|
89
|
+
if (results.length > 0 && !this.options.strict && !hasFitHeader(blob, start)) {
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
if (remaining < 12) {
|
|
93
|
+
throw new Error('File to small to be a FIT file');
|
|
94
|
+
}
|
|
95
|
+
if (headerLength !== 12 && headerLength !== 14) {
|
|
96
|
+
throw new Error('Incorrect header size');
|
|
97
|
+
}
|
|
98
|
+
if (remaining < headerLength) {
|
|
99
|
+
throw new Error('File to small to be a FIT file');
|
|
100
|
+
}
|
|
101
|
+
if (blob[start + 8] !== 0x2E
|
|
102
|
+
|| blob[start + 9] !== 0x46
|
|
103
|
+
|| blob[start + 10] !== 0x49
|
|
104
|
+
|| blob[start + 11] !== 0x54) {
|
|
105
|
+
throw new Error('Missing \'.FIT\' in header');
|
|
106
|
+
}
|
|
107
|
+
const dataLength = new DataView(blob.buffer, blob.byteOffset + start, remaining)
|
|
108
|
+
.getUint32(4, true);
|
|
109
|
+
const crcStart = start + headerLength + dataLength;
|
|
110
|
+
// File completeness and CRC checks belong to the shared parser below,
|
|
111
|
+
// preserving the same validation policy and error order in every API.
|
|
112
|
+
let end = Math.min(crcStart + 2, blob.length);
|
|
113
|
+
// Missing CRC bytes can also precede the next file. Check only the
|
|
114
|
+
// declared boundary and its one-byte CRC variant; never scan activity
|
|
115
|
+
// payloads for a guessed file boundary.
|
|
116
|
+
if (this.options.force && !this.options.strict) {
|
|
117
|
+
if (hasFitHeader(blob, crcStart)) {
|
|
118
|
+
end = crcStart;
|
|
119
|
+
}
|
|
120
|
+
else if (hasFitHeader(blob, crcStart + 1)) {
|
|
121
|
+
end = crcStart + 1;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
results.push(yield new Promise((resolve, reject) => {
|
|
126
|
+
this.parseFile(blob.slice(start, end).buffer, (error, data) => {
|
|
127
|
+
if (error) {
|
|
128
|
+
reject(error);
|
|
129
|
+
}
|
|
130
|
+
else if (data) {
|
|
131
|
+
resolve(data);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}));
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
138
|
+
}
|
|
139
|
+
start = end;
|
|
140
|
+
} while (start < blob.length);
|
|
141
|
+
return results;
|
|
142
|
+
});
|
|
143
|
+
}
|
|
54
144
|
parse(content, callback) {
|
|
145
|
+
this.parseFile(content, callback);
|
|
146
|
+
}
|
|
147
|
+
parseFile(content, callback) {
|
|
55
148
|
var _a, _b, _c;
|
|
56
149
|
const blob = content instanceof ArrayBuffer
|
|
57
150
|
? new Uint8Array(content)
|
|
@@ -94,10 +187,14 @@ class FitParser {
|
|
|
94
187
|
callback('File data exceeds input length', undefined);
|
|
95
188
|
return;
|
|
96
189
|
}
|
|
97
|
-
if (!this.options.force && crcStart + 2 > blob.length) {
|
|
190
|
+
if ((!this.options.force || this.options.strict) && crcStart + 2 > blob.length) {
|
|
98
191
|
callback('File CRC missing', undefined);
|
|
99
192
|
return;
|
|
100
193
|
}
|
|
194
|
+
if (this.options.strict && crcStart + 2 < blob.length) {
|
|
195
|
+
callback('Unexpected bytes after FIT file', undefined);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
101
198
|
if (!this.options.force) {
|
|
102
199
|
const crcFile = blob[crcStart] + (blob[crcStart + 1] << 8);
|
|
103
200
|
const crcFileCalc = (0, binary_js_1.calculateCRC)(blob, 0, crcStart);
|
|
@@ -111,6 +208,7 @@ class FitParser {
|
|
|
111
208
|
protocolVersion,
|
|
112
209
|
};
|
|
113
210
|
const messages = {};
|
|
211
|
+
const batteries = [];
|
|
114
212
|
let sessions = [];
|
|
115
213
|
let laps = [];
|
|
116
214
|
const records = [];
|
|
@@ -160,6 +258,10 @@ class FitParser {
|
|
|
160
258
|
let pausedTime = 0;
|
|
161
259
|
while (loopIndex < crcStart) {
|
|
162
260
|
const { globalMessageNumber, littleEndian, message, messageType, nextIndex, compressedTimestamp, rawFields: recordRawFields, rawDeveloperFields: recordRawDeveloperFields, unmappedFields: recordUnmappedFields, unmappedDeveloperFields: recordUnmappedDeveloperFields, } = (0, binary_js_1.readRecord)(blob, messageTypes, developerFields, loopIndex, this.options, startDate, pausedTime, dataView, decoderState, crcStart);
|
|
261
|
+
if (this.options.strict
|
|
262
|
+
&& (!Number.isInteger(nextIndex) || nextIndex <= loopIndex || nextIndex > crcStart)) {
|
|
263
|
+
throw new Error('Invalid FIT record bounds');
|
|
264
|
+
}
|
|
163
265
|
loopIndex = nextIndex;
|
|
164
266
|
if (globalMessageNumber !== undefined) {
|
|
165
267
|
const messageIndex = (_a = messageCountsByGlobalNumber.get(globalMessageNumber)) !== null && _a !== void 0 ? _a : 0;
|
|
@@ -210,6 +312,9 @@ class FitParser {
|
|
|
210
312
|
((_b = messages[messageType]) !== null && _b !== void 0 ? _b : (messages[messageType] = [])).push(message);
|
|
211
313
|
}
|
|
212
314
|
switch (messageType) {
|
|
315
|
+
case 'battery':
|
|
316
|
+
batteries.push(message);
|
|
317
|
+
break;
|
|
213
318
|
case 'lap':
|
|
214
319
|
laps.push(message);
|
|
215
320
|
break;
|
|
@@ -354,6 +459,7 @@ class FitParser {
|
|
|
354
459
|
fitObj.time_in_zone = time_in_zone;
|
|
355
460
|
fitObj.activity_metrics = activity_metrics;
|
|
356
461
|
fitObj.user_metrics = user_metrics;
|
|
462
|
+
fitObj.batteries = batteries;
|
|
357
463
|
fitObj.messages = messages;
|
|
358
464
|
if (rawDeveloperFields) {
|
|
359
465
|
fitObj.raw_developer_fields = rawDeveloperFields;
|
package/dist/cjs/fit_types.d.ts
CHANGED
|
@@ -156,7 +156,7 @@ export type MaxMetCategory = 'generic' | 'cycling' | number;
|
|
|
156
156
|
export type MaxMetHeartRateSource = 'whr' | 'hrm' | number;
|
|
157
157
|
export type MaxMetSpeedSource = 'onboard_gps' | 'connected_gps' | 'cadence' | number;
|
|
158
158
|
export type MesgCount = 'num_per_file' | 'max_per_file' | 'max_per_file_type' | number;
|
|
159
|
-
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' | 'training_settings' | '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' | 'ohr_settings' | 'exd_screen_configuration' | 'exd_data_field_configuration' | 'exd_data_concept_configuration' | 'field_description' | 'developer_data_id' | 'magnetometer_data' | 'barometer_data' | 'one_d_sensor_calibration' | 'monitoring_hr_data' | 'time_in_zone' | 'set' | 'stress_level' | 'max_met_data' | 'dive_settings' | 'dive_gas' | 'dive_alarm' | 'exercise_title' | 'dive_summary' | 'spo2_data' | 'sleep_level' | 'jump' | 'aad_accel_features' | 'beat_intervals' | 'respiration_rate' | 'hsa_accelerometer_data' | 'hsa_step_data' | 'hsa_spo2_data' | 'hsa_stress_data' | 'hsa_respiration_data' | 'hsa_heart_rate_data' | 'split' | 'split_summary' | 'hsa_body_battery_data' | 'hsa_event' | 'climb_pro' | 'tank_update' | 'tank_summary' | 'sleep_assessment' | 'hrv_status_summary' | 'hrv_value' | 'raw_bbi' | 'device_aux_battery_info' | 'hsa_gyroscope_data' | 'chrono_shot_session' | 'chrono_shot_data' | 'hsa_configuration_data' | 'dive_apnea_alarm' | 'skin_temp_overnight' | 'hsa_wrist_temperature_data' | 'nap_event' | 'sleep_disruption_severity_period' | 'sleep_disruption_overnight_severity' | 'mfg_range_min' | 'mfg_range_max' | 'definition' | number;
|
|
159
|
+
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' | 'training_settings' | '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' | 'battery' | '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' | 'ohr_settings' | 'exd_screen_configuration' | 'exd_data_field_configuration' | 'exd_data_concept_configuration' | 'field_description' | 'developer_data_id' | 'magnetometer_data' | 'barometer_data' | 'one_d_sensor_calibration' | 'monitoring_hr_data' | 'time_in_zone' | 'set' | 'stress_level' | 'max_met_data' | 'dive_settings' | 'dive_gas' | 'dive_alarm' | 'exercise_title' | 'dive_summary' | 'spo2_data' | 'sleep_level' | 'jump' | 'aad_accel_features' | 'beat_intervals' | 'respiration_rate' | 'hsa_accelerometer_data' | 'hsa_step_data' | 'hsa_spo2_data' | 'hsa_stress_data' | 'hsa_respiration_data' | 'hsa_heart_rate_data' | 'split' | 'split_summary' | 'hsa_body_battery_data' | 'hsa_event' | 'climb_pro' | 'tank_update' | 'tank_summary' | 'sleep_assessment' | 'hrv_status_summary' | 'hrv_value' | 'raw_bbi' | 'device_aux_battery_info' | 'hsa_gyroscope_data' | 'chrono_shot_session' | 'chrono_shot_data' | 'hsa_configuration_data' | 'dive_apnea_alarm' | 'skin_temp_overnight' | 'hsa_wrist_temperature_data' | 'nap_event' | 'sleep_disruption_severity_period' | 'sleep_disruption_overnight_severity' | 'mfg_range_min' | 'mfg_range_max' | 'definition' | number;
|
|
160
160
|
export interface MessageIndex {
|
|
161
161
|
value: number;
|
|
162
162
|
reserved: boolean;
|
|
@@ -498,6 +498,8 @@ export interface ParsedSession {
|
|
|
498
498
|
best_lap_index?: number;
|
|
499
499
|
min_altitude?: number;
|
|
500
500
|
active_time?: number;
|
|
501
|
+
avg_strokes_per_length?: number;
|
|
502
|
+
avg_swolf?: number;
|
|
501
503
|
player_score?: number;
|
|
502
504
|
opponent_score?: number;
|
|
503
505
|
opponent_name?: string;
|
|
@@ -522,6 +524,9 @@ export interface ParsedSession {
|
|
|
522
524
|
avg_left_pedal_smoothness?: number;
|
|
523
525
|
avg_right_pedal_smoothness?: number;
|
|
524
526
|
avg_combined_pedal_smoothness?: number;
|
|
527
|
+
num_segment_laps?: number;
|
|
528
|
+
front_gear_shift_count?: number;
|
|
529
|
+
rear_gear_shift_count?: number;
|
|
525
530
|
sport_profile_name?: string;
|
|
526
531
|
sport_index?: number;
|
|
527
532
|
time_standing?: number;
|
|
@@ -588,6 +593,7 @@ export interface ParsedSession {
|
|
|
588
593
|
avg_core_temperature?: number;
|
|
589
594
|
min_core_temperature?: number;
|
|
590
595
|
max_core_temperature?: number;
|
|
596
|
+
avg_grade_adjusted_speed?: number;
|
|
591
597
|
timestamp?: Date;
|
|
592
598
|
message_index?: MessageIndex;
|
|
593
599
|
laps?: ParsedLap[];
|
|
@@ -620,6 +626,10 @@ export interface ParsedLap {
|
|
|
620
626
|
lap_trigger?: LapTrigger;
|
|
621
627
|
sport?: Sport;
|
|
622
628
|
event_group?: number;
|
|
629
|
+
nec_lat?: number;
|
|
630
|
+
nec_long?: number;
|
|
631
|
+
swc_lat?: number;
|
|
632
|
+
swc_long?: number;
|
|
623
633
|
num_lengths?: number;
|
|
624
634
|
normalized_power?: number;
|
|
625
635
|
left_right_balance?: LeftRightBalance100;
|
|
@@ -653,6 +663,7 @@ export interface ParsedLap {
|
|
|
653
663
|
min_heart_rate?: number;
|
|
654
664
|
active_time?: number;
|
|
655
665
|
wkt_step_index?: MessageIndex;
|
|
666
|
+
avg_swolf?: number;
|
|
656
667
|
opponent_score?: number;
|
|
657
668
|
stroke_count?: (number | null)[];
|
|
658
669
|
zone_count?: (number | null)[];
|
|
@@ -669,11 +680,14 @@ export interface ParsedLap {
|
|
|
669
680
|
avg_saturated_hemoglobin_percent?: (number | null)[];
|
|
670
681
|
min_saturated_hemoglobin_percent?: (number | null)[];
|
|
671
682
|
max_saturated_hemoglobin_percent?: (number | null)[];
|
|
683
|
+
avg_strokes_per_length?: number;
|
|
672
684
|
avg_left_torque_effectiveness?: number;
|
|
673
685
|
avg_right_torque_effectiveness?: number;
|
|
674
686
|
avg_left_pedal_smoothness?: number;
|
|
675
687
|
avg_right_pedal_smoothness?: number;
|
|
676
688
|
avg_combined_pedal_smoothness?: number;
|
|
689
|
+
front_gear_shift_count?: number;
|
|
690
|
+
rear_gear_shift_count?: number;
|
|
677
691
|
time_standing?: number;
|
|
678
692
|
stand_count?: number;
|
|
679
693
|
avg_left_pco?: number;
|
|
@@ -710,11 +724,13 @@ export interface ParsedLap {
|
|
|
710
724
|
jump_count?: number;
|
|
711
725
|
avg_grit?: number;
|
|
712
726
|
avg_flow?: number;
|
|
727
|
+
metabolic_calories?: number;
|
|
713
728
|
total_fractional_ascent?: number;
|
|
714
729
|
total_fractional_descent?: number;
|
|
715
730
|
avg_core_temperature?: number;
|
|
716
731
|
min_core_temperature?: number;
|
|
717
732
|
max_core_temperature?: number;
|
|
733
|
+
avg_grade_adjusted_speed?: number;
|
|
718
734
|
timestamp?: Date;
|
|
719
735
|
message_index?: MessageIndex;
|
|
720
736
|
records?: ParsedRecord[];
|
|
@@ -1119,6 +1135,10 @@ export interface ParsedMonitoringInfo {
|
|
|
1119
1135
|
resting_metabolic_rate?: number;
|
|
1120
1136
|
timestamp?: Date;
|
|
1121
1137
|
}
|
|
1138
|
+
export interface ParsedBattery {
|
|
1139
|
+
capacity?: number;
|
|
1140
|
+
timestamp?: Date;
|
|
1141
|
+
}
|
|
1122
1142
|
export interface ParsedPad {
|
|
1123
1143
|
}
|
|
1124
1144
|
export interface ParsedSlaveDevice {
|
|
@@ -2007,6 +2027,7 @@ export interface ParsedMessages {
|
|
|
2007
2027
|
ant_channel_id?: ParsedAntChannelId[];
|
|
2008
2028
|
length?: ParsedLength[];
|
|
2009
2029
|
monitoring_info?: ParsedMonitoringInfo[];
|
|
2030
|
+
battery?: ParsedBattery[];
|
|
2010
2031
|
pad?: ParsedPad[];
|
|
2011
2032
|
slave_device?: ParsedSlaveDevice[];
|
|
2012
2033
|
connectivity?: ParsedConnectivity[];
|
|
@@ -2134,6 +2155,7 @@ export interface ParsedFit {
|
|
|
2134
2155
|
time_in_zone?: ParsedTimeInZone[];
|
|
2135
2156
|
activity_metrics?: ParsedActivityMetrics[];
|
|
2136
2157
|
user_metrics?: ParsedUserMetrics[];
|
|
2158
|
+
batteries?: ParsedBattery[];
|
|
2137
2159
|
capabilities?: ParsedCapabilities;
|
|
2138
2160
|
hrm_profile?: ParsedHrmProfile;
|
|
2139
2161
|
sdm_profile?: ParsedSdmProfile;
|
package/dist/cjs/profile.js
CHANGED
|
@@ -1348,6 +1348,60 @@ exports.PROFILE_MESSAGES = {
|
|
|
1348
1348
|
name: 'goal',
|
|
1349
1349
|
},
|
|
1350
1350
|
18: {
|
|
1351
|
+
79: {
|
|
1352
|
+
field: 'avg_strokes_per_length',
|
|
1353
|
+
type: 'uint16',
|
|
1354
|
+
baseType: 'uint16',
|
|
1355
|
+
array: false,
|
|
1356
|
+
scale: 10,
|
|
1357
|
+
offset: 0,
|
|
1358
|
+
units: 'strokes/length',
|
|
1359
|
+
},
|
|
1360
|
+
80: {
|
|
1361
|
+
field: 'avg_swolf',
|
|
1362
|
+
type: 'uint16',
|
|
1363
|
+
baseType: 'uint16',
|
|
1364
|
+
array: false,
|
|
1365
|
+
scale: 1,
|
|
1366
|
+
offset: 0,
|
|
1367
|
+
units: '',
|
|
1368
|
+
},
|
|
1369
|
+
106: {
|
|
1370
|
+
field: 'num_segment_laps',
|
|
1371
|
+
type: 'uint16',
|
|
1372
|
+
baseType: 'uint16',
|
|
1373
|
+
array: false,
|
|
1374
|
+
scale: 1,
|
|
1375
|
+
offset: 0,
|
|
1376
|
+
units: '',
|
|
1377
|
+
},
|
|
1378
|
+
107: {
|
|
1379
|
+
field: 'front_gear_shift_count',
|
|
1380
|
+
type: 'uint16',
|
|
1381
|
+
baseType: 'uint16',
|
|
1382
|
+
array: false,
|
|
1383
|
+
scale: 1,
|
|
1384
|
+
offset: 0,
|
|
1385
|
+
units: '',
|
|
1386
|
+
},
|
|
1387
|
+
108: {
|
|
1388
|
+
field: 'rear_gear_shift_count',
|
|
1389
|
+
type: 'uint16',
|
|
1390
|
+
baseType: 'uint16',
|
|
1391
|
+
array: false,
|
|
1392
|
+
scale: 1,
|
|
1393
|
+
offset: 0,
|
|
1394
|
+
units: '',
|
|
1395
|
+
},
|
|
1396
|
+
211: {
|
|
1397
|
+
field: 'avg_grade_adjusted_speed',
|
|
1398
|
+
type: 'uint32',
|
|
1399
|
+
baseType: 'uint32',
|
|
1400
|
+
array: false,
|
|
1401
|
+
scale: 1000,
|
|
1402
|
+
offset: 0,
|
|
1403
|
+
units: 'm/s',
|
|
1404
|
+
},
|
|
1351
1405
|
0: {
|
|
1352
1406
|
field: 'event',
|
|
1353
1407
|
type: 'event',
|
|
@@ -2808,6 +2862,96 @@ exports.PROFILE_MESSAGES = {
|
|
|
2808
2862
|
name: 'session',
|
|
2809
2863
|
},
|
|
2810
2864
|
19: {
|
|
2865
|
+
27: {
|
|
2866
|
+
field: 'nec_lat',
|
|
2867
|
+
type: 'sint32',
|
|
2868
|
+
baseType: 'sint32',
|
|
2869
|
+
array: false,
|
|
2870
|
+
scale: 1,
|
|
2871
|
+
offset: 0,
|
|
2872
|
+
units: 'semicircles',
|
|
2873
|
+
},
|
|
2874
|
+
28: {
|
|
2875
|
+
field: 'nec_long',
|
|
2876
|
+
type: 'sint32',
|
|
2877
|
+
baseType: 'sint32',
|
|
2878
|
+
array: false,
|
|
2879
|
+
scale: 1,
|
|
2880
|
+
offset: 0,
|
|
2881
|
+
units: 'semicircles',
|
|
2882
|
+
},
|
|
2883
|
+
29: {
|
|
2884
|
+
field: 'swc_lat',
|
|
2885
|
+
type: 'sint32',
|
|
2886
|
+
baseType: 'sint32',
|
|
2887
|
+
array: false,
|
|
2888
|
+
scale: 1,
|
|
2889
|
+
offset: 0,
|
|
2890
|
+
units: 'semicircles',
|
|
2891
|
+
},
|
|
2892
|
+
30: {
|
|
2893
|
+
field: 'swc_long',
|
|
2894
|
+
type: 'sint32',
|
|
2895
|
+
baseType: 'sint32',
|
|
2896
|
+
array: false,
|
|
2897
|
+
scale: 1,
|
|
2898
|
+
offset: 0,
|
|
2899
|
+
units: 'semicircles',
|
|
2900
|
+
},
|
|
2901
|
+
73: {
|
|
2902
|
+
field: 'avg_swolf',
|
|
2903
|
+
type: 'uint16',
|
|
2904
|
+
baseType: 'uint16',
|
|
2905
|
+
array: false,
|
|
2906
|
+
scale: 1,
|
|
2907
|
+
offset: 0,
|
|
2908
|
+
units: '',
|
|
2909
|
+
},
|
|
2910
|
+
90: {
|
|
2911
|
+
field: 'avg_strokes_per_length',
|
|
2912
|
+
type: 'uint16',
|
|
2913
|
+
baseType: 'uint16',
|
|
2914
|
+
array: false,
|
|
2915
|
+
scale: 10,
|
|
2916
|
+
offset: 0,
|
|
2917
|
+
units: 'strokes / length',
|
|
2918
|
+
},
|
|
2919
|
+
96: {
|
|
2920
|
+
field: 'front_gear_shift_count',
|
|
2921
|
+
type: 'uint16',
|
|
2922
|
+
baseType: 'uint16',
|
|
2923
|
+
array: false,
|
|
2924
|
+
scale: 1,
|
|
2925
|
+
offset: 0,
|
|
2926
|
+
units: '',
|
|
2927
|
+
},
|
|
2928
|
+
97: {
|
|
2929
|
+
field: 'rear_gear_shift_count',
|
|
2930
|
+
type: 'uint16',
|
|
2931
|
+
baseType: 'uint16',
|
|
2932
|
+
array: false,
|
|
2933
|
+
scale: 1,
|
|
2934
|
+
offset: 0,
|
|
2935
|
+
units: '',
|
|
2936
|
+
},
|
|
2937
|
+
155: {
|
|
2938
|
+
field: 'metabolic_calories',
|
|
2939
|
+
type: 'uint16',
|
|
2940
|
+
baseType: 'uint16',
|
|
2941
|
+
array: false,
|
|
2942
|
+
scale: 1,
|
|
2943
|
+
offset: 0,
|
|
2944
|
+
units: 'kcal',
|
|
2945
|
+
},
|
|
2946
|
+
161: {
|
|
2947
|
+
field: 'avg_grade_adjusted_speed',
|
|
2948
|
+
type: 'uint32',
|
|
2949
|
+
baseType: 'uint32',
|
|
2950
|
+
array: false,
|
|
2951
|
+
scale: 1000,
|
|
2952
|
+
offset: 0,
|
|
2953
|
+
units: 'm/s',
|
|
2954
|
+
},
|
|
2811
2955
|
0: {
|
|
2812
2956
|
field: 'event',
|
|
2813
2957
|
type: 'event',
|
|
@@ -6986,6 +7130,27 @@ exports.PROFILE_MESSAGES = {
|
|
|
6986
7130
|
},
|
|
6987
7131
|
name: 'monitoring_info',
|
|
6988
7132
|
},
|
|
7133
|
+
104: {
|
|
7134
|
+
2: {
|
|
7135
|
+
field: 'capacity',
|
|
7136
|
+
type: 'uint8',
|
|
7137
|
+
baseType: 'uint8',
|
|
7138
|
+
array: false,
|
|
7139
|
+
scale: 1,
|
|
7140
|
+
offset: 0,
|
|
7141
|
+
units: '%',
|
|
7142
|
+
},
|
|
7143
|
+
253: {
|
|
7144
|
+
field: 'timestamp',
|
|
7145
|
+
type: 'date_time',
|
|
7146
|
+
baseType: 'uint32',
|
|
7147
|
+
array: false,
|
|
7148
|
+
scale: 1,
|
|
7149
|
+
offset: 0,
|
|
7150
|
+
units: '',
|
|
7151
|
+
},
|
|
7152
|
+
name: 'battery',
|
|
7153
|
+
},
|
|
6989
7154
|
105: {
|
|
6990
7155
|
name: 'pad',
|
|
6991
7156
|
},
|
|
@@ -15266,6 +15431,7 @@ exports.PROFILE_TYPES = {
|
|
|
15266
15431
|
82: 'ant_channel_id',
|
|
15267
15432
|
101: 'length',
|
|
15268
15433
|
103: 'monitoring_info',
|
|
15434
|
+
104: 'battery',
|
|
15269
15435
|
105: 'pad',
|
|
15270
15436
|
106: 'slave_device',
|
|
15271
15437
|
127: 'connectivity',
|
|
@@ -261,6 +261,7 @@ function generateFitType() {
|
|
|
261
261
|
time_in_zone: 'parsed_time_in_zone',
|
|
262
262
|
activity_metrics: 'parsed_activity_metrics',
|
|
263
263
|
user_metrics: 'parsed_user_metrics',
|
|
264
|
+
batteries: 'parsed_battery',
|
|
264
265
|
};
|
|
265
266
|
const referenceProperties = {
|
|
266
267
|
file_creator: 'parsed_file_creator',
|
package/dist/fit-parser.d.ts
CHANGED
|
@@ -7,7 +7,10 @@ export { getFitCoursePointId, getFitGarminProductDisplayName, getFitGarminProduc
|
|
|
7
7
|
export { FitMessageReaderError, fitTimestampToUnixMilliseconds, getFitBaseTypeId, readFitMessages, readFitStringField, readFitUnsignedField, } from './raw-message-reader.js';
|
|
8
8
|
export type { FitMessageReaderErrorCode, FitMessageReaderIssue, FitMessageReaderIssueCode, FitMessageReaderOptions, FitMessageReaderResult, FitRawDeveloperField, FitRawField, FitRawMessage, } from './raw-message-reader.js';
|
|
9
9
|
export interface FitParserOptions {
|
|
10
|
+
/** Skips CRC validation and enables supported best-effort recovery. Defaults to true. */
|
|
10
11
|
force?: boolean;
|
|
12
|
+
/** Requires complete files and records, and rejects trailing bytes. Defaults to false. */
|
|
13
|
+
strict?: boolean;
|
|
11
14
|
speedUnit?: string;
|
|
12
15
|
lengthUnit?: string;
|
|
13
16
|
temperatureUnit?: string;
|
|
@@ -28,5 +31,13 @@ export default class FitParser {
|
|
|
28
31
|
private readonly options;
|
|
29
32
|
constructor(options?: FitParserOptions);
|
|
30
33
|
parseAsync(content: ArrayBuffer | Buffer<ArrayBuffer>): Promise<ParsedFit>;
|
|
34
|
+
/**
|
|
35
|
+
* Parses FIT files in input order with independent decoder state. Uses the
|
|
36
|
+
* same force and strict policies as parseAsync; strict mode rejects trailing
|
|
37
|
+
* bytes, while the default ignores a non-FIT suffix after parsed files.
|
|
38
|
+
* Rejects with an Error when any file cannot be parsed.
|
|
39
|
+
*/
|
|
40
|
+
parseFilesAsync(content: ArrayBuffer | Buffer<ArrayBuffer>): Promise<ParsedFit[]>;
|
|
31
41
|
parse(content: ArrayBuffer | Buffer<ArrayBuffer>, callback: FitParserCallback): void;
|
|
42
|
+
private parseFile;
|
|
32
43
|
}
|