ts-watches 0.1.0 → 0.1.1
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/bin/cli.d.ts +1 -0
- package/dist/bin/cli.js +2 -2
- package/dist/chunk-b68y8bzg.js +2 -0
- package/dist/chunk-cahf1yhs.js +1 -0
- package/dist/chunk-x32nxjdz.js +2 -0
- package/dist/{cloud → src/cloud}/garmin-activity-api.d.ts +29 -1
- package/dist/src/cloud/index.d.ts +11 -0
- package/dist/src/drivers/index.js +1 -0
- package/dist/src/fit/index.js +1 -0
- package/dist/src/index.js +142 -143
- package/package.json +5 -5
- package/dist/chunk-gsgt8r0z.js +0 -2
- package/dist/cloud/index.d.ts +0 -4
- /package/dist/{analysis → src/analysis}/index.d.ts +0 -0
- /package/dist/{analysis → src/analysis}/personal-records.d.ts +0 -0
- /package/dist/{analysis → src/analysis}/race-predictor.d.ts +0 -0
- /package/dist/{analysis → src/analysis}/running-dynamics.d.ts +0 -0
- /package/dist/{analysis → src/analysis}/training-load.d.ts +0 -0
- /package/dist/{analysis → src/analysis}/zones.d.ts +0 -0
- /package/dist/{cloud → src/cloud}/garmin-connect.d.ts +0 -0
- /package/dist/{cloud → src/cloud}/strava.d.ts +0 -0
- /package/dist/{cloud → src/cloud}/trainingpeaks.d.ts +0 -0
- /package/dist/{config.d.ts → src/config.d.ts} +0 -0
- /package/dist/{drivers → src/drivers}/apple.d.ts +0 -0
- /package/dist/{drivers → src/drivers}/coros.d.ts +0 -0
- /package/dist/{drivers → src/drivers}/garmin.d.ts +0 -0
- /package/dist/{drivers → src/drivers}/index.d.ts +0 -0
- /package/dist/{drivers → src/drivers}/polar.d.ts +0 -0
- /package/dist/{drivers → src/drivers}/suunto.d.ts +0 -0
- /package/dist/{drivers → src/drivers}/wahoo.d.ts +0 -0
- /package/dist/{export → src/export}/csv.d.ts +0 -0
- /package/dist/{export → src/export}/geojson.d.ts +0 -0
- /package/dist/{export → src/export}/gpx.d.ts +0 -0
- /package/dist/{export → src/export}/index.d.ts +0 -0
- /package/dist/{export → src/export}/tcx.d.ts +0 -0
- /package/dist/{fit → src/fit}/constants.d.ts +0 -0
- /package/dist/{fit → src/fit}/decoder.d.ts +0 -0
- /package/dist/{fit → src/fit}/index.d.ts +0 -0
- /package/dist/{fit → src/fit}/parser.d.ts +0 -0
- /package/dist/{index.d.ts → src/index.d.ts} +0 -0
- /package/dist/{realtime → src/realtime}/ant-plus.d.ts +0 -0
- /package/dist/{realtime → src/realtime}/bluetooth.d.ts +0 -0
- /package/dist/{realtime → src/realtime}/index.d.ts +0 -0
- /package/dist/{realtime → src/realtime}/live-tracking.d.ts +0 -0
- /package/dist/{types.d.ts → src/types.d.ts} +0 -0
- /package/dist/{workouts → src/workouts}/builder.d.ts +0 -0
- /package/dist/{workouts → src/workouts}/course.d.ts +0 -0
- /package/dist/{workouts → src/workouts}/index.d.ts +0 -0
- /package/dist/{workouts → src/workouts}/training-plan.d.ts +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
package/dist/bin/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import{
|
|
2
|
+
import{l as E}from"../chunk-b68y8bzg.js";import"../chunk-cahf1yhs.js";import{existsSync as q6}from"node:fs";import h from"node:fs/promises";import p from"node:os";import k from"node:path";import P from"node:process";import{EventEmitter as j6}from"node:events";import L from"node:process";import n from"node:process";import g from"node:process";import b from"node:process";import B from"node:process";import r from"node:tty";import r6,{stdin as bz,stdout as Az}from"node:process";import s,{stdin as t6,stdout as o6}from"node:process";import e6 from"node:readline";class o{configPath;config=null;events=[];retryCount=0;maxRetries=3;retryDelayMs=1000;constructor(){let z=p.homedir(),J=k.join(z,".config","clapp");this.configPath=k.join(J,"telemetry.json")}async isEnabled(){if(P.env.DO_NOT_TRACK==="1"||P.env.DO_NOT_TRACK==="true")return!1;if(P.env.NO_TELEMETRY==="1"||P.env.NO_TELEMETRY==="true")return!1;return(await this.loadConfig()).enabled}async enable(){let z=await this.loadConfig();if(z.enabled=!0,!z.userId)z.userId=this.generateUserId();await this.saveConfig(z)}async disable(){let z=await this.loadConfig();z.enabled=!1,await this.saveConfig(z)}async track(z,J){if(!await this.isEnabled())return;let $={event:z,...J,timestamp:Date.now(),platform:p.platform(),nodeVersion:P.version};if(this.events.push($),this.events.length>=10)await this.send()}async trackCommand(z,J){await this.track("command",{command:z,duration:J})}async trackError(z,J){await this.track("error",{error:z,command:J})}async send(){if(!await this.isEnabled()||this.events.length===0)return!0;try{this.events=[],this.retryCount=0;let J=await this.loadConfig();return J.lastSent=Date.now(),await this.saveConfig(J),!0}catch{if(this.retryCount<this.maxRetries){this.retryCount++;let J=this.retryDelayMs*2**(this.retryCount-1);return await this.sleep(J),this.send()}return this.events=[],this.retryCount=0,!1}}async flush(){if(this.events.length===0)return!0;return this.send()}sleep(z){return new Promise((J)=>setTimeout(J,z))}async status(){let z=await this.loadConfig();return{enabled:z.enabled,doNotTrack:P.env.DO_NOT_TRACK==="1"||P.env.DO_NOT_TRACK==="true",eventsQueued:this.events.length,lastSent:z.lastSent}}async loadConfig(){if(this.config)return this.config;try{if(q6(this.configPath)){let z=await h.readFile(this.configPath,"utf-8");return this.config=JSON.parse(z),this.config}}catch{}return this.config={enabled:!1},this.config}async saveConfig(z){this.config=z;try{let J=k.dirname(this.configPath);await h.mkdir(J,{recursive:!0}),await h.writeFile(this.configPath,JSON.stringify(z,null,2),"utf-8")}catch{}}generateUserId(){let z=Math.random().toString(36).substring(2,15),J=Date.now().toString(36);return`${z}-${J}`}}var wz=new o;function X6(z,J={}){let Z={_:[]},$=J.alias||{},Q=new Set(J.boolean||[]),q={};for(let j of Object.keys($))for(let Y of $[j])q[Y]=j;for(let j of Q)if($[j])for(let Y of $[j])Q.add(Y);function X(j,Y){let U=q[j]||j;if(Z[U]=Y,$[U])for(let F of $[U])Z[F]=Y;if(q[j]&&$[q[j]])for(let F of $[q[j]])Z[F]=Y;Z[j]=Y}for(let j=0;j<z.length;j++){let Y=z[j];if(Y==="--"){Z._.push(...z.slice(j+1));break}if(Y.startsWith("--")){let U=Y.indexOf("=");if(U!==-1){let F=Y.slice(2,U),G=Y.slice(U+1);X(F,G)}else{let F=Y.slice(2);if(F.startsWith("no-")){let H=F.slice(3);X(H,!1);continue}let G=q[F]||F;if(Q.has(G)||Q.has(F))X(F,!0);else{let H=z[j+1];if(H!==void 0&&!H.startsWith("-"))X(F,H),j++;else X(F,!0)}}}else if(Y.startsWith("-")&&Y.length>1){let U=Y.slice(1);for(let F=0;F<U.length;F++){let G=U[F],H=q[G]||G;if(F===U.length-1&&!Q.has(H)&&!Q.has(G)){let K=z[j+1];if(K!==void 0&&!K.startsWith("-"))X(G,K),j++;else X(G,!0)}else X(G,!0)}}else Z._.push(Y)}return Z}function v(z){return z.replace(/[<[].+/,"").trim()}function U6(z){let J=/<([^>]+)>/g,Z=/\[([^\]]+)\]/g,$=[],Q=(j)=>{let Y=!1,U=j[1];if(U.startsWith("..."))U=U.slice(3),Y=!0;return{required:j[0].startsWith("<"),value:U,variadic:Y}},q;while(q=J.exec(z))$.push(Q(q));let X;while(X=Z.exec(z))$.push(Q(X));return $}function F6(z){let J={alias:{},boolean:[]};for(let[Z,$]of z.entries()){if($.names.length>1)J.alias[$.names[0]]=$.names.slice(1);if($.isBoolean)if($.negated){if(!z.some((q,X)=>{return X!==Z&&q.names.some((j)=>$.names.includes(j))&&typeof q.required==="boolean"}))J.boolean.push($.names[0])}else J.boolean.push($.names[0])}return J}function i(z){return z.reduce((J,Z)=>J.length>=Z.length?J:Z,"")}function S(z,J){return z.length>=J?z:`${z}${" ".repeat(J-z.length)}`}function G6(z){return z.replace(/([a-z])-([a-z])/g,(J,Z,$)=>{return Z+$.toUpperCase()})}function H6(z,J,Z){let $=0,Q=J.length,q=z,X;for(;$<Q;++$)X=q[J[$]],q=q[J[$]]=$===Q-1?Z:X!=null?X:!!~J[$+1].indexOf(".")||!(+J[$+1]>-1)?{}:[]}function K6(z,J){for(let Z of Object.keys(J)){let $=J[Z];if($.shouldTransform){if(z[Z]=Array.prototype.concat.call([],z[Z]),typeof $.transformFunction==="function")z[Z]=z[Z].map($.transformFunction)}}}function V6(z){let J=/([^\\/]+)$/.exec(z);return J?J[1]:""}function e(z){return z.split(".").map((J,Z)=>{return Z===0?G6(J):J}).join(".")}class I extends Error{exitCode=2;isUsageError=!0;constructor(z){super(z);if(this.name=this.constructor.name,typeof Error.captureStackTrace==="function")Error.captureStackTrace(this,this.constructor);else this.stack=Error(z).stack}format(z=!1){if(z&&this.stack)return`${this.message}
|
|
3
3
|
|
|
4
4
|
Stack trace:
|
|
5
5
|
${this.stack}`;return this.message}}function W6(){let{env:z}=n,{TERM:J,TERM_PROGRAM:Z}=z;if(n.platform!=="win32")return J!=="linux";return Boolean(z.WT_SESSION)||Boolean(z.TERMINUS_SUBLIME)||z.ConEmuTask==="{cmd::Cmder}"||Z==="Terminus-Sublime"||Z==="vscode"||J==="xterm-256color"||J==="alacritty"||J==="rxvt-unicode"||J==="rxvt-unicode-256color"||z.TERMINAL_EMULATOR==="JetBrains-JediTerm"}var C="\x1B",w=`${C}[`;var D={to(z,J){if(!J)return`${w}${z+1}G`;return`${w}${J+1};${z+1}H`},move(z,J){let Z="";if(z<0)Z+=`${w}${-z}D`;else if(z>0)Z+=`${w}${z}C`;if(J<0)Z+=`${w}${-J}A`;else if(J>0)Z+=`${w}${J}B`;return Z},up:(z=1)=>`${w}${z}A`,down:(z=1)=>`${w}${z}B`,forward:(z=1)=>`${w}${z}C`,backward:(z=1)=>`${w}${z}D`,nextLine:(z=1)=>`${w}E`.repeat(z),prevLine:(z=1)=>`${w}F`.repeat(z),left:`${w}G`,hide:`${w}?25l`,show:`${w}?25h`,save:`${C}7`,restore:`${C}8`};var y={screen:`${w}2J`,up:(z=1)=>`${w}1J`.repeat(z),down:(z=1)=>`${w}J`.repeat(z),line:`${w}2K`,lineEnd:`${w}K`,lineStart:`${w}1K`,lines(z){let J="";for(let Z=0;Z<z;Z++)J+=this.line+(Z<z-1?D.up():"");if(z)J+=D.left;return J}},Nz={screen:`${C}c`};function w6(z,J){let Z=[];for(let $=0;$<=J.length;$++)Z[$]=[$];for(let $=0;$<=z.length;$++)Z[0][$]=$;for(let $=1;$<=J.length;$++)for(let Q=1;Q<=z.length;Q++)if(J.charAt($-1)===z.charAt(Q-1))Z[$][Q]=Z[$-1][Q-1];else Z[$][Q]=Math.min(Z[$-1][Q-1]+1,Z[$][Q-1]+1,Z[$-1][Q]+1);return Z[J.length][z.length]}function z6(z,J,Z=2,$=3){return J.map((Q)=>({cmd:Q,distance:w6(z,Q)})).filter(({distance:Q})=>Q<=Z).sort((Q,q)=>Q.distance-q.distance).slice(0,$).map(({cmd:Q})=>Q)}class J6{rawName;description;name;names;isBoolean;required;config;negated;constructor(z,J,Z){if(this.rawName=z,this.description=J,this.config=Object.assign({},Z),z=z.replace(/\.\*/g,""),this.negated=!1,this.names=v(z).split(",").map(($)=>{let Q=$.trim().replace(/^-{1,2}/,"");if(Q.startsWith("no-"))this.negated=!0,Q=Q.replace(/^no-/,"");return e(Q)}).sort(($,Q)=>$.length>Q.length?1:-1),this.name=this.names[this.names.length-1],this.negated&&this.config.default==null)this.config.default=!0;if(z.includes("<"))this.required=!0;else if(z.includes("["))this.required=!1;else this.isBoolean=!0}}var Oz=g.argv,D6=`${g.platform}-${g.arch} bun-v${typeof Bun<"u"?Bun.version:"unknown"}`,l=b.argv,L6=`${b.platform}-${b.arch} node-${b.version}`;class _{rawName;description;config;cli;options;aliasNames;name;namespace;args;commandAction;usageText;versionNumber;examples;helpCallback;globalCommand;beforeHooks;afterHooks;middleware;constructor(z,J,Z,$){this.rawName=z,this.description=J,this.config=Z,this.cli=$,this.options=[],this.aliasNames=[],this.name=v(z);let Q=v(z),q=Q.indexOf(":");if(q>0)this.namespace=Q.substring(0,q),this.name=Q.substring(q+1);if(this.args=U6(z),this.examples=[],this.beforeHooks=[],this.afterHooks=[],this.middleware=[],!Z)this.config={}}usage(z){return this.usageText=z,this}allowUnknownOptions(){return this.config.allowUnknownOptions=!0,this}ignoreOptionDefaultValue(){return this.config.ignoreOptionDefaultValue=!0,this}version(z,J="-v, --version"){return this.versionNumber=z,this.option(J,"Display version number"),this}example(z){return this.examples.push(z),this}option(z,J,Z){let $=new J6(z,J,Z);return this.options.push($),this}alias(z){return this.aliasNames.push(z),this}action(z){return this.commandAction=z,this}before(z){return this.beforeHooks.push(z),this}after(z){return this.afterHooks.push(z),this}use(z){return this.middleware.push(z),this}isMatched(z){if(this.aliasNames.includes(z))return!0;if(this.namespace)return`${this.namespace}:${this.name}`===z;return this.name===z}get isDefaultCommand(){return this.name===""||this.aliasNames.includes("!")}get isGlobalCommand(){return this instanceof f}get displayName(){return this.namespace?`${this.namespace}:${this.name}`:this.name}hasOption(z){return z=z.split(".")[0],!!this.options.find((J)=>{return J.names.includes(z)})}outputHelp(){let{name:z,commands:J}=this.cli,{versionNumber:Z,options:$,helpCallback:Q}=this.cli.globalCommand,q=[{body:`${z}${Z?`/${Z}`:""}`}];if(q.push({title:"Usage",body:` $ ${z} ${this.usageText||this.rawName}`}),(this.isGlobalCommand||this.isDefaultCommand)&&J.length>0){let Y=i(J.map((K)=>K.rawName)),U=new Map,F=[];for(let K of J)if(K.namespace){if(!U.has(K.namespace))U.set(K.namespace,[]);U.get(K.namespace).push(K)}else F.push(K);let G="";if(F.length>0)G+=F.map((K)=>{return` ${S(K.rawName,Y.length)} ${K.description}`}).join(`
|
|
@@ -37,7 +37,7 @@ Run \`${this.name??"cli"} --help\` for usage.`;L.stderr.write(`${q}${Q}${X}
|
|
|
37
37
|
`).length-1;this.output.write(D.move(-999,z*-1))}render(){let z=t(this._render(this)??"",s.stdout.columns,{hard:!0,trim:!1});if(z===this._prevFrame)return;if(this.state==="initial")this.output.write(D.hide);else{let J=s6(this._prevFrame,z);if(this.restoreCursor(),J&&J?.length===1){let Z=J[0];this.output.write(D.move(0,Z)),this.output.write(y.lines(1));let $=z.split(`
|
|
38
38
|
`);this.output.write($[Z]),this._prevFrame=z,this.output.write(D.move(0,$.length-Z-1));return}if(J&&J?.length>1){let Z=J[0];this.output.write(D.move(0,Z)),this.output.write(y.down());let Q=z.split(`
|
|
39
39
|
`).slice(Z);this.output.write(Q.join(`
|
|
40
|
-
`)),this._prevFrame=z;return}this.output.write(y.down())}if(this.output.write(z),this.state==="initial")this.state="active";this._prevFrame=z}}function Zz(z,J){if(z===void 0)return 0;if(J.length===0)return 0;let $=J.findIndex((Q)=>Q.value===z);return $!==-1?$:0}function $z(z,J){return(J.label??String(J.value)).toLowerCase().includes(z.toLowerCase())}function Qz(z,J){if(!J)return;if(z)return J;return J[0]}class Yz extends d{filteredOptions;multiple;isNavigating=!1;selectedValues=[];focusedValue;#z=0;#Z="";#$;#J;get cursor(){return this.#z}get userInputWithCursor(){if(!this.userInput)return A.inverse(A.hidden("_"));if(this._cursor>=this.userInput.length)return`${this.userInput}█`;let z=this.userInput.slice(0,this._cursor),[J,...Z]=this.userInput.slice(this._cursor);return`${z}${A.inverse(J)}${Z.join("")}`}get options(){if(typeof this.#J==="function")return this.#J();return this.#J}constructor(z){super(z);this.#J=z.options;let J=this.options;this.filteredOptions=[...J],this.multiple=z.multiple===!0,this.#$=z.filter??$z;let Z;if(z.initialValue&&Array.isArray(z.initialValue))if(this.multiple)Z=z.initialValue;else Z=z.initialValue.slice(0,1);else if(!this.multiple&&this.options.length>0)Z=[this.options[0].value];if(Z)for(let $ of Z){let Q=J.findIndex((q)=>q.value===$);if(Q!==-1)this.toggleSelected($),this.#z=Q}this.focusedValue=this.options[this.#z]?.value,this.on("key",($,Q)=>this.#Q($,Q)),this.on("userInput",($)=>this.#Y($))}_isActionKey(z,J){return z==="\t"||this.multiple&&this.isNavigating&&J.name==="space"&&z!==void 0&&z!==""}#Q(z,J){let Z=J.name==="up",$=J.name==="down",Q=J.name==="return";if(Z||$){if(this.#z=Math.max(0,Math.min(this.#z+(Z?-1:1),this.filteredOptions.length-1)),this.focusedValue=this.filteredOptions[this.#z]?.value,!this.multiple)this.selectedValues=[this.focusedValue];this.isNavigating=!0}else if(Q)this.value=Qz(this.multiple,this.selectedValues);else if(this.multiple)if(this.focusedValue!==void 0&&(J.name==="tab"||this.isNavigating&&J.name==="space"))this.toggleSelected(this.focusedValue);else this.isNavigating=!1;else{if(this.focusedValue)this.selectedValues=[this.focusedValue];this.isNavigating=!1}}deselectAll(){this.selectedValues=[]}toggleSelected(z){if(this.filteredOptions.length===0)return;if(this.multiple)if(this.selectedValues.includes(z))this.selectedValues=this.selectedValues.filter((J)=>J!==z);else this.selectedValues=[...this.selectedValues,z];else this.selectedValues=[z]}#Y(z){if(z!==this.#Z){this.#Z=z;let J=this.options;if(z)this.filteredOptions=J.filter((Z)=>this.#$(z,Z));else this.filteredOptions=[...J];if(this.#z=Zz(this.focusedValue,this.filteredOptions),this.focusedValue=this.filteredOptions[this.#z]?.value,!this.multiple)if(this.focusedValue!==void 0)this.toggleSelected(this.focusedValue);else this.deselectAll()}}}class qz extends d{options;cursor=0;#z;getGroupItems(z){return this.options.filter((J)=>J.group===z)}isGroupSelected(z){let J=this.getGroupItems(z),Z=this.value;if(Z===void 0)return!1;return J.every(($)=>Z.includes($.value))}toggleValue(){let z=this.options[this.cursor];if(this.value===void 0)this.value=[];if(z.group===!0){let J=String(z.value),Z=this.getGroupItems(J);if(this.isGroupSelected(J))this.value=this.value.filter(($)=>Z.findIndex((Q)=>Q.value===$)===-1);else this.value=[...this.value,...Z.map(($)=>$.value)];this.value=Array.from(new Set(this.value))}else{let J=this.value.includes(z.value);this.value=J?this.value.filter((Z)=>Z!==z.value):[...this.value,z.value]}}constructor(z){super(z,!1);let{options:J}=z;this.#z=z.selectableGroups!==!1,this.options=Object.entries(J).flatMap(([Z,$])=>[{value:Z,group:!0,label:Z},...$.map((Q)=>({...Q,group:Z}))]),this.value=[...z.initialValues??[]],this.cursor=Math.max(this.options.findIndex(({value:Z})=>Z===z.cursorAt),this.#z?0:1),this.on("cursor",(Z)=>{switch(Z){case"left":case"up":{this.cursor=this.cursor===0?this.options.length-1:this.cursor-1;let $=this.options[this.cursor]?.group===!0;if(!this.#z&&$)this.cursor=this.cursor===0?this.options.length-1:this.cursor-1;break}case"down":case"right":{this.cursor=this.cursor===this.options.length-1?0:this.cursor+1;let $=this.options[this.cursor]?.group===!0;if(!this.#z&&$)this.cursor=this.cursor===this.options.length-1?0:this.cursor+1;break}case"space":this.toggleValue();break}})}}var jz=W6();var V=(z,J)=>jz?z:J,kz=V("◆","*"),Sz=V("■","x"),yz=V("▲","x"),vz=V("◇","o"),gz=V("┌","T"),Xz=V("│","|"),_z=V("└","—"),fz=V("●",">"),mz=V("○"," "),dz=V("◻","[•]"),uz=V("◼","[+]"),cz=V("◻","[ ]"),pz=V("▪","•"),nz=V("─","-"),iz=V("╮","+"),lz=V("├","+"),rz=V("╯","+"),az=V("●","•"),sz=V("◆","*"),tz=V("▲","!"),oz=V("■","x");var ez={light:V("─","-"),heavy:V("━","="),block:V("█","#")};function Uz(){return`${A.gray(Xz)} `}var z4=Uz();var u="0.1.
|
|
40
|
+
`)),this._prevFrame=z;return}this.output.write(y.down())}if(this.output.write(z),this.state==="initial")this.state="active";this._prevFrame=z}}function Zz(z,J){if(z===void 0)return 0;if(J.length===0)return 0;let $=J.findIndex((Q)=>Q.value===z);return $!==-1?$:0}function $z(z,J){return(J.label??String(J.value)).toLowerCase().includes(z.toLowerCase())}function Qz(z,J){if(!J)return;if(z)return J;return J[0]}class Yz extends d{filteredOptions;multiple;isNavigating=!1;selectedValues=[];focusedValue;#z=0;#Z="";#$;#J;get cursor(){return this.#z}get userInputWithCursor(){if(!this.userInput)return A.inverse(A.hidden("_"));if(this._cursor>=this.userInput.length)return`${this.userInput}█`;let z=this.userInput.slice(0,this._cursor),[J,...Z]=this.userInput.slice(this._cursor);return`${z}${A.inverse(J)}${Z.join("")}`}get options(){if(typeof this.#J==="function")return this.#J();return this.#J}constructor(z){super(z);this.#J=z.options;let J=this.options;this.filteredOptions=[...J],this.multiple=z.multiple===!0,this.#$=z.filter??$z;let Z;if(z.initialValue&&Array.isArray(z.initialValue))if(this.multiple)Z=z.initialValue;else Z=z.initialValue.slice(0,1);else if(!this.multiple&&this.options.length>0)Z=[this.options[0].value];if(Z)for(let $ of Z){let Q=J.findIndex((q)=>q.value===$);if(Q!==-1)this.toggleSelected($),this.#z=Q}this.focusedValue=this.options[this.#z]?.value,this.on("key",($,Q)=>this.#Q($,Q)),this.on("userInput",($)=>this.#Y($))}_isActionKey(z,J){return z==="\t"||this.multiple&&this.isNavigating&&J.name==="space"&&z!==void 0&&z!==""}#Q(z,J){let Z=J.name==="up",$=J.name==="down",Q=J.name==="return";if(Z||$){if(this.#z=Math.max(0,Math.min(this.#z+(Z?-1:1),this.filteredOptions.length-1)),this.focusedValue=this.filteredOptions[this.#z]?.value,!this.multiple)this.selectedValues=[this.focusedValue];this.isNavigating=!0}else if(Q)this.value=Qz(this.multiple,this.selectedValues);else if(this.multiple)if(this.focusedValue!==void 0&&(J.name==="tab"||this.isNavigating&&J.name==="space"))this.toggleSelected(this.focusedValue);else this.isNavigating=!1;else{if(this.focusedValue)this.selectedValues=[this.focusedValue];this.isNavigating=!1}}deselectAll(){this.selectedValues=[]}toggleSelected(z){if(this.filteredOptions.length===0)return;if(this.multiple)if(this.selectedValues.includes(z))this.selectedValues=this.selectedValues.filter((J)=>J!==z);else this.selectedValues=[...this.selectedValues,z];else this.selectedValues=[z]}#Y(z){if(z!==this.#Z){this.#Z=z;let J=this.options;if(z)this.filteredOptions=J.filter((Z)=>this.#$(z,Z));else this.filteredOptions=[...J];if(this.#z=Zz(this.focusedValue,this.filteredOptions),this.focusedValue=this.filteredOptions[this.#z]?.value,!this.multiple)if(this.focusedValue!==void 0)this.toggleSelected(this.focusedValue);else this.deselectAll()}}}class qz extends d{options;cursor=0;#z;getGroupItems(z){return this.options.filter((J)=>J.group===z)}isGroupSelected(z){let J=this.getGroupItems(z),Z=this.value;if(Z===void 0)return!1;return J.every(($)=>Z.includes($.value))}toggleValue(){let z=this.options[this.cursor];if(this.value===void 0)this.value=[];if(z.group===!0){let J=String(z.value),Z=this.getGroupItems(J);if(this.isGroupSelected(J))this.value=this.value.filter(($)=>Z.findIndex((Q)=>Q.value===$)===-1);else this.value=[...this.value,...Z.map(($)=>$.value)];this.value=Array.from(new Set(this.value))}else{let J=this.value.includes(z.value);this.value=J?this.value.filter((Z)=>Z!==z.value):[...this.value,z.value]}}constructor(z){super(z,!1);let{options:J}=z;this.#z=z.selectableGroups!==!1,this.options=Object.entries(J).flatMap(([Z,$])=>[{value:Z,group:!0,label:Z},...$.map((Q)=>({...Q,group:Z}))]),this.value=[...z.initialValues??[]],this.cursor=Math.max(this.options.findIndex(({value:Z})=>Z===z.cursorAt),this.#z?0:1),this.on("cursor",(Z)=>{switch(Z){case"left":case"up":{this.cursor=this.cursor===0?this.options.length-1:this.cursor-1;let $=this.options[this.cursor]?.group===!0;if(!this.#z&&$)this.cursor=this.cursor===0?this.options.length-1:this.cursor-1;break}case"down":case"right":{this.cursor=this.cursor===this.options.length-1?0:this.cursor+1;let $=this.options[this.cursor]?.group===!0;if(!this.#z&&$)this.cursor=this.cursor===this.options.length-1?0:this.cursor+1;break}case"space":this.toggleValue();break}})}}var jz=W6();var V=(z,J)=>jz?z:J,kz=V("◆","*"),Sz=V("■","x"),yz=V("▲","x"),vz=V("◇","o"),gz=V("┌","T"),Xz=V("│","|"),_z=V("└","—"),fz=V("●",">"),mz=V("○"," "),dz=V("◻","[•]"),uz=V("◼","[+]"),cz=V("◻","[ ]"),pz=V("▪","•"),nz=V("─","-"),iz=V("╮","+"),lz=V("├","+"),rz=V("╯","+"),az=V("●","•"),sz=V("◆","*"),tz=V("▲","!"),oz=V("■","x");var ez={light:V("─","-"),heavy:V("━","="),block:V("█","#")};function Uz(){return`${A.gray(Xz)} `}var z4=Uz();var u="0.1.1";var N=new m("watch");N.command("detect","Detect connected watch devices").option("--verbose","Enable verbose output").action(async(z)=>{let J=E();if(z.verbose)console.log(`Searching for connected watch devices...
|
|
41
41
|
`);let Z=await J.detectDevices();if(Z.length===0){console.log("No watch devices found."),console.log(`
|
|
42
42
|
Make sure your watch is:`),console.log(" 1. Connected via USB, or"),console.log(" 2. Synced via Garmin Express (data will be read from cache)");return}console.log(`Found ${Z.length} device(s):
|
|
43
43
|
`);for(let $ of Z){if(console.log(` ${$.name}`),console.log(` Type: ${$.type}`),$.isGarminExpress)console.log(" Source: Garmin Express cache");else console.log(` Path: ${$.path}`);if($.model)console.log(` Model: ${$.model}`);if($.serial)console.log(` Serial: ${$.serial}`);if($.firmware)console.log(` Firmware: ${$.firmware}`);console.log()}});N.command("download","Download data from connected watch").option("-o, --output <dir>","Output directory",{default:"./watch-data"}).option("--since <date>","Only download data after this date (YYYY-MM-DD)").option("--until <date>","Only download data before this date (YYYY-MM-DD)").option("--activities","Download activity data only").option("--monitoring","Download monitoring data only").option("--no-raw","Do not copy raw FIT files").option("--verbose","Enable verbose output").action(async(z)=>{let J=E();console.log("Detecting devices...");let Z=await J.detectDevices();if(Z.length===0)console.error("No watch devices found."),console.error(`
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{A as g,E as R}from"./chunk-cahf1yhs.js";import{existsSync as b,readdirSync as w,statSync as M,mkdirSync as I,copyFileSync as E,readFileSync as x}from"fs";import{join as q,extname as v}from"path";import{homedir as m}from"os";var p="/Volumes",F=q(m(),"Library/Application Support/Garmin/Express/RegisteredDevices"),S=["GARMIN","ENDURO","FENIX","FORERUNNER","VENU","INSTINCT","VIVOACTIVE","EPIX","TACTIX","MARQ","QUATIX","DESCENT","APPROACH","LILY","VIVOSMART","VIVOMOVE"],j={ACTIVITY:"GARMIN/Activity",MONITOR:"GARMIN/Monitor",SPORTS:"GARMIN/Sports",SETTINGS:"GARMIN/Settings",TOTALS:"GARMIN/Totals",RECORDS:"GARMIN/Records",METRICS:"GARMIN/Metrics",SLEEP:"GARMIN/Sleep",WORKOUTS:"GARMIN/Workouts",COURSES:"GARMIN/Courses",LOCATIONS:"GARMIN/Locations",GOALS:"GARMIN/Goals",SCHEDULES:"GARMIN/Schedules"};class f{name="Garmin";type="garmin";async detectDevices(){let W=[];if(b(p)){let B=w(p);for(let O of B){let H=q(p,O);try{if(!M(H).isDirectory())continue}catch{continue}let T=O.toUpperCase(),k=S.some(($)=>T.includes($));if(!k){let $=q(H,"GARMIN");k=b($)}if(k){let $=await this.getDeviceInfo(H,O);if($)W.push($)}}}let V=await this.detectGarminExpressDevices();return W.push(...V),W}async detectGarminExpressDevices(){let W=[];if(!b(F))return W;let V=w(F);for(let B of V){let O=q(F,B);try{if(!M(O).isDirectory())continue}catch{continue}let H=q(O,"GarminDevice.xml");if(!b(H))continue;try{let T=x(H,"utf8"),k=T.match(/<Description>([^<]+)<\/Description>/i),$=T.match(/<Id>([^<]+)<\/Id>/i),N=T.match(/<DisplayName>([^<]+)<\/DisplayName>/i),C=T.match(/<PartNumber>([^<]+)<\/PartNumber>/i),G=T.match(/<SoftwareVersion>([^<]+)<\/SoftwareVersion>/i),X=N?.[1]||k?.[1]||B,Y=$?.[1]||B,J=G?.[1],z=q(O,"PendingSyncUploads/Garmin");if(!b(z))continue;W.push({name:X,path:O,type:"garmin",model:X,serial:B,unitId:Y,firmware:J,partNumber:C?.[1],isGarminExpress:!0,garminExpressPath:z})}catch{}}return W}async getDeviceInfo(W,V){let B=q(W,"GARMIN");if(!b(B))return null;let O=V,H,T,k=q(B,"GarminDevice.xml");if(b(k))try{let N=x(k,"utf8"),C=N.match(/<Model>([^<]+)<\/Model>/i),G=N.match(/<Id>([^<]+)<\/Id>/i);if(C)O=C[1];if(G)T=G[1]}catch{}let $=q(W,j.ACTIVITY);if(b($)){let N=w($).filter((C)=>C.toLowerCase().endsWith(".fit"));if(N.length>0)try{let C=q($,N[0]),G=x(C),Y=new g(G).parse(),z=new R(Y).getDeviceInfo();if(z?.serialNumber)H=z.serialNumber.toString();if(z?.productName)O=z.productName}catch{}}return{name:O,path:W,type:"garmin",model:O,serial:H,unitId:T}}async downloadData(W,V={}){let B=W,{outputDir:O="./garmin-data",includeActivities:H=!0,includeMonitoring:T=!0,since:k,until:$,copyRawFiles:N=!0}=V,C={device:W,activities:[],monitoring:new Map,rawFiles:[],errors:[]},G=new Date().toISOString().replace(/[:.]/g,"-").slice(0,19),X=q(O,G);if(N)I(X,{recursive:!0});if(B.isGarminExpress&&B.garminExpressPath)return this.downloadFromGarminExpress(B,V,C,X);if(H){let Y=q(W.path,j.ACTIVITY);if(b(Y)){let J=w(Y).filter((z)=>z.toLowerCase().endsWith(".fit"));for(let z of J){let Q=q(Y,z);try{let Z=M(Q).mtime;if(k&&Z<k)continue;if($&&Z>$)continue;let L=await this.parseActivityFile(Q);if(L)L.rawFilePath=Q,C.activities.push(L);if(N){let K=q(X,"Activity");I(K,{recursive:!0});let A=q(K,z);E(Q,A),C.rawFiles.push(A)}}catch(U){C.errors.push(U instanceof Error?U:Error(String(U)))}}}}if(T){let Y=q(W.path,j.MONITOR);if(b(Y)){let z=w(Y).filter((Q)=>Q.toLowerCase().endsWith(".fit"));for(let Q of z){let U=q(Y,Q);try{let L=M(U).mtime;if(k&&L<k)continue;if($&&L>$)continue;let K=await this.parseMonitoringFile(U);if(K){let A=L.toISOString().slice(0,10),_=C.monitoring.get(A)||{};C.monitoring.set(A,{..._,...K})}if(N){let A=q(X,"Monitor");I(A,{recursive:!0});let _=q(A,Q);E(U,_),C.rawFiles.push(_)}}catch(Z){C.errors.push(Z instanceof Error?Z:Error(String(Z)))}}}let J=q(W.path,"GARMIN/Sleep");if(b(J)){let z=w(J).filter((Q)=>Q.toLowerCase().endsWith(".fit"));for(let Q of z){let U=q(J,Q);try{let Z=await this.parseMonitoringFile(U);if(Z?.sleep){let L=Z.sleep.date.toISOString().slice(0,10),K=C.monitoring.get(L)||{};C.monitoring.set(L,{...K,sleep:Z.sleep})}if(N){let L=q(X,"Sleep");I(L,{recursive:!0});let K=q(L,Q);E(U,K),C.rawFiles.push(K)}}catch(Z){C.errors.push(Z instanceof Error?Z:Error(String(Z)))}}}}return C.activities.sort((Y,J)=>Y.startTime.getTime()-J.startTime.getTime()),C}async downloadFromGarminExpress(W,V,B,O){let{includeActivities:H=!0,includeMonitoring:T=!0,since:k,until:$,copyRawFiles:N=!0}=V,C=W.garminExpressPath,G={Activity:q(C,"Activity"),Monitor:q(C,"Monitor"),Sleep:q(C,"Sleep"),HRVStatus:q(C,"HRVStatus"),SkinTemp:q(C,"SkinTemp"),Metrics:q(C,"Metrics"),Coach:q(C,"Coach")},X=async(Y,J,z)=>{if(!b(Y))return;let Q=w(Y).filter((U)=>U.toLowerCase().endsWith(".fit"));for(let U of Q){let Z=q(Y,U);try{let K=M(Z).mtime;if(k&&K<k)continue;if($&&K>$)continue;let A=await this.parseMonitoringFile(Z);if(A)J(Z,A);if(N){let _=q(O,z);I(_,{recursive:!0});let D=q(_,U);E(Z,D),B.rawFiles.push(D)}}catch(L){B.errors.push(L instanceof Error?L:Error(String(L)))}}};if(H&&b(G.Activity)){let Y=w(G.Activity).filter((J)=>J.toLowerCase().endsWith(".fit"));for(let J of Y){let z=q(G.Activity,J);try{let U=M(z).mtime;if(k&&U<k)continue;if($&&U>$)continue;let Z=await this.parseActivityFile(z);if(Z)Z.rawFilePath=z,B.activities.push(Z);if(N){let L=q(O,"Activity");I(L,{recursive:!0});let K=q(L,J);E(z,K),B.rawFiles.push(K)}}catch(Q){B.errors.push(Q instanceof Error?Q:Error(String(Q)))}}}if(T)await X(G.Monitor,(Y,J)=>{let z=new Date().toISOString().slice(0,10),Q=B.monitoring.get(z)||{};B.monitoring.set(z,{...Q,...J})},"Monitor"),await X(G.HRVStatus,(Y,J)=>{if(J.hrv){let z=new Date().toISOString().slice(0,10),Q=B.monitoring.get(z)||{};B.monitoring.set(z,{...Q,hrv:J.hrv})}},"HRVStatus"),await X(G.SkinTemp,(Y,J)=>{let z=new Date().toISOString().slice(0,10),Q=B.monitoring.get(z)||{};B.monitoring.set(z,{...Q})},"SkinTemp"),await X(G.Sleep,(Y,J)=>{if(J.sleep){let z=J.sleep.date?.toISOString().slice(0,10)||new Date().toISOString().slice(0,10),Q=B.monitoring.get(z)||{};B.monitoring.set(z,{...Q,sleep:J.sleep})}},"Sleep");return B.activities.sort((Y,J)=>Y.startTime.getTime()-J.startTime.getTime()),B}async parseActivityFile(W){let V=v(W).toLowerCase();if(V!==".fit")throw Error(`Unsupported file format: ${V}`);let B=x(W),H=new g(B).parse();return new R(H).decodeActivity()}async parseMonitoringFile(W){let V=v(W).toLowerCase();if(V!==".fit")throw Error(`Unsupported file format: ${V}`);let B=x(W),H=new g(B).parse();return new R(H).decodeMonitoring()}}function d(){return new f}
|
|
2
|
+
export{f as k,d as l};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createRequire as c}from"node:module";var L=c(import.meta.url);var B=14,u=12,v=".FIT",j={ENUM:0,SINT8:1,UINT8:2,SINT16:131,UINT16:132,SINT32:133,UINT32:134,STRING:7,FLOAT32:136,FLOAT64:137,UINT8Z:10,UINT16Z:139,UINT32Z:140,BYTE:13,SINT64:142,UINT64:143,UINT64Z:144},I={[j.ENUM]:1,[j.SINT8]:1,[j.UINT8]:1,[j.SINT16]:2,[j.UINT16]:2,[j.SINT32]:4,[j.UINT32]:4,[j.STRING]:1,[j.FLOAT32]:4,[j.FLOAT64]:8,[j.UINT8Z]:1,[j.UINT16Z]:2,[j.UINT32Z]:4,[j.BYTE]:1,[j.SINT64]:8,[j.UINT64]:8,[j.UINT64Z]:8},y={FILE_ID:0,CAPABILITIES:1,DEVICE_SETTINGS:2,USER_PROFILE:3,HRM_PROFILE:4,SDM_PROFILE:5,BIKE_PROFILE:6,ZONES_TARGET:7,HR_ZONE:8,POWER_ZONE:9,MET_ZONE:10,SPORT:12,GOAL:15,SESSION:18,LAP:19,RECORD:20,EVENT:21,DEVICE_INFO:23,WORKOUT:26,WORKOUT_STEP:27,SCHEDULE:28,WEIGHT_SCALE:30,COURSE:31,COURSE_POINT:32,TOTALS:33,ACTIVITY:34,SOFTWARE:35,FILE_CAPABILITIES:37,MESG_CAPABILITIES:38,FIELD_CAPABILITIES:39,FILE_CREATOR:49,BLOOD_PRESSURE:51,SPEED_ZONE:53,MONITORING:55,TRAINING_FILE:72,HRV:78,ANT_RX:80,ANT_TX:81,ANT_CHANNEL_ID:82,LENGTH:101,MONITORING_INFO:103,PAD:105,SLAVE_DEVICE:106,CONNECTIVITY:127,WEATHER_CONDITIONS:128,WEATHER_ALERT:129,CADENCE_ZONE:131,HR:132,SEGMENT_LAP:142,MEMO_GLOB:145,SEGMENT_ID:148,SEGMENT_LEADERBOARD_ENTRY:149,SEGMENT_POINT:150,SEGMENT_FILE:151,WORKOUT_SESSION:158,WATCHFACE_SETTINGS:159,GPS_METADATA:160,CAMERA_EVENT:161,TIMESTAMP_CORRELATION:162,GYROSCOPE_DATA:164,ACCELEROMETER_DATA:165,THREE_D_SENSOR_CALIBRATION:167,VIDEO_FRAME:169,OBDII_DATA:174,NMEA_SENTENCE:177,AVIATION_ATTITUDE:178,VIDEO:184,VIDEO_TITLE:185,VIDEO_DESCRIPTION:186,VIDEO_CLIP:187,OHR_SETTINGS:188,EXD_SCREEN_CONFIGURATION:200,EXD_DATA_FIELD_CONFIGURATION:201,EXD_DATA_CONCEPT_CONFIGURATION:202,FIELD_DESCRIPTION:206,DEVELOPER_DATA_ID:207,MAGNETOMETER_DATA:208,BAROMETER_DATA:209,ONE_D_SENSOR_CALIBRATION:210,MONITORING_HR_DATA:211,TIME_IN_ZONE:216,SET:225,STRESS_LEVEL:227,MAX_MET_DATA:229,DIVE_SETTINGS:258,DIVE_GAS:259,DIVE_ALARM:262,EXERCISE_TITLE:264,DIVE_SUMMARY:268,SPO2_DATA:269,SLEEP_LEVEL:275,JUMP:285,BEAT_INTERVALS:290,RESPIRATION_RATE:297,SPLIT:312,CLIMB_PRO:317,TANK_UPDATE:319,TANK_SUMMARY:323,SLEEP_ASSESSMENT:346,HRV_STATUS_SUMMARY:370,HRV_VALUE:371,DEVICE_AUX_BATTERY_INFO:375,DIVE_APNEA_ALARM:393,SKIN_TEMP_OVERNIGHT:398},Q={FILE_ID:{TYPE:0,MANUFACTURER:1,PRODUCT:2,SERIAL_NUMBER:3,TIME_CREATED:4,NUMBER:5,PRODUCT_NAME:8},SESSION:{TIMESTAMP:253,START_TIME:2,START_POSITION_LAT:3,START_POSITION_LONG:4,TOTAL_ELAPSED_TIME:7,TOTAL_TIMER_TIME:8,TOTAL_DISTANCE:9,TOTAL_CYCLES:10,TOTAL_CALORIES:11,TOTAL_FAT_CALORIES:13,AVG_SPEED:14,MAX_SPEED:15,AVG_HEART_RATE:16,MAX_HEART_RATE:17,AVG_CADENCE:18,MAX_CADENCE:19,AVG_POWER:20,MAX_POWER:21,TOTAL_ASCENT:22,TOTAL_DESCENT:23,SPORT:5,SUB_SPORT:6,EVENT:0,EVENT_TYPE:1,FIRST_LAP_INDEX:25,NUM_LAPS:26,NORMALIZED_POWER:34,TRAINING_STRESS_SCORE:35,INTENSITY_FACTOR:36,AVG_TEMPERATURE:57,MAX_TEMPERATURE:58},LAP:{TIMESTAMP:253,EVENT:0,EVENT_TYPE:1,START_TIME:2,START_POSITION_LAT:3,START_POSITION_LONG:4,END_POSITION_LAT:5,END_POSITION_LONG:6,TOTAL_ELAPSED_TIME:7,TOTAL_TIMER_TIME:8,TOTAL_DISTANCE:9,TOTAL_CYCLES:10,TOTAL_CALORIES:11,TOTAL_FAT_CALORIES:12,AVG_SPEED:13,MAX_SPEED:14,AVG_HEART_RATE:15,MAX_HEART_RATE:16,AVG_CADENCE:17,MAX_CADENCE:18,AVG_POWER:19,MAX_POWER:20,TOTAL_ASCENT:21,TOTAL_DESCENT:22,SPORT:23,SUB_SPORT:24,AVG_TEMPERATURE:50,MAX_TEMPERATURE:51},RECORD:{TIMESTAMP:253,POSITION_LAT:0,POSITION_LONG:1,ALTITUDE:2,HEART_RATE:3,CADENCE:4,DISTANCE:5,SPEED:6,POWER:7,COMPRESSED_SPEED_DISTANCE:8,GRADE:9,RESISTANCE:10,TIME_FROM_COURSE:11,CYCLE_LENGTH:12,TEMPERATURE:13,SPEED_1S:17,CYCLES:18,TOTAL_CYCLES:19,COMPRESSED_ACCUMULATED_POWER:28,ACCUMULATED_POWER:29,LEFT_RIGHT_BALANCE:30,GPS_ACCURACY:31,VERTICAL_SPEED:32,CALORIES:33,VERTICAL_OSCILLATION:39,STANCE_TIME_PERCENT:40,STANCE_TIME:41,ACTIVITY_TYPE:42,LEFT_TORQUE_EFFECTIVENESS:43,RIGHT_TORQUE_EFFECTIVENESS:44,LEFT_PEDAL_SMOOTHNESS:45,RIGHT_PEDAL_SMOOTHNESS:46,COMBINED_PEDAL_SMOOTHNESS:47,TIME128:48,STROKE_TYPE:49,ZONE:50,BALL_SPEED:51,CADENCE256:52,FRACTIONAL_CADENCE:53,TOTAL_HEMOGLOBIN_CONC:54,TOTAL_HEMOGLOBIN_CONC_MIN:55,TOTAL_HEMOGLOBIN_CONC_MAX:56,SATURATED_HEMOGLOBIN_PERCENT:57,SATURATED_HEMOGLOBIN_PERCENT_MIN:58,SATURATED_HEMOGLOBIN_PERCENT_MAX:59,DEVICE_INDEX:62,LEFT_PCO:67,RIGHT_PCO:68,LEFT_POWER_PHASE:69,LEFT_POWER_PHASE_PEAK:70,RIGHT_POWER_PHASE:71,RIGHT_POWER_PHASE_PEAK:72,ENHANCED_SPEED:73,ENHANCED_ALTITUDE:78,BATTERY_SOC:81,MOTOR_POWER:82,VERTICAL_RATIO:83,STANCE_TIME_BALANCE:84,STEP_LENGTH:85,ABSOLUTE_PRESSURE:91,DEPTH:92,NEXT_STOP_DEPTH:93,NEXT_STOP_TIME:94,TIME_TO_SURFACE:95,NDL_TIME:96,CNS_LOAD:97,N2_LOAD:98,RESPIRATION_RATE:99,ENHANCED_RESPIRATION_RATE:108,GRIT:114,FLOW:115,CURRENT_STRESS:116,EBIKE_TRAVEL_RANGE:117,EBIKE_BATTERY_LEVEL:118,EBIKE_ASSIST_MODE:119,EBIKE_ASSIST_LEVEL_PERCENT:120,AIR_TIME_REMAINING:123,PRESSURE_SAC:124,VOLUME_SAC:125,RMV:126,ASCENT_RATE:127,PO2:129,CORE_TEMPERATURE:139},ACTIVITY:{TIMESTAMP:253,TOTAL_TIMER_TIME:0,NUM_SESSIONS:1,TYPE:2,EVENT:3,EVENT_TYPE:4,LOCAL_TIMESTAMP:5,EVENT_GROUP:6},MONITORING:{TIMESTAMP:253,DEVICE_INDEX:0,CALORIES:1,DISTANCE:2,CYCLES:3,ACTIVE_TIME:4,ACTIVITY_TYPE:5,ACTIVITY_SUBTYPE:6,ACTIVITY_LEVEL:7,DISTANCE_16:8,CYCLES_16:9,ACTIVE_TIME_16:10,LOCAL_TIMESTAMP:11,TEMPERATURE:12,TEMPERATURE_MIN:14,TEMPERATURE_MAX:15,ACTIVITY_TIME:16,ACTIVE_CALORIES:19,CURRENT_ACTIVITY_TYPE_INTENSITY:24,TIMESTAMP_MIN_8:25,TIMESTAMP_16:26,HEART_RATE:27,INTENSITY:28,DURATION_MIN:29,DURATION:30,ASCENT:31,DESCENT:32,MODERATE_ACTIVITY_MINUTES:33,VIGOROUS_ACTIVITY_MINUTES:34},HRV:{TIME:0},STRESS_LEVEL:{STRESS_LEVEL_VALUE:0,STRESS_LEVEL_TIME:1},SPO2_DATA:{TIMESTAMP:253,READING_SPO2:0,READING_CONFIDENCE:1,MODE:2},SLEEP_LEVEL:{TIMESTAMP:253,SLEEP_LEVEL:0},RESPIRATION_RATE:{TIMESTAMP:253,RESPIRATION_RATE:0},DEVICE_INFO:{TIMESTAMP:253,DEVICE_INDEX:0,DEVICE_TYPE:1,MANUFACTURER:2,SERIAL_NUMBER:3,PRODUCT:4,SOFTWARE_VERSION:5,HARDWARE_VERSION:6,CUM_OPERATING_TIME:7,BATTERY_VOLTAGE:10,BATTERY_STATUS:11,SENSOR_POSITION:18,DESCRIPTOR:19,ANT_TRANSMISSION_TYPE:20,ANT_DEVICE_NUMBER:21,ANT_NETWORK:22,SOURCE_TYPE:25,PRODUCT_NAME:27,BATTERY_LEVEL:32}},H={GENERIC:0,RUNNING:1,CYCLING:2,TRANSITION:3,FITNESS_EQUIPMENT:4,SWIMMING:5,BASKETBALL:6,SOCCER:7,TENNIS:8,AMERICAN_FOOTBALL:9,TRAINING:10,WALKING:11,CROSS_COUNTRY_SKIING:12,ALPINE_SKIING:13,SNOWBOARDING:14,ROWING:15,MOUNTAINEERING:16,HIKING:17,MULTISPORT:18,PADDLING:19,FLYING:20,E_BIKING:21,MOTORCYCLING:22,BOATING:23,DRIVING:24,GOLF:25,HANG_GLIDING:26,HORSEBACK_RIDING:27,HUNTING:28,FISHING:29,INLINE_SKATING:30,ROCK_CLIMBING:31,SAILING:32,ICE_SKATING:33,SKY_DIVING:34,SNOWSHOEING:35,SNOWMOBILING:36,STAND_UP_PADDLEBOARDING:37,SURFING:38,WAKEBOARDING:39,WATER_SKIING:40,KAYAKING:41,RAFTING:42,WINDSURFING:43,KITESURFING:44,TACTICAL:45,JUMPMASTER:46,BOXING:47,FLOOR_CLIMBING:48,DIVING:53,HIIT:62,RACKET:64,WHEELCHAIR_PUSH_WALK:65,WHEELCHAIR_PUSH_RUN:66,MEDITATION:67,DISC_GOLF:69,CRICKET:82,RUGBY:83,HOCKEY:84,LACROSSE:85,VOLLEYBALL:86,WATER_TUBING:87,WAKESURFING:88,MIXED_MARTIAL_ARTS:105,SNORKELING:109,YOGA:123,PILATES:124,INDOOR_RUNNING:125,INDOOR_CYCLING:126,BREATHWORK:134,ALL:254},N={GENERIC:0,TREADMILL:1,STREET:2,TRAIL:3,TRACK:4,SPIN:5,INDOOR_CYCLING:6,ROAD:7,MOUNTAIN:8,DOWNHILL:9,RECUMBENT:10,CYCLOCROSS:11,HAND_CYCLING:12,TRACK_CYCLING:13,INDOOR_ROWING:14,ELLIPTICAL:15,STAIR_CLIMBING:16,LAP_SWIMMING:17,OPEN_WATER:18,FLEXIBILITY_TRAINING:19,STRENGTH_TRAINING:20,WARM_UP:21,MATCH:22,EXERCISE:23,CHALLENGE:24,INDOOR_SKIING:25,CARDIO_TRAINING:26,INDOOR_WALKING:27,E_BIKE_FITNESS:28,BMX:29,CASUAL_WALKING:30,SPEED_WALKING:31,BIKE_TO_RUN_TRANSITION:32,RUN_TO_BIKE_TRANSITION:33,SWIM_TO_BIKE_TRANSITION:34,ATV:35,MOTOCROSS:36,BACKCOUNTRY:37,RESORT:38,RC_DRONE:39,WINGSUIT:40,WHITEWATER:41,SKATE_SKIING:42,YOGA:43,PILATES:44,INDOOR_RUNNING:45,GRAVEL_CYCLING:46,E_BIKE_MOUNTAIN:47,COMMUTING:48,MIXED_SURFACE:49,NAVIGATE:50,TRACK_ME:51,MAP:52,SINGLE_GAS_DIVING:53,MULTI_GAS_DIVING:54,GAUGE_DIVING:55,APNEA_DIVING:56,APNEA_HUNTING:57,VIRTUAL_ACTIVITY:58,OBSTACLE:59,BREATHING:62,SAIL_RACE:65,ULTRA:67,INDOOR_CLIMBING:68,BOULDERING:69,HIIT:70,AMRAP:73,EMOM:74,TABATA:75,PICKLEBALL:84,PADEL:85,INDOOR_WHEELCHAIR_WALK:86,INDOOR_WHEELCHAIR_RUN:87,INDOOR_HAND_CYCLING:88,FLY:110,ALL:254},O={UNMEASURABLE:0,AWAKE:1,LIGHT:2,DEEP:3,REM:4},M=Date.UTC(1989,11,31,0,0,0),d={GARMIN:1,GARMIN_FR405_ANTFS:2,ZEPHYR:3,DAYTON:4,IDT:5,SRM:6,QUARQ:7,IBIKE:8,SARIS:9,SPARK_HK:10,TANITA:11,ECHOWELL:12,DYNASTREAM_OEM:13,NAUTILUS:14,DYNASTREAM:15,TIMEX:16,METRIGEAR:17,XELIC:18,BEURER:19,CARDIOSPORT:20,A_AND_D:21,HMM:22,SUUNTO:23,THITA_ELEKTRONIK:24,GPULSE:25,CLEAN_MOBILE:26,PEDAL_BRAIN:27,PEAKSWARE:28,SAXONAR:29,LEMOND_FITNESS:30,DEXCOM:31,WAHOO_FITNESS:32,OCTANE_FITNESS:33,ARCHINOETICS:34,THE_HURT_BOX:35,CITIZEN_SYSTEMS:36,MAGELLAN:37,OSYNCE:38,HOLUX:39,CONCEPT2:40,SHIMANO:72,PIONEER:86,BRYTON:267,ZWIFT:260,WAHOO:32,TACX:89};class z extends Error{offset;constructor(K,J){super(J!==void 0?`${K} at offset ${J}`:K);this.offset=J;this.name="FitParseError"}}class P{buffer;offset=0;definitions=new Map;littleEndian=!0;constructor(K){if(K instanceof ArrayBuffer)this.buffer=Buffer.from(K);else if(K instanceof Uint8Array)this.buffer=Buffer.from(K);else this.buffer=K}parse(){let K=this.parseHeader(),J=[],Z=K.headerSize+K.dataSize;while(this.offset<Z)try{let C=this.parseRecord();if(C)J.push(C)}catch(C){if(C instanceof z)this.offset++;else throw C}return{header:K,messages:J}}parseHeader(){if(this.buffer.length<u)throw new z("File too small to contain FIT header");let K=this.buffer.readUInt8(0);if(K!==B&&K!==u)throw new z(`Invalid header size: ${K}`);let J=this.buffer.readUInt8(1),Z=this.buffer.readUInt16LE(2),C=this.buffer.readUInt32LE(4),X=this.buffer.toString("ascii",8,12);if(X!==v)throw new z(`Invalid FIT signature: ${X}`);let q;if(K===B)q=this.buffer.readUInt16LE(12);return this.offset=K,{headerSize:K,protocolVersion:J,profileVersion:Z,dataSize:C,dataType:X,crc:q}}parseRecord(){if(this.offset>=this.buffer.length)return null;let K=this.buffer.readUInt8(this.offset);if(this.offset++,(K&128)===128){let q=K>>5&3,V=K&31;return this.parseDataMessage(q,V)}let Z=(K&64)===64,C=(K&32)===32,X=K&15;if(Z)return this.parseDefinitionMessage(X,C),null;return this.parseDataMessage(X)}parseDefinitionMessage(K,J){let Z=this.buffer.readUInt8(this.offset);this.offset++;let C=this.buffer.readUInt8(this.offset);this.offset++,this.littleEndian=C===0;let X=this.readUInt16(),q=this.buffer.readUInt8(this.offset);this.offset++;let V=[];for(let W=0;W<q;W++){let k=this.buffer.readUInt8(this.offset);this.offset++;let $=this.buffer.readUInt8(this.offset);this.offset++;let b=this.buffer.readUInt8(this.offset);this.offset++,V.push({fieldDefNum:k,size:$,baseType:b})}if(J){let W=this.buffer.readUInt8(this.offset);this.offset++,this.offset+=W*3}this.definitions.set(K,{reserved:Z,arch:this.littleEndian?"little":"big",globalMsgNum:X,numFields:q,fields:V})}parseDataMessage(K,J){let Z=this.definitions.get(K);if(!Z)return null;let C={};for(let X of Z.fields){let q=this.readFieldValue(X);if(q!==null&&q!==void 0)C[X.fieldDefNum]=q}return{globalMsgNum:Z.globalMsgNum,fields:C}}readFieldValue(K){let{size:J,baseType:Z}=K;switch(Z&31){case j.ENUM:case j.UINT8:case j.UINT8Z:{if(J===1){let q=this.buffer.readUInt8(this.offset);return this.offset++,q===255?null:q}let X=[];for(let q=0;q<J;q++)X.push(this.buffer.readUInt8(this.offset)),this.offset++;return X}case j.SINT8:{if(J===1){let q=this.buffer.readInt8(this.offset);return this.offset++,q===127?null:q}let X=[];for(let q=0;q<J;q++)X.push(this.buffer.readInt8(this.offset)),this.offset++;return X}case j.UINT16:case j.UINT16Z:{if(J===2){let q=this.readUInt16();return q===65535?null:q}let X=[];for(let q=0;q<J/2;q++)X.push(this.readUInt16());return X}case j.SINT16:{if(J===2){let q=this.readInt16();return q===32767?null:q}let X=[];for(let q=0;q<J/2;q++)X.push(this.readInt16());return X}case j.UINT32:case j.UINT32Z:{if(J===4){let q=this.readUInt32();return q===4294967295?null:q}let X=[];for(let q=0;q<J/4;q++)X.push(this.readUInt32());return X}case j.SINT32:{if(J===4){let q=this.readInt32();return q===2147483647?null:q}let X=[];for(let q=0;q<J/4;q++)X.push(this.readInt32());return X}case j.FLOAT32:{if(J===4){let q=this.readFloat32();return Number.isNaN(q)?null:q}let X=[];for(let q=0;q<J/4;q++)X.push(this.readFloat32());return X}case j.FLOAT64:{if(J===8){let q=this.readFloat64();return Number.isNaN(q)?null:q}let X=[];for(let q=0;q<J/8;q++)X.push(this.readFloat64());return X}case j.STRING:{let X=this.buffer.slice(this.offset,this.offset+J);this.offset+=J;let q=X.indexOf(0),V=X.toString("utf8",0,q>=0?q:J);return V.length>0?V:null}case j.UINT64:case j.UINT64Z:{if(J===8)return this.readUInt64();return this.offset+=J,null}case j.SINT64:{if(J===8)return this.readInt64();return this.offset+=J,null}case j.BYTE:default:{let X=this.buffer.slice(this.offset,this.offset+J);return this.offset+=J,X}}}readUInt16(){let K=this.littleEndian?this.buffer.readUInt16LE(this.offset):this.buffer.readUInt16BE(this.offset);return this.offset+=2,K}readInt16(){let K=this.littleEndian?this.buffer.readInt16LE(this.offset):this.buffer.readInt16BE(this.offset);return this.offset+=2,K}readUInt32(){let K=this.littleEndian?this.buffer.readUInt32LE(this.offset):this.buffer.readUInt32BE(this.offset);return this.offset+=4,K}readInt32(){let K=this.littleEndian?this.buffer.readInt32LE(this.offset):this.buffer.readInt32BE(this.offset);return this.offset+=4,K}readFloat32(){let K=this.littleEndian?this.buffer.readFloatLE(this.offset):this.buffer.readFloatBE(this.offset);return this.offset+=4,K}readFloat64(){let K=this.littleEndian?this.buffer.readDoubleLE(this.offset):this.buffer.readDoubleBE(this.offset);return this.offset+=8,K}readUInt64(){let K=this.littleEndian?this.buffer.readBigUInt64LE(this.offset):this.buffer.readBigUInt64BE(this.offset);return this.offset+=8,K}readInt64(){let K=this.littleEndian?this.buffer.readBigInt64LE(this.offset):this.buffer.readBigInt64BE(this.offset);return this.offset+=8,K}}function U(K){return new Date(M+K*1000)}function Y(K){return K*(180/Math.pow(2,31))}function T(K){return K*(Math.pow(2,31)/180)}class n{messages;fileType="unknown";deviceInfo=null;constructor(K){this.messages=K.messages,this.extractFileInfo()}extractFileInfo(){let K=this.messages.find((Z)=>Z.globalMsgNum===y.FILE_ID);if(K){let Z=K.fields[Q.FILE_ID.TYPE];this.fileType=this.resolveFileType(Z)}let J=this.messages.find((Z)=>Z.globalMsgNum===y.DEVICE_INFO);if(J)this.deviceInfo={manufacturer:J.fields[Q.DEVICE_INFO.MANUFACTURER],product:J.fields[Q.DEVICE_INFO.PRODUCT],serialNumber:J.fields[Q.DEVICE_INFO.SERIAL_NUMBER],softwareVersion:J.fields[Q.DEVICE_INFO.SOFTWARE_VERSION],productName:J.fields[Q.DEVICE_INFO.PRODUCT_NAME]}}resolveFileType(K){return{1:"device",2:"settings",3:"sport",4:"activity",5:"workout",6:"course",7:"schedules",9:"weight",10:"totals",11:"goals",14:"blood_pressure",15:"monitoring_a",20:"activity_summary",28:"monitoring_daily",32:"monitoring_b",34:"segment",35:"segment_list",40:"exd_configuration"}[K]||"unknown"}getFileType(){return this.fileType}getDeviceInfo(){return this.deviceInfo}decodeActivity(){if(!["activity","activity_summary"].includes(this.fileType))return null;let K=this.messages.filter(($)=>$.globalMsgNum===y.SESSION),J=this.messages.filter(($)=>$.globalMsgNum===y.LAP),Z=this.messages.filter(($)=>$.globalMsgNum===y.RECORD),C=this.messages.find(($)=>$.globalMsgNum===y.ACTIVITY);if(K.length===0)return null;let q=K[0].fields,V=q[Q.SESSION.START_TIME],W=q[Q.SESSION.TIMESTAMP],k={id:this.generateActivityId(V),sport:this.mapSport(q[Q.SESSION.SPORT]),subSport:this.mapSubSport(q[Q.SESSION.SUB_SPORT]),startTime:U(V),endTime:U(W),totalElapsedTime:q[Q.SESSION.TOTAL_ELAPSED_TIME]/1000,totalTimerTime:q[Q.SESSION.TOTAL_TIMER_TIME]/1000,totalDistance:q[Q.SESSION.TOTAL_DISTANCE]/100,totalCalories:q[Q.SESSION.TOTAL_CALORIES],avgHeartRate:q[Q.SESSION.AVG_HEART_RATE],maxHeartRate:q[Q.SESSION.MAX_HEART_RATE],avgSpeed:q[Q.SESSION.AVG_SPEED]!=null?q[Q.SESSION.AVG_SPEED]/1000:void 0,maxSpeed:q[Q.SESSION.MAX_SPEED]!=null?q[Q.SESSION.MAX_SPEED]/1000:void 0,avgCadence:q[Q.SESSION.AVG_CADENCE],maxCadence:q[Q.SESSION.MAX_CADENCE],avgPower:q[Q.SESSION.AVG_POWER],maxPower:q[Q.SESSION.MAX_POWER],normalizedPower:q[Q.SESSION.NORMALIZED_POWER],totalAscent:q[Q.SESSION.TOTAL_ASCENT],totalDescent:q[Q.SESSION.TOTAL_DESCENT],trainingStressScore:q[Q.SESSION.TRAINING_STRESS_SCORE]!=null?q[Q.SESSION.TRAINING_STRESS_SCORE]/10:void 0,intensityFactor:q[Q.SESSION.INTENSITY_FACTOR]!=null?q[Q.SESSION.INTENSITY_FACTOR]/1000:void 0,laps:J.map(($)=>this.decodeLap($)),records:Z.map(($)=>this.decodeRecord($)),source:"garmin"};return this.cleanUndefined(k)}decodeLap(K){let J=K.fields,Z=J[Q.LAP.START_TIME],C=J[Q.LAP.TIMESTAMP],X=J[Q.LAP.START_POSITION_LAT],q=J[Q.LAP.START_POSITION_LONG],V=J[Q.LAP.END_POSITION_LAT],W=J[Q.LAP.END_POSITION_LONG],k={startTime:U(Z),endTime:U(C),totalElapsedTime:J[Q.LAP.TOTAL_ELAPSED_TIME]/1000,totalTimerTime:J[Q.LAP.TOTAL_TIMER_TIME]/1000,totalDistance:J[Q.LAP.TOTAL_DISTANCE]/100,totalCalories:J[Q.LAP.TOTAL_CALORIES],avgHeartRate:J[Q.LAP.AVG_HEART_RATE],maxHeartRate:J[Q.LAP.MAX_HEART_RATE],avgSpeed:J[Q.LAP.AVG_SPEED]!=null?J[Q.LAP.AVG_SPEED]/1000:void 0,maxSpeed:J[Q.LAP.MAX_SPEED]!=null?J[Q.LAP.MAX_SPEED]/1000:void 0,avgCadence:J[Q.LAP.AVG_CADENCE],maxCadence:J[Q.LAP.MAX_CADENCE],avgPower:J[Q.LAP.AVG_POWER],maxPower:J[Q.LAP.MAX_POWER],totalAscent:J[Q.LAP.TOTAL_ASCENT],totalDescent:J[Q.LAP.TOTAL_DESCENT],startPosition:X!=null&&q!=null?{lat:Y(X),lng:Y(q)}:void 0,endPosition:V!=null&&W!=null?{lat:Y(V),lng:Y(W)}:void 0};return this.cleanUndefined(k)}decodeRecord(K){let J=K.fields,Z=J[Q.RECORD.TIMESTAMP],C=J[Q.RECORD.POSITION_LAT],X=J[Q.RECORD.POSITION_LONG],q=J[Q.RECORD.ENHANCED_ALTITUDE];if(q==null){if(q=J[Q.RECORD.ALTITUDE],q!=null)q=q/5-500}else q=q/5-500;let V=J[Q.RECORD.ENHANCED_SPEED];if(V==null){if(V=J[Q.RECORD.SPEED],V!=null)V=V/1000}else V=V/1000;let W={timestamp:U(Z),position:C!=null&&X!=null?{lat:Y(C),lng:Y(X),altitude:q}:void 0,heartRate:J[Q.RECORD.HEART_RATE],cadence:J[Q.RECORD.CADENCE],speed:V,power:J[Q.RECORD.POWER],altitude:q,distance:J[Q.RECORD.DISTANCE]!=null?J[Q.RECORD.DISTANCE]/100:void 0,temperature:J[Q.RECORD.TEMPERATURE],grade:J[Q.RECORD.GRADE]!=null?J[Q.RECORD.GRADE]/100:void 0,calories:J[Q.RECORD.CALORIES]};return this.cleanUndefined(W)}decodeMonitoring(){let K={},J=this.messages.filter((W)=>W.globalMsgNum===y.MONITORING);if(J.length>0){let W=[],k=1/0,$=0,b=0,x=0;for(let w of J){let G=w.fields[Q.MONITORING.HEART_RATE],h=w.fields[Q.MONITORING.TIMESTAMP];if(G!=null&&h!=null)W.push({timestamp:U(h),heartRate:G}),k=Math.min(k,G),$=Math.max($,G),b+=G,x++}if(W.length>0)K.heartRate={date:W[0].timestamp,minHeartRate:k,maxHeartRate:$,avgHeartRate:Math.round(b/x),samples:W}}let Z=this.messages.filter((W)=>W.globalMsgNum===y.SLEEP_LEVEL);if(Z.length>0){let W=[],k=null;for(let $ of Z){let b=$.fields[Q.SLEEP_LEVEL.SLEEP_LEVEL],x=$.fields[Q.SLEEP_LEVEL.TIMESTAMP];if(b!=null&&x!=null){let w=this.mapSleepLevel(b),G=U(x);if(k&&k.stage!==w)k.endTime=G,W.push(k),k={stage:w,startTime:G,endTime:G};else if(!k)k={stage:w,startTime:G,endTime:G}}}if(k)W.push(k);if(W.length>0){let $=W[0].startTime,b=W[W.length-1].endTime,x=0,w=0,G=0,h=0;for(let R of W){let A=(R.endTime.getTime()-R.startTime.getTime())/60000;switch(R.stage){case"deep":x+=A;break;case"light":w+=A;break;case"rem":G+=A;break;case"awake":h+=A;break}}K.sleep={date:$,startTime:$,endTime:b,totalSleepTime:x+w+G,deepSleepTime:x,lightSleepTime:w,remSleepTime:G,awakeTime:h,stages:W}}}let C=this.messages.filter((W)=>W.globalMsgNum===y.STRESS_LEVEL);if(C.length>0){let W=[],k=0,$=0;for(let b of C){let x=b.fields[Q.STRESS_LEVEL.STRESS_LEVEL_VALUE],w=b.fields[Q.STRESS_LEVEL.STRESS_LEVEL_TIME];if(x!=null&&x>=0&&x<=100&&w!=null)W.push({timestamp:U(w),stressLevel:x}),k+=x,$=Math.max($,x)}if(W.length>0)K.stress={date:W[0].timestamp,avgStressLevel:Math.round(k/W.length),maxStressLevel:$,restStressDuration:0,lowStressDuration:0,mediumStressDuration:0,highStressDuration:0,samples:W}}let X=this.messages.filter((W)=>W.globalMsgNum===y.SPO2_DATA);if(X.length>0){let W=[],k=100,$=0,b=0;for(let x of X){let w=x.fields[Q.SPO2_DATA.READING_SPO2],G=x.fields[Q.SPO2_DATA.TIMESTAMP];if(w!=null&&G!=null&&w>0&&w<=100)W.push({timestamp:U(G),spO2:w}),k=Math.min(k,w),$=Math.max($,w),b+=w}if(W.length>0)K.spO2={date:W[0].timestamp,avgSpO2:Math.round(b/W.length),minSpO2:k,maxSpO2:$,samples:W}}let q=this.messages.filter((W)=>W.globalMsgNum===y.RESPIRATION_RATE);if(q.length>0){let W=[],k=1/0,$=0,b=0;for(let x of q){let w=x.fields[Q.RESPIRATION_RATE.RESPIRATION_RATE],G=x.fields[Q.RESPIRATION_RATE.TIMESTAMP];if(w!=null&&G!=null&&w>0){let h=w/100;W.push({timestamp:U(G),respirationRate:h}),k=Math.min(k,h),$=Math.max($,h),b+=h}}if(W.length>0)K.respiration={date:W[0].timestamp,avgRespirationRate:b/W.length,minRespirationRate:k,maxRespirationRate:$,samples:W}}let V=this.messages.filter((W)=>W.globalMsgNum===y.HRV);if(V.length>0){let W=[];for(let k of V){let $=k.fields[Q.HRV.TIME];if(Array.isArray($)){for(let b of $)if(b!=null&&b!==65535)W.push({timestamp:new Date,hrv:b/1024*1000})}else if($!=null&&$!==65535)W.push({timestamp:new Date,hrv:$/1024*1000})}if(W.length>0)K.hrv={date:new Date,samples:W}}return K}mapSport(K){return{[H.RUNNING]:"running",[H.CYCLING]:"cycling",[H.SWIMMING]:"swimming",[H.HIKING]:"hiking",[H.WALKING]:"walking",[H.TRAINING]:"strength_training",[H.FITNESS_EQUIPMENT]:"cardio",[H.YOGA]:"yoga",[H.GENERIC]:"generic"}[K]||"other"}mapSubSport(K){return{[N.GENERIC]:"generic",[N.TREADMILL]:"treadmill",[N.STREET]:"street",[N.TRAIL]:"trail",[N.TRACK]:"track",[N.SPIN]:"spin",[N.INDOOR_CYCLING]:"indoor_cycling",[N.ROAD]:"road",[N.MOUNTAIN]:"mountain",[N.GRAVEL_CYCLING]:"gravel",[N.LAP_SWIMMING]:"lap_swimming",[N.OPEN_WATER]:"open_water"}[K]}mapSleepLevel(K){return{[O.AWAKE]:"awake",[O.LIGHT]:"light",[O.DEEP]:"deep",[O.REM]:"rem"}[K]||"light"}generateActivityId(K){return`garmin_${K}`}cleanUndefined(K){let J={};for(let[Z,C]of Object.entries(K))if(C!==void 0&&C!==null)J[Z]=C;return J}}export{L as m,B as n,u as o,v as p,j as q,I as r,y as s,Q as t,H as u,N as v,O as w,M as x,d as y,z,P as A,U as B,Y as C,T as D,n as E};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{A as F,E as w}from"./chunk-cahf1yhs.js";import{existsSync as Rq,readdirSync as s,statSync as r,readFileSync as S,mkdirSync as jq,copyFileSync as i}from"fs";import{join as f,extname as Cq}from"path";var v="/Volumes",Mq=["POLAR","VANTAGE","GRIT","IGNITE","PACER","UNITE"];function a(z){let q=z.split(`
|
|
2
|
+
`).map((L)=>L.trim()),Q=new Map,Z="";for(let L of q)if(L.startsWith("[")&&L.endsWith("]"))Z=L.slice(1,-1),Q.set(Z,[]);else if(Z&&L)Q.get(Z)?.push(L);let G=Q.get("Params")||[],J=Q.get("HRData")||[];if(G.length===0)return null;let Y=new Map;for(let L of G){let[U,R]=L.split("=");if(U&&R)Y.set(U.trim(),R.trim())}let $=Y.get("Date"),b=Y.get("StartTime"),B=parseInt(Y.get("Interval")||"1",10),X=Y.get("Length");if(!$||!b)return null;let I=parseInt($.slice(0,4),10),N=parseInt($.slice(4,6),10)-1,K=parseInt($.slice(6,8),10),[H,E,M]=b.split(":"),O=parseFloat(M||"0"),j=new Date(I,N,K,parseInt(H,10),parseInt(E,10),Math.floor(O)),C=0;if(X){let[L,U,R]=X.split(":").map(Number);C=L*3600+U*60+R}let A=[],x=new Date(j);for(let L of J){let U=L.split("\t").map((g)=>parseInt(g,10)),R=U[0];if(R>0)A.push({timestamp:new Date(x),heartRate:R,speed:U[1]?U[1]/10:void 0,cadence:U[2],altitude:U[3],power:U[4]});x=new Date(x.getTime()+B*1000)}let D=A.filter((L)=>L.heartRate).map((L)=>L.heartRate),W=D.length>0?Math.round(D.reduce((L,U)=>L+U,0)/D.length):void 0,_=D.length>0?Math.max(...D):void 0;return{id:`polar_${j.getTime()}`,sport:"other",startTime:j,endTime:new Date(j.getTime()+C*1000),totalElapsedTime:C,totalTimerTime:C,totalDistance:0,totalCalories:parseInt(Y.get("Calories")||"0",10),avgHeartRate:W,maxHeartRate:_,laps:[],records:A,source:"garmin"}}function e(z){try{let q=JSON.parse(z);if(!q.startTime)return null;let Q=new Date(q.startTime),Z=q.stopTime?new Date(q.stopTime):new Date(Q.getTime()+(q.duration||0)),G=[];if(q.samples)for(let Y of q.samples)G.push({timestamp:new Date(Y.dateTime||Q),heartRate:Y.heartRate,speed:Y.speed,cadence:Y.cadence,altitude:Y.altitude,distance:Y.distance,power:Y.power,position:Y.latitude&&Y.longitude?{lat:Y.latitude,lng:Y.longitude,altitude:Y.altitude}:void 0});let J=[];if(q.laps)for(let Y of q.laps)J.push({startTime:new Date(Y.startTime||Q),endTime:new Date(Y.stopTime||Z),totalElapsedTime:Y.duration||0,totalTimerTime:Y.duration||0,totalDistance:Y.distance||0,totalCalories:Y.calories||0,avgHeartRate:Y.heartRate?.average,maxHeartRate:Y.heartRate?.maximum,avgSpeed:Y.speed?.average,maxSpeed:Y.speed?.maximum,avgCadence:Y.cadence?.average,maxCadence:Y.cadence?.maximum});return{id:`polar_${q.id||Q.getTime()}`,name:q.name,sport:Aq(q.sport),startTime:Q,endTime:Z,totalElapsedTime:q.duration||(Z.getTime()-Q.getTime())/1000,totalTimerTime:q.duration||(Z.getTime()-Q.getTime())/1000,totalDistance:q.distance||0,totalCalories:q.calories||0,avgHeartRate:q.heartRate?.average,maxHeartRate:q.heartRate?.maximum,avgSpeed:q.speed?.average,maxSpeed:q.speed?.maximum,avgCadence:q.cadence?.average,maxCadence:q.cadence?.maximum,avgPower:q.power?.average,maxPower:q.power?.maximum,totalAscent:q.ascent,totalDescent:q.descent,laps:J,records:G,source:"garmin"}}catch{return null}}function Aq(z){if(!z)return"other";return{RUNNING:"running",CYCLING:"cycling",SWIMMING:"swimming",WALKING:"walking",HIKING:"hiking",STRENGTH_TRAINING:"strength_training",OTHER:"other"}[z.toUpperCase()]||"other"}class t{name="Polar";type="polar";async detectDevices(){let z=[];if(!Rq(v))return z;let q=s(v);for(let Q of q){let Z=f(v,Q);try{if(!r(Z).isDirectory())continue}catch{continue}let G=Q.toUpperCase();if(Mq.some((Y)=>G.includes(Y)))z.push({name:Q,path:Z,type:"polar",model:Q})}return z}async downloadData(z,q={}){let{outputDir:Q="./polar-data",copyRawFiles:Z=!0}=q,G={device:z,activities:[],monitoring:new Map,rawFiles:[],errors:[]},J=new Date().toISOString().replace(/[:.]/g,"-").slice(0,19),Y=f(Q,J);if(Z)jq(Y,{recursive:!0});let $=this.findFiles(z.path,".hrm");for(let B of $)try{let X=S(B,"utf-8"),I=a(X);if(I)I.rawFilePath=B,G.activities.push(I);if(Z){let N=f(Y,B.split("/").pop());i(B,N),G.rawFiles.push(N)}}catch(X){G.errors.push(X instanceof Error?X:Error(String(X)))}let b=this.findFiles(z.path,".json");for(let B of b)try{let X=S(B,"utf-8"),I=e(X);if(I)I.rawFilePath=B,G.activities.push(I);if(Z){let N=f(Y,B.split("/").pop());i(B,N),G.rawFiles.push(N)}}catch(X){G.errors.push(X instanceof Error?X:Error(String(X)))}return G.activities.sort((B,X)=>B.startTime.getTime()-X.startTime.getTime()),G}async parseActivityFile(z){let q=Cq(z).toLowerCase();if(q===".hrm"){let Q=S(z,"utf-8");return a(Q)}if(q===".json"){let Q=S(z,"utf-8");return e(Q)}throw Error(`Unsupported file format: ${q}`)}async parseMonitoringFile(z){return{}}findFiles(z,q){let Q=[];try{let Z=s(z);for(let G of Z){let J=f(z,G);try{if(r(J).isDirectory())Q.push(...this.findFiles(J,q));else if(G.toLowerCase().endsWith(q))Q.push(J)}catch{}}}catch{}return Q}}function hq(){return new t}import{existsSync as Vq,readdirSync as qq,statSync as zq,readFileSync as P,mkdirSync as kq,copyFileSync as Qq}from"fs";import{join as T,extname as Dq}from"path";var h="/Volumes",Fq=["SUUNTO","AMBIT","SPARTAN","SUUNTO 9","SUUNTO 7","SUUNTO 5","VERTICAL","RACE"];function Yq(z){let q=(W,_)=>{let L=new RegExp(`<${_}[^>]*>([\\s\\S]*?)</${_}>`,"i"),U=W.match(L);return U?U[1].trim():null},Q=(W,_)=>{let L=new RegExp(`<${_}[^>]*>([\\s\\S]*?)</${_}>`,"gi"),U=[],R;while((R=L.exec(W))!==null)U.push(R[1].trim());return U},Z=q(z,"Header");if(!Z)return null;let G=q(Z,"DateTime"),J=parseFloat(q(Z,"Duration")||"0"),Y=parseFloat(q(Z,"Distance")||"0"),$=parseInt(q(Z,"Energy")||"0",10)/4184,b=parseFloat(q(Z,"Ascent")||"0"),B=parseFloat(q(Z,"Descent")||"0"),X=q(Z,"ActivityType");if(!G)return null;let I=new Date(G),N=new Date(I.getTime()+J*1000),K=[],H=Q(z,"Sample");for(let W of H){let _=q(W,"UTC"),L=parseInt(q(W,"HR")||"0",10),U=parseFloat(q(W,"Speed")||"0"),R=parseInt(q(W,"Cadence")||"0",10),g=parseFloat(q(W,"Altitude")||"0"),l=parseFloat(q(W,"Latitude")||"0"),n=parseFloat(q(W,"Longitude")||"0"),o=parseInt(q(W,"BikePower")||"0",10);if(_)K.push({timestamp:new Date(_),heartRate:L>0?L*60:void 0,speed:U>0?U:void 0,cadence:R>0?R*60:void 0,altitude:g!==0?g:void 0,power:o>0?o:void 0,position:l!==0&&n!==0?{lat:l*(180/Math.PI),lng:n*(180/Math.PI),altitude:g}:void 0})}let E=[],M=Q(z,"Mark");for(let W of M){let _=q(W,"Time");if(q(W,"Type")==="lap"&&_){let U=parseFloat(_);E.push({startTime:new Date(I.getTime()+U*1000),endTime:new Date(I.getTime()+U*1000),totalElapsedTime:0,totalTimerTime:0,totalDistance:0,totalCalories:0})}}let O=K.filter((W)=>W.heartRate).map((W)=>W.heartRate),j=O.length>0?Math.round(O.reduce((W,_)=>W+_,0)/O.length):void 0,C=O.length>0?Math.max(...O):void 0,A=K.filter((W)=>W.speed).map((W)=>W.speed),x=A.length>0?A.reduce((W,_)=>W+_,0)/A.length:void 0,D=A.length>0?Math.max(...A):void 0;return{id:`suunto_${I.getTime()}`,sport:$q(X??void 0),startTime:I,endTime:N,totalElapsedTime:J,totalTimerTime:J,totalDistance:Y,totalCalories:Math.round($),avgHeartRate:j,maxHeartRate:C,avgSpeed:x,maxSpeed:D,totalAscent:b,totalDescent:B,laps:E,records:K,source:"garmin"}}function Zq(z){try{let q=JSON.parse(z),Q=new Date(q.StartTime||q.startTime),Z=q.Duration||q.duration||0,G=new Date(Q.getTime()+Z*1000),J=[],Y=q.TrackPoints||q.trackPoints||q.Samples||q.samples||[];for(let $ of Y)J.push({timestamp:new Date($.Time||$.time||$.Timestamp),heartRate:$.HR||$.hr||$.HeartRate,speed:$.Speed||$.speed,cadence:$.Cadence||$.cadence,altitude:$.Altitude||$.altitude,distance:$.Distance||$.distance,power:$.Power||$.power,position:($.Latitude||$.latitude)&&($.Longitude||$.longitude)?{lat:$.Latitude||$.latitude,lng:$.Longitude||$.longitude,altitude:$.Altitude||$.altitude}:void 0});return{id:`suunto_${q.MoveId||q.moveId||Q.getTime()}`,name:q.Name||q.name,sport:$q(q.ActivityType||q.activityType||q.Sport||q.sport),startTime:Q,endTime:G,totalElapsedTime:Z,totalTimerTime:Z,totalDistance:q.Distance||q.distance||0,totalCalories:Math.round((q.Energy||q.energy||0)/4.184),avgHeartRate:q.AvgHR||q.avgHR||q.HeartRateAvg,maxHeartRate:q.MaxHR||q.maxHR||q.HeartRateMax,avgSpeed:q.AvgSpeed||q.avgSpeed,maxSpeed:q.MaxSpeed||q.maxSpeed,totalAscent:q.Ascent||q.ascent||q.AscentAltitude,totalDescent:q.Descent||q.descent||q.DescentAltitude,laps:[],records:J,source:"garmin"}}catch{return null}}function $q(z){if(!z)return"other";let q=typeof z==="number"?z.toString():z.toLowerCase();return{running:"running",run:"running","1":"running",cycling:"cycling",bike:"cycling","2":"cycling",swimming:"swimming",swim:"swimming","5":"swimming",hiking:"hiking",trekking:"hiking","11":"hiking",walking:"walking","3":"walking"}[q]||"other"}class Gq{name="Suunto";type="suunto";async detectDevices(){let z=[];if(!Vq(h))return z;let q=qq(h);for(let Q of q){let Z=T(h,Q);try{if(!zq(Z).isDirectory())continue}catch{continue}let G=Q.toUpperCase();if(Fq.some((Y)=>G.includes(Y)))z.push({name:Q,path:Z,type:"suunto",model:Q})}return z}async downloadData(z,q={}){let{outputDir:Q="./suunto-data",copyRawFiles:Z=!0}=q,G={device:z,activities:[],monitoring:new Map,rawFiles:[],errors:[]},J=new Date().toISOString().replace(/[:.]/g,"-").slice(0,19),Y=T(Q,J);if(Z)kq(Y,{recursive:!0});let $=this.findFiles(z.path,".sml");for(let B of $)try{let X=P(B,"utf-8"),I=Yq(X);if(I)I.rawFilePath=B,G.activities.push(I);if(Z){let N=T(Y,B.split("/").pop());Qq(B,N),G.rawFiles.push(N)}}catch(X){G.errors.push(X instanceof Error?X:Error(String(X)))}let b=this.findFiles(z.path,".json");for(let B of b)try{let X=P(B,"utf-8"),I=Zq(X);if(I)I.rawFilePath=B,G.activities.push(I);if(Z){let N=T(Y,B.split("/").pop());Qq(B,N),G.rawFiles.push(N)}}catch(X){G.errors.push(X instanceof Error?X:Error(String(X)))}return G.activities.sort((B,X)=>B.startTime.getTime()-X.startTime.getTime()),G}async parseActivityFile(z){let q=Dq(z).toLowerCase();if(q===".sml"){let Q=P(z,"utf-8");return Yq(Q)}if(q===".json"){let Q=P(z,"utf-8");return Zq(Q)}throw Error(`Unsupported file format: ${q}`)}async parseMonitoringFile(z){return{}}findFiles(z,q){let Q=[];try{let Z=qq(z);for(let G of Z){let J=T(z,G);try{if(zq(J).isDirectory())Q.push(...this.findFiles(J,q));else if(G.toLowerCase().endsWith(q))Q.push(J)}catch{}}}catch{}return Q}}function cq(){return new Gq}import{existsSync as u,readdirSync as Iq,statSync as Jq,mkdirSync as Xq,copyFileSync as wq,readFileSync as Bq}from"fs";import{join as V,extname as Nq}from"path";var m="/Volumes",xq=["COROS","PACE","APEX","VERTIX","DURA"];class Wq{name="Coros";type="coros";async detectDevices(){let z=[];if(!u(m))return z;let q=Iq(m);for(let Q of q){let Z=V(m,Q);try{if(!Jq(Z).isDirectory())continue}catch{continue}let G=Q.toUpperCase(),J=xq.some((Y)=>G.includes(Y));if(!J){let Y=V(Z,"COROS");if(u(Y)){z.push({name:Q,path:Z,type:"coros",model:Q});continue}}if(J)z.push({name:Q,path:Z,type:"coros",model:Q})}return z}async downloadData(z,q={}){let{outputDir:Q="./coros-data",includeActivities:Z=!0,since:G,until:J,copyRawFiles:Y=!0}=q,$={device:z,activities:[],monitoring:new Map,rawFiles:[],errors:[]},b=new Date().toISOString().replace(/[:.]/g,"-").slice(0,19),B=V(Q,b);if(Y)Xq(B,{recursive:!0});let X=[V(z.path,"Activity"),V(z.path,"COROS","Activity"),V(z.path,"GARMIN","Activity")];if(Z)for(let I of X){if(!u(I))continue;let N=Iq(I).filter((K)=>K.toLowerCase().endsWith(".fit"));for(let K of N){let H=V(I,K);try{let M=Jq(H).mtime;if(G&&M<G)continue;if(J&&M>J)continue;let O=await this.parseActivityFile(H);if(O)O.rawFilePath=H,$.activities.push(O);if(Y){let j=V(B,"Activity");Xq(j,{recursive:!0});let C=V(j,K);wq(H,C),$.rawFiles.push(C)}}catch(E){$.errors.push(E instanceof Error?E:Error(String(E)))}}}return $.activities.sort((I,N)=>I.startTime.getTime()-N.startTime.getTime()),$}async parseActivityFile(z){let q=Nq(z).toLowerCase();if(q!==".fit")throw Error(`Unsupported file format: ${q}`);let Q=Bq(z),G=new F(Q).parse();return new w(G).decodeActivity()}async parseMonitoringFile(z){let q=Nq(z).toLowerCase();if(q!==".fit")throw Error(`Unsupported file format: ${q}`);let Q=Bq(z),G=new F(Q).parse();return new w(G).decodeMonitoring()}}function sq(){return new Wq}import{existsSync as p,readdirSync as c,statSync as Kq,mkdirSync as Lq,copyFileSync as gq,readFileSync as Uq}from"fs";import{join as k,extname as Hq}from"path";var d="/Volumes",fq=["WAHOO","ELEMNT","BOLT","ROAM","RIVAL"];class bq{name="Wahoo";type="wahoo";async detectDevices(){let z=[];if(!p(d))return z;let q=c(d);for(let Q of q){let Z=k(d,Q);try{if(!Kq(Z).isDirectory())continue}catch{continue}let G=Q.toUpperCase(),J=fq.some((Y)=>G.includes(Y));if(!J){let Y=k(Z,"activities");if(p(Y)){if(c(Y).some((b)=>b.toLowerCase().endsWith(".fit"))){z.push({name:Q,path:Z,type:"wahoo",model:Q});continue}}}if(J)z.push({name:Q,path:Z,type:"wahoo",model:Q})}return z}async downloadData(z,q={}){let{outputDir:Q="./wahoo-data",includeActivities:Z=!0,since:G,until:J,copyRawFiles:Y=!0}=q,$={device:z,activities:[],monitoring:new Map,rawFiles:[],errors:[]},b=new Date().toISOString().replace(/[:.]/g,"-").slice(0,19),B=k(Q,b);if(Y)Lq(B,{recursive:!0});let X=[k(z.path,"activities"),k(z.path,"Activity"),k(z.path,"workouts")];if(Z)for(let I of X){if(!p(I))continue;let N=c(I).filter((K)=>K.toLowerCase().endsWith(".fit"));for(let K of N){let H=k(I,K);try{let M=Kq(H).mtime;if(G&&M<G)continue;if(J&&M>J)continue;let O=await this.parseActivityFile(H);if(O)O.rawFilePath=H,$.activities.push(O);if(Y){let j=k(B,"activities");Lq(j,{recursive:!0});let C=k(j,K);gq(H,C),$.rawFiles.push(C)}}catch(E){$.errors.push(E instanceof Error?E:Error(String(E)))}}}return $.activities.sort((I,N)=>I.startTime.getTime()-N.startTime.getTime()),$}async parseActivityFile(z){let q=Hq(z).toLowerCase();if(q!==".fit")throw Error(`Unsupported file format: ${q}`);let Q=Uq(z),G=new F(Q).parse();return new w(G).decodeActivity()}async parseMonitoringFile(z){let q=Hq(z).toLowerCase();if(q!==".fit")throw Error(`Unsupported file format: ${q}`);let Q=Uq(z),G=new F(Q).parse();return new w(G).decodeMonitoring()}}function tq(){return new bq}import{existsSync as Eq,readFileSync as Tq}from"fs";function Sq(z){let q=[],Q=[],Z=/<Workout([^>]+)>/g,G;while((G=Z.exec(z))!==null){let $=_q(G[1]);q.push({workoutActivityType:$.workoutActivityType||"",duration:$.duration||"0",durationUnit:$.durationUnit||"min",totalDistance:$.totalDistance||"0",totalDistanceUnit:$.totalDistanceUnit||"km",totalEnergyBurned:$.totalEnergyBurned||"0",totalEnergyBurnedUnit:$.totalEnergyBurnedUnit||"kcal",sourceName:$.sourceName||"",startDate:$.startDate||"",endDate:$.endDate||""})}let J=/<Record([^>]+)\/>/g,Y;while((Y=J.exec(z))!==null){let $=_q(Y[1]);Q.push({type:$.type||"",sourceName:$.sourceName||"",unit:$.unit||"",value:$.value||"0",startDate:$.startDate||"",endDate:$.endDate||"",creationDate:$.creationDate})}return{workouts:q,records:Q}}function _q(z){let q={},Q=/(\w+)="([^"]*)"/g,Z;while((Z=Q.exec(z))!==null)q[Z[1]]=Z[2];return q}function y(z){return new Date(z.replace(" ","T").replace(" ",""))}function Pq(z){return{HKWorkoutActivityTypeRunning:"running",HKWorkoutActivityTypeCycling:"cycling",HKWorkoutActivityTypeSwimming:"swimming",HKWorkoutActivityTypeHiking:"hiking",HKWorkoutActivityTypeWalking:"walking",HKWorkoutActivityTypeFunctionalStrengthTraining:"strength_training",HKWorkoutActivityTypeTraditionalStrengthTraining:"strength_training",HKWorkoutActivityTypeYoga:"yoga",HKWorkoutActivityTypeCrossTraining:"cardio",HKWorkoutActivityTypeElliptical:"cardio",HKWorkoutActivityTypeRowing:"cardio",HKWorkoutActivityTypeStairClimbing:"cardio"}[z]||"other"}class Oq{name="Apple";type="apple";async detectDevices(){return[]}async downloadData(z,q={}){return{device:z,activities:[],monitoring:new Map,rawFiles:[],errors:[Error("Apple Watch data must be imported from Health app export. Use parseHealthExport() instead.")]}}async parseHealthExport(z){let q=Eq(z)?z:`${z}/apple_health_export/export.xml`;if(!Eq(q))throw Error(`Health export not found at ${q}`);let Q=Tq(q,"utf-8"),{workouts:Z,records:G}=Sq(Q),J=Z.filter((I)=>I.sourceName.includes("Watch")).map((I)=>this.workoutToActivity(I)),Y=new Map,$=G.filter((I)=>I.type==="HKQuantityTypeIdentifierHeartRate"),b=new Map;for(let I of $){let N=y(I.startDate),K=N.toISOString().slice(0,10),H=b.get(K)||[];H.push({timestamp:N,heartRate:parseInt(I.value,10)}),b.set(K,H)}for(let[I,N]of b){let K=Y.get(I)||{},H=N.map((E)=>E.heartRate);K.heartRate={date:new Date(I),minHeartRate:Math.min(...H),maxHeartRate:Math.max(...H),avgHeartRate:Math.round(H.reduce((E,M)=>E+M,0)/H.length),samples:N},Y.set(I,K)}let B=G.filter((I)=>I.type==="HKQuantityTypeIdentifierStepCount"),X=new Map;for(let I of B){let K=y(I.startDate).toISOString().slice(0,10),H=X.get(K)||0;X.set(K,H+parseInt(I.value,10))}for(let[I,N]of X){let K=Y.get(I)||{};K.steps={date:new Date(I),totalSteps:N,goal:1e4,distance:0,calories:0,activeMinutes:0},Y.set(I,K)}return{activities:J,monitoring:Y}}workoutToActivity(z){let q=y(z.startDate),Q=y(z.endDate),Z=parseFloat(z.duration);if(z.durationUnit==="min")Z*=60;else if(z.durationUnit==="hr")Z*=3600;let G=parseFloat(z.totalDistance);if(z.totalDistanceUnit==="km")G*=1000;else if(z.totalDistanceUnit==="mi")G*=1609.34;let J=parseFloat(z.totalEnergyBurned);if(z.totalEnergyBurnedUnit==="kJ")J/=4.184;return{id:`apple_${q.getTime()}`,sport:Pq(z.workoutActivityType),startTime:q,endTime:Q,totalElapsedTime:Z,totalTimerTime:Z,totalDistance:G,totalCalories:Math.round(J),laps:[],records:[],source:"garmin"}}async parseActivityFile(z){throw Error("Apple Watch activities must be imported via Health export")}async parseMonitoringFile(z){throw Error("Apple Watch monitoring data must be imported via Health export")}}function Qz(){return new Oq}export{t as a,hq as b,Gq as c,cq as d,Wq as e,sq as f,bq as g,tq as h,Oq as i,Qz as j};
|
|
@@ -38,7 +38,26 @@ export declare function signState(payload: string, secret: string): string;
|
|
|
38
38
|
/** Verify and decode a value produced by {@link signState}, or null if it was altered. */
|
|
39
39
|
export declare function verifyState(token: string | undefined, secret: string): string | null;
|
|
40
40
|
/** Is a token past, or nearly past, its expiry? */
|
|
41
|
-
export declare function isTokenExpired(tokens: GarminTokens, skewSeconds?: number, now?:
|
|
41
|
+
export declare function isTokenExpired(tokens: GarminTokens, skewSeconds?: number, now?: number): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Seal an in-flight attempt into a token safe to hand to a browser.
|
|
44
|
+
*
|
|
45
|
+
* The callback is a top-level navigation from Garmin carrying no session, so
|
|
46
|
+
* the app has to stash who was connecting somewhere the browser holds - which
|
|
47
|
+
* means the value is under the visitor's control and must be signed. Without a
|
|
48
|
+
* signature someone edits the subject in their own cookie and attaches their
|
|
49
|
+
* watch to another person's account.
|
|
50
|
+
*
|
|
51
|
+
* This is {@link signState} with the shape the flow actually needs: a subject,
|
|
52
|
+
* the state parameter, the PKCE verifier, and an issue time so a stale attempt
|
|
53
|
+
* can be refused instead of silently resumed.
|
|
54
|
+
*/
|
|
55
|
+
export declare function sealOAuthAttempt<TSubject>(attempt: OAuthAttempt<TSubject>, secret: string): string;
|
|
56
|
+
/**
|
|
57
|
+
* Open a sealed attempt, or return null when it was tampered with, malformed,
|
|
58
|
+
* or has expired. Null always means "start again", never "trust it anyway".
|
|
59
|
+
*/
|
|
60
|
+
export declare function openOAuthAttempt<TSubject = string>(token: string | undefined, secret: string, options?: { now?: number, ttlMs?: number }): OAuthAttempt<TSubject> | null;
|
|
42
61
|
/** Endpoints from Garmin's OAuth 2.0 PKCE specification. */
|
|
43
62
|
export declare const GARMIN_ENDPOINTS: {
|
|
44
63
|
authorize: 'https://connect.garmin.com/oauth2Confirm';
|
|
@@ -48,6 +67,8 @@ export declare const GARMIN_ENDPOINTS: {
|
|
|
48
67
|
registration: 'https://apis.garmin.com/wellness-api/rest/user/registration';
|
|
49
68
|
backfillActivities: 'https://apis.garmin.com/wellness-api/rest/backfill/activities'
|
|
50
69
|
};
|
|
70
|
+
/** How long an in-flight attempt stays valid, in milliseconds. */
|
|
71
|
+
export declare const OAUTH_ATTEMPT_TTL_MS: number;
|
|
51
72
|
export declare interface GarminActivityApiConfig {
|
|
52
73
|
clientId: string
|
|
53
74
|
clientSecret: string
|
|
@@ -109,6 +130,13 @@ export declare interface GarminDeregistration {
|
|
|
109
130
|
userId: string
|
|
110
131
|
userAccessToken?: string
|
|
111
132
|
}
|
|
133
|
+
/** An in-flight authorization attempt, as it survives the round trip to Garmin. */
|
|
134
|
+
export declare interface OAuthAttempt<TSubject = string> {
|
|
135
|
+
subject: TSubject
|
|
136
|
+
state: string
|
|
137
|
+
verifier: string
|
|
138
|
+
issuedAt: number
|
|
139
|
+
}
|
|
112
140
|
/**
|
|
113
141
|
* A client for the official Garmin Activity API.
|
|
114
142
|
*
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from './garmin-activity-api';
|
|
2
|
+
export {
|
|
3
|
+
createGarminConnectClient,
|
|
4
|
+
GarminConnectClient,
|
|
5
|
+
type DailyHeartRate,
|
|
6
|
+
type DailySummary,
|
|
7
|
+
type GarminActivitySummary as GarminConnectActivitySummary,
|
|
8
|
+
type GarminConnectConfig,
|
|
9
|
+
} from './garmin-connect';
|
|
10
|
+
export * from './strava';
|
|
11
|
+
export * from './trainingpeaks';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as c,b as d,c as e,d as f,e as g,f as h,g as i,h as j,i as k,j as l}from"../../chunk-x32nxjdz.js";import{k as a,l as b}from"../../chunk-b68y8bzg.js";import"../../chunk-cahf1yhs.js";export{j as createWahooDriver,f as createSuuntoDriver,d as createPolarDriver,b as createGarminDriver,h as createCorosDriver,l as createAppleDriver,i as WahooDriver,e as SuuntoDriver,c as PolarDriver,a as GarminDriver,g as CorosDriver,k as AppleDriver};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{A as n,B as o,C as p,D as q,E as r,n as a,o as b,p as c,q as d,r as e,s as f,t as g,u as h,v as i,w as j,x as k,y as l,z as m}from"../../chunk-cahf1yhs.js";export{p as semicirclesToDegrees,o as fitTimestampToDate,q as degreesToSemicircles,i as SUB_SPORT,h as SPORT,j as SLEEP_LEVEL,f as MESG_NUM,l as MANUFACTURER,n as FitParser,m as FitParseError,r as FitDecoder,c as FIT_SIGNATURE,b as FIT_HEADER_SIZE_LEGACY,a as FIT_HEADER_SIZE,k as FIT_EPOCH,g as FIELD_DEF,e as BASE_TYPE_SIZES,d as BASE_TYPES};
|