@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 CHANGED
@@ -1,4 +1,4 @@
1
- import { sportSchema, durationTypeSchema, createConsoleLogger, createFitParsingError, fileTypeSchema, workoutSchema, isRepetitionBlock, convertLengthToMeters, subSportSchema, lengthUnitSchema, FIT_TO_SWIM_STROKE, equipmentSchema, targetTypeSchema, targetUnitSchema, intensitySchema } from '@kaiord/core';
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
- for (const message of value) {
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 mapFitRecordToKrd = (fit) => {
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
- record.position = {
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
- created,
1162
- sport: session?.sport ?? "other",
1163
- subSport: session?.subSport
1164
- },
1165
- sessions: session ? [session] : void 0,
1166
- laps: laps.length > 0 ? laps : void 0,
1167
- records: records.length > 0 ? records : void 0,
1168
- events: events.length > 0 ? events : void 0,
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 === fitDurationTypeSchema.enum.time)
1378
- return durationTypeSchema.enum.time;
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 validateMessages = (fileId, workoutMsg, messages, logger, options = {}) => {
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", {