@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 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 { auth, service } = createGarminConnectClient();
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 tokenStore = createFileTokenStore("./tokens.json");
44
- const { auth, service } = createGarminConnectClient({ tokenStore });
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
- // Login (tokens are saved automatically)
47
- await auth.login("email@example.com", "password");
55
+ ```typescript
56
+ import { createGarminConnectClient } from "@kaiord/garmin-connect";
48
57
 
49
- // On next run, tokens are restored automatically
50
- // No need to login again if tokens are still valid
58
+ const client = createGarminConnectClient({
59
+ retry: { maxRetries: 3, baseDelay: 1000, maxDelay: 10000 },
60
+ });
51
61
  ```
52
62
 
53
- ### Custom Cookie-Aware Fetch
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 cookieFetch = createCookieFetch();
62
- const { auth, service } = createGarminConnectClient({ fetchFn: cookieFetch });
71
+ const client = createGarminConnectClient({
72
+ fetchFn: createCookieFetch(),
73
+ });
63
74
  ```
64
75
 
65
76
  ## API
66
77
 
67
- ### `createGarminConnectClient(options?): { auth, service }`
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 (defaults to in-memory)
85
+ - `tokenStore` - Token persistence store
86
+ - `logger` - Custom logger
87
+ - `retry` - Retry options: `{ maxRetries?, baseDelay?, maxDelay? }`
75
88
 
76
- ### `auth.login(email, password): Promise<void>`
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
- ### `service.list(options?): Promise<WorkoutSummary[]>`
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 structured workout to Garmin Connect.
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
- ### `createFileTokenStore(path): TokenStore`
135
+ ## Migration from v5.x
105
136
 
106
- Creates a file-based token store for persistent authentication.
137
+ ```typescript
138
+ // Before (v5.x)
139
+ const { auth, service } = createGarminConnectClient();
140
+ await auth.login(email, password);
107
141
 
108
- ### `createMemoryTokenStore(): TokenStore`
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
- Creates an in-memory token store (tokens lost on process exit).
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 * as _kaiord_core from '@kaiord/core';
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
- type GarminHttpClient = {
18
- get: <T>(url: string) => Promise<T>;
19
- post: <T>(url: string, body: unknown) => Promise<T>;
20
- del: <T>(url: string) => Promise<T>;
21
- setTokens: (oauth1: OAuth1Token, oauth2: OAuth2Token) => void;
22
- clearTokens: () => void;
23
- getOAuth2Token: () => OAuth2Token | undefined;
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 = Pick<WorkoutService, "push" | "list">;
26
+ type GarminWorkoutClient = WorkoutService;
27
27
 
28
- type GarminAuthProviderOptions = {
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?: typeof globalThis.fetch;
39
+ fetchFn?: FetchFn;
40
+ retry?: RetryOptions;
32
41
  };
33
- type GarminAuthProviderResult = {
34
- auth: AuthProvider;
35
- httpClient: GarminHttpClient;
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
- declare const createGarminAuthProvider: (options?: GarminAuthProviderOptions) => GarminAuthProviderResult;
56
+ type TokenReader = Pick<TokenManager, "getAccessToken" | "getGeneration" | "refresh" | "isAuthenticated">;
57
+ type RefreshFn = (oauth1: OAuth1Token) => Promise<OAuth2Token>;
38
58
 
39
- type GarminConnectClientOptions = GarminAuthProviderOptions;
40
- declare const createGarminConnectClient: (options?: GarminConnectClientOptions) => {
41
- auth: _kaiord_core.AuthProvider;
42
- service: GarminWorkoutClient;
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 };