@dofek/xert 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 +21 -0
- package/README.md +135 -0
- package/dist/client.d.ts +36 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +125 -0
- package/dist/client.js.map +1 -0
- package/dist/parsing.d.ts +14 -0
- package/dist/parsing.d.ts.map +1 -0
- package/dist/parsing.js +43 -0
- package/dist/parsing.js.map +1 -0
- package/dist/types.d.ts +63 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +24 -0
- package/dist/types.js.map +1 -0
- package/package.json +62 -0
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,135 @@
|
|
|
1
|
+
# @dofek/xert
|
|
2
|
+
|
|
3
|
+
TypeScript client for Xert authentication, token refresh, observed activity
|
|
4
|
+
paging, runtime response validation, and conversion to provider-agnostic
|
|
5
|
+
activity records.
|
|
6
|
+
|
|
7
|
+
Xert publishes an API reference that documents its password and refresh-token
|
|
8
|
+
grants, including the `xert_public` client credentials. The paginated activity
|
|
9
|
+
response consumed here is an observed Xert web API shape rather than the
|
|
10
|
+
activity-list representation in that reference. See the
|
|
11
|
+
[Xert API documentation](https://www.xertonline.com/API.html).
|
|
12
|
+
|
|
13
|
+
This package is not affiliated with, endorsed by, or supported by Xert or Baron
|
|
14
|
+
Biosystems. Undocumented endpoints and response shapes may change without
|
|
15
|
+
notice.
|
|
16
|
+
|
|
17
|
+
## Requirements and installation
|
|
18
|
+
|
|
19
|
+
Requires Node.js 22.14 or newer and its built-in
|
|
20
|
+
[`fetch`](https://nodejs.org/api/globals.html#fetch) implementation.
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
npm install @dofek/xert
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quick start
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { XertClient } from "@dofek/xert";
|
|
30
|
+
import { parseXertActivity } from "@dofek/xert/parsing";
|
|
31
|
+
|
|
32
|
+
const email = process.env.XERT_EMAIL;
|
|
33
|
+
const password = process.env.XERT_PASSWORD;
|
|
34
|
+
if (!email || !password) {
|
|
35
|
+
throw new Error("Set XERT_EMAIL and XERT_PASSWORD");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const token = await XertClient.signIn(email, password);
|
|
39
|
+
const client = new XertClient(token.accessToken);
|
|
40
|
+
const activities = await client.listActivities({
|
|
41
|
+
from: Math.floor(Date.parse("2026-07-01T00:00:00Z") / 1000),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
console.log(activities.map(parseXertActivity));
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`from` is a Unix timestamp in seconds. `page` defaults to `0`, and `limit`
|
|
48
|
+
defaults to `50`.
|
|
49
|
+
|
|
50
|
+
## Authentication and token refresh
|
|
51
|
+
|
|
52
|
+
`XertClient.signIn(email, password, fetch?, credentials?)` uses the resource
|
|
53
|
+
owner password grant documented by Xert. It returns:
|
|
54
|
+
|
|
55
|
+
- `accessToken`
|
|
56
|
+
- `refreshToken`
|
|
57
|
+
- `expiresAt`
|
|
58
|
+
- `scopes`
|
|
59
|
+
|
|
60
|
+
The library defaults to the documented `xert_public` client ID and secret. To
|
|
61
|
+
use different credentials, pass them explicitly:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
const token = await XertClient.signIn(
|
|
65
|
+
email,
|
|
66
|
+
password,
|
|
67
|
+
fetch,
|
|
68
|
+
{ clientId: "client-id", clientSecret: "client-secret" },
|
|
69
|
+
);
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The library never reads environment variables. Applications decide how to load
|
|
73
|
+
configuration and must store account passwords, access tokens, and refresh
|
|
74
|
+
tokens as password-equivalent secrets.
|
|
75
|
+
|
|
76
|
+
Refresh before `expiresAt`:
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
const refreshed = await XertClient.refreshToken(token.refreshToken!);
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The standalone `signInToXert` and `refreshXertToken` functions expose the same
|
|
83
|
+
operations. If Xert does not return a replacement refresh token,
|
|
84
|
+
`refreshXertToken` retains the supplied token.
|
|
85
|
+
|
|
86
|
+
## Public API
|
|
87
|
+
|
|
88
|
+
- `new XertClient(accessToken, fetch?)`
|
|
89
|
+
- `XertClient.signIn(email, password, fetch?, credentials?)`
|
|
90
|
+
- `XertClient.refreshToken(refreshToken, fetch?, credentials?)`
|
|
91
|
+
- `client.listActivities({ from, page?, limit? })`
|
|
92
|
+
- `signInToXert(...)`
|
|
93
|
+
- `refreshXertToken(...)`
|
|
94
|
+
- `DEFAULT_XERT_CLIENT_CREDENTIALS`
|
|
95
|
+
- `XertAuthenticationError`
|
|
96
|
+
- `XertApiError`
|
|
97
|
+
|
|
98
|
+
Supported deep imports:
|
|
99
|
+
|
|
100
|
+
- `@dofek/xert/client` — authentication, refresh, and API client.
|
|
101
|
+
- `@dofek/xert/parsing` — sport mapping and normalized activity parsing.
|
|
102
|
+
- `@dofek/xert/types` — Zod schemas and TypeScript types.
|
|
103
|
+
|
|
104
|
+
All token and activity responses cross a
|
|
105
|
+
[Zod](https://zod.dev/) runtime-validation boundary. A response-shape change
|
|
106
|
+
therefore throws `ZodError` instead of returning unchecked data.
|
|
107
|
+
|
|
108
|
+
## Errors and rate limits
|
|
109
|
+
|
|
110
|
+
Rejected authentication and refresh requests throw
|
|
111
|
+
`XertAuthenticationError`. Other unsuccessful activity requests throw
|
|
112
|
+
`XertApiError`. Both expose `statusCode` and `responseBody`.
|
|
113
|
+
|
|
114
|
+
The shared HTTP wrapper throws `ProviderRateLimitError` for `429` and
|
|
115
|
+
`ProviderServiceUnavailableError` for `502`, `503`, and `504`, retaining a
|
|
116
|
+
parsed
|
|
117
|
+
[`Retry-After`](https://www.rfc-editor.org/rfc/rfc9110.html#name-retry-after)
|
|
118
|
+
value when supplied.
|
|
119
|
+
|
|
120
|
+
If your application handles these classes directly, declare
|
|
121
|
+
`@dofek/provider-http` as a direct dependency:
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
import {
|
|
125
|
+
ProviderRateLimitError,
|
|
126
|
+
ProviderServiceUnavailableError,
|
|
127
|
+
} from "@dofek/provider-http/rate-limit";
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Project
|
|
131
|
+
|
|
132
|
+
- [Source](https://github.com/Asherlc/dofek/tree/main/packages/xert-client)
|
|
133
|
+
- [Report an issue](https://github.com/Asherlc/dofek/issues)
|
|
134
|
+
- [Contribute a pull request](https://github.com/Asherlc/dofek/pulls)
|
|
135
|
+
- License: [MIT](./LICENSE)
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type XertActivity, type XertActivityListOptions, type XertClientCredentials, type XertTokenSet } from "./types.ts";
|
|
2
|
+
export declare const XERT_API_BASE_URL = "https://www.xertonline.com";
|
|
3
|
+
export declare const DEFAULT_XERT_CLIENT_CREDENTIALS: Readonly<XertClientCredentials>;
|
|
4
|
+
export declare class XertAuthenticationError extends Error {
|
|
5
|
+
readonly statusCode: number;
|
|
6
|
+
readonly responseBody: string;
|
|
7
|
+
readonly operation: "sign-in" | "token refresh";
|
|
8
|
+
constructor(operation: "sign-in" | "token refresh", statusCode: number, responseBody: string, options?: ErrorOptions);
|
|
9
|
+
}
|
|
10
|
+
export declare class XertApiError extends Error {
|
|
11
|
+
readonly statusCode: number;
|
|
12
|
+
readonly responseBody: string;
|
|
13
|
+
constructor(statusCode: number, responseBody: string, options?: ErrorOptions);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Signs in with Xert's documented resource-owner password grant.
|
|
17
|
+
*
|
|
18
|
+
* Credentials are explicit so the library never reads process environment.
|
|
19
|
+
*/
|
|
20
|
+
export declare function signInToXert(email: string, password: string, fetchFn?: typeof globalThis.fetch, credentials?: XertClientCredentials): Promise<XertTokenSet>;
|
|
21
|
+
/**
|
|
22
|
+
* Exchanges a refresh token for a new token set.
|
|
23
|
+
*
|
|
24
|
+
* Xert normally rotates refresh tokens. If it omits one, this retains the
|
|
25
|
+
* supplied refresh token so callers do not accidentally discard it.
|
|
26
|
+
*/
|
|
27
|
+
export declare function refreshXertToken(refreshToken: string, fetchFn?: typeof globalThis.fetch, credentials?: XertClientCredentials): Promise<XertTokenSet>;
|
|
28
|
+
export declare class XertClient {
|
|
29
|
+
#private;
|
|
30
|
+
constructor(accessToken: string, fetchFn?: typeof globalThis.fetch);
|
|
31
|
+
static signIn(email: string, password: string, fetchFn?: typeof globalThis.fetch, credentials?: XertClientCredentials): Promise<XertTokenSet>;
|
|
32
|
+
static refreshToken(refreshToken: string, fetchFn?: typeof globalThis.fetch, credentials?: XertClientCredentials): Promise<XertTokenSet>;
|
|
33
|
+
listActivities(options: XertActivityListOptions): Promise<XertActivity[]>;
|
|
34
|
+
}
|
|
35
|
+
export type { XertActivity, XertActivityListOptions, XertClientCredentials, XertTokenSet, } from "./types.ts";
|
|
36
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,uBAAuB,EAE5B,KAAK,qBAAqB,EAC1B,KAAK,YAAY,EAClB,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,iBAAiB,+BAA+B,CAAC;AAE9D,eAAO,MAAM,+BAA+B,EAAE,QAAQ,CAAC,qBAAqB,CAG1E,CAAC;AAYH,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,eAAe,CAAC;gBAG9C,SAAS,EAAE,SAAS,GAAG,eAAe,EACtC,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,YAAY;CAQzB;AAED,qBAAa,YAAa,SAAQ,KAAK;IACrC,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;AA6CD;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,OAAO,UAAU,CAAC,KAAwB,EACnD,WAAW,GAAE,qBAAuD,GACnE,OAAO,CAAC,YAAY,CAAC,CAWvB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,OAAO,UAAU,CAAC,KAAwB,EACnD,WAAW,GAAE,qBAAuD,GACnE,OAAO,CAAC,YAAY,CAAC,CAWvB;AAED,qBAAa,UAAU;;gBAIT,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE,OAAO,UAAU,CAAC,KAAwB;IAKpF,MAAM,CAAC,MAAM,CACX,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,OAAO,UAAU,CAAC,KAAwB,EACnD,WAAW,GAAE,qBAAuD,GACnE,OAAO,CAAC,YAAY,CAAC;IAIxB,MAAM,CAAC,YAAY,CACjB,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,OAAO,UAAU,CAAC,KAAwB,EACnD,WAAW,GAAE,qBAAuD,GACnE,OAAO,CAAC,YAAY,CAAC;IAIlB,cAAc,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;CAwBhF;AAED,YAAY,EACV,YAAY,EACZ,uBAAuB,EACvB,qBAAqB,EACrB,YAAY,GACb,MAAM,YAAY,CAAC"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { createRateLimitAwareFetch } from "@dofek/provider-http/rate-limit";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { XertActivityListSchema, } from "./types.js";
|
|
4
|
+
export const XERT_API_BASE_URL = "https://www.xertonline.com";
|
|
5
|
+
export const DEFAULT_XERT_CLIENT_CREDENTIALS = Object.freeze({
|
|
6
|
+
clientId: "xert_public",
|
|
7
|
+
clientSecret: "xert_public",
|
|
8
|
+
});
|
|
9
|
+
const DEFAULT_EXPIRES_IN_SECONDS = 365 * 24 * 60 * 60;
|
|
10
|
+
const XertTokenResponseSchema = z.object({
|
|
11
|
+
access_token: z.string(),
|
|
12
|
+
refresh_token: z.string().optional(),
|
|
13
|
+
expires_in: z.number().optional(),
|
|
14
|
+
token_type: z.string().optional(),
|
|
15
|
+
scope: z.string().optional(),
|
|
16
|
+
});
|
|
17
|
+
export class XertAuthenticationError extends Error {
|
|
18
|
+
statusCode;
|
|
19
|
+
responseBody;
|
|
20
|
+
operation;
|
|
21
|
+
constructor(operation, statusCode, responseBody, options) {
|
|
22
|
+
super(`Xert ${operation} failed (${statusCode}): ${responseBody}`, options);
|
|
23
|
+
this.name = new.target.name;
|
|
24
|
+
this.operation = operation;
|
|
25
|
+
this.statusCode = statusCode;
|
|
26
|
+
this.responseBody = responseBody;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export class XertApiError extends Error {
|
|
30
|
+
statusCode;
|
|
31
|
+
responseBody;
|
|
32
|
+
constructor(statusCode, responseBody, options) {
|
|
33
|
+
super(`Xert API error (${statusCode}): ${responseBody}`, options);
|
|
34
|
+
this.name = new.target.name;
|
|
35
|
+
this.statusCode = statusCode;
|
|
36
|
+
this.responseBody = responseBody;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function authorizationHeader(credentials) {
|
|
40
|
+
return `Basic ${btoa(`${credentials.clientId}:${credentials.clientSecret}`)}`;
|
|
41
|
+
}
|
|
42
|
+
function parseTokenResponse(data, fallbackRefreshToken = null) {
|
|
43
|
+
const parsed = XertTokenResponseSchema.parse(data);
|
|
44
|
+
return {
|
|
45
|
+
accessToken: parsed.access_token,
|
|
46
|
+
refreshToken: parsed.refresh_token ?? fallbackRefreshToken,
|
|
47
|
+
expiresAt: new Date(Date.now() + (parsed.expires_in ?? DEFAULT_EXPIRES_IN_SECONDS) * 1000),
|
|
48
|
+
scopes: parsed.scope ?? null,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
async function requestToken(operation, body, fetchFn, credentials, fallbackRefreshToken = null) {
|
|
52
|
+
const rateLimitFetchFn = createRateLimitAwareFetch(fetchFn, { providerId: "xert" });
|
|
53
|
+
const response = await rateLimitFetchFn(`${XERT_API_BASE_URL}/oauth/token`, {
|
|
54
|
+
method: "POST",
|
|
55
|
+
headers: {
|
|
56
|
+
Authorization: authorizationHeader(credentials),
|
|
57
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
58
|
+
},
|
|
59
|
+
body: body.toString(),
|
|
60
|
+
});
|
|
61
|
+
if (!response.ok) {
|
|
62
|
+
const responseBody = await response.text();
|
|
63
|
+
throw new XertAuthenticationError(operation, response.status, responseBody);
|
|
64
|
+
}
|
|
65
|
+
const data = await response.json();
|
|
66
|
+
return parseTokenResponse(data, fallbackRefreshToken);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Signs in with Xert's documented resource-owner password grant.
|
|
70
|
+
*
|
|
71
|
+
* Credentials are explicit so the library never reads process environment.
|
|
72
|
+
*/
|
|
73
|
+
export function signInToXert(email, password, fetchFn = globalThis.fetch, credentials = DEFAULT_XERT_CLIENT_CREDENTIALS) {
|
|
74
|
+
return requestToken("sign-in", new URLSearchParams({
|
|
75
|
+
grant_type: "password",
|
|
76
|
+
username: email,
|
|
77
|
+
password,
|
|
78
|
+
}), fetchFn, credentials);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Exchanges a refresh token for a new token set.
|
|
82
|
+
*
|
|
83
|
+
* Xert normally rotates refresh tokens. If it omits one, this retains the
|
|
84
|
+
* supplied refresh token so callers do not accidentally discard it.
|
|
85
|
+
*/
|
|
86
|
+
export function refreshXertToken(refreshToken, fetchFn = globalThis.fetch, credentials = DEFAULT_XERT_CLIENT_CREDENTIALS) {
|
|
87
|
+
return requestToken("token refresh", new URLSearchParams({
|
|
88
|
+
grant_type: "refresh_token",
|
|
89
|
+
refresh_token: refreshToken,
|
|
90
|
+
}), fetchFn, credentials, refreshToken);
|
|
91
|
+
}
|
|
92
|
+
export class XertClient {
|
|
93
|
+
#accessToken;
|
|
94
|
+
#fetchFn;
|
|
95
|
+
constructor(accessToken, fetchFn = globalThis.fetch) {
|
|
96
|
+
this.#accessToken = accessToken;
|
|
97
|
+
this.#fetchFn = createRateLimitAwareFetch(fetchFn, { providerId: "xert" });
|
|
98
|
+
}
|
|
99
|
+
static signIn(email, password, fetchFn = globalThis.fetch, credentials = DEFAULT_XERT_CLIENT_CREDENTIALS) {
|
|
100
|
+
return signInToXert(email, password, fetchFn, credentials);
|
|
101
|
+
}
|
|
102
|
+
static refreshToken(refreshToken, fetchFn = globalThis.fetch, credentials = DEFAULT_XERT_CLIENT_CREDENTIALS) {
|
|
103
|
+
return refreshXertToken(refreshToken, fetchFn, credentials);
|
|
104
|
+
}
|
|
105
|
+
async listActivities(options) {
|
|
106
|
+
const query = new URLSearchParams({
|
|
107
|
+
from: String(options.from),
|
|
108
|
+
page: String(options.page ?? 0),
|
|
109
|
+
limit: String(options.limit ?? 50),
|
|
110
|
+
});
|
|
111
|
+
const response = await this.#fetchFn(`${XERT_API_BASE_URL}/oauth/activity/?${query.toString()}`, {
|
|
112
|
+
headers: {
|
|
113
|
+
Authorization: `Bearer ${this.#accessToken}`,
|
|
114
|
+
Accept: "application/json",
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
if (!response.ok) {
|
|
118
|
+
const responseBody = await response.text();
|
|
119
|
+
throw new XertApiError(response.status, responseBody);
|
|
120
|
+
}
|
|
121
|
+
const data = await response.json();
|
|
122
|
+
return XertActivityListSchema.parse(data);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# 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,14 @@
|
|
|
1
|
+
import type { CanonicalActivityType } from "@dofek/training/training";
|
|
2
|
+
import type { XertActivity } from "./types.ts";
|
|
3
|
+
export interface ParsedXertActivity {
|
|
4
|
+
externalId: string;
|
|
5
|
+
activityType: CanonicalActivityType;
|
|
6
|
+
name: string;
|
|
7
|
+
startedAt: Date;
|
|
8
|
+
endedAt: Date;
|
|
9
|
+
raw: Record<string, unknown>;
|
|
10
|
+
}
|
|
11
|
+
export declare const XERT_SPORT_MAP: Readonly<Record<string, CanonicalActivityType>>;
|
|
12
|
+
export declare function mapXertSport(sport: string): CanonicalActivityType;
|
|
13
|
+
export declare function parseXertActivity(activity: XertActivity): ParsedXertActivity;
|
|
14
|
+
//# 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,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,qBAAqB,CAAC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,IAAI,CAAC;IAChB,OAAO,EAAE,IAAI,CAAC;IACd,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC9B;AAED,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAY1E,CAAC;AAEF,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,qBAAqB,CAEjE;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,YAAY,GAAG,kBAAkB,CAyB5E"}
|
package/dist/parsing.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export const XERT_SPORT_MAP = {
|
|
2
|
+
Cycling: "cycling",
|
|
3
|
+
Running: "running",
|
|
4
|
+
Swimming: "swimming",
|
|
5
|
+
Walking: "walking",
|
|
6
|
+
Hiking: "hiking",
|
|
7
|
+
Rowing: "rowing",
|
|
8
|
+
Skiing: "skiing",
|
|
9
|
+
"Virtual Cycling": "virtual_cycling",
|
|
10
|
+
"Mountain Biking": "mountain_biking",
|
|
11
|
+
"Trail Running": "trail_running",
|
|
12
|
+
"Cross Country Skiing": "cross_country_skiing",
|
|
13
|
+
};
|
|
14
|
+
export function mapXertSport(sport) {
|
|
15
|
+
return XERT_SPORT_MAP[sport] ?? "other";
|
|
16
|
+
}
|
|
17
|
+
export function parseXertActivity(activity) {
|
|
18
|
+
return {
|
|
19
|
+
externalId: String(activity.id),
|
|
20
|
+
activityType: mapXertSport(activity.sport),
|
|
21
|
+
name: activity.name,
|
|
22
|
+
startedAt: new Date(activity.startTimestamp * 1000),
|
|
23
|
+
endedAt: new Date(activity.endTimestamp * 1000),
|
|
24
|
+
raw: {
|
|
25
|
+
sport: activity.sport,
|
|
26
|
+
duration: activity.duration,
|
|
27
|
+
distance: activity.distance,
|
|
28
|
+
powerAvg: activity.power_avg,
|
|
29
|
+
powerMax: activity.power_max,
|
|
30
|
+
powerNormalized: activity.power_normalized,
|
|
31
|
+
heartrateAvg: activity.heartrate_avg,
|
|
32
|
+
heartrateMax: activity.heartrate_max,
|
|
33
|
+
cadenceAvg: activity.cadence_avg,
|
|
34
|
+
cadenceMax: activity.cadence_max,
|
|
35
|
+
elevationGain: activity.elevation_gain,
|
|
36
|
+
elevationLoss: activity.elevation_loss,
|
|
37
|
+
xss: activity.xss,
|
|
38
|
+
focus: activity.focus,
|
|
39
|
+
difficulty: activity.difficulty,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=parsing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parsing.js","sourceRoot":"","sources":["../src/parsing.ts"],"names":[],"mappings":"AAYA,MAAM,CAAC,MAAM,cAAc,GAAoD;IAC7E,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;IAClB,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,QAAQ;IAChB,iBAAiB,EAAE,iBAAiB;IACpC,iBAAiB,EAAE,iBAAiB;IACpC,eAAe,EAAE,eAAe;IAChC,sBAAsB,EAAE,sBAAsB;CAC/C,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,OAAO,cAAc,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAsB;IACtD,OAAO;QACL,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/B,YAAY,EAAE,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC;QAC1C,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,SAAS,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,cAAc,GAAG,IAAI,CAAC;QACnD,OAAO,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,GAAG,IAAI,CAAC;QAC/C,GAAG,EAAE;YACH,KAAK,EAAE,QAAQ,CAAC,KAAK;YACrB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,QAAQ,EAAE,QAAQ,CAAC,SAAS;YAC5B,QAAQ,EAAE,QAAQ,CAAC,SAAS;YAC5B,eAAe,EAAE,QAAQ,CAAC,gBAAgB;YAC1C,YAAY,EAAE,QAAQ,CAAC,aAAa;YACpC,YAAY,EAAE,QAAQ,CAAC,aAAa;YACpC,UAAU,EAAE,QAAQ,CAAC,WAAW;YAChC,UAAU,EAAE,QAAQ,CAAC,WAAW;YAChC,aAAa,EAAE,QAAQ,CAAC,cAAc;YACtC,aAAa,EAAE,QAAQ,CAAC,cAAc;YACtC,GAAG,EAAE,QAAQ,CAAC,GAAG;YACjB,KAAK,EAAE,QAAQ,CAAC,KAAK;YACrB,UAAU,EAAE,QAAQ,CAAC,UAAU;SAChC;KACF,CAAC;AACJ,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const XertActivitySchema: z.ZodObject<{
|
|
3
|
+
id: z.ZodNumber;
|
|
4
|
+
name: z.ZodString;
|
|
5
|
+
sport: z.ZodString;
|
|
6
|
+
startTimestamp: z.ZodNumber;
|
|
7
|
+
endTimestamp: z.ZodNumber;
|
|
8
|
+
duration: z.ZodNumber;
|
|
9
|
+
distance: z.ZodNumber;
|
|
10
|
+
power_avg: z.ZodNumber;
|
|
11
|
+
power_max: z.ZodNumber;
|
|
12
|
+
power_normalized: z.ZodNumber;
|
|
13
|
+
heartrate_avg: z.ZodNumber;
|
|
14
|
+
heartrate_max: z.ZodNumber;
|
|
15
|
+
cadence_avg: z.ZodNumber;
|
|
16
|
+
cadence_max: z.ZodNumber;
|
|
17
|
+
elevation_gain: z.ZodNumber;
|
|
18
|
+
elevation_loss: z.ZodNumber;
|
|
19
|
+
xss: z.ZodNumber;
|
|
20
|
+
focus: z.ZodNumber;
|
|
21
|
+
difficulty: z.ZodNumber;
|
|
22
|
+
}, z.core.$strip>;
|
|
23
|
+
export declare const XertActivityListSchema: z.ZodArray<z.ZodObject<{
|
|
24
|
+
id: z.ZodNumber;
|
|
25
|
+
name: z.ZodString;
|
|
26
|
+
sport: z.ZodString;
|
|
27
|
+
startTimestamp: z.ZodNumber;
|
|
28
|
+
endTimestamp: z.ZodNumber;
|
|
29
|
+
duration: z.ZodNumber;
|
|
30
|
+
distance: z.ZodNumber;
|
|
31
|
+
power_avg: z.ZodNumber;
|
|
32
|
+
power_max: z.ZodNumber;
|
|
33
|
+
power_normalized: z.ZodNumber;
|
|
34
|
+
heartrate_avg: z.ZodNumber;
|
|
35
|
+
heartrate_max: z.ZodNumber;
|
|
36
|
+
cadence_avg: z.ZodNumber;
|
|
37
|
+
cadence_max: z.ZodNumber;
|
|
38
|
+
elevation_gain: z.ZodNumber;
|
|
39
|
+
elevation_loss: z.ZodNumber;
|
|
40
|
+
xss: z.ZodNumber;
|
|
41
|
+
focus: z.ZodNumber;
|
|
42
|
+
difficulty: z.ZodNumber;
|
|
43
|
+
}, z.core.$strip>>;
|
|
44
|
+
export type XertActivity = z.infer<typeof XertActivitySchema>;
|
|
45
|
+
export interface XertClientCredentials {
|
|
46
|
+
clientId: string;
|
|
47
|
+
clientSecret: string;
|
|
48
|
+
}
|
|
49
|
+
export interface XertTokenSet {
|
|
50
|
+
accessToken: string;
|
|
51
|
+
refreshToken: string | null;
|
|
52
|
+
expiresAt: Date;
|
|
53
|
+
scopes: string | null;
|
|
54
|
+
}
|
|
55
|
+
export interface XertActivityListOptions {
|
|
56
|
+
/** Earliest activity start time, expressed as Unix seconds. */
|
|
57
|
+
from: number;
|
|
58
|
+
/** Zero-based page number. */
|
|
59
|
+
page?: number;
|
|
60
|
+
/** Number of activities requested per page. */
|
|
61
|
+
limit?: number;
|
|
62
|
+
}
|
|
63
|
+
//# 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,kBAAkB;;;;;;;;;;;;;;;;;;;;iBAoB7B,CAAC;AAEH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;kBAA8B,CAAC;AAElE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,IAAI,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,uBAAuB;IACtC,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,8BAA8B;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const XertActivitySchema = z.object({
|
|
3
|
+
id: z.number(),
|
|
4
|
+
name: z.string(),
|
|
5
|
+
sport: z.string(),
|
|
6
|
+
startTimestamp: z.number(),
|
|
7
|
+
endTimestamp: z.number(),
|
|
8
|
+
duration: z.number(),
|
|
9
|
+
distance: z.number(),
|
|
10
|
+
power_avg: z.number(),
|
|
11
|
+
power_max: z.number(),
|
|
12
|
+
power_normalized: z.number(),
|
|
13
|
+
heartrate_avg: z.number(),
|
|
14
|
+
heartrate_max: z.number(),
|
|
15
|
+
cadence_avg: z.number(),
|
|
16
|
+
cadence_max: z.number(),
|
|
17
|
+
elevation_gain: z.number(),
|
|
18
|
+
elevation_loss: z.number(),
|
|
19
|
+
xss: z.number(),
|
|
20
|
+
focus: z.number(),
|
|
21
|
+
difficulty: z.number(),
|
|
22
|
+
});
|
|
23
|
+
export const XertActivityListSchema = z.array(XertActivitySchema);
|
|
24
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE;IAC1B,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE;IACxB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;IACpB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;IACpB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE;IAC5B,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE;IACzB,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE;IACzB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE;IAC1B,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE;IAC1B,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE;IACf,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;CACvB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dofek/xert",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Unofficial Xert API client with password authentication, token refresh, and activity parsing",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/Asherlc/dofek.git",
|
|
10
|
+
"directory": "packages/xert-client"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/Asherlc/dofek/tree/main/packages/xert-client#readme",
|
|
13
|
+
"bugs": "https://github.com/Asherlc/dofek/issues",
|
|
14
|
+
"keywords": [
|
|
15
|
+
"xert",
|
|
16
|
+
"cycling",
|
|
17
|
+
"api-client",
|
|
18
|
+
"oauth",
|
|
19
|
+
"unofficial",
|
|
20
|
+
"typescript"
|
|
21
|
+
],
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=22.14.0"
|
|
24
|
+
},
|
|
25
|
+
"sideEffects": false,
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"README.md",
|
|
29
|
+
"LICENSE"
|
|
30
|
+
],
|
|
31
|
+
"exports": {
|
|
32
|
+
".": {
|
|
33
|
+
"types": "./dist/client.d.ts",
|
|
34
|
+
"import": "./dist/client.js"
|
|
35
|
+
},
|
|
36
|
+
"./*": {
|
|
37
|
+
"types": "./dist/*.d.ts",
|
|
38
|
+
"import": "./dist/*.js"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"test": "vitest run",
|
|
46
|
+
"test:watch": "vitest --watch",
|
|
47
|
+
"build": "tsc",
|
|
48
|
+
"prepack": "pnpm run build",
|
|
49
|
+
"lint": "biome check .",
|
|
50
|
+
"typecheck": "tsc --noEmit"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@dofek/provider-http": "0.1.0",
|
|
54
|
+
"@dofek/training": "0.1.0",
|
|
55
|
+
"zod": "4.4.3"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"typescript": "6.0.3",
|
|
59
|
+
"vitest": "3.2.6"
|
|
60
|
+
},
|
|
61
|
+
"gitHead": "ac95258c753c7e75b57da7ae47426d22b78e8c01"
|
|
62
|
+
}
|