@pinta365/strava 0.0.1 → 0.0.3

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 CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 Pinta <https://github.com/Pinta365>
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.
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Pinta <https://github.com/Pinta365>
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 CHANGED
@@ -16,18 +16,42 @@ A cross-runtime TypeScript client for the Strava API v3. Works on Deno, Node.js
16
16
 
17
17
  ### Deno
18
18
 
19
- ```typescript
20
- import { StravaClient } from "https://deno.land/x/strava/mod.ts";
19
+ ```bash
20
+ deno add jsr:@pinta365/strava
21
21
  ```
22
22
 
23
- ### Node.js / Bun
23
+ ### Node.js
24
+
25
+ #### Using npm
24
26
 
25
27
  ```bash
26
28
  npm install @pinta365/strava
27
29
  ```
28
30
 
29
- ```typescript
30
- import { StravaClient } from "@pinta365/strava";
31
+ #### Using JSR (recommended)
32
+
33
+ ```bash
34
+ npx jsr add @pinta365/strava
35
+ ```
36
+
37
+ #### Using pnpm
38
+
39
+ ```bash
40
+ pnpm i jsr:@pinta365/strava
41
+ ```
42
+
43
+ ### Bun
44
+
45
+ #### Using JSR (recommended)
46
+
47
+ ```bash
48
+ bunx jsr add @pinta365/strava
49
+ ```
50
+
51
+ #### Using npm
52
+
53
+ ```bash
54
+ bun add @pinta365/strava
31
55
  ```
32
56
 
33
57
  ## Quick Start
@@ -38,25 +38,39 @@ export declare class OAuthManager {
38
38
  private tokenStore;
39
39
  private clientId;
40
40
  private clientSecret;
41
+ /**
42
+ * Create a new OAuth manager
43
+ * @param clientId - Strava client ID
44
+ * @param clientSecret - Strava client secret
45
+ * @param tokenStore - Token storage implementation
46
+ */
41
47
  constructor(clientId: string, clientSecret: string, tokenStore: TokenStore);
42
48
  /**
43
49
  * Get authorization URL
50
+ * @param options - Authorization URL options
51
+ * @returns Authorization URL to redirect user to
44
52
  */
45
53
  getAuthorizationUrl(options: Omit<AuthorizationUrlOptions, "clientId">): string;
46
54
  /**
47
55
  * Exchange code and store tokens
56
+ * @param code - Authorization code from OAuth callback
57
+ * @param redirectUri - Redirect URI used in authorization (optional)
58
+ * @returns Token data
48
59
  */
49
60
  authenticate(code: string, redirectUri?: string): Promise<TokenData>;
50
61
  /**
51
62
  * Get current token, refreshing if needed
63
+ * @returns Token data or null if not authenticated
52
64
  */
53
65
  getToken(): Promise<TokenData | null>;
54
66
  /**
55
67
  * Manually refresh token
68
+ * @returns New token data
56
69
  */
57
70
  refreshToken(): Promise<TokenData>;
58
71
  /**
59
72
  * Get current scopes
73
+ * @returns Array of current OAuth scopes
60
74
  */
61
75
  getScopes(): Promise<StravaScope[]>;
62
76
  /**
@@ -100,6 +100,12 @@ export function isTokenExpired(token, bufferSeconds = 300) {
100
100
  * OAuth manager for handling authentication and token refresh
101
101
  */
102
102
  export class OAuthManager {
103
+ /**
104
+ * Create a new OAuth manager
105
+ * @param clientId - Strava client ID
106
+ * @param clientSecret - Strava client secret
107
+ * @param tokenStore - Token storage implementation
108
+ */
103
109
  constructor(clientId, clientSecret, tokenStore) {
104
110
  Object.defineProperty(this, "tokenStore", {
105
111
  enumerable: true,
@@ -125,6 +131,8 @@ export class OAuthManager {
125
131
  }
126
132
  /**
127
133
  * Get authorization URL
134
+ * @param options - Authorization URL options
135
+ * @returns Authorization URL to redirect user to
128
136
  */
129
137
  getAuthorizationUrl(options) {
130
138
  return getAuthorizationUrl({
@@ -134,6 +142,9 @@ export class OAuthManager {
134
142
  }
135
143
  /**
136
144
  * Exchange code and store tokens
145
+ * @param code - Authorization code from OAuth callback
146
+ * @param redirectUri - Redirect URI used in authorization (optional)
147
+ * @returns Token data
137
148
  */
138
149
  async authenticate(code, redirectUri) {
139
150
  const token = await exchangeCode(code, this.clientId, this.clientSecret, redirectUri);
@@ -142,6 +153,7 @@ export class OAuthManager {
142
153
  }
143
154
  /**
144
155
  * Get current token, refreshing if needed
156
+ * @returns Token data or null if not authenticated
145
157
  */
146
158
  async getToken() {
147
159
  const token = await this.tokenStore.get();
@@ -169,6 +181,7 @@ export class OAuthManager {
169
181
  }
170
182
  /**
171
183
  * Manually refresh token
184
+ * @returns New token data
172
185
  */
173
186
  async refreshToken() {
174
187
  const token = await this.tokenStore.get();
@@ -186,6 +199,7 @@ export class OAuthManager {
186
199
  }
187
200
  /**
188
201
  * Get current scopes
202
+ * @returns Array of current OAuth scopes
189
203
  */
190
204
  async getScopes() {
191
205
  const token = await this.tokenStore.get();
@@ -16,8 +16,19 @@ export interface TokenData {
16
16
  * Token storage interface
17
17
  */
18
18
  export interface TokenStore {
19
+ /**
20
+ * Get stored token data
21
+ * @returns Token data or null if not found
22
+ */
19
23
  get(): Promise<TokenData | null>;
24
+ /**
25
+ * Store token data
26
+ * @param token - Token data to store
27
+ */
20
28
  set(token: TokenData): Promise<void>;
29
+ /**
30
+ * Clear stored token data
31
+ */
21
32
  clear(): Promise<void>;
22
33
  }
23
34
  /**
@@ -25,8 +36,19 @@ export interface TokenStore {
25
36
  */
26
37
  export declare class MemoryTokenStore implements TokenStore {
27
38
  private token;
39
+ /**
40
+ * Get stored token data
41
+ * @returns Token data or null if not found
42
+ */
28
43
  get(): Promise<TokenData | null>;
44
+ /**
45
+ * Store token data
46
+ * @param token - Token data to store
47
+ */
29
48
  set(token: TokenData): Promise<void>;
49
+ /**
50
+ * Clear stored token data
51
+ */
30
52
  clear(): Promise<void>;
31
53
  }
32
54
  /**
@@ -34,9 +56,23 @@ export declare class MemoryTokenStore implements TokenStore {
34
56
  */
35
57
  export declare class LocalStorageTokenStore implements TokenStore {
36
58
  private readonly key;
59
+ /**
60
+ * @param key - localStorage key to use (default: "strava_tokens")
61
+ */
37
62
  constructor(key?: string);
63
+ /**
64
+ * Get stored token data
65
+ * @returns Token data or null if not found
66
+ */
38
67
  get(): Promise<TokenData | null>;
68
+ /**
69
+ * Store token data
70
+ * @param token - Token data to store
71
+ */
39
72
  set(token: TokenData): Promise<void>;
73
+ /**
74
+ * Clear stored token data
75
+ */
40
76
  clear(): Promise<void>;
41
77
  }
42
78
  /**
@@ -44,9 +80,23 @@ export declare class LocalStorageTokenStore implements TokenStore {
44
80
  */
45
81
  export declare class FileSystemTokenStore implements TokenStore {
46
82
  private readonly path;
83
+ /**
84
+ * @param path - File path to store tokens (default: "./.strava-tokens.json")
85
+ */
47
86
  constructor(path?: string);
87
+ /**
88
+ * Get stored token data
89
+ * @returns Token data or null if not found
90
+ */
48
91
  get(): Promise<TokenData | null>;
92
+ /**
93
+ * Store token data
94
+ * @param token - Token data to store
95
+ */
49
96
  set(token: TokenData): Promise<void>;
97
+ /**
98
+ * Clear stored token data
99
+ */
50
100
  clear(): Promise<void>;
51
101
  }
52
102
  /**
@@ -14,13 +14,24 @@ export class MemoryTokenStore {
14
14
  value: null
15
15
  });
16
16
  }
17
+ /**
18
+ * Get stored token data
19
+ * @returns Token data or null if not found
20
+ */
17
21
  get() {
18
22
  return Promise.resolve(this.token);
19
23
  }
24
+ /**
25
+ * Store token data
26
+ * @param token - Token data to store
27
+ */
20
28
  set(token) {
21
29
  this.token = token;
22
30
  return Promise.resolve();
23
31
  }
32
+ /**
33
+ * Clear stored token data
34
+ */
24
35
  clear() {
25
36
  this.token = null;
26
37
  return Promise.resolve();
@@ -30,6 +41,9 @@ export class MemoryTokenStore {
30
41
  * Browser localStorage token store
31
42
  */
32
43
  export class LocalStorageTokenStore {
44
+ /**
45
+ * @param key - localStorage key to use (default: "strava_tokens")
46
+ */
33
47
  constructor(key = "strava_tokens") {
34
48
  Object.defineProperty(this, "key", {
35
49
  enumerable: true,
@@ -39,6 +53,10 @@ export class LocalStorageTokenStore {
39
53
  });
40
54
  this.key = key;
41
55
  }
56
+ /**
57
+ * Get stored token data
58
+ * @returns Token data or null if not found
59
+ */
42
60
  get() {
43
61
  if (CurrentRuntime !== Runtime.Browser) {
44
62
  throw new Error("LocalStorageTokenStore can only be used in browser environment");
@@ -53,6 +71,10 @@ export class LocalStorageTokenStore {
53
71
  return Promise.resolve(null);
54
72
  }
55
73
  }
74
+ /**
75
+ * Store token data
76
+ * @param token - Token data to store
77
+ */
56
78
  set(token) {
57
79
  if (CurrentRuntime !== Runtime.Browser) {
58
80
  throw new Error("LocalStorageTokenStore can only be used in browser environment");
@@ -60,6 +82,9 @@ export class LocalStorageTokenStore {
60
82
  localStorage.setItem(this.key, JSON.stringify(token));
61
83
  return Promise.resolve();
62
84
  }
85
+ /**
86
+ * Clear stored token data
87
+ */
63
88
  clear() {
64
89
  if (CurrentRuntime !== Runtime.Browser) {
65
90
  throw new Error("LocalStorageTokenStore can only be used in browser environment");
@@ -72,6 +97,9 @@ export class LocalStorageTokenStore {
72
97
  * File system token store (Node.js/Deno)
73
98
  */
74
99
  export class FileSystemTokenStore {
100
+ /**
101
+ * @param path - File path to store tokens (default: "./.strava-tokens.json")
102
+ */
75
103
  constructor(path = "./.strava-tokens.json") {
76
104
  Object.defineProperty(this, "path", {
77
105
  enumerable: true,
@@ -81,6 +109,10 @@ export class FileSystemTokenStore {
81
109
  });
82
110
  this.path = path;
83
111
  }
112
+ /**
113
+ * Get stored token data
114
+ * @returns Token data or null if not found
115
+ */
84
116
  async get() {
85
117
  try {
86
118
  let content;
@@ -98,6 +130,10 @@ export class FileSystemTokenStore {
98
130
  return null;
99
131
  }
100
132
  }
133
+ /**
134
+ * Store token data
135
+ * @param token - Token data to store
136
+ */
101
137
  async set(token) {
102
138
  const content = JSON.stringify(token, null, 2);
103
139
  if (CurrentRuntime === Runtime.Node || CurrentRuntime === Runtime.Bun) {
@@ -109,6 +145,9 @@ export class FileSystemTokenStore {
109
145
  await Deno.writeTextFile(this.path, content);
110
146
  }
111
147
  }
148
+ /**
149
+ * Clear stored token data
150
+ */
112
151
  async clear() {
113
152
  try {
114
153
  if (CurrentRuntime === Runtime.Node || CurrentRuntime === Runtime.Bun) {
@@ -7,25 +7,40 @@ import type { RateLimitStrategy, RequestConfig, RetryConfig } from "./types/comm
7
7
  * Client configuration options
8
8
  */
9
9
  export interface ClientOptions {
10
+ /** Strava client ID */
10
11
  clientId: string;
12
+ /** Strava client secret */
11
13
  clientSecret: string;
14
+ /** OAuth redirect URI */
12
15
  redirectUri?: string;
16
+ /** Token storage implementation (default: auto-detected based on runtime) */
13
17
  tokenStore?: TokenStore;
18
+ /** Base URL for API requests (default: "https://www.strava.com/api/v3") */
14
19
  baseUrl?: string;
20
+ /** Request timeout in milliseconds (default: 30000) */
15
21
  timeout?: number;
22
+ /** Retry configuration */
16
23
  retries?: RetryConfig;
24
+ /** Rate limit handling strategy (default: "queue") */
17
25
  rateLimitStrategy?: RateLimitStrategy;
26
+ /** Request deduplication window in milliseconds (default: 5000) */
18
27
  deduplicationWindow?: number;
28
+ /** Normalize snake_case keys to camelCase (default: true) */
19
29
  normalizeKeys?: boolean;
30
+ /** Transform ISO date strings to Date objects (default: true) */
20
31
  transformDates?: boolean;
32
+ /** Flatten nested response structures (default: true) */
21
33
  flattenResponses?: boolean;
34
+ /** Add computed fields (pace, duration, etc.) (default: true) */
22
35
  addComputedFields?: boolean;
23
36
  }
24
37
  /**
25
38
  * Authentication credentials
26
39
  */
27
40
  export interface AuthCredentials {
41
+ /** Authorization code from OAuth callback */
28
42
  code: string;
43
+ /** Redirect URI used in authorization (optional, uses client default if not provided) */
29
44
  redirectUri?: string;
30
45
  }
31
46
  /**
@@ -45,9 +60,14 @@ export declare class StravaClient {
45
60
  private _routes?;
46
61
  private _uploads?;
47
62
  private _streams?;
63
+ /**
64
+ * Create a new Strava API client
65
+ * @param options - Client configuration options
66
+ */
48
67
  constructor(options: ClientOptions);
49
68
  /**
50
69
  * Authenticate with authorization code
70
+ * @param credentials - Authentication credentials
51
71
  */
52
72
  authenticate(credentials: AuthCredentials): Promise<void>;
53
73
  /**
@@ -55,7 +75,13 @@ export declare class StravaClient {
55
75
  */
56
76
  refreshToken(): Promise<void>;
57
77
  /**
58
- * Get authorization URL
78
+ * Get authorization URL for OAuth flow
79
+ * @param options - Authorization URL options
80
+ * @param options.redirectUri - Redirect URI (optional, uses client default if not provided)
81
+ * @param options.scope - OAuth scopes to request
82
+ * @param options.state - Optional state parameter for CSRF protection
83
+ * @param options.approvalPrompt - Approval prompt behavior (default: "auto")
84
+ * @returns Authorization URL to redirect user to
59
85
  */
60
86
  getAuthorizationUrl(options: {
61
87
  redirectUri?: string;
@@ -65,20 +91,51 @@ export declare class StravaClient {
65
91
  }): string;
66
92
  /**
67
93
  * Get current access token (for direct fetch calls)
94
+ * @returns Current access token
95
+ * @throws Error if not authenticated
68
96
  */
69
97
  getAccessToken(): Promise<string>;
70
98
  /**
71
99
  * Low-level request method
100
+ * @param config - Request configuration
101
+ * @returns Response data
72
102
  */
73
103
  request<T>(config: RequestConfig): Promise<T>;
104
+ /**
105
+ * Athletes resource
106
+ */
74
107
  get athletes(): AthletesResource;
108
+ /**
109
+ * Activities resource
110
+ */
75
111
  get activities(): ActivitiesResource;
112
+ /**
113
+ * Segments resource
114
+ */
76
115
  get segments(): SegmentsResource;
116
+ /**
117
+ * Segment efforts resource
118
+ */
77
119
  get segmentEfforts(): SegmentEffortsResource;
120
+ /**
121
+ * Clubs resource
122
+ */
78
123
  get clubs(): ClubsResource;
124
+ /**
125
+ * Gears resource
126
+ */
79
127
  get gears(): GearsResource;
128
+ /**
129
+ * Routes resource
130
+ */
80
131
  get routes(): RoutesResource;
132
+ /**
133
+ * Uploads resource
134
+ */
81
135
  get uploads(): UploadsResource;
136
+ /**
137
+ * Streams resource
138
+ */
82
139
  get streams(): StreamsResource;
83
140
  /**
84
141
  * Clean up resources (stop timers, clear caches)
package/esm/src/client.js CHANGED
@@ -10,6 +10,10 @@ import { getDefaultTokenStore } from "./auth/token-store.js";
10
10
  * Main Strava API client class
11
11
  */
12
12
  export class StravaClient {
13
+ /**
14
+ * Create a new Strava API client
15
+ * @param options - Client configuration options
16
+ */
13
17
  constructor(options) {
14
18
  Object.defineProperty(this, "options", {
15
19
  enumerable: true,
@@ -110,6 +114,7 @@ export class StravaClient {
110
114
  }
111
115
  /**
112
116
  * Authenticate with authorization code
117
+ * @param credentials - Authentication credentials
113
118
  */
114
119
  async authenticate(credentials) {
115
120
  await this.oauthManager.authenticate(credentials.code, credentials.redirectUri || this.options.redirectUri);
@@ -121,7 +126,13 @@ export class StravaClient {
121
126
  await this.oauthManager.refreshToken();
122
127
  }
123
128
  /**
124
- * Get authorization URL
129
+ * Get authorization URL for OAuth flow
130
+ * @param options - Authorization URL options
131
+ * @param options.redirectUri - Redirect URI (optional, uses client default if not provided)
132
+ * @param options.scope - OAuth scopes to request
133
+ * @param options.state - Optional state parameter for CSRF protection
134
+ * @param options.approvalPrompt - Approval prompt behavior (default: "auto")
135
+ * @returns Authorization URL to redirect user to
125
136
  */
126
137
  getAuthorizationUrl(options) {
127
138
  return this.oauthManager.getAuthorizationUrl({
@@ -133,6 +144,8 @@ export class StravaClient {
133
144
  }
134
145
  /**
135
146
  * Get current access token (for direct fetch calls)
147
+ * @returns Current access token
148
+ * @throws Error if not authenticated
136
149
  */
137
150
  async getAccessToken() {
138
151
  const token = await this.oauthManager.getToken();
@@ -143,6 +156,8 @@ export class StravaClient {
143
156
  }
144
157
  /**
145
158
  * Low-level request method
159
+ * @param config - Request configuration
160
+ * @returns Response data
146
161
  */
147
162
  async request(config) {
148
163
  const token = await this.oauthManager.getToken();
@@ -162,54 +177,81 @@ export class StravaClient {
162
177
  addComputedFields: this.options.addComputedFields,
163
178
  });
164
179
  }
180
+ /**
181
+ * Athletes resource
182
+ */
165
183
  get athletes() {
166
184
  if (!this._athletes) {
167
185
  this._athletes = new AthletesResource(this);
168
186
  }
169
187
  return this._athletes;
170
188
  }
189
+ /**
190
+ * Activities resource
191
+ */
171
192
  get activities() {
172
193
  if (!this._activities) {
173
194
  this._activities = new ActivitiesResource(this);
174
195
  }
175
196
  return this._activities;
176
197
  }
198
+ /**
199
+ * Segments resource
200
+ */
177
201
  get segments() {
178
202
  if (!this._segments) {
179
203
  this._segments = new SegmentsResource(this);
180
204
  }
181
205
  return this._segments;
182
206
  }
207
+ /**
208
+ * Segment efforts resource
209
+ */
183
210
  get segmentEfforts() {
184
211
  if (!this._segmentEfforts) {
185
212
  this._segmentEfforts = new SegmentEffortsResource(this);
186
213
  }
187
214
  return this._segmentEfforts;
188
215
  }
216
+ /**
217
+ * Clubs resource
218
+ */
189
219
  get clubs() {
190
220
  if (!this._clubs) {
191
221
  this._clubs = new ClubsResource(this);
192
222
  }
193
223
  return this._clubs;
194
224
  }
225
+ /**
226
+ * Gears resource
227
+ */
195
228
  get gears() {
196
229
  if (!this._gears) {
197
230
  this._gears = new GearsResource(this);
198
231
  }
199
232
  return this._gears;
200
233
  }
234
+ /**
235
+ * Routes resource
236
+ */
201
237
  get routes() {
202
238
  if (!this._routes) {
203
239
  this._routes = new RoutesResource(this);
204
240
  }
205
241
  return this._routes;
206
242
  }
243
+ /**
244
+ * Uploads resource
245
+ */
207
246
  get uploads() {
208
247
  if (!this._uploads) {
209
248
  this._uploads = new UploadsResource(this);
210
249
  }
211
250
  return this._uploads;
212
251
  }
252
+ /**
253
+ * Streams resource
254
+ */
213
255
  get streams() {
214
256
  if (!this._streams) {
215
257
  this._streams = new StreamsResource(this);
@@ -14,18 +14,21 @@ export declare class PaginatedIterator<T> {
14
14
  constructor(fetchPage: (page: number, perPage: number) => Promise<T[]>, perPage?: number);
15
15
  /**
16
16
  * Get next page
17
+ * @returns True if a page was fetched, false if no more pages
17
18
  */
18
19
  next(): Promise<boolean>;
19
20
  /**
20
21
  * Get current page items
22
+ * @returns Array of items from the current page
21
23
  */
22
24
  get current(): T[];
23
25
  /**
24
26
  * Check if there are more pages
27
+ * @returns True if there are more pages available
25
28
  */
26
29
  get hasMorePages(): boolean;
27
30
  /**
28
- * Reset iterator
31
+ * Reset iterator to start from the first page
29
32
  */
30
33
  reset(): void;
31
34
  }
@@ -39,6 +39,7 @@ export class PaginatedIterator {
39
39
  }
40
40
  /**
41
41
  * Get next page
42
+ * @returns True if a page was fetched, false if no more pages
42
43
  */
43
44
  async next() {
44
45
  if (!this.hasMore) {
@@ -54,18 +55,20 @@ export class PaginatedIterator {
54
55
  }
55
56
  /**
56
57
  * Get current page items
58
+ * @returns Array of items from the current page
57
59
  */
58
60
  get current() {
59
61
  return this.currentItems;
60
62
  }
61
63
  /**
62
64
  * Check if there are more pages
65
+ * @returns True if there are more pages available
63
66
  */
64
67
  get hasMorePages() {
65
68
  return this.hasMore;
66
69
  }
67
70
  /**
68
- * Reset iterator
71
+ * Reset iterator to start from the first page
69
72
  */
70
73
  reset() {
71
74
  this.currentPage = 1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pinta365/strava",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "A library for interacting with the Strava API.",
5
5
  "keywords": [
6
6
  "strava",
@@ -38,25 +38,39 @@ export declare class OAuthManager {
38
38
  private tokenStore;
39
39
  private clientId;
40
40
  private clientSecret;
41
+ /**
42
+ * Create a new OAuth manager
43
+ * @param clientId - Strava client ID
44
+ * @param clientSecret - Strava client secret
45
+ * @param tokenStore - Token storage implementation
46
+ */
41
47
  constructor(clientId: string, clientSecret: string, tokenStore: TokenStore);
42
48
  /**
43
49
  * Get authorization URL
50
+ * @param options - Authorization URL options
51
+ * @returns Authorization URL to redirect user to
44
52
  */
45
53
  getAuthorizationUrl(options: Omit<AuthorizationUrlOptions, "clientId">): string;
46
54
  /**
47
55
  * Exchange code and store tokens
56
+ * @param code - Authorization code from OAuth callback
57
+ * @param redirectUri - Redirect URI used in authorization (optional)
58
+ * @returns Token data
48
59
  */
49
60
  authenticate(code: string, redirectUri?: string): Promise<TokenData>;
50
61
  /**
51
62
  * Get current token, refreshing if needed
63
+ * @returns Token data or null if not authenticated
52
64
  */
53
65
  getToken(): Promise<TokenData | null>;
54
66
  /**
55
67
  * Manually refresh token
68
+ * @returns New token data
56
69
  */
57
70
  refreshToken(): Promise<TokenData>;
58
71
  /**
59
72
  * Get current scopes
73
+ * @returns Array of current OAuth scopes
60
74
  */
61
75
  getScopes(): Promise<StravaScope[]>;
62
76
  /**
@@ -107,6 +107,12 @@ function isTokenExpired(token, bufferSeconds = 300) {
107
107
  * OAuth manager for handling authentication and token refresh
108
108
  */
109
109
  class OAuthManager {
110
+ /**
111
+ * Create a new OAuth manager
112
+ * @param clientId - Strava client ID
113
+ * @param clientSecret - Strava client secret
114
+ * @param tokenStore - Token storage implementation
115
+ */
110
116
  constructor(clientId, clientSecret, tokenStore) {
111
117
  Object.defineProperty(this, "tokenStore", {
112
118
  enumerable: true,
@@ -132,6 +138,8 @@ class OAuthManager {
132
138
  }
133
139
  /**
134
140
  * Get authorization URL
141
+ * @param options - Authorization URL options
142
+ * @returns Authorization URL to redirect user to
135
143
  */
136
144
  getAuthorizationUrl(options) {
137
145
  return getAuthorizationUrl({
@@ -141,6 +149,9 @@ class OAuthManager {
141
149
  }
142
150
  /**
143
151
  * Exchange code and store tokens
152
+ * @param code - Authorization code from OAuth callback
153
+ * @param redirectUri - Redirect URI used in authorization (optional)
154
+ * @returns Token data
144
155
  */
145
156
  async authenticate(code, redirectUri) {
146
157
  const token = await exchangeCode(code, this.clientId, this.clientSecret, redirectUri);
@@ -149,6 +160,7 @@ class OAuthManager {
149
160
  }
150
161
  /**
151
162
  * Get current token, refreshing if needed
163
+ * @returns Token data or null if not authenticated
152
164
  */
153
165
  async getToken() {
154
166
  const token = await this.tokenStore.get();
@@ -176,6 +188,7 @@ class OAuthManager {
176
188
  }
177
189
  /**
178
190
  * Manually refresh token
191
+ * @returns New token data
179
192
  */
180
193
  async refreshToken() {
181
194
  const token = await this.tokenStore.get();
@@ -193,6 +206,7 @@ class OAuthManager {
193
206
  }
194
207
  /**
195
208
  * Get current scopes
209
+ * @returns Array of current OAuth scopes
196
210
  */
197
211
  async getScopes() {
198
212
  const token = await this.tokenStore.get();
@@ -16,8 +16,19 @@ export interface TokenData {
16
16
  * Token storage interface
17
17
  */
18
18
  export interface TokenStore {
19
+ /**
20
+ * Get stored token data
21
+ * @returns Token data or null if not found
22
+ */
19
23
  get(): Promise<TokenData | null>;
24
+ /**
25
+ * Store token data
26
+ * @param token - Token data to store
27
+ */
20
28
  set(token: TokenData): Promise<void>;
29
+ /**
30
+ * Clear stored token data
31
+ */
21
32
  clear(): Promise<void>;
22
33
  }
23
34
  /**
@@ -25,8 +36,19 @@ export interface TokenStore {
25
36
  */
26
37
  export declare class MemoryTokenStore implements TokenStore {
27
38
  private token;
39
+ /**
40
+ * Get stored token data
41
+ * @returns Token data or null if not found
42
+ */
28
43
  get(): Promise<TokenData | null>;
44
+ /**
45
+ * Store token data
46
+ * @param token - Token data to store
47
+ */
29
48
  set(token: TokenData): Promise<void>;
49
+ /**
50
+ * Clear stored token data
51
+ */
30
52
  clear(): Promise<void>;
31
53
  }
32
54
  /**
@@ -34,9 +56,23 @@ export declare class MemoryTokenStore implements TokenStore {
34
56
  */
35
57
  export declare class LocalStorageTokenStore implements TokenStore {
36
58
  private readonly key;
59
+ /**
60
+ * @param key - localStorage key to use (default: "strava_tokens")
61
+ */
37
62
  constructor(key?: string);
63
+ /**
64
+ * Get stored token data
65
+ * @returns Token data or null if not found
66
+ */
38
67
  get(): Promise<TokenData | null>;
68
+ /**
69
+ * Store token data
70
+ * @param token - Token data to store
71
+ */
39
72
  set(token: TokenData): Promise<void>;
73
+ /**
74
+ * Clear stored token data
75
+ */
40
76
  clear(): Promise<void>;
41
77
  }
42
78
  /**
@@ -44,9 +80,23 @@ export declare class LocalStorageTokenStore implements TokenStore {
44
80
  */
45
81
  export declare class FileSystemTokenStore implements TokenStore {
46
82
  private readonly path;
83
+ /**
84
+ * @param path - File path to store tokens (default: "./.strava-tokens.json")
85
+ */
47
86
  constructor(path?: string);
87
+ /**
88
+ * Get stored token data
89
+ * @returns Token data or null if not found
90
+ */
48
91
  get(): Promise<TokenData | null>;
92
+ /**
93
+ * Store token data
94
+ * @param token - Token data to store
95
+ */
49
96
  set(token: TokenData): Promise<void>;
97
+ /**
98
+ * Clear stored token data
99
+ */
50
100
  clear(): Promise<void>;
51
101
  }
52
102
  /**
@@ -51,13 +51,24 @@ class MemoryTokenStore {
51
51
  value: null
52
52
  });
53
53
  }
54
+ /**
55
+ * Get stored token data
56
+ * @returns Token data or null if not found
57
+ */
54
58
  get() {
55
59
  return Promise.resolve(this.token);
56
60
  }
61
+ /**
62
+ * Store token data
63
+ * @param token - Token data to store
64
+ */
57
65
  set(token) {
58
66
  this.token = token;
59
67
  return Promise.resolve();
60
68
  }
69
+ /**
70
+ * Clear stored token data
71
+ */
61
72
  clear() {
62
73
  this.token = null;
63
74
  return Promise.resolve();
@@ -68,6 +79,9 @@ exports.MemoryTokenStore = MemoryTokenStore;
68
79
  * Browser localStorage token store
69
80
  */
70
81
  class LocalStorageTokenStore {
82
+ /**
83
+ * @param key - localStorage key to use (default: "strava_tokens")
84
+ */
71
85
  constructor(key = "strava_tokens") {
72
86
  Object.defineProperty(this, "key", {
73
87
  enumerable: true,
@@ -77,6 +91,10 @@ class LocalStorageTokenStore {
77
91
  });
78
92
  this.key = key;
79
93
  }
94
+ /**
95
+ * Get stored token data
96
+ * @returns Token data or null if not found
97
+ */
80
98
  get() {
81
99
  if (mod_js_1.CurrentRuntime !== mod_js_1.Runtime.Browser) {
82
100
  throw new Error("LocalStorageTokenStore can only be used in browser environment");
@@ -91,6 +109,10 @@ class LocalStorageTokenStore {
91
109
  return Promise.resolve(null);
92
110
  }
93
111
  }
112
+ /**
113
+ * Store token data
114
+ * @param token - Token data to store
115
+ */
94
116
  set(token) {
95
117
  if (mod_js_1.CurrentRuntime !== mod_js_1.Runtime.Browser) {
96
118
  throw new Error("LocalStorageTokenStore can only be used in browser environment");
@@ -98,6 +120,9 @@ class LocalStorageTokenStore {
98
120
  localStorage.setItem(this.key, JSON.stringify(token));
99
121
  return Promise.resolve();
100
122
  }
123
+ /**
124
+ * Clear stored token data
125
+ */
101
126
  clear() {
102
127
  if (mod_js_1.CurrentRuntime !== mod_js_1.Runtime.Browser) {
103
128
  throw new Error("LocalStorageTokenStore can only be used in browser environment");
@@ -111,6 +136,9 @@ exports.LocalStorageTokenStore = LocalStorageTokenStore;
111
136
  * File system token store (Node.js/Deno)
112
137
  */
113
138
  class FileSystemTokenStore {
139
+ /**
140
+ * @param path - File path to store tokens (default: "./.strava-tokens.json")
141
+ */
114
142
  constructor(path = "./.strava-tokens.json") {
115
143
  Object.defineProperty(this, "path", {
116
144
  enumerable: true,
@@ -120,6 +148,10 @@ class FileSystemTokenStore {
120
148
  });
121
149
  this.path = path;
122
150
  }
151
+ /**
152
+ * Get stored token data
153
+ * @returns Token data or null if not found
154
+ */
123
155
  async get() {
124
156
  try {
125
157
  let content;
@@ -137,6 +169,10 @@ class FileSystemTokenStore {
137
169
  return null;
138
170
  }
139
171
  }
172
+ /**
173
+ * Store token data
174
+ * @param token - Token data to store
175
+ */
140
176
  async set(token) {
141
177
  const content = JSON.stringify(token, null, 2);
142
178
  if (mod_js_1.CurrentRuntime === mod_js_1.Runtime.Node || mod_js_1.CurrentRuntime === mod_js_1.Runtime.Bun) {
@@ -148,6 +184,9 @@ class FileSystemTokenStore {
148
184
  await Deno.writeTextFile(this.path, content);
149
185
  }
150
186
  }
187
+ /**
188
+ * Clear stored token data
189
+ */
151
190
  async clear() {
152
191
  try {
153
192
  if (mod_js_1.CurrentRuntime === mod_js_1.Runtime.Node || mod_js_1.CurrentRuntime === mod_js_1.Runtime.Bun) {
@@ -7,25 +7,40 @@ import type { RateLimitStrategy, RequestConfig, RetryConfig } from "./types/comm
7
7
  * Client configuration options
8
8
  */
9
9
  export interface ClientOptions {
10
+ /** Strava client ID */
10
11
  clientId: string;
12
+ /** Strava client secret */
11
13
  clientSecret: string;
14
+ /** OAuth redirect URI */
12
15
  redirectUri?: string;
16
+ /** Token storage implementation (default: auto-detected based on runtime) */
13
17
  tokenStore?: TokenStore;
18
+ /** Base URL for API requests (default: "https://www.strava.com/api/v3") */
14
19
  baseUrl?: string;
20
+ /** Request timeout in milliseconds (default: 30000) */
15
21
  timeout?: number;
22
+ /** Retry configuration */
16
23
  retries?: RetryConfig;
24
+ /** Rate limit handling strategy (default: "queue") */
17
25
  rateLimitStrategy?: RateLimitStrategy;
26
+ /** Request deduplication window in milliseconds (default: 5000) */
18
27
  deduplicationWindow?: number;
28
+ /** Normalize snake_case keys to camelCase (default: true) */
19
29
  normalizeKeys?: boolean;
30
+ /** Transform ISO date strings to Date objects (default: true) */
20
31
  transformDates?: boolean;
32
+ /** Flatten nested response structures (default: true) */
21
33
  flattenResponses?: boolean;
34
+ /** Add computed fields (pace, duration, etc.) (default: true) */
22
35
  addComputedFields?: boolean;
23
36
  }
24
37
  /**
25
38
  * Authentication credentials
26
39
  */
27
40
  export interface AuthCredentials {
41
+ /** Authorization code from OAuth callback */
28
42
  code: string;
43
+ /** Redirect URI used in authorization (optional, uses client default if not provided) */
29
44
  redirectUri?: string;
30
45
  }
31
46
  /**
@@ -45,9 +60,14 @@ export declare class StravaClient {
45
60
  private _routes?;
46
61
  private _uploads?;
47
62
  private _streams?;
63
+ /**
64
+ * Create a new Strava API client
65
+ * @param options - Client configuration options
66
+ */
48
67
  constructor(options: ClientOptions);
49
68
  /**
50
69
  * Authenticate with authorization code
70
+ * @param credentials - Authentication credentials
51
71
  */
52
72
  authenticate(credentials: AuthCredentials): Promise<void>;
53
73
  /**
@@ -55,7 +75,13 @@ export declare class StravaClient {
55
75
  */
56
76
  refreshToken(): Promise<void>;
57
77
  /**
58
- * Get authorization URL
78
+ * Get authorization URL for OAuth flow
79
+ * @param options - Authorization URL options
80
+ * @param options.redirectUri - Redirect URI (optional, uses client default if not provided)
81
+ * @param options.scope - OAuth scopes to request
82
+ * @param options.state - Optional state parameter for CSRF protection
83
+ * @param options.approvalPrompt - Approval prompt behavior (default: "auto")
84
+ * @returns Authorization URL to redirect user to
59
85
  */
60
86
  getAuthorizationUrl(options: {
61
87
  redirectUri?: string;
@@ -65,20 +91,51 @@ export declare class StravaClient {
65
91
  }): string;
66
92
  /**
67
93
  * Get current access token (for direct fetch calls)
94
+ * @returns Current access token
95
+ * @throws Error if not authenticated
68
96
  */
69
97
  getAccessToken(): Promise<string>;
70
98
  /**
71
99
  * Low-level request method
100
+ * @param config - Request configuration
101
+ * @returns Response data
72
102
  */
73
103
  request<T>(config: RequestConfig): Promise<T>;
104
+ /**
105
+ * Athletes resource
106
+ */
74
107
  get athletes(): AthletesResource;
108
+ /**
109
+ * Activities resource
110
+ */
75
111
  get activities(): ActivitiesResource;
112
+ /**
113
+ * Segments resource
114
+ */
76
115
  get segments(): SegmentsResource;
116
+ /**
117
+ * Segment efforts resource
118
+ */
77
119
  get segmentEfforts(): SegmentEffortsResource;
120
+ /**
121
+ * Clubs resource
122
+ */
78
123
  get clubs(): ClubsResource;
124
+ /**
125
+ * Gears resource
126
+ */
79
127
  get gears(): GearsResource;
128
+ /**
129
+ * Routes resource
130
+ */
80
131
  get routes(): RoutesResource;
132
+ /**
133
+ * Uploads resource
134
+ */
81
135
  get uploads(): UploadsResource;
136
+ /**
137
+ * Streams resource
138
+ */
82
139
  get streams(): StreamsResource;
83
140
  /**
84
141
  * Clean up resources (stop timers, clear caches)
@@ -13,6 +13,10 @@ const token_store_js_1 = require("./auth/token-store.js");
13
13
  * Main Strava API client class
14
14
  */
15
15
  class StravaClient {
16
+ /**
17
+ * Create a new Strava API client
18
+ * @param options - Client configuration options
19
+ */
16
20
  constructor(options) {
17
21
  Object.defineProperty(this, "options", {
18
22
  enumerable: true,
@@ -113,6 +117,7 @@ class StravaClient {
113
117
  }
114
118
  /**
115
119
  * Authenticate with authorization code
120
+ * @param credentials - Authentication credentials
116
121
  */
117
122
  async authenticate(credentials) {
118
123
  await this.oauthManager.authenticate(credentials.code, credentials.redirectUri || this.options.redirectUri);
@@ -124,7 +129,13 @@ class StravaClient {
124
129
  await this.oauthManager.refreshToken();
125
130
  }
126
131
  /**
127
- * Get authorization URL
132
+ * Get authorization URL for OAuth flow
133
+ * @param options - Authorization URL options
134
+ * @param options.redirectUri - Redirect URI (optional, uses client default if not provided)
135
+ * @param options.scope - OAuth scopes to request
136
+ * @param options.state - Optional state parameter for CSRF protection
137
+ * @param options.approvalPrompt - Approval prompt behavior (default: "auto")
138
+ * @returns Authorization URL to redirect user to
128
139
  */
129
140
  getAuthorizationUrl(options) {
130
141
  return this.oauthManager.getAuthorizationUrl({
@@ -136,6 +147,8 @@ class StravaClient {
136
147
  }
137
148
  /**
138
149
  * Get current access token (for direct fetch calls)
150
+ * @returns Current access token
151
+ * @throws Error if not authenticated
139
152
  */
140
153
  async getAccessToken() {
141
154
  const token = await this.oauthManager.getToken();
@@ -146,6 +159,8 @@ class StravaClient {
146
159
  }
147
160
  /**
148
161
  * Low-level request method
162
+ * @param config - Request configuration
163
+ * @returns Response data
149
164
  */
150
165
  async request(config) {
151
166
  const token = await this.oauthManager.getToken();
@@ -165,54 +180,81 @@ class StravaClient {
165
180
  addComputedFields: this.options.addComputedFields,
166
181
  });
167
182
  }
183
+ /**
184
+ * Athletes resource
185
+ */
168
186
  get athletes() {
169
187
  if (!this._athletes) {
170
188
  this._athletes = new athletes_js_1.AthletesResource(this);
171
189
  }
172
190
  return this._athletes;
173
191
  }
192
+ /**
193
+ * Activities resource
194
+ */
174
195
  get activities() {
175
196
  if (!this._activities) {
176
197
  this._activities = new activities_js_1.ActivitiesResource(this);
177
198
  }
178
199
  return this._activities;
179
200
  }
201
+ /**
202
+ * Segments resource
203
+ */
180
204
  get segments() {
181
205
  if (!this._segments) {
182
206
  this._segments = new segments_js_1.SegmentsResource(this);
183
207
  }
184
208
  return this._segments;
185
209
  }
210
+ /**
211
+ * Segment efforts resource
212
+ */
186
213
  get segmentEfforts() {
187
214
  if (!this._segmentEfforts) {
188
215
  this._segmentEfforts = new segment_efforts_js_1.SegmentEffortsResource(this);
189
216
  }
190
217
  return this._segmentEfforts;
191
218
  }
219
+ /**
220
+ * Clubs resource
221
+ */
192
222
  get clubs() {
193
223
  if (!this._clubs) {
194
224
  this._clubs = new clubs_js_1.ClubsResource(this);
195
225
  }
196
226
  return this._clubs;
197
227
  }
228
+ /**
229
+ * Gears resource
230
+ */
198
231
  get gears() {
199
232
  if (!this._gears) {
200
233
  this._gears = new gears_js_1.GearsResource(this);
201
234
  }
202
235
  return this._gears;
203
236
  }
237
+ /**
238
+ * Routes resource
239
+ */
204
240
  get routes() {
205
241
  if (!this._routes) {
206
242
  this._routes = new routes_js_1.RoutesResource(this);
207
243
  }
208
244
  return this._routes;
209
245
  }
246
+ /**
247
+ * Uploads resource
248
+ */
210
249
  get uploads() {
211
250
  if (!this._uploads) {
212
251
  this._uploads = new uploads_js_1.UploadsResource(this);
213
252
  }
214
253
  return this._uploads;
215
254
  }
255
+ /**
256
+ * Streams resource
257
+ */
216
258
  get streams() {
217
259
  if (!this._streams) {
218
260
  this._streams = new streams_js_1.StreamsResource(this);
@@ -14,18 +14,21 @@ export declare class PaginatedIterator<T> {
14
14
  constructor(fetchPage: (page: number, perPage: number) => Promise<T[]>, perPage?: number);
15
15
  /**
16
16
  * Get next page
17
+ * @returns True if a page was fetched, false if no more pages
17
18
  */
18
19
  next(): Promise<boolean>;
19
20
  /**
20
21
  * Get current page items
22
+ * @returns Array of items from the current page
21
23
  */
22
24
  get current(): T[];
23
25
  /**
24
26
  * Check if there are more pages
27
+ * @returns True if there are more pages available
25
28
  */
26
29
  get hasMorePages(): boolean;
27
30
  /**
28
- * Reset iterator
31
+ * Reset iterator to start from the first page
29
32
  */
30
33
  reset(): void;
31
34
  }
@@ -44,6 +44,7 @@ class PaginatedIterator {
44
44
  }
45
45
  /**
46
46
  * Get next page
47
+ * @returns True if a page was fetched, false if no more pages
47
48
  */
48
49
  async next() {
49
50
  if (!this.hasMore) {
@@ -59,18 +60,20 @@ class PaginatedIterator {
59
60
  }
60
61
  /**
61
62
  * Get current page items
63
+ * @returns Array of items from the current page
62
64
  */
63
65
  get current() {
64
66
  return this.currentItems;
65
67
  }
66
68
  /**
67
69
  * Check if there are more pages
70
+ * @returns True if there are more pages available
68
71
  */
69
72
  get hasMorePages() {
70
73
  return this.hasMore;
71
74
  }
72
75
  /**
73
- * Reset iterator
76
+ * Reset iterator to start from the first page
74
77
  */
75
78
  reset() {
76
79
  this.currentPage = 1;