trainingpeaks-sdk
Version:
TypeScript SDK for TrainingPeaks API integration
163 lines (162 loc) • 6.57 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getAggregateSummary = exports.isAggregateConsistent = exports.getAggregateDuration = exports.removeWorkoutFile = exports.addWorkoutFile = exports.removeWorkoutStructure = exports.updateWorkoutStructure = exports.updateWorkoutAggregate = exports.createWorkoutAggregate = void 0;
const domain_errors_1 = require("../../domain/errors/domain-errors.js");
const workout_errors_1 = require("../../domain/errors/workout-errors.js");
const workout_1 = require("./workout.js");
const createWorkoutAggregate = (id, name, date, duration, description, distance, activityType, structure, fileContent, fileName) => {
let workout;
if (structure) {
validateWorkoutStructure(structure);
const calculatedDuration = (0, workout_1.calculateWorkoutDuration)(structure);
if (Math.abs(duration - calculatedDuration) > 1) {
throw new workout_errors_1.WorkoutValidationError(`Provided duration (${duration}s) does not match calculated duration (${calculatedDuration}s)`);
}
workout = (0, workout_1.createStructuredWorkout)(id, name, date, structure, description, activityType);
}
else {
workout = (0, workout_1.createWorkout)(id, name, date, duration, description, distance, activityType, structure, fileContent, fileName);
}
return {
workout,
structure,
};
};
exports.createWorkoutAggregate = createWorkoutAggregate;
const updateWorkoutAggregate = (aggregate, updates) => {
const updatedWorkout = (0, workout_1.updateWorkout)(aggregate.workout, updates);
return {
...aggregate,
workout: updatedWorkout,
};
};
exports.updateWorkoutAggregate = updateWorkoutAggregate;
const updateWorkoutStructure = (aggregate, newStructure) => {
validateWorkoutStructure(newStructure);
const newDuration = (0, workout_1.calculateWorkoutDuration)(newStructure);
const updatedWorkout = {
...aggregate.workout,
structure: newStructure,
duration: newDuration,
updatedAt: new Date(),
};
return {
workout: updatedWorkout,
structure: newStructure,
};
};
exports.updateWorkoutStructure = updateWorkoutStructure;
const removeWorkoutStructure = (aggregate, newDuration) => {
if (newDuration < 0 || !isFinite(newDuration)) {
throw new domain_errors_1.ValidationError('Duration must be a non-negative finite number', 'duration');
}
const updatedWorkout = {
...aggregate.workout,
structure: undefined,
duration: newDuration,
updatedAt: new Date(),
};
return {
workout: updatedWorkout,
structure: undefined,
};
};
exports.removeWorkoutStructure = removeWorkoutStructure;
const addWorkoutFile = (aggregate, fileContent, fileName) => {
if (!fileContent || !fileName) {
throw new domain_errors_1.ValidationError('File content and name are required');
}
if (fileName.trim().length > 255) {
throw new domain_errors_1.ValidationError('File name cannot exceed 255 characters', 'fileName');
}
const updatedWorkout = {
...aggregate.workout,
fileContent,
fileName: fileName.trim(),
updatedAt: new Date(),
};
return {
...aggregate,
workout: updatedWorkout,
};
};
exports.addWorkoutFile = addWorkoutFile;
const removeWorkoutFile = (aggregate) => {
const updatedWorkout = {
...aggregate.workout,
fileContent: undefined,
fileName: undefined,
updatedAt: new Date(),
};
return {
...aggregate,
workout: updatedWorkout,
};
};
exports.removeWorkoutFile = removeWorkoutFile;
const getAggregateDuration = (aggregate) => {
if (aggregate.structure) {
return (0, workout_1.calculateWorkoutDuration)(aggregate.structure);
}
return aggregate.workout.duration;
};
exports.getAggregateDuration = getAggregateDuration;
const isAggregateConsistent = (aggregate) => {
try {
if (aggregate.structure) {
const calculatedDuration = (0, workout_1.calculateWorkoutDuration)(aggregate.structure);
const durationDiff = Math.abs(aggregate.workout.duration - calculatedDuration);
if (durationDiff > 1) {
return false;
}
validateWorkoutStructure(aggregate.structure);
}
if (aggregate.workout.fileContent && !aggregate.workout.fileName) {
return false;
}
if (!aggregate.workout.fileContent && aggregate.workout.fileName) {
return false;
}
return true;
}
catch {
return false;
}
};
exports.isAggregateConsistent = isAggregateConsistent;
const getAggregateSummary = (aggregate) => {
const { workout, structure } = aggregate;
return {
id: workout.id,
name: workout.name,
date: workout.date,
duration: (0, exports.getAggregateDuration)(aggregate),
distance: workout.distance,
activityType: workout.activityType,
isStructured: Boolean(structure),
hasFile: Boolean(workout.fileContent),
structureElementCount: structure?.structure.length || 0,
isConsistent: (0, exports.isAggregateConsistent)(aggregate),
};
};
exports.getAggregateSummary = getAggregateSummary;
const validateWorkoutStructure = (structure) => {
if (!structure.structure || structure.structure.length === 0) {
throw new workout_errors_1.WorkoutStructureError('Workout structure must contain at least one element');
}
for (let i = 0; i < structure.structure.length - 1; i++) {
const current = structure.structure[i];
const next = structure.structure[i + 1];
if (current && next && current.end > next.begin) {
throw new workout_errors_1.WorkoutStructureError(`Structure elements overlap: element ${i} ends after element ${i + 1} begins`, { elementIndex: i, nextElementIndex: i + 1 });
}
}
structure.structure.forEach((element, index) => {
if (!element.steps || element.steps.length === 0) {
throw new workout_errors_1.WorkoutStructureError(`Structure element ${index} must have at least one step`, { elementIndex: index });
}
if (element.end <= element.begin) {
throw new workout_errors_1.WorkoutStructureError(`Structure element ${index} end time must be greater than begin time`, { elementIndex: index, begin: element.begin, end: element.end });
}
});
};