@pinta365/strava 0.0.1
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 +390 -0
- package/esm/_dnt.shims.d.ts +2 -0
- package/esm/_dnt.shims.js +57 -0
- package/esm/deps/jsr.io/@cross/runtime/1.2.1/mod.d.ts +126 -0
- package/esm/deps/jsr.io/@cross/runtime/1.2.1/mod.js +480 -0
- package/esm/mod.d.ts +27 -0
- package/esm/mod.js +27 -0
- package/esm/package.json +3 -0
- package/esm/src/auth/oauth.d.ts +68 -0
- package/esm/src/auth/oauth.js +203 -0
- package/esm/src/auth/scopes.d.ts +52 -0
- package/esm/src/auth/scopes.js +71 -0
- package/esm/src/auth/token-store.d.ts +57 -0
- package/esm/src/auth/token-store.js +142 -0
- package/esm/src/client.d.ts +98 -0
- package/esm/src/client.js +235 -0
- package/esm/src/errors.d.ts +52 -0
- package/esm/src/errors.js +102 -0
- package/esm/src/http/deduplication.d.ts +33 -0
- package/esm/src/http/deduplication.js +96 -0
- package/esm/src/http/rate-limiter.d.ts +47 -0
- package/esm/src/http/rate-limiter.js +168 -0
- package/esm/src/http/request.d.ts +24 -0
- package/esm/src/http/request.js +158 -0
- package/esm/src/http/retry.d.ts +9 -0
- package/esm/src/http/retry.js +61 -0
- package/esm/src/resources/activities.d.ts +149 -0
- package/esm/src/resources/activities.js +189 -0
- package/esm/src/resources/athletes.d.ts +37 -0
- package/esm/src/resources/athletes.js +85 -0
- package/esm/src/resources/clubs.d.ts +45 -0
- package/esm/src/resources/clubs.js +71 -0
- package/esm/src/resources/gears.d.ts +17 -0
- package/esm/src/resources/gears.js +27 -0
- package/esm/src/resources/routes.d.ts +33 -0
- package/esm/src/resources/routes.js +71 -0
- package/esm/src/resources/segment-efforts.d.ts +38 -0
- package/esm/src/resources/segment-efforts.js +53 -0
- package/esm/src/resources/segments.d.ts +42 -0
- package/esm/src/resources/segments.js +67 -0
- package/esm/src/resources/streams.d.ts +44 -0
- package/esm/src/resources/streams.js +75 -0
- package/esm/src/resources/uploads.d.ts +41 -0
- package/esm/src/resources/uploads.js +79 -0
- package/esm/src/types/api.d.ts +9 -0
- package/esm/src/types/api.js +7 -0
- package/esm/src/types/common.d.ts +65 -0
- package/esm/src/types/common.js +4 -0
- package/esm/src/types/generated.d.ts +731 -0
- package/esm/src/types/generated.js +7 -0
- package/esm/src/utils/pagination.d.ts +45 -0
- package/esm/src/utils/pagination.js +112 -0
- package/esm/src/utils/transformers.d.ts +30 -0
- package/esm/src/utils/transformers.js +189 -0
- package/esm/src/utils/validators.d.ts +53 -0
- package/esm/src/utils/validators.js +84 -0
- package/package.json +40 -0
- package/script/_dnt.shims.d.ts +2 -0
- package/script/_dnt.shims.js +60 -0
- package/script/deps/jsr.io/@cross/runtime/1.2.1/mod.d.ts +126 -0
- package/script/deps/jsr.io/@cross/runtime/1.2.1/mod.js +526 -0
- package/script/mod.d.ts +27 -0
- package/script/mod.js +73 -0
- package/script/package.json +3 -0
- package/script/src/auth/oauth.d.ts +68 -0
- package/script/src/auth/oauth.js +211 -0
- package/script/src/auth/scopes.d.ts +52 -0
- package/script/src/auth/scopes.js +79 -0
- package/script/src/auth/token-store.d.ts +57 -0
- package/script/src/auth/token-store.js +182 -0
- package/script/src/client.d.ts +98 -0
- package/script/src/client.js +239 -0
- package/script/src/errors.d.ts +52 -0
- package/script/src/errors.js +111 -0
- package/script/src/http/deduplication.d.ts +33 -0
- package/script/src/http/deduplication.js +100 -0
- package/script/src/http/rate-limiter.d.ts +47 -0
- package/script/src/http/rate-limiter.js +172 -0
- package/script/src/http/request.d.ts +24 -0
- package/script/src/http/request.js +161 -0
- package/script/src/http/retry.d.ts +9 -0
- package/script/src/http/retry.js +64 -0
- package/script/src/resources/activities.d.ts +149 -0
- package/script/src/resources/activities.js +193 -0
- package/script/src/resources/athletes.d.ts +37 -0
- package/script/src/resources/athletes.js +89 -0
- package/script/src/resources/clubs.d.ts +45 -0
- package/script/src/resources/clubs.js +75 -0
- package/script/src/resources/gears.d.ts +17 -0
- package/script/src/resources/gears.js +31 -0
- package/script/src/resources/routes.d.ts +33 -0
- package/script/src/resources/routes.js +75 -0
- package/script/src/resources/segment-efforts.d.ts +38 -0
- package/script/src/resources/segment-efforts.js +57 -0
- package/script/src/resources/segments.d.ts +42 -0
- package/script/src/resources/segments.js +71 -0
- package/script/src/resources/streams.d.ts +44 -0
- package/script/src/resources/streams.js +79 -0
- package/script/src/resources/uploads.d.ts +41 -0
- package/script/src/resources/uploads.js +83 -0
- package/script/src/types/api.d.ts +9 -0
- package/script/src/types/api.js +23 -0
- package/script/src/types/common.d.ts +65 -0
- package/script/src/types/common.js +5 -0
- package/script/src/types/generated.d.ts +731 -0
- package/script/src/types/generated.js +8 -0
- package/script/src/utils/pagination.d.ts +45 -0
- package/script/src/utils/pagination.js +118 -0
- package/script/src/utils/transformers.d.ts +30 -0
- package/script/src/utils/transformers.js +196 -0
- package/script/src/utils/validators.d.ts +53 -0
- package/script/src/utils/validators.js +92 -0
package/LICENSE
ADDED
|
@@ -0,0 +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.
|
package/README.md
ADDED
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
# @pinta365/strava
|
|
2
|
+
|
|
3
|
+
A cross-runtime TypeScript client for the Strava API v3. Works on Deno, Node.js (18+), Bun, and browsers.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ✅ **Type-safe**: Full TypeScript support with generated types from Swagger specification
|
|
8
|
+
- ✅ **Cross-runtime**: Works on Deno, Node.js, Bun, and browsers
|
|
9
|
+
- ✅ **OAuth 2.0**: Complete authentication flow with automatic token refresh
|
|
10
|
+
- ✅ **Rate limiting**: Built-in rate limit handling and queue management
|
|
11
|
+
- ✅ **Request optimization**: Automatic request deduplication and retry logic
|
|
12
|
+
- ✅ **Opinionated helpers**: Key normalization (snake_case → camelCase), date transformations, response flattening, computed fields
|
|
13
|
+
- ✅ **Pagination**: Auto-pagination iterators for easy data fetching
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
### Deno
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { StravaClient } from "https://deno.land/x/strava/mod.ts";
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Node.js / Bun
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install @pinta365/strava
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { StravaClient } from "@pinta365/strava";
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
### 1. Generate Types (First Time)
|
|
36
|
+
|
|
37
|
+
Before using the library, generate TypeScript types from the Strava API specification:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
deno task generate:types
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 2. Create Client
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { StravaClient } from "@pinta365/strava";
|
|
47
|
+
|
|
48
|
+
const client = new StravaClient({
|
|
49
|
+
clientId: "your-client-id",
|
|
50
|
+
clientSecret: "your-client-secret",
|
|
51
|
+
redirectUri: "https://yourapp.com/callback",
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 3. Authenticate
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
// Get authorization URL
|
|
59
|
+
const authUrl = client.getAuthorizationUrl({
|
|
60
|
+
scope: ["activity:read_all", "profile:read_all"],
|
|
61
|
+
state: "optional-csrf-token",
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Redirect user to authUrl
|
|
65
|
+
// After user authorizes, Strava redirects to your redirectUri with a code
|
|
66
|
+
|
|
67
|
+
// Exchange code for tokens
|
|
68
|
+
await client.authenticate({
|
|
69
|
+
code: "authorization-code-from-redirect",
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 4. Use the API
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
// Get authenticated athlete
|
|
77
|
+
const athlete = await client.athletes.get();
|
|
78
|
+
|
|
79
|
+
// Get activity by ID
|
|
80
|
+
const activity = await client.activities.getById(123456);
|
|
81
|
+
|
|
82
|
+
// Analyze activity with comprehensive data (zones, laps, best efforts, analysis)
|
|
83
|
+
const analysis = await client.activities.analyze(123456, {
|
|
84
|
+
includeStreams: false, // Optional: include stream data
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Get athlete stats with recent activities and gear
|
|
88
|
+
const profile = await client.athletes.getStatsWithActivities(athleteId, {
|
|
89
|
+
recentActivitiesLimit: 10,
|
|
90
|
+
includeGear: true,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// List activities with auto-pagination
|
|
94
|
+
for await (const activity of client.activities.listAll()) {
|
|
95
|
+
console.log(activity.name);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Get activity with all details
|
|
99
|
+
const details = await client.activities.getWithDetails(123456);
|
|
100
|
+
// Returns: activity + laps + zones + comments + kudoers
|
|
101
|
+
|
|
102
|
+
// Get activity streams
|
|
103
|
+
const streams = await client.streams.getForActivity(123456, {
|
|
104
|
+
types: ["time", "distance", "latlng", "altitude", "heartrate"],
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Clean up resources when done (important for long-running processes)
|
|
108
|
+
client.destroy();
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Configuration
|
|
112
|
+
|
|
113
|
+
### Client Options
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
const client = new StravaClient({
|
|
117
|
+
clientId: "your-client-id",
|
|
118
|
+
clientSecret: "your-client-secret",
|
|
119
|
+
redirectUri: "https://yourapp.com/callback",
|
|
120
|
+
|
|
121
|
+
// Token storage (auto-detected by default)
|
|
122
|
+
tokenStore: new FileSystemTokenStore("./tokens.json"),
|
|
123
|
+
|
|
124
|
+
// HTTP options
|
|
125
|
+
baseUrl: "https://www.strava.com/api/v3",
|
|
126
|
+
timeout: 30000,
|
|
127
|
+
|
|
128
|
+
// Retry configuration
|
|
129
|
+
retries: {
|
|
130
|
+
maxAttempts: 3,
|
|
131
|
+
initialDelay: 1000,
|
|
132
|
+
maxDelay: 10000,
|
|
133
|
+
backoffFactor: 2,
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
// Rate limit strategy
|
|
137
|
+
rateLimitStrategy: "queue", // 'queue' | 'throw' | 'wait'
|
|
138
|
+
|
|
139
|
+
// Request deduplication
|
|
140
|
+
deduplicationWindow: 5000, // milliseconds
|
|
141
|
+
|
|
142
|
+
// Response transformations
|
|
143
|
+
normalizeKeys: true, // Convert snake_case to camelCase (default: true)
|
|
144
|
+
transformDates: true, // Convert ISO strings to Date objects (default: true)
|
|
145
|
+
flattenResponses: true, // Flatten nested structures (default: true)
|
|
146
|
+
addComputedFields: true, // Add computed properties (see below) (default: true)
|
|
147
|
+
});
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Token Storage
|
|
151
|
+
|
|
152
|
+
The library automatically selects an appropriate token store based on the runtime:
|
|
153
|
+
|
|
154
|
+
- **Browser**: `LocalStorageTokenStore`
|
|
155
|
+
- **Node.js/Deno**: `FileSystemTokenStore`
|
|
156
|
+
- **Other**: `MemoryTokenStore`
|
|
157
|
+
|
|
158
|
+
You can also provide a custom token store:
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
import { TokenData, TokenStore } from "@pinta365/strava";
|
|
162
|
+
|
|
163
|
+
class CustomTokenStore implements TokenStore {
|
|
164
|
+
async get(): Promise<TokenData | null> {
|
|
165
|
+
// Load from your storage
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async set(token: TokenData): Promise<void> {
|
|
169
|
+
// Save to your storage
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async clear(): Promise<void> {
|
|
173
|
+
// Clear from your storage
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const client = new StravaClient({
|
|
178
|
+
clientId: "...",
|
|
179
|
+
clientSecret: "...",
|
|
180
|
+
tokenStore: new CustomTokenStore(),
|
|
181
|
+
});
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Response Transformations
|
|
185
|
+
|
|
186
|
+
The library applies opinionated transformations to API responses by default. These can be controlled via client options:
|
|
187
|
+
|
|
188
|
+
### Key Normalization (`normalizeKeys`)
|
|
189
|
+
|
|
190
|
+
Converts snake_case keys from the API to camelCase for JavaScript/TypeScript conventions:
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
// API returns: { start_date_local: "...", athlete_id: 123 }
|
|
194
|
+
// Library returns: { startDateLocal: "...", athleteId: 123 }
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Date Transformation (`transformDates`)
|
|
198
|
+
|
|
199
|
+
Converts ISO date strings to JavaScript `Date` objects:
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
// API returns: { startDateLocal: "2024-01-15T10:30:00Z" }
|
|
203
|
+
// Library returns: { startDateLocal: Date("2024-01-15T10:30:00Z") }
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Response Flattening (`flattenResponses`)
|
|
207
|
+
|
|
208
|
+
Flattens nested objects to the top level for easier access:
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
// API returns: { athlete: { id: 123, firstname: "John" } }
|
|
212
|
+
// Library returns: { athlete: { id: 123, firstname: "John" }, athleteId: 123, athleteFirstname: "John" }
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Computed Fields (`addComputedFields`)
|
|
216
|
+
|
|
217
|
+
Adds computed properties to activity objects for convenience:
|
|
218
|
+
|
|
219
|
+
#### For All Activities:
|
|
220
|
+
|
|
221
|
+
- **`averageSpeed`** (number, m/s): `distance / movingTime`
|
|
222
|
+
- **`averageSpeedKmh`** (number, km/h): `(distance / 1000) / (movingTime / 3600)`
|
|
223
|
+
- **`duration`** (object):
|
|
224
|
+
- `seconds`: Raw time in seconds
|
|
225
|
+
- `minutes`: `Math.floor(time / 60)`
|
|
226
|
+
- `hours`: `Math.floor(time / 3600)`
|
|
227
|
+
- `formatted`: Human-readable string (e.g., "1:23:45" or "23:45")
|
|
228
|
+
|
|
229
|
+
#### For Run Activities Only:
|
|
230
|
+
|
|
231
|
+
- **`pace`** (string): Formatted as "min:sec/km" (e.g., "5:30/km")
|
|
232
|
+
|
|
233
|
+
Example:
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
const activity = await client.activities.getById(123456);
|
|
237
|
+
|
|
238
|
+
// Computed fields available:
|
|
239
|
+
console.log(activity.averageSpeed); // 3.5 (m/s)
|
|
240
|
+
console.log(activity.averageSpeedKmh); // 12.6 (km/h)
|
|
241
|
+
console.log(activity.pace); // "5:30/km" (if it's a Run)
|
|
242
|
+
console.log(activity.duration.formatted); // "1:23:45"
|
|
243
|
+
console.log(activity.duration.hours); // 1
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Cleanup
|
|
247
|
+
|
|
248
|
+
When you're done with the client (especially in long-running processes or scripts), call `destroy()` to clean up resources and allow the process to
|
|
249
|
+
exit:
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
// After all API calls are complete
|
|
253
|
+
client.destroy();
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
This clears internal timers and caches, which is important for scripts that should exit automatically.
|
|
257
|
+
|
|
258
|
+
## Resources
|
|
259
|
+
|
|
260
|
+
The client provides resource namespaces for different API endpoints:
|
|
261
|
+
|
|
262
|
+
- `client.athletes` - Athlete information and stats
|
|
263
|
+
- `client.activities` - Activity CRUD and operations
|
|
264
|
+
- `client.segments` - Segment information and exploration
|
|
265
|
+
- `client.segmentEfforts` - Segment effort data
|
|
266
|
+
- `client.clubs` - Club information and members
|
|
267
|
+
- `client.gears` - Gear information
|
|
268
|
+
- `client.routes` - Route information and downloads
|
|
269
|
+
- `client.uploads` - Activity file uploads
|
|
270
|
+
- `client.streams` - Activity, segment, and route streams
|
|
271
|
+
|
|
272
|
+
### Opinionated Helpers
|
|
273
|
+
|
|
274
|
+
The library provides opinionated helper methods that combine multiple API calls for convenience:
|
|
275
|
+
|
|
276
|
+
#### Activity Analysis
|
|
277
|
+
|
|
278
|
+
Analyze an activity with comprehensive data including zones, laps, best efforts, and computed insights:
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
const analysis = await client.activities.analyze(activityId, {
|
|
282
|
+
includeStreams: false, // Optional: include stream data (may require premium)
|
|
283
|
+
streamTypes: ["heartrate", "watts", "cadence"], // Optional: specific stream types
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
// Analysis includes:
|
|
287
|
+
// - Full activity details
|
|
288
|
+
// - Zones (power/heart rate)
|
|
289
|
+
// - Laps
|
|
290
|
+
// - Best efforts (segment efforts)
|
|
291
|
+
// - Optional streams
|
|
292
|
+
// - Computed analysis:
|
|
293
|
+
// - hasPowerData: boolean
|
|
294
|
+
// - hasHeartRateData: boolean
|
|
295
|
+
// - totalLaps: number
|
|
296
|
+
// - bestEffortCount: number
|
|
297
|
+
// - averageLapTime: number (seconds)
|
|
298
|
+
// - averageLapDistance: number (meters)
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
#### Activity Details
|
|
302
|
+
|
|
303
|
+
Get activity with all related data (laps, zones, comments, kudoers):
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
const details = await client.activities.getWithDetails(activityId);
|
|
307
|
+
// Returns: activity + laps + zones + comments + kudoers
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
#### Athlete Profile with Stats
|
|
311
|
+
|
|
312
|
+
Get comprehensive athlete profile including stats, recent activities, and gear:
|
|
313
|
+
|
|
314
|
+
```typescript
|
|
315
|
+
const profile = await client.athletes.getStatsWithActivities(athleteId, {
|
|
316
|
+
recentActivitiesLimit: 10, // Number of recent activities to fetch
|
|
317
|
+
includeGear: true, // Include detailed gear information (bikes + shoes)
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
// Profile includes:
|
|
321
|
+
// - Full athlete details
|
|
322
|
+
// - Activity stats (totals, PRs, etc.)
|
|
323
|
+
// - Recent activities array
|
|
324
|
+
// - Gear details (optional)
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
## Error Handling
|
|
328
|
+
|
|
329
|
+
The library provides custom error classes:
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
import { StravaAuthError, StravaError, StravaNotFoundError, StravaRateLimitError, StravaServerError, StravaValidationError } from "@pinta365/strava";
|
|
333
|
+
|
|
334
|
+
try {
|
|
335
|
+
const activity = await client.activities.getById(123);
|
|
336
|
+
} catch (error) {
|
|
337
|
+
if (error instanceof StravaNotFoundError) {
|
|
338
|
+
console.log("Activity not found");
|
|
339
|
+
} else if (error instanceof StravaRateLimitError) {
|
|
340
|
+
console.log(`Rate limited. Retry after ${error.retryAfter} seconds`);
|
|
341
|
+
} else if (error instanceof StravaAuthError) {
|
|
342
|
+
console.log("Authentication failed");
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
## OAuth Scopes
|
|
348
|
+
|
|
349
|
+
Available scopes:
|
|
350
|
+
|
|
351
|
+
- `read` - Read public segments, public routes, public profile data, public posts, public events, club feeds, and leaderboards
|
|
352
|
+
- `read_all` - Read private routes, private segments, and private events for the user
|
|
353
|
+
- `profile:read_all` - Read all profile information even if the user has set their profile visibility to Followers or Only You
|
|
354
|
+
- `profile:write` - Update the user's weight and Functional Threshold Power (FTP), and access to star or unstar segments on their behalf
|
|
355
|
+
- `activity:read` - Read the user's activity data for activities that are visible to Everyone and Followers, excluding privacy zone data
|
|
356
|
+
- `activity:read_all` - The same access as `activity:read`, plus privacy zone data and access to read the user's activities with visibility set to
|
|
357
|
+
Only You
|
|
358
|
+
- `activity:write` - Access to create manual activities and uploads, and access to edit any activities that are visible to the app, based on activity
|
|
359
|
+
read access level
|
|
360
|
+
|
|
361
|
+
## Development
|
|
362
|
+
|
|
363
|
+
### Generate Types
|
|
364
|
+
|
|
365
|
+
```bash
|
|
366
|
+
deno task generate:types
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### Run Tests
|
|
370
|
+
|
|
371
|
+
```bash
|
|
372
|
+
deno test -A
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### Format and Lint
|
|
376
|
+
|
|
377
|
+
```bash
|
|
378
|
+
deno fmt
|
|
379
|
+
deno lint
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### Pre-push Validation
|
|
383
|
+
|
|
384
|
+
```bash
|
|
385
|
+
deno task prepush
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
## License
|
|
389
|
+
|
|
390
|
+
MIT
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const dntGlobals = {};
|
|
2
|
+
export const dntGlobalThis = createMergeProxy(globalThis, dntGlobals);
|
|
3
|
+
function createMergeProxy(baseObj, extObj) {
|
|
4
|
+
return new Proxy(baseObj, {
|
|
5
|
+
get(_target, prop, _receiver) {
|
|
6
|
+
if (prop in extObj) {
|
|
7
|
+
return extObj[prop];
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
return baseObj[prop];
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
set(_target, prop, value) {
|
|
14
|
+
if (prop in extObj) {
|
|
15
|
+
delete extObj[prop];
|
|
16
|
+
}
|
|
17
|
+
baseObj[prop] = value;
|
|
18
|
+
return true;
|
|
19
|
+
},
|
|
20
|
+
deleteProperty(_target, prop) {
|
|
21
|
+
let success = false;
|
|
22
|
+
if (prop in extObj) {
|
|
23
|
+
delete extObj[prop];
|
|
24
|
+
success = true;
|
|
25
|
+
}
|
|
26
|
+
if (prop in baseObj) {
|
|
27
|
+
delete baseObj[prop];
|
|
28
|
+
success = true;
|
|
29
|
+
}
|
|
30
|
+
return success;
|
|
31
|
+
},
|
|
32
|
+
ownKeys(_target) {
|
|
33
|
+
const baseKeys = Reflect.ownKeys(baseObj);
|
|
34
|
+
const extKeys = Reflect.ownKeys(extObj);
|
|
35
|
+
const extKeysSet = new Set(extKeys);
|
|
36
|
+
return [...baseKeys.filter((k) => !extKeysSet.has(k)), ...extKeys];
|
|
37
|
+
},
|
|
38
|
+
defineProperty(_target, prop, desc) {
|
|
39
|
+
if (prop in extObj) {
|
|
40
|
+
delete extObj[prop];
|
|
41
|
+
}
|
|
42
|
+
Reflect.defineProperty(baseObj, prop, desc);
|
|
43
|
+
return true;
|
|
44
|
+
},
|
|
45
|
+
getOwnPropertyDescriptor(_target, prop) {
|
|
46
|
+
if (prop in extObj) {
|
|
47
|
+
return Reflect.getOwnPropertyDescriptor(extObj, prop);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
return Reflect.getOwnPropertyDescriptor(baseObj, prop);
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
has(_target, prop) {
|
|
54
|
+
return prop in extObj || prop in baseObj;
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enum of supported Runtimes.
|
|
3
|
+
* @enum {string}
|
|
4
|
+
*/
|
|
5
|
+
export declare enum Runtime {
|
|
6
|
+
Deno = "deno",
|
|
7
|
+
Bun = "bun",
|
|
8
|
+
Node = "node",
|
|
9
|
+
Browser = "browser",
|
|
10
|
+
Tauri = "tauri",
|
|
11
|
+
Workerd = "workerd",
|
|
12
|
+
Netlify = "netlify",
|
|
13
|
+
EdgeLight = "edgelight",
|
|
14
|
+
Fastly = "fastly",
|
|
15
|
+
Unsupported = "unsupported"
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Enum of supported Operating Systems.
|
|
19
|
+
* @enum {string}
|
|
20
|
+
*/
|
|
21
|
+
export declare enum OperatingSystem {
|
|
22
|
+
Windows = "windows",
|
|
23
|
+
macOS = "macos",
|
|
24
|
+
Linux = "linux",
|
|
25
|
+
Android = "android",
|
|
26
|
+
Unix = "unix",
|
|
27
|
+
iOS = "ios",
|
|
28
|
+
Unsupported = "unsupported"
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Enum of supported Products.
|
|
32
|
+
* @enum {string}
|
|
33
|
+
*/
|
|
34
|
+
export declare enum Product {
|
|
35
|
+
Deno = "deno",
|
|
36
|
+
Bun = "bun",
|
|
37
|
+
Node = "node",
|
|
38
|
+
Tauri = "tauri",
|
|
39
|
+
Workerd = "workerd",
|
|
40
|
+
Netlify = "netlify",
|
|
41
|
+
EdgeLight = "edgelight",
|
|
42
|
+
Fastly = "fastly",
|
|
43
|
+
Firefox = "firefox",
|
|
44
|
+
Safari = "safari",
|
|
45
|
+
Chrome = "chrome",
|
|
46
|
+
Edge = "edge",
|
|
47
|
+
Opera = "opera",
|
|
48
|
+
Brave = "brave",
|
|
49
|
+
Unsupported = "unsupported"
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Enum of common CPU architectures.
|
|
53
|
+
* @enum {string}
|
|
54
|
+
*/
|
|
55
|
+
export declare enum Architecture {
|
|
56
|
+
x86 = "x86",
|
|
57
|
+
x64 = "x86_64",
|
|
58
|
+
arm = "arm",
|
|
59
|
+
arm64 = "arm64",
|
|
60
|
+
Unsupported = "unsupported"
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Dynamically determines the current runtime environment.
|
|
64
|
+
*/
|
|
65
|
+
export declare function getCurrentRuntime(): Runtime;
|
|
66
|
+
/**
|
|
67
|
+
* Dynamically determines the current operating system.
|
|
68
|
+
*/
|
|
69
|
+
export declare function getCurrentOS(): OperatingSystem;
|
|
70
|
+
/**
|
|
71
|
+
* Determine operating system from user agent string, if possible
|
|
72
|
+
*/
|
|
73
|
+
export declare function getOSFromUserAgent(userAgent: string): OperatingSystem;
|
|
74
|
+
/**
|
|
75
|
+
* Dynamically determines the current browser and its version (if applicable).
|
|
76
|
+
*/
|
|
77
|
+
export declare function getCurrentProduct(): Product;
|
|
78
|
+
/**
|
|
79
|
+
* Determines the product from a user agent string, if possible
|
|
80
|
+
*/
|
|
81
|
+
export declare function getProductFromUserAgent(userAgent: string): Product;
|
|
82
|
+
/**
|
|
83
|
+
* Dynamically determines the version of the current product/runtime
|
|
84
|
+
* @returns {string} A string containing the detected version, or undefined if the product is not supported.
|
|
85
|
+
*/
|
|
86
|
+
export declare function getCurrentVersion(): string | undefined;
|
|
87
|
+
/**
|
|
88
|
+
* Determines the product version from a user agent string, if possible
|
|
89
|
+
*/
|
|
90
|
+
export declare function getVersionFromUserAgent(userAgent: string): string | undefined;
|
|
91
|
+
/**
|
|
92
|
+
* Attempts to determine the current CPU architecture of the runtime's environment.
|
|
93
|
+
*/
|
|
94
|
+
export declare function getCurrentArchitecture(): Architecture;
|
|
95
|
+
/**
|
|
96
|
+
* Logs current system information to the console.
|
|
97
|
+
*
|
|
98
|
+
* @param {boolean} [useTable=false] - If true, formats the output as a table.
|
|
99
|
+
*/
|
|
100
|
+
export declare function dumpSystemInfo(useTable?: boolean): void;
|
|
101
|
+
/**
|
|
102
|
+
* Gets the current system information as a formatted JSON string.
|
|
103
|
+
* @returns {string}
|
|
104
|
+
*/
|
|
105
|
+
export declare function getSystemInfo(): string;
|
|
106
|
+
/**
|
|
107
|
+
* Static variable containing the current runtime.
|
|
108
|
+
*/
|
|
109
|
+
export declare const CurrentRuntime: Runtime;
|
|
110
|
+
/**
|
|
111
|
+
* Static variable containing the current product.
|
|
112
|
+
*/
|
|
113
|
+
export declare const CurrentProduct: Product;
|
|
114
|
+
/**
|
|
115
|
+
* Static variable containing the current product/runtime version.
|
|
116
|
+
*/
|
|
117
|
+
export declare const CurrentVersion: string | undefined;
|
|
118
|
+
/**
|
|
119
|
+
* Static variable containing the current operating system.
|
|
120
|
+
*/
|
|
121
|
+
export declare const CurrentOS: OperatingSystem | undefined;
|
|
122
|
+
/**
|
|
123
|
+
* Static variable containing the current operating system.
|
|
124
|
+
*/
|
|
125
|
+
export declare const CurrentArchitecture: Architecture | undefined;
|
|
126
|
+
//# sourceMappingURL=mod.d.ts.map
|