garmin-bud 0.2.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/.env.example +11 -0
- package/CHANGELOG.md +56 -0
- package/LICENSE +21 -0
- package/QUICKSTART.md +174 -0
- package/README.md +227 -0
- package/dist/appDb.d.ts +32 -0
- package/dist/appDb.d.ts.map +1 -0
- package/dist/appDb.js +131 -0
- package/dist/appDb.js.map +1 -0
- package/dist/check.d.ts +9 -0
- package/dist/check.d.ts.map +1 -0
- package/dist/check.js +156 -0
- package/dist/check.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +187 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +28 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +108 -0
- package/dist/config.js.map +1 -0
- package/dist/dashboard.d.ts +4 -0
- package/dist/dashboard.d.ts.map +1 -0
- package/dist/dashboard.js +111 -0
- package/dist/dashboard.js.map +1 -0
- package/dist/garmin/auth.d.ts +10 -0
- package/dist/garmin/auth.d.ts.map +1 -0
- package/dist/garmin/auth.js +81 -0
- package/dist/garmin/auth.js.map +1 -0
- package/dist/garmin/cache.d.ts +20 -0
- package/dist/garmin/cache.d.ts.map +1 -0
- package/dist/garmin/cache.js +115 -0
- package/dist/garmin/cache.js.map +1 -0
- package/dist/garmin/client.d.ts +5 -0
- package/dist/garmin/client.d.ts.map +1 -0
- package/dist/garmin/client.js +68 -0
- package/dist/garmin/client.js.map +1 -0
- package/dist/garmin/garminApiTypes.d.ts +70 -0
- package/dist/garmin/garminApiTypes.d.ts.map +1 -0
- package/dist/garmin/garminApiTypes.js +3 -0
- package/dist/garmin/garminApiTypes.js.map +1 -0
- package/dist/garmin/garminConnect.d.ts +17 -0
- package/dist/garmin/garminConnect.d.ts.map +1 -0
- package/dist/garmin/garminConnect.js +5 -0
- package/dist/garmin/garminConnect.js.map +1 -0
- package/dist/garmin/rawApi.d.ts +18 -0
- package/dist/garmin/rawApi.d.ts.map +1 -0
- package/dist/garmin/rawApi.js +53 -0
- package/dist/garmin/rawApi.js.map +1 -0
- package/dist/garmin/types.d.ts +68 -0
- package/dist/garmin/types.d.ts.map +1 -0
- package/dist/garmin/types.js +11 -0
- package/dist/garmin/types.js.map +1 -0
- package/dist/httpServer.d.ts +7 -0
- package/dist/httpServer.d.ts.map +1 -0
- package/dist/httpServer.js +386 -0
- package/dist/httpServer.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/mcpConfig.d.ts +37 -0
- package/dist/mcpConfig.d.ts.map +1 -0
- package/dist/mcpConfig.js +83 -0
- package/dist/mcpConfig.js.map +1 -0
- package/dist/pairApi.d.ts +14 -0
- package/dist/pairApi.d.ts.map +1 -0
- package/dist/pairApi.js +34 -0
- package/dist/pairApi.js.map +1 -0
- package/dist/promptApi.d.ts +13 -0
- package/dist/promptApi.d.ts.map +1 -0
- package/dist/promptApi.js +102 -0
- package/dist/promptApi.js.map +1 -0
- package/dist/server.d.ts +10 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +67 -0
- package/dist/server.js.map +1 -0
- package/dist/setup.d.ts +2 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +194 -0
- package/dist/setup.js.map +1 -0
- package/dist/toolErrors.d.ts +2 -0
- package/dist/toolErrors.d.ts.map +1 -0
- package/dist/toolErrors.js +18 -0
- package/dist/toolErrors.js.map +1 -0
- package/dist/tools/activities.d.ts +11 -0
- package/dist/tools/activities.d.ts.map +1 -0
- package/dist/tools/activities.js +134 -0
- package/dist/tools/activities.js.map +1 -0
- package/dist/tools/bodyComposition.d.ts +7 -0
- package/dist/tools/bodyComposition.d.ts.map +1 -0
- package/dist/tools/bodyComposition.js +97 -0
- package/dist/tools/bodyComposition.js.map +1 -0
- package/dist/tools/heartRate.d.ts +7 -0
- package/dist/tools/heartRate.d.ts.map +1 -0
- package/dist/tools/heartRate.js +88 -0
- package/dist/tools/heartRate.js.map +1 -0
- package/dist/tools/index.d.ts +39 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +77 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/recovery.d.ts +16 -0
- package/dist/tools/recovery.d.ts.map +1 -0
- package/dist/tools/recovery.js +214 -0
- package/dist/tools/recovery.js.map +1 -0
- package/dist/tools/sleep.d.ts +7 -0
- package/dist/tools/sleep.d.ts.map +1 -0
- package/dist/tools/sleep.js +93 -0
- package/dist/tools/sleep.js.map +1 -0
- package/dist/tools/stress.d.ts +7 -0
- package/dist/tools/stress.d.ts.map +1 -0
- package/dist/tools/stress.js +69 -0
- package/dist/tools/stress.js.map +1 -0
- package/dist/tools/trainingInsights.d.ts +7 -0
- package/dist/tools/trainingInsights.d.ts.map +1 -0
- package/dist/tools/trainingInsights.js +61 -0
- package/dist/tools/trainingInsights.js.map +1 -0
- package/dist/tools/types.d.ts +12 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +2 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/vo2Max.d.ts +7 -0
- package/dist/tools/vo2Max.d.ts.map +1 -0
- package/dist/tools/vo2Max.js +72 -0
- package/dist/tools/vo2Max.js.map +1 -0
- package/dist/utils/batch.d.ts +2 -0
- package/dist/utils/batch.d.ts.map +1 -0
- package/dist/utils/batch.js +18 -0
- package/dist/utils/batch.js.map +1 -0
- package/dist/utils/helpers.d.ts +19 -0
- package/dist/utils/helpers.d.ts.map +1 -0
- package/dist/utils/helpers.js +131 -0
- package/dist/utils/helpers.js.map +1 -0
- package/dist/utils/logger.d.ts +4 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +59 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +7 -0
- package/dist/version.js.map +1 -0
- package/dist/watchApi.d.ts +47 -0
- package/dist/watchApi.d.ts.map +1 -0
- package/dist/watchApi.js +222 -0
- package/dist/watchApi.js.map +1 -0
- package/package.json +77 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { GarminConnectInstance } from "./garminConnect.js";
|
|
2
|
+
import type { StoredSession } from "./types.js";
|
|
3
|
+
export declare function sessionDirectory(): string;
|
|
4
|
+
export declare function sessionExists(): boolean;
|
|
5
|
+
export declare function readStoredSession(): StoredSession | null;
|
|
6
|
+
export declare function writeStoredSession(session: StoredSession): void;
|
|
7
|
+
export declare function clearStoredSession(): void;
|
|
8
|
+
export declare function createGarminClient(): GarminConnectInstance;
|
|
9
|
+
export declare function authenticateGarmin(force?: boolean): Promise<GarminConnectInstance>;
|
|
10
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/garmin/auth.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAIhE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAIhD,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAED,wBAAgB,iBAAiB,IAAI,aAAa,GAAG,IAAI,CAoBxD;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAI/D;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAKzC;AAID,wBAAgB,kBAAkB,IAAI,qBAAqB,CAM1D;AAED,wBAAsB,kBAAkB,CAAC,KAAK,UAAQ,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAkCtF"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { GarminConnect } from "./garminConnect.js";
|
|
4
|
+
import { appConfig, assertGarminCredentials } from "../config.js";
|
|
5
|
+
import { logger } from "../utils/logger.js";
|
|
6
|
+
// SECTION: Session Persistence
|
|
7
|
+
export function sessionDirectory() {
|
|
8
|
+
return path.dirname(appConfig.sessionPath);
|
|
9
|
+
}
|
|
10
|
+
export function sessionExists() {
|
|
11
|
+
return fs.existsSync(appConfig.sessionPath);
|
|
12
|
+
}
|
|
13
|
+
export function readStoredSession() {
|
|
14
|
+
const sessionPath = appConfig.sessionPath;
|
|
15
|
+
if (!fs.existsSync(sessionPath)) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
const raw = fs.readFileSync(sessionPath, "utf8");
|
|
20
|
+
const parsed = JSON.parse(raw);
|
|
21
|
+
if (!parsed.oauth1 || !parsed.oauth2) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
return parsed;
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
logger.warn({ error }, "Failed to read stored Garmin session");
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function writeStoredSession(session) {
|
|
32
|
+
const sessionPath = appConfig.sessionPath;
|
|
33
|
+
fs.mkdirSync(path.dirname(sessionPath), { recursive: true });
|
|
34
|
+
fs.writeFileSync(sessionPath, JSON.stringify(session, null, 2), "utf8");
|
|
35
|
+
}
|
|
36
|
+
export function clearStoredSession() {
|
|
37
|
+
const sessionPath = appConfig.sessionPath;
|
|
38
|
+
if (fs.existsSync(sessionPath)) {
|
|
39
|
+
fs.unlinkSync(sessionPath);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// SECTION: Authentication
|
|
43
|
+
export function createGarminClient() {
|
|
44
|
+
assertGarminCredentials();
|
|
45
|
+
return new GarminConnect({
|
|
46
|
+
username: appConfig.garminEmail,
|
|
47
|
+
password: appConfig.garminPassword,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
export async function authenticateGarmin(force = false) {
|
|
51
|
+
const client = createGarminClient();
|
|
52
|
+
if (!force) {
|
|
53
|
+
const storedSession = readStoredSession();
|
|
54
|
+
if (storedSession) {
|
|
55
|
+
client.loadToken(storedSession.oauth1, storedSession.oauth2);
|
|
56
|
+
try {
|
|
57
|
+
await client.getUserProfile();
|
|
58
|
+
logger.info("Restored Garmin session from disk");
|
|
59
|
+
return client;
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
logger.warn({ error }, "Stored Garmin session expired, re-authenticating");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
clearStoredSession();
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
await client.login();
|
|
71
|
+
const tokens = client.exportToken();
|
|
72
|
+
writeStoredSession(tokens);
|
|
73
|
+
logger.info("Authenticated with Garmin Connect");
|
|
74
|
+
return client;
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
const message = error instanceof Error ? error.message : "Unknown authentication error";
|
|
78
|
+
throw new Error(`Garmin authentication failed: ${message}. Verify credentials in .env. MFA is not supported yet.`, { cause: error });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/garmin/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare class GarminCache {
|
|
2
|
+
private readonly db;
|
|
3
|
+
constructor(databasePath?: string);
|
|
4
|
+
private initialize;
|
|
5
|
+
buildKey(tool: string, params: Record<string, unknown>): string;
|
|
6
|
+
get<T>(key: string): T | null;
|
|
7
|
+
set<T>(key: string, value: T, ttlSeconds: number): void;
|
|
8
|
+
delete(key: string): void;
|
|
9
|
+
clear(): number;
|
|
10
|
+
stats(): {
|
|
11
|
+
entries: number;
|
|
12
|
+
expiredEntries: number;
|
|
13
|
+
};
|
|
14
|
+
close(): void;
|
|
15
|
+
}
|
|
16
|
+
export declare function getCache(): GarminCache;
|
|
17
|
+
export declare function closeCache(): void;
|
|
18
|
+
export declare function buildToolCacheKey(tool: string, params: Record<string, unknown>): string;
|
|
19
|
+
export declare function withCache<T>(key: string, ttlSeconds: number, fetcher: () => Promise<T>): Promise<T>;
|
|
20
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/garmin/cache.ts"],"names":[],"mappings":"AAgBA,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAoB;gBAE3B,YAAY,SAAsB;IAM9C,OAAO,CAAC,UAAU;IAWlB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM;IAI/D,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI;IAwB7B,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAqBvD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIzB,KAAK,IAAI,MAAM;IAKf,KAAK,IAAI;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE;IAepD,KAAK,IAAI,IAAI;CAGd;AAID,wBAAgB,QAAQ,IAAI,WAAW,CAMtC;AAED,wBAAgB,UAAU,IAAI,IAAI,CAKjC;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAEvF;AAED,wBAAsB,SAAS,CAAC,CAAC,EAC/B,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACxB,OAAO,CAAC,CAAC,CAAC,CAWZ"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import Database from "better-sqlite3";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { appConfig } from "../config.js";
|
|
5
|
+
import { hashParams } from "../utils/helpers.js";
|
|
6
|
+
import { logger } from "../utils/logger.js";
|
|
7
|
+
// SECTION: SQLite Cache
|
|
8
|
+
export class GarminCache {
|
|
9
|
+
db;
|
|
10
|
+
constructor(databasePath = appConfig.cachePath) {
|
|
11
|
+
fs.mkdirSync(path.dirname(databasePath), { recursive: true });
|
|
12
|
+
this.db = new Database(databasePath);
|
|
13
|
+
this.initialize();
|
|
14
|
+
}
|
|
15
|
+
initialize() {
|
|
16
|
+
this.db.exec(`
|
|
17
|
+
CREATE TABLE IF NOT EXISTS cache (
|
|
18
|
+
key TEXT PRIMARY KEY,
|
|
19
|
+
data TEXT NOT NULL,
|
|
20
|
+
cached_at INTEGER NOT NULL,
|
|
21
|
+
ttl INTEGER NOT NULL
|
|
22
|
+
)
|
|
23
|
+
`);
|
|
24
|
+
}
|
|
25
|
+
buildKey(tool, params) {
|
|
26
|
+
return `${tool}:${hashParams(params)}`;
|
|
27
|
+
}
|
|
28
|
+
get(key) {
|
|
29
|
+
const row = this.db
|
|
30
|
+
.prepare("SELECT key, data, cached_at, ttl FROM cache WHERE key = ?")
|
|
31
|
+
.get(key);
|
|
32
|
+
if (!row) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const expiresAt = row.cached_at + row.ttl;
|
|
36
|
+
if (Date.now() > expiresAt * 1000) {
|
|
37
|
+
this.delete(key);
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
return JSON.parse(row.data);
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
logger.warn({ error, key }, "Failed to parse cached payload");
|
|
45
|
+
this.delete(key);
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
set(key, value, ttlSeconds) {
|
|
50
|
+
const cachedAt = Math.floor(Date.now() / 1000);
|
|
51
|
+
this.db
|
|
52
|
+
.prepare(`
|
|
53
|
+
INSERT INTO cache (key, data, cached_at, ttl)
|
|
54
|
+
VALUES (@key, @data, @cached_at, @ttl)
|
|
55
|
+
ON CONFLICT(key) DO UPDATE SET
|
|
56
|
+
data = excluded.data,
|
|
57
|
+
cached_at = excluded.cached_at,
|
|
58
|
+
ttl = excluded.ttl
|
|
59
|
+
`)
|
|
60
|
+
.run({
|
|
61
|
+
key,
|
|
62
|
+
data: JSON.stringify(value),
|
|
63
|
+
cached_at: cachedAt,
|
|
64
|
+
ttl: ttlSeconds,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
delete(key) {
|
|
68
|
+
this.db.prepare("DELETE FROM cache WHERE key = ?").run(key);
|
|
69
|
+
}
|
|
70
|
+
clear() {
|
|
71
|
+
const result = this.db.prepare("DELETE FROM cache").run();
|
|
72
|
+
return result.changes;
|
|
73
|
+
}
|
|
74
|
+
stats() {
|
|
75
|
+
const now = Math.floor(Date.now() / 1000);
|
|
76
|
+
const entries = this.db.prepare("SELECT COUNT(*) as count FROM cache").get();
|
|
77
|
+
const expiredEntries = this.db
|
|
78
|
+
.prepare("SELECT COUNT(*) as count FROM cache WHERE cached_at + ttl < ?")
|
|
79
|
+
.get(now);
|
|
80
|
+
return {
|
|
81
|
+
entries: entries.count,
|
|
82
|
+
expiredEntries: expiredEntries.count,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
close() {
|
|
86
|
+
this.db.close();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
let cacheInstance = null;
|
|
90
|
+
export function getCache() {
|
|
91
|
+
if (!cacheInstance) {
|
|
92
|
+
cacheInstance = new GarminCache();
|
|
93
|
+
}
|
|
94
|
+
return cacheInstance;
|
|
95
|
+
}
|
|
96
|
+
export function closeCache() {
|
|
97
|
+
if (cacheInstance) {
|
|
98
|
+
cacheInstance.close();
|
|
99
|
+
cacheInstance = null;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
export function buildToolCacheKey(tool, params) {
|
|
103
|
+
return getCache().buildKey(tool, params);
|
|
104
|
+
}
|
|
105
|
+
export async function withCache(key, ttlSeconds, fetcher) {
|
|
106
|
+
const cache = getCache();
|
|
107
|
+
const cached = cache.get(key);
|
|
108
|
+
if (cached !== null) {
|
|
109
|
+
return cached;
|
|
110
|
+
}
|
|
111
|
+
const fresh = await fetcher();
|
|
112
|
+
cache.set(key, fresh, ttlSeconds);
|
|
113
|
+
return fresh;
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/garmin/cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { GarminConnectInstance } from "./garminConnect.js";
|
|
2
|
+
export declare function getGarminClient(forceAuth?: boolean): Promise<GarminConnectInstance>;
|
|
3
|
+
export declare function resetGarminClient(): void;
|
|
4
|
+
export declare function withGarminClient<T>(operation: (client: GarminConnectInstance) => Promise<T>): Promise<T>;
|
|
5
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/garmin/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAUhE,wBAAsB,eAAe,CAAC,SAAS,UAAQ,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAmBvF;AAED,wBAAgB,iBAAiB,IAAI,IAAI,CAGxC;AA8BD,wBAAsB,gBAAgB,CAAC,CAAC,EACtC,SAAS,EAAE,CAAC,MAAM,EAAE,qBAAqB,KAAK,OAAO,CAAC,CAAC,CAAC,GACvD,OAAO,CAAC,CAAC,CAAC,CAmBZ"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { authenticateGarmin } from "./auth.js";
|
|
2
|
+
import { logger } from "../utils/logger.js";
|
|
3
|
+
import { GarminApiError } from "./types.js";
|
|
4
|
+
// SECTION: Garmin Client Singleton
|
|
5
|
+
let clientInstance = null;
|
|
6
|
+
let clientPromise = null;
|
|
7
|
+
export async function getGarminClient(forceAuth = false) {
|
|
8
|
+
if (forceAuth) {
|
|
9
|
+
clientInstance = await authenticateGarmin(true);
|
|
10
|
+
clientPromise = Promise.resolve(clientInstance);
|
|
11
|
+
return clientInstance;
|
|
12
|
+
}
|
|
13
|
+
if (clientInstance) {
|
|
14
|
+
return clientInstance;
|
|
15
|
+
}
|
|
16
|
+
if (!clientPromise) {
|
|
17
|
+
clientPromise = authenticateGarmin(false).then((client) => {
|
|
18
|
+
clientInstance = client;
|
|
19
|
+
return client;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return clientPromise;
|
|
23
|
+
}
|
|
24
|
+
export function resetGarminClient() {
|
|
25
|
+
clientInstance = null;
|
|
26
|
+
clientPromise = null;
|
|
27
|
+
}
|
|
28
|
+
function isAuthError(error) {
|
|
29
|
+
if (!(error instanceof Error)) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
const message = error.message.toLowerCase();
|
|
33
|
+
return (message.includes("401") ||
|
|
34
|
+
message.includes("403") ||
|
|
35
|
+
message.includes("unauthorized") ||
|
|
36
|
+
message.includes("token") ||
|
|
37
|
+
message.includes("login failed"));
|
|
38
|
+
}
|
|
39
|
+
function toRateLimitError(error) {
|
|
40
|
+
if (!(error instanceof Error)) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const message = error.message.toLowerCase();
|
|
44
|
+
if (!message.includes("429") && !message.includes("rate limit")) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
return new GarminApiError("Garmin rate limit reached. Retry in about 60 seconds.", 429, 60);
|
|
48
|
+
}
|
|
49
|
+
export async function withGarminClient(operation) {
|
|
50
|
+
try {
|
|
51
|
+
const client = await getGarminClient(false);
|
|
52
|
+
return await operation(client);
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
const rateLimitError = toRateLimitError(error);
|
|
56
|
+
if (rateLimitError) {
|
|
57
|
+
throw rateLimitError;
|
|
58
|
+
}
|
|
59
|
+
if (!isAuthError(error)) {
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
logger.warn({ error }, "Garmin request failed auth, retrying once");
|
|
63
|
+
resetGarminClient();
|
|
64
|
+
const client = await getGarminClient(true);
|
|
65
|
+
return await operation(client);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/garmin/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export interface GarminOAuth1 {
|
|
2
|
+
oauth_token: string;
|
|
3
|
+
oauth_token_secret: string;
|
|
4
|
+
}
|
|
5
|
+
export interface GarminOAuth2 {
|
|
6
|
+
scope: string;
|
|
7
|
+
jti: string;
|
|
8
|
+
access_token: string;
|
|
9
|
+
token_type: string;
|
|
10
|
+
refresh_token: string;
|
|
11
|
+
expires_in: number;
|
|
12
|
+
expires_at: number;
|
|
13
|
+
refresh_token_expires_in: number;
|
|
14
|
+
refresh_token_expires_at: number;
|
|
15
|
+
}
|
|
16
|
+
export interface StoredSessionTokens {
|
|
17
|
+
oauth1: GarminOAuth1;
|
|
18
|
+
oauth2: GarminOAuth2;
|
|
19
|
+
}
|
|
20
|
+
export interface IActivity {
|
|
21
|
+
activityId: number;
|
|
22
|
+
activityName: string;
|
|
23
|
+
startTimeLocal: string;
|
|
24
|
+
distance: number;
|
|
25
|
+
duration: number;
|
|
26
|
+
averageHR?: number;
|
|
27
|
+
maxHR?: number;
|
|
28
|
+
elevationGain: number;
|
|
29
|
+
calories: number;
|
|
30
|
+
averageSpeed: number;
|
|
31
|
+
activityType: {
|
|
32
|
+
typeKey: string;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export interface SleepData {
|
|
36
|
+
avgOvernightHrv?: number | null;
|
|
37
|
+
hrvStatus?: string | null;
|
|
38
|
+
dailySleepDTO?: {
|
|
39
|
+
sleepTimeSeconds: number;
|
|
40
|
+
deepSleepSeconds: number;
|
|
41
|
+
lightSleepSeconds: number;
|
|
42
|
+
remSleepSeconds: number;
|
|
43
|
+
awakeCount: number;
|
|
44
|
+
avgSleepStress?: number | null;
|
|
45
|
+
sleepScores?: {
|
|
46
|
+
overall?: {
|
|
47
|
+
value: number;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export interface HeartRateData {
|
|
53
|
+
restingHeartRate?: number;
|
|
54
|
+
maxHeartRate?: number;
|
|
55
|
+
minHeartRate?: number;
|
|
56
|
+
lastSevenDaysAvgRestingHeartRate?: number;
|
|
57
|
+
heartRateValues?: Array<Array<{
|
|
58
|
+
heartrate: number;
|
|
59
|
+
} | null> | null> | null;
|
|
60
|
+
}
|
|
61
|
+
export interface WeightDataResponse {
|
|
62
|
+
dateWeightList: Array<{
|
|
63
|
+
calendarDate: string;
|
|
64
|
+
weight: number;
|
|
65
|
+
bodyFat: number | null;
|
|
66
|
+
muscleMass: number | null;
|
|
67
|
+
bmi: number | null;
|
|
68
|
+
}>;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=garminApiTypes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"garminApiTypes.d.ts","sourceRoot":"","sources":["../../src/garmin/garminApiTypes.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,wBAAwB,EAAE,MAAM,CAAC;IACjC,wBAAwB,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE;QACZ,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED,MAAM,WAAW,SAAS;IACxB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,CAAC,EAAE;QACd,gBAAgB,EAAE,MAAM,CAAC;QACzB,gBAAgB,EAAE,MAAM,CAAC;QACzB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,eAAe,EAAE,MAAM,CAAC;QACxB,UAAU,EAAE,MAAM,CAAC;QACnB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC/B,WAAW,CAAC,EAAE;YACZ,OAAO,CAAC,EAAE;gBACR,KAAK,EAAE,MAAM,CAAC;aACf,CAAC;SACH,CAAC;KACH,CAAC;CACH;AAED,MAAM,WAAW,aAAa;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gCAAgC,CAAC,EAAE,MAAM,CAAC;IAC1C,eAAe,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;CAC5E;AAED,MAAM,WAAW,kBAAkB;IACjC,cAAc,EAAE,KAAK,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;KACpB,CAAC,CAAC;CACJ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"garminApiTypes.js","sourceRoot":"","sources":["../../src/garmin/garminApiTypes.ts"],"names":[],"mappings":"AAAA,wGAAwG"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { HeartRateData, IActivity, SleepData, StoredSessionTokens, WeightDataResponse } from "./garminApiTypes.js";
|
|
2
|
+
export interface GarminConnectInstance {
|
|
3
|
+
login: (username?: string, password?: string) => Promise<GarminConnectInstance>;
|
|
4
|
+
loadToken: (oauth1: StoredSessionTokens["oauth1"], oauth2: StoredSessionTokens["oauth2"]) => void;
|
|
5
|
+
exportToken: () => StoredSessionTokens;
|
|
6
|
+
getUserProfile: () => Promise<unknown>;
|
|
7
|
+
getActivities: (start?: number, limit?: number) => Promise<IActivity[]>;
|
|
8
|
+
getSleepData: (date?: Date) => Promise<SleepData>;
|
|
9
|
+
getHeartRate: (date?: Date) => Promise<HeartRateData>;
|
|
10
|
+
getDailyWeightData: (date?: Date) => Promise<WeightDataResponse>;
|
|
11
|
+
get: (url: string, data?: Record<string, unknown>) => Promise<unknown>;
|
|
12
|
+
}
|
|
13
|
+
export declare const GarminConnect: new (credentials?: {
|
|
14
|
+
username: string;
|
|
15
|
+
password: string;
|
|
16
|
+
}) => GarminConnectInstance;
|
|
17
|
+
//# sourceMappingURL=garminConnect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"garminConnect.d.ts","sourceRoot":"","sources":["../../src/garmin/garminConnect.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,aAAa,EACb,SAAS,EACT,SAAS,EACT,mBAAmB,EACnB,kBAAkB,EACnB,MAAM,qBAAqB,CAAC;AAQ7B,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAChF,SAAS,EAAE,CAAC,MAAM,EAAE,mBAAmB,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,mBAAmB,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAClG,WAAW,EAAE,MAAM,mBAAmB,CAAC;IACvC,cAAc,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,aAAa,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IACxE,YAAY,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IAClD,YAAY,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;IACtD,kBAAkB,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACjE,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACxE;AAID,eAAO,MAAM,aAAa,qBAjBU;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,KAAK,qBAiB3B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"garminConnect.js","sourceRoot":"","sources":["../../src/garmin/garminConnect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAS5C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAkB/C,MAAM,SAAS,GAAG,OAAO,CAAC,gBAAgB,CAAwB,CAAC;AAEnE,MAAM,CAAC,MAAM,aAAa,GAAG,SAAS,CAAC,aAAa,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { GarminConnectInstance } from "./garminConnect.js";
|
|
2
|
+
export declare function fetchDailyStress(client: GarminConnectInstance, date: Date): Promise<unknown>;
|
|
3
|
+
export declare function fetchMaxMetrics(client: GarminConnectInstance, date: Date): Promise<unknown>;
|
|
4
|
+
export interface DailyStressSummary {
|
|
5
|
+
date: string;
|
|
6
|
+
averageStress: number | null;
|
|
7
|
+
maxStress: number | null;
|
|
8
|
+
restStress: number | null;
|
|
9
|
+
stressDurationSeconds: number | null;
|
|
10
|
+
}
|
|
11
|
+
export interface Vo2MaxEntry {
|
|
12
|
+
date: string;
|
|
13
|
+
vo2Max: number | null;
|
|
14
|
+
vo2MaxCycling: number | null;
|
|
15
|
+
}
|
|
16
|
+
export declare function mapDailyStress(date: Date, payload: unknown): DailyStressSummary | null;
|
|
17
|
+
export declare function mapMaxMetrics(date: Date, payload: unknown): Vo2MaxEntry | null;
|
|
18
|
+
//# sourceMappingURL=rawApi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rawApi.d.ts","sourceRoot":"","sources":["../../src/garmin/rawApi.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAQhE,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,qBAAqB,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAIlG;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,qBAAqB,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAEjG;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,GAAG,kBAAkB,GAAG,IAAI,CAetF;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,GAAG,WAAW,GAAG,IAAI,CAgC9E"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { DateTime } from "luxon";
|
|
2
|
+
const GC_API = "https://connectapi.garmin.com";
|
|
3
|
+
function toGarminDate(date) {
|
|
4
|
+
return DateTime.fromJSDate(date, { zone: "utc" }).toFormat("yyyy-MM-dd");
|
|
5
|
+
}
|
|
6
|
+
export async function fetchDailyStress(client, date) {
|
|
7
|
+
return client.get(`${GC_API}/wellness-service/wellness/dailyStress`, {
|
|
8
|
+
params: { date: toGarminDate(date) },
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
export async function fetchMaxMetrics(client, date) {
|
|
12
|
+
return client.get(`${GC_API}/metrics-service/metrics/maxmet/daily/${toGarminDate(date)}`);
|
|
13
|
+
}
|
|
14
|
+
export function mapDailyStress(date, payload) {
|
|
15
|
+
if (!payload || typeof payload !== "object") {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
const data = payload;
|
|
19
|
+
return {
|
|
20
|
+
date: toGarminDate(date),
|
|
21
|
+
averageStress: typeof data.overallStressLevel === "number" ? data.overallStressLevel : null,
|
|
22
|
+
maxStress: typeof data.maxStressLevel === "number" ? data.maxStressLevel : null,
|
|
23
|
+
restStress: typeof data.restStressLevel === "number" ? data.restStressLevel : null,
|
|
24
|
+
stressDurationSeconds: typeof data.stressDuration === "number" ? data.stressDuration : null,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export function mapMaxMetrics(date, payload) {
|
|
28
|
+
if (!payload || typeof payload !== "object") {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
const data = payload;
|
|
32
|
+
const generic = data.generic;
|
|
33
|
+
const cycling = data.cycling;
|
|
34
|
+
const vo2Max = typeof generic?.vo2MaxValue === "number"
|
|
35
|
+
? generic.vo2MaxValue
|
|
36
|
+
: typeof data.vo2MaxValue === "number"
|
|
37
|
+
? data.vo2MaxValue
|
|
38
|
+
: null;
|
|
39
|
+
const vo2MaxCycling = typeof cycling?.vo2MaxValue === "number"
|
|
40
|
+
? cycling.vo2MaxValue
|
|
41
|
+
: typeof data.vo2MaxCyclingValue === "number"
|
|
42
|
+
? data.vo2MaxCyclingValue
|
|
43
|
+
: null;
|
|
44
|
+
if (vo2Max === null && vo2MaxCycling === null) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
date: toGarminDate(date),
|
|
49
|
+
vo2Max,
|
|
50
|
+
vo2MaxCycling,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=rawApi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rawApi.js","sourceRoot":"","sources":["../../src/garmin/rawApi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAGjC,MAAM,MAAM,GAAG,+BAA+B,CAAC;AAE/C,SAAS,YAAY,CAAC,IAAU;IAC9B,OAAO,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAA6B,EAAE,IAAU;IAC9E,OAAO,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,wCAAwC,EAAE;QACnE,MAAM,EAAE,EAAE,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE;KACrC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAA6B,EAAE,IAAU;IAC7E,OAAO,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,yCAAyC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC5F,CAAC;AAgBD,MAAM,UAAU,cAAc,CAAC,IAAU,EAAE,OAAgB;IACzD,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC5C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,IAAI,GAAG,OAAkC,CAAC;IAEhD,OAAO;QACL,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC;QACxB,aAAa,EAAE,OAAO,IAAI,CAAC,kBAAkB,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI;QAC3F,SAAS,EAAE,OAAO,IAAI,CAAC,cAAc,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI;QAC/E,UAAU,EAAE,OAAO,IAAI,CAAC,eAAe,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI;QAClF,qBAAqB,EACnB,OAAO,IAAI,CAAC,cAAc,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI;KACvE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAU,EAAE,OAAgB;IACxD,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC5C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,IAAI,GAAG,OAAkC,CAAC;IAChD,MAAM,OAAO,GAAG,IAAI,CAAC,OAA8C,CAAC;IACpE,MAAM,OAAO,GAAG,IAAI,CAAC,OAA8C,CAAC;IAEpE,MAAM,MAAM,GACV,OAAO,OAAO,EAAE,WAAW,KAAK,QAAQ;QACtC,CAAC,CAAC,OAAO,CAAC,WAAW;QACrB,CAAC,CAAC,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ;YACpC,CAAC,CAAC,IAAI,CAAC,WAAW;YAClB,CAAC,CAAC,IAAI,CAAC;IAEb,MAAM,aAAa,GACjB,OAAO,OAAO,EAAE,WAAW,KAAK,QAAQ;QACtC,CAAC,CAAC,OAAO,CAAC,WAAW;QACrB,CAAC,CAAC,OAAO,IAAI,CAAC,kBAAkB,KAAK,QAAQ;YAC3C,CAAC,CAAC,IAAI,CAAC,kBAAkB;YACzB,CAAC,CAAC,IAAI,CAAC;IAEb,IAAI,MAAM,KAAK,IAAI,IAAI,aAAa,KAAK,IAAI,EAAE,CAAC;QAC9C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO;QACL,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC;QACxB,MAAM;QACN,aAAa;KACd,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { StoredSessionTokens } from "./garminApiTypes.js";
|
|
2
|
+
export type StoredSession = StoredSessionTokens;
|
|
3
|
+
export interface ActivitySummary {
|
|
4
|
+
activityId: number;
|
|
5
|
+
name: string;
|
|
6
|
+
type: string;
|
|
7
|
+
startTimeLocal: string;
|
|
8
|
+
distanceMeters: number;
|
|
9
|
+
durationSeconds: number;
|
|
10
|
+
averageHeartRate: number | null;
|
|
11
|
+
maxHeartRate: number | null;
|
|
12
|
+
elevationGainMeters: number;
|
|
13
|
+
calories: number;
|
|
14
|
+
averageSpeedMps: number;
|
|
15
|
+
}
|
|
16
|
+
export interface SleepNightSummary {
|
|
17
|
+
date: string;
|
|
18
|
+
totalSleepSeconds: number;
|
|
19
|
+
deepSleepSeconds: number;
|
|
20
|
+
lightSleepSeconds: number;
|
|
21
|
+
remSleepSeconds: number;
|
|
22
|
+
awakeCount: number;
|
|
23
|
+
sleepScore: number | null;
|
|
24
|
+
avgSleepStress: number | null;
|
|
25
|
+
avgOvernightHrv: number | null;
|
|
26
|
+
hrvStatus: string | null;
|
|
27
|
+
}
|
|
28
|
+
export interface HeartRateDaySummary {
|
|
29
|
+
date: string;
|
|
30
|
+
restingHeartRate: number | null;
|
|
31
|
+
maxHeartRate: number | null;
|
|
32
|
+
minHeartRate: number | null;
|
|
33
|
+
averageHeartRate: number | null;
|
|
34
|
+
}
|
|
35
|
+
export interface BodyCompositionEntry {
|
|
36
|
+
date: string;
|
|
37
|
+
weightKg: number | null;
|
|
38
|
+
bodyFatPercent: number | null;
|
|
39
|
+
muscleMassKg: number | null;
|
|
40
|
+
bmi: number | null;
|
|
41
|
+
}
|
|
42
|
+
export interface RecoveryWeights {
|
|
43
|
+
hrv: number;
|
|
44
|
+
sleep: number;
|
|
45
|
+
stress: number;
|
|
46
|
+
restingHr: number;
|
|
47
|
+
}
|
|
48
|
+
export interface RecoveryStatusResult {
|
|
49
|
+
score: number;
|
|
50
|
+
status: "recovered" | "good" | "fatigued";
|
|
51
|
+
recommendation: string;
|
|
52
|
+
components: {
|
|
53
|
+
hrvScore: number;
|
|
54
|
+
sleepScore: number;
|
|
55
|
+
stressScore: number;
|
|
56
|
+
restingHrScore: number;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export interface ToolTextResult {
|
|
60
|
+
type: "text";
|
|
61
|
+
text: string;
|
|
62
|
+
}
|
|
63
|
+
export declare class GarminApiError extends Error {
|
|
64
|
+
readonly statusCode?: number;
|
|
65
|
+
readonly retryAfterSeconds?: number;
|
|
66
|
+
constructor(message: string, statusCode?: number, retryAfterSeconds?: number);
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/garmin/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE/D,MAAM,MAAM,aAAa,GAAG,mBAAmB,CAAC;AAEhD,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,WAAW,GAAG,MAAM,GAAG,UAAU,CAAC;IAC1C,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE;QACV,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;CACH;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;gBAExB,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM;CAM7E"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export class GarminApiError extends Error {
|
|
2
|
+
statusCode;
|
|
3
|
+
retryAfterSeconds;
|
|
4
|
+
constructor(message, statusCode, retryAfterSeconds) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = "GarminApiError";
|
|
7
|
+
this.statusCode = statusCode;
|
|
8
|
+
this.retryAfterSeconds = retryAfterSeconds;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/garmin/types.ts"],"names":[],"mappings":"AAuEA,MAAM,OAAO,cAAe,SAAQ,KAAK;IAC9B,UAAU,CAAU;IACpB,iBAAiB,CAAU;IAEpC,YAAY,OAAe,EAAE,UAAmB,EAAE,iBAA0B;QAC1E,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;QAC7B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;IAC7C,CAAC;CACF"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface HttpMcpServer {
|
|
2
|
+
start: () => Promise<void>;
|
|
3
|
+
close: () => Promise<void>;
|
|
4
|
+
}
|
|
5
|
+
export declare function createHttpMcpServer(): HttpMcpServer;
|
|
6
|
+
export declare function getRemoteConnectorInstructions(publicUrl: string): string;
|
|
7
|
+
//# sourceMappingURL=httpServer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"httpServer.d.ts","sourceRoot":"","sources":["../src/httpServer.ts"],"names":[],"mappings":"AAuBA,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AA6HD,wBAAgB,mBAAmB,IAAI,aAAa,CAoRnD;AAED,wBAAgB,8BAA8B,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAqBxE"}
|