@kaiord/garmin-connect 5.0.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -29
- package/dist/index.d.ts +64 -21
- package/dist/index.js +387 -226
- package/dist/index.js.map +1 -1
- package/package.json +9 -6
package/README.md
CHANGED
|
@@ -17,22 +17,21 @@ pnpm add @kaiord/garmin-connect
|
|
|
17
17
|
|
|
18
18
|
```typescript
|
|
19
19
|
import { createGarminConnectClient } from "@kaiord/garmin-connect";
|
|
20
|
-
import type { KRD } from "@kaiord/core";
|
|
21
20
|
|
|
22
|
-
const
|
|
21
|
+
const client = createGarminConnectClient();
|
|
23
22
|
|
|
24
23
|
// Login
|
|
25
|
-
await auth.login("email@example.com", "password");
|
|
24
|
+
await client.auth.login("email@example.com", "password");
|
|
26
25
|
|
|
27
26
|
// List workouts
|
|
28
|
-
const workouts = await service.list({ limit: 10 });
|
|
27
|
+
const workouts = await client.service.list({ limit: 10 });
|
|
29
28
|
|
|
30
29
|
// Push a KRD workout to Garmin Connect
|
|
31
|
-
const result = await service.push(krd);
|
|
30
|
+
const result = await client.service.push(krd);
|
|
32
31
|
console.log(`Pushed workout: ${result.name} (id: ${result.id})`);
|
|
33
32
|
```
|
|
34
33
|
|
|
35
|
-
### Token Persistence
|
|
34
|
+
### Token Persistence with Auto-Restore
|
|
36
35
|
|
|
37
36
|
```typescript
|
|
38
37
|
import {
|
|
@@ -40,17 +39,28 @@ import {
|
|
|
40
39
|
createFileTokenStore,
|
|
41
40
|
} from "@kaiord/garmin-connect";
|
|
42
41
|
|
|
43
|
-
const
|
|
44
|
-
|
|
42
|
+
const client = createGarminConnectClient({
|
|
43
|
+
tokenStore: createFileTokenStore("./tokens.json"),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Auto-restore tokens from store (login not needed if tokens are valid)
|
|
47
|
+
const { restored } = await client.init();
|
|
48
|
+
if (!restored) {
|
|
49
|
+
await client.auth.login("email@example.com", "password");
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### With Retry for Transient Failures
|
|
45
54
|
|
|
46
|
-
|
|
47
|
-
|
|
55
|
+
```typescript
|
|
56
|
+
import { createGarminConnectClient } from "@kaiord/garmin-connect";
|
|
48
57
|
|
|
49
|
-
|
|
50
|
-
|
|
58
|
+
const client = createGarminConnectClient({
|
|
59
|
+
retry: { maxRetries: 3, baseDelay: 1000, maxDelay: 10000 },
|
|
60
|
+
});
|
|
51
61
|
```
|
|
52
62
|
|
|
53
|
-
### Custom
|
|
63
|
+
### Custom Fetch Function
|
|
54
64
|
|
|
55
65
|
```typescript
|
|
56
66
|
import {
|
|
@@ -58,56 +68,84 @@ import {
|
|
|
58
68
|
createCookieFetch,
|
|
59
69
|
} from "@kaiord/garmin-connect";
|
|
60
70
|
|
|
61
|
-
const
|
|
62
|
-
|
|
71
|
+
const client = createGarminConnectClient({
|
|
72
|
+
fetchFn: createCookieFetch(),
|
|
73
|
+
});
|
|
63
74
|
```
|
|
64
75
|
|
|
65
76
|
## API
|
|
66
77
|
|
|
67
|
-
### `createGarminConnectClient(options?):
|
|
78
|
+
### `createGarminConnectClient(options?): GarminConnectClient`
|
|
68
79
|
|
|
69
80
|
Creates a Garmin Connect client with authentication and workout service.
|
|
70
81
|
|
|
71
82
|
**Options:**
|
|
72
83
|
|
|
73
84
|
- `fetchFn` - Custom fetch function (defaults to cookie-aware fetch)
|
|
74
|
-
- `tokenStore` - Token persistence store
|
|
85
|
+
- `tokenStore` - Token persistence store
|
|
86
|
+
- `logger` - Custom logger
|
|
87
|
+
- `retry` - Retry options: `{ maxRetries?, baseDelay?, maxDelay? }`
|
|
75
88
|
|
|
76
|
-
|
|
89
|
+
**Returns:** `{ auth, service, init }`
|
|
90
|
+
|
|
91
|
+
### `client.init(): Promise<{ restored: boolean }>`
|
|
92
|
+
|
|
93
|
+
Auto-restores tokens from the token store. Returns `{ restored: true }` if valid tokens were found. Idempotent: no-op if tokens are already in memory.
|
|
94
|
+
|
|
95
|
+
### `client.auth.login(email, password): Promise<void>`
|
|
77
96
|
|
|
78
97
|
Authenticates with Garmin Connect via SSO.
|
|
79
98
|
|
|
80
|
-
### `auth.is_authenticated(): boolean`
|
|
99
|
+
### `client.auth.is_authenticated(): boolean`
|
|
81
100
|
|
|
82
|
-
Checks if the client has valid authentication tokens.
|
|
101
|
+
Checks if the client has valid (non-expired) authentication tokens.
|
|
83
102
|
|
|
84
|
-
### `auth.export_tokens(): Promise<TokenData>`
|
|
103
|
+
### `client.auth.export_tokens(): Promise<TokenData>`
|
|
85
104
|
|
|
86
105
|
Exports current tokens for external storage.
|
|
87
106
|
|
|
88
|
-
### `auth.restore_tokens(tokens): Promise<void>`
|
|
107
|
+
### `client.auth.restore_tokens(tokens): Promise<void>`
|
|
89
108
|
|
|
90
109
|
Restores previously exported tokens.
|
|
91
110
|
|
|
92
|
-
### `
|
|
111
|
+
### `client.auth.logout(): Promise<void>`
|
|
112
|
+
|
|
113
|
+
Clears all tokens from memory and token store.
|
|
114
|
+
|
|
115
|
+
### `client.service.list(options?): Promise<WorkoutSummary[]>`
|
|
93
116
|
|
|
94
117
|
Lists workouts from Garmin Connect.
|
|
95
118
|
|
|
96
|
-
### `service.push(krd): Promise<PushResult>`
|
|
119
|
+
### `client.service.push(krd): Promise<PushResult>`
|
|
97
120
|
|
|
98
|
-
Pushes a KRD
|
|
121
|
+
Pushes a KRD-structured workout to Garmin Connect.
|
|
122
|
+
|
|
123
|
+
### `createFileTokenStore(path?): TokenStore`
|
|
124
|
+
|
|
125
|
+
Creates a file-based token store. Defaults to `~/.kaiord/garmin-tokens.json`.
|
|
126
|
+
|
|
127
|
+
### `createMemoryTokenStore(): TokenStore`
|
|
128
|
+
|
|
129
|
+
Creates an in-memory token store (tokens lost on process exit).
|
|
99
130
|
|
|
100
131
|
### `createCookieFetch(): typeof fetch`
|
|
101
132
|
|
|
102
133
|
Creates a cookie-aware fetch wrapper for SSO authentication flows.
|
|
103
134
|
|
|
104
|
-
|
|
135
|
+
## Migration from v5.x
|
|
105
136
|
|
|
106
|
-
|
|
137
|
+
```typescript
|
|
138
|
+
// Before (v5.x)
|
|
139
|
+
const { auth, service } = createGarminConnectClient();
|
|
140
|
+
await auth.login(email, password);
|
|
107
141
|
|
|
108
|
-
|
|
142
|
+
// After (v6.x)
|
|
143
|
+
const client = createGarminConnectClient({ tokenStore });
|
|
144
|
+
const { restored } = await client.init();
|
|
145
|
+
if (!restored) await client.auth.login(email, password);
|
|
146
|
+
```
|
|
109
147
|
|
|
110
|
-
|
|
148
|
+
See the [design document](https://github.com/pablo-albaladejo/kaiord/blob/main/openspec/changes/archive/2026-04-03-refactor-garmin-auth/design.md) for the full migration guide.
|
|
111
149
|
|
|
112
150
|
## License
|
|
113
151
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { WorkoutService, Logger, TokenStore, AuthProvider } from '@kaiord/core';
|
|
1
|
+
import { Logger, WorkoutService, AuthProvider, TokenStore } from '@kaiord/core';
|
|
3
2
|
export { ListOptions, PushResult, TokenData, TokenStore, WorkoutSummary } from '@kaiord/core';
|
|
4
3
|
|
|
4
|
+
type FetchFn = typeof globalThis.fetch;
|
|
5
5
|
type OAuth1Token = {
|
|
6
6
|
oauth_token: string;
|
|
7
7
|
oauth_token_secret: string;
|
|
@@ -14,33 +14,76 @@ type OAuth2Token = {
|
|
|
14
14
|
refresh_token_expires_in: number;
|
|
15
15
|
expires_at: number;
|
|
16
16
|
};
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
|
|
18
|
+
type RetryOptions = {
|
|
19
|
+
maxRetries?: number;
|
|
20
|
+
baseDelay?: number;
|
|
21
|
+
maxDelay?: number;
|
|
22
|
+
randomFn?: () => number;
|
|
23
|
+
logger?: Logger;
|
|
24
24
|
};
|
|
25
25
|
|
|
26
|
-
type GarminWorkoutClient =
|
|
26
|
+
type GarminWorkoutClient = WorkoutService;
|
|
27
27
|
|
|
28
|
-
type
|
|
28
|
+
type InitResult = {
|
|
29
|
+
restored: boolean;
|
|
30
|
+
};
|
|
31
|
+
type GarminConnectClient = {
|
|
32
|
+
auth: AuthProvider;
|
|
33
|
+
service: GarminWorkoutClient;
|
|
34
|
+
init: () => Promise<InitResult>;
|
|
35
|
+
};
|
|
36
|
+
type GarminConnectClientOptions = {
|
|
29
37
|
logger?: Logger;
|
|
30
38
|
tokenStore?: TokenStore;
|
|
31
|
-
fetchFn?:
|
|
39
|
+
fetchFn?: FetchFn;
|
|
40
|
+
retry?: RetryOptions;
|
|
32
41
|
};
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
42
|
+
|
|
43
|
+
type TokenManager = {
|
|
44
|
+
getAccessToken: () => string | undefined;
|
|
45
|
+
getOAuth1Token: () => OAuth1Token | undefined;
|
|
46
|
+
getOAuth2Token: () => OAuth2Token | undefined;
|
|
47
|
+
getGeneration: () => number;
|
|
48
|
+
isAuthenticated: () => boolean;
|
|
49
|
+
setTokens: (oauth1: OAuth1Token, oauth2: OAuth2Token) => Promise<void>;
|
|
50
|
+
clearTokens: () => Promise<void>;
|
|
51
|
+
refresh: () => Promise<void>;
|
|
52
|
+
init: () => Promise<{
|
|
53
|
+
restored: boolean;
|
|
54
|
+
}>;
|
|
36
55
|
};
|
|
37
|
-
|
|
56
|
+
type TokenReader = Pick<TokenManager, "getAccessToken" | "getGeneration" | "refresh" | "isAuthenticated">;
|
|
57
|
+
type RefreshFn = (oauth1: OAuth1Token) => Promise<OAuth2Token>;
|
|
38
58
|
|
|
39
|
-
type
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
59
|
+
type GarminAuthProviderOptions = {
|
|
60
|
+
tokenManager: TokenManager;
|
|
61
|
+
logger?: Logger;
|
|
62
|
+
fetchFn?: FetchFn;
|
|
43
63
|
};
|
|
64
|
+
declare const createGarminAuthProvider: (options: GarminAuthProviderOptions) => AuthProvider;
|
|
65
|
+
|
|
66
|
+
type Options = {
|
|
67
|
+
refreshFn: RefreshFn;
|
|
68
|
+
logger: Logger;
|
|
69
|
+
tokenStore?: TokenStore;
|
|
70
|
+
};
|
|
71
|
+
declare const createTokenManager: (options: Options) => TokenManager;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Create a Garmin Connect client with auth, workout service, and optional token auto-restore.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```ts
|
|
78
|
+
* const client = createGarminConnectClient({
|
|
79
|
+
* tokenStore: createFileTokenStore(),
|
|
80
|
+
* retry: { maxRetries: 3 },
|
|
81
|
+
* });
|
|
82
|
+
* const { restored } = await client.init();
|
|
83
|
+
* if (!restored) await client.auth.login(email, password);
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
declare const createGarminConnectClient: (options?: GarminConnectClientOptions) => GarminConnectClient;
|
|
44
87
|
|
|
45
88
|
declare const createCookieFetch: () => typeof globalThis.fetch;
|
|
46
89
|
|
|
@@ -48,4 +91,4 @@ declare const createFileTokenStore: (filePath?: string) => TokenStore;
|
|
|
48
91
|
|
|
49
92
|
declare const createMemoryTokenStore: () => TokenStore;
|
|
50
93
|
|
|
51
|
-
export { type GarminWorkoutClient, createCookieFetch, createFileTokenStore, createGarminAuthProvider, createGarminConnectClient, createMemoryTokenStore };
|
|
94
|
+
export { type GarminConnectClient, type GarminConnectClientOptions, type GarminWorkoutClient, type InitResult, type RetryOptions, type TokenReader, createCookieFetch, createFileTokenStore, createGarminAuthProvider, createGarminConnectClient, createMemoryTokenStore, createTokenManager };
|