ts-garmin 0.1.1 → 0.1.3
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 +1 -0
- package/dist/garmin/GarminConnect.d.ts +4 -2
- package/dist/garmin/types/activity.d.ts +18 -0
- package/dist/index.js +106 -94
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -172,6 +172,7 @@ const userId = await garmin.getUserId(tokens.accessToken) // the key push notifi
|
|
|
172
172
|
const legacy = new GarminConnectClient()
|
|
173
173
|
await legacy.login('email@example.com', 'password')
|
|
174
174
|
const activities = await legacy.getActivities(new Date('2024-01-01'))
|
|
175
|
+
const { bytes, filename } = await legacy.downloadOriginalActivity(activityId) // "Export Original" zip, in memory
|
|
175
176
|
|
|
176
177
|
// Strava
|
|
177
178
|
const strava = new StravaClient({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HttpClient } from '../common/HttpClient';
|
|
2
|
-
import type { ActivitySubType, ActivityType, ExportFileTypeValue, GCActivityId, GCGearId, GarminDomain, IActivity, ICountActivities, IGarminTokens, IOauth1Token, IOauth2Token, ISocialProfile, IUserSettings, IWorkout, IWorkoutDetail, ListCoursesResponse, UploadFileTypeValue } from './types/index';
|
|
2
|
+
import type { ActivitySubType, ActivityType, ExportFileTypeValue, GCActivityId, GCGearId, GarminDomain, IActivity, IActivityDetails, ICountActivities, IGarminTokens, IOauth1Token, IOauth2Token, ISocialProfile, IUserSettings, IWorkout, IWorkoutDetail, ListCoursesResponse, UploadFileTypeValue } from './types/index';
|
|
3
3
|
import type { CoursePoint, GeoPoint, GpxActivityType, ImportedGpxResponse } from './types/gpx';
|
|
4
4
|
import type { GearData } from './types/gear';
|
|
5
5
|
import type { HeartRate } from './types/heartrate';
|
|
@@ -29,8 +29,10 @@ export default class GarminConnect {
|
|
|
29
29
|
getUserProfile(): Promise<ISocialProfile>;
|
|
30
30
|
getActivities(start?: number, limit?: number, activityType?: ActivityType, subActivityType?: ActivitySubType): Promise<IActivity[]>;
|
|
31
31
|
getActivity(activity: { activityId: GCActivityId }): Promise<IActivity>;
|
|
32
|
+
getActivityDetails(activity: { activityId: GCActivityId }, maxChartSize?: number): Promise<IActivityDetails>;
|
|
32
33
|
countActivities(): Promise<ICountActivities>;
|
|
33
|
-
|
|
34
|
+
getOriginalActivityData(activity: { activityId: GCActivityId }, type?: ExportFileTypeValue): Promise<{ bytes: Uint8Array, filename: string }>;
|
|
35
|
+
downloadOriginalActivityData(activity: { activityId: GCActivityId }, dir: string, type?: ExportFileTypeValue): Promise<string>;
|
|
34
36
|
uploadActivity(file: string, format?: UploadFileTypeValue): Promise<unknown>;
|
|
35
37
|
deleteActivity(activity: { activityId: GCActivityId }): Promise<void>;
|
|
36
38
|
getWorkouts(start: number, limit: number): Promise<IWorkout[]>;
|
|
@@ -377,6 +377,24 @@ export declare interface IActivityDetails {
|
|
|
377
377
|
maxDistance: number
|
|
378
378
|
}[] | null
|
|
379
379
|
}
|
|
380
|
+
/** One series in an activity's details, e.g. directHeartRate or sumDuration. */
|
|
381
|
+
export declare interface IActivityDetailMetricDescriptor {
|
|
382
|
+
metricsIndex: number
|
|
383
|
+
key: string
|
|
384
|
+
unit?: { id?: number, key?: string, factor?: number }
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* An activity's recorded time series from activity-service's details
|
|
388
|
+
* endpoint: `activityDetailMetrics[i].metrics[metricsIndex]` is sample i of
|
|
389
|
+
* the series the descriptor names. Garmin downsamples to `maxChartSize`.
|
|
390
|
+
*/
|
|
391
|
+
export declare interface IActivityDetails {
|
|
392
|
+
activityId: number
|
|
393
|
+
measurementCount?: number
|
|
394
|
+
metricsCount?: number
|
|
395
|
+
metricDescriptors: IActivityDetailMetricDescriptor[]
|
|
396
|
+
activityDetailMetrics: Array<{ metrics: Array<number | null> }>
|
|
397
|
+
}
|
|
380
398
|
export type GCActivityId = number;
|
|
381
399
|
export declare enum ActivityType {
|
|
382
400
|
Cycling = 'cycling',
|
package/dist/index.js
CHANGED
|
@@ -143,13 +143,13 @@ class HttpClient {
|
|
|
143
143
|
const text = await response.text();
|
|
144
144
|
throw new Error(`HTTP Error: ${response.status} ${response.statusText} - ${text}`);
|
|
145
145
|
}
|
|
146
|
+
if (responseType === "arraybuffer") {
|
|
147
|
+
return response.arrayBuffer();
|
|
148
|
+
}
|
|
146
149
|
const contentType = response.headers.get("content-type");
|
|
147
150
|
if (contentType?.includes("application/json")) {
|
|
148
151
|
return response.json();
|
|
149
152
|
}
|
|
150
|
-
if (responseType === "arraybuffer") {
|
|
151
|
-
return response.arrayBuffer();
|
|
152
|
-
}
|
|
153
153
|
return response.text();
|
|
154
154
|
}
|
|
155
155
|
async get(url, config) {
|
|
@@ -538,54 +538,54 @@ class UrlClass {
|
|
|
538
538
|
|
|
539
539
|
// src/garmin/types/activity.ts
|
|
540
540
|
var ActivityType;
|
|
541
|
-
((
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
541
|
+
((ActivityType) => {
|
|
542
|
+
ActivityType["Cycling"] = "cycling";
|
|
543
|
+
ActivityType["FitnessEquipment"] = "fitness_equipment";
|
|
544
|
+
ActivityType["Walking"] = "walking";
|
|
545
|
+
ActivityType["Hiking"] = "hiking";
|
|
546
|
+
ActivityType["Other"] = "other";
|
|
547
|
+
ActivityType["WaterSport"] = "water_sports";
|
|
548
|
+
ActivityType["Running"] = "street_running";
|
|
549
549
|
})(ActivityType ||= {});
|
|
550
550
|
var ActivitySubType;
|
|
551
|
-
((
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
551
|
+
((ActivitySubType) => {
|
|
552
|
+
ActivitySubType["IndoorCardio"] = "indoor_cardio";
|
|
553
|
+
ActivitySubType["StrengthTraining"] = "strength_training";
|
|
554
|
+
ActivitySubType["HIIT"] = "hiit";
|
|
555
|
+
ActivitySubType["Yoga"] = "yoga";
|
|
556
|
+
ActivitySubType["IndoorCycling"] = "indoor_cycling";
|
|
557
|
+
ActivitySubType["Breathwork"] = "breathwork";
|
|
558
|
+
ActivitySubType["Surfing"] = "surfing";
|
|
559
|
+
ActivitySubType["StreetRunning"] = "street_running";
|
|
560
|
+
ActivitySubType["TrailRunning"] = "trail_running";
|
|
561
|
+
ActivitySubType["IndoorRunning"] = "indoor_running";
|
|
562
562
|
})(ActivitySubType ||= {});
|
|
563
563
|
// src/garmin/types/gpx.ts
|
|
564
564
|
var GpxActivityType;
|
|
565
|
-
((
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
565
|
+
((GpxActivityType) => {
|
|
566
|
+
GpxActivityType[GpxActivityType["Running"] = 1] = "Running";
|
|
567
|
+
GpxActivityType[GpxActivityType["Running_Road"] = 1] = "Running_Road";
|
|
568
|
+
GpxActivityType[GpxActivityType["Running_Trail"] = 1] = "Running_Trail";
|
|
569
|
+
GpxActivityType[GpxActivityType["Cycling"] = 10] = "Cycling";
|
|
570
|
+
GpxActivityType[GpxActivityType["Cycling_Road"] = 10] = "Cycling_Road";
|
|
571
|
+
GpxActivityType[GpxActivityType["Cycling_Gravel"] = 143] = "Cycling_Gravel";
|
|
572
|
+
GpxActivityType[GpxActivityType["Hiking"] = 3] = "Hiking";
|
|
573
|
+
GpxActivityType[GpxActivityType["Other"] = 4] = "Other";
|
|
574
574
|
})(GpxActivityType ||= {});
|
|
575
575
|
|
|
576
576
|
// src/garmin/types/index.ts
|
|
577
577
|
var ExportFileType;
|
|
578
|
-
((
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
578
|
+
((ExportFileType) => {
|
|
579
|
+
ExportFileType["tcx"] = "tcx";
|
|
580
|
+
ExportFileType["gpx"] = "gpx";
|
|
581
|
+
ExportFileType["kml"] = "kml";
|
|
582
|
+
ExportFileType["zip"] = "zip";
|
|
583
583
|
})(ExportFileType ||= {});
|
|
584
584
|
var UploadFileType;
|
|
585
|
-
((
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
585
|
+
((UploadFileType) => {
|
|
586
|
+
UploadFileType["tcx"] = "tcx";
|
|
587
|
+
UploadFileType["gpx"] = "gpx";
|
|
588
|
+
UploadFileType["fit"] = "fit";
|
|
589
589
|
})(UploadFileType ||= {});
|
|
590
590
|
|
|
591
591
|
// src/garmin/common/DateUtils.ts
|
|
@@ -720,10 +720,17 @@ class GarminConnect {
|
|
|
720
720
|
params: { start, limit, activityType, subActivityType }
|
|
721
721
|
});
|
|
722
722
|
}
|
|
723
|
-
async getActivity(
|
|
724
|
-
if (!
|
|
723
|
+
async getActivity(activity) {
|
|
724
|
+
if (!activity.activityId)
|
|
725
|
+
throw new Error("Missing activityId");
|
|
726
|
+
return this.client.get(`${this.url.ACTIVITY}${activity.activityId}`);
|
|
727
|
+
}
|
|
728
|
+
async getActivityDetails(activity, maxChartSize = 2000) {
|
|
729
|
+
if (!activity.activityId)
|
|
725
730
|
throw new Error("Missing activityId");
|
|
726
|
-
return this.client.get(`${this.url.
|
|
731
|
+
return this.client.get(`${this.url.ACTIVITY_BY_ID(activity.activityId)}/details`, {
|
|
732
|
+
params: { maxChartSize, maxPolylineSize: 0, maxHeatMapSize: 0 }
|
|
733
|
+
});
|
|
727
734
|
}
|
|
728
735
|
async countActivities() {
|
|
729
736
|
const now = new Date;
|
|
@@ -737,27 +744,32 @@ class GarminConnect {
|
|
|
737
744
|
}
|
|
738
745
|
});
|
|
739
746
|
}
|
|
740
|
-
async
|
|
741
|
-
if (!
|
|
747
|
+
async getOriginalActivityData(activity, type = "zip") {
|
|
748
|
+
if (!activity.activityId)
|
|
742
749
|
throw new Error("Missing activityId");
|
|
743
|
-
if (!checkIsDirectory(dir)) {
|
|
744
|
-
createDirectory(dir);
|
|
745
|
-
}
|
|
746
|
-
let fileBuffer;
|
|
747
750
|
let url;
|
|
748
751
|
if (type === "tcx") {
|
|
749
|
-
url = `${this.url.DOWNLOAD_TCX}${
|
|
752
|
+
url = `${this.url.DOWNLOAD_TCX}${activity.activityId}`;
|
|
750
753
|
} else if (type === "gpx") {
|
|
751
|
-
url = `${this.url.DOWNLOAD_GPX}${
|
|
754
|
+
url = `${this.url.DOWNLOAD_GPX}${activity.activityId}`;
|
|
752
755
|
} else if (type === "kml") {
|
|
753
|
-
url = `${this.url.DOWNLOAD_KML}${
|
|
756
|
+
url = `${this.url.DOWNLOAD_KML}${activity.activityId}`;
|
|
754
757
|
} else if (type === "zip") {
|
|
755
|
-
url = `${this.url.DOWNLOAD_ZIP}${
|
|
758
|
+
url = `${this.url.DOWNLOAD_ZIP}${activity.activityId}`;
|
|
756
759
|
} else {
|
|
757
|
-
throw new Error(`
|
|
760
|
+
throw new Error(`getOriginalActivityData - Invalid type: ${type}`);
|
|
761
|
+
}
|
|
762
|
+
const body = await this.client.get(url, { responseType: "arraybuffer" });
|
|
763
|
+
return { bytes: new Uint8Array(body), filename: `${activity.activityId}.${type}` };
|
|
764
|
+
}
|
|
765
|
+
async downloadOriginalActivityData(activity, dir, type = "zip") {
|
|
766
|
+
const { bytes, filename } = await this.getOriginalActivityData(activity, type);
|
|
767
|
+
if (!checkIsDirectory(dir)) {
|
|
768
|
+
createDirectory(dir);
|
|
758
769
|
}
|
|
759
|
-
|
|
760
|
-
writeToFile(
|
|
770
|
+
const file = path.join(dir, filename);
|
|
771
|
+
writeToFile(file, bytes);
|
|
772
|
+
return file;
|
|
761
773
|
}
|
|
762
774
|
async uploadActivity(file, format = "fit") {
|
|
763
775
|
const detectedFormat = (format || path.extname(file))?.toLowerCase();
|
|
@@ -776,31 +788,31 @@ class GarminConnect {
|
|
|
776
788
|
});
|
|
777
789
|
return response.json();
|
|
778
790
|
}
|
|
779
|
-
async deleteActivity(
|
|
780
|
-
if (!
|
|
791
|
+
async deleteActivity(activity) {
|
|
792
|
+
if (!activity.activityId)
|
|
781
793
|
throw new Error("Missing activityId");
|
|
782
|
-
await this.client.delete(`${this.url.ACTIVITY}${
|
|
794
|
+
await this.client.delete(`${this.url.ACTIVITY}${activity.activityId}`);
|
|
783
795
|
}
|
|
784
796
|
async getWorkouts(start, limit) {
|
|
785
797
|
return this.client.get(this.url.WORKOUTS, {
|
|
786
798
|
params: { start, limit }
|
|
787
799
|
});
|
|
788
800
|
}
|
|
789
|
-
async getWorkoutDetail(
|
|
790
|
-
if (!
|
|
801
|
+
async getWorkoutDetail(workout) {
|
|
802
|
+
if (!workout.workoutId)
|
|
791
803
|
throw new Error("Missing workoutId");
|
|
792
|
-
return this.client.get(this.url.WORKOUT(
|
|
804
|
+
return this.client.get(this.url.WORKOUT(workout.workoutId));
|
|
793
805
|
}
|
|
794
|
-
async createWorkout(
|
|
795
|
-
return this.client.post(this.url.WORKOUT(),
|
|
806
|
+
async createWorkout(workout) {
|
|
807
|
+
return this.client.post(this.url.WORKOUT(), workout);
|
|
796
808
|
}
|
|
797
|
-
async deleteWorkout(
|
|
798
|
-
if (!
|
|
809
|
+
async deleteWorkout(workout) {
|
|
810
|
+
if (!workout.workoutId)
|
|
799
811
|
throw new Error("Missing workout");
|
|
800
|
-
return this.client.delete(this.url.WORKOUT(
|
|
812
|
+
return this.client.delete(this.url.WORKOUT(workout.workoutId));
|
|
801
813
|
}
|
|
802
|
-
async scheduleWorkout(
|
|
803
|
-
return this.client.post(this.url.SCHEDULE_WORKOUT(Number.parseInt(
|
|
814
|
+
async scheduleWorkout(workout, scheduleDate) {
|
|
815
|
+
return this.client.post(this.url.SCHEDULE_WORKOUT(Number.parseInt(workout.workoutId)), { date: scheduleDate });
|
|
804
816
|
}
|
|
805
817
|
async getSteps(date = new Date) {
|
|
806
818
|
const dateString = toDateString(date);
|
|
@@ -1482,30 +1494,30 @@ class WorkoutType {
|
|
|
1482
1494
|
static Cardio = new WorkoutType("cardio_training", 6);
|
|
1483
1495
|
}
|
|
1484
1496
|
export {
|
|
1485
|
-
|
|
1486
|
-
WorkoutType,
|
|
1487
|
-
WorkoutBuilder,
|
|
1488
|
-
UploadFileType,
|
|
1489
|
-
TimeDuration,
|
|
1490
|
-
Target,
|
|
1491
|
-
StepType,
|
|
1492
|
-
Step,
|
|
1493
|
-
PowerZoneTarget,
|
|
1494
|
-
PowerZone,
|
|
1495
|
-
PaceTarget,
|
|
1496
|
-
NoTarget,
|
|
1497
|
-
NoDuration,
|
|
1498
|
-
LapPressDuration,
|
|
1499
|
-
HrmZoneTarget,
|
|
1500
|
-
HrmTarget,
|
|
1501
|
-
HeartRateDuration,
|
|
1502
|
-
GpxActivityType,
|
|
1503
|
-
GarminConnect,
|
|
1504
|
-
ExportFileType,
|
|
1505
|
-
Duration,
|
|
1506
|
-
DistanceDuration,
|
|
1507
|
-
CaloriesDuration,
|
|
1508
|
-
CadenceTarget,
|
|
1497
|
+
ActivitySubType,
|
|
1509
1498
|
ActivityType,
|
|
1510
|
-
|
|
1499
|
+
CadenceTarget,
|
|
1500
|
+
CaloriesDuration,
|
|
1501
|
+
DistanceDuration,
|
|
1502
|
+
Duration,
|
|
1503
|
+
ExportFileType,
|
|
1504
|
+
GarminConnect,
|
|
1505
|
+
GpxActivityType,
|
|
1506
|
+
HeartRateDuration,
|
|
1507
|
+
HrmTarget,
|
|
1508
|
+
HrmZoneTarget,
|
|
1509
|
+
LapPressDuration,
|
|
1510
|
+
NoDuration,
|
|
1511
|
+
NoTarget,
|
|
1512
|
+
PaceTarget,
|
|
1513
|
+
PowerZone,
|
|
1514
|
+
PowerZoneTarget,
|
|
1515
|
+
Step,
|
|
1516
|
+
StepType,
|
|
1517
|
+
Target,
|
|
1518
|
+
TimeDuration,
|
|
1519
|
+
UploadFileType,
|
|
1520
|
+
WorkoutBuilder,
|
|
1521
|
+
WorkoutType,
|
|
1522
|
+
courseRequestTemplate
|
|
1511
1523
|
};
|