@kaiord/fit 4.7.2 → 7.0.0
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/index.js +151 -133
- package/dist/index.js.map +1 -1
- package/package.json +11 -7
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { sportSchema, durationTypeSchema, createConsoleLogger, createFitParsingError, fileTypeSchema, workoutSchema, isRepetitionBlock, convertLengthToMeters, subSportSchema, lengthUnitSchema,
|
|
1
|
+
import { sportSchema, durationTypeSchema, createConsoleLogger, createFitParsingError, fileTypeSchema, workoutSchema, isRepetitionBlock, convertLengthToMeters, subSportSchema, lengthUnitSchema, equipmentSchema, targetTypeSchema, FIT_TO_SWIM_STROKE, targetUnitSchema, intensitySchema } from '@kaiord/core';
|
|
2
2
|
import { Stream, Decoder, Encoder, Profile } from '@garmin/fitsdk';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
|
|
@@ -673,63 +673,6 @@ var fitMessageKeySchema = z.enum([
|
|
|
673
673
|
"eventMesgs",
|
|
674
674
|
"lapMesgs"
|
|
675
675
|
]);
|
|
676
|
-
var fitEventSchema = z.enum([
|
|
677
|
-
"timer",
|
|
678
|
-
"workout",
|
|
679
|
-
"workoutStep",
|
|
680
|
-
"powerDown",
|
|
681
|
-
"powerUp",
|
|
682
|
-
"offCourse",
|
|
683
|
-
"session",
|
|
684
|
-
"lap",
|
|
685
|
-
"coursePoint",
|
|
686
|
-
"battery",
|
|
687
|
-
"virtualPartnerPace",
|
|
688
|
-
"hrHighAlert",
|
|
689
|
-
"hrLowAlert",
|
|
690
|
-
"speedHighAlert",
|
|
691
|
-
"speedLowAlert",
|
|
692
|
-
"cadHighAlert",
|
|
693
|
-
"cadLowAlert",
|
|
694
|
-
"powerHighAlert",
|
|
695
|
-
"powerLowAlert",
|
|
696
|
-
"recoveryHr",
|
|
697
|
-
"batteryLow",
|
|
698
|
-
"timeDurationAlert",
|
|
699
|
-
"distanceDurationAlert",
|
|
700
|
-
"calorieDurationAlert",
|
|
701
|
-
"activity",
|
|
702
|
-
"fitnessEquipment",
|
|
703
|
-
"length",
|
|
704
|
-
"userMarker",
|
|
705
|
-
"sportPoint",
|
|
706
|
-
"calibration",
|
|
707
|
-
"frontGearChange",
|
|
708
|
-
"rearGearChange",
|
|
709
|
-
"riderPositionChange",
|
|
710
|
-
"elevHighAlert",
|
|
711
|
-
"elevLowAlert"
|
|
712
|
-
]);
|
|
713
|
-
var fitEventTypeSchema = z.enum([
|
|
714
|
-
"start",
|
|
715
|
-
"stop",
|
|
716
|
-
"consecutiveDepreciated",
|
|
717
|
-
"marker",
|
|
718
|
-
"stopAll",
|
|
719
|
-
"beginDepreciated",
|
|
720
|
-
"endDepreciated",
|
|
721
|
-
"endAllDepreciated",
|
|
722
|
-
"stopDisable",
|
|
723
|
-
"stopDisableAll"
|
|
724
|
-
]);
|
|
725
|
-
var fitEventMessageSchema = z.object({
|
|
726
|
-
timestamp: z.number(),
|
|
727
|
-
event: fitEventSchema,
|
|
728
|
-
eventType: fitEventTypeSchema,
|
|
729
|
-
eventGroup: z.number().optional(),
|
|
730
|
-
data: z.number().optional(),
|
|
731
|
-
data16: z.number().optional()
|
|
732
|
-
});
|
|
733
676
|
|
|
734
677
|
// src/adapters/event/event-type-maps.ts
|
|
735
678
|
var FIT_EVENT_TO_KRD_TYPE = {
|
|
@@ -793,6 +736,63 @@ var mapFitEventToKrd = (fit) => ({
|
|
|
793
736
|
eventGroup: fit.eventGroup,
|
|
794
737
|
data: fit.data
|
|
795
738
|
});
|
|
739
|
+
var fitEventSchema = z.enum([
|
|
740
|
+
"timer",
|
|
741
|
+
"workout",
|
|
742
|
+
"workoutStep",
|
|
743
|
+
"powerDown",
|
|
744
|
+
"powerUp",
|
|
745
|
+
"offCourse",
|
|
746
|
+
"session",
|
|
747
|
+
"lap",
|
|
748
|
+
"coursePoint",
|
|
749
|
+
"battery",
|
|
750
|
+
"virtualPartnerPace",
|
|
751
|
+
"hrHighAlert",
|
|
752
|
+
"hrLowAlert",
|
|
753
|
+
"speedHighAlert",
|
|
754
|
+
"speedLowAlert",
|
|
755
|
+
"cadHighAlert",
|
|
756
|
+
"cadLowAlert",
|
|
757
|
+
"powerHighAlert",
|
|
758
|
+
"powerLowAlert",
|
|
759
|
+
"recoveryHr",
|
|
760
|
+
"batteryLow",
|
|
761
|
+
"timeDurationAlert",
|
|
762
|
+
"distanceDurationAlert",
|
|
763
|
+
"calorieDurationAlert",
|
|
764
|
+
"activity",
|
|
765
|
+
"fitnessEquipment",
|
|
766
|
+
"length",
|
|
767
|
+
"userMarker",
|
|
768
|
+
"sportPoint",
|
|
769
|
+
"calibration",
|
|
770
|
+
"frontGearChange",
|
|
771
|
+
"rearGearChange",
|
|
772
|
+
"riderPositionChange",
|
|
773
|
+
"elevHighAlert",
|
|
774
|
+
"elevLowAlert"
|
|
775
|
+
]);
|
|
776
|
+
var fitEventTypeSchema = z.enum([
|
|
777
|
+
"start",
|
|
778
|
+
"stop",
|
|
779
|
+
"consecutiveDepreciated",
|
|
780
|
+
"marker",
|
|
781
|
+
"stopAll",
|
|
782
|
+
"beginDepreciated",
|
|
783
|
+
"endDepreciated",
|
|
784
|
+
"endAllDepreciated",
|
|
785
|
+
"stopDisable",
|
|
786
|
+
"stopDisableAll"
|
|
787
|
+
]);
|
|
788
|
+
var fitEventMessageSchema = z.object({
|
|
789
|
+
timestamp: z.number(),
|
|
790
|
+
event: fitEventSchema,
|
|
791
|
+
eventType: fitEventTypeSchema,
|
|
792
|
+
eventGroup: z.number().optional(),
|
|
793
|
+
data: z.number().optional(),
|
|
794
|
+
data16: z.number().optional()
|
|
795
|
+
});
|
|
796
796
|
|
|
797
797
|
// src/adapters/event/fit-to-krd-event.converter.ts
|
|
798
798
|
var convertFitToKrdEvent = (data) => {
|
|
@@ -803,6 +803,34 @@ var convertFitToKrdEvents = (events) => {
|
|
|
803
803
|
return events.map(convertFitToKrdEvent);
|
|
804
804
|
};
|
|
805
805
|
|
|
806
|
+
// src/adapters/extensions/developer-fields.extractor.ts
|
|
807
|
+
var extractDeveloperFields = (message) => {
|
|
808
|
+
const devFields = [];
|
|
809
|
+
for (const [key, value] of Object.entries(message)) {
|
|
810
|
+
if (key.startsWith("developer_") || key.includes("DeveloperField")) {
|
|
811
|
+
devFields.push({
|
|
812
|
+
fieldName: key,
|
|
813
|
+
value
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
return devFields;
|
|
818
|
+
};
|
|
819
|
+
var extractFieldsFromMessageArray = (messages) => {
|
|
820
|
+
const developerFields = [];
|
|
821
|
+
for (const message of messages) {
|
|
822
|
+
if (message && typeof message === "object") {
|
|
823
|
+
const devFields = extractDeveloperFields(
|
|
824
|
+
message
|
|
825
|
+
);
|
|
826
|
+
if (devFields.length > 0) {
|
|
827
|
+
developerFields.push(...devFields);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
return developerFields;
|
|
832
|
+
};
|
|
833
|
+
|
|
806
834
|
// src/adapters/extensions/extensions.extractor.ts
|
|
807
835
|
var extractFitExtensions = (messages, logger) => {
|
|
808
836
|
logger.debug("Extracting FIT extensions");
|
|
@@ -829,30 +857,11 @@ var extractAllDeveloperFields = (messages) => {
|
|
|
829
857
|
const developerFields = [];
|
|
830
858
|
for (const value of Object.values(messages)) {
|
|
831
859
|
if (value && Array.isArray(value)) {
|
|
832
|
-
|
|
833
|
-
if (message && typeof message === "object") {
|
|
834
|
-
const devFields = extractDeveloperFields(message);
|
|
835
|
-
if (devFields.length > 0) {
|
|
836
|
-
developerFields.push(...devFields);
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
}
|
|
860
|
+
developerFields.push(...extractFieldsFromMessageArray(value));
|
|
840
861
|
}
|
|
841
862
|
}
|
|
842
863
|
return developerFields;
|
|
843
864
|
};
|
|
844
|
-
var extractDeveloperFields = (message) => {
|
|
845
|
-
const devFields = [];
|
|
846
|
-
for (const [key, value] of Object.entries(message)) {
|
|
847
|
-
if (key.startsWith("developer_") || key.includes("DeveloperField")) {
|
|
848
|
-
devFields.push({
|
|
849
|
-
fieldName: key,
|
|
850
|
-
value
|
|
851
|
-
});
|
|
852
|
-
}
|
|
853
|
-
}
|
|
854
|
-
return devFields;
|
|
855
|
-
};
|
|
856
865
|
var buildExtensions = (unknownMessages, developerFields, logger) => {
|
|
857
866
|
const extensions = {};
|
|
858
867
|
if (developerFields.length > 0) {
|
|
@@ -950,7 +959,7 @@ var mapFitLapTriggerToKrd = (fit) => {
|
|
|
950
959
|
}
|
|
951
960
|
};
|
|
952
961
|
|
|
953
|
-
// src/adapters/lap/lap.mapper.ts
|
|
962
|
+
// src/adapters/lap/fit-to-krd-lap.mapper.ts
|
|
954
963
|
var mapFitLapToKrd = (fit) => ({
|
|
955
964
|
// Timing - convert ms to seconds
|
|
956
965
|
startTime: new Date(fit.startTime * 1e3).toISOString(),
|
|
@@ -1016,17 +1025,17 @@ var fitRecordSchema = z.object({
|
|
|
1016
1025
|
compressedTimestamp: z.number().optional()
|
|
1017
1026
|
});
|
|
1018
1027
|
|
|
1019
|
-
// src/adapters/record/record.mapper.ts
|
|
1020
|
-
var
|
|
1021
|
-
const record = {
|
|
1022
|
-
timestamp: new Date(fit.timestamp * 1e3).toISOString()
|
|
1023
|
-
};
|
|
1028
|
+
// src/adapters/record/record-from-fit.mapper.ts
|
|
1029
|
+
var mapFitPosition = (fit) => {
|
|
1024
1030
|
if (fit.positionLat !== void 0 && fit.positionLong !== void 0) {
|
|
1025
|
-
|
|
1031
|
+
return {
|
|
1026
1032
|
lat: semicirclesToDegrees(fit.positionLat),
|
|
1027
1033
|
lon: semicirclesToDegrees(fit.positionLong)
|
|
1028
1034
|
};
|
|
1029
1035
|
}
|
|
1036
|
+
return void 0;
|
|
1037
|
+
};
|
|
1038
|
+
var mapFitAltitudeAndSpeed = (fit, record) => {
|
|
1030
1039
|
if (fit.enhancedAltitude !== void 0) {
|
|
1031
1040
|
record.altitude = fit.enhancedAltitude;
|
|
1032
1041
|
} else if (fit.altitude !== void 0) {
|
|
@@ -1037,6 +1046,8 @@ var mapFitRecordToKrd = (fit) => {
|
|
|
1037
1046
|
} else if (fit.speed !== void 0) {
|
|
1038
1047
|
record.speed = fit.speed;
|
|
1039
1048
|
}
|
|
1049
|
+
};
|
|
1050
|
+
var mapFitCoreFields = (fit, record) => {
|
|
1040
1051
|
if (fit.distance !== void 0) record.distance = fit.distance;
|
|
1041
1052
|
if (fit.heartRate !== void 0) record.heartRate = fit.heartRate;
|
|
1042
1053
|
if (fit.power !== void 0) record.power = fit.power;
|
|
@@ -1044,11 +1055,23 @@ var mapFitRecordToKrd = (fit) => {
|
|
|
1044
1055
|
if (fit.cadence !== void 0) {
|
|
1045
1056
|
record.cadence = fit.cadence + (fit.fractionalCadence ?? 0);
|
|
1046
1057
|
}
|
|
1058
|
+
};
|
|
1059
|
+
var mapFitRunningDynamics = (fit, record) => {
|
|
1047
1060
|
if (fit.verticalOscillation !== void 0) {
|
|
1048
1061
|
record.verticalOscillation = fit.verticalOscillation;
|
|
1049
1062
|
}
|
|
1050
1063
|
if (fit.stanceTime !== void 0) record.stanceTime = fit.stanceTime;
|
|
1051
1064
|
if (fit.stepLength !== void 0) record.stepLength = fit.stepLength;
|
|
1065
|
+
};
|
|
1066
|
+
var mapFitRecordToKrd = (fit) => {
|
|
1067
|
+
const record = {
|
|
1068
|
+
timestamp: new Date(fit.timestamp * 1e3).toISOString()
|
|
1069
|
+
};
|
|
1070
|
+
const position = mapFitPosition(fit);
|
|
1071
|
+
if (position) record.position = position;
|
|
1072
|
+
mapFitAltitudeAndSpeed(fit, record);
|
|
1073
|
+
mapFitCoreFields(fit, record);
|
|
1074
|
+
mapFitRunningDynamics(fit, record);
|
|
1052
1075
|
return record;
|
|
1053
1076
|
};
|
|
1054
1077
|
|
|
@@ -1136,6 +1159,13 @@ var convertTimeCreated = (timeCreated) => {
|
|
|
1136
1159
|
return new Date(timeCreated * 1e3).toISOString();
|
|
1137
1160
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
1138
1161
|
};
|
|
1162
|
+
var buildKrdMetadata = (fileId, session) => ({
|
|
1163
|
+
created: convertTimeCreated(fileId ? fileId.timeCreated : void 0),
|
|
1164
|
+
sport: (session ? session.sport : void 0) ?? "other",
|
|
1165
|
+
subSport: session ? session.subSport : void 0
|
|
1166
|
+
});
|
|
1167
|
+
var toOptionalArray = (items) => items.length > 0 ? items : void 0;
|
|
1168
|
+
var toOptionalSingle = (item) => item !== void 0 ? [item] : void 0;
|
|
1139
1169
|
var mapActivityFileToKRD = (messages, logger) => {
|
|
1140
1170
|
const fileId = messages[fitMessageKeySchema.enum.fileIdMesgs]?.[0];
|
|
1141
1171
|
const sessionMsgs = messages[fitMessageKeySchema.enum.sessionMesgs] || [];
|
|
@@ -1153,22 +1183,18 @@ var mapActivityFileToKRD = (messages, logger) => {
|
|
|
1153
1183
|
const events = convertFitToKrdEvents(eventMsgs);
|
|
1154
1184
|
const laps = convertFitToKrdLaps(lapMsgs);
|
|
1155
1185
|
const fitExtensions = extractFitExtensions(messages, logger);
|
|
1156
|
-
const created = convertTimeCreated(fileId?.timeCreated);
|
|
1157
1186
|
return {
|
|
1158
1187
|
version: KRD_VERSION,
|
|
1159
1188
|
type: fileTypeSchema.enum.recorded_activity,
|
|
1160
|
-
metadata:
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
extensions: {
|
|
1170
|
-
fit: fitExtensions
|
|
1171
|
-
}
|
|
1189
|
+
metadata: buildKrdMetadata(
|
|
1190
|
+
fileId,
|
|
1191
|
+
session
|
|
1192
|
+
),
|
|
1193
|
+
sessions: toOptionalSingle(session),
|
|
1194
|
+
laps: toOptionalArray(laps),
|
|
1195
|
+
records: toOptionalArray(records),
|
|
1196
|
+
events: toOptionalArray(events),
|
|
1197
|
+
extensions: { fit: fitExtensions }
|
|
1172
1198
|
};
|
|
1173
1199
|
};
|
|
1174
1200
|
var DEFAULT_SPORT = sportSchema.enum.cycling;
|
|
@@ -1373,34 +1399,24 @@ var convertFitDuration = (data) => {
|
|
|
1373
1399
|
var mapDuration = (step) => {
|
|
1374
1400
|
return convertFitDuration(step);
|
|
1375
1401
|
};
|
|
1402
|
+
var FIT_TO_KRD_DURATION_TYPE = {
|
|
1403
|
+
[fitDurationTypeSchema.enum.time]: durationTypeSchema.enum.time,
|
|
1404
|
+
[fitDurationTypeSchema.enum.distance]: durationTypeSchema.enum.distance,
|
|
1405
|
+
[fitDurationTypeSchema.enum.hrLessThan]: durationTypeSchema.enum.heart_rate_less_than,
|
|
1406
|
+
[fitDurationTypeSchema.enum.repeatUntilHrGreaterThan]: durationTypeSchema.enum.repeat_until_heart_rate_greater_than,
|
|
1407
|
+
[fitDurationTypeSchema.enum.calories]: durationTypeSchema.enum.calories,
|
|
1408
|
+
[fitDurationTypeSchema.enum.powerLessThan]: durationTypeSchema.enum.power_less_than,
|
|
1409
|
+
[fitDurationTypeSchema.enum.powerGreaterThan]: durationTypeSchema.enum.power_greater_than,
|
|
1410
|
+
[fitDurationTypeSchema.enum.repeatUntilTime]: durationTypeSchema.enum.repeat_until_time,
|
|
1411
|
+
[fitDurationTypeSchema.enum.repeatUntilDistance]: durationTypeSchema.enum.repeat_until_distance,
|
|
1412
|
+
[fitDurationTypeSchema.enum.repeatUntilCalories]: durationTypeSchema.enum.repeat_until_calories,
|
|
1413
|
+
[fitDurationTypeSchema.enum.repeatUntilHrLessThan]: durationTypeSchema.enum.repeat_until_heart_rate_less_than,
|
|
1414
|
+
[fitDurationTypeSchema.enum.repeatUntilPowerLessThan]: durationTypeSchema.enum.repeat_until_power_less_than,
|
|
1415
|
+
[fitDurationTypeSchema.enum.repeatUntilPowerGreaterThan]: durationTypeSchema.enum.repeat_until_power_greater_than
|
|
1416
|
+
};
|
|
1376
1417
|
var mapDurationType = (fitDurationType) => {
|
|
1377
|
-
if (fitDurationType
|
|
1378
|
-
|
|
1379
|
-
if (fitDurationType === fitDurationTypeSchema.enum.distance)
|
|
1380
|
-
return durationTypeSchema.enum.distance;
|
|
1381
|
-
if (fitDurationType === fitDurationTypeSchema.enum.hrLessThan)
|
|
1382
|
-
return durationTypeSchema.enum.heart_rate_less_than;
|
|
1383
|
-
if (fitDurationType === fitDurationTypeSchema.enum.repeatUntilHrGreaterThan)
|
|
1384
|
-
return durationTypeSchema.enum.repeat_until_heart_rate_greater_than;
|
|
1385
|
-
if (fitDurationType === fitDurationTypeSchema.enum.calories)
|
|
1386
|
-
return durationTypeSchema.enum.calories;
|
|
1387
|
-
if (fitDurationType === fitDurationTypeSchema.enum.powerLessThan)
|
|
1388
|
-
return durationTypeSchema.enum.power_less_than;
|
|
1389
|
-
if (fitDurationType === fitDurationTypeSchema.enum.powerGreaterThan)
|
|
1390
|
-
return durationTypeSchema.enum.power_greater_than;
|
|
1391
|
-
if (fitDurationType === fitDurationTypeSchema.enum.repeatUntilTime)
|
|
1392
|
-
return durationTypeSchema.enum.repeat_until_time;
|
|
1393
|
-
if (fitDurationType === fitDurationTypeSchema.enum.repeatUntilDistance)
|
|
1394
|
-
return durationTypeSchema.enum.repeat_until_distance;
|
|
1395
|
-
if (fitDurationType === fitDurationTypeSchema.enum.repeatUntilCalories)
|
|
1396
|
-
return durationTypeSchema.enum.repeat_until_calories;
|
|
1397
|
-
if (fitDurationType === fitDurationTypeSchema.enum.repeatUntilHrLessThan)
|
|
1398
|
-
return durationTypeSchema.enum.repeat_until_heart_rate_less_than;
|
|
1399
|
-
if (fitDurationType === fitDurationTypeSchema.enum.repeatUntilPowerLessThan)
|
|
1400
|
-
return durationTypeSchema.enum.repeat_until_power_less_than;
|
|
1401
|
-
if (fitDurationType === fitDurationTypeSchema.enum.repeatUntilPowerGreaterThan)
|
|
1402
|
-
return durationTypeSchema.enum.repeat_until_power_greater_than;
|
|
1403
|
-
return durationTypeSchema.enum.open;
|
|
1418
|
+
if (!fitDurationType) return durationTypeSchema.enum.open;
|
|
1419
|
+
return FIT_TO_KRD_DURATION_TYPE[fitDurationType] ?? durationTypeSchema.enum.open;
|
|
1404
1420
|
};
|
|
1405
1421
|
var convertCadenceTarget2 = (data) => {
|
|
1406
1422
|
const rangeTarget = buildCadenceRangeTarget(data);
|
|
@@ -1830,22 +1846,24 @@ var mapWorkout = (workoutMsg, workoutSteps, logger) => {
|
|
|
1830
1846
|
}
|
|
1831
1847
|
return workout;
|
|
1832
1848
|
};
|
|
1833
|
-
var
|
|
1834
|
-
const { strict = true } = options;
|
|
1849
|
+
var checkFileId = (fileId, logger, strict) => {
|
|
1835
1850
|
if (!fileId) {
|
|
1836
1851
|
const message = "Missing required fileId message in FIT file";
|
|
1837
|
-
if (strict)
|
|
1838
|
-
throw createFitParsingError(message);
|
|
1839
|
-
}
|
|
1852
|
+
if (strict) throw createFitParsingError(message);
|
|
1840
1853
|
logger.warn(message);
|
|
1841
1854
|
}
|
|
1855
|
+
};
|
|
1856
|
+
var checkWorkoutMsg = (workoutMsg, logger, strict) => {
|
|
1842
1857
|
if (!workoutMsg) {
|
|
1843
1858
|
const message = "Missing required workout message in FIT file";
|
|
1844
|
-
if (strict)
|
|
1845
|
-
throw createFitParsingError(message);
|
|
1846
|
-
}
|
|
1859
|
+
if (strict) throw createFitParsingError(message);
|
|
1847
1860
|
logger.warn(message);
|
|
1848
1861
|
}
|
|
1862
|
+
};
|
|
1863
|
+
var validateMessages = (...[fileId, workoutMsg, messages, logger, options = {}]) => {
|
|
1864
|
+
const { strict = true } = options;
|
|
1865
|
+
checkFileId(fileId, logger, strict);
|
|
1866
|
+
checkWorkoutMsg(workoutMsg, logger, strict);
|
|
1849
1867
|
const workoutMessages = messages[fitMessageKeySchema.enum.workoutMesgs];
|
|
1850
1868
|
if (workoutMessages && workoutMessages.length > 1) {
|
|
1851
1869
|
logger.warn("Multiple workout messages found, using first one", {
|