From c60c40aa0d6efba4f685024728d272eec4884981 Mon Sep 17 00:00:00 2001 From: Wes Schlenker <49787065+wesleyschlenker@users.noreply.github.com> Date: Thu, 22 Jan 2026 12:11:31 -0500 Subject: [PATCH 01/11] test: implement and enhance listZones() test for activities - Convert the existing test for listZones() from a skipped test to an active one. - Mock the API response for heart rate and power zones. - Add assertions to verify the structure and values of the returned zones, including distribution buckets. - Ensure the test checks both power and heartrate zones for expected properties. --- test/activities.js | 104 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 94 insertions(+), 10 deletions(-) diff --git a/test/activities.js b/test/activities.js index 98aff4e..86301bb 100644 --- a/test/activities.js +++ b/test/activities.js @@ -149,18 +149,102 @@ describe('activities_test', function () { }) }) - // TODO can't test b/c this requires premium account describe('#listZones()', function () { - xit('should list heart rate and power zones relating to activity', function (done) { - strava.activities.listZones({ id: testActivity.id }, function (err, payload) { - if (!err) { - assert.ok(Array.isArray(payload)) - } else { - console.log(err) - } + it('should list heart rate and power zones relating to activity', async function () { + // Mock the list zones API call + nock('https://www.strava.com') + .get('/api/v3/activities/' + testActivity.id + '/zones') + .reply(200, [ + { + score: 82, + distribution_buckets: [ + { + max: 0, + min: 0, + time: 1498 + }, + { + max: 50, + min: 0, + time: 62 + }, + { + max: 100, + min: 50, + time: 169 + } + ], + type: 'power', + sensor_based: true, + points: 250, + custom_zones: false, + max: 450 + }, + { + score: 75, + distribution_buckets: [ + { + max: 0, + min: 0, + time: 200 + }, + { + max: 100, + min: 0, + time: 150 + }, + { + max: 120, + min: 100, + time: 300 + } + ], + type: 'heartrate', + sensor_based: false, + points: 180, + custom_zones: true, + max: 200 + } + ]) - done() - }) + const payload = await strava.activities.listZones({ id: testActivity.id }) + assert.ok(Array.isArray(payload)) + assert.strictEqual(payload.length, 2) + + // Verify power zone + const powerZone = payload.find(zone => zone.type === 'power') + assert.ok(powerZone) + assert.strictEqual(typeof powerZone.score, 'number') + assert.strictEqual(powerZone.score, 82) + assert.ok(Array.isArray(powerZone.distribution_buckets)) + assert.strictEqual(powerZone.distribution_buckets.length, 3) + assert.strictEqual(powerZone.type, 'power') + assert.strictEqual(powerZone.sensor_based, true) + assert.strictEqual(typeof powerZone.points, 'number') + assert.strictEqual(powerZone.points, 250) + assert.strictEqual(powerZone.custom_zones, false) + assert.strictEqual(typeof powerZone.max, 'number') + assert.strictEqual(powerZone.max, 450) + + // Verify distribution bucket structure + const bucket = powerZone.distribution_buckets[0] + assert.strictEqual(typeof bucket.min, 'number') + assert.strictEqual(typeof bucket.max, 'number') + assert.strictEqual(typeof bucket.time, 'number') + + // Verify heartrate zone + const heartrateZone = payload.find(zone => zone.type === 'heartrate') + assert.ok(heartrateZone) + assert.strictEqual(typeof heartrateZone.score, 'number') + assert.strictEqual(heartrateZone.score, 75) + assert.ok(Array.isArray(heartrateZone.distribution_buckets)) + assert.strictEqual(heartrateZone.type, 'heartrate') + assert.strictEqual(heartrateZone.sensor_based, false) + assert.strictEqual(typeof heartrateZone.points, 'number') + assert.strictEqual(heartrateZone.points, 180) + assert.strictEqual(heartrateZone.custom_zones, true) + assert.strictEqual(typeof heartrateZone.max, 'number') + assert.strictEqual(heartrateZone.max, 200) }) }) From 1648be8f55c8eaeae8367d23ddab8409f92794c2 Mon Sep 17 00:00:00 2001 From: Wes Schlenker <49787065+wesleyschlenker@users.noreply.github.com> Date: Thu, 22 Jan 2026 12:31:23 -0500 Subject: [PATCH 02/11] refactor: remove listPhotos method This method doesn't actually exist in the library, only the typescript definitions and a skipped test exist. There is also no corollary in the strava api documentation. - Deleted the listPhotos method from the ActivitiesRoutes interface in index.d.ts. - Removed the associated test case for listPhotos from activities.js, which was previously marked as skipped. --- index.d.ts | 1 - test/activities.js | 15 --------------- 2 files changed, 16 deletions(-) diff --git a/index.d.ts b/index.d.ts index d61ee78..77bdf57 100644 --- a/index.d.ts +++ b/index.d.ts @@ -291,7 +291,6 @@ export interface ActivitiesRoutes { listLaps(args: any, done?: Callback): Promise; listComments(args: any, done?: Callback): Promise; listKudos(args: any, done?: Callback): Promise; - listPhotos(args: any, done?: Callback): Promise; listRelated(args: any, done?: Callback): Promise; } diff --git a/test/activities.js b/test/activities.js index 86301bb..24eefab 100644 --- a/test/activities.js +++ b/test/activities.js @@ -292,19 +292,4 @@ describe('activities_test', function () { assert.ok(Array.isArray(payload)) }) }) - - // TODO check w/ strava dudes, this is returning undefined instead of an empty array (no photos) - describe('#listPhotos()', function () { - xit('should list photos relating to activity', function (done) { - strava.activities.listPhotos({ id: testActivity.id }, function (err, payload) { - if (!err) { - assert.ok(Array.isArray(payload)) - } else { - console.log(err) - } - - done() - }) - }) - }) }) From 3cdbfb2104797e500b0a75ad2b124f830b3ebf9e Mon Sep 17 00:00:00 2001 From: Wes Schlenker <49787065+wesleyschlenker@users.noreply.github.com> Date: Thu, 22 Jan 2026 12:33:37 -0500 Subject: [PATCH 03/11] refactor: clean up unmocked api calls in test helpers All tests are written and mocked! - Removed several functions from testsHelper that were designed to fetch sample data from the Strava API, including getSampleAthlete, getSampleActivity, getSampleClub, getSampleRoute, getSampleGear, getSampleSegmentEffort, getSampleSegment, and getSampleRunningRace. - This cleanup reduces code complexity and focuses on essential helper functions. --- test/_helper.js | 83 ------------------------------------------------- 1 file changed, 83 deletions(-) diff --git a/test/_helper.js b/test/_helper.js index c3ad5f7..0a7df82 100644 --- a/test/_helper.js +++ b/test/_helper.js @@ -16,87 +16,4 @@ testsHelper.cleanupAuth = function () { authenticator.purge() } -testsHelper.getSampleAthlete = async function () { - return await strava.athlete.get({}) -} - -testsHelper.getSampleActivity = function (done) { - strava.athlete.listActivities({ include_all_efforts: true }, function (err, payload) { - if (err) { return done(err) } - - if (!payload.length) { return done(new Error('Must have at least one activity posted to Strava to test with.')) } - - // If we find an activity with an achievement, there's a better chance - // that it contains a segment. - // This is necessary for getSampleSegment, which uses this function. - function hasAchievement (activity) { return activity.achievement_count > 1 } - - var withSegment = payload.filter(hasAchievement)[0] - - if (!withSegment) { return done(new Error('Must have at least one activity posted to Strava with a segment effort to test with.')) } - - return strava.activities.get({ id: withSegment.id, include_all_efforts: true }, done) - }) -} - -testsHelper.getSampleClub = function (done) { - strava.athlete.listClubs({}, function (err, payload) { - if (err) { return done(err) } - - if (!payload.length) { return done(new Error('Must have joined at least one club on Strava to test with.')) } - - done(err, payload[0]) - }) -} - -testsHelper.getSampleRoute = function (done) { - strava.athlete.listRoutes({}, function (err, payload) { - if (err) { return done(err) } - - if (!payload.length) { return done(new Error('Must have created at least one route on Strava to test with.')) } - - done(err, payload[0]) - }) -} - -testsHelper.getSampleGear = async function () { - const payload = await this.getSampleAthlete() - - var gear - - if (payload.bikes && payload.bikes.length) { - gear = payload.bikes[0] - } else if (payload.shoes) { - gear = payload.shoes[0] - } else { - throw new Error('Must post at least one bike or shoes to Strava to test with') - } - - return gear -} - -testsHelper.getSampleSegmentEffort = function (done) { - this.getSampleActivity(function (err, payload) { - if (err) { return done(err) } - - if (!payload.segment_efforts.length) { return done(new Error('Must have at least one segment effort posted to Strava to test with.')) } - - done(err, payload.segment_efforts[0]) - }) -} - -testsHelper.getSampleSegment = function (done) { - this.getSampleSegmentEffort(function (err, payload) { - if (err) { return done(err) } - - done(err, payload.segment) - }) -} - -testsHelper.getSampleRunningRace = function (done) { - strava.runningRaces.listRaces({ 'year': 2015 }, function (err, payload) { - done(err, payload[0]) - }) -} - module.exports = testsHelper From 81f829b968abc5d17cc2fbe78be930223fa9fbad Mon Sep 17 00:00:00 2001 From: Wes Schlenker <49787065+wesleyschlenker@users.noreply.github.com> Date: Thu, 22 Jan 2026 12:36:05 -0500 Subject: [PATCH 04/11] chore: bump version to 3.3.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bb88b72..730b745 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "strava-v3", - "version": "3.2.0", + "version": "3.3.0", "description": "Simple wrapper for Strava v3 API", "main": "index.js", "types": "index.d.ts", From 4415ff79f764f51ab06677fdd444e7a1a4b9584e Mon Sep 17 00:00:00 2001 From: Wes Schlenker <49787065+wesleyschlenker@users.noreply.github.com> Date: Thu, 22 Jan 2026 12:51:26 -0500 Subject: [PATCH 05/11] chore: remove unused CI configuration files for Drone and Travis --- .drone.yml | 20 -------------------- .travis.yml | 6 ------ 2 files changed, 26 deletions(-) delete mode 100644 .drone.yml delete mode 100644 .travis.yml diff --git a/.drone.yml b/.drone.yml deleted file mode 100644 index 5ca948e..0000000 --- a/.drone.yml +++ /dev/null @@ -1,20 +0,0 @@ ---- -kind: pipeline -type: docker - -steps: -- name: build - image: node:12 - commands: - - npm install -- name: unit-test - image: node:12 - commands: - - npm test -- name: promote_test - image: node:12 - commands: - - echo "Testing Promote" - when: - event: - - promote diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 6cebf47..0000000 --- a/.travis.yml +++ /dev/null @@ -1,6 +0,0 @@ -language: node_js -node_js: -- '8' -- '10' -- '12' -before_install: npm install -g grunt-cli From ece39a30e5f08db0ae5a8371aba4ce26c095f1c3 Mon Sep 17 00:00:00 2001 From: Wes Schlenker <49787065+wesleyschlenker@users.noreply.github.com> Date: Thu, 22 Jan 2026 12:54:09 -0500 Subject: [PATCH 06/11] docs: update README to reflect test and CI updates - Replaced Travis CI badge with GitHub Actions badge. - Clarified test instructions, emphasizing that all tests now use `nock` to mock the Strava API. - Enhanced the description of the test suite's functionality and requirements. - Updated maintainer information to include Wesley Schlenker. --- README.md | 58 ++++++++++++++++++------------------------------------- 1 file changed, 19 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 335a11a..e7abfa8 100644 --- a/README.md +++ b/README.md @@ -3,14 +3,14 @@ [![NPM Version][npm-image]][npm-url] [![NPM Downloads][downloads-image]][downloads-url] -[![Build Status][travis-image]][travis-url] +[![Test Suite][github-actions-image]][github-actions-url] [npm-image]: https://img.shields.io/npm/v/strava-v3.svg?style=flat [npm-url]: https://npmjs.org/package/strava-v3 [downloads-image]: https://img.shields.io/npm/dm/strava-v3.svg?style=flat [downloads-url]: https://npmjs.org/package/strava-v3 -[travis-image]: https://travis-ci.org/UnbounDev/node-strava-v3.svg?branch=master&style=flat -[travis-url]: https://travis-ci.org/UnbounDev/node-strava-v3 +[github-actions-image]: https://github.com/node-strava/node-strava-v3/actions/workflows/on-pull-request.yml/badge.svg +[github-actions-url]: https://github.com/node-strava/node-strava-v3/actions/workflows/on-pull-request.yml ### Status @@ -161,7 +161,7 @@ strava = new stravaApi.client(access_token); const payload = await strava.athlete.get({}) ``` -Less conveniently, you can also explictly pass an `access_token` to API calls: +Less conveniently, you can also explicitly pass an `access_token` to API calls: Example usage: @@ -392,48 +392,29 @@ It will both lint and run tests on API endpoints. ### Running the tests -Many unit tests now use nock to mock the Strava API and can run without any real credentials. -However, some integration-style tests still expect a real token and account data. +All tests use `nock` to mock the Strava API and can run without any real credentials or network access. -If you want to run the full test suite (including integration tests), you'll need to supply `data/strava_config` with an `access_token` that -has both private read and write permissions. Look in `./scripts` for a tool -to help generate this token. +Simply run: -* Make sure you've filled out all the fields in `data/strava_config`. -* Use `strava.oauth.getRequestAccessURL({scope:"view_private,write"})` to generate the request url and query it via your browser. -* Strava will prompt you (the user) to allow access, say yes and you'll be sent to your Authorization Redirection URI - the parameter `code` will be included in the redirection url. -* Exchange the `code` for a new `access_token`: - -```js -// access_token is at payload.access_token -const payload = await strava.oauth.getToken(authorizationCode) +```bash +yarn test ``` -Finally, the test suite has some expectations about the Strava account that it -connects for the tests to pass. The following should be true about the Strava -data in the account: - - * Must have at least one activity posted on Strava - * Must have joined at least one club - * Must have added at least one piece of gear (bike or shoes) - * Must have created at least one route - * Most recent activity with an achievement should also contain a segment -(Parts of the test suite already use `nock` to mock the API. Contributions to convert remaining integration tests to mocks are welcome.) +The test suite will: -You're done! Paste the new `access_token` to `data/strava_config` and run the full tests: - -`yarn test`. +- Run ESLint on all JavaScript files +- Execute all unit tests using mocked API responses ### How the tests work -- Tests use Mocha and Should.js. -- HTTP interaction is performed with Axios; tests that mock HTTP use `nock`. - -Using the provided `access_token` tests will access each endpoint individually: +- Tests use Mocha and Node.js's built-in `assert` module +- HTTP interaction is performed with Axios; all tests mock HTTP requests using `nock` -* (For all `GET` endpoints) checks to ensure the correct type has been returned from the Strava. -* (For `PUT` in `athlete.update`) changes some athlete properties, then changes them back. -* (For `POST/PUT/DELETE` in `activities.create/update/delete`) first creates an activity, runs some operations on it, then deletes it. +The test suite validates: +* All `GET` endpoints return the correct data structure +* All `POST`/`PUT`/`DELETE` endpoints handle requests and responses correctly +* Error handling works as expected +* Rate limiting functionality is properly tested ## Resources @@ -444,5 +425,4 @@ Using the provided `access_token` tests will access each endpoint individually: Authored by Austin Brown (http://austinjamesbrown.com/). -Currently Maintained by Mark Stosberg - +Currently Maintained by Mark Stosberg and Wesley Schlenker From 85a5dffae77b30781fe306af25aa9f8862c9875a Mon Sep 17 00:00:00 2001 From: Wes Schlenker <49787065+wesleyschlenker@users.noreply.github.com> Date: Thu, 22 Jan 2026 12:59:10 -0500 Subject: [PATCH 07/11] docs: markdownlint README.md --- README.md | 91 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index e7abfa8..f036d32 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ -# strava-v3: Simple Node wrapper for Strava's v3 API +# strava-v3 + +A simple Node.js wrapper for Strava's v3 API [![NPM Version][npm-image]][npm-url] [![NPM Downloads][downloads-image]][downloads-url] @@ -12,8 +14,6 @@ [github-actions-image]: https://github.com/node-strava/node-strava-v3/actions/workflows/on-pull-request.yml/badge.svg [github-actions-url]: https://github.com/node-strava/node-strava-v3/actions/workflows/on-pull-request.yml -### Status - Supports many but not all Strava API endpoints: * `oauth` @@ -36,12 +36,16 @@ npm install strava-v3 ``` ## Import syntax + Importing only the library: -``` + +```js import strava from 'strava-v3'; ``` + Importing both the library as well as interfaces: -``` + +```js import { default as strava, Strava } from 'strava-v3'; ``` @@ -97,15 +101,15 @@ strava.config({ "redirect_uri" : "Your apps Authorization Redirection URI (Required for oauth)", }); ``` + ##### Environment variables You may alternatively supply the values via environment variables named following the convention `STRAVA_`, so -- `STRAVA_ACCESS_TOKEN` = `access_token` -- `STRAVA_CLIENT_ID` = `client_id` -- `STRAVA_CLIENT_SECRET` = `client_secret` -- `STRAVA_REDIRECT_URI` = `redirect_uri` - +* `STRAVA_ACCESS_TOKEN` = `access_token` +* `STRAVA_CLIENT_ID` = `client_id` +* `STRAVA_CLIENT_SECRET` = `client_secret` +* `STRAVA_REDIRECT_URI` = `redirect_uri` #### Config File (Deprecated) @@ -185,6 +189,7 @@ const payload = await strava.athlete.listFollowers({ ``` ### Uploading files + To upload a file you'll have to pass in the `data_type` as specified in Strava's API reference as well as a string `file` designating the `/`. If you want to get updates on the status of your upload pass in `statusCallback` along with the rest of your `args` - the wrapper will check on the upload once a second until complete. Example usage: @@ -202,6 +207,7 @@ const payload = await strava.uploads.post({ ``` ### Rate limits + According to Strava's API each response contains information about rate limits. For more details see: [Rate Limits](https://developers.strava.com/docs/rate-limits/) @@ -250,6 +256,7 @@ strava.athlete.get({'access_token':'abcde'},function(err,payload,limits) { */ }); ``` + ### Supported API Endpoints To used the Promise-based API, do not provide a callback. A promise will be returned. @@ -301,41 +308,41 @@ See Strava API docs for returned data structures. These methods Authenticate with a Client ID and Client Secret. Since they don't use OAuth, they are not available on the `client` object. - * `strava.pushSubscriptions.list({},done)` - * `strava.pushSubscriptions.create({callback_url:...},done)` - * We set 'object\_type to "activity" and "aspect\_type" to "create" for you. - * `strava.pushSubscriptions.delete({id:...},done)` +* `strava.pushSubscriptions.list({},done)` +* `strava.pushSubscriptions.create({callback_url:...},done)` +* We set 'object\_type to "activity" and "aspect\_type" to "create" for you. +* `strava.pushSubscriptions.delete({id:...},done)` #### Running Races - * `strava.runningRaces.get(args,done)` - * `strava.runningRaces.listRaces(args,done)` +* `strava.runningRaces.get(args,done)` +* `strava.runningRaces.listRaces(args,done)` #### Routes - * `strava.routes.getFile({ id: routeId, file_type: 'gpx' },done)` *file_type may also be 'tcx'* - * `strava.routes.get(args,done)` +* `strava.routes.getFile({ id: routeId, file_type: 'gpx' },done)` *file_type may also be 'tcx'* +* `strava.routes.get(args,done)` #### Segments - * `strava.segments.get(args,done)` - * `strava.segments.listStarred(args,done)` - * `strava.segments.listEfforts(args,done)` - * `strava.segments.explore(args,done)` *Expects arg `bounds` as a comma separated string, for two points describing a rectangular boundary for the search: `"southwest corner latitutde, southwest corner longitude, northeast corner latitude, northeast corner longitude"`*. +* `strava.segments.get(args,done)` +* `strava.segments.listStarred(args,done)` +* `strava.segments.listEfforts(args,done)` +* `strava.segments.explore(args,done)` *Expects arg `bounds` as a comma separated string, for two points describing a rectangular boundary for the search: `"southwest corner latitude, southwest corner longitude, northeast corner latitude, northeast corner longitude"`*. #### Segment Efforts - * `strava.segmentEfforts.get(args,done)` +* `strava.segmentEfforts.get(args,done)` #### Streams - * `strava.streams.activity(args,done)` - * `strava.streams.effort(args,done)` - * `strava.streams.segment(args,done)` +* `strava.streams.activity(args,done)` +* `strava.streams.effort(args,done)` +* `strava.streams.segment(args,done)` #### Uploads - * `strava.uploads.post(args,done)` +* `strava.uploads.post(args,done)` ## Error Handling @@ -369,22 +376,21 @@ Example error checking: The `StatusCodeError` object includes extra properties to help with debugging: - - `name` is always `StatusCodeError` - - `statusCode` contains the HTTP status code - - `message` contains the response's status message and additional error details - - `data` contains the body of the response, which can be useful for debugging - - `options` contains the options used in the request - - `response` contains the response object +* `name` is always `StatusCodeError` +* `statusCode` contains the HTTP status code +* `message` contains the response's status message and additional error details +* `data` contains the body of the response, which can be useful for debugging +* `options` contains the options used in the request +* `response` contains the response object The `RequestError` object is used for errors that occur due to technical issues, such as no response being received or request setup issues, and includes the following properties: -- `name` is always `RequestError` -- `message` contains the error message -- `options` contains the options used in the request +* `name` is always `RequestError` +* `message` contains the error message +* `options` contains the options used in the request This update maintains feature parity with the previous implementation of `request-promise` while using the Axios HTTP client under the hood. - ## Development This package includes a full test suite runnable via `yarn test`. @@ -402,15 +408,16 @@ yarn test The test suite will: -- Run ESLint on all JavaScript files -- Execute all unit tests using mocked API responses +* Run ESLint on all JavaScript files +* Execute all unit tests using mocked API responses ### How the tests work -- Tests use Mocha and Node.js's built-in `assert` module -- HTTP interaction is performed with Axios; all tests mock HTTP requests using `nock` +* Tests use Mocha and Node.js's built-in `assert` module +* HTTP interaction is performed with Axios; all tests mock HTTP requests using `nock` The test suite validates: + * All `GET` endpoints return the correct data structure * All `POST`/`PUT`/`DELETE` endpoints handle requests and responses correctly * Error handling works as expected @@ -423,6 +430,6 @@ The test suite validates: ## Author and Maintainer -Authored by Austin Brown (http://austinjamesbrown.com/). +Authored by Austin Brown (). Currently Maintained by Mark Stosberg and Wesley Schlenker From 2189eb08053e59e86c783fee55e83c6a5d7ea828 Mon Sep 17 00:00:00 2001 From: Wes Schlenker <49787065+wesleyschlenker@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:31:22 -0500 Subject: [PATCH 08/11] fix: update TypeScript definitions and README - Added `starSegment` method to `SegmentsRoutes` interface in index.d.ts. - Introduced `route` method to `StreamsRoutes` interface in index.d.ts. - Removed references to `running_races` from README.md. - Updated README.md --- README.md | 8 ++------ index.d.ts | 10 ++-------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index f036d32..5db9ec1 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,6 @@ Supports many but not all Strava API endpoints: * `activities` * `clubs` * `gear` -* `running_races` * `routes` * `segments` * `segment_efforts` @@ -313,11 +312,6 @@ use OAuth, they are not available on the `client` object. * We set 'object\_type to "activity" and "aspect\_type" to "create" for you. * `strava.pushSubscriptions.delete({id:...},done)` -#### Running Races - -* `strava.runningRaces.get(args,done)` -* `strava.runningRaces.listRaces(args,done)` - #### Routes * `strava.routes.getFile({ id: routeId, file_type: 'gpx' },done)` *file_type may also be 'tcx'* @@ -329,6 +323,7 @@ use OAuth, they are not available on the `client` object. * `strava.segments.listStarred(args,done)` * `strava.segments.listEfforts(args,done)` * `strava.segments.explore(args,done)` *Expects arg `bounds` as a comma separated string, for two points describing a rectangular boundary for the search: `"southwest corner latitude, southwest corner longitude, northeast corner latitude, northeast corner longitude"`*. +* `strava.segments.starSegment(args,done)` #### Segment Efforts @@ -339,6 +334,7 @@ use OAuth, they are not available on the `client` object. * `strava.streams.activity(args,done)` * `strava.streams.effort(args,done)` * `strava.streams.segment(args,done)` +* `strava.streams.route(args,done)` #### Uploads diff --git a/index.d.ts b/index.d.ts index 77bdf57..535d9c6 100644 --- a/index.d.ts +++ b/index.d.ts @@ -67,8 +67,8 @@ export interface UploadResponse { export interface SegmentsRoutes { get(args: any, done?: Callback): Promise; listStarred(args: any, done?: Callback): Promise; + starSegment(args: any, done?: Callback): Promise; listEfforts(args: any, done?: Callback): Promise; - listLeaderboard(args: any, done?: Callback): Promise; explore(args: any, done?: Callback): Promise; } @@ -80,6 +80,7 @@ export interface StreamsRoutes { activity(args: any, done?: Callback): Promise; effort(args: any, done?: Callback): Promise; segment(args: any, done?: Callback): Promise; + route(args: any, done?: Callback): Promise; } export interface RoutesRoutes { @@ -107,11 +108,7 @@ export interface ClubsRoutes { args: ClubsRoutesListArgs, done?: Callback ): Promise; - listAnnouncements(args: ClubsRoutesListArgs, done?: Callback): Promise; - listEvents(args: ClubsRoutesListArgs, done?: Callback): Promise; listAdmins(args: ClubsRoutesListArgs, done?: Callback): Promise; - joinClub(args: ClubsRoutesListArgs, done?: Callback): Promise; - leaveClub(args: ClubsRoutesListArgs, done?: Callback): Promise; } export interface ClubsRoutesArgs extends BaseArgs { @@ -140,7 +137,6 @@ export interface ClubActivity { } export interface AthletesRoutes { - get(args: AthleteRouteArgs, done?: Callback): Promise; stats(args: any, done?: Callback): Promise; } @@ -286,12 +282,10 @@ export interface ActivitiesRoutes { get(args: any, done?: Callback): Promise; create(args: any, done?: Callback): Promise; update(args: any, done?: Callback): Promise; - listFriends(args: any, done?: Callback): Promise; listZones(args: any, done?: Callback): Promise; listLaps(args: any, done?: Callback): Promise; listComments(args: any, done?: Callback): Promise; listKudos(args: any, done?: Callback): Promise; - listRelated(args: any, done?: Callback): Promise; } export interface AthleteRoutes { From 5f6b6b4329ba141aa2bd4d4fafa5271526397136 Mon Sep 17 00:00:00 2001 From: Wes Schlenker <49787065+wesleyschlenker@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:40:22 -0500 Subject: [PATCH 09/11] docs: update README example to use listActivities method listFollowers doesn't exist --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5db9ec1..cfcc01a 100644 --- a/README.md +++ b/README.md @@ -181,7 +181,7 @@ Example usage: ```js const strava = require('strava-v3'); -const payload = await strava.athlete.listFollowers({ +const payload = await strava.athlete.listActivities({ page: 1, per_page: 2 }); From ca768ba82c4bcafd3882b9fa3645788ebc61576f Mon Sep 17 00:00:00 2001 From: Wes Schlenker <49787065+wesleyschlenker@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:40:52 -0500 Subject: [PATCH 10/11] feat: add listRoutes method to athlete class https://developers.strava.com/docs/reference/#api-Routes-getRoutesByAthleteId --- lib/athlete.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/athlete.js b/lib/athlete.js index ebf86e3..7f24aa0 100644 --- a/lib/athlete.js +++ b/lib/athlete.js @@ -25,6 +25,9 @@ athlete.prototype.get = async function (args) { athlete.prototype.listActivities = async function (args) { return await this._listHelper('activities', args) } +athlete.prototype.listRoutes = async function (args) { + return await this._listHelper('routes', args) +} athlete.prototype.listClubs = async function (args) { return await this._listHelper('clubs', args) } From 93410798e6426efcfcaa46ce15f4eb58a815b9bb Mon Sep 17 00:00:00 2001 From: Wes Schlenker <49787065+wesleyschlenker@users.noreply.github.com> Date: Thu, 22 Jan 2026 22:23:24 -0500 Subject: [PATCH 11/11] fix: rename updateSportType test The test is named `#updateSportType()` but calls `strava.activities.update()`. There is no `updateSportType()` method in the implementation. The test name suggests a different method. --- test/activities.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/activities.js b/test/activities.js index 24eefab..e3b751d 100644 --- a/test/activities.js +++ b/test/activities.js @@ -124,7 +124,7 @@ describe('activities_test', function () { }) }) - describe('#updateSportType()', function () { + describe('#update()', function () { it('should update the sport type of an activity', async function () { const sportType = 'MountainBikeRide' const args = {