@gooin/garmin-connect 1.8.4 → 1.8.6
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/README.md +59 -0
- package/dist/common/FileMFASessionStorage.js +1 -1
- package/dist/common/HttpClient copy.js +1 -1
- package/dist/common/HttpClient.js +1 -1
- package/dist/common/HttpClientOLD.js +1 -1
- package/dist/common/HttpClientOLDV1.js +1 -1
- package/dist/common/HttpClientV1.js +1 -1
- package/dist/common/MFAManager.js +1 -1
- package/dist/common/MFASessionStorage.js +1 -1
- package/dist/common/RedisMFASessionStorage.js +1 -1
- package/dist/garmin/GarminConnect.d.ts +18 -4
- package/dist/garmin/GarminConnect.js +1 -1
- package/dist/garmin/UrlClass.d.ts +6 -0
- package/dist/garmin/UrlClass.js +1 -1
- package/dist/garmin/UrlClass.js.map +1 -1
- package/dist/garmin/common/DateUtils.js +1 -1
- package/dist/garmin/common/HydrationUtils.js +1 -1
- package/dist/garmin/common/WeightUtils.js +1 -1
- package/dist/garmin/modules/activity/base.d.ts +5 -2
- package/dist/garmin/modules/activity/base.js +1 -1
- package/dist/garmin/modules/activity/base.js.map +1 -1
- package/dist/garmin/modules/activity/cycling.js +1 -1
- package/dist/garmin/modules/activity/running.d.ts +3 -0
- package/dist/garmin/modules/activity/running.js +1 -1
- package/dist/garmin/modules/activity/running.js.map +1 -1
- package/dist/garmin/modules/activity/training-status.d.ts +3 -0
- package/dist/garmin/modules/activity/training-status.js +1 -1
- package/dist/garmin/modules/activity/training-status.js.map +1 -1
- package/dist/garmin/modules/coach/activity-summary.d.ts +1 -0
- package/dist/garmin/modules/coach/activity-summary.js +1 -1
- package/dist/garmin/modules/coach/activity-summary.js.map +1 -1
- package/dist/garmin/modules/coach/helpers.d.ts +12 -2
- package/dist/garmin/modules/coach/helpers.js +1 -1
- package/dist/garmin/modules/coach/helpers.js.map +1 -1
- package/dist/garmin/modules/coach/sleep-analysis.d.ts +8 -0
- package/dist/garmin/modules/coach/sleep-analysis.js +1 -0
- package/dist/garmin/modules/coach/sleep-analysis.js.map +1 -0
- package/dist/garmin/modules/coach/training-overview.js +1 -1
- package/dist/garmin/modules/coach/training-overview.js.map +1 -1
- package/dist/garmin/modules/coach/wellness-overview.js +1 -1
- package/dist/garmin/modules/coach/wellness-overview.js.map +1 -1
- package/dist/garmin/modules/coach/wellness-summary.js +1 -1
- package/dist/garmin/modules/coach.d.ts +2 -1
- package/dist/garmin/modules/coach.js +1 -1
- package/dist/garmin/modules/coach.js.map +1 -1
- package/dist/garmin/modules/course.js +1 -1
- package/dist/garmin/modules/device.js +1 -1
- package/dist/garmin/modules/misc.js +1 -1
- package/dist/garmin/modules/types.js +1 -1
- package/dist/garmin/modules/user.js +1 -1
- package/dist/garmin/modules/wellness/body-battery.js +1 -1
- package/dist/garmin/modules/wellness/heart-rate.js +1 -1
- package/dist/garmin/modules/wellness/hrv.js +1 -1
- package/dist/garmin/modules/wellness/hydration.js +1 -1
- package/dist/garmin/modules/wellness/sleep.js +1 -1
- package/dist/garmin/modules/wellness/sleep.js.map +1 -1
- package/dist/garmin/modules/wellness/weight.js +1 -1
- package/dist/garmin/modules/workout.d.ts +9 -3
- package/dist/garmin/modules/workout.js +1 -1
- package/dist/garmin/modules/workout.js.map +1 -1
- package/dist/garmin/types/activity-stats.js +1 -1
- package/dist/garmin/types/activity.d.ts +30 -0
- package/dist/garmin/types/activity.js +1 -1
- package/dist/garmin/types/body-battery.js +1 -1
- package/dist/garmin/types/coach.d.ts +21 -0
- package/dist/garmin/types/coach.js +1 -1
- package/dist/garmin/types/course.js +1 -1
- package/dist/garmin/types/cycling.js +1 -1
- package/dist/garmin/types/device.js +1 -1
- package/dist/garmin/types/golf.js +1 -1
- package/dist/garmin/types/heartrate.js +1 -1
- package/dist/garmin/types/hrv.js +1 -1
- package/dist/garmin/types/hydration.js +1 -1
- package/dist/garmin/types/index.d.ts +1 -0
- package/dist/garmin/types/index.js +1 -1
- package/dist/garmin/types/index.js.map +1 -1
- package/dist/garmin/types/personal-info.js +1 -1
- package/dist/garmin/types/race-prediction.js +1 -1
- package/dist/garmin/types/sleep.d.ts +31 -0
- package/dist/garmin/types/sleep.js +1 -1
- package/dist/garmin/types/training-status.js +1 -1
- package/dist/garmin/types/weight.js +1 -1
- package/dist/garmin/types/workout.d.ts +167 -0
- package/dist/garmin/types/workout.js +1 -0
- package/dist/garmin/types/workout.js.map +1 -0
- package/dist/garmin/workouts/Running.js +1 -1
- package/dist/garmin/workouts/templates/RunningTemplate.js +1 -1
- package/dist/garmin/workouts/workout-draft.d.ts +3 -0
- package/dist/garmin/workouts/workout-draft.js +1 -0
- package/dist/garmin/workouts/workout-draft.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/utils.js +1 -1
- package/package.json +8 -3
package/README.md
CHANGED
|
@@ -547,6 +547,65 @@ GCClient.addRunningWorkout('My 5k run', 5000, 'Some description');
|
|
|
547
547
|
|
|
548
548
|
Will add a running workout of 5km called 'My 5k run' and return a JSON object representing the saved workout.
|
|
549
549
|
|
|
550
|
+
### Compile an AI coach workout draft
|
|
551
|
+
|
|
552
|
+
Use `workout_draft_v1` as a transport-neutral, metric input. The compiler
|
|
553
|
+
validates the draft and converts user-readable values to Garmin workout fields.
|
|
554
|
+
Compilation does not write to Garmin.
|
|
555
|
+
|
|
556
|
+
```ts
|
|
557
|
+
import { compileWorkoutDraft, type WorkoutDraft } from '@gooin/garmin-connect';
|
|
558
|
+
|
|
559
|
+
const draft: WorkoutDraft = {
|
|
560
|
+
schema: 'workout_draft_v1',
|
|
561
|
+
sport: 'running',
|
|
562
|
+
name: '4 x 1 km threshold',
|
|
563
|
+
estimatedDurationSec: 3600,
|
|
564
|
+
steps: [
|
|
565
|
+
{
|
|
566
|
+
type: 'step',
|
|
567
|
+
stepType: 'warmup',
|
|
568
|
+
duration: { type: 'time', seconds: 600 }
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
type: 'repeat',
|
|
572
|
+
iterations: 4,
|
|
573
|
+
steps: [
|
|
574
|
+
{
|
|
575
|
+
type: 'step',
|
|
576
|
+
stepType: 'interval',
|
|
577
|
+
duration: { type: 'distance', meters: 1000 },
|
|
578
|
+
target: {
|
|
579
|
+
type: 'pace',
|
|
580
|
+
fastestSecPerKm: 270,
|
|
581
|
+
slowestSecPerKm: 285
|
|
582
|
+
}
|
|
583
|
+
},
|
|
584
|
+
{
|
|
585
|
+
type: 'step',
|
|
586
|
+
stepType: 'recovery',
|
|
587
|
+
duration: { type: 'time', seconds: 120 }
|
|
588
|
+
}
|
|
589
|
+
]
|
|
590
|
+
},
|
|
591
|
+
{
|
|
592
|
+
type: 'step',
|
|
593
|
+
stepType: 'cooldown',
|
|
594
|
+
duration: { type: 'time', seconds: 600 }
|
|
595
|
+
}
|
|
596
|
+
]
|
|
597
|
+
};
|
|
598
|
+
|
|
599
|
+
const payload = compileWorkoutDraft(draft);
|
|
600
|
+
|
|
601
|
+
// Execute these write operations only after explicit user confirmation.
|
|
602
|
+
const workout = await GCClient.addWorkout(payload);
|
|
603
|
+
await GCClient.scheduleWorkout(
|
|
604
|
+
{ workoutId: String(workout.workoutId) },
|
|
605
|
+
new Date('2026-06-16')
|
|
606
|
+
);
|
|
607
|
+
```
|
|
608
|
+
|
|
550
609
|
### Schedule workout
|
|
551
610
|
|
|
552
611
|
To add a workout to your calendar, first find your workout and then add it to a specific date.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
'use strict';const
|
|
1
|
+
'use strict';const a0_0x5c6317=a0_0x33a1;(function(_0x858e43,_0x4f861e){const _0xb43b40=a0_0x33a1,_0x4c7b8f=_0x858e43();while(!![]){try{const _0x3d2bab=parseInt(_0xb43b40(0x154))/0x1*(-parseInt(_0xb43b40(0x13e))/0x2)+-parseInt(_0xb43b40(0x178))/0x3*(parseInt(_0xb43b40(0x177))/0x4)+-parseInt(_0xb43b40(0x173))/0x5*(-parseInt(_0xb43b40(0x158))/0x6)+parseInt(_0xb43b40(0x15d))/0x7+-parseInt(_0xb43b40(0x14a))/0x8*(parseInt(_0xb43b40(0x16e))/0x9)+-parseInt(_0xb43b40(0x15b))/0xa+parseInt(_0xb43b40(0x162))/0xb;if(_0x3d2bab===_0x4f861e)break;else _0x4c7b8f['push'](_0x4c7b8f['shift']());}catch(_0x1ca367){_0x4c7b8f['push'](_0x4c7b8f['shift']());}}}(a0_0x339f,0xd4572));function a0_0x339f(){const _0x274adb=['MFA验证已取消','8488452YjBYBc','waiting','code','readdir','创建MFA存储目录失败:','14211725Nvvvtg','mkdir','log','unlink','未找到MFA验证会话:\x20','FileMFASessionStorage','replace','清理了\x20','__importDefault','access','join','resolvedAt','18aiccJA','storageDir','endsWith','default',',\x20状态:\x20','15GhxkWN','error','cleanupExpiredRequests','submitMFACode','5636dyWLuN','921UdrSVz','__esModule','readFile','map','resolved','now','2jslwgZ','status','rejected','message','rejectedAt','toISOString','writeFile','stringify','promises','.json','parse','utf8','2161336JQcgbv','getSessionFilePath','清理过期请求失败:','defineProperty','getActiveSessions','MFA验证会话状态不正确:\x20','cleanupRequest',',\x20sessionId\x20','ensureStorageDir',',\x20错误:\x20','503541ITqlBA','getTime',',\x20原因:\x20','\x20个过期的MFA验证会话','2913066RzhRft','获取活跃会话失败:','DEFAULT_TIMEOUT','16149600BSimjJ'];a0_0x339f=function(){return _0x274adb;};return a0_0x339f();}var __importDefault=this&&this[a0_0x5c6317(0x16a)]||function(_0x33642d){return _0x33642d&&_0x33642d['__esModule']?_0x33642d:{'default':_0x33642d};};Object[a0_0x5c6317(0x14d)](exports,a0_0x5c6317(0x179),{'value':!![]}),exports[a0_0x5c6317(0x167)]=void 0x0;const fs_1=require('fs'),path_1=__importDefault(require('path'));function a0_0x33a1(_0xc48a8d,_0x4212c9){_0xc48a8d=_0xc48a8d-0x13c;const _0x339f70=a0_0x339f();let _0x33a132=_0x339f70[_0xc48a8d];return _0x33a132;}class FileMFASessionStorage{constructor(_0x3e185e){const _0x41d434=a0_0x5c6317;this[_0x41d434(0x15a)]=0x5*0x3c*0x3e8,this[_0x41d434(0x16f)]=_0x3e185e,this[_0x41d434(0x152)]();}async[a0_0x5c6317(0x152)](){const _0x3dd3d9=a0_0x5c6317;try{await fs_1[_0x3dd3d9(0x146)][_0x3dd3d9(0x163)](this[_0x3dd3d9(0x16f)],{'recursive':!![]});}catch(_0x26920d){console[_0x3dd3d9(0x174)](_0x3dd3d9(0x161),_0x26920d);}}[a0_0x5c6317(0x14b)](_0x3d6d62){const _0x996659=a0_0x5c6317;return path_1[_0x996659(0x171)]['join'](this['storageDir'],_0x3d6d62+_0x996659(0x147));}async['waitForMFACode'](_0x2f8861,_0x4963ff=this['DEFAULT_TIMEOUT']){const _0x309714=a0_0x5c6317;await this[_0x309714(0x152)](),await this[_0x309714(0x150)](_0x2f8861);const _0x2d810a={'sessionId':_0x2f8861,'status':_0x309714(0x15e),'createdAt':new Date()[_0x309714(0x143)](),'timeout':_0x4963ff},_0x27b5b4=this[_0x309714(0x14b)](_0x2f8861);return await fs_1[_0x309714(0x146)][_0x309714(0x144)](_0x27b5b4,JSON[_0x309714(0x145)](_0x2d810a),_0x309714(0x149)),console[_0x309714(0x164)]('MFA验证会话已创建:\x20'+_0x2f8861),new Promise((_0x276d1f,_0x1ce846)=>{const _0x26541d=Date['now'](),_0x15eb4a=setInterval(async()=>{const _0x1c6cc1=a0_0x33a1;try{if(Date[_0x1c6cc1(0x13d)]()-_0x26541d>_0x4963ff){clearInterval(_0x15eb4a),await this[_0x1c6cc1(0x150)](_0x2f8861),_0x1ce846(new Error('MFA验证超时,请重新登录'));return;}try{const _0x78c200=await fs_1['promises'][_0x1c6cc1(0x17a)](_0x27b5b4,_0x1c6cc1(0x149)),_0x458463=JSON[_0x1c6cc1(0x148)](_0x78c200);if(_0x458463[_0x1c6cc1(0x13f)]===_0x1c6cc1(0x13c)&&_0x458463[_0x1c6cc1(0x15f)]){clearInterval(_0x15eb4a),await this[_0x1c6cc1(0x150)](_0x2f8861),_0x276d1f(_0x458463[_0x1c6cc1(0x15f)]);return;}if(_0x458463[_0x1c6cc1(0x13f)]===_0x1c6cc1(0x140)&&_0x458463[_0x1c6cc1(0x174)]){clearInterval(_0x15eb4a),await this[_0x1c6cc1(0x150)](_0x2f8861),_0x1ce846(new Error(_0x458463[_0x1c6cc1(0x174)]));return;}}catch(_0x55bc47){}}catch(_0x29824d){clearInterval(_0x15eb4a),await this[_0x1c6cc1(0x150)](_0x2f8861),_0x1ce846(_0x29824d instanceof Error?_0x29824d:new Error(String(_0x29824d)));}},0x3e8);});}async[a0_0x5c6317(0x176)](_0x4e8de3,_0x7a277a){const _0x8b9abc=a0_0x5c6317,_0x5d73ce=this[_0x8b9abc(0x14b)](_0x4e8de3);try{const _0x5c27a2=await fs_1['promises'][_0x8b9abc(0x17a)](_0x5d73ce,_0x8b9abc(0x149)),_0x922930=JSON[_0x8b9abc(0x148)](_0x5c27a2);if(_0x922930['status']!=='waiting')return console[_0x8b9abc(0x164)](_0x8b9abc(0x14f)+_0x4e8de3+_0x8b9abc(0x172)+_0x922930['status']),![];return _0x922930[_0x8b9abc(0x13f)]='resolved',_0x922930[_0x8b9abc(0x15f)]=_0x7a277a,_0x922930[_0x8b9abc(0x16d)]=new Date()['toISOString'](),await fs_1[_0x8b9abc(0x146)]['writeFile'](_0x5d73ce,JSON[_0x8b9abc(0x145)](_0x922930),_0x8b9abc(0x149)),console['log']('MFA验证码已提交:\x20code\x20'+_0x7a277a+_0x8b9abc(0x151)+_0x4e8de3),!![];}catch(_0x2de17a){return console['log'](_0x8b9abc(0x166)+_0x4e8de3+',\x20错误:\x20'+(_0x2de17a instanceof Error?_0x2de17a[_0x8b9abc(0x141)]:String(_0x2de17a))),![];}}async['cancelMFARequest'](_0x42c823,_0x287ac1=a0_0x5c6317(0x15c)){const _0x4c2bb8=a0_0x5c6317,_0x5cb2b3=this[_0x4c2bb8(0x14b)](_0x42c823);try{const _0x523f9a=await fs_1[_0x4c2bb8(0x146)][_0x4c2bb8(0x17a)](_0x5cb2b3,_0x4c2bb8(0x149)),_0x4e0c37=JSON[_0x4c2bb8(0x148)](_0x523f9a);return _0x4e0c37[_0x4c2bb8(0x13f)]=_0x4c2bb8(0x140),_0x4e0c37[_0x4c2bb8(0x174)]=_0x287ac1,_0x4e0c37[_0x4c2bb8(0x142)]=new Date()[_0x4c2bb8(0x143)](),await fs_1[_0x4c2bb8(0x146)]['writeFile'](_0x5cb2b3,JSON[_0x4c2bb8(0x145)](_0x4e0c37),_0x4c2bb8(0x149)),console['log']('MFA验证已取消:\x20'+_0x42c823+_0x4c2bb8(0x156)+_0x287ac1),!![];}catch(_0x572c3a){return console[_0x4c2bb8(0x164)](_0x4c2bb8(0x166)+_0x42c823+_0x4c2bb8(0x153)+(_0x572c3a instanceof Error?_0x572c3a[_0x4c2bb8(0x141)]:String(_0x572c3a))),![];}}async['hasSession'](_0x3b1136){const _0x15db75=a0_0x5c6317,_0x3a700e=this[_0x15db75(0x14b)](_0x3b1136);try{return await fs_1['promises'][_0x15db75(0x16b)](_0x3a700e),!![];}catch(_0x3e4edf){return![];}}async[a0_0x5c6317(0x14e)](){const _0x4b3b4b=a0_0x5c6317;try{await this[_0x4b3b4b(0x152)]();const _0x1e97f3=await fs_1[_0x4b3b4b(0x146)][_0x4b3b4b(0x160)](this[_0x4b3b4b(0x16f)]);return _0x1e97f3['filter'](_0x10eb54=>_0x10eb54[_0x4b3b4b(0x170)](_0x4b3b4b(0x147)))[_0x4b3b4b(0x17b)](_0x2ed9fa=>_0x2ed9fa[_0x4b3b4b(0x168)](_0x4b3b4b(0x147),''));}catch(_0x4ecc58){return console[_0x4b3b4b(0x174)](_0x4b3b4b(0x159),_0x4ecc58 instanceof Error?_0x4ecc58:String(_0x4ecc58)),[];}}async[a0_0x5c6317(0x175)](_0x122db9=this['DEFAULT_TIMEOUT']){const _0x1c8ab0=a0_0x5c6317;try{await this[_0x1c8ab0(0x152)]();const _0xc4ec71=await fs_1[_0x1c8ab0(0x146)]['readdir'](this[_0x1c8ab0(0x16f)]),_0x165841=new Date();let _0x294014=0x0;for(const _0x17dc34 of _0xc4ec71){if(!_0x17dc34[_0x1c8ab0(0x170)]('.json'))continue;try{const _0x57935c=path_1[_0x1c8ab0(0x171)][_0x1c8ab0(0x16c)](this[_0x1c8ab0(0x16f)],_0x17dc34),_0x2c74cb=await fs_1[_0x1c8ab0(0x146)][_0x1c8ab0(0x17a)](_0x57935c,'utf8'),_0x48356e=JSON[_0x1c8ab0(0x148)](_0x2c74cb),_0x2ae058=new Date(_0x48356e['createdAt']);_0x165841[_0x1c8ab0(0x155)]()-_0x2ae058[_0x1c8ab0(0x155)]()>_0x122db9&&(await fs_1[_0x1c8ab0(0x146)][_0x1c8ab0(0x165)](_0x57935c),_0x294014++);}catch(_0x23bad8){try{await fs_1[_0x1c8ab0(0x146)][_0x1c8ab0(0x165)](path_1[_0x1c8ab0(0x171)][_0x1c8ab0(0x16c)](this[_0x1c8ab0(0x16f)],_0x17dc34)),_0x294014++;}catch(_0x1ef3b7){console['error']('删除过期会话文件失败:\x20'+_0x17dc34,_0x1ef3b7 instanceof Error?_0x1ef3b7:String(_0x1ef3b7));}}}_0x294014>0x0&&console[_0x1c8ab0(0x164)](_0x1c8ab0(0x169)+_0x294014+_0x1c8ab0(0x157));}catch(_0x55ce66){console[_0x1c8ab0(0x174)](_0x1c8ab0(0x14c),_0x55ce66 instanceof Error?_0x55ce66:String(_0x55ce66));}}async[a0_0x5c6317(0x150)](_0x40f669){const _0x3609ed=a0_0x5c6317,_0x2f6c52=this[_0x3609ed(0x14b)](_0x40f669);try{await fs_1[_0x3609ed(0x146)][_0x3609ed(0x165)](_0x2f6c52);}catch(_0x18667d){}}}exports[a0_0x5c6317(0x167)]=FileMFASessionStorage;
|