@gooin/garmin-connect 1.4.4 → 1.6.0

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.
Files changed (38) hide show
  1. package/README.md +225 -35
  2. package/dist/common/CFClient.d.ts +22 -0
  3. package/dist/common/CFClient.js +137 -140
  4. package/dist/common/CFClient.js.map +1 -0
  5. package/dist/common/DateUtils.d.ts +1 -0
  6. package/dist/common/DateUtils.js +11 -10
  7. package/dist/common/DateUtils.js.map +1 -0
  8. package/dist/common/HttpClient.d.ts +34 -0
  9. package/dist/common/HttpClient.js +299 -0
  10. package/dist/common/HttpClient.js.map +1 -0
  11. package/dist/garmin/GarminConnect.d.ts +40 -0
  12. package/dist/garmin/GarminConnect.js +178 -438
  13. package/dist/garmin/GarminConnect.js.map +1 -0
  14. package/dist/garmin/UrlClass.d.ts +25 -0
  15. package/dist/garmin/UrlClass.js +64 -0
  16. package/dist/garmin/UrlClass.js.map +1 -0
  17. package/dist/garmin/Urls.d.ts +64 -0
  18. package/dist/garmin/Urls.js +104 -102
  19. package/dist/garmin/Urls.js.map +1 -0
  20. package/dist/garmin/types.d.ts +706 -0
  21. package/dist/garmin/types.js +17 -0
  22. package/dist/garmin/types.js.map +1 -0
  23. package/dist/garmin/workouts/Running.d.ts +16 -0
  24. package/dist/garmin/workouts/Running.js +47 -53
  25. package/dist/garmin/workouts/Running.js.map +1 -0
  26. package/dist/garmin/workouts/templates/RunningTemplate.d.ts +68 -0
  27. package/dist/garmin/workouts/templates/RunningTemplate.js +78 -48
  28. package/dist/garmin/workouts/templates/RunningTemplate.js.map +1 -0
  29. package/dist/index.d.ts +1 -0
  30. package/dist/index.js +9 -3
  31. package/dist/index.js.map +1 -0
  32. package/dist/utils.d.ts +3 -0
  33. package/dist/utils.js +46 -0
  34. package/dist/utils.js.map +1 -0
  35. package/examples/example.js +21 -6
  36. package/package.json +66 -51
  37. package/dist/common/Client.js +0 -189
  38. package/dist/garmin/workouts/index.js +0 -5
package/README.md CHANGED
@@ -1,35 +1,107 @@
1
+ # garmin-connect
1
2
 
3
+ ## v1.6.0 refactor
4
+
5
+ TODO:
6
+
7
+ - [x] New HttpClient class
8
+ - [x] Login and get user token
9
+ - [x] Garmin URLs works with `garmin.cn` and `garmin.com`
10
+ - [x] Auto refresh Ouath2 token
11
+ - [x] Oauth1,Oauth2 token import and export.
12
+ - [x] Download Activity, countActivities, getActivities, getActivity, getUserProfile, getUserSettings
13
+ - [x] Upload Activity, delete Activity
14
+ - [ ] Implementation of other methods, such as Badge,Workout,Gear etc
15
+ - [ ] Handle MFA
16
+ - [x] Handle Account locked
17
+ - [ ] Unit test
18
+ - [ ] Listeners
19
+
20
+ If something is not working, please check [https://connect.garmin.com/status/](https://connect.garmin.com/status/) first.
21
+
22
+ Currently, most of previous features are working, but some of Rest API are not added, such as `Gear`,`Workout`,`Badge` etc. So if you need these features, please add a PR.
23
+
24
+ All of above work inspired by [https://github.com/matin/garth](https://github.com/matin/garth). Many thanks.
25
+
26
+ ---
2
27
 
3
- # garmin-connect
4
28
  A powerful JavaScript library for connecting to Garmin Connect for sending and receiving health and workout data. It comes with some predefined methods to get and set different kinds of data for your Garmin account, but also have the possibility to make [custom requests](#custom-requests) `GET`, `POST` and `PUT` are currently supported. This makes it easy to implement whatever may be missing to suite your needs.
5
29
 
6
30
  ## Prerequisites
31
+
7
32
  This library will require you to add a configuration file to your project root called `garmin.config.json` containing your username and password for the Garmin Connect service.
33
+
8
34
  ```json
9
35
  {
10
- "username": "my.email@example.com",
11
- "password": "MySecretPassword"
36
+ "username": "my.email@example.com",
37
+ "password": "MySecretPassword"
12
38
  }
13
39
  ```
40
+
14
41
  ## How to install
42
+
15
43
  ```shell
16
44
  $ npm install garmin-connect
17
45
  ```
46
+
18
47
  ## How to use
48
+
19
49
  ```js
20
50
  const { GarminConnect } = require('garmin-connect');
21
51
  // Create a new Garmin Connect Client
22
- const GCClient = new GarminConnect();
52
+ const GCClient = new GarminConnect({
53
+ username: 'my.email@example.com',
54
+ password: 'MySecretPassword'
55
+ });
23
56
  // Uses credentials from garmin.config.json or uses supplied params
24
- await GCClient.login('my.email@example.com', 'MySecretPassword');
25
- const userInfo = await GCClient.getUserInfo();
57
+ await GCClient.login();
58
+ const userProfile = await GCClient.getUserProfile();
59
+ ```
60
+
61
+ Now you can check `userProfile.userName` (userName is your email address) to verify that your login was successful.
62
+
63
+ ## Reusing your session(since v1.6.0)
64
+
65
+ ### Save token to file and reuse it.
66
+
67
+ ```js
68
+ GCClient.saveTokenToFile('/path/to/save/tokens');
69
+ ```
70
+
71
+ Result:
72
+
73
+ ```bash
74
+ $ ls /path/to/save/tokens
75
+ oauth1_token.json oauth2_token.json
76
+ ```
77
+
78
+ Reuse token:
79
+
80
+ ```js
81
+ GCClient.loadTokenByFile('/path/to/save/tokens');
82
+ ```
83
+
84
+ ### Or just save your token to db or other storage.
85
+
86
+ ```js
87
+ const oauth1 = GCClient.client.oauth1Token;
88
+ const oauth2 = GCClient.client.oauth2Token;
89
+ // save to db or other storage
90
+ ...
91
+ ```
92
+
93
+ Reuse token:
94
+
95
+ ```js
96
+ GCClient.loadToken(oauth1, oauth2);
26
97
  ```
27
- Now you can check `userInfo.emailAddress` to verify that your login was successful.
28
98
 
29
- ## Reusing your session
99
+ ## Reusing your session(depreated)
100
+
30
101
  This is an experimental feature and might not yet provide full stability.
31
102
 
32
- After a successful login the ```sessionJson``` getter and setter can be used to export and restore your session.
103
+ After a successful login the `sessionJson` getter and setter can be used to export and restore your session.
104
+
33
105
  ```js
34
106
  // Exporting the session
35
107
  const session = GCClient.sessionJson;
@@ -38,11 +110,13 @@ const session = GCClient.sessionJson;
38
110
  // This will throw an error if the stored session cannot be reused
39
111
  GCClient.restore(session);
40
112
  ```
113
+
41
114
  The exported session should be serializable and can be stored as a JSON string.
42
115
 
43
- A stored session can only be reused once and will need to be stored after each request. This can be done by attaching some storage to the ```sessionChange``` event.
116
+ A stored session can only be reused once and will need to be stored after each request. This can be done by attaching some storage to the `sessionChange` event.
117
+
44
118
  ```js
45
- GCClient.onSessionChange(session => {
119
+ GCClient.onSessionChange((session) => {
46
120
  /*
47
121
  Your choice of storage here
48
122
  node-persist will probably work in most cases
@@ -51,150 +125,250 @@ GCClient.onSessionChange(session => {
51
125
  ```
52
126
 
53
127
  ### Login fallback
54
- To make sure to use a stored session if possible, but fallback to regular login, one can use the ```restoreOrLogin``` method.
55
- The arguments ```username``` and ```password``` are both optional and the regular ```.login()``` will be
128
+
129
+ To make sure to use a stored session if possible, but fallback to regular login, one can use the `restoreOrLogin` method.
130
+ The arguments `username` and `password` are both optional and the regular `.login()` will be
56
131
  called if session restore fails.
132
+
57
133
  ```js
58
134
  await GCClient.restoreOrLogin(session, username, password);
59
135
  ```
60
136
 
61
137
  ## Events
62
138
 
63
- * ```sessionChange``` will trigger on a change in the current ```sessionJson```
139
+ - `sessionChange` will trigger on a change in the current `sessionJson`
140
+
141
+ To attach a listener to an event, use the `.on()` method.
64
142
 
65
- To attach a listener to an event, use the ```.on()``` method.
66
143
  ```js
67
- GCClient.on('sessionChange', session => console.log(session));
144
+ GCClient.on('sessionChange', (session) => console.log(session));
68
145
  ```
146
+
69
147
  There's currently no way of removing listeners.
70
148
 
71
149
  ## Reading data
150
+
72
151
  ### User info
152
+
73
153
  Receive basic user information
154
+
74
155
  ```js
75
156
  GCClient.getUserInfo();
76
157
  ```
158
+
77
159
  ### Social Profile
160
+
78
161
  Receive social user information
162
+
79
163
  ```js
80
164
  GCClient.getSocialProfile();
81
165
  ```
166
+
82
167
  ### Social Connections
168
+
83
169
  Get a list of all social connections
170
+
84
171
  ```js
85
172
  GCClient.getSocialConnections();
86
173
  ```
174
+
87
175
  ### Device info
176
+
88
177
  Get a list of all registered devices including model numbers and firmware versions.
178
+
89
179
  ```js
90
180
  GCClient.getDeviceInfo();
91
181
  ```
182
+
92
183
  ### Activities
93
- To get a list of recent activities, use the `getActivities` method. This function takes two arguments, *start* and *limit*, which is used for pagination. Both are optional and will default to whatever Garmin Connect is using. To be sure to get all activities, use this correctly.
184
+
185
+ To get a list of recent activities, use the `getActivities` method. This function takes two arguments, _start_ and _limit_, which is used for pagination. Both are optional and will default to whatever Garmin Connect is using. To be sure to get all activities, use this correctly.
186
+
94
187
  ```js
95
188
  // Get a list of default length with most recent activities
96
189
  GCClient.getActivities();
97
190
  // Get activities 10 through 15. (start 10, limit 5)
98
191
  GCClient.getActivities(10, 5);
99
192
  ```
193
+
100
194
  ### Activity details
101
- Use the activityId to get details about that specific activity.
195
+
196
+ Use the activityId to get activity details.
197
+
198
+ ```js
199
+ // search for the activity (optional)
200
+ const [activity] = await GCClient.getActivities(0, 1);
201
+ // get the activity details
202
+ const activityDetails = await GCClient.getActivityDetails(activity.activityId);
203
+ ```
204
+
205
+ ### Activity metrics details
206
+
207
+ Use the activityId to get metrics details about that specific activity.
208
+
102
209
  ```js
103
210
  const activities = await GCClient.getActivities(0, 1);
104
211
  const id = activities[0].activityId;
105
- // Use the id as a parameter
212
+ // Use the id as a parameter
106
213
  GCClient.getActivity({ activityId: id });
107
214
  // Or the whole activity response
108
215
  GCClient.getActivity(activities[0]);
109
216
  ```
217
+
110
218
  ### Activities
111
- To get a list of activities in your news feed, use the `getNewsFeed` method. This function takes two arguments, *start* and *limit*, which is used for pagination. Both are optional and will default to whatever Garmin Connect is using. To be sure to get all activities, use this correctly.
219
+
220
+ To get a list of activities in your news feed, use the `getNewsFeed` method. This function takes two arguments, _start_ and _limit_, which is used for pagination. Both are optional and will default to whatever Garmin Connect is using. To be sure to get all activities, use this correctly.
221
+
112
222
  ```js
113
223
  // Get the news feed with a default length with most recent activities
114
224
  GCClient.getNewsFeed();
115
225
  // Get activities in feed, 10 through 15. (start 10, limit 5)
116
226
  GCClient.getNewsFeed(10, 5);
117
227
  ```
228
+
118
229
  ### Download original activity data
230
+
119
231
  Use the activityId to download the original activity data. Usually this is supplied as a .zip file.
232
+
120
233
  ```js
121
234
  const [activity] = await GCClient.getActivities(0, 1);
122
235
  // Directory path is optional and defaults to the current working directory.
123
236
  // Downloads filename will be supplied by Garmin.
124
237
  GCClient.downloadOriginalActivityData(activity, './some/path/that/exists');
125
238
  ```
239
+
126
240
  ### Upload activity file
241
+
127
242
  Uploads an activity file as a new Activity. The file can be a `gpx`, `tcx`, or `fit` file. If the activity already exists, the result will have a status code of 409.
128
243
  Upload fixed in 1.4.4, Garmin changed the upload api, the response `detailedImportResult` doesn't contain the new activityId.
129
- ```js
130
244
 
245
+ ```js
131
246
  const upload = await GCClient.uploadActivity('./some/path/to/file.fit');
132
247
  // not working
133
248
  const activityId = upload.detailedImportResult.successes[0].internalId;
134
-
135
249
  const uploadId = upload.detailedImportResult.uploadId;
136
250
  ```
251
+
252
+ ### Upload activity image
253
+
254
+ Uploads an image to activity
255
+
256
+ ```js
257
+ const [latestActivty] = await GCClient.getActivities(0, 1);
258
+
259
+ const upload = await GCClient.uploadImage(
260
+ latestActivty,
261
+ './some/path/to/file.jpg'
262
+ );
263
+ ```
264
+
265
+ ### Delete activity image
266
+
267
+ Delete an image from activity
268
+
269
+ ```js
270
+ const [activity] = await GCClient.getActivities(0, 1);
271
+ const activityDetails = await GCClient.getActivityDetails(activity.activityId);
272
+
273
+ await GCClient.deleteImage(
274
+ activity,
275
+ activityDetails.metadataDTO.activityImages[0].imageId
276
+ );
277
+ ```
278
+
137
279
  ### Step count
280
+
138
281
  Get timestamp and number of steps taken for a specific date.
282
+
139
283
  ```js
140
284
  // This will default to today if no date is supplied
141
285
  const steps = await GCClient.getSteps(new Date('2020-03-24'));
142
286
  ```
287
+
143
288
  ### Heart rate
289
+
144
290
  Get heart rate for a specific date.
291
+
145
292
  ```js
146
293
  // This will default to today if no date is supplied
147
294
  const heartRate = await GCClient.getHeartRate(new Date('2020-03-24'));
148
295
  ```
296
+
149
297
  ### Sleep summary
298
+
150
299
  Get the summary of how well you've slept for a specific date.
300
+
151
301
  ```js
152
302
  // This will default to today if no date is supplied
153
303
  const sleep = await GCClient.getSleep(new Date('2020-03-24'));
154
304
  ```
305
+
155
306
  ### Detailed sleep data
307
+
156
308
  Get the details of your sleep for a specific date.
309
+
157
310
  ```js
158
311
  // This will default to today if no date is supplied
159
312
  const detailedSleep = await GCClient.getSleepData(new Date('2020-03-24'));
160
313
  ```
314
+
161
315
  ## Modifying data
316
+
162
317
  ### Update activity
318
+
163
319
  ```js
164
320
  const activities = await GCClient.getActivities(0, 1);
165
321
  const activity = activities[0];
166
322
  activity['activityName'] = 'The Updated Name';
167
323
  await GCClient.updateActivity(activity);
168
324
  ```
325
+
169
326
  ### Delete an activity
327
+
170
328
  Deletes an activty.
329
+
171
330
  ```js
172
331
  const activities = await GCClient.getActivities(0, 1);
173
332
  const activity = activities[0];
174
333
  await GCClient.deleteActivity(activity);
175
334
  ```
335
+
176
336
  ### Add weight
177
- To add a new weight measurement, use `setBodyWeight`. Here you specify your weight in *kg*.
337
+
338
+ To add a new weight measurement, use `setBodyWeight`. Here you specify your weight in _kg_.
339
+
178
340
  ```js
179
341
  GCClient.setBodyWeight(81.4);
180
342
  ```
343
+
181
344
  Will set your current weight to 81.4kg. The unit used might be tied to your preferred weight settings.
345
+
182
346
  ### Add workout
347
+
183
348
  To add a custom workout, use the `addWorkout` or more specifically `addRunningWorkout`.
349
+
184
350
  ```js
185
351
  GCClient.addRunningWorkout('My 5k run', 5000, 'Some description');
186
352
  ```
353
+
187
354
  Will add a running workout of 5km called 'My 5k run' and return a JSON object representing the saved workout.
355
+
188
356
  ### Schedule workout
357
+
189
358
  To add a workout to your calendar, first find your workout and then add it to a specific date.
359
+
190
360
  ```js
191
361
  const workouts = await GCClient.getWorkouts();
192
362
  const id = workouts[0].workoutId;
193
363
  GCClient.scheduleWorkout({ workoutId: id }, new Date('2020-03-24'));
194
364
  ```
365
+
195
366
  This will add the workout to a specific date in your calendar and make it show up automatically if you're using any of the Garmin watches.
367
+
196
368
  ### Delete workout
369
+
197
370
  Deleting a workout is very similar to [scheduling](#schedule-workout) one.
371
+
198
372
  ```js
199
373
  const workouts = await GCClient.getWorkouts();
200
374
  const id = workouts[0].workoutId;
@@ -202,35 +376,51 @@ GCClient.deleteWorkout({ workoutId: id });
202
376
  ```
203
377
 
204
378
  ## Custom requests
379
+
205
380
  This library will handle custom requests to your active Garmin Connect session. There are a lot of different url's that is used, which means that this library probably wont cover them all. By using the network analyze tool you can find url's that are used by Garmin Connect to fetch data.
206
381
 
207
382
  Let's assume I found a `GET` requests to the following url:
383
+
208
384
  ```
209
385
  https://connect.garmin.com/modern/proxy/wellness-service/wellness/dailyHeartRate/22f5f84c-de9d-4ad6-97f2-201097b3b983?date=2020-03-24
210
386
  ```
387
+
211
388
  The request can be sent using `GCClient` by running
389
+
212
390
  ```js
213
391
  // You can get your displayName by using the getUserInfo method;
214
392
  const displayName = '22f5f84c-de9d-4ad6-97f2-201097b3b983';
215
- const url = 'https://connect.garmin.com/modern/proxy/wellness-service/wellness/dailyHeartRate/';
393
+ const url =
394
+ 'https://connect.garmin.com/modern/proxy/wellness-service/wellness/dailyHeartRate/';
216
395
  const dateString = '2020-03-24';
217
396
  GCClient.get(url + displayName, { date: dateString });
218
397
  ```
398
+
219
399
  and will net you the same result as using the provided way
400
+
220
401
  ```js
221
402
  GCClient.getHeartRate();
222
403
  ```
404
+
223
405
  Notice how the client will keep track of the url's, your user information as well as keeping the session alive.
406
+
224
407
  ## Limitations
408
+
409
+ Many responses from Garmin Connect are missing type definitions and defaults to `unknown`. Feel free to add types by opening a pull request.
410
+
225
411
  For now, this library only supports the following:
226
- * Get user info
227
- * Get social user info
228
- * Get heart rate
229
- * Set body weight
230
- * Get list of workouts
231
- * Add new workouts
232
- * Add workouts to you calendar
233
- * Remove previously added workouts
234
- * Get list of activities
235
- * Get details about one specific activity
236
- * Get the step count
412
+
413
+ - Get user info
414
+ - Get social user info
415
+ - Get heart rate
416
+ - Set body weight
417
+ - Get list of workouts
418
+ - Add new workouts
419
+ - Add workouts to you calendar
420
+ - Remove previously added workouts
421
+ - Get list of activities
422
+ - Get details about one specific activity
423
+ - Get the step count
424
+ - Get earned badges
425
+ - Get available badges
426
+ - Get details about one specific badge
@@ -0,0 +1,22 @@
1
+ import { Options, Response } from 'cloudscraper';
2
+ import { Headers } from 'request';
3
+ import { CookieJar as ToughCookieJar } from 'tough-cookie';
4
+ export default class CFClient {
5
+ private cookies;
6
+ private headers;
7
+ constructor(headers: Headers);
8
+ serializeCookies(): ToughCookieJar.Serialized | undefined;
9
+ importCookies(cookies: ToughCookieJar.Serialized): void;
10
+ scraper(options: Options): Promise<Response>;
11
+ /**
12
+ * @param {string} downloadDir
13
+ * @param {string} url
14
+ * @param {*} data
15
+ */
16
+ downloadBlob(downloadDir: string | undefined, url: string, data?: any): Promise<unknown>;
17
+ get<T>(url: string, data?: any): Promise<T>;
18
+ post<T>(url: string, data: any): Promise<T>;
19
+ delete<T>(url: string): Promise<T>;
20
+ postJson<T>(url: string, data: any, headers: Headers): Promise<T>;
21
+ putJson<T>(url: string, data: any): Promise<T>;
22
+ }