@dofek/peloton 0.1.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025-2026 Asher Cohen
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,170 @@
1
+ # @dofek/peloton
2
+
3
+ Unofficial TypeScript client for Peloton's private member API. It includes
4
+ workout and performance-graph access, runtime response validation, PKCE token
5
+ exchange and refresh, and the observed Auth0 username/password browser flow.
6
+
7
+ This package is not affiliated with, endorsed by, or supported by Peloton.
8
+ The endpoints and automated login flow are undocumented implementation
9
+ details and may change without notice. Review the
10
+ [implementation](https://github.com/Asherlc/dofek/tree/main/packages/peloton-client/src)
11
+ before using it with an account you care about.
12
+
13
+ ## Requirements and installation
14
+
15
+ Requires Node.js 22.14 or newer and its built-in
16
+ [`fetch`](https://nodejs.org/api/globals.html#fetch).
17
+
18
+ ```sh
19
+ npm install @dofek/peloton
20
+ ```
21
+
22
+ ## Quick start: automated sign-in
23
+
24
+ Set `PELOTON_EMAIL` and `PELOTON_PASSWORD`, save this as `example.mjs`, and run
25
+ `node example.mjs`:
26
+
27
+ ```js
28
+ import { PelotonClient } from "@dofek/peloton";
29
+ import { pelotonAutomatedLogin } from "@dofek/peloton/auth";
30
+
31
+ const email = process.env.PELOTON_EMAIL;
32
+ const password = process.env.PELOTON_PASSWORD;
33
+ if (!email || !password) {
34
+ throw new Error("Set PELOTON_EMAIL and PELOTON_PASSWORD");
35
+ }
36
+
37
+ const tokens = await pelotonAutomatedLogin(email, password);
38
+ const client = new PelotonClient(tokens.accessToken);
39
+ const workouts = await client.getWorkouts(0, 20);
40
+
41
+ console.log(workouts.data);
42
+ ```
43
+
44
+ `pelotonAutomatedLogin` drives the currently observed Auth0 Universal Login
45
+ HTML flow. Auth0 documents Universal Login as a browser authentication
46
+ experience, so automation is inherently more fragile than opening the
47
+ authorization URL in a user-controlled browser.
48
+ [Auth0 Universal Login documentation](https://auth0.com/docs/authenticate/login/auth0-universal-login)
49
+
50
+ Treat the password, access token, and refresh token as secrets. Do not log or
51
+ commit them. Multi-factor authentication, bot checks, account policy, or an
52
+ upstream page change can prevent automated login.
53
+
54
+ ## Browser authorization with PKCE
55
+
56
+ For applications that can receive Peloton's configured callback, create a
57
+ PKCE authorization request, retain the verifier, and exchange the callback
58
+ code:
59
+
60
+ ```ts
61
+ import {
62
+ createPelotonAuthorization,
63
+ exchangePelotonAuthorizationCode,
64
+ } from "@dofek/peloton/auth";
65
+
66
+ const authorization = createPelotonAuthorization();
67
+ console.log("Open this URL:", authorization.url);
68
+
69
+ // Obtain `code` from the callback URL in your application.
70
+ const tokens = await exchangePelotonAuthorizationCode(
71
+ code,
72
+ authorization.codeVerifier,
73
+ );
74
+ ```
75
+
76
+ The verifier must remain private and be paired with the same authorization
77
+ request. PKCE is standardized by
78
+ [RFC 7636](https://www.rfc-editor.org/rfc/rfc7636), and Auth0 describes the
79
+ [authorization-code flow with PKCE](https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce).
80
+
81
+ ## Refreshing tokens
82
+
83
+ Persist the complete token set in encrypted storage. Before API use, compare
84
+ `expiresAt` with the current time. Refresh an expired token and atomically
85
+ replace the stored set:
86
+
87
+ ```ts
88
+ import { refreshPelotonAccessToken } from "@dofek/peloton/auth";
89
+
90
+ if (!tokens.refreshToken) {
91
+ throw new Error("Peloton did not return a refresh token; sign in again");
92
+ }
93
+
94
+ const refreshed = await refreshPelotonAccessToken(tokens.refreshToken);
95
+ ```
96
+
97
+ If Peloton does not rotate the refresh token, the returned token set retains
98
+ the one supplied to `refreshPelotonAccessToken`.
99
+
100
+ ## API client
101
+
102
+ ```ts
103
+ import { PelotonClient } from "@dofek/peloton/client";
104
+
105
+ const client = new PelotonClient(accessToken);
106
+
107
+ const userId = await client.getUserId();
108
+ const page = await client.getWorkouts(0, 20);
109
+ const graph = await client.getPerformanceGraph(page.data[0].id, 5);
110
+ ```
111
+
112
+ - `getUserId()` retrieves and caches the current Peloton member ID.
113
+ - `getWorkouts(page?, limit?)` returns a validated workout page joined with
114
+ ride and instructor details.
115
+ - `getPerformanceGraph(workoutId, everyN?)` returns validated metric samples;
116
+ `everyN` is the requested sampling interval in seconds.
117
+
118
+ All remote JSON crosses a
119
+ [`zod`](https://zod.dev/) schema boundary. A successful HTTP response whose
120
+ shape does not match the currently observed API throws
121
+ `PelotonResponseError`.
122
+
123
+ ## Parsing
124
+
125
+ ```ts
126
+ import {
127
+ parsePerformanceGraph,
128
+ parseWorkout,
129
+ } from "@dofek/peloton/parsing";
130
+
131
+ const workout = parseWorkout(page.data[0]);
132
+ const series = parsePerformanceGraph(graph, 5);
133
+ ```
134
+
135
+ `parseWorkout` maps Peloton disciplines to the canonical activity types from
136
+ `@dofek/training`, converts Unix timestamps to `Date`, and retains useful
137
+ source metadata. `parsePerformanceGraph` adds a seconds offset to every metric
138
+ sample. It does not aggregate, merge, or discard samples.
139
+
140
+ ## Errors and rate limits
141
+
142
+ - `PelotonAuthenticationError` indicates an API `401`.
143
+ - `PelotonServiceError` represents other unsuccessful Peloton API responses
144
+ and exposes `statusCode` and `responseBody`.
145
+ - `PelotonAuthFlowError` identifies the failed authentication stage and may
146
+ include HTTP diagnostics.
147
+ - `PelotonResponseError` identifies an invalid successful response.
148
+ - `ProviderRateLimitError` and `ProviderServiceUnavailableError` come from
149
+ `@dofek/provider-http` for `429` and transient `502`/`503`/`504` responses.
150
+
151
+ Declare `@dofek/provider-http` directly if your application imports its error
152
+ classes. Its retry-delay parsing follows the HTTP `Retry-After` semantics in
153
+ [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-retry-after).
154
+
155
+ ## Public modules
156
+
157
+ - `@dofek/peloton` — API client and base URL.
158
+ - `@dofek/peloton/auth` — login, authorization-code exchange, refresh, and
159
+ token types.
160
+ - `@dofek/peloton/client` — API client and base URL.
161
+ - `@dofek/peloton/errors` — typed package errors.
162
+ - `@dofek/peloton/parsing` — pure workout and graph parsers.
163
+ - `@dofek/peloton/types` — Zod schemas and inferred raw API types.
164
+
165
+ ## Project
166
+
167
+ - [Source](https://github.com/Asherlc/dofek/tree/main/packages/peloton-client)
168
+ - [Report an issue](https://github.com/Asherlc/dofek/issues)
169
+ - [Contribute a pull request](https://github.com/Asherlc/dofek/pulls)
170
+ - License: [MIT](./LICENSE)
package/dist/auth.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ import type { PelotonOAuthConfig, PelotonTokenSet } from "./types.ts";
2
+ export declare function pelotonOAuthConfig(_host?: string): PelotonOAuthConfig;
3
+ export interface PelotonAuthorization {
4
+ url: string;
5
+ codeVerifier: string;
6
+ }
7
+ export declare function createPelotonAuthorization(): PelotonAuthorization;
8
+ export declare function exchangePelotonAuthorizationCode(code: string, codeVerifier: string, fetchFn?: typeof globalThis.fetch): Promise<PelotonTokenSet>;
9
+ export declare function refreshPelotonAccessToken(refreshToken: string, fetchFn?: typeof globalThis.fetch): Promise<PelotonTokenSet>;
10
+ export declare function parseAuth0FormHtml(html: string): {
11
+ action: string;
12
+ fields: Record<string, string>;
13
+ };
14
+ export declare function pelotonAutomatedLogin(email: string, password: string, fetchFn?: typeof globalThis.fetch): Promise<PelotonTokenSet>;
15
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAqBtE,wBAAgB,kBAAkB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,kBAAkB,CAUrE;AAyBD,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,0BAA0B,IAAI,oBAAoB,CAMjE;AAmCD,wBAAgB,gCAAgC,CAC9C,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,OAAO,UAAU,CAAC,KAAwB,GAClD,OAAO,CAAC,eAAe,CAAC,CAY1B;AAED,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,OAAO,UAAU,CAAC,KAAwB,GAClD,OAAO,CAAC,eAAe,CAAC,CAM1B;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC,CAaA;AA8DD,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,OAAO,UAAU,CAAC,KAAwB,GAClD,OAAO,CAAC,eAAe,CAAC,CA+G1B"}
package/dist/auth.js ADDED
@@ -0,0 +1,252 @@
1
+ import { createHash, randomBytes } from "node:crypto";
2
+ import { createRateLimitAwareFetch } from "@dofek/provider-http/rate-limit";
3
+ import { z } from "zod";
4
+ import { PelotonAuthFlowError, PelotonResponseError } from "./errors.js";
5
+ const PELOTON_AUTH_DOMAIN = "https://auth.onepeloton.com";
6
+ const PELOTON_CLIENT_ID = "WVoJxVDdPoFx4RNewvvg6ch2mZ7bwnsM";
7
+ const PELOTON_REDIRECT_URI = "https://members.onepeloton.com/callback";
8
+ const PELOTON_API_BASE = "https://api.onepeloton.com";
9
+ const AUTH0_CLIENT = btoa(JSON.stringify({ name: "auth0.js-ulp", version: "9.14.3" }));
10
+ const tokenResponseSchema = z.object({
11
+ access_token: z.string().min(1),
12
+ refresh_token: z.string().min(1).optional(),
13
+ expires_in: z.number().positive(),
14
+ scope: z.string().optional(),
15
+ });
16
+ const injectedConfigSchema = z.object({
17
+ extraParams: z.object({
18
+ state: z.string().min(1),
19
+ _csrf: z.string().min(1),
20
+ nonce: z.string().optional(),
21
+ }),
22
+ });
23
+ export function pelotonOAuthConfig(_host) {
24
+ return {
25
+ clientId: PELOTON_CLIENT_ID,
26
+ authorizeUrl: `${PELOTON_AUTH_DOMAIN}/authorize`,
27
+ tokenUrl: `${PELOTON_AUTH_DOMAIN}/oauth/token`,
28
+ redirectUri: PELOTON_REDIRECT_URI,
29
+ scopes: ["offline_access", "openid", "peloton-api.members:default"],
30
+ usePkce: true,
31
+ audience: `${PELOTON_API_BASE}/`,
32
+ };
33
+ }
34
+ function generateCodeVerifier() {
35
+ return randomBytes(32).toString("base64url");
36
+ }
37
+ function generateCodeChallenge(verifier) {
38
+ return createHash("sha256").update(verifier).digest("base64url");
39
+ }
40
+ function buildAuthorizationUrl(codeChallenge, state, nonce) {
41
+ const config = pelotonOAuthConfig();
42
+ const url = new URL(config.authorizeUrl);
43
+ url.searchParams.set("client_id", config.clientId);
44
+ url.searchParams.set("redirect_uri", config.redirectUri);
45
+ url.searchParams.set("response_type", "code");
46
+ url.searchParams.set("scope", config.scopes.join(" "));
47
+ url.searchParams.set("audience", config.audience);
48
+ url.searchParams.set("code_challenge", codeChallenge);
49
+ url.searchParams.set("code_challenge_method", "S256");
50
+ if (state)
51
+ url.searchParams.set("state", state);
52
+ if (nonce)
53
+ url.searchParams.set("nonce", nonce);
54
+ return url.toString();
55
+ }
56
+ export function createPelotonAuthorization() {
57
+ const codeVerifier = generateCodeVerifier();
58
+ return {
59
+ url: buildAuthorizationUrl(generateCodeChallenge(codeVerifier)),
60
+ codeVerifier,
61
+ };
62
+ }
63
+ async function requestTokens(params, fallbackRefreshToken, fetchFn) {
64
+ const config = pelotonOAuthConfig();
65
+ const rateLimitFetch = createRateLimitAwareFetch(fetchFn, { providerId: "peloton" });
66
+ const response = await rateLimitFetch(config.tokenUrl, {
67
+ method: "POST",
68
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
69
+ body: new URLSearchParams({ ...params, client_id: config.clientId }).toString(),
70
+ });
71
+ if (!response.ok) {
72
+ const responseBody = await response.text();
73
+ throw new PelotonAuthFlowError("token", `Peloton token request failed (${response.status})`, {
74
+ statusCode: response.status,
75
+ responseBody,
76
+ });
77
+ }
78
+ try {
79
+ const body = tokenResponseSchema.parse(await response.json());
80
+ return {
81
+ accessToken: body.access_token,
82
+ refreshToken: body.refresh_token ?? fallbackRefreshToken,
83
+ expiresAt: new Date(Date.now() + body.expires_in * 1000),
84
+ scopes: body.scope ?? null,
85
+ };
86
+ }
87
+ catch (error) {
88
+ throw new PelotonResponseError("token", error);
89
+ }
90
+ }
91
+ export function exchangePelotonAuthorizationCode(code, codeVerifier, fetchFn = globalThis.fetch) {
92
+ const config = pelotonOAuthConfig();
93
+ return requestTokens({
94
+ grant_type: "authorization_code",
95
+ code,
96
+ redirect_uri: config.redirectUri,
97
+ code_verifier: codeVerifier,
98
+ }, null, fetchFn);
99
+ }
100
+ export function refreshPelotonAccessToken(refreshToken, fetchFn = globalThis.fetch) {
101
+ return requestTokens({ grant_type: "refresh_token", refresh_token: refreshToken }, refreshToken, fetchFn);
102
+ }
103
+ export function parseAuth0FormHtml(html) {
104
+ const action = html.match(/<form[^>]+action="([^"]+)"/)?.[1];
105
+ if (!action) {
106
+ throw new PelotonAuthFlowError("login-form", "Could not find form action in Auth0 response");
107
+ }
108
+ const fields = {};
109
+ for (const match of html.matchAll(/<input[^>]+type="hidden"[^>]*>/gi)) {
110
+ const tag = match[0];
111
+ const name = tag.match(/name="([^"]+)"/)?.[1];
112
+ if (name)
113
+ fields[name] = tag.match(/value="([^"]*)"/)?.[1] ?? "";
114
+ }
115
+ return { action, fields };
116
+ }
117
+ function getSetCookieHeaders(headers) {
118
+ if (typeof headers.getSetCookie === "function")
119
+ return headers.getSetCookie();
120
+ const combined = headers.get("set-cookie");
121
+ return combined ? combined.split(/,\s*(?=[^;,=\s]+=[^;,]*)/) : [];
122
+ }
123
+ class CookieJar {
124
+ #cookies = new Map();
125
+ addFromResponse(url, headers) {
126
+ const domain = new URL(url).hostname;
127
+ const cookies = this.#cookies.get(domain) ?? new Map();
128
+ for (const header of getSetCookieHeaders(headers)) {
129
+ const match = header.match(/^([^=]+)=([^;]*)/);
130
+ const name = match?.[1];
131
+ const value = match?.[2];
132
+ if (name !== undefined && value !== undefined)
133
+ cookies.set(name, value);
134
+ }
135
+ this.#cookies.set(domain, cookies);
136
+ }
137
+ getForUrl(url) {
138
+ const hostname = new URL(url).hostname;
139
+ const values = [];
140
+ for (const [domain, cookies] of this.#cookies) {
141
+ if (hostname === domain || hostname.endsWith(`.${domain}`)) {
142
+ for (const [name, value] of cookies)
143
+ values.push(`${name}=${value}`);
144
+ }
145
+ }
146
+ return values.join("; ");
147
+ }
148
+ }
149
+ async function followRedirect(url, jar, fetchFn, init) {
150
+ const fullUrl = new URL(url, PELOTON_AUTH_DOMAIN).toString();
151
+ const response = await fetchFn(fullUrl, {
152
+ ...init,
153
+ redirect: "manual",
154
+ headers: { ...(init?.headers ?? {}), Cookie: jar.getForUrl(fullUrl) },
155
+ });
156
+ jar.addFromResponse(fullUrl, response.headers);
157
+ return { response, location: response.headers.get("location") };
158
+ }
159
+ function decodeHtmlEntities(value) {
160
+ return value
161
+ .replace(/&#34;/g, '"')
162
+ .replace(/&#39;/g, "'")
163
+ .replace(/&quot;/g, '"')
164
+ .replace(/&#x27;/g, "'")
165
+ .replace(/&lt;/g, "<")
166
+ .replace(/&gt;/g, ">")
167
+ .replace(/&amp;/g, "&");
168
+ }
169
+ export async function pelotonAutomatedLogin(email, password, fetchFn = globalThis.fetch) {
170
+ const rateLimitFetch = createRateLimitAwareFetch(fetchFn, { providerId: "peloton" });
171
+ const config = pelotonOAuthConfig();
172
+ const codeVerifier = generateCodeVerifier();
173
+ const codeChallenge = generateCodeChallenge(codeVerifier);
174
+ const state = generateCodeVerifier();
175
+ const nonce = generateCodeVerifier();
176
+ const jar = new CookieJar();
177
+ let { response, location } = await followRedirect(buildAuthorizationUrl(codeChallenge, state, nonce), jar, rateLimitFetch);
178
+ let redirectsRemaining = 15;
179
+ while (location && redirectsRemaining > 0) {
180
+ ({ response, location } = await followRedirect(location, jar, rateLimitFetch));
181
+ redirectsRemaining--;
182
+ }
183
+ if (location) {
184
+ throw new PelotonAuthFlowError("authorize", "Auth0 authorization redirect limit exceeded");
185
+ }
186
+ const loginPageHtml = await response.text();
187
+ const encodedConfig = loginPageHtml.match(/window\.injectedConfig\s*=\s*[^"]*"([^"]+)"/)?.[1];
188
+ if (!encodedConfig) {
189
+ throw new PelotonAuthFlowError("authorize", "Could not find injectedConfig in Auth0 login page");
190
+ }
191
+ let extraParams;
192
+ try {
193
+ extraParams = injectedConfigSchema.parse(JSON.parse(Buffer.from(encodedConfig, "base64").toString("utf8"))).extraParams;
194
+ }
195
+ catch (error) {
196
+ throw new PelotonResponseError("Auth0 injected configuration", error);
197
+ }
198
+ const loginUrl = `${PELOTON_AUTH_DOMAIN}/usernamepassword/login`;
199
+ const { response: loginResponse } = await followRedirect(loginUrl, jar, rateLimitFetch, {
200
+ method: "POST",
201
+ headers: { "Content-Type": "application/json", "Auth0-Client": AUTH0_CLIENT },
202
+ body: JSON.stringify({
203
+ client_id: config.clientId,
204
+ redirect_uri: config.redirectUri,
205
+ tenant: "peloton-prod",
206
+ response_type: "code",
207
+ scope: config.scopes.join(" "),
208
+ audience: config.audience,
209
+ _csrf: extraParams._csrf,
210
+ state: extraParams.state,
211
+ nonce: extraParams.nonce ?? nonce,
212
+ connection: "pelo-user-password",
213
+ username: email,
214
+ password,
215
+ code_challenge: codeChallenge,
216
+ code_challenge_method: "S256",
217
+ }),
218
+ });
219
+ if (!loginResponse.ok) {
220
+ const responseBody = await loginResponse.text();
221
+ throw new PelotonAuthFlowError("credentials", `Auth0 login failed (${loginResponse.status}): ${responseBody}`, { statusCode: loginResponse.status, responseBody });
222
+ }
223
+ const { action, fields: encodedFields } = parseAuth0FormHtml(await loginResponse.text());
224
+ const fields = Object.fromEntries(Object.entries(encodedFields).map(([key, value]) => [key, decodeHtmlEntities(value)]));
225
+ let { location: callbackLocation } = await followRedirect(action, jar, rateLimitFetch, {
226
+ method: "POST",
227
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
228
+ body: new URLSearchParams(fields).toString(),
229
+ });
230
+ redirectsRemaining = 15;
231
+ while (callbackLocation &&
232
+ !callbackLocation.includes("code=") &&
233
+ !callbackLocation.includes("error=") &&
234
+ redirectsRemaining > 0) {
235
+ ({ location: callbackLocation } = await followRedirect(callbackLocation, jar, rateLimitFetch));
236
+ redirectsRemaining--;
237
+ }
238
+ if (!callbackLocation) {
239
+ throw new PelotonAuthFlowError("callback", "Auth0 redirect chain ended without a Location header");
240
+ }
241
+ const callbackUrl = new URL(callbackLocation, PELOTON_REDIRECT_URI);
242
+ const authError = callbackUrl.searchParams.get("error");
243
+ if (authError) {
244
+ throw new PelotonAuthFlowError("callback", `Auth0 returned error: ${callbackUrl.searchParams.get("error_description") ?? authError}`);
245
+ }
246
+ const code = callbackUrl.searchParams.get("code");
247
+ if (!code) {
248
+ throw new PelotonAuthFlowError("callback", "Authorization code not found in callback URL");
249
+ }
250
+ return exchangePelotonAuthorizationCode(code, codeVerifier, rateLimitFetch);
251
+ }
252
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { type PelotonPerformanceGraph, type PelotonWorkoutListResponse } from "./types.ts";
2
+ export declare const PELOTON_API_BASE = "https://api.onepeloton.com";
3
+ export declare class PelotonClient {
4
+ #private;
5
+ constructor(accessToken: string, fetchFn?: typeof globalThis.fetch);
6
+ getUserId(): Promise<string>;
7
+ getWorkouts(page?: number, limit?: number): Promise<PelotonWorkoutListResponse>;
8
+ getPerformanceGraph(workoutId: string, everyN?: number): Promise<PelotonPerformanceGraph>;
9
+ }
10
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,0BAA0B,EAGhC,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,gBAAgB,+BAA+B,CAAC;AAI7D,qBAAa,aAAa;;gBAKZ,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE,OAAO,UAAU,CAAC,KAAwB;IA2B9E,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IAmB5B,WAAW,CAAC,IAAI,SAAI,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAwBtE,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,SAAI,GAAG,OAAO,CAAC,uBAAuB,CAAC;CAmB3F"}
package/dist/client.js ADDED
@@ -0,0 +1,90 @@
1
+ import { createRateLimitAwareFetch, ProviderRateLimitError, ProviderServiceUnavailableError, } from "@dofek/provider-http/rate-limit";
2
+ import { z } from "zod";
3
+ import { PelotonAuthenticationError, PelotonResponseError, PelotonServiceError } from "./errors.js";
4
+ import { pelotonPerformanceGraphSchema, pelotonWorkoutListResponseSchema, } from "./types.js";
5
+ export const PELOTON_API_BASE = "https://api.onepeloton.com";
6
+ const pelotonUserSchema = z.object({ id: z.string().min(1) });
7
+ export class PelotonClient {
8
+ #accessToken;
9
+ #userId = null;
10
+ #fetchFn;
11
+ constructor(accessToken, fetchFn = globalThis.fetch) {
12
+ this.#accessToken = accessToken;
13
+ this.#fetchFn = createRateLimitAwareFetch(fetchFn, { providerId: "peloton" });
14
+ }
15
+ async #get(path, params) {
16
+ const url = new URL(path, PELOTON_API_BASE);
17
+ for (const [key, value] of Object.entries(params ?? {})) {
18
+ url.searchParams.set(key, value);
19
+ }
20
+ const response = await this.#fetchFn(url.toString(), {
21
+ headers: {
22
+ Authorization: `Bearer ${this.#accessToken}`,
23
+ "peloton-platform": "web",
24
+ },
25
+ });
26
+ if (!response.ok) {
27
+ const responseBody = await response.text();
28
+ if (response.status === 401) {
29
+ throw new PelotonAuthenticationError(response.status, responseBody);
30
+ }
31
+ throw new PelotonServiceError(response.status, responseBody);
32
+ }
33
+ return response.json();
34
+ }
35
+ async getUserId() {
36
+ if (this.#userId)
37
+ return this.#userId;
38
+ try {
39
+ const parsed = pelotonUserSchema.parse(await this.#get("/api/me"));
40
+ this.#userId = parsed.id;
41
+ return parsed.id;
42
+ }
43
+ catch (error) {
44
+ if (error instanceof PelotonAuthenticationError ||
45
+ error instanceof PelotonServiceError ||
46
+ error instanceof ProviderRateLimitError ||
47
+ error instanceof ProviderServiceUnavailableError) {
48
+ throw error;
49
+ }
50
+ throw new PelotonResponseError("current-user", error);
51
+ }
52
+ }
53
+ async getWorkouts(page = 0, limit = 20) {
54
+ const userId = await this.getUserId();
55
+ try {
56
+ return pelotonWorkoutListResponseSchema.parse(await this.#get(`/api/user/${userId}/workouts`, {
57
+ page: String(page),
58
+ limit: String(limit),
59
+ sort_by: "-created_at",
60
+ joins: "ride",
61
+ }));
62
+ }
63
+ catch (error) {
64
+ if (error instanceof PelotonAuthenticationError ||
65
+ error instanceof PelotonServiceError ||
66
+ error instanceof ProviderRateLimitError ||
67
+ error instanceof ProviderServiceUnavailableError) {
68
+ throw error;
69
+ }
70
+ throw new PelotonResponseError("workouts", error);
71
+ }
72
+ }
73
+ async getPerformanceGraph(workoutId, everyN = 5) {
74
+ try {
75
+ return pelotonPerformanceGraphSchema.parse(await this.#get(`/api/workout/${workoutId}/performance_graph`, {
76
+ every_n: String(everyN),
77
+ }));
78
+ }
79
+ catch (error) {
80
+ if (error instanceof PelotonAuthenticationError ||
81
+ error instanceof PelotonServiceError ||
82
+ error instanceof ProviderRateLimitError ||
83
+ error instanceof ProviderServiceUnavailableError) {
84
+ throw error;
85
+ }
86
+ throw new PelotonResponseError("performance-graph", error);
87
+ }
88
+ }
89
+ }
90
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ export declare class PelotonServiceError extends Error {
2
+ readonly statusCode: number;
3
+ readonly responseBody: string;
4
+ constructor(statusCode: number, responseBody: string, options?: ErrorOptions);
5
+ }
6
+ export declare class PelotonAuthenticationError extends PelotonServiceError {
7
+ constructor(statusCode: number, responseBody: string, options?: ErrorOptions);
8
+ }
9
+ export declare class PelotonAuthFlowError extends Error {
10
+ readonly stage: string;
11
+ readonly statusCode?: number;
12
+ readonly responseBody?: string;
13
+ constructor(stage: string, message: string, details?: {
14
+ statusCode?: number;
15
+ responseBody?: string;
16
+ cause?: unknown;
17
+ });
18
+ }
19
+ export declare class PelotonResponseError extends Error {
20
+ readonly source: string;
21
+ constructor(source: string, cause: unknown);
22
+ }
23
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;gBAElB,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;CAM7E;AAED,qBAAa,0BAA2B,SAAQ,mBAAmB;gBACrD,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;CAI7E;AAED,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;gBAG7B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAQ5E;AAED,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;CAK3C"}
package/dist/errors.js ADDED
@@ -0,0 +1,37 @@
1
+ export class PelotonServiceError extends Error {
2
+ statusCode;
3
+ responseBody;
4
+ constructor(statusCode, responseBody, options) {
5
+ super(`Peloton API error (${statusCode}): ${responseBody}`, options);
6
+ this.name = "PelotonServiceError";
7
+ this.statusCode = statusCode;
8
+ this.responseBody = responseBody;
9
+ }
10
+ }
11
+ export class PelotonAuthenticationError extends PelotonServiceError {
12
+ constructor(statusCode, responseBody, options) {
13
+ super(statusCode, responseBody, options);
14
+ this.name = "PelotonAuthenticationError";
15
+ }
16
+ }
17
+ export class PelotonAuthFlowError extends Error {
18
+ stage;
19
+ statusCode;
20
+ responseBody;
21
+ constructor(stage, message, details) {
22
+ super(message, { cause: details?.cause });
23
+ this.name = "PelotonAuthFlowError";
24
+ this.stage = stage;
25
+ this.statusCode = details?.statusCode;
26
+ this.responseBody = details?.responseBody;
27
+ }
28
+ }
29
+ export class PelotonResponseError extends Error {
30
+ source;
31
+ constructor(source, cause) {
32
+ super(`Peloton returned an invalid ${source} response`, { cause });
33
+ this.name = "PelotonResponseError";
34
+ this.source = source;
35
+ }
36
+ }
37
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IACnC,UAAU,CAAS;IACnB,YAAY,CAAS;IAE9B,YAAY,UAAkB,EAAE,YAAoB,EAAE,OAAsB;QAC1E,KAAK,CAAC,sBAAsB,UAAU,MAAM,YAAY,EAAE,EAAE,OAAO,CAAC,CAAC;QACrE,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;QAClC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;IACnC,CAAC;CACF;AAED,MAAM,OAAO,0BAA2B,SAAQ,mBAAmB;IACjE,YAAY,UAAkB,EAAE,YAAoB,EAAE,OAAsB;QAC1E,KAAK,CAAC,UAAU,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC;QACzC,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAC;IAC3C,CAAC;CACF;AAED,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IACpC,KAAK,CAAS;IACd,UAAU,CAAU;IACpB,YAAY,CAAU;IAE/B,YACE,KAAa,EACb,OAAe,EACf,OAAyE;QAEzE,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1C,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;QACnC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,UAAU,GAAG,OAAO,EAAE,UAAU,CAAC;QACtC,IAAI,CAAC,YAAY,GAAG,OAAO,EAAE,YAAY,CAAC;IAC5C,CAAC;CACF;AAED,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IACpC,MAAM,CAAS;IAExB,YAAY,MAAc,EAAE,KAAc;QACxC,KAAK,CAAC,+BAA+B,MAAM,WAAW,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QACnE,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;QACnC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF"}
@@ -0,0 +1,24 @@
1
+ import type { CanonicalActivityType } from "@dofek/training/training";
2
+ import type { PelotonPerformanceGraph, PelotonWorkout } from "./types.ts";
3
+ export declare function mapFitnessDiscipline(discipline: string): CanonicalActivityType;
4
+ export interface ParsedPelotonWorkout {
5
+ externalId: string;
6
+ activityType: CanonicalActivityType;
7
+ name?: string;
8
+ timezone?: string;
9
+ stravaId?: string;
10
+ startedAt: Date;
11
+ endedAt?: Date;
12
+ raw: Record<string, unknown>;
13
+ }
14
+ export declare function parseWorkout(workout: PelotonWorkout): ParsedPelotonWorkout;
15
+ export interface ParsedMetricSeries {
16
+ slug: string;
17
+ displayName: string;
18
+ values: number[];
19
+ offsetsSeconds: number[];
20
+ averageValue: number;
21
+ maxValue: number;
22
+ }
23
+ export declare function parsePerformanceGraph(graph: PelotonPerformanceGraph, everyN: number): ParsedMetricSeries[];
24
+ //# sourceMappingURL=parsing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parsing.d.ts","sourceRoot":"","sources":["../src/parsing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,KAAK,EAAE,uBAAuB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAkB1E,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,qBAAqB,CAE9E;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,qBAAqB,CAAC;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,IAAI,CAAC;IAChB,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC9B;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,cAAc,GAAG,oBAAoB,CAiC1E;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,uBAAuB,EAC9B,MAAM,EAAE,MAAM,GACb,kBAAkB,EAAE,CAStB"}
@@ -0,0 +1,62 @@
1
+ const DISCIPLINE_MAP = {
2
+ cycling: "indoor_cycling",
3
+ running: "running",
4
+ walking: "walking",
5
+ rowing: "rowing",
6
+ caesar: "rowing",
7
+ strength: "strength",
8
+ yoga: "yoga",
9
+ meditation: "meditation",
10
+ stretching: "stretching",
11
+ cardio: "cardio",
12
+ bike_bootcamp: "bootcamp",
13
+ tread_bootcamp: "bootcamp",
14
+ outdoor: "running",
15
+ };
16
+ export function mapFitnessDiscipline(discipline) {
17
+ return DISCIPLINE_MAP[discipline] ?? "other";
18
+ }
19
+ export function parseWorkout(workout) {
20
+ const startedAt = new Date(workout.start_time * 1000);
21
+ const endedAt = workout.end_time > 0 ? new Date(workout.end_time * 1000) : undefined;
22
+ const stravaId = workout.strava_id && workout.strava_id !== "-1" ? workout.strava_id : undefined;
23
+ return {
24
+ externalId: workout.id,
25
+ activityType: mapFitnessDiscipline(workout.fitness_discipline),
26
+ name: workout.ride?.title,
27
+ timezone: workout.timezone || undefined,
28
+ stravaId,
29
+ startedAt,
30
+ endedAt,
31
+ raw: {
32
+ instructor: workout.ride?.instructor?.name,
33
+ classTitle: workout.ride?.title,
34
+ difficultyRating: workout.ride?.difficulty_rating_avg,
35
+ overallRating: workout.ride?.overall_rating_avg,
36
+ rideDescription: workout.ride?.description,
37
+ leaderboardRank: workout.leaderboard_rank,
38
+ totalLeaderboardUsers: workout.total_leaderboard_users,
39
+ totalWorkJoules: workout.total_work || undefined,
40
+ isPersonalRecord: workout.is_total_work_personal_record || undefined,
41
+ fitnessDiscipline: workout.fitness_discipline,
42
+ pelotonRideId: workout.ride?.id,
43
+ deviceType: workout.device_type || undefined,
44
+ platform: workout.platform || undefined,
45
+ pelotonClassId: workout.peloton_id || undefined,
46
+ workoutType: workout.workout_type || undefined,
47
+ hasPedalingMetrics: workout.has_pedaling_metrics,
48
+ timezone: workout.timezone || undefined,
49
+ },
50
+ };
51
+ }
52
+ export function parsePerformanceGraph(graph, everyN) {
53
+ return graph.metrics.map((metric) => ({
54
+ slug: metric.slug,
55
+ displayName: metric.display_name,
56
+ values: metric.values,
57
+ offsetsSeconds: metric.values.map((_, index) => index * everyN),
58
+ averageValue: metric.average_value,
59
+ maxValue: metric.max_value,
60
+ }));
61
+ }
62
+ //# sourceMappingURL=parsing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parsing.js","sourceRoot":"","sources":["../src/parsing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,154 @@
1
+ import { z } from "zod";
2
+ export declare const pelotonInstructorSchema: z.ZodObject<{
3
+ id: z.ZodString;
4
+ name: z.ZodString;
5
+ image_url: z.ZodOptional<z.ZodString>;
6
+ }, z.core.$strip>;
7
+ export declare const pelotonRideSchema: z.ZodObject<{
8
+ id: z.ZodString;
9
+ title: z.ZodString;
10
+ description: z.ZodOptional<z.ZodString>;
11
+ duration: z.ZodNumber;
12
+ difficulty_rating_avg: z.ZodOptional<z.ZodNumber>;
13
+ overall_rating_avg: z.ZodOptional<z.ZodNumber>;
14
+ instructor: z.ZodOptional<z.ZodObject<{
15
+ id: z.ZodString;
16
+ name: z.ZodString;
17
+ image_url: z.ZodOptional<z.ZodString>;
18
+ }, z.core.$strip>>;
19
+ }, z.core.$strip>;
20
+ export declare const pelotonWorkoutSchema: z.ZodObject<{
21
+ id: z.ZodString;
22
+ status: z.ZodString;
23
+ fitness_discipline: z.ZodString;
24
+ name: z.ZodOptional<z.ZodString>;
25
+ title: z.ZodOptional<z.ZodString>;
26
+ created_at: z.ZodNumber;
27
+ start_time: z.ZodNumber;
28
+ end_time: z.ZodNumber;
29
+ total_work: z.ZodNumber;
30
+ is_total_work_personal_record: z.ZodBoolean;
31
+ metrics_type: z.ZodOptional<z.ZodString>;
32
+ device_type: z.ZodOptional<z.ZodString>;
33
+ platform: z.ZodOptional<z.ZodString>;
34
+ peloton_id: z.ZodOptional<z.ZodString>;
35
+ workout_type: z.ZodOptional<z.ZodString>;
36
+ has_pedaling_metrics: z.ZodOptional<z.ZodBoolean>;
37
+ has_leaderboard_metrics: z.ZodOptional<z.ZodBoolean>;
38
+ timezone: z.ZodOptional<z.ZodString>;
39
+ strava_id: z.ZodOptional<z.ZodString>;
40
+ ride: z.ZodOptional<z.ZodObject<{
41
+ id: z.ZodString;
42
+ title: z.ZodString;
43
+ description: z.ZodOptional<z.ZodString>;
44
+ duration: z.ZodNumber;
45
+ difficulty_rating_avg: z.ZodOptional<z.ZodNumber>;
46
+ overall_rating_avg: z.ZodOptional<z.ZodNumber>;
47
+ instructor: z.ZodOptional<z.ZodObject<{
48
+ id: z.ZodString;
49
+ name: z.ZodString;
50
+ image_url: z.ZodOptional<z.ZodString>;
51
+ }, z.core.$strip>>;
52
+ }, z.core.$strip>>;
53
+ total_leaderboard_users: z.ZodOptional<z.ZodNumber>;
54
+ leaderboard_rank: z.ZodOptional<z.ZodNumber>;
55
+ average_effort_score: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
56
+ }, z.core.$strip>;
57
+ export declare const pelotonWorkoutListResponseSchema: z.ZodObject<{
58
+ data: z.ZodArray<z.ZodObject<{
59
+ id: z.ZodString;
60
+ status: z.ZodString;
61
+ fitness_discipline: z.ZodString;
62
+ name: z.ZodOptional<z.ZodString>;
63
+ title: z.ZodOptional<z.ZodString>;
64
+ created_at: z.ZodNumber;
65
+ start_time: z.ZodNumber;
66
+ end_time: z.ZodNumber;
67
+ total_work: z.ZodNumber;
68
+ is_total_work_personal_record: z.ZodBoolean;
69
+ metrics_type: z.ZodOptional<z.ZodString>;
70
+ device_type: z.ZodOptional<z.ZodString>;
71
+ platform: z.ZodOptional<z.ZodString>;
72
+ peloton_id: z.ZodOptional<z.ZodString>;
73
+ workout_type: z.ZodOptional<z.ZodString>;
74
+ has_pedaling_metrics: z.ZodOptional<z.ZodBoolean>;
75
+ has_leaderboard_metrics: z.ZodOptional<z.ZodBoolean>;
76
+ timezone: z.ZodOptional<z.ZodString>;
77
+ strava_id: z.ZodOptional<z.ZodString>;
78
+ ride: z.ZodOptional<z.ZodObject<{
79
+ id: z.ZodString;
80
+ title: z.ZodString;
81
+ description: z.ZodOptional<z.ZodString>;
82
+ duration: z.ZodNumber;
83
+ difficulty_rating_avg: z.ZodOptional<z.ZodNumber>;
84
+ overall_rating_avg: z.ZodOptional<z.ZodNumber>;
85
+ instructor: z.ZodOptional<z.ZodObject<{
86
+ id: z.ZodString;
87
+ name: z.ZodString;
88
+ image_url: z.ZodOptional<z.ZodString>;
89
+ }, z.core.$strip>>;
90
+ }, z.core.$strip>>;
91
+ total_leaderboard_users: z.ZodOptional<z.ZodNumber>;
92
+ leaderboard_rank: z.ZodOptional<z.ZodNumber>;
93
+ average_effort_score: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
94
+ }, z.core.$strip>>;
95
+ total: z.ZodNumber;
96
+ count: z.ZodNumber;
97
+ page: z.ZodNumber;
98
+ limit: z.ZodNumber;
99
+ page_count: z.ZodNumber;
100
+ sort_by: z.ZodString;
101
+ show_next: z.ZodBoolean;
102
+ show_previous: z.ZodBoolean;
103
+ }, z.core.$strip>;
104
+ export declare const pelotonMetricSchema: z.ZodObject<{
105
+ display_name: z.ZodString;
106
+ slug: z.ZodString;
107
+ values: z.ZodArray<z.ZodNumber>;
108
+ average_value: z.ZodNumber;
109
+ max_value: z.ZodNumber;
110
+ }, z.core.$strip>;
111
+ export declare const pelotonPerformanceGraphSchema: z.ZodObject<{
112
+ duration: z.ZodNumber;
113
+ is_class_plan_shown: z.ZodBoolean;
114
+ segment_list: z.ZodArray<z.ZodUnknown>;
115
+ average_summaries: z.ZodArray<z.ZodObject<{
116
+ display_name: z.ZodString;
117
+ value: z.ZodString;
118
+ slug: z.ZodString;
119
+ }, z.core.$strip>>;
120
+ summaries: z.ZodArray<z.ZodObject<{
121
+ display_name: z.ZodString;
122
+ value: z.ZodString;
123
+ slug: z.ZodString;
124
+ }, z.core.$strip>>;
125
+ metrics: z.ZodArray<z.ZodObject<{
126
+ display_name: z.ZodString;
127
+ slug: z.ZodString;
128
+ values: z.ZodArray<z.ZodNumber>;
129
+ average_value: z.ZodNumber;
130
+ max_value: z.ZodNumber;
131
+ }, z.core.$strip>>;
132
+ }, z.core.$strip>;
133
+ export type PelotonInstructor = z.infer<typeof pelotonInstructorSchema>;
134
+ export type PelotonRide = z.infer<typeof pelotonRideSchema>;
135
+ export type PelotonWorkout = z.infer<typeof pelotonWorkoutSchema>;
136
+ export type PelotonWorkoutListResponse = z.infer<typeof pelotonWorkoutListResponseSchema>;
137
+ export type PelotonMetric = z.infer<typeof pelotonMetricSchema>;
138
+ export type PelotonPerformanceGraph = z.infer<typeof pelotonPerformanceGraphSchema>;
139
+ export interface PelotonOAuthConfig {
140
+ clientId: string;
141
+ authorizeUrl: string;
142
+ tokenUrl: string;
143
+ redirectUri: string;
144
+ scopes: string[];
145
+ usePkce: true;
146
+ audience: string;
147
+ }
148
+ export interface PelotonTokenSet {
149
+ accessToken: string;
150
+ refreshToken: string | null;
151
+ expiresAt: Date;
152
+ scopes: string | null;
153
+ }
154
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,uBAAuB;;;;iBAIlC,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;iBAQ5B,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwB/B,CAAC;AAEH,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAU3C,CAAC;AAEH,eAAO,MAAM,mBAAmB;;;;;;iBAM9B,CAAC;AAQH,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;;iBAOxC,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AACxE,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC5D,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAClE,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gCAAgC,CAAC,CAAC;AAC1F,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAChE,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAEpF,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,IAAI,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,IAAI,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB"}
package/dist/types.js ADDED
@@ -0,0 +1,72 @@
1
+ import { z } from "zod";
2
+ export const pelotonInstructorSchema = z.object({
3
+ id: z.string(),
4
+ name: z.string(),
5
+ image_url: z.string().optional(),
6
+ });
7
+ export const pelotonRideSchema = z.object({
8
+ id: z.string(),
9
+ title: z.string(),
10
+ description: z.string().optional(),
11
+ duration: z.number(),
12
+ difficulty_rating_avg: z.number().optional(),
13
+ overall_rating_avg: z.number().optional(),
14
+ instructor: pelotonInstructorSchema.optional(),
15
+ });
16
+ export const pelotonWorkoutSchema = z.object({
17
+ id: z.string(),
18
+ status: z.string(),
19
+ fitness_discipline: z.string(),
20
+ name: z.string().optional(),
21
+ title: z.string().optional(),
22
+ created_at: z.number(),
23
+ start_time: z.number(),
24
+ end_time: z.number(),
25
+ total_work: z.number(),
26
+ is_total_work_personal_record: z.boolean(),
27
+ metrics_type: z.string().optional(),
28
+ device_type: z.string().optional(),
29
+ platform: z.string().optional(),
30
+ peloton_id: z.string().optional(),
31
+ workout_type: z.string().optional(),
32
+ has_pedaling_metrics: z.boolean().optional(),
33
+ has_leaderboard_metrics: z.boolean().optional(),
34
+ timezone: z.string().optional(),
35
+ strava_id: z.string().optional(),
36
+ ride: pelotonRideSchema.optional(),
37
+ total_leaderboard_users: z.number().optional(),
38
+ leaderboard_rank: z.number().optional(),
39
+ average_effort_score: z.number().nullable().optional(),
40
+ });
41
+ export const pelotonWorkoutListResponseSchema = z.object({
42
+ data: z.array(pelotonWorkoutSchema),
43
+ total: z.number(),
44
+ count: z.number(),
45
+ page: z.number(),
46
+ limit: z.number(),
47
+ page_count: z.number(),
48
+ sort_by: z.string(),
49
+ show_next: z.boolean(),
50
+ show_previous: z.boolean(),
51
+ });
52
+ export const pelotonMetricSchema = z.object({
53
+ display_name: z.string(),
54
+ slug: z.string(),
55
+ values: z.array(z.number()),
56
+ average_value: z.number(),
57
+ max_value: z.number(),
58
+ });
59
+ const pelotonSummarySchema = z.object({
60
+ display_name: z.string(),
61
+ value: z.string(),
62
+ slug: z.string(),
63
+ });
64
+ export const pelotonPerformanceGraphSchema = z.object({
65
+ duration: z.number(),
66
+ is_class_plan_shown: z.boolean(),
67
+ segment_list: z.array(z.unknown()),
68
+ average_summaries: z.array(pelotonSummarySchema),
69
+ summaries: z.array(pelotonSummarySchema),
70
+ metrics: z.array(pelotonMetricSchema),
71
+ });
72
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@dofek/peloton",
3
+ "version": "0.1.0",
4
+ "description": "Unofficial Peloton API client with reverse-engineered Auth0 authentication",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/Asherlc/dofek.git",
10
+ "directory": "packages/peloton-client"
11
+ },
12
+ "homepage": "https://github.com/Asherlc/dofek/tree/main/packages/peloton-client#readme",
13
+ "bugs": "https://github.com/Asherlc/dofek/issues",
14
+ "keywords": [
15
+ "peloton",
16
+ "fitness",
17
+ "api-client",
18
+ "auth0",
19
+ "oauth",
20
+ "unofficial",
21
+ "typescript"
22
+ ],
23
+ "engines": {
24
+ "node": ">=22.14.0"
25
+ },
26
+ "sideEffects": false,
27
+ "files": [
28
+ "dist",
29
+ "README.md",
30
+ "LICENSE"
31
+ ],
32
+ "exports": {
33
+ ".": {
34
+ "types": "./dist/client.d.ts",
35
+ "import": "./dist/client.js"
36
+ },
37
+ "./*": {
38
+ "types": "./dist/*.d.ts",
39
+ "import": "./dist/*.js"
40
+ }
41
+ },
42
+ "publishConfig": {
43
+ "access": "public"
44
+ },
45
+ "scripts": {
46
+ "test": "vitest run src",
47
+ "test:watch": "vitest --watch src",
48
+ "build": "tsc",
49
+ "prepack": "pnpm run build",
50
+ "lint": "biome check .",
51
+ "typecheck": "tsc --noEmit"
52
+ },
53
+ "dependencies": {
54
+ "@dofek/provider-http": "0.1.0",
55
+ "@dofek/training": "0.1.0",
56
+ "zod": "4.4.3"
57
+ },
58
+ "devDependencies": {
59
+ "@types/node": "22.19.15",
60
+ "typescript": "6.0.3",
61
+ "vitest": "3.2.6"
62
+ },
63
+ "gitHead": "ac95258c753c7e75b57da7ae47426d22b78e8c01"
64
+ }