@torqlab/strava-api 1.0.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.
- package/LICENSE +21 -0
- package/README.md +167 -0
- package/dist/client/client.d.ts +34 -0
- package/dist/client/client.d.ts.map +1 -0
- package/dist/client/create-error/create-error.d.ts +13 -0
- package/dist/client/create-error/create-error.d.ts.map +1 -0
- package/dist/client/create-error/index.d.ts +2 -0
- package/dist/client/create-error/index.d.ts.map +1 -0
- package/dist/client/get-auth-headers/get-auth-headers.d.ts +22 -0
- package/dist/client/get-auth-headers/get-auth-headers.d.ts.map +1 -0
- package/dist/client/get-auth-headers/index.d.ts +2 -0
- package/dist/client/get-auth-headers/index.d.ts.map +1 -0
- package/dist/client/handle-fetch-error/handle-fetch-error.d.ts +19 -0
- package/dist/client/handle-fetch-error/handle-fetch-error.d.ts.map +1 -0
- package/dist/client/handle-fetch-error/index.d.ts +2 -0
- package/dist/client/handle-fetch-error/index.d.ts.map +1 -0
- package/dist/client/handle-rate-limit/constants.d.ts +3 -0
- package/dist/client/handle-rate-limit/constants.d.ts.map +1 -0
- package/dist/client/handle-rate-limit/handle-rate-limit.d.ts +32 -0
- package/dist/client/handle-rate-limit/handle-rate-limit.d.ts.map +1 -0
- package/dist/client/handle-rate-limit/index.d.ts +2 -0
- package/dist/client/handle-rate-limit/index.d.ts.map +1 -0
- package/dist/client/handle-retry/handle-retry.d.ts +30 -0
- package/dist/client/handle-retry/handle-retry.d.ts.map +1 -0
- package/dist/client/handle-retry/index.d.ts +2 -0
- package/dist/client/handle-retry/index.d.ts.map +1 -0
- package/dist/client/handle-retry/types.d.ts +7 -0
- package/dist/client/handle-retry/types.d.ts.map +1 -0
- package/dist/client/index.d.ts +4 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/parse-error/index.d.ts +2 -0
- package/dist/client/parse-error/index.d.ts.map +1 -0
- package/dist/client/parse-error/parse-error.d.ts +14 -0
- package/dist/client/parse-error/parse-error.d.ts.map +1 -0
- package/dist/client/parse-error-code/index.d.ts +2 -0
- package/dist/client/parse-error-code/index.d.ts.map +1 -0
- package/dist/client/parse-error-code/parse-error-code.d.ts +12 -0
- package/dist/client/parse-error-code/parse-error-code.d.ts.map +1 -0
- package/dist/client/parse-response/index.d.ts +2 -0
- package/dist/client/parse-response/index.d.ts.map +1 -0
- package/dist/client/parse-response/parse-response.d.ts +30 -0
- package/dist/client/parse-response/parse-response.d.ts.map +1 -0
- package/dist/constants.d.ts +35 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/exchange-token/exchange-token.d.ts +36 -0
- package/dist/exchange-token/exchange-token.d.ts.map +1 -0
- package/dist/exchange-token/index.d.ts +2 -0
- package/dist/exchange-token/index.d.ts.map +1 -0
- package/dist/fetch-activities/fetch-activities.d.ts +39 -0
- package/dist/fetch-activities/fetch-activities.d.ts.map +1 -0
- package/dist/fetch-activities/index.d.ts +2 -0
- package/dist/fetch-activities/index.d.ts.map +1 -0
- package/dist/fetch-activity/fetch-activity.d.ts +49 -0
- package/dist/fetch-activity/fetch-activity.d.ts.map +1 -0
- package/dist/fetch-activity/index.d.ts +2 -0
- package/dist/fetch-activity/index.d.ts.map +1 -0
- package/dist/get-auth-url/get-auth-url.d.ts +30 -0
- package/dist/get-auth-url/get-auth-url.d.ts.map +1 -0
- package/dist/get-auth-url/index.d.ts +2 -0
- package/dist/get-auth-url/index.d.ts.map +1 -0
- package/dist/index.cjs +473 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +431 -0
- package/dist/refresh-token/index.d.ts +2 -0
- package/dist/refresh-token/index.d.ts.map +1 -0
- package/dist/refresh-token/refresh-token.d.ts +34 -0
- package/dist/refresh-token/refresh-token.d.ts.map +1 -0
- package/dist/refresh-token/types.d.ts +5 -0
- package/dist/refresh-token/types.d.ts.map +1 -0
- package/dist/types.d.ts +192 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/validators/index.d.ts +2 -0
- package/dist/validators/index.d.ts.map +1 -0
- package/dist/validators/validate-activity-id/index.d.ts +2 -0
- package/dist/validators/validate-activity-id/index.d.ts.map +1 -0
- package/dist/validators/validate-activity-id/validate-activity-id.d.ts +22 -0
- package/dist/validators/validate-activity-id/validate-activity-id.d.ts.map +1 -0
- package/package.json +69 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 TORQ Lab
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# @torqlab/strava-api
|
|
2
|
+
|
|
3
|
+
TypeScript client for the Strava API with automatic rate limiting, retry handling, and comprehensive type safety.
|
|
4
|
+
|
|
5
|
+
This package provides a robust interface to the Strava API, handling OAuth authentication, automatic token refresh, intelligent rate limiting, and retry logic. Built with TypeScript for complete type safety and designed for production use.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
Published to NPM.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm i @torqlab/strava-api
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Or with Bun:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
bun add @torqlab/strava-api
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick start
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { fetchActivity, fetchActivities, getAuthUrl, exchangeToken } from '@torqlab/strava-api';
|
|
25
|
+
import type { StravaApiConfig, StravaActivity } from '@torqlab/strava-api';
|
|
26
|
+
|
|
27
|
+
// OAuth flow - get authorization URL
|
|
28
|
+
const authUrl = getAuthUrl({
|
|
29
|
+
clientId: 'your-client-id',
|
|
30
|
+
redirectUri: 'http://localhost:3000/callback',
|
|
31
|
+
scope: 'read,activity:read_all',
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
console.log(`Visit: ${authUrl}`);
|
|
35
|
+
|
|
36
|
+
// Exchange authorization code for tokens
|
|
37
|
+
const tokens = await exchangeToken({
|
|
38
|
+
clientId: 'your-client-id',
|
|
39
|
+
clientSecret: 'your-client-secret',
|
|
40
|
+
code: 'authorization-code-from-callback',
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Configure API client
|
|
44
|
+
const config: StravaApiConfig = {
|
|
45
|
+
accessToken: tokens.access_token,
|
|
46
|
+
refreshToken: tokens.refresh_token,
|
|
47
|
+
clientId: 'your-client-id',
|
|
48
|
+
clientSecret: 'your-client-secret',
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Fetch a single activity
|
|
52
|
+
const activity: StravaActivity = await fetchActivity(config, 12345678);
|
|
53
|
+
|
|
54
|
+
console.log(`Activity: ${activity.name}`);
|
|
55
|
+
console.log(`Distance: ${activity.distance}m`);
|
|
56
|
+
console.log(`Moving time: ${activity.moving_time}s`);
|
|
57
|
+
|
|
58
|
+
// Fetch multiple activities
|
|
59
|
+
const activities: StravaActivity[] = await fetchActivities(config, {
|
|
60
|
+
per_page: 10,
|
|
61
|
+
page: 1,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
console.log(`Found ${activities.length} activities`);
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Features
|
|
68
|
+
|
|
69
|
+
- **Type Safety**: Full TypeScript support with comprehensive type definitions
|
|
70
|
+
- **OAuth 2.0**: Complete OAuth flow with authorization URL generation and token exchange
|
|
71
|
+
- **Automatic Token Refresh**: Handles expired access tokens automatically
|
|
72
|
+
- **Rate Limiting**: Intelligent rate limit handling with exponential backoff
|
|
73
|
+
- **Retry Logic**: Automatic retry for transient failures
|
|
74
|
+
- **Error Handling**: Comprehensive error types and messages
|
|
75
|
+
- **Validation**: Input validation for activity IDs and configuration
|
|
76
|
+
- **Zero Dependencies**: No external runtime dependencies
|
|
77
|
+
|
|
78
|
+
## API Reference
|
|
79
|
+
|
|
80
|
+
### Authentication
|
|
81
|
+
|
|
82
|
+
#### `getAuthUrl(params)`
|
|
83
|
+
|
|
84
|
+
Generate OAuth authorization URL.
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
const authUrl = getAuthUrl({
|
|
88
|
+
clientId: 'your-client-id',
|
|
89
|
+
redirectUri: 'http://localhost:3000/callback',
|
|
90
|
+
scope: 'read,activity:read_all', // Optional, defaults to 'read'
|
|
91
|
+
state: 'random-state-string', // Optional
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
#### `exchangeToken(params)`
|
|
96
|
+
|
|
97
|
+
Exchange authorization code for access tokens.
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
const tokens = await exchangeToken({
|
|
101
|
+
clientId: 'your-client-id',
|
|
102
|
+
clientSecret: 'your-client-secret',
|
|
103
|
+
code: 'authorization-code',
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Activities
|
|
108
|
+
|
|
109
|
+
#### `fetchActivity(config, activityId)`
|
|
110
|
+
|
|
111
|
+
Fetch a single activity by ID.
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
const activity = await fetchActivity(config, 12345678);
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### `fetchActivities(config, params?)`
|
|
118
|
+
|
|
119
|
+
Fetch multiple activities with optional pagination.
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
const activities = await fetchActivities(config, {
|
|
123
|
+
per_page: 30,
|
|
124
|
+
page: 1,
|
|
125
|
+
before: 1640995200, // Unix timestamp
|
|
126
|
+
after: 1609459200, // Unix timestamp
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Configuration
|
|
131
|
+
|
|
132
|
+
The `StravaApiConfig` interface supports:
|
|
133
|
+
|
|
134
|
+
- `accessToken`: OAuth2 access token (required)
|
|
135
|
+
- `refreshToken`: OAuth2 refresh token for automatic renewal
|
|
136
|
+
- `clientId`: OAuth2 client ID for token refresh
|
|
137
|
+
- `clientSecret`: OAuth2 client secret for token refresh
|
|
138
|
+
- `guardrails`: Optional validation callback for activities
|
|
139
|
+
|
|
140
|
+
## Error Handling
|
|
141
|
+
|
|
142
|
+
The package provides comprehensive error handling with typed error codes:
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
import { fetchActivity } from '@torqlab/strava-api';
|
|
146
|
+
import type { StravaApiError } from '@torqlab/strava-api';
|
|
147
|
+
|
|
148
|
+
try {
|
|
149
|
+
const activity = await fetchActivity(config, activityId);
|
|
150
|
+
} catch (error) {
|
|
151
|
+
if (error.code === 'RATE_LIMITED') {
|
|
152
|
+
console.log('Rate limited, retry after delay');
|
|
153
|
+
} else if (error.code === 'UNAUTHORIZED') {
|
|
154
|
+
console.log('Token expired, refresh needed');
|
|
155
|
+
} else if (error.code === 'NOT_FOUND') {
|
|
156
|
+
console.log('Activity not found');
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## License
|
|
162
|
+
|
|
163
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
|
164
|
+
|
|
165
|
+
## Contributing
|
|
166
|
+
|
|
167
|
+
Issues and pull requests are welcome on [GitHub](https://github.com/torqlab/strava-api).
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { StravaApiConfig } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Fetches activities list from the Strava API.
|
|
4
|
+
*
|
|
5
|
+
* Makes an authenticated HTTP GET request to the Strava API to retrieve
|
|
6
|
+
* a list of activities for the authenticated athlete. Handles various HTTP
|
|
7
|
+
* error responses and maps them to appropriate `StravaApiError` codes.
|
|
8
|
+
*
|
|
9
|
+
* @template T - The expected return type of the API response (e.g. `StravaActivity`).
|
|
10
|
+
* @param {string} url - The API endpoint URL.
|
|
11
|
+
* @param {StravaApiConfig} config - Strava API configuration with access token and optional base URL.
|
|
12
|
+
* @returns {Promise<T>} Promise resolving to the raw Strava API response data array.
|
|
13
|
+
* @throws {Error} Throws an error with `StravaApiError` structure for various failure scenarios:
|
|
14
|
+
* - 'NETWORK_ERROR' (retryable): Network connection failure.
|
|
15
|
+
* - 'UNAUTHORIZED' (not retryable): Invalid or expired token (401).
|
|
16
|
+
* - 'FORBIDDEN' (not retryable): Insufficient permissions (403).
|
|
17
|
+
* - 'RATE_LIMITED' (retryable): Rate limit exceeded (429).
|
|
18
|
+
* - 'SERVER_ERROR' (retryable): Strava API server error (5xx).
|
|
19
|
+
* - 'MALFORMED_RESPONSE' (not retryable): Invalid JSON response or not an array.
|
|
20
|
+
* - And others...
|
|
21
|
+
*
|
|
22
|
+
* @see {@link https://developers.strava.com/docs/reference/#api-Activities-getLoggedInAthleteActivities | Strava Get Activities API}
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* const activities = await client<StravaActivity[]>(
|
|
27
|
+
* STRAVA_API_ENDPOINTS.ACTIVITIES,
|
|
28
|
+
* { accessToken: 'abc123' },
|
|
29
|
+
* );
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
declare const client: <T>(url: string, config: StravaApiConfig) => Promise<T>;
|
|
33
|
+
export default client;
|
|
34
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../client/client.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAwBhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,QAAA,MAAM,MAAM,GAAU,CAAC,EAAE,KAAK,MAAM,EAAE,QAAQ,eAAe,KAAG,OAAO,CAAC,CAAC,CAMxE,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { StravaApiErrorCode } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Creates an `StravaApiError` wrapped in an `Error` object.
|
|
4
|
+
* @param {StravaApiErrorCode} code - Error code from `StravaApiErrorCode` union type.
|
|
5
|
+
* @param {string} message - User-friendly error message.
|
|
6
|
+
* @param {boolean} [retryable=false] - Whether the error is retryable (default: false).
|
|
7
|
+
* @param {Response} [response] - Optional fetch `Response` object to include in the error for additional context (e.g. rate limit headers).
|
|
8
|
+
* @returns {Error} Error object with JSON-stringified `StravaApiError` in message.
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
declare const createError: (code: StravaApiErrorCode, message: string, retryable?: boolean, response?: Response) => Error;
|
|
12
|
+
export default createError;
|
|
13
|
+
//# sourceMappingURL=create-error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-error.d.ts","sourceRoot":"","sources":["../../../client/create-error/create-error.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtE;;;;;;;;GAQG;AACH,QAAA,MAAM,WAAW,GACf,MAAM,kBAAkB,EACxB,SAAS,MAAM,EACf,YAAW,OAAe,EAC1B,WAAW,QAAQ,KAClB,KAkBF,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../client/create-error/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { StravaApiConfig } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Builds HTTP headers for Strava API authentication.
|
|
4
|
+
*
|
|
5
|
+
* Creates the Authorization header using OAuth2 Bearer token format as required
|
|
6
|
+
* by the Strava API. The header format follows RFC 6750 Bearer Token Usage.
|
|
7
|
+
*
|
|
8
|
+
* @param {StravaApiConfig} config - Strava API configuration containing the access token.
|
|
9
|
+
* @returns {HeadersInit} Headers object with Authorization header set to "Bearer {token}".
|
|
10
|
+
*
|
|
11
|
+
* @see {@link https://developers.strava.com/docs/authentication/ | Strava API Authentication}
|
|
12
|
+
* @see {@link https://datatracker.ietf.org/doc/html/rfc6750 | RFC 6750: Bearer Token Usage}
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const headers = getAuthHeaders({ accessToken: 'abc123' });
|
|
17
|
+
* // Returns: { Authorization: 'Bearer abc123' }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
declare const getAuthHeaders: (config: StravaApiConfig) => HeadersInit;
|
|
21
|
+
export default getAuthHeaders;
|
|
22
|
+
//# sourceMappingURL=get-auth-headers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-auth-headers.d.ts","sourceRoot":"","sources":["../../../client/get-auth-headers/get-auth-headers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C;;;;;;;;;;;;;;;;;GAiBG;AACH,QAAA,MAAM,cAAc,GAAI,QAAQ,eAAe,KAAG,WAMjD,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../client/get-auth-headers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { StravaApiConfig } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Handles errors from API fetch, including rate limits and unauthorized errors.
|
|
4
|
+
*
|
|
5
|
+
* For rate limit errors, it waits for the appropriate duration before retrying.
|
|
6
|
+
* For unauthorized errors, it attempts to refresh the token if possible and retry.
|
|
7
|
+
* For other errors, it rethrows them to be handled by the retry logic.
|
|
8
|
+
*
|
|
9
|
+
* @template T - The expected return type of the API fetch function.
|
|
10
|
+
* @param {Function} fn - The API fetch function to execute during error handling.
|
|
11
|
+
* @param {StravaApiConfig} config - Strava API configuration.
|
|
12
|
+
* @param {unknown} error - The error object thrown from the API fetch attempt.
|
|
13
|
+
* @returns {Promise<T>} Promise resolving to the expected return type if retry is successful.
|
|
14
|
+
* @throws {Error} Throws the original error if it's not a rate limit or unauthorized error, or if retries are exhausted.
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
17
|
+
declare const handleFetchError: <T>(fn: (config: StravaApiConfig) => Promise<T>, config: StravaApiConfig, error: unknown) => Promise<T>;
|
|
18
|
+
export default handleFetchError;
|
|
19
|
+
//# sourceMappingURL=handle-fetch-error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handle-fetch-error.d.ts","sourceRoot":"","sources":["../../../client/handle-fetch-error/handle-fetch-error.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAA8B,MAAM,aAAa,CAAC;AAK1E;;;;;;;;;;;;;;GAcG;AACH,QAAA,MAAM,gBAAgB,GAAU,CAAC,EAC/B,IAAI,CAAC,MAAM,EAAE,eAAe,KAAK,OAAO,CAAC,CAAC,CAAC,EAC3C,QAAQ,eAAe,EACvB,OAAO,OAAO,KACb,OAAO,CAAC,CAAC,CAwCX,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../client/handle-fetch-error/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../client/handle-rate-limit/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,QAAY,CAAC;AAEzC,eAAO,MAAM,SAAS,QAAiB,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handles rate limit responses from Strava API by waiting appropriately.
|
|
3
|
+
*
|
|
4
|
+
* Parses rate limit headers from HTTP response and waits for the appropriate
|
|
5
|
+
* duration before allowing retry. Prioritizes `Retry-After` header if present,
|
|
6
|
+
* otherwise uses rate limit usage headers to calculate wait time. Falls back
|
|
7
|
+
* to default 60-second wait if no rate limit information is available.
|
|
8
|
+
*
|
|
9
|
+
* Rate limit headers parsed:
|
|
10
|
+
* - `Retry-After`: Seconds to wait (highest priority)
|
|
11
|
+
* - `X-RateLimit-Limit`: Maximum requests per window
|
|
12
|
+
* - `X-RateLimit-Usage`: Current request count
|
|
13
|
+
*
|
|
14
|
+
* If usage >= limit, waits for full 15-minute window.
|
|
15
|
+
*
|
|
16
|
+
* @param {Response} response - HTTP Response object containing rate limit headers.
|
|
17
|
+
* @returns {Promise<void>} Promise that resolves after waiting for the calculated duration.
|
|
18
|
+
*
|
|
19
|
+
* @see {@link https://developers.strava.com/docs/rate-limits/ | Strava API Rate Limits}
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const response = new Response('Rate Limited', {
|
|
24
|
+
* status: 429,
|
|
25
|
+
* headers: { 'Retry-After': '5' }
|
|
26
|
+
* });
|
|
27
|
+
* await handleRateLimit(response); // Waits 5 seconds
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
declare const handleRateLimit: (response: Response) => Promise<void>;
|
|
31
|
+
export default handleRateLimit;
|
|
32
|
+
//# sourceMappingURL=handle-rate-limit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handle-rate-limit.d.ts","sourceRoot":"","sources":["../../../client/handle-rate-limit/handle-rate-limit.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,QAAA,MAAM,eAAe,GAAU,UAAU,QAAQ,KAAG,OAAO,CAAC,IAAI,CAkC/D,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../client/handle-rate-limit/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Input } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Implements retry logic with exponential backoff for async operations.
|
|
4
|
+
*
|
|
5
|
+
* Executes a function with automatic retries on failure. Uses exponential backoff
|
|
6
|
+
* strategy (doubling delay on each retry) up to a maximum delay. Only retries
|
|
7
|
+
* errors marked as retryable (`ActivityError.retryable === true`). Non-retryable
|
|
8
|
+
* errors are immediately thrown without retry attempts.
|
|
9
|
+
*
|
|
10
|
+
* @template T - The return type of the function being retried.
|
|
11
|
+
* @param {Input<T>} params - Parameters for the retry logic.
|
|
12
|
+
* @param {RetryFunction<T>} params.fn - Async function to execute and retry on failure.
|
|
13
|
+
* @param {number} params.maxRetries - Maximum number of retry attempts before giving up.
|
|
14
|
+
* @param {number} [params.initialBackoffMs=STRAVA_API_INITIAL_BACKOFF_MS] - Initial backoff delay in milliseconds (default is 1000ms).
|
|
15
|
+
* @returns {Promise<T>} Promise resolving to the function's return value on success.
|
|
16
|
+
* @throws {Error} Throws the last error encountered if all retries are exhausted.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const result = await handleRetry(
|
|
21
|
+
* () => fetchFromApi('123456', config),
|
|
22
|
+
* 3, // max 3 retries
|
|
23
|
+
* 1000 // start with 1 second delay
|
|
24
|
+
* );
|
|
25
|
+
* // Retry delays: 1s, 2s, 4s (capped at MAX_BACKOFF_MS)
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
declare const handleRetry: <T>({ fn, maxRetries, initialBackoffMs, }: Input<T>) => Promise<T>;
|
|
29
|
+
export default handleRetry;
|
|
30
|
+
//# sourceMappingURL=handle-retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handle-retry.d.ts","sourceRoot":"","sources":["../../../client/handle-retry/handle-retry.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAiB,MAAM,SAAS,CAAC;AAuE/C;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,QAAA,MAAM,WAAW,GAAU,CAAC,EAAE,uCAI3B,KAAK,CAAC,CAAC,CAAC,KAAG,OAAO,CAAC,CAAC,CAAkE,CAAC;AAE1F,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../client/handle-retry/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../client/handle-retry/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC;AAEhD,MAAM,WAAW,KAAK,CAAC,CAAC;IACtB,EAAE,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../client/parse-error/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { StravaApiError } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Parses an `Error` object to extract `StravaApiError` if present.
|
|
4
|
+
*
|
|
5
|
+
* Attempts to parse the error message as JSON to extract structured `StravaApiError`.
|
|
6
|
+
* Returns `null` if parsing fails or error doesn't contain `StravaApiError` structure.
|
|
7
|
+
*
|
|
8
|
+
* @param {Error} error - Error object potentially containing `StravaApiError` in message.
|
|
9
|
+
* @returns {StravaApiError | null} `StravaApiError` if successfully parsed, `null` otherwise.
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
declare const parseError: (error: unknown) => StravaApiError | null;
|
|
13
|
+
export default parseError;
|
|
14
|
+
//# sourceMappingURL=parse-error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-error.d.ts","sourceRoot":"","sources":["../../../client/parse-error/parse-error.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;;;;;GASG;AACH,QAAA,MAAM,UAAU,GAAI,OAAO,OAAO,KAAG,cAAc,GAAG,IAMrD,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../client/parse-error-code/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { StravaApiErrorCode } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Parses error code from an Error object.
|
|
4
|
+
* Attempts to parse the error message as JSON to extract structured `StravaApiError`.
|
|
5
|
+
* Returns `null` if parsing fails or error doesn't contain `StravaApiError` structure.
|
|
6
|
+
* @param {Error} error - Error object potentially containing `StravaApiError` in message.
|
|
7
|
+
* @returns {StravaApiErrorCode | null} `StravaApiErrorCode` if successfully parsed, `null` otherwise.
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
declare const parseErrorCode: (error: unknown) => StravaApiErrorCode | null;
|
|
11
|
+
export default parseErrorCode;
|
|
12
|
+
//# sourceMappingURL=parse-error-code.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-error-code.d.ts","sourceRoot":"","sources":["../../../client/parse-error-code/parse-error-code.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGtD;;;;;;;GAOG;AACH,QAAA,MAAM,cAAc,GAAI,OAAO,OAAO,KAAG,kBAAkB,GAAG,IAQ7D,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../client/parse-response/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses Strava API response.
|
|
3
|
+
* Handles various HTTP error responses and maps them to appropriate `StravaApiError` codes.
|
|
4
|
+
* @template T - The expected return type of the parsed API response (e.g. `StravaActivity`).
|
|
5
|
+
* @param {Response} response - The fetch `Response` object from the API request.
|
|
6
|
+
* @returns {Promise<T>} Promise resolving to the raw Strava API response.
|
|
7
|
+
* @throws {Error} Throws an error with `StravaApiError` structure for various failure scenarios:
|
|
8
|
+
* - 'NETWORK_ERROR' (retryable): Network connection failure.
|
|
9
|
+
* - 'UNAUTHORIZED' (not retryable): Invalid or expired token (401).
|
|
10
|
+
* - 'FORBIDDEN' (not retryable): Insufficient permissions (403).
|
|
11
|
+
* - 'RATE_LIMITED' (retryable): Rate limit exceeded (429).
|
|
12
|
+
* - 'SERVER_ERROR' (retryable): Strava API server error (5xx).
|
|
13
|
+
* - 'MALFORMED_RESPONSE' (not retryable): Invalid JSON response or empty response.
|
|
14
|
+
* - And others...
|
|
15
|
+
*
|
|
16
|
+
* @see {@link https://developers.strava.com/docs/reference/ | Strava API}
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const response = await fetch('https://www.strava.com/api/v3/athlete/activities', {
|
|
21
|
+
* headers: {
|
|
22
|
+
* Authorization: 'Bearer abc123',
|
|
23
|
+
* },
|
|
24
|
+
* });
|
|
25
|
+
* const data = await parseResponse(response);
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
declare const parseResponse: <T>(response: Response) => Promise<T>;
|
|
29
|
+
export default parseResponse;
|
|
30
|
+
//# sourceMappingURL=parse-response.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-response.d.ts","sourceRoot":"","sources":["../../../client/parse-response/parse-response.ts"],"names":[],"mappings":"AAgCA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,QAAA,MAAM,aAAa,GAAU,CAAC,EAAE,UAAU,QAAQ,KAAG,OAAO,CAAC,CAAC,CA4B7D,CAAC;AAEF,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export declare const STRAVA_API_INITIAL_BACKOFF_MS = 1000;
|
|
2
|
+
export declare const STRAVA_API_MAX_BACKOFF_MS = 16000;
|
|
3
|
+
export declare const STRAVA_API_MAX_RETRIES = 3;
|
|
4
|
+
export declare const STRAVA_AUTH_DEFAULT_SCOPE = "activity:read";
|
|
5
|
+
export declare const STRAVA_OAUTH_BASE_URL = "https://www.strava.com/oauth";
|
|
6
|
+
export declare const STRAVA_API_BASE_URL = "https://www.strava.com/api/v3";
|
|
7
|
+
export declare const STRAVA_API_ENDPOINTS: {
|
|
8
|
+
TOKEN: string;
|
|
9
|
+
AUTH: string;
|
|
10
|
+
ACTIVITIES: string;
|
|
11
|
+
/**
|
|
12
|
+
* Requires `/:id` for a specific activity.
|
|
13
|
+
*/
|
|
14
|
+
ACTIVITY: string;
|
|
15
|
+
};
|
|
16
|
+
export declare const STRAVA_API_ERROR_CODES: {
|
|
17
|
+
readonly UNAUTHORIZED: "UNAUTHORIZED";
|
|
18
|
+
readonly FORBIDDEN: "FORBIDDEN";
|
|
19
|
+
readonly RATE_LIMITED: "RATE_LIMITED";
|
|
20
|
+
readonly SERVER_ERROR: "SERVER_ERROR";
|
|
21
|
+
readonly MALFORMED_RESPONSE: "MALFORMED_RESPONSE";
|
|
22
|
+
readonly INVALID_ID: "INVALID_ID";
|
|
23
|
+
readonly NOT_FOUND: "NOT_FOUND";
|
|
24
|
+
readonly NETWORK_ERROR: "NETWORK_ERROR";
|
|
25
|
+
readonly VALIDATION_FAILED: "VALIDATION_FAILED";
|
|
26
|
+
readonly INVALID_CONFIG: "INVALID_CONFIG";
|
|
27
|
+
readonly INVALID_CODE: "INVALID_CODE";
|
|
28
|
+
};
|
|
29
|
+
export declare const STRAVA_API_STATUS_CODES: {
|
|
30
|
+
readonly UNAUTHORIZED: 401;
|
|
31
|
+
readonly FORBIDDEN: 403;
|
|
32
|
+
readonly RATE_LIMITED: 429;
|
|
33
|
+
readonly SERVER_ERROR: 500;
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,6BAA6B,OAAO,CAAC;AAElD,eAAO,MAAM,yBAAyB,QAAQ,CAAC;AAE/C,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC,eAAO,MAAM,yBAAyB,kBAAkB,CAAC;AAEzD,eAAO,MAAM,qBAAqB,iCAAiC,CAAC;AAEpE,eAAO,MAAM,mBAAmB,kCAAkC,CAAC;AAEnE,eAAO,MAAM,oBAAoB;;;;IAK/B;;OAEG;;CAEJ,CAAC;AAEF,eAAO,MAAM,sBAAsB;;;;;;;;;;;;CAYzB,CAAC;AAEX,eAAO,MAAM,uBAAuB;;;;;CAK1B,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { StravaAuthConfig, StravaAuthTokenResponse } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Exchanges an authorization code for OAuth2 access and refresh tokens.
|
|
4
|
+
*
|
|
5
|
+
* After a user authorizes the application via the authorization URL, Strava
|
|
6
|
+
* redirects to the redirect URI with an authorization code. This function
|
|
7
|
+
* exchanges that code for access and refresh tokens that can be used to make
|
|
8
|
+
* API requests.
|
|
9
|
+
*
|
|
10
|
+
* @param {string} authorizationCode - Authorization code received from Strava redirect.
|
|
11
|
+
* @param {StravaAuthConfig} config - OAuth2 configuration including client ID, secret, and redirect URI.
|
|
12
|
+
* @returns {Promise<StravaTokenResponse>} Promise resolving to token response containing access token, refresh token, and expiration info.
|
|
13
|
+
*
|
|
14
|
+
* @throws {Error} Throws an error with StravaAuthError structure for various failure scenarios:
|
|
15
|
+
* - 'INVALID_CONFIG' (not retryable): Missing required configuration.
|
|
16
|
+
* - 'INVALID_CODE' (not retryable): Authorization code is missing or invalid.
|
|
17
|
+
* - 'NETWORK_ERROR' (retryable): Network connection failure.
|
|
18
|
+
* - 'UNAUTHORIZED' (not retryable): Invalid client credentials or authorization code.
|
|
19
|
+
* - 'MALFORMED_RESPONSE' (not retryable): Invalid JSON response or missing required fields.
|
|
20
|
+
* - And others...
|
|
21
|
+
*
|
|
22
|
+
* @see {@link https://developers.strava.com/docs/authentication/#tokenexchange | Strava Token Exchange}
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* const tokens = await exchangeToken('authorization-code-123', {
|
|
27
|
+
* clientId: '12345',
|
|
28
|
+
* clientSecret: 'secret',
|
|
29
|
+
* redirectUri: 'http://localhost'
|
|
30
|
+
* });
|
|
31
|
+
* // Returns: { access_token: '...', refresh_token: '...', expires_at: 1234567890, ... }
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
declare const exchangeToken: (authorizationCode: string, config: StravaAuthConfig) => Promise<StravaAuthTokenResponse | null>;
|
|
35
|
+
export default exchangeToken;
|
|
36
|
+
//# sourceMappingURL=exchange-token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exchange-token.d.ts","sourceRoot":"","sources":["../../exchange-token/exchange-token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAwCrE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,QAAA,MAAM,aAAa,GACjB,mBAAmB,MAAM,EACzB,QAAQ,gBAAgB,KACvB,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAmCxC,CAAC;AAEF,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../exchange-token/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC"}
|