{"_id":"@dc99dc99/strava-v3","name":"@dc99dc99/strava-v3","dist-tags":{"latest":"2.2.1"},"versions":{"2.2.1":{"name":"@dc99dc99/strava-v3","version":"2.2.1","description":"Simple wrapper for Strava v3 API","main":"index.js","types":"index.d.ts","scripts":{"test":"npx eslint *.js lib test && npx mocha test/*.js","lint":"npx eslint *.js lib test"},"repository":{"type":"git","url":"git+https://github.com/node-strava/node-strava-v3.git"},"keywords":["strava","node","api"],"author":{"name":"austin brown","email":"austin@unboundev.com","url":"http://austinjamesbrown.com/"},"contributors":[{"name":"Mark Stosberg","email":"mark@rideamigos.com"}],"license":"MIT","bugs":{"url":"https://github.com/node-strava/node-strava-v3/issues"},"homepage":"https://github.com/node-strava/node-strava-v3","dependencies":{"axios":"^1.7.7","json-bigint":"^1.0.0"},"devDependencies":{"env-restorer":"^1.0.0","es6-promise":"^3.2.1","eslint":"^8.3.0","eslint-config-standard":"^12.0.0","eslint-plugin-import":"^2.17.3","eslint-plugin-node":"^9.1.0","eslint-plugin-promise":"^4.1.1","eslint-plugin-standard":"^4.0.0","inquirer":"^7.0.0","mocha":"^9.2.0","mock-fs":"^4.10.1","nock":"^11.3.4","should":"^13.2.3","sinon":"^1.17.4","yargs":"^17.3.0"},"mocha":{"globals":["should"],"timeout":20000,"checkLeaks":true,"ui":"bdd","reporter":"spec"},"eslintConfig":{"extends":"standard","env":{"mocha":true,"node":true}},"engines":{"node":">=8.0.0"},"_id":"@dc99dc99/strava-v3@2.2.1","gitHead":"3ecfb9316c23da8d4b185e1baec3c097eb874ecb","_nodeVersion":"20.5.1","_npmVersion":"9.8.0","dist":{"integrity":"sha512-kJr8qzAh+h2sEyl7CYpN73J0b0x33IFg2A5630TT/Guns3jkyahU+Yt78KgrbFcQsxkNxNGgyrlMJxbMkLnxHA==","shasum":"6534a2bd2b306bfd20d07f6dbed9bc82d92d05ba","tarball":"https://registry.npmjs.org/@dc99dc99/strava-v3/-/strava-v3-2.2.1.tgz","fileCount":47,"unpackedSize":357766,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCjzN49u2eUzEmXlhS8q7ZkE5dmf3JToaRYLU34w2CJbAIhAKmshfeXEpWogkVZYExNyAQKLh/rrRMFx+IF8wTUOy1b"}]},"_npmUser":{"name":"dc99dc99","email":"david@creativefootprint.co.uk"},"directories":{},"maintainers":[{"name":"dc99dc99","email":"david@creativefootprint.co.uk"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/strava-v3_2.2.1_1746137270190_0.5062711453039084"},"_hasShrinkwrap":false}},"time":{"created":"2025-05-01T22:07:50.075Z","2.2.1":"2025-05-01T22:07:50.455Z","modified":"2025-05-01T22:07:50.713Z"},"maintainers":[{"name":"dc99dc99","email":"david@creativefootprint.co.uk"}],"description":"Simple wrapper for Strava v3 API","homepage":"https://github.com/node-strava/node-strava-v3","keywords":["strava","node","api"],"repository":{"type":"git","url":"git+https://github.com/node-strava/node-strava-v3.git"},"contributors":[{"name":"Mark Stosberg","email":"mark@rideamigos.com"}],"author":{"name":"austin brown","email":"austin@unboundev.com","url":"http://austinjamesbrown.com/"},"bugs":{"url":"https://github.com/node-strava/node-strava-v3/issues"},"license":"MIT","readme":"\r\n# strava-v3: Simple Node wrapper for Strava's v3 API\r\n\r\n[![NPM Version][npm-image]][npm-url]\r\n[![NPM Downloads][downloads-image]][downloads-url]\r\n[![Build Status][travis-image]][travis-url]\r\n\r\n[npm-image]: https://img.shields.io/npm/v/strava-v3.svg?style=flat\r\n[npm-url]: https://npmjs.org/package/strava-v3\r\n[downloads-image]: https://img.shields.io/npm/dm/strava-v3.svg?style=flat\r\n[downloads-url]: https://npmjs.org/package/strava-v3\r\n[travis-image]: https://travis-ci.org/UnbounDev/node-strava-v3.svg?branch=master&style=flat\r\n[travis-url]: https://travis-ci.org/UnbounDev/node-strava-v3\r\n\r\n### Status\r\n\r\nSupports many but not all Strava API endpoints:\r\n\r\n* `oauth`\r\n* `athlete`\r\n* `athletes`\r\n* `activities`\r\n* `clubs`\r\n* `gear`\r\n* `running_races`\r\n* `routes`\r\n* `segments`\r\n* `segment_efforts`\r\n* `streams`\r\n* `uploads`\r\n\r\n## Installation\r\n\r\n```bash\r\nnpm install strava-v3\r\n```\r\n\r\n## Import syntax\r\nImporting only the library:\r\n```\r\nimport strava from 'strava-v3';\r\n```\r\nImporting both the library as well as interfaces:\r\n```\r\nimport { default as strava, Strava } from 'strava-v3';\r\n```\r\n\r\n## Quick start\r\n\r\n* Create an application at [strava.com/settings/api](https://www.strava.com/settings/api) and make note of your `access_token`\r\n\r\n### Promise API\r\n\r\n```js\r\nconst strava = require('strava-v3')\r\nstrava.config({...})\r\nconst payload = await strava.athlete.get({})\r\nconsole.log(payload)\r\n```\r\n\r\n### Callback API (Deprecated)\r\n\r\n```js\r\nconst strava = require('strava-v3');\r\nstrava.athlete.get({},function(err,payload,limits) {\r\n    if(!err) {\r\n        console.log(payload);\r\n    }\r\n    else {\r\n        console.log(err);\r\n    }\r\n});\r\n```\r\n\r\n## Usage\r\n\r\n### OAuth configuration\r\n\r\nIf you are writing an app that other Strava users will authorize against their\r\nown account, you'll need to use the OAuth flow. This requires that you provide\r\na `client_id`, `client_secret` and `redirect_uri` that ultimately result in\r\ngetting back an `access_token` which can be used for calls on behalf of that\r\nuser.\r\n\r\nYou have three options to configure your OAuth calls:\r\n\r\n#### Explicit configuration\r\n\r\nUse explicit configuration, which will override both the config file and the environment variables:\r\n\r\n```js\r\nvar strava = require('strava-v3')\r\nstrava.config({\r\n  \"access_token\"  : \"Your apps access token (Required for Quickstart)\",\r\n  \"client_id\"     : \"Your apps Client ID (Required for oauth)\",\r\n  \"client_secret\" : \"Your apps Client Secret (Required for oauth)\",\r\n  \"redirect_uri\"  : \"Your apps Authorization Redirection URI (Required for oauth)\",\r\n});\r\n```\r\n##### Environment variables\r\n\r\nYou may alternatively supply the values via environment variables named following the convention `STRAVA_<keyName>`, so\r\n\r\n- `STRAVA_ACCESS_TOKEN` = `access_token`\r\n- `STRAVA_CLIENT_ID` = `client_id`\r\n- `STRAVA_CLIENT_SECRET` = `client_secret`\r\n- `STRAVA_REDIRECT_URI` = `redirect_uri`\r\n\r\n\r\n#### Config File (Deprecated)\r\n\r\nThe template `strava_config` file can be found at the modules root directory and has the following structure\r\n\r\n```json\r\n{\r\n  \"access_token\"  : \"Your apps access token (Required for Quickstart)\",\r\n  \"client_id\"     : \"Your apps Client ID (Required for oauth)\",\r\n  \"client_secret\" : \"Your apps Client Secret (Required for oauth)\",\r\n  \"redirect_uri\"  : \"Your apps Authorization Redirection URI (Required for oauth)\",\r\n}\r\n```\r\n\r\n### General\r\n\r\nAPI access is designed to be as closely similar in layout as possible to Strava's own architecture, with the general call definition being\r\n\r\n```js\r\nvar strava = require('strava-v3')\r\n\r\n// Promise API\r\nstrava.<api endpoint>.<api endpoint option>(args)\r\n\r\n// Callback API\r\nstrava.<api endpoint>.<api endpoint option>(args,callback)\r\n```\r\n\r\nExample usage:\r\n\r\n```js\r\nvar strava = require('strava-v3');\r\nstrava.athletes.get({id:12345},function(err,payload,limits) {\r\n    //do something with your payload, track rate limits\r\n});\r\n```\r\n\r\n### Overriding the default `access_token`\r\n\r\nYou'll may want to use OAuth `access_token`s on behalf of specific users once\r\nyour app is in production. Using an `access_token` specific to a validated user\r\nallows for detailed athlete information, as well as the option for additional\r\n`PUT`/`POST`/`DELETE` privileges.\r\n\r\nUse app-specific logic to retrieve the `access\\_token` for a particular user, then create a Strava client for that user, with their token:\r\n\r\n```js\r\nconst stravaApi = require('strava-v3');\r\n\r\n// ... get access_token from somewhere\r\nstrava = new stravaApi.client(access_token);\r\n\r\nconst payload = await strava.athlete.get({})\r\n```\r\n\r\nLess conveniently, you can also explictly pass an `access_token` to API calls:\r\n\r\nExample usage:\r\n\r\n```js\r\nconst strava = require('strava-v3');\r\nconst payload = await strava.athlete.get({'access_token':'abcde'})\r\n```\r\n\r\n### Dealing with pagination\r\n\r\nFor those API calls that support pagination, you can control both the `page` being retrieved and the number of responses to return `per_page` by adding the corresponding properties to `args`.\r\n\r\nExample usage:\r\n\r\n```js\r\nconst strava = require('strava-v3');\r\nconst payload = await strava.athlete.listFollowers({\r\n    page: 1,\r\n    per_page: 2\r\n});\r\n```\r\n\r\n### Uploading files\r\nTo 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 `<filepath>/<filename>`. 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.\r\n\r\nExample usage:\r\n\r\n```js\r\nconst strava = require('strava-v3');\r\nconst payload = await strava.uploads.post({\r\n    data_type: 'gpx',\r\n    file: 'data/your_file.gpx',\r\n    name: 'Epic times',\r\n    statusCallback: (err,payload) => {\r\n        //do something with your payload\r\n    }\r\n});\r\n```\r\n\r\n### Rate limits\r\nAccording to Strava's API each response contains information about rate limits.\r\nFor more details see: [Rate Limits](https://developers.strava.com/docs/rate-limits/)\r\n\r\nReturns `null` if `X-Ratelimit-Limit` or `X-RateLimit-Usage` headers are not provided\r\n\r\n#### Global status\r\n\r\nIn our promise API, only the response body \"payload\" value is returned as a\r\n[Bluebird promise](https://bluebirdjs.com/docs/api-reference.html). To track\r\nrate limiting we use a global counter accessible through `strava.rateLimiting`.\r\n The rate limiting status is updated with each request.\r\n\r\n\r\n    // returns true if the most recent request exceeded the rate limit\r\n    strava.rateLimiting.exceeded()\r\n\r\n    // returns the current decimal fraction (from 0 to 1) of rate used. The greater of the short and long term limits.\r\n    strava.rateLimiting.fractionReached();\r\n\r\n#### Callback interface (Rate limits)\r\n\r\n```js\r\nconst strava = require('strava-v3');\r\nstrava.athlete.get({'access_token':'abcde'},function(err,payload,limits) {\r\n    //do something with your payload, track rate limits\r\n    console.log(limits);\r\n    /*\r\n    output:\r\n    {\r\n       shortTermUsage: 3,\r\n       shortTermLimit: 600,\r\n       longTermUsage: 12,\r\n       longTermLimit: 30000\r\n    }\r\n    */\r\n});\r\n```\r\n### Supported API Endpoints\r\n\r\nTo used the Promise-based API, do not provide a callback. A promise will be returned.\r\n\r\nSee Strava API docs for returned data structures.\r\n\r\n#### OAuth\r\n\r\n* `strava.oauth.getRequestAccessURL(args)`\r\n* `strava.oauth.getToken(code,done)` (Used to token exchange)\r\n* `strava.oauth.refreshToken(code)` (Callback API not supported)\r\n* `strava.oauth.deauthorize(args,done)`\r\n\r\n#### Athlete\r\n\r\n* `strava.athlete.get(args,done)`\r\n* `strava.athlete.update(args,done)` // only 'weight' can be updated.\r\n* `strava.athlete.listActivities(args,done)` *Get list of activity summaries*\r\n* `strava.athlete.listRoutes(args,done)`\r\n* `strava.athlete.listClubs(args,done)`\r\n* `strava.athlete.listZones(args,done)`\r\n\r\n#### Athletes\r\n\r\n* `strava.athletes.get(args,done)` *Get a single activity. args.id is required*\r\n* `strava.athletes.stats(args,done)`\r\n\r\n#### Activities\r\n\r\n* `strava.activities.get(args,done)`\r\n* `strava.activities.create(args,done)`\r\n* `strava.activities.update(args,done)`\r\n* `strava.activities.listFriends(args,done)` -> deprecated at 2.2.0\r\n* `strava.activities.listZones(args,done)`\r\n* `strava.activities.listLaps(args,done)`\r\n* `strava.activities.listComments(args,done)`\r\n* `strava.activities.listKudos(args,done)`\r\n* `strava.activities.listPhotos(args,done)` -> deprecated at 2.2.0\r\n\r\n#### Clubs\r\n\r\n* `strava.clubs.get(args,done)`\r\n* `strava.clubs.listMembers(args,done)`\r\n* `strava.clubs.listActivities(args,done)`\r\n* `strava.clubs.listAdmins(args,done)`\r\n\r\n#### Gear\r\n\r\n* `strava.gear.get(args,done)`\r\n\r\n#### Push Subscriptions\r\n\r\nThese methods Authenticate with a Client ID and Client Secret. Since they don't\r\nuse OAuth, they are not available on the `client` object.\r\n\r\n * `strava.pushSubscriptions.list({},done)`\r\n * `strava.pushSubscriptions.create({callback_url:...},done)`\r\n *  We set 'object\\_type to \"activity\" and \"aspect\\_type\" to \"create\" for you.\r\n * `strava.pushSubscriptions.delete({id:...},done)`\r\n\r\n#### Running Races\r\n\r\n * `strava.runningRaces.get(args,done)`\r\n * `strava.runningRaces.listRaces(args,done)`\r\n\r\n#### Routes\r\n\r\n * `strava.routes.getFile({ id: routeId, file_type: 'gpx' },done)` *file_type may also be 'tcx'*\r\n * `strava.routes.get(args,done)`\r\n\r\n#### Segments\r\n\r\n * `strava.segments.get(args,done)`\r\n * `strava.segments.listStarred(args,done)`\r\n * `strava.segments.listEfforts(args,done)`\r\n * `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\"`*.\r\n\r\n#### Segment Efforts\r\n\r\n * `strava.segmentEfforts.get(args,done)`\r\n\r\n#### Streams\r\n\r\n * `strava.streams.activity(args,done)`\r\n * `strava.streams.effort(args,done)`\r\n * `strava.streams.segment(args,done)`\r\n\r\n#### Uploads\r\n\r\n * `strava.uploads.post(args,done)`\r\n\r\n## Error Handling\r\n\r\nExcept for the OAuth calls, errors returned will be instances of `StatusCodeError` when the HTTP status code is not 2xx. In the Promise-based API, the promise will be rejected. An error of type `RequestError` will be returned if the request fails for technical reasons.\r\n\r\nThe updated version now uses Axios for HTTP requests and custom error classes for compatibility with the previous implementation.\r\n\r\nIn the Promise-based API, errors will reject the Promise. In the callback-based API (where supported), errors will pass to the `err` argument in the callback.\r\n\r\nThe project no longer relies on Bluebird. Where applicable, callback handling has been removed.\r\n\r\nExample error checking:\r\n\r\n```javascript\r\n    const { StatusCodeError, RequestError } = require('./axiosUtility');\r\n\r\n    // Catch a non-2xx response with the Promise API\r\n    badClient.athlete.get({})\r\n        .catch(StatusCodeError, function (e) {\r\n        });\r\n\r\n    badClient.athlete.get({}, function(err, payload) {\r\n      // err will be an instance of StatusCodeError or RequestError\r\n    });\r\n```\r\n\r\nThe `StatusCodeError` object includes extra properties to help with debugging:\r\n\r\n - `name` is always `StatusCodeError`\r\n - `statusCode` contains the HTTP status code\r\n - `message` contains the response's status message and additional error details\r\n - `data` contains the body of the response, which can be useful for debugging\r\n - `options` contains the options used in the request\r\n - `response` contains the response object\r\n\r\nThe `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:\r\n\r\n- `name` is always `RequestError`\r\n- `message` contains the error message\r\n- `options` contains the options used in the request\r\n\r\nThis update maintains feature parity with the previous implementation of `request-promise` while using the Axios HTTP client under the hood.\r\n\r\n\r\n## Development\r\n\r\nThis package includes a full test suite runnable via `yarn test`.\r\nIt will both lint and run shallow tests on API endpoints.\r\n\r\n### Running the tests\r\n\r\nYou'll first need to supply `data/strava_config` with an `access_token` that\r\nhas both private read and write permissions. Look in `./scripts` for a tool\r\nto help generate this token. Going forward we plan to more testing with a mocked\r\nversion of the Strava API so testing with real account credentials are not required.\r\n\r\n* Make sure you've filled out all the fields in `data/strava_config`.\r\n* Use `strava.oauth.getRequestAccessURL({scope:\"view_private,write\"})` to generate the request url and query it via your browser.\r\n* 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.\r\n* Exchange the `code` for a new `access_token`:\r\n\r\n```js\r\n// access_token is at payload.access_token\r\nconst payload = await strava.oauth.getToken(authorizationCode)\r\n```\r\nFinally, the test suite has some expectations about the Strava account that it\r\nconnects for the tests to pass. The following should be true about the Strava\r\ndata in the account:\r\n\r\n * Must have at least one activity posted on Strava\r\n * Must have joined at least one club\r\n * Must have added at least one piece of gear (bike or shoes)\r\n * Must have created at least one route\r\n * Most recent activity with an achievement should also contain a segment\r\n\r\n(Contributions to make the test suite more self-contained and robust by converting more tests\r\nto use `nock` are welcome!)\r\n\r\n* You're done! Paste the new `access_token` to `data/strava_config` and go run some tests:\r\n\r\n`yarn test`.\r\n\r\n### How the tests work\r\n\r\nUsing the provided `access_token` tests will access each endpoint individually:\r\n\r\n* (For all `GET` endpoints) checks to ensure the correct type has been returned from the Strava.\r\n* (For `PUT` in `athlete.update`) changes some athlete properties, then changes them back.\r\n* (For `POST/PUT/DELETE` in `activities.create/update/delete`) first creates an activity, runs some operations on it, then deletes it.\r\n\r\n## Debugging\r\n\r\nYou can enable a debug mode for the underlying `request` module to see details\r\nabout the raw HTTP requests and responses being sent back and forth from the\r\nStrava API.\r\n\r\nTo enable this, set this in the environment before this module is loaded:\r\n\r\n  NODE\\_DEBUG=request\r\n\r\nYou can also set `process.env.NODE_DEBUG='request' in your script before this module is loaded.\r\n\r\n## Resources\r\n\r\n* [Strava Developers Center](http://www.strava.com/developers)\r\n* [Strava API Reference](https://developers.strava.com/docs/reference/)\r\n\r\n## Author and Maintainer\r\n\r\nAuthored by Austin Brown <austin@unboundev.com> (http://austinjamesbrown.com/).\r\n\r\nCurrently Maintained by Mark Stosberg <mark@rideamigos.com>  \r\n\r\n","readmeFilename":"README.md","_rev":"1-d3214bf5f7bfc23dce8afa0978bb2442"}