@kaiord/fit 4.8.1 → 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
@@ -3,6 +3,13 @@ import { Stream, Decoder, Encoder, Profile } from '@garmin/fitsdk';
3
3
  import { z } from 'zod';
4
4
 
5
5
  // src/index.ts
6
+
7
+ // src/adapters/shared/message-numbers.ts
8
+ var FIT_MESSAGE_NUMBERS = {
9
+ FILE_ID: 0,
10
+ WORKOUT: 26,
11
+ WORKOUT_STEP: 27
12
+ };
6
13
  z.enum([
7
14
  "device",
8
15
  "settings",
@@ -276,6 +283,49 @@ var fitDurationTypeSchema = z.enum([
276
283
  "repeatUntilPowerGreaterThan",
277
284
  "open"
278
285
  ]);
286
+ var fitTargetTypeSchema = z.enum([
287
+ "power",
288
+ "heartRate",
289
+ "cadence",
290
+ "speed",
291
+ "swimStroke",
292
+ "open"
293
+ ]);
294
+ var fitEquipmentSchema = z.enum([
295
+ "none",
296
+ "swimFins",
297
+ "swimKickboard",
298
+ "swimPaddles",
299
+ "swimPullBuoy",
300
+ "swimSnorkel"
301
+ ]);
302
+
303
+ // src/adapters/equipment/equipment.mapper.ts
304
+ var FIT_TO_KRD_EQUIPMENT_MAP = {
305
+ none: "none",
306
+ swimFins: "swim_fins",
307
+ swimKickboard: "swim_kickboard",
308
+ swimPaddles: "swim_paddles",
309
+ swimPullBuoy: "swim_pull_buoy",
310
+ swimSnorkel: "swim_snorkel"
311
+ };
312
+ var KRD_TO_FIT_EQUIPMENT_MAP = Object.fromEntries(
313
+ Object.entries(FIT_TO_KRD_EQUIPMENT_MAP).map(([fit, krd]) => [krd, fit])
314
+ );
315
+ var mapEquipmentToKrd = (fitEquipment) => {
316
+ const result = fitEquipmentSchema.safeParse(fitEquipment);
317
+ if (!result.success) {
318
+ return equipmentSchema.enum.none;
319
+ }
320
+ return FIT_TO_KRD_EQUIPMENT_MAP[result.data] || equipmentSchema.enum.none;
321
+ };
322
+ var mapEquipmentToFit = (krdEquipment) => {
323
+ const result = equipmentSchema.safeParse(krdEquipment);
324
+ if (!result.success) {
325
+ return fitEquipmentSchema.enum.none;
326
+ }
327
+ return KRD_TO_FIT_EQUIPMENT_MAP[result.data] || fitEquipmentSchema.enum.none;
328
+ };
279
329
  var convertConditionalDuration = (duration, message) => {
280
330
  if (duration.type === durationTypeSchema.enum.heart_rate_less_than) {
281
331
  message.durationType = fitDurationTypeSchema.enum.hrLessThan;
@@ -371,16 +421,6 @@ var convertDuration = (step, message) => {
371
421
  if (convertRepeatHrPowerDuration(duration, message)) return;
372
422
  message.durationType = fitDurationTypeSchema.enum.open;
373
423
  };
374
- var fitTargetTypeSchema = z.enum([
375
- "power",
376
- "heartRate",
377
- "cadence",
378
- "speed",
379
- "swimStroke",
380
- "open"
381
- ]);
382
-
383
- // src/adapters/krd-to-fit/krd-to-fit-target-cadence.mapper.ts
384
424
  var convertCadenceTarget = (step, message) => {
385
425
  message.targetType = fitTargetTypeSchema.enum.cadence;
386
426
  if (step.target.type !== targetTypeSchema.enum.cadence) return;
@@ -468,41 +508,6 @@ var convertTarget = (step, message) => {
468
508
  convertStrokeTarget(step, message);
469
509
  }
470
510
  };
471
- var fitEquipmentSchema = z.enum([
472
- "none",
473
- "swimFins",
474
- "swimKickboard",
475
- "swimPaddles",
476
- "swimPullBuoy",
477
- "swimSnorkel"
478
- ]);
479
-
480
- // src/adapters/equipment/equipment.mapper.ts
481
- var FIT_TO_KRD_EQUIPMENT_MAP = {
482
- none: "none",
483
- swimFins: "swim_fins",
484
- swimKickboard: "swim_kickboard",
485
- swimPaddles: "swim_paddles",
486
- swimPullBuoy: "swim_pull_buoy",
487
- swimSnorkel: "swim_snorkel"
488
- };
489
- var KRD_TO_FIT_EQUIPMENT_MAP = Object.fromEntries(
490
- Object.entries(FIT_TO_KRD_EQUIPMENT_MAP).map(([fit, krd]) => [krd, fit])
491
- );
492
- var mapEquipmentToKrd = (fitEquipment) => {
493
- const result = fitEquipmentSchema.safeParse(fitEquipment);
494
- if (!result.success) {
495
- return equipmentSchema.enum.none;
496
- }
497
- return FIT_TO_KRD_EQUIPMENT_MAP[result.data] || equipmentSchema.enum.none;
498
- };
499
- var mapEquipmentToFit = (krdEquipment) => {
500
- const result = equipmentSchema.safeParse(krdEquipment);
501
- if (!result.success) {
502
- return fitEquipmentSchema.enum.none;
503
- }
504
- return KRD_TO_FIT_EQUIPMENT_MAP[result.data] || fitEquipmentSchema.enum.none;
505
- };
506
511
 
507
512
  // src/adapters/krd-to-fit/krd-to-fit-step.mapper.ts
508
513
  var FIT_NOTES_MAX_LENGTH = 256;
@@ -549,13 +554,6 @@ var convertNotes = (notes, stepIndex, behavior, logger) => {
549
554
  return notes.substring(0, FIT_NOTES_MAX_LENGTH);
550
555
  };
551
556
 
552
- // src/adapters/shared/message-numbers.ts
553
- var FIT_MESSAGE_NUMBERS = {
554
- FILE_ID: 0,
555
- WORKOUT: 26,
556
- WORKOUT_STEP: 27
557
- };
558
-
559
557
  // src/adapters/krd-to-fit/krd-to-fit-workout.mapper.ts
560
558
  var convertWorkoutSteps = (workout, logger, options = {}) => {
561
559
  logger.debug("Converting workout steps", { stepCount: workout.steps.length });
@@ -666,6 +664,15 @@ var validateCoordinates = (latSemicircles, lonSemicircles) => {
666
664
  const degreesLon = semicirclesToDegrees(lonSemicircles);
667
665
  return degreesLat >= -90 && degreesLat <= 90 && degreesLon >= -180 && degreesLon <= 180;
668
666
  };
667
+ var fitMessageKeySchema = z.enum([
668
+ "fileIdMesgs",
669
+ "workoutMesgs",
670
+ "workoutStepMesgs",
671
+ "sessionMesgs",
672
+ "recordMesgs",
673
+ "eventMesgs",
674
+ "lapMesgs"
675
+ ]);
669
676
 
670
677
  // src/adapters/event/event-type-maps.ts
671
678
  var FIT_EVENT_TO_KRD_TYPE = {
@@ -795,15 +802,34 @@ var convertFitToKrdEvent = (data) => {
795
802
  var convertFitToKrdEvents = (events) => {
796
803
  return events.map(convertFitToKrdEvent);
797
804
  };
798
- var fitMessageKeySchema = z.enum([
799
- "fileIdMesgs",
800
- "workoutMesgs",
801
- "workoutStepMesgs",
802
- "sessionMesgs",
803
- "recordMesgs",
804
- "eventMesgs",
805
- "lapMesgs"
806
- ]);
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
+ };
807
833
 
808
834
  // src/adapters/extensions/extensions.extractor.ts
809
835
  var extractFitExtensions = (messages, logger) => {
@@ -831,30 +857,11 @@ var extractAllDeveloperFields = (messages) => {
831
857
  const developerFields = [];
832
858
  for (const value of Object.values(messages)) {
833
859
  if (value && Array.isArray(value)) {
834
- for (const message of value) {
835
- if (message && typeof message === "object") {
836
- const devFields = extractDeveloperFields(message);
837
- if (devFields.length > 0) {
838
- developerFields.push(...devFields);
839
- }
840
- }
841
- }
860
+ developerFields.push(...extractFieldsFromMessageArray(value));
842
861
  }
843
862
  }
844
863
  return developerFields;
845
864
  };
846
- var extractDeveloperFields = (message) => {
847
- const devFields = [];
848
- for (const [key, value] of Object.entries(message)) {
849
- if (key.startsWith("developer_") || key.includes("DeveloperField")) {
850
- devFields.push({
851
- fieldName: key,
852
- value
853
- });
854
- }
855
- }
856
- return devFields;
857
- };
858
865
  var buildExtensions = (unknownMessages, developerFields, logger) => {
859
866
  const extensions = {};
860
867
  if (developerFields.length > 0) {
@@ -871,64 +878,6 @@ var buildExtensions = (unknownMessages, developerFields, logger) => {
871
878
  }
872
879
  return extensions;
873
880
  };
874
-
875
- // src/adapters/lap/lap-trigger.mapper.ts
876
- var mapFitLapTriggerToKrd = (fit) => {
877
- switch (fit) {
878
- case "manual":
879
- return "manual";
880
- case "time":
881
- return "time";
882
- case "distance":
883
- return "distance";
884
- case "positionStart":
885
- case "positionLap":
886
- case "positionWaypoint":
887
- case "positionMarked":
888
- return "position";
889
- case "sessionEnd":
890
- return "session_end";
891
- case "fitnessEquipment":
892
- return "fitness_equipment";
893
- }
894
- };
895
-
896
- // src/adapters/lap/lap.mapper.ts
897
- var mapFitLapToKrd = (fit) => ({
898
- // Timing - convert ms to seconds
899
- startTime: new Date(fit.startTime * 1e3).toISOString(),
900
- totalElapsedTime: fit.totalElapsedTime / 1e3,
901
- totalTimerTime: fit.totalTimerTime / 1e3,
902
- // Distance
903
- totalDistance: fit.totalDistance,
904
- // Heart rate
905
- avgHeartRate: fit.avgHeartRate,
906
- maxHeartRate: fit.maxHeartRate,
907
- // Cadence
908
- avgCadence: fit.avgCadence,
909
- maxCadence: fit.maxCadence,
910
- // Power
911
- avgPower: fit.avgPower,
912
- maxPower: fit.maxPower,
913
- normalizedPower: fit.normalizedPower,
914
- // Speed - prefer enhanced values
915
- avgSpeed: fit.enhancedAvgSpeed ?? fit.avgSpeed,
916
- maxSpeed: fit.enhancedMaxSpeed ?? fit.maxSpeed,
917
- // Elevation
918
- totalAscent: fit.totalAscent,
919
- totalDescent: fit.totalDescent,
920
- // Calories
921
- totalCalories: fit.totalCalories,
922
- // Classification
923
- trigger: fit.lapTrigger ? mapFitLapTriggerToKrd(fit.lapTrigger) : void 0,
924
- sport: fit.sport,
925
- subSport: fit.subSport ? mapSubSportToKrd(fit.subSport) : void 0,
926
- // Workout reference
927
- workoutStepIndex: fit.wktStepIndex,
928
- // Swimming
929
- numLengths: fit.numLengths,
930
- swimStroke: fit.swimStroke !== void 0 ? FIT_TO_SWIM_STROKE[fit.swimStroke] : void 0
931
- });
932
881
  var fitLapTriggerSchema = z.enum([
933
882
  "manual",
934
883
  "time",
@@ -989,6 +938,64 @@ var fitLapSchema = z.object({
989
938
  wktStepIndex: z.number().optional()
990
939
  });
991
940
 
941
+ // src/adapters/lap/lap-trigger.mapper.ts
942
+ var mapFitLapTriggerToKrd = (fit) => {
943
+ switch (fit) {
944
+ case "manual":
945
+ return "manual";
946
+ case "time":
947
+ return "time";
948
+ case "distance":
949
+ return "distance";
950
+ case "positionStart":
951
+ case "positionLap":
952
+ case "positionWaypoint":
953
+ case "positionMarked":
954
+ return "position";
955
+ case "sessionEnd":
956
+ return "session_end";
957
+ case "fitnessEquipment":
958
+ return "fitness_equipment";
959
+ }
960
+ };
961
+
962
+ // src/adapters/lap/fit-to-krd-lap.mapper.ts
963
+ var mapFitLapToKrd = (fit) => ({
964
+ // Timing - convert ms to seconds
965
+ startTime: new Date(fit.startTime * 1e3).toISOString(),
966
+ totalElapsedTime: fit.totalElapsedTime / 1e3,
967
+ totalTimerTime: fit.totalTimerTime / 1e3,
968
+ // Distance
969
+ totalDistance: fit.totalDistance,
970
+ // Heart rate
971
+ avgHeartRate: fit.avgHeartRate,
972
+ maxHeartRate: fit.maxHeartRate,
973
+ // Cadence
974
+ avgCadence: fit.avgCadence,
975
+ maxCadence: fit.maxCadence,
976
+ // Power
977
+ avgPower: fit.avgPower,
978
+ maxPower: fit.maxPower,
979
+ normalizedPower: fit.normalizedPower,
980
+ // Speed - prefer enhanced values
981
+ avgSpeed: fit.enhancedAvgSpeed ?? fit.avgSpeed,
982
+ maxSpeed: fit.enhancedMaxSpeed ?? fit.maxSpeed,
983
+ // Elevation
984
+ totalAscent: fit.totalAscent,
985
+ totalDescent: fit.totalDescent,
986
+ // Calories
987
+ totalCalories: fit.totalCalories,
988
+ // Classification
989
+ trigger: fit.lapTrigger ? mapFitLapTriggerToKrd(fit.lapTrigger) : void 0,
990
+ sport: fit.sport,
991
+ subSport: fit.subSport ? mapSubSportToKrd(fit.subSport) : void 0,
992
+ // Workout reference
993
+ workoutStepIndex: fit.wktStepIndex,
994
+ // Swimming
995
+ numLengths: fit.numLengths,
996
+ swimStroke: fit.swimStroke !== void 0 ? FIT_TO_SWIM_STROKE[fit.swimStroke] : void 0
997
+ });
998
+
992
999
  // src/adapters/lap/fit-to-krd-lap.converter.ts
993
1000
  var convertFitToKrdLap = (data) => {
994
1001
  const fitLap = fitLapSchema.parse(data);
@@ -997,18 +1004,38 @@ var convertFitToKrdLap = (data) => {
997
1004
  var convertFitToKrdLaps = (laps) => {
998
1005
  return laps.map(convertFitToKrdLap);
999
1006
  };
1007
+ var fitRecordSchema = z.object({
1008
+ timestamp: z.number(),
1009
+ positionLat: z.number().optional(),
1010
+ positionLong: z.number().optional(),
1011
+ altitude: z.number().optional(),
1012
+ enhancedAltitude: z.number().optional(),
1013
+ speed: z.number().optional(),
1014
+ enhancedSpeed: z.number().optional(),
1015
+ distance: z.number().optional(),
1016
+ heartRate: z.number().optional(),
1017
+ cadence: z.number().optional(),
1018
+ fractionalCadence: z.number().optional(),
1019
+ power: z.number().optional(),
1020
+ temperature: z.number().optional(),
1021
+ verticalOscillation: z.number().optional(),
1022
+ stanceTime: z.number().optional(),
1023
+ stanceTimePercent: z.number().optional(),
1024
+ stepLength: z.number().optional(),
1025
+ compressedTimestamp: z.number().optional()
1026
+ });
1000
1027
 
1001
- // src/adapters/record/record.mapper.ts
1002
- var mapFitRecordToKrd = (fit) => {
1003
- const record = {
1004
- timestamp: new Date(fit.timestamp * 1e3).toISOString()
1005
- };
1028
+ // src/adapters/record/record-from-fit.mapper.ts
1029
+ var mapFitPosition = (fit) => {
1006
1030
  if (fit.positionLat !== void 0 && fit.positionLong !== void 0) {
1007
- record.position = {
1031
+ return {
1008
1032
  lat: semicirclesToDegrees(fit.positionLat),
1009
1033
  lon: semicirclesToDegrees(fit.positionLong)
1010
1034
  };
1011
1035
  }
1036
+ return void 0;
1037
+ };
1038
+ var mapFitAltitudeAndSpeed = (fit, record) => {
1012
1039
  if (fit.enhancedAltitude !== void 0) {
1013
1040
  record.altitude = fit.enhancedAltitude;
1014
1041
  } else if (fit.altitude !== void 0) {
@@ -1019,6 +1046,8 @@ var mapFitRecordToKrd = (fit) => {
1019
1046
  } else if (fit.speed !== void 0) {
1020
1047
  record.speed = fit.speed;
1021
1048
  }
1049
+ };
1050
+ var mapFitCoreFields = (fit, record) => {
1022
1051
  if (fit.distance !== void 0) record.distance = fit.distance;
1023
1052
  if (fit.heartRate !== void 0) record.heartRate = fit.heartRate;
1024
1053
  if (fit.power !== void 0) record.power = fit.power;
@@ -1026,33 +1055,25 @@ var mapFitRecordToKrd = (fit) => {
1026
1055
  if (fit.cadence !== void 0) {
1027
1056
  record.cadence = fit.cadence + (fit.fractionalCadence ?? 0);
1028
1057
  }
1058
+ };
1059
+ var mapFitRunningDynamics = (fit, record) => {
1029
1060
  if (fit.verticalOscillation !== void 0) {
1030
1061
  record.verticalOscillation = fit.verticalOscillation;
1031
1062
  }
1032
1063
  if (fit.stanceTime !== void 0) record.stanceTime = fit.stanceTime;
1033
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);
1034
1075
  return record;
1035
1076
  };
1036
- var fitRecordSchema = z.object({
1037
- timestamp: z.number(),
1038
- positionLat: z.number().optional(),
1039
- positionLong: z.number().optional(),
1040
- altitude: z.number().optional(),
1041
- enhancedAltitude: z.number().optional(),
1042
- speed: z.number().optional(),
1043
- enhancedSpeed: z.number().optional(),
1044
- distance: z.number().optional(),
1045
- heartRate: z.number().optional(),
1046
- cadence: z.number().optional(),
1047
- fractionalCadence: z.number().optional(),
1048
- power: z.number().optional(),
1049
- temperature: z.number().optional(),
1050
- verticalOscillation: z.number().optional(),
1051
- stanceTime: z.number().optional(),
1052
- stanceTimePercent: z.number().optional(),
1053
- stepLength: z.number().optional(),
1054
- compressedTimestamp: z.number().optional()
1055
- });
1056
1077
 
1057
1078
  // src/adapters/record/fit-to-krd-record.converter.ts
1058
1079
  var convertFitToKrdRecord = (data) => {
@@ -1072,30 +1093,6 @@ var convertFitToKrdRecord = (data) => {
1072
1093
  var convertFitToKrdRecords = (records) => {
1073
1094
  return records.map(convertFitToKrdRecord);
1074
1095
  };
1075
-
1076
- // src/adapters/session/session.mapper.ts
1077
- var mapFitSessionToKrd = (fit) => ({
1078
- startTime: new Date(fit.startTime * 1e3).toISOString(),
1079
- totalElapsedTime: fit.totalElapsedTime / 1e3,
1080
- totalTimerTime: fit.totalTimerTime !== void 0 ? fit.totalTimerTime / 1e3 : void 0,
1081
- totalDistance: fit.totalDistance,
1082
- sport: String(fit.sport),
1083
- subSport: fit.subSport ? mapSubSportToKrd(fit.subSport) : void 0,
1084
- avgHeartRate: fit.avgHeartRate,
1085
- maxHeartRate: fit.maxHeartRate,
1086
- avgCadence: fit.avgCadence,
1087
- maxCadence: fit.maxCadence,
1088
- avgPower: fit.avgPower,
1089
- maxPower: fit.maxPower,
1090
- normalizedPower: fit.normalizedPower,
1091
- trainingStressScore: fit.trainingStressScore,
1092
- intensityFactor: fit.intensityFactor,
1093
- totalCalories: fit.totalCalories,
1094
- totalAscent: fit.totalAscent,
1095
- totalDescent: fit.totalDescent,
1096
- avgSpeed: fit.enhancedAvgSpeed ?? fit.avgSpeed,
1097
- maxSpeed: fit.enhancedMaxSpeed ?? fit.maxSpeed
1098
- });
1099
1096
  var fitSessionSchema = z.object({
1100
1097
  timestamp: z.number(),
1101
1098
  startTime: z.number(),
@@ -1124,6 +1121,30 @@ var fitSessionSchema = z.object({
1124
1121
  firstLapIndex: z.number().optional()
1125
1122
  });
1126
1123
 
1124
+ // src/adapters/session/session.mapper.ts
1125
+ var mapFitSessionToKrd = (fit) => ({
1126
+ startTime: new Date(fit.startTime * 1e3).toISOString(),
1127
+ totalElapsedTime: fit.totalElapsedTime / 1e3,
1128
+ totalTimerTime: fit.totalTimerTime !== void 0 ? fit.totalTimerTime / 1e3 : void 0,
1129
+ totalDistance: fit.totalDistance,
1130
+ sport: String(fit.sport),
1131
+ subSport: fit.subSport ? mapSubSportToKrd(fit.subSport) : void 0,
1132
+ avgHeartRate: fit.avgHeartRate,
1133
+ maxHeartRate: fit.maxHeartRate,
1134
+ avgCadence: fit.avgCadence,
1135
+ maxCadence: fit.maxCadence,
1136
+ avgPower: fit.avgPower,
1137
+ maxPower: fit.maxPower,
1138
+ normalizedPower: fit.normalizedPower,
1139
+ trainingStressScore: fit.trainingStressScore,
1140
+ intensityFactor: fit.intensityFactor,
1141
+ totalCalories: fit.totalCalories,
1142
+ totalAscent: fit.totalAscent,
1143
+ totalDescent: fit.totalDescent,
1144
+ avgSpeed: fit.enhancedAvgSpeed ?? fit.avgSpeed,
1145
+ maxSpeed: fit.enhancedMaxSpeed ?? fit.maxSpeed
1146
+ });
1147
+
1127
1148
  // src/adapters/session/fit-to-krd-session.converter.ts
1128
1149
  var convertFitToKrdSession = (data) => {
1129
1150
  const fitSession = fitSessionSchema.parse(data);
@@ -1138,6 +1159,13 @@ var convertTimeCreated = (timeCreated) => {
1138
1159
  return new Date(timeCreated * 1e3).toISOString();
1139
1160
  return (/* @__PURE__ */ new Date()).toISOString();
1140
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;
1141
1169
  var mapActivityFileToKRD = (messages, logger) => {
1142
1170
  const fileId = messages[fitMessageKeySchema.enum.fileIdMesgs]?.[0];
1143
1171
  const sessionMsgs = messages[fitMessageKeySchema.enum.sessionMesgs] || [];
@@ -1155,47 +1183,20 @@ var mapActivityFileToKRD = (messages, logger) => {
1155
1183
  const events = convertFitToKrdEvents(eventMsgs);
1156
1184
  const laps = convertFitToKrdLaps(lapMsgs);
1157
1185
  const fitExtensions = extractFitExtensions(messages, logger);
1158
- const created = convertTimeCreated(fileId?.timeCreated);
1159
1186
  return {
1160
1187
  version: KRD_VERSION,
1161
1188
  type: fileTypeSchema.enum.recorded_activity,
1162
- metadata: {
1163
- created,
1164
- sport: session?.sport ?? "other",
1165
- subSport: session?.subSport
1166
- },
1167
- sessions: session ? [session] : void 0,
1168
- laps: laps.length > 0 ? laps : void 0,
1169
- records: records.length > 0 ? records : void 0,
1170
- events: events.length > 0 ? events : void 0,
1171
- extensions: {
1172
- fit: fitExtensions
1173
- }
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 }
1174
1198
  };
1175
1199
  };
1176
- var validateMessages = (fileId, workoutMsg, messages, logger, options = {}) => {
1177
- const { strict = true } = options;
1178
- if (!fileId) {
1179
- const message = "Missing required fileId message in FIT file";
1180
- if (strict) {
1181
- throw createFitParsingError(message);
1182
- }
1183
- logger.warn(message);
1184
- }
1185
- if (!workoutMsg) {
1186
- const message = "Missing required workout message in FIT file";
1187
- if (strict) {
1188
- throw createFitParsingError(message);
1189
- }
1190
- logger.warn(message);
1191
- }
1192
- const workoutMessages = messages[fitMessageKeySchema.enum.workoutMesgs];
1193
- if (workoutMessages && workoutMessages.length > 1) {
1194
- logger.warn("Multiple workout messages found, using first one", {
1195
- count: workoutMessages.length
1196
- });
1197
- }
1198
- };
1199
1200
  var DEFAULT_SPORT = sportSchema.enum.cycling;
1200
1201
  var mapSportType = (fitSport) => {
1201
1202
  if (!fitSport) {
@@ -1231,6 +1232,16 @@ var mapCreatedTimestamp = (fileId) => {
1231
1232
  }
1232
1233
  return (/* @__PURE__ */ new Date()).toISOString();
1233
1234
  };
1235
+ var FIT_LENGTH_UNIT_MAP = {
1236
+ 0: "meters",
1237
+ 1: "yards"
1238
+ };
1239
+ var mapLengthUnitToKrd = (fitUnit) => {
1240
+ if (fitUnit === void 0) {
1241
+ return lengthUnitSchema.enum.meters;
1242
+ }
1243
+ return FIT_LENGTH_UNIT_MAP[fitUnit] || lengthUnitSchema.enum.meters;
1244
+ };
1234
1245
  var convertTimeDuration = (data) => {
1235
1246
  if (data.durationTime !== void 0) {
1236
1247
  return {
@@ -1388,34 +1399,24 @@ var convertFitDuration = (data) => {
1388
1399
  var mapDuration = (step) => {
1389
1400
  return convertFitDuration(step);
1390
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
+ };
1391
1417
  var mapDurationType = (fitDurationType) => {
1392
- if (fitDurationType === fitDurationTypeSchema.enum.time)
1393
- return durationTypeSchema.enum.time;
1394
- if (fitDurationType === fitDurationTypeSchema.enum.distance)
1395
- return durationTypeSchema.enum.distance;
1396
- if (fitDurationType === fitDurationTypeSchema.enum.hrLessThan)
1397
- return durationTypeSchema.enum.heart_rate_less_than;
1398
- if (fitDurationType === fitDurationTypeSchema.enum.repeatUntilHrGreaterThan)
1399
- return durationTypeSchema.enum.repeat_until_heart_rate_greater_than;
1400
- if (fitDurationType === fitDurationTypeSchema.enum.calories)
1401
- return durationTypeSchema.enum.calories;
1402
- if (fitDurationType === fitDurationTypeSchema.enum.powerLessThan)
1403
- return durationTypeSchema.enum.power_less_than;
1404
- if (fitDurationType === fitDurationTypeSchema.enum.powerGreaterThan)
1405
- return durationTypeSchema.enum.power_greater_than;
1406
- if (fitDurationType === fitDurationTypeSchema.enum.repeatUntilTime)
1407
- return durationTypeSchema.enum.repeat_until_time;
1408
- if (fitDurationType === fitDurationTypeSchema.enum.repeatUntilDistance)
1409
- return durationTypeSchema.enum.repeat_until_distance;
1410
- if (fitDurationType === fitDurationTypeSchema.enum.repeatUntilCalories)
1411
- return durationTypeSchema.enum.repeat_until_calories;
1412
- if (fitDurationType === fitDurationTypeSchema.enum.repeatUntilHrLessThan)
1413
- return durationTypeSchema.enum.repeat_until_heart_rate_less_than;
1414
- if (fitDurationType === fitDurationTypeSchema.enum.repeatUntilPowerLessThan)
1415
- return durationTypeSchema.enum.repeat_until_power_less_than;
1416
- if (fitDurationType === fitDurationTypeSchema.enum.repeatUntilPowerGreaterThan)
1417
- return durationTypeSchema.enum.repeat_until_power_greater_than;
1418
- return durationTypeSchema.enum.open;
1418
+ if (!fitDurationType) return durationTypeSchema.enum.open;
1419
+ return FIT_TO_KRD_DURATION_TYPE[fitDurationType] ?? durationTypeSchema.enum.open;
1419
1420
  };
1420
1421
  var convertCadenceTarget2 = (data) => {
1421
1422
  const rangeTarget = buildCadenceRangeTarget(data);
@@ -1822,16 +1823,6 @@ var buildRepetitionBlock = (step, workoutSteps, currentIndex) => {
1822
1823
  steps: repeatedSteps
1823
1824
  };
1824
1825
  };
1825
- var FIT_LENGTH_UNIT_MAP = {
1826
- 0: "meters",
1827
- 1: "yards"
1828
- };
1829
- var mapLengthUnitToKrd = (fitUnit) => {
1830
- if (fitUnit === void 0) {
1831
- return lengthUnitSchema.enum.meters;
1832
- }
1833
- return FIT_LENGTH_UNIT_MAP[fitUnit] || lengthUnitSchema.enum.meters;
1834
- };
1835
1826
 
1836
1827
  // src/adapters/workout/workout.mapper.ts
1837
1828
  var mapWorkout = (workoutMsg, workoutSteps, logger) => {
@@ -1855,6 +1846,31 @@ var mapWorkout = (workoutMsg, workoutSteps, logger) => {
1855
1846
  }
1856
1847
  return workout;
1857
1848
  };
1849
+ var checkFileId = (fileId, logger, strict) => {
1850
+ if (!fileId) {
1851
+ const message = "Missing required fileId message in FIT file";
1852
+ if (strict) throw createFitParsingError(message);
1853
+ logger.warn(message);
1854
+ }
1855
+ };
1856
+ var checkWorkoutMsg = (workoutMsg, logger, strict) => {
1857
+ if (!workoutMsg) {
1858
+ const message = "Missing required workout message in FIT file";
1859
+ if (strict) throw createFitParsingError(message);
1860
+ logger.warn(message);
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);
1867
+ const workoutMessages = messages[fitMessageKeySchema.enum.workoutMesgs];
1868
+ if (workoutMessages && workoutMessages.length > 1) {
1869
+ logger.warn("Multiple workout messages found, using first one", {
1870
+ count: workoutMessages.length
1871
+ });
1872
+ }
1873
+ };
1858
1874
 
1859
1875
  // src/adapters/messages/workout.mapper.ts
1860
1876
  var KRD_VERSION2 = "1.0";