strava-api-handler
Version:
Unofficial handler for Strava API
220 lines (188 loc) • 5.68 kB
JavaScript
;
var FormData = require('form-data');
var restApiHandler = require('rest-api-handler');
var Activity = require('./Activity.js');
var StravaException = require('./StravaException.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var FormData__default = /*#__PURE__*/_interopDefaultLegacy(FormData);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
global.FormData = FormData__default["default"];
function base64Encode(string) {
if (typeof btoa !== 'undefined') {
// eslint-disable-next-line no-undef
return btoa(string);
}
return Buffer.from(string).toString('base64');
}
class Api extends restApiHandler.Api {
constructor(clientId, secret) {
super('https://www.strava.com', [new restApiHandler.DefaultResponseProcessor(restApiHandler.DefaultApiException)], {
'content-Type': 'application/json'
});
this.clientId = clientId;
this.secret = secret;
}
setAccessToken(token) {
this.accessToken = token;
this.setDefaultHeader('Authorization', `Bearer ${token}`);
}
getAccessToken() {
return this.accessToken;
} // eslint-disable-next-line default-param-last
getLoginUrl(redirectUri, scope = ['read'], approvalPrompt, state) {
const parameters = {
client_id: this.clientId,
redirect_uri: redirectUri,
response_type: 'code',
scope: scope.join(','),
...(state ? {
state
} : {}),
...(approvalPrompt ? {
approval_prompt: approvalPrompt
} : {})
};
return `https://www.strava.com/oauth/authorize${restApiHandler.Api.convertParametersToUrl(parameters)}`;
}
async requestToken(parameters) {
const {
data
} = await this.request(`oauth/token${restApiHandler.Api.convertParametersToUrl({
client_id: this.clientId,
client_secret: this.secret,
...parameters
})}`, 'POST', {}, {
'content-type': 'application/x-www-form-urlencoded',
'Authorization': `Basic ${base64Encode(`${this.clientId}:${this.secret}`)}`
});
this.setAccessToken(data.access_token);
return data;
}
requestAccessToken(code) {
return this.requestToken({
code
});
}
refreshToken(token) {
return this.requestToken({
grant_type: 'refresh_token',
refresh_token: token
});
}
async getActivity(id) {
const {
data
} = await this.get(`api/v3/activities/${id}`);
return Activity.getFromApi(data);
}
async getStream(id, streams = []) {
const {
data
} = await this.get(`api/v3/activities/${id}/streams`, {
keys: streams.join(','),
key_by_type: false
});
const points = [];
Object.keys(data).forEach(item => {
data[item].data.forEach((value, key) => {
if (!points[key]) {
points[key] = {};
}
points[key][item] = value;
});
});
return points;
}
async getActivities(parameters) {
const {
after,
before
} = parameters;
const {
data
} = await this.get(`api/v3/athlete/activities${restApiHandler.Api.convertParametersToUrl({ ...parameters,
...(after ? {
after: typeof after === 'number' ? after : after.valueOf() / 1000
} : {}),
...(before ? {
before: typeof before === 'number' ? before : before.valueOf() / 1000
} : {})
})}`);
return data.map(activity => {
return Activity.getFromApi(activity);
});
}
async processActivities( // eslint-disable-next-line default-param-last
filter = {}, processor) {
const activities = await this.getActivities(filter);
const processorPromises = activities.map(activity => {
return processor(activity);
});
if (activities.length > 0) {
const {
page
} = filter;
processorPromises.push(...(await this.processActivities({ ...filter,
page: page ? page + 1 : 2
}, processor)));
}
return Promise.all(processorPromises);
} // eslint-disable-next-line complexity
async uploadActivity(activity, fileContent, externalId, dataType = 'gpx') {
const body = Api.convertData({
data_type: dataType,
...(activity.getTitle() != null ? {
name: activity.getTitle()
} : {}),
...(activity.getDescription() != null ? {
description: activity.getDescription()
} : {}),
...(activity.isCommute != null ? {
commute: activity.isCommute ? 1 : 0
} : {})
}, Api.FORMATS.FORM_DATA);
body.append('file', fileContent, {
filename: `${externalId}.${dataType}`
});
const contentType = this.getDefaultHeaders()['content-Type'];
this.removeDefaultHeader('content-Type');
const {
data
} = await this.request('api/v3/uploads', 'POST', {
body: body
});
this.setDefaultHeader('content-Type', contentType);
return data;
}
async getUploadStatus(uploadId) {
const {
data
} = await this.get(`api/v3/uploads/${uploadId}`);
if (data.error) {
throw new StravaException(data.error);
}
return data;
}
async createActivity(activity) {
const {
data
} = await this.post('api/v3/activities', activity.toApiObject());
return Activity.getFromApi(data);
}
async updateActivity(activity) {
const {
data
} = await this.put(`api/v3/activities/${activity.getId()}`, activity.toApiObject());
return Activity.getFromApi(data);
}
async updateWeight(weight) {
const {
data
} = await this.put('api/v3/athlete', {
weight
});
return data;
}
}
module.exports = Api;