trackswap 0.0.17 → 0.0.18

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.cjs CHANGED
@@ -23,4 +23,4 @@
23
23
  `)}buildPosition(e){let t=["<Position>"];return e.LatitudeDegrees&&t.push(`<LatitudeDegrees>${this.formatCoordinate(parseFloat(e.LatitudeDegrees))}</LatitudeDegrees>`),e.LongitudeDegrees&&t.push(`<LongitudeDegrees>${this.formatCoordinate(parseFloat(e.LongitudeDegrees))}</LongitudeDegrees>`),t.push("</Position>"),t.join("")}buildCadence(e){return`<Cadence><Low>${e.Low}</Low><High>${e.High}</High></Cadence>`}buildMultiActivitySession(e){let t=["<MultiActivitySession>"];return e.Id&&t.push(`<Id>${this.formatTime(e.Id)}</Id>`),e.FirstActivity&&t.push(this.buildFirstActivity(e.FirstActivity)),e.NextActivity&&e.NextActivity.forEach(r=>{t.push(this.buildNextActivity(r))}),this.addOptionalElement(t,"Notes",e.Notes),t.push("</MultiActivitySession>"),t.join(`
24
24
  `)}buildFirstActivity(e){let t=["<FirstActivity>"];return e.Activity&&t.push(this.buildActivity(e.Activity)),t.push("</FirstActivity>"),t.join(`
25
25
  `)}buildNextActivity(e){let t=["<NextActivity>"];return e.Transition&&t.push(`<Transition>${this.buildActivityLap(e.Transition)}</Transition>`),e.Activity&&t.push(this.buildActivity(e.Activity)),t.push("</NextActivity>"),t.join(`
26
- `)}buildWorkouts(e){return"<Workouts></Workouts>"}buildCourses(e){return"<Courses></Courses>"}buildAuthor(e){let t=["<Author>"];return this.addOptionalElement(t,"Name",e.Name),t.push("</Author>"),t.join("")}buildExtensions(e){let t=this.buildExtensionContent(e);return t?`<Extensions>${t}</Extensions>`:""}buildExtensionContent(e){return Object.entries(e).filter(([t])=>!t.startsWith("xmlns")).map(([t,r])=>{if(r&&typeof r=="object"){let i=this.buildExtensionContent(r);return`<${t}>${i}</${t}>`}else if(r!=null)return`<${t}>${this.escapeXML(String(r))}</${t}>`;return""}).filter(t=>t).join("")}formatTime(e){return typeof e=="string"&&/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(e)?e:(0,Ge.default)(e).utc().format("YYYY-MM-DDTHH:mm:ss[Z]")}addOptionalElement(e,t,r,i){if(r!=null&&r!==""){let n=i?i(r):this.escapeXML(r);e.push(`<${t}>${n}</${t}>`)}}addOptionalNumericElement(e,t,r){r!=null&&!isNaN(r)&&e.push(`<${t}>${r}</${t}>`)}isValidCoordinate(e,t){return e!=null&&t!==void 0&&t!==null&&!isNaN(e)&&!isNaN(t)}formatCoordinate(e){return this.roundTo(e,6).toString()}roundTo(e,t){let r=Math.pow(10,t);return Math.round(e*r)/r}escapeXML(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}escapeXMLAttribute(e){return typeof e!="string"?String(e||""):e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/'/g,"&apos;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\r/g,"&#13;").replace(/\n/g,"&#10;").replace(/\t/g,"&#9;")}deepClone(e){if(e===null||typeof e!="object")return e;if(e instanceof Date)return new Date(e.getTime());if(Array.isArray(e))return e.map(r=>this.deepClone(r));let t={};for(let r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=this.deepClone(e[r]));return t}encoder(e){return this.encode(e)}};var Qe=g(require("dayjs")),R=class extends P{convertPoints(e){return e.map(t=>this.convertPoint(t)).filter(t=>t!==void 0)}convertTime(e){if(!e)return;if(typeof e=="number")return e;let t=(0,Qe.default)(e);return t.isValid()?t.valueOf():void 0}},X=class{constructor(){this.version="1.0.0";this.priority=100}supports(e){return this.supportedTags.includes(e)}async initialize(e){e.metadata.set(`plugin:${this.name}:initialized`,!0)}async destroy(e){e.metadata.delete(`plugin:${this.name}:initialized`)}async validate(e){return!0}convertTimeToDate(e){return e?new Date(e):new Date}convertTimeToString(e){return this.convertTimeToDate(e).toISOString()}ensureValidCoordinates(e,t){return e>=-90&&e<=90&&t>=-180&&t<=180}round(e,t=6){let r=Math.pow(10,t);return Math.round(e*r)/r}},Be=class extends I{async onError(e,t){t.warnings.push(`Middleware ${this.name} error: ${e.message}`)}validateActivityFile(e){if(!e.metadata)return!1;if(e.routes){for(let t of e.routes)if(!this.validateRoute(t))return!1}if(e.points){for(let t of e.points)if(!this.validatePoint(t))return!1}if(e.activities){for(let t of e.activities)if(!this.validateActivity(t))return!1}return!0}validateActivity(e){return!!(e&&typeof e.index>"u"&&e.laps&&e.laps.length>0)}validateRoute(e){return!!(e.records&&e.records.length>0)}validatePoint(e){return!!(e.positionLat&&e.positionLong&&e.positionLat>=-90&&e.positionLat<=90&&e.positionLong>=-180&&e.positionLong<=180)}};var et={heartrate:"heartRate","gpxtpx:hr":"heartRate","ns3:hr":"heartRate","gpxdata:hr":"heartRate","gpxdata:cadence":"cadence","gpxtpx:cad":"cadence","ns3:cad":"cadence",cadence:"cadence","gpxtpx:speed":"speed","ns3:speed":"speed",speed:"speed",power:"power","gpxdata:power":"power","gpxpx:PowerInWatts":"power",PowerInWatts:"power","gpxtpx:temp":"temperature","gpxtpx:wtemp":"wtemp","gpxtpx:atemp":"atemp","gpxx:Temperature":"temperature","gpxx:Depth":"depth"},y=c=>c*(180/Math.pow(2,31));var Ve=g(require("dayjs"));var He=g(require("dayjs")),tt=require("geolib"),L=class{calculateRecordsAggMetrics(e){if(!e||e.length===0)return;let t={records:this.preprocessRecords(e)},r=0;for(let i=0;i<t.records.length;i++){let n=t.records[i];if(!(!n.positionLat||!n.positionLong)){if(t!=null&&t.startPositionLat||(t.startPositionLat=n.positionLat),t!=null&&t.startPositionLong||(t.startPositionLong=n.positionLong),t.endPositionLat=n.positionLat,t.endPositionLong=n.positionLong,t.timestamp=n.timestamp,t!=null&&t.startTime||(t.startTime=n.timestamp),t.endTime=n.timestamp,n!=null&&n.distance?t.totalDistance=n.distance:i>0&&(r+=this.calculatePointDistance(e[i-1],n)||0,t.totalDistance=r),n!=null&&n.speed&&(t.avgSpeed=t.avgSpeed?(t.avgSpeed+n.speed)/2:n.speed,t.maxSpeed=Math.max(t.maxSpeed||0,n.speed)),n!=null&&n.heartRate&&(t.maxHeartRate=Math.max(t.maxHeartRate||0,n.heartRate),t.minHeartRate=Math.min(t.minHeartRate||n.heartRate,n.heartRate),t.avgHeartRate?t.avgHeartRate=(t.avgHeartRate+n.heartRate)/2:t.avgHeartRate=n.heartRate),n!=null&&n.altitude&&(t.maxAltitude=Math.max(t.maxAltitude||0,n.altitude),t.minAltitude=Math.min(t.minAltitude||n.altitude,n.altitude),t.avgAltitude=t.avgAltitude?(t.avgAltitude+n.altitude)/2:n.altitude,i>0&&e[i-1].altitude)){let s=this.calculateElevationChanges(e[i-1],n);t.totalAscent=(t.totalAscent||0)+s.ascent,t.totalDescent=(t.totalDescent||0)+s.descent}if(n!=null&&n.cadence&&(t.maxCadence=Math.max(t.maxCadence||0,n.cadence),t.avgCadence?t.avgCadence=(t.avgCadence+n.cadence)/2:t.avgCadence=n.cadence),n!=null&&n.power){t.maxPower=Math.max(t.maxPower||0,n.power),t.avgPower?t.avgPower=(t.avgPower+n.power)/2:t.avgPower=n.power;let s=this.calculateAccumulatedPower(i>0?e[i-1]:n,n,t.totalWork||0);t.totalWork=s.newAccumulatedWork,t.normalizedPower=void 0}n!=null&&n.temperature&&(t.avgTemperature?t.avgTemperature=(t.avgTemperature+n.temperature)/2:t.avgTemperature=n.temperature,t.maxTemperature=Math.max(t.maxTemperature||0,n.temperature),t.minTemperature=Math.min(t.minTemperature||n.temperature,n.temperature))}}}calculateLapAggMetrics(e){var r;if(!e||e.length===0)return;let t={laps:e,timestamp:((r=e[0])==null?void 0:r.timestamp)||new Date};for(let i=0;i<e.length;i++){let n=e[i];n.startPositionLat&&n.startPositionLong&&!(t!=null&&t.startPositionLat)&&!(t!=null&&t.startPositionLong)&&(t.startPositionLat=n.startPositionLat,t.startPositionLong=n.startPositionLong),n.endPositionLat&&n.endPositionLong&&(t.endPositionLat=n.endPositionLat,t.endPositionLong=n.endPositionLong),n.startTime&&!(t!=null&&t.startTime)&&(t.startTime=n.startTime),n.endTime&&(t.endTime=n.endTime),t.timestamp=n.timestamp||n.endTime||t.timestamp,n.totalDistance&&(t.totalDistance=(t.totalDistance||0)+n.totalDistance),n.totalElapsedTime&&(t.totalElapsedTime=(t.totalElapsedTime||0)+n.totalElapsedTime),n.maxSpeed&&(t.maxSpeed=Math.max(t.maxSpeed||0,n.maxSpeed)),n.avgSpeed&&(t.avgSpeed?t.avgSpeed=(t.avgSpeed+n.avgSpeed)/2:t.avgSpeed=n.avgSpeed),n.maxHeartRate&&(t.maxHeartRate=Math.max(t.maxHeartRate||0,n.maxHeartRate)),n.minHeartRate&&(t.minHeartRate=t.minHeartRate?Math.min(t.minHeartRate,n.minHeartRate):n.minHeartRate),n.avgHeartRate&&(t.avgHeartRate?t.avgHeartRate=(t.avgHeartRate+n.avgHeartRate)/2:t.avgHeartRate=n.avgHeartRate),n.maxAltitude&&(t.maxAltitude=Math.max(t.maxAltitude||0,n.maxAltitude)),n.minAltitude&&(t.minAltitude=t.minAltitude?Math.min(t.minAltitude,n.minAltitude):n.minAltitude),n.avgAltitude&&(t.avgAltitude?t.avgAltitude=(t.avgAltitude+n.avgAltitude)/2:t.avgAltitude=n.avgAltitude),n.totalAscent&&(t.totalAscent=(t.totalAscent||0)+n.totalAscent),n.totalDescent&&(t.totalDescent=(t.totalDescent||0)+n.totalDescent),n.maxCadence&&(t.maxCadence=Math.max(t.maxCadence||0,n.maxCadence)),n.avgCadence&&(t.avgCadence?t.avgCadence=(t.avgCadence+n.avgCadence)/2:t.avgCadence=n.avgCadence),n.maxPower&&(t.maxPower=Math.max(t.maxPower||0,n.maxPower)),n.avgPower&&(t.avgPower?t.avgPower=(t.avgPower+n.avgPower)/2:t.avgPower=n.avgPower),n.totalWork&&(t.totalWork=(t.totalWork||0)+n.totalWork),n.maxTemperature&&(t.maxTemperature=Math.max(t.maxTemperature||0,n.maxTemperature)),n.minTemperature&&(t.minTemperature=t.minTemperature?Math.min(t.minTemperature,n.minTemperature):n.minTemperature),n.avgTemperature&&(t.avgTemperature?t.avgTemperature=(t.avgTemperature+n.avgTemperature)/2:t.avgTemperature=n.avgTemperature)}return t}preprocessRecords(e){if(!e||e.length===0)return e;let t=e.filter(s=>s.timestamp).sort((s,o)=>s.timestamp.valueOf()-o.timestamp.valueOf()),r=0,i=[],n=null;for(let s=0;s<t.length;s++){let o=t[s],a={...o};if(!(!a.positionLat||!a.positionLong)){if(s>0&&n&&(o.distance||(a.distance=this.calculatePointDistance(n,a)||0),o.speed||(a.speed=this.calculateInstantSpeed(n,a,a.distance)),o.power)){let p=this.calculateAccumulatedPower(n,a,r);a.accumulatedPower=p.accumulatedPower,r=p.newAccumulatedWork}n=a,i.push(a)}}return i}calculatePointDistance(e,t){if(!e.positionLat||!e.positionLong||!t.positionLat||!t.positionLong)return 0;try{return(0,tt.getPreciseDistance)({latitude:e.positionLat,longitude:e.positionLong},{latitude:t.positionLat,longitude:t.positionLong})}catch{return 0}}calculateInstantSpeed(e,t,r){if(!e.timestamp||!t.timestamp||!r)return;let i=((0,He.default)(t.timestamp).valueOf()-(0,He.default)(e.timestamp).valueOf())/1e3;if(!(i<=0))return r/i}calculateAccumulatedPower(e,t,r){var a,p;if(e.power===void 0||t.power===void 0||!e.timestamp||!t.timestamp)return{accumulatedPower:r,newAccumulatedWork:r};let i=((a=t.timestamp)==null?void 0:a.valueOf())-((p=e.timestamp)==null?void 0:p.valueOf());if(i<=0)return{accumulatedPower:r,newAccumulatedWork:r};let s=(e.power+t.power)/2*i,o=r+s;return{accumulatedPower:o,newAccumulatedWork:o}}calculateElevationChanges(e,t){let r=0,i=0;return t.altitude!==void 0&&e.altitude!==void 0&&(t.altitude>e.altitude?r=t.altitude-e.altitude:t.altitude<=e.altitude&&(i=e.altitude-t.altitude)),{ascent:r,descent:i}}};function h(c,e=0){let t=Math.pow(10,e);return Math.round(c*t)/t}var M=class extends R{constructor(){super(...arguments);this.name="gpx-to-activity-converter";this.supportedTags=["gpx"];this.convertGPXExtensions=t=>{let r={};return Object.entries(t).forEach(([i,n])=>{if(typeof n<"u"&&n!=="undefined"){let s=et[i]||i;r[s]=this.autoNumber(n)}}),r}}convert(t,r){if(r.sourceFormat!=="gpx")return;let i=r.sourceData;return this.convertGPX(i)}convertGPX(t){let r={metadata:{originType:"GPX",fileType:"gpx"},activities:[]};return t.wpt&&(r.points=this.convertWpts2Points(t.wpt)),t.trk&&(r.activities=t.trk.map((i,n)=>this.convertTrk2Activity(i,n))),t.rte&&(r.routes=t.rte.map((i,n)=>this.convertTrackSeg2Lap(i,n))),r}convertPoint(t,r){let{extensions:i}=t,n=i?this.convertGPXExtensions(i):{};return{index:r||0,positionLat:t.lat,positionLong:t.lon,altitude:t.ele,heartRate:t==null?void 0:t.heartRate,speed:t==null?void 0:t.speed,power:t==null?void 0:t.power,cadence:t==null?void 0:t.cadence,timestamp:(0,Ve.default)(t.time).toDate(),...n}}convertTrk2Activity(t,r){var s;let i=((s=t.trkseg)==null?void 0:s.map((o,a)=>this.convertTrackSeg2Lap(o,a)))||[],n=new L().calculateLapAggMetrics(i);return{index:r,messageIndex:r,laps:i,...n}}convertTrackSeg2Lap(t,r){var a,p;let i=((p=(a=t.trkpt)==null?void 0:a.filter(d=>d!==void 0&&d.lat&&d.lon))==null?void 0:p.map((d,l)=>this.convertPoint(d,l)))||[],s=new L().calculateRecordsAggMetrics(i);return{index:r,messageIndex:r,...s,records:(s==null?void 0:s.records)||[]}}convertWpts2Points(t){let r=[];for(let i=0;i<t.length;i++){let n=t[i];if(n.lat!=null&&n.lon!=null){let s=this.convertPoint(n,i);s&&r.push(s)}}return r}autoNumber(t){return typeof t=="string"&&t.trim()!==""&&!isNaN(t)?Number(t):t}},O=class extends R{constructor(){super(...arguments);this.name="fit-to-activity-converter";this.supportedTags=["fit"]}convert(t,r){if(r.sourceFormat!=="fit")return;let i=r.sourceData;return this.convertFIT(i)}convertFIT(t){var i,n;let r={metadata:{originType:"FIT",fileType:"fit"},activities:[]};return(i=t.sessionMesgs)!=null&&i.length?r.activities=t.sessionMesgs.map((s,o)=>({index:o,...s,startPositionLat:s.startPositionLat?h(y(Number(s.startPositionLat)),6):void 0,startPositionLong:s.startPositionLong?h(y(Number(s.startPositionLong)),6):void 0,endPositionLat:s.endPositionLat?h(y(Number(s.endPositionLat)),6):void 0,endPositionLong:s.endPositionLong?h(y(Number(s.endPositionLong)),6):void 0,laps:this.convertFITLap2Trackseg(s==null?void 0:s.lapMesgs)})):(n=t.courseMesgs)!=null&&n.length&&(r.routes=t.courseMesgs.map((s,o)=>({index:o,...s,records:this.convertLap2Points(s==null?void 0:s.lapMesgs)}))),r}convertPoint(t,r){let{positionLong:i,positionLat:n,altitude:s,timestamp:o,heartRate:a,cadence:p,distance:d,power:l,enhancedAltitude:w,enhancedSpeed:u,speed:T,temperature:E,..._}=t;if(!(i==null||n==null))return{index:r||0,positionLat:h(y(Number(n)),6),positionLong:h(y(Number(i)),6),altitude:s||w,distance:d,speed:T||u,heartRate:a,power:l,cadence:p,temperature:E,timestamp:o,..._}}convertFITLap2Trackseg(t){var n;let r=[];if(!(t!=null&&t.length))return[];for(let s of t){let o=((n=s==null?void 0:s.recordMesgs)==null?void 0:n.map((a,p)=>this.convertPoint(a,p)).filter(a=>a!==void 0))||[];r.push({index:r.length,...s,startPositionLat:s.startPositionLat?h(y(Number(s.startPositionLat)),6):void 0,startPositionLong:s.startPositionLong?h(y(Number(s.startPositionLong)),6):void 0,endPositionLat:s.endPositionLat?h(y(Number(s.endPositionLat)),6):void 0,endPositionLong:s.endPositionLong?h(y(Number(s.endPositionLong)),6):void 0,records:o})}return r}convertLap2Points(t){var n;let r=[];if(!(t!=null&&t.length))return[];for(let s of t){let o=((n=s.recordMesgs)==null?void 0:n.map((a,p)=>this.convertPoint(a,p)).filter(a=>a!==void 0))||[];o.length&&(r=[...r,...o])}return r}},$=class extends R{constructor(){super(...arguments);this.name="tcx-to-activity-converter";this.supportedTags=["tcx"]}convert(t,r){if(r.sourceFormat!=="tcx")return;let i=r.sourceData;return this.convertTCX(i)}convertTCX(t){var i,n,s,o;let r={metadata:{originType:"TCX",fileType:"tcx"},activities:[]};return(n=(i=t.Activities)==null?void 0:i.Activity)!=null&&n.length&&(r.activities=t.Activities.Activity.map((a,p)=>this.convertTCXActivityToActivity(a,p))),(o=(s=t.Courses)==null?void 0:s.Course)!=null&&o.length,r}convertTCXActivityToActivity(t,r){var s;let i=((s=t.Lap)==null?void 0:s.map((o,a)=>this.convertTCXLap2Lap(o,a)))||[],n=new L().calculateLapAggMetrics(i);return{index:r,messageIndex:r,laps:i,...n}}convertTCXLap2Lap(t,r){var a;let i=((a=t==null?void 0:t.Track)==null?void 0:a.flatMap(p=>p.Trackpoint))||[],n=(i==null?void 0:i.filter(p=>{var d;return p!==void 0&&((d=p.Position)==null?void 0:d.LatitudeDegrees)!==void 0&&p.Position.LongitudeDegrees!==void 0&&p.Time!==void 0}).map((p,d)=>this.convertPoint(p,d)))||[],o=new L().calculateRecordsAggMetrics(n);return{index:r,messageIndex:r,...o,records:(o==null?void 0:o.records)||[]}}convertPoint(t,r){let{Position:i,Time:n,DistanceMeters:s,AltitudeMeters:o}=t;return{index:r||0,positionLat:Number(i.LatitudeDegrees),positionLong:Number(i.LongitudeDegrees),timestamp:(0,Ve.default)(n).toDate(),distance:s,altitude:o}}};var rt=g(require("dayjs"));var G=class extends X{constructor(){super(...arguments);this.name="activity-to-gpx-encoder";this.supportedTags=["gpx"]}encode(t,r){var s,o,a,p,d;if(r.targetFormat!=="gpx"||!((s=t==null?void 0:t.activities)!=null&&s.length))return;let n={version:"1.1",creator:"TrackSwap",metadata:{time:((o=t.activities)==null?void 0:o[0]).timestamp}};return(a=t.points)!=null&&a.length&&(n.wpt=this.convertRecords2Wpts(t.points)),(p=t.routes)!=null&&p.length&&(n.rte=t.routes.map(l=>this.convertRoute2GPXRoute(l))),(d=t.activities)!=null&&d.length&&(n.trk=t.activities.map(l=>this.convertActivity2GPXTrack(l))),n}convertRecords2Wpts(t){return t==null?void 0:t.filter(r=>typeof r.positionLat=="number"&&typeof r.positionLong=="number").map(r=>({lat:r.positionLat,lon:r.positionLong,ele:r==null?void 0:r.altitude,time:r==null?void 0:r.timestamp,speed:r==null?void 0:r.speed,hdop:r==null?void 0:r.hdop,vdop:r==null?void 0:r.vdop,pdop:r==null?void 0:r.pdop,extensions:this.extractGPXExtensions(r)}))}convertRoute2GPXRoute(t){return{rtept:t.records?this.convertRecords2Wpts(t.records):[]}}convertActivity2GPXTrack(t){var r;return{trkseg:((r=t.laps)==null?void 0:r.map(i=>({trkpt:i.records?this.convertRecords2Wpts(i.records):[]})))||[]}}extractGPXExtensions(t){let r={},i={};return typeof(t==null?void 0:t.heartRate)<"u"&&(i["gpxtpx:hr"]=t.heartRate),typeof(t==null?void 0:t.cadence)<"u"&&(i["gpxtpx:cad"]=t.cadence),typeof(t==null?void 0:t.temperature)<"u"&&(i["gpxtpx:atemp"]=t.temperature),Object.keys(i).length>0&&(r["gpxtpx:TrackPointExtension"]=i),typeof(t==null?void 0:t.power)<"u"&&(r["gpxpx:PowerExtension"]={"gpxpx:PowerInWatts":t.power}),Object.keys(r).length>0?r:void 0}},B=class extends X{constructor(){super(...arguments);this.name="activity-to-fit-encoder";this.supportedTags=["fit"]}encode(t,r){var n,s;if(r.targetFormat!=="fit"||!((n=t==null?void 0:t.activities)!=null&&n.length))return;let i={};return i.sessionMesgs=(s=t.activities)==null?void 0:s.map(o=>this.convertActivity2FITSession(o)),i}convertActivity2FITSession(t){var i;return{...t,event:(t==null?void 0:t.event)||"session",sport:(t==null?void 0:t.sport)||"generic",lapMesgs:((i=t.laps)==null?void 0:i.map(n=>this.convertLap2FITLap(n)))||[]}}convertLap2FITLap(t){var i;return{startTime:t.startTime,...t,recordMesgs:((i=t.records)==null?void 0:i.map(n=>this.convertPoint2FITRecord(n)))||[]}}convertPoint2FITRecord(t){return t}},H=class extends X{constructor(){super(...arguments);this.name="sport-to-tcx-encoder";this.supportedTags=["tcx"]}encode(t,r){var n;if(r.targetFormat!=="tcx"||!((n=t==null?void 0:t.activities)!=null&&n.length))return;let i={Author:{Name:"TrackSwap"}};return i.Activities={Activity:t.activities.map(s=>this.convertActivity2TCXActivity(s))},i}convertActivity2TCXActivity(t){var i;let r="Other";return(t.sport==="Running"||t.sport==="Biking")&&(r=t.sport),{Id:`Activity_${Date.now()}`,Activity:r,Lap:((i=t.laps)==null?void 0:i.map(n=>this.convertLap2TCXLap(n)))||[]}}convertLap2TCXLap(t){let r={TotalTimeSeconds:t.totalElapsedTime,DistanceMeters:t.totalDistance,MaximumSpeed:t.maxSpeed,Calories:t.totalCalories,AverageHeartRateBpm:t.avgHeartRate,MaximumHeartRateBpm:t.maxHeartRate,Intensity:"Active",TriggerMethod:"Manual",Track:t.records?[this.convertRecords2TCXTrack(t.records)]:[]};return(t.avgCadence!==void 0||t.maxCadence!==void 0)&&(r.Cadence={Low:t.avgCadence||0,High:t.maxCadence||0}),r}convertRecords2TCXTrack(t){return{Trackpoint:t.map(r=>this.convertPoint2TCXTrackpoint(r))}}convertPoint2TCXTrackpoint(t){var i,n;let r={Time:(0,rt.default)(t.timestamp).toISOString(),Position:{LatitudeDegrees:((i=t.positionLat)==null?void 0:i.toString())||"0",LongitudeDegrees:((n=t.positionLong)==null?void 0:n.toString())||"0"},AltitudeMeters:t.altitude,DistanceMeters:t.distance};return t.heartRate&&(r.HeartRateBpm=t.heartRate),t.cadence&&(r.Cadence={Low:t.cadence,High:t.cadence}),t.power&&(r.Extensions={"ns3:TPX":{"ns3:Watts":t.power}}),r}convertRoute2TCXCourse(t){return{Name:`Course_${Date.now()}`,Track:t.records?[this.convertRecords2TCXTrack(t.records)]:[]}}};var V=class{constructor(){this.converters=new Map;this.encoders=new Map;this.registerDefaultConverters(),this.registerDefaultEncoders()}registerDefaultConverters(){this.registerConverter(new M),this.registerConverter(new O),this.registerConverter(new $)}registerDefaultEncoders(){this.registerEncoder(new G),this.registerEncoder(new B),this.registerEncoder(new H)}registerConverter(e){this.converters.set(e.name,e)}registerEncoder(e){this.encoders.set(e.name,e)}async convertToActivity(e,t){let r={metadata:new Map,errors:[],warnings:[],stats:{startTime:Date.now(),processedTokens:0,convertedElements:0},sourceFormat:t,sourceData:e,performance:{startTime:Date.now()}};try{let i=this.findConverter(t);if(!i)throw new Error(`No converter found for format "${t}"`);let n=Date.now(),s=i.convert(e,r);if(r.performance.convertTime=Date.now()-n,!s)throw new Error(`Converter "${i.name}" returned empty result`);let o=s;return r.result=o,r.performance.endTime=Date.now(),r.stats.endTime=Date.now(),o}catch(i){throw r.errors.push(i),i}}async encodeActivity(e,t){let r={metadata:new Map,errors:[],warnings:[],stats:{startTime:Date.now(),processedTokens:0,convertedElements:0},targetFormat:t,performance:{startTime:Date.now()}};try{let i=this.findEncoder(t);if(!i)throw new Error(`No encoder found for format "${t}"`);let n=Date.now(),s=i.encode(e,r);if(r.performance.encodeTime=Date.now()-n,!s)throw new Error(`Encoder "${i.name}" returned empty result`);return r.result=s,r.performance.endTime=Date.now(),r.stats.endTime=Date.now(),s}catch(i){throw r.errors.push(i),i}}findConverter(e){return Array.from(this.converters.values()).find(t=>{var r;return(r=t.supportedTags)==null?void 0:r.includes(e)})}findEncoder(e){return Array.from(this.encoders.values()).find(t=>{var r;return(r=t.supportedTags)==null?void 0:r.includes(e)})}async destroy(){this.converters.clear(),this.encoders.clear()}};var z=class{constructor(){this.gpxDecoder=new k,this.gpxEncoder=new F,this.fitDecoder=new x,this.fitEncoder=new C,this.tcxDecoder=new S,this.tcxEncoder=new D,this.activityProcessor=new V}async parseGPX(e){try{return await this.gpxDecoder.parserByBuffer(e)}catch(t){throw new Error(`GPX parsing failed: ${t.message}`)}}async parseGPXString(e){let t=Buffer.from(e,"utf-8");return this.parseGPX(t)}async encodeGPX(e){try{return await this.gpxEncoder.encode(e)}catch(t){throw new Error(`GPX encoding failed: ${t.message}`)}}encodeGPXString(e){try{return this.gpxEncoder.encodeToString(e)}catch(t){throw new Error(`GPX encoding failed: ${t.message}`)}}async parseFIT(e){try{return await this.fitDecoder.parseByBuffer(e)}catch(t){throw new Error(`FIT parsing failed: ${t.message}`)}}async encodeFIT(e){try{return await this.fitEncoder.encode(e)}catch(t){throw new Error(`FIT encoding failed: ${t.message}`)}}async encodeFITCourse(e){try{return await this.fitEncoder.encodeCourse(e)}catch(t){throw new Error(`FIT Course encoding failed: ${t.message}`)}}async parseTCXString(e){let t=Buffer.from(e,"utf-8");return this.parseTCX(t)}async parseTCX(e){try{let t=await this.tcxDecoder.parseByBuffer(e);if(!t)throw new Error("TCX parsing result is empty");return t}catch(t){throw new Error(`TCX parsing failed: ${t.message}`)}}async encodeTCX(e){try{return await this.tcxEncoder.encode(e)}catch(t){throw new Error(`TCX encoding failed: ${t.message}`)}}async encodeTCXString(e){try{return await this.tcxEncoder.encodeToString(e)}catch(t){throw new Error(`TCX encoding failed: ${t.message}`)}}async convertGPXToActivity(e){return await this.activityProcessor.convertToActivity(e,"gpx")}async convertFITToActivity(e){return await this.activityProcessor.convertToActivity(e,"fit")}async convertTCXToActivity(e){return await this.activityProcessor.convertToActivity(e,"tcx")}async convertActivityToGPX(e){return await this.activityProcessor.encodeActivity(e,"gpx")}async convertActivityToFIT(e){return await this.activityProcessor.encodeActivity(e,"fit")}async convertActivityToTCX(e){return await this.activityProcessor.encodeActivity(e,"tcx")}async convertFile(e,t,r){try{let i=r||this.detectFormat(e);if(i==="unknown"||i==null)throw new Error("Unable to recognize source file format, please specify sourceType parameter");if(i===t)return e;let n;switch(i){case"gpx":let o=await this.parseGPX(e);if(!o)throw new Error("GPX file parsing failed");n=o;break;case"fit":n=await this.parseFIT(e);break;case"tcx":n=await this.parseTCX(e);break;default:throw new Error(`Unsupported source file format: ${i}`)}let s;switch(i){case"gpx":s=await this.convertGPXToActivity(n);break;case"fit":s=await this.convertFITToActivity(n);break;case"tcx":s=await this.convertTCXToActivity(n);break;default:throw new Error(`Unsupported source file format conversion: ${i}`)}switch(t){case"gpx":let o=await this.convertActivityToGPX(s);return await this.encodeGPX(o);case"fit":let a=await this.convertActivityToFIT(s);return await this.encodeFIT(a);case"tcx":let p=await this.convertActivityToTCX(s);return await this.encodeTCX(p);default:throw new Error(`Unsupported target file format: ${t}`)}}catch(i){let n=r||"auto-detect";throw new Error(`${n} to ${t.toUpperCase()} failed: ${i.message}`)}}detectFormat(e){let t=e.toString("utf-8",0,Math.min(1024,e.length));if(e.length>=12&&e.toString("ascii",8,12)===".FIT")return"fit";if(t.includes("<?xml")){if(t.includes("<gpx")||t.includes("http://www.topografix.com/GPX/"))return"gpx";if(t.includes("<TrainingCenterDatabase")||t.includes("http://www.garmin.com/xmlschemas/TrainingCenterDatabase/"))return"tcx"}return"unknown"}async parseFile(e,t){let r=t||this.detectFormat(e);if(r==="unknown")throw new Error("Unable to recognize file format, please specify sourceType parameter");switch(r){case"gpx":let i=await this.parseGPX(e);if(!i)throw new Error("GPX parsing failed");return i;case"fit":return await this.parseFIT(e);case"tcx":return await this.parseTCX(e);default:throw new Error(`Unsupported file format: ${r}`)}}async parseToActivity(e,t){let r=t||this.detectFormat(e);if(r==="unknown")throw new Error("Unable to recognize file format, please specify sourceType parameter");let i;switch(r){case"gpx":let n=await this.parseGPX(e);if(!n)throw new Error("GPX parsing failed");i=await this.convertGPXToActivity(n);break;case"fit":let s=await this.parseFIT(e);s&&(i=await this.convertFITToActivity(s));break;case"tcx":let o=await this.parseTCX(e);i=await this.convertTCXToActivity(o);break;default:throw new Error(`Unsupported file format: ${r}`)}return i}getActivityProcessor(){return this.activityProcessor}getGPXDecoder(){return this.gpxDecoder}getGPXEncoder(){return this.gpxEncoder}getFITDecoder(){return this.fitDecoder}getFITEncoder(){return this.fitEncoder}getTCXDecoder(){return this.tcxDecoder}getTCXEncoder(){return this.tcxEncoder}async destroy(){await this.gpxDecoder.destroy(),await this.fitDecoder.destroy(),await this.tcxDecoder.destroy(),await this.activityProcessor.destroy()}};var Pt=z;0&&(module.exports={ActivityProcessor,ActivityToFITEncoder,ActivityToGPXEncoder,ActivityToTCXEncoder,BaseActivityConverter,BaseActivityEncoder,BaseActivityMiddleware,FITDecoder,FITEncoder,FITToActivityConverter,GPXDecoder,GPXEncoder,GPXToActivityConverter,PipelineStage,TCXDecoder,TCXEncoder,TCXToActivityConverter,TrackSwap,registerDefaultMiddlewares});
26
+ `)}buildWorkouts(e){return"<Workouts></Workouts>"}buildCourses(e){return"<Courses></Courses>"}buildAuthor(e){let t=["<Author>"];return this.addOptionalElement(t,"Name",e.Name),t.push("</Author>"),t.join("")}buildExtensions(e){let t=this.buildExtensionContent(e);return t?`<Extensions>${t}</Extensions>`:""}buildExtensionContent(e){return Object.entries(e).filter(([t])=>!t.startsWith("xmlns")).map(([t,r])=>{if(r&&typeof r=="object"){let i=this.buildExtensionContent(r);return`<${t}>${i}</${t}>`}else if(r!=null)return`<${t}>${this.escapeXML(String(r))}</${t}>`;return""}).filter(t=>t).join("")}formatTime(e){return typeof e=="string"&&/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(e)?e:(0,Ge.default)(e).utc().format("YYYY-MM-DDTHH:mm:ss[Z]")}addOptionalElement(e,t,r,i){if(r!=null&&r!==""){let n=i?i(r):this.escapeXML(r);e.push(`<${t}>${n}</${t}>`)}}addOptionalNumericElement(e,t,r){r!=null&&!isNaN(r)&&e.push(`<${t}>${r}</${t}>`)}isValidCoordinate(e,t){return e!=null&&t!==void 0&&t!==null&&!isNaN(e)&&!isNaN(t)}formatCoordinate(e){return this.roundTo(e,6).toString()}roundTo(e,t){let r=Math.pow(10,t);return Math.round(e*r)/r}escapeXML(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}escapeXMLAttribute(e){return typeof e!="string"?String(e||""):e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/'/g,"&apos;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\r/g,"&#13;").replace(/\n/g,"&#10;").replace(/\t/g,"&#9;")}deepClone(e){if(e===null||typeof e!="object")return e;if(e instanceof Date)return new Date(e.getTime());if(Array.isArray(e))return e.map(r=>this.deepClone(r));let t={};for(let r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=this.deepClone(e[r]));return t}encoder(e){return this.encode(e)}};var Qe=g(require("dayjs")),R=class extends P{convertPoints(e){return e.map(t=>this.convertPoint(t)).filter(t=>t!==void 0)}convertTime(e){if(!e)return;if(typeof e=="number")return e;let t=(0,Qe.default)(e);return t.isValid()?t.valueOf():void 0}},X=class{constructor(){this.version="1.0.0";this.priority=100}supports(e){return this.supportedTags.includes(e)}async initialize(e){e.metadata.set(`plugin:${this.name}:initialized`,!0)}async destroy(e){e.metadata.delete(`plugin:${this.name}:initialized`)}async validate(e){return!0}convertTimeToDate(e){return e?new Date(e):new Date}convertTimeToString(e){return this.convertTimeToDate(e).toISOString()}ensureValidCoordinates(e,t){return e>=-90&&e<=90&&t>=-180&&t<=180}round(e,t=6){let r=Math.pow(10,t);return Math.round(e*r)/r}},Be=class extends I{async onError(e,t){t.warnings.push(`Middleware ${this.name} error: ${e.message}`)}validateActivityFile(e){if(!e.metadata)return!1;if(e.routes){for(let t of e.routes)if(!this.validateRoute(t))return!1}if(e.points){for(let t of e.points)if(!this.validatePoint(t))return!1}if(e.activities){for(let t of e.activities)if(!this.validateActivity(t))return!1}return!0}validateActivity(e){return!!(e&&typeof e.index>"u"&&e.laps&&e.laps.length>0)}validateRoute(e){return!!(e.records&&e.records.length>0)}validatePoint(e){return!!(e.positionLat&&e.positionLong&&e.positionLat>=-90&&e.positionLat<=90&&e.positionLong>=-180&&e.positionLong<=180)}};var et={heartrate:"heartRate","gpxtpx:hr":"heartRate","ns3:hr":"heartRate","gpxdata:hr":"heartRate","gpxdata:cadence":"cadence","gpxtpx:cad":"cadence","ns3:cad":"cadence",cadence:"cadence","gpxtpx:speed":"speed","ns3:speed":"speed",speed:"speed",power:"power","gpxdata:power":"power","gpxpx:PowerInWatts":"power",PowerInWatts:"power","gpxtpx:temp":"temperature","gpxtpx:wtemp":"wtemp","gpxtpx:atemp":"atemp","gpxx:Temperature":"temperature","gpxx:Depth":"depth"},y=c=>c*(180/Math.pow(2,31));var Ve=g(require("dayjs"));var He=g(require("dayjs")),tt=require("geolib"),L=class{calculateRecordsAggMetrics(e){if(!e||e.length===0)return;let t={records:this.preprocessRecords(e)},r=0;for(let i=0;i<t.records.length;i++){let n=t.records[i];if(!(!n.positionLat||!n.positionLong)){if(t!=null&&t.startPositionLat||(t.startPositionLat=n.positionLat),t!=null&&t.startPositionLong||(t.startPositionLong=n.positionLong),t.endPositionLat=n.positionLat,t.endPositionLong=n.positionLong,t.timestamp=n.timestamp,t!=null&&t.startTime||(t.startTime=n.timestamp),t.endTime=n.timestamp,n!=null&&n.distance?t.totalDistance=n.distance:i>0&&(r+=this.calculatePointDistance(e[i-1],n)||0,t.totalDistance=r),n!=null&&n.speed&&(t.avgSpeed=t.avgSpeed?(t.avgSpeed+n.speed)/2:n.speed,t.maxSpeed=Math.max(t.maxSpeed||0,n.speed)),n!=null&&n.heartRate&&(t.maxHeartRate=Math.max(t.maxHeartRate||0,n.heartRate),t.minHeartRate=Math.min(t.minHeartRate||n.heartRate,n.heartRate),t.avgHeartRate?t.avgHeartRate=(t.avgHeartRate+n.heartRate)/2:t.avgHeartRate=n.heartRate),n!=null&&n.altitude&&(t.maxAltitude=Math.max(t.maxAltitude||0,n.altitude),t.minAltitude=Math.min(t.minAltitude||n.altitude,n.altitude),t.avgAltitude=t.avgAltitude?(t.avgAltitude+n.altitude)/2:n.altitude,i>0&&e[i-1].altitude)){let s=this.calculateElevationChanges(e[i-1],n);t.totalAscent=(t.totalAscent||0)+s.ascent,t.totalDescent=(t.totalDescent||0)+s.descent}if(n!=null&&n.cadence&&(t.maxCadence=Math.max(t.maxCadence||0,n.cadence),t.avgCadence?t.avgCadence=(t.avgCadence+n.cadence)/2:t.avgCadence=n.cadence),n!=null&&n.power){t.maxPower=Math.max(t.maxPower||0,n.power),t.avgPower?t.avgPower=(t.avgPower+n.power)/2:t.avgPower=n.power;let s=this.calculateAccumulatedPower(i>0?e[i-1]:n,n,t.totalWork||0);t.totalWork=s.newAccumulatedWork,t.normalizedPower=void 0}n!=null&&n.temperature&&(t.avgTemperature?t.avgTemperature=(t.avgTemperature+n.temperature)/2:t.avgTemperature=n.temperature,t.maxTemperature=Math.max(t.maxTemperature||0,n.temperature),t.minTemperature=Math.min(t.minTemperature||n.temperature,n.temperature))}}return t}calculateLapAggMetrics(e){var r;if(!e||e.length===0)return;let t={laps:e,timestamp:((r=e[0])==null?void 0:r.timestamp)||new Date};for(let i=0;i<e.length;i++){let n=e[i];n.startPositionLat&&n.startPositionLong&&!(t!=null&&t.startPositionLat)&&!(t!=null&&t.startPositionLong)&&(t.startPositionLat=n.startPositionLat,t.startPositionLong=n.startPositionLong),n.endPositionLat&&n.endPositionLong&&(t.endPositionLat=n.endPositionLat,t.endPositionLong=n.endPositionLong),n.startTime&&!(t!=null&&t.startTime)&&(t.startTime=n.startTime),n.endTime&&(t.endTime=n.endTime),t.timestamp=n.timestamp||n.endTime||t.timestamp,n.totalDistance&&(t.totalDistance=(t.totalDistance||0)+n.totalDistance),n.totalElapsedTime&&(t.totalElapsedTime=(t.totalElapsedTime||0)+n.totalElapsedTime),n.maxSpeed&&(t.maxSpeed=Math.max(t.maxSpeed||0,n.maxSpeed)),n.avgSpeed&&(t.avgSpeed?t.avgSpeed=(t.avgSpeed+n.avgSpeed)/2:t.avgSpeed=n.avgSpeed),n.maxHeartRate&&(t.maxHeartRate=Math.max(t.maxHeartRate||0,n.maxHeartRate)),n.minHeartRate&&(t.minHeartRate=t.minHeartRate?Math.min(t.minHeartRate,n.minHeartRate):n.minHeartRate),n.avgHeartRate&&(t.avgHeartRate?t.avgHeartRate=(t.avgHeartRate+n.avgHeartRate)/2:t.avgHeartRate=n.avgHeartRate),n.maxAltitude&&(t.maxAltitude=Math.max(t.maxAltitude||0,n.maxAltitude)),n.minAltitude&&(t.minAltitude=t.minAltitude?Math.min(t.minAltitude,n.minAltitude):n.minAltitude),n.avgAltitude&&(t.avgAltitude?t.avgAltitude=(t.avgAltitude+n.avgAltitude)/2:t.avgAltitude=n.avgAltitude),n.totalAscent&&(t.totalAscent=(t.totalAscent||0)+n.totalAscent),n.totalDescent&&(t.totalDescent=(t.totalDescent||0)+n.totalDescent),n.maxCadence&&(t.maxCadence=Math.max(t.maxCadence||0,n.maxCadence)),n.avgCadence&&(t.avgCadence?t.avgCadence=(t.avgCadence+n.avgCadence)/2:t.avgCadence=n.avgCadence),n.maxPower&&(t.maxPower=Math.max(t.maxPower||0,n.maxPower)),n.avgPower&&(t.avgPower?t.avgPower=(t.avgPower+n.avgPower)/2:t.avgPower=n.avgPower),n.totalWork&&(t.totalWork=(t.totalWork||0)+n.totalWork),n.maxTemperature&&(t.maxTemperature=Math.max(t.maxTemperature||0,n.maxTemperature)),n.minTemperature&&(t.minTemperature=t.minTemperature?Math.min(t.minTemperature,n.minTemperature):n.minTemperature),n.avgTemperature&&(t.avgTemperature?t.avgTemperature=(t.avgTemperature+n.avgTemperature)/2:t.avgTemperature=n.avgTemperature)}return t}preprocessRecords(e){if(!e||e.length===0)return e;let t=e.filter(s=>s.timestamp).sort((s,o)=>s.timestamp.valueOf()-o.timestamp.valueOf()),r=0,i=[],n=null;for(let s=0;s<t.length;s++){let o=t[s],a={...o};if(!(!a.positionLat||!a.positionLong)){if(s>0&&n&&(o.distance||(a.distance=this.calculatePointDistance(n,a)||0),o.speed||(a.speed=this.calculateInstantSpeed(n,a,a.distance)),o.power)){let p=this.calculateAccumulatedPower(n,a,r);a.accumulatedPower=p.accumulatedPower,r=p.newAccumulatedWork}n=a,i.push(a)}}return i}calculatePointDistance(e,t){if(!e.positionLat||!e.positionLong||!t.positionLat||!t.positionLong)return 0;try{return(0,tt.getPreciseDistance)({latitude:e.positionLat,longitude:e.positionLong},{latitude:t.positionLat,longitude:t.positionLong})}catch{return 0}}calculateInstantSpeed(e,t,r){if(!e.timestamp||!t.timestamp||!r)return;let i=((0,He.default)(t.timestamp).valueOf()-(0,He.default)(e.timestamp).valueOf())/1e3;if(!(i<=0))return r/i}calculateAccumulatedPower(e,t,r){var a,p;if(e.power===void 0||t.power===void 0||!e.timestamp||!t.timestamp)return{accumulatedPower:r,newAccumulatedWork:r};let i=((a=t.timestamp)==null?void 0:a.valueOf())-((p=e.timestamp)==null?void 0:p.valueOf());if(i<=0)return{accumulatedPower:r,newAccumulatedWork:r};let s=(e.power+t.power)/2*i,o=r+s;return{accumulatedPower:o,newAccumulatedWork:o}}calculateElevationChanges(e,t){let r=0,i=0;return t.altitude!==void 0&&e.altitude!==void 0&&(t.altitude>e.altitude?r=t.altitude-e.altitude:t.altitude<=e.altitude&&(i=e.altitude-t.altitude)),{ascent:r,descent:i}}};function h(c,e=0){let t=Math.pow(10,e);return Math.round(c*t)/t}var M=class extends R{constructor(){super(...arguments);this.name="gpx-to-activity-converter";this.supportedTags=["gpx"];this.convertGPXExtensions=t=>{let r={};return Object.entries(t).forEach(([i,n])=>{if(typeof n<"u"&&n!=="undefined"){let s=et[i]||i;r[s]=this.autoNumber(n)}}),r}}convert(t,r){if(r.sourceFormat!=="gpx")return;let i=r.sourceData;return this.convertGPX(i)}convertGPX(t){let r={metadata:{originType:"GPX",fileType:"gpx"},activities:[]};return t.wpt&&(r.points=this.convertWpts2Points(t.wpt)),t.trk&&(r.activities=t.trk.map((i,n)=>this.convertTrk2Activity(i,n))),t.rte&&(r.routes=t.rte.map((i,n)=>this.convertTrackSeg2Lap(i,n))),r}convertPoint(t,r){let{extensions:i}=t,n=i?this.convertGPXExtensions(i):{};return{index:r||0,positionLat:t.lat,positionLong:t.lon,altitude:t.ele,heartRate:t==null?void 0:t.heartRate,speed:t==null?void 0:t.speed,power:t==null?void 0:t.power,cadence:t==null?void 0:t.cadence,timestamp:(0,Ve.default)(t.time).toDate(),...n}}convertTrk2Activity(t,r){var s;let i=((s=t.trkseg)==null?void 0:s.map((o,a)=>this.convertTrackSeg2Lap(o,a)))||[],n=new L().calculateLapAggMetrics(i);return{index:r,messageIndex:r,laps:i,...n}}convertTrackSeg2Lap(t,r){var a,p;let i=((p=(a=t.trkpt)==null?void 0:a.filter(d=>d!==void 0&&d.lat&&d.lon))==null?void 0:p.map((d,l)=>this.convertPoint(d,l)))||[],s=new L().calculateRecordsAggMetrics(i);return{index:r,messageIndex:r,...s,records:(s==null?void 0:s.records)||[]}}convertWpts2Points(t){let r=[];for(let i=0;i<t.length;i++){let n=t[i];if(n.lat!=null&&n.lon!=null){let s=this.convertPoint(n,i);s&&r.push(s)}}return r}autoNumber(t){return typeof t=="string"&&t.trim()!==""&&!isNaN(t)?Number(t):t}},O=class extends R{constructor(){super(...arguments);this.name="fit-to-activity-converter";this.supportedTags=["fit"]}convert(t,r){if(r.sourceFormat!=="fit")return;let i=r.sourceData;return this.convertFIT(i)}convertFIT(t){var i,n;let r={metadata:{originType:"FIT",fileType:"fit"},activities:[]};return(i=t.sessionMesgs)!=null&&i.length?r.activities=t.sessionMesgs.map((s,o)=>({index:o,...s,startPositionLat:s.startPositionLat?h(y(Number(s.startPositionLat)),6):void 0,startPositionLong:s.startPositionLong?h(y(Number(s.startPositionLong)),6):void 0,endPositionLat:s.endPositionLat?h(y(Number(s.endPositionLat)),6):void 0,endPositionLong:s.endPositionLong?h(y(Number(s.endPositionLong)),6):void 0,laps:this.convertFITLap2Trackseg(s==null?void 0:s.lapMesgs)})):(n=t.courseMesgs)!=null&&n.length&&(r.routes=t.courseMesgs.map((s,o)=>({index:o,...s,records:this.convertLap2Points(s==null?void 0:s.lapMesgs)}))),r}convertPoint(t,r){let{positionLong:i,positionLat:n,altitude:s,timestamp:o,heartRate:a,cadence:p,distance:d,power:l,enhancedAltitude:w,enhancedSpeed:u,speed:T,temperature:E,..._}=t;if(!(i==null||n==null))return{index:r||0,positionLat:h(y(Number(n)),6),positionLong:h(y(Number(i)),6),altitude:s||w,distance:d,speed:T||u,heartRate:a,power:l,cadence:p,temperature:E,timestamp:o,..._}}convertFITLap2Trackseg(t){var n;let r=[];if(!(t!=null&&t.length))return[];for(let s of t){let o=((n=s==null?void 0:s.recordMesgs)==null?void 0:n.map((a,p)=>this.convertPoint(a,p)).filter(a=>a!==void 0))||[];r.push({index:r.length,...s,startPositionLat:s.startPositionLat?h(y(Number(s.startPositionLat)),6):void 0,startPositionLong:s.startPositionLong?h(y(Number(s.startPositionLong)),6):void 0,endPositionLat:s.endPositionLat?h(y(Number(s.endPositionLat)),6):void 0,endPositionLong:s.endPositionLong?h(y(Number(s.endPositionLong)),6):void 0,records:o})}return r}convertLap2Points(t){var n;let r=[];if(!(t!=null&&t.length))return[];for(let s of t){let o=((n=s.recordMesgs)==null?void 0:n.map((a,p)=>this.convertPoint(a,p)).filter(a=>a!==void 0))||[];o.length&&(r=[...r,...o])}return r}},$=class extends R{constructor(){super(...arguments);this.name="tcx-to-activity-converter";this.supportedTags=["tcx"]}convert(t,r){if(r.sourceFormat!=="tcx")return;let i=r.sourceData;return this.convertTCX(i)}convertTCX(t){var i,n,s,o;let r={metadata:{originType:"TCX",fileType:"tcx"},activities:[]};return(n=(i=t.Activities)==null?void 0:i.Activity)!=null&&n.length&&(r.activities=t.Activities.Activity.map((a,p)=>this.convertTCXActivityToActivity(a,p))),(o=(s=t.Courses)==null?void 0:s.Course)!=null&&o.length,r}convertTCXActivityToActivity(t,r){var s;let i=((s=t.Lap)==null?void 0:s.map((o,a)=>this.convertTCXLap2Lap(o,a)))||[],n=new L().calculateLapAggMetrics(i);return{index:r,messageIndex:r,laps:i,...n}}convertTCXLap2Lap(t,r){var a;let i=((a=t==null?void 0:t.Track)==null?void 0:a.flatMap(p=>p.Trackpoint))||[],n=(i==null?void 0:i.filter(p=>{var d;return p!==void 0&&((d=p.Position)==null?void 0:d.LatitudeDegrees)!==void 0&&p.Position.LongitudeDegrees!==void 0&&p.Time!==void 0}).map((p,d)=>this.convertPoint(p,d)))||[],o=new L().calculateRecordsAggMetrics(n);return{index:r,messageIndex:r,...o,records:(o==null?void 0:o.records)||[]}}convertPoint(t,r){let{Position:i,Time:n,DistanceMeters:s,AltitudeMeters:o}=t;return{index:r||0,positionLat:Number(i.LatitudeDegrees),positionLong:Number(i.LongitudeDegrees),timestamp:(0,Ve.default)(n).toDate(),distance:s,altitude:o}}};var rt=g(require("dayjs"));var G=class extends X{constructor(){super(...arguments);this.name="activity-to-gpx-encoder";this.supportedTags=["gpx"]}encode(t,r){var s,o,a,p,d;if(r.targetFormat!=="gpx"||!((s=t==null?void 0:t.activities)!=null&&s.length))return;let n={version:"1.1",creator:"TrackSwap",metadata:{time:((o=t.activities)==null?void 0:o[0]).timestamp}};return(a=t.points)!=null&&a.length&&(n.wpt=this.convertRecords2Wpts(t.points)),(p=t.routes)!=null&&p.length&&(n.rte=t.routes.map(l=>this.convertRoute2GPXRoute(l))),(d=t.activities)!=null&&d.length&&(n.trk=t.activities.map(l=>this.convertActivity2GPXTrack(l))),n}convertRecords2Wpts(t){return t==null?void 0:t.filter(r=>typeof r.positionLat=="number"&&typeof r.positionLong=="number").map(r=>({lat:r.positionLat,lon:r.positionLong,ele:r==null?void 0:r.altitude,time:r==null?void 0:r.timestamp,speed:r==null?void 0:r.speed,hdop:r==null?void 0:r.hdop,vdop:r==null?void 0:r.vdop,pdop:r==null?void 0:r.pdop,extensions:this.extractGPXExtensions(r)}))}convertRoute2GPXRoute(t){return{rtept:t.records?this.convertRecords2Wpts(t.records):[]}}convertActivity2GPXTrack(t){var r;return{trkseg:((r=t.laps)==null?void 0:r.map(i=>({trkpt:i.records?this.convertRecords2Wpts(i.records):[]})))||[]}}extractGPXExtensions(t){let r={},i={};return typeof(t==null?void 0:t.heartRate)<"u"&&(i["gpxtpx:hr"]=t.heartRate),typeof(t==null?void 0:t.cadence)<"u"&&(i["gpxtpx:cad"]=t.cadence),typeof(t==null?void 0:t.temperature)<"u"&&(i["gpxtpx:atemp"]=t.temperature),Object.keys(i).length>0&&(r["gpxtpx:TrackPointExtension"]=i),typeof(t==null?void 0:t.power)<"u"&&(r["gpxpx:PowerExtension"]={"gpxpx:PowerInWatts":t.power}),Object.keys(r).length>0?r:void 0}},B=class extends X{constructor(){super(...arguments);this.name="activity-to-fit-encoder";this.supportedTags=["fit"]}encode(t,r){var n,s;if(r.targetFormat!=="fit"||!((n=t==null?void 0:t.activities)!=null&&n.length))return;let i={};return i.sessionMesgs=(s=t.activities)==null?void 0:s.map(o=>this.convertActivity2FITSession(o)),i}convertActivity2FITSession(t){var i;return{...t,event:(t==null?void 0:t.event)||"session",sport:(t==null?void 0:t.sport)||"generic",lapMesgs:((i=t.laps)==null?void 0:i.map(n=>this.convertLap2FITLap(n)))||[]}}convertLap2FITLap(t){var i;return{startTime:t.startTime,...t,recordMesgs:((i=t.records)==null?void 0:i.map(n=>this.convertPoint2FITRecord(n)))||[]}}convertPoint2FITRecord(t){return t}},H=class extends X{constructor(){super(...arguments);this.name="sport-to-tcx-encoder";this.supportedTags=["tcx"]}encode(t,r){var n;if(r.targetFormat!=="tcx"||!((n=t==null?void 0:t.activities)!=null&&n.length))return;let i={Author:{Name:"TrackSwap"}};return i.Activities={Activity:t.activities.map(s=>this.convertActivity2TCXActivity(s))},i}convertActivity2TCXActivity(t){var i;let r="Other";return(t.sport==="Running"||t.sport==="Biking")&&(r=t.sport),{Id:`Activity_${Date.now()}`,Activity:r,Lap:((i=t.laps)==null?void 0:i.map(n=>this.convertLap2TCXLap(n)))||[]}}convertLap2TCXLap(t){let r={TotalTimeSeconds:t.totalElapsedTime,DistanceMeters:t.totalDistance,MaximumSpeed:t.maxSpeed,Calories:t.totalCalories,AverageHeartRateBpm:t.avgHeartRate,MaximumHeartRateBpm:t.maxHeartRate,Intensity:"Active",TriggerMethod:"Manual",Track:t.records?[this.convertRecords2TCXTrack(t.records)]:[]};return(t.avgCadence!==void 0||t.maxCadence!==void 0)&&(r.Cadence={Low:t.avgCadence||0,High:t.maxCadence||0}),r}convertRecords2TCXTrack(t){return{Trackpoint:t.map(r=>this.convertPoint2TCXTrackpoint(r))}}convertPoint2TCXTrackpoint(t){var i,n;let r={Time:(0,rt.default)(t.timestamp).toISOString(),Position:{LatitudeDegrees:((i=t.positionLat)==null?void 0:i.toString())||"0",LongitudeDegrees:((n=t.positionLong)==null?void 0:n.toString())||"0"},AltitudeMeters:t.altitude,DistanceMeters:t.distance};return t.heartRate&&(r.HeartRateBpm=t.heartRate),t.cadence&&(r.Cadence={Low:t.cadence,High:t.cadence}),t.power&&(r.Extensions={"ns3:TPX":{"ns3:Watts":t.power}}),r}convertRoute2TCXCourse(t){return{Name:`Course_${Date.now()}`,Track:t.records?[this.convertRecords2TCXTrack(t.records)]:[]}}};var V=class{constructor(){this.converters=new Map;this.encoders=new Map;this.registerDefaultConverters(),this.registerDefaultEncoders()}registerDefaultConverters(){this.registerConverter(new M),this.registerConverter(new O),this.registerConverter(new $)}registerDefaultEncoders(){this.registerEncoder(new G),this.registerEncoder(new B),this.registerEncoder(new H)}registerConverter(e){this.converters.set(e.name,e)}registerEncoder(e){this.encoders.set(e.name,e)}async convertToActivity(e,t){let r={metadata:new Map,errors:[],warnings:[],stats:{startTime:Date.now(),processedTokens:0,convertedElements:0},sourceFormat:t,sourceData:e,performance:{startTime:Date.now()}};try{let s=this.findConverter(t);if(!s)throw new Error(`No converter found for format "${t}"`);let o=Date.now(),a=s.convert(e,r);if(r.performance.convertTime=Date.now()-o,!a)throw new Error(`Converter "${s.name}" returned empty result`);let p=a;return r.result=p,r.performance.endTime=Date.now(),r.stats.endTime=Date.now(),p}catch(s){throw r.errors.push(s),s}}async encodeActivity(e,t){let r={metadata:new Map,errors:[],warnings:[],stats:{startTime:Date.now(),processedTokens:0,convertedElements:0},targetFormat:t,performance:{startTime:Date.now()}};try{let i=this.findEncoder(t);if(!i)throw new Error(`No encoder found for format "${t}"`);let n=Date.now(),s=i.encode(e,r);if(r.performance.encodeTime=Date.now()-n,!s)throw new Error(`Encoder "${i.name}" returned empty result`);return r.result=s,r.performance.endTime=Date.now(),r.stats.endTime=Date.now(),s}catch(i){throw r.errors.push(i),i}}findConverter(e){return Array.from(this.converters.values()).find(t=>{var r;return(r=t.supportedTags)==null?void 0:r.includes(e)})}findEncoder(e){return Array.from(this.encoders.values()).find(t=>{var r;return(r=t.supportedTags)==null?void 0:r.includes(e)})}async destroy(){this.converters.clear(),this.encoders.clear()}};var z=class{constructor(){this.gpxDecoder=new k,this.gpxEncoder=new F,this.fitDecoder=new x,this.fitEncoder=new C,this.tcxDecoder=new S,this.tcxEncoder=new D,this.activityProcessor=new V}async parseGPX(e){try{return await this.gpxDecoder.parserByBuffer(e)}catch(t){throw new Error(`GPX parsing failed: ${t.message}`)}}async parseGPXString(e){let t=Buffer.from(e,"utf-8");return this.parseGPX(t)}async encodeGPX(e){try{return await this.gpxEncoder.encode(e)}catch(t){throw new Error(`GPX encoding failed: ${t.message}`)}}encodeGPXString(e){try{return this.gpxEncoder.encodeToString(e)}catch(t){throw new Error(`GPX encoding failed: ${t.message}`)}}async parseFIT(e){try{return await this.fitDecoder.parseByBuffer(e)}catch(t){throw new Error(`FIT parsing failed: ${t.message}`)}}async encodeFIT(e){try{return await this.fitEncoder.encode(e)}catch(t){throw new Error(`FIT encoding failed: ${t.message}`)}}async encodeFITCourse(e){try{return await this.fitEncoder.encodeCourse(e)}catch(t){throw new Error(`FIT Course encoding failed: ${t.message}`)}}async parseTCXString(e){let t=Buffer.from(e,"utf-8");return this.parseTCX(t)}async parseTCX(e){try{let t=await this.tcxDecoder.parseByBuffer(e);if(!t)throw new Error("TCX parsing result is empty");return t}catch(t){throw new Error(`TCX parsing failed: ${t.message}`)}}async encodeTCX(e){try{return await this.tcxEncoder.encode(e)}catch(t){throw new Error(`TCX encoding failed: ${t.message}`)}}async encodeTCXString(e){try{return await this.tcxEncoder.encodeToString(e)}catch(t){throw new Error(`TCX encoding failed: ${t.message}`)}}async convertGPXToActivity(e){return await this.activityProcessor.convertToActivity(e,"gpx")}async convertFITToActivity(e){return await this.activityProcessor.convertToActivity(e,"fit")}async convertTCXToActivity(e){return await this.activityProcessor.convertToActivity(e,"tcx")}async convertActivityToGPX(e){return await this.activityProcessor.encodeActivity(e,"gpx")}async convertActivityToFIT(e){return await this.activityProcessor.encodeActivity(e,"fit")}async convertActivityToTCX(e){return await this.activityProcessor.encodeActivity(e,"tcx")}async convertFile(e,t,r){try{let i=r||this.detectFormat(e);if(i==="unknown"||i==null)throw new Error("Unable to recognize source file format, please specify sourceType parameter");if(i===t)return e;let n;switch(i){case"gpx":let o=await this.parseGPX(e);if(!o)throw new Error("GPX file parsing failed");n=o;break;case"fit":n=await this.parseFIT(e);break;case"tcx":n=await this.parseTCX(e);break;default:throw new Error(`Unsupported source file format: ${i}`)}let s;switch(i){case"gpx":s=await this.convertGPXToActivity(n);break;case"fit":s=await this.convertFITToActivity(n);break;case"tcx":s=await this.convertTCXToActivity(n);break;default:throw new Error(`Unsupported source file format conversion: ${i}`)}switch(t){case"gpx":let o=await this.convertActivityToGPX(s);return await this.encodeGPX(o);case"fit":let a=await this.convertActivityToFIT(s);return await this.encodeFIT(a);case"tcx":let p=await this.convertActivityToTCX(s);return await this.encodeTCX(p);default:throw new Error(`Unsupported target file format: ${t}`)}}catch(i){let n=r||"auto-detect";throw new Error(`${n} to ${t.toUpperCase()} failed: ${i.message}`)}}detectFormat(e){let t=e.toString("utf-8",0,Math.min(1024,e.length));if(e.length>=12&&e.toString("ascii",8,12)===".FIT")return"fit";if(t.includes("<?xml")){if(t.includes("<gpx")||t.includes("http://www.topografix.com/GPX/"))return"gpx";if(t.includes("<TrainingCenterDatabase")||t.includes("http://www.garmin.com/xmlschemas/TrainingCenterDatabase/"))return"tcx"}return"unknown"}async parseFile(e,t){let r=t||this.detectFormat(e);if(r==="unknown")throw new Error("Unable to recognize file format, please specify sourceType parameter");switch(r){case"gpx":let i=await this.parseGPX(e);if(!i)throw new Error("GPX parsing failed");return i;case"fit":return await this.parseFIT(e);case"tcx":return await this.parseTCX(e);default:throw new Error(`Unsupported file format: ${r}`)}}async parseToActivity(e,t){let r=t||this.detectFormat(e);if(r==="unknown")throw new Error("Unable to recognize file format, please specify sourceType parameter");let i;switch(r){case"gpx":let n=await this.parseGPX(e);if(!n)throw new Error("GPX parsing failed");i=await this.convertGPXToActivity(n);break;case"fit":let s=await this.parseFIT(e);s&&(i=await this.convertFITToActivity(s));break;case"tcx":let o=await this.parseTCX(e);i=await this.convertTCXToActivity(o);break;default:throw new Error(`Unsupported file format: ${r}`)}return i}getActivityProcessor(){return this.activityProcessor}getGPXDecoder(){return this.gpxDecoder}getGPXEncoder(){return this.gpxEncoder}getFITDecoder(){return this.fitDecoder}getFITEncoder(){return this.fitEncoder}getTCXDecoder(){return this.tcxDecoder}getTCXEncoder(){return this.tcxEncoder}async destroy(){await this.gpxDecoder.destroy(),await this.fitDecoder.destroy(),await this.tcxDecoder.destroy(),await this.activityProcessor.destroy()}};var Pt=z;0&&(module.exports={ActivityProcessor,ActivityToFITEncoder,ActivityToGPXEncoder,ActivityToTCXEncoder,BaseActivityConverter,BaseActivityEncoder,BaseActivityMiddleware,FITDecoder,FITEncoder,FITToActivityConverter,GPXDecoder,GPXEncoder,GPXToActivityConverter,PipelineStage,TCXDecoder,TCXEncoder,TCXToActivityConverter,TrackSwap,registerDefaultMiddlewares});
package/dist/index.js CHANGED
@@ -23,4 +23,4 @@ var K=class{constructor(){this.stage="parse"}async process(e){let t=Date.now();i
23
23
  `)}buildPosition(e){let t=["<Position>"];return e.LatitudeDegrees&&t.push(`<LatitudeDegrees>${this.formatCoordinate(parseFloat(e.LatitudeDegrees))}</LatitudeDegrees>`),e.LongitudeDegrees&&t.push(`<LongitudeDegrees>${this.formatCoordinate(parseFloat(e.LongitudeDegrees))}</LongitudeDegrees>`),t.push("</Position>"),t.join("")}buildCadence(e){return`<Cadence><Low>${e.Low}</Low><High>${e.High}</High></Cadence>`}buildMultiActivitySession(e){let t=["<MultiActivitySession>"];return e.Id&&t.push(`<Id>${this.formatTime(e.Id)}</Id>`),e.FirstActivity&&t.push(this.buildFirstActivity(e.FirstActivity)),e.NextActivity&&e.NextActivity.forEach(r=>{t.push(this.buildNextActivity(r))}),this.addOptionalElement(t,"Notes",e.Notes),t.push("</MultiActivitySession>"),t.join(`
24
24
  `)}buildFirstActivity(e){let t=["<FirstActivity>"];return e.Activity&&t.push(this.buildActivity(e.Activity)),t.push("</FirstActivity>"),t.join(`
25
25
  `)}buildNextActivity(e){let t=["<NextActivity>"];return e.Transition&&t.push(`<Transition>${this.buildActivityLap(e.Transition)}</Transition>`),e.Activity&&t.push(this.buildActivity(e.Activity)),t.push("</NextActivity>"),t.join(`
26
- `)}buildWorkouts(e){return"<Workouts></Workouts>"}buildCourses(e){return"<Courses></Courses>"}buildAuthor(e){let t=["<Author>"];return this.addOptionalElement(t,"Name",e.Name),t.push("</Author>"),t.join("")}buildExtensions(e){let t=this.buildExtensionContent(e);return t?`<Extensions>${t}</Extensions>`:""}buildExtensionContent(e){return Object.entries(e).filter(([t])=>!t.startsWith("xmlns")).map(([t,r])=>{if(r&&typeof r=="object"){let i=this.buildExtensionContent(r);return`<${t}>${i}</${t}>`}else if(r!=null)return`<${t}>${this.escapeXML(String(r))}</${t}>`;return""}).filter(t=>t).join("")}formatTime(e){return typeof e=="string"&&/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(e)?e:Ve(e).utc().format("YYYY-MM-DDTHH:mm:ss[Z]")}addOptionalElement(e,t,r,i){if(r!=null&&r!==""){let n=i?i(r):this.escapeXML(r);e.push(`<${t}>${n}</${t}>`)}}addOptionalNumericElement(e,t,r){r!=null&&!isNaN(r)&&e.push(`<${t}>${r}</${t}>`)}isValidCoordinate(e,t){return e!=null&&t!==void 0&&t!==null&&!isNaN(e)&&!isNaN(t)}formatCoordinate(e){return this.roundTo(e,6).toString()}roundTo(e,t){let r=Math.pow(10,t);return Math.round(e*r)/r}escapeXML(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}escapeXMLAttribute(e){return typeof e!="string"?String(e||""):e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/'/g,"&apos;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\r/g,"&#13;").replace(/\n/g,"&#10;").replace(/\t/g,"&#9;")}deepClone(e){if(e===null||typeof e!="object")return e;if(e instanceof Date)return new Date(e.getTime());if(Array.isArray(e))return e.map(r=>this.deepClone(r));let t={};for(let r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=this.deepClone(e[r]));return t}encoder(e){return this.encode(e)}};import pt from"dayjs";var X=class extends h{convertPoints(e){return e.map(t=>this.convertPoint(t)).filter(t=>t!==void 0)}convertTime(e){if(!e)return;if(typeof e=="number")return e;let t=pt(e);return t.isValid()?t.valueOf():void 0}},L=class{constructor(){this.version="1.0.0";this.priority=100}supports(e){return this.supportedTags.includes(e)}async initialize(e){e.metadata.set(`plugin:${this.name}:initialized`,!0)}async destroy(e){e.metadata.delete(`plugin:${this.name}:initialized`)}async validate(e){return!0}convertTimeToDate(e){return e?new Date(e):new Date}convertTimeToString(e){return this.convertTimeToDate(e).toISOString()}ensureValidCoordinates(e,t){return e>=-90&&e<=90&&t>=-180&&t<=180}round(e,t=6){let r=Math.pow(10,t);return Math.round(e*r)/r}},ze=class extends b{async onError(e,t){t.warnings.push(`Middleware ${this.name} error: ${e.message}`)}validateActivityFile(e){if(!e.metadata)return!1;if(e.routes){for(let t of e.routes)if(!this.validateRoute(t))return!1}if(e.points){for(let t of e.points)if(!this.validatePoint(t))return!1}if(e.activities){for(let t of e.activities)if(!this.validateActivity(t))return!1}return!0}validateActivity(e){return!!(e&&typeof e.index>"u"&&e.laps&&e.laps.length>0)}validateRoute(e){return!!(e.records&&e.records.length>0)}validatePoint(e){return!!(e.positionLat&&e.positionLong&&e.positionLat>=-90&&e.positionLat<=90&&e.positionLong>=-180&&e.positionLong<=180)}};var We={heartrate:"heartRate","gpxtpx:hr":"heartRate","ns3:hr":"heartRate","gpxdata:hr":"heartRate","gpxdata:cadence":"cadence","gpxtpx:cad":"cadence","ns3:cad":"cadence",cadence:"cadence","gpxtpx:speed":"speed","ns3:speed":"speed",speed:"speed",power:"power","gpxdata:power":"power","gpxpx:PowerInWatts":"power",PowerInWatts:"power","gpxtpx:temp":"temperature","gpxtpx:wtemp":"wtemp","gpxtpx:atemp":"atemp","gpxx:Temperature":"temperature","gpxx:Depth":"depth"},g=p=>p*(180/Math.pow(2,31));import je from"dayjs";import Ue from"dayjs";import{getPreciseDistance as dt}from"geolib";var I=class{calculateRecordsAggMetrics(e){if(!e||e.length===0)return;let t={records:this.preprocessRecords(e)},r=0;for(let i=0;i<t.records.length;i++){let n=t.records[i];if(!(!n.positionLat||!n.positionLong)){if(t!=null&&t.startPositionLat||(t.startPositionLat=n.positionLat),t!=null&&t.startPositionLong||(t.startPositionLong=n.positionLong),t.endPositionLat=n.positionLat,t.endPositionLong=n.positionLong,t.timestamp=n.timestamp,t!=null&&t.startTime||(t.startTime=n.timestamp),t.endTime=n.timestamp,n!=null&&n.distance?t.totalDistance=n.distance:i>0&&(r+=this.calculatePointDistance(e[i-1],n)||0,t.totalDistance=r),n!=null&&n.speed&&(t.avgSpeed=t.avgSpeed?(t.avgSpeed+n.speed)/2:n.speed,t.maxSpeed=Math.max(t.maxSpeed||0,n.speed)),n!=null&&n.heartRate&&(t.maxHeartRate=Math.max(t.maxHeartRate||0,n.heartRate),t.minHeartRate=Math.min(t.minHeartRate||n.heartRate,n.heartRate),t.avgHeartRate?t.avgHeartRate=(t.avgHeartRate+n.heartRate)/2:t.avgHeartRate=n.heartRate),n!=null&&n.altitude&&(t.maxAltitude=Math.max(t.maxAltitude||0,n.altitude),t.minAltitude=Math.min(t.minAltitude||n.altitude,n.altitude),t.avgAltitude=t.avgAltitude?(t.avgAltitude+n.altitude)/2:n.altitude,i>0&&e[i-1].altitude)){let s=this.calculateElevationChanges(e[i-1],n);t.totalAscent=(t.totalAscent||0)+s.ascent,t.totalDescent=(t.totalDescent||0)+s.descent}if(n!=null&&n.cadence&&(t.maxCadence=Math.max(t.maxCadence||0,n.cadence),t.avgCadence?t.avgCadence=(t.avgCadence+n.cadence)/2:t.avgCadence=n.cadence),n!=null&&n.power){t.maxPower=Math.max(t.maxPower||0,n.power),t.avgPower?t.avgPower=(t.avgPower+n.power)/2:t.avgPower=n.power;let s=this.calculateAccumulatedPower(i>0?e[i-1]:n,n,t.totalWork||0);t.totalWork=s.newAccumulatedWork,t.normalizedPower=void 0}n!=null&&n.temperature&&(t.avgTemperature?t.avgTemperature=(t.avgTemperature+n.temperature)/2:t.avgTemperature=n.temperature,t.maxTemperature=Math.max(t.maxTemperature||0,n.temperature),t.minTemperature=Math.min(t.minTemperature||n.temperature,n.temperature))}}}calculateLapAggMetrics(e){var r;if(!e||e.length===0)return;let t={laps:e,timestamp:((r=e[0])==null?void 0:r.timestamp)||new Date};for(let i=0;i<e.length;i++){let n=e[i];n.startPositionLat&&n.startPositionLong&&!(t!=null&&t.startPositionLat)&&!(t!=null&&t.startPositionLong)&&(t.startPositionLat=n.startPositionLat,t.startPositionLong=n.startPositionLong),n.endPositionLat&&n.endPositionLong&&(t.endPositionLat=n.endPositionLat,t.endPositionLong=n.endPositionLong),n.startTime&&!(t!=null&&t.startTime)&&(t.startTime=n.startTime),n.endTime&&(t.endTime=n.endTime),t.timestamp=n.timestamp||n.endTime||t.timestamp,n.totalDistance&&(t.totalDistance=(t.totalDistance||0)+n.totalDistance),n.totalElapsedTime&&(t.totalElapsedTime=(t.totalElapsedTime||0)+n.totalElapsedTime),n.maxSpeed&&(t.maxSpeed=Math.max(t.maxSpeed||0,n.maxSpeed)),n.avgSpeed&&(t.avgSpeed?t.avgSpeed=(t.avgSpeed+n.avgSpeed)/2:t.avgSpeed=n.avgSpeed),n.maxHeartRate&&(t.maxHeartRate=Math.max(t.maxHeartRate||0,n.maxHeartRate)),n.minHeartRate&&(t.minHeartRate=t.minHeartRate?Math.min(t.minHeartRate,n.minHeartRate):n.minHeartRate),n.avgHeartRate&&(t.avgHeartRate?t.avgHeartRate=(t.avgHeartRate+n.avgHeartRate)/2:t.avgHeartRate=n.avgHeartRate),n.maxAltitude&&(t.maxAltitude=Math.max(t.maxAltitude||0,n.maxAltitude)),n.minAltitude&&(t.minAltitude=t.minAltitude?Math.min(t.minAltitude,n.minAltitude):n.minAltitude),n.avgAltitude&&(t.avgAltitude?t.avgAltitude=(t.avgAltitude+n.avgAltitude)/2:t.avgAltitude=n.avgAltitude),n.totalAscent&&(t.totalAscent=(t.totalAscent||0)+n.totalAscent),n.totalDescent&&(t.totalDescent=(t.totalDescent||0)+n.totalDescent),n.maxCadence&&(t.maxCadence=Math.max(t.maxCadence||0,n.maxCadence)),n.avgCadence&&(t.avgCadence?t.avgCadence=(t.avgCadence+n.avgCadence)/2:t.avgCadence=n.avgCadence),n.maxPower&&(t.maxPower=Math.max(t.maxPower||0,n.maxPower)),n.avgPower&&(t.avgPower?t.avgPower=(t.avgPower+n.avgPower)/2:t.avgPower=n.avgPower),n.totalWork&&(t.totalWork=(t.totalWork||0)+n.totalWork),n.maxTemperature&&(t.maxTemperature=Math.max(t.maxTemperature||0,n.maxTemperature)),n.minTemperature&&(t.minTemperature=t.minTemperature?Math.min(t.minTemperature,n.minTemperature):n.minTemperature),n.avgTemperature&&(t.avgTemperature?t.avgTemperature=(t.avgTemperature+n.avgTemperature)/2:t.avgTemperature=n.avgTemperature)}return t}preprocessRecords(e){if(!e||e.length===0)return e;let t=e.filter(s=>s.timestamp).sort((s,o)=>s.timestamp.valueOf()-o.timestamp.valueOf()),r=0,i=[],n=null;for(let s=0;s<t.length;s++){let o=t[s],a={...o};if(!(!a.positionLat||!a.positionLong)){if(s>0&&n&&(o.distance||(a.distance=this.calculatePointDistance(n,a)||0),o.speed||(a.speed=this.calculateInstantSpeed(n,a,a.distance)),o.power)){let c=this.calculateAccumulatedPower(n,a,r);a.accumulatedPower=c.accumulatedPower,r=c.newAccumulatedWork}n=a,i.push(a)}}return i}calculatePointDistance(e,t){if(!e.positionLat||!e.positionLong||!t.positionLat||!t.positionLong)return 0;try{return dt({latitude:e.positionLat,longitude:e.positionLong},{latitude:t.positionLat,longitude:t.positionLong})}catch{return 0}}calculateInstantSpeed(e,t,r){if(!e.timestamp||!t.timestamp||!r)return;let i=(Ue(t.timestamp).valueOf()-Ue(e.timestamp).valueOf())/1e3;if(!(i<=0))return r/i}calculateAccumulatedPower(e,t,r){var a,c;if(e.power===void 0||t.power===void 0||!e.timestamp||!t.timestamp)return{accumulatedPower:r,newAccumulatedWork:r};let i=((a=t.timestamp)==null?void 0:a.valueOf())-((c=e.timestamp)==null?void 0:c.valueOf());if(i<=0)return{accumulatedPower:r,newAccumulatedWork:r};let s=(e.power+t.power)/2*i,o=r+s;return{accumulatedPower:o,newAccumulatedWork:o}}calculateElevationChanges(e,t){let r=0,i=0;return t.altitude!==void 0&&e.altitude!==void 0&&(t.altitude>e.altitude?r=t.altitude-e.altitude:t.altitude<=e.altitude&&(i=e.altitude-t.altitude)),{ascent:r,descent:i}}};function y(p,e=0){let t=Math.pow(10,e);return Math.round(p*t)/t}var G=class extends X{constructor(){super(...arguments);this.name="gpx-to-activity-converter";this.supportedTags=["gpx"];this.convertGPXExtensions=t=>{let r={};return Object.entries(t).forEach(([i,n])=>{if(typeof n<"u"&&n!=="undefined"){let s=We[i]||i;r[s]=this.autoNumber(n)}}),r}}convert(t,r){if(r.sourceFormat!=="gpx")return;let i=r.sourceData;return this.convertGPX(i)}convertGPX(t){let r={metadata:{originType:"GPX",fileType:"gpx"},activities:[]};return t.wpt&&(r.points=this.convertWpts2Points(t.wpt)),t.trk&&(r.activities=t.trk.map((i,n)=>this.convertTrk2Activity(i,n))),t.rte&&(r.routes=t.rte.map((i,n)=>this.convertTrackSeg2Lap(i,n))),r}convertPoint(t,r){let{extensions:i}=t,n=i?this.convertGPXExtensions(i):{};return{index:r||0,positionLat:t.lat,positionLong:t.lon,altitude:t.ele,heartRate:t==null?void 0:t.heartRate,speed:t==null?void 0:t.speed,power:t==null?void 0:t.power,cadence:t==null?void 0:t.cadence,timestamp:je(t.time).toDate(),...n}}convertTrk2Activity(t,r){var s;let i=((s=t.trkseg)==null?void 0:s.map((o,a)=>this.convertTrackSeg2Lap(o,a)))||[],n=new I().calculateLapAggMetrics(i);return{index:r,messageIndex:r,laps:i,...n}}convertTrackSeg2Lap(t,r){var a,c;let i=((c=(a=t.trkpt)==null?void 0:a.filter(d=>d!==void 0&&d.lat&&d.lon))==null?void 0:c.map((d,l)=>this.convertPoint(d,l)))||[],s=new I().calculateRecordsAggMetrics(i);return{index:r,messageIndex:r,...s,records:(s==null?void 0:s.records)||[]}}convertWpts2Points(t){let r=[];for(let i=0;i<t.length;i++){let n=t[i];if(n.lat!=null&&n.lon!=null){let s=this.convertPoint(n,i);s&&r.push(s)}}return r}autoNumber(t){return typeof t=="string"&&t.trim()!==""&&!isNaN(t)?Number(t):t}},B=class extends X{constructor(){super(...arguments);this.name="fit-to-activity-converter";this.supportedTags=["fit"]}convert(t,r){if(r.sourceFormat!=="fit")return;let i=r.sourceData;return this.convertFIT(i)}convertFIT(t){var i,n;let r={metadata:{originType:"FIT",fileType:"fit"},activities:[]};return(i=t.sessionMesgs)!=null&&i.length?r.activities=t.sessionMesgs.map((s,o)=>({index:o,...s,startPositionLat:s.startPositionLat?y(g(Number(s.startPositionLat)),6):void 0,startPositionLong:s.startPositionLong?y(g(Number(s.startPositionLong)),6):void 0,endPositionLat:s.endPositionLat?y(g(Number(s.endPositionLat)),6):void 0,endPositionLong:s.endPositionLong?y(g(Number(s.endPositionLong)),6):void 0,laps:this.convertFITLap2Trackseg(s==null?void 0:s.lapMesgs)})):(n=t.courseMesgs)!=null&&n.length&&(r.routes=t.courseMesgs.map((s,o)=>({index:o,...s,records:this.convertLap2Points(s==null?void 0:s.lapMesgs)}))),r}convertPoint(t,r){let{positionLong:i,positionLat:n,altitude:s,timestamp:o,heartRate:a,cadence:c,distance:d,power:l,enhancedAltitude:v,enhancedSpeed:u,speed:T,temperature:x,...k}=t;if(!(i==null||n==null))return{index:r||0,positionLat:y(g(Number(n)),6),positionLong:y(g(Number(i)),6),altitude:s||v,distance:d,speed:T||u,heartRate:a,power:l,cadence:c,temperature:x,timestamp:o,...k}}convertFITLap2Trackseg(t){var n;let r=[];if(!(t!=null&&t.length))return[];for(let s of t){let o=((n=s==null?void 0:s.recordMesgs)==null?void 0:n.map((a,c)=>this.convertPoint(a,c)).filter(a=>a!==void 0))||[];r.push({index:r.length,...s,startPositionLat:s.startPositionLat?y(g(Number(s.startPositionLat)),6):void 0,startPositionLong:s.startPositionLong?y(g(Number(s.startPositionLong)),6):void 0,endPositionLat:s.endPositionLat?y(g(Number(s.endPositionLat)),6):void 0,endPositionLong:s.endPositionLong?y(g(Number(s.endPositionLong)),6):void 0,records:o})}return r}convertLap2Points(t){var n;let r=[];if(!(t!=null&&t.length))return[];for(let s of t){let o=((n=s.recordMesgs)==null?void 0:n.map((a,c)=>this.convertPoint(a,c)).filter(a=>a!==void 0))||[];o.length&&(r=[...r,...o])}return r}},H=class extends X{constructor(){super(...arguments);this.name="tcx-to-activity-converter";this.supportedTags=["tcx"]}convert(t,r){if(r.sourceFormat!=="tcx")return;let i=r.sourceData;return this.convertTCX(i)}convertTCX(t){var i,n,s,o;let r={metadata:{originType:"TCX",fileType:"tcx"},activities:[]};return(n=(i=t.Activities)==null?void 0:i.Activity)!=null&&n.length&&(r.activities=t.Activities.Activity.map((a,c)=>this.convertTCXActivityToActivity(a,c))),(o=(s=t.Courses)==null?void 0:s.Course)!=null&&o.length,r}convertTCXActivityToActivity(t,r){var s;let i=((s=t.Lap)==null?void 0:s.map((o,a)=>this.convertTCXLap2Lap(o,a)))||[],n=new I().calculateLapAggMetrics(i);return{index:r,messageIndex:r,laps:i,...n}}convertTCXLap2Lap(t,r){var a;let i=((a=t==null?void 0:t.Track)==null?void 0:a.flatMap(c=>c.Trackpoint))||[],n=(i==null?void 0:i.filter(c=>{var d;return c!==void 0&&((d=c.Position)==null?void 0:d.LatitudeDegrees)!==void 0&&c.Position.LongitudeDegrees!==void 0&&c.Time!==void 0}).map((c,d)=>this.convertPoint(c,d)))||[],o=new I().calculateRecordsAggMetrics(n);return{index:r,messageIndex:r,...o,records:(o==null?void 0:o.records)||[]}}convertPoint(t,r){let{Position:i,Time:n,DistanceMeters:s,AltitudeMeters:o}=t;return{index:r||0,positionLat:Number(i.LatitudeDegrees),positionLong:Number(i.LongitudeDegrees),timestamp:je(n).toDate(),distance:s,altitude:o}}};import lt from"dayjs";var V=class extends L{constructor(){super(...arguments);this.name="activity-to-gpx-encoder";this.supportedTags=["gpx"]}encode(t,r){var s,o,a,c,d;if(r.targetFormat!=="gpx"||!((s=t==null?void 0:t.activities)!=null&&s.length))return;let n={version:"1.1",creator:"TrackSwap",metadata:{time:((o=t.activities)==null?void 0:o[0]).timestamp}};return(a=t.points)!=null&&a.length&&(n.wpt=this.convertRecords2Wpts(t.points)),(c=t.routes)!=null&&c.length&&(n.rte=t.routes.map(l=>this.convertRoute2GPXRoute(l))),(d=t.activities)!=null&&d.length&&(n.trk=t.activities.map(l=>this.convertActivity2GPXTrack(l))),n}convertRecords2Wpts(t){return t==null?void 0:t.filter(r=>typeof r.positionLat=="number"&&typeof r.positionLong=="number").map(r=>({lat:r.positionLat,lon:r.positionLong,ele:r==null?void 0:r.altitude,time:r==null?void 0:r.timestamp,speed:r==null?void 0:r.speed,hdop:r==null?void 0:r.hdop,vdop:r==null?void 0:r.vdop,pdop:r==null?void 0:r.pdop,extensions:this.extractGPXExtensions(r)}))}convertRoute2GPXRoute(t){return{rtept:t.records?this.convertRecords2Wpts(t.records):[]}}convertActivity2GPXTrack(t){var r;return{trkseg:((r=t.laps)==null?void 0:r.map(i=>({trkpt:i.records?this.convertRecords2Wpts(i.records):[]})))||[]}}extractGPXExtensions(t){let r={},i={};return typeof(t==null?void 0:t.heartRate)<"u"&&(i["gpxtpx:hr"]=t.heartRate),typeof(t==null?void 0:t.cadence)<"u"&&(i["gpxtpx:cad"]=t.cadence),typeof(t==null?void 0:t.temperature)<"u"&&(i["gpxtpx:atemp"]=t.temperature),Object.keys(i).length>0&&(r["gpxtpx:TrackPointExtension"]=i),typeof(t==null?void 0:t.power)<"u"&&(r["gpxpx:PowerExtension"]={"gpxpx:PowerInWatts":t.power}),Object.keys(r).length>0?r:void 0}},z=class extends L{constructor(){super(...arguments);this.name="activity-to-fit-encoder";this.supportedTags=["fit"]}encode(t,r){var n,s;if(r.targetFormat!=="fit"||!((n=t==null?void 0:t.activities)!=null&&n.length))return;let i={};return i.sessionMesgs=(s=t.activities)==null?void 0:s.map(o=>this.convertActivity2FITSession(o)),i}convertActivity2FITSession(t){var i;return{...t,event:(t==null?void 0:t.event)||"session",sport:(t==null?void 0:t.sport)||"generic",lapMesgs:((i=t.laps)==null?void 0:i.map(n=>this.convertLap2FITLap(n)))||[]}}convertLap2FITLap(t){var i;return{startTime:t.startTime,...t,recordMesgs:((i=t.records)==null?void 0:i.map(n=>this.convertPoint2FITRecord(n)))||[]}}convertPoint2FITRecord(t){return t}},W=class extends L{constructor(){super(...arguments);this.name="sport-to-tcx-encoder";this.supportedTags=["tcx"]}encode(t,r){var n;if(r.targetFormat!=="tcx"||!((n=t==null?void 0:t.activities)!=null&&n.length))return;let i={Author:{Name:"TrackSwap"}};return i.Activities={Activity:t.activities.map(s=>this.convertActivity2TCXActivity(s))},i}convertActivity2TCXActivity(t){var i;let r="Other";return(t.sport==="Running"||t.sport==="Biking")&&(r=t.sport),{Id:`Activity_${Date.now()}`,Activity:r,Lap:((i=t.laps)==null?void 0:i.map(n=>this.convertLap2TCXLap(n)))||[]}}convertLap2TCXLap(t){let r={TotalTimeSeconds:t.totalElapsedTime,DistanceMeters:t.totalDistance,MaximumSpeed:t.maxSpeed,Calories:t.totalCalories,AverageHeartRateBpm:t.avgHeartRate,MaximumHeartRateBpm:t.maxHeartRate,Intensity:"Active",TriggerMethod:"Manual",Track:t.records?[this.convertRecords2TCXTrack(t.records)]:[]};return(t.avgCadence!==void 0||t.maxCadence!==void 0)&&(r.Cadence={Low:t.avgCadence||0,High:t.maxCadence||0}),r}convertRecords2TCXTrack(t){return{Trackpoint:t.map(r=>this.convertPoint2TCXTrackpoint(r))}}convertPoint2TCXTrackpoint(t){var i,n;let r={Time:lt(t.timestamp).toISOString(),Position:{LatitudeDegrees:((i=t.positionLat)==null?void 0:i.toString())||"0",LongitudeDegrees:((n=t.positionLong)==null?void 0:n.toString())||"0"},AltitudeMeters:t.altitude,DistanceMeters:t.distance};return t.heartRate&&(r.HeartRateBpm=t.heartRate),t.cadence&&(r.Cadence={Low:t.cadence,High:t.cadence}),t.power&&(r.Extensions={"ns3:TPX":{"ns3:Watts":t.power}}),r}convertRoute2TCXCourse(t){return{Name:`Course_${Date.now()}`,Track:t.records?[this.convertRecords2TCXTrack(t.records)]:[]}}};var U=class{constructor(){this.converters=new Map;this.encoders=new Map;this.registerDefaultConverters(),this.registerDefaultEncoders()}registerDefaultConverters(){this.registerConverter(new G),this.registerConverter(new B),this.registerConverter(new H)}registerDefaultEncoders(){this.registerEncoder(new V),this.registerEncoder(new z),this.registerEncoder(new W)}registerConverter(e){this.converters.set(e.name,e)}registerEncoder(e){this.encoders.set(e.name,e)}async convertToActivity(e,t){let r={metadata:new Map,errors:[],warnings:[],stats:{startTime:Date.now(),processedTokens:0,convertedElements:0},sourceFormat:t,sourceData:e,performance:{startTime:Date.now()}};try{let i=this.findConverter(t);if(!i)throw new Error(`No converter found for format "${t}"`);let n=Date.now(),s=i.convert(e,r);if(r.performance.convertTime=Date.now()-n,!s)throw new Error(`Converter "${i.name}" returned empty result`);let o=s;return r.result=o,r.performance.endTime=Date.now(),r.stats.endTime=Date.now(),o}catch(i){throw r.errors.push(i),i}}async encodeActivity(e,t){let r={metadata:new Map,errors:[],warnings:[],stats:{startTime:Date.now(),processedTokens:0,convertedElements:0},targetFormat:t,performance:{startTime:Date.now()}};try{let i=this.findEncoder(t);if(!i)throw new Error(`No encoder found for format "${t}"`);let n=Date.now(),s=i.encode(e,r);if(r.performance.encodeTime=Date.now()-n,!s)throw new Error(`Encoder "${i.name}" returned empty result`);return r.result=s,r.performance.endTime=Date.now(),r.stats.endTime=Date.now(),s}catch(i){throw r.errors.push(i),i}}findConverter(e){return Array.from(this.converters.values()).find(t=>{var r;return(r=t.supportedTags)==null?void 0:r.includes(e)})}findEncoder(e){return Array.from(this.encoders.values()).find(t=>{var r;return(r=t.supportedTags)==null?void 0:r.includes(e)})}async destroy(){this.converters.clear(),this.encoders.clear()}};var j=class{constructor(){this.gpxDecoder=new F,this.gpxEncoder=new S,this.fitDecoder=new w,this.fitEncoder=new A,this.tcxDecoder=new D,this.tcxEncoder=new R,this.activityProcessor=new U}async parseGPX(e){try{return await this.gpxDecoder.parserByBuffer(e)}catch(t){throw new Error(`GPX parsing failed: ${t.message}`)}}async parseGPXString(e){let t=Buffer.from(e,"utf-8");return this.parseGPX(t)}async encodeGPX(e){try{return await this.gpxEncoder.encode(e)}catch(t){throw new Error(`GPX encoding failed: ${t.message}`)}}encodeGPXString(e){try{return this.gpxEncoder.encodeToString(e)}catch(t){throw new Error(`GPX encoding failed: ${t.message}`)}}async parseFIT(e){try{return await this.fitDecoder.parseByBuffer(e)}catch(t){throw new Error(`FIT parsing failed: ${t.message}`)}}async encodeFIT(e){try{return await this.fitEncoder.encode(e)}catch(t){throw new Error(`FIT encoding failed: ${t.message}`)}}async encodeFITCourse(e){try{return await this.fitEncoder.encodeCourse(e)}catch(t){throw new Error(`FIT Course encoding failed: ${t.message}`)}}async parseTCXString(e){let t=Buffer.from(e,"utf-8");return this.parseTCX(t)}async parseTCX(e){try{let t=await this.tcxDecoder.parseByBuffer(e);if(!t)throw new Error("TCX parsing result is empty");return t}catch(t){throw new Error(`TCX parsing failed: ${t.message}`)}}async encodeTCX(e){try{return await this.tcxEncoder.encode(e)}catch(t){throw new Error(`TCX encoding failed: ${t.message}`)}}async encodeTCXString(e){try{return await this.tcxEncoder.encodeToString(e)}catch(t){throw new Error(`TCX encoding failed: ${t.message}`)}}async convertGPXToActivity(e){return await this.activityProcessor.convertToActivity(e,"gpx")}async convertFITToActivity(e){return await this.activityProcessor.convertToActivity(e,"fit")}async convertTCXToActivity(e){return await this.activityProcessor.convertToActivity(e,"tcx")}async convertActivityToGPX(e){return await this.activityProcessor.encodeActivity(e,"gpx")}async convertActivityToFIT(e){return await this.activityProcessor.encodeActivity(e,"fit")}async convertActivityToTCX(e){return await this.activityProcessor.encodeActivity(e,"tcx")}async convertFile(e,t,r){try{let i=r||this.detectFormat(e);if(i==="unknown"||i==null)throw new Error("Unable to recognize source file format, please specify sourceType parameter");if(i===t)return e;let n;switch(i){case"gpx":let o=await this.parseGPX(e);if(!o)throw new Error("GPX file parsing failed");n=o;break;case"fit":n=await this.parseFIT(e);break;case"tcx":n=await this.parseTCX(e);break;default:throw new Error(`Unsupported source file format: ${i}`)}let s;switch(i){case"gpx":s=await this.convertGPXToActivity(n);break;case"fit":s=await this.convertFITToActivity(n);break;case"tcx":s=await this.convertTCXToActivity(n);break;default:throw new Error(`Unsupported source file format conversion: ${i}`)}switch(t){case"gpx":let o=await this.convertActivityToGPX(s);return await this.encodeGPX(o);case"fit":let a=await this.convertActivityToFIT(s);return await this.encodeFIT(a);case"tcx":let c=await this.convertActivityToTCX(s);return await this.encodeTCX(c);default:throw new Error(`Unsupported target file format: ${t}`)}}catch(i){let n=r||"auto-detect";throw new Error(`${n} to ${t.toUpperCase()} failed: ${i.message}`)}}detectFormat(e){let t=e.toString("utf-8",0,Math.min(1024,e.length));if(e.length>=12&&e.toString("ascii",8,12)===".FIT")return"fit";if(t.includes("<?xml")){if(t.includes("<gpx")||t.includes("http://www.topografix.com/GPX/"))return"gpx";if(t.includes("<TrainingCenterDatabase")||t.includes("http://www.garmin.com/xmlschemas/TrainingCenterDatabase/"))return"tcx"}return"unknown"}async parseFile(e,t){let r=t||this.detectFormat(e);if(r==="unknown")throw new Error("Unable to recognize file format, please specify sourceType parameter");switch(r){case"gpx":let i=await this.parseGPX(e);if(!i)throw new Error("GPX parsing failed");return i;case"fit":return await this.parseFIT(e);case"tcx":return await this.parseTCX(e);default:throw new Error(`Unsupported file format: ${r}`)}}async parseToActivity(e,t){let r=t||this.detectFormat(e);if(r==="unknown")throw new Error("Unable to recognize file format, please specify sourceType parameter");let i;switch(r){case"gpx":let n=await this.parseGPX(e);if(!n)throw new Error("GPX parsing failed");i=await this.convertGPXToActivity(n);break;case"fit":let s=await this.parseFIT(e);s&&(i=await this.convertFITToActivity(s));break;case"tcx":let o=await this.parseTCX(e);i=await this.convertTCXToActivity(o);break;default:throw new Error(`Unsupported file format: ${r}`)}return i}getActivityProcessor(){return this.activityProcessor}getGPXDecoder(){return this.gpxDecoder}getGPXEncoder(){return this.gpxEncoder}getFITDecoder(){return this.fitDecoder}getFITEncoder(){return this.fitEncoder}getTCXDecoder(){return this.tcxDecoder}getTCXEncoder(){return this.tcxEncoder}async destroy(){await this.gpxDecoder.destroy(),await this.fitDecoder.destroy(),await this.tcxDecoder.destroy(),await this.activityProcessor.destroy()}};var Mn=j;export{U as ActivityProcessor,z as ActivityToFITEncoder,V as ActivityToGPXEncoder,W as ActivityToTCXEncoder,X as BaseActivityConverter,L as BaseActivityEncoder,ze as BaseActivityMiddleware,w as FITDecoder,A as FITEncoder,B as FITToActivityConverter,F as GPXDecoder,S as GPXEncoder,G as GPXToActivityConverter,me as PipelineStage,D as TCXDecoder,R as TCXEncoder,H as TCXToActivityConverter,j as TrackSwap,Mn as default,Be as registerDefaultMiddlewares};
26
+ `)}buildWorkouts(e){return"<Workouts></Workouts>"}buildCourses(e){return"<Courses></Courses>"}buildAuthor(e){let t=["<Author>"];return this.addOptionalElement(t,"Name",e.Name),t.push("</Author>"),t.join("")}buildExtensions(e){let t=this.buildExtensionContent(e);return t?`<Extensions>${t}</Extensions>`:""}buildExtensionContent(e){return Object.entries(e).filter(([t])=>!t.startsWith("xmlns")).map(([t,r])=>{if(r&&typeof r=="object"){let i=this.buildExtensionContent(r);return`<${t}>${i}</${t}>`}else if(r!=null)return`<${t}>${this.escapeXML(String(r))}</${t}>`;return""}).filter(t=>t).join("")}formatTime(e){return typeof e=="string"&&/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(e)?e:Ve(e).utc().format("YYYY-MM-DDTHH:mm:ss[Z]")}addOptionalElement(e,t,r,i){if(r!=null&&r!==""){let n=i?i(r):this.escapeXML(r);e.push(`<${t}>${n}</${t}>`)}}addOptionalNumericElement(e,t,r){r!=null&&!isNaN(r)&&e.push(`<${t}>${r}</${t}>`)}isValidCoordinate(e,t){return e!=null&&t!==void 0&&t!==null&&!isNaN(e)&&!isNaN(t)}formatCoordinate(e){return this.roundTo(e,6).toString()}roundTo(e,t){let r=Math.pow(10,t);return Math.round(e*r)/r}escapeXML(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}escapeXMLAttribute(e){return typeof e!="string"?String(e||""):e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/'/g,"&apos;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\r/g,"&#13;").replace(/\n/g,"&#10;").replace(/\t/g,"&#9;")}deepClone(e){if(e===null||typeof e!="object")return e;if(e instanceof Date)return new Date(e.getTime());if(Array.isArray(e))return e.map(r=>this.deepClone(r));let t={};for(let r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=this.deepClone(e[r]));return t}encoder(e){return this.encode(e)}};import pt from"dayjs";var X=class extends h{convertPoints(e){return e.map(t=>this.convertPoint(t)).filter(t=>t!==void 0)}convertTime(e){if(!e)return;if(typeof e=="number")return e;let t=pt(e);return t.isValid()?t.valueOf():void 0}},L=class{constructor(){this.version="1.0.0";this.priority=100}supports(e){return this.supportedTags.includes(e)}async initialize(e){e.metadata.set(`plugin:${this.name}:initialized`,!0)}async destroy(e){e.metadata.delete(`plugin:${this.name}:initialized`)}async validate(e){return!0}convertTimeToDate(e){return e?new Date(e):new Date}convertTimeToString(e){return this.convertTimeToDate(e).toISOString()}ensureValidCoordinates(e,t){return e>=-90&&e<=90&&t>=-180&&t<=180}round(e,t=6){let r=Math.pow(10,t);return Math.round(e*r)/r}},ze=class extends b{async onError(e,t){t.warnings.push(`Middleware ${this.name} error: ${e.message}`)}validateActivityFile(e){if(!e.metadata)return!1;if(e.routes){for(let t of e.routes)if(!this.validateRoute(t))return!1}if(e.points){for(let t of e.points)if(!this.validatePoint(t))return!1}if(e.activities){for(let t of e.activities)if(!this.validateActivity(t))return!1}return!0}validateActivity(e){return!!(e&&typeof e.index>"u"&&e.laps&&e.laps.length>0)}validateRoute(e){return!!(e.records&&e.records.length>0)}validatePoint(e){return!!(e.positionLat&&e.positionLong&&e.positionLat>=-90&&e.positionLat<=90&&e.positionLong>=-180&&e.positionLong<=180)}};var We={heartrate:"heartRate","gpxtpx:hr":"heartRate","ns3:hr":"heartRate","gpxdata:hr":"heartRate","gpxdata:cadence":"cadence","gpxtpx:cad":"cadence","ns3:cad":"cadence",cadence:"cadence","gpxtpx:speed":"speed","ns3:speed":"speed",speed:"speed",power:"power","gpxdata:power":"power","gpxpx:PowerInWatts":"power",PowerInWatts:"power","gpxtpx:temp":"temperature","gpxtpx:wtemp":"wtemp","gpxtpx:atemp":"atemp","gpxx:Temperature":"temperature","gpxx:Depth":"depth"},g=p=>p*(180/Math.pow(2,31));import je from"dayjs";import Ue from"dayjs";import{getPreciseDistance as dt}from"geolib";var I=class{calculateRecordsAggMetrics(e){if(!e||e.length===0)return;let t={records:this.preprocessRecords(e)},r=0;for(let i=0;i<t.records.length;i++){let n=t.records[i];if(!(!n.positionLat||!n.positionLong)){if(t!=null&&t.startPositionLat||(t.startPositionLat=n.positionLat),t!=null&&t.startPositionLong||(t.startPositionLong=n.positionLong),t.endPositionLat=n.positionLat,t.endPositionLong=n.positionLong,t.timestamp=n.timestamp,t!=null&&t.startTime||(t.startTime=n.timestamp),t.endTime=n.timestamp,n!=null&&n.distance?t.totalDistance=n.distance:i>0&&(r+=this.calculatePointDistance(e[i-1],n)||0,t.totalDistance=r),n!=null&&n.speed&&(t.avgSpeed=t.avgSpeed?(t.avgSpeed+n.speed)/2:n.speed,t.maxSpeed=Math.max(t.maxSpeed||0,n.speed)),n!=null&&n.heartRate&&(t.maxHeartRate=Math.max(t.maxHeartRate||0,n.heartRate),t.minHeartRate=Math.min(t.minHeartRate||n.heartRate,n.heartRate),t.avgHeartRate?t.avgHeartRate=(t.avgHeartRate+n.heartRate)/2:t.avgHeartRate=n.heartRate),n!=null&&n.altitude&&(t.maxAltitude=Math.max(t.maxAltitude||0,n.altitude),t.minAltitude=Math.min(t.minAltitude||n.altitude,n.altitude),t.avgAltitude=t.avgAltitude?(t.avgAltitude+n.altitude)/2:n.altitude,i>0&&e[i-1].altitude)){let s=this.calculateElevationChanges(e[i-1],n);t.totalAscent=(t.totalAscent||0)+s.ascent,t.totalDescent=(t.totalDescent||0)+s.descent}if(n!=null&&n.cadence&&(t.maxCadence=Math.max(t.maxCadence||0,n.cadence),t.avgCadence?t.avgCadence=(t.avgCadence+n.cadence)/2:t.avgCadence=n.cadence),n!=null&&n.power){t.maxPower=Math.max(t.maxPower||0,n.power),t.avgPower?t.avgPower=(t.avgPower+n.power)/2:t.avgPower=n.power;let s=this.calculateAccumulatedPower(i>0?e[i-1]:n,n,t.totalWork||0);t.totalWork=s.newAccumulatedWork,t.normalizedPower=void 0}n!=null&&n.temperature&&(t.avgTemperature?t.avgTemperature=(t.avgTemperature+n.temperature)/2:t.avgTemperature=n.temperature,t.maxTemperature=Math.max(t.maxTemperature||0,n.temperature),t.minTemperature=Math.min(t.minTemperature||n.temperature,n.temperature))}}return t}calculateLapAggMetrics(e){var r;if(!e||e.length===0)return;let t={laps:e,timestamp:((r=e[0])==null?void 0:r.timestamp)||new Date};for(let i=0;i<e.length;i++){let n=e[i];n.startPositionLat&&n.startPositionLong&&!(t!=null&&t.startPositionLat)&&!(t!=null&&t.startPositionLong)&&(t.startPositionLat=n.startPositionLat,t.startPositionLong=n.startPositionLong),n.endPositionLat&&n.endPositionLong&&(t.endPositionLat=n.endPositionLat,t.endPositionLong=n.endPositionLong),n.startTime&&!(t!=null&&t.startTime)&&(t.startTime=n.startTime),n.endTime&&(t.endTime=n.endTime),t.timestamp=n.timestamp||n.endTime||t.timestamp,n.totalDistance&&(t.totalDistance=(t.totalDistance||0)+n.totalDistance),n.totalElapsedTime&&(t.totalElapsedTime=(t.totalElapsedTime||0)+n.totalElapsedTime),n.maxSpeed&&(t.maxSpeed=Math.max(t.maxSpeed||0,n.maxSpeed)),n.avgSpeed&&(t.avgSpeed?t.avgSpeed=(t.avgSpeed+n.avgSpeed)/2:t.avgSpeed=n.avgSpeed),n.maxHeartRate&&(t.maxHeartRate=Math.max(t.maxHeartRate||0,n.maxHeartRate)),n.minHeartRate&&(t.minHeartRate=t.minHeartRate?Math.min(t.minHeartRate,n.minHeartRate):n.minHeartRate),n.avgHeartRate&&(t.avgHeartRate?t.avgHeartRate=(t.avgHeartRate+n.avgHeartRate)/2:t.avgHeartRate=n.avgHeartRate),n.maxAltitude&&(t.maxAltitude=Math.max(t.maxAltitude||0,n.maxAltitude)),n.minAltitude&&(t.minAltitude=t.minAltitude?Math.min(t.minAltitude,n.minAltitude):n.minAltitude),n.avgAltitude&&(t.avgAltitude?t.avgAltitude=(t.avgAltitude+n.avgAltitude)/2:t.avgAltitude=n.avgAltitude),n.totalAscent&&(t.totalAscent=(t.totalAscent||0)+n.totalAscent),n.totalDescent&&(t.totalDescent=(t.totalDescent||0)+n.totalDescent),n.maxCadence&&(t.maxCadence=Math.max(t.maxCadence||0,n.maxCadence)),n.avgCadence&&(t.avgCadence?t.avgCadence=(t.avgCadence+n.avgCadence)/2:t.avgCadence=n.avgCadence),n.maxPower&&(t.maxPower=Math.max(t.maxPower||0,n.maxPower)),n.avgPower&&(t.avgPower?t.avgPower=(t.avgPower+n.avgPower)/2:t.avgPower=n.avgPower),n.totalWork&&(t.totalWork=(t.totalWork||0)+n.totalWork),n.maxTemperature&&(t.maxTemperature=Math.max(t.maxTemperature||0,n.maxTemperature)),n.minTemperature&&(t.minTemperature=t.minTemperature?Math.min(t.minTemperature,n.minTemperature):n.minTemperature),n.avgTemperature&&(t.avgTemperature?t.avgTemperature=(t.avgTemperature+n.avgTemperature)/2:t.avgTemperature=n.avgTemperature)}return t}preprocessRecords(e){if(!e||e.length===0)return e;let t=e.filter(s=>s.timestamp).sort((s,o)=>s.timestamp.valueOf()-o.timestamp.valueOf()),r=0,i=[],n=null;for(let s=0;s<t.length;s++){let o=t[s],a={...o};if(!(!a.positionLat||!a.positionLong)){if(s>0&&n&&(o.distance||(a.distance=this.calculatePointDistance(n,a)||0),o.speed||(a.speed=this.calculateInstantSpeed(n,a,a.distance)),o.power)){let c=this.calculateAccumulatedPower(n,a,r);a.accumulatedPower=c.accumulatedPower,r=c.newAccumulatedWork}n=a,i.push(a)}}return i}calculatePointDistance(e,t){if(!e.positionLat||!e.positionLong||!t.positionLat||!t.positionLong)return 0;try{return dt({latitude:e.positionLat,longitude:e.positionLong},{latitude:t.positionLat,longitude:t.positionLong})}catch{return 0}}calculateInstantSpeed(e,t,r){if(!e.timestamp||!t.timestamp||!r)return;let i=(Ue(t.timestamp).valueOf()-Ue(e.timestamp).valueOf())/1e3;if(!(i<=0))return r/i}calculateAccumulatedPower(e,t,r){var a,c;if(e.power===void 0||t.power===void 0||!e.timestamp||!t.timestamp)return{accumulatedPower:r,newAccumulatedWork:r};let i=((a=t.timestamp)==null?void 0:a.valueOf())-((c=e.timestamp)==null?void 0:c.valueOf());if(i<=0)return{accumulatedPower:r,newAccumulatedWork:r};let s=(e.power+t.power)/2*i,o=r+s;return{accumulatedPower:o,newAccumulatedWork:o}}calculateElevationChanges(e,t){let r=0,i=0;return t.altitude!==void 0&&e.altitude!==void 0&&(t.altitude>e.altitude?r=t.altitude-e.altitude:t.altitude<=e.altitude&&(i=e.altitude-t.altitude)),{ascent:r,descent:i}}};function y(p,e=0){let t=Math.pow(10,e);return Math.round(p*t)/t}var G=class extends X{constructor(){super(...arguments);this.name="gpx-to-activity-converter";this.supportedTags=["gpx"];this.convertGPXExtensions=t=>{let r={};return Object.entries(t).forEach(([i,n])=>{if(typeof n<"u"&&n!=="undefined"){let s=We[i]||i;r[s]=this.autoNumber(n)}}),r}}convert(t,r){if(r.sourceFormat!=="gpx")return;let i=r.sourceData;return this.convertGPX(i)}convertGPX(t){let r={metadata:{originType:"GPX",fileType:"gpx"},activities:[]};return t.wpt&&(r.points=this.convertWpts2Points(t.wpt)),t.trk&&(r.activities=t.trk.map((i,n)=>this.convertTrk2Activity(i,n))),t.rte&&(r.routes=t.rte.map((i,n)=>this.convertTrackSeg2Lap(i,n))),r}convertPoint(t,r){let{extensions:i}=t,n=i?this.convertGPXExtensions(i):{};return{index:r||0,positionLat:t.lat,positionLong:t.lon,altitude:t.ele,heartRate:t==null?void 0:t.heartRate,speed:t==null?void 0:t.speed,power:t==null?void 0:t.power,cadence:t==null?void 0:t.cadence,timestamp:je(t.time).toDate(),...n}}convertTrk2Activity(t,r){var s;let i=((s=t.trkseg)==null?void 0:s.map((o,a)=>this.convertTrackSeg2Lap(o,a)))||[],n=new I().calculateLapAggMetrics(i);return{index:r,messageIndex:r,laps:i,...n}}convertTrackSeg2Lap(t,r){var a,c;let i=((c=(a=t.trkpt)==null?void 0:a.filter(d=>d!==void 0&&d.lat&&d.lon))==null?void 0:c.map((d,l)=>this.convertPoint(d,l)))||[],s=new I().calculateRecordsAggMetrics(i);return{index:r,messageIndex:r,...s,records:(s==null?void 0:s.records)||[]}}convertWpts2Points(t){let r=[];for(let i=0;i<t.length;i++){let n=t[i];if(n.lat!=null&&n.lon!=null){let s=this.convertPoint(n,i);s&&r.push(s)}}return r}autoNumber(t){return typeof t=="string"&&t.trim()!==""&&!isNaN(t)?Number(t):t}},B=class extends X{constructor(){super(...arguments);this.name="fit-to-activity-converter";this.supportedTags=["fit"]}convert(t,r){if(r.sourceFormat!=="fit")return;let i=r.sourceData;return this.convertFIT(i)}convertFIT(t){var i,n;let r={metadata:{originType:"FIT",fileType:"fit"},activities:[]};return(i=t.sessionMesgs)!=null&&i.length?r.activities=t.sessionMesgs.map((s,o)=>({index:o,...s,startPositionLat:s.startPositionLat?y(g(Number(s.startPositionLat)),6):void 0,startPositionLong:s.startPositionLong?y(g(Number(s.startPositionLong)),6):void 0,endPositionLat:s.endPositionLat?y(g(Number(s.endPositionLat)),6):void 0,endPositionLong:s.endPositionLong?y(g(Number(s.endPositionLong)),6):void 0,laps:this.convertFITLap2Trackseg(s==null?void 0:s.lapMesgs)})):(n=t.courseMesgs)!=null&&n.length&&(r.routes=t.courseMesgs.map((s,o)=>({index:o,...s,records:this.convertLap2Points(s==null?void 0:s.lapMesgs)}))),r}convertPoint(t,r){let{positionLong:i,positionLat:n,altitude:s,timestamp:o,heartRate:a,cadence:c,distance:d,power:l,enhancedAltitude:v,enhancedSpeed:u,speed:T,temperature:x,...k}=t;if(!(i==null||n==null))return{index:r||0,positionLat:y(g(Number(n)),6),positionLong:y(g(Number(i)),6),altitude:s||v,distance:d,speed:T||u,heartRate:a,power:l,cadence:c,temperature:x,timestamp:o,...k}}convertFITLap2Trackseg(t){var n;let r=[];if(!(t!=null&&t.length))return[];for(let s of t){let o=((n=s==null?void 0:s.recordMesgs)==null?void 0:n.map((a,c)=>this.convertPoint(a,c)).filter(a=>a!==void 0))||[];r.push({index:r.length,...s,startPositionLat:s.startPositionLat?y(g(Number(s.startPositionLat)),6):void 0,startPositionLong:s.startPositionLong?y(g(Number(s.startPositionLong)),6):void 0,endPositionLat:s.endPositionLat?y(g(Number(s.endPositionLat)),6):void 0,endPositionLong:s.endPositionLong?y(g(Number(s.endPositionLong)),6):void 0,records:o})}return r}convertLap2Points(t){var n;let r=[];if(!(t!=null&&t.length))return[];for(let s of t){let o=((n=s.recordMesgs)==null?void 0:n.map((a,c)=>this.convertPoint(a,c)).filter(a=>a!==void 0))||[];o.length&&(r=[...r,...o])}return r}},H=class extends X{constructor(){super(...arguments);this.name="tcx-to-activity-converter";this.supportedTags=["tcx"]}convert(t,r){if(r.sourceFormat!=="tcx")return;let i=r.sourceData;return this.convertTCX(i)}convertTCX(t){var i,n,s,o;let r={metadata:{originType:"TCX",fileType:"tcx"},activities:[]};return(n=(i=t.Activities)==null?void 0:i.Activity)!=null&&n.length&&(r.activities=t.Activities.Activity.map((a,c)=>this.convertTCXActivityToActivity(a,c))),(o=(s=t.Courses)==null?void 0:s.Course)!=null&&o.length,r}convertTCXActivityToActivity(t,r){var s;let i=((s=t.Lap)==null?void 0:s.map((o,a)=>this.convertTCXLap2Lap(o,a)))||[],n=new I().calculateLapAggMetrics(i);return{index:r,messageIndex:r,laps:i,...n}}convertTCXLap2Lap(t,r){var a;let i=((a=t==null?void 0:t.Track)==null?void 0:a.flatMap(c=>c.Trackpoint))||[],n=(i==null?void 0:i.filter(c=>{var d;return c!==void 0&&((d=c.Position)==null?void 0:d.LatitudeDegrees)!==void 0&&c.Position.LongitudeDegrees!==void 0&&c.Time!==void 0}).map((c,d)=>this.convertPoint(c,d)))||[],o=new I().calculateRecordsAggMetrics(n);return{index:r,messageIndex:r,...o,records:(o==null?void 0:o.records)||[]}}convertPoint(t,r){let{Position:i,Time:n,DistanceMeters:s,AltitudeMeters:o}=t;return{index:r||0,positionLat:Number(i.LatitudeDegrees),positionLong:Number(i.LongitudeDegrees),timestamp:je(n).toDate(),distance:s,altitude:o}}};import lt from"dayjs";var V=class extends L{constructor(){super(...arguments);this.name="activity-to-gpx-encoder";this.supportedTags=["gpx"]}encode(t,r){var s,o,a,c,d;if(r.targetFormat!=="gpx"||!((s=t==null?void 0:t.activities)!=null&&s.length))return;let n={version:"1.1",creator:"TrackSwap",metadata:{time:((o=t.activities)==null?void 0:o[0]).timestamp}};return(a=t.points)!=null&&a.length&&(n.wpt=this.convertRecords2Wpts(t.points)),(c=t.routes)!=null&&c.length&&(n.rte=t.routes.map(l=>this.convertRoute2GPXRoute(l))),(d=t.activities)!=null&&d.length&&(n.trk=t.activities.map(l=>this.convertActivity2GPXTrack(l))),n}convertRecords2Wpts(t){return t==null?void 0:t.filter(r=>typeof r.positionLat=="number"&&typeof r.positionLong=="number").map(r=>({lat:r.positionLat,lon:r.positionLong,ele:r==null?void 0:r.altitude,time:r==null?void 0:r.timestamp,speed:r==null?void 0:r.speed,hdop:r==null?void 0:r.hdop,vdop:r==null?void 0:r.vdop,pdop:r==null?void 0:r.pdop,extensions:this.extractGPXExtensions(r)}))}convertRoute2GPXRoute(t){return{rtept:t.records?this.convertRecords2Wpts(t.records):[]}}convertActivity2GPXTrack(t){var r;return{trkseg:((r=t.laps)==null?void 0:r.map(i=>({trkpt:i.records?this.convertRecords2Wpts(i.records):[]})))||[]}}extractGPXExtensions(t){let r={},i={};return typeof(t==null?void 0:t.heartRate)<"u"&&(i["gpxtpx:hr"]=t.heartRate),typeof(t==null?void 0:t.cadence)<"u"&&(i["gpxtpx:cad"]=t.cadence),typeof(t==null?void 0:t.temperature)<"u"&&(i["gpxtpx:atemp"]=t.temperature),Object.keys(i).length>0&&(r["gpxtpx:TrackPointExtension"]=i),typeof(t==null?void 0:t.power)<"u"&&(r["gpxpx:PowerExtension"]={"gpxpx:PowerInWatts":t.power}),Object.keys(r).length>0?r:void 0}},z=class extends L{constructor(){super(...arguments);this.name="activity-to-fit-encoder";this.supportedTags=["fit"]}encode(t,r){var n,s;if(r.targetFormat!=="fit"||!((n=t==null?void 0:t.activities)!=null&&n.length))return;let i={};return i.sessionMesgs=(s=t.activities)==null?void 0:s.map(o=>this.convertActivity2FITSession(o)),i}convertActivity2FITSession(t){var i;return{...t,event:(t==null?void 0:t.event)||"session",sport:(t==null?void 0:t.sport)||"generic",lapMesgs:((i=t.laps)==null?void 0:i.map(n=>this.convertLap2FITLap(n)))||[]}}convertLap2FITLap(t){var i;return{startTime:t.startTime,...t,recordMesgs:((i=t.records)==null?void 0:i.map(n=>this.convertPoint2FITRecord(n)))||[]}}convertPoint2FITRecord(t){return t}},W=class extends L{constructor(){super(...arguments);this.name="sport-to-tcx-encoder";this.supportedTags=["tcx"]}encode(t,r){var n;if(r.targetFormat!=="tcx"||!((n=t==null?void 0:t.activities)!=null&&n.length))return;let i={Author:{Name:"TrackSwap"}};return i.Activities={Activity:t.activities.map(s=>this.convertActivity2TCXActivity(s))},i}convertActivity2TCXActivity(t){var i;let r="Other";return(t.sport==="Running"||t.sport==="Biking")&&(r=t.sport),{Id:`Activity_${Date.now()}`,Activity:r,Lap:((i=t.laps)==null?void 0:i.map(n=>this.convertLap2TCXLap(n)))||[]}}convertLap2TCXLap(t){let r={TotalTimeSeconds:t.totalElapsedTime,DistanceMeters:t.totalDistance,MaximumSpeed:t.maxSpeed,Calories:t.totalCalories,AverageHeartRateBpm:t.avgHeartRate,MaximumHeartRateBpm:t.maxHeartRate,Intensity:"Active",TriggerMethod:"Manual",Track:t.records?[this.convertRecords2TCXTrack(t.records)]:[]};return(t.avgCadence!==void 0||t.maxCadence!==void 0)&&(r.Cadence={Low:t.avgCadence||0,High:t.maxCadence||0}),r}convertRecords2TCXTrack(t){return{Trackpoint:t.map(r=>this.convertPoint2TCXTrackpoint(r))}}convertPoint2TCXTrackpoint(t){var i,n;let r={Time:lt(t.timestamp).toISOString(),Position:{LatitudeDegrees:((i=t.positionLat)==null?void 0:i.toString())||"0",LongitudeDegrees:((n=t.positionLong)==null?void 0:n.toString())||"0"},AltitudeMeters:t.altitude,DistanceMeters:t.distance};return t.heartRate&&(r.HeartRateBpm=t.heartRate),t.cadence&&(r.Cadence={Low:t.cadence,High:t.cadence}),t.power&&(r.Extensions={"ns3:TPX":{"ns3:Watts":t.power}}),r}convertRoute2TCXCourse(t){return{Name:`Course_${Date.now()}`,Track:t.records?[this.convertRecords2TCXTrack(t.records)]:[]}}};var U=class{constructor(){this.converters=new Map;this.encoders=new Map;this.registerDefaultConverters(),this.registerDefaultEncoders()}registerDefaultConverters(){this.registerConverter(new G),this.registerConverter(new B),this.registerConverter(new H)}registerDefaultEncoders(){this.registerEncoder(new V),this.registerEncoder(new z),this.registerEncoder(new W)}registerConverter(e){this.converters.set(e.name,e)}registerEncoder(e){this.encoders.set(e.name,e)}async convertToActivity(e,t){let r={metadata:new Map,errors:[],warnings:[],stats:{startTime:Date.now(),processedTokens:0,convertedElements:0},sourceFormat:t,sourceData:e,performance:{startTime:Date.now()}};try{let s=this.findConverter(t);if(!s)throw new Error(`No converter found for format "${t}"`);let o=Date.now(),a=s.convert(e,r);if(r.performance.convertTime=Date.now()-o,!a)throw new Error(`Converter "${s.name}" returned empty result`);let c=a;return r.result=c,r.performance.endTime=Date.now(),r.stats.endTime=Date.now(),c}catch(s){throw r.errors.push(s),s}}async encodeActivity(e,t){let r={metadata:new Map,errors:[],warnings:[],stats:{startTime:Date.now(),processedTokens:0,convertedElements:0},targetFormat:t,performance:{startTime:Date.now()}};try{let i=this.findEncoder(t);if(!i)throw new Error(`No encoder found for format "${t}"`);let n=Date.now(),s=i.encode(e,r);if(r.performance.encodeTime=Date.now()-n,!s)throw new Error(`Encoder "${i.name}" returned empty result`);return r.result=s,r.performance.endTime=Date.now(),r.stats.endTime=Date.now(),s}catch(i){throw r.errors.push(i),i}}findConverter(e){return Array.from(this.converters.values()).find(t=>{var r;return(r=t.supportedTags)==null?void 0:r.includes(e)})}findEncoder(e){return Array.from(this.encoders.values()).find(t=>{var r;return(r=t.supportedTags)==null?void 0:r.includes(e)})}async destroy(){this.converters.clear(),this.encoders.clear()}};var j=class{constructor(){this.gpxDecoder=new F,this.gpxEncoder=new S,this.fitDecoder=new w,this.fitEncoder=new A,this.tcxDecoder=new D,this.tcxEncoder=new R,this.activityProcessor=new U}async parseGPX(e){try{return await this.gpxDecoder.parserByBuffer(e)}catch(t){throw new Error(`GPX parsing failed: ${t.message}`)}}async parseGPXString(e){let t=Buffer.from(e,"utf-8");return this.parseGPX(t)}async encodeGPX(e){try{return await this.gpxEncoder.encode(e)}catch(t){throw new Error(`GPX encoding failed: ${t.message}`)}}encodeGPXString(e){try{return this.gpxEncoder.encodeToString(e)}catch(t){throw new Error(`GPX encoding failed: ${t.message}`)}}async parseFIT(e){try{return await this.fitDecoder.parseByBuffer(e)}catch(t){throw new Error(`FIT parsing failed: ${t.message}`)}}async encodeFIT(e){try{return await this.fitEncoder.encode(e)}catch(t){throw new Error(`FIT encoding failed: ${t.message}`)}}async encodeFITCourse(e){try{return await this.fitEncoder.encodeCourse(e)}catch(t){throw new Error(`FIT Course encoding failed: ${t.message}`)}}async parseTCXString(e){let t=Buffer.from(e,"utf-8");return this.parseTCX(t)}async parseTCX(e){try{let t=await this.tcxDecoder.parseByBuffer(e);if(!t)throw new Error("TCX parsing result is empty");return t}catch(t){throw new Error(`TCX parsing failed: ${t.message}`)}}async encodeTCX(e){try{return await this.tcxEncoder.encode(e)}catch(t){throw new Error(`TCX encoding failed: ${t.message}`)}}async encodeTCXString(e){try{return await this.tcxEncoder.encodeToString(e)}catch(t){throw new Error(`TCX encoding failed: ${t.message}`)}}async convertGPXToActivity(e){return await this.activityProcessor.convertToActivity(e,"gpx")}async convertFITToActivity(e){return await this.activityProcessor.convertToActivity(e,"fit")}async convertTCXToActivity(e){return await this.activityProcessor.convertToActivity(e,"tcx")}async convertActivityToGPX(e){return await this.activityProcessor.encodeActivity(e,"gpx")}async convertActivityToFIT(e){return await this.activityProcessor.encodeActivity(e,"fit")}async convertActivityToTCX(e){return await this.activityProcessor.encodeActivity(e,"tcx")}async convertFile(e,t,r){try{let i=r||this.detectFormat(e);if(i==="unknown"||i==null)throw new Error("Unable to recognize source file format, please specify sourceType parameter");if(i===t)return e;let n;switch(i){case"gpx":let o=await this.parseGPX(e);if(!o)throw new Error("GPX file parsing failed");n=o;break;case"fit":n=await this.parseFIT(e);break;case"tcx":n=await this.parseTCX(e);break;default:throw new Error(`Unsupported source file format: ${i}`)}let s;switch(i){case"gpx":s=await this.convertGPXToActivity(n);break;case"fit":s=await this.convertFITToActivity(n);break;case"tcx":s=await this.convertTCXToActivity(n);break;default:throw new Error(`Unsupported source file format conversion: ${i}`)}switch(t){case"gpx":let o=await this.convertActivityToGPX(s);return await this.encodeGPX(o);case"fit":let a=await this.convertActivityToFIT(s);return await this.encodeFIT(a);case"tcx":let c=await this.convertActivityToTCX(s);return await this.encodeTCX(c);default:throw new Error(`Unsupported target file format: ${t}`)}}catch(i){let n=r||"auto-detect";throw new Error(`${n} to ${t.toUpperCase()} failed: ${i.message}`)}}detectFormat(e){let t=e.toString("utf-8",0,Math.min(1024,e.length));if(e.length>=12&&e.toString("ascii",8,12)===".FIT")return"fit";if(t.includes("<?xml")){if(t.includes("<gpx")||t.includes("http://www.topografix.com/GPX/"))return"gpx";if(t.includes("<TrainingCenterDatabase")||t.includes("http://www.garmin.com/xmlschemas/TrainingCenterDatabase/"))return"tcx"}return"unknown"}async parseFile(e,t){let r=t||this.detectFormat(e);if(r==="unknown")throw new Error("Unable to recognize file format, please specify sourceType parameter");switch(r){case"gpx":let i=await this.parseGPX(e);if(!i)throw new Error("GPX parsing failed");return i;case"fit":return await this.parseFIT(e);case"tcx":return await this.parseTCX(e);default:throw new Error(`Unsupported file format: ${r}`)}}async parseToActivity(e,t){let r=t||this.detectFormat(e);if(r==="unknown")throw new Error("Unable to recognize file format, please specify sourceType parameter");let i;switch(r){case"gpx":let n=await this.parseGPX(e);if(!n)throw new Error("GPX parsing failed");i=await this.convertGPXToActivity(n);break;case"fit":let s=await this.parseFIT(e);s&&(i=await this.convertFITToActivity(s));break;case"tcx":let o=await this.parseTCX(e);i=await this.convertTCXToActivity(o);break;default:throw new Error(`Unsupported file format: ${r}`)}return i}getActivityProcessor(){return this.activityProcessor}getGPXDecoder(){return this.gpxDecoder}getGPXEncoder(){return this.gpxEncoder}getFITDecoder(){return this.fitDecoder}getFITEncoder(){return this.fitEncoder}getTCXDecoder(){return this.tcxDecoder}getTCXEncoder(){return this.tcxEncoder}async destroy(){await this.gpxDecoder.destroy(),await this.fitDecoder.destroy(),await this.tcxDecoder.destroy(),await this.activityProcessor.destroy()}};var Mn=j;export{U as ActivityProcessor,z as ActivityToFITEncoder,V as ActivityToGPXEncoder,W as ActivityToTCXEncoder,X as BaseActivityConverter,L as BaseActivityEncoder,ze as BaseActivityMiddleware,w as FITDecoder,A as FITEncoder,B as FITToActivityConverter,F as GPXDecoder,S as GPXEncoder,G as GPXToActivityConverter,me as PipelineStage,D as TCXDecoder,R as TCXEncoder,H as TCXToActivityConverter,j as TrackSwap,Mn as default,Be as registerDefaultMiddlewares};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trackswap",
3
- "version": "0.0.17",
3
+ "version": "0.0.18",
4
4
  "description": "A powerful and flexible GPX parser and encoder library for Node.js and TypeScript. TrackSwap provides comprehensive support for GPX 1.1 format with advanced features like plugin system, middleware support, and optimized performance.",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",