@dynamicsninja/garminconnect-mcp 0.7.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts","../../src/errors.ts","../../src/http/cookie-jar.ts","../../src/http/fetcher.ts","../../src/auth/constants.ts","../../src/auth/consumer.ts","../../src/auth/oauth1.ts","../../src/auth/widget.ts","../../src/auth/tokens.ts","../../src/auth/sso.ts","../../src/auth/token-store.ts","../../src/client.ts","../../src/util/validate.ts","../../src/util/date.ts","../../src/services/activities.ts","../../src/services/badges.ts","../../src/util/fit.ts","../../src/services/bodyComposition.ts","../../src/services/courses.ts","../../src/services/devices.ts","../../src/services/gear.ts","../../src/services/goals.ts","../../src/services/golf.ts","../../src/services/metrics.ts","../../src/services/misc.ts","../../src/services/nutrition.ts","../../src/services/trainingPlans.ts","../../src/services/weight.ts","../../src/services/wellness.ts","../../src/services/userProfile.ts","../../src/types/workouts.ts","../../src/services/workouts.ts","../../src/services/womensHealth.ts","../../src/garmin.ts","../../src/workout-builder.ts","../../src/workout-spec.ts","../../src/workout-spec-schema.ts","../src/session.ts","../src/errors.ts","../src/login.ts","../src/server.ts","../../src/generated/manifest.ts","../src/files.ts","../src/results.ts","../src/validate.ts","../src/method-tools.ts","../../src/exercises.ts","../src/summary.ts","../src/workout-tools.ts","../src/tools.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `garminconnect-mcp` start the MCP server on stdio (Claude Desktop runs this)\n * `garminconnect-mcp login` sign in once and save the session\n *\n * stdout carries MCP protocol frames only; everything human-readable goes to stderr.\n */\nimport { createRequire } from \"node:module\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { FileTokenStore, Garmin, GarminClient } from \"garminconnect-js\";\nimport { describeError } from \"./errors.js\";\nimport { login, terminalIo } from \"./login.js\";\nimport { createServer } from \"./server.js\";\nimport { fileSession, loadConfig } from \"./session.js\";\nimport { TOOL_FACTORIES } from \"./tools.js\";\n\n// From src/cli.ts and from dist/cli.js alike, ../package.json is this package's manifest.\nconst { version } = createRequire(import.meta.url)(\"../package.json\") as { version: string };\nconst USAGE = `garminconnect-mcp ${version}\n\n garminconnect-mcp start the MCP server (stdio); Claude Desktop runs this\n garminconnect-mcp login sign in to Garmin once and save the session\n`;\n\nconst config = loadConfig();\nconst command = process.argv[2];\ntry {\n if (command === \"login\") {\n const client = new GarminClient({ tokenStore: new FileTokenStore(config.tokenDir) });\n await login(terminalIo(), client);\n const profile = await new Garmin(client).getUserProfile();\n console.error(`Logged in as ${profile.displayName}. Session saved to ${config.tokenDir}.`);\n } else if (command === undefined) {\n const server = createServer({ config, session: fileSession(config.tokenDir), version }, TOOL_FACTORIES);\n await server.connect(new StdioServerTransport());\n } else {\n console.error(USAGE);\n process.exitCode = 2;\n }\n} catch (error) {\n console.error(describeError(error));\n process.exitCode = 1;\n}\n","export class GarminError extends Error {\r\n constructor(message: string, options?: { cause?: unknown }) {\r\n super(message, options);\r\n this.name = new.target.name;\r\n Error.captureStackTrace?.(this, new.target);\r\n }\r\n}\r\n\r\n/** 401/403, failed SSO, or an expired OAuth1 token. Re-login is required. */\r\nexport class GarminAuthError extends GarminError {}\r\n\r\n/**\r\n * Network failure or timeout, after retries — PLUS a small set of semantic HTTP statuses that a\r\n * few services deliberately re-raise as this class to mirror upstream python-garminconnect:\r\n *\r\n * - `importActivity` — EVERY HTTP error, not just the 409 (\"Activity already exists\r\n * (duplicate): ...\"): it wraps any `GarminHttpError` as `Import error: ...`, so a 400 or a\r\n * 413 from an import arrives as this class too\r\n * - `addGearToActivity` / `removeGearFromActivity` — a 404\r\n * (\"gear not found (likely retired/removed)\")\r\n * - `getDeviceSolarData` — a falsy response or one missing `deviceSolarInput`\r\n *\r\n * Those are PERMANENT conditions, not transient ones. A consumer writing\r\n * `if (e instanceof GarminConnectionError) retryWithBackoff()` would spin forever on them, so\r\n * inspect the message (or the `cause`, which carries the original `GarminHttpError`) before\r\n * deciding to retry. Splitting these into a separate class would be a behaviour change; it is\r\n * recorded as a post-0.1.0 candidate instead.\r\n */\r\nexport class GarminConnectionError extends GarminError {}\r\n\r\n/** 429. `retryAfter` is seconds, taken from the Retry-After header when present. */\r\nexport class GarminRateLimitError extends GarminError {\r\n constructor(\r\n message: string,\r\n readonly retryAfter?: number,\r\n options?: { cause?: unknown },\r\n ) {\r\n super(message, options);\r\n }\r\n}\r\n\r\n/** Any other non-2xx response. */\r\nexport class GarminHttpError extends GarminError {\r\n constructor(\r\n message: string,\r\n readonly status: number,\r\n readonly url: string,\r\n readonly body: string,\r\n options?: { cause?: unknown },\r\n ) {\r\n super(message, options);\r\n }\r\n}\r\n","export interface SerializedCookie {\n name: string;\n value: string;\n domain: string;\n path: string;\n /** epoch milliseconds; absent means a session cookie */\n expires?: number;\n secure: boolean;\n /** true when no Domain attribute was sent: match this host exactly */\n hostOnly: boolean;\n}\n\nfunction defaultPath(pathname: string): string {\n if (!pathname.startsWith(\"/\") || pathname === \"/\") return \"/\";\n const i = pathname.lastIndexOf(\"/\");\n return i === 0 ? \"/\" : pathname.slice(0, i);\n}\n\nfunction domainMatches(requestHost: string, cookieDomain: string, hostOnly: boolean): boolean {\n if (hostOnly) return requestHost === cookieDomain;\n return (\n requestHost === cookieDomain || requestHost.endsWith(\".\" + cookieDomain)\n );\n}\n\nfunction pathMatches(requestPath: string, cookiePath: string): boolean {\n if (requestPath === cookiePath) return true;\n if (!requestPath.startsWith(cookiePath)) return false;\n return cookiePath.endsWith(\"/\") || requestPath[cookiePath.length] === \"/\";\n}\n\nexport class CookieJar {\n #cookies: SerializedCookie[] = [];\n\n setFromResponse(url: string, setCookieHeaders: string[]): void {\n const u = new URL(url);\n for (const header of setCookieHeaders) {\n const cookie = this.#parse(header, u);\n if (!cookie) continue;\n this.#cookies = this.#cookies.filter(\n (c) =>\n !(\n c.name === cookie.name &&\n c.domain === cookie.domain &&\n c.path === cookie.path\n ),\n );\n this.#cookies.push(cookie);\n }\n }\n\n #parse(header: string, u: URL): SerializedCookie | null {\n const [pair, ...attrs] = header.split(\";\");\n if (!pair) return null;\n const eq = pair.indexOf(\"=\");\n if (eq < 1) return null;\n const name = pair.slice(0, eq).trim();\n const value = pair.slice(eq + 1).trim();\n\n let domain = u.hostname;\n let hostOnly = true;\n let path = defaultPath(u.pathname);\n let expires: number | undefined;\n let secure = false;\n let maxAge: number | undefined;\n\n for (const attr of attrs) {\n const [rawKey, ...rest] = attr.split(\"=\");\n const key = rawKey?.trim().toLowerCase();\n const val = rest.join(\"=\").trim();\n if (key === \"domain\" && val) {\n domain = val.replace(/^\\./, \"\").toLowerCase();\n hostOnly = false;\n } else if (key === \"path\" && val.startsWith(\"/\")) {\n path = val;\n } else if (key === \"expires\" && val) {\n const t = Date.parse(val);\n if (!Number.isNaN(t)) expires = t;\n } else if (key === \"max-age\" && val) {\n const n = Number(val);\n if (!Number.isNaN(n)) maxAge = n;\n } else if (key === \"secure\") {\n secure = true;\n }\n }\n // Max-Age wins over Expires per RFC 6265 section 5.3.\n if (maxAge !== undefined) expires = Date.now() + maxAge * 1000;\n\n return { name, value, domain, path, expires, secure, hostOnly };\n }\n\n cookieHeaderFor(url: string): string | undefined {\n const u = new URL(url);\n const now = Date.now();\n this.#cookies = this.#cookies.filter((c) => c.expires === undefined || c.expires > now);\n\n const matches = this.#cookies.filter(\n (c) =>\n domainMatches(u.hostname, c.domain, c.hostOnly) &&\n pathMatches(u.pathname, c.path) &&\n (!c.secure || u.protocol === \"https:\"),\n );\n if (matches.length === 0) return undefined;\n return matches.map((c) => `${c.name}=${c.value}`).join(\"; \");\n }\n\n toJSON(): SerializedCookie[] {\n return this.#cookies.map((c) => ({ ...c }));\n }\n\n /**\n * Upsert deserialized cookies into this jar, preserving every field\n * (`secure`, `expires`, `hostOnly`/`Domain`) exactly as stored — unlike\n * replaying them as synthetic `Set-Cookie` headers through\n * `setFromResponse`, which can only reconstruct what a real header would\n * carry and silently downgrades a `Domain`-scoped cookie to host-only.\n */\n mergeFromJSON(cookies: SerializedCookie[]): void {\n for (const cookie of cookies) {\n this.#cookies = this.#cookies.filter(\n (c) =>\n !(\n c.name === cookie.name &&\n c.domain === cookie.domain &&\n c.path === cookie.path\n ),\n );\n this.#cookies.push({ ...cookie });\n }\n }\n\n static fromJSON(cookies: SerializedCookie[]): CookieJar {\n const jar = new CookieJar();\n for (const c of cookies) jar.#cookies.push({ ...c });\n return jar;\n }\n}\n","import {\n GarminAuthError,\n GarminConnectionError,\n GarminHttpError,\n GarminRateLimitError,\n} from \"../errors.js\";\nimport { CookieJar } from \"./cookie-jar.js\";\n\nconst RETRY_STATUSES = new Set([408, 500, 502, 503, 504]);\n\n/**\n * Methods safe to retry automatically: repeating them has no side effect\n * beyond the first successful application. POST is not idempotent — Garmin\n * may already have processed a write when a 502/503 or network blip hits\n * after the fact, so replaying it would duplicate the write. A caller that\n * knows a specific POST is safe (e.g. it's idempotent in effect on the\n * server) can opt in per-request via `RequestOptions.retry`.\n */\nconst IDEMPOTENT_METHODS = new Set([\"GET\", \"HEAD\", \"PUT\", \"DELETE\", \"OPTIONS\"]);\n\nexport interface FetcherOptions {\n timeoutMs?: number;\n retries?: number;\n backoffMs?: number;\n fetchImpl?: typeof fetch;\n jar?: CookieJar;\n}\n\nexport interface RequestOptions {\n method?: string;\n params?: Record<string, string | number | undefined>;\n body?: RequestInit[\"body\"];\n json?: unknown;\n /**\n * Widened from `Record<string, string>`: callers that must GUARANTEE a header wins\n * (e.g. `GarminClient` injecting the bearer token) build a `Headers` and use `.set()`, which is\n * case-insensitive. Object spread is not — `Authorization` and `authorization` are distinct\n * object keys, and `new Headers()` then COMBINES them with `\", \"` rather than replacing.\n */\n headers?: RequestInit[\"headers\"];\n referer?: boolean;\n /** Per-request timeout, overriding the Fetcher's default. */\n timeoutMs?: number;\n /**\n * Opt in to retrying a non-idempotent method (i.e. POST) on a retryable\n * status or network error. Idempotent methods (GET/HEAD/PUT/DELETE/OPTIONS)\n * already retry by default and ignore this flag.\n */\n retry?: boolean;\n}\n\nconst sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));\n\nexport class Fetcher {\n readonly jar: CookieJar;\n lastUrl: string | undefined;\n\n readonly #options: FetcherOptions;\n readonly #timeoutMs: number;\n readonly #retries: number;\n readonly #backoffMs: number;\n readonly #fetch: typeof fetch;\n\n constructor(options: FetcherOptions = {}) {\n this.#options = options;\n this.jar = options.jar ?? new CookieJar();\n this.#timeoutMs = options.timeoutMs ?? 10_000;\n this.#retries = options.retries ?? 3;\n this.#backoffMs = options.backoffMs ?? 500;\n this.#fetch = options.fetchImpl ?? globalThis.fetch;\n }\n\n /**\n * The same timeouts, retries and `fetchImpl`, with an empty cookie jar. The SSO widget sign-in\n * uses it so cookies left by a failed mobile sign-in never mix into the widget's session.\n */\n withFreshJar(): Fetcher {\n return new Fetcher({ ...this.#options, jar: new CookieJar() });\n }\n\n async request(url: string, options: RequestOptions = {}): Promise<Response> {\n const target = new URL(url);\n for (const [k, v] of Object.entries(options.params ?? {})) {\n if (v !== undefined) target.searchParams.set(k, String(v));\n }\n const finalUrl = target.toString();\n // Computed once, alongside finalUrl, so every error construction path\n // in this method (including the retry-exhausted branch below) uses it\n // rather than the raw, secret-carrying URL.\n const safeUrl = this.#redactUrl(finalUrl);\n\n const headers = new Headers(options.headers ?? {});\n const cookie = this.jar.cookieHeaderFor(finalUrl);\n if (cookie) headers.set(\"cookie\", cookie);\n if (options.referer && this.lastUrl) headers.set(\"referer\", this.lastUrl);\n\n let body = options.body;\n if (options.json !== undefined) {\n body = JSON.stringify(options.json);\n if (!headers.has(\"content-type\")) headers.set(\"content-type\", \"application/json\");\n }\n\n const method = options.method ?? \"GET\";\n const canRetry = IDEMPOTENT_METHODS.has(method.toUpperCase()) || options.retry === true;\n const timeoutMs = options.timeoutMs ?? this.#timeoutMs;\n\n let lastError: unknown;\n for (let attempt = 0; attempt <= this.#retries; attempt++) {\n if (attempt > 0) await sleep(this.#backoffMs * 2 ** (attempt - 1));\n\n let res: Response;\n try {\n res = await this.#fetch(finalUrl, {\n method,\n headers,\n body,\n redirect: \"follow\",\n signal: AbortSignal.timeout(timeoutMs),\n });\n } catch (cause) {\n lastError = cause;\n if (canRetry && attempt < this.#retries) continue;\n throw new GarminConnectionError(\n `Request to ${safeUrl} failed after ${attempt + 1} attempt${attempt === 0 ? \"\" : \"s\"}`,\n { cause: lastError },\n );\n }\n\n const setCookie = this.#readSetCookie(res);\n if (setCookie.length > 0) this.jar.setFromResponse(finalUrl, setCookie);\n this.lastUrl = res.url || finalUrl;\n\n if (res.ok) return res;\n\n if (RETRY_STATUSES.has(res.status) && canRetry && attempt < this.#retries) {\n continue;\n }\n throw await this.#toError(res, safeUrl);\n }\n\n throw new GarminConnectionError(\n `Request to ${safeUrl} failed after ${this.#retries + 1} attempts`,\n { cause: lastError },\n );\n }\n\n #readSetCookie(res: Response): string[] {\n const getSetCookie = (res.headers as Headers & { getSetCookie?: () => string[] })\n .getSetCookie;\n if (typeof getSetCookie === \"function\") return getSetCookie.call(res.headers);\n const single = res.headers.get(\"set-cookie\");\n return single ? [single] : [];\n }\n\n /** `safeUrl` must already be redacted (see `#redactUrl`) — callers compute it once. */\n async #toError(res: Response, safeUrl: string): Promise<Error> {\n const body = await res.text().catch(() => \"\");\n if (res.status === 429) {\n const raw = res.headers.get(\"retry-after\");\n const retryAfter = raw && !Number.isNaN(Number(raw)) ? Number(raw) : undefined;\n return new GarminRateLimitError(`Rate limited by Garmin at ${safeUrl}`, retryAfter);\n }\n if (res.status === 401 || res.status === 403) {\n return new GarminAuthError(`Not authorized for ${safeUrl} (${res.status})`);\n }\n return new GarminHttpError(\n `Request to ${safeUrl} failed with ${res.status}`,\n res.status,\n safeUrl,\n body,\n );\n }\n\n #redactUrl(url: string): string {\n try {\n const u = new URL(url);\n return `${u.origin}${u.pathname}`;\n } catch {\n return url;\n }\n }\n}\n","export const CLIENT_ID = \"GCM_ANDROID_DARK\";\nexport const OAUTH_CONSUMER_URL = \"https://thegarth.s3.amazonaws.com/oauth_consumer.json\";\n\n/** Must match the Android consumer key fetched from S3. */\nexport const OAUTH_USER_AGENT = \"com.garmin.android.apps.connectmobile\";\nexport const API_USER_AGENT = \"GCM-iOS-5.22.1.4\";\n\nconst SSO_UA =\n \"Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) \" +\n \"AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148\";\n\n/**\n * The SSO endpoints run in a WebView. Without browser-shaped headers,\n * Cloudflare challenges the request and login fails.\n */\nexport const SSO_PAGE_HEADERS: Record<string, string> = {\n \"User-Agent\": SSO_UA,\n Accept: \"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\",\n \"Accept-Language\": \"en-US,en;q=0.9\",\n \"Sec-Fetch-Mode\": \"navigate\",\n \"Sec-Fetch-Dest\": \"document\",\n};\n","import type { Fetcher } from \"../http/fetcher.js\";\nimport { GarminAuthError } from \"../errors.js\";\nimport { OAUTH_CONSUMER_URL } from \"./constants.js\";\n\nexport interface ConsumerCredentials {\n consumer_key: string;\n consumer_secret: string;\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === \"string\" && value.length > 0;\n}\n\nlet cached: ConsumerCredentials | undefined;\n\n/**\n * The consumer key/secret come from a bucket controlled by garth's author.\n * Cached process-wide because they never change between calls.\n *\n * A malformed payload (missing/empty keys) is the hardest failure in this\n * library to diagnose otherwise: it would silently produce an unsignable\n * OAuth1 request that surfaces as a confusing 401 during login. Fail loudly\n * here instead, and never cache the bad response.\n */\nexport async function fetchConsumer(\n fetcher: Fetcher,\n url: string = OAUTH_CONSUMER_URL,\n): Promise<ConsumerCredentials> {\n if (cached) return cached;\n const res = await fetcher.request(url);\n const body = (await res.json()) as Partial<ConsumerCredentials>;\n if (!isNonEmptyString(body.consumer_key) || !isNonEmptyString(body.consumer_secret)) {\n throw new GarminAuthError(\n `Consumer credentials response from ${url} is missing consumer_key/consumer_secret`,\n );\n }\n cached = { consumer_key: body.consumer_key, consumer_secret: body.consumer_secret };\n return cached;\n}\n\n/** Test seam. */\nexport function resetConsumerCache(): void {\n cached = undefined;\n}\n","import { createHmac, randomBytes } from \"node:crypto\";\n\n/** RFC 3986 percent-encoding. `encodeURIComponent` leaves !*'() unescaped. */\nexport function percentEncode(value: string): string {\n return encodeURIComponent(value).replace(\n /[!*'()]/g,\n (c) => \"%\" + c.charCodeAt(0).toString(16).toUpperCase(),\n );\n}\n\n/** Scheme and host lowercased, default port dropped, query and fragment removed. */\nfunction normalizeUrl(url: string): string {\n const u = new URL(url);\n const isDefaultPort =\n (u.protocol === \"https:\" && u.port === \"443\") ||\n (u.protocol === \"http:\" && u.port === \"80\");\n const port = u.port && !isDefaultPort ? `:${u.port}` : \"\";\n return `${u.protocol.toLowerCase()}//${u.hostname.toLowerCase()}${port}${u.pathname}`;\n}\n\nexport function signatureBaseString(\n method: string,\n url: string,\n params: Record<string, string>,\n): string {\n const encoded = Object.entries(params).map(\n ([k, v]) => [percentEncode(k), percentEncode(v)] as const,\n );\n encoded.sort((a, b) => (a[0] === b[0] ? (a[1] < b[1] ? -1 : 1) : a[0] < b[0] ? -1 : 1));\n const normalized = encoded.map(([k, v]) => `${k}=${v}`).join(\"&\");\n return [\n method.toUpperCase(),\n percentEncode(normalizeUrl(url)),\n percentEncode(normalized),\n ].join(\"&\");\n}\n\nexport interface OAuth1Args {\n method: string;\n url: string;\n consumerKey: string;\n consumerSecret: string;\n token?: string;\n tokenSecret?: string;\n /** form-encoded body params, which must be included in the signature */\n bodyParams?: Record<string, string>;\n /** injectable for deterministic tests */\n nonce?: string;\n timestamp?: number;\n}\n\nexport function buildOAuth1Header(args: OAuth1Args): string {\n const nonce = args.nonce ?? randomBytes(16).toString(\"hex\");\n const timestamp = args.timestamp ?? Math.floor(Date.now() / 1000);\n\n const oauthParams: Record<string, string> = {\n oauth_consumer_key: args.consumerKey,\n oauth_nonce: nonce,\n oauth_signature_method: \"HMAC-SHA1\",\n oauth_timestamp: String(timestamp),\n oauth_version: \"1.0\",\n };\n if (args.token) oauthParams[\"oauth_token\"] = args.token;\n\n const queryParams: Record<string, string> = {};\n for (const [k, v] of new URL(args.url).searchParams) queryParams[k] = v;\n\n const base = signatureBaseString(args.method, args.url, {\n ...queryParams,\n ...args.bodyParams,\n ...oauthParams,\n });\n\n const key = `${percentEncode(args.consumerSecret)}&${percentEncode(args.tokenSecret ?? \"\")}`;\n const signature = createHmac(\"sha1\", key).update(base).digest(\"base64\");\n\n const headerParams = { ...oauthParams, oauth_signature: signature };\n const parts = Object.entries(headerParams)\n .sort(([a], [b]) => (a < b ? -1 : 1))\n .map(([k, v]) => `${percentEncode(k)}=\"${percentEncode(v)}\"`);\n return `OAuth ${parts.join(\", \")}`;\n}\n","/**\n * Garmin's SSO web widget (`/sso/embed` + `/sso/signin`): the HTML form sign-in garth used before\n * the mobile JSON API. It sends no `clientId`, so it sits outside the rate-limit bucket that\n * blocks the mobile route, and `login()` falls back to it when that route answers 429.\n */\n\nimport { GarminAuthError, GarminConnectionError } from \"../errors.js\";\nimport type { Fetcher } from \"../http/fetcher.js\";\nimport type { SerializedCookie } from \"../http/cookie-jar.js\";\nimport { SSO_PAGE_HEADERS } from \"./constants.js\";\nimport type { OAuth1Token, OAuth2Token } from \"./tokens.js\";\n\nexport interface WidgetUrls {\n base: string;\n embed: string;\n signin: string;\n embedParams: Record<string, string>;\n signinParams: Record<string, string>;\n}\n\nexport function widgetUrls(domain: string): WidgetUrls {\n const base = `https://sso.${domain}/sso`;\n const embed = `${base}/embed`;\n const embedParams = { id: \"gauth-widget\", embedWidget: \"true\", gauthHost: base };\n return {\n base,\n embed,\n signin: `${base}/signin`,\n embedParams,\n signinParams: {\n ...embedParams,\n gauthHost: embed,\n service: embed,\n source: embed,\n redirectAfterAccountLoginUrl: embed,\n redirectAfterAccountCreationUrl: embed,\n },\n };\n}\n\nconst CSRF_RE = /name=\"_csrf\"\\s+value=\"(.+?)\"/;\nconst TITLE_RE = /<title>([\\s\\S]*?)<\\/title>/i;\nconst TICKET_RE = /\\?ticket=(ST-[^\"&\\s]+)/;\nconst MFA_VAR_RE = /var\\s+(customerGuid|mfaMethod|locale|clientId|codeSentTo)\\s*=\\s*\"([^\"]*)\"\\s*;/g;\n\nexport type MfaVars = Partial<\n Record<\"customerGuid\" | \"mfaMethod\" | \"locale\" | \"clientId\" | \"codeSentTo\", string>\n>;\n\nexport function csrfFrom(html: string): string | null {\n return CSRF_RE.exec(html)?.[1] ?? null;\n}\n\nexport function titleFrom(html: string): string {\n return TITLE_RE.exec(html)?.[1]?.trim() ?? \"\";\n}\n\nexport function ticketFrom(html: string): string | null {\n return TICKET_RE.exec(html)?.[1] ?? null;\n}\n\n/** The inline `var name = \"value\";` declarations Garmin's MFA page carries. */\nexport function mfaVarsFrom(html: string): MfaVars {\n const vars: MfaVars = {};\n for (const [, name, value] of html.matchAll(MFA_VAR_RE)) {\n if (name !== undefined && value !== undefined) vars[name as keyof MfaVars] = value;\n }\n return vars;\n}\n\n/** Pause before posting credentials; Cloudflare flags an instant GET-then-POST as a bot. */\nexport function widgetDelayMs(override?: number): number {\n return override ?? 3000 + Math.floor(Math.random() * 5001);\n}\n\nexport type WidgetSuccess = { state: \"success\"; oauth1: OAuth1Token; oauth2: OAuth2Token };\n/** Turns a service ticket into tokens; `sso.ts` passes `completeLogin` so there is no import cycle. */\nexport type CompleteTicket = (ticket: string, loginUrl: string) => Promise<WidgetSuccess>;\n\nexport interface WidgetMfaState {\n flow: \"widget\";\n mfaMethod: string;\n csrf: string;\n signinParams: Record<string, string>;\n referer: string;\n cookies: SerializedCookie[];\n domain: string;\n}\n\nexport type WidgetLoginResult = WidgetSuccess | { state: \"mfa_required\"; mfaState: WidgetMfaState };\n\nconst FORM_HEADERS = { ...SSO_PAGE_HEADERS, \"content-type\": \"application/x-www-form-urlencoded\" };\n/** Titles of Garmin/Cloudflare error and challenge pages (\"Just a moment...\", \"Attention Required!\"). */\nconst SERVER_ERROR_HINTS = [\n \"bad gateway\",\n \"service unavailable\",\n \"cloudflare\",\n \"502\",\n \"503\",\n \"just a moment\",\n \"attention required\",\n];\n\nfunction isServerErrorTitle(title: string): boolean {\n const lower = title.toLowerCase();\n return SERVER_ERROR_HINTS.some((h) => lower.includes(h));\n}\nconst CREDENTIAL_HINTS = [\"locked\", \"invalid\", \"incorrect\", \"account error\"];\nconst RESTRICTED_HINTS = [\"unable to sign in\", \"unable to login\"];\n\nconst sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));\n\n/**\n * Email and SMS codes are not always sent by the sign-in POST itself. The page's own\n * \"Request a new code\" link calls this endpoint, so it is called when no code was sent.\n */\nasync function requestMfaCode(\n fetcher: Fetcher,\n base: string,\n vars: MfaVars,\n referer: string,\n): Promise<void> {\n const method = (vars.mfaMethod ?? \"\").toLowerCase();\n if ((method !== \"email\" && method !== \"sms\") || vars.codeSentTo) return;\n await fetcher.request(`${base}/verifyMFA/mfaCode`, {\n method: \"POST\",\n params: { clientId: vars.clientId ?? \"\" },\n headers: { ...SSO_PAGE_HEADERS, Accept: \"application/json, text/plain, */*\", Referer: referer },\n json: {\n customerGuid: vars.customerGuid ?? \"\",\n mfaMethod: vars.mfaMethod ?? \"\",\n locale: vars.locale ?? \"\",\n },\n });\n}\n\nexport async function widgetLogin(\n email: string,\n password: string,\n fetcher: Fetcher,\n domain: string,\n opts: { delayMs?: number; complete: CompleteTicket },\n): Promise<WidgetLoginResult> {\n const urls = widgetUrls(domain);\n\n // 1. The embed page sets the widget's session cookies.\n await fetcher.request(urls.embed, { params: urls.embedParams, headers: SSO_PAGE_HEADERS });\n\n // 2. The sign-in page carries the CSRF token the POST must echo.\n const signinPage = await fetcher.request(urls.signin, {\n params: urls.signinParams,\n headers: { ...SSO_PAGE_HEADERS, Referer: urls.embed },\n });\n const signinHtml = await signinPage.text();\n const csrf = csrfFrom(signinHtml);\n if (!csrf) {\n // The title names what came back instead, e.g. a Cloudflare \"Just a moment...\" challenge.\n throw new GarminConnectionError(\n `Widget login: missing CSRF token on page '${titleFrom(signinHtml)}'`,\n );\n }\n const referer = fetcher.lastUrl ?? urls.signin;\n\n const delay = widgetDelayMs(opts.delayMs);\n if (delay > 0) await sleep(delay);\n\n // 3. Credentials go in a form body, never the URL. A POST is never retried automatically.\n const res = await fetcher.request(urls.signin, {\n method: \"POST\",\n params: urls.signinParams,\n headers: { ...FORM_HEADERS, Referer: referer },\n body: new URLSearchParams({ username: email, password, embed: \"true\", _csrf: csrf }).toString(),\n timeoutMs: 30_000,\n });\n const html = await res.text();\n const title = titleFrom(html);\n const lower = title.toLowerCase();\n\n if (isServerErrorTitle(title)) {\n throw new GarminConnectionError(`Widget login: server error '${title}'`);\n }\n // \"SSO error:\" matches the mobile route's rejections, so callers classify both the same way.\n if (CREDENTIAL_HINTS.some((h) => lower.includes(h))) {\n throw new GarminAuthError(`SSO error: INVALID_CREDENTIALS: ${title}`);\n }\n if (RESTRICTED_HINTS.some((h) => lower.includes(h))) {\n throw new GarminAuthError(`SSO error: ACCOUNT_RESTRICTED: ${title}`);\n }\n const vars = mfaVarsFrom(html);\n if (lower.includes(\"mfa\") || vars.mfaMethod) {\n const mfaCsrf = csrfFrom(html);\n if (!mfaCsrf) throw new GarminConnectionError(\"Widget login: MFA page has no CSRF token\");\n const mfaReferer = fetcher.lastUrl ?? urls.signin;\n await requestMfaCode(fetcher, urls.base, vars, mfaReferer);\n return {\n state: \"mfa_required\",\n mfaState: {\n flow: \"widget\",\n mfaMethod: vars.mfaMethod || \"email\",\n csrf: mfaCsrf,\n signinParams: urls.signinParams,\n referer: mfaReferer,\n cookies: fetcher.jar.toJSON(),\n domain,\n },\n };\n }\n if (title !== \"Success\") {\n throw new GarminConnectionError(`Widget login: unexpected page '${title}'`);\n }\n const ticket = ticketFrom(html);\n if (!ticket) throw new GarminAuthError(\"Widget login: missing service ticket\");\n return opts.complete(ticket, urls.embed);\n}\n\nexport async function widgetResume(\n state: WidgetMfaState,\n code: string,\n fetcher: Fetcher,\n complete: CompleteTicket,\n): Promise<WidgetSuccess> {\n fetcher.jar.mergeFromJSON(state.cookies);\n const urls = widgetUrls(state.domain);\n const res = await fetcher.request(`${urls.base}/verifyMFA/loginEnterMfaCode`, {\n method: \"POST\",\n params: state.signinParams,\n headers: { ...FORM_HEADERS, Referer: state.referer },\n body: new URLSearchParams({\n \"mfa-code\": code,\n embed: \"true\",\n _csrf: state.csrf,\n fromPage: \"setupEnterMfaCode\",\n }).toString(),\n timeoutMs: 30_000,\n });\n const html = await res.text();\n const title = titleFrom(html);\n // An outage is not a wrong code: report it as retryable, not as an auth failure.\n if (isServerErrorTitle(title)) {\n throw new GarminConnectionError(`Widget MFA: server error '${title}'`);\n }\n if (title !== \"Success\") throw new GarminAuthError(`SSO error: INVALID_MFA_CODE: ${title}`);\n const ticket = ticketFrom(html);\n if (!ticket) throw new GarminAuthError(\"Widget login: missing service ticket\");\n return complete(ticket, urls.embed);\n}\n","export interface OAuth1Token {\n oauth_token: string;\n oauth_token_secret: string;\n mfa_token?: string;\n mfa_expiration_timestamp?: string;\n domain?: string;\n}\n\nexport interface RawOAuth2Token {\n scope: string;\n jti: string;\n token_type: string;\n access_token: string;\n refresh_token: string;\n expires_in: number;\n refresh_token_expires_in: number;\n}\n\nexport interface OAuth2Token extends RawOAuth2Token {\n /** epoch seconds */\n expires_at: number;\n /** epoch seconds */\n refresh_token_expires_at: number;\n}\n\nexport interface Tokens {\n oauth1: OAuth1Token;\n oauth2: OAuth2Token;\n}\n\nexport function setExpirations(raw: RawOAuth2Token, nowMs: number = Date.now()): OAuth2Token {\n const now = Math.floor(nowMs / 1000);\n return {\n ...raw,\n expires_at: now + raw.expires_in,\n refresh_token_expires_at: now + raw.refresh_token_expires_in,\n };\n}\n\n/**\n * Fails CLOSED on a malformed token. `expires_at` is typed as a `number`, but a token that came\n * back from a caller-implemented `TokenStore` (the normal production choice — see AGENTS.md §5)\n * can lose the field to a database schema or a field allowlist. The naive arithmetic\n * (`undefined - 60 <= now` -> `NaN <= number` -> `false`) reports \"not expired\", so the client\n * never refreshes and the user is silently logged out roughly every 27 hours with nothing pointing\n * at the cause. Treating an unknown expiry as expired is self-healing instead: it triggers a\n * refresh, which succeeds as long as the OAuth1 token is still live.\n */\nexport function isExpired(\n token: OAuth2Token,\n marginSeconds = 60,\n nowMs: number = Date.now(),\n): boolean {\n if (!Number.isFinite(token.expires_at)) return true;\n return token.expires_at - marginSeconds <= Math.floor(nowMs / 1000);\n}\n\n/** Fails closed on a malformed token, same reasoning as `isExpired`. */\nexport function refreshExpired(\n token: OAuth2Token,\n nowMs: number = Date.now(),\n): boolean {\n if (!Number.isFinite(token.refresh_token_expires_at)) return true;\n return token.refresh_token_expires_at <= Math.floor(nowMs / 1000);\n}\n\nexport function authorizationHeader(token: OAuth2Token): string {\n const type = token.token_type;\n const titled = type.charAt(0).toUpperCase() + type.slice(1).toLowerCase();\n return `${titled} ${token.access_token}`;\n}\n","import {\n GarminAuthError,\n GarminConnectionError,\n GarminError,\n GarminHttpError,\n GarminRateLimitError,\n} from \"../errors.js\";\nimport { Fetcher } from \"../http/fetcher.js\";\nimport type { SerializedCookie } from \"../http/cookie-jar.js\";\nimport { fetchConsumer } from \"./consumer.js\";\nimport { buildOAuth1Header } from \"./oauth1.js\";\nimport { CLIENT_ID, OAUTH_USER_AGENT, SSO_PAGE_HEADERS } from \"./constants.js\";\nimport { widgetLogin, widgetResume, type WidgetMfaState } from \"./widget.js\";\nimport {\n setExpirations,\n type OAuth1Token,\n type OAuth2Token,\n type RawOAuth2Token,\n} from \"./tokens.js\";\n\nconst SSO_SUCCESSFUL = \"SUCCESSFUL\";\nconst SSO_MFA_REQUIRED = \"MFA_REQUIRED\";\n\nexport interface SsoContext {\n fetcher: Fetcher;\n domain: string;\n /** Pause before the widget's credential POST, in ms; default random 3000-8000. */\n loginDelayMs?: number;\n}\n\nexport interface LoginParams {\n clientId: string;\n locale: string;\n service: string;\n}\n\n/** Mobile-route MFA state. `flow` is absent on states saved by 0.1.0 or 0.2.0; absent means mobile. */\nexport interface MobileMfaState {\n flow?: \"mobile\";\n loginParams: LoginParams;\n mfaMethod: string;\n cookies: SerializedCookie[];\n domain: string;\n}\n\nexport type MfaState = MobileMfaState | WidgetMfaState;\n\nexport type LoginResult =\n | { state: \"success\"; oauth1: OAuth1Token; oauth2: OAuth2Token }\n | { state: \"mfa_required\"; mfaState: MfaState };\n\ninterface SsoResponse {\n responseStatus?: { type?: string; message?: string };\n serviceTicketId?: string;\n customerMfaInfo?: { mfaLastMethodUsed?: string };\n error?: { \"status-code\"?: string };\n}\n\nfunction ssoUrl(domain: string, path: string): string {\n return `https://sso.${domain}${path}`;\n}\n\n/**\n * Garmin's SSO endpoints sit behind Cloudflare. A challenged request comes\n * back as HTTP 200 with an HTML body instead of JSON, and `res.json()`\n * throws a bare `SyntaxError` that callers can't branch on. Convert that\n * into the same `GarminAuthError` taxonomy as every other auth failure.\n */\nasync function parseJson<T>(res: Response): Promise<T> {\n try {\n return (await res.json()) as T;\n } catch (cause) {\n throw new GarminAuthError(\n \"SSO returned a non-JSON response (Cloudflare challenge?)\",\n { cause },\n );\n }\n}\n\nfunction requireSuccess(body: SsoResponse): SsoResponse {\n const type = body.responseStatus?.type ?? \"UNKNOWN\";\n if (type !== SSO_SUCCESSFUL) {\n const message = body.responseStatus?.message;\n throw new GarminAuthError(`SSO error: ${message ? `${type}: ${message}` : type}`);\n }\n return body;\n}\n\nexport function loginParamsFor(domain: string): LoginParams {\n return {\n clientId: CLIENT_ID,\n locale: \"en-US\",\n service: mobileLoginUrl(domain),\n };\n}\n\nexport function mobileLoginUrl(domain: string): string {\n return `https://mobile.integration.${domain}/gcm/android`;\n}\n\n/** The mobile credentials step, or `\"rate_limited\"` when Garmin refused it with a 429. */\nasync function mobileCredentials(\n email: string,\n password: string,\n ctx: SsoContext,\n params: LoginParams,\n): Promise<SsoResponse | \"rate_limited\"> {\n let res: Response;\n try {\n // 1. Seed cookies.\n await ctx.fetcher.request(ssoUrl(ctx.domain, \"/mobile/sso/en/sign-in\"), {\n params: { clientId: CLIENT_ID },\n headers: { ...SSO_PAGE_HEADERS, \"Sec-Fetch-Site\": \"none\" },\n });\n // 2. Submit credentials. Opt into retrying this POST: Garmin's login endpoint is idempotent\n // in effect (re-submitting after a 5xx/network blip succeeds identically).\n res = await ctx.fetcher.request(ssoUrl(ctx.domain, \"/mobile/api/login\"), {\n method: \"POST\",\n params: { ...params },\n headers: SSO_PAGE_HEADERS,\n json: { username: email, password, rememberMe: false, captchaToken: \"\" },\n retry: true,\n });\n } catch (err) {\n if (err instanceof GarminRateLimitError) return \"rate_limited\";\n throw err;\n }\n const body = await parseJson<SsoResponse>(res);\n // Garmin sometimes reports the rate limit inside a 200 JSON body instead of an HTTP 429.\n if (body.error?.[\"status-code\"] === \"429\") return \"rate_limited\";\n return body;\n}\n\nconst WIDGET_CONTEXT = \"Mobile login rate limited; \";\n\n/**\n * Says the widget only ran because the mobile route was rate limited, so a widget failure is\n * not read as the whole login's cause. Left unchanged: `GarminAuthError` \"SSO error: ...\"\n * messages (consumers match that prefix) and `GarminRateLimitError` (its message names the\n * widget URL; `retryAfter` is kept). Rethrown with the same class and the original as `cause`:\n * `GarminHttpError` keeps its status/url/body; other errors pass through untouched.\n */\nfunction explainWidgetFailure(err: unknown): unknown {\n if (!(err instanceof GarminError) || err instanceof GarminRateLimitError) return err;\n const message = WIDGET_CONTEXT + err.message;\n const options = { cause: err };\n if (err instanceof GarminAuthError) {\n return err.message.startsWith(\"SSO error:\") ? err : new GarminAuthError(message, options);\n }\n if (err instanceof GarminConnectionError) return new GarminConnectionError(message, options);\n if (err instanceof GarminHttpError) {\n return new GarminHttpError(message, err.status, err.url, err.body, options);\n }\n // Any other subclass (none today) is passed through rather than downgraded to its base class.\n return err.constructor === GarminError ? new GarminError(message, options) : err;\n}\n\nexport async function login(\n email: string,\n password: string,\n ctx: SsoContext,\n): Promise<LoginResult> {\n const params = loginParamsFor(ctx.domain);\n const body = await mobileCredentials(email, password, ctx, params);\n\n if (body === \"rate_limited\") {\n // Garmin rate limits the mobile route per client id and source. The web widget sends no\n // client id, so it is tried once before giving up; a 429 there names the widget URL.\n try {\n return await widgetLogin(email, password, ctx.fetcher.withFreshJar(), ctx.domain, {\n delayMs: ctx.loginDelayMs,\n complete: (ticket, loginUrl) => completeLogin(ticket, ctx, loginUrl),\n });\n } catch (err) {\n throw explainWidgetFailure(err);\n }\n }\n\n const type = body.responseStatus?.type;\n if (type === SSO_MFA_REQUIRED) {\n return {\n state: \"mfa_required\",\n mfaState: {\n flow: \"mobile\",\n loginParams: params,\n // Upstream garth (sso.py) does `mfa_info.get(\"mfaLastMethodUsed\")\n // or \"email\"` — this default mirrors that behavior, not a guess.\n mfaMethod: body.customerMfaInfo?.mfaLastMethodUsed ?? \"email\",\n cookies: ctx.fetcher.jar.toJSON(),\n domain: ctx.domain,\n },\n };\n }\n\n requireSuccess(body);\n const ticket = body.serviceTicketId;\n if (!ticket) throw new GarminAuthError(\"SSO succeeded but returned no service ticket\");\n return completeLogin(ticket, ctx);\n}\n\nexport async function completeLogin(\n ticket: string,\n ctx: SsoContext,\n loginUrl: string = mobileLoginUrl(ctx.domain),\n): Promise<{ state: \"success\"; oauth1: OAuth1Token; oauth2: OAuth2Token }> {\n // Best-effort: sets a Cloudflare load-balancer cookie pinning the backend.\n try {\n await ctx.fetcher.request(ssoUrl(ctx.domain, \"/portal/sso/embed\"), {\n headers: { ...SSO_PAGE_HEADERS, \"Sec-Fetch-Site\": \"same-origin\" },\n referer: true,\n });\n } catch (err) {\n // Non-fatal; login works without it. But only swallow known Garmin/HTTP\n // failures — a programmer error (e.g. a TypeError) should still surface.\n if (!(err instanceof GarminError)) throw err;\n }\n\n const oauth1 = await getOauth1Token(ticket, ctx, loginUrl);\n const oauth2 = await exchange(oauth1, ctx, { login: true });\n return { state: \"success\", oauth1, oauth2 };\n}\n\nexport async function getOauth1Token(\n ticket: string,\n ctx: SsoContext,\n loginUrl: string = mobileLoginUrl(ctx.domain),\n): Promise<OAuth1Token> {\n const consumer = await fetchConsumer(ctx.fetcher);\n const url =\n `https://connectapi.${ctx.domain}/oauth-service/oauth/preauthorized` +\n `?ticket=${encodeURIComponent(ticket)}` +\n `&login-url=${encodeURIComponent(loginUrl)}` +\n `&accepts-mfa-tokens=true`;\n\n const authorization = buildOAuth1Header({\n method: \"GET\",\n url,\n consumerKey: consumer.consumer_key,\n consumerSecret: consumer.consumer_secret,\n });\n\n const res = await ctx.fetcher.request(url, {\n headers: { authorization, \"User-Agent\": OAUTH_USER_AGENT },\n });\n\n // The response is form-urlencoded, not JSON, so there's no JSON.parse to\n // fail here — but a Cloudflare HTML challenge body parses via\n // URLSearchParams into zero recognized keys, so the missing-token check\n // below already turns that into a GarminAuthError.\n const parsed = new URLSearchParams(await res.text());\n const oauth_token = parsed.get(\"oauth_token\");\n const oauth_token_secret = parsed.get(\"oauth_token_secret\");\n if (!oauth_token || !oauth_token_secret) {\n throw new GarminAuthError(\"OAuth1 exchange returned no token\");\n }\n return {\n oauth_token,\n oauth_token_secret,\n mfa_token: parsed.get(\"mfa_token\") ?? undefined,\n mfa_expiration_timestamp: parsed.get(\"mfa_expiration_timestamp\") ?? undefined,\n domain: ctx.domain,\n };\n}\n\nexport async function exchange(\n oauth1: OAuth1Token,\n ctx: SsoContext,\n opts: { login?: boolean } = {},\n): Promise<OAuth2Token> {\n const consumer = await fetchConsumer(ctx.fetcher);\n const url = `https://connectapi.${ctx.domain}/oauth-service/oauth/exchange/user/2.0`;\n\n const bodyParams: Record<string, string> = {};\n if (opts.login) bodyParams[\"audience\"] = \"GARMIN_CONNECT_MOBILE_ANDROID_DI\";\n if (oauth1.mfa_token) bodyParams[\"mfa_token\"] = oauth1.mfa_token;\n\n const authorization = buildOAuth1Header({\n method: \"POST\",\n url,\n consumerKey: consumer.consumer_key,\n consumerSecret: consumer.consumer_secret,\n token: oauth1.oauth_token,\n tokenSecret: oauth1.oauth_token_secret,\n bodyParams,\n });\n\n const res = await ctx.fetcher.request(url, {\n method: \"POST\",\n headers: {\n authorization,\n \"User-Agent\": OAUTH_USER_AGENT,\n \"content-type\": \"application/x-www-form-urlencoded\",\n },\n body: new URLSearchParams(bodyParams).toString(),\n });\n\n return setExpirations(await parseJson<RawOAuth2Token>(res));\n}\n\n/**\n * Complete an MFA login from a JSON-serializable `MfaState`. This is the\n * deliberate divergence from upstream garth: garth's resume holds a live\n * client object in memory, which doesn't survive a serverless request\n * boundary where the MFA code arrives in a SECOND HTTP request — likely on\n * a different instance. `MfaState` is plain JSON, so it can cross that\n * boundary; the cookies captured at `login()` time travel with it.\n *\n * When `options.fetcher` is supplied (the normal application path — see\n * `GarminClient.resumeLogin`), the stored cookies are merged into that\n * fetcher's existing jar via `mergeFromJSON`, which preserves every field\n * (`secure`, `expires`, `hostOnly`/`Domain`) exactly as captured. Replaying\n * them as synthetic `Set-Cookie` headers instead would silently downgrade a\n * `Domain=.garmin.com` cookie to host-only, so it would never be attached to\n * `connectapi.garmin.com` requests later in the flow.\n */\nexport async function resumeLogin(\n mfaState: MfaState,\n code: string,\n options: { fetcher?: Fetcher } = {},\n): Promise<{ state: \"success\"; oauth1: OAuth1Token; oauth2: OAuth2Token }> {\n const fetcher = options.fetcher ?? new Fetcher();\n const ctx: SsoContext = { fetcher, domain: mfaState.domain };\n if (mfaState.flow === \"widget\") {\n // The verify POST runs on a fresh jar holding only the widget's own cookies: the caller's\n // jar may still hold the mobile route's cookies (e.g. on a client that just ran `login()`).\n // The ticket exchange still runs on the caller's fetcher, like the mobile route's.\n return widgetResume(mfaState, code, fetcher.withFreshJar(), (ticket, loginUrl) =>\n completeLogin(ticket, ctx, loginUrl),\n );\n }\n fetcher.jar.mergeFromJSON(mfaState.cookies);\n\n const res = await fetcher.request(ssoUrl(ctx.domain, \"/mobile/api/mfa/verifyCode\"), {\n method: \"POST\",\n params: { ...mfaState.loginParams },\n headers: SSO_PAGE_HEADERS,\n json: {\n mfaMethod: mfaState.mfaMethod,\n mfaVerificationCode: code,\n rememberMyBrowser: false,\n reconsentList: [],\n mfaSetup: false,\n },\n });\n\n const body = requireSuccess(await parseJson<SsoResponse>(res));\n const ticket = body.serviceTicketId;\n if (!ticket) throw new GarminAuthError(\"MFA succeeded but returned no service ticket\");\n return completeLogin(ticket, ctx);\n}\n","import { mkdir, readFile, rename, rm, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { OAuth1Token, OAuth2Token, Tokens } from \"./tokens.js\";\n\nexport interface TokenStore {\n load(): Promise<Tokens | null>;\n save(tokens: Tokens): Promise<void>;\n clear(): Promise<void>;\n}\n\nexport class MemoryTokenStore implements TokenStore {\n #tokens: Tokens | null = null;\n\n async load(): Promise<Tokens | null> {\n return this.#tokens;\n }\n async save(tokens: Tokens): Promise<void> {\n this.#tokens = tokens;\n }\n async clear(): Promise<void> {\n this.#tokens = null;\n }\n}\n\nconst OAUTH1_FILE = \"oauth1_token.json\";\nconst OAUTH2_FILE = \"oauth2_token.json\";\n\n/** garth-compatible on-disk format: tokens written by Python garth load directly. */\nexport class FileTokenStore implements TokenStore {\n constructor(private readonly dir: string) {}\n\n async load(): Promise<Tokens | null> {\n try {\n const [raw1, raw2] = await Promise.all([\n readFile(join(this.dir, OAUTH1_FILE), \"utf8\"),\n readFile(join(this.dir, OAUTH2_FILE), \"utf8\"),\n ]);\n const parsed1 = JSON.parse(raw1) as Record<string, unknown>;\n const parsed2 = JSON.parse(raw2) as Record<string, unknown>;\n\n // Validate required OAuth1 fields are present and non-empty.\n const token1 = parsed1[\"oauth_token\"];\n const secret1 = parsed1[\"oauth_token_secret\"];\n if (typeof token1 !== \"string\" || !token1 || typeof secret1 !== \"string\" || !secret1) {\n return null;\n }\n\n // Validate required OAuth2 fields are present and non-empty.\n const access2 = parsed2[\"access_token\"];\n const refresh2 = parsed2[\"refresh_token\"];\n if (typeof access2 !== \"string\" || !access2 || typeof refresh2 !== \"string\" || !refresh2) {\n return null;\n }\n\n // The two expiry stamps are validated too, not just the token strings. They drive every\n // refresh decision (`isExpired`/`refreshExpired`), and a file missing or corrupting them\n // used to slip through the `as unknown as OAuth2Token` cast below and produce a token the\n // client could never decide about. Those predicates now fail closed, but rejecting the\n // whole file here is better still: `loadTokens()` returns `false` and the caller is told to\n // log in, rather than the client carrying a half-valid token around.\n const expiresAt = parsed2[\"expires_at\"];\n const refreshExpiresAt = parsed2[\"refresh_token_expires_at\"];\n if (!Number.isFinite(expiresAt) || !Number.isFinite(refreshExpiresAt)) {\n return null;\n }\n\n const oauth1: OAuth1Token = {\n oauth_token: token1,\n oauth_token_secret: secret1,\n // Python writes null where TS wants undefined.\n mfa_token: (parsed1[\"mfa_token\"] as string | null) ?? undefined,\n mfa_expiration_timestamp:\n (parsed1[\"mfa_expiration_timestamp\"] as string | null) ?? undefined,\n domain: (parsed1[\"domain\"] as string | null) ?? undefined,\n };\n return { oauth1, oauth2: parsed2 as unknown as OAuth2Token };\n } catch {\n return null;\n }\n }\n\n async save(tokens: Tokens): Promise<void> {\n await mkdir(this.dir, { recursive: true });\n // Unique per call (pid + random suffix) so two processes sharing a\n // token directory (a cron refresher beside a web server, two Node\n // workers) can never interleave writes to the same temp file and\n // persist a torn pair; the catch block below only ever cleans up the\n // temp files THIS call created.\n const suffix = `${process.pid}-${Math.random().toString(36).slice(2)}`;\n const tmp1 = join(this.dir, `${OAUTH1_FILE}.${suffix}.tmp`);\n const tmp2 = join(this.dir, `${OAUTH2_FILE}.${suffix}.tmp`);\n\n try {\n // Write both temp files first with 0o600 permissions.\n await Promise.all([\n writeFile(tmp1, JSON.stringify(tokens.oauth1, null, 2), { mode: 0o600 }),\n writeFile(tmp2, JSON.stringify(tokens.oauth2, null, 2), { mode: 0o600 }),\n ]);\n\n // Then atomically rename both temp files into place.\n await Promise.all([\n rename(tmp1, join(this.dir, OAUTH1_FILE)),\n rename(tmp2, join(this.dir, OAUTH2_FILE)),\n ]);\n } catch (err) {\n // Clean up temp files if something went wrong.\n await Promise.all([\n rm(tmp1, { force: true }),\n rm(tmp2, { force: true }),\n ]);\n throw err;\n }\n }\n\n async clear(): Promise<void> {\n await Promise.all([\n rm(join(this.dir, OAUTH1_FILE), { force: true }),\n rm(join(this.dir, OAUTH2_FILE), { force: true }),\n ]);\n }\n}\n","import { GarminAuthError, GarminError } from \"./errors.js\";\nimport { Fetcher } from \"./http/fetcher.js\";\nimport { API_USER_AGENT } from \"./auth/constants.js\";\nimport {\n exchange,\n login as ssoLogin,\n resumeLogin as ssoResumeLogin,\n type LoginResult,\n type MfaState,\n type SsoContext,\n} from \"./auth/sso.js\";\nimport {\n authorizationHeader,\n isExpired,\n refreshExpired,\n type Tokens,\n} from \"./auth/tokens.js\";\nimport { MemoryTokenStore, type TokenStore } from \"./auth/token-store.js\";\n\nexport interface GarminClientOptions {\n tokenStore?: TokenStore;\n isCn?: boolean;\n timeoutMs?: number;\n retries?: number;\n backoffMs?: number;\n fetchImpl?: typeof fetch;\n /**\n * Pause before the SSO widget's credential POST (the fallback when the mobile login is rate\n * limited), in ms. Default: random 3000–8000. Tests pass 0.\n */\n loginDelayMs?: number;\n}\n\nexport interface ApiOptions {\n method?: string;\n params?: Record<string, string | number | undefined>;\n json?: unknown;\n headers?: Record<string, string>;\n /** Per-request timeout, overriding the client's default (10s). */\n timeoutMs?: number;\n}\n\n/**\n * `download()`/`upload()` move binary payloads (FIT files, images) rather\n * than a small JSON body, so they get a longer default timeout than the\n * client's general-purpose 10s — a caller on a slow link can still override\n * it via `ApiOptions.timeoutMs`.\n */\nconst TRANSFER_DEFAULT_TIMEOUT_MS = 60_000;\n\nexport class GarminClient {\n readonly domain: string;\n readonly tokenStore: TokenStore;\n\n #fetcher: Fetcher;\n #tokens: Tokens | null = null;\n #refreshing: Promise<void> | null = null;\n readonly #loginDelayMs: number | undefined;\n\n constructor(options: GarminClientOptions = {}) {\n this.domain = options.isCn ? \"garmin.cn\" : \"garmin.com\";\n this.tokenStore = options.tokenStore ?? new MemoryTokenStore();\n this.#loginDelayMs = options.loginDelayMs;\n this.#fetcher = new Fetcher({\n timeoutMs: options.timeoutMs,\n retries: options.retries,\n backoffMs: options.backoffMs,\n fetchImpl: options.fetchImpl,\n });\n }\n\n get #ssoContext(): SsoContext {\n return { fetcher: this.#fetcher, domain: this.domain, loginDelayMs: this.#loginDelayMs };\n }\n\n async login(email: string, password: string): Promise<LoginResult> {\n const result = await ssoLogin(email, password, this.#ssoContext);\n if (result.state === \"success\") {\n await this.#persist({ oauth1: result.oauth1, oauth2: result.oauth2 });\n }\n return result;\n }\n\n async resumeLogin(mfaState: MfaState, code: string): Promise<void> {\n this.#checkDomain(mfaState.domain);\n const result = await ssoResumeLogin(mfaState, code, { fetcher: this.#fetcher });\n await this.#persist({ oauth1: result.oauth1, oauth2: result.oauth2 });\n }\n\n /** Returns false when the store holds nothing. */\n async loadTokens(): Promise<boolean> {\n const tokens = await this.tokenStore.load();\n if (!tokens) return false;\n this.#checkDomain(tokens.oauth1.domain);\n this.#tokens = tokens;\n return true;\n }\n\n /**\n * A `.cn` MFA state resumed on a default `.com` client (or vice versa)\n * mints tokens whose signed `oauth_token` is scoped to the wrong SSO\n * realm, but every later request would still be sent to *this* client's\n * `connectapi.<domain>` — a mismatch severe enough to fail loudly rather\n * than surface as a confusing downstream 401. Tokens with no domain\n * recorded (e.g. hand-constructed, or from an older on-disk format) are\n * accepted as-is.\n */\n #checkDomain(tokenDomain: string | undefined): void {\n if (tokenDomain && tokenDomain !== this.domain) {\n throw new GarminAuthError(\n `Token domain ${tokenDomain} does not match client domain ${this.domain}; ` +\n `construct the client with isCn: ${tokenDomain === \"garmin.cn\"}`,\n );\n }\n }\n\n setTokens(tokens: Tokens): void {\n this.#tokens = tokens;\n }\n\n getTokens(): Tokens | null {\n return this.#tokens;\n }\n\n async #persist(tokens: Tokens): Promise<void> {\n this.#tokens = tokens;\n await this.tokenStore.save(tokens);\n }\n\n async #ensureFresh(): Promise<Tokens> {\n const tokens = this.#tokens;\n if (!tokens) {\n throw new GarminAuthError(\"Not authenticated: call login() or loadTokens() first\");\n }\n if (!isExpired(tokens.oauth2)) return tokens;\n\n if (refreshExpired(tokens.oauth2)) {\n await this.tokenStore.clear();\n this.#tokens = null;\n throw new GarminAuthError(\"Refresh token expired; log in again\");\n }\n\n // Collapse concurrent refreshes into one exchange. Captured into a local\n // immediately after the assignment so a later `await` can never observe\n // a `this.#refreshing` that a concurrent `finally` has already reset to\n // null out from under us.\n const refreshing = (this.#refreshing ??= (async () => {\n try {\n const oauth2 = await exchange(tokens.oauth1, this.#ssoContext);\n await this.#persist({ oauth1: tokens.oauth1, oauth2 });\n } catch (cause) {\n // Only a dead credential justifies destroying the user's saved tokens,\n // and only a 401 says that. The Fetcher maps 403 to GarminAuthError too,\n // but a 403 here is usually Cloudflare blocking the request, and a 200\n // HTML challenge page also surfaces as GarminAuthError (non-JSON).\n // Those, like a DNS blip, a timeout, a 5xx or a 429, must not force a\n // full interactive re-login: leave the store untouched and let the\n // error propagate so the caller can retry later.\n if (cause instanceof GarminAuthError && cause.message.endsWith(\"(401)\")) {\n await this.tokenStore.clear();\n this.#tokens = null;\n }\n throw cause;\n } finally {\n // Reset unconditionally (success or failure) so a failed refresh\n // never wedges the client: the next call always tries again rather\n // than re-serving this rejected promise forever.\n this.#refreshing = null;\n }\n })());\n await refreshing;\n\n const refreshed = this.#tokens;\n if (!refreshed) throw new GarminAuthError(\"Token refresh failed; log in again\");\n return refreshed;\n }\n\n /**\n * Seeds a `Headers` from the caller's headers, then `.set()`s the transport's own on top so\n * they always win regardless of the caller's casing. See the callers' comments.\n */\n #withTransportHeaders(callerHeaders: Record<string, string> | undefined, tokens: Tokens): Headers {\n const headers = new Headers(callerHeaders ?? {});\n headers.set(\"authorization\", authorizationHeader(tokens.oauth2));\n headers.set(\"User-Agent\", API_USER_AGENT);\n return headers;\n }\n\n async #apiRequest(path: string, options: ApiOptions = {}): Promise<Response> {\n const tokens = await this.#ensureFresh();\n return this.#fetcher.request(`https://connectapi.${this.domain}${path}`, {\n method: options.method,\n params: options.params,\n json: options.json,\n timeoutMs: options.timeoutMs,\n // Caller headers seed a `Headers` object, then the transport's own\n // headers are `.set()` on top. `Headers.set` matches case-insensitively\n // and REPLACES, so a caller-supplied `authorization` — or a\n // differently-cased `Authorization` — can never survive alongside the\n // injected bearer token. Object spread cannot do this: `Authorization`\n // and `authorization` are distinct object keys, and `new Headers()`\n // combines the duplicates with `\", \"` instead of dropping one.\n headers: this.#withTransportHeaders(options.headers, tokens),\n });\n }\n\n /**\n * Parses a JSON body, returning `null` for a 204 or an empty body. A 200\n * with a non-JSON body (e.g. an HTML Cloudflare challenge page) is turned\n * into a `GarminError` instead of letting a bare `SyntaxError` escape.\n */\n async #parseBody<T>(res: Response): Promise<T | null> {\n if (res.status === 204) return null;\n const text = await res.text();\n if (text.length === 0) return null;\n try {\n return JSON.parse(text) as T;\n } catch (cause) {\n throw new GarminError(\"Garmin API returned a non-JSON response\", { cause });\n }\n }\n\n async connectapi<T = unknown>(path: string, options: ApiOptions = {}): Promise<T | null> {\n const res = await this.#apiRequest(path, options);\n return this.#parseBody<T>(res);\n }\n\n async download(path: string, options: ApiOptions = {}): Promise<Buffer> {\n const res = await this.#apiRequest(path, {\n ...options,\n timeoutMs: options.timeoutMs ?? TRANSFER_DEFAULT_TIMEOUT_MS,\n });\n return Buffer.from(await res.arrayBuffer());\n }\n\n async upload(\n file: Blob,\n filename: string,\n path = \"/upload-service/upload\",\n options: Pick<ApiOptions, \"timeoutMs\" | \"headers\"> = {},\n ): Promise<unknown> {\n const tokens = await this.#ensureFresh();\n const form = new FormData();\n form.append(\"file\", file, filename);\n // Content-Type is deliberately unset so fetch adds the multipart boundary.\n const uploadHeaders = new Headers({ \"User-Agent\": API_USER_AGENT });\n for (const [key, value] of new Headers(options.headers ?? {})) {\n uploadHeaders.set(key, value);\n }\n uploadHeaders.set(\"authorization\", authorizationHeader(tokens.oauth2));\n const res = await this.#fetcher.request(`https://connectapi.${this.domain}${path}`, {\n method: \"POST\",\n body: form,\n timeoutMs: options.timeoutMs ?? TRANSFER_DEFAULT_TIMEOUT_MS,\n // Default `User-Agent` first, then caller headers (e.g.\n // `importActivity`'s load-bearing `NK`/`origin`/`User-Agent`\n // overrides — a caller MAY replace the User-Agent), then the\n // transport's own auth header `.set()` last so it can never be\n // replaced. Same case-insensitivity reasoning as `#apiRequest`.\n headers: uploadHeaders,\n });\n return this.#parseBody(res);\n }\n}\n","import { GarminError } from \"../errors.js\";\n\nconst SPORT_KEY_RE = /^[A-Z_]+$/;\n\n/**\n * Mirrors upstream `_validate_sport_key`: upper-cases the input and requires it to match\n * `^[A-Z_]+$` afterward. Originally lived in `src/services/metrics.ts` (live-verified there across\n * 20+ read probes covering FTP/power-zone/sport-key endpoints) before being extracted here so\n * `src/services/gear.ts` (which needs the identical rule for `gearType`/`usageType`/`activityType`)\n * could share it instead of duplicating the regex and risking drift between two copies.\n */\nexport function validateSportKey(sport: string): string {\n const normalized = sport.toUpperCase();\n if (!SPORT_KEY_RE.test(normalized)) {\n throw new GarminError(`Invalid sport key: \"${sport}\"`);\n }\n return normalized;\n}\n\n/**\n * Mirrors upstream `_validate_non_negative_integer`. Extracted here (from `badges.ts`, where it was\n * first written and live-verified) when `goals.ts` needed the same rule — third-copy prevention,\n * same reason `validateSportKey` lives here.\n */\nexport function validateNonNegativeInteger(value: number, paramName: string): number {\n if (!Number.isInteger(value)) {\n throw new GarminError(`${paramName} must be an integer`);\n }\n if (value < 0) {\n throw new GarminError(`${paramName} must be non-negative, got: ${value}`);\n }\n return value;\n}\n\n/** Mirrors upstream `_validate_positive_integer`. See `validateNonNegativeInteger` above. */\nexport function validatePositiveInteger(value: number, paramName: string): number {\n if (!Number.isInteger(value)) {\n throw new GarminError(`${paramName} must be an integer`);\n }\n if (value <= 0) {\n throw new GarminError(`${paramName} must be a positive integer, got: ${value}`);\n }\n return value;\n}\n\n/**\n * Percent-encodes a single URL path segment before it is interpolated into a request path.\n *\n * Every service in this library builds its path with a template literal (`` `/activity-service/\n * activity/${activityId}` ``), and `Fetcher.request` then hands that string to `new URL()`, which\n * NORMALIZES `..` segments. Without encoding, a caller-controlled id is a path-traversal /\n * request-redirection primitive: `getActivity(\"../../weight-service/weight/2026-01-01/byversion/\n * 999\")` resolved to a completely different Garmin service, carrying the user's bearer token, and\n * `getActivity(\"1?x=y#frag\")` smuggled a query string and fragment into the request. The headline\n * use case for this library is a Next.js route handler forwarding a user-controlled route param,\n * so that is the DEFAULT shape of consuming code, not an exotic one.\n *\n * This also restores parity with upstream python-garminconnect, whose `_require_display_name`\n * does `quote(name, safe=\"\")`.\n *\n * Encoding is behaviour-preserving for every legitimate value: numeric ids, hex UUIDs,\n * `YYYY-MM-DD` dates and Garmin display names all round-trip through `encodeURIComponent`\n * unchanged.\n */\nexport function pathSegment(value: string | number): string {\n return encodeURIComponent(String(value));\n}\n\nconst UUID_HEX_RE = /^[0-9a-fA-F]+$/;\n\n/**\n * Mirrors upstream `_validate_uuid`: hex characters, hyphens optional (stripped before checking).\n *\n * Originally private to `src/services/gear.ts` and applied at exactly ONE of the eight `gearUUID`\n * interpolation sites (`getGearStats`). Extracted here and applied at all eight so the rule is\n * uniform: a `gearUUID` that reaches a URL has been checked, everywhere. It is a defence in depth\n * alongside `pathSegment` — encoding neutralises injection, validation rejects the value outright.\n */\nexport function validateUuid(uuid: string): string {\n const stripped = uuid.replace(/-/g, \"\");\n if (stripped.length === 0 || !UUID_HEX_RE.test(stripped)) {\n throw new GarminError(`Invalid gear UUID: \"${uuid}\"`);\n }\n return uuid;\n}\n","import { GarminError } from \"../errors.js\";\n\nconst ISO_DATE = /^\\d{4}-\\d{2}-\\d{2}$/;\n\n/**\n * Normalizes to the `YYYY-MM-DD` form Garmin expects.\n *\n * `Date` objects are formatted in UTC, not the local timezone. Garmin's API\n * consumes UTC calendar dates, so this is correct — but it is a foot-gun for\n * a caller in a negative UTC offset: passing `new Date()` late in their local\n * day can format as tomorrow's date, because it is already tomorrow in UTC.\n */\nexport function formatDate(value: string | Date): string {\n if (value instanceof Date) {\n if (Number.isNaN(value.getTime())) {\n throw new GarminError(\"Expected a valid date\");\n }\n return value.toISOString().slice(0, 10);\n }\n if (!ISO_DATE.test(value)) {\n throw new GarminError(`Expected a date in YYYY-MM-DD format, got \"${value}\"`);\n }\n const parsed = new Date(`${value}T00:00:00Z`);\n if (Number.isNaN(parsed.getTime()) || parsed.toISOString().slice(0, 10) !== value) {\n throw new GarminError(`Expected a valid date, got \"${value}\"`);\n }\n return value;\n}\n\nconst pad = (n: number): string => String(n).padStart(2, \"0\");\n\n/**\n * Local wall-clock time formatted as Garmin's `*TimestampLocal`/`dateTimestamp`\n * write fields expect (`YYYY-MM-DDTHH:mm:ss.00`, no offset). Deliberately\n * built from the local getters (`getFullYear`/`getHours`/...), not\n * `toISOString()`, which is always UTC. Shared by every write endpoint that\n * pairs a local timestamp with a GMT one (`addWeighIn`, `setBloodPressure`,\n * `addHydrationData`, ...) — live-verified against real Garmin via\n * `addWeighIn` (the endpoint implicated in the historical \"93,000 kg\" bug),\n * so do not alter its output when reusing it.\n */\nexport function formatLocalTimestamp(d: Date): string {\n return (\n `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}` +\n `T${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}.00`\n );\n}\n\n/**\n * UTC instant formatted as Garmin's `*TimestampGMT`/`gmtTimestamp` write\n * fields expect. See `formatLocalTimestamp` above for the pairing and the\n * live-verification note.\n */\nexport function formatGmtTimestamp(d: Date): string {\n return d.toISOString().slice(0, 19) + \".00\";\n}\n\nconst HAS_TIME = /\\d{2}:\\d{2}/;\nconst HAS_ZONE = /(?:Z|[+-]\\d{2}:?\\d{2})$/i;\n\n/**\n * Parse an ISO timestamp the way Python's `datetime.fromisoformat(s).astimezone()`\n * does for a NAIVE string: the wall clock is taken as LOCAL time.\n *\n * JavaScript's `new Date(s)` disagrees with that in two places, both handled\n * here: a date-only string (`\"2026-09-20\"`) is parsed as UTC midnight by spec,\n * and a bare date is not a datetime at all. A string carrying its own offset\n * or `Z` is passed through untouched — it already names an instant.\n */\nexport function parseIsoLocal(s: string): Date {\n return new Date(HAS_TIME.test(s) ? s : `${s}T00:00:00`);\n}\n\n/**\n * Parse an ISO timestamp the way upstream treats a supplied `gmtTimestamp`:\n * \"assume provided GMT is UTC if naive\". A naive string therefore gets `Z`\n * appended rather than being read as local time, which is what `new Date`\n * would otherwise do.\n */\nexport function parseIsoUtc(s: string): Date {\n if (HAS_ZONE.test(s)) return new Date(s);\n return new Date(`${HAS_TIME.test(s) ? s : `${s}T00:00:00`}Z`);\n}\n","import { pathSegment, validateUuid } from \"../util/validate.js\";\nimport { GarminConnectionError, GarminError, GarminHttpError } from \"../errors.js\";\nimport type { GarminClient } from \"../client.js\";\nimport { formatDate } from \"../util/date.js\";\nimport type {\n Activity,\n ActivitiesForDateResponse,\n ActivityDetails,\n ActivityDownloadFormat,\n ActivityExerciseSets,\n ActivityGear,\n ActivityHrInTimezones,\n ActivityPowerInTimezones,\n ActivitySplits,\n ActivitySplitSummaries,\n ActivityTypedSplits,\n ActivityTypesResponse,\n ActivityWeather,\n GearActivity,\n GearLinkResult,\n ImportActivityResult,\n PersonalRecords,\n ProgressSummary,\n UploadActivityResult,\n} from \"../types/activities.js\";\n\nexport interface ActivitiesHost {\n readonly client: GarminClient;\n /** Only needed by `getPersonalRecord`, which URLs by display name like the date-scoped methods. */\n displayName(): Promise<string>;\n}\n\n/** Upstream `count_activities`: returns the envelope's `totalCount`, not the whole response. */\nexport async function countActivities(host: ActivitiesHost): Promise<number> {\n const data = await host.client.connectapi<{ totalCount?: number }>(\n \"/activitylist-service/activities/count\",\n );\n if (!data || typeof data.totalCount !== \"number\") {\n throw new GarminError(\"No activities count data received\");\n }\n return data.totalCount;\n}\n\nexport async function getActivities(\n host: ActivitiesHost,\n start = 0,\n limit = 20,\n): Promise<Activity[]> {\n const activities = await host.client.connectapi<Activity[]>(\n \"/activitylist-service/activities/search/activities\",\n { params: { start, limit } },\n );\n return activities ?? [];\n}\n\nexport async function getActivity(\n host: ActivitiesHost,\n activityId: number | string,\n): Promise<Activity> {\n const activity = await host.client.connectapi<Activity>(\n `/activity-service/activity/${pathSegment(activityId)}`,\n );\n if (!activity) throw new GarminError(`No activity ${activityId} found`);\n return activity;\n}\n\nconst DOWNLOAD_PATHS: Record<ActivityDownloadFormat, string> = {\n ORIGINAL: \"/download-service/files/activity\",\n TCX: \"/download-service/export/tcx/activity\",\n GPX: \"/download-service/export/gpx/activity\",\n KML: \"/download-service/export/kml/activity\",\n CSV: \"/download-service/export/csv/activity\",\n};\n\nexport async function downloadActivity(\n host: ActivitiesHost,\n activityId: number | string,\n format: ActivityDownloadFormat = \"ORIGINAL\",\n): Promise<Buffer> {\n const base = DOWNLOAD_PATHS[format];\n if (!base) {\n throw new GarminError(`Unknown download format \"${format}\"`);\n }\n return host.client.download(`${base}/${pathSegment(activityId)}`);\n}\n\n/**\n * Upstream's `garmin_connect_activity_fordate` constant points at a\n * `/mobile-gateway/heartRate/...` path despite the \"activities\" name and\n * despite this being the activities service — transcribed verbatim from the\n * inventory, not a typo introduced here. `fordate` is routed through\n * `formatDate` like every other date-taking method in this library.\n */\nexport async function getActivitiesForDate(\n host: ActivitiesHost,\n fordate: string | Date,\n): Promise<ActivitiesForDateResponse | null> {\n const date = formatDate(fordate);\n return host.client.connectapi<ActivitiesForDateResponse>(\n `/mobile-gateway/heartRate/forDate/${pathSegment(date)}`,\n );\n}\n\n/**\n * Handles both response shapes `get_activities` can (in principle) hand\n * back upstream. In this port `getActivities` always coalesces to `[]`\n * (never the dict-with-`activityList`-key shape), so only the bare-array\n * branch is reachable here — kept for parity with upstream's defensive\n * handling of both shapes.\n */\nexport async function getLastActivity(host: ActivitiesHost): Promise<Activity | null> {\n const activities = await getActivities(host, 0, 1);\n return activities.length > 0 ? (activities[activities.length - 1] ?? null) : null;\n}\n\n/** `dict`, passes through unchecked per the inventory. */\nexport async function getActivityTypes(\n host: ActivitiesHost,\n): Promise<ActivityTypesResponse | null> {\n return host.client.connectapi<ActivityTypesResponse>(\n \"/activity-service/activity/activityTypes\",\n );\n}\n\n/**\n * UNCERTAIN (inventory): \"no explicit null handling, returns raw response\".\n * `client.py`'s exact behaviour on a non-2xx/empty body was not reviewed;\n * this passes `connectapi`'s own null-on-204/empty-body result straight\n * through rather than inventing a throw.\n */\nexport async function deleteActivity(\n host: ActivitiesHost,\n activityId: number | string,\n): Promise<unknown> {\n return host.client.connectapi(`/activity-service/activity/${pathSegment(activityId)}`, {\n method: \"DELETE\",\n });\n}\n\n/** UNCERTAIN (inventory): \"no explicit null handling, returns raw response\". */\nexport async function setActivityName(\n host: ActivitiesHost,\n activityId: number | string,\n activityName: string,\n): Promise<unknown> {\n return host.client.connectapi(`/activity-service/activity/${pathSegment(activityId)}`, {\n method: \"PUT\",\n json: { activityId, activityName },\n });\n}\n\n/** UNCERTAIN (inventory): \"no explicit null handling, returns raw response\". */\nexport async function setActivityType(\n host: ActivitiesHost,\n activityId: number | string,\n typeId: number,\n typeKey: string,\n parentTypeId: number,\n): Promise<unknown> {\n return host.client.connectapi(`/activity-service/activity/${pathSegment(activityId)}`, {\n method: \"PUT\",\n json: {\n activityId,\n activityTypeDTO: { typeId, typeKey, parentTypeId },\n },\n });\n}\n\n/** UNCERTAIN (inventory): \"no explicit null handling, returns raw response\". */\nexport async function setActivityDescription(\n host: ActivitiesHost,\n activityId: number | string,\n description: string,\n): Promise<unknown> {\n return host.client.connectapi(`/activity-service/activity/${pathSegment(activityId)}`, {\n method: \"PUT\",\n json: { activityId, description },\n });\n}\n\n/**\n * Low-level entry point: `payload` is sent to Garmin verbatim, no shape\n * validation. `create_manual_activity` builds on top of this.\n * UNCERTAIN (inventory): \"no explicit null handling, returns raw response\".\n */\nexport async function createManualActivityFromJson(\n host: ActivitiesHost,\n payload: Record<string, unknown>,\n): Promise<unknown> {\n return host.client.connectapi(\"/activity-service/activity\", {\n method: \"POST\",\n json: payload,\n });\n}\n\n/**\n * CONVERTS units before sending — the opposite direction from `addWeighIn`.\n * `distanceKm` (km) is multiplied by 1000 to become the wire `distance`\n * (meters); `durationMin` (minutes) is multiplied by 60 to become the wire\n * `duration` (seconds). Getting this backwards silently corrupts the\n * stored activity's distance/duration by 1000x/60x.\n *\n * `startDatetime` is passed through unmodified, NOT routed through\n * `formatDate`: upstream types it as a bare `str` (Garmin's local\n * start-time format), not a `YYYY-MM-DD` calendar date, so `formatDate`'s\n * stricter date-only validation would reject a legitimate value. It MUST\n * include milliseconds, e.g. `\"2026-09-22T09:00:00.000\"` (upstream's\n * documented pattern) — live-verified against the Garmin test account:\n * omitting the `.000` produced an HTTP 500 `ValueInstantiationException`\n * from Garmin, while the same body with `.000` appended succeeded.\n *\n * `typeKey` is the Garmin activity type key WITHOUT the `activity_type_`\n * prefix (e.g. `\"resort_skiing\"`), per the inventory notes.\n */\nexport async function createManualActivity(\n host: ActivitiesHost,\n startDatetime: string,\n timeZone: string,\n typeKey: string,\n distanceKm: number,\n durationMin: number,\n activityName: string,\n): Promise<unknown> {\n const payload = {\n activityTypeDTO: { typeKey },\n accessControlRuleDTO: { typeId: 2, typeKey: \"private\" },\n timeZoneUnitDTO: { unitKey: timeZone },\n activityName,\n metadataDTO: { autoCalcCalories: true },\n summaryDTO: {\n startTimeLocal: startDatetime,\n distance: distanceKm * 1000,\n duration: durationMin * 60,\n },\n };\n return createManualActivityFromJson(host, payload);\n}\n\nconst ACTIVITIES_BY_DATE_PAGE_SIZE = 20;\n/** Matches upstream's `MAX_PAGINATED_REQUESTS` safety cap. */\nconst MAX_PAGINATED_REQUESTS = 2000;\n\n/**\n * Replicates upstream's internal pagination loop: fetches fixed pages of\n * `ACTIVITIES_BY_DATE_PAGE_SIZE` (20), incrementing `start` by that amount\n * each call, until a page comes back empty/falsy (the normal end of data)\n * or `MAX_PAGINATED_REQUESTS` pages have been fetched without ever seeing\n * an empty page (an abort-with-error safety cap, not a normal outcome).\n */\nexport async function getActivitiesByDate(\n host: ActivitiesHost,\n startdate: string | Date,\n enddate?: string | Date,\n activitytype?: string,\n sortorder?: string,\n): Promise<Activity[]> {\n const startDate = formatDate(startdate);\n const endDate = enddate !== undefined ? formatDate(enddate) : undefined;\n const results: Activity[] = [];\n let start = 0;\n let sawEmptyPage = false;\n\n for (let page = 0; page < MAX_PAGINATED_REQUESTS; page++) {\n const batch = await host.client.connectapi<Activity[]>(\n \"/activitylist-service/activities/search/activities\",\n {\n params: {\n startDate,\n start,\n limit: ACTIVITIES_BY_DATE_PAGE_SIZE,\n endDate,\n activityType: activitytype,\n sortOrder: sortorder,\n },\n },\n );\n if (!batch || batch.length === 0) {\n sawEmptyPage = true;\n break;\n }\n results.push(...batch);\n start += ACTIVITIES_BY_DATE_PAGE_SIZE;\n }\n\n if (!sawEmptyPage) {\n throw new GarminError(`Pagination exceeded ${MAX_PAGINATED_REQUESTS} requests; aborting`);\n }\n return results;\n}\n\nconst IMPORT_UPLOAD_HEADERS: Record<string, string> = {\n NK: \"NT\",\n origin: \"https://sso.garmin.com\",\n \"User-Agent\": \"GCM-iOS-5.7.2.1\",\n};\n\nconst IMPORT_ACTIVITY_EXTENSIONS = new Set([\"fit\", \"gpx\", \"tcx\"]);\n\n/**\n * Distinct endpoint and headers from a plain device-sync upload\n * (`client.upload()`'s default path): the `NK`/`origin`/custom `User-Agent`\n * headers are load-bearing — without them Garmin treats the request as an\n * ordinary device sync rather than an import, per the inventory notes.\n */\nexport async function importActivity(\n host: ActivitiesHost,\n file: Blob,\n filename: string,\n): Promise<ImportActivityResult> {\n const dotIndex = filename.lastIndexOf(\".\");\n if (dotIndex <= 0 || dotIndex === filename.length - 1) {\n throw new GarminError(`Cannot determine file extension from \"${filename}\"`);\n }\n const extension = filename.slice(dotIndex + 1).toLowerCase();\n if (!IMPORT_ACTIVITY_EXTENSIONS.has(extension)) {\n throw new GarminError(\n `Unsupported activity file format \".${extension}\" — expected fit, gpx, or tcx`,\n );\n }\n\n try {\n const result = await host.client.upload(file, filename, `/upload-service/upload/${pathSegment(extension)}`, {\n headers: IMPORT_UPLOAD_HEADERS,\n });\n // Upstream: \"if the client response has no `.json` attribute\" (e.g. an\n // empty body) it synthesizes this fallback instead of raising. Our\n // `upload()` returns `null` in the equivalent case.\n if (result && typeof result === \"object\") {\n return result as ImportActivityResult;\n }\n return { status: \"uploaded\", fileName: filename };\n } catch (cause) {\n if (cause instanceof GarminHttpError && cause.status === 409) {\n throw new GarminConnectionError(`Activity already exists (duplicate): ${filename}`, {\n cause,\n });\n }\n if (cause instanceof GarminHttpError || cause instanceof GarminConnectionError) {\n throw new GarminConnectionError(`Import error: ${cause.message}`, { cause });\n }\n throw cause;\n }\n}\n\n// --- per-activity detail sub-resources (Task 4) ---\n\n/** `dict`, passes through unchecked per the inventory. */\nexport async function getActivitySplits(\n host: ActivitiesHost,\n activityId: number | string,\n): Promise<ActivitySplits | null> {\n return host.client.connectapi<ActivitySplits>(`/activity-service/activity/${pathSegment(activityId)}/splits`);\n}\n\n/** `dict`, passes through unchecked per the inventory. Richer detail than `getActivitySplits` for some activity types (e.g. Bouldering). */\nexport async function getActivityTypedSplits(\n host: ActivitiesHost,\n activityId: number | string,\n): Promise<ActivityTypedSplits | null> {\n return host.client.connectapi<ActivityTypedSplits>(\n `/activity-service/activity/${pathSegment(activityId)}/typedsplits`,\n );\n}\n\n/** `dict`, passes through unchecked per the inventory. */\nexport async function getActivitySplitSummaries(\n host: ActivitiesHost,\n activityId: number | string,\n): Promise<ActivitySplitSummaries | null> {\n return host.client.connectapi<ActivitySplitSummaries>(\n `/activity-service/activity/${pathSegment(activityId)}/split_summaries`,\n );\n}\n\n/** `dict`, passes through unchecked per the inventory. */\nexport async function getActivityWeather(\n host: ActivitiesHost,\n activityId: number | string,\n): Promise<ActivityWeather | null> {\n return host.client.connectapi<ActivityWeather>(`/activity-service/activity/${pathSegment(activityId)}/weather`);\n}\n\n/** `dict`, passes through unchecked per the inventory. */\nexport async function getActivityHrInTimezones(\n host: ActivitiesHost,\n activityId: number | string,\n): Promise<ActivityHrInTimezones | null> {\n return host.client.connectapi<ActivityHrInTimezones>(\n `/activity-service/activity/${pathSegment(activityId)}/hrTimeInZones`,\n );\n}\n\n/** `dict`, passes through unchecked per the inventory. */\nexport async function getActivityPowerInTimezones(\n host: ActivitiesHost,\n activityId: number | string,\n): Promise<ActivityPowerInTimezones | null> {\n return host.client.connectapi<ActivityPowerInTimezones>(\n `/activity-service/activity/${pathSegment(activityId)}/powerTimeInZones`,\n );\n}\n\n/**\n * `dict`, passes through unchecked per the inventory. Upstream validates `maxchart` positive and\n * `maxpoly` non-negative before the call; this port does not re-validate (matching the \"no\n * explicit null handling\" posture applied elsewhere in this file for un-reviewed edge cases) —\n * an invalid value is Garmin's problem to reject, not re-validated client-side here.\n */\nexport async function getActivityDetails(\n host: ActivitiesHost,\n activityId: number | string,\n maxchart = 2000,\n maxpoly = 4000,\n): Promise<ActivityDetails | null> {\n return host.client.connectapi<ActivityDetails>(`/activity-service/activity/${pathSegment(activityId)}/details`, {\n params: { maxChartSize: String(maxchart), maxPolylineSize: String(maxpoly) },\n });\n}\n\n/** `dict`, passes through unchecked per the inventory. */\nexport async function getActivityExerciseSets(\n host: ActivitiesHost,\n activityId: number | string,\n): Promise<ActivityExerciseSets | null> {\n return host.client.connectapi<ActivityExerciseSets>(\n `/activity-service/activity/${pathSegment(activityId)}/exerciseSets`,\n );\n}\n\n/**\n * UNCERTAIN (inventory): \"no explicit null handling, returns raw response\".\n * **Replace-all semantics** — `payload` fully overwrites the existing `exerciseSets` array on\n * Garmin's side, it is not merged. Garmin validates `exercises[].category`/`exercises[].name`\n * against its FIT enum server-side (400 \"Invalid Sub-Category Passed\" on unknown values).\n */\nexport async function setActivityExerciseSets(\n host: ActivitiesHost,\n activityId: number | string,\n payload: ActivityExerciseSets,\n): Promise<unknown> {\n return host.client.connectapi(`/activity-service/activity/${pathSegment(activityId)}/exerciseSets`, {\n method: \"PUT\",\n json: payload,\n });\n}\n\n/**\n * Inventory places this row under the \"gear\" section, not \"activities\" — reuses `get_gear`'s base\n * URL (`/gear-service/gear/filterGear`) with an `activityId` query param instead of `userProfilePk`.\n * Implemented here per the task brief, which assigns the activity/gear-association methods to this\n * service rather than the dedicated gear service (`src/services/gear.ts`, ported in Task 7).\n *\n * Returns an ARRAY (`ActivityGear[]`), not a single object — confirmed live in Task 7's\n * fix-round-1 (see `ActivityGear`'s doc comment in `src/types/activities.ts`); this was fixed from\n * an earlier `ActivityGear | null` signature that mistyped it as a single object.\n */\nexport async function getActivityGear(\n host: ActivitiesHost,\n activityId: number | string,\n): Promise<ActivityGear[] | null> {\n return host.client.connectapi<ActivityGear[]>(\"/gear-service/gear/filterGear\", {\n params: { activityId },\n });\n}\n\nconst GEAR_ACTIVITIES_MAX_LIMIT = 1000;\n\n/**\n * Inventory places this row under the \"gear\" section — see `getActivityGear`'s note.\n * `limit` is clamped to `GEAR_ACTIVITIES_MAX_LIMIT` (1000), matching upstream. On a 404, upstream\n * logs a warning and returns `[]` rather than raising; other errors are re-raised as-is.\n */\nexport async function getGearActivities(\n host: ActivitiesHost,\n gearUUID: string,\n limit = 1000,\n): Promise<GearActivity[]> {\n const cappedLimit = Math.min(limit, GEAR_ACTIVITIES_MAX_LIMIT);\n const uuid = validateUuid(gearUUID);\n try {\n const data = await host.client.connectapi<GearActivity[]>(\n `/activitylist-service/activities/${pathSegment(uuid)}/gear`,\n { params: { start: 0, limit: cappedLimit } },\n );\n return data ?? [];\n } catch (cause) {\n if (cause instanceof GarminHttpError && cause.status === 404) {\n return [];\n }\n throw cause;\n }\n}\n\n/**\n * Inventory places this row under the \"gear\" section — see `getActivityGear`'s note.\n * On 404, re-raised as `GarminConnectionError` with a \"gear not found (likely retired/removed)\"\n * message, matching upstream; other errors re-raised as-is.\n */\nexport async function addGearToActivity(\n host: ActivitiesHost,\n gearUUID: string,\n activityId: number | string,\n): Promise<GearLinkResult | null> {\n const uuid = validateUuid(gearUUID);\n try {\n return await host.client.connectapi<GearLinkResult>(\n `/gear-service/gear/link/${pathSegment(uuid)}/activity/${pathSegment(activityId)}`,\n { method: \"PUT\" },\n );\n } catch (cause) {\n if (cause instanceof GarminHttpError && cause.status === 404) {\n throw new GarminConnectionError(\n `Cannot add gear ${gearUUID} to activity ${activityId}: gear not found (likely retired/removed)`,\n { cause },\n );\n }\n throw cause;\n }\n}\n\n/**\n * Inventory places this row under the \"gear\" section — see `getActivityGear`'s note.\n * Note: unlinking is also a **PUT**, not a DELETE, matching upstream exactly. Same 404-handling\n * pattern as `addGearToActivity`, with a \"remove ... from activity\" message.\n */\nexport async function removeGearFromActivity(\n host: ActivitiesHost,\n gearUUID: string,\n activityId: number | string,\n): Promise<GearLinkResult | null> {\n const uuid = validateUuid(gearUUID);\n try {\n return await host.client.connectapi<GearLinkResult>(\n `/gear-service/gear/unlink/${pathSegment(uuid)}/activity/${pathSegment(activityId)}`,\n { method: \"PUT\" },\n );\n } catch (cause) {\n if (cause instanceof GarminHttpError && cause.status === 404) {\n throw new GarminConnectionError(\n `Cannot remove gear ${gearUUID} from activity ${activityId}: gear not found (likely retired/removed)`,\n { cause },\n );\n }\n throw cause;\n }\n}\n\n/** `dict`, passes through unchecked per the inventory. Both dates are routed through `formatDate`. */\nexport async function getProgressSummaryBetweenDates(\n host: ActivitiesHost,\n startdate: string | Date,\n enddate: string | Date,\n metric = \"distance\",\n groupbyactivities = true,\n): Promise<ProgressSummary | null> {\n const startDate = formatDate(startdate);\n const endDate = formatDate(enddate);\n return host.client.connectapi<ProgressSummary>(\"/fitnessstats-service/activity\", {\n params: {\n startDate,\n endDate,\n aggregation: \"lifetime\",\n groupByParentActivityType: String(groupbyactivities),\n metric,\n },\n });\n}\n\n/**\n * UNCERTAIN (inventory): routed through `client.download`, no null-handling visible upstream.\n * Returns a ZIP file's raw bytes, matching `downloadActivity`'s `ORIGINAL` format.\n */\nexport async function downloadHealthSnapshot(\n host: ActivitiesHost,\n requestedDate: string | Date,\n): Promise<Buffer> {\n const date = formatDate(requestedDate);\n return host.client.download(`/download-service/files/wellness/${pathSegment(date)}`);\n}\n\n/**\n * Upstream `get_personal_record`. No inventory task ever ported this row — discovered missing by\n * `tests/parity.test.ts` during Task 15's reconciliation pass and closed here rather than left\n * failing, since it is a simple unauthenticated-by-args GET with a direct precedent\n * (`getActivity`'s date-scoped sibling methods already key off `displayName()`). `null_behaviour`:\n * passes through unchecked, per the inventory.\n */\nexport async function getPersonalRecord(host: ActivitiesHost): Promise<PersonalRecords | null> {\n const displayName = await host.displayName();\n return host.client.connectapi<PersonalRecords>(\n `/personalrecord-service/personalrecord/prs/${pathSegment(displayName)}`,\n );\n}\n\n/**\n * Upstream validates `upload_activity` and `import_activity` against the same `ActivityUploadFormat`\n * enum, so this alias is not a placeholder for a future divergence — it exists to make the shared\n * constraint explicit at both call sites rather than having one method reach into a constant named\n * for the other.\n */\nconst UPLOAD_ACTIVITY_EXTENSIONS = IMPORT_ACTIVITY_EXTENSIONS;\n\n/**\n * Upstream `upload_activity`. Like `get_personal_record`, no inventory task ever ported this row;\n * closed here during Task 15's reconciliation pass rather than left as a permanent parity-test\n * failure.\n *\n * **Distinct from `importActivity`**: this hits the PLAIN `/upload-service/upload` path with no\n * file-extension suffix and none of `importActivity`'s load-bearing `NK`/`origin`/custom\n * `User-Agent` headers — upstream's own `upload_activity` is the ordinary device-sync-shaped\n * upload, while `import_activity` (already ported) is the one that spoofs a different client to\n * make Garmin treat it as an import. Do not conflate the two; sending the import headers here (or\n * omitting them from `importActivity`) would swap their observed behaviour.\n *\n * Upstream's signature takes a filesystem path (`activity_path: str`) and reads the file itself.\n * This port follows the same Blob-based convention `importActivity` already established (this\n * library targets a server runtime, not a CLI with a trusted local filesystem convention) rather\n * than adding a second, inconsistent file-path-based entry point — a caller on Node can still\n * build a `Blob` from a file trivially (`new Blob([await readFile(path)])`).\n *\n * UNCERTAIN upstream null handling (upstream returns \"Any (raw client response)\" with no explicit\n * null-guard): implemented as a straightforward pass-through, matching this project's standing\n * rule for UNCERTAIN rows.\n */\nexport async function uploadActivity(\n host: ActivitiesHost,\n file: Blob,\n filename: string,\n): Promise<UploadActivityResult | null> {\n const dotIndex = filename.lastIndexOf(\".\");\n if (dotIndex <= 0 || dotIndex === filename.length - 1) {\n throw new GarminError(`Cannot determine file extension from \"${filename}\"`);\n }\n const extension = filename.slice(dotIndex + 1).toLowerCase();\n if (!UPLOAD_ACTIVITY_EXTENSIONS.has(extension)) {\n throw new GarminError(\n `Unsupported activity file format \".${extension}\" — expected fit, gpx, or tcx`,\n );\n }\n const result = await host.client.upload(file, filename);\n return (result as UploadActivityResult | null) ?? null;\n}\n","import type { GarminClient } from \"../client.js\";\r\nimport type {\r\n AdhocChallenge,\r\n AvailableBadgeChallenge,\r\n Badge,\r\n BadgeChallenge,\r\n BadgeDetail,\r\n BadgeImageUrls,\r\n InprogressVirtualChallenge,\r\n NonCompletedBadgeChallenge,\r\n} from \"../types/badges.js\";\r\nimport { validateNonNegativeInteger, validatePositiveInteger } from \"../util/validate.js\";\r\n\r\nexport interface BadgesHost {\r\n readonly client: GarminClient;\r\n}\r\n\r\nconst BADGE_IMAGES = \"https://connect.garmin.com/images/badges/xxhdpi\";\r\n\r\n/**\r\n * Garmin sends no image URL; its web app builds one from `badgeUuid` (newer challenge badges) or\r\n * `badgeId`. Same here, both sizes. A key that isn't plain alphanumeric is refused rather than\r\n * interpolated into a URL.\r\n */\r\nfunction imageUrls(badge: { badgeId?: unknown; badgeUuid?: unknown }): BadgeImageUrls | undefined {\r\n const uuid = typeof badge.badgeUuid === \"string\" ? badge.badgeUuid : \"\";\r\n const id = typeof badge.badgeId === \"number\" && Number.isInteger(badge.badgeId) ? String(badge.badgeId) : \"\";\r\n const key = uuid || id;\r\n if (!/^[A-Za-z0-9]+$/.test(key)) return undefined;\r\n return { small: `${BADGE_IMAGES}/badge_${key}_sml.png`, large: `${BADGE_IMAGES}/badge_${key}_lrg.png` };\r\n}\r\n\r\n/** Returns a copy with `badgeImageUrls` set, or the badge unchanged when there is no id. */\r\nfunction withImageUrls<T extends { badgeId?: unknown; badgeUuid?: unknown }>(badge: T): T {\r\n if (!badge || typeof badge !== \"object\") return badge;\r\n const urls = imageUrls(badge);\r\n return urls ? { ...badge, badgeImageUrls: urls } : badge;\r\n}\r\n\r\nfunction listWithImageUrls(badges: Badge[] | null): Badge[] | null {\r\n return Array.isArray(badges) ? badges.map(withImageUrls) : badges;\r\n}\r\n\r\n/**\r\n * Upstream `get_earned_badges`. Stays nullable, not coalesced. Each badge gains `badgeImageUrls`,\r\n * which Garmin does not send; everything else passes through unchanged.\r\n */\r\nexport async function getEarnedBadges(host: BadgesHost): Promise<Badge[] | null> {\r\n return listWithImageUrls(await host.client.connectapi<Badge[]>(\"/badge-service/badge/earned\"));\r\n}\r\n\r\n/**\r\n * Upstream `get_available_badges`. Stays nullable, not coalesced. Each badge gains\r\n * `badgeImageUrls`, which Garmin does not send; everything else passes through unchanged.\r\n */\r\nexport async function getAvailableBadges(host: BadgesHost): Promise<Badge[] | null> {\r\n return listWithImageUrls(\r\n await host.client.connectapi<Badge[]>(\"/badge-service/badge/available\", {\r\n params: { showExclusiveBadge: \"true\" },\r\n }),\r\n );\r\n}\r\n\r\n/**\r\n * NOT upstream parity: upstream has no per-badge call. `GET /badge-service/badge/detail/v3/{id}`\r\n * is what Garmin Connect's web app requests when a badge is opened (it adds\r\n * `followingLimit=7`, which only caps `followings` and is left out here). Works for badges the\r\n * caller has not earned. An unknown id is a 400 `GarminHttpError` from Garmin, not a 404. The badge\r\n * and each of its `relatedBadges` gain `badgeImageUrls`, which Garmin does not send.\r\n */\r\nexport async function getBadgeDetail(host: BadgesHost, badgeId: number): Promise<BadgeDetail | null> {\r\n const id = validatePositiveInteger(badgeId, \"badgeId\");\r\n const detail = await host.client.connectapi<BadgeDetail>(`/badge-service/badge/detail/v3/${id}`);\r\n if (!detail || typeof detail !== \"object\") return detail;\r\n const related = Array.isArray(detail.relatedBadges) ? detail.relatedBadges.map(withImageUrls) : detail.relatedBadges;\r\n return { ...withImageUrls(detail), relatedBadges: related };\r\n}\r\n\r\n/**\r\n * Mirrors upstream's nested `is_badge_in_progress`: a badge counts as \"in progress\" when its\r\n * progress is truthy (non-zero) AND either it hasn't reached its target yet, or — having reached\r\n * the target — it has a `badgeLimitCount` (a repeatable badge) that has not yet been fully earned\r\n * (`badgeEarnedNumber < badgeLimitCount`).\r\n */\r\nfunction isBadgeInProgress(badge: Badge): boolean {\r\n const progress = badge.badgeProgressValue;\r\n if (!progress) return false;\r\n const target = badge.badgeTargetValue;\r\n if (progress === target) {\r\n if (badge.badgeLimitCount == null) return false;\r\n return (badge.badgeEarnedNumber ?? 0) < badge.badgeLimitCount;\r\n }\r\n return true;\r\n}\r\n\r\n/**\r\n * Upstream `get_in_progress_badges` has no HTTP path of its own. It calls `get_earned_badges()`\r\n * and `get_available_badges()` (in that order), filters each list with `is_badge_in_progress`,\r\n * then merges the two filtered lists into a dict keyed by `badgeId` — `available` overwrites\r\n * `earned` on a key collision — and returns `list(combined.values())`. Never raises: if either\r\n * upstream call returns `null` (204/empty body), that side is treated as an empty list rather than\r\n * throwing, matching the inventory's \"never raises ... tolerant of missing keys\" note.\r\n */\r\nexport async function getInProgressBadges(host: BadgesHost): Promise<Badge[]> {\r\n const [earned, available] = await Promise.all([getEarnedBadges(host), getAvailableBadges(host)]);\r\n\r\n const earnedInProgress = (earned ?? []).filter(isBadgeInProgress);\r\n const availableInProgress = (available ?? []).filter(isBadgeInProgress);\r\n\r\n const combined = new Map<number | undefined, Badge>();\r\n for (const badge of earnedInProgress) combined.set(badge.badgeId, badge);\r\n for (const badge of availableInProgress) combined.set(badge.badgeId, badge);\r\n return Array.from(combined.values());\r\n}\r\n\r\n/**\r\n * Upstream `get_adhoc_challenges`: `start` validated non-negative, `limit` validated positive.\r\n * Passes through unchecked — stays nullable. The inventory labels the `returns` column `dict`,\r\n * but the live test account (Task 9 smoke run) returned a JSON array — see the file-level comment\r\n * in `src/types/badges.ts`.\r\n */\r\nexport async function getAdhocChallenges(\r\n host: BadgesHost,\r\n start: number,\r\n limit: number,\r\n): Promise<AdhocChallenge[] | null> {\r\n const validStart = validateNonNegativeInteger(start, \"start\");\r\n const validLimit = validatePositiveInteger(limit, \"limit\");\r\n return host.client.connectapi<AdhocChallenge[]>(\r\n \"/adhocchallenge-service/adHocChallenge/historical\",\r\n { params: { start: validStart, limit: validLimit } },\r\n );\r\n}\r\n\r\n/**\r\n * Upstream `get_badge_challenges`: `start` validated non-negative, `limit` validated positive.\r\n * Passes through unchecked — stays nullable. Live-verified as a JSON array (see\r\n * `src/types/badges.ts`), not the `dict` the inventory's `returns` column names.\r\n */\r\nexport async function getBadgeChallenges(\r\n host: BadgesHost,\r\n start: number,\r\n limit: number,\r\n): Promise<BadgeChallenge[] | null> {\r\n const validStart = validateNonNegativeInteger(start, \"start\");\r\n const validLimit = validatePositiveInteger(limit, \"limit\");\r\n return host.client.connectapi<BadgeChallenge[]>(\r\n \"/badgechallenge-service/badgeChallenge/completed\",\r\n { params: { start: validStart, limit: validLimit } },\r\n );\r\n}\r\n\r\n/**\r\n * Upstream `get_available_badge_challenges`: `start` validated non-negative, `limit` validated\r\n * positive. Passes through unchecked — stays nullable. Live-verified as a JSON array (see\r\n * `src/types/badges.ts`), not the `dict` the inventory's `returns` column names.\r\n */\r\nexport async function getAvailableBadgeChallenges(\r\n host: BadgesHost,\r\n start: number,\r\n limit: number,\r\n): Promise<AvailableBadgeChallenge[] | null> {\r\n const validStart = validateNonNegativeInteger(start, \"start\");\r\n const validLimit = validatePositiveInteger(limit, \"limit\");\r\n return host.client.connectapi<AvailableBadgeChallenge[]>(\r\n \"/badgechallenge-service/badgeChallenge/available\",\r\n { params: { start: validStart, limit: validLimit } },\r\n );\r\n}\r\n\r\n/**\r\n * Upstream `get_non_completed_badge_challenges`: `start` validated non-negative, `limit`\r\n * validated positive. Passes through unchecked — stays nullable. Live-verified as a JSON array\r\n * (see `src/types/badges.ts`), not the `dict` the inventory's `returns` column names.\r\n */\r\nexport async function getNonCompletedBadgeChallenges(\r\n host: BadgesHost,\r\n start: number,\r\n limit: number,\r\n): Promise<NonCompletedBadgeChallenge[] | null> {\r\n const validStart = validateNonNegativeInteger(start, \"start\");\r\n const validLimit = validatePositiveInteger(limit, \"limit\");\r\n return host.client.connectapi<NonCompletedBadgeChallenge[]>(\r\n \"/badgechallenge-service/badgeChallenge/non-completed\",\r\n { params: { start: validStart, limit: validLimit } },\r\n );\r\n}\r\n\r\n/**\r\n * Upstream `get_inprogress_virtual_challenges`. **Asymmetric validation**: unlike the four\r\n * challenge-listing methods above, `start` here is validated as POSITIVE (rejecting `start=0`),\r\n * not merely non-negative — an easy detail to miss when porting a \"generic pagination\" helper.\r\n * `limit` validated positive, same as the others. Passes through unchecked — stays nullable.\r\n * Live-verified as a JSON array (see `src/types/badges.ts`), not the `dict` the inventory's\r\n * `returns` column names.\r\n */\r\nexport async function getInprogressVirtualChallenges(\r\n host: BadgesHost,\r\n start: number,\r\n limit: number,\r\n): Promise<InprogressVirtualChallenge[] | null> {\r\n const validStart = validatePositiveInteger(start, \"start\");\r\n const validLimit = validatePositiveInteger(limit, \"limit\");\r\n return host.client.connectapi<InprogressVirtualChallenge[]>(\r\n \"/badgechallenge-service/virtualChallenge/inProgress\",\r\n { params: { start: validStart, limit: validLimit } },\r\n );\r\n}\r\n","/**\r\n * Minimal FIT-file encoder for a weight-scale record, ported from upstream\r\n * python-garminconnect's `garminconnect/fit.py` (`FitEncoder`,\r\n * `FitEncoderWeight`). `addBodyComposition` (see\r\n * `src/services/bodyComposition.ts`) is the only caller: it builds a tiny\r\n * `.fit` binary in memory (file_id, file_creator, device_info, weight_scale\r\n * messages) and uploads it, exactly like upstream's `add_body_composition`.\r\n *\r\n * UNCERTAIN (inventory, `add_body_composition` row): the inventory flagged\r\n * \"check FitEncoderWeight before assuming raw kg is correct on the wire\" as\r\n * unresolved. Having now read `fit.py` directly (not just the inventory),\r\n * the answer is: `write_weight_scale`'s `weight` field IS scaled — packed as\r\n * `uint16(round(weight_kg * 100))` — but that scaling is a property of the\r\n * FIT binary format's `weight_scale` message (an official Garmin FIT SDK\r\n * field defined in kilograms with an implicit 1/100 resolution), not an\r\n * application-level unit conversion like the one that corrupted `addWeighIn`.\r\n * There is no evidence upstream converts lbs<->kg anywhere in this path;\r\n * `weight` is assumed to already be in kilograms both in `gc.py` and here.\r\n * LIVE-VERIFIED on 2026-09-23 (this note previously said it was not): a\r\n * 69.42 kg upload built by this encoder read back from `getBodyComposition`\r\n * as 69.42 kg. That single round-trip proves two separate things — Garmin\r\n * accepted the bytes, so the header and CRC are correct, and it parsed the\r\n * value correctly, so the x100 scaling is correct. Only the read-back could\r\n * distinguish the second: a wrong scale factor is accepted and misparsed\r\n * silently, where a wrong CRC is rejected outright.\r\n */\r\n\r\nconst CRC_TABLE = [\r\n 0x0000, 0xcc01, 0xd801, 0x1400, 0xf001, 0x3c00, 0x2800, 0xe401, 0xa001, 0x6c00, 0x7800, 0xb401,\r\n 0x5000, 0x9c01, 0x8801, 0x4400,\r\n];\r\n\r\nfunction calcCrc(crc: number, byte: number): number {\r\n let tmp = CRC_TABLE[crc & 0xf]!;\r\n crc = (crc >> 4) & 0x0fff;\r\n crc = crc ^ tmp ^ CRC_TABLE[byte & 0xf]!;\r\n tmp = CRC_TABLE[crc & 0xf]!;\r\n crc = (crc >> 4) & 0x0fff;\r\n return crc ^ tmp ^ CRC_TABLE[(byte >> 4) & 0xf]!;\r\n}\r\n\r\ninterface BaseType {\r\n size: number;\r\n field: number;\r\n invalid: number;\r\n write: (buf: Buffer, offset: number, value: number) => void;\r\n}\r\n\r\nconst ENUM: BaseType = { size: 1, field: 0x00, invalid: 0xff, write: (b, o, v) => b.writeUInt8(v, o) };\r\nconst UINT8: BaseType = { size: 1, field: 0x02, invalid: 0xff, write: (b, o, v) => b.writeUInt8(v, o) };\r\nconst UINT16: BaseType = {\r\n size: 2,\r\n field: 0x84,\r\n invalid: 0xffff,\r\n write: (b, o, v) => b.writeUInt16LE(v, o),\r\n};\r\nconst UINT32: BaseType = {\r\n size: 4,\r\n field: 0x86,\r\n invalid: 0xffffffff,\r\n write: (b, o, v) => b.writeUInt32LE(v >>> 0, o),\r\n};\r\nconst UINT32Z: BaseType = {\r\n size: 4,\r\n field: 0x8c, // uint32z field code\r\n invalid: 0x00000000,\r\n write: (b, o, v) => b.writeUInt32LE(v >>> 0, o),\r\n};\r\n\r\ninterface Field {\r\n num: number;\r\n type: BaseType;\r\n value: number | null | undefined;\r\n scale: number | null;\r\n}\r\n\r\nfunction buildContentBlock(fields: Field[]): { defs: Buffer; values: Buffer } {\r\n const defParts: Buffer[] = [];\r\n const valParts: Buffer[] = [];\r\n for (const f of fields) {\r\n const def = Buffer.alloc(3);\r\n def.writeUInt8(f.num, 0);\r\n def.writeUInt8(f.type.size, 1);\r\n def.writeUInt8(f.type.field, 2);\r\n defParts.push(def);\r\n\r\n const val = Buffer.alloc(f.type.size);\r\n if (f.value === null || f.value === undefined) {\r\n f.type.write(val, 0, f.type.invalid);\r\n } else {\r\n const scaled = f.scale !== null ? f.value * f.scale : f.value;\r\n // Upstream's FitBaseType.pack calls Python's int(value), which\r\n // truncates toward zero — matched here with Math.trunc rather than\r\n // Math.round.\r\n f.type.write(val, 0, Math.trunc(scaled));\r\n }\r\n valParts.push(val);\r\n }\r\n return { defs: Buffer.concat(defParts), values: Buffer.concat(valParts) };\r\n}\r\n\r\n/** Seconds since the FIT epoch (1989-12-31T00:00:00 UTC), matching upstream's `Fit.timestamp`. */\r\nconst FIT_EPOCH_OFFSET_SECONDS = 631065600;\r\n\r\nfunction fitTimestamp(d: Date): number {\r\n return Math.floor(d.getTime() / 1000) - FIT_EPOCH_OFFSET_SECONDS;\r\n}\r\n\r\nconst GMSG_FILE_ID = 0;\r\nconst GMSG_DEVICE_INFO = 23;\r\nconst GMSG_WEIGHT_SCALE = 30;\r\nconst GMSG_FILE_CREATOR = 49;\r\n\r\nconst LMSG_FILE_INFO = 0;\r\nconst LMSG_FILE_CREATOR = 1;\r\nconst LMSG_DEVICE_INFO = 2;\r\nconst LMSG_WEIGHT_SCALE = 3;\r\n\r\nconst FILE_TYPE_WEIGHT = 9;\r\n\r\nexport interface WeightScaleFields {\r\n percentFat?: number;\r\n percentHydration?: number;\r\n visceralFatMass?: number;\r\n boneMass?: number;\r\n muscleMass?: number;\r\n basalMet?: number;\r\n activeMet?: number;\r\n physiqueRating?: number;\r\n metabolicAge?: number;\r\n visceralFatRating?: number;\r\n bmi?: number;\r\n}\r\n\r\nexport class FitEncoderWeight {\r\n #chunks: Buffer[] = [];\r\n #deviceInfoDefined = false;\r\n #weightScaleDefined = false;\r\n\r\n constructor() {\r\n this.#chunks.push(this.#header(0));\r\n }\r\n\r\n #header(dataSize: number): Buffer {\r\n const b = Buffer.alloc(12);\r\n b.writeUInt8(12, 0); // header_size\r\n b.writeUInt8(16, 1); // protocol_version\r\n b.writeUInt16LE(108, 2); // profile_version\r\n b.writeUInt32LE(dataSize, 4);\r\n b.write(\".FIT\", 8, \"ascii\");\r\n return b;\r\n }\r\n\r\n #recordHeader(definition: boolean, lmsgType: number): Buffer {\r\n return Buffer.from([(definition ? 1 << 6 : 0) | lmsgType]);\r\n }\r\n\r\n #emit(lmsgType: number, gmsgNum: number, content: Field[], defined?: { flag: boolean }): void {\r\n const { defs, values } = buildContentBlock(content);\r\n if (!defined || !defined.flag) {\r\n const fixed = Buffer.alloc(5);\r\n fixed.writeUInt8(0, 0); // reserved\r\n fixed.writeUInt8(0, 1); // architecture: little-endian\r\n fixed.writeUInt16LE(gmsgNum, 2);\r\n fixed.writeUInt8(content.length, 4);\r\n this.#chunks.push(this.#recordHeader(true, lmsgType), fixed, defs);\r\n if (defined) defined.flag = true;\r\n }\r\n this.#chunks.push(this.#recordHeader(false, lmsgType), values);\r\n }\r\n\r\n writeFileInfo(timeCreated: Date = new Date()): void {\r\n this.#emit(LMSG_FILE_INFO, GMSG_FILE_ID, [\r\n { num: 3, type: UINT32Z, value: null, scale: null }, // serial_number\r\n { num: 4, type: UINT32, value: fitTimestamp(timeCreated), scale: null },\r\n { num: 1, type: UINT16, value: null, scale: null }, // manufacturer\r\n { num: 2, type: UINT16, value: null, scale: null }, // product\r\n { num: 5, type: UINT16, value: null, scale: null }, // number\r\n { num: 0, type: ENUM, value: FILE_TYPE_WEIGHT, scale: null }, // type\r\n ]);\r\n }\r\n\r\n writeFileCreator(): void {\r\n this.#emit(LMSG_FILE_CREATOR, GMSG_FILE_CREATOR, [\r\n { num: 0, type: UINT16, value: null, scale: null }, // software_version\r\n { num: 1, type: UINT8, value: null, scale: null }, // hardware_version\r\n ]);\r\n }\r\n\r\n writeDeviceInfo(timestamp: Date): void {\r\n const defined = { flag: this.#deviceInfoDefined };\r\n this.#emit(\r\n LMSG_DEVICE_INFO,\r\n GMSG_DEVICE_INFO,\r\n [\r\n { num: 253, type: UINT32, value: fitTimestamp(timestamp), scale: 1 },\r\n { num: 3, type: UINT32Z, value: null, scale: 1 }, // serial_number\r\n { num: 7, type: UINT32, value: null, scale: 1 }, // cum_operating_time\r\n { num: 8, type: UINT32, value: null, scale: null }, // unknown/undocumented field\r\n { num: 2, type: UINT16, value: null, scale: 1 }, // manufacturer\r\n { num: 4, type: UINT16, value: null, scale: 1 }, // product\r\n { num: 5, type: UINT16, value: null, scale: 100 }, // software_version\r\n { num: 10, type: UINT16, value: null, scale: 256 }, // battery_voltage\r\n { num: 0, type: UINT8, value: null, scale: 1 }, // device_index\r\n { num: 1, type: UINT8, value: null, scale: 1 }, // device_type\r\n { num: 6, type: UINT8, value: null, scale: 1 }, // hardware_version\r\n { num: 11, type: UINT8, value: null, scale: null }, // battery_status\r\n ],\r\n defined,\r\n );\r\n this.#deviceInfoDefined = defined.flag;\r\n }\r\n\r\n writeWeightScale(timestamp: Date, weight: number, extra: WeightScaleFields = {}): void {\r\n const defined = { flag: this.#weightScaleDefined };\r\n this.#emit(\r\n LMSG_WEIGHT_SCALE,\r\n GMSG_WEIGHT_SCALE,\r\n [\r\n { num: 253, type: UINT32, value: fitTimestamp(timestamp), scale: 1 },\r\n { num: 0, type: UINT16, value: weight, scale: 100 },\r\n { num: 1, type: UINT16, value: extra.percentFat, scale: 100 },\r\n { num: 2, type: UINT16, value: extra.percentHydration, scale: 100 },\r\n { num: 3, type: UINT16, value: extra.visceralFatMass, scale: 100 },\r\n { num: 4, type: UINT16, value: extra.boneMass, scale: 100 },\r\n { num: 5, type: UINT16, value: extra.muscleMass, scale: 100 },\r\n { num: 7, type: UINT16, value: extra.basalMet, scale: 4 },\r\n { num: 9, type: UINT16, value: extra.activeMet, scale: 4 },\r\n { num: 8, type: UINT8, value: extra.physiqueRating, scale: 1 },\r\n { num: 10, type: UINT8, value: extra.metabolicAge, scale: 1 },\r\n { num: 11, type: UINT8, value: extra.visceralFatRating, scale: 1 },\r\n { num: 13, type: UINT16, value: extra.bmi, scale: 10 },\r\n ],\r\n defined,\r\n );\r\n this.#weightScaleDefined = defined.flag;\r\n }\r\n\r\n #totalSize(): number {\r\n return this.#chunks.reduce((n, c) => n + c.length, 0);\r\n }\r\n\r\n #crc(): Buffer {\r\n let crc = 0;\r\n for (const chunk of this.#chunks) {\r\n for (const byte of chunk) {\r\n crc = calcCrc(crc, byte);\r\n }\r\n }\r\n const out = Buffer.alloc(2);\r\n out.writeUInt16LE(crc, 0);\r\n return out;\r\n }\r\n\r\n finish(): Buffer {\r\n const dataSize = this.#totalSize() - 12;\r\n this.#chunks[0] = this.#header(dataSize);\r\n const crc = this.#crc();\r\n return Buffer.concat([...this.#chunks, crc]);\r\n }\r\n}\r\n","import { GarminError } from \"../errors.js\";\r\nimport type { GarminClient } from \"../client.js\";\r\nimport { formatDate } from \"../util/date.js\";\r\nimport { FitEncoderWeight, type WeightScaleFields } from \"../util/fit.js\";\r\nimport type { BodyCompositionRange } from \"../types/bodyComposition.js\";\r\n\r\nexport interface BodyCompositionHost {\r\n readonly client: GarminClient;\r\n}\r\n\r\nexport async function getBodyComposition(\r\n host: BodyCompositionHost,\r\n startdate: string | Date,\r\n enddate?: string | Date,\r\n): Promise<BodyCompositionRange | null> {\r\n const start = formatDate(startdate);\r\n const end = enddate === undefined ? start : formatDate(enddate);\r\n if (start > end) {\r\n throw new GarminError(\"getBodyComposition: start date must not be after end date\");\r\n }\r\n return host.client.connectapi<BodyCompositionRange>(\"/weight-service/weight/dateRange\", {\r\n params: { startDate: start, endDate: end },\r\n });\r\n}\r\n\r\n/**\r\n * UNCERTAIN (inventory): upstream `add_body_composition` has no null check\r\n * on the multipart-upload response and returns `self.client.post(...)`\r\n * directly; this mirrors that by returning whatever `client.upload` gives\r\n * back unchecked (`null` on a 204/empty body, per this library's `upload`\r\n * contract).\r\n *\r\n * `weight` (and every optional metric) is assumed to already be in the\r\n * units upstream's `gc.py` assumes (kilograms for `weight`, percentages for\r\n * the `percent*` fields, etc.) — `gc.py` itself performs no unit conversion\r\n * before handing values to `FitEncoderWeight`. See `src/util/fit.ts` for the\r\n * scaling `write_weight_scale` DOES apply (a FIT binary-format requirement,\r\n * confirmed by reading upstream's `fit.py` directly — not left as a guess).\r\n * LIVE-VERIFIED end to end on 2026-09-23 (this note previously said it was\r\n * not): 69.42 kg was uploaded as a `.fit` binary and read back from\r\n * `getBodyComposition` as 69.42 kg. Garmin both ACCEPTED the bytes — so the\r\n * CRC and header are right — and PARSED them correctly, so the x100 scaling\r\n * is right. A wrong CRC would have been rejected outright; a wrong scale\r\n * factor would have been accepted and silently misparsed, which only the\r\n * read-back could tell apart.\r\n *\r\n * `timestamp`, if given, is parsed with `new Date(timestamp)`; if omitted,\r\n * `new Date()` is used, matching upstream's `datetime.fromisoformat(timestamp)\r\n * if timestamp else datetime.now()`.\r\n */\r\nexport async function addBodyComposition(\r\n host: BodyCompositionHost,\r\n weight: number,\r\n extra: WeightScaleFields & { timestamp?: string } = {},\r\n): Promise<unknown> {\r\n if (!Number.isFinite(weight) || weight <= 0) {\r\n throw new GarminError(\"weight must be a positive, finite number\");\r\n }\r\n const { timestamp, ...fields } = extra;\r\n const when = timestamp !== undefined ? new Date(timestamp) : new Date();\r\n if (Number.isNaN(when.getTime())) {\r\n throw new GarminError(`invalid timestamp: \"${String(timestamp)}\"`);\r\n }\r\n\r\n const encoder = new FitEncoderWeight();\r\n // No argument, matching upstream's bare `fitEncoder.write_file_info()`.\r\n // `file_id.time_created` is file METADATA — when the .fit was produced —\r\n // and stays at the real current instant even when `when` is backdated.\r\n // Only the health data below carries the caller's timestamp.\r\n encoder.writeFileInfo();\r\n encoder.writeFileCreator();\r\n encoder.writeDeviceInfo(when);\r\n encoder.writeWeightScale(when, weight, fields);\r\n const fitBytes = encoder.finish();\r\n\r\n const file = new Blob([fitBytes], { type: \"application/octet-stream\" });\r\n return host.client.upload(file, \"body_composition.fit\", \"/upload-service/upload\");\r\n}\r\n","import { GarminError } from \"../errors.js\";\nimport type { GarminClient } from \"../client.js\";\nimport { pathSegment } from \"../util/validate.js\";\nimport type {\n Course,\n CourseInput,\n CourseList,\n CoursePrivacy,\n CourseUpdate,\n} from \"../types/courses.js\";\n\n/**\n * Courses — saved tracks you can send to a device and follow.\n *\n * **NOT upstream parity**: python-garminconnect has no course methods. The endpoints come from the\n * `florianpasteur/garmin-connect` JavaScript fork, and every one of them was re-verified here,\n * live, on 2026-09-24 by a create -> read back -> update -> read back -> export -> delete round-trip on the test\n * account (`npm run smoke:gaps`). `deleteCourse` has no counterpart in that fork either.\n *\n * Creating a course is TWO calls. `importCourseGpx` uploads the GPX and gets back the parsed,\n * resampled track WITHOUT saving anything (`courseId: null`); `createCourse` then posts that track\n * as a new course. `createCourseFromGpx` does both.\n *\n * **\"Not yet ready\" (HTTP 429).** Garmin processes a new course in the background, and until that\n * finishes, `PUT` and `DELETE` answer 429 `\"The course [id] is not yet ready to delete or update\"`\n * (a `TooManyRequestsException`, surfaced as `GarminRateLimitError` — it is not rate limiting).\n * For a track on land it clears within seconds: a rename 5s after creation succeeded. For a track\n * in open water it NEVER cleared for updates — a probe course at 0°N 0°E still refused a PUT\n * after five minutes, which is how this was first misread as \"the PUT does not work\". Garmin's\n * own web editor, observed on 2026-09-24, saves with the same full-record PUT this library sends.\n */\nexport interface CoursesHost {\n readonly client: GarminClient;\n}\n\nconst PRIVACY_RULE: Record<CoursePrivacy, number> = { public: 1, private: 2 };\n\nfunction privacyRule(privacy: CoursePrivacy): number {\n const rule = PRIVACY_RULE[privacy];\n if (rule === undefined) {\n throw new GarminError(`Unknown course privacy \"${String(privacy)}\" — expected \"private\" or \"public\"`);\n }\n return rule;\n}\n\n/** `GET /web-gateway/course/owner/`. An envelope: the courses are under `coursesForUser`. */\nexport async function listCourses(host: CoursesHost): Promise<CourseList | null> {\n return host.client.connectapi<CourseList>(\"/web-gateway/course/owner/\");\n}\n\n/** `GET /course-service/course/{courseId}`. A missing id is a 404 (`GarminHttpError`). */\nexport async function getCourse(host: CoursesHost, courseId: number | string): Promise<Course | null> {\n return host.client.connectapi<Course>(`/course-service/course/${pathSegment(courseId)}`);\n}\n\n/**\n * `POST /course-service/course/import` (multipart, field `file`). Parses a GPX file into a course\n * record and saves NOTHING — the result has `courseId: null`. Pass its `geoPoints` and\n * `coursePoints` to `createCourse`, or use `createCourseFromGpx`.\n *\n * The track comes back resampled (13 GPX points became 37) with `elevation` and `timestamp` null,\n * and `courseName` taken from the GPX `<name>`. Only `.gpx` has been verified, so only `.gpx` is\n * accepted.\n */\nexport async function importCourseGpx(\n host: CoursesHost,\n file: Blob,\n filename: string,\n): Promise<Course> {\n if (!filename.toLowerCase().endsWith(\".gpx\")) {\n throw new GarminError(`importCourseGpx expects a .gpx file, got \"${filename}\"`);\n }\n const result = await host.client.upload(file, filename, \"/course-service/course/import\");\n if (!result || typeof result !== \"object\") {\n throw new GarminError(`Garmin returned no parsed course for \"${filename}\"`);\n }\n return result as Course;\n}\n\n/**\n * `POST /course-service/course`. Saves a new course and returns it with its `courseId` and the\n * server-computed `distanceMeter` and elevation totals.\n *\n * The body is the template Garmin's own web client sends; only the name, track, activity type and\n * privacy vary. `activityTypeId` is a Garmin activity-type id (`getActivityTypes()`'s `typeId`),\n * default 1 (running).\n */\nexport async function createCourse(host: CoursesHost, input: CourseInput): Promise<Course | null> {\n if (!input.name.trim()) throw new GarminError(\"createCourse requires a non-empty name\");\n if (input.geoPoints.length < 2) {\n throw new GarminError(\"createCourse requires at least two geoPoints\");\n }\n const body = {\n activityTypePk: input.activityTypeId ?? 1,\n hasTurnDetectionDisabled: false,\n geoPoints: input.geoPoints,\n courseLines: [],\n coursePoints: input.coursePoints ?? [],\n startPoint: input.geoPoints[0],\n elapsedSeconds: null,\n openStreetMap: false,\n coordinateSystem: \"WGS84\",\n rulePK: privacyRule(input.privacy ?? \"private\"),\n courseName: input.name,\n matchedToSegments: false,\n includeLaps: false,\n hasPaceBand: false,\n hasPowerGuide: false,\n favorite: false,\n speedMeterPerSecond: null,\n sourceTypeId: 3,\n };\n return host.client.connectapi<Course>(\"/course-service/course\", { method: \"POST\", json: body });\n}\n\n/**\n * `importCourseGpx` then `createCourse`. The name defaults to the GPX track's own `<name>`, then to\n * the filename without its extension.\n */\nexport async function createCourseFromGpx(\n host: CoursesHost,\n file: Blob,\n filename: string,\n options: Omit<CourseInput, \"geoPoints\" | \"coursePoints\" | \"name\"> & { name?: string } = {},\n): Promise<Course | null> {\n const parsed = await importCourseGpx(host, file, filename);\n const name = options.name ?? parsed.courseName ?? filename.replace(/\\.gpx$/i, \"\");\n return createCourse(host, {\n ...options,\n name,\n geoPoints: parsed.geoPoints,\n coursePoints: parsed.coursePoints,\n });\n}\n\n/**\n * Renames a course and/or changes its privacy.\n *\n * READ-MODIFY-WRITE, like `setGearActivityDefaults`: GETs the current record, overlays the changes,\n * and PUTs the whole record back to `/course-service/course/{courseId}` — the same request Garmin's\n * own web editor sends on Save. Two concurrent callers can clobber each other; every field not\n * named in `changes` is carried over untouched. A just-created course may 429 \"not yet ready\";\n * see the note at the top of this file.\n */\nexport async function updateCourse(\n host: CoursesHost,\n courseId: number | string,\n changes: CourseUpdate,\n): Promise<Course | null> {\n if (changes.name === undefined && changes.privacy === undefined) {\n throw new GarminError(\"updateCourse needs at least one of name or privacy\");\n }\n if (changes.name !== undefined && !changes.name.trim()) {\n throw new GarminError(\"updateCourse cannot set an empty name\");\n }\n const path = `/course-service/course/${pathSegment(courseId)}`;\n const current = await host.client.connectapi<Course>(path);\n if (!current) throw new GarminError(`Cannot update course ${String(courseId)}: Garmin returned nothing`);\n const body: Course = { ...current };\n if (changes.name !== undefined) body.courseName = changes.name;\n if (changes.privacy !== undefined) body.rulePK = privacyRule(changes.privacy);\n return host.client.connectapi<Course>(path, { method: \"PUT\", json: body });\n}\n\n/**\n * `DELETE /course-service/course/{courseId}`. Resolves to `null` on success; a later `getCourse`\n * on the same id is a 404. IRREVERSIBLE.\n *\n * A course created a moment ago may 429 \"not yet ready\"; retry a few seconds later. See the note\n * at the top of this file.\n */\nexport async function deleteCourse(host: CoursesHost, courseId: number | string): Promise<unknown> {\n return host.client.connectapi(`/course-service/course/${pathSegment(courseId)}`, {\n method: \"DELETE\",\n });\n}\n\n/** `GET /course-service/course/gpx/{courseId}` — the course as GPX file bytes. */\nexport async function downloadCourseGpx(host: CoursesHost, courseId: number | string): Promise<Buffer> {\n return host.client.download(`/course-service/course/gpx/${pathSegment(courseId)}`);\n}\n","import { pathSegment } from \"../util/validate.js\";\nimport { GarminConnectionError, GarminError } from \"../errors.js\";\nimport type { GarminClient } from \"../client.js\";\nimport { formatDate } from \"../util/date.js\";\nimport type {\n Device,\n DeviceLastUsed,\n DeviceSettings,\n DeviceSolarDataResponse,\n PrimaryTrainingDevice,\n} from \"../types/devices.js\";\n\n/** Devices, device settings, primary training device, solar data, alarms, last-used. */\nexport interface DevicesHost {\n readonly client: GarminClient;\n}\n\n/**\n * Mirrors upstream's implicit `int(device_id)` coercion + positivity check before the value is\n * re-stringified into the URL path. `Number(...)` (not `parseInt`) is used deliberately so a\n * partially-numeric string like `\"123abc\"` is rejected instead of silently truncated, matching\n * Python's `int(\"123abc\")` raising `ValueError` rather than reading `123`.\n */\nfunction validateDeviceId(deviceId: number | string): string {\n const n = Number(deviceId);\n if (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {\n throw new GarminError(`Invalid device id: \"${String(deviceId)}\"`);\n }\n return String(n);\n}\n\n/**\n * Upstream `get_devices`. `null_behaviour`: passes through unchecked. Undocumented shape — see\n * `Device` in `src/types/devices.ts`.\n */\nexport async function getDevices(host: DevicesHost): Promise<Device[] | null> {\n return host.client.connectapi<Device[]>(\n \"/device-service/deviceregistration/devices\",\n );\n}\n\n/**\n * Upstream `get_device_settings`. `deviceId` is coerced to an int, validated positive, and\n * re-stringified before being placed in the path (see `validateDeviceId`), matching upstream's\n * `_validate_positive_integer(int(device_id), \"device_id\")` in `get_device_settings`. `null_behaviour`: passes through\n * unchecked. Call sequence: obtain `device_id` from a `getDevices()` entry's `deviceId` field\n * first, then pass it here.\n */\nexport async function getDeviceSettings(\n host: DevicesHost,\n deviceId: number | string,\n): Promise<DeviceSettings | null> {\n const id = validateDeviceId(deviceId);\n return host.client.connectapi<DeviceSettings>(\n `/device-service/deviceservice/device-info/settings/${pathSegment(id)}`,\n );\n}\n\n/** Upstream `get_primary_training_device`. `null_behaviour`: passes through unchecked. */\nexport async function getPrimaryTrainingDevice(\n host: DevicesHost,\n): Promise<PrimaryTrainingDevice | null> {\n return host.client.connectapi<PrimaryTrainingDevice>(\n \"/web-gateway/device-info/primary-training-device\",\n );\n}\n\n/**\n * Upstream `get_device_solar_data`. Unlike every other method in this service, this one RAISES\n * (`GarminConnectionError`, mirroring upstream's `GarminConnectConnectionError`) when the response\n * is falsy or missing the `deviceSolarInput` key, and returns `resp[\"deviceSolarInput\"]` — NOT the\n * whole envelope. `enddate` defaults to `startdate`, and `singleDayView` is sent `\"true\"` exactly\n * when `enddate` was omitted (i.e. it tracks omission, not date equality — an explicit\n * `enddate === startdate` still sends `singleDayView=false`, matching upstream). Both dates are\n * routed through `formatDate`.\n *\n * DEVIATION (deliberate): upstream returns `resp[\"deviceSolarInput\"]` raw, so a payload carrying\n * the key with an explicit `null` value passes the `in` check and yields `None`. This returns `[]`\n * in that case, forced by the `Promise<unknown[]>` return type and strictly friendlier to callers.\n * The `in` check (rather than a truthiness test) is upstream's and is kept: a legitimately empty\n * `deviceSolarInput: []` must return `[]`, not raise.\n */\nexport async function getDeviceSolarData(\n host: DevicesHost,\n deviceId: number | string,\n startdate: string | Date,\n enddate?: string | Date,\n): Promise<unknown[]> {\n const id = validateDeviceId(deviceId);\n const start = formatDate(startdate);\n const singleDayView = enddate === undefined;\n const end = singleDayView ? start : formatDate(enddate);\n const resp = await host.client.connectapi<DeviceSolarDataResponse>(\n `/web-gateway/solar/${pathSegment(id)}/${pathSegment(start)}/${pathSegment(end)}`,\n { params: { singleDayView: String(singleDayView) } },\n );\n if (!resp || !(\"deviceSolarInput\" in resp)) {\n throw new GarminConnectionError(\"No device solar input data received\");\n }\n return resp.deviceSolarInput ?? [];\n}\n\n/** Upstream `get_device_last_used`. `null_behaviour`: passes through unchecked. */\nexport async function getDeviceLastUsed(\n host: DevicesHost,\n): Promise<DeviceLastUsed | null> {\n return host.client.connectapi<DeviceLastUsed>(\n \"/device-service/deviceservice/mylastused\",\n );\n}\n\n/**\n * Upstream `get_device_alarms`. No HTTP path of its own: calls `getDevices()` once, then\n * `getDeviceSettings(device.deviceId)` **once per device** (an N+1 fan-out — ported faithfully and\n * sequentially; parallelizing it would be a behavioural change from upstream). Concatenates each\n * device's `alarms` list; a device with no `alarms` (or `null`) contributes nothing, matching\n * upstream's `if device_alarms is not None: alarms += device_alarms`. A device entry missing\n * `deviceId` throws `GarminError` rather than silently skipping, mirroring upstream's implicit\n * `device[\"deviceId\"]` dict access, which would raise `KeyError` in the same situation.\n *\n * DEVIATIONS (deliberate, both strictly more forgiving than upstream): a `null` from `getDevices()`\n * yields `[]` here, where upstream would `TypeError` iterating `None`; and a `null` from\n * `getDeviceSettings()` contributes nothing, where upstream would `AttributeError` calling\n * `.get(\"alarms\")` on `None`. Both are reachable in this port because `connectapi` resolves to\n * `null` on a 204/empty body, a case upstream's client does not surface the same way.\n */\nexport async function getDeviceAlarms(host: DevicesHost): Promise<unknown[]> {\n const devices = await getDevices(host);\n const alarms: unknown[] = [];\n for (const device of devices ?? []) {\n if (device.deviceId === undefined) {\n throw new GarminError(\"getDeviceAlarms: device entry missing deviceId\");\n }\n const settings = await getDeviceSettings(host, device.deviceId);\n const deviceAlarms = settings?.alarms;\n if (deviceAlarms != null) {\n alarms.push(...deviceAlarms);\n }\n }\n return alarms;\n}\n","import { GarminError, GarminHttpError } from \"../errors.js\";\r\nimport type { GarminClient } from \"../client.js\";\r\nimport { formatDate } from \"../util/date.js\";\r\nimport { validateSportKey, validateUuid, pathSegment } from \"../util/validate.js\";\r\nimport type { Gear, GearDefaults, GearStats } from \"../types/gear.js\";\r\n\r\n/**\r\n * This is the dedicated gear-CRUD service (`get_gear`, `create_gear`, `get_gear_stats`,\r\n * `get_gear_defaults`, `set_gear_default`). The activity/gear-*association* surface\r\n * (`getActivityGear`, `getGearActivities`, `addGearToActivity`, `removeGearFromActivity`) lives in\r\n * `src/services/activities.ts` instead — see that file's comments for why.\r\n */\r\nexport interface GearHost {\r\n readonly client: GarminClient;\r\n}\r\n\r\n/**\r\n * Upstream `get_gear`. Reuses the same base URL as `getActivityGear`\r\n * (`/gear-service/gear/filterGear`) with `userProfilePk` instead of `activityId` — see that\r\n * function's comment in `src/services/activities.ts`.\r\n *\r\n * Upstream's own docstring flags a possible deprecation: Garmin's web client calls\r\n * `/gear-service/gear/v2/list`, not this `filterGear` path. Live-verified in Task 7: `filterGear`\r\n * returns 200 with a JSON array (empty before any gear exists, non-empty once it does) — NOT\r\n * deprecated/broken. See the task-7 report for the full evidence.\r\n *\r\n * `null_behaviour`: passes through unchecked (no throw, no coalescing) — but the payload IS an\r\n * array of gear entries, not a single object; `Gear` (see `src/types/gear.ts`) types one entry.\r\n */\r\nexport async function getGear(\r\n host: GearHost,\r\n userProfileNumber: number | string,\r\n): Promise<Gear[] | null> {\r\n return host.client.connectapi<Gear[]>(\"/gear-service/gear/filterGear\", {\r\n params: { userProfilePk: userProfileNumber },\r\n });\r\n}\r\n\r\nfunction convertMaxUsageDistanceKm(km: number): number {\r\n const meters = Math.round(km * 1000);\r\n if (meters < 1) {\r\n throw new GarminError(\r\n `max_usage_distance_km must convert to at least 1 meter, got ${meters}m from ${km}km`,\r\n );\r\n }\r\n return meters;\r\n}\r\n\r\nfunction convertMaxUsageDurationMin(min: number): number {\r\n const seconds = Math.round(min * 60);\r\n if (seconds < 1) {\r\n throw new GarminError(\r\n `max_usage_duration_min must convert to at least 1 second, got ${seconds}s from ${min}min`,\r\n );\r\n }\r\n return seconds;\r\n}\r\n\r\n/**\r\n * Upstream `create_gear`. **Conversions happen here and must be replicated exactly** — the\r\n * OPPOSITE direction from `addWeighIn`'s \"send the raw value\" rule: `maxUsageDistanceKm` is\r\n * converted km -> metres (`round(km * 1000)`, must floor to >= 1), and `maxUsageDurationMin` is\r\n * converted min -> seconds (`round(min * 60)`, must floor to >= 1). Both floors throw\r\n * `GarminError` (mirroring upstream's `ValueError`) rather than silently sending 0.\r\n *\r\n * **BOTH conversions are live-verified**, by create -> read-back round-trip. Distance: 5 km sent\r\n * read back as `getGear`'s `maximumMeters: 5000`. Duration: 90 min sent read back as\r\n * `maxUsageDurationSeconds: 5400` from `/gear-service/gear/v2/{uuid}` — a record no earlier read\r\n * surfaced, which is why this note used to say the duration direction was unverifiable. Neither\r\n * rests on source review alone any more.\r\n *\r\n * `gearType`/`usageType` are normalized upper-case via `validateSportKey`, matching upstream's\r\n * `_validate_sport_key`. `usageType` must be one of `NONE`/`DISTANCE`/`DURATION`/`DATE`, read\r\n * live from `/gear-service/gear/v2/usagetypes` — these were once \"unverified guesses\" here and\r\n * are not any more. Note `\"TIME\"` is NOT valid (400 `Invalid value 'TIME' for usageType`); the\r\n * duration option is spelled `DURATION`.\r\n *\r\n * `activityTypeKeys` entries are sent lower-case (matching `getActivities`' `activitytype`\r\n * convention), which is the opposite case convention from upstream's `set_gear_default` —\r\n * a subtle asymmetry inherited from upstream. That method is not ported here (its endpoint is\r\n * dead); `setGearActivityDefaults` replaces it and also takes lowercase keys.\r\n *\r\n * `firstUseDate` is routed through `formatDate` per this project's date-argument rule, even\r\n * though it is a body field rather than a path/query segment.\r\n *\r\n * UNCERTAIN (inventory): \"no explicit null handling\" on the response — implemented as a\r\n * straightforward pass-through of the raw response. What would resolve it: a live account where\r\n * `create_gear` was observed returning something other than the created gear object.\r\n */\r\nexport async function createGear(\r\n host: GearHost,\r\n gearType: string,\r\n brand: string,\r\n model: string,\r\n name: string,\r\n firstUseDate: string | Date,\r\n usageType = \"DISTANCE\",\r\n maxUsageDistanceKm?: number,\r\n maxUsageDurationMin?: number,\r\n notes = \"\",\r\n activityTypeKeys?: string[],\r\n): Promise<unknown> {\r\n const body: Record<string, unknown> = {\r\n uuid: null,\r\n gearType: validateSportKey(gearType),\r\n brand,\r\n model,\r\n name,\r\n firstUseDate: formatDate(firstUseDate),\r\n maxUsageDate: null,\r\n usageType: validateSportKey(usageType),\r\n notes,\r\n associatedActivityTypes: (activityTypeKeys ?? []).map((activityTypeKey) => ({\r\n activityTypeKey,\r\n defaultGear: true,\r\n preferredGear: false,\r\n })),\r\n };\r\n if (maxUsageDistanceKm !== undefined) {\r\n body[\"maxUsageDistanceMeters\"] = convertMaxUsageDistanceKm(maxUsageDistanceKm);\r\n }\r\n if (maxUsageDurationMin !== undefined) {\r\n body[\"maxUsageDurationSeconds\"] = convertMaxUsageDurationMin(maxUsageDurationMin);\r\n }\r\n return host.client.connectapi(\"/gear-service/gear/v2\", { method: \"POST\", json: body });\r\n}\r\n\r\n/**\r\n * Upstream `get_gear_stats`. On a 404, returns `{}` rather than throwing (matching upstream\r\n * exactly); any other error is re-raised as-is. `gearUUID` is validated via `validateUuid`\r\n * (hex characters, hyphens optional), matching upstream's `_validate_uuid`.\r\n */\r\nexport async function getGearStats(host: GearHost, gearUUID: string): Promise<GearStats> {\r\n const uuid = validateUuid(gearUUID);\r\n try {\r\n const data = await host.client.connectapi<GearStats>(`/gear-service/gear/stats/${pathSegment(uuid)}`);\r\n return data ?? {};\r\n } catch (cause) {\r\n if (cause instanceof GarminHttpError && cause.status === 404) {\r\n return {};\r\n }\r\n throw cause;\r\n }\r\n}\r\n\r\n/**\r\n * Upstream `get_gear_defaults`. `null_behaviour`: passes through unchecked (no throw, no\r\n * coalescing) — the payload is an array of `{uuid, activityTypePk, defaultGear}`-shaped entries\r\n * (live-verified in Task 7, see `GearDefaults` in `src/types/gear.ts`), not a single object.\r\n */\r\nexport async function getGearDefaults(\r\n host: GearHost,\r\n userProfileNumber: number | string,\r\n): Promise<GearDefaults[] | null> {\r\n return host.client.connectapi<GearDefaults[]>(\r\n `/gear-service/gear/user/${pathSegment(userProfileNumber)}/activityTypes`,\r\n );\r\n}\r\n\r\n/**\r\n * `DELETE /gear-service/gear/v2/{gearUUID}` — permanently removes a gear item and its activity\r\n * history. Resolves to `null` on success (Garmin answers 204).\r\n *\r\n * **NOT a port of upstream python-garminconnect** — upstream has no delete-gear method, which is\r\n * why this project spent its entire build documenting gear fixtures as permanent residue. The\r\n * endpoint was found on 2026-09-23 by watching Garmin's own web client delete a gear item\r\n * (`connect.garmin.com/app/gear` -> gear detail -> ⋮ -> Delete), and then verified through this\r\n * client against the test account.\r\n *\r\n * **The UUID must be HYPHENATED.** This is the trap: `getGear` returns `uuid` WITHOUT hyphens\r\n * (`bf86b328b51f...`), and passing that form back here returns 404 — confirmed live, both ways.\r\n * `createGear`'s own response uses the hyphenated form. This function re-inserts the hyphens for\r\n * you when given the 32-character bare form, so either shape works; the 404 only bites callers who\r\n * hand-roll the URL.\r\n *\r\n * IRREVERSIBLE: Garmin's own confirmation dialog warns it \"will permanently remove this gear and\r\n * its activity history\". There is no undo.\r\n */\r\nexport async function deleteGear(host: GearHost, gearUUID: string): Promise<unknown> {\r\n const uuid = validateUuid(gearUUID);\r\n const bare = uuid.replace(/-/g, \"\");\r\n const hyphenated =\r\n bare.length === 32\r\n ? `${bare.slice(0, 8)}-${bare.slice(8, 12)}-${bare.slice(12, 16)}-${bare.slice(16, 20)}-${bare.slice(20)}`\r\n : uuid;\r\n return host.client.connectapi(`/gear-service/gear/v2/${pathSegment(hyphenated)}`, {\r\n method: \"DELETE\",\r\n });\r\n}\r\n\r\n/**\r\n * Sets which activity types this gear is the default for — the **replacement for upstream's\r\n * `set_gear_default`**, whose endpoint is dead and which this port removed on 2026-09-24.\r\n *\r\n * **NOT upstream parity.** Upstream's\r\n * `PUT /gear-service/gear/{uuid}/activityType/{TYPE}/default/true` 404s on every activityType\r\n * spelling, against fresh gear and real gear alike — four investigations failed to make it work,\r\n * the last decisively: gear created WITH `activityTypeKeys`, linked to an activity, and defaulted\r\n * through THIS function, all succeeded against the same UUID seconds before that endpoint again\r\n * reported \"gear not found\". Watching Garmin's own client save the \"Activities for This Gear\" field showed why: the\r\n * modern mechanism is not a dedicated endpoint at all, but a full-record\r\n * `PUT /gear-service/gear/v2/{uuid}` carrying `associatedActivityTypes` — the same array shape\r\n * `createGear` already posts.\r\n *\r\n * `activityTypeKeys` are LOWERCASE (`\"running\"`, `\"cycling\"`), matching `createGear`'s convention —\r\n * NOT the upper-cased form upstream's `set_gear_default` sent through `validateSportKey`. That\r\n * asymmetry is upstream's, and it is one plausible reason the old endpoint never matched.\r\n *\r\n * READ-MODIFY-WRITE: this GETs the current gear record, swaps `associatedActivityTypes` wholesale,\r\n * and PUTs the whole record back. Two concurrent callers can clobber each other, and any field\r\n * Garmin adds to the record travels along untouched. Passing `[]` clears all defaults.\r\n *\r\n * Verified live 2026-09-23: setting `[\"running\", \"cycling\"]` was read back from both\r\n * `/gear-service/gear/v2/{uuid}` and this port's own `getGearDefaults` (which reported\r\n * `activityTypePk` 1 and 2).\r\n */\r\nexport async function setGearActivityDefaults(\r\n host: GearHost,\r\n gearUUID: string,\r\n activityTypeKeys: string[],\r\n): Promise<unknown> {\r\n const uuid = validateUuid(gearUUID);\r\n const path = `/gear-service/gear/v2/${pathSegment(uuid)}`;\r\n const current = await host.client.connectapi<Record<string, unknown>>(path);\r\n if (!current) {\r\n throw new GarminError(`Cannot set gear defaults: no gear found for UUID ${gearUUID}`);\r\n }\r\n const body = {\r\n ...current,\r\n associatedActivityTypes: activityTypeKeys.map((activityTypeKey) => ({\r\n activityTypeKey,\r\n defaultGear: true,\r\n preferredGear: false,\r\n })),\r\n };\r\n return host.client.connectapi(path, { method: \"PUT\", json: body });\r\n}\r\n","import { GarminError } from \"../errors.js\";\nimport type { GarminClient } from \"../client.js\";\nimport { validateNonNegativeInteger, validatePositiveInteger } from \"../util/validate.js\";\nimport type { Goal, GoalStatus } from \"../types/goals.js\";\n\nexport interface GoalsHost {\n readonly client: GarminClient;\n}\n\n/** Matches upstream's `MAX_PAGINATED_REQUESTS` safety cap (same value used by `getActivitiesByDate`). */\nconst MAX_PAGINATED_REQUESTS = 2000;\n\nconst VALID_STATUSES: readonly GoalStatus[] = [\"active\", \"future\", \"past\"];\n\n/**\n * Upstream `get_goals`. `status` must be one of `active`/`future`/`past` or this throws\n * `GarminError` before any request (mirroring upstream's `ValueError`).\n *\n * **Paginated, same fixed-page-size pattern as `getActivitiesByDate`** (see\n * `src/services/activities.ts`): starting from the caller's `start`, it fetches pages of `limit`\n * entries, incrementing `start` by `limit` each call, until a page comes back empty/falsy (the\n * normal end of data) or `MAX_PAGINATED_REQUESTS` pages have been fetched without ever seeing one\n * — the latter throws `GarminError` (mirroring upstream's `GarminConnectConnectionError`), matching\n * `getActivitiesByDate`'s abort-with-error safety cap.\n *\n * **`Sec-Fetch-Site: same-origin` is LOAD-BEARING and sent on every request.** Without it,\n * `goal-service` silently returns `[]` for newer custom accumulation-goal types (upstream cites\n * issue #431) — no error, no 404, just wrong (empty) data. Do not drop this header.\n *\n * **`start` DEFAULTS TO 1, NOT 0 — a deliberate divergence from upstream, because `goal-service`\n * is 1-INDEXED and `start=0` silently returns an EMPTY ARRAY.** Verified live on an account holding\n * exactly one active goal: `start=0` -> `[]`, `start=1` -> `[goal]`. Upstream defaults to `0`, so\n * `get_goals()` there returns nothing on an account that has goals — no error, no warning, just an\n * empty list, which is indistinguishable from \"you have no goals\".\n *\n * This quirk is specific to `goal-service`. The same probe confirmed `activitylist-service`'s\n * activity search and `workout-service/workouts` both return identical results at `start=0` and\n * `start=1`, so their 0-based defaults are correct and were left alone. `start=0` is still ACCEPTED\n * here — it is a legal argument, it just returns nothing, exactly as Garmin behaves.\n *\n * `start` is validated non-negative and `limit` positive, matching upstream's\n * `_validate_non_negative_integer`/`_validate_positive_integer` calls and the identical guards\n * `getAdhocChallenges`/`getBadgeChallenges` already use. `limit` in particular MUST be rejected at\n * zero: `start` advances by `limit` each page, so `limit = 0` never advances and would issue 2000\n * identical live requests before the safety cap fired.\n */\nexport async function getGoals(\n host: GoalsHost,\n status: GoalStatus = \"active\",\n start = 1,\n limit = 30,\n): Promise<Goal[]> {\n if (!VALID_STATUSES.includes(status)) {\n throw new GarminError(\n `Invalid goal status \"${status}\" — must be one of ${VALID_STATUSES.join(\", \")}`,\n );\n }\n const validStart = validateNonNegativeInteger(start, \"start\");\n const validLimit = validatePositiveInteger(limit, \"limit\");\n\n const results: Goal[] = [];\n let currentStart = validStart;\n let sawEmptyPage = false;\n\n for (let page = 0; page < MAX_PAGINATED_REQUESTS; page++) {\n const batch = await host.client.connectapi<Goal[]>(\"/goal-service/goal/goals\", {\n params: { status, start: currentStart, limit: validLimit, sortOrder: \"asc\" },\n headers: { \"Sec-Fetch-Site\": \"same-origin\" },\n });\n if (!batch || batch.length === 0) {\n sawEmptyPage = true;\n break;\n }\n results.push(...batch);\n currentStart += validLimit;\n }\n\n if (!sawEmptyPage) {\n throw new GarminError(`Pagination exceeded ${MAX_PAGINATED_REQUESTS} requests; aborting`);\n }\n return results;\n}\n","import { GarminError } from \"../errors.js\";\nimport type { GarminClient } from \"../client.js\";\nimport { validateNonNegativeInteger, validatePositiveInteger, pathSegment } from \"../util/validate.js\";\nimport type {\n GolfClubStats,\n GolfScorecardDetail,\n GolfScorecardSummary,\n GolfShotData,\n GolfUserStats,\n} from \"../types/golf.js\";\n\n/** Golf: scorecard summaries/details, shot data, club stats, handicap/strokes-gained overview. */\nexport interface GolfHost {\n readonly client: GarminClient;\n}\n\n/**\n * Upstream `get_golf_summary`. `null_behaviour`: passes through unchecked. Query params are\n * literally hyphenated (`per-page`, not `perPage`) — this is Garmin's own param naming, not a\n * typo.\n *\n * The inventory's `returns` column says \"list\"; live-verified WRONG on the test account, which\n * returned a single pagination-envelope OBJECT (`{pageNumber, rowsPerPage, totalRows}`), not an\n * array — see `GolfScorecardSummary` in `src/types/golf.ts`.\n */\nexport async function getGolfSummary(\n host: GolfHost,\n start = 0,\n limit = 100,\n): Promise<GolfScorecardSummary | null> {\n validateNonNegativeInteger(start, \"start\");\n validatePositiveInteger(limit, \"limit\");\n return host.client.connectapi<GolfScorecardSummary>(\n \"/gcs-golfcommunity/api/v2/scorecard/summary\",\n { params: { \"per-page\": limit, start } },\n );\n}\n\n/**\n * Upstream `get_golf_scorecard`. `null_behaviour`: passes through unchecked. Both query params\n * are literally hyphenated: `scorecard-ids` and `include-longest-shot-distance` (sent as the\n * literal string `\"true\"`, matching upstream, not a JSON boolean).\n */\nexport async function getGolfScorecard(\n host: GolfHost,\n scorecardId: number | string,\n): Promise<GolfScorecardDetail | null> {\n return host.client.connectapi<GolfScorecardDetail>(\n \"/gcs-golfcommunity/api/v2/scorecard/detail\",\n {\n params: {\n \"scorecard-ids\": String(scorecardId),\n \"include-longest-shot-distance\": \"true\",\n },\n },\n );\n}\n\nconst HOLE_NUMBER_RE = /^\\d+$/;\nconst MIN_HOLE = 1;\nconst MAX_HOLE = 18;\n\n/**\n * Mirrors upstream `_validate_hole_numbers`: strips spaces, accepts commas or hyphens as\n * separators between individual hole numbers, then re-joins with `-` (\"Garmin's API only accepts\n * '-'\"). Returns `undefined` (not the normalized string) when any requested hole number is >9,\n * because Garmin's endpoint silently drops double-digit hole numbers from a filtered query —\n * upstream logs a warning and requests all 18 holes unfiltered in that case; this port drops the\n * filter the same way and lets the caller's own logging (if any) note it, rather than adding a\n * console.warn a library shouldn't own.\n *\n * Every token must be a hole in 1-18, matching upstream's\n * `HOLE_NUMBERS_REGEX = ^([1-9]|1[0-8])([,-]([1-9]|1[0-8]))*$`. The range check runs BEFORE the\n * >9 drop-filter, and the ordering is load-bearing: without it, a typo like `\"19\"` or `\"100\"` would\n * fall into the >9 branch and silently fetch ALL EIGHTEEN holes instead of raising. A caller's\n * mistake must fail loudly, not quietly widen the query's scope.\n */\nfunction normalizeHoleNumbers(holeNumbers: string): string | undefined {\n const stripped = holeNumbers.replace(/\\s+/g, \"\");\n if (stripped.length === 0) {\n throw new GarminError(`Invalid hole_numbers: \"${holeNumbers}\"`);\n }\n const tokens = stripped.split(/[,-]/);\n const numbers = tokens.map((token) => {\n if (!HOLE_NUMBER_RE.test(token)) {\n throw new GarminError(`Invalid hole_numbers: \"${holeNumbers}\"`);\n }\n const n = Number(token);\n if (n < MIN_HOLE || n > MAX_HOLE) {\n throw new GarminError(\n `Invalid hole_numbers: \"${holeNumbers}\" — holes must be ${MIN_HOLE}-${MAX_HOLE}, got ${n}`,\n );\n }\n return n;\n });\n if (numbers.some((n) => n > 9)) {\n return undefined;\n }\n return numbers.join(\"-\");\n}\n\n/**\n * Upstream `get_golf_shot_data`. `null_behaviour`: passes through unchecked. `holeNumbers` is\n * normalized via `normalizeHoleNumbers`: commas/hyphens accepted as input separators, spaces\n * stripped, re-joined with `-`. **Special case**: if any requested hole number is >9 (10-18), the\n * filter is silently dropped and all 18 holes are fetched instead (Garmin's endpoint drops\n * double-digit hole numbers from a filtered query) — matching upstream's behaviour, minus its\n * warning log. Upstream passes a raw pre-formatted query string (`\"hole-numbers={value}\"`)\n * straight to its HTTP client rather than a params dict; this port sends the equivalent\n * `{ \"hole-numbers\": value }` params entry, which composes into an identical query string via\n * this client's `URLSearchParams`-based query builder.\n */\nexport async function getGolfShotData(\n host: GolfHost,\n scorecardId: number | string,\n holeNumbers?: string,\n): Promise<GolfShotData | null> {\n const normalized = holeNumbers === undefined ? undefined : normalizeHoleNumbers(holeNumbers);\n return host.client.connectapi<GolfShotData>(\n `/gcs-golfcommunity/api/v2/shot/scorecard/${pathSegment(scorecardId)}/hole`,\n normalized === undefined ? {} : { params: { \"hole-numbers\": normalized } },\n );\n}\n\n/**\n * Upstream `get_golf_club_stats`. `null_behaviour`: passes through unchecked. Query params are\n * literally hyphenated (`per-page`) with `include-stats` sent as the literal string `\"true\"`.\n *\n * The inventory's `returns` column says \"dict\"; live-verified WRONG on the test account, which\n * returned a JSON ARRAY of 17 club entries — see `GolfClubStats` in `src/types/golf.ts`.\n */\nexport async function getGolfClubStats(\n host: GolfHost,\n limit = 1000,\n): Promise<GolfClubStats[] | null> {\n validatePositiveInteger(limit, \"limit\");\n return host.client.connectapi<GolfClubStats[]>(\"/gcs-golfcommunity/api/v2/club/player\", {\n params: { \"per-page\": limit, \"include-stats\": \"true\" },\n });\n}\n\n/**\n * Upstream `get_golf_user_stats`. Handicap and strokes-gained overview. `null_behaviour`: passes\n * through unchecked. No parameters.\n */\nexport async function getGolfUserStats(host: GolfHost): Promise<GolfUserStats | null> {\n return host.client.connectapi<GolfUserStats>(\"/gcs-golfcommunity/api/v2/player/stats\");\n}\n","import { GarminError } from \"../errors.js\";\nimport type { GarminClient } from \"../client.js\";\nimport { formatDate } from \"../util/date.js\";\nimport { validateSportKey, pathSegment } from \"../util/validate.js\";\nimport type {\n CyclingFtpResult,\n EnduranceScoreResult,\n FitnessAgeResult,\n FtpRangeResult,\n HeartRateZoneEntry,\n HillScoreResult,\n LactateThresholdLatest,\n LactateThresholdRange,\n MaxMetricsResult,\n PowerZoneEntry,\n PowerZonesForSportResult,\n RacePredictionsResult,\n RunningToleranceEntry,\n TrainingReadinessEntry,\n TrainingStatusResult,\n} from \"../types/metrics.js\";\n\n/** Implemented against a host exposing `client` and `displayName()` (race predictions interpolates it). */\nexport interface MetricsHost {\n readonly client: GarminClient;\n displayName(): Promise<string>;\n}\n\nconst MS_PER_DAY = 86_400_000;\n\nfunction toUtcMidnight(dateStr: string): Date {\n return new Date(`${dateStr}T00:00:00Z`);\n}\n\n/** Exact day count between two `YYYY-MM-DD` strings (end minus start). */\nfunction daysBetween(startStr: string, endStr: string): number {\n return Math.round((toUtcMidnight(endStr).getTime() - toUtcMidnight(startStr).getTime()) / MS_PER_DAY);\n}\n\nconst FTP_AGGREGATIONS = new Set([\"daily\", \"weekly\", \"monthly\", \"yearly\"]);\n\nfunction validateFtpAggregation(aggregation: string): string {\n if (!FTP_AGGREGATIONS.has(aggregation)) {\n throw new GarminError(\n `aggregation must be one of daily, weekly, monthly, yearly; got \"${aggregation}\"`,\n );\n }\n return aggregation;\n}\n\n/** Note the date is repeated twice in the path (start=end=cdate), per upstream. */\nexport async function getMaxMetrics(\n host: MetricsHost,\n cdate: string | Date,\n): Promise<MaxMetricsResult | null> {\n const date = formatDate(cdate);\n return host.client.connectapi<MaxMetricsResult>(\n `/metrics-service/metrics/maxmet/daily/${pathSegment(date)}/${pathSegment(date)}`,\n );\n}\n\n/** Upstream's `_validate_date_range` also enforces `start <= end`. */\nexport async function getMaxMetricsRange(\n host: MetricsHost,\n start: string | Date,\n end: string | Date,\n): Promise<MaxMetricsResult | null> {\n const startDate = formatDate(start);\n const endDate = formatDate(end);\n if (startDate > endDate) {\n throw new GarminError(\"getMaxMetricsRange: start date must not be after end date\");\n }\n return host.client.connectapi<MaxMetricsResult>(\n `/metrics-service/metrics/maxmet/daily/${pathSegment(startDate)}/${pathSegment(endDate)}`,\n );\n}\n\n/**\n * Undocumented endpoint used because `getCyclingFtp` only returns the\n * latest value. `sport` is normalized via `validateSportKey`; `aggregation`\n * must be one of `daily`/`weekly`/`monthly`/`yearly`.\n */\nexport async function getFunctionalThresholdPowerRange(\n host: MetricsHost,\n start: string | Date,\n end: string | Date,\n sport = \"RUNNING\",\n aggregation = \"daily\",\n): Promise<FtpRangeResult | null> {\n const startDate = formatDate(start);\n const endDate = formatDate(end);\n const normalizedSport = validateSportKey(sport);\n const validatedAggregation = validateFtpAggregation(aggregation);\n return host.client.connectapi<FtpRangeResult>(\n `/biometric-service/stats/functionalThresholdPower/range/${pathSegment(startDate)}/${pathSegment(endDate)}`,\n { params: { sport: normalizedSport, aggregation: validatedAggregation, aggregationStrategy: \"LATEST\" } },\n );\n}\n\n/**\n * **Two distinct call shapes per branch, both implemented — this is the\n * defining branching method in this service, per the inventory.**\n *\n * `latest=true` (default): fires two GETs —\n * `/biometric-service/biometric/latestLactateThreshold` (an iterable of\n * speed/heart-rate entries, merged into one dict — falling back\n * `heartRate ?? hearRate`, Garmin's own historical typo) and\n * `/biometric-service/biometric/powerToWeight/latest/{today}` with the\n * LITERAL param `sport: \"Running\"` (mixed case — deliberately NOT run\n * through `validateSportKey`, because upstream sends this exact literal,\n * distinct from the range branch's fully-uppercase `\"RUNNING\"`). Upstream\n * has no null-guard before iterating `speed_and_heart_rate`: if that\n * endpoint returns nothing, upstream's `for` raises `TypeError`, mirrored\n * here by not guarding before the `for...of` (iterating `null`/`undefined`\n * throws the JS equivalent).\n *\n * `latest=false`: requires `startDate` (throws if omitted); `endDate`\n * defaults to today. Fires\n * `/biometric-service/stats/lactateThresholdSpeed/range/{start}/{end}` and\n * `.../lactateThresholdHeartRate/range/{start}/{end}` with\n * `sport: \"RUNNING\"` (validated/uppercase) + `aggregation` +\n * `aggregationStrategy: \"LATEST\"`, plus a `getFunctionalThresholdPowerRange`\n * call for `power`.\n */\nexport async function getLactateThreshold(\n host: MetricsHost,\n latest = true,\n startDate?: string | Date,\n endDate?: string | Date,\n aggregation = \"daily\",\n): Promise<LactateThresholdLatest | LactateThresholdRange> {\n if (latest) {\n const today = formatDate(new Date());\n const [speedAndHeartRateRaw, powerRaw] = await Promise.all([\n host.client.connectapi<unknown>(\"/biometric-service/biometric/latestLactateThreshold\"),\n host.client.connectapi<unknown>(\n `/biometric-service/biometric/powerToWeight/latest/${pathSegment(today)}`,\n { params: { sport: \"Running\" } },\n ),\n ]);\n const power: Record<string, unknown> = Array.isArray(powerRaw)\n ? ((powerRaw[0] as Record<string, unknown> | undefined) ?? {})\n : powerRaw && typeof powerRaw === \"object\"\n ? (powerRaw as Record<string, unknown>)\n : {};\n const merged: Record<string, unknown> = {};\n for (const entry of speedAndHeartRateRaw as Iterable<unknown>) {\n const record = entry as Record<string, unknown>;\n for (const [key, value] of Object.entries(record)) {\n if (key === \"heartRate\" || key === \"hearRate\") continue;\n merged[key] = value;\n }\n const heartRate = record.heartRate ?? record.hearRate;\n if (heartRate !== undefined) merged.heartRate = heartRate;\n }\n return { speed_and_heart_rate: merged, power };\n }\n\n if (startDate === undefined) {\n throw new GarminError(\"getLactateThreshold: startDate is required when latest is false\");\n }\n const start = formatDate(startDate);\n const end = endDate === undefined ? formatDate(new Date()) : formatDate(endDate);\n const validatedAggregation = validateFtpAggregation(aggregation);\n const params = { sport: \"RUNNING\", aggregation: validatedAggregation, aggregationStrategy: \"LATEST\" };\n const [speed, heartRate, power] = await Promise.all([\n host.client.connectapi<unknown>(\n `/biometric-service/stats/lactateThresholdSpeed/range/${pathSegment(start)}/${pathSegment(end)}`,\n { params },\n ),\n host.client.connectapi<unknown>(\n `/biometric-service/stats/lactateThresholdHeartRate/range/${pathSegment(start)}/${pathSegment(end)}`,\n { params },\n ),\n getFunctionalThresholdPowerRange(host, start, end, \"RUNNING\", validatedAggregation),\n ]);\n return { speed, heart_rate: heartRate, power };\n}\n\nexport async function getTrainingReadiness(\n host: MetricsHost,\n cdate: string | Date,\n): Promise<TrainingReadinessEntry[] | null> {\n return host.client.connectapi<TrainingReadinessEntry[]>(\n `/metrics-service/metrics/trainingreadiness/${pathSegment(formatDate(cdate))}`,\n );\n}\n\n/**\n * Delegates to `getTrainingReadiness` — no HTTP call of its own. Returns\n * `null` if the underlying result is falsy, including an EMPTY array (which\n * is falsy in Python but truthy in JS — the empty-array case is checked\n * explicitly to match). Filters for `inputContext === \"AFTER_WAKEUP_RESET\"`,\n * falling back to the first entry if no such entry exists (not all firmware\n * populates `inputContext`). Defensively returns a non-array result as-is,\n * matching upstream's defensive dict handling even though the real endpoint\n * returns a list.\n */\nexport async function getMorningTrainingReadiness(\n host: MetricsHost,\n cdate: string | Date,\n): Promise<TrainingReadinessEntry | null> {\n const data = (await getTrainingReadiness(host, cdate)) as unknown;\n if (!data || (Array.isArray(data) && data.length === 0)) return null;\n if (!Array.isArray(data)) return data as TrainingReadinessEntry;\n const list = data as TrainingReadinessEntry[];\n const match = list.find((entry) => entry.inputContext === \"AFTER_WAKEUP_RESET\");\n return match ?? list[0] ?? null;\n}\n\n/**\n * Two branches by presence of `enddate`. Single day hits\n * `/metrics-service/metrics/endurancescore` with `calendarDate`; a range\n * hits `.../endurancescore/stats` with a hard-coded `aggregation=\"weekly\"`\n * (NOT configurable — contrast with `getHillScore`'s range branch, which\n * hard-codes `\"daily\"`; do not conflate the two).\n */\nexport async function getEnduranceScore(\n host: MetricsHost,\n startdate: string | Date,\n enddate?: string | Date,\n): Promise<EnduranceScoreResult | null> {\n const start = formatDate(startdate);\n if (enddate === undefined) {\n return host.client.connectapi<EnduranceScoreResult>(\n \"/metrics-service/metrics/endurancescore\",\n { params: { calendarDate: start } },\n );\n }\n const end = formatDate(enddate);\n return host.client.connectapi<EnduranceScoreResult>(\n \"/metrics-service/metrics/endurancescore/stats\",\n { params: { startDate: start, endDate: end, aggregation: \"weekly\" } },\n );\n}\n\nconst RUNNING_TOLERANCE_AGGREGATIONS = new Set([\"daily\", \"weekly\"]);\n\n/** `aggregation` is restricted to `{daily, weekly}` — narrower than the FTP/lactate methods. */\nexport async function getRunningTolerance(\n host: MetricsHost,\n startdate: string | Date,\n enddate: string | Date,\n aggregation = \"weekly\",\n): Promise<RunningToleranceEntry[] | null> {\n if (!RUNNING_TOLERANCE_AGGREGATIONS.has(aggregation)) {\n throw new GarminError(`aggregation must be one of daily, weekly; got \"${aggregation}\"`);\n }\n const start = formatDate(startdate);\n const end = formatDate(enddate);\n return host.client.connectapi<RunningToleranceEntry[]>(\n \"/metrics-service/metrics/runningtolerance/stats\",\n { params: { startDate: start, endDate: end, aggregation } },\n );\n}\n\n/**\n * Two branches, all-or-nothing params: with none of `startdate`/`enddate`/\n * `type` supplied, hits `/metrics-service/metrics/racepredictions/latest/{displayName}`.\n * With all three supplied, hits `/metrics-service/metrics/racepredictions/{type}/{displayName}`\n * with `fromCalendarDate`/`toCalendarDate`. Any partial combination throws.\n * `type` must be `\"daily\"` or `\"monthly\"`. The range branch also enforces\n * `(enddate - startdate) <= 366` days (a negative span, i.e. `enddate` before\n * `startdate`, is NOT rejected here — mirroring upstream's literal\n * `(enddate - startdate).days <= 366` check, which a negative delta already\n * satisfies).\n */\nexport async function getRacePredictions(\n host: MetricsHost,\n startdate?: string | Date,\n enddate?: string | Date,\n type?: \"daily\" | \"monthly\",\n): Promise<RacePredictionsResult | null> {\n const provided = [startdate, enddate, type].filter((v) => v !== undefined).length;\n if (provided !== 0 && provided !== 3) {\n throw new GarminError(\n \"getRacePredictions: you must either provide all parameters or no parameters\",\n );\n }\n if (provided === 0) {\n return host.client.connectapi<RacePredictionsResult>(\n `/metrics-service/metrics/racepredictions/latest/${pathSegment(await host.displayName())}`,\n );\n }\n if (type !== \"daily\" && type !== \"monthly\") {\n throw new GarminError('getRacePredictions: type must be \"daily\" or \"monthly\"');\n }\n const start = formatDate(startdate as string | Date);\n const end = formatDate(enddate as string | Date);\n if (daysBetween(start, end) > 366) {\n throw new GarminError(\"getRacePredictions: date range must not exceed 366 days\");\n }\n return host.client.connectapi<RacePredictionsResult>(\n `/metrics-service/metrics/racepredictions/${pathSegment(type)}/${pathSegment(await host.displayName())}`,\n { params: { fromCalendarDate: start, toCalendarDate: end } },\n );\n}\n\nexport async function getTrainingStatus(\n host: MetricsHost,\n cdate: string | Date,\n): Promise<TrainingStatusResult | null> {\n return host.client.connectapi<TrainingStatusResult>(\n `/metrics-service/metrics/trainingstatus/aggregated/${pathSegment(formatDate(cdate))}`,\n );\n}\n\nexport async function getFitnessAgeData(\n host: MetricsHost,\n cdate: string | Date,\n): Promise<FitnessAgeResult | null> {\n return host.client.connectapi<FitnessAgeResult>(`/fitnessage-service/fitnessage/${pathSegment(formatDate(cdate))}`);\n}\n\n/**\n * Two branches by presence of `enddate`, same shape as `getEnduranceScore`\n * but with the OPPOSITE hard-coded range aggregation: `\"daily\"`, not\n * `\"weekly\"` — do not conflate the two.\n */\nexport async function getHillScore(\n host: MetricsHost,\n startdate: string | Date,\n enddate?: string | Date,\n): Promise<HillScoreResult | null> {\n const start = formatDate(startdate);\n if (enddate === undefined) {\n return host.client.connectapi<HillScoreResult>(\n \"/metrics-service/metrics/hillscore\",\n { params: { calendarDate: start } },\n );\n }\n const end = formatDate(enddate);\n return host.client.connectapi<HillScoreResult>(\n \"/metrics-service/metrics/hillscore/stats\",\n { params: { startDate: start, endDate: end, aggregation: \"daily\" } },\n );\n}\n\n/** Returns only the latest value; use `getFunctionalThresholdPowerRange` for history. */\nexport async function getCyclingFtp(host: MetricsHost): Promise<CyclingFtpResult | null> {\n return host.client.connectapi<CyclingFtpResult>(\n \"/biometric-service/biometric/latestFunctionalThresholdPower/CYCLING\",\n );\n}\n\n/** Configured HR zones for all sport profiles. */\nexport async function getHeartRateZones(host: MetricsHost): Promise<HeartRateZoneEntry[] | null> {\n return host.client.connectapi<HeartRateZoneEntry[]>(\"/biometric-service/heartRateZones\");\n}\n\nexport async function getPowerZones(host: MetricsHost): Promise<PowerZoneEntry[] | null> {\n return host.client.connectapi<PowerZoneEntry[]>(\"/biometric-service/powerZones/sports/all\");\n}\n\nexport async function getPowerZonesForSport(\n host: MetricsHost,\n sport: string,\n): Promise<PowerZonesForSportResult | null> {\n const normalized = validateSportKey(sport);\n return host.client.connectapi<PowerZonesForSportResult>(\n `/biometric-service/powerZones/sport/${pathSegment(normalized)}`,\n );\n}\n","import { pathSegment } from \"../util/validate.js\";\nimport type { GarminClient } from \"../client.js\";\nimport { formatDate } from \"../util/date.js\";\nimport type { GraphqlResult, LifestyleLoggingData, ReloadRequestResult } from \"../types/misc.js\";\n\n/**\n * The `misc` inventory section: lifestyle-logging data, the \"request a reload\" write, the raw\n * GraphQL gateway passthrough, and `logout`. `logout` is the only member with no HTTP call.\n */\nexport interface MiscHost {\n readonly client: GarminClient;\n}\n\n/**\n * Upstream `get_lifestyle_logging_data`. `null_behaviour`: passes through unchecked.\n */\nexport async function getLifestyleLoggingData(\n host: MiscHost,\n cdate: string | Date,\n): Promise<LifestyleLoggingData | null> {\n return host.client.connectapi<LifestyleLoggingData>(\n `/lifestylelogging-service/dailyLog/${pathSegment(formatDate(cdate))}`,\n );\n}\n\n/**\n * Upstream `request_reload`. A WRITE: asks Garmin to reload/recompute a day's data (Garmin\n * offloads older data, so this is how a caller forces it back). Sent with no JSON body, matching\n * upstream's `client.post(url)` call with no `json=` kwarg.\n *\n * UNCERTAIN upstream null handling (inventory row is explicitly marked UNCERTAIN — `client.post`\n * has no explicit null-guard on the response in `gc.py`): implemented as a straightforward\n * pass-through, matching this project's standing rule for UNCERTAIN rows. Resolving this for real\n * would mean reading Garmin's actual response body for a reload request, which was out of scope\n * here per the task's SAFETY section (do not execute this against the live account without the\n * controller's explicit go-ahead).\n */\nexport async function requestReload(\n host: MiscHost,\n cdate: string | Date,\n): Promise<ReloadRequestResult | null> {\n return host.client.connectapi<ReloadRequestResult>(\n `/wellness-service/wellness/epoch/request/${pathSegment(formatDate(cdate))}`,\n { method: \"POST\" },\n );\n}\n\n/**\n * Upstream `query_garmin_graphql`. Pure passthrough to Garmin's GraphQL gateway; `query` is sent\n * to Garmin verbatim, matching upstream's raw `{\"query\": \"...\", \"variables\": {...}}` body.\n *\n * **The composed URL is the highest-risk part of this method.** Upstream's own endpoint constant\n * is `\"graphql-gateway/graphql\"` — no leading slash, unlike every other constant in `gc.py`.\n * Upstream's HTTP layer (`requests` + a base URL) tolerates that because of how `urljoin`-style\n * joining treats a relative path. This TS client's `connectapi` does NOT do relative joining: `\n * GarminClient#apiRequest` composes the request URL by plain string concatenation\n * (`` `https://connectapi.${domain}${path}` ``), so a path with no leading slash would silently\n * glue onto the hostname instead of starting a new path segment (`connectapi.garmin.comgraphql-\n * gateway/graphql` — no such host, and NOT a 404 that would flag the mistake as \"wrong URL\").\n * The leading slash below is therefore load-bearing and deliberate, not a stylistic choice — see\n * `tests/services/misc.test.ts` for the literal composed-URL assertion that pins this.\n *\n * UNCERTAIN upstream null handling (inventory row is explicitly marked UNCERTAIN — upstream calls\n * `.json()` on the response directly, with no null-guard): implemented as a straightforward\n * pass-through per this project's standing rule for UNCERTAIN rows.\n */\nexport async function queryGarminGraphql(\n host: MiscHost,\n query: Record<string, unknown>,\n): Promise<GraphqlResult | null> {\n return host.client.connectapi<GraphqlResult>(\"/graphql-gateway/graphql\", {\n method: \"POST\",\n json: query,\n });\n}\n\n/**\n * Upstream `logout`. Makes **no HTTP call** — Garmin's token is never revoked server-side, only\n * cleared locally, matching upstream exactly (\"Does not revoke the token server-side — local-only\").\n *\n * Upstream additionally clears in-memory auth fields (`username`, `full_name`, `unit_system`, …)\n * and optionally unlinks an on-disk token file resolved from an argument or the `GARMINTOKENS`\n * env var. Neither of those maps cleanly onto this port: there is no equivalent in-memory cache to\n * clear here (each `Garmin` instance's `getUserProfile()` cache is simply abandoned along with the\n * instance itself — a fresh `Garmin` re-fetches), and file-vs-inline-token resolution is already\n * `TokenStore`'s job, not this method's. So this method reduces to upstream's actual load-bearing\n * side effect for a server: clearing the configured `TokenStore` — `host.client.tokenStore.clear()`.\n *\n * **Does NOT clear the in-memory tokens already held by this `GarminClient` instance** — there is\n * no public API to do that (only `setTokens`/`getTokens`, no `clearTokens`), and `MiscHost` is\n * deliberately scoped to `{ client }` only, per this task's brief. A process that calls `logout()`\n * and keeps using the same `GarminClient`/`Garmin` instance afterward will keep succeeding against\n * Garmin until the in-memory OAuth2 token expires (~27h) or a refresh is attempted after the\n * OAuth1 token also goes stale — at which point `tokenStore.load()` finds nothing and any refresh\n * fails. The safe pattern is to discard the `GarminClient` instance after calling `logout()`, not\n * to keep issuing requests through it.\n */\nexport async function logout(host: MiscHost): Promise<void> {\n await host.client.tokenStore.clear();\n}\n","import { pathSegment } from \"../util/validate.js\";\nimport type { GarminClient } from \"../client.js\";\nimport { formatDate } from \"../util/date.js\";\nimport type {\n NutritionDailyFoodLog,\n NutritionDailyMeals,\n NutritionDailySettings,\n} from \"../types/nutrition.js\";\n\n/** Nutrition: daily food log, daily meals, daily nutrition settings. */\nexport interface NutritionHost {\n readonly client: GarminClient;\n}\n\n/**\n * Upstream `get_nutrition_daily_food_log`. `null_behaviour`: passes through unchecked.\n */\nexport async function getNutritionDailyFoodLog(\n host: NutritionHost,\n cdate: string | Date,\n): Promise<NutritionDailyFoodLog | null> {\n return host.client.connectapi<NutritionDailyFoodLog>(\n `/nutrition-service/food/logs/${pathSegment(formatDate(cdate))}`,\n );\n}\n\n/**\n * Upstream `get_nutrition_daily_meals`. `null_behaviour`: passes through unchecked.\n */\nexport async function getNutritionDailyMeals(\n host: NutritionHost,\n cdate: string | Date,\n): Promise<NutritionDailyMeals | null> {\n return host.client.connectapi<NutritionDailyMeals>(\n `/nutrition-service/meals/${pathSegment(formatDate(cdate))}`,\n );\n}\n\n/**\n * Upstream `get_nutrition_daily_settings`. `null_behaviour`: passes through unchecked.\n */\nexport async function getNutritionDailySettings(\n host: NutritionHost,\n cdate: string | Date,\n): Promise<NutritionDailySettings | null> {\n return host.client.connectapi<NutritionDailySettings>(\n `/nutrition-service/settings/${pathSegment(formatDate(cdate))}`,\n );\n}\n","import { pathSegment } from \"../util/validate.js\";\nimport type { GarminClient } from \"../client.js\";\nimport type {\n AdaptiveTrainingPlanDetail,\n TrainingPlanDetail,\n TrainingPlansResult,\n} from \"../types/trainingPlans.js\";\n\n/** Training plans: the plan library, a phased plan's detail, an adaptive plan's detail. */\nexport interface TrainingPlansHost {\n readonly client: GarminClient;\n}\n\n/**\n * Upstream `get_training_plans`. `null_behaviour`: passes through unchecked. No parameters.\n */\nexport async function getTrainingPlans(\n host: TrainingPlansHost,\n): Promise<TrainingPlansResult | null> {\n return host.client.connectapi<TrainingPlansResult>(\n \"/trainingplan-service/trainingplan/plans\",\n );\n}\n\n/**\n * Upstream `get_training_plan_by_id`. `null_behaviour`: passes through unchecked.\n */\nexport async function getTrainingPlanById(\n host: TrainingPlansHost,\n planId: number | string,\n): Promise<TrainingPlanDetail | null> {\n return host.client.connectapi<TrainingPlanDetail>(\n `/trainingplan-service/trainingplan/phased/${pathSegment(planId)}`,\n );\n}\n\n/**\n * Upstream `get_adaptive_training_plan_by_id`. `null_behaviour`: passes through unchecked. Note\n * the distinct sub-path (`fbt-adaptive`) from `getTrainingPlanById`'s `phased` path.\n */\nexport async function getAdaptiveTrainingPlanById(\n host: TrainingPlansHost,\n planId: number | string,\n): Promise<AdaptiveTrainingPlanDetail | null> {\n return host.client.connectapi<AdaptiveTrainingPlanDetail>(\n `/trainingplan-service/trainingplan/fbt-adaptive/${pathSegment(planId)}`,\n );\n}\n","import { pathSegment } from \"../util/validate.js\";\nimport { GarminError } from \"../errors.js\";\nimport type { GarminClient } from \"../client.js\";\nimport {\n formatDate,\n formatGmtTimestamp,\n formatLocalTimestamp,\n parseIsoLocal,\n parseIsoUtc,\n} from \"../util/date.js\";\nimport type { DailyWeighIns, WeighInRange } from \"../types/weight.js\";\n\nexport interface WeightHost {\n readonly client: GarminClient;\n}\n\n/**\n * NOTE the read/write asymmetry: Garmin's read side (here) always returns\n * weight in GRAMS regardless of the unit the entry was recorded in — dividing\n * by 1000 is correct. `addWeighIn` below sends the value in the CALLER'S unit\n * (kg or lbs) unconverted; Garmin converts server-side from `unitKey`. The\n * two are not symmetric — do not \"fix\" one to match the other.\n */\nexport async function getWeighIns(\n host: WeightHost,\n startdate: string | Date,\n enddate: string | Date,\n): Promise<WeighInRange> {\n const start = formatDate(startdate);\n const end = formatDate(enddate);\n const data = await host.client.connectapi<WeighInRange>(\n `/weight-service/weight/range/${pathSegment(start)}/${pathSegment(end)}`,\n { params: { includeAll: \"true\" } },\n );\n return data ?? {};\n}\n\n/**\n * NOTE the read/write asymmetry: unlike `getWeighIns` above (which always\n * receives grams from Garmin), this sends `value` as the RAW number in the\n * unit named by `unitKey` — no grams conversion, no rounding. Garmin\n * converts server-side. Upstream python-garminconnect does exactly this\n * (`payload[\"value\"] = weight`); sending a pre-converted gram figure\n * alongside `unitKey: \"kg\"` tells Garmin \"this many kilograms\" and inflates\n * the stored value by 1000x — confirmed against a live account.\n */\nexport async function addWeighIn(\n host: WeightHost,\n weight: number,\n unitKey: \"kg\" | \"lbs\" = \"kg\",\n when: Date = new Date(),\n): Promise<unknown> {\n // `when` is captured once by the caller (defaulting to `new Date()` at the\n // call site) so both fields describe the same instant — computing it twice\n // here could straddle a millisecond and disagree by a second.\n return host.client.connectapi(\"/weight-service/user-weight\", {\n method: \"POST\",\n json: {\n dateTimestamp: formatLocalTimestamp(when),\n gmtTimestamp: formatGmtTimestamp(when),\n unitKey,\n sourceType: \"MANUAL\",\n value: weight,\n },\n });\n}\n\nexport async function deleteWeighIn(\n host: WeightHost,\n cdate: string | Date,\n weightPk: number,\n): Promise<null> {\n await host.client.connectapi(\n `/weight-service/weight/${pathSegment(formatDate(cdate))}/byversion/${pathSegment(weightPk)}`,\n { method: \"DELETE\" },\n );\n return null;\n}\n\n/**\n * Same raw-value, no-conversion rule as `addWeighIn` above — `weight` is\n * sent as-is in `value`, in whatever unit `unitKey` names. This method's\n * only difference from `addWeighIn` is that the caller supplies the local\n * and GMT timestamp strings directly (matching upstream's\n * `add_weigh_in_with_timestamps(weight, unitKey, dateTimestamp, gmtTimestamp)`)\n * instead of a single `Date` this library derives both from.\n *\n * The two timestamps are COUPLED, exactly as upstream couples them, and this\n * is the whole subtlety of the method. Upstream resolves the local instant\n * first — from `dateTimestamp` if given, otherwise from now — and then\n * derives GMT from THAT instant (`dtGMT = dt.astimezone(UTC)`) whenever\n * `gmtTimestamp` is omitted. Deriving the two independently looks equivalent\n * but is not: a caller backdating an entry with `dateTimestamp` alone would\n * get a `gmtTimestamp` pinned to the current moment, silently writing a\n * weigh-in whose two halves describe different days.\n *\n * Both supplied strings are re-formatted rather than forwarded verbatim,\n * again matching upstream, which parses each one and emits `_fmt_ts(...)`.\n * A naive `dateTimestamp` is read as LOCAL time and a naive `gmtTimestamp`\n * as UTC — see `parseIsoLocal`/`parseIsoUtc`.\n */\nexport async function addWeighInWithTimestamps(\n host: WeightHost,\n weight: number,\n unitKey: \"kg\" | \"lbs\" = \"kg\",\n dateTimestamp?: string,\n gmtTimestamp?: string,\n when: Date = new Date(),\n): Promise<unknown> {\n const localInstant = dateTimestamp ? parseIsoLocal(dateTimestamp) : when;\n if (Number.isNaN(localInstant.getTime())) {\n throw new GarminError(`invalid dateTimestamp: \"${dateTimestamp ?? \"\"}\"`);\n }\n // NOT `when`: GMT falls out of whatever local instant was just resolved.\n const gmtInstant = gmtTimestamp ? parseIsoUtc(gmtTimestamp) : localInstant;\n if (Number.isNaN(gmtInstant.getTime())) {\n throw new GarminError(`invalid gmtTimestamp: \"${gmtTimestamp ?? \"\"}\"`);\n }\n\n return host.client.connectapi(\"/weight-service/user-weight\", {\n method: \"POST\",\n json: {\n dateTimestamp: formatLocalTimestamp(localInstant),\n gmtTimestamp: formatGmtTimestamp(gmtInstant),\n unitKey,\n sourceType: \"MANUAL\",\n value: weight,\n },\n });\n}\n\nexport async function getDailyWeighIns(\n host: WeightHost,\n cdate: string | Date,\n): Promise<DailyWeighIns | null> {\n return host.client.connectapi<DailyWeighIns>(\n `/weight-service/weight/dayview/${pathSegment(formatDate(cdate))}`,\n { params: { includeAll: \"true\" } },\n );\n}\n\n/**\n * Multi-step, no HTTP path of its own — mirrors upstream's `delete_weigh_ins`:\n * fetches the day's weigh-ins via `getDailyWeighIns`, then:\n * - if there are none, returns `null` (upstream logs a warning);\n * - if there is more than one and `deleteAll` is not `true`, also returns\n * `null` without deleting anything (upstream logs a warning instead of\n * guessing which entry the caller meant);\n * - otherwise deletes every entry on that date via `deleteWeighIn` and\n * returns the count deleted.\n *\n * IRREVERSIBLE: every weigh-in recorded on `cdate` is gone once this\n * resolves. Never call this against a date you did not populate yourself.\n */\nexport async function deleteWeighIns(\n host: WeightHost,\n cdate: string | Date,\n deleteAll = false,\n): Promise<number | null> {\n const date = formatDate(cdate);\n const day = await getDailyWeighIns(host, date);\n const entries = day?.dateWeightList ?? [];\n if (entries.length === 0) return null;\n if (entries.length > 1 && !deleteAll) return null;\n\n let deleted = 0;\n for (const entry of entries) {\n if (typeof entry.samplePk !== \"number\") continue;\n await deleteWeighIn(host, date, entry.samplePk);\n deleted++;\n }\n return deleted;\n}\n","import { pathSegment } from \"../util/validate.js\";\nimport { GarminAuthError, GarminError } from \"../errors.js\";\nimport type { GarminClient } from \"../client.js\";\nimport { formatDate, formatGmtTimestamp, formatLocalTimestamp } from \"../util/date.js\";\nimport { getBodyComposition } from \"./bodyComposition.js\";\nimport type {\n BloodPressureRange,\n BloodPressureSetResult,\n BodyBatteryEntry,\n BodyBatteryEvent,\n CaloriesDailyEntry,\n DailyEventsData,\n DailyStepsEntry,\n DailyStressData,\n FloorsData,\n HeartRateData,\n HrvData,\n HrvDataRange,\n HydrationLogResult,\n IntensityMinutesData,\n RespirationData,\n RhrDailyEntry,\n RhrDayData,\n SleepData,\n SleepDailyEntry,\n Spo2Data,\n StatsAndBody,\n StepsEntry,\n UserSummary,\n WeeklyIntensityMinutesEntry,\n WeeklyStepsEntry,\n WeeklyStressEntry,\n} from \"../types/wellness.js\";\n\n/** Implemented against a host exposing `client` and `displayName()`. */\nexport interface WellnessHost {\n readonly client: GarminClient;\n displayName(): Promise<string>;\n}\n\nexport async function getUserSummary(\n host: WellnessHost,\n cdate: string | Date,\n): Promise<UserSummary> {\n const date = formatDate(cdate);\n const summary = await host.client.connectapi<UserSummary>(\n `/usersummary-service/usersummary/daily/${pathSegment(await host.displayName())}`,\n { params: { calendarDate: date } },\n );\n if (!summary) throw new GarminError(\"No user summary received from Garmin\");\n if (summary.privacyProtected === true) {\n throw new GarminAuthError(\"User summary is privacy-protected\");\n }\n return summary;\n}\n\nexport async function getStepsData(\n host: WellnessHost,\n cdate: string | Date,\n): Promise<StepsEntry[]> {\n const date = formatDate(cdate);\n const steps = await host.client.connectapi<StepsEntry[]>(\n `/wellness-service/wellness/dailySummaryChart/${pathSegment(await host.displayName())}`,\n { params: { date } },\n );\n return steps ?? [];\n}\n\nexport async function getHeartRates(\n host: WellnessHost,\n cdate: string | Date,\n): Promise<HeartRateData> {\n const date = formatDate(cdate);\n const data = await host.client.connectapi<HeartRateData>(\n `/wellness-service/wellness/dailyHeartRate/${pathSegment(await host.displayName())}`,\n { params: { date } },\n );\n if (!data) throw new GarminError(\"No heart rate data received from Garmin\");\n return data;\n}\n\n// Upstream's get_sleep_data has no null check — it returns whatever\n// connectapi gives back, including nothing for a night the user didn't wear\n// the watch. That's an ordinary, expected result, not an error, so this\n// mirrors upstream and returns null instead of throwing. Match upstream's\n// null behaviour per-method rather than applying a blanket policy here.\nexport async function getSleepData(\n host: WellnessHost,\n cdate: string | Date,\n): Promise<SleepData | null> {\n const date = formatDate(cdate);\n return host.client.connectapi<SleepData>(\n `/wellness-service/wellness/dailySleepData/${pathSegment(await host.displayName())}`,\n { params: { date, nonSleepBufferMinutes: 60 } },\n );\n}\n\nexport async function getHrvData(\n host: WellnessHost,\n cdate: string | Date,\n): Promise<HrvData | null> {\n return host.client.connectapi<HrvData>(`/hrv-service/hrv/${pathSegment(formatDate(cdate))}`);\n}\n\nexport async function getBodyBattery(\n host: WellnessHost,\n startdate: string | Date,\n enddate?: string | Date,\n): Promise<BodyBatteryEntry[]> {\n const start = formatDate(startdate);\n const end = enddate === undefined ? start : formatDate(enddate);\n const data = await host.client.connectapi<BodyBatteryEntry[]>(\n \"/wellness-service/wellness/bodyBattery/reports/daily\",\n { params: { startDate: start, endDate: end } },\n );\n return data ?? [];\n}\n\nexport async function getBodyBatteryEvents(\n host: WellnessHost,\n cdate: string | Date,\n): Promise<BodyBatteryEvent[] | null> {\n return host.client.connectapi<BodyBatteryEvent[]>(\n `/wellness-service/wellness/bodyBattery/events/${pathSegment(formatDate(cdate))}`,\n );\n}\n\nexport async function getFloors(host: WellnessHost, cdate: string | Date): Promise<FloorsData> {\n const date = formatDate(cdate);\n const data = await host.client.connectapi<FloorsData>(\n `/wellness-service/wellness/floorsChartData/daily/${pathSegment(date)}`,\n );\n if (!data) throw new GarminError(\"No floors data received from Garmin\");\n return data;\n}\n\nconst MS_PER_DAY = 86_400_000;\n\nfunction toUtcMidnight(dateStr: string): Date {\n return new Date(`${dateStr}T00:00:00Z`);\n}\n\n/** Adds (or subtracts) whole days to a `YYYY-MM-DD` string, staying in UTC. */\nfunction addDays(dateStr: string, days: number): string {\n const d = toUtcMidnight(dateStr);\n d.setUTCDate(d.getUTCDate() + days);\n return d.toISOString().slice(0, 10);\n}\n\n/** Exact day count between two `YYYY-MM-DD` strings (end minus start). */\nfunction daysBetween(startStr: string, endStr: string): number {\n return Math.round((toUtcMidnight(endStr).getTime() - toUtcMidnight(startStr).getTime()) / MS_PER_DAY);\n}\n\n/**\n * Upstream splits ranges over Garmin's 28-day-per-request limit into\n * `timedelta(days=27)` windows (i.e. ≤28 calendar days per request) and\n * concatenates. Within the limit, a single request's raw (possibly `null`)\n * result is returned unchecked, matching upstream's \"single-request path\n * returns whatever connectapi returns unchecked\" behaviour; a chunked\n * request only appends a chunk's results when they are truthy.\n */\nexport async function getDailySteps(\n host: WellnessHost,\n start: string | Date,\n end: string | Date,\n): Promise<DailyStepsEntry[] | null> {\n const startDate = formatDate(start);\n const endDate = formatDate(end);\n if (startDate > endDate) {\n throw new GarminError(\"getDailySteps: start date must not be after end date\");\n }\n const url = (s: string, e: string): string => `/usersummary-service/stats/steps/daily/${pathSegment(s)}/${pathSegment(e)}`;\n if (daysBetween(startDate, endDate) <= 28) {\n return host.client.connectapi<DailyStepsEntry[]>(url(startDate, endDate));\n }\n const results: DailyStepsEntry[] = [];\n let chunkStart = startDate;\n while (chunkStart <= endDate) {\n const chunkEnd = daysBetween(chunkStart, endDate) > 27 ? addDays(chunkStart, 27) : endDate;\n const chunkResults = await host.client.connectapi<DailyStepsEntry[]>(url(chunkStart, chunkEnd));\n if (chunkResults) results.push(...chunkResults);\n chunkStart = addDays(chunkEnd, 1);\n }\n return results;\n}\n\nfunction assertPositiveInteger(value: number, name: string): void {\n if (!Number.isInteger(value) || value <= 0) {\n throw new GarminError(`${name} must be a positive integer`);\n }\n}\n\nexport async function getWeeklySteps(\n host: WellnessHost,\n end: string | Date,\n weeks = 52,\n): Promise<WeeklyStepsEntry[] | null> {\n assertPositiveInteger(weeks, \"weeks\");\n const endDate = formatDate(end);\n return host.client.connectapi<WeeklyStepsEntry[]>(\n `/usersummary-service/stats/steps/weekly/${pathSegment(endDate)}/${pathSegment(weeks)}`,\n );\n}\n\nexport async function getWeeklyStress(\n host: WellnessHost,\n end: string | Date,\n weeks = 52,\n): Promise<WeeklyStressEntry[] | null> {\n assertPositiveInteger(weeks, \"weeks\");\n const endDate = formatDate(end);\n return host.client.connectapi<WeeklyStressEntry[]>(\n `/usersummary-service/stats/stress/weekly/${pathSegment(endDate)}/${pathSegment(weeks)}`,\n );\n}\n\nexport async function getWeeklyIntensityMinutes(\n host: WellnessHost,\n start: string | Date,\n end: string | Date,\n): Promise<WeeklyIntensityMinutesEntry[] | null> {\n const s = formatDate(start);\n const e = formatDate(end);\n return host.client.connectapi<WeeklyIntensityMinutesEntry[]>(\n `/usersummary-service/stats/im/weekly/${pathSegment(s)}/${pathSegment(e)}`,\n );\n}\n\n/**\n * Upstream `get_stats_and_body` calls `get_stats(cdate)` (== `getUserSummary`\n * here) then `get_body_composition(cdate)` and merges `stats` with\n * `body.get(\"totalAverage\", {})`. Delegates to `getBodyComposition` from the\n * `bodyComposition` service (Task 10) rather than inlining its own\n * `GET /weight-service/weight/dateRange` call, as an earlier version of this\n * function did before that service existed.\n */\nexport async function getStatsAndBody(\n host: WellnessHost,\n cdate: string | Date,\n): Promise<StatsAndBody> {\n const date = formatDate(cdate);\n const [stats, body] = await Promise.all([\n getUserSummary(host, date),\n getBodyComposition(host, date),\n ]);\n const totalAverage =\n body && typeof body === \"object\" && body.totalAverage && typeof body.totalAverage === \"object\"\n ? body.totalAverage\n : {};\n return { ...stats, ...totalAverage };\n}\n\n\n/**\n * `pulse` is optional — Garmin's own UI allows a blood-pressure entry\n * without a heart rate. Ranges enforced by upstream: systolic 70-260,\n * diastolic 40-150, pulse (if given) 20-250, all integers.\n *\n * UNCERTAIN (inventory): upstream has no explicit null-check on this write\n * and returns `self.client.post(...).json()` directly; this mirrors that by\n * returning whatever `connectapi` gives back unchecked (which is `null` on a\n * 204/empty body, per this library's `connectapi` contract).\n */\nexport async function setBloodPressure(\n host: WellnessHost,\n systolic: number,\n diastolic: number,\n pulse?: number,\n when: Date = new Date(),\n notes = \"\",\n): Promise<BloodPressureSetResult | null> {\n if (!Number.isInteger(systolic) || systolic < 70 || systolic > 260) {\n throw new GarminError(\"systolic must be an integer between 70 and 260\");\n }\n if (!Number.isInteger(diastolic) || diastolic < 40 || diastolic > 150) {\n throw new GarminError(\"diastolic must be an integer between 40 and 150\");\n }\n if (pulse !== undefined && (!Number.isInteger(pulse) || pulse < 20 || pulse > 250)) {\n throw new GarminError(\"pulse must be an integer between 20 and 250\");\n }\n return host.client.connectapi<BloodPressureSetResult>(\"/bloodpressure-service/bloodpressure\", {\n method: \"POST\",\n json: {\n measurementTimestampLocal: formatLocalTimestamp(when),\n measurementTimestampGMT: formatGmtTimestamp(when),\n systolic,\n diastolic,\n sourceType: \"MANUAL\",\n notes,\n ...(pulse !== undefined ? { pulse } : {}),\n },\n });\n}\n\nexport async function getBloodPressure(\n host: WellnessHost,\n startdate: string | Date,\n enddate?: string | Date,\n): Promise<BloodPressureRange | null> {\n const start = formatDate(startdate);\n const end = enddate === undefined ? start : formatDate(enddate);\n return host.client.connectapi<BloodPressureRange>(\n `/bloodpressure-service/bloodpressure/range/${pathSegment(start)}/${pathSegment(end)}`,\n { params: { includeAll: \"true\" } },\n );\n}\n\n/**\n * UNCERTAIN (inventory): upstream has no explicit null-check and calls\n * `.json()` on the DELETE response directly.\n */\nexport async function deleteBloodPressure(\n host: WellnessHost,\n version: number | string,\n cdate: string | Date,\n): Promise<unknown> {\n const v = Number(version);\n assertPositiveInteger(v, \"version\");\n const date = formatDate(cdate);\n return host.client.connectapi(`/bloodpressure-service/bloodpressure/${pathSegment(date)}/${pathSegment(v)}`, {\n method: \"DELETE\",\n });\n}\n\nconst MAX_HYDRATION_ML = 10_000;\n\n/**\n * `valueInMl` is sent RAW in milliliters (field name `valueInML`) —\n * negative values are allowed (they subtract), magnitude capped at\n * `MAX_HYDRATION_ML`. Date/timestamp reconciliation mirrors upstream: if\n * both `when` and `cdate` are omitted, uses now(); if only `cdate` is given,\n * uses local midnight of that date; if only `when` is given, derives\n * `cdate` from it; if both are given, their dates must agree or this\n * throws.\n *\n * UNCERTAIN (inventory): upstream has no explicit null-check on this write.\n */\nexport async function addHydrationData(\n host: WellnessHost,\n valueInMl: number,\n when?: Date,\n cdate?: string | Date,\n): Promise<HydrationLogResult | null> {\n if (Math.abs(valueInMl) > MAX_HYDRATION_ML) {\n throw new GarminError(`valueInMl magnitude must not exceed ${MAX_HYDRATION_ML}`);\n }\n let date: string;\n let timestampLocal: string;\n if (when === undefined && cdate === undefined) {\n const now = new Date();\n date = formatDate(now);\n timestampLocal = formatLocalTimestamp(now);\n } else if (when === undefined) {\n date = formatDate(cdate as string | Date);\n timestampLocal = `${date}T00:00:00.00`;\n } else if (cdate === undefined) {\n date = formatDate(when);\n timestampLocal = formatLocalTimestamp(when);\n } else {\n date = formatDate(cdate);\n const derivedDate = formatDate(when);\n if (derivedDate !== date) {\n throw new GarminError(\"timestamp's date does not match cdate\");\n }\n timestampLocal = formatLocalTimestamp(when);\n }\n return host.client.connectapi<HydrationLogResult>(\n \"/usersummary-service/usersummary/hydration/log\",\n {\n method: \"PUT\",\n json: { calendarDate: date, timestampLocal, valueInML: valueInMl },\n },\n );\n}\n\nexport async function getHydrationData(\n host: WellnessHost,\n cdate: string | Date,\n): Promise<HydrationLogResult | null> {\n return host.client.connectapi<HydrationLogResult>(\n `/usersummary-service/usersummary/hydration/daily/${pathSegment(formatDate(cdate))}`,\n );\n}\n\nexport async function getRespirationData(\n host: WellnessHost,\n cdate: string | Date,\n): Promise<RespirationData | null> {\n return host.client.connectapi<RespirationData>(\n `/wellness-service/wellness/daily/respiration/${pathSegment(formatDate(cdate))}`,\n );\n}\n\n/**\n * If Garmin sends `lastSevenDaysAvgSpO2` as a string, upstream coerces it to\n * a float in place before returning; replicated here.\n */\nexport async function getSpo2Data(\n host: WellnessHost,\n cdate: string | Date,\n): Promise<Spo2Data | null> {\n const data = await host.client.connectapi<Spo2Data>(\n `/wellness-service/wellness/daily/spo2/${pathSegment(formatDate(cdate))}`,\n );\n if (data && typeof data === \"object\" && typeof data.lastSevenDaysAvgSpO2 === \"string\") {\n data.lastSevenDaysAvgSpO2 = Number(data.lastSevenDaysAvgSpO2);\n }\n return data;\n}\n\nexport async function getIntensityMinutesData(\n host: WellnessHost,\n cdate: string | Date,\n): Promise<IntensityMinutesData | null> {\n return host.client.connectapi<IntensityMinutesData>(\n `/wellness-service/wellness/daily/im/${pathSegment(formatDate(cdate))}`,\n );\n}\n\nexport async function getAllDayStress(\n host: WellnessHost,\n cdate: string | Date,\n): Promise<DailyStressData | null> {\n return host.client.connectapi<DailyStressData>(\n `/wellness-service/wellness/dailyStress/${pathSegment(formatDate(cdate))}`,\n );\n}\n\n/**\n * Same URL as `getAllDayStress` — upstream keeps `get_stress_data` and\n * `get_all_day_stress` as two separate methods hitting the identical\n * endpoint, for API compatibility. Kept as two TS functions to match.\n */\nexport async function getStressData(\n host: WellnessHost,\n cdate: string | Date,\n): Promise<DailyStressData | null> {\n return host.client.connectapi<DailyStressData>(\n `/wellness-service/wellness/dailyStress/${pathSegment(formatDate(cdate))}`,\n );\n}\n\nexport async function getAllDayEvents(\n host: WellnessHost,\n cdate: string | Date,\n): Promise<DailyEventsData | null> {\n const date = formatDate(cdate);\n return host.client.connectapi<DailyEventsData>(\"/wellness-service/wellness/dailyEvents\", {\n params: { calendarDate: date },\n });\n}\n\n/**\n * Garmin's `sleep-service/stats/sleep/daily` endpoint has a documented\n * 28-day-per-request limit; ranges longer than that are auto-chunked into\n * ≤28-day windows (same chunking scheme as `getDailySteps`), and the\n * per-chunk `individualStats` rows are de-duplicated by `calendarDate` and\n * sorted by `calendarDate` before being returned.\n */\nexport async function getSleepDaily(\n host: WellnessHost,\n start: string | Date,\n end: string | Date,\n): Promise<SleepDailyEntry[]> {\n const startDate = formatDate(start);\n const endDate = formatDate(end);\n if (startDate > endDate) {\n throw new GarminError(\"getSleepDaily: start date must not be after end date\");\n }\n const byDate = new Map<string, SleepDailyEntry>();\n let chunkStart = startDate;\n while (chunkStart <= endDate) {\n const chunkEnd = daysBetween(chunkStart, endDate) > 27 ? addDays(chunkStart, 27) : endDate;\n const data = await host.client.connectapi<{ individualStats?: SleepDailyEntry[] }>(\n `/sleep-service/stats/sleep/daily/${pathSegment(chunkStart)}/${pathSegment(chunkEnd)}`,\n );\n for (const row of data?.individualStats ?? []) {\n const key = typeof row.calendarDate === \"string\" ? row.calendarDate : JSON.stringify(row);\n byDate.set(key, row);\n }\n chunkStart = addDays(chunkEnd, 1);\n }\n return [...byDate.values()].sort((a, b) =>\n String(a.calendarDate ?? \"\").localeCompare(String(b.calendarDate ?? \"\")),\n );\n}\n\nexport async function getRhrDay(\n host: WellnessHost,\n cdate: string | Date,\n): Promise<RhrDayData | null> {\n const date = formatDate(cdate);\n return host.client.connectapi<RhrDayData>(\n `/userstats-service/wellness/daily/${pathSegment(await host.displayName())}`,\n { params: { fromDate: date, untilDate: date, metricId: 60 } },\n );\n}\n\n/**\n * Reshapes Garmin's `allMetrics.metricsMap` response into\n * `[{ calendarDate, value }, ...]`, dropping rows whose value is\n * null/missing — matching upstream's defensive\n * `(data or {}).get(\"allMetrics\") or {}).get(\"metricsMap\", {})` navigation.\n * The exact key(s) `metricsMap` uses were not in the inventory (only the\n * navigation/filtering logic was documented), so this iterates every array\n * found under `metricsMap` rather than assuming a specific key name —\n * `metricId: 60` in the request already scopes the server-side response to\n * resting heart rate.\n */\nexport async function getRhrDaily(\n host: WellnessHost,\n start: string | Date,\n end: string | Date,\n): Promise<RhrDailyEntry[]> {\n const s = formatDate(start);\n const e = formatDate(end);\n const data = await host.client.connectapi<{\n allMetrics?: { metricsMap?: Record<string, unknown> };\n }>(`/userstats-service/wellness/daily/${pathSegment(await host.displayName())}`, {\n params: { fromDate: s, untilDate: e, metricId: 60 },\n });\n const metricsMap = data?.allMetrics?.metricsMap ?? {};\n const rows: RhrDailyEntry[] = [];\n for (const entries of Object.values(metricsMap)) {\n if (!Array.isArray(entries)) continue;\n for (const entry of entries as unknown[]) {\n if (!entry || typeof entry !== \"object\") continue;\n const e2 = entry as Record<string, unknown>;\n if (e2.value === null || e2.value === undefined) continue;\n rows.push({ calendarDate: e2.calendarDate as string | undefined, value: e2.value as number });\n }\n }\n return rows;\n}\n\n/**\n * Same `metricsMap` navigation as `getRhrDaily`, requesting `metricId=22`\n * (active calories) and `metricId=23` (BMR/resting calories) and merging\n * both series by `calendarDate` into\n * `{ calendarDate, active, resting, total }`, where\n * `total = (active ?? 0) + (resting ?? 0)`. Rows where both are\n * null/missing are skipped, matching upstream.\n *\n * Two details the inventory did not spell out were resolved by a live\n * probe against `/userstats-service/wellness/daily/{displayName}` rather\n * than guessed:\n * - A *repeated* `metricId` query param (`?metricId=22&metricId=23`) is\n * required — a comma-joined `metricId=22,23` (what a naive port of\n * Python's `metricId=[22, 23]` might produce) 404s. `connectapi`'s\n * `params` option only supports one value per key, so the repeated pair\n * is built into the path's query string directly instead.\n * - `metricsMap`'s keys are the metric names, not ids — confirmed live as\n * `WELLNESS_ACTIVE_CALORIES` (22) and `WELLNESS_BMR_CALORIES` (23); there\n * is no per-entry `metricId` field to key off of.\n */\nexport async function getCaloriesDaily(\n host: WellnessHost,\n start: string | Date,\n end: string | Date,\n): Promise<CaloriesDailyEntry[]> {\n const s = formatDate(start);\n const e = formatDate(end);\n const query = new URLSearchParams({ fromDate: s, untilDate: e });\n query.append(\"metricId\", \"22\");\n query.append(\"metricId\", \"23\");\n const data = await host.client.connectapi<{\n allMetrics?: { metricsMap?: Record<string, unknown> };\n }>(`/userstats-service/wellness/daily/${pathSegment(await host.displayName())}?${query.toString()}`);\n const metricsMap = data?.allMetrics?.metricsMap ?? {};\n const byDate = new Map<string, { calendarDate: string; active?: number; resting?: number }>();\n const collect = (key: string, assign: (row: { active?: number; resting?: number }, value: number | undefined) => void) => {\n const entries = metricsMap[key];\n if (!Array.isArray(entries)) return;\n for (const entry of entries as unknown[]) {\n if (!entry || typeof entry !== \"object\") continue;\n const e2 = entry as Record<string, unknown>;\n const calendarDate = e2.calendarDate as string | undefined;\n if (!calendarDate) continue;\n const value = e2.value as number | null | undefined;\n const existing = byDate.get(calendarDate) ?? { calendarDate };\n assign(existing, value ?? undefined);\n byDate.set(calendarDate, existing);\n }\n };\n collect(\"WELLNESS_ACTIVE_CALORIES\", (row, value) => {\n row.active = value;\n });\n collect(\"WELLNESS_BMR_CALORIES\", (row, value) => {\n row.resting = value;\n });\n const result: CaloriesDailyEntry[] = [];\n for (const { calendarDate, active, resting } of byDate.values()) {\n if (active === undefined && resting === undefined) continue;\n result.push({ calendarDate, active, resting, total: (active ?? 0) + (resting ?? 0) });\n }\n return result;\n}\n\nexport async function getHrvDataRange(\n host: WellnessHost,\n start: string | Date,\n end: string | Date,\n): Promise<HrvDataRange | null> {\n const s = formatDate(start);\n const e = formatDate(end);\n return host.client.connectapi<HrvDataRange>(`/hrv-service/hrv/daily/${pathSegment(s)}/${pathSegment(e)}`);\n}\n","import type { GarminClient } from \"../client.js\";\nimport type { UserprofileSettings } from \"../types/userProfile.js\";\n\n/**\n * This file covers the `userProfile` inventory section, minus the three rows that already have a\n * live-verified equivalent elsewhere in this port under a different name:\n *\n * | upstream | already exists as |\n * |---------------------|--------------------------------------------------------------------------|\n * | `get_full_name` | `Garmin.fullName()` (cached accessor, no HTTP call) |\n * | `get_unit_system` | `Garmin.unitSystem()` (cached accessor, no HTTP call) |\n * | `get_user_profile` | `Garmin.getUserSettings()` — SAME endpoint (`user-settings`), different name |\n *\n * **Ruling (Task 12):** no aliases were added for these three. Upstream's `get_user_profile` name\n * collides with this port's PRE-EXISTING `getUserProfile()`, which hits a DIFFERENT endpoint\n * (`/userprofile-service/socialProfile`) and is cached/relied upon by `displayName()`/`fullName()`/\n * `userName()` and every date-scoped method in the library. Repointing it, or adding a second method\n * with a near-identical name pointing at `user-settings`, would either break that caching chain or\n * create two ways to call the same endpoint. The mapping above is the resolution: callers porting\n * upstream code that calls `get_user_profile()`/`get_full_name()`/`get_unit_system()` should call\n * `getUserSettings()`/`fullName()`/`unitSystem()` instead. See `AGENTS.md` section 3 for the same\n * table in the published method inventory.\n *\n * That leaves one genuinely new method here: `getUserprofileSettings`.\n */\nexport interface UserProfileHost {\n readonly client: GarminClient;\n}\n\n/**\n * Upstream `get_userprofile_settings`. Hits `/userprofile-service/userprofile/settings` — SINGULAR\n * \"settings\", NOT the hyphenated \"user-settings\" that `Garmin.getUserSettings()` already uses. The\n * two paths are one character apart and easy to transpose; the test for this method asserts the\n * literal URL for exactly that reason. `null_behaviour`: passes through unchecked, per the\n * inventory.\n */\nexport async function getUserprofileSettings(\n host: UserProfileHost,\n): Promise<UserprofileSettings | null> {\n return host.client.connectapi<UserprofileSettings>(\"/userprofile-service/userprofile/settings\");\n}\n","/**\r\n * Types for the `workouts` service (workout templates, per-sport upload\r\n * helpers, scheduling, and device push).\r\n *\r\n * The upstream inventory (`docs/upstream-method-inventory.md`, `workouts`\r\n * section) documents the six per-sport upload helpers only as \"`dict` built\r\n * from `workout.to_dict()` of a pydantic `RunningWorkout`/`CyclingWorkout`/...\r\n * model\" — it does not give the model's field-level shape. That shape was\r\n * NOT invented for this port: it was read directly from upstream's own\r\n * source, `garminconnect/workout.py` in cyberjunky/python-garminconnect\r\n * (fetched live from GitHub during this task, not from training-data\r\n * memory), which is the actual implementation the inventory row summarizes.\r\n * See workouts.ts and task-6-report.md for the full account of this\r\n * deviation from \"transcribe from the inventory table alone\".\r\n *\r\n * This port has zero runtime dependencies, so there is no pydantic model —\r\n * these are plain structural interfaces (`extra=\"allow\"` on the upstream\r\n * models is reflected here as an index signature) and a runtime `TypeError`\r\n * equivalent (upstream raises if `workout` isn't an instance of the right\r\n * pydantic class) is NOT reproduced; the six wrappers instead do minimal\r\n * required-field validation on a plain object. See the workouts.ts module\r\n * doc comment for the full reasoning.\r\n */\r\n\r\n/** `SportType` IDs — from `/workout-service/workout/types`, transcribed from upstream `workout.py`. */\r\nexport const WORKOUT_SPORT_TYPE_ID = {\r\n RUNNING: 1,\r\n CYCLING: 2,\r\n OTHER: 3,\r\n SWIMMING: 4,\r\n STRENGTH_TRAINING: 5,\r\n CARDIO_TRAINING: 6,\r\n YOGA: 7,\r\n PILATES: 8,\r\n HIIT: 9,\r\n MULTI_SPORT: 10,\r\n MOBILITY: 11,\r\n /** Live-only: present in Garmin's enum, absent from upstream entirely. */\r\n RUCKING: 13,\r\n /**\r\n * There is deliberately no WALKING or HIKING entry. Garmin's own workout enum\r\n * (`GET /workout-service/workout/types` -> `workoutSportTypes`) lists only\r\n * 1,2,3,4,5,6,7,8,9,10,11,13 — no walking or hiking workout sport type exists.\r\n *\r\n * Upstream python-garminconnect's `WalkingWorkout`/`HikingWorkout` send 17 and 18, which look\r\n * like Garmin ACTIVITY-type ids mistaken for workout sport types. Garmin ACCEPTS those and\r\n * stores `{sportTypeId: 0, sportTypeKey: null}` — a workout with no sport. This port shipped\r\n * `uploadWalkingWorkout`/`uploadHikingWorkout` for a while on parity grounds and removed them\r\n * on 2026-09-24: a method whose only behaviour is to create a broken record is worse than no\r\n * method, and the parity argument does not survive knowing more than upstream does.\r\n *\r\n * For a walk or hike template, use `uploadWorkout` with `OTHER` (3) or `CARDIO_TRAINING` (6).\r\n */\r\n} as const;\r\n\r\n/**\r\n * Swim stroke types — `GET /workout-service/workout/types` -> `workoutStrokeTypes`, read live\r\n * 2026-09-23. Not modelled upstream. Used as a step's `strokeType`.\r\n */\r\nexport const WORKOUT_STROKE_TYPE_ID = {\r\n ANY_STROKE: 1,\r\n BACKSTROKE: 2,\r\n BREASTSTROKE: 3,\r\n DRILL: 4,\r\n FLY: 5,\r\n FREE: 6,\r\n INDIVIDUAL_MEDLEY: 7,\r\n MIXED: 8,\r\n INDIVIDUAL_MEDLEY_BY_ROUND: 9,\r\n REVERSE_INDIVIDUAL_MEDLEY_BY_ROUND: 10,\r\n} as const;\r\n\r\n/** Swim drill types — `workoutDrillTypes`. Used as a step's `drillType`. */\r\nexport const WORKOUT_DRILL_TYPE_ID = { KICK: 1, PULL: 2, DRILL: 3 } as const;\r\n\r\n/** Swim equipment — `workoutEquipmentTypes`. Used as a step's `equipmentType`. */\r\nexport const WORKOUT_EQUIPMENT_TYPE_ID = {\r\n FINS: 1,\r\n KICKBOARD: 2,\r\n PADDLES: 3,\r\n PULL_BUOY: 4,\r\n SNORKEL: 5,\r\n} as const;\r\n\r\n/** Swim instruction intensities — `workoutSwimInstructionTypes`. */\r\nexport const WORKOUT_SWIM_INSTRUCTION_TYPE_ID = {\r\n RECOVERY: 1,\r\n VERY_EASY: 2,\r\n EASY: 3,\r\n MODERATE: 4,\r\n HARD: 5,\r\n VERY_HARD: 6,\r\n ALL_OUT: 7,\r\n FAST: 8,\r\n ASCEND: 9,\r\n DESCEND: 10,\r\n} as const;\r\n\r\n/**\r\n * Every exercise category Garmin's workout service accepts, verified exhaustively against a live\r\n * account on 2026-09-23 by submitting each candidate on its own and keeping only those that were\r\n * accepted.\r\n *\r\n * The set is the FIT SDK's `exercise_category` enum (the first 34 entries here, in enum order) plus\r\n * 16 Garmin Connect additions — 50 in total. The Connect ones were found by reading the web\r\n * exercise picker's `data-category-key` attributes and then confirming each against the API. 49\r\n * other plausible names were tested and ALL rejected: `COOL_DOWN` (though `WARM_UP` is valid),\r\n * `BURPEE`, `KETTLEBELL`, `MOBILITY`, `YOGA`, `PILATES`, muscle groups like `CHEST` and `LEGS`, and\r\n * lift names like `CLEAN` and `SNATCH` (those belong in the exercise `name`, under `OLYMPIC_LIFT`).\r\n *\r\n * `BIKE`, `STRETCH` and `UNKNOWN` are accepted by the API but are NOT offered in the web picker.\r\n *\r\n * This matters more than a normal enum because **an invalid category fails the WHOLE upload** with\r\n * `400 \"Invalid category\"`, not just the offending step, and no endpoint lists the valid values.\r\n */\r\nexport const WORKOUT_EXERCISE_CATEGORIES = [\r\n // --- FIT SDK `exercise_category`, in enum order ---\r\n \"BENCH_PRESS\",\r\n \"CALF_RAISE\",\r\n \"CARDIO\",\r\n \"CARRY\",\r\n \"CHOP\",\r\n \"CORE\",\r\n \"CRUNCH\",\r\n \"CURL\",\r\n \"DEADLIFT\",\r\n \"FLYE\",\r\n \"HIP_RAISE\",\r\n \"HIP_STABILITY\",\r\n \"HIP_SWING\",\r\n \"HYPEREXTENSION\",\r\n \"LATERAL_RAISE\",\r\n \"LEG_CURL\",\r\n \"LEG_RAISE\",\r\n \"LUNGE\",\r\n \"OLYMPIC_LIFT\",\r\n \"PLANK\",\r\n \"PLYO\",\r\n \"PULL_UP\",\r\n \"PUSH_UP\",\r\n \"ROW\",\r\n \"SHOULDER_PRESS\",\r\n \"SHOULDER_STABILITY\",\r\n \"SHRUG\",\r\n \"SIT_UP\",\r\n \"SQUAT\",\r\n \"TOTAL_BODY\",\r\n \"TRICEPS_EXTENSION\",\r\n \"WARM_UP\",\r\n \"RUN\",\r\n \"UNKNOWN\",\r\n // --- Garmin Connect additions, beyond the FIT enum ---\r\n // The first three are accepted by the API but are NOT offered in the web exercise picker.\r\n \"BIKE\",\r\n \"STRETCH\",\r\n \"BANDED_EXERCISES\",\r\n \"BATTLE_ROPE\",\r\n \"SLED\",\r\n \"SUSPENSION\",\r\n // Equipment- and modality-specific categories, read from the web picker's `data-category-key`\r\n // and then each confirmed against the API.\r\n \"BIKE_OUTDOOR\",\r\n \"INDOOR_BIKE\",\r\n \"RUN_INDOOR\",\r\n \"ELLIPTICAL\",\r\n \"STAIR_STEPPER\",\r\n \"FLOOR_CLIMB\",\r\n \"LADDER\",\r\n \"SANDBAG\",\r\n \"SLEDGE_HAMMER\",\r\n \"TIRE\",\r\n \"INDOOR_ROW\",\r\n // Yoga poses and pilates/mobility moves. Neither appears in the strength exercise picker — they\r\n // came from Garmin's `exercise_types` translations bundle and were then confirmed against the\r\n // API, which accepts both and stores their names intact.\r\n \"POSE\",\r\n \"MOVE\",\r\n] as const;\r\n\r\n/**\r\n * One of the 53 categories Garmin accepts. See `WORKOUT_EXERCISE_CATEGORIES`.\r\n *\r\n * The exercise NAMES valid within each category ship separately, in\r\n * `garminconnect-js/exercises` — see that module for why the two halves are validated so\r\n * differently.\r\n */\r\nexport type ExerciseCategory = (typeof WORKOUT_EXERCISE_CATEGORIES)[number];\r\n\r\n/** Step intensity — `workoutIntensityTypes`. */\r\nexport const WORKOUT_INTENSITY_TYPE_ID = {\r\n ACTIVE: 1,\r\n REST: 2,\r\n WARMUP: 3,\r\n COOLDOWN: 4,\r\n} as const;\r\n\r\n/** `StepType` IDs — from `/workout-service/workout/types`. */\r\nexport const WORKOUT_STEP_TYPE_ID = {\r\n WARMUP: 1,\r\n COOLDOWN: 2,\r\n INTERVAL: 3,\r\n RECOVERY: 4,\r\n REST: 5,\r\n REPEAT: 6,\r\n OTHER: 7,\r\n MAIN: 8,\r\n} as const;\r\n\r\n/** End-condition `ConditionType` IDs. */\r\nexport const WORKOUT_CONDITION_TYPE_ID = {\r\n LAP_BUTTON: 1,\r\n TIME: 2,\r\n DISTANCE: 3,\r\n CALORIES: 4,\r\n POWER: 5,\r\n HEART_RATE: 6,\r\n ITERATIONS: 7,\r\n FIXED_REST: 8,\r\n FIXED_REPETITION: 9,\r\n REPS: 10,\r\n // 11-24 exist in Garmin's live enum but not upstream. Read from\r\n // `GET /workout-service/workout/types` -> `workoutConditionTypes` on 2026-09-23.\r\n TRAINING_PEAKS_TSS: 11,\r\n REPETITION_TIME: 12,\r\n TIME_AT_VALID_CDA: 13,\r\n POWER_LAST_LAP: 14,\r\n MAX_POWER_LAST_LAP: 15,\r\n REPETITION_SWIM_CSS_OFFSET: 16,\r\n VELOCITY_LOSS: 17,\r\n CUSTOM_VELOCITY: 18,\r\n VBT_VELOCITY_ZONE: 19,\r\n VELOCITY_MIN: 20,\r\n PEAK_VELOCITY_MIN: 21,\r\n PEAK_VELOCITY_LOSS: 22,\r\n CUSTOM_PEAK_VELOCITY: 23,\r\n POWER_LOSS: 24,\r\n} as const;\r\n\r\n/** `TargetType` IDs. */\r\nexport const WORKOUT_TARGET_TYPE_ID = {\r\n NO_TARGET: 1,\r\n POWER_ZONE: 2,\r\n CADENCE: 3,\r\n HEART_RATE_ZONE: 4,\r\n SPEED_ZONE: 5,\r\n PACE_ZONE: 6,\r\n GRADE: 7,\r\n HEART_RATE_LAP: 8,\r\n POWER_LAP: 9,\r\n RESISTANCE: 15,\r\n // 10-27 (minus those above) exist in Garmin's live enum but not upstream. Read from\r\n // `GET /workout-service/workout/types` -> `workoutTargetTypes` on 2026-09-23.\r\n POWER_3S: 10,\r\n POWER_10S: 11,\r\n POWER_30S: 12,\r\n SPEED_LAP: 13,\r\n SWIM_STROKE: 14,\r\n POWER_CURVE: 16,\r\n SWIM_CSS_OFFSET: 17,\r\n SWIM_INSTRUCTION: 18,\r\n INSTRUCTION: 19,\r\n VELOCITY_LOSS: 20,\r\n CUSTOM_VELOCITY: 21,\r\n VBT_VELOCITY_ZONE: 22,\r\n POWER_LOSS: 23,\r\n VELOCITY_MIN: 24,\r\n PEAK_VELOCITY_MIN: 25,\r\n PEAK_VELOCITY_LOSS: 26,\r\n CUSTOM_PEAK_VELOCITY: 27,\r\n} as const;\r\n\r\n/** A generic `{id, key, displayOrder}`-shaped reference object used throughout workout JSON. */\r\nexport interface WorkoutTypeRef {\r\n [key: string]: unknown;\r\n}\r\n\r\n/** One executable workout step (warmup, interval, recovery, cooldown, rest, ...). */\r\nexport interface ExecutableWorkoutStep {\r\n type?: string; // default \"ExecutableStepDTO\" upstream\r\n stepOrder: number;\r\n stepType?: WorkoutTypeRef | null;\r\n endCondition?: WorkoutTypeRef | null;\r\n endConditionValue?: number | null;\r\n targetType?: WorkoutTypeRef | null;\r\n strokeType?: WorkoutTypeRef | null;\r\n equipmentType?: WorkoutTypeRef | null;\r\n childStepId?: number | null;\r\n /** Upstream's pydantic models declare `extra=\"allow\"` on this type. */\r\n [key: string]: unknown;\r\n}\r\n\r\n/** A repeat block wrapping a set of steps (e.g. \"3x\" a warmup+interval pair). */\r\nexport interface RepeatWorkoutGroup {\r\n type?: string; // default \"RepeatGroupDTO\" upstream\r\n stepOrder: number;\r\n stepType?: WorkoutTypeRef | null;\r\n /**\r\n * The iteration count for a COUNT-based repeat. **Nullable**, because a repeat can instead be\r\n * TIME-based: Garmin's HIIT designer offers \"Repeat Until Time Is\", which stores\r\n * `endCondition: time`, the seconds in `endConditionValue`, and `numberOfIterations: null`.\r\n * Confirmed live 2026-09-23. Upstream types this as a plain required number, which cannot\r\n * express the time-based form.\r\n */\r\n numberOfIterations: number | null;\r\n workoutSteps: (ExecutableWorkoutStep | RepeatWorkoutGroup)[];\r\n endCondition?: WorkoutTypeRef | null;\r\n endConditionValue?: number | null;\r\n childStepId?: number | null;\r\n smartRepeat?: boolean;\r\n [key: string]: unknown;\r\n}\r\n\r\n/** One segment of a workout (upstream supports multiple, e.g. for multi-sport workouts). */\r\nexport interface WorkoutSegment {\r\n segmentOrder: number;\r\n sportType: WorkoutTypeRef;\r\n workoutSteps: (ExecutableWorkoutStep | RepeatWorkoutGroup)[];\r\n [key: string]: unknown;\r\n}\r\n\r\n/**\r\n * The shape accepted by the six per-sport upload helpers (`uploadRunningWorkout` etc.), mirroring\r\n * upstream's `BaseWorkout` pydantic model. `sportType` is optional here — each helper fills in the\r\n * correct default (matching that sport's upstream subclass default) when omitted, but an explicit\r\n * value is passed through unchanged if the caller supplies one.\r\n */\r\nexport interface WorkoutInput {\r\n workoutName: string;\r\n sportType?: WorkoutTypeRef;\r\n estimatedDurationInSecs: number;\r\n workoutSegments: WorkoutSegment[];\r\n author?: WorkoutTypeRef;\r\n description?: string;\r\n [key: string]: unknown;\r\n}\r\n\r\n/** A stored Garmin workout template. Untyped beyond the fields observed/documented; passes through unchecked. */\r\nexport interface WorkoutRecord {\r\n workoutId?: number;\r\n workoutName?: string;\r\n [key: string]: unknown;\r\n}\r\n\r\n/** One calendar item as returned inside `/calendar-service/year/{y}/month/{m}`'s `calendarItems`. */\r\nexport interface CalendarItem {\r\n itemType?: string;\r\n date?: string;\r\n [key: string]: unknown;\r\n}\r\n\r\n/** Response of `/calendar-service/year/{year}/month/{month}`. */\r\nexport interface CalendarMonth {\r\n calendarItems?: CalendarItem[];\r\n [key: string]: unknown;\r\n}\r\n\r\n/**\r\n * One queued device message, as returned by `pushWorkoutToDevice`.\r\n *\r\n * Shape read live on 2026-09-24 from a real account with a paired Forerunner. The method's return\r\n * type used to be `WorkoutRecord | null`, which was wrong in two ways at once: the response is an\r\n * ARRAY, and its rows are device-messaging records, not workouts. Nothing caught it because the\r\n * final POST had never run — the test account has no device, so the call always failed before\r\n * returning. This is the same \"declared shape was never observed\" class as the seven inventory\r\n * rows labelled `dict` that turned out to be arrays.\r\n *\r\n * Pushing the SAME workout again returns `[]`: the message is already queued for that device.\r\n */\r\nexport interface DeviceMessage {\r\n messageId: number;\r\n messageType: string;\r\n messageStatus: string;\r\n deviceId: number;\r\n deviceName: string;\r\n fileType: string;\r\n messageUrl: string;\r\n messageName: string;\r\n priority: number;\r\n metaDataId: number;\r\n wifiSetup: boolean;\r\n hidden: boolean;\r\n applicationKey: string | null;\r\n firmwareVersion: string | null;\r\n deviceXmlDataType: string | null;\r\n createdTimeStamp: string | null;\r\n updatedTimeStamp: string | null;\r\n uniqueIdentifier: string | null;\r\n groupName: string | null;\r\n appDetails: unknown;\r\n}\r\n","import { pathSegment } from \"../util/validate.js\";\r\nimport { GarminError } from \"../errors.js\";\r\nimport type { GarminClient } from \"../client.js\";\r\nimport * as devices from \"./devices.js\";\r\nimport { formatDate } from \"../util/date.js\";\r\nimport {\r\n WORKOUT_SPORT_TYPE_ID,\r\n type CalendarItem,\r\n type CalendarMonth,\r\n type WorkoutInput,\r\n type WorkoutRecord,\r\n type DeviceMessage,\r\n} from \"../types/workouts.js\";\r\n\r\nexport interface WorkoutsHost {\r\n readonly client: GarminClient;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Basic CRUD\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * `list`, \"passes through unchecked\" per the inventory — stays nullable, NOT\r\n * coalesced to `[]` (per the project rule: only methods whose inventory row\r\n * explicitly documents `[]`-coalescing do that; \"passes through unchecked\"\r\n * means exactly what it says).\r\n */\r\nexport async function getWorkouts(\r\n host: WorkoutsHost,\r\n start = 0,\r\n limit = 100,\r\n): Promise<WorkoutRecord[] | null> {\r\n return host.client.connectapi<WorkoutRecord[]>(\"/workout-service/workouts\", {\r\n params: { start, limit },\r\n });\r\n}\r\n\r\n/** `dict`, passes through unchecked per the inventory. */\r\nexport async function getWorkoutById(\r\n host: WorkoutsHost,\r\n workoutId: number | string,\r\n): Promise<WorkoutRecord | null> {\r\n return host.client.connectapi<WorkoutRecord>(`/workout-service/workout/${pathSegment(workoutId)}`);\r\n}\r\n\r\n/**\r\n * UNCERTAIN (inventory): \"no explicit null handling\". Deletes the template\r\n * from the workout library — irreversible.\r\n */\r\nexport async function deleteWorkout(host: WorkoutsHost, workoutId: number | string): Promise<unknown> {\r\n return host.client.connectapi(`/workout-service/workout/${pathSegment(workoutId)}`, { method: \"DELETE\" });\r\n}\r\n\r\n/**\r\n * UNCERTAIN (inventory): \"routed through `self.download(url)`\", no explicit\r\n * null handling reviewed. Returns the workout's FIT-file bytes.\r\n */\r\nexport async function downloadWorkout(host: WorkoutsHost, workoutId: number | string): Promise<Buffer> {\r\n return host.client.download(`/workout-service/workout/FIT/${pathSegment(workoutId)}`);\r\n}\r\n\r\n/**\r\n * `workout_json` may be a caller-built object/array, or a JSON string (parsed here, matching\r\n * upstream's `json.loads` — an invalid string throws `GarminError`, the TS analogue of upstream's\r\n * `ValueError`). After parsing, the result must be an object or an array, else `GarminError`\r\n * (upstream: `ValueError`). UNCERTAIN (inventory): no explicit null handling on the response\r\n * beyond this input validation.\r\n */\r\n/**\r\n * MULTI-SPORT WORKOUTS ARE SUPPORTED by this method, though no helper wraps them.\r\n *\r\n * Confirmed 2026-09-23 by building one in Garmin's own workout designer, capturing the POST, and\r\n * then round-tripping the same shape through this method: created, read back with both segments\r\n * and the transition flag intact, deleted. A multi-sport workout is a single workout whose\r\n * top-level `sportType` is `multi_sport` (`WORKOUT_SPORT_TYPE_ID.MULTI_SPORT`, id 10) and whose\r\n * `workoutSegments` each carry their OWN `sportType` — the array this library already models.\r\n *\r\n * ```ts\r\n * await garmin.uploadWorkout({\r\n * workoutName: \"Brick\",\r\n * sportType: { sportTypeId: WORKOUT_SPORT_TYPE_ID.MULTI_SPORT, sportTypeKey: \"multi_sport\", displayOrder: 5 },\r\n * estimatedDurationInSecs: 3000,\r\n * isSessionTransitionEnabled: true, // the designer's \"Transitions\" toggle\r\n * workoutSegments: [\r\n * { segmentOrder: 1, sportType: { sportTypeId: 1, sportTypeKey: \"running\", displayOrder: 1 }, workoutSteps: [ ... ] },\r\n * { segmentOrder: 2, sportType: { sportTypeId: 2, sportTypeKey: \"cycling\", displayOrder: 2 }, workoutSteps: [ ... ] },\r\n * ],\r\n * });\r\n * ```\r\n *\r\n * **`stepOrder` IS GLOBAL ACROSS SEGMENTS, not per-segment.** Numbering each segment's steps from 1\r\n * is the obvious mistake and Garmin rejects it with\r\n * `400 \"The workout steps need to have unique step orders, or all be unset and rely on submission\r\n * structure order.\"` Either number every step uniquely across the whole workout, or omit\r\n * `stepOrder` entirely and let submission order decide.\r\n *\r\n * REPEAT BLOCKS work, and their shape is confirmed against a designer-built workout:\r\n * `{ type: \"RepeatGroupDTO\", stepType: repeat (id 6), numberOfIterations, smartRepeat, childStepId,\r\n * endCondition: iterations (id 7), workoutSteps: [ ...nested ExecutableStepDTO ] }` — exactly what\r\n * `RepeatWorkoutGroup` models. Round-tripped through `uploadWorkout`: a warmup, a 3-iteration\r\n * repeat containing an interval and a recovery, and a cooldown, all read back intact.\r\n *\r\n * **`stepOrder` numbering continues THROUGH a repeat's children.** In the designer's own payload:\r\n * warmup=1, interval=2, repeat=3, its two children=4 and 5, cooldown=6. Nested steps share the one\r\n * global sequence; they do not restart at 1 inside the block.\r\n *\r\n * **`pace.zone` targets are SPEEDS IN METRES PER SECOND, not paces** — and `targetValueOne` is the\r\n * FASTER bound, so it is the LARGER number. The designer's 8:30-9:30 min/mile became\r\n * `targetValueOne: 3.1556, targetValueTwo: 2.8234` (1609.344 m / 510 s and / 570 s). A caller\r\n * thinking in minutes-per-km will produce a wildly wrong target with no error.\r\n *\r\n * A REPEAT CAN BE TIME-BASED instead of count-based. Garmin's HIIT designer offers \"Repeat Until\r\n * Time Is\", which produces `endCondition: time`, the seconds in `endConditionValue`, and\r\n * **`numberOfIterations: null`** — which is why `RepeatWorkoutGroup.numberOfIterations` is\r\n * `number | null` here where upstream types it as a plain required number. Both forms\r\n * round-tripped through `uploadWorkout`.\r\n *\r\n * WEIGHT rides on a step as `weightValue` plus `weightUnit` (`{unitId, unitKey, factor}`), and\r\n * Garmin stores it in KILOGRAMS whatever the UI shows. Entering \"20 lbs\" in the designer stored\r\n * `weightValue: 19.998…` with `unitKey: \"pound\"`; sending `9.0718474` with `unitKey: \"kilogram\"`\r\n * stored `9.071`. Expect small round-trip drift either way — do not assert exact equality on a\r\n * weight you sent.\r\n *\r\n * Two naming traps around exercises, both observed live:\r\n * - The DISPLAY name is not the stored key. \"Barbell Overhead Press\" in the picker stores as\r\n * `category: \"SHOULDER_PRESS\", exerciseName: \"OVERHEAD_BARBELL_PRESS\"`.\r\n * - Adding a weight can CHANGE the exercise. A \"Push-up\" with a manual weight stored as\r\n * `category: \"PUSH_UP\", exerciseName: \"WEIGHTED_PUSH_UP\"` — Garmin swapped in the weighted\r\n * variant by itself.\r\n *\r\n * STRENGTH steps carry an exercise pair: `category` plus `exerciseName`, both SCREAMING_SNAKE_CASE\r\n * (`category: \"SQUAT\"`, `exerciseName: \"BARBELL_BACK_SQUAT\"`), with `endCondition: reps` (id 10)\r\n * and `endConditionValue` as the rep count. The designer offers 548 exercises. Verified by\r\n * round-trip. The same category vocabulary appears in `setActivityExerciseSets`.\r\n *\r\n * `displayOrder` inside a `sportType`/`stepType`/`endCondition` ref is COSMETIC — Garmin accepts a\r\n * strength workout with `displayOrder: 4` (what its own client sends) or `5` (what this library's\r\n * `uploadStrengthWorkout` sends) identically. Do not treat a mismatch there as a bug.\r\n *\r\n * The designer also offers workout types this library has no helper for — Cardio, HIIT, Yoga,\r\n * Pilates, Mobility, Rucking, Custom and Multisport. All are reachable here by passing the matching\r\n * `sportType` explicitly; `WORKOUT_SPORT_TYPE_ID` already exports the ids, and they were confirmed\r\n * against a real designer-produced payload.\r\n */\r\nexport async function uploadWorkout(\r\n host: WorkoutsHost,\r\n workoutJson: Record<string, unknown> | unknown[] | string,\r\n): Promise<WorkoutRecord | null> {\r\n const body = parseWorkoutJson(workoutJson, /* allowArray */ true);\r\n return host.client.connectapi<WorkoutRecord>(\"/workout-service/workout\", {\r\n method: \"POST\",\r\n json: body,\r\n });\r\n}\r\n\r\n/**\r\n * Full-replace semantics: Garmin's PUT replaces the whole workout, so `workout_json` must be the\r\n * complete structure. `workoutId` is forced into the body to match the path id, overriding\r\n * whatever (if anything) the caller put there — matches upstream's `{**parsed, \"workoutId\":\r\n * workout_id}` merge. Unlike `uploadWorkout`, a string input must resolve to an object, not an\r\n * array (upstream: `ValueError` otherwise; here: `GarminError`). UNCERTAIN (inventory): no\r\n * explicit null handling on the response.\r\n */\r\nexport async function updateWorkout(\r\n host: WorkoutsHost,\r\n workoutId: number | string,\r\n workoutJson: Record<string, unknown> | string,\r\n): Promise<WorkoutRecord | null> {\r\n const parsed = parseWorkoutJson(workoutJson, /* allowArray */ false);\r\n const body = { ...(parsed as Record<string, unknown>), workoutId };\r\n return host.client.connectapi<WorkoutRecord>(`/workout-service/workout/${pathSegment(workoutId)}`, {\r\n method: \"PUT\",\r\n json: body,\r\n });\r\n}\r\n\r\nfunction parseWorkoutJson(\r\n input: Record<string, unknown> | unknown[] | string,\r\n allowArray: boolean,\r\n): Record<string, unknown> | unknown[] {\r\n let value: unknown = input;\r\n if (typeof input === \"string\") {\r\n try {\r\n value = JSON.parse(input) as unknown;\r\n } catch (cause) {\r\n throw new GarminError(\"workout_json is not valid JSON\", { cause });\r\n }\r\n }\r\n if (Array.isArray(value)) {\r\n if (!allowArray) {\r\n throw new GarminError(\"workout_json must resolve to an object, not an array, for updateWorkout\");\r\n }\r\n // `Array.isArray` narrows `unknown` to `any[]` (a lib.d.ts quirk, not a\r\n // real loss of safety here — `value` came from `unknown`), so an\r\n // explicit cast back to `unknown[]` is needed to satisfy\r\n // `no-unsafe-return`.\r\n return value as unknown[];\r\n }\r\n if (value !== null && typeof value === \"object\") {\r\n return value as Record<string, unknown>;\r\n }\r\n throw new GarminError(\"workout_json must be an object or array (or a JSON string of one)\");\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Per-sport upload helpers\r\n//\r\n// The inventory's `body` column for these six rows says only \"`workout.to_dict()` from a\r\n// `<Sport>Workout` pydantic model\" — it does not give the model's field-level shape, and this\r\n// port carries zero runtime dependencies, so there is no pydantic model to port. The shape below\r\n// was NOT invented to fill that gap: it was read directly from upstream's actual implementation,\r\n// `garminconnect/workout.py` (cyberjunky/python-garminconnect, fetched from GitHub during this\r\n// task), which is the primary source the inventory row itself summarizes. See task-6-report.md\r\n// for the full account of this deviation from \"transcribe from the inventory table alone\".\r\n//\r\n// All six sports share IDENTICAL structure beyond `sportType`'s default value (workoutName,\r\n// estimatedDurationInSecs, workoutSegments, author, description — upstream's `BaseWorkout`) — that\r\n// commonality is real and is factored into one `buildSportWorkout` helper below, not six\r\n// near-copies. The one thing that differs per sport (the default `sportType` id/key/displayOrder)\r\n// is kept as six distinct constants rather than flattened into a lookup, because a caller can\r\n// override `sportType` per call and each of the six default triples IS the fact this port must get\r\n// exactly right.\r\n//\r\n// Upstream additionally raises `TypeError` if `workout` isn't an instance of the matching pydantic\r\n// class, and `ImportError` if pydantic isn't installed. Neither is reproduced here: there is no\r\n// pydantic dependency to be missing, and there is no runtime class to check `instanceof` against a\r\n// plain object literal. Minimal shape validation (`workoutName`, `estimatedDurationInSecs`,\r\n// `workoutSegments` all present) substitutes for the `TypeError` case.\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction buildSportWorkout(\r\n input: WorkoutInput,\r\n defaultSportType: Record<string, unknown>,\r\n): Record<string, unknown> {\r\n if (\r\n typeof input.workoutName !== \"string\" ||\r\n typeof input.estimatedDurationInSecs !== \"number\" ||\r\n !Array.isArray(input.workoutSegments)\r\n ) {\r\n throw new GarminError(\r\n \"workout must have workoutName (string), estimatedDurationInSecs (number), and workoutSegments (array)\",\r\n );\r\n }\r\n return {\r\n ...input,\r\n sportType: input.sportType ?? defaultSportType,\r\n };\r\n}\r\n\r\nconst RUNNING_SPORT_TYPE = {\r\n sportTypeId: WORKOUT_SPORT_TYPE_ID.RUNNING,\r\n sportTypeKey: \"running\",\r\n displayOrder: 1,\r\n};\r\nconst CYCLING_SPORT_TYPE = {\r\n sportTypeId: WORKOUT_SPORT_TYPE_ID.CYCLING,\r\n sportTypeKey: \"cycling\",\r\n displayOrder: 2,\r\n};\r\nconst SWIMMING_SPORT_TYPE = {\r\n sportTypeId: WORKOUT_SPORT_TYPE_ID.SWIMMING,\r\n sportTypeKey: \"swimming\",\r\n displayOrder: 3,\r\n};\r\nconst STRENGTH_SPORT_TYPE = {\r\n sportTypeId: WORKOUT_SPORT_TYPE_ID.STRENGTH_TRAINING,\r\n sportTypeKey: \"strength_training\",\r\n displayOrder: 5,\r\n};\r\n\r\n/** Delegates to `uploadWorkout`, matching the inventory's \"POST (delegates to upload_workout)\". */\r\nexport async function uploadRunningWorkout(\r\n host: WorkoutsHost,\r\n workout: WorkoutInput,\r\n): Promise<WorkoutRecord | null> {\r\n return uploadWorkout(host, buildSportWorkout(workout, RUNNING_SPORT_TYPE));\r\n}\r\n\r\nexport async function uploadCyclingWorkout(\r\n host: WorkoutsHost,\r\n workout: WorkoutInput,\r\n): Promise<WorkoutRecord | null> {\r\n return uploadWorkout(host, buildSportWorkout(workout, CYCLING_SPORT_TYPE));\r\n}\r\n\r\nexport async function uploadSwimmingWorkout(\r\n host: WorkoutsHost,\r\n workout: WorkoutInput,\r\n): Promise<WorkoutRecord | null> {\r\n return uploadWorkout(host, buildSportWorkout(workout, SWIMMING_SPORT_TYPE));\r\n}\r\n\r\nexport async function uploadStrengthWorkout(\r\n host: WorkoutsHost,\r\n workout: WorkoutInput,\r\n): Promise<WorkoutRecord | null> {\r\n return uploadWorkout(host, buildSportWorkout(workout, STRENGTH_SPORT_TYPE));\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Device push\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Multi-step, matching upstream exactly: resolves a missing `deviceId` via the devices service's\r\n * `getDeviceLastUsed()`'s `userDeviceId` (upstream: `get_device_last_used()[\"userDeviceId\"]` — a\r\n * plain dict index that would KeyError on a missing key; translated here as a `GarminError` throw\r\n * rather than letting `undefined.userDeviceId` crash), and a missing `workoutId` via\r\n * the first result of `getWorkouts(0, 1)` (throws `GarminError` matching\r\n * upstream's `ValueError(\"No workouts found to push.\")` if the account has no\r\n * workouts). `messageName` always comes from `getWorkoutById(workoutId)`'s\r\n * `workoutName`. `messageUrl` is the literal relative string upstream sends\r\n * (no leading slash), NOT an absolute path.\r\n *\r\n * Returns the queued device messages — an ARRAY of `DeviceMessage`, live-verified 2026-09-24\r\n * against a real account with a paired device. It was declared `WorkoutRecord | null` until then,\r\n * which was wrong twice over (an array, and of a different record type); nothing caught it because\r\n * the final POST had never successfully run. Pushing the same workout twice returns `[]` the\r\n * second time — the message is already queued.\r\n */\r\nexport async function pushWorkoutToDevice(\r\n host: WorkoutsHost,\r\n workoutId?: number | string,\r\n deviceId?: number | string,\r\n): Promise<DeviceMessage[] | null> {\r\n const resolvedDeviceId = deviceId ?? (await resolveLastUsedDeviceId(host));\r\n const resolvedWorkoutId = workoutId ?? (await resolveFirstWorkoutId(host));\r\n\r\n const workout = await getWorkoutById(host, resolvedWorkoutId);\r\n const messageName = workout?.workoutName;\r\n if (typeof messageName !== \"string\") {\r\n throw new GarminError(\r\n `Cannot push workout ${String(resolvedWorkoutId)}: getWorkoutById returned no workoutName`,\r\n );\r\n }\r\n\r\n return host.client.connectapi<DeviceMessage[]>(\"/device-service/devicemessage/messages\", {\r\n method: \"POST\",\r\n json: [\r\n {\r\n deviceId: resolvedDeviceId,\r\n messageUrl: `workout-service/workout/FIT/${resolvedWorkoutId}`,\r\n messageType: \"workouts\",\r\n groupName: null,\r\n messageName,\r\n priority: 1,\r\n fileType: \"FIT\",\r\n metaDataId: resolvedWorkoutId,\r\n },\r\n ],\r\n });\r\n}\r\n\r\nasync function resolveLastUsedDeviceId(host: WorkoutsHost): Promise<number | string> {\r\n const device = await devices.getDeviceLastUsed(host);\r\n const id = device?.userDeviceId;\r\n if (id === undefined) {\r\n throw new GarminError(\"No last-used device found (userDeviceId missing) to push workout to\");\r\n }\r\n return id;\r\n}\r\n\r\nasync function resolveFirstWorkoutId(host: WorkoutsHost): Promise<number | string> {\r\n const list = await getWorkouts(host, 0, 1);\r\n const id = list?.[0]?.workoutId;\r\n if (id === undefined) {\r\n throw new GarminError(\"No workouts found to push.\");\r\n }\r\n return id;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Scheduling\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * `dict`, passes through unchecked. **Month is 0-indexed on the wire**: this\r\n * takes a normal 1-12 `month` and subtracts 1 before building the URL. Both\r\n * `year` (>=2000) and `month` (1-12) are validated as upstream does.\r\n */\r\nexport async function getScheduledWorkouts(\r\n host: WorkoutsHost,\r\n year: number | string,\r\n month: number | string,\r\n): Promise<CalendarMonth | null> {\r\n const yearNum = Number(year);\r\n const monthNum = Number(month);\r\n if (!Number.isInteger(yearNum) || yearNum < 2000) {\r\n throw new GarminError(`Expected year >= 2000, got \"${String(year)}\"`);\r\n }\r\n if (!Number.isInteger(monthNum) || monthNum < 1 || monthNum > 12) {\r\n throw new GarminError(`Expected month between 1 and 12, got \"${String(month)}\"`);\r\n }\r\n return host.client.connectapi<CalendarMonth>(\r\n `/calendar-service/year/${pathSegment(yearNum)}/month/${pathSegment(monthNum - 1)}`,\r\n );\r\n}\r\n\r\n/**\r\n * `dict`, passes through unchecked. Uses a DIFFERENT base\r\n * (`/workout-service/schedule`) than `getScheduledWorkouts`\r\n * (`/calendar-service`), despite both being about scheduled workouts —\r\n * transcribed verbatim from the inventory, not a typo.\r\n */\r\nexport async function getScheduledWorkoutById(\r\n host: WorkoutsHost,\r\n scheduledWorkoutId: number | string,\r\n): Promise<WorkoutRecord | null> {\r\n return host.client.connectapi<WorkoutRecord>(`/workout-service/schedule/${pathSegment(scheduledWorkoutId)}`);\r\n}\r\n\r\n/**\r\n * Computed, no HTTP path of its own: calls `getScheduledWorkouts` for the\r\n * current month and the next (handling a December->January year rollover),\r\n * treats a falsy/`null` result from either as `{}`, merges `calendarItems`\r\n * from both, filters to `itemType === \"workout\"` with `date >= today`, sorts\r\n * by date, and returns the first match. Returns `{}` (never throws) if\r\n * nothing matches — matching the inventory's documented behaviour.\r\n */\r\nexport async function getNextScheduledWorkout(\r\n host: WorkoutsHost,\r\n): Promise<CalendarItem | Record<string, never>> {\r\n const today = new Date();\r\n const todayStr = formatDate(today);\r\n const year = today.getUTCFullYear();\r\n const month = today.getUTCMonth() + 1; // 1-12\r\n const nextMonth = month === 12 ? 1 : month + 1;\r\n const nextYear = month === 12 ? year + 1 : year;\r\n\r\n const [current, next] = await Promise.all([\r\n getScheduledWorkouts(host, year, month),\r\n getScheduledWorkouts(host, nextYear, nextMonth),\r\n ]);\r\n\r\n const items = [...(current?.calendarItems ?? []), ...(next?.calendarItems ?? [])].filter(\r\n (item): item is CalendarItem & { date: string } =>\r\n item.itemType === \"workout\" && typeof item.date === \"string\" && item.date >= todayStr,\r\n );\r\n items.sort((a, b) => a.date.localeCompare(b.date));\r\n return items[0] ?? {};\r\n}\r\n\r\n/**\r\n * UNCERTAIN (inventory): \"no explicit null handling\". `date_str` is routed\r\n * through `formatDate`, matching upstream's `_validate_date_format`.\r\n */\r\nexport async function scheduleWorkout(\r\n host: WorkoutsHost,\r\n workoutId: number | string,\r\n dateStr: string | Date,\r\n): Promise<WorkoutRecord | null> {\r\n const date = formatDate(dateStr);\r\n return host.client.connectapi<WorkoutRecord>(`/workout-service/schedule/${pathSegment(workoutId)}`, {\r\n method: \"POST\",\r\n json: { date },\r\n });\r\n}\r\n\r\n/**\r\n * UNCERTAIN (inventory): \"no explicit null handling\". Removes the calendar\r\n * entry without deleting the underlying workout template — irreversible.\r\n */\r\nexport async function unscheduleWorkout(\r\n host: WorkoutsHost,\r\n scheduledWorkoutId: number | string,\r\n): Promise<unknown> {\r\n return host.client.connectapi(`/workout-service/schedule/${pathSegment(scheduledWorkoutId)}`, {\r\n method: \"DELETE\",\r\n });\r\n}\r\n","/**\n * ============================================================================================\n * STANDING EXCEPTION to this project's write-verification policy — DO NOT REMOVE THIS COMMENT\n * ============================================================================================\n *\n * Every other service in this port live-verifies its writes with a create -> read-back ->\n * (delete, where possible) round-trip against a dedicated, empty Garmin test account. The five\n * write methods in THIS file (`updateMenstrualDailyLog`, `updateMenstrualCalendar`,\n * `initMenstrualCycleSetup`, `confirmMenstrualPeriodStart`, `updateMenstrualSettings`) are\n * deliberately EXCLUDED from that policy by default and MUST NOT be executed against any live\n * account — not with synthetic values, not \"just to see the error shape.\"\n *\n * ONE EXPLICIT EXEMPTION, granted by the repo owner on 2026-09-23: the dedicated throwaway test\n * account (profileId 151388919) may be written to, on the stated grounds that it is a blank\n * account created solely for testing and that permanent residue there does not matter. That\n * exemption is account-scoped and does not generalise: `scripts/seed-test-account.ts` still\n * refuses to run unless the live profileId matches GARMIN_TEST_PROFILE_ID, and no other account\n * is covered by it. Anyone reusing this library must treat the default rule above as binding.\n *\n * Why: these are irreversible writes to real health-data categories (menstrual-cycle and\n * pregnancy records). None of the five has a documented delete/undo endpoint anywhere in\n * upstream python-garminconnect. `initMenstrualCycleSetup` and `updateMenstrualSettings`\n * plausibly alter account-level configuration (cycle-tracking setup, tracking-preference flags)\n * rather than a single dated record that could plausibly be overwritten back to a neutral state.\n * Unlike other services where an unverified unit conversion was judged a worse risk than\n * permanent throwaway-account residue (see gear's `createGear` duration conversion), there is no\n * equivalent forcing argument here: no unit conversion to get backwards, no silent-corruption\n * risk of the \"93 kg -> 93,000 kg\" kind that only a read-back would catch.\n *\n * These five writes ship IMPLEMENTED and UNIT-TESTED (against MSW-mocked responses only) and are\n * marked in AGENTS.md with the reason stated. Their unit tests — including literal composed-URL\n * and composed-body assertions — were for a long time the ONLY verification they had; under the\n * 2026-09-23 exemption above they are additionally exercised against the test account by\n * `scripts/seed-test-account.ts`. `scripts/smoke-writes.ts` still intentionally has no\n * `womensHealth` entry: the exemption covers a deliberate, gated, one-account seeding run, not\n * routine inclusion in the general write harness.\n *\n * The six read methods in this file (`getMenstrualDataForDate`, `getMenstrualCalendarData`,\n * `getMenstrualLastConfirmed`, `getMenstrualCycleSummary`, `getMenstrualReports`,\n * `getPregnancySummary`) are ordinary GETs with no side effects and ARE live-verified as normal\n * via `scripts/smoke-reads.ts` — that part of this service follows the standard policy.\n */\n\nimport { pathSegment } from \"../util/validate.js\";\n\nimport { GarminError } from \"../errors.js\";\nimport type { GarminClient } from \"../client.js\";\nimport { formatDate, formatGmtTimestamp } from \"../util/date.js\";\nimport type {\n MenstrualCalendarData,\n MenstrualCycleSummary,\n MenstrualDayView,\n MenstrualLastConfirmed,\n MenstrualReports,\n PregnancySummary,\n} from \"../types/womensHealth.js\";\n\n/**\n * `getUserProfile()` is used only as a best-effort source of `userProfilePk` for the write\n * bodies below (see `resolveUserProfilePk`) — mirrors upstream's optional `self.profile_id`.\n * `Garmin` already implements this shape via its cached `getUserProfile()`.\n */\nexport interface WomensHealthHost {\n readonly client: GarminClient;\n getUserProfile(): Promise<{ profileId: number; [key: string]: unknown }>;\n}\n\nconst VALID_REPORT_CYCLE_COUNTS = new Set([1, 6, 12]);\n\n/**\n * Upstream includes `userProfilePk` in the write body only \"if `self.profile_id` set\" — a cached\n * attribute populated elsewhere in the Python client, not something this port has an equivalent\n * cache for outside `Garmin.getUserProfile()`. Implemented as best-effort: fetch the social\n * profile, use its `profileId` if present, and silently omit the field if the fetch fails, rather\n * than failing an otherwise-valid write over a profile-lookup hiccup. This is a port-specific\n * design decision, not a value taken directly from upstream source.\n */\nasync function resolveUserProfilePk(host: WomensHealthHost): Promise<number | undefined> {\n try {\n const profile = await host.getUserProfile();\n return typeof profile.profileId === \"number\" ? profile.profileId : undefined;\n } catch {\n return undefined;\n }\n}\n\n// --- reads ---\n\n/**\n * Upstream `get_menstrual_data_for_date`. `null_behaviour`: passes through unchecked.\n */\nexport async function getMenstrualDataForDate(\n host: WomensHealthHost,\n fordate: string | Date,\n): Promise<MenstrualDayView | null> {\n return host.client.connectapi<MenstrualDayView>(\n `/periodichealth-service/menstrualcycle/dayview/${pathSegment(formatDate(fordate))}`,\n );\n}\n\n/**\n * Upstream `get_menstrual_calendar_data`. `null_behaviour`: passes through unchecked. Upstream's\n * own docstring warns Garmin rejects windows of 92+ inclusive days (keep the range <= 90 days);\n * this is NOT enforced here, matching upstream, which also leaves it to the caller.\n */\nexport async function getMenstrualCalendarData(\n host: WomensHealthHost,\n startdate: string | Date,\n enddate: string | Date,\n): Promise<MenstrualCalendarData | null> {\n const start = formatDate(startdate);\n const end = formatDate(enddate);\n return host.client.connectapi<MenstrualCalendarData>(\n `/periodichealth-service/menstrualcycle/calendar/${pathSegment(start)}/${pathSegment(end)}`,\n );\n}\n\n/**\n * Upstream `get_menstrual_last_confirmed`. `null_behaviour`: passes through unchecked.\n */\nexport async function getMenstrualLastConfirmed(\n host: WomensHealthHost,\n fordate: string | Date,\n): Promise<MenstrualLastConfirmed | null> {\n return host.client.connectapi<MenstrualLastConfirmed>(\n `/periodichealth-service/menstrualcycle/lastconfirmed/${pathSegment(formatDate(fordate))}`,\n );\n}\n\n/**\n * Upstream `get_menstrual_cycle_summary`. `null_behaviour`: passes through unchecked.\n */\nexport async function getMenstrualCycleSummary(\n host: WomensHealthHost,\n fordate: string | Date,\n): Promise<MenstrualCycleSummary | null> {\n return host.client.connectapi<MenstrualCycleSummary>(\n `/periodichealth-service/menstrualcycle/summary/${pathSegment(formatDate(fordate))}`,\n );\n}\n\n/**\n * Upstream `get_menstrual_reports`. `null_behaviour`: passes through unchecked.\n * `numberOfCycles` is restricted to `{1, 6, 12}` (upstream's `VALID_MENSTRUAL_REPORT_CYCLES`) —\n * any other value throws `GarminError`, mirroring upstream's `ValueError`. `todayCalendarDate`\n * defaults to today (routed through `formatDate` either way). `reportType` is trimmed, matching\n * upstream's `.strip()`.\n */\nexport async function getMenstrualReports(\n host: WomensHealthHost,\n fordate: string | Date,\n numberOfCycles = 6,\n options: {\n nextReport?: boolean;\n reportType?: string;\n todayCalendarDate?: string | Date;\n } = {},\n): Promise<MenstrualReports | null> {\n const date = formatDate(fordate);\n if (!VALID_REPORT_CYCLE_COUNTS.has(numberOfCycles)) {\n throw new GarminError(\n `number_of_cycles must be one of 1, 6, or 12; got ${numberOfCycles}`,\n );\n }\n const todayCalendarDate = formatDate(options.todayCalendarDate ?? new Date());\n const reportType = (options.reportType ?? \"CYCLE\").trim();\n return host.client.connectapi<MenstrualReports>(\n `/periodichealth-service/reports/menstrualcycle/${pathSegment(numberOfCycles)}/${pathSegment(date)}`,\n {\n params: {\n next: String(options.nextReport ?? false),\n reportType,\n todayCalendarDate,\n },\n },\n );\n}\n\n/**\n * Upstream `get_pregnancy_summary`. `null_behaviour`: passes through unchecked.\n */\nexport async function getPregnancySummary(\n host: WomensHealthHost,\n): Promise<PregnancySummary | null> {\n return host.client.connectapi<PregnancySummary>(\n \"/periodichealth-service/menstrualcycle/pregnancysnapshot\",\n );\n}\n\n// --- writes ---\n// See the file-level comment at the top of this file: NONE of the following five methods may be\n// executed against a live account, ever. All were verified by unit test only.\n\nfunction isEmptyCollection(value: unknown): boolean {\n if (typeof value === \"string\") return value.length === 0;\n if (Array.isArray(value)) return value.length === 0;\n if (typeof value === \"object\" && value !== null) return Object.keys(value).length === 0;\n return false;\n}\n\n/**\n * Mirrors upstream's `_clean_menstrual_daily_log`: drops any key whose value is `undefined`\n * (Python `None`), and drops any key whose value is an empty string/array/object — EXCEPT\n * `notes`, which is exempt so `notes: \"\"` (explicit clear) survives while `notes: undefined`\n * (omitted, preserve existing) is dropped by the first rule.\n */\nfunction cleanMenstrualDailyLog(body: Record<string, unknown>): Record<string, unknown> {\n const cleaned: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(body)) {\n if (value === undefined || value === null) continue;\n if (key !== \"notes\" && isEmptyCollection(value)) continue;\n cleaned[key] = value;\n }\n return cleaned;\n}\n\n/**\n * Upstream `update_menstrual_daily_log`. UNCERTAIN (inventory): \"no explicit null handling on the\n * response\" — implemented as a raw pass-through (`Promise<unknown>`), same convention as every\n * other UNCERTAIN write in this port (see e.g. `createGear`). What would resolve it: observing a\n * real response body, which this service is deliberately never allowed to do (see file-level\n * comment).\n *\n * **This is a full-day replace, not a field-level merge** — matching upstream, an omitted field\n * (`undefined`) is dropped from the body entirely (server-side: cleared), while `notes: \"\"`\n * (explicit empty string) is sent and clears the note; `notes: undefined` preserves the existing\n * note. This distinction is load-bearing and intentionally preserved, per the inventory notes.\n *\n * At least one of the optional fields must be provided, or this throws `GarminError` before\n * making a request — guards against an accidental full-day wipe, mirroring upstream's `ValueError`.\n *\n * `discharge` rejects combining `\"NO_DISCHARGE\"` with any other value, mirroring upstream.\n *\n * **Known gap, not one of the inventory's UNCERTAIN rows but worth flagging honestly**: upstream\n * validates/normalizes `symptoms`/`moods`/`flow`/`discharge`/`sexDrive`/`sexualActivity` against\n * fixed enum sets (`VALID_MENSTRUAL_SYMPTOMS`, etc.) whose exact member values are not captured in\n * `docs/upstream-method-inventory.md`. Rather than invent a member list, this port only\n * upper-cases the caller's strings (matching upstream's normalization step) without whitelisting\n * them — an invalid value will surface as a Garmin-side rejection instead of a local one. Would be\n * resolved by reading `garminconnect/__init__.py`'s literal enum definitions upstream.\n *\n * `reportTimestamp` uses the UTC formatter (`formatGmtTimestamp`), NOT the local-time formatter\n * used by weight/blood-pressure/hydration writes — matches upstream's `_fmt_ts_utc()` for this\n * endpoint specifically.\n */\nexport async function updateMenstrualDailyLog(\n host: WomensHealthHost,\n calendarDate: string | Date,\n options: {\n symptoms?: string[];\n moods?: string[];\n flow?: string;\n discharge?: string[];\n sexDrive?: string;\n sexualActivity?: string;\n notes?: string;\n ovulationDay?: boolean;\n } = {},\n): Promise<unknown> {\n const date = formatDate(calendarDate);\n\n const hasAnyField =\n options.symptoms !== undefined ||\n options.moods !== undefined ||\n options.flow !== undefined ||\n options.discharge !== undefined ||\n options.sexDrive !== undefined ||\n options.sexualActivity !== undefined ||\n options.notes !== undefined ||\n options.ovulationDay !== undefined;\n if (!hasAnyField) {\n throw new GarminError(\n \"updateMenstrualDailyLog requires at least one field besides calendarDate \" +\n \"(this guards against an accidental full-day wipe, since omitted fields are cleared server-side)\",\n );\n }\n\n const discharge = options.discharge?.map((value) => value.toUpperCase());\n if (discharge && discharge.includes(\"NO_DISCHARGE\") && discharge.length > 1) {\n throw new GarminError('\"NO_DISCHARGE\" cannot be combined with any other discharge value');\n }\n\n const pk = await resolveUserProfilePk(host);\n\n const rawBody: Record<string, unknown> = {\n calendarDate: date,\n symptoms: options.symptoms?.map((value) => value.toUpperCase()),\n moods: options.moods?.map((value) => value.toUpperCase()),\n flow: options.flow?.toUpperCase(),\n discharge,\n sexDrive: options.sexDrive?.toUpperCase(),\n sexualActivity: options.sexualActivity?.toUpperCase(),\n notes: options.notes,\n ovulationDay: options.ovulationDay ?? false,\n reportTimestamp: formatGmtTimestamp(new Date()),\n ...(pk !== undefined ? { userProfilePk: pk } : {}),\n };\n\n return host.client.connectapi(`/periodichealth-service/menstrualcycle/dailylog/${pathSegment(date)}`, {\n method: \"POST\",\n json: cleanMenstrualDailyLog(rawBody),\n });\n}\n\n/** One calendar-day-apart check, used to validate each `cycleDatesLists` group is consecutive. */\nfunction assertConsecutiveDates(dates: string[], groupIndex: number): void {\n for (let i = 1; i < dates.length; i++) {\n const prevMs = Date.parse(`${dates[i - 1]}T00:00:00Z`);\n const curMs = Date.parse(`${dates[i]}T00:00:00Z`);\n if (curMs - prevMs !== 86_400_000) {\n throw new GarminError(\n `cycleDatesLists[${groupIndex}] must be consecutive calendar dates; ` +\n `\"${dates[i - 1]}\" is not immediately followed by \"${dates[i]}\"`,\n );\n }\n }\n}\n\n/**\n * Upstream `update_menstrual_calendar`. UNCERTAIN (inventory): \"no explicit null handling\" —\n * implemented as a raw pass-through (`Promise<unknown>`), see `updateMenstrualDailyLog`'s doc\n * comment for the general UNCERTAIN convention used across this port.\n *\n * **This is also a full replace, not a merge** — matching upstream, omitted previously-confirmed\n * days within `[startdate, enddate]` are removed server-side by this call.\n *\n * `cycleDatesLists` is validated exactly as upstream: each inner group must be non-empty and\n * consist of consecutive calendar dates, and every date in every group must fall within\n * `[startdate, enddate]` (inclusive) — any violation throws `GarminError` before a request is\n * made, mirroring upstream's `ValueError`. Predicted (unconfirmed) cycles should not be posted\n * here, per upstream's docstring — not enforced in code, since there is no way to distinguish a\n * predicted date from a confirmed one at this layer; it is the caller's responsibility, same as\n * upstream.\n *\n * `reportTimestamp` uses `formatGmtTimestamp` (UTC), matching upstream's `_fmt_ts_utc()`.\n */\nexport async function updateMenstrualCalendar(\n host: WomensHealthHost,\n startdate: string | Date,\n enddate: string | Date,\n cycleDatesLists: (string | Date)[][],\n options: { todayCalendarDate?: string | Date } = {},\n): Promise<unknown> {\n const start = formatDate(startdate);\n const end = formatDate(enddate);\n\n const normalizedLists = cycleDatesLists.map((group, index) => {\n if (group.length === 0) {\n throw new GarminError(`cycleDatesLists[${index}] must be non-empty`);\n }\n const formatted = group.map((value) => formatDate(value));\n assertConsecutiveDates(formatted, index);\n for (const date of formatted) {\n if (date < start || date > end) {\n throw new GarminError(\n `cycleDatesLists[${index}] date \"${date}\" falls outside [${start}, ${end}]`,\n );\n }\n }\n return formatted;\n });\n\n const todayCalendarDate = formatDate(options.todayCalendarDate ?? new Date());\n const pk = await resolveUserProfilePk(host);\n\n return host.client.connectapi(\"/periodichealth-service/menstrualcycle/calendarupdates\", {\n method: \"POST\",\n json: {\n todayCalendarDate,\n startDate: start,\n endDate: end,\n reportTimestamp: formatGmtTimestamp(new Date()),\n cycleDatesLists: normalizedLists,\n futureEditsByFE: true,\n ...(pk !== undefined ? { userProfilePk: pk } : {}),\n },\n });\n}\n\n/**\n * Upstream `init_menstrual_cycle_setup`. UNCERTAIN (inventory): \"no explicit null handling\" —\n * implemented as a raw pass-through (`Promise<unknown>`).\n *\n * Upstream's docstring warns Garmin's own first-run wizard also PUTs user menstrual settings\n * (tracking-preference flags) in the same save; this method deliberately does NOT do that — call\n * `updateMenstrualSettings` separately if those flags need to change. Not intended for editing an\n * already-configured account.\n *\n * `reportTimestamp` uses `formatGmtTimestamp` (UTC), matching upstream's `_fmt_ts_utc()`.\n */\nexport async function initMenstrualCycleSetup(\n host: WomensHealthHost,\n periodStartDate: string | Date,\n periodLength: number,\n cycleLength: number,\n): Promise<unknown> {\n const date = formatDate(periodStartDate);\n const pk = await resolveUserProfilePk(host);\n return host.client.connectapi(\"/periodichealth-service/menstrualcycle/initCycleSetup\", {\n method: \"POST\",\n json: {\n periodStartDate: date,\n periodLength,\n cycleLength,\n reportTimestamp: formatGmtTimestamp(new Date()),\n ...(pk !== undefined ? { userProfilePk: pk } : {}),\n },\n });\n}\n\n/**\n * Upstream `confirm_menstrual_period_start`. UNCERTAIN (inventory): \"no explicit null handling\" —\n * implemented as a raw pass-through (`Promise<unknown>`).\n *\n * Can convert a predicted cycle into a confirmed period (`options.predictedCycle: true`).\n *\n * **Path base is `/periodichealth-service/menstrualcycle` directly** — NOT the `dayview`/\n * `calendar`/`lastconfirmed`/`summary` sub-paths used by the read methods above; easy to mix up,\n * called out explicitly in the inventory notes.\n *\n * `reportTimestamp` uses `formatGmtTimestamp` (UTC), matching upstream's `_fmt_ts_utc()`.\n */\nexport async function confirmMenstrualPeriodStart(\n host: WomensHealthHost,\n periodStartDate: string | Date,\n periodLength: number,\n cycleLength: number,\n options: { predictedCycle?: boolean } = {},\n): Promise<unknown> {\n const date = formatDate(periodStartDate);\n const pk = await resolveUserProfilePk(host);\n return host.client.connectapi(`/periodichealth-service/menstrualcycle/${pathSegment(date)}`, {\n method: \"POST\",\n json: {\n periodStartDate: date,\n periodLength,\n cycleLength,\n predictedCycle: options.predictedCycle ?? false,\n hasSpecifiedCycleLength: true,\n hasSpecifiedPeriodLength: true,\n reportTimestamp: formatGmtTimestamp(new Date()),\n ...(pk !== undefined ? { userProfilePk: pk } : {}),\n },\n });\n}\n\n/** Shape of `GET /userprofile-service/userprofile/user-settings`, as consumed by `updateMenstrualSettings`. */\ninterface UserSettingsSnapshot {\n id?: unknown;\n userMenstrualCycleSettings?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n/**\n * Upstream `update_menstrual_settings`. UNCERTAIN (inventory): \"no explicit null handling on the\n * PUT response\" — implemented as a raw pass-through (`Promise<unknown>`).\n *\n * `settings` must be a non-empty object, or this throws `GarminError` before any request,\n * mirroring upstream's `ValueError`.\n *\n * **Multi-step, matching upstream exactly**: first GETs the SAME endpoint this then PUTs\n * (`/userprofile-service/userprofile/user-settings` — this is also what `Garmin.getUserSettings()`\n * / upstream `get_user_profile()` hits) to read the current `userMenstrualCycleSettings`, used as\n * an overlay base — the caller's `settings` keys win, keys the caller omitted are preserved from\n * the current state. This is a deliberate direct GET, not `Garmin`'s cached `getUserSettings()`,\n * so the merge always overlays onto freshly-read state rather than a possibly-stale cache.\n *\n * If `options.userSettingsId` is not given, this tries to pull `id` from that same GET response\n * and include it as `id` in the PUT body — only if it is a `number` (mirrors upstream's \"non-bool\n * int\" check; a JS `boolean` is never `typeof === \"number\"`, so no separate bool guard is needed).\n *\n * Pregnancy-only fields are explicitly out of scope for this method, per upstream's docstring.\n */\nexport async function updateMenstrualSettings(\n host: WomensHealthHost,\n settings: Record<string, unknown>,\n options: { userSettingsId?: number } = {},\n): Promise<unknown> {\n if (Object.keys(settings).length === 0) {\n throw new GarminError(\"settings must be a non-empty object\");\n }\n\n const path = \"/userprofile-service/userprofile/user-settings\";\n const current = await host.client.connectapi<UserSettingsSnapshot>(path);\n const currentMenstrualSettings = current?.userMenstrualCycleSettings ?? {};\n const merged = { ...currentMenstrualSettings, ...settings };\n\n let userSettingsId = options.userSettingsId;\n if (userSettingsId === undefined && typeof current?.id === \"number\") {\n userSettingsId = current.id;\n }\n\n return host.client.connectapi(path, {\n method: \"PUT\",\n json: {\n userMenstrualCycleSettings: merged,\n ...(userSettingsId !== undefined ? { id: userSettingsId } : {}),\n },\n });\n}\n","import type { GarminClient } from \"./client.js\";\r\nimport { GarminError } from \"./errors.js\";\r\nimport * as activities from \"./services/activities.js\";\r\nimport * as badges from \"./services/badges.js\";\r\nimport * as bodyComposition from \"./services/bodyComposition.js\";\r\nimport * as courses from \"./services/courses.js\";\r\nimport * as devices from \"./services/devices.js\";\r\nimport * as gear from \"./services/gear.js\";\r\nimport * as goals from \"./services/goals.js\";\r\nimport * as golf from \"./services/golf.js\";\r\nimport * as metrics from \"./services/metrics.js\";\r\nimport * as misc from \"./services/misc.js\";\r\nimport * as nutrition from \"./services/nutrition.js\";\r\nimport * as trainingPlans from \"./services/trainingPlans.js\";\r\nimport * as weight from \"./services/weight.js\";\r\nimport * as wellness from \"./services/wellness.js\";\r\nimport * as userProfile from \"./services/userProfile.js\";\r\nimport * as workouts from \"./services/workouts.js\";\r\nimport * as womensHealth from \"./services/womensHealth.js\";\r\nimport type { ActivityDownloadFormat, ActivityExerciseSets } from \"./types/activities.js\";\r\nimport type { CourseInput, CourseUpdate } from \"./types/courses.js\";\r\nimport type { GearUsageType } from \"./types/gear.js\";\r\nimport type { GoalStatus } from \"./types/goals.js\";\r\nimport type { FtpAggregation, RunningToleranceAggregation } from \"./types/metrics.js\";\r\nimport type { WorkoutInput } from \"./types/workouts.js\";\r\nimport type { WeightScaleFields } from \"./util/fit.js\";\r\n\r\nexport interface SocialProfile {\r\n displayName: string;\r\n userName: string;\r\n fullName: string;\r\n profileId: number;\r\n [key: string]: unknown;\r\n}\r\n\r\n/** Response of `/userprofile-service/userprofile/user-settings`. */\r\nexport interface UserSettings {\r\n id?: number;\r\n userData?: {\r\n measurementSystem?: string;\r\n [key: string]: unknown;\r\n };\r\n [key: string]: unknown;\r\n}\r\n\r\nexport class Garmin {\r\n #profile: Promise<SocialProfile> | null = null;\r\n #settings: Promise<UserSettings> | null = null;\r\n\r\n constructor(readonly client: GarminClient) {}\r\n\r\n /** Cached per instance; every date-scoped endpoint needs the display name. */\r\n getUserProfile(): Promise<SocialProfile> {\r\n this.#profile ??= (async () => {\r\n const profile = await this.client.connectapi<SocialProfile>(\r\n \"/userprofile-service/socialProfile\",\r\n );\r\n if (!profile) throw new GarminError(\"Garmin returned no user profile\");\r\n return profile;\r\n })().catch((error: unknown) => {\r\n this.#profile = null; // allow a retry on the next call\r\n throw error;\r\n });\r\n return this.#profile;\r\n }\r\n\r\n /** Cached per instance, same eviction-on-failure pattern as `getUserProfile()`. */\r\n getUserSettings(): Promise<UserSettings> {\r\n this.#settings ??= (async () => {\r\n const settings = await this.client.connectapi<UserSettings>(\r\n \"/userprofile-service/userprofile/user-settings\",\r\n );\r\n if (!settings) throw new GarminError(\"Garmin returned no user settings\");\r\n return settings;\r\n })().catch((error: unknown) => {\r\n this.#settings = null; // allow a retry on the next call\r\n throw error;\r\n });\r\n return this.#settings;\r\n }\r\n\r\n async displayName(): Promise<string> {\r\n return (await this.getUserProfile()).displayName;\r\n }\r\n\r\n async fullName(): Promise<string> {\r\n return (await this.getUserProfile()).fullName;\r\n }\r\n\r\n async userName(): Promise<string> {\r\n return (await this.getUserProfile()).userName;\r\n }\r\n\r\n /**\r\n * `measurementSystem` lives on `/userprofile-service/userprofile/user-settings`\r\n * (under `userData`), not on the social profile. A convenience accessor, not\r\n * a data endpoint: returns `undefined` rather than throwing if the payload\r\n * shape is missing.\r\n */\r\n async unitSystem(): Promise<string | undefined> {\r\n return (await this.getUserSettings()).userData?.measurementSystem;\r\n }\r\n\r\n // --- userProfile ---\r\n /**\r\n * Upstream `get_userprofile_settings` — `/userprofile-service/userprofile/settings` (SINGULAR\r\n * \"settings\", distinct from `getUserSettings()`'s \"user-settings\"). Upstream's `get_user_profile`,\r\n * `get_full_name`, and `get_unit_system` are NOT ported as separate methods here: they map onto\r\n * this port's pre-existing `getUserSettings()`, `fullName()`, and `unitSystem()` respectively —\r\n * see the file-level comment in `src/services/userProfile.ts` for the full ruling.\r\n */\r\n getUserprofileSettings() {\r\n return userProfile.getUserprofileSettings(this);\r\n }\r\n\r\n // --- wellness ---\r\n getUserSummary(cdate: string | Date) {\r\n return wellness.getUserSummary(this, cdate);\r\n }\r\n /** Alias kept for parity with python-garminconnect's get_stats. */\r\n getStats(cdate: string | Date) {\r\n return wellness.getUserSummary(this, cdate);\r\n }\r\n getStepsData(cdate: string | Date) {\r\n return wellness.getStepsData(this, cdate);\r\n }\r\n getHeartRates(cdate: string | Date) {\r\n return wellness.getHeartRates(this, cdate);\r\n }\r\n getSleepData(cdate: string | Date) {\r\n return wellness.getSleepData(this, cdate);\r\n }\r\n getHrvData(cdate: string | Date) {\r\n return wellness.getHrvData(this, cdate);\r\n }\r\n getBodyBattery(startdate: string | Date, enddate?: string | Date) {\r\n return wellness.getBodyBattery(this, startdate, enddate);\r\n }\r\n getBodyBatteryEvents(cdate: string | Date) {\r\n return wellness.getBodyBatteryEvents(this, cdate);\r\n }\r\n getFloors(cdate: string | Date) {\r\n return wellness.getFloors(this, cdate);\r\n }\r\n getDailySteps(start: string | Date, end: string | Date) {\r\n return wellness.getDailySteps(this, start, end);\r\n }\r\n getWeeklySteps(end: string | Date, weeks?: number) {\r\n return wellness.getWeeklySteps(this, end, weeks);\r\n }\r\n getWeeklyStress(end: string | Date, weeks?: number) {\r\n return wellness.getWeeklyStress(this, end, weeks);\r\n }\r\n getWeeklyIntensityMinutes(start: string | Date, end: string | Date) {\r\n return wellness.getWeeklyIntensityMinutes(this, start, end);\r\n }\r\n getStatsAndBody(cdate: string | Date) {\r\n return wellness.getStatsAndBody(this, cdate);\r\n }\r\n setBloodPressure(\r\n systolic: number,\r\n diastolic: number,\r\n pulse?: number,\r\n when?: Date,\r\n notes?: string,\r\n ) {\r\n return wellness.setBloodPressure(this, systolic, diastolic, pulse, when, notes);\r\n }\r\n getBloodPressure(startdate: string | Date, enddate?: string | Date) {\r\n return wellness.getBloodPressure(this, startdate, enddate);\r\n }\r\n deleteBloodPressure(version: number | string, cdate: string | Date) {\r\n return wellness.deleteBloodPressure(this, version, cdate);\r\n }\r\n addHydrationData(valueInMl: number, when?: Date, cdate?: string | Date) {\r\n return wellness.addHydrationData(this, valueInMl, when, cdate);\r\n }\r\n getHydrationData(cdate: string | Date) {\r\n return wellness.getHydrationData(this, cdate);\r\n }\r\n getRespirationData(cdate: string | Date) {\r\n return wellness.getRespirationData(this, cdate);\r\n }\r\n getSpo2Data(cdate: string | Date) {\r\n return wellness.getSpo2Data(this, cdate);\r\n }\r\n getIntensityMinutesData(cdate: string | Date) {\r\n return wellness.getIntensityMinutesData(this, cdate);\r\n }\r\n getAllDayStress(cdate: string | Date) {\r\n return wellness.getAllDayStress(this, cdate);\r\n }\r\n getStressData(cdate: string | Date) {\r\n return wellness.getStressData(this, cdate);\r\n }\r\n getAllDayEvents(cdate: string | Date) {\r\n return wellness.getAllDayEvents(this, cdate);\r\n }\r\n getSleepDaily(start: string | Date, end: string | Date) {\r\n return wellness.getSleepDaily(this, start, end);\r\n }\r\n getRhrDay(cdate: string | Date) {\r\n return wellness.getRhrDay(this, cdate);\r\n }\r\n getRhrDaily(start: string | Date, end: string | Date) {\r\n return wellness.getRhrDaily(this, start, end);\r\n }\r\n getCaloriesDaily(start: string | Date, end: string | Date) {\r\n return wellness.getCaloriesDaily(this, start, end);\r\n }\r\n getHrvDataRange(start: string | Date, end: string | Date) {\r\n return wellness.getHrvDataRange(this, start, end);\r\n }\r\n\r\n // --- activities ---\r\n countActivities() {\r\n return activities.countActivities(this);\r\n }\r\n getActivities(start?: number, limit?: number) {\r\n return activities.getActivities(this, start, limit);\r\n }\r\n getActivitiesForDate(fordate: string | Date) {\r\n return activities.getActivitiesForDate(this, fordate);\r\n }\r\n getActivitiesByDate(\r\n startdate: string | Date,\r\n enddate?: string | Date,\r\n activitytype?: string,\r\n sortorder?: string,\r\n ) {\r\n return activities.getActivitiesByDate(this, startdate, enddate, activitytype, sortorder);\r\n }\r\n getLastActivity() {\r\n return activities.getLastActivity(this);\r\n }\r\n getActivity(activityId: number | string) {\r\n return activities.getActivity(this, activityId);\r\n }\r\n getActivityTypes() {\r\n return activities.getActivityTypes(this);\r\n }\r\n deleteActivity(activityId: number | string) {\r\n return activities.deleteActivity(this, activityId);\r\n }\r\n setActivityName(activityId: number | string, activityName: string) {\r\n return activities.setActivityName(this, activityId, activityName);\r\n }\r\n setActivityType(activityId: number | string, typeId: number, typeKey: string, parentTypeId: number) {\r\n return activities.setActivityType(this, activityId, typeId, typeKey, parentTypeId);\r\n }\r\n setActivityDescription(activityId: number | string, description: string) {\r\n return activities.setActivityDescription(this, activityId, description);\r\n }\r\n createManualActivityFromJson(payload: Record<string, unknown>) {\r\n return activities.createManualActivityFromJson(this, payload);\r\n }\r\n createManualActivity(\r\n startDatetime: string,\r\n timeZone: string,\r\n typeKey: string,\r\n distanceKm: number,\r\n durationMin: number,\r\n activityName: string,\r\n ) {\r\n return activities.createManualActivity(\r\n this,\r\n startDatetime,\r\n timeZone,\r\n typeKey,\r\n distanceKm,\r\n durationMin,\r\n activityName,\r\n );\r\n }\r\n importActivity(file: Blob, filename: string) {\r\n return activities.importActivity(this, file, filename);\r\n }\r\n uploadActivity(file: Blob, filename: string) {\r\n return activities.uploadActivity(this, file, filename);\r\n }\r\n getPersonalRecord() {\r\n return activities.getPersonalRecord(this);\r\n }\r\n downloadActivity(activityId: number | string, format?: ActivityDownloadFormat) {\r\n return activities.downloadActivity(this, activityId, format);\r\n }\r\n getActivitySplits(activityId: number | string) {\r\n return activities.getActivitySplits(this, activityId);\r\n }\r\n getActivityTypedSplits(activityId: number | string) {\r\n return activities.getActivityTypedSplits(this, activityId);\r\n }\r\n getActivitySplitSummaries(activityId: number | string) {\r\n return activities.getActivitySplitSummaries(this, activityId);\r\n }\r\n getActivityWeather(activityId: number | string) {\r\n return activities.getActivityWeather(this, activityId);\r\n }\r\n getActivityHrInTimezones(activityId: number | string) {\r\n return activities.getActivityHrInTimezones(this, activityId);\r\n }\r\n getActivityPowerInTimezones(activityId: number | string) {\r\n return activities.getActivityPowerInTimezones(this, activityId);\r\n }\r\n getActivityDetails(activityId: number | string, maxchart?: number, maxpoly?: number) {\r\n return activities.getActivityDetails(this, activityId, maxchart, maxpoly);\r\n }\r\n getActivityExerciseSets(activityId: number | string) {\r\n return activities.getActivityExerciseSets(this, activityId);\r\n }\r\n setActivityExerciseSets(activityId: number | string, payload: ActivityExerciseSets) {\r\n return activities.setActivityExerciseSets(this, activityId, payload);\r\n }\r\n getActivityGear(activityId: number | string) {\r\n return activities.getActivityGear(this, activityId);\r\n }\r\n getGearActivities(gearUUID: string, limit?: number) {\r\n return activities.getGearActivities(this, gearUUID, limit);\r\n }\r\n addGearToActivity(gearUUID: string, activityId: number | string) {\r\n return activities.addGearToActivity(this, gearUUID, activityId);\r\n }\r\n removeGearFromActivity(gearUUID: string, activityId: number | string) {\r\n return activities.removeGearFromActivity(this, gearUUID, activityId);\r\n }\r\n getProgressSummaryBetweenDates(\r\n startdate: string | Date,\r\n enddate: string | Date,\r\n metric?: string,\r\n groupbyactivities?: boolean,\r\n ) {\r\n return activities.getProgressSummaryBetweenDates(\r\n this,\r\n startdate,\r\n enddate,\r\n metric,\r\n groupbyactivities,\r\n );\r\n }\r\n downloadHealthSnapshot(requestedDate: string | Date) {\r\n return activities.downloadHealthSnapshot(this, requestedDate);\r\n }\r\n\r\n // --- gear ---\r\n getGear(userProfileNumber: number | string) {\r\n return gear.getGear(this, userProfileNumber);\r\n }\r\n createGear(\r\n gearType: string,\r\n brand: string,\r\n model: string,\r\n name: string,\r\n firstUseDate: string | Date,\r\n usageType?: GearUsageType,\r\n maxUsageDistanceKm?: number,\r\n maxUsageDurationMin?: number,\r\n notes?: string,\r\n activityTypeKeys?: string[],\r\n ) {\r\n return gear.createGear(\r\n this,\r\n gearType,\r\n brand,\r\n model,\r\n name,\r\n firstUseDate,\r\n usageType,\r\n maxUsageDistanceKm,\r\n maxUsageDurationMin,\r\n notes,\r\n activityTypeKeys,\r\n );\r\n }\r\n getGearStats(gearUUID: string) {\r\n return gear.getGearStats(this, gearUUID);\r\n }\r\n /**\r\n * NOT upstream parity — upstream has no delete-gear method. Endpoint discovered by observing\r\n * Garmin's own web client; see `src/services/gear.ts`. IRREVERSIBLE.\r\n */\r\n deleteGear(gearUUID: string) {\r\n return gear.deleteGear(this, gearUUID);\r\n }\r\n /**\r\n * NOT upstream parity — the replacement for upstream's `set_gear_default`, whose endpoint is\r\n * dead and which this port therefore does NOT expose. Uses the v2 full-record PUT Garmin's own\r\n * web client uses. See `src/services/gear.ts`.\r\n */\r\n setGearActivityDefaults(gearUUID: string, activityTypeKeys: string[]) {\r\n return gear.setGearActivityDefaults(this, gearUUID, activityTypeKeys);\r\n }\r\n getGearDefaults(userProfileNumber: number | string) {\r\n return gear.getGearDefaults(this, userProfileNumber);\r\n }\r\n\r\n // --- courses (NOT upstream parity — python-garminconnect has no course methods) ---\r\n listCourses() {\r\n return courses.listCourses(this);\r\n }\r\n getCourse(courseId: number | string) {\r\n return courses.getCourse(this, courseId);\r\n }\r\n /** Parses a GPX file into a course WITHOUT saving it (`courseId: null`). */\r\n importCourseGpx(file: Blob, filename: string) {\r\n return courses.importCourseGpx(this, file, filename);\r\n }\r\n createCourse(input: CourseInput) {\r\n return courses.createCourse(this, input);\r\n }\r\n /** `importCourseGpx` then `createCourse`, in one call. */\r\n createCourseFromGpx(\r\n file: Blob,\r\n filename: string,\r\n options?: Omit<CourseInput, \"geoPoints\" | \"coursePoints\" | \"name\"> & { name?: string },\r\n ) {\r\n return courses.createCourseFromGpx(this, file, filename, options);\r\n }\r\n /** Rename and/or change privacy. Read-modify-write of the whole record. */\r\n updateCourse(courseId: number | string, changes: CourseUpdate) {\r\n return courses.updateCourse(this, courseId, changes);\r\n }\r\n /** IRREVERSIBLE. A course created seconds ago may 429 \"not yet ready\"; retry shortly. */\r\n deleteCourse(courseId: number | string) {\r\n return courses.deleteCourse(this, courseId);\r\n }\r\n downloadCourseGpx(courseId: number | string) {\r\n return courses.downloadCourseGpx(this, courseId);\r\n }\r\n\r\n // --- devices ---\r\n getDevices() {\r\n return devices.getDevices(this);\r\n }\r\n getDeviceSettings(deviceId: number | string) {\r\n return devices.getDeviceSettings(this, deviceId);\r\n }\r\n getPrimaryTrainingDevice() {\r\n return devices.getPrimaryTrainingDevice(this);\r\n }\r\n getDeviceSolarData(deviceId: number | string, startdate: string | Date, enddate?: string | Date) {\r\n return devices.getDeviceSolarData(this, deviceId, startdate, enddate);\r\n }\r\n getDeviceAlarms() {\r\n return devices.getDeviceAlarms(this);\r\n }\r\n getDeviceLastUsed() {\r\n return devices.getDeviceLastUsed(this);\r\n }\r\n\r\n // --- badges & challenges ---\r\n getEarnedBadges() {\r\n return badges.getEarnedBadges(this);\r\n }\r\n getAvailableBadges() {\r\n return badges.getAvailableBadges(this);\r\n }\r\n getInProgressBadges() {\r\n return badges.getInProgressBadges(this);\r\n }\r\n getBadgeDetail(badgeId: number) {\r\n return badges.getBadgeDetail(this, badgeId);\r\n }\r\n getAdhocChallenges(start: number, limit: number) {\r\n return badges.getAdhocChallenges(this, start, limit);\r\n }\r\n getBadgeChallenges(start: number, limit: number) {\r\n return badges.getBadgeChallenges(this, start, limit);\r\n }\r\n getAvailableBadgeChallenges(start: number, limit: number) {\r\n return badges.getAvailableBadgeChallenges(this, start, limit);\r\n }\r\n getNonCompletedBadgeChallenges(start: number, limit: number) {\r\n return badges.getNonCompletedBadgeChallenges(this, start, limit);\r\n }\r\n getInprogressVirtualChallenges(start: number, limit: number) {\r\n return badges.getInprogressVirtualChallenges(this, start, limit);\r\n }\r\n\r\n // --- weight ---\r\n getWeighIns(startdate: string | Date, enddate: string | Date) {\r\n return weight.getWeighIns(this, startdate, enddate);\r\n }\r\n addWeighIn(weightValue: number, unitKey?: \"kg\" | \"lbs\", when?: Date) {\r\n return weight.addWeighIn(this, weightValue, unitKey, when);\r\n }\r\n deleteWeighIn(cdate: string | Date, weightPk: number) {\r\n return weight.deleteWeighIn(this, cdate, weightPk);\r\n }\r\n addWeighInWithTimestamps(\r\n weightValue: number,\r\n unitKey?: \"kg\" | \"lbs\",\r\n dateTimestamp?: string,\r\n gmtTimestamp?: string,\r\n when?: Date,\r\n ) {\r\n return weight.addWeighInWithTimestamps(\r\n this,\r\n weightValue,\r\n unitKey,\r\n dateTimestamp,\r\n gmtTimestamp,\r\n when,\r\n );\r\n }\r\n getDailyWeighIns(cdate: string | Date) {\r\n return weight.getDailyWeighIns(this, cdate);\r\n }\r\n /** Irreversible — see `src/services/weight.ts` for the multi-entry/`deleteAll` semantics. */\r\n deleteWeighIns(cdate: string | Date, deleteAll?: boolean) {\r\n return weight.deleteWeighIns(this, cdate, deleteAll);\r\n }\r\n\r\n // --- bodyComposition ---\r\n getBodyComposition(startdate: string | Date, enddate?: string | Date) {\r\n return bodyComposition.getBodyComposition(this, startdate, enddate);\r\n }\r\n /**\r\n * `add_body_composition` is UNCERTAIN in the inventory — see\r\n * `src/services/bodyComposition.ts` for what was (and wasn't) resolved by\r\n * reading upstream's `fit.py` directly.\r\n */\r\n addBodyComposition(weight: number, extra?: WeightScaleFields & { timestamp?: string }) {\r\n return bodyComposition.addBodyComposition(this, weight, extra);\r\n }\r\n\r\n // --- metrics ---\r\n getMaxMetrics(cdate: string | Date) {\r\n return metrics.getMaxMetrics(this, cdate);\r\n }\r\n getMaxMetricsRange(start: string | Date, end: string | Date) {\r\n return metrics.getMaxMetricsRange(this, start, end);\r\n }\r\n getFunctionalThresholdPowerRange(\r\n start: string | Date,\r\n end: string | Date,\r\n sport?: string,\r\n aggregation?: FtpAggregation,\r\n ) {\r\n return metrics.getFunctionalThresholdPowerRange(this, start, end, sport, aggregation);\r\n }\r\n getLactateThreshold(\r\n latest?: boolean,\r\n startDate?: string | Date,\r\n endDate?: string | Date,\r\n aggregation?: FtpAggregation,\r\n ) {\r\n return metrics.getLactateThreshold(this, latest, startDate, endDate, aggregation);\r\n }\r\n getTrainingReadiness(cdate: string | Date) {\r\n return metrics.getTrainingReadiness(this, cdate);\r\n }\r\n getMorningTrainingReadiness(cdate: string | Date) {\r\n return metrics.getMorningTrainingReadiness(this, cdate);\r\n }\r\n getEnduranceScore(startdate: string | Date, enddate?: string | Date) {\r\n return metrics.getEnduranceScore(this, startdate, enddate);\r\n }\r\n getRunningTolerance(\r\n startdate: string | Date,\r\n enddate: string | Date,\r\n aggregation?: RunningToleranceAggregation,\r\n ) {\r\n return metrics.getRunningTolerance(this, startdate, enddate, aggregation);\r\n }\r\n getRacePredictions(\r\n startdate?: string | Date,\r\n enddate?: string | Date,\r\n type?: \"daily\" | \"monthly\",\r\n ) {\r\n return metrics.getRacePredictions(this, startdate, enddate, type);\r\n }\r\n getTrainingStatus(cdate: string | Date) {\r\n return metrics.getTrainingStatus(this, cdate);\r\n }\r\n getFitnessAgeData(cdate: string | Date) {\r\n return metrics.getFitnessAgeData(this, cdate);\r\n }\r\n getHillScore(startdate: string | Date, enddate?: string | Date) {\r\n return metrics.getHillScore(this, startdate, enddate);\r\n }\r\n getCyclingFtp() {\r\n return metrics.getCyclingFtp(this);\r\n }\r\n getHeartRateZones() {\r\n return metrics.getHeartRateZones(this);\r\n }\r\n getPowerZones() {\r\n return metrics.getPowerZones(this);\r\n }\r\n getPowerZonesForSport(sport: string) {\r\n return metrics.getPowerZonesForSport(this, sport);\r\n }\r\n\r\n // --- workouts ---\r\n getWorkouts(start?: number, limit?: number) {\r\n return workouts.getWorkouts(this, start, limit);\r\n }\r\n getWorkoutById(workoutId: number | string) {\r\n return workouts.getWorkoutById(this, workoutId);\r\n }\r\n deleteWorkout(workoutId: number | string) {\r\n return workouts.deleteWorkout(this, workoutId);\r\n }\r\n downloadWorkout(workoutId: number | string) {\r\n return workouts.downloadWorkout(this, workoutId);\r\n }\r\n uploadWorkout(workoutJson: Record<string, unknown> | unknown[] | string) {\r\n return workouts.uploadWorkout(this, workoutJson);\r\n }\r\n updateWorkout(workoutId: number | string, workoutJson: Record<string, unknown> | string) {\r\n return workouts.updateWorkout(this, workoutId, workoutJson);\r\n }\r\n uploadRunningWorkout(workout: WorkoutInput) {\r\n return workouts.uploadRunningWorkout(this, workout);\r\n }\r\n uploadCyclingWorkout(workout: WorkoutInput) {\r\n return workouts.uploadCyclingWorkout(this, workout);\r\n }\r\n uploadSwimmingWorkout(workout: WorkoutInput) {\r\n return workouts.uploadSwimmingWorkout(this, workout);\r\n }\r\n uploadStrengthWorkout(workout: WorkoutInput) {\r\n return workouts.uploadStrengthWorkout(this, workout);\r\n }\r\n pushWorkoutToDevice(workoutId?: number | string, deviceId?: number | string) {\r\n return workouts.pushWorkoutToDevice(this, workoutId, deviceId);\r\n }\r\n getScheduledWorkouts(year: number | string, month: number | string) {\r\n return workouts.getScheduledWorkouts(this, year, month);\r\n }\r\n getScheduledWorkoutById(scheduledWorkoutId: number | string) {\r\n return workouts.getScheduledWorkoutById(this, scheduledWorkoutId);\r\n }\r\n getNextScheduledWorkout() {\r\n return workouts.getNextScheduledWorkout(this);\r\n }\r\n scheduleWorkout(workoutId: number | string, dateStr: string | Date) {\r\n return workouts.scheduleWorkout(this, workoutId, dateStr);\r\n }\r\n unscheduleWorkout(scheduledWorkoutId: number | string) {\r\n return workouts.unscheduleWorkout(this, scheduledWorkoutId);\r\n }\r\n\r\n // --- womensHealth ---\r\n getMenstrualDataForDate(fordate: string | Date) {\r\n return womensHealth.getMenstrualDataForDate(this, fordate);\r\n }\r\n getMenstrualCalendarData(startdate: string | Date, enddate: string | Date) {\r\n return womensHealth.getMenstrualCalendarData(this, startdate, enddate);\r\n }\r\n getMenstrualLastConfirmed(fordate: string | Date) {\r\n return womensHealth.getMenstrualLastConfirmed(this, fordate);\r\n }\r\n getMenstrualCycleSummary(fordate: string | Date) {\r\n return womensHealth.getMenstrualCycleSummary(this, fordate);\r\n }\r\n getMenstrualReports(\r\n fordate: string | Date,\r\n numberOfCycles?: number,\r\n options?: { nextReport?: boolean; reportType?: string; todayCalendarDate?: string | Date },\r\n ) {\r\n return womensHealth.getMenstrualReports(this, fordate, numberOfCycles, options);\r\n }\r\n getPregnancySummary() {\r\n return womensHealth.getPregnancySummary(this);\r\n }\r\n /**\r\n * Irreversible write to real health data. Live-verified ONCE, on 2026-09-23, under the\r\n * account-scoped exemption described in the file-level comment at the top of\r\n * `src/services/womensHealth.ts` — which also states the default rule that still binds every\r\n * other account: do not execute this against one whose data matters. There is no delete/undo\r\n * endpoint for it anywhere in upstream.\r\n */\r\n updateMenstrualDailyLog(\r\n calendarDate: string | Date,\r\n options?: {\r\n symptoms?: string[];\r\n moods?: string[];\r\n flow?: string;\r\n discharge?: string[];\r\n sexDrive?: string;\r\n sexualActivity?: string;\r\n notes?: string;\r\n ovulationDay?: boolean;\r\n },\r\n ) {\r\n return womensHealth.updateMenstrualDailyLog(this, calendarDate, options);\r\n }\r\n /**\r\n * Irreversible write to real health data. Live-verified ONCE, on 2026-09-23, under the\r\n * account-scoped exemption described in the file-level comment at the top of\r\n * `src/services/womensHealth.ts` — which also states the default rule that still binds every\r\n * other account: do not execute this against one whose data matters. There is no delete/undo\r\n * endpoint for it anywhere in upstream.\r\n */\r\n updateMenstrualCalendar(\r\n startdate: string | Date,\r\n enddate: string | Date,\r\n cycleDatesLists: (string | Date)[][],\r\n options?: { todayCalendarDate?: string | Date },\r\n ) {\r\n return womensHealth.updateMenstrualCalendar(this, startdate, enddate, cycleDatesLists, options);\r\n }\r\n /**\r\n * Irreversible write to real health data (account-level cycle-tracking setup). NOT\r\n * live-verified — see the file-level comment at the top of `src/services/womensHealth.ts` for\r\n * why this must never be executed against a live account.\r\n */\r\n initMenstrualCycleSetup(periodStartDate: string | Date, periodLength: number, cycleLength: number) {\r\n return womensHealth.initMenstrualCycleSetup(this, periodStartDate, periodLength, cycleLength);\r\n }\r\n /**\r\n * Irreversible write to real health data. Live-verified ONCE, on 2026-09-23, under the\r\n * account-scoped exemption described in the file-level comment at the top of\r\n * `src/services/womensHealth.ts` — which also states the default rule that still binds every\r\n * other account: do not execute this against one whose data matters. There is no delete/undo\r\n * endpoint for it anywhere in upstream.\r\n */\r\n confirmMenstrualPeriodStart(\r\n periodStartDate: string | Date,\r\n periodLength: number,\r\n cycleLength: number,\r\n options?: { predictedCycle?: boolean },\r\n ) {\r\n return womensHealth.confirmMenstrualPeriodStart(\r\n this,\r\n periodStartDate,\r\n periodLength,\r\n cycleLength,\r\n options,\r\n );\r\n }\r\n /**\r\n * Irreversible write to real health data (account-level tracking-preference flags). NOT\r\n * live-verified — see the file-level comment at the top of `src/services/womensHealth.ts` for\r\n * why this must never be executed against a live account.\r\n */\r\n updateMenstrualSettings(settings: Record<string, unknown>, options?: { userSettingsId?: number }) {\r\n return womensHealth.updateMenstrualSettings(this, settings, options);\r\n }\r\n\r\n // --- goals ---\r\n /**\r\n * Upstream `get_goals`. Paginated (see `src/services/goals.ts` for the loop, matching\r\n * `getActivitiesByDate`'s pattern) and sends the load-bearing `Sec-Fetch-Site: same-origin`\r\n * header on every request — without it `goal-service` silently returns `[]` for newer\r\n * accumulation-goal types.\r\n */\r\n getGoals(status?: GoalStatus, start?: number, limit?: number) {\r\n return goals.getGoals(this, status, start, limit);\r\n }\r\n\r\n // --- golf ---\r\n getGolfSummary(start?: number, limit?: number) {\r\n return golf.getGolfSummary(this, start, limit);\r\n }\r\n getGolfScorecard(scorecardId: number | string) {\r\n return golf.getGolfScorecard(this, scorecardId);\r\n }\r\n getGolfShotData(scorecardId: number | string, holeNumbers?: string) {\r\n return golf.getGolfShotData(this, scorecardId, holeNumbers);\r\n }\r\n getGolfClubStats(limit?: number) {\r\n return golf.getGolfClubStats(this, limit);\r\n }\r\n getGolfUserStats() {\r\n return golf.getGolfUserStats(this);\r\n }\r\n\r\n // --- nutrition ---\r\n getNutritionDailyFoodLog(cdate: string | Date) {\r\n return nutrition.getNutritionDailyFoodLog(this, cdate);\r\n }\r\n getNutritionDailyMeals(cdate: string | Date) {\r\n return nutrition.getNutritionDailyMeals(this, cdate);\r\n }\r\n getNutritionDailySettings(cdate: string | Date) {\r\n return nutrition.getNutritionDailySettings(this, cdate);\r\n }\r\n\r\n // --- training plans ---\r\n getTrainingPlans() {\r\n return trainingPlans.getTrainingPlans(this);\r\n }\r\n getTrainingPlanById(planId: number | string) {\r\n return trainingPlans.getTrainingPlanById(this, planId);\r\n }\r\n getAdaptiveTrainingPlanById(planId: number | string) {\r\n return trainingPlans.getAdaptiveTrainingPlanById(this, planId);\r\n }\r\n\r\n // --- misc ---\r\n getLifestyleLoggingData(cdate: string | Date) {\r\n return misc.getLifestyleLoggingData(this, cdate);\r\n }\r\n requestReload(cdate: string | Date) {\r\n return misc.requestReload(this, cdate);\r\n }\r\n queryGarminGraphql(query: Record<string, unknown>) {\r\n return misc.queryGarminGraphql(this, query);\r\n }\r\n logout() {\r\n return misc.logout(this);\r\n }\r\n}\r\n","/**\r\n * A fluent builder for Garmin workouts.\r\n *\r\n * **NOT upstream parity** — upstream python-garminconnect has no equivalent. This is a convenience\r\n * layer over `uploadWorkout`, which still accepts raw JSON exactly as before. Nothing here changes\r\n * the wire format; `build()` returns the same `WorkoutInput` you would have written by hand.\r\n *\r\n * It exists because hand-writing that JSON has four traps, all of which were found the hard way by\r\n * building workouts in Garmin's own designer and diffing the payloads:\r\n *\r\n * 1. **`stepOrder` is global and runs THROUGH repeat children.** Numbering each block from 1 earns\r\n * `400 \"The workout steps need to have unique step orders\"`. The builder owns one counter.\r\n * 2. **Every enum reference needs a matching id AND key AND displayOrder.** Nothing stops you\r\n * pairing `stepTypeId: 3` with `stepTypeKey: \"warmup\"`. The builder pairs them from the live\r\n * enums, so a typo is a compile error instead of a silently wrong workout.\r\n * 3. **A rest in seconds is `fixed.rest`, not `time`.** `.rest(15)` picks the right one.\r\n * 4. **Pace targets are SPEEDS in m/s, and the FASTER bound comes first** — so a \"5:00 to 5:30 per\r\n * km\" range is `[3.33, 3.03]`, descending. `.target({ pace: ... })` takes minutes per km (or\r\n * mile) and does the conversion and the inversion for you.\r\n *\r\n * ```ts\r\n * const workout = buildWorkout(\"Threshold 100s\", { sport: \"swimming\", poolLength: 25 })\r\n * .warmup({ distance: 400, stroke: \"free\" })\r\n * .rest({ lapButton: true })\r\n * .repeat(8, (r) => r.interval({ distance: 100, stroke: \"free\", drill: \"kick\" }).rest(15))\r\n * .cooldown({ distance: 200, stroke: \"any_stroke\" })\r\n * .build();\r\n *\r\n * await garmin.uploadWorkout(workout);\r\n * ```\r\n */\r\nimport { GarminError } from \"./errors.js\";\r\nimport {\r\n WORKOUT_CONDITION_TYPE_ID as COND,\r\n WORKOUT_DRILL_TYPE_ID,\r\n WORKOUT_EQUIPMENT_TYPE_ID,\r\n WORKOUT_SPORT_TYPE_ID,\r\n WORKOUT_STEP_TYPE_ID as STEP,\r\n WORKOUT_STROKE_TYPE_ID,\r\n WORKOUT_TARGET_TYPE_ID as TARGET,\r\n} from \"./types/workouts.js\";\r\nimport type {\r\n ExerciseCategory,\r\n ExecutableWorkoutStep,\r\n RepeatWorkoutGroup,\r\n WorkoutInput,\r\n WorkoutSegment,\r\n WorkoutTypeRef,\r\n} from \"./types/workouts.js\";\r\n// Type-only: erased from the emitted JavaScript, so the root bundle still carries none of the\r\n// catalogue's data. Only the name unions reach the declarations.\r\nimport type { ExerciseCategoryWithNames, ExerciseName } from \"./exercises.js\";\r\n\r\n/**\r\n * `displayOrder` for each sport, as Garmin itself stores it. It is cosmetic — a workout is accepted\r\n * with the \"wrong\" value — but matching Garmin's own numbers costs nothing and avoids a diff that\r\n * looks like a bug.\r\n */\r\nconst SPORTS = {\r\n running: [WORKOUT_SPORT_TYPE_ID.RUNNING, 1],\r\n cycling: [WORKOUT_SPORT_TYPE_ID.CYCLING, 2],\r\n swimming: [WORKOUT_SPORT_TYPE_ID.SWIMMING, 3],\r\n strength_training: [WORKOUT_SPORT_TYPE_ID.STRENGTH_TRAINING, 4],\r\n multi_sport: [WORKOUT_SPORT_TYPE_ID.MULTI_SPORT, 5],\r\n cardio_training: [WORKOUT_SPORT_TYPE_ID.CARDIO_TRAINING, 6],\r\n hiit: [WORKOUT_SPORT_TYPE_ID.HIIT, 7],\r\n yoga: [WORKOUT_SPORT_TYPE_ID.YOGA, 8],\r\n pilates: [WORKOUT_SPORT_TYPE_ID.PILATES, 9],\r\n mobility: [WORKOUT_SPORT_TYPE_ID.MOBILITY, 10],\r\n rucking: [WORKOUT_SPORT_TYPE_ID.RUCKING, 12],\r\n other: [WORKOUT_SPORT_TYPE_ID.OTHER, 13],\r\n} as const satisfies Record<string, readonly [number, number]>;\r\n\r\n/**\r\n * Sports you can build a workout for. Deliberately EXCLUDES walking and hiking: Garmin has no\r\n * workout sport type for either, and sending upstream's ids (17/18) produces a workout with\r\n * `sportTypeKey: null`. See `WORKOUT_SPORT_TYPE_ID`'s doc comment.\r\n */\r\nexport type WorkoutSport = keyof typeof SPORTS;\r\n\r\n/** Every `WorkoutSport`, at runtime — for validating JSON input and building schemas. */\r\nexport const WORKOUT_SPORTS = Object.keys(SPORTS) as readonly WorkoutSport[];\r\n\r\nexport type StrokeKey = Lowercase<keyof typeof WORKOUT_STROKE_TYPE_ID>;\r\nexport type DrillKey = Lowercase<keyof typeof WORKOUT_DRILL_TYPE_ID>;\r\nexport type EquipmentKey = Lowercase<keyof typeof WORKOUT_EQUIPMENT_TYPE_ID>;\r\n\r\nconst STROKES: Record<StrokeKey, number> = {\r\n any_stroke: 1,\r\n backstroke: 2,\r\n breaststroke: 3,\r\n drill: 4,\r\n fly: 5,\r\n free: 6,\r\n individual_medley: 7,\r\n mixed: 8,\r\n individual_medley_by_round: 9,\r\n reverse_individual_medley_by_round: 10,\r\n};\r\nconst DRILLS: Record<DrillKey, number> = { kick: 1, pull: 2, drill: 3 };\r\nconst EQUIPMENT: Record<EquipmentKey, number> = {\r\n fins: 1,\r\n kickboard: 2,\r\n paddles: 3,\r\n pull_buoy: 4,\r\n snorkel: 5,\r\n};\r\n\r\n/**\r\n * A step's exercise: a category, and optionally one of THAT category's exercise names.\r\n *\r\n * `name` autocompletes once `category` is set, and a name from another category (or a typo) is a\r\n * compile error. That matters because Garmin does not reject a bad name: it stores it as `\"\"` and\r\n * returns success. `STRETCH` and `UNKNOWN` have no names, so they take `category` alone.\r\n *\r\n * The last member lets a category typed as the whole `ExerciseCategory` union (read from config,\r\n * or a loop) through without a name. TypeScript cannot match such a value against a 53-member\r\n * union on its own; it stops decomposing at 25.\r\n */\r\nexport type WorkoutExercise =\r\n | {\r\n [C in ExerciseCategory]: {\r\n category: C;\r\n name?: C extends ExerciseCategoryWithNames ? ExerciseName<C> : never;\r\n };\r\n }[ExerciseCategory]\r\n | { category: ExerciseCategory; name?: undefined };\r\n\r\n/** How a step ends. Supply exactly one. Every option here is live-verified. */\r\nexport interface StepEnd {\r\n /** Metres. */\r\n distance?: number;\r\n /** Seconds. */\r\n time?: number;\r\n /** Repetitions (strength/HIIT). */\r\n reps?: number;\r\n /** Runs until the user presses lap. */\r\n lapButton?: boolean;\r\n /** A fixed rest in SECONDS — becomes `fixed.rest`, not `time`. */\r\n restSeconds?: number;\r\n /** Ends once this many calories are burned. */\r\n calories?: number;\r\n /** Ends when heart rate reaches this many BPM. */\r\n heartRateBpm?: number;\r\n /** Ends when power reaches this many watts. */\r\n powerWatts?: number;\r\n /** Swim: ends after this many pool lengths (`fixed.repetition`). */\r\n fixedRepetition?: number;\r\n}\r\n\r\n/**\r\n * A step's intensity target. Supply at most one key.\r\n *\r\n * `pace` is given the way a human thinks about it — minutes per kilometre (or mile), slower number\r\n * second — and converted to the descending metres-per-second pair Garmin stores.\r\n */\r\nexport type StepTarget =\r\n | { pace: { minPerKm: [number, number] } }\r\n | { pace: { minPerMile: [number, number] } }\r\n | { speedMetresPerSecond: [number, number] }\r\n /** A configured power zone, by number. Stores `zoneNumber`. */\r\n | { powerZone: number }\r\n /** An explicit watt range. Stores value pairs under the SAME `power.zone` target key. */\r\n | { powerWatts: [number, number] }\r\n /** A configured heart-rate zone, by number. Stores `zoneNumber`. */\r\n | { heartRateZone: number }\r\n /** An explicit BPM range. Stores value pairs under the SAME `heart.rate.zone` target key. */\r\n | { heartRateBpm: [number, number] }\r\n | { cadence: [number, number] }\r\n /** Percent incline range. */\r\n | { gradePercent: [number, number] }\r\n /** Trainer resistance range. */\r\n | { resistance: [number, number] }\r\n /** Swim: seconds offset from critical swim speed. */\r\n | { swimCssOffsetSeconds: number };\r\n\r\nexport interface StepOptions extends StepEnd {\r\n target?: StepTarget;\r\n /**\r\n * A second, simultaneous target — Garmin's bike designer calls this \"Secondary Target\". Stores\r\n * `secondaryTargetType` plus `secondaryTargetValueOne`/`Two` or `secondaryZoneNumber`.\r\n * e.g. hold a power zone AND a cadence range at once.\r\n */\r\n secondaryTarget?: StepTarget;\r\n /** Swim only. */\r\n stroke?: StrokeKey;\r\n /** Swim only. */\r\n drill?: DrillKey;\r\n /** Swim only. */\r\n equipment?: EquipmentKey;\r\n /**\r\n * Strength/HIIT. `category` is constrained to the 53 values Garmin accepts, because an invalid\r\n * one fails the ENTIRE upload with `400 \"Invalid category\"`, not just this step. `name` is the\r\n * specific exercise — Garmin's SCREAMING_SNAKE_CASE key, not the display name the web UI shows —\r\n * and is optional; a category on its own is accepted. See {@link WorkoutExercise}.\r\n */\r\n exercise?: WorkoutExercise;\r\n /** Strength/HIIT, in kilograms. Garmin stores kg and round-trips with small drift. */\r\n weightKg?: number;\r\n /** Free-text note shown on the device. */\r\n notes?: string;\r\n}\r\n\r\nconst ref = (id: number, key: string) => ({ conditionTypeId: id, conditionTypeKey: key, displayOrder: id, displayable: true });\r\n\r\n/** Minutes-per-km -> metres-per-second. 5 min/km = 1000 m / 300 s = 3.333 m/s. */\r\nconst paceToMps = (minPerKm: number) => 1000 / (minPerKm * 60);\r\nconst milePaceToMps = (minPerMile: number) => 1609.344 / (minPerMile * 60);\r\n\r\nfunction endOf(o: StepEnd): { endCondition: WorkoutTypeRef; endConditionValue?: number } {\r\n const options: [keyof StepEnd, number, string][] = [\r\n [\"distance\", COND.DISTANCE, \"distance\"],\r\n [\"time\", COND.TIME, \"time\"],\r\n [\"reps\", COND.REPS, \"reps\"],\r\n [\"restSeconds\", COND.FIXED_REST, \"fixed.rest\"],\r\n [\"calories\", COND.CALORIES, \"calories\"],\r\n [\"heartRateBpm\", COND.HEART_RATE, \"heart.rate\"],\r\n [\"powerWatts\", COND.POWER, \"power\"],\r\n [\"fixedRepetition\", COND.FIXED_REPETITION, \"fixed.repetition\"],\r\n ];\r\n const chosen = options.filter(([k]) => o[k] !== undefined);\r\n const lapButton = o.lapButton === true;\r\n const total = chosen.length + (lapButton ? 1 : 0);\r\n\r\n if (total === 0) {\r\n throw new GarminError(\r\n \"Workout step needs an end condition: one of distance, time, reps, lapButton, restSeconds, \" +\r\n \"calories, heartRateBpm, powerWatts or fixedRepetition\",\r\n );\r\n }\r\n if (total > 1) {\r\n const names = [...chosen.map(([k]) => k), ...(lapButton ? [\"lapButton\"] : [])];\r\n throw new GarminError(\r\n `Workout step has ${total} end conditions (${names.join(\", \")}); supply exactly one`,\r\n );\r\n }\r\n if (lapButton) return { endCondition: ref(COND.LAP_BUTTON, \"lap.button\") };\r\n const [key, id, name] = chosen[0]!;\r\n return { endCondition: ref(id, name), endConditionValue: o[key] as number };\r\n}\r\n\r\n/**\r\n * Encodes a target into the field names Garmin expects. `secondary` switches to the\r\n * `secondaryTargetType` / `secondaryTargetValueOne` / `secondaryZoneNumber` family, which is the\r\n * \"Secondary Target\" the bike designer exposes.\r\n *\r\n * Note that HR and power each have TWO encodings under the SAME target key: a configured zone\r\n * (`zoneNumber`) or an explicit range (value pair). Both are live-verified.\r\n */\r\nfunction targetOf(t: StepTarget | undefined, secondary = false): Record<string, unknown> {\r\n const typeField = secondary ? \"secondaryTargetType\" : \"targetType\";\r\n const oneField = secondary ? \"secondaryTargetValueOne\" : \"targetValueOne\";\r\n const twoField = secondary ? \"secondaryTargetValueTwo\" : \"targetValueTwo\";\r\n const zoneField = secondary ? \"secondaryZoneNumber\" : \"zoneNumber\";\r\n\r\n const typed = (id: number, key: string) => ({\r\n [typeField]: { workoutTargetTypeId: id, workoutTargetTypeKey: key, displayOrder: id },\r\n });\r\n const range = (id: number, key: string, [a, b]: [number, number], descending = false) => ({\r\n ...typed(id, key),\r\n [oneField]: descending ? Math.max(a, b) : Math.min(a, b),\r\n [twoField]: descending ? Math.min(a, b) : Math.max(a, b),\r\n });\r\n const zone = (id: number, key: string, n: number) => ({ ...typed(id, key), [zoneField]: n });\r\n\r\n if (!t) {\r\n // A secondary \"no target\" is meaningless — omit the fields entirely rather than send nulls.\r\n return secondary ? {} : typed(TARGET.NO_TARGET, \"no.target\");\r\n }\r\n\r\n if (\"pace\" in t) {\r\n // Garmin wants SPEEDS, faster (larger) first. Either input order is accepted: the two speeds\r\n // are sorted here, exactly as `range(..., descending)` does for speed targets.\r\n const [a, b] =\r\n \"minPerKm\" in t.pace\r\n ? [paceToMps(t.pace.minPerKm[0]), paceToMps(t.pace.minPerKm[1])]\r\n : [milePaceToMps(t.pace.minPerMile[0]), milePaceToMps(t.pace.minPerMile[1])];\r\n return { ...typed(TARGET.PACE_ZONE, \"pace.zone\"), [oneField]: Math.max(a, b), [twoField]: Math.min(a, b) };\r\n }\r\n if (\"speedMetresPerSecond\" in t) return range(TARGET.SPEED_ZONE, \"speed.zone\", t.speedMetresPerSecond, true);\r\n if (\"powerZone\" in t) return zone(TARGET.POWER_ZONE, \"power.zone\", t.powerZone);\r\n if (\"powerWatts\" in t) return range(TARGET.POWER_ZONE, \"power.zone\", t.powerWatts);\r\n if (\"heartRateZone\" in t) return zone(TARGET.HEART_RATE_ZONE, \"heart.rate.zone\", t.heartRateZone);\r\n if (\"heartRateBpm\" in t) return range(TARGET.HEART_RATE_ZONE, \"heart.rate.zone\", t.heartRateBpm);\r\n if (\"cadence\" in t) return range(TARGET.CADENCE, \"cadence\", t.cadence);\r\n if (\"gradePercent\" in t) {\r\n // REJECTED as a secondary target, because Garmin does not round-trip it there: the stored\r\n // `secondaryTargetValueOne` comes back MULTIPLIED BY TEN while `secondaryTargetValueTwo` is\r\n // untouched. Confirmed over six pairs on 2026-09-23 — [2,5]->[20,5], [1,10]->[10,10],\r\n // [3,7]->[30,7], [4,4]->[40,4], [6,12]->[60,12], [0,1]->[0,1]. As a PRIMARY target grade is\r\n // exact, so this is a Garmin-side inconsistency in the secondary slot, not a bug here.\r\n //\r\n // Silently sending a value that comes back tenfold is worse than refusing, and dividing by ten\r\n // to compensate would be guesswork that breaks the day Garmin fixes it.\r\n if (secondary) {\r\n throw new GarminError(\r\n \"gradePercent cannot be used as a secondaryTarget: Garmin stores its first value multiplied \" +\r\n \"by ten there (sending [2, 5] reads back as [20, 5]), so it does not round-trip. Use it as \" +\r\n \"the primary `target` instead, where it is exact.\",\r\n );\r\n }\r\n return range(TARGET.GRADE, \"grade\", t.gradePercent);\r\n }\r\n if (\"resistance\" in t) return range(TARGET.RESISTANCE, \"resistance\", t.resistance);\r\n return { ...typed(TARGET.SWIM_CSS_OFFSET, \"swim.css.offset\"), [oneField]: t.swimCssOffsetSeconds };\r\n}\r\n\r\n/** Shared step-adding surface, used both at the top level and inside a `repeat()`. */\r\nexport class WorkoutStepList {\r\n protected readonly steps: (ExecutableWorkoutStep | RepeatWorkoutGroup)[] = [];\r\n constructor(protected readonly nextOrder: () => number) {}\r\n\r\n private add(stepTypeId: number, stepTypeKey: string, o: StepOptions): this {\r\n const { endCondition, endConditionValue } = endOf(o);\r\n const step: ExecutableWorkoutStep = {\r\n type: \"ExecutableStepDTO\",\r\n stepOrder: this.nextOrder(),\r\n stepType: { stepTypeId, stepTypeKey, displayOrder: stepTypeId },\r\n endCondition,\r\n ...(endConditionValue !== undefined && { endConditionValue }),\r\n ...targetOf(o.target),\r\n ...targetOf(o.secondaryTarget, true),\r\n ...(o.stroke && {\r\n strokeType: { strokeTypeId: STROKES[o.stroke], strokeTypeKey: o.stroke, displayOrder: STROKES[o.stroke] },\r\n }),\r\n ...(o.drill && {\r\n drillType: { drillTypeId: DRILLS[o.drill], drillTypeKey: o.drill, displayOrder: DRILLS[o.drill] },\r\n }),\r\n ...(o.equipment && {\r\n equipmentType: {\r\n equipmentTypeId: EQUIPMENT[o.equipment],\r\n equipmentTypeKey: o.equipment,\r\n displayOrder: EQUIPMENT[o.equipment],\r\n },\r\n }),\r\n ...(o.exercise && { category: o.exercise.category, exerciseName: o.exercise.name ?? null }),\r\n ...(o.weightKg !== undefined && {\r\n weightValue: o.weightKg,\r\n weightUnit: { unitId: 8, unitKey: \"kilogram\", factor: 1000 },\r\n }),\r\n ...(o.notes !== undefined && { description: o.notes }),\r\n };\r\n this.steps.push(step);\r\n return this;\r\n }\r\n\r\n warmup(o: StepOptions): this {\r\n return this.add(STEP.WARMUP, \"warmup\", o);\r\n }\r\n cooldown(o: StepOptions): this {\r\n return this.add(STEP.COOLDOWN, \"cooldown\", o);\r\n }\r\n interval(o: StepOptions): this {\r\n return this.add(STEP.INTERVAL, \"interval\", o);\r\n }\r\n recovery(o: StepOptions): this {\r\n return this.add(STEP.RECOVERY, \"recovery\", o);\r\n }\r\n main(o: StepOptions): this {\r\n return this.add(STEP.MAIN, \"main\", o);\r\n }\r\n other(o: StepOptions): this {\r\n return this.add(STEP.OTHER, \"other\", o);\r\n }\r\n\r\n /** A rest. Given a number, it is SECONDS and becomes `fixed.rest`. */\r\n rest(o: StepOptions | number): this {\r\n return this.add(STEP.REST, \"rest\", typeof o === \"number\" ? { restSeconds: o } : o);\r\n }\r\n\r\n /** Repeat a block `times` times. The group takes its own stepOrder BEFORE its children. */\r\n repeat(times: number, build: (block: WorkoutStepList) => unknown): this {\r\n if (!Number.isInteger(times) || times < 1) {\r\n throw new GarminError(`repeat() needs a positive whole number of iterations, got ${times}`);\r\n }\r\n return this.#pushRepeat(build, {\r\n numberOfIterations: times,\r\n endCondition: ref(COND.ITERATIONS, \"iterations\"),\r\n });\r\n }\r\n\r\n /**\r\n * Repeat a block until `seconds` have elapsed — Garmin's \"Repeat Until Time Is\". Stores\r\n * `numberOfIterations: null`, which is why that field is nullable.\r\n */\r\n repeatForSeconds(seconds: number, build: (block: WorkoutStepList) => unknown): this {\r\n if (!(seconds > 0)) {\r\n throw new GarminError(`repeatForSeconds() needs a positive duration, got ${seconds}`);\r\n }\r\n return this.#pushRepeat(build, {\r\n numberOfIterations: null,\r\n endCondition: ref(COND.TIME, \"time\"),\r\n endConditionValue: seconds,\r\n });\r\n }\r\n\r\n #pushRepeat(\r\n build: (block: WorkoutStepList) => unknown,\r\n tail: Partial<RepeatWorkoutGroup>,\r\n ): this {\r\n const stepOrder = this.nextOrder();\r\n const block = new WorkoutStepList(this.nextOrder);\r\n build(block);\r\n const children = block.collect();\r\n if (children.length === 0) {\r\n throw new GarminError(\"A repeat block must contain at least one step\");\r\n }\r\n this.steps.push({\r\n type: \"RepeatGroupDTO\",\r\n stepOrder,\r\n stepType: { stepTypeId: STEP.REPEAT, stepTypeKey: \"repeat\", displayOrder: STEP.REPEAT },\r\n smartRepeat: false,\r\n workoutSteps: children,\r\n numberOfIterations: null,\r\n ...tail,\r\n });\r\n return this;\r\n }\r\n\r\n /** @internal */\r\n collect(): (ExecutableWorkoutStep | RepeatWorkoutGroup)[] {\r\n return this.steps;\r\n }\r\n}\r\n\r\nexport interface WorkoutBuildOptions {\r\n sport: WorkoutSport;\r\n /** Swim only, in the unit given by `poolLengthUnit` (default metres). */\r\n poolLength?: number;\r\n poolLengthUnit?: \"meter\" | \"yard\";\r\n /** Only meaningful for `multi_sport`; shows as the designer's \"Transitions\" toggle. */\r\n sessionTransitionsEnabled?: boolean;\r\n estimatedDurationInSecs?: number;\r\n}\r\n\r\n/** The top-level builder. See the module doc comment for the rationale and an example. */\r\nexport class WorkoutBuilder extends WorkoutStepList {\r\n private readonly legs: WorkoutSegment[] = [];\r\n\r\n constructor(\r\n private readonly name: string,\r\n private readonly options: WorkoutBuildOptions,\r\n nextOrder: () => number,\r\n ) {\r\n super(nextOrder);\r\n if (!(name.trim().length > 0)) throw new GarminError(\"A workout needs a name\");\r\n }\r\n\r\n /**\r\n * Add a multi-sport leg. Each leg becomes its own segment with its own sport, which is exactly\r\n * how Garmin models a brick. Using this switches the workout to `multi_sport`.\r\n */\r\n leg(sport: WorkoutSport, build: (block: WorkoutStepList) => unknown): this {\r\n const block = new WorkoutStepList(this.nextOrder);\r\n build(block);\r\n const steps = block.collect();\r\n if (steps.length === 0) throw new GarminError(`Multi-sport leg \"${sport}\" has no steps`);\r\n const [id, displayOrder] = SPORTS[sport];\r\n this.legs.push({\r\n segmentOrder: this.legs.length + 1,\r\n sportType: { sportTypeId: id, sportTypeKey: sport, displayOrder },\r\n workoutSteps: steps,\r\n });\r\n return this;\r\n }\r\n\r\n build(): WorkoutInput {\r\n const own = this.collect();\r\n if (own.length === 0 && this.legs.length === 0) {\r\n throw new GarminError(\"A workout needs at least one step\");\r\n }\r\n if (own.length > 0 && this.legs.length > 0) {\r\n throw new GarminError(\r\n \"A workout is either single-sport (steps added directly) or multi-sport (legs); it cannot be both\",\r\n );\r\n }\r\n\r\n const multi = this.legs.length > 0;\r\n const sport: WorkoutSport = multi ? \"multi_sport\" : this.options.sport;\r\n const [sportId, sportOrder] = SPORTS[sport];\r\n const sportType = { sportTypeId: sportId, sportTypeKey: sport, displayOrder: sportOrder };\r\n\r\n const segments: WorkoutSegment[] = multi\r\n ? this.legs\r\n : [{ segmentOrder: 1, sportType, workoutSteps: own }];\r\n\r\n return {\r\n workoutName: this.name,\r\n sportType,\r\n // Garmin recomputes this; a sane non-zero default keeps the UI from showing 0:00 before sync.\r\n estimatedDurationInSecs: this.options.estimatedDurationInSecs ?? 0,\r\n workoutSegments: segments,\r\n ...(this.options.poolLength !== undefined && {\r\n poolLength: this.options.poolLength,\r\n poolLengthUnit:\r\n (this.options.poolLengthUnit ?? \"meter\") === \"yard\"\r\n ? { unitId: 2, unitKey: \"yard\", factor: 91.44 }\r\n : { unitId: 1, unitKey: \"meter\", factor: 100 },\r\n }),\r\n ...(this.options.sessionTransitionsEnabled !== undefined && {\r\n isSessionTransitionEnabled: this.options.sessionTransitionsEnabled,\r\n }),\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Start building a workout. The result of `.build()` goes straight to `uploadWorkout`.\r\n *\r\n * @example Single sport\r\n * ```ts\r\n * buildWorkout(\"Tempo\", { sport: \"running\" })\r\n * .warmup({ lapButton: true })\r\n * .repeat(4, (r) => r.interval({ distance: 1000, target: { pace: { minPerKm: [4.5, 5] } } }).recovery({ time: 120 }))\r\n * .cooldown({ lapButton: true })\r\n * .build();\r\n * ```\r\n *\r\n * @example Multi-sport brick\r\n * ```ts\r\n * buildWorkout(\"Brick\", { sport: \"multi_sport\", sessionTransitionsEnabled: true })\r\n * .leg(\"cycling\", (l) => l.interval({ time: 1800 }))\r\n * .leg(\"running\", (l) => l.interval({ distance: 5000 }))\r\n * .build();\r\n * ```\r\n */\r\nexport function buildWorkout(name: string, options: WorkoutBuildOptions): WorkoutBuilder {\r\n // One counter for the whole tree — this is what makes stepOrder globally unique, including\r\n // through repeat children, which Garmin requires.\r\n let order = 0;\r\n return new WorkoutBuilder(name, options, () => ++order);\r\n}\r\n","/**\n * Workouts as plain JSON: the declarative twin of `buildWorkout`.\n *\n * `buildWorkout` is fluent and takes callbacks, which is ideal from TypeScript and impossible from\n * JSON: a database row, a form post or an LLM tool call cannot contain a function. This module\n * accepts the same workout as data and REPLAYS it through the real builder. There is one encoder,\n * so every builder guard (global stepOrder, pace inversion, one end condition per step, the\n * gradePercent-as-secondary refusal) applies unchanged.\n *\n * It is deliberately stricter than the builder, because its input is not type-checked:\n * - an unknown key anywhere is an error naming its path, not silently ignored;\n * - an exercise `name` is checked against the catalogue you pass in. Garmin would otherwise\n * store an unknown name as \"\" and report success.\n *\n * The catalogue is a parameter rather than an import so the root bundle keeps carrying none of its\n * ~60 KB. Pass `EXERCISES` from `garminconnect-js/exercises`.\n */\nimport { GarminError } from \"./errors.js\";\nimport {\n WORKOUT_DRILL_TYPE_ID,\n WORKOUT_EQUIPMENT_TYPE_ID,\n WORKOUT_EXERCISE_CATEGORIES,\n WORKOUT_STROKE_TYPE_ID,\n} from \"./types/workouts.js\";\nimport type { ExerciseCategory, WorkoutInput } from \"./types/workouts.js\";\nimport { buildWorkout, WORKOUT_SPORTS } from \"./workout-builder.js\";\nimport type {\n DrillKey,\n EquipmentKey,\n StepEnd,\n StepOptions,\n StepTarget,\n StrokeKey,\n WorkoutBuildOptions,\n WorkoutExercise,\n WorkoutSport,\n WorkoutStepList,\n} from \"./workout-builder.js\";\n\nexport const SIMPLE_STEP_TYPES = [\"warmup\", \"cooldown\", \"interval\", \"recovery\", \"main\", \"other\", \"rest\"] as const;\nexport type SimpleStepType = (typeof SIMPLE_STEP_TYPES)[number];\n\n/** One step: a plain step with builder options, or a block of nested steps. */\nexport type WorkoutSpecStep =\n | ({ type: SimpleStepType } & StepOptions)\n | { type: \"repeat\"; times: number; steps: WorkoutSpecStep[] }\n | { type: \"repeatForSeconds\"; seconds: number; steps: WorkoutSpecStep[] };\n\nexport interface WorkoutSpecLeg {\n sport: WorkoutSport;\n steps: WorkoutSpecStep[];\n}\n\n/** A whole workout: `steps` for one sport, or `legs` for multi-sport, never both. */\nexport type WorkoutSpec = { name: string } & WorkoutBuildOptions &\n ({ steps: WorkoutSpecStep[]; legs?: never } | { legs: WorkoutSpecLeg[]; steps?: never });\n\n/** Category -> valid exercise names. Pass `EXERCISES` from `garminconnect-js/exercises`. */\nexport type ExerciseCatalogue = Readonly<Record<string, readonly string[]>>;\n\ntype KeysOfUnion<T> = T extends unknown ? keyof T : never;\n\n// Runtime key lists. `tests/workout-spec.test.ts` pins each to its TypeScript type, so a builder\n// option added without being added here fails `npm run typecheck`.\nexport const SPEC_END_KEYS = [\n \"distance\", \"time\", \"reps\", \"lapButton\", \"restSeconds\", \"calories\", \"heartRateBpm\", \"powerWatts\", \"fixedRepetition\",\n] as const satisfies readonly (keyof StepEnd)[];\nexport const SPEC_STEP_OPTION_KEYS = [\n ...SPEC_END_KEYS, \"target\", \"secondaryTarget\", \"stroke\", \"drill\", \"equipment\", \"exercise\", \"weightKg\", \"notes\",\n] as const satisfies readonly (keyof StepOptions)[];\nexport const SPEC_TARGET_KEYS = [\n \"pace\", \"speedMetresPerSecond\", \"powerZone\", \"powerWatts\", \"heartRateZone\", \"heartRateBpm\", \"cadence\",\n \"gradePercent\", \"resistance\", \"swimCssOffsetSeconds\",\n] as const satisfies readonly KeysOfUnion<StepTarget>[];\nexport const SPEC_TOP_KEYS = [\n \"name\", \"sport\", \"poolLength\", \"poolLengthUnit\", \"sessionTransitionsEnabled\", \"estimatedDurationInSecs\", \"steps\", \"legs\",\n] as const;\n\nconst lower = <T extends string>(o: object) => Object.keys(o).map((k) => k.toLowerCase()) as T[];\nexport const STROKE_KEYS: readonly StrokeKey[] = lower<StrokeKey>(WORKOUT_STROKE_TYPE_ID);\nexport const DRILL_KEYS: readonly DrillKey[] = lower<DrillKey>(WORKOUT_DRILL_TYPE_ID);\nexport const EQUIPMENT_KEYS: readonly EquipmentKey[] = lower<EquipmentKey>(WORKOUT_EQUIPMENT_TYPE_ID);\n\nconst STEP_TYPES = [...SIMPLE_STEP_TYPES, \"repeat\", \"repeatForSeconds\"] as const;\nconst NUMERIC_END_KEYS = SPEC_END_KEYS.filter((k) => k !== \"lapButton\");\n\n/** Keys people (and models) reach for that belong somewhere else. */\nconst STEP_HINTS: Record<string, string> = {\n ...Object.fromEntries(\n SPEC_TARGET_KEYS.filter((k) => !(SPEC_STEP_OPTION_KEYS as readonly string[]).includes(k)).map((k) => [\n k,\n `target: { ${k}: … }`,\n ]),\n ),\n minPerKm: \"target: { pace: { minPerKm: [fast, slow] } }\",\n minPerMile: \"target: { pace: { minPerMile: [fast, slow] } }\",\n duration: \"time (seconds)\",\n seconds: \"time (seconds)\",\n meters: \"distance (metres)\",\n metres: \"distance (metres)\",\n repetitions: \"reps\",\n description: \"notes\",\n note: \"notes\",\n weight: \"weightKg\",\n times: 'a block: { type: \"repeat\", times, steps }',\n steps: 'a block: { type: \"repeat\", times, steps }',\n};\nconst TOP_HINTS: Record<string, string> = {\n workoutName: \"name\",\n title: \"name\",\n sportType: \"sport\",\n segments: \"steps (or legs for multi-sport)\",\n workoutSteps: \"steps\",\n};\nconst REPEAT_HINTS: Record<string, string> = {\n iterations: \"times\",\n count: \"times\",\n repeat: \"times\",\n children: \"steps\",\n workoutSteps: \"steps\",\n};\n\ntype Json = Record<string, unknown>;\n\n/** A spec error already carrying its path, so outer levels do not prefix it again. */\nclass SpecError extends GarminError {}\n\nfunction fail(path: string, message: string): never {\n throw new SpecError(`${path}: ${message}`);\n}\n\nfunction show(v: unknown): string {\n if (v === undefined) return \"nothing\";\n const s = JSON.stringify(v) ?? Object.prototype.toString.call(v);\n return s.length > 40 ? `${s.slice(0, 37)}...` : s;\n}\n\n/** Runs a builder call, prefixing the builder's own GarminError with the spec path. */\nfunction at<T>(path: string, run: () => T): T {\n try {\n return run();\n } catch (error) {\n if (error instanceof SpecError || !(error instanceof GarminError)) throw error;\n throw new SpecError(`${path}: ${error.message}`, { cause: error });\n }\n}\n\nfunction object(v: unknown, path: string): Json {\n if (typeof v !== \"object\" || v === null || Array.isArray(v)) fail(path, `expected an object, got ${show(v)}`);\n return v as Json;\n}\nfunction list(v: unknown, path: string): unknown[] {\n if (!Array.isArray(v)) fail(path, `expected an array, got ${show(v)}`);\n return v as unknown[];\n}\nfunction number(v: unknown, path: string): number {\n if (typeof v !== \"number\" || !Number.isFinite(v)) fail(path, `expected a number, got ${show(v)}`);\n return v;\n}\nfunction text(v: unknown, path: string): string {\n if (typeof v !== \"string\") fail(path, `expected a string, got ${show(v)}`);\n return v;\n}\nfunction flag(v: unknown, path: string): boolean {\n if (typeof v !== \"boolean\") fail(path, `expected true or false, got ${show(v)}`);\n return v;\n}\nfunction oneOf<T extends string>(v: unknown, allowed: readonly T[], path: string): T {\n if (typeof v !== \"string\" || !(allowed as readonly string[]).includes(v)) {\n fail(path, `expected one of ${allowed.join(\", \")}; got ${show(v)}`);\n }\n return v as T;\n}\nfunction pair(v: unknown, path: string): [number, number] {\n const a = list(v, path);\n if (a.length !== 2) fail(path, `expected [low, high], two numbers; got ${show(v)}`);\n return [number(a[0], `${path}[0]`), number(a[1], `${path}[1]`)];\n}\nfunction positivePair(v: unknown, path: string): [number, number] {\n const p = pair(v, path);\n if (!(p[0] > 0 && p[1] > 0)) fail(path, `both values must be greater than zero; got ${show(v)}`);\n return p;\n}\nfunction zone(v: unknown, path: string): number {\n const n = number(v, path);\n if (!Number.isInteger(n) || n < 1) fail(path, `expected a zone number (1, 2, 3, …), got ${show(v)}`);\n return n;\n}\nfunction onlyKeys(o: Json, allowed: readonly string[], path: string, hints: Record<string, string> = {}): void {\n for (const key of Object.keys(o)) {\n if (allowed.includes(key)) continue;\n const hint = Object.hasOwn(hints, key) ? `; did you mean ${hints[key]!}?` : `; allowed: ${allowed.join(\", \")}`;\n fail(path, `unknown key \"${key}\"${hint}`);\n }\n}\n\n/** Levenshtein distance. The candidate lists are small (at most a few hundred names). */\nfunction distance(a: string, b: string): number {\n let prev = Array.from({ length: b.length + 1 }, (_, i) => i);\n for (let i = 1; i <= a.length; i++) {\n const next = [i];\n for (let j = 1; j <= b.length; j++) {\n next[j] = Math.min(next[j - 1]! + 1, prev[j]! + 1, prev[j - 1]! + (a[i - 1] === b[j - 1] ? 0 : 1));\n }\n prev = next;\n }\n return prev[b.length]!;\n}\n\n/**\n * Up to `limit` candidates closest to `input`, best first. Case, spaces and punctuation are\n * ignored, so \"barbell back squat\" finds BARBELL_BACK_SQUAT first.\n */\nexport function suggest(input: string, candidates: readonly string[], limit = 5): string[] {\n const norm = (s: string) => s.toUpperCase().replace(/[^A-Z0-9]+/g, \"_\").replace(/^_+|_+$/g, \"\");\n const q = norm(input);\n if (!q) return [];\n const words = q.split(\"_\");\n return candidates\n .map((c) => {\n const n = norm(c);\n const parts = n.split(\"_\");\n let score: number;\n if (n === q) score = 0;\n else if (n.includes(q) || q.includes(n)) score = 1 + Math.abs(n.length - q.length) / 1000;\n else if (words.every((w) => parts.includes(w))) score = 2 + parts.length / 1000;\n else score = 3 + distance(q, n) / Math.max(q.length, n.length);\n return { c, score };\n })\n .filter((s) => s.score < 3.5)\n .sort((a, b) => a.score - b.score || a.c.localeCompare(b.c))\n .slice(0, limit)\n .map((s) => s.c);\n}\n\nfunction target(v: unknown, path: string): StepTarget {\n const t = object(v, path);\n const keys = Object.keys(t);\n if (keys.length !== 1) {\n fail(\n path,\n `a target has exactly one key (one of ${SPEC_TARGET_KEYS.join(\", \")}); got ${keys.length === 0 ? \"none\" : keys.join(\", \")}`,\n );\n }\n const key = oneOf(keys[0], SPEC_TARGET_KEYS, path);\n const here = `${path}.${key}`;\n const value = t[key];\n switch (key) {\n case \"pace\": {\n const pace = object(value, here);\n onlyKeys(pace, [\"minPerKm\", \"minPerMile\"], here);\n if ((\"minPerKm\" in pace) === (\"minPerMile\" in pace)) {\n fail(here, 'give exactly one of \"minPerKm\" or \"minPerMile\", as [fast, slow] minutes; 4:30 is 4.5');\n }\n return \"minPerKm\" in pace\n ? { pace: { minPerKm: positivePair(pace[\"minPerKm\"], `${here}.minPerKm`) } }\n : { pace: { minPerMile: positivePair(pace[\"minPerMile\"], `${here}.minPerMile`) } };\n }\n case \"powerZone\":\n return { powerZone: zone(value, here) };\n case \"heartRateZone\":\n return { heartRateZone: zone(value, here) };\n case \"swimCssOffsetSeconds\":\n return { swimCssOffsetSeconds: number(value, here) };\n case \"speedMetresPerSecond\":\n return { speedMetresPerSecond: pair(value, here) };\n case \"powerWatts\":\n return { powerWatts: pair(value, here) };\n case \"heartRateBpm\":\n return { heartRateBpm: pair(value, here) };\n case \"cadence\":\n return { cadence: pair(value, here) };\n case \"gradePercent\":\n return { gradePercent: pair(value, here) };\n case \"resistance\":\n return { resistance: pair(value, here) };\n }\n}\n\nfunction exercise(v: unknown, path: string, exercises: ExerciseCatalogue): WorkoutExercise {\n const e = object(v, path);\n onlyKeys(e, [\"category\", \"name\"], path, { exerciseName: \"name\", exercise: \"name\" });\n const raw = e[\"category\"];\n if (typeof raw !== \"string\" || !(WORKOUT_EXERCISE_CATEGORIES as readonly string[]).includes(raw)) {\n const close = typeof raw === \"string\" ? suggest(raw, WORKOUT_EXERCISE_CATEGORIES) : [];\n fail(`${path}.category`, `${show(raw)} is not an exercise category${close.length ? `; closest: ${close.join(\", \")}` : \"\"}`);\n }\n const category = raw as ExerciseCategory;\n if (e[\"name\"] === undefined) return { category };\n const name = text(e[\"name\"], `${path}.name`);\n const names = Object.hasOwn(exercises, category) ? (exercises[category] ?? []) : [];\n if (names.length === 0) fail(`${path}.name`, `category ${category} has no named exercises; omit \"name\"`);\n if (!names.includes(name)) {\n const close = suggest(name, names);\n fail(`${path}.name`, `\"${name}\" is not an exercise in ${category}${close.length ? `; closest: ${close.join(\", \")}` : \"\"}`);\n }\n return { category, name } as unknown as WorkoutExercise;\n}\n\nfunction stepOptions(step: Json, path: string, exercises: ExerciseCatalogue): StepOptions {\n const o: StepOptions = {};\n for (const key of NUMERIC_END_KEYS) {\n if (step[key] !== undefined) o[key] = number(step[key], `${path}.${key}`);\n }\n if (step[\"lapButton\"] !== undefined) o.lapButton = flag(step[\"lapButton\"], `${path}.lapButton`);\n if (step[\"target\"] !== undefined) o.target = target(step[\"target\"], `${path}.target`);\n if (step[\"secondaryTarget\"] !== undefined) {\n o.secondaryTarget = target(step[\"secondaryTarget\"], `${path}.secondaryTarget`);\n }\n if (step[\"stroke\"] !== undefined) o.stroke = oneOf(step[\"stroke\"], STROKE_KEYS, `${path}.stroke`);\n if (step[\"drill\"] !== undefined) o.drill = oneOf(step[\"drill\"], DRILL_KEYS, `${path}.drill`);\n if (step[\"equipment\"] !== undefined) o.equipment = oneOf(step[\"equipment\"], EQUIPMENT_KEYS, `${path}.equipment`);\n if (step[\"exercise\"] !== undefined) o.exercise = exercise(step[\"exercise\"], `${path}.exercise`, exercises);\n if (step[\"weightKg\"] !== undefined) o.weightKg = number(step[\"weightKg\"], `${path}.weightKg`);\n if (step[\"notes\"] !== undefined) o.notes = text(step[\"notes\"], `${path}.notes`);\n return o;\n}\n\nfunction addSteps(block: WorkoutStepList, steps: unknown[], path: string, exercises: ExerciseCatalogue): void {\n steps.forEach((raw, i) => {\n const here = `${path}[${i}]`;\n const step = object(raw, here);\n const type = oneOf(step[\"type\"], STEP_TYPES, `${here}.type`);\n if (type === \"repeat\" || type === \"repeatForSeconds\") {\n const countKey = type === \"repeat\" ? \"times\" : \"seconds\";\n onlyKeys(step, [\"type\", countKey, \"steps\"], here, REPEAT_HINTS);\n const count = number(step[countKey], `${here}.${countKey}`);\n const children = list(step[\"steps\"], `${here}.steps`);\n const fill = (inner: WorkoutStepList) => addSteps(inner, children, `${here}.steps`, exercises);\n at(here, () => (type === \"repeat\" ? block.repeat(count, fill) : block.repeatForSeconds(count, fill)));\n return;\n }\n onlyKeys(step, [\"type\", ...SPEC_STEP_OPTION_KEYS], here, STEP_HINTS);\n const options = stepOptions(step, here, exercises);\n at(here, () => block[type](options));\n });\n}\n\n/**\n * Build a workout from JSON. The result goes straight to `uploadWorkout`.\n *\n * @example\n * ```ts\n * import { workoutFromSpec } from \"garminconnect-js\";\n * import { EXERCISES } from \"garminconnect-js/exercises\";\n *\n * const workout = workoutFromSpec(\n * { name: \"Tempo\", sport: \"running\", steps: [{ type: \"interval\", time: 1200, target: { pace: { minPerKm: [4.5, 4.7] } } }] },\n * EXERCISES,\n * );\n * await garmin.uploadWorkout(workout);\n * ```\n *\n * @throws GarminError with a message of the form `workout.steps[1].target: …` naming what is wrong.\n */\nexport function workoutFromSpec(spec: unknown, exercises: ExerciseCatalogue): WorkoutInput {\n const top = object(spec, \"workout\");\n onlyKeys(top, SPEC_TOP_KEYS, \"workout\", TOP_HINTS);\n const name = text(top[\"name\"], \"workout.name\");\n const options: WorkoutBuildOptions = { sport: oneOf(top[\"sport\"], WORKOUT_SPORTS, \"workout.sport\") };\n if (top[\"poolLength\"] !== undefined) options.poolLength = number(top[\"poolLength\"], \"workout.poolLength\");\n if (top[\"poolLengthUnit\"] !== undefined) {\n options.poolLengthUnit = oneOf(top[\"poolLengthUnit\"], [\"meter\", \"yard\"] as const, \"workout.poolLengthUnit\");\n }\n if (top[\"sessionTransitionsEnabled\"] !== undefined) {\n options.sessionTransitionsEnabled = flag(top[\"sessionTransitionsEnabled\"], \"workout.sessionTransitionsEnabled\");\n }\n if (top[\"estimatedDurationInSecs\"] !== undefined) {\n options.estimatedDurationInSecs = number(top[\"estimatedDurationInSecs\"], \"workout.estimatedDurationInSecs\");\n }\n\n const hasSteps = top[\"steps\"] !== undefined;\n const hasLegs = top[\"legs\"] !== undefined;\n if (hasSteps === hasLegs) {\n fail(\"workout\", 'give exactly one of \"steps\" (a single-sport workout) or \"legs\" (multi-sport)');\n }\n\n const builder = at(\"workout\", () => buildWorkout(name, options));\n if (hasSteps) {\n addSteps(builder, list(top[\"steps\"], \"workout.steps\"), \"workout.steps\", exercises);\n } else {\n list(top[\"legs\"], \"workout.legs\").forEach((raw, i) => {\n const path = `workout.legs[${i}]`;\n const leg = object(raw, path);\n onlyKeys(leg, [\"sport\", \"steps\"], path);\n const sport = oneOf(leg[\"sport\"], WORKOUT_SPORTS, `${path}.sport`);\n const steps = list(leg[\"steps\"], `${path}.steps`);\n at(path, () => builder.leg(sport, (block) => addSteps(block, steps, `${path}.steps`, exercises)));\n });\n }\n return at(\"workout\", () => builder.build());\n}\n","/**\n * JSON Schema (draft 2020-12) for `workoutFromSpec`'s input.\n *\n * BUILT from the same constants the builder and `workoutFromSpec` use (sports, strokes, drills,\n * equipment, exercise categories, step option keys), never hand-listed, so it cannot drift from\n * them. The `Record<…>` tables below are exhaustive over the key lists, so a new step option or\n * target fails `tsc` until it is described here.\n *\n * Exercise NAMES are deliberately absent: 1830 of them would cost ~40 KB wherever this schema is\n * shown to a model. `workoutFromSpec` checks names at runtime instead.\n *\n * The root has no oneOf/anyOf/allOf: the Claude API rejects those at the top level of a tool's\n * input schema. \"Exactly one of steps or legs\" is enforced by `workoutFromSpec`.\n */\nimport { WORKOUT_EXERCISE_CATEGORIES } from \"./types/workouts.js\";\nimport { WORKOUT_SPORTS } from \"./workout-builder.js\";\nimport {\n DRILL_KEYS,\n EQUIPMENT_KEYS,\n SIMPLE_STEP_TYPES,\n SPEC_STEP_OPTION_KEYS,\n SPEC_TARGET_KEYS,\n STROKE_KEYS,\n} from \"./workout-spec.js\";\n\nexport interface JsonSchemaDocument {\n $schema: string;\n $defs: Record<string, unknown>;\n [key: string]: unknown;\n}\n\nconst positive = (description: string) => ({ type: \"number\", exclusiveMinimum: 0, description });\nconst range = (description: string) => ({ type: \"array\", items: { type: \"number\" }, minItems: 2, maxItems: 2, description });\nconst stepList = { type: \"array\", minItems: 1, items: { $ref: \"#/$defs/step\" } };\n\nconst TARGETS: Record<(typeof SPEC_TARGET_KEYS)[number], object> = {\n pace: {\n type: \"object\",\n description:\n \"Pace range as [fast, slow] minutes, in decimals (4:30 is 4.5). Give exactly one of minPerKm or minPerMile.\",\n properties: {\n minPerKm: range(\"e.g. [4.5, 5] = 4:30–5:00 per km\"),\n minPerMile: range(\"e.g. [8.5, 9.5] = 8:30–9:30 per mile\"),\n },\n minProperties: 1,\n maxProperties: 1,\n additionalProperties: false,\n },\n speedMetresPerSecond: range(\"Speed range in metres per second\"),\n powerZone: { type: \"integer\", minimum: 1, description: \"One of the user's configured power zones\" },\n powerWatts: range(\"Power range in watts\"),\n heartRateZone: { type: \"integer\", minimum: 1, description: \"One of the user's configured heart-rate zones\" },\n heartRateBpm: range(\"Heart-rate range in beats per minute\"),\n cadence: range(\"Cadence range: rpm on a bike, steps per minute running\"),\n gradePercent: range(\"Incline range in percent. Primary target only; rejected as a secondaryTarget\"),\n resistance: range(\"Trainer resistance range\"),\n swimCssOffsetSeconds: { type: \"number\", description: \"Swim: seconds per 100 relative to critical swim speed\" },\n};\n\nconst STEP_PROPERTIES: Record<(typeof SPEC_STEP_OPTION_KEYS)[number], object> = {\n distance: positive(\"End after this many metres\"),\n time: positive(\"End after this many seconds\"),\n reps: { type: \"integer\", minimum: 1, description: \"End after this many repetitions (strength, HIIT)\" },\n lapButton: { type: \"boolean\", const: true, description: \"End when the user presses lap\" },\n restSeconds: positive(\"A fixed rest of this many seconds (use on rest steps)\"),\n calories: positive(\"End after this many kilocalories\"),\n heartRateBpm: positive(\"End when heart rate reaches this many bpm\"),\n powerWatts: positive(\"End when power reaches this many watts\"),\n fixedRepetition: { type: \"integer\", minimum: 1, description: \"Swim: end after this many pool lengths\" },\n target: { $ref: \"#/$defs/target\" },\n secondaryTarget: {\n $ref: \"#/$defs/target\",\n description: \"A second simultaneous target, e.g. a power zone plus a cadence range. gradePercent is not allowed here.\",\n },\n stroke: { enum: STROKE_KEYS, description: \"Swim stroke\" },\n drill: { enum: DRILL_KEYS, description: \"Swim drill\" },\n equipment: { enum: EQUIPMENT_KEYS, description: \"Swim equipment\" },\n exercise: { $ref: \"#/$defs/exercise\" },\n weightKg: positive(\"Weight in kilograms (strength)\"),\n notes: { type: \"string\", description: \"Free text shown on the watch\" },\n};\n\nexport const WORKOUT_SPEC_JSON_SCHEMA: JsonSchemaDocument = {\n $schema: \"https://json-schema.org/draft/2020-12/schema\",\n title: \"WorkoutSpec\",\n description:\n \"A Garmin workout. Give `steps` for one sport, or `legs` (each with its own sport) for a multi-sport workout, not both. \" +\n \"Distances are metres, times seconds.\",\n type: \"object\",\n properties: {\n name: { type: \"string\", minLength: 1 },\n sport: { enum: WORKOUT_SPORTS, description: \"Use multi_sport together with legs\" },\n poolLength: positive(\"Swim: pool length, in poolLengthUnit\"),\n poolLengthUnit: { enum: [\"meter\", \"yard\"] },\n sessionTransitionsEnabled: { type: \"boolean\", description: \"Multi-sport: record transitions between legs\" },\n estimatedDurationInSecs: { type: \"number\", minimum: 0 },\n steps: stepList,\n legs: { type: \"array\", minItems: 1, items: { $ref: \"#/$defs/leg\" } },\n },\n required: [\"name\", \"sport\"],\n additionalProperties: false,\n $defs: {\n step: {\n oneOf: [{ $ref: \"#/$defs/simpleStep\" }, { $ref: \"#/$defs/repeat\" }, { $ref: \"#/$defs/repeatForSeconds\" }],\n },\n simpleStep: {\n type: \"object\",\n description:\n \"One step. Give exactly ONE end condition: distance, time, reps, lapButton, restSeconds, calories, \" +\n \"heartRateBpm, powerWatts or fixedRepetition.\",\n properties: { type: { enum: SIMPLE_STEP_TYPES }, ...STEP_PROPERTIES },\n required: [\"type\"],\n additionalProperties: false,\n },\n repeat: {\n type: \"object\",\n description: \"Repeat the nested steps a number of times\",\n properties: { type: { const: \"repeat\" }, times: { type: \"integer\", minimum: 1 }, steps: stepList },\n required: [\"type\", \"times\", \"steps\"],\n additionalProperties: false,\n },\n repeatForSeconds: {\n type: \"object\",\n description: \"Keep repeating the nested steps until this much time has passed\",\n properties: { type: { const: \"repeatForSeconds\" }, seconds: positive(\"Total seconds\"), steps: stepList },\n required: [\"type\", \"seconds\", \"steps\"],\n additionalProperties: false,\n },\n leg: {\n type: \"object\",\n properties: { sport: { enum: WORKOUT_SPORTS.filter((s) => s !== \"multi_sport\") }, steps: stepList },\n required: [\"sport\", \"steps\"],\n additionalProperties: false,\n },\n target: {\n type: \"object\",\n description: \"Exactly one key\",\n properties: TARGETS,\n minProperties: 1,\n maxProperties: 1,\n additionalProperties: false,\n },\n exercise: {\n type: \"object\",\n properties: {\n category: { enum: WORKOUT_EXERCISE_CATEGORIES },\n name: {\n type: \"string\",\n description:\n \"Garmin's exercise key in SCREAMING_SNAKE_CASE. Look it up with search_exercises; \" +\n \"an unknown name is rejected. Omit it to use the category alone.\",\n },\n },\n required: [\"category\"],\n additionalProperties: false,\n },\n },\n};\n","import os from \"node:os\";\nimport path from \"node:path\";\nimport { FileTokenStore, Garmin, GarminAuthError, GarminClient, type GarminClientOptions } from \"garminconnect-js\";\n\nexport interface McpConfig {\n tokenDir: string;\n downloadDir: string;\n /** Manifest categories to expose; `null` means all. */\n groups: ReadonlySet<string> | null;\n enableGraphql: boolean;\n}\n\nexport function loadConfig(env: Record<string, string | undefined> = process.env): McpConfig {\n const home = os.homedir();\n const groups = (env[\"GARMIN_MCP_GROUPS\"] ?? \"\")\n .split(\",\")\n .map((g) => g.trim())\n .filter(Boolean);\n return {\n tokenDir: env[\"GARMIN_MCP_TOKEN_DIR\"] || path.join(home, \".garminconnect-mcp\", \"tokens\"),\n downloadDir: env[\"GARMIN_MCP_DOWNLOAD_DIR\"] || path.join(home, \"Downloads\", \"garmin\"),\n groups: groups.length > 0 ? new Set(groups) : null,\n enableGraphql: env[\"GARMIN_MCP_ENABLE_GRAPHQL\"] === \"1\",\n };\n}\n\n/** No saved login to load. */\nexport class NotLoggedInError extends GarminAuthError {}\n\n/**\n * Where tools get their `Garmin` from. Today: one session from a token directory. A hosted\n * version would supply one per user; tool code only ever sees this interface.\n */\nexport interface Session {\n get(): Promise<Garmin>;\n /** Drop the cached client so the next `get()` reloads tokens from disk. */\n reset(): void;\n}\n\nexport function fileSession(tokenDir: string, options: Omit<GarminClientOptions, \"tokenStore\"> = {}): Session {\n let current: Promise<Garmin> | null = null;\n return {\n get() {\n current ??= (async () => {\n const client = new GarminClient({ ...options, tokenStore: new FileTokenStore(tokenDir) });\n if (!(await client.loadTokens())) throw new NotLoggedInError(`No saved Garmin login in ${tokenDir}`);\n return new Garmin(client);\n })().catch((error: unknown) => {\n current = null; // a failure is never cached: a login made later is picked up on the next call\n throw error;\n });\n return current;\n },\n reset() {\n current = null;\n },\n };\n}\n","import type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { GarminAuthError, GarminHttpError, GarminRateLimitError } from \"garminconnect-js\";\nimport { NotLoggedInError } from \"./session.js\";\n\nexport const LOGIN_HINT = \"run `npx @dynamicsninja/garminconnect-mcp login` in a terminal, then try again\";\n\n/** Plain-language text for a failure. Library messages are already free of tokens. */\nexport function describeError(error: unknown): string {\n if (error instanceof NotLoggedInError) return `Not logged in to Garmin: ${LOGIN_HINT}.`;\n if (error instanceof GarminAuthError) {\n return `Garmin session expired or was rejected (${error.message}): ${LOGIN_HINT}.`;\n }\n if (error instanceof GarminRateLimitError) {\n const wait = error.retryAfter !== undefined ? `; retry after ${error.retryAfter} s` : \"\";\n return `Garmin is rate limiting requests${wait}. ${error.message}`;\n }\n if (error instanceof GarminHttpError) return `Garmin returned HTTP ${error.status}: ${error.message}`;\n if (error instanceof Error) return error.message;\n return String(error);\n}\n\nexport function errorResult(error: unknown): CallToolResult {\n return { isError: true, content: [{ type: \"text\", text: describeError(error) }] };\n}\n","import { createInterface } from \"node:readline/promises\";\nimport type { LoginResult, MfaState } from \"garminconnect-js\";\n\nexport interface LoginClient {\n login(email: string, password: string): Promise<LoginResult>;\n resumeLogin(mfaState: MfaState, code: string): Promise<void>;\n}\n\nexport interface LoginIo {\n ask(question: string): Promise<string>;\n askHidden(question: string): Promise<string>;\n log(line: string): void;\n}\n\n/** Sign in once. The client's token store saves the session; nothing is printed to stdout. */\nexport async function login(io: LoginIo, client: LoginClient, env: Record<string, string | undefined> = process.env): Promise<void> {\n const email = env[\"GARMIN_EMAIL\"]?.trim() || (await io.ask(\"Garmin email: \")).trim();\n const password = env[\"GARMIN_PASSWORD\"] || (await io.askHidden(\"Garmin password: \"));\n if (!email || !password) throw new Error(\"Email and password are required.\");\n const result = await client.login(email, password);\n if (result.state === \"mfa_required\") {\n const code = (await io.ask(\"MFA code from Garmin: \")).trim();\n if (!code) throw new Error(\"No MFA code entered.\");\n await client.resumeLogin(result.mfaState, code);\n }\n}\n\n/** Prompts on stderr, so stdout stays clean even here. */\nexport function terminalIo(): LoginIo {\n return {\n async ask(question) {\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n try {\n return await rl.question(question);\n } finally {\n rl.close();\n }\n },\n askHidden(question) {\n return new Promise((resolve, reject) => {\n const stdin = process.stdin;\n process.stderr.write(question);\n stdin.setRawMode?.(true);\n stdin.resume();\n stdin.setEncoding(\"utf8\");\n let value = \"\";\n const done = (error?: Error) => {\n stdin.setRawMode?.(false);\n stdin.pause();\n stdin.off(\"data\", onData);\n process.stderr.write(\"\\n\");\n if (error) reject(error);\n else resolve(value);\n };\n const onData = (chunk: string) => {\n for (const ch of chunk) {\n if (ch === \"\\r\" || ch === \"\\n\") return done();\n if (ch === \"\\u0003\") return done(new Error(\"Cancelled.\"));\n if (ch === \"\\u007f\" || ch === \"\\b\") value = value.slice(0, -1);\n else value += ch;\n }\n };\n stdin.on(\"data\", onData);\n });\n },\n log: (line) => console.error(line),\n };\n}\n","import { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n type CallToolResult,\n type Tool,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { GarminAuthError } from \"garminconnect-js\";\nimport { errorResult } from \"./errors.js\";\nimport type { McpConfig, Session } from \"./session.js\";\n\nexport interface ToolDef {\n tool: Tool;\n run(input: Record<string, unknown>): Promise<CallToolResult>;\n}\n\nexport interface ServerDeps {\n config: McpConfig;\n session: Session;\n version?: string;\n}\n\nexport type ToolFactory = (deps: ServerDeps) => ToolDef[];\n\nexport function createServer(deps: ServerDeps, factories: readonly ToolFactory[]): Server {\n const tools = factories.flatMap((factory) => factory(deps));\n const byName = new Map<string, ToolDef>();\n for (const def of tools) {\n if (byName.has(def.tool.name)) throw new Error(`Duplicate tool name ${def.tool.name}`);\n byName.set(def.tool.name, def);\n }\n\n const server = new Server(\n { name: \"garminconnect-mcp\", version: deps.version ?? \"0.0.0\" },\n { capabilities: { tools: {} } },\n );\n server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: tools.map((t) => t.tool) }));\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const def = byName.get(request.params.name);\n if (!def) return errorResult(new Error(`Unknown tool \"${request.params.name}\"`));\n try {\n return await def.run(request.params.arguments ?? {});\n } catch (error) {\n // After `login` in a terminal, the next call must use the NEW tokens, not the cached client.\n if (error instanceof GarminAuthError) deps.session.reset();\n return errorResult(error);\n }\n });\n return server;\n}\n","// GENERATED by scripts/generate-manifest.ts. Do not edit; run `npm run manifest`.\n// tests/manifest.test.ts fails if this file is out of date.\nimport type { ManifestMethod } from \"../manifest.js\";\n\nexport const GARMIN_METHODS: readonly ManifestMethod[] = [\n {\n \"name\": \"getUserProfile\",\n \"category\": \"profile-and-misc\",\n \"description\": \"Cached per instance; every date-scoped endpoint needs the display name.\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getUserSettings\",\n \"category\": \"profile-and-misc\",\n \"description\": \"Cached per instance, same eviction-on-failure pattern as `getUserProfile()`.\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"displayName\",\n \"category\": \"profile-and-misc\",\n \"description\": \"Display name.\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"fullName\",\n \"category\": \"profile-and-misc\",\n \"description\": \"Full name.\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"userName\",\n \"category\": \"profile-and-misc\",\n \"description\": \"User name.\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"unitSystem\",\n \"category\": \"profile-and-misc\",\n \"description\": \"`measurementSystem` lives on `/userprofile-service/userprofile/user-settings` (under `userData`), not on the social profile. A convenience accessor, not a data endpoint: returns `undefined` rather than throwing if the payload shape is missing.\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getUserprofileSettings\",\n \"category\": \"profile-and-misc\",\n \"description\": \"GETs `/userprofile-service/userprofile/settings` (SINGULAR \\\"settings\\\", distinct from `getUserSettings`'s \\\"user-settings\\\" — the two paths are one character apart and easy to transpose) Upstream naming ruling, applies to the three rows above: upstream's `get_user_profile`, `get_full_name`, and `get_unit_system` were NOT ported as separate methods — they map onto this port's PRE-EXISTING `getUserSettings()`, `fullName()`, and `unitSystem()` respectively (see `src/services/userProfile.ts` for the full rationale: this port's own `getUserProfile()` already existed with a different, unrelated meanin…\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getUserSummary\",\n \"category\": \"wellness\",\n \"description\": \"Get user summary.\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getStats\",\n \"category\": \"wellness\",\n \"description\": \"alias of `getUserSummary`\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getStepsData\",\n \"category\": \"wellness\",\n \"description\": \"Get steps data.\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getHeartRates\",\n \"category\": \"wellness\",\n \"description\": \"Get heart rates.\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getSleepData\",\n \"category\": \"wellness\",\n \"description\": \"Get sleep data.\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getHrvData\",\n \"category\": \"wellness\",\n \"description\": \"Get hrv data.\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getBodyBattery\",\n \"category\": \"wellness\",\n \"description\": \"Get body battery.\",\n \"params\": [\n {\n \"name\": \"startdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"enddate\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getBodyBatteryEvents\",\n \"category\": \"wellness\",\n \"description\": \"Get body battery events.\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getFloors\",\n \"category\": \"wellness\",\n \"description\": \"throws `GarminError` if Garmin returns nothing\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getDailySteps\",\n \"category\": \"wellness\",\n \"description\": \"auto-chunks ranges over Garmin's 28-day-per-request limit into ≤28-day windows and concatenates; a single request within the limit passes its (possibly `null`) result through unchecked\",\n \"params\": [\n {\n \"name\": \"start\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"end\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getWeeklySteps\",\n \"category\": \"wellness\",\n \"description\": \"`weeks` defaults to 52, must be a positive integer\",\n \"params\": [\n {\n \"name\": \"end\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"weeks\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"number\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getWeeklyStress\",\n \"category\": \"wellness\",\n \"description\": \"same `weeks` default/validation as `getWeeklySteps`\",\n \"params\": [\n {\n \"name\": \"end\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"weeks\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"number\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getWeeklyIntensityMinutes\",\n \"category\": \"wellness\",\n \"description\": \"Get weekly intensity minutes.\",\n \"params\": [\n {\n \"name\": \"start\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"end\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getStatsAndBody\",\n \"category\": \"wellness\",\n \"description\": \"merges `getUserSummary` with the body-composition `totalAverage` block, delegating to `getBodyComposition` (bodyComposition service) for the latter\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"setBloodPressure\",\n \"category\": \"wellness\",\n \"description\": \"validates systolic 70-260, diastolic 40-150, pulse (if given) 20-250, all integers; `when` defaults to `new Date()`\",\n \"params\": [\n {\n \"name\": \"systolic\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"diastolic\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"pulse\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"when\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"description\": \"A moment in time, ISO 8601, e.g. 2026-09-28T07:30:00 (local) or with Z/offset\"\n },\n \"coerce\": \"date\"\n },\n {\n \"name\": \"notes\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getBloodPressure\",\n \"category\": \"wellness\",\n \"description\": \"`enddate` defaults to `startdate`\",\n \"params\": [\n {\n \"name\": \"startdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"enddate\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"deleteBloodPressure\",\n \"category\": \"wellness\",\n \"description\": \"Delete blood pressure.\",\n \"params\": [\n {\n \"name\": \"version\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ]\n }\n },\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"destructive\",\n \"io\": \"json\"\n },\n {\n \"name\": \"addHydrationData\",\n \"category\": \"wellness\",\n \"description\": \"raw milliliters, magnitude capped at 10000, negative values allowed; no delete endpoint exists, so **not safely round-trippable**\",\n \"params\": [\n {\n \"name\": \"valueInMl\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"when\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"description\": \"A moment in time, ISO 8601, e.g. 2026-09-28T07:30:00 (local) or with Z/offset\"\n },\n \"coerce\": \"date\"\n },\n {\n \"name\": \"cdate\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getHydrationData\",\n \"category\": \"wellness\",\n \"description\": \"Get hydration data.\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getRespirationData\",\n \"category\": \"wellness\",\n \"description\": \"Get respiration data.\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getSpo2Data\",\n \"category\": \"wellness\",\n \"description\": \"coerces a string `lastSevenDaysAvgSpO2` to a number\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getIntensityMinutesData\",\n \"category\": \"wellness\",\n \"description\": \"Get intensity minutes data.\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getAllDayStress\",\n \"category\": \"wellness\",\n \"description\": \"Get all day stress.\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getStressData\",\n \"category\": \"wellness\",\n \"description\": \"identical URL to `getAllDayStress`\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getAllDayEvents\",\n \"category\": \"wellness\",\n \"description\": \"Get all day events.\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getSleepDaily\",\n \"category\": \"wellness\",\n \"description\": \"Garmin's endpoint has a documented **28-day-per-request limit**; ranges beyond that are auto-chunked, de-duplicated by `calendarDate`, and sorted\",\n \"params\": [\n {\n \"name\": \"start\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"end\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getRhrDay\",\n \"category\": \"wellness\",\n \"description\": \"Get rhr day.\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getRhrDaily\",\n \"category\": \"wellness\",\n \"description\": \"reshapes `allMetrics.metricsMap` into `[{calendarDate, value}]`, dropping null values\",\n \"params\": [\n {\n \"name\": \"start\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"end\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getCaloriesDaily\",\n \"category\": \"wellness\",\n \"description\": \"merges active (metricId 22) and resting/BMR (metricId 23) series into `[{calendarDate, active, resting, total}]`\",\n \"params\": [\n {\n \"name\": \"start\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"end\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getHrvDataRange\",\n \"category\": \"wellness\",\n \"description\": \"Get hrv data range.\",\n \"params\": [\n {\n \"name\": \"start\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"end\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"countActivities\",\n \"category\": \"activities\",\n \"description\": \"returns the envelope's `totalCount`, not the whole response; throws `GarminError` if Garmin returns nothing or a non-numeric `totalCount`\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getActivities\",\n \"category\": \"activities\",\n \"description\": \"defaults `start=0, limit=20`\",\n \"params\": [\n {\n \"name\": \"start\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"limit\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"number\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getActivitiesForDate\",\n \"category\": \"activities\",\n \"description\": \"upstream's constant name is `garmin_connect_activity_fordate` but the resolved path is `/mobile-gateway/heartRate/...`, not an activities-service path\",\n \"params\": [\n {\n \"name\": \"fordate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getActivitiesByDate\",\n \"category\": \"activities\",\n \"description\": \"replicates upstream's internal pagination: fetches fixed pages of 20, incrementing `start` by 20, until an empty page (normal end) or 2000 pages without one (throws `GarminError`)\",\n \"params\": [\n {\n \"name\": \"startdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"enddate\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"activitytype\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"name\": \"sortorder\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getLastActivity\",\n \"category\": \"activities\",\n \"description\": \"delegates to `getActivities(0, 1)`, returns the last element or `null`\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getActivity\",\n \"category\": \"activities\",\n \"description\": \"Get activity.\",\n \"params\": [\n {\n \"name\": \"activityId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getActivityTypes\",\n \"category\": \"activities\",\n \"description\": \"`ActivityTypesResponse` is `ActivityType[]` (154 entries observed live: `{typeId, typeKey, parentTypeId, isHidden, restricted, trimmable}`) — **the upstream inventory's `returns` column says \\\"dict\\\", but the live response is an array; this type reflects the observed reality, not that label**\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"deleteActivity\",\n \"category\": \"activities\",\n \"description\": \"resolves to `null` on success (204). Live-verified on synthetic fixtures created by the probe itself (never against pre-existing data) — create → delete → poll-confirm gone via `getActivities`\",\n \"params\": [\n {\n \"name\": \"activityId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"destructive\",\n \"io\": \"json\"\n },\n {\n \"name\": \"setActivityName\",\n \"category\": \"activities\",\n \"description\": \"resolves to `null` on success. Live-verified: value read back via `getActivity` after the call, not just that the request was accepted\",\n \"params\": [\n {\n \"name\": \"activityId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n },\n {\n \"name\": \"activityName\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"setActivityType\",\n \"category\": \"activities\",\n \"description\": \"resolves to `null` on success. Live-verified: `activityTypeDTO` read back via `getActivity` after the call\",\n \"params\": [\n {\n \"name\": \"activityId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n },\n {\n \"name\": \"typeId\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"typeKey\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"name\": \"parentTypeId\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"setActivityDescription\",\n \"category\": \"activities\",\n \"description\": \"resolves to `null` on success. Live-verified: `description` read back via `getActivity` after the call\",\n \"params\": [\n {\n \"name\": \"activityId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n },\n {\n \"name\": \"description\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"createManualActivityFromJson\",\n \"category\": \"activities\",\n \"description\": \"sends `payload` to Garmin verbatim, no shape validation\",\n \"params\": [\n {\n \"name\": \"payload\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"createManualActivity\",\n \"category\": \"activities\",\n \"description\": \"**converts units**: `distanceKm * 1000` → meters, `durationMin * 60` → seconds, before building the request body; `startDatetime` is NOT routed through `formatDate` (it's a full local timestamp, not a bare calendar date) — **must include milliseconds**, e.g. `\\\"2026-09-22T10:00:00.000\\\"` (upstream's documented pattern); omitting them produced a live HTTP 500 `ValueInstantiationException` from Garmin during verification. Live-verified: the converted `summaryDTO.distance`/`summaryDTO.duration` were read back via `getActivity` and matched the expected meters/seconds exactly (5.5km/30min → 5500m/18…\",\n \"params\": [\n {\n \"name\": \"startDatetime\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"name\": \"timeZone\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"name\": \"typeKey\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"name\": \"distanceKm\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"durationMin\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"activityName\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"importActivity\",\n \"category\": \"activities\",\n \"description\": \"multipart upload to `/upload-service/upload/{ext}` (extension from `filename`, must be `fit`/`gpx`/`tcx`) with the load-bearing `NK`/`origin`/custom `User-Agent` headers that make Garmin treat it as an import rather than a device sync; a 409 is re-raised as `GarminConnectionError` (\\\"Activity already exists (duplicate):...\\\")\",\n \"params\": [\n {\n \"name\": \"file\",\n \"optional\": false,\n \"role\": \"file\",\n \"schema\": {\n \"description\": \"File contents\"\n }\n },\n {\n \"name\": \"filename\",\n \"optional\": false,\n \"role\": \"filename\",\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"binary-in\"\n },\n {\n \"name\": \"uploadActivity\",\n \"category\": \"activities\",\n \"description\": \"multipart upload to the PLAIN `/upload-service/upload` path, no extension suffix and none of `importActivity`'s load-bearing import headers (ordinary device-sync-shaped upload, distinct from `importActivity`'s spoofed-client import)\",\n \"params\": [\n {\n \"name\": \"file\",\n \"optional\": false,\n \"role\": \"file\",\n \"schema\": {\n \"description\": \"File contents\"\n }\n },\n {\n \"name\": \"filename\",\n \"optional\": false,\n \"role\": \"filename\",\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"binary-in\"\n },\n {\n \"name\": \"getPersonalRecord\",\n \"category\": \"activities\",\n \"description\": \"GETs `/personalrecord-service/personalrecord/prs/{displayName}`; no args `PersonalRecords` is `PersonalRecord[]` — **the upstream inventory's `returns` column says \\\"dict\\\"; live-verified WRONG**, the test account returned `array[0]`. Note the plural type name: upstream's method name is singular but the payload is a list, so the result type is named for what it is\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"downloadActivity\",\n \"category\": \"activities\",\n \"description\": \"`ActivityDownloadFormat` is `\\\"ORIGINAL\\\" | \\\"TCX\\\" | \\\"GPX\\\" | \\\"KML\\\" | \\\"CSV\\\"`, default `\\\"ORIGINAL\\\"`\",\n \"params\": [\n {\n \"name\": \"activityId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n },\n {\n \"name\": \"format\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"enum\": [\n \"ORIGINAL\",\n \"TCX\",\n \"GPX\",\n \"KML\",\n \"CSV\"\n ]\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"binary-out\"\n },\n {\n \"name\": \"getActivitySplits\",\n \"category\": \"activities\",\n \"description\": \"Get activity splits.\",\n \"params\": [\n {\n \"name\": \"activityId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getActivityTypedSplits\",\n \"category\": \"activities\",\n \"description\": \"richer detail than `getActivitySplits` for some activity types (e.g. Bouldering)\",\n \"params\": [\n {\n \"name\": \"activityId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getActivitySplitSummaries\",\n \"category\": \"activities\",\n \"description\": \"Get activity split summaries.\",\n \"params\": [\n {\n \"name\": \"activityId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getActivityWeather\",\n \"category\": \"activities\",\n \"description\": \"Get activity weather.\",\n \"params\": [\n {\n \"name\": \"activityId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getActivityHrInTimezones\",\n \"category\": \"activities\",\n \"description\": \"Get activity hr in timezones.\",\n \"params\": [\n {\n \"name\": \"activityId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getActivityPowerInTimezones\",\n \"category\": \"activities\",\n \"description\": \"Get activity power in timezones.\",\n \"params\": [\n {\n \"name\": \"activityId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getActivityDetails\",\n \"category\": \"activities\",\n \"description\": \"defaults `maxchart=2000, maxpoly=4000`, sent as `maxChartSize`/`maxPolylineSize`\",\n \"params\": [\n {\n \"name\": \"activityId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n },\n {\n \"name\": \"maxchart\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"maxpoly\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"number\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getActivityExerciseSets\",\n \"category\": \"activities\",\n \"description\": \"Get activity exercise sets.\",\n \"params\": [\n {\n \"name\": \"activityId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"setActivityExerciseSets\",\n \"category\": \"activities\",\n \"description\": \"**replace-all semantics**, `payload` sent verbatim\",\n \"params\": [\n {\n \"name\": \"activityId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n },\n {\n \"name\": \"payload\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"exerciseSets\": {\n \"type\": \"array\",\n \"items\": {\n \"description\": \"Any JSON value\"\n }\n }\n },\n \"additionalProperties\": true\n }\n }\n ],\n \"safety\": \"destructive\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getActivityGear\",\n \"category\": \"activities\",\n \"description\": \"returns an ARRAY; inventory places this row under the \\\"gear\\\" section, not \\\"activities\\\"\",\n \"params\": [\n {\n \"name\": \"activityId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getGearActivities\",\n \"category\": \"activities\",\n \"description\": \"`limit` clamped to 1000; returns `[]` on a 404 instead of throwing; inventory places this row under \\\"gear\\\"\",\n \"params\": [\n {\n \"name\": \"gearUUID\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"name\": \"limit\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"number\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"addGearToActivity\",\n \"category\": \"activities\",\n \"description\": \"on 404 re-raises as `GarminConnectionError` (\\\"gear not found (likely retired/removed)\\\"); inventory places this row under \\\"gear\\\"\",\n \"params\": [\n {\n \"name\": \"gearUUID\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"name\": \"activityId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"removeGearFromActivity\",\n \"category\": \"activities\",\n \"description\": \"**PUT**, not DELETE; same 404-handling pattern as `addGearToActivity`; inventory places this row under \\\"gear\\\"\",\n \"params\": [\n {\n \"name\": \"gearUUID\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"name\": \"activityId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getProgressSummaryBetweenDates\",\n \"category\": \"activities\",\n \"description\": \"defaults `metric=\\\"distance\\\", groupbyactivities=true`; both dates routed through `formatDate`\",\n \"params\": [\n {\n \"name\": \"startdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"enddate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"metric\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"name\": \"groupbyactivities\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"boolean\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"downloadHealthSnapshot\",\n \"category\": \"activities\",\n \"description\": \"routed through `formatDate`; routed through `client.download`\",\n \"params\": [\n {\n \"name\": \"requestedDate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"binary-out\"\n },\n {\n \"name\": \"getGear\",\n \"category\": \"gear\",\n \"description\": \"hits `/gear-service/gear/filterGear?userProfilePk=...`; returns an ARRAY of gear entries. This is the dedicated gear-CRUD service (`src/services/gear.ts`), distinct from `getActivityGear` (activities service, reuses the same base URL with `activityId` instead)\",\n \"params\": [\n {\n \"name\": \"userProfileNumber\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ]\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"createGear\",\n \"category\": \"gear\",\n \"description\": \"POSTs `/gear-service/gear/v2`; defaults `usageType=\\\"DISTANCE\\\", notes=\\\"\\\"`; `firstUseDate` routed through `formatDate`; `gearType`/`usageType` upper-cased via `validateSportKey`; **converts** `maxUsageDistanceKm` -> `maxUsageDistanceMeters` (`round(km*1000)`, floor 1) and `maxUsageDurationMin` -> `maxUsageDurationSeconds` (`round(min*60)`, floor 1) — the opposite direction from `addWeighIn`'s \\\"send raw\\\" rule; (implemented as a raw pass-through)\",\n \"params\": [\n {\n \"name\": \"gearType\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"name\": \"brand\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"name\": \"model\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"name\": \"name\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"name\": \"firstUseDate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"usageType\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"enum\": [\n \"distance\",\n \"NONE\",\n \"DISTANCE\",\n \"DURATION\",\n \"DATE\",\n \"none\",\n \"duration\",\n \"date\"\n ]\n }\n },\n {\n \"name\": \"maxUsageDistanceKm\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"maxUsageDurationMin\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"notes\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"name\": \"activityTypeKeys\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getGearStats\",\n \"category\": \"gear\",\n \"description\": \"GETs `/gear-service/gear/stats/{gearUUID}`; `gearUUID` validated via `validateUuid` (hex, hyphens optional); returns `{}` on a 404 instead of throwing; other errors re-raised\",\n \"params\": [\n {\n \"name\": \"gearUUID\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"deleteGear\",\n \"category\": \"gear\",\n \"description\": \"**NOT upstream parity**: upstream python-garminconnect has no delete-gear method. `DELETE /gear-service/gear/v2/{gearUUID}`, resolves `null` on success (204). **The UUID must be HYPHENATED** — `getGear` returns them WITHOUT hyphens and that form 404s, so this method re-inserts them for you when handed the bare 32-char form; only hand-rolled URLs hit the 404. IRREVERSIBLE: removes the gear AND its activity history\",\n \"params\": [\n {\n \"name\": \"gearUUID\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"safety\": \"destructive\",\n \"io\": \"json\"\n },\n {\n \"name\": \"setGearActivityDefaults\",\n \"category\": \"gear\",\n \"description\": \"**NOT upstream parity**: a WORKING replacement for `setGearDefault`, whose upstream endpoint is dead. Read-modify-writes the v2 record: GETs `/gear-service/gear/v2/{uuid}`, replaces `associatedActivityTypes` with `[{activityTypeKey, defaultGear: true, preferredGear: false}]` per key, PUTs the whole record back. Keys are **lowercase** (`\\\"running\\\"`), matching `createGear` — NOT `setGearDefault`'s upper-cased form. `[]` clears all defaults. Concurrent callers can clobber each other\",\n \"params\": [\n {\n \"name\": \"gearUUID\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"name\": \"activityTypeKeys\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n ],\n \"safety\": \"destructive\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getGearDefaults\",\n \"category\": \"gear\",\n \"description\": \"GETs `/gear-service/gear/user/{userProfileNumber}/activityTypes`; returns an ARRAY of `{uuid, activityTypePk, defaultGear}` entries\",\n \"params\": [\n {\n \"name\": \"userProfileNumber\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ]\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"listCourses\",\n \"category\": \"courses\",\n \"description\": \"**NOT upstream parity** (upstream has no courses). GETs `/web-gateway/course/owner/` (trailing slash included); returns an ENVELOPE `{ coursesForUser: CourseSummary[] }`, not a bare array\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getCourse\",\n \"category\": \"courses\",\n \"description\": \"GETs `/course-service/course/{courseId}`; a missing id is a 404 `GarminHttpError` (\\\"Course not found : {id}\\\")\",\n \"params\": [\n {\n \"name\": \"courseId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"importCourseGpx\",\n \"category\": \"courses\",\n \"description\": \"multipart POST (field `file`) to `/course-service/course/import`. **Parses only, saves NOTHING**: the result has `courseId: null` and a RESAMPLED track (13 GPX points came back as 37) with null elevations/timestamps; `courseName` is the GPX `<name>`. Only `.gpx` accepted (only `.gpx` verified); throws `GarminError` on an empty response\",\n \"params\": [\n {\n \"name\": \"file\",\n \"optional\": false,\n \"role\": \"file\",\n \"schema\": {\n \"description\": \"File contents\"\n }\n },\n {\n \"name\": \"filename\",\n \"optional\": false,\n \"role\": \"filename\",\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"binary-in\"\n },\n {\n \"name\": \"createCourse\",\n \"category\": \"courses\",\n \"description\": \"POSTs `/course-service/course` with the template Garmin's web client sends. `CourseInput` = `{ name, geoPoints, coursePoints?, activityTypeId? = 1 (running), privacy? = \\\"private\\\" }`; privacy maps to `rulePK` public 1 / private 2. Garmin computes `distanceMeter` and elevation. Throws `GarminError` before any request on an empty name or fewer than two geoPoints\",\n \"params\": [\n {\n \"name\": \"input\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"name\": {\n \"type\": \"string\"\n },\n \"geoPoints\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"latitude\": {\n \"type\": \"number\"\n },\n \"longitude\": {\n \"type\": \"number\"\n },\n \"elevation\": {\n \"type\": \"number\"\n },\n \"distance\": {\n \"type\": \"number\"\n },\n \"timestamp\": {\n \"type\": \"number\"\n }\n },\n \"required\": [\n \"latitude\",\n \"longitude\",\n \"elevation\",\n \"distance\",\n \"timestamp\"\n ],\n \"additionalProperties\": true\n }\n },\n \"coursePoints\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n }\n },\n \"activityTypeId\": {\n \"type\": \"number\",\n \"description\": \"Garmin activity-type id (`getActivityTypes()`'s `typeId`). Default 1, running.\"\n },\n \"privacy\": {\n \"type\": \"string\",\n \"enum\": [\n \"private\",\n \"public\"\n ],\n \"description\": \"Default `\\\"private\\\"`.\"\n }\n },\n \"required\": [\n \"name\",\n \"geoPoints\"\n ],\n \"additionalProperties\": false\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"createCourseFromGpx\",\n \"category\": \"courses\",\n \"description\": \"`importCourseGpx` then `createCourse`. Name defaults to the GPX `<name>`, then the filename without `.gpx`\",\n \"params\": [\n {\n \"name\": \"file\",\n \"optional\": false,\n \"role\": \"file\",\n \"schema\": {\n \"description\": \"File contents\"\n }\n },\n {\n \"name\": \"filename\",\n \"optional\": false,\n \"role\": \"filename\",\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"name\": \"options\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"activityTypeId\": {\n \"type\": \"number\",\n \"description\": \"Garmin activity-type id (`getActivityTypes()`'s `typeId`). Default 1, running.\"\n },\n \"privacy\": {\n \"type\": \"string\",\n \"enum\": [\n \"private\",\n \"public\"\n ],\n \"description\": \"Default `\\\"private\\\"`.\"\n },\n \"name\": {\n \"type\": \"string\"\n }\n },\n \"additionalProperties\": false\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"binary-in\"\n },\n {\n \"name\": \"updateCourse\",\n \"category\": \"courses\",\n \"description\": \"READ-MODIFY-WRITE: GETs the record, overlays the changes, PUTs the whole record back to `/course-service/course/{courseId}` — the same request Garmin's own web editor sends on Save (observed 2026-09-24). Concurrent callers can clobber each other. Throws before any request if neither field is given or the name is blank. A just-created course may 429 \\\"not yet ready\\\"\",\n \"params\": [\n {\n \"name\": \"courseId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n },\n {\n \"name\": \"changes\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"name\": {\n \"type\": \"string\"\n },\n \"privacy\": {\n \"type\": \"string\",\n \"enum\": [\n \"private\",\n \"public\"\n ]\n }\n },\n \"additionalProperties\": false\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"deleteCourse\",\n \"category\": \"courses\",\n \"description\": \"`DELETE /course-service/course/{courseId}`, resolves `null` (204). IRREVERSIBLE. May 429 \\\"not yet ready\\\" for a few seconds after creation\",\n \"params\": [\n {\n \"name\": \"courseId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"destructive\",\n \"io\": \"json\"\n },\n {\n \"name\": \"downloadCourseGpx\",\n \"category\": \"courses\",\n \"description\": \"GETs `/course-service/course/gpx/{courseId}` through `client.download`\",\n \"params\": [\n {\n \"name\": \"courseId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"binary-out\"\n },\n {\n \"name\": \"getDevices\",\n \"category\": \"devices\",\n \"description\": \"undocumented per-device shape, `deviceId` is the field the other device methods key off of\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getDeviceSettings\",\n \"category\": \"devices\",\n \"description\": \"`deviceId` coerced to an int, validated positive, re-stringified before being placed in the path Two-call sequence: get a `deviceId` from a `getDevices()` entry first, then pass it here\",\n \"params\": [\n {\n \"name\": \"deviceId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getPrimaryTrainingDevice\",\n \"category\": \"devices\",\n \"description\": \"Get primary training device.\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getDeviceSolarData\",\n \"category\": \"devices\",\n \"description\": \"the only raising method in this group: throws `GarminConnectionError` if the response is falsy or missing the `deviceSolarInput` key; returns `resp.deviceSolarInput`, NOT the envelope. `enddate` defaults to `startdate`, and `singleDayView` is sent `\\\"true\\\"` exactly when `enddate` was omitted\",\n \"params\": [\n {\n \"name\": \"deviceId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n },\n {\n \"name\": \"startdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"enddate\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getDeviceAlarms\",\n \"category\": \"devices\",\n \"description\": \"no HTTP path of its own: calls `getDevices()` once, then `getDeviceSettings(device.deviceId)` once per device (N+1 fan-out, sequential, ported faithfully — do not parallelize), concatenating each device's `alarms`; a device with no alarms contributes nothing, never throws for that case\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getDeviceLastUsed\",\n \"category\": \"devices\",\n \"description\": \"also used internally by `pushWorkoutToDevice` to resolve a missing `deviceId`\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getEarnedBadges\",\n \"category\": \"badges-challenges\",\n \"description\": \"GETs `/badge-service/badge/earned`; each badge gains `badgeImageUrls: { small, large }`, added by this library (Garmin sends no image URL): `https://connect.garmin.com/images/badges/xxhdpi/badge_<badgeUuid ?? badgeId>_sml.png` (`_lrg.png` for `large`), the URL Garmin Connect's web app builds; public, no session. Every other field passes through unchanged; stays nullable (does NOT coalesce to `[]`)\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getAvailableBadges\",\n \"category\": \"badges-challenges\",\n \"description\": \"GETs `/badge-service/badge/available?showExclusiveBadge=true`; same `badgeImageUrls` as `getEarnedBadges`; stays nullable\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getInProgressBadges\",\n \"category\": \"badges-challenges\",\n \"description\": \"no HTTP path of its own: calls `getEarnedBadges()` and `getAvailableBadges()`, filters each with upstream's `is_badge_in_progress` predicate (progress truthy; if `progress === target`, only \\\"in progress\\\" when `badgeLimitCount` is set and `badgeEarnedNumber < badgeLimitCount`), then merges both filtered lists into a `Map` keyed by `badgeId` (available overwrites earned on collision, same key-position semantics as Python's `dict.update`); never raises — a `null` from either upstream call is treated as `[]`. Badges carry `badgeImageUrls` (inherited from the two calls)\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getBadgeDetail\",\n \"category\": \"badges-challenges\",\n \"description\": \"**NOT upstream parity** (upstream has no per-badge call). GETs `/badge-service/badge/detail/v3/{badgeId}`, the request Garmin Connect's web app makes when a badge is opened; `badgeId` validated as a positive integer. Returns an OBJECT: the `getEarnedBadges` fields plus `relatedBadges` (the rest of the series, each with `earnedByMe`), `badgeAssocType`/`badgeAssocDataId`/`badgeAssocDataName` (for `\\\"activityId\\\"`, the activity that earned it) and `followings`. Works for unearned badges. An unknown id is a **400** `GarminHttpError`, not a 404. The badge and each `relatedBadges` entry gain `badgeIm…\",\n \"params\": [\n {\n \"name\": \"badgeId\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getAdhocChallenges\",\n \"category\": \"badges-challenges\",\n \"description\": \"GETs `/adhocchallenge-service/adHocChallenge/historical`; `start` validated non-negative, `limit` validated positive (throws `GarminError` otherwise); live-verified as a JSON ARRAY, not the `dict` the inventory's `returns` column names\",\n \"params\": [\n {\n \"name\": \"start\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"limit\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getBadgeChallenges\",\n \"category\": \"badges-challenges\",\n \"description\": \"GETs `/badgechallenge-service/badgeChallenge/completed`; same `start`/`limit` validation as `getAdhocChallenges`; same array-not-dict correction. **Live discovery**: Garmin's server itself rejects `start=0` with a 400 (`\\\"start should > 0.\\\"`) on this endpoint despite upstream's own client-side validation allowing it — the client-side check here faithfully matches upstream (non-negative), the 400 is Garmin's server, not a wrong URL; call with `start>=1` in practice\",\n \"params\": [\n {\n \"name\": \"start\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"limit\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getAvailableBadgeChallenges\",\n \"category\": \"badges-challenges\",\n \"description\": \"GETs `/badgechallenge-service/badgeChallenge/available`; same `start`/`limit` validation; same array-not-dict correction and same live `start=0` -> 400 discovery as `getBadgeChallenges`\",\n \"params\": [\n {\n \"name\": \"start\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"limit\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getNonCompletedBadgeChallenges\",\n \"category\": \"badges-challenges\",\n \"description\": \"GETs `/badgechallenge-service/badgeChallenge/non-completed`; same `start`/`limit` validation; same array-not-dict correction and same live `start=0` -> 400 discovery as `getBadgeChallenges`\",\n \"params\": [\n {\n \"name\": \"start\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"limit\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getInprogressVirtualChallenges\",\n \"category\": \"badges-challenges\",\n \"description\": \"GETs `/badgechallenge-service/virtualChallenge/inProgress`; **asymmetric validation**: `start` validated POSITIVE here (rejects `start=0`), unlike the non-negative `start` on the four challenge methods above; `limit` validated positive; same array-not-dict correction\",\n \"params\": [\n {\n \"name\": \"start\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"limit\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getWeighIns\",\n \"category\": \"body-composition-weight\",\n \"description\": \"Get weigh ins.\",\n \"params\": [\n {\n \"name\": \"startdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"enddate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"addWeighIn\",\n \"category\": \"body-composition-weight\",\n \"description\": \"defaults `unitKey=\\\"kg\\\"`, `when=new Date()`\",\n \"params\": [\n {\n \"name\": \"weightValue\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"unitKey\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"enum\": [\n \"kg\",\n \"lbs\"\n ]\n }\n },\n {\n \"name\": \"when\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"description\": \"A moment in time, ISO 8601, e.g. 2026-09-28T07:30:00 (local) or with Z/offset\"\n },\n \"coerce\": \"date\"\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"deleteWeighIn\",\n \"category\": \"body-composition-weight\",\n \"description\": \"Delete weigh in.\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"weightPk\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n }\n ],\n \"safety\": \"destructive\",\n \"io\": \"json\"\n },\n {\n \"name\": \"addWeighInWithTimestamps\",\n \"category\": \"body-composition-weight\",\n \"description\": \"same raw-value, no-conversion rule as `addWeighIn`; the two timestamps are COUPLED: the local instant resolves from `dateTimestamp` if given (naive strings read as LOCAL time) else from `when` (defaults `new Date()`), and `gmtTimestamp`, when omitted, is derived from THAT resolved instant — never independently from `when`. Both supplied strings are re-formatted rather than forwarded verbatim (a naive `gmtTimestamp` is read as UTC), matching upstream\",\n \"params\": [\n {\n \"name\": \"weightValue\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"unitKey\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"enum\": [\n \"kg\",\n \"lbs\"\n ]\n }\n },\n {\n \"name\": \"dateTimestamp\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"name\": \"gmtTimestamp\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"name\": \"when\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date-time\",\n \"description\": \"A moment in time, ISO 8601, e.g. 2026-09-28T07:30:00 (local) or with Z/offset\"\n },\n \"coerce\": \"date\"\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getDailyWeighIns\",\n \"category\": \"body-composition-weight\",\n \"description\": \"GETs `/weight-service/weight/dayview/{cdate}?includeAll=true`\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"deleteWeighIns\",\n \"category\": \"body-composition-weight\",\n \"description\": \"no HTTP path of its own: calls `getDailyWeighIns`, then loops `deleteWeighIn` per entry; returns `null` (deletes nothing) if there are zero entries, or more than one entry and `deleteAll` is not `true`; otherwise deletes every entry that day and returns the count. **IRREVERSIBLE** — deletes ALL weigh-ins recorded on `cdate` when it proceeds\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"deleteAll\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"boolean\"\n }\n }\n ],\n \"safety\": \"destructive\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getBodyComposition\",\n \"category\": \"body-composition-weight\",\n \"description\": \"GETs `/weight-service/weight/dateRange`; `enddate` defaults to `startdate`; throws `GarminError` if `startdate > enddate` `getStatsAndBody` (wellness service) now delegates to this instead of inlining its own copy of the same call\",\n \"params\": [\n {\n \"name\": \"startdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"enddate\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"addBodyComposition\",\n \"category\": \"body-composition-weight\",\n \"description\": \"builds a `.fit` binary in memory (`src/util/fit.ts`, ported from upstream `fit.py`'s `FitEncoderWeight`) and uploads it via `client.upload` to `/upload-service/upload`; `weight` validated positive/finite, throws `GarminError` otherwise; (passes `client.upload`'s result through unchecked `self.client.post(...)`)\",\n \"params\": [\n {\n \"name\": \"weight\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"extra\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"percentFat\": {\n \"type\": \"number\"\n },\n \"percentHydration\": {\n \"type\": \"number\"\n },\n \"visceralFatMass\": {\n \"type\": \"number\"\n },\n \"boneMass\": {\n \"type\": \"number\"\n },\n \"muscleMass\": {\n \"type\": \"number\"\n },\n \"basalMet\": {\n \"type\": \"number\"\n },\n \"activeMet\": {\n \"type\": \"number\"\n },\n \"physiqueRating\": {\n \"type\": \"number\"\n },\n \"metabolicAge\": {\n \"type\": \"number\"\n },\n \"visceralFatRating\": {\n \"type\": \"number\"\n },\n \"bmi\": {\n \"type\": \"number\"\n },\n \"timestamp\": {\n \"type\": \"string\"\n }\n },\n \"additionalProperties\": false\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getMaxMetrics\",\n \"category\": \"metrics\",\n \"description\": \"the date is repeated twice in the path (start=end=cdate)\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getMaxMetricsRange\",\n \"category\": \"metrics\",\n \"description\": \"throws `GarminError` if `start > end`\",\n \"params\": [\n {\n \"name\": \"start\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"end\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getFunctionalThresholdPowerRange\",\n \"category\": \"metrics\",\n \"description\": \"defaults `sport=\\\"RUNNING\\\"`, `aggregation=\\\"daily\\\"`; `sport` upper-cased and validated (`^[A-Z_]+$`); `aggregation` restricted to `{daily,weekly,monthly,yearly}`\",\n \"params\": [\n {\n \"name\": \"start\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"end\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"sport\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"name\": \"aggregation\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"enum\": [\n \"daily\",\n \"weekly\",\n \"monthly\",\n \"yearly\"\n ]\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getLactateThreshold\",\n \"category\": \"metrics\",\n \"description\": \"defaults `latest=true`, `aggregation=\\\"daily\\\"`. TWO DIFFERENT branches: `latest=true` returns `{speed_and_heart_rate, power}` from two GETs; `latest=false` (requires `startDate`, throws otherwise) returns `{speed, heart_rate, power}` from three GETs\",\n \"params\": [\n {\n \"name\": \"latest\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"boolean\"\n }\n },\n {\n \"name\": \"startDate\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"endDate\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"aggregation\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"enum\": [\n \"daily\",\n \"weekly\",\n \"monthly\",\n \"yearly\"\n ]\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getTrainingReadiness\",\n \"category\": \"metrics\",\n \"description\": \"Get training readiness.\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getMorningTrainingReadiness\",\n \"category\": \"metrics\",\n \"description\": \"delegates to `getTrainingReadiness`, no HTTP call of its own; filters for `inputContext === \\\"AFTER_WAKEUP_RESET\\\"`, falls back to the first entry; `null` for a falsy or empty result\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getEnduranceScore\",\n \"category\": \"metrics\",\n \"description\": \"TWO branches by presence of `enddate`: no `enddate` hits the single-day endpoint; with `enddate` hits `.../stats` with hard-coded `aggregation=\\\"weekly\\\"`\",\n \"params\": [\n {\n \"name\": \"startdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"enddate\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getRunningTolerance\",\n \"category\": \"metrics\",\n \"description\": \"defaults `aggregation=\\\"weekly\\\"`; restricted to `{daily,weekly}` (narrower than the FTP/lactate methods)\",\n \"params\": [\n {\n \"name\": \"startdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"enddate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"aggregation\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"enum\": [\n \"daily\",\n \"weekly\"\n ]\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getRacePredictions\",\n \"category\": \"metrics\",\n \"description\": \"TWO branches, all-or-nothing params (throws on a partial combination): no params hits `.../latest/{displayName}`; all three hit `.../{type}/{displayName}`, capped at a 366-day span\",\n \"params\": [\n {\n \"name\": \"startdate\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"enddate\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"type\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"enum\": [\n \"daily\",\n \"monthly\"\n ]\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getTrainingStatus\",\n \"category\": \"metrics\",\n \"description\": \"Get training status.\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getFitnessAgeData\",\n \"category\": \"metrics\",\n \"description\": \"Get fitness age data.\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getHillScore\",\n \"category\": \"metrics\",\n \"description\": \"TWO branches by presence of `enddate`, same shape as `getEnduranceScore` but the range branch hard-codes `aggregation=\\\"daily\\\"` (NOT `\\\"weekly\\\"` — do not conflate the two)\",\n \"params\": [\n {\n \"name\": \"startdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"enddate\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getCyclingFtp\",\n \"category\": \"metrics\",\n \"description\": \"latest value only; use `getFunctionalThresholdPowerRange` for history\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getHeartRateZones\",\n \"category\": \"metrics\",\n \"description\": \"Get heart rate zones.\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getPowerZones\",\n \"category\": \"metrics\",\n \"description\": \"Get power zones.\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getPowerZonesForSport\",\n \"category\": \"metrics\",\n \"description\": \"`sport` upper-cased and validated the same way as `getFunctionalThresholdPowerRange`\",\n \"params\": [\n {\n \"name\": \"sport\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getWorkouts\",\n \"category\": \"workouts\",\n \"description\": \"defaults `start=0, limit=100`, stays nullable (does NOT coalesce to `[]`)\",\n \"params\": [\n {\n \"name\": \"start\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"limit\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"number\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getWorkoutById\",\n \"category\": \"workouts\",\n \"description\": \"Get workout by id.\",\n \"params\": [\n {\n \"name\": \"workoutId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"deleteWorkout\",\n \"category\": \"workouts\",\n \"description\": \"deletes the template from the workout library, irreversible\",\n \"params\": [\n {\n \"name\": \"workoutId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"destructive\",\n \"io\": \"json\"\n },\n {\n \"name\": \"downloadWorkout\",\n \"category\": \"workouts\",\n \"description\": \"FIT-file bytes\",\n \"params\": [\n {\n \"name\": \"workoutId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"binary-out\"\n },\n {\n \"name\": \"uploadWorkout\",\n \"category\": \"workouts\",\n \"description\": \"a string is JSON-parsed (throws `GarminError` on invalid JSON or a non-object/array result)\",\n \"params\": [\n {\n \"name\": \"workoutJson\",\n \"optional\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"type\": \"string\"\n },\n {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n {\n \"type\": \"array\",\n \"items\": {\n \"description\": \"Any JSON value\"\n }\n }\n ]\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"updateWorkout\",\n \"category\": \"workouts\",\n \"description\": \"full-replace PUT; forces `workoutId` into the body to match the path id; unlike `uploadWorkout`, a string must resolve to an object, not an array\",\n \"params\": [\n {\n \"name\": \"workoutId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n },\n {\n \"name\": \"workoutJson\",\n \"optional\": false,\n \"schema\": {\n \"anyOf\": [\n {\n \"type\": \"string\"\n },\n {\n \"type\": \"object\",\n \"additionalProperties\": true\n }\n ]\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"uploadRunningWorkout\",\n \"category\": \"workouts\",\n \"description\": \"fills the default `running` `sportType` (`{sportTypeId:1, sportTypeKey:\\\"running\\\", displayOrder:1}`) if the caller didn't supply one, then delegates to `uploadWorkout`\",\n \"params\": [\n {\n \"name\": \"workout\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"workoutName\": {\n \"type\": \"string\"\n },\n \"sportType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"estimatedDurationInSecs\": {\n \"type\": \"number\"\n },\n \"workoutSegments\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"segmentOrder\": {\n \"type\": \"number\"\n },\n \"sportType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"workoutSteps\": {\n \"type\": \"array\",\n \"items\": {\n \"anyOf\": [\n {\n \"type\": \"object\",\n \"properties\": {\n \"type\": {\n \"type\": \"string\"\n },\n \"stepOrder\": {\n \"type\": \"number\"\n },\n \"stepType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"endCondition\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"endConditionValue\": {\n \"type\": \"number\"\n },\n \"targetType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"strokeType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"equipmentType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"childStepId\": {\n \"type\": \"number\"\n }\n },\n \"required\": [\n \"stepOrder\"\n ],\n \"additionalProperties\": true\n },\n {\n \"type\": \"object\",\n \"properties\": {\n \"type\": {\n \"type\": \"string\"\n },\n \"stepOrder\": {\n \"type\": \"number\"\n },\n \"stepType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"numberOfIterations\": {\n \"type\": \"number\",\n \"description\": \"The iteration count for a COUNT-based repeat. **Nullable**, because a repeat can instead be\\nTIME-based: Garmin's HIIT designer offers \\\"Repeat Until Time Is\\\", which stores\\n`endCondition: time`, the seconds in `endConditionValue`, and `numberOfIterations: null`.\\nConfirmed live 2026-09-23. Upstream types this as a plain required number, which cannot\\nexpress the time-based form.\"\n },\n \"workoutSteps\": {\n \"type\": \"array\",\n \"items\": {\n \"anyOf\": [\n {\n \"type\": \"object\",\n \"properties\": {\n \"type\": {\n \"type\": \"string\"\n },\n \"stepOrder\": {\n \"type\": \"number\"\n },\n \"stepType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"endCondition\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"endConditionValue\": {\n \"type\": \"number\"\n },\n \"targetType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"strokeType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"equipmentType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"childStepId\": {\n \"type\": \"number\"\n }\n },\n \"required\": [\n \"stepOrder\"\n ],\n \"additionalProperties\": true\n },\n {\n \"type\": \"object\",\n \"description\": \"Recursive: same shape as the enclosing RepeatWorkoutGroup\"\n }\n ]\n }\n },\n \"endCondition\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"endConditionValue\": {\n \"type\": \"number\"\n },\n \"childStepId\": {\n \"type\": \"number\"\n },\n \"smartRepeat\": {\n \"type\": \"boolean\"\n }\n },\n \"required\": [\n \"stepOrder\",\n \"numberOfIterations\",\n \"workoutSteps\"\n ],\n \"additionalProperties\": true\n }\n ]\n }\n }\n },\n \"required\": [\n \"segmentOrder\",\n \"sportType\",\n \"workoutSteps\"\n ],\n \"additionalProperties\": true\n }\n },\n \"author\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"description\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"workoutName\",\n \"estimatedDurationInSecs\",\n \"workoutSegments\"\n ],\n \"additionalProperties\": true\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"uploadCyclingWorkout\",\n \"category\": \"workouts\",\n \"description\": \"same pattern, default `sportType` `{sportTypeId:2, sportTypeKey:\\\"cycling\\\", displayOrder:2}`\",\n \"params\": [\n {\n \"name\": \"workout\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"workoutName\": {\n \"type\": \"string\"\n },\n \"sportType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"estimatedDurationInSecs\": {\n \"type\": \"number\"\n },\n \"workoutSegments\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"segmentOrder\": {\n \"type\": \"number\"\n },\n \"sportType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"workoutSteps\": {\n \"type\": \"array\",\n \"items\": {\n \"anyOf\": [\n {\n \"type\": \"object\",\n \"properties\": {\n \"type\": {\n \"type\": \"string\"\n },\n \"stepOrder\": {\n \"type\": \"number\"\n },\n \"stepType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"endCondition\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"endConditionValue\": {\n \"type\": \"number\"\n },\n \"targetType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"strokeType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"equipmentType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"childStepId\": {\n \"type\": \"number\"\n }\n },\n \"required\": [\n \"stepOrder\"\n ],\n \"additionalProperties\": true\n },\n {\n \"type\": \"object\",\n \"properties\": {\n \"type\": {\n \"type\": \"string\"\n },\n \"stepOrder\": {\n \"type\": \"number\"\n },\n \"stepType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"numberOfIterations\": {\n \"type\": \"number\",\n \"description\": \"The iteration count for a COUNT-based repeat. **Nullable**, because a repeat can instead be\\nTIME-based: Garmin's HIIT designer offers \\\"Repeat Until Time Is\\\", which stores\\n`endCondition: time`, the seconds in `endConditionValue`, and `numberOfIterations: null`.\\nConfirmed live 2026-09-23. Upstream types this as a plain required number, which cannot\\nexpress the time-based form.\"\n },\n \"workoutSteps\": {\n \"type\": \"array\",\n \"items\": {\n \"anyOf\": [\n {\n \"type\": \"object\",\n \"properties\": {\n \"type\": {\n \"type\": \"string\"\n },\n \"stepOrder\": {\n \"type\": \"number\"\n },\n \"stepType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"endCondition\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"endConditionValue\": {\n \"type\": \"number\"\n },\n \"targetType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"strokeType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"equipmentType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"childStepId\": {\n \"type\": \"number\"\n }\n },\n \"required\": [\n \"stepOrder\"\n ],\n \"additionalProperties\": true\n },\n {\n \"type\": \"object\",\n \"description\": \"Recursive: same shape as the enclosing RepeatWorkoutGroup\"\n }\n ]\n }\n },\n \"endCondition\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"endConditionValue\": {\n \"type\": \"number\"\n },\n \"childStepId\": {\n \"type\": \"number\"\n },\n \"smartRepeat\": {\n \"type\": \"boolean\"\n }\n },\n \"required\": [\n \"stepOrder\",\n \"numberOfIterations\",\n \"workoutSteps\"\n ],\n \"additionalProperties\": true\n }\n ]\n }\n }\n },\n \"required\": [\n \"segmentOrder\",\n \"sportType\",\n \"workoutSteps\"\n ],\n \"additionalProperties\": true\n }\n },\n \"author\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"description\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"workoutName\",\n \"estimatedDurationInSecs\",\n \"workoutSegments\"\n ],\n \"additionalProperties\": true\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"uploadSwimmingWorkout\",\n \"category\": \"workouts\",\n \"description\": \"same pattern, default `sportType` `{sportTypeId:4, sportTypeKey:\\\"swimming\\\", displayOrder:3}`\",\n \"params\": [\n {\n \"name\": \"workout\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"workoutName\": {\n \"type\": \"string\"\n },\n \"sportType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"estimatedDurationInSecs\": {\n \"type\": \"number\"\n },\n \"workoutSegments\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"segmentOrder\": {\n \"type\": \"number\"\n },\n \"sportType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"workoutSteps\": {\n \"type\": \"array\",\n \"items\": {\n \"anyOf\": [\n {\n \"type\": \"object\",\n \"properties\": {\n \"type\": {\n \"type\": \"string\"\n },\n \"stepOrder\": {\n \"type\": \"number\"\n },\n \"stepType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"endCondition\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"endConditionValue\": {\n \"type\": \"number\"\n },\n \"targetType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"strokeType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"equipmentType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"childStepId\": {\n \"type\": \"number\"\n }\n },\n \"required\": [\n \"stepOrder\"\n ],\n \"additionalProperties\": true\n },\n {\n \"type\": \"object\",\n \"properties\": {\n \"type\": {\n \"type\": \"string\"\n },\n \"stepOrder\": {\n \"type\": \"number\"\n },\n \"stepType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"numberOfIterations\": {\n \"type\": \"number\",\n \"description\": \"The iteration count for a COUNT-based repeat. **Nullable**, because a repeat can instead be\\nTIME-based: Garmin's HIIT designer offers \\\"Repeat Until Time Is\\\", which stores\\n`endCondition: time`, the seconds in `endConditionValue`, and `numberOfIterations: null`.\\nConfirmed live 2026-09-23. Upstream types this as a plain required number, which cannot\\nexpress the time-based form.\"\n },\n \"workoutSteps\": {\n \"type\": \"array\",\n \"items\": {\n \"anyOf\": [\n {\n \"type\": \"object\",\n \"properties\": {\n \"type\": {\n \"type\": \"string\"\n },\n \"stepOrder\": {\n \"type\": \"number\"\n },\n \"stepType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"endCondition\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"endConditionValue\": {\n \"type\": \"number\"\n },\n \"targetType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"strokeType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"equipmentType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"childStepId\": {\n \"type\": \"number\"\n }\n },\n \"required\": [\n \"stepOrder\"\n ],\n \"additionalProperties\": true\n },\n {\n \"type\": \"object\",\n \"description\": \"Recursive: same shape as the enclosing RepeatWorkoutGroup\"\n }\n ]\n }\n },\n \"endCondition\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"endConditionValue\": {\n \"type\": \"number\"\n },\n \"childStepId\": {\n \"type\": \"number\"\n },\n \"smartRepeat\": {\n \"type\": \"boolean\"\n }\n },\n \"required\": [\n \"stepOrder\",\n \"numberOfIterations\",\n \"workoutSteps\"\n ],\n \"additionalProperties\": true\n }\n ]\n }\n }\n },\n \"required\": [\n \"segmentOrder\",\n \"sportType\",\n \"workoutSteps\"\n ],\n \"additionalProperties\": true\n }\n },\n \"author\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"description\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"workoutName\",\n \"estimatedDurationInSecs\",\n \"workoutSegments\"\n ],\n \"additionalProperties\": true\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"uploadStrengthWorkout\",\n \"category\": \"workouts\",\n \"description\": \"same pattern, default `sportType` `{sportTypeId:5, sportTypeKey:\\\"strength_training\\\", displayOrder:5}`\",\n \"params\": [\n {\n \"name\": \"workout\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"workoutName\": {\n \"type\": \"string\"\n },\n \"sportType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"estimatedDurationInSecs\": {\n \"type\": \"number\"\n },\n \"workoutSegments\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"segmentOrder\": {\n \"type\": \"number\"\n },\n \"sportType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"workoutSteps\": {\n \"type\": \"array\",\n \"items\": {\n \"anyOf\": [\n {\n \"type\": \"object\",\n \"properties\": {\n \"type\": {\n \"type\": \"string\"\n },\n \"stepOrder\": {\n \"type\": \"number\"\n },\n \"stepType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"endCondition\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"endConditionValue\": {\n \"type\": \"number\"\n },\n \"targetType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"strokeType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"equipmentType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"childStepId\": {\n \"type\": \"number\"\n }\n },\n \"required\": [\n \"stepOrder\"\n ],\n \"additionalProperties\": true\n },\n {\n \"type\": \"object\",\n \"properties\": {\n \"type\": {\n \"type\": \"string\"\n },\n \"stepOrder\": {\n \"type\": \"number\"\n },\n \"stepType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"numberOfIterations\": {\n \"type\": \"number\",\n \"description\": \"The iteration count for a COUNT-based repeat. **Nullable**, because a repeat can instead be\\nTIME-based: Garmin's HIIT designer offers \\\"Repeat Until Time Is\\\", which stores\\n`endCondition: time`, the seconds in `endConditionValue`, and `numberOfIterations: null`.\\nConfirmed live 2026-09-23. Upstream types this as a plain required number, which cannot\\nexpress the time-based form.\"\n },\n \"workoutSteps\": {\n \"type\": \"array\",\n \"items\": {\n \"anyOf\": [\n {\n \"type\": \"object\",\n \"properties\": {\n \"type\": {\n \"type\": \"string\"\n },\n \"stepOrder\": {\n \"type\": \"number\"\n },\n \"stepType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"endCondition\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"endConditionValue\": {\n \"type\": \"number\"\n },\n \"targetType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"strokeType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"equipmentType\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"childStepId\": {\n \"type\": \"number\"\n }\n },\n \"required\": [\n \"stepOrder\"\n ],\n \"additionalProperties\": true\n },\n {\n \"type\": \"object\",\n \"description\": \"Recursive: same shape as the enclosing RepeatWorkoutGroup\"\n }\n ]\n }\n },\n \"endCondition\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"endConditionValue\": {\n \"type\": \"number\"\n },\n \"childStepId\": {\n \"type\": \"number\"\n },\n \"smartRepeat\": {\n \"type\": \"boolean\"\n }\n },\n \"required\": [\n \"stepOrder\",\n \"numberOfIterations\",\n \"workoutSteps\"\n ],\n \"additionalProperties\": true\n }\n ]\n }\n }\n },\n \"required\": [\n \"segmentOrder\",\n \"sportType\",\n \"workoutSteps\"\n ],\n \"additionalProperties\": true\n }\n },\n \"author\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"description\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"workoutName\",\n \"estimatedDurationInSecs\",\n \"workoutSegments\"\n ],\n \"additionalProperties\": true\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"pushWorkoutToDevice\",\n \"category\": \"workouts\",\n \"description\": \"multi-call: resolves a missing `deviceId` via `/device-service/deviceservice/mylastused`'s `userDeviceId`, a missing `workoutId` via `getWorkouts(0,1)`'s first result (throws if none), then reads `getWorkoutById(workoutId).workoutName` for the push message; on the final POST\",\n \"params\": [\n {\n \"name\": \"workoutId\",\n \"optional\": true,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n },\n {\n \"name\": \"deviceId\",\n \"optional\": true,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getScheduledWorkouts\",\n \"category\": \"workouts\",\n \"description\": \"`month` is 1-12 on the way in, converted to 0-indexed on the wire; validates `year>=2000`, `month` 1-12\",\n \"params\": [\n {\n \"name\": \"year\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ]\n }\n },\n {\n \"name\": \"month\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ]\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getScheduledWorkoutById\",\n \"category\": \"workouts\",\n \"description\": \"uses a DIFFERENT base (`/workout-service/schedule`) than `getScheduledWorkouts` (`/calendar-service`)\",\n \"params\": [\n {\n \"name\": \"scheduledWorkoutId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getNextScheduledWorkout\",\n \"category\": \"workouts\",\n \"description\": \"computed from two `getScheduledWorkouts` calls (this month + next, handling Dec->Jan rollover); returns `{}` if nothing matches, never throws\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"scheduleWorkout\",\n \"category\": \"workouts\",\n \"description\": \"`dateStr` routed through `formatDate`\",\n \"params\": [\n {\n \"name\": \"workoutId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n },\n {\n \"name\": \"dateStr\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"unscheduleWorkout\",\n \"category\": \"workouts\",\n \"description\": \"removes the calendar entry without deleting the workout template; irreversible\",\n \"params\": [\n {\n \"name\": \"scheduledWorkoutId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"destructive\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getMenstrualDataForDate\",\n \"category\": \"womens-health\",\n \"description\": \"Get menstrual data for date.\",\n \"params\": [\n {\n \"name\": \"fordate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getMenstrualCalendarData\",\n \"category\": \"womens-health\",\n \"description\": \"Garmin rejects windows of 92+ inclusive days per upstream's docstring, not enforced here (caller's responsibility, matching upstream)\",\n \"params\": [\n {\n \"name\": \"startdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"enddate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getMenstrualLastConfirmed\",\n \"category\": \"womens-health\",\n \"description\": \"Get menstrual last confirmed.\",\n \"params\": [\n {\n \"name\": \"fordate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getMenstrualCycleSummary\",\n \"category\": \"womens-health\",\n \"description\": \"Get menstrual cycle summary.\",\n \"params\": [\n {\n \"name\": \"fordate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getMenstrualReports\",\n \"category\": \"womens-health\",\n \"description\": \"defaults `numberOfCycles=6, nextReport=false, reportType=\\\"CYCLE\\\"`, `todayCalendarDate` defaults to today; `numberOfCycles` restricted to `{1,6,12}` or throws `GarminError`\",\n \"params\": [\n {\n \"name\": \"fordate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"numberOfCycles\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"options\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"nextReport\": {\n \"type\": \"boolean\"\n },\n \"reportType\": {\n \"type\": \"string\"\n },\n \"todayCalendarDate\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n \"additionalProperties\": false\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getPregnancySummary\",\n \"category\": \"womens-health\",\n \"description\": \"Get pregnancy summary.\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"updateMenstrualDailyLog\",\n \"category\": \"womens-health\",\n \"description\": \"**full-day replace, not a merge**; at least one optional field required or throws `GarminError`; `notes: undefined` preserves the existing note, `notes: \\\"\\\"` clears it (distinct, load-bearing); `discharge` rejects combining `\\\"NO_DISCHARGE\\\"` with any other value\",\n \"params\": [\n {\n \"name\": \"calendarDate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"options\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"symptoms\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n },\n \"moods\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n },\n \"flow\": {\n \"type\": \"string\"\n },\n \"discharge\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n },\n \"sexDrive\": {\n \"type\": \"string\"\n },\n \"sexualActivity\": {\n \"type\": \"string\"\n },\n \"notes\": {\n \"type\": \"string\"\n },\n \"ovulationDay\": {\n \"type\": \"boolean\"\n }\n },\n \"additionalProperties\": false\n }\n }\n ],\n \"safety\": \"destructive\",\n \"io\": \"json\"\n },\n {\n \"name\": \"updateMenstrualCalendar\",\n \"category\": \"womens-health\",\n \"description\": \"**full replace, not a merge**; each `cycleDatesLists` group must be non-empty, consecutive calendar dates, and fall within `[startdate, enddate]`, else throws `GarminError`\",\n \"params\": [\n {\n \"name\": \"startdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"enddate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"cycleDatesLists\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n }\n },\n {\n \"name\": \"options\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"todayCalendarDate\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n \"additionalProperties\": false\n }\n }\n ],\n \"safety\": \"destructive\",\n \"io\": \"json\"\n },\n {\n \"name\": \"initMenstrualCycleSetup\",\n \"category\": \"womens-health\",\n \"description\": \"does NOT also update tracking-preference settings (call `updateMenstrualSettings` separately for that); not intended for an already-configured account\",\n \"params\": [\n {\n \"name\": \"periodStartDate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"periodLength\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"cycleLength\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"confirmMenstrualPeriodStart\",\n \"category\": \"womens-health\",\n \"description\": \"POSTs `/periodichealth-service/menstrualcycle/{periodStartDate}` directly, NOT the `dayview`/`calendar`/`lastconfirmed`/`summary` sub-paths\",\n \"params\": [\n {\n \"name\": \"periodStartDate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n },\n {\n \"name\": \"periodLength\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"cycleLength\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"options\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"predictedCycle\": {\n \"type\": \"boolean\"\n }\n },\n \"additionalProperties\": false\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"updateMenstrualSettings\",\n \"category\": \"womens-health\",\n \"description\": \"`settings` must be non-empty or throws `GarminError`; multi-step: GETs `/userprofile-service/userprofile/user-settings`, overlays `settings` onto the current `userMenstrualCycleSettings`, then PUTs the same endpoint, including `id` if resolvable\",\n \"params\": [\n {\n \"name\": \"settings\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n }\n },\n {\n \"name\": \"options\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"object\",\n \"properties\": {\n \"userSettingsId\": {\n \"type\": \"number\"\n }\n },\n \"additionalProperties\": false\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getGoals\",\n \"category\": \"profile-and-misc\",\n \"description\": \"defaults `status=\\\"active\\\", **start=1**, limit=30` — `start` defaults to 1, NOT upstream's 0, because goal-service is 1-INDEXED and `start=0` silently returns `[]`; throws `GarminError` before any request for an invalid `status`. **Paginated, multi-call**: starting at `start`, fetches successive pages of `limit` entries (incrementing `start` by `limit` each call) until a page comes back empty/falsy, same fixed-page-size pattern as `getActivitiesByDate`; throws `GarminError` if `MAX_PAGINATED_REQUESTS` (2000) pages are fetched without ever seeing an empty one. **Sends the load-bearing `Sec-Fetc…\",\n \"params\": [\n {\n \"name\": \"status\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\",\n \"enum\": [\n \"active\",\n \"future\",\n \"past\"\n ]\n }\n },\n {\n \"name\": \"start\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"limit\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"number\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getGolfSummary\",\n \"category\": \"golf\",\n \"description\": \"defaults `start=0, limit=100`; `start` validated non-negative, `limit` validated positive (throws `GarminError` otherwise); query params are literally hyphenated (`per-page`, `start`), matching Garmin's own naming. **Inventory's `returns` column says \\\"list\\\"; live-verified WRONG** — the test account (0 rounds recorded) returned a single pagination-envelope OBJECT `{pageNumber, rowsPerPage, totalRows}`, not an array\",\n \"params\": [\n {\n \"name\": \"start\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"number\"\n }\n },\n {\n \"name\": \"limit\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"number\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getGolfScorecard\",\n \"category\": \"golf\",\n \"description\": \"GETs `/gcs-golfcommunity/api/v2/scorecard/detail`; hyphenated query params `scorecard-ids` and `include-longest-shot-distance` (sent as the literal string `\\\"true\\\"`)\",\n \"params\": [\n {\n \"name\": \"scorecardId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getGolfShotData\",\n \"category\": \"golf\",\n \"description\": \"GETs `/gcs-golfcommunity/api/v2/shot/scorecard/{scorecardId}/hole`; `holeNumbers` accepts commas or hyphens as separators (spaces stripped), re-joined with `-` before sending as the hyphenated `hole-numbers` param; **if any requested hole number is >9, the filter is silently dropped and all 18 holes are requested instead** (Garmin's endpoint drops double-digit hole numbers from a filtered query); omitting `holeNumbers` also fetches all 18\",\n \"params\": [\n {\n \"name\": \"scorecardId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n },\n {\n \"name\": \"holeNumbers\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getGolfClubStats\",\n \"category\": \"golf\",\n \"description\": \"defaults `limit=1000`; validated positive; GETs `/gcs-golfcommunity/api/v2/club/player`; hyphenated query params `per-page` and `include-stats` (literal `\\\"true\\\"`). **Inventory's `returns` column says \\\"dict\\\"; live-verified WRONG** — the test account returned a JSON ARRAY of 17 club entries (`{id, clubTypeId, shaftLength, flexTypeId, averageDistance, adviceDistance, retired, deleted, lastModifiedTime}`), not a single object\",\n \"params\": [\n {\n \"name\": \"limit\",\n \"optional\": true,\n \"schema\": {\n \"type\": \"number\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getGolfUserStats\",\n \"category\": \"golf\",\n \"description\": \"GETs `/gcs-golfcommunity/api/v2/player/stats`; handicap and strokes-gained overview, no params\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getNutritionDailyFoodLog\",\n \"category\": \"profile-and-misc\",\n \"description\": \"GETs `/nutrition-service/food/logs/{cdate}`\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getNutritionDailyMeals\",\n \"category\": \"profile-and-misc\",\n \"description\": \"GETs `/nutrition-service/meals/{cdate}`\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getNutritionDailySettings\",\n \"category\": \"profile-and-misc\",\n \"description\": \"GETs `/nutrition-service/settings/{cdate}`\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getTrainingPlans\",\n \"category\": \"profile-and-misc\",\n \"description\": \"GETs `/trainingplan-service/trainingplan/plans`; no params\",\n \"params\": [],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getTrainingPlanById\",\n \"category\": \"profile-and-misc\",\n \"description\": \"GETs `/trainingplan-service/trainingplan/phased/{planId}`\",\n \"params\": [\n {\n \"name\": \"planId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getAdaptiveTrainingPlanById\",\n \"category\": \"profile-and-misc\",\n \"description\": \"GETs `/trainingplan-service/trainingplan/fbt-adaptive/{planId}`, a distinct sub-path from `getTrainingPlanById`'s `phased` path\",\n \"params\": [\n {\n \"name\": \"planId\",\n \"optional\": false,\n \"schema\": {\n \"type\": [\n \"integer\",\n \"string\"\n ],\n \"description\": \"Numeric id\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"getLifestyleLoggingData\",\n \"category\": \"profile-and-misc\",\n \"description\": \"GETs `/lifestylelogging-service/dailyLog/{cdate}` Grouped under `misc` per the plan's explicit instruction, even though it superficially resembles a wellness-daily endpoint\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"read\",\n \"io\": \"json\"\n },\n {\n \"name\": \"requestReload\",\n \"category\": \"profile-and-misc\",\n \"description\": \"POSTs `/wellness-service/wellness/epoch/request/{cdate}` with no JSON body; asks Garmin to reload/recompute a day's data (Garmin offloads older data, so this forces it back)\",\n \"params\": [\n {\n \"name\": \"cdate\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"string\",\n \"format\": \"date\",\n \"description\": \"Calendar date, YYYY-MM-DD (UTC)\"\n }\n }\n ],\n \"safety\": \"write\",\n \"io\": \"json\"\n },\n {\n \"name\": \"queryGarminGraphql\",\n \"category\": \"profile-and-misc\",\n \"description\": \"POSTs the caller's GraphQL body verbatim to `/graphql-gateway/graphql`; (upstream calls `.json()` directly with no null-check). **The composed URL is this library's highest-risk item**: upstream's own constant is `\\\"graphql-gateway/graphql\\\"`, no leading slash, unlike every other constant in `gc.py` — but this port's `connectapi` composes the request URL by plain string concatenation (`` `https://connectapi.${domain}${path}` ``), not `URL`-relative joining, so omitting the leading slash here would silently glue onto the hostname (`connectapi.garmin.comgraphql-gateway/graphql`) rather than 404 —…\",\n \"params\": [\n {\n \"name\": \"query\",\n \"optional\": false,\n \"schema\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n }\n }\n ],\n \"safety\": \"destructive\",\n \"io\": \"json\"\n },\n {\n \"name\": \"logout\",\n \"category\": \"profile-and-misc\",\n \"description\": \"clears the configured `TokenStore` (`host.client.tokenStore.clear()`); makes **no HTTP call** (the token is never revoked server-side). Does NOT clear the in-memory tokens already held by the calling `GarminClient` instance — there is no public API to do that, and this method's host is deliberately scoped to `{ client }` only. **NEVER call this against a `FileTokenStore` pointed at `./tokens`** —\",\n \"params\": [],\n \"safety\": \"destructive\",\n \"io\": \"json\"\n }\n];\n","import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nexport const UPLOAD_EXTENSIONS = [\".fit\", \".gpx\", \".tcx\"] as const;\n\n/** `~/x` means the home directory, as it does in any shell the user would copy a path from. */\nexport function expandHome(p: string): string {\n if (p === \"~\") return os.homedir();\n if (p.startsWith(\"~/\") || p.startsWith(\"~\\\\\")) return path.join(os.homedir(), p.slice(2));\n return p;\n}\n\nexport async function readUpload(filePath: unknown): Promise<{ blob: Blob; filename: string }> {\n const p = typeof filePath === \"string\" ? expandHome(filePath.trim()) : \"\";\n if (!p || !path.isAbsolute(p)) {\n throw new Error(\"filePath must be an absolute path to a local file, e.g. /Users/me/Downloads/run.gpx\");\n }\n const ext = path.extname(p).toLowerCase();\n if (!(UPLOAD_EXTENSIONS as readonly string[]).includes(ext)) {\n throw new Error(`Only .fit, .gpx and .tcx files can be uploaded; got \"${ext || \"no extension\"}\"`);\n }\n let data: Buffer;\n try {\n data = await readFile(p);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"EISDIR\") throw new Error(`${p} is a folder, not a file`);\n throw new Error(`Cannot read ${p}: the file does not exist or is not readable`);\n }\n return { blob: new Blob([data]), filename: path.basename(p) };\n}\n\n/** A file extension from the bytes themselves, so the server needs no per-endpoint knowledge. */\nexport function sniffExtension(bytes: Uint8Array): string {\n if (bytes[0] === 0x50 && bytes[1] === 0x4b) return \"zip\";\n if (bytes.length >= 12 && new TextDecoder().decode(bytes.subarray(8, 12)) === \".FIT\") return \"fit\";\n const head = new TextDecoder().decode(bytes.subarray(0, 512)).trimStart();\n if (head.startsWith(\"<\")) {\n if (/<gpx[\\s>]/.test(head)) return \"gpx\";\n if (/<TrainingCenterDatabase[\\s>]/.test(head)) return \"tcx\";\n if (/<kml[\\s>]/.test(head)) return \"kml\";\n return \"xml\";\n }\n if (head.startsWith(\"{\") || head.startsWith(\"[\")) return \"json\";\n if (/^[^\\n]*,[^\\n]*\\n/.test(head)) return \"csv\";\n return \"bin\";\n}\n\n/**\n * Writes the bytes under `dir`, never replacing an earlier file: a second download of the same\n * thing becomes `name-2.ext`, then `name-3.ext`. The exclusive-create flag makes the check and the\n * write one step, so two downloads racing for a name cannot both claim it.\n */\nexport async function saveDownload(dir: string, baseName: string, bytes: Uint8Array): Promise<{ path: string; bytes: number }> {\n await mkdir(dir, { recursive: true });\n const ext = sniffExtension(bytes);\n for (let n = 1; ; n++) {\n const target = path.join(dir, `${baseName}${n === 1 ? \"\" : `-${n}`}.${ext}`);\n try {\n await writeFile(target, bytes, { flag: \"wx\" });\n return { path: target, bytes: bytes.length };\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n }\n }\n}\n","import type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\n\n/** One tool result may not exceed this; some Garmin responses run to megabytes. */\nexport const MAX_RESULT_CHARS = 100_000;\n\nexport function truncate(text: string): string {\n if (text.length <= MAX_RESULT_CHARS) return text;\n return `${text.slice(0, MAX_RESULT_CHARS)}\\n[truncated: ${MAX_RESULT_CHARS} of ${text.length} characters]`;\n}\n\nexport function textResult(text: string): CallToolResult {\n return { content: [{ type: \"text\", text: truncate(text) }] };\n}\n\nexport function jsonResult(value: unknown): CallToolResult {\n if (value === undefined) return textResult(\"Done. Garmin returned no content.\");\n if (value === null) return textResult(\"null (Garmin returned no data)\");\n return textResult(JSON.stringify(value, null, 2));\n}\n","/**\n * Checks a tool call's arguments against the tool's own input schema, before anything reaches\n * Garmin.\n *\n * The low-level MCP `Server` passes arguments through unchecked, so without this a wrong type went\n * straight into the library (where some calls fail late and unclearly) and a misspelt optional\n * argument was silently ignored. Messages are written for Claude to act on:\n * `Invalid arguments for get_activities: start must be number`.\n */\nimport Ajv2020, { type ErrorObject, type ValidateFunction } from \"ajv/dist/2020.js\";\n\n// `strict: false` and no format validation: the manifest's schemas use `format: \"date\"` /\n// `\"date-time\"` as documentation, and dates are checked (or coerced) by the library and argsFor.\nconst ajv = new Ajv2020({ strict: false, validateFormats: false });\n\n/** `/options/name` -> `options.name`, `/days/0` -> `days[0]`. */\nfunction pathOf(instancePath: string): string {\n return instancePath\n .split(\"/\")\n .filter(Boolean)\n .map((part, i) => (/^\\d+$/.test(part) ? `[${part}]` : i === 0 ? part : `.${part}`))\n .join(\"\");\n}\n\nfunction describe(error: ErrorObject): string {\n const at = pathOf(error.instancePath);\n const params = error.params as Record<string, unknown>;\n switch (error.keyword) {\n case \"additionalProperties\":\n return at === \"\"\n ? `unknown argument \"${String(params[\"additionalProperty\"])}\"`\n : `${at}: unknown key \"${String(params[\"additionalProperty\"])}\"`;\n case \"required\":\n return at === \"\"\n ? `missing required argument \"${String(params[\"missingProperty\"])}\"`\n : `${at}: missing \"${String(params[\"missingProperty\"])}\"`;\n case \"enum\":\n return `${at} must be one of ${(params[\"allowedValues\"] as unknown[]).map(String).join(\", \")}`;\n case \"type\": {\n const type = params[\"type\"];\n return `${at} must be ${Array.isArray(type) ? type.join(\" or \") : String(type)}`;\n }\n default:\n return `${at || \"arguments\"} ${error.message ?? \"is invalid\"}`;\n }\n}\n\n/** Compiles once; the returned function throws an Error naming the tool and the first problem. */\nexport function argumentValidator(toolName: string, schema: object): (input: Record<string, unknown>) => void {\n let validate: ValidateFunction | undefined;\n return (input) => {\n validate ??= ajv.compile(schema);\n if (validate(input)) return;\n const first = validate.errors?.[0];\n throw new Error(`Invalid arguments for ${toolName}: ${first ? describe(first) : \"rejected by the input schema\"}`);\n };\n}\n","import type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { GARMIN_METHODS, type ManifestMethod } from \"garminconnect-js/manifest\";\nimport { readUpload, saveDownload } from \"./files.js\";\nimport { jsonResult } from \"./results.js\";\nimport type { ServerDeps, ToolDef, ToolFactory } from \"./server.js\";\nimport { argumentValidator } from \"./validate.js\";\n\n/** Methods deliberately NOT exposed, each with the reason. */\nexport const EXCLUDED: Readonly<Record<string, string>> = {\n logout: \"Deletes the saved Garmin login; not something to do from a chat.\",\n uploadWorkout: \"Takes raw workout JSON, skipping the builder's checks. create_workout replaces it.\",\n uploadRunningWorkout: \"Raw workout JSON; create_workout replaces it.\",\n uploadCyclingWorkout: \"Raw workout JSON; create_workout replaces it.\",\n uploadSwimmingWorkout: \"Raw workout JSON; create_workout replaces it.\",\n uploadStrengthWorkout: \"Raw workout JSON; create_workout replaces it.\",\n updateWorkout: \"Raw workout JSON; update_workout (which takes a spec) replaces it.\",\n};\n\n/** Methods exposed only when a config flag is on. */\nexport const OPT_IN: Readonly<Record<string, \"enableGraphql\">> = {\n queryGarminGraphql: \"enableGraphql\",\n};\n\nexport const toolName = (method: string): string => method.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);\n\nfunction inputSchemaOf(m: ManifestMethod): Tool[\"inputSchema\"] {\n const properties: Record<string, object> = {};\n const required: string[] = [];\n for (const p of m.params) {\n if (p.role === \"filename\") continue; // derived from filePath\n if (p.role === \"file\") {\n properties[\"filePath\"] = {\n type: \"string\",\n description: \"Absolute path to a local .fit, .gpx or .tcx file (~ is expanded)\",\n };\n required.push(\"filePath\");\n continue;\n }\n properties[p.name] = p.schema;\n if (!p.optional) required.push(p.name);\n }\n return { type: \"object\", properties, ...(required.length > 0 && { required }), additionalProperties: false };\n}\n\nfunction descriptionOf(m: ManifestMethod): string {\n if (m.safety === \"destructive\") return `${m.description} IRREVERSIBLE: confirm with the user before calling.`;\n return m.description;\n}\n\nasync function argsFor(m: ManifestMethod, input: Record<string, unknown>): Promise<unknown[]> {\n const args: unknown[] = [];\n let filename: string | undefined;\n for (const p of m.params) {\n if (p.role === \"file\") {\n const upload = await readUpload(input[\"filePath\"]);\n filename = upload.filename;\n args.push(upload.blob);\n } else if (p.role === \"filename\") {\n args.push(filename);\n } else if (p.coerce === \"date\" && input[p.name] !== undefined) {\n const raw = input[p.name];\n if (typeof raw !== \"string\") {\n throw new Error(`${p.name}: expected an ISO 8601 date-time, got ${JSON.stringify(raw)}`);\n }\n const date = new Date(raw);\n if (Number.isNaN(date.getTime())) {\n throw new Error(`${p.name}: expected an ISO 8601 date-time, got ${JSON.stringify(raw)}`);\n }\n args.push(date);\n } else {\n args.push(input[p.name]);\n }\n }\n while (args.length > 0 && args[args.length - 1] === undefined) args.pop(); // let defaults apply\n return args;\n}\n\nfunction downloadName(m: ManifestMethod, input: Record<string, unknown>): string {\n const first = m.params[0] ? input[m.params[0].name] : undefined;\n const raw = typeof first === \"string\" || typeof first === \"number\" || typeof first === \"boolean\" ? String(first) : \"file\";\n const id = first === undefined ? \"file\" : raw.replace(/[^A-Za-z0-9_-]+/g, \"_\").slice(0, 64);\n return `${toolName(m.name)}-${id}`;\n}\n\nfunction toolFor(m: ManifestMethod, deps: ServerDeps): ToolDef {\n const name = toolName(m.name);\n const inputSchema = inputSchemaOf(m);\n const checkArguments = argumentValidator(name, inputSchema);\n return {\n tool: {\n name,\n description: descriptionOf(m),\n inputSchema,\n annotations: {\n title: m.name,\n readOnlyHint: m.safety === \"read\",\n // MCP treats a MISSING destructiveHint as true, so writes say false explicitly.\n ...(m.safety !== \"read\" && { destructiveHint: m.safety === \"destructive\" }),\n openWorldHint: true,\n },\n },\n async run(input) {\n checkArguments(input);\n const args = await argsFor(m, input); // argument and file errors surface BEFORE any Garmin call\n const garmin = await deps.session.get();\n const fn = (garmin as unknown as Record<string, unknown>)[m.name];\n if (typeof fn !== \"function\") throw new Error(`garminconnect-js has no method ${m.name}`);\n const result: unknown = await (fn as (...a: unknown[]) => Promise<unknown>).apply(garmin, args);\n if (m.io === \"binary-out\") {\n return jsonResult(await saveDownload(deps.config.downloadDir, downloadName(m, input), result as Uint8Array));\n }\n return jsonResult(result);\n },\n };\n}\n\nexport const methodTools: ToolFactory = (deps) => {\n const known = new Set(GARMIN_METHODS.map((m) => m.category));\n if (deps.config.groups) {\n const unknown = [...deps.config.groups].filter((g) => !known.has(g));\n if (unknown.length > 0) {\n throw new Error(`Unknown GARMIN_MCP_GROUPS value(s): ${unknown.join(\", \")}. Valid: ${[...known].sort().join(\", \")}`);\n }\n }\n return GARMIN_METHODS.filter((m) => !Object.hasOwn(EXCLUDED, m.name))\n .filter((m) => !Object.hasOwn(OPT_IN, m.name) || deps.config[OPT_IN[m.name]!])\n .filter((m) => deps.config.groups === null || deps.config.groups.has(m.category))\n .map((m) => toolFor(m, deps));\n};\n","/**\r\n * Garmin's exercise catalogue: every 1830 exercise names Garmin accepts, grouped by the\r\n * 51 categories that have any.\r\n *\r\n * Published as a SEPARATE entry point — `garminconnect-js/exercises` — because it is roughly a\r\n * third of the package's size and most callers never need it. Importing the package root does not\r\n * pull it in.\r\n *\r\n * Why it exists: Garmin validates the two halves of an exercise differently. A bad `category`\r\n * fails the whole upload with a 400 — loud. A bad `exerciseName` is accepted and SILENTLY STORED\r\n * AS `\"\"`, leaving a step with a category and no exercise and no error anywhere. This module makes\r\n * that failure a compile error instead:\r\n *\r\n * ```ts\r\n * import { buildWorkout } from \"garminconnect-js\";\r\n * import { exercise } from \"garminconnect-js/exercises\";\r\n *\r\n * buildWorkout(\"Legs\", { sport: \"strength_training\" })\r\n * .interval({ reps: 8, exercise: exercise(\"SQUAT\", \"BARBELL_BACK_SQUAT\") })\r\n * .interval({ reps: 8, exercise: exercise(\"SQUAT\", \"BARBELL_BENCH_PRESS\") }) // compile error\r\n * .build();\r\n * ```\r\n *\r\n * PROVENANCE — every pair here was confirmed by the server, not assumed. Candidates came from\r\n * Garmin Connect's own translations bundle\r\n * (https://connect.garmin.com/web-translations/exercise_types/exercise_types.properties, public,\r\n * no auth), and `scripts/verify-exercises.ts` then uploaded each one to a live account, read the\r\n * stored workout back, and kept only the names Garmin echoed unchanged. 44 candidates were\r\n * rejected that way — mostly the translation file's per-category generic label\r\n * (`SQUAT_SQUAT` and friends), which is not an exercise.\r\n *\r\n * Two further categories, `STRETCH` and `UNKNOWN`, are valid on the wire but have no exercise\r\n * names in Garmin's catalogue, so they do not appear here. Pass them as a bare\r\n * `{ category }` with no `name`. The full category list is `WORKOUT_EXERCISE_CATEGORIES` in the\r\n * package root.\r\n *\r\n * This file is generated. To regenerate, see `scripts/verify-exercises.ts`.\r\n */\r\nimport type { ExerciseCategory } from \"./types/workouts.js\";\r\n\r\n/** Every verified exercise name, keyed by category. */\r\nexport const EXERCISES = {\r\n BANDED_EXERCISES: [\r\n \"AB_TWIST\",\r\n \"AROUND_THE_WORLD_WHEELCHAIR\",\r\n \"BACK_EXTENSION\",\r\n \"BICYCLE_CRUNCH\",\r\n \"CALF_RAISES\",\r\n \"CHEST_FLY_DECLINE_WHEELCHAIR\",\r\n \"CHEST_FLY_INCLINE_WHEELCHAIR\",\r\n \"CLAM_SHELLS\",\r\n \"CURL\",\r\n \"CURL_WHEELCHAIR\",\r\n \"DEADBUG\",\r\n \"DEADLIFT\",\r\n \"DONKEY_KICK\",\r\n \"EXTERNAL_ROTATION\",\r\n \"EXTERNAL_ROTATION_AT_90_DEGREE_ABDUCTION\",\r\n \"FACE_PULL_WHEELCHAIR\",\r\n \"FIRE_HYDRANT\",\r\n \"FLY\",\r\n \"FRONT_RAISE\",\r\n \"GLUTE_BRIDGE\",\r\n \"HAMSTRING_CURLS\",\r\n \"HIGH_PLANK_LEG_LIFTS\",\r\n \"HIP_EXTENSION\",\r\n \"INTERNAL_ROTATION\",\r\n \"JUMPING_JACK\",\r\n \"KNEELING_CRUNCH\",\r\n \"LATERAL_BAND_WALKS\",\r\n \"LATERAL_RAISE\",\r\n \"LATERAL_RAISE_WHEELCHAIR\",\r\n \"LATPULL\",\r\n \"LEG_ABDUCTION\",\r\n \"LEG_ADDUCTION\",\r\n \"LEG_EXTENSION\",\r\n \"LUNGE\",\r\n \"OVERHEAD_CURL_WHEELCHAIR\",\r\n \"OVERHEAD_PRESS_WHEELCHAIR\",\r\n \"PLANK\",\r\n \"PULL_APART\",\r\n \"PULL_APART_WHEELCHAIR\",\r\n \"PULL_DOWN_WHEELCHAIR\",\r\n \"PUSH_UPS\",\r\n \"REVERSE_CRUNCH\",\r\n \"ROW\",\r\n \"SHOULDER_ABDUCTION\",\r\n \"SHOULDER_EXTENSION\",\r\n \"SHOULDER_EXTERNAL_ROTATION\",\r\n \"SHOULDER_FLEXION_TO_90_DEGREES\",\r\n \"SIDE_CURL_WHEELCHAIR\",\r\n \"SIDE_PLANK_LEG_LIFTS\",\r\n \"SQUAT\",\r\n \"SQUAT_TO_PRESS\",\r\n \"STRAIGHT_ARM_PULL_DOWN_WHEELCHAIR\",\r\n \"TRICEPS_EXTENSION_WHEELCHAIR\",\r\n \"TRICEP_EXTENSION\",\r\n \"TRICEP_KICKBACK\",\r\n \"UPRIGHT_ROW\",\r\n \"WALL_CRAWL_WITH_EXTERNAL_ROTATION\",\r\n ],\r\n BATTLE_ROPE: [\r\n \"ALTERNATING_FIGURE_EIGHT\",\r\n \"ALTERNATING_JUMP_WAVE\",\r\n \"ALTERNATING_KNEELING_TO_STANDING_WAVE\",\r\n \"ALTERNATING_LUNGE_WAVE\",\r\n \"ALTERNATING_SQUAT_WAVE\",\r\n \"ALTERNATING_WAVE\",\r\n \"ALTERNATING_WAVE_WITH_LATERAL_SHUFFLE\",\r\n \"CLAP_WAVE\",\r\n \"DOUBLE_ARM_FIGURE_EIGHT\",\r\n \"DOUBLE_ARM_SIDE_TO_SIDE_SNAKE\",\r\n \"DOUBLE_ARM_SIDE_WAVE\",\r\n \"DOUBLE_ARM_SLAM\",\r\n \"DOUBLE_ARM_WAVE\",\r\n \"GRAPPLER_TOSS\",\r\n \"HIP_TOSS\",\r\n \"INSIDE_CIRCLE\",\r\n \"IN_AND_OUT_WAVE\",\r\n \"JUMPING_JACKS\",\r\n \"OUTSIDE_CIRCLE\",\r\n \"RAINBOW\",\r\n \"SIDEWINDER\",\r\n \"SIDE_PLANK_WAVE\",\r\n \"SITTING_RUSSIAN_TWIST\",\r\n \"SNAKE_WAVE\",\r\n \"SPLIT_JACK\",\r\n \"STAGE_COACH\",\r\n \"ULTIMATE_WARRIOR\",\r\n \"UPPER_CUTS\",\r\n ],\r\n BENCH_PRESS: [\r\n \"ALTERNATING_DUMBBELL_CHEST_PRESS\",\r\n \"ALTERNATING_DUMBBELL_CHEST_PRESS_ON_SWISS_BALL\",\r\n \"BARBELL_BENCH_PRESS\",\r\n \"BARBELL_BOARD_BENCH_PRESS\",\r\n \"BARBELL_FLOOR_PRESS\",\r\n \"CLOSE_GRIP_BARBELL_BENCH_PRESS\",\r\n \"DECLINE_BARBELL_BENCH_PRESS\",\r\n \"DECLINE_DUMBBELL_BENCH_PRESS\",\r\n \"DUMBBELL_BENCH_PRESS\",\r\n \"DUMBBELL_FLOOR_PRESS\",\r\n \"INCLINE_BARBELL_BENCH_PRESS\",\r\n \"INCLINE_DUMBBELL_BENCH_PRESS\",\r\n \"INCLINE_SMITH_MACHINE_BENCH_PRESS\",\r\n \"ISOMETRIC_BARBELL_BENCH_PRESS\",\r\n \"KETTLEBELL_CHEST_PRESS\",\r\n \"NEUTRAL_GRIP_DUMBBELL_BENCH_PRESS\",\r\n \"NEUTRAL_GRIP_DUMBBELL_INCLINE_BENCH_PRESS\",\r\n \"ONE_ARM_FLOOR_PRESS\",\r\n \"PARTIAL_LOCKOUT\",\r\n \"REVERSE_GRIP_BARBELL_BENCH_PRESS\",\r\n \"REVERSE_GRIP_INCLINE_BENCH_PRESS\",\r\n \"SINGLE_ARM_CABLE_CHEST_PRESS\",\r\n \"SINGLE_ARM_DUMBBELL_BENCH_PRESS\",\r\n \"SMITH_MACHINE_BENCH_PRESS\",\r\n \"SWISS_BALL_DUMBBELL_CHEST_PRESS\",\r\n \"TRIPLE_STOP_BARBELL_BENCH_PRESS\",\r\n \"WEIGHTED_ONE_ARM_FLOOR_PRESS\",\r\n \"WIDE_GRIP_BARBELL_BENCH_PRESS\",\r\n ],\r\n BIKE: [\r\n \"BIKE\",\r\n ],\r\n BIKE_OUTDOOR: [\r\n \"BIKE\",\r\n ],\r\n CALF_RAISE: [\r\n \"DONKEY_CALF_RAISE\",\r\n \"SEATED_CALF_RAISE\",\r\n \"SEATED_DUMBBELL_TOE_RAISE\",\r\n \"SINGLE_LEG_BENT_KNEE_CALF_RAISE\",\r\n \"SINGLE_LEG_DECLINE_PUSH_UP\",\r\n \"SINGLE_LEG_DONKEY_CALF_RAISE\",\r\n \"SINGLE_LEG_HIP_RAISE_WITH_KNEE_HOLD\",\r\n \"SINGLE_LEG_STANDING_CALF_RAISE\",\r\n \"SINGLE_LEG_STANDING_DUMBBELL_CALF_RAISE\",\r\n \"STANDING_BARBELL_CALF_RAISE\",\r\n \"STANDING_CALF_RAISE\",\r\n \"STANDING_DUMBBELL_CALF_RAISE\",\r\n \"WEIGHTED_DONKEY_CALF_RAISE\",\r\n \"WEIGHTED_SEATED_CALF_RAISE\",\r\n \"WEIGHTED_SINGLE_LEG_BENT_KNEE_CALF_RAISE\",\r\n \"WEIGHTED_SINGLE_LEG_DONKEY_CALF_RAISE\",\r\n \"WEIGHTED_STANDING_CALF_RAISE\",\r\n \"_3_WAY_CALF_RAISE\",\r\n \"_3_WAY_SINGLE_LEG_CALF_RAISE\",\r\n \"_3_WAY_WEIGHTED_CALF_RAISE\",\r\n \"_3_WAY_WEIGHTED_SINGLE_LEG_CALF_RAISE\",\r\n ],\r\n CARDIO: [\r\n \"BOB_AND_WEAVE_CIRCLE\",\r\n \"BUTTERFLY_ARMS_WHEELCHAIR\",\r\n \"CARDIO_CORE_CRAWL\",\r\n \"DOUBLE_PUNCH_DOWN_WHEELCHAIR\",\r\n \"DOUBLE_PUNCH_FORWARD_WHEELCHAIR\",\r\n \"DOUBLE_PUNCH_SIDEWAYS_WHEELCHAIR\",\r\n \"DOUBLE_PUNCH_UP_WHEELCHAIR\",\r\n \"DOUBLE_UNDER\",\r\n \"JUMPING_JACKS\",\r\n \"JUMP_ROPE\",\r\n \"JUMP_ROPE_CROSSOVER\",\r\n \"JUMP_ROPE_JOG\",\r\n \"POLE_DD_FF_UU_WHEELCHAIR\",\r\n \"POLE_HANDCYCLE_BACKWARD_WHEELCHAIR\",\r\n \"POLE_HANDCYCLE_FORWARD_WHEELCHAIR\",\r\n \"POLE_PADDLE_BACKWARD_WHEELCHAIR\",\r\n \"POLE_PADDLE_FORWARD_WHEELCHAIR\",\r\n \"POLE_RAINBOW_WHEELCHAIR\",\r\n \"PUNCH_BAG_WHEELCHAIR\",\r\n \"PUNCH_DOWN_WHEELCHAIR\",\r\n \"PUNCH_FORWARD_WHEELCHAIR\",\r\n \"PUNCH_SIDEWAYS_WHEELCHAIR\",\r\n \"PUNCH_UP_WHEELCHAIR\",\r\n \"SITTING_JACKS_WHEELCHAIR\",\r\n \"SIT_SKI_WHEELCHAIR\",\r\n \"SKI_MOGULS\",\r\n \"SPLIT_JACKS\",\r\n \"SQUAT_JACKS\",\r\n \"TRIPLE_UNDER\",\r\n \"WEIGHTED_BOB_AND_WEAVE_CIRCLE\",\r\n \"WEIGHTED_CARDIO_CORE_CRAWL\",\r\n \"WEIGHTED_DOUBLE_UNDER\",\r\n \"WEIGHTED_JUMPING_JACKS\",\r\n \"WEIGHTED_JUMP_ROPE\",\r\n \"WEIGHTED_JUMP_ROPE_CROSSOVER\",\r\n \"WEIGHTED_JUMP_ROPE_JOG\",\r\n \"WEIGHTED_SKI_MOGULS\",\r\n \"WEIGHTED_SPLIT_JACKS\",\r\n \"WEIGHTED_SQUAT_JACKS\",\r\n \"WEIGHTED_TRIPLE_UNDER\",\r\n ],\r\n CARRY: [\r\n \"BAR_HOLDS\",\r\n \"DUMBBELL_WAITER_CARRY\",\r\n \"FARMERS_CARRY\",\r\n \"FARMERS_CARRY_ON_TOES\",\r\n \"FARMERS_CARRY_WALK_LUNGE\",\r\n \"FARMERS_WALK\",\r\n \"FARMERS_WALK_ON_TOES\",\r\n \"HEX_DUMBBELL_HOLD\",\r\n \"OVERHEAD_CARRY\",\r\n ],\r\n CHOP: [\r\n \"CABLE_PULL_THROUGH\",\r\n \"CABLE_ROTATIONAL_LIFT\",\r\n \"CABLE_WOODCHOP\",\r\n \"CROSS_CHOP_TO_KNEE\",\r\n \"DUMBBELL_CHOP\",\r\n \"HALF_KNEELING_ROTATION\",\r\n \"HALF_KNEELING_ROTATIONAL_CHOP\",\r\n \"HALF_KNEELING_ROTATIONAL_REVERSE_CHOP\",\r\n \"HALF_KNEELING_STABILITY_CHOP\",\r\n \"HALF_KNEELING_STABILITY_REVERSE_CHOP\",\r\n \"KNEELING_ROTATIONAL_CHOP\",\r\n \"KNEELING_ROTATIONAL_REVERSE_CHOP\",\r\n \"KNEELING_STABILITY_CHOP\",\r\n \"KNEELING_WOODCHOPPER\",\r\n \"MEDICINE_BALL_WOOD_CHOPS\",\r\n \"POWER_SQUAT_CHOPS\",\r\n \"STANDING_ROTATIONAL_CHOP\",\r\n \"STANDING_SPLIT_ROTATIONAL_CHOP\",\r\n \"STANDING_SPLIT_ROTATIONAL_REVERSE_CHOP\",\r\n \"STANDING_STABILITY_REVERSE_CHOP\",\r\n \"WEIGHTED_CROSS_CHOP_TO_KNEE\",\r\n \"WEIGHTED_HALF_KNEELING_ROTATION\",\r\n \"WEIGHTED_POWER_SQUAT_CHOPS\",\r\n ],\r\n CORE: [\r\n \"ABS_JABS\",\r\n \"ALTERNATING_PLATE_REACH\",\r\n \"ALTERNATING_SLIDE_OUT\",\r\n \"ARM_AND_LEG_EXTENSION_ON_KNEES\",\r\n \"BARBELL_ROLLOUT\",\r\n \"BICEP_CURL_WITH_LEG_EXTENSION\",\r\n \"BICEP_CURL_WITH_LEG_EXTENSION_WITH_WEIGHTS\",\r\n \"BICYCLE\",\r\n \"BODY_BAR_OBLIQUE_TWIST\",\r\n \"CABLE_CORE_PRESS\",\r\n \"CABLE_SIDE_BEND\",\r\n \"CAT_COW\",\r\n \"CORKSCREW\",\r\n \"CRESCENT_CIRCLE\",\r\n \"CRISS_CROSS\",\r\n \"CYCLING_RUSSIAN_TWIST\",\r\n \"DOUBLE_LEG_STRETCH\",\r\n \"ELEVATED_FEET_RUSSIAN_TWIST\",\r\n \"GHD_BACK_EXTENSIONS\",\r\n \"HALF_TURKISH_GET_UP\",\r\n \"HANGING_L_SIT\",\r\n \"INCHWORM\",\r\n \"KETTLEBELL_WINDMILL\",\r\n \"KNEELING_AB_WHEEL\",\r\n \"KNEE_FOLDS\",\r\n \"LOWER_LIFT\",\r\n \"LOWER_LIFT_WITH_WEIGHTS\",\r\n \"L_SIT\",\r\n \"MODIFIED_FRONT_LEVER\",\r\n \"NECK_PULL\",\r\n \"OPEN_KNEE_TUCKS\",\r\n \"OVERHEAD_WALK\",\r\n \"PELVIC_CLOCKS\",\r\n \"RING_L_SIT\",\r\n \"ROLLING\",\r\n \"ROLL_OVER\",\r\n \"ROLL_UP\",\r\n \"ROWING_1\",\r\n \"ROWING_1_WITH_WEIGHTS\",\r\n \"ROWING_2\",\r\n \"ROWING_2_WITH_WEIGHTS\",\r\n \"RUSSIAN_TWIST\",\r\n \"SCISSORS\",\r\n \"SCISSORS_WITH_WEIGHTS\",\r\n \"SIDE_ABS_LEG_LIFT\",\r\n \"SIDE_BEND\",\r\n \"SIDE_BEND_HIGH_WHEELCHAIR\",\r\n \"SIDE_BEND_LOW_WHEELCHAIR\",\r\n \"SIDE_BEND_MID_WHEELCHAIR\",\r\n \"SINGLE_LEG_CIRCLES\",\r\n \"SINGLE_LEG_STRETCH\",\r\n \"SINGLE_LEG_STRETCH_WITH_WEIGHTS\",\r\n \"SNAKE_TWIST_1_AND_2\",\r\n \"SWAN\",\r\n \"SWIMMING\",\r\n \"SWISS_BALL_JACKKNIFE\",\r\n \"SWISS_BALL_PIKE\",\r\n \"SWISS_BALL_ROLLOUT\",\r\n \"TEASER\",\r\n \"THE_HUNDRED\",\r\n \"TOES_TO_ELBOWS\",\r\n \"TRIANGLE_HIP_PRESS\",\r\n \"TRX_SUSPENDED_JACKKNIFE\",\r\n \"TURKISH_GET_UP\",\r\n \"U_BOAT\",\r\n \"WEIGHTED_ABS_JABS\",\r\n \"WEIGHTED_ALTERNATING_SLIDE_OUT\",\r\n \"WEIGHTED_BARBELL_ROLLOUT\",\r\n \"WEIGHTED_CRESCENT_CIRCLE\",\r\n \"WEIGHTED_CRISS_CROSS\",\r\n \"WEIGHTED_CYCLING_RUSSIAN_TWIST\",\r\n \"WEIGHTED_DOUBLE_LEG_STRETCH\",\r\n \"WEIGHTED_ELEVATED_FEET_RUSSIAN_TWIST\",\r\n \"WEIGHTED_GHD_BACK_EXTENSIONS\",\r\n \"WEIGHTED_HANGING_L_SIT\",\r\n \"WEIGHTED_KNEELING_AB_WHEEL\",\r\n \"WEIGHTED_L_SIT\",\r\n \"WEIGHTED_MODIFIED_FRONT_LEVER\",\r\n \"WEIGHTED_OPEN_KNEE_TUCKS\",\r\n \"WEIGHTED_RING_L_SIT\",\r\n \"WEIGHTED_SIDE_ABS_LEG_LIFT\",\r\n \"WEIGHTED_SIDE_BEND\",\r\n \"WEIGHTED_SWISS_BALL_JACKKNIFE\",\r\n \"WEIGHTED_SWISS_BALL_PIKE\",\r\n \"WEIGHTED_SWISS_BALL_ROLLOUT\",\r\n \"WEIGHTED_THE_HUNDRED\",\r\n \"WEIGHTED_TRIANGLE_HIP_PRESS\",\r\n \"WEIGHTED_TRX_SUSPENDED_JACKKNIFE\",\r\n \"WEIGHTED_U_BOAT\",\r\n \"WEIGHTED_WINDMILL_SWITCHES\",\r\n \"WINDMILL_SWITCHES\",\r\n ],\r\n CRUNCH: [\r\n \"BICYCLE_CRUNCH\",\r\n \"CABLE_CRUNCH\",\r\n \"CIRCULAR_ARM_CRUNCH\",\r\n \"CROSSED_ARMS_CRUNCH\",\r\n \"CROSS_LEG_REVERSE_CRUNCH\",\r\n \"CRUNCH\",\r\n \"CRUNCH_CHOP\",\r\n \"DOUBLE_CRUNCH\",\r\n \"ELBOW_TO_KNEE_CRUNCH\",\r\n \"FLUTTER_KICKS\",\r\n \"FOAM_ROLLER_REVERSE_CRUNCH_ON_BENCH\",\r\n \"FOAM_ROLLER_REVERSE_CRUNCH_WITH_DUMBBELL\",\r\n \"FOAM_ROLLER_REVERSE_CRUNCH_WITH_MEDICINE_BALL\",\r\n \"FROG_PRESS\",\r\n \"HANGING_KNEE_RAISE_OBLIQUE_CRUNCH\",\r\n \"HIP_CROSSOVER\",\r\n \"HOLLOW_ROCK\",\r\n \"INCLINE_REVERSE_CRUNCH\",\r\n \"KNEELING_CABLE_CRUNCH\",\r\n \"KNEELING_CROSS_CRUNCH\",\r\n \"KNEELING_OBLIQUE_CABLE_CRUNCH\",\r\n \"KNEES_TO_ELBOW\",\r\n \"LEG_CLIMB_CRUNCH\",\r\n \"LEG_EXTENSIONS\",\r\n \"LEG_LEVERS\",\r\n \"MCGILL_CURL_UP\",\r\n \"MODIFIED_PILATES_ROLL_UP_WITH_BALL\",\r\n \"PILATES_CRUNCH\",\r\n \"PILATES_ROLL_UP_WITH_BALL\",\r\n \"RAISED_LEGS_CRUNCH\",\r\n \"REVERSE_CRUNCH\",\r\n \"REVERSE_CRUNCH_ON_A_BENCH\",\r\n \"REVERSE_CURL_AND_LIFT\",\r\n \"ROTATIONAL_LIFT\",\r\n \"RUCK_FLUTTER_KICKS\",\r\n \"SEATED_ALTERNATING_REVERSE_CRUNCH\",\r\n \"SEATED_LEG_U\",\r\n \"SIDE_TO_SIDE_CRUNCH_AND_WEAVE\",\r\n \"SINGLE_LEG_REVERSE_CRUNCH\",\r\n \"SKATER_CRUNCH_CROSS\",\r\n \"STANDING_CABLE_CRUNCH\",\r\n \"STANDING_SIDE_CRUNCH\",\r\n \"STEP_CLIMB\",\r\n \"STRAIGHT_LEG_CRUNCH_WITH_BALL\",\r\n \"SWISS_BALL_CRUNCH\",\r\n \"SWISS_BALL_REVERSE_CRUNCH\",\r\n \"SWISS_BALL_RUSSIAN_TWIST\",\r\n \"SWISS_BALL_SIDE_CRUNCH\",\r\n \"THORACIC_CRUNCHES_ON_FOAM_ROLLER\",\r\n \"TOES_TO_BAR\",\r\n \"TRICEPS_CRUNCH\",\r\n \"WEIGHTED_BICYCLE_CRUNCH\",\r\n \"WEIGHTED_CROSSED_ARMS_CRUNCH\",\r\n \"WEIGHTED_CROSS_LEG_REVERSE_CRUNCH\",\r\n \"WEIGHTED_CRUNCH\",\r\n \"WEIGHTED_CRUNCH_CHOP\",\r\n \"WEIGHTED_DOUBLE_CRUNCH\",\r\n \"WEIGHTED_ELBOW_TO_KNEE_CRUNCH\",\r\n \"WEIGHTED_FLUTTER_KICKS\",\r\n \"WEIGHTED_FOAM_ROLLER_REVERSE_CRUNCH_ON_BENCH\",\r\n \"WEIGHTED_HANGING_KNEE_RAISE_OBLIQUE_CRUNCH\",\r\n \"WEIGHTED_HIP_CROSSOVER\",\r\n \"WEIGHTED_HOLLOW_ROCK\",\r\n \"WEIGHTED_INCLINE_REVERSE_CRUNCH\",\r\n \"WEIGHTED_KNEELING_CROSS_CRUNCH\",\r\n \"WEIGHTED_LEG_EXTENSIONS\",\r\n \"WEIGHTED_MCGILL_CURL_UP\",\r\n \"WEIGHTED_MODIFIED_PILATES_ROLL_UP_WITH_BALL\",\r\n \"WEIGHTED_PILATES_CRUNCH\",\r\n \"WEIGHTED_PILATES_ROLL_UP_WITH_BALL\",\r\n \"WEIGHTED_RAISED_LEGS_CRUNCH\",\r\n \"WEIGHTED_REVERSE_CRUNCH\",\r\n \"WEIGHTED_REVERSE_CRUNCH_ON_A_BENCH\",\r\n \"WEIGHTED_REVERSE_CURL_AND_LIFT\",\r\n \"WEIGHTED_ROTATIONAL_LIFT\",\r\n \"WEIGHTED_SEATED_ALTERNATING_REVERSE_CRUNCH\",\r\n \"WEIGHTED_SEATED_LEG_U\",\r\n \"WEIGHTED_SIDE_TO_SIDE_CRUNCH_AND_WEAVE\",\r\n \"WEIGHTED_SINGLE_LEG_REVERSE_CRUNCH\",\r\n \"WEIGHTED_SKATER_CRUNCH_CROSS\",\r\n \"WEIGHTED_STEP_CLIMB\",\r\n \"WEIGHTED_SWISS_BALL_CRUNCH\",\r\n \"WEIGHTED_SWISS_BALL_REVERSE_CRUNCH\",\r\n \"WEIGHTED_SWISS_BALL_RUSSIAN_TWIST\",\r\n \"WEIGHTED_SWISS_BALL_SIDE_CRUNCH\",\r\n \"WEIGHTED_THORACIC_CRUNCHES_ON_FOAM_ROLLER\",\r\n \"WEIGHTED_TOES_TO_BAR\",\r\n ],\r\n CURL: [\r\n \"ALTERNATING_DUMBBELL_BICEPS_CURL\",\r\n \"ALTERNATING_DUMBBELL_BICEPS_CURL_ON_SWISS_BALL\",\r\n \"ALTERNATING_INCLINE_DUMBBELL_BICEPS_CURL\",\r\n \"BARBELL_BICEPS_CURL\",\r\n \"BARBELL_REVERSE_WRIST_CURL\",\r\n \"BARBELL_WRIST_CURL\",\r\n \"BEHIND_THE_BACK_BARBELL_REVERSE_WRIST_CURL\",\r\n \"BEHIND_THE_BACK_ONE_ARM_CABLE_CURL\",\r\n \"CABLE_BICEPS_CURL\",\r\n \"CABLE_HAMMER_CURL\",\r\n \"CHEATING_BARBELL_BICEPS_CURL\",\r\n \"CLOSE_GRIP_EZ_BAR_BICEPS_CURL\",\r\n \"CROSS_BODY_DUMBBELL_HAMMER_CURL\",\r\n \"DEAD_HANG_BICEPS_CURL\",\r\n \"DECLINE_HAMMER_CURL\",\r\n \"DRAG_CURL_WHEELCHAIR\",\r\n \"DUMBBELL_BICEPS_CURL\",\r\n \"DUMBBELL_BICEPS_CURL_WHEELCHAIR\",\r\n \"DUMBBELL_BICEPS_CURL_WITH_STATIC_HOLD\",\r\n \"DUMBBELL_HAMMER_CURL\",\r\n \"DUMBBELL_REVERSE_WRIST_CURL\",\r\n \"DUMBBELL_WRIST_CURL\",\r\n \"EZ_BAR_PREACHER_CURL\",\r\n \"FORWARD_BEND_BICEPS_CURL\",\r\n \"HAMMER_CURL_TO_PRESS\",\r\n \"INCLINE_DUMBBELL_BICEPS_CURL\",\r\n \"INCLINE_OFFSET_THUMB_DUMBBELL_CURL\",\r\n \"KETTLEBELL_BICEPS_CURL\",\r\n \"LYING_CONCENTRATION_CABLE_CURL\",\r\n \"ONE_ARM_CONCENTRATION_CURL\",\r\n \"ONE_ARM_PREACHER_CURL\",\r\n \"PLATE_PINCH_CURL\",\r\n \"PREACHER_CURL_WITH_CABLE\",\r\n \"REVERSE_EZ_BAR_CURL\",\r\n \"REVERSE_GRIP_BARBELL_BICEPS_CURL\",\r\n \"REVERSE_GRIP_WRIST_CURL\",\r\n \"SEATED_ALTERNATING_DUMBBELL_BICEPS_CURL\",\r\n \"SEATED_DUMBBELL_BICEPS_CURL\",\r\n \"SEATED_REVERSE_DUMBBELL_CURL\",\r\n \"SPLIT_STANCE_OFFSET_PINKY_DUMBBELL_CURL\",\r\n \"STANDING_ALTERNATING_DUMBBELL_CURLS\",\r\n \"STANDING_DUMBBELL_BICEPS_CURL\",\r\n \"STANDING_EZ_BAR_BICEPS_CURL\",\r\n \"STANDING_ZOTTMAN_BICEPS_CURL\",\r\n \"STATIC_CURL\",\r\n \"SWISS_BALL_DUMBBELL_OVERHEAD_TRICEPS_EXTENSION\",\r\n \"SWISS_BALL_EZ_BAR_PREACHER_CURL\",\r\n \"TWISTING_STANDING_DUMBBELL_BICEPS_CURL\",\r\n \"WIDE_GRIP_EZ_BAR_BICEPS_CURL\",\r\n ],\r\n DEADLIFT: [\r\n \"BARBELL_DEADLIFT\",\r\n \"BARBELL_STRAIGHT_LEG_DEADLIFT\",\r\n \"DUMBBELL_DEADLIFT\",\r\n \"DUMBBELL_SINGLE_LEG_DEADLIFT_TO_ROW\",\r\n \"DUMBBELL_STRAIGHT_LEG_DEADLIFT\",\r\n \"KETTLEBELL_DEADLIFT\",\r\n \"KETTLEBELL_FLOOR_TO_SHELF\",\r\n \"KETTLEBELL_SUMO_DEADLIFT\",\r\n \"ONE_ARM_ONE_LEG_DEADLIFT\",\r\n \"RACK_PULL\",\r\n \"ROMANIAN_DEADLIFT\",\r\n \"ROTATIONAL_DUMBBELL_STRAIGHT_LEG_DEADLIFT\",\r\n \"RUCK_DEADLIFT\",\r\n \"SINGLE_ARM_DEADLIFT\",\r\n \"SINGLE_LEG_BARBELL_DEADLIFT\",\r\n \"SINGLE_LEG_BARBELL_STRAIGHT_LEG_DEADLIFT\",\r\n \"SINGLE_LEG_DEADLIFT_WITH_BARBELL\",\r\n \"SINGLE_LEG_RDL_CIRCUIT\",\r\n \"SINGLE_LEG_ROMANIAN_DEADLIFT_CIRCUIT\",\r\n \"SINGLE_LEG_ROMANIAN_DEADLIFT_WITH_DUMBBELL\",\r\n \"STRAIGHT_LEG_DEADLIFT\",\r\n \"SUMO_DEADLIFT\",\r\n \"SUMO_DEADLIFT_HIGH_PULL\",\r\n \"TRAP_BAR_DEADLIFT\",\r\n \"WIDE_GRIP_BARBELL_DEADLIFT\",\r\n ],\r\n ELLIPTICAL: [\r\n \"ELLIPTICAL\",\r\n ],\r\n FLOOR_CLIMB: [\r\n \"FLOOR_CLIMB\",\r\n ],\r\n FLYE: [\r\n \"ARM_ROTATIONS\",\r\n \"CABLE_CROSSOVER\",\r\n \"DECLINE_DUMBBELL_FLYE\",\r\n \"DUMBBELL_FLYE\",\r\n \"HUG_A_TREE\",\r\n \"INCLINE_DUMBBELL_FLYE\",\r\n \"INCLINE_REVERSE_FLYE\",\r\n \"KETTLEBELL_FLYE\",\r\n \"KNEELING_REAR_FLYE\",\r\n \"REAR_DELT_FLY_WHEELCHAIR\",\r\n \"SINGLE_ARM_STANDING_CABLE_REVERSE_FLYE\",\r\n \"SWISS_BALL_DUMBBELL_FLYE\",\r\n ],\r\n HIP_RAISE: [\r\n \"BARBELL_HIP_THRUST_ON_FLOOR\",\r\n \"BARBELL_HIP_THRUST_WITH_BENCH\",\r\n \"BENT_KNEE_SWISS_BALL_REVERSE_HIP_RAISE\",\r\n \"BRIDGE_WITH_LEG_EXTENSION\",\r\n \"CLAMS\",\r\n \"CLAM_BRIDGE\",\r\n \"FRONT_KICK_TABLETOP\",\r\n \"HIP_EXTENSION_AND_CROSS\",\r\n \"HIP_RAISE\",\r\n \"HIP_RAISE_WITH_FEET_ON_SWISS_BALL\",\r\n \"HIP_RAISE_WITH_HEAD_ON_BOSU_BALL\",\r\n \"HIP_RAISE_WITH_HEAD_ON_SWISS_BALL\",\r\n \"HIP_RAISE_WITH_KNEE_SQUEEZE\",\r\n \"INCLINE_REAR_LEG_EXTENSION\",\r\n \"KETTLEBELL_SWING\",\r\n \"LEG_CIRCLES\",\r\n \"LEG_LIFT\",\r\n \"LEG_LIFT_IN_EXTERNAL_ROTATION\",\r\n \"MARCHING_HIP_RAISE\",\r\n \"MARCHING_HIP_RAISE_WITH_FEET_ON_A_SWISS_BALL\",\r\n \"REVERSE_HIP_RAISE\",\r\n \"SINGLE_LEG_HIP_RAISE\",\r\n \"SINGLE_LEG_HIP_RAISE_WITH_FOOT_ON_BENCH\",\r\n \"SINGLE_LEG_HIP_RAISE_WITH_FOOT_ON_BOSU_BALL\",\r\n \"SINGLE_LEG_HIP_RAISE_WITH_FOOT_ON_FOAM_ROLLER\",\r\n \"SINGLE_LEG_HIP_RAISE_WITH_FOOT_ON_MEDICINE_BALL\",\r\n \"SINGLE_LEG_HIP_RAISE_WITH_HEAD_ON_BOSU_BALL\",\r\n \"SINGLE_LEG_SWISS_BALL_HIP_RAISE_AND_LEG_CURL\",\r\n \"WEIGHTED_BENT_KNEE_SWISS_BALL_REVERSE_HIP_RAISE\",\r\n \"WEIGHTED_BRIDGE_WITH_LEG_EXTENSION\",\r\n \"WEIGHTED_CLAM_BRIDGE\",\r\n \"WEIGHTED_FRONT_KICK_TABLETOP\",\r\n \"WEIGHTED_HIP_EXTENSION_AND_CROSS\",\r\n \"WEIGHTED_HIP_RAISE\",\r\n \"WEIGHTED_HIP_RAISE_WITH_FEET_ON_SWISS_BALL\",\r\n \"WEIGHTED_HIP_RAISE_WITH_HEAD_ON_BOSU_BALL\",\r\n \"WEIGHTED_HIP_RAISE_WITH_HEAD_ON_SWISS_BALL\",\r\n \"WEIGHTED_HIP_RAISE_WITH_KNEE_SQUEEZE\",\r\n \"WEIGHTED_INCLINE_REAR_LEG_EXTENSION\",\r\n \"WEIGHTED_MARCHING_HIP_RAISE\",\r\n \"WEIGHTED_MARCHING_HIP_RAISE_WITH_FEET_ON_A_SWISS_BALL\",\r\n \"WEIGHTED_REVERSE_HIP_RAISE\",\r\n \"WEIGHTED_SINGLE_LEG_HIP_RAISE\",\r\n \"WEIGHTED_SINGLE_LEG_HIP_RAISE_WITH_FOOT_ON_BENCH\",\r\n \"WEIGHTED_SINGLE_LEG_HIP_RAISE_WITH_FOOT_ON_BOSU_BALL\",\r\n \"WEIGHTED_SINGLE_LEG_HIP_RAISE_WITH_FOOT_ON_FOAM_ROLLER\",\r\n \"WEIGHTED_SINGLE_LEG_HIP_RAISE_WITH_FOOT_ON_MEDICINE_BALL\",\r\n \"WEIGHTED_SINGLE_LEG_HIP_RAISE_WITH_HEAD_ON_BOSU_BALL\",\r\n ],\r\n HIP_STABILITY: [\r\n \"BAND_SIDE_LYING_LEG_RAISE\",\r\n \"DEAD_BUG\",\r\n \"EXTERNAL_HIP_RAISE\",\r\n \"FIRE_HYDRANT_KICKS\",\r\n \"HIP_CIRCLES\",\r\n \"INNER_THIGH_LIFT\",\r\n \"LATERAL_WALKS_WITH_BAND_AT_ANKLES\",\r\n \"LYING_ABDUCTION_STRETCH\",\r\n \"PRETZEL_SIDE_KICK\",\r\n \"PRONE_HIP_INTERNAL_ROTATION\",\r\n \"QUADRUPED\",\r\n \"QUADRUPED_HIP_EXTENSION\",\r\n \"QUADRUPED_WITH_LEG_LIFT\",\r\n \"SIDE_LYING_LEG_RAISE\",\r\n \"SLIDING_HIP_ADDUCTION\",\r\n \"STANDING_ADDUCTION\",\r\n \"STANDING_CABLE_HIP_ABDUCTION\",\r\n \"STANDING_HIP_ABDUCTION\",\r\n \"STANDING_REAR_LEG_RAISE\",\r\n \"SUPINE_HIP_INTERNAL_ROTATION\",\r\n \"WEIGHTED_DEAD_BUG\",\r\n \"WEIGHTED_EXTERNAL_HIP_RAISE\",\r\n \"WEIGHTED_FIRE_HYDRANT_KICKS\",\r\n \"WEIGHTED_HIP_CIRCLES\",\r\n \"WEIGHTED_INNER_THIGH_LIFT\",\r\n \"WEIGHTED_PRETZEL_SIDE_KICK\",\r\n \"WEIGHTED_PRONE_HIP_INTERNAL_ROTATION\",\r\n \"WEIGHTED_QUADRUPED_HIP_EXTENSION\",\r\n \"WEIGHTED_QUADRUPED_WITH_LEG_LIFT\",\r\n \"WEIGHTED_SIDE_LYING_LEG_RAISE\",\r\n \"WEIGHTED_SLIDING_HIP_ADDUCTION\",\r\n \"WEIGHTED_STANDING_ADDUCTION\",\r\n \"WEIGHTED_STANDING_HIP_ABDUCTION\",\r\n \"WEIGHTED_STANDING_REAR_LEG_RAISE\",\r\n \"WEIGHTED_SUPINE_HIP_INTERNAL_ROTATION\",\r\n ],\r\n HIP_SWING: [\r\n \"ONE_ARM_SWING\",\r\n \"SINGLE_ARM_DUMBBELL_SWING\",\r\n \"SINGLE_ARM_KETTLEBELL_SWING\",\r\n \"STEP_OUT_SWING\",\r\n ],\r\n HYPEREXTENSION: [\r\n \"BACK_EXTENSION_WITH_OPPOSITE_ARM_AND_LEG_REACH\",\r\n \"BASE_ROTATIONS\",\r\n \"BENT_KNEE_REVERSE_HYPEREXTENSION\",\r\n \"COBRA\",\r\n \"HOLLOW_HOLD_AND_ROLL\",\r\n \"KICKS\",\r\n \"KNEELING_SUPERMAN\",\r\n \"KNEE_RAISES\",\r\n \"LAT_PULL_DOWN_WITH_ROW\",\r\n \"MEDICINE_BALL_DEADLIFT_TO_REACH\",\r\n \"ONE_ARM_ONE_LEG_ROW\",\r\n \"ONE_ARM_ROW_WITH_BAND\",\r\n \"OVERHEAD_LUNGE_WITH_MEDICINE_BALL\",\r\n \"PLANK_KNEE_TUCKS\",\r\n \"SIDE_STEP\",\r\n \"SINGLE_LEG_BACK_EXTENSION\",\r\n \"SPINE_EXTENSION\",\r\n \"STATIC_BACK_EXTENSION\",\r\n \"SUPERMAN_FROM_FLOOR\",\r\n \"SUPERMAN_ON_SWISS_BALL\",\r\n \"SWISS_BALL_BACK_EXTENSION\",\r\n \"SWISS_BALL_HYPEREXTENSION\",\r\n \"SWISS_BALL_OPPOSITE_ARM_AND_LEG_LIFT\",\r\n \"WEIGHTED_BACK_EXTENSION_WITH_OPPOSITE_ARM_AND_LEG_REACH\",\r\n \"WEIGHTED_BASE_ROTATIONS\",\r\n \"WEIGHTED_BENT_KNEE_REVERSE_HYPEREXTENSION\",\r\n \"WEIGHTED_HOLLOW_HOLD_AND_ROLL\",\r\n \"WEIGHTED_KICKS\",\r\n \"WEIGHTED_KNEELING_SUPERMAN\",\r\n \"WEIGHTED_KNEE_RAISES\",\r\n \"WEIGHTED_PLANK_KNEE_TUCKS\",\r\n \"WEIGHTED_SIDE_STEP\",\r\n \"WEIGHTED_SINGLE_LEG_BACK_EXTENSION\",\r\n \"WEIGHTED_SPINE_EXTENSION\",\r\n \"WEIGHTED_STATIC_BACK_EXTENSION\",\r\n \"WEIGHTED_SUPERMAN_FROM_FLOOR\",\r\n \"WEIGHTED_SWISS_BALL_BACK_EXTENSION\",\r\n \"WEIGHTED_SWISS_BALL_HYPEREXTENSION\",\r\n \"WEIGHTED_SWISS_BALL_OPPOSITE_ARM_AND_LEG_LIFT\",\r\n ],\r\n INDOOR_BIKE: [\r\n \"AIR_BIKE\",\r\n \"ASSAULT_BIKE\",\r\n \"STATIONARY_BIKE\",\r\n ],\r\n INDOOR_ROW: [\r\n \"ROWING_MACHINE\",\r\n ],\r\n LADDER: [\r\n \"AGILITY\",\r\n \"SPEED\",\r\n ],\r\n LATERAL_RAISE: [\r\n \"ALTERNATING_LATERAL_RAISE_WITH_STATIC_HOLD\",\r\n \"ARM_CIRCLES\",\r\n \"BAR_MUSCLE_UP\",\r\n \"BENT_OVER_LATERAL_RAISE\",\r\n \"CABLE_DIAGONAL_RAISE\",\r\n \"CABLE_FRONT_RAISE\",\r\n \"CALORIE_ROW\",\r\n \"COMBO_SHOULDER_RAISE\",\r\n \"DUMBBELL_DIAGONAL_RAISE\",\r\n \"DUMBBELL_FRONT_RAISE_WHEELCHAIR\",\r\n \"DUMBBELL_LATERAL_RAISE\",\r\n \"DUMBBELL_LATERAL_RAISE_WHEELCHAIR\",\r\n \"DUMBBELL_V_RAISE\",\r\n \"FRONT_RAISE\",\r\n \"LEANING_DUMBBELL_LATERAL_RAISE\",\r\n \"LYING_DUMBBELL_RAISE\",\r\n \"MUSCLE_UP\",\r\n \"ONE_ARM_CABLE_LATERAL_RAISE\",\r\n \"OVERHAND_GRIP_REAR_LATERAL_RAISE\",\r\n \"PLATE_RAISES\",\r\n \"POLE_DOUBLE_ARM_OVERHEAD_AND_FORWARD_WHEELCHAIR\",\r\n \"POLE_STRAIGHT_ARM_OVERHEAD_WHEELCHAIR\",\r\n \"RING_DIP\",\r\n \"RING_DIP_KIPPING\",\r\n \"RING_MUSCLE_UP\",\r\n \"ROPE_CLIMB\",\r\n \"SCAPTION\",\r\n \"SEATED_LATERAL_RAISE\",\r\n \"SEATED_REAR_LATERAL_RAISE\",\r\n \"SHAVING_THE_HEAD\",\r\n \"SIDE_LYING_LATERAL_RAISE\",\r\n \"STANDING_LIFT\",\r\n \"SUSPENDED_ROW\",\r\n \"UNDERHAND_GRIP_REAR_LATERAL_RAISE\",\r\n \"WALL_SLIDE\",\r\n \"WALL_WALK\",\r\n \"WEIGHTED_RING_DIP\",\r\n \"WEIGHTED_RING_MUSCLE_UP\",\r\n \"WEIGHTED_ROPE_CLIMB\",\r\n \"WEIGHTED_WALL_SLIDE\",\r\n \"_45_DEGREE_CABLE_EXTERNAL_ROTATION\",\r\n ],\r\n LEG_CURL: [\r\n \"BAND_GOOD_MORNING\",\r\n \"BAR_GOOD_MORNING\",\r\n \"GOOD_MORNING\",\r\n \"LEG_CURL\",\r\n \"SEATED_BARBELL_GOOD_MORNING\",\r\n \"SINGLE_LEG_BARBELL_GOOD_MORNING\",\r\n \"SINGLE_LEG_SLIDING_LEG_CURL\",\r\n \"SLIDING_LEG_CURL\",\r\n \"SPLIT_BARBELL_GOOD_MORNING\",\r\n \"SPLIT_STANCE_EXTENSION\",\r\n \"STAGGERED_STANCE_GOOD_MORNING\",\r\n \"SWISS_BALL_HIP_RAISE_AND_LEG_CURL\",\r\n \"WEIGHTED_LEG_CURL\",\r\n \"ZERCHER_GOOD_MORNING\",\r\n ],\r\n LEG_RAISE: [\r\n \"HANGING_KNEE_RAISE\",\r\n \"HANGING_LEG_RAISE\",\r\n \"HANGING_SINGLE_LEG_RAISE\",\r\n \"KETTLEBELL_LEG_RAISES\",\r\n \"LATERAL_STEPOVER\",\r\n \"LEG_LOWERING_DRILL\",\r\n \"LYING_STRAIGHT_LEG_RAISE\",\r\n \"MEDICINE_BALL_LEG_DROPS\",\r\n \"QUADRUPED_LEG_RAISE\",\r\n \"REVERSE_LEG_RAISE\",\r\n \"REVERSE_LEG_RAISE_ON_SWISS_BALL\",\r\n \"SINGLE_LEG_LOWERING_DRILL\",\r\n \"WEIGHTED_HANGING_KNEE_RAISE\",\r\n \"WEIGHTED_HANGING_LEG_RAISE\",\r\n \"WEIGHTED_HANGING_SINGLE_LEG_RAISE\",\r\n \"WEIGHTED_LATERAL_STEPOVER\",\r\n \"WEIGHTED_LEG_LOWERING_DRILL\",\r\n \"WEIGHTED_LYING_STRAIGHT_LEG_RAISE\",\r\n \"WEIGHTED_QUADRUPED_LEG_RAISE\",\r\n \"WEIGHTED_REVERSE_LEG_RAISE\",\r\n \"WEIGHTED_REVERSE_LEG_RAISE_ON_SWISS_BALL\",\r\n \"WEIGHTED_SINGLE_LEG_LOWERING_DRILL\",\r\n ],\r\n LUNGE: [\r\n \"ALTERNATING_BARBELL_FORWARD_LUNGE\",\r\n \"ALTERNATING_DUMBBELL_LUNGE\",\r\n \"ALTERNATING_DUMBBELL_LUNGE_WITH_REACH\",\r\n \"BACK_FOOT_ELEVATED_DUMBBELL_SPLIT_SQUAT\",\r\n \"BARBELL_BOX_LUNGE\",\r\n \"BARBELL_BULGARIAN_SPLIT_SQUAT\",\r\n \"BARBELL_CROSSOVER_LUNGE\",\r\n \"BARBELL_FRONT_SPLIT_SQUAT\",\r\n \"BARBELL_LUNGE\",\r\n \"BARBELL_REVERSE_LUNGE\",\r\n \"BARBELL_SIDE_LUNGE\",\r\n \"BARBELL_SPLIT_SQUAT\",\r\n \"CORE_CONTROL_REAR_LUNGE\",\r\n \"CURTSY_LUNGE\",\r\n \"DIAGONAL_LUNGE\",\r\n \"DROP_LUNGE\",\r\n \"DUMBBELL_BOX_LUNGE\",\r\n \"DUMBBELL_BULGARIAN_SPLIT_SQUAT\",\r\n \"DUMBBELL_CROSSOVER_LUNGE\",\r\n \"DUMBBELL_DIAGONAL_LUNGE\",\r\n \"DUMBBELL_LUNGE\",\r\n \"DUMBBELL_LUNGE_AND_ROTATION\",\r\n \"DUMBBELL_OVERHEAD_BULGARIAN_SPLIT_SQUAT\",\r\n \"DUMBBELL_OVERHEAD_WALKING_LUNGE\",\r\n \"DUMBBELL_REVERSE_LUNGE\",\r\n \"DUMBBELL_REVERSE_LUNGE_TO_HIGH_KNEE_AND_PRESS\",\r\n \"DUMBBELL_SIDE_LUNGE\",\r\n \"ELEVATED_FRONT_FOOT_BARBELL_SPLIT_SQUAT\",\r\n \"FRONT_FOOT_ELEVATED_DUMBBELL_SPLIT_SQUAT\",\r\n \"GUNSLINGER_LUNGE\",\r\n \"LAWNMOWER_LUNGE\",\r\n \"LOW_LUNGE_WITH_ISOMETRIC_ADDUCTION\",\r\n \"LOW_SIDE_TO_SIDE_LUNGE\",\r\n \"LUNGE\",\r\n \"LUNGE_MATRIX\",\r\n \"LUNGE_WITH_ARM_REACH\",\r\n \"LUNGE_WITH_DIAGONAL_REACH\",\r\n \"LUNGE_WITH_SIDE_BEND\",\r\n \"OFFSET_DUMBBELL_LUNGE\",\r\n \"OFFSET_DUMBBELL_REVERSE_LUNGE\",\r\n \"OVERHEAD_BULGARIAN_SPLIT_SQUAT\",\r\n \"OVERHEAD_DUMBBELL_LUNGE\",\r\n \"OVERHEAD_DUMBBELL_REVERSE_LUNGE\",\r\n \"OVERHEAD_DUMBBELL_SPLIT_SQUAT\",\r\n \"OVERHEAD_LUNGE\",\r\n \"OVERHEAD_LUNGE_WITH_ROTATION\",\r\n \"REVERSE_BARBELL_BOX_LUNGE\",\r\n \"REVERSE_BOX_LUNGE\",\r\n \"REVERSE_DUMBBELL_BOX_LUNGE\",\r\n \"REVERSE_DUMBBELL_CROSSOVER_LUNGE\",\r\n \"REVERSE_DUMBBELL_DIAGONAL_LUNGE\",\r\n \"REVERSE_LUNGE_WITH_REACH_BACK\",\r\n \"REVERSE_LUNGE_WITH_TWIST_AND_OVERHEAD_REACH\",\r\n \"REVERSE_SLIDING_BOX_LUNGE\",\r\n \"REVERSE_SLIDING_LUNGE\",\r\n \"RUCK_BACK_LUNGE\",\r\n \"RUCK_OVERHEAD_LUNGE\",\r\n \"RUNNERS_LUNGE_TO_BALANCE\",\r\n \"SCISSOR_POWER_SWITCH\",\r\n \"SHIFTING_SIDE_LUNGE\",\r\n \"SIDE_AND_CROSSOVER_LUNGE\",\r\n \"SIDE_LUNGE\",\r\n \"SIDE_LUNGE_AND_PRESS\",\r\n \"SIDE_LUNGE_JUMP_OFF\",\r\n \"SIDE_LUNGE_SWEEP\",\r\n \"SIDE_LUNGE_TO_CROSSOVER_TAP\",\r\n \"SIDE_TO_SIDE_LUNGE_CHOPS\",\r\n \"SIFF_JUMP_LUNGE\",\r\n \"SINGLE_ARM_REVERSE_LUNGE_AND_PRESS\",\r\n \"SLIDING_LATERAL_LUNGE\",\r\n \"WALKING_BARBELL_LUNGE\",\r\n \"WALKING_DUMBBELL_LUNGE\",\r\n \"WALKING_LUNGE\",\r\n \"WEIGHTED_CURTSY_LUNGE\",\r\n \"WEIGHTED_LUNGE\",\r\n \"WEIGHTED_LUNGE_MATRIX\",\r\n \"WEIGHTED_REVERSE_LUNGE_WITH_REACH_BACK\",\r\n \"WEIGHTED_REVERSE_LUNGE_WITH_TWIST_AND_OVERHEAD_REACH\",\r\n \"WEIGHTED_REVERSE_SLIDING_BOX_LUNGE\",\r\n \"WEIGHTED_REVERSE_SLIDING_LUNGE\",\r\n \"WEIGHTED_RUNNERS_LUNGE_TO_BALANCE\",\r\n \"WEIGHTED_SHIFTING_SIDE_LUNGE\",\r\n \"WEIGHTED_SIDE_AND_CROSSOVER_LUNGE\",\r\n \"WEIGHTED_SIDE_LUNGE\",\r\n \"WEIGHTED_SIDE_LUNGE_AND_PRESS\",\r\n \"WEIGHTED_SIDE_LUNGE_JUMP_OFF\",\r\n \"WEIGHTED_SIDE_LUNGE_SWEEP\",\r\n \"WEIGHTED_SIDE_LUNGE_TO_CROSSOVER_TAP\",\r\n \"WEIGHTED_SIDE_TO_SIDE_LUNGE_CHOPS\",\r\n \"WEIGHTED_SIFF_JUMP_LUNGE\",\r\n \"WEIGHTED_SLIDING_LATERAL_LUNGE\",\r\n \"WEIGHTED_WALKING_LUNGE\",\r\n \"WIDE_GRIP_OVERHEAD_BARBELL_SPLIT_SQUAT\",\r\n ],\r\n MOVE: [\r\n \"ARCH_AND_CURL\",\r\n \"ARM_CIRCLES_HIGH_BACKWARD_WHEELCHAIR\",\r\n \"ARM_CIRCLES_HIGH_FORWARD_WHEELCHAIR\",\r\n \"ARM_CIRCLES_LOW_BACKWARD_WHEELCHAIR\",\r\n \"ARM_CIRCLES_LOW_FORWARD_WHEELCHAIR\",\r\n \"ARM_CIRCLES_MID_BACKWARD_WHEELCHAIR\",\r\n \"ARM_CIRCLES_MID_FORWARD_WHEELCHAIR\",\r\n \"ARM_CIRCLES_WITH_BALL_BAND_AND_WEIGHT\",\r\n \"ARM_EXTEND_WHEELCHAIR\",\r\n \"ARM_RAISE_WHEELCHAIR\",\r\n \"ARM_STRETCH\",\r\n \"BACK_MASSAGE\",\r\n \"BELLY_BREATHING\",\r\n \"BRIDGE_WITH_BALL\",\r\n \"CHEST_EXPAND_WHEELCHAIR\",\r\n \"CORE_TWISTS_WHEELCHAIR\",\r\n \"DIAMOND_LEG_CRUNCH\",\r\n \"DIAMOND_LEG_LIFT\",\r\n \"EIGHT_POINT_SHOULDER_OPENER\",\r\n \"EXTENDED_TOE_TOUCH_WHEELCHAIR\",\r\n \"FOOTWORK\",\r\n \"FOOTWORK_ON_DISC\",\r\n \"FOOT_ROLLING\",\r\n \"FORWARD_BEND_WHEELCHAIR\",\r\n \"FORWARD_FOLD\",\r\n \"FORWARD_FOLD_PLUS_WHEELCHAIR\",\r\n \"FORWARD_FOLD_WHEELCHAIR\",\r\n \"FROG_WITH_BAND\",\r\n \"HALF_ROLL_UP\",\r\n \"HAMSTRING_CURL\",\r\n \"HAMSTRING_STRETCH\",\r\n \"HIP_STRETCH\",\r\n \"HUG_A_TREE_WITH_BALL_BAND_AND_WEIGHT\",\r\n \"KNEE_CIRCLES\",\r\n \"KNEE_FOLDS_ON_DISC\",\r\n \"LATERAL_FLEXION\",\r\n \"LEG_STRETCH_WITH_BAND\",\r\n \"LEG_STRETCH_WITH_LEG_CIRCLES\",\r\n \"LOWER_LIFT_ON_DISC\",\r\n \"LUNGES_WITH_KNEE_LIFT\",\r\n \"LUNGE_SQUAT\",\r\n \"MERMAID_STRETCH\",\r\n \"NEUTRAL_PELVIC_POSITION\",\r\n \"PELVIC_CLOCKS_ON_DISC\",\r\n \"PILATES_PLIE_SQUATS_PARALLEL_TURNED_OUT_FLAT_AND_HEELS_WITH_CHAIR\",\r\n \"PIRIFORMIS_STRETCH\",\r\n \"PLANK_KNEE_CROSSES\",\r\n \"PLANK_KNEE_PULLS\",\r\n \"PLANK_UP_DOWNS\",\r\n \"PRAYER_MUDRA\",\r\n \"PSOAS_LUNGE_STRETCH\",\r\n \"RIBCAGE_BREATHING\",\r\n \"ROLL_DOWN\",\r\n \"ROLL_UP_WITH_WEIGHT_AND_BAND\",\r\n \"SAW\",\r\n \"SCAPULAR_STABILIZATION\",\r\n \"SCISSORS_ON_DISC\",\r\n \"SEATED_HIP_STRETCHUP\",\r\n \"SEATED_TWIST\",\r\n \"SHAVING_THE_HEAD_WITH_BALL_BAND_AND_WEIGHT\",\r\n \"SPINAL_TWIST\",\r\n \"SPINAL_TWIST_STRETCH\",\r\n \"SPINE_STRETCH_FORWARD\",\r\n \"SQUATS_WITH_BALL\",\r\n \"STANDING_SIDE_STRETCH\",\r\n \"STANDING_SINGLE_LEG_FORWARD_BEND_WITH_IT_BAND_OPENER\",\r\n \"STAND_AND_HANG\",\r\n \"STRAIGHT_LEG_CRUNCH_WITH_LEGS_CROSSED\",\r\n \"STRAIGHT_LEG_CRUNCH_WITH_LEGS_CROSSED_WITH_BALL\",\r\n \"STRAIGHT_LEG_CRUNCH_WITH_LEG_LIFT\",\r\n \"STRAIGHT_LEG_CRUNCH_WITH_LEG_LIFT_WITH_BALL\",\r\n \"STRAIGHT_LEG_DIAGONAL_CRUNCH\",\r\n \"STRAIGHT_LEG_DIAGONAL_CRUNCH_WITH_BALL\",\r\n \"TAILBONE_CURL\",\r\n \"THROAT_LOCK\",\r\n \"TICK_TOCK_SIDE_ROLL\",\r\n \"TOE_TOUCH_WHEELCHAIR\",\r\n \"TWIST\",\r\n \"V_LEG_CRUNCHES\",\r\n \"V_SIT\",\r\n ],\r\n OLYMPIC_LIFT: [\r\n \"BARBELL_HANG_POWER_CLEAN\",\r\n \"BARBELL_HANG_POWER_SNATCH\",\r\n \"BARBELL_HANG_PULL\",\r\n \"BARBELL_HANG_SQUAT_CLEAN\",\r\n \"BARBELL_HIGH_PULL\",\r\n \"BARBELL_HIGH_PULL_BLOCK\",\r\n \"BARBELL_POWER_CLEAN\",\r\n \"BARBELL_POWER_SNATCH\",\r\n \"BARBELL_POWER_SNATCH_BLOCK\",\r\n \"BARBELL_SNATCH\",\r\n \"BARBELL_SPLIT_JERK\",\r\n \"BARBELL_SQUAT_CLEAN\",\r\n \"CLEAN\",\r\n \"CLEAN_AND_JERK\",\r\n \"CLEAN_AND_PRESS\",\r\n \"DUMBBELL_CLEAN\",\r\n \"DUMBBELL_HANG_PULL\",\r\n \"DUMBBELL_HANG_SNATCH\",\r\n \"DUMBBELL_POWER_CLEAN_AND_JERK\",\r\n \"DUMBBELL_POWER_CLEAN_AND_PUSH_PRESS\",\r\n \"DUMBBELL_POWER_CLEAN_AND_STRICT_PRESS\",\r\n \"DUMBBELL_SNATCH\",\r\n \"MEDICINE_BALL_CLEAN\",\r\n \"ONE_HAND_DUMBBELL_SPLIT_SNATCH\",\r\n \"PUSH_JERK\",\r\n \"SINGLE_ARM_DUMBBELL_SNATCH\",\r\n \"SINGLE_ARM_HANG_SNATCH\",\r\n \"SINGLE_ARM_KETTLEBELL_SNATCH\",\r\n \"SNATCH\",\r\n \"SPLIT_JERK\",\r\n \"SQUAT_CLEAN_AND_JERK\",\r\n \"TRAP_BAR_HIGH_PULL\",\r\n ],\r\n PLANK: [\r\n \"BEAR_CRAWL\",\r\n \"BRIDGE_ONE_LEG_BRIDGE\",\r\n \"BRIDGE_WITH_GLUTE_LOWER_LIFT\",\r\n \"CROSS_BODY_MOUNTAIN_CLIMBER\",\r\n \"ELBOW_PLANK_PIKE_JACKS\",\r\n \"ELEVATED_FEET_PLANK\",\r\n \"ELEVATOR_ABS\",\r\n \"EXTENDED_PLANK\",\r\n \"FULL_PLANK_PASSE_TWIST\",\r\n \"INCHING_ELBOW_PLANK\",\r\n \"INCHWORM_TO_SIDE_PLANK\",\r\n \"KNEELING_PLANK\",\r\n \"KNEELING_SIDE_PLANK_WITH_LEG_LIFT\",\r\n \"LATERAL_ROLL\",\r\n \"LYING_REVERSE_PLANK\",\r\n \"MEDICINE_BALL_MOUNTAIN_CLIMBER\",\r\n \"MODIFIED_MOUNTAIN_CLIMBER_AND_EXTENSION\",\r\n \"MOUNTAIN_CLIMBER\",\r\n \"MOUNTAIN_CLIMBER_ON_SLIDING_DISCS\",\r\n \"MOUNTAIN_CLIMBER_WITH_FEET_ON_BOSU_BALL\",\r\n \"MOUNTAIN_CLIMBER_WITH_HANDS_ON_BENCH\",\r\n \"MOUNTAIN_CLIMBER_WITH_HANDS_ON_SWISS_BALL\",\r\n \"PLANK\",\r\n \"PLANK_JACKS_WITH_FEET_ON_SLIDING_DISCS\",\r\n \"PLANK_KNEE_TWIST\",\r\n \"PLANK_PIKES\",\r\n \"PLANK_PIKE_JUMPS\",\r\n \"PLANK_TO_STAND_UP\",\r\n \"PLANK_WITH_ARM_RAISE\",\r\n \"PLANK_WITH_ARM_VARIATIONS\",\r\n \"PLANK_WITH_FEET_ON_SWISS_BALL\",\r\n \"PLANK_WITH_KNEE_TO_ELBOW\",\r\n \"PLANK_WITH_LEG_LIFT\",\r\n \"PLANK_WITH_OBLIQUE_CRUNCH\",\r\n \"PLYOMETRIC_SIDE_PLANK\",\r\n \"REVERSE_PLANK_WITH_LEG_PULL\",\r\n \"RING_PLANK_SPRAWLS\",\r\n \"ROLLING_SIDE_PLANK\",\r\n \"SIDE_KICK_PLANK\",\r\n \"SIDE_PLANK\",\r\n \"SIDE_PLANK_AND_ROW\",\r\n \"SIDE_PLANK_LIFT\",\r\n \"SIDE_PLANK_TO_PLANK_WITH_REACH_UNDER\",\r\n \"SIDE_PLANK_WITH_ELBOW_ON_BOSU_BALL\",\r\n \"SIDE_PLANK_WITH_FEET_ON_BENCH\",\r\n \"SIDE_PLANK_WITH_KNEE_CIRCLE\",\r\n \"SIDE_PLANK_WITH_KNEE_TUCK\",\r\n \"SIDE_PLANK_WITH_LEG_LIFT\",\r\n \"SIDE_PLANK_WITH_REACH_UNDER\",\r\n \"SINGLE_LEG_ELEVATED_FEET_PLANK\",\r\n \"SINGLE_LEG_FLEX_AND_EXTEND\",\r\n \"SINGLE_LEG_SIDE_PLANK\",\r\n \"SPIDERMAN_PLANK\",\r\n \"STRAIGHT_ARM_PLANK\",\r\n \"STRAIGHT_ARM_PLANK_WITH_SHOULDER_TOUCH\",\r\n \"SWISS_BALL_PLANK\",\r\n \"SWISS_BALL_PLANK_LEG_LIFT\",\r\n \"SWISS_BALL_PLANK_LEG_LIFT_AND_HOLD\",\r\n \"SWISS_BALL_PLANK_WITH_FEET_ON_BENCH\",\r\n \"SWISS_BALL_PRONE_JACKKNIFE\",\r\n \"SWISS_BALL_SIDE_PLANK\",\r\n \"THREE_WAY_PLANK\",\r\n \"TOWEL_PLANK_AND_KNEE_IN\",\r\n \"TURKISH_GET_UP_TO_SIDE_PLANK\",\r\n \"TWO_POINT_PLANK\",\r\n \"T_STABILIZATION\",\r\n \"WEIGHTED_45_DEGREE_PLANK\",\r\n \"WEIGHTED_90_DEGREE_STATIC_HOLD\",\r\n \"WEIGHTED_BEAR_CRAWL\",\r\n \"WEIGHTED_CROSS_BODY_MOUNTAIN_CLIMBER\",\r\n \"WEIGHTED_ELBOW_PLANK_PIKE_JACKS\",\r\n \"WEIGHTED_ELEVATED_FEET_PLANK\",\r\n \"WEIGHTED_ELEVATOR_ABS\",\r\n \"WEIGHTED_EXTENDED_PLANK\",\r\n \"WEIGHTED_FULL_PLANK_PASSE_TWIST\",\r\n \"WEIGHTED_INCHING_ELBOW_PLANK\",\r\n \"WEIGHTED_INCHWORM_TO_SIDE_PLANK\",\r\n \"WEIGHTED_KNEELING_PLANK\",\r\n \"WEIGHTED_KNEELING_SIDE_PLANK_WITH_LEG_LIFT\",\r\n \"WEIGHTED_LATERAL_ROLL\",\r\n \"WEIGHTED_LYING_REVERSE_PLANK\",\r\n \"WEIGHTED_MEDICINE_BALL_MOUNTAIN_CLIMBER\",\r\n \"WEIGHTED_MODIFIED_MOUNTAIN_CLIMBER_AND_EXTENSION\",\r\n \"WEIGHTED_MOUNTAIN_CLIMBER\",\r\n \"WEIGHTED_MOUNTAIN_CLIMBER_ON_SLIDING_DISCS\",\r\n \"WEIGHTED_MOUNTAIN_CLIMBER_WITH_FEET_ON_BOSU_BALL\",\r\n \"WEIGHTED_MOUNTAIN_CLIMBER_WITH_HANDS_ON_BENCH\",\r\n \"WEIGHTED_MOUNTAIN_CLIMBER_WITH_HANDS_ON_SWISS_BALL\",\r\n \"WEIGHTED_PLANK\",\r\n \"WEIGHTED_PLANK_JACKS_WITH_FEET_ON_SLIDING_DISCS\",\r\n \"WEIGHTED_PLANK_KNEE_TWIST\",\r\n \"WEIGHTED_PLANK_PIKES\",\r\n \"WEIGHTED_PLANK_PIKE_JUMPS\",\r\n \"WEIGHTED_PLANK_TO_STAND_UP\",\r\n \"WEIGHTED_PLANK_WITH_ARM_RAISE\",\r\n \"WEIGHTED_PLANK_WITH_KNEE_TO_ELBOW\",\r\n \"WEIGHTED_PLANK_WITH_OBLIQUE_CRUNCH\",\r\n \"WEIGHTED_PLYOMETRIC_SIDE_PLANK\",\r\n \"WEIGHTED_ROLLING_SIDE_PLANK\",\r\n \"WEIGHTED_SIDE_KICK_PLANK\",\r\n \"WEIGHTED_SIDE_PLANK\",\r\n \"WEIGHTED_SIDE_PLANK_AND_ROW\",\r\n \"WEIGHTED_SIDE_PLANK_LIFT\",\r\n \"WEIGHTED_SIDE_PLANK_WITH_ELBOW_ON_BOSU_BALL\",\r\n \"WEIGHTED_SIDE_PLANK_WITH_FEET_ON_BENCH\",\r\n \"WEIGHTED_SIDE_PLANK_WITH_KNEE_CIRCLE\",\r\n \"WEIGHTED_SIDE_PLANK_WITH_KNEE_TUCK\",\r\n \"WEIGHTED_SIDE_PLANK_WITH_LEG_LIFT\",\r\n \"WEIGHTED_SIDE_PLANK_WITH_REACH_UNDER\",\r\n \"WEIGHTED_SINGLE_LEG_ELEVATED_FEET_PLANK\",\r\n \"WEIGHTED_SINGLE_LEG_FLEX_AND_EXTEND\",\r\n \"WEIGHTED_SINGLE_LEG_SIDE_PLANK\",\r\n \"WEIGHTED_SPIDERMAN_PLANK\",\r\n \"WEIGHTED_STRAIGHT_ARM_PLANK\",\r\n \"WEIGHTED_STRAIGHT_ARM_PLANK_WITH_SHOULDER_TOUCH\",\r\n \"WEIGHTED_SWISS_BALL_PLANK\",\r\n \"WEIGHTED_SWISS_BALL_PLANK_LEG_LIFT\",\r\n \"WEIGHTED_SWISS_BALL_PLANK_LEG_LIFT_AND_HOLD\",\r\n \"WEIGHTED_SWISS_BALL_PLANK_WITH_FEET_ON_BENCH\",\r\n \"WEIGHTED_SWISS_BALL_PRONE_JACKKNIFE\",\r\n \"WEIGHTED_SWISS_BALL_SIDE_PLANK\",\r\n \"WEIGHTED_THREE_WAY_PLANK\",\r\n \"WEIGHTED_TOWEL_PLANK_AND_KNEE_IN\",\r\n \"WEIGHTED_TURKISH_GET_UP_TO_SIDE_PLANK\",\r\n \"WEIGHTED_TWO_POINT_PLANK\",\r\n \"WEIGHTED_T_STABILIZATION\",\r\n \"WEIGHTED_WIDE_STANCE_PLANK_WITH_DIAGONAL_ARM_LIFT\",\r\n \"WEIGHTED_WIDE_STANCE_PLANK_WITH_DIAGONAL_LEG_LIFT\",\r\n \"WEIGHTED_WIDE_STANCE_PLANK_WITH_LEG_LIFT\",\r\n \"WIDE_STANCE_PLANK_WITH_DIAGONAL_ARM_LIFT\",\r\n \"WIDE_STANCE_PLANK_WITH_DIAGONAL_LEG_LIFT\",\r\n \"WIDE_STANCE_PLANK_WITH_LEG_LIFT\",\r\n \"WIDE_STANCE_PLANK_WITH_OPPOSITE_ARM_AND_LEG_LIFT\",\r\n \"_45_DEGREE_PLANK\",\r\n \"_90_DEGREE_STATIC_HOLD\",\r\n ],\r\n PLYO: [\r\n \"ALTERNATING_JUMP_LUNGE\",\r\n \"BARBELL_JUMP_SQUAT\",\r\n \"BARBELL_SPLIT_JUMP\",\r\n \"BODY_WEIGHT_JUMP_SQUAT\",\r\n \"BOX_JUMP\",\r\n \"BOX_JUMP_OVERS\",\r\n \"BOX_JUMP_OVERS_OVER_THE_BOX\",\r\n \"CROSS_KNEE_STRIKE\",\r\n \"DEPTH_JUMP\",\r\n \"DUMBBELL_JUMP_SQUAT\",\r\n \"DUMBBELL_SPLIT_JUMP\",\r\n \"FRONT_KNEE_STRIKE\",\r\n \"HIGH_BOX_JUMP\",\r\n \"ISOMETRIC_EXPLOSIVE_BODY_WEIGHT_JUMP_SQUAT\",\r\n \"JUMP_SQUAT\",\r\n \"JUMP_TRAP_BAR\",\r\n \"LATERAL_LEAP_AND_HOP\",\r\n \"LATERAL_PLYO_SQUATS\",\r\n \"LATERAL_SLIDE\",\r\n \"MEDICINE_BALL_OVERHEAD_THROWS\",\r\n \"MEDICINE_BALL_SIDE_THROW\",\r\n \"MEDICINE_BALL_SLAM\",\r\n \"SIDE_TO_SIDE_MEDICINE_BALL_THROWS\",\r\n \"SIDE_TO_SIDE_SHUFFLE_JUMP\",\r\n \"SQUAT_JUMPS_IN_AND_OUT\",\r\n \"SQUAT_JUMP_ONTO_BOX\",\r\n \"STAR_JUMP_SQUATS\",\r\n \"WEIGHTED_ALTERNATING_JUMP_LUNGE\",\r\n \"WEIGHTED_CROSS_KNEE_STRIKE\",\r\n \"WEIGHTED_DEPTH_JUMP\",\r\n \"WEIGHTED_FRONT_KNEE_STRIKE\",\r\n \"WEIGHTED_HIGH_BOX_JUMP\",\r\n \"WEIGHTED_ISOMETRIC_EXPLOSIVE_JUMP_SQUAT\",\r\n \"WEIGHTED_JUMP_SQUAT\",\r\n \"WEIGHTED_LATERAL_LEAP_AND_HOP\",\r\n \"WEIGHTED_LATERAL_PLYO_SQUATS\",\r\n \"WEIGHTED_LATERAL_SLIDE\",\r\n \"WEIGHTED_SIDE_TO_SIDE_SHUFFLE_JUMP\",\r\n \"WEIGHTED_SQUAT_JUMPS_IN_AND_OUT\",\r\n \"WEIGHTED_SQUAT_JUMP_ONTO_BOX\",\r\n ],\r\n POSE: [\r\n \"ALL_FOURS\",\r\n \"ALTERNATIVE_SKIING_WHEELCHAIR\",\r\n \"ANKLE_TO_KNEE\",\r\n \"BABY_COBRA\",\r\n \"BOAT\",\r\n \"BOUND_ANGLE\",\r\n \"BOUND_SEATED_SINGLE_LEG_FORWARD_BEND\",\r\n \"BOW\",\r\n \"BOWED_HALF_MOON\",\r\n \"BREATHING_PUNCHES_EXTENDED_SIDE_WHEELCHAIR\",\r\n \"BREATHING_PUNCHES_EXTENDED_WHEELCHAIR\",\r\n \"BREATHING_PUNCHES_OVERHEAD_AND_DOWN_SIDE_WHEELCHAIR\",\r\n \"BREATHING_PUNCHES_OVERHEAD_AND_DOWN_WHEELCHAIR\",\r\n \"BREATHING_PUNCHES_OVERHEAD_SIDE_WHEELCHAIR\",\r\n \"BREATHING_PUNCHES_OVERHEAD_WHEELCHAIR\",\r\n \"BREATHING_PUNCHES_SIDE_WHEELCHAIR\",\r\n \"BREATHING_PUNCHES_WHEELCHAIR\",\r\n \"BRIDGE\",\r\n \"CACTUS_WHEELCHAIR\",\r\n \"CAT\",\r\n \"CHAIR\",\r\n \"CHILDS\",\r\n \"CORPSE\",\r\n \"COW\",\r\n \"COW_FACE\",\r\n \"DEEP_BREATHING_HIGH_WHEELCHAIR\",\r\n \"DEEP_BREATHING_LOW_WHEELCHAIR\",\r\n \"DEEP_BREATHING_MID_WHEELCHAIR\",\r\n \"DEEP_BREATHING_WHEELCHAIR\",\r\n \"DEVOTIONAL_WARRIOR\",\r\n \"DOLPHIN\",\r\n \"DOLPHIN_PLANK\",\r\n \"DOWNWARD_FACING_DOG\",\r\n \"DOWNWARD_FACING_DOG_TO_COBRA\",\r\n \"DOWN_DOG_KNEE_TO_NOSE\",\r\n \"DOWN_DOG_SPLIT\",\r\n \"DOWN_DOG_SPLIT_OPEN_HIP_BENT_KNEE\",\r\n \"EAGLE\",\r\n \"EASY_SEATED\",\r\n \"EXTENDED_PUPPY\",\r\n \"EXTENDED_SIDE_ANGLE\",\r\n \"FISH\",\r\n \"FOUR_LIMBED_STAFF\",\r\n \"FULL_SPLIT\",\r\n \"GATE\",\r\n \"HALF_CHAIR_HALF_ANKLE_TO_KNEE\",\r\n \"HALF_MOON\",\r\n \"HEAD_TO_KNEE\",\r\n \"HERON\",\r\n \"HEROS\",\r\n \"HIGH_LUNGE\",\r\n \"KNEES_CHEST_CHIN\",\r\n \"LEFT_HAND_BACK_WHEELCHAIR\",\r\n \"LIZARD\",\r\n \"LOCUST\",\r\n \"LOW_LUNGE\",\r\n \"LOW_LUNGE_TWIST\",\r\n \"LOW_LUNGE_WITH_KNEE_DOWN\",\r\n \"MERMAID\",\r\n \"MOUNTAIN\",\r\n \"NECK_FLEXION_AND_EXTENSION_WHEELCHAIR\",\r\n \"NECK_LATERAL_FLEXION_WHEELCHAIR\",\r\n \"ONE_LEGGED_DOWNWARD_FACING_POSE_OPEN_HIP_BENT_KNEE\",\r\n \"ONE_LEGGED_PIGEON\",\r\n \"OVERHEAD_PRAYER_WHEELCHAIR\",\r\n \"PEACEFUL_WARRIOR\",\r\n \"PLOW\",\r\n \"PRAYER_WHEELCHAIR\",\r\n \"REACH_FORWARD_WHEELCHAIR\",\r\n \"RECLINED_HAND_TO_FOOT\",\r\n \"REVERSE_WARRIOR_WHEELCHAIR\",\r\n \"REVOLVED_HALF_MOON\",\r\n \"REVOLVED_HEAD_TO_KNEE\",\r\n \"REVOLVED_TRIANGLE\",\r\n \"RUNNERS_LUNGE\",\r\n \"SEATED_EASY_SIDE_BEND\",\r\n \"SEATED_EASY_TWIST\",\r\n \"SEATED_LONG_LEG_FORWARD_BEND\",\r\n \"SEATED_WIDE_LEG_FORWARD_BEND\",\r\n \"SHOULDER_STAND\",\r\n \"SIDE_BOAT\",\r\n \"SPHINX\",\r\n \"SPINE_FLEXION_AND_EXTENSION_WHEELCHAIR\",\r\n \"SPINE_LATERAL_FLEXION_WHEELCHAIR\",\r\n \"SPINE_ROTATION_WHEELCHAIR\",\r\n \"SQUAT_OPEN_ARM_TWIST\",\r\n \"SQUAT_PALM_PRESS\",\r\n \"STAFF\",\r\n \"STANDING_ARMS_UP\",\r\n \"STANDING_FORWARD_BEND\",\r\n \"STANDING_FORWARD_BEND_HALFWAY_UP\",\r\n \"STANDING_SIDE_OPENER\",\r\n \"STANDING_SINGLE_LEG_FORWARD_BEND\",\r\n \"STANDING_SPLIT\",\r\n \"STANDING_WIDE_LEG_FORWARD_BEND\",\r\n \"STANDING_WIDE_LEG_FORWARD_BEND_WITH_TWIST\",\r\n \"SUPINE_SPINAL_TWIST\",\r\n \"TABLE_TOP\",\r\n \"THREAD_THE_NEEDLE\",\r\n \"THREAD_THE_NEEDLE_WHEELCHAIR\",\r\n \"THUNDERBOLT\",\r\n \"THUNDERBOLT_POSE_BOTH_SIDES_ARM_STRETCH\",\r\n \"TREE\",\r\n \"TRIANGLE\",\r\n \"TRIANGLE_WHEELCHAIR\",\r\n \"UPWARD_FACING_PLANK\",\r\n \"UP_DOG\",\r\n \"WARRIOR_ONE\",\r\n \"WARRIOR_THREE\",\r\n \"WARRIOR_TWO\",\r\n \"WARRIOR_WHEELCHAIR\",\r\n \"WHEEL\",\r\n \"WIDE_SIDE_LUNGE\",\r\n ],\r\n PULL_UP: [\r\n \"BANDED_PULL_UPS\",\r\n \"BAND_ASSISTED_CHIN_UP\",\r\n \"BAND_ASSISTED_PULL_UP\",\r\n \"BURPEE_PULL_UP\",\r\n \"CHIN_UP\",\r\n \"CLOSE_GRIP_CHIN_UP\",\r\n \"CLOSE_GRIP_LAT_PULLDOWN\",\r\n \"CROSSOVER_CHIN_UP\",\r\n \"EZ_BAR_PULLOVER\",\r\n \"HANGING_HURDLE\",\r\n \"JUMPING_PULL_UPS\",\r\n \"KIPPING_PULL_UP\",\r\n \"KNEELING_LAT_PULLDOWN\",\r\n \"KNEELING_UNDERHAND_GRIP_LAT_PULLDOWN\",\r\n \"LAT_PULLDOWN\",\r\n \"L_PULL_UP\",\r\n \"MIXED_GRIP_CHIN_UP\",\r\n \"MIXED_GRIP_PULL_UP\",\r\n \"NEUTRAL_GRIP_CHIN_UP\",\r\n \"NEUTRAL_GRIP_PULL_UP\",\r\n \"PULL_UP\",\r\n \"REVERSE_GRIP_PULLDOWN\",\r\n \"STANDING_CABLE_PULLOVER\",\r\n \"STRAIGHT_ARM_PULLDOWN\",\r\n \"SUSPENDED_CHIN_UP\",\r\n \"SWISS_BALL_EZ_BAR_PULLOVER\",\r\n \"TOWEL_PULL_UP\",\r\n \"WEIGHTED_BURPEE_PULL_UP\",\r\n \"WEIGHTED_CHIN_UP\",\r\n \"WEIGHTED_CLOSE_GRIP_CHIN_UP\",\r\n \"WEIGHTED_CROSSOVER_CHIN_UP\",\r\n \"WEIGHTED_HANGING_HURDLE\",\r\n \"WEIGHTED_JUMPING_PULL_UPS\",\r\n \"WEIGHTED_KIPPING_PULL_UP\",\r\n \"WEIGHTED_L_PULL_UP\",\r\n \"WEIGHTED_MIXED_GRIP_CHIN_UP\",\r\n \"WEIGHTED_MIXED_GRIP_PULL_UP\",\r\n \"WEIGHTED_NEUTRAL_GRIP_CHIN_UP\",\r\n \"WEIGHTED_NEUTRAL_GRIP_PULL_UP\",\r\n \"WEIGHTED_PULL_UP\",\r\n \"WEIGHTED_SUSPENDED_CHIN_UP\",\r\n \"WEIGHTED_TOWEL_PULL_UP\",\r\n \"WEIGHTED_WIDE_GRIP_PULL_UP\",\r\n \"WIDE_GRIP_LAT_PULLDOWN\",\r\n \"WIDE_GRIP_PULL_UP\",\r\n \"_30_DEGREE_LAT_PULLDOWN\",\r\n ],\r\n PUSH_UP: [\r\n \"ALTERNATING_HANDS_MEDICINE_BALL_PUSH_UP\",\r\n \"ALTERNATING_STAGGERED_PUSH_UP\",\r\n \"BICEPS_PUSH_UP\",\r\n \"BOSU_BALL_PUSH_UP\",\r\n \"CHEST_PRESS_WITH_BAND\",\r\n \"CLAPPING_PUSH_UP\",\r\n \"CLOSE_GRIP_MEDICINE_BALL_PUSH_UP\",\r\n \"CLOSE_HANDS_PUSH_UP\",\r\n \"DECLINE_PUSH_UP\",\r\n \"DIAMOND_PUSH_UP\",\r\n \"DYNAMIC_PUSH_UP\",\r\n \"EXPLOSIVE_CROSSOVER_PUSH_UP\",\r\n \"EXPLOSIVE_PUSH_UP\",\r\n \"FEET_ELEVATED_SIDE_TO_SIDE_PUSH_UP\",\r\n \"HANDSTAND_PUSH_UP\",\r\n \"HAND_RELEASE_PUSH_UP\",\r\n \"HINDU_PUSH_UP\",\r\n \"INCLINE_PUSH_UP\",\r\n \"ISOMETRIC_EXPLOSIVE_PUSH_UP\",\r\n \"JUDO_PUSH_UP\",\r\n \"KIPPING_HANDSTAND_PUSH_UP\",\r\n \"KIPPING_PARALLETTE_HANDSTAND_PUSH_UP\",\r\n \"KNEELING_PUSH_UP\",\r\n \"MEDICINE_BALL_CHEST_PASS\",\r\n \"MEDICINE_BALL_PUSH_UP\",\r\n \"ONE_ARM_PUSH_UP\",\r\n \"PARALLETTE_HANDSTAND_PUSH_UP\",\r\n \"PIKE_PUSH_UP\",\r\n \"PILATES_PUSHUP\",\r\n \"PUSH_UP\",\r\n \"PUSH_UP_AND_ROW\",\r\n \"PUSH_UP_PLUS\",\r\n \"PUSH_UP_WITH_FEET_ON_SWISS_BALL\",\r\n \"PUSH_UP_WITH_ONE_HAND_ON_MEDICINE_BALL\",\r\n \"RING_HANDSTAND_PUSH_UP\",\r\n \"RING_PUSH_UP\",\r\n \"SHOULDER_PUSH_UP\",\r\n \"SHOULDER_TAPPING_PUSH_UP\",\r\n \"SINGLE_ARM_MEDICINE_BALL_PUSH_UP\",\r\n \"SPIDERMAN_PUSH_UP\",\r\n \"STACKED_FEET_PUSH_UP\",\r\n \"STAGGERED_HANDS_PUSH_UP\",\r\n \"SUSPENDED_PUSH_UP\",\r\n \"SWISS_BALL_PUSH_UP\",\r\n \"SWISS_BALL_PUSH_UP_PLUS\",\r\n \"TRIPLE_STOP_PUSH_UP\",\r\n \"T_PUSH_UP\",\r\n \"WEIGHTED_ALTERNATING_HANDS_MEDICINE_BALL_PUSH_UP\",\r\n \"WEIGHTED_ALTERNATING_STAGGERED_PUSH_UP\",\r\n \"WEIGHTED_BICEPS_PUSH_UP\",\r\n \"WEIGHTED_BOSU_BALL_PUSH_UP\",\r\n \"WEIGHTED_CLAPPING_PUSH_UP\",\r\n \"WEIGHTED_CLOSE_GRIP_MEDICINE_BALL_PUSH_UP\",\r\n \"WEIGHTED_CLOSE_HANDS_PUSH_UP\",\r\n \"WEIGHTED_DECLINE_PUSH_UP\",\r\n \"WEIGHTED_DIAMOND_PUSH_UP\",\r\n \"WEIGHTED_EXPLOSIVE_CROSSOVER_PUSH_UP\",\r\n \"WEIGHTED_EXPLOSIVE_PUSH_UP\",\r\n \"WEIGHTED_FEET_ELEVATED_SIDE_TO_SIDE_PUSH_UP\",\r\n \"WEIGHTED_HANDSTAND_PUSH_UP\",\r\n \"WEIGHTED_HAND_RELEASE_PUSH_UP\",\r\n \"WEIGHTED_HINDU_PUSH_UP\",\r\n \"WEIGHTED_INCLINE_PUSH_UP\",\r\n \"WEIGHTED_ISOMETRIC_EXPLOSIVE_PUSH_UP\",\r\n \"WEIGHTED_JUDO_PUSH_UP\",\r\n \"WEIGHTED_KNEELING_PUSH_UP\",\r\n \"WEIGHTED_MEDICINE_BALL_PUSH_UP\",\r\n \"WEIGHTED_ONE_ARM_PUSH_UP\",\r\n \"WEIGHTED_PARALLETTE_HANDSTAND_PUSH_UP\",\r\n \"WEIGHTED_PIKE_PUSH_UP\",\r\n \"WEIGHTED_PUSH_UP\",\r\n \"WEIGHTED_PUSH_UP_AND_ROW\",\r\n \"WEIGHTED_PUSH_UP_PLUS\",\r\n \"WEIGHTED_PUSH_UP_WITH_FEET_ON_SWISS_BALL\",\r\n \"WEIGHTED_PUSH_UP_WITH_ONE_HAND_ON_MEDICINE_BALL\",\r\n \"WEIGHTED_RING_HANDSTAND_PUSH_UP\",\r\n \"WEIGHTED_RING_PUSH_UP\",\r\n \"WEIGHTED_SHOULDER_PUSH_UP\",\r\n \"WEIGHTED_SINGLE_ARM_MEDICINE_BALL_PUSH_UP\",\r\n \"WEIGHTED_SPIDERMAN_PUSH_UP\",\r\n \"WEIGHTED_STACKED_FEET_PUSH_UP\",\r\n \"WEIGHTED_STAGGERED_HANDS_PUSH_UP\",\r\n \"WEIGHTED_SUSPENDED_PUSH_UP\",\r\n \"WEIGHTED_SWISS_BALL_PUSH_UP\",\r\n \"WEIGHTED_SWISS_BALL_PUSH_UP_PLUS\",\r\n \"WEIGHTED_TRIPLE_STOP_PUSH_UP\",\r\n \"WEIGHTED_T_PUSH_UP\",\r\n \"WEIGHTED_WIDE_HANDS_PUSH_UP\",\r\n \"WIDE_GRIP_PUSH_UP\",\r\n \"WIDE_HANDS_PUSH_UP\",\r\n ],\r\n ROW: [\r\n \"ALTERNATING_DUMBBELL_ROW\",\r\n \"BANDED_FACE_PULLS\",\r\n \"BARBELL_BENCH_PULL\",\r\n \"BARBELL_ROW\",\r\n \"BARBELL_STRAIGHT_LEG_DEADLIFT_TO_ROW\",\r\n \"BENT_OVER_ROW_WITH_BARBELL\",\r\n \"BENT_OVER_ROW_WITH_DUMBELL\",\r\n \"CABLE_ROW_STANDING\",\r\n \"CHEST_SUPPORTED_DUMBBELL_ROW\",\r\n \"DECLINE_RING_ROW\",\r\n \"DUMBBELL_ROW\",\r\n \"DUMBBELL_ROW_WHEELCHAIR\",\r\n \"ELEVATED_FEET_INVERTED_ROW\",\r\n \"ELEVATED_RING_ROW\",\r\n \"FACE_PULL\",\r\n \"FACE_PULL_WITH_EXTERNAL_ROTATION\",\r\n \"INDOOR_ROW\",\r\n \"INVERTED_ROW\",\r\n \"INVERTED_ROW_WITH_FEET_ON_SWISS_BALL\",\r\n \"KETTLEBELL_ROW\",\r\n \"MODIFIED_INVERTED_ROW\",\r\n \"NEUTRAL_GRIP_ALTERNATING_DUMBBELL_ROW\",\r\n \"ONE_ARM_BENT_OVER_ROW\",\r\n \"ONE_LEGGED_DUMBBELL_ROW\",\r\n \"RENEGADE_ROW\",\r\n \"REVERSE_GRIP_BARBELL_ROW\",\r\n \"RING_ROW\",\r\n \"ROPE_HANDLE_CABLE_ROW\",\r\n \"ROW\",\r\n \"RUCK_BENTOVER_ROW\",\r\n \"SEATED_CABLE_ROW\",\r\n \"SEATED_DUMBBELL_ROW\",\r\n \"SEATED_UNDERHAND_GRIP_CABLE_ROW\",\r\n \"SINGLE_ARM_CABLE_ROW\",\r\n \"SINGLE_ARM_CABLE_ROW_AND_ROTATION\",\r\n \"SINGLE_ARM_INVERTED_ROW\",\r\n \"SINGLE_ARM_NEUTRAL_GRIP_DUMBBELL_ROW\",\r\n \"SINGLE_ARM_NEUTRAL_GRIP_DUMBBELL_ROW_AND_ROTATION\",\r\n \"SUSPENDED_INVERTED_ROW\",\r\n \"TOWEL_GRIP_INVERTED_ROW\",\r\n \"TRX_INVERTED_ROW\",\r\n \"T_BAR_ROW\",\r\n \"UNDERHAND_GRIP_CABLE_ROW\",\r\n \"V_GRIP_CABLE_ROW\",\r\n \"WEIGHTED_ELEVATED_FEET_INVERTED_ROW\",\r\n \"WEIGHTED_INVERTED_ROW\",\r\n \"WEIGHTED_INVERTED_ROW_WITH_FEET_ON_SWISS_BALL\",\r\n \"WEIGHTED_MODIFIED_INVERTED_ROW\",\r\n \"WEIGHTED_ROW\",\r\n \"WEIGHTED_SINGLE_ARM_INVERTED_ROW\",\r\n \"WEIGHTED_SUSPENDED_INVERTED_ROW\",\r\n \"WEIGHTED_TOWEL_GRIP_INVERTED_ROW\",\r\n \"WEIGHTED_TRX_INVERTED_ROW\",\r\n \"WIDE_GRIP_SEATED_CABLE_ROW\",\r\n ],\r\n RUN: [\r\n \"JOG\",\r\n \"RUN\",\r\n \"RUN_OR_WALK\",\r\n \"SPRINT\",\r\n \"WALK\",\r\n ],\r\n RUN_INDOOR: [\r\n \"INDOOR_TRACK_RUN\",\r\n \"TREADMILL\",\r\n ],\r\n SANDBAG: [\r\n \"AROUND_THE_WORLD\",\r\n \"BACK_SQUAT\",\r\n \"BEAR_CRAWL_PULL_THROUGH\",\r\n \"BEAR_HUG_SQUAT\",\r\n \"CLEAN\",\r\n \"CLEAN_AND_PRESS\",\r\n \"CURL\",\r\n \"FRONT_CARRY\",\r\n \"FRONT_SQUAT\",\r\n \"LUNGE\",\r\n \"OVERHEAD_PRESS\",\r\n \"PLANK_PULL_THROUGH\",\r\n \"ROTATIONAL_LUNGE\",\r\n \"ROW\",\r\n \"RUSSIAN_TWIST\",\r\n \"SHOULDERING\",\r\n \"SHOVELING\",\r\n \"SIDE_LUNGE\",\r\n \"SPRINT\",\r\n \"ZERCHER_SQUAT\",\r\n ],\r\n SHOULDER_PRESS: [\r\n \"ALTERNATING_DUMBBELL_SHOULDER_PRESS\",\r\n \"ARNOLD_PRESS\",\r\n \"ARNOLD_PRESS_WHEELCHAIR\",\r\n \"BARBELL_FRONT_SQUAT_TO_PUSH_PRESS\",\r\n \"BARBELL_PUSH_PRESS\",\r\n \"DEAD_CURL_PRESS\",\r\n \"DUMBBELL_ALTERNATING_SHOULDER_PRESS_AND_TWIST\",\r\n \"DUMBBELL_CURL_TO_OVERHEAD_PRESS_WHEELCHAIR\",\r\n \"DUMBBELL_FRONT_RAISE\",\r\n \"DUMBBELL_HAMMER_CURL_TO_LUNGE_TO_PRESS\",\r\n \"DUMBBELL_PUSH_PRESS\",\r\n \"DUMBBELL_SHOULDER_PRESS\",\r\n \"FLOOR_INVERTED_SHOULDER_PRESS\",\r\n \"INVERTED_SHOULDER_PRESS\",\r\n \"KNEELING_LANDMINE_PRESS\",\r\n \"MILITARY_PRESS\",\r\n \"ONE_ARM_PUSH_PRESS\",\r\n \"OVERHEAD_BARBELL_PRESS\",\r\n \"OVERHEAD_DUMBBELL_PRESS\",\r\n \"OVERHEAD_DUMBBELL_PRESS_WHEELCHAIR\",\r\n \"RUCK_PRESS\",\r\n \"SEATED_BARBELL_SHOULDER_PRESS\",\r\n \"SEATED_DUMBBELL_SHOULDER_PRESS\",\r\n \"SINGLE_ARM_DUMBBELL_SHOULDER_PRESS\",\r\n \"SINGLE_ARM_STEP_UP_AND_PRESS\",\r\n \"SMITH_MACHINE_OVERHEAD_PRESS\",\r\n \"SPLIT_STANCE_HAMMER_CURL_TO_PRESS\",\r\n \"STANDING_LANDMINE_PRESS\",\r\n \"STRICT_PRESS\",\r\n \"SWISS_BALL_DUMBBELL_SHOULDER_PRESS\",\r\n \"WEIGHTED_FLOOR_INVERTED_SHOULDER_PRESS\",\r\n \"WEIGHTED_INVERTED_SHOULDER_PRESS\",\r\n \"WEIGHT_PLATE_FRONT_RAISE\",\r\n ],\r\n SHOULDER_STABILITY: [\r\n \"BAND_EXTERNAL_ROTATION\",\r\n \"BAND_INTERNAL_ROTATION\",\r\n \"BENT_ARM_LATERAL_RAISE_AND_EXTERNAL_ROTATION\",\r\n \"CABLE_EXTERNAL_ROTATION\",\r\n \"CABLE_INTERNAL_ROTATION\",\r\n \"DUMBBELL_FACE_PULL_WITH_EXTERNAL_ROTATION\",\r\n \"FLOOR_I_RAISE\",\r\n \"FLOOR_T_RAISE\",\r\n \"FLOOR_Y_RAISE\",\r\n \"INCLINE_I_RAISE\",\r\n \"INCLINE_L_RAISE\",\r\n \"INCLINE_T_RAISE\",\r\n \"INCLINE_W_RAISE\",\r\n \"INCLINE_Y_RAISE\",\r\n \"LYING_EXTERNAL_ROTATION\",\r\n \"LYING_INTERNAL_ROTATION\",\r\n \"SEATED_DUMBBELL_EXTERNAL_ROTATION\",\r\n \"SEATED_DUMBBELL_INTERNAL_ROTATION\",\r\n \"STANDING_L_RAISE\",\r\n \"SWISS_BALL_I_RAISE\",\r\n \"SWISS_BALL_T_RAISE\",\r\n \"SWISS_BALL_W_RAISE\",\r\n \"SWISS_BALL_Y_RAISE\",\r\n \"WEIGHTED_FLOOR_I_RAISE\",\r\n \"WEIGHTED_FLOOR_T_RAISE\",\r\n \"WEIGHTED_FLOOR_Y_RAISE\",\r\n \"WEIGHTED_INCLINE_I_RAISE\",\r\n \"WEIGHTED_INCLINE_L_RAISE\",\r\n \"WEIGHTED_INCLINE_T_RAISE\",\r\n \"WEIGHTED_INCLINE_W_RAISE\",\r\n \"WEIGHTED_INCLINE_Y_RAISE\",\r\n \"WEIGHTED_SWISS_BALL_I_RAISE\",\r\n \"WEIGHTED_SWISS_BALL_T_RAISE\",\r\n \"WEIGHTED_SWISS_BALL_W_RAISE\",\r\n \"WEIGHTED_SWISS_BALL_Y_RAISE\",\r\n \"_90_DEGREE_CABLE_EXTERNAL_ROTATION\",\r\n ],\r\n SHRUG: [\r\n \"BARBELL_JUMP_SHRUG\",\r\n \"BARBELL_SHRUG\",\r\n \"BARBELL_UPRIGHT_ROW\",\r\n \"BEHIND_THE_BACK_SHRUG\",\r\n \"BEHIND_THE_BACK_SMITH_MACHINE_SHRUG\",\r\n \"DUMBBELL_JUMP_SHRUG\",\r\n \"DUMBBELL_SHRUG\",\r\n \"DUMBBELL_SHRUG_WHEELCHAIR\",\r\n \"DUMBBELL_UPRIGHT_ROW\",\r\n \"INCLINE_DUMBBELL_SHRUG\",\r\n \"OVERHEAD_BARBELL_SHRUG\",\r\n \"OVERHEAD_DUMBBELL_SHRUG\",\r\n \"SCAPTION_AND_SHRUG\",\r\n \"SCAPULAR_RETRACTION\",\r\n \"SERRATUS_CHAIR_SHRUG\",\r\n \"SERRATUS_SHRUG\",\r\n \"SHRUG_ARM_DOWN_WHEELCHAIR\",\r\n \"SHRUG_ARM_MID_WHEELCHAIR\",\r\n \"SHRUG_ARM_UP_WHEELCHAIR\",\r\n \"SHRUG_WHEELCHAIR\",\r\n \"UPRIGHT_ROW\",\r\n \"WEIGHTED_SERRATUS_CHAIR_SHRUG\",\r\n \"WEIGHTED_SERRATUS_SHRUG\",\r\n \"WIDE_GRIP_BARBELL_SHRUG\",\r\n \"WIDE_GRIP_JUMP_SHRUG\",\r\n ],\r\n SIT_UP: [\r\n \"ALTERNATING_SIT_UP\",\r\n \"BENT_KNEE_V_UP\",\r\n \"BUTTERFLY_SIT_UP\",\r\n \"CROSSED_ARMS_SIT_UP\",\r\n \"CROSS_PUNCH_ROLL_UP\",\r\n \"GET_UP_SIT_UP\",\r\n \"GHD_SIT_UPS\",\r\n \"HOVERING_SIT_UP\",\r\n \"KETTLEBELL_SIT_UP\",\r\n \"MEDICINE_BALL_ALTERNATING_V_UP\",\r\n \"MEDICINE_BALL_SIT_UP\",\r\n \"MEDICINE_BALL_V_UP\",\r\n \"MODIFIED_SIT_UP\",\r\n \"NEGATIVE_SIT_UP\",\r\n \"ONE_ARM_FULL_SIT_UP\",\r\n \"RECLINING_CIRCLE\",\r\n \"REVERSE_CURL_UP\",\r\n \"RUSSIAN_TWIST_ON_SWISS_BALL\",\r\n \"SINGLE_LEG_SWISS_BALL_JACKKNIFE\",\r\n \"SIT_UP\",\r\n \"SIT_UP_TURKISH_GET_UP\",\r\n \"THE_TEASER\",\r\n \"THE_TEASER_WEIGHTED\",\r\n \"THREE_PART_ROLL_DOWN\",\r\n \"V_UP\",\r\n \"WEIGHTED_ALTERNATING_SIT_UP\",\r\n \"WEIGHTED_BENT_KNEE_V_UP\",\r\n \"WEIGHTED_BUTTERFLY_SITUP\",\r\n \"WEIGHTED_CROSSED_ARMS_SIT_UP\",\r\n \"WEIGHTED_CROSS_PUNCH_ROLL_UP\",\r\n \"WEIGHTED_GET_UP_SIT_UP\",\r\n \"WEIGHTED_HOVERING_SIT_UP\",\r\n \"WEIGHTED_RECLINING_CIRCLE\",\r\n \"WEIGHTED_REVERSE_CURL_UP\",\r\n \"WEIGHTED_RUSSIAN_TWIST_ON_SWISS_BALL\",\r\n \"WEIGHTED_SINGLE_LEG_SWISS_BALL_JACKKNIFE\",\r\n \"WEIGHTED_SIT_UP\",\r\n \"WEIGHTED_THREE_PART_ROLL_DOWN\",\r\n \"WEIGHTED_V_UP\",\r\n \"WEIGHTED_X_ABS\",\r\n \"X_ABS\",\r\n ],\r\n SLED: [\r\n \"BACKWARD_DRAG\",\r\n \"CHEST_PRESS\",\r\n \"FORWARD_DRAG\",\r\n \"LOW_PUSH\",\r\n \"PUSH\",\r\n \"ROW\",\r\n ],\r\n SLEDGE_HAMMER: [\r\n \"HAMMER_SLAM\",\r\n \"LATERAL_SWING\",\r\n ],\r\n SQUAT: [\r\n \"AIR_SQUAT\",\r\n \"ALTERNATING_BOX_DUMBBELL_STEP_UPS\",\r\n \"BACK_SQUATS\",\r\n \"BACK_SQUAT_WITH_BODY_BAR\",\r\n \"BALANCING_SQUAT\",\r\n \"BARBELL_BACK_SQUAT\",\r\n \"BARBELL_BOX_SQUAT\",\r\n \"BARBELL_FRONT_SQUAT\",\r\n \"BARBELL_HACK_SQUAT\",\r\n \"BARBELL_HALF_SQUAT\",\r\n \"BARBELL_HANG_SQUAT_SNATCH\",\r\n \"BARBELL_LATERAL_STEP_UP\",\r\n \"BARBELL_QUARTER_SQUAT\",\r\n \"BARBELL_SIFF_SQUAT\",\r\n \"BARBELL_SQUAT_SNATCH\",\r\n \"BARBELL_SQUAT_WITH_HEELS_RAISED\",\r\n \"BARBELL_STEPOVER\",\r\n \"BARBELL_STEP_UP\",\r\n \"BELT_SQUAT\",\r\n \"BENCH_SQUAT_WITH_ROTATIONAL_CHOP\",\r\n \"BODY_WEIGHT_WALL_SQUAT\",\r\n \"BOX_STEP_SQUAT\",\r\n \"BRACED_SQUAT\",\r\n \"CROSSED_ARM_BARBELL_FRONT_SQUAT\",\r\n \"CROSSOVER_DUMBBELL_STEP_UP\",\r\n \"DUMBBELL_FRONT_SQUAT\",\r\n \"DUMBBELL_OVERHEAD_SQUAT_SINGLE_ARM\",\r\n \"DUMBBELL_SPLIT_SQUAT\",\r\n \"DUMBBELL_SQUAT\",\r\n \"DUMBBELL_SQUAT_CLEAN\",\r\n \"DUMBBELL_SQUAT_SNATCH\",\r\n \"DUMBBELL_STEPOVER\",\r\n \"DUMBBELL_STEP_UP\",\r\n \"DUMBBELL_THRUSTERS\",\r\n \"ELEVATED_SINGLE_LEG_SQUAT\",\r\n \"FIGURE_FOUR_SQUATS\",\r\n \"GOBLET_SQUAT\",\r\n \"KETTLEBELL_SQUAT\",\r\n \"KETTLEBELL_SWING_OVERHEAD\",\r\n \"KETTLEBELL_SWING_WITH_FLIP_TO_SQUAT\",\r\n \"LATERAL_DUMBBELL_STEP_UP\",\r\n \"LEG_PRESS\",\r\n \"MEDICINE_BALL_SQUAT\",\r\n \"ONE_LEGGED_SQUAT\",\r\n \"OVERHEAD_BARBELL_SQUAT\",\r\n \"OVERHEAD_DUMBBELL_SQUAT\",\r\n \"OVERHEAD_SQUAT\",\r\n \"PARTIAL_SINGLE_LEG_SQUAT\",\r\n \"PILATES_PLIE_SQUATS_PARALLEL_TURNED_OUT_FLAT_AND_HEELS\",\r\n \"PISTOL_SQUAT\",\r\n \"PLIE_SLIDES\",\r\n \"PLIE_SQUAT\",\r\n \"PRISONER_SQUAT\",\r\n \"RELEVE_STRAIGHT_LEG_AND_KNEE_BENT_WITH_ONE_LEG_VARIATION\",\r\n \"RUCK_BACK_SQUAT\",\r\n \"RUCK_FRONT_SQUAT\",\r\n \"RUCK_OVERHEAD_SQUAT\",\r\n \"SAFETY_BAR_SQUAT\",\r\n \"SINGLE_LEG_BENCH_GET_UP\",\r\n \"SINGLE_LEG_BENCH_SQUAT\",\r\n \"SINGLE_LEG_SQUAT_ON_SWISS_BALL\",\r\n \"SQUAT\",\r\n \"SQUATS_WITH_BAND\",\r\n \"SQUAT_AMERICAN_SWING\",\r\n \"SQUAT_AND_SIDE_KICK\",\r\n \"SQUAT_JUMPS_IN_N_OUT\",\r\n \"STAGGERED_SQUAT\",\r\n \"STEP_UP\",\r\n \"SUITCASE_SQUATS\",\r\n \"SUMO_SQUAT\",\r\n \"SUMO_SQUAT_SLIDE_IN\",\r\n \"SUMO_SQUAT_TO_HIGH_PULL\",\r\n \"SUMO_SQUAT_TO_STAND\",\r\n \"SUMO_SQUAT_WITH_ROTATION\",\r\n \"SWISS_BALL_BODY_WEIGHT_WALL_SQUAT\",\r\n \"THRUSTERS\",\r\n \"UNEVEN_SQUAT\",\r\n \"WAIST_SLIMMING_SQUAT\",\r\n \"WALL_BALL\",\r\n \"WALL_BALL_SQUAT_AND_PRESS\",\r\n \"WEIGHTED_BACK_SQUATS\",\r\n \"WEIGHTED_BALANCING_SQUAT\",\r\n \"WEIGHTED_BENCH_SQUAT_WITH_ROTATIONAL_CHOP\",\r\n \"WEIGHTED_BOX_STEP_SQUAT\",\r\n \"WEIGHTED_ELEVATED_SINGLE_LEG_SQUAT\",\r\n \"WEIGHTED_FIGURE_FOUR_SQUATS\",\r\n \"WEIGHTED_PARTIAL_SINGLE_LEG_SQUAT\",\r\n \"WEIGHTED_PISTOL_SQUAT\",\r\n \"WEIGHTED_PLIE_SLIDES\",\r\n \"WEIGHTED_PLIE_SQUAT\",\r\n \"WEIGHTED_PRISONER_SQUAT\",\r\n \"WEIGHTED_SINGLE_LEG_BENCH_GET_UP\",\r\n \"WEIGHTED_SINGLE_LEG_BENCH_SQUAT\",\r\n \"WEIGHTED_SINGLE_LEG_SQUAT_ON_SWISS_BALL\",\r\n \"WEIGHTED_SQUAT\",\r\n \"WEIGHTED_STAGGERED_SQUAT\",\r\n \"WEIGHTED_STEP_UP\",\r\n \"WEIGHTED_SUMO_SQUAT_SLIDE_IN\",\r\n \"WEIGHTED_SUMO_SQUAT_TO_STAND\",\r\n \"WEIGHTED_SUMO_SQUAT_WITH_ROTATION\",\r\n \"WEIGHTED_SWISS_BALL_WALL_SQUAT\",\r\n \"WEIGHTED_UNEVEN_SQUAT\",\r\n \"WEIGHTED_WALL_SQUAT\",\r\n \"WIDE_STANCE_BARBELL_SQUAT\",\r\n \"WIDE_STANCE_GOBLET_SQUAT\",\r\n \"ZERCHER_SQUAT\",\r\n ],\r\n STAIR_STEPPER: [\r\n \"STAIR_STEPPER\",\r\n ],\r\n SUSPENSION: [\r\n \"CHEST_FLY\",\r\n \"CHEST_PRESS\",\r\n \"CRUNCH\",\r\n \"CURL\",\r\n \"DIP\",\r\n \"FACE_PULL\",\r\n \"GLUTE_BRIDGE\",\r\n \"HAMSTRING_CURL\",\r\n \"HIP_DROP\",\r\n \"KNEE_DRIVE_JUMP\",\r\n \"KNEE_TO_CHEST\",\r\n \"LAT_PULLOVER\",\r\n \"LUNGE\",\r\n \"MOUNTAIN_CLIMBER\",\r\n \"PENDULUM\",\r\n \"PIKE\",\r\n \"PLANK\",\r\n \"POWER_PULL\",\r\n \"PULL_UP\",\r\n \"PUSH_UP\",\r\n \"REVERSE_MOUNTAIN_CLIMBER\",\r\n \"REVERSE_PLANK\",\r\n \"ROLLOUT\",\r\n \"ROW\",\r\n \"SIDE_LUNGE\",\r\n \"SIDE_PLANK\",\r\n \"SINGLE_LEG_DEADLIFT\",\r\n \"SINGLE_LEG_SQUAT\",\r\n \"SIT_UP\",\r\n \"SQUAT\",\r\n \"SQUAT_JUMP\",\r\n \"TRICEP_PRESS\",\r\n \"Y_FLY\",\r\n ],\r\n TIRE: [\r\n \"FLIP\",\r\n ],\r\n TOTAL_BODY: [\r\n \"BARBELL_BURPEE\",\r\n \"BURPEE\",\r\n \"BURPEE_BOX_JUMP\",\r\n \"BURPEE_BOX_JUMP_OVER\",\r\n \"BURPEE_BOX_JUMP_STEP_UP_OVER\",\r\n \"BURPEE_WHEELCHAIR\",\r\n \"HIGH_PULL_BURPEE\",\r\n \"LATERAL_BARBELL_BURPEE\",\r\n \"MAN_MAKERS\",\r\n \"ONE_ARM_BURPEE\",\r\n \"SQUAT_PLANK_PUSH_UP\",\r\n \"SQUAT_THRUSTS\",\r\n \"STANDING_T_ROTATION_BALANCE\",\r\n \"TOTAL_BODY_BURPEE_OVER_BAR\",\r\n \"WEIGHTED_BURPEE\",\r\n \"WEIGHTED_BURPEE_BOX_JUMP\",\r\n \"WEIGHTED_SQUAT_PLANK_PUSH_UP\",\r\n \"WEIGHTED_SQUAT_THRUSTS\",\r\n \"WEIGHTED_STANDING_T_ROTATION_BALANCE\",\r\n ],\r\n TRICEPS_EXTENSION: [\r\n \"ALTERNATING_DUMBBELL_LYING_TRICEPS_EXTENSION\",\r\n \"BENCH_DIP\",\r\n \"BODY_WEIGHT_DIP\",\r\n \"CABLE_KICKBACK\",\r\n \"CABLE_LYING_TRICEPS_EXTENSION\",\r\n \"CABLE_OVERHEAD_TRICEPS_EXTENSION\",\r\n \"DUMBBELL_KICKBACK\",\r\n \"DUMBBELL_KICKBACK_WHEELCHAIR\",\r\n \"DUMBBELL_LYING_TRICEPS_EXTENSION\",\r\n \"EZ_BAR_OVERHEAD_TRICEPS_EXTENSION\",\r\n \"INCLINE_DIP\",\r\n \"INCLINE_EZ_BAR_LYING_TRICEPS_EXTENSION\",\r\n \"LYING_DUMBBELL_PULLOVER_TO_EXTENSION\",\r\n \"LYING_EZ_BAR_TRICEPS_EXTENSION\",\r\n \"LYING_TRICEPS_EXTENSION_TO_CLOSE_GRIP_BENCH_PRESS\",\r\n \"OVERHEAD_DUMBBELL_TRICEPS_EXTENSION\",\r\n \"OVERHEAD_DUMBBELL_TRICEPS_EXTENSION_WHEELCHAIR\",\r\n \"RECLINING_TRICEPS_PRESS\",\r\n \"REVERSE_GRIP_PRESSDOWN\",\r\n \"REVERSE_GRIP_TRICEPS_PRESSDOWN\",\r\n \"ROPE_PRESSDOWN\",\r\n \"SEATED_BARBELL_OVERHEAD_TRICEPS_EXTENSION\",\r\n \"SEATED_DUMBBELL_OVERHEAD_TRICEPS_EXTENSION\",\r\n \"SEATED_EZ_BAR_OVERHEAD_TRICEPS_EXTENSION\",\r\n \"SEATED_SINGLE_ARM_OVERHEAD_DUMBBELL_EXTENSION\",\r\n \"SINGLE_ARM_DUMBBELL_OVERHEAD_TRICEPS_EXTENSION\",\r\n \"SINGLE_DUMBBELL_SEATED_OVERHEAD_TRICEPS_EXTENSION\",\r\n \"SINGLE_LEG_BENCH_DIP_AND_KICK\",\r\n \"SINGLE_LEG_DIP\",\r\n \"STATIC_LYING_TRICEPS_EXTENSION\",\r\n \"SUSPENDED_DIP\",\r\n \"SWISS_BALL_DUMBBELL_LYING_TRICEPS_EXTENSION\",\r\n \"SWISS_BALL_EZ_BAR_LYING_TRICEPS_EXTENSION\",\r\n \"SWISS_BALL_EZ_BAR_OVERHEAD_TRICEPS_EXTENSION\",\r\n \"TABLETOP_DIP\",\r\n \"TRICEPS_EXTENSION_ON_FLOOR\",\r\n \"TRICEPS_PRESS\",\r\n \"TRICEPS_PRESSDOWN\",\r\n \"WEIGHTED_BENCH_DIP\",\r\n \"WEIGHTED_DIP\",\r\n \"WEIGHTED_INCLINE_DIP\",\r\n \"WEIGHTED_SINGLE_LEG_BENCH_DIP_AND_KICK\",\r\n \"WEIGHTED_SINGLE_LEG_DIP\",\r\n \"WEIGHTED_SUSPENDED_DIP\",\r\n \"WEIGHTED_TABLETOP_DIP\",\r\n ],\r\n WARM_UP: [\r\n \"ACTIVE_FROG\",\r\n \"ANKLE_CIRCLES\",\r\n \"ANKLE_DORSIFLEXION_WITH_BAND\",\r\n \"ANKLE_INTERNAL_ROTATION\",\r\n \"ANKLE_LUNGES\",\r\n \"ANKLE_STRETCH\",\r\n \"ARM_CIRCLES\",\r\n \"BACK_ROLL_FOAM_ROLLER\",\r\n \"BEAR_CRAWL\",\r\n \"BENT_OVER_REACH_TO_SKY\",\r\n \"BICEPS_STRETCH\",\r\n \"CAT_CAMEL\",\r\n \"CHEST_OPENERS\",\r\n \"ELBOW_TO_FOOT_LUNGE\",\r\n \"FORWARD_AND_BACKWARD_LEG_SWINGS\",\r\n \"GLUTES_STRETCH\",\r\n \"GROINERS\",\r\n \"HALF_KNEELING_ARM_ROTATION\",\r\n \"HIP_CIRCLES\",\r\n \"INVERTED_HAMSTRING_STRETCH\",\r\n \"LATERAL_DUCK_UNDER\",\r\n \"LATISSIMUS_DORSI_FOAM_ROLL\",\r\n \"NECK_ROTATIONS\",\r\n \"NECK_ROTATIONS_WHEELCHAIR\",\r\n \"NECK_TILTS\",\r\n \"NINETY_NINETY_HIP_SWITCH\",\r\n \"OPPOSITE_ARM_AND_LEG_BALANCE\",\r\n \"QUADRUPED_ROCKING\",\r\n \"REACH_ROLL_AND_LIFT\",\r\n \"REVERSE_T_HIP_OPENER\",\r\n \"SHOULDER_CIRCLES\",\r\n \"SHOULDER_ROLLS\",\r\n \"SHOULDER_SWEEPS\",\r\n \"SIDE_TO_SIDE_LEG_SWINGS\",\r\n \"SLEEPER_STRETCH\",\r\n \"SLIDE_OUT\",\r\n \"STANDING_HAMSTRING_STRETCH\",\r\n \"STRETCH_90_90\",\r\n \"STRETCH_ABS\",\r\n \"STRETCH_BUTTERFLY\",\r\n \"STRETCH_CALF\",\r\n \"STRETCH_CAT_COW\",\r\n \"STRETCH_CHILDS_POSE\",\r\n \"STRETCH_COBRA\",\r\n \"STRETCH_FOREARMS\",\r\n \"STRETCH_FORWARD_GLUTES\",\r\n \"STRETCH_FRONT_SPLIT\",\r\n \"STRETCH_HAMSTRING\",\r\n \"STRETCH_HIP_FLEXOR_AND_QUAD\",\r\n \"STRETCH_LAT\",\r\n \"STRETCH_LEVATOR_SCAPULAE\",\r\n \"STRETCH_LUNGE_WITH_SPINAL_TWIST\",\r\n \"STRETCH_LUNGING_HIP_FLEXOR\",\r\n \"STRETCH_LYING_ABDUCTION\",\r\n \"STRETCH_LYING_IT_BAND\",\r\n \"STRETCH_LYING_KNEE_TO_CHEST\",\r\n \"STRETCH_LYING_PIRIFORMIS\",\r\n \"STRETCH_LYING_SPINAL_TWIST\",\r\n \"STRETCH_NECK\",\r\n \"STRETCH_OBLIQUES\",\r\n \"STRETCH_OVER_UNDER_SHOULDER\",\r\n \"STRETCH_PECTORAL\",\r\n \"STRETCH_PIGEON_POSE\",\r\n \"STRETCH_PIRIFORMIS\",\r\n \"STRETCH_QUAD\",\r\n \"STRETCH_SCORPION\",\r\n \"STRETCH_SHOULDER\",\r\n \"STRETCH_SIDE\",\r\n \"STRETCH_SIDE_LUNGE\",\r\n \"STRETCH_SIDE_SPLIT\",\r\n \"STRETCH_STANDING_IT_BAND\",\r\n \"STRETCH_STRADDLE\",\r\n \"STRETCH_TRICEPS\",\r\n \"STRETCH_WALL_CHEST_AND_SHOULDER\",\r\n \"SWISS_BALL_HIP_CROSSOVER\",\r\n \"SWISS_BALL_REACH_ROLL_AND_LIFT\",\r\n \"SWISS_BALL_WINDSHIELD_WIPERS\",\r\n \"THORACIC_ROTATION\",\r\n \"THREE_WAY_ANKLE_MOBILIZATION\",\r\n \"TRICEPS_STRETCH\",\r\n \"TRICEPS_STRETCH_WHEELCHAIR\",\r\n \"UPPER_BACK_STRETCH\",\r\n \"UPPER_BACK_STRETCH_WHEELCHAIR\",\r\n \"WALKING_HIGH_KICKS\",\r\n \"WALKING_HIGH_KNEES\",\r\n \"WALKING_KNEE_HUGS\",\r\n \"WALKING_LEG_CRADLES\",\r\n \"WALKOUT\",\r\n \"WALKOUT_FROM_PUSH_UP_POSITION\",\r\n ],\r\n} as const satisfies Partial<Record<ExerciseCategory, readonly string[]>>;\r\n\r\n/** A category that has at least one named exercise — every key of {@link EXERCISES}. */\r\nexport type ExerciseCategoryWithNames = keyof typeof EXERCISES;\r\n\r\n/** The exercise names valid for one category. */\r\nexport type ExerciseName<C extends ExerciseCategoryWithNames> = (typeof EXERCISES)[C][number];\r\n\r\n/**\r\n * A `{ category, name }` pair, checked at compile time.\r\n *\r\n * Pass the result straight to a builder step's `exercise` option. At runtime this is the identity\r\n * function — all the work happens in the type system, so it costs nothing:\r\n *\r\n * ```ts\r\n * .interval({ reps: 10, exercise: exercise(\"BENCH_PRESS\", \"BARBELL_BENCH_PRESS\") })\r\n * ```\r\n */\r\nexport function exercise<C extends ExerciseCategoryWithNames, N extends ExerciseName<C>>(\r\n category: C,\r\n name: N,\r\n): { category: C; name: N } {\r\n return { category, name };\r\n}\r\n\r\n/**\r\n * Whether `name` is a valid exercise for `category`, checked at runtime.\r\n *\r\n * For names that only exist as strings at runtime — read from a database, a form, or a user —\r\n * where {@link exercise}'s compile-time check cannot reach. A `false` here is the upload that\r\n * would otherwise have stored an empty `exerciseName`.\r\n */\r\nexport function isExerciseName(category: string, name: string): boolean {\r\n // `Object.hasOwn`, not a bare index: `isExerciseName(\"constructor\", ...)` would otherwise reach\r\n // `Object.prototype.constructor` and throw on `.includes`, and `\"toString\"` would be reported\r\n // as a valid exercise for every category.\r\n if (!Object.hasOwn(EXERCISES, category)) return false;\r\n const names = (EXERCISES as Record<string, readonly string[]>)[category]!;\r\n return names.includes(name);\r\n}\r\n","/**\n * A workout as a person reads it. Presentation only: it reads the built `WorkoutInput`, so what\n * the user confirms in a preview is exactly what would be uploaded.\n */\nimport type { WorkoutInput } from \"garminconnect-js\";\n\ntype Doc = Record<string, unknown>;\n\nconst key = (ref: unknown, field: string): string | undefined => {\n const v = (ref as Doc | null | undefined)?.[field];\n return typeof v === \"string\" ? v : undefined;\n};\nconst num = (v: unknown): number | undefined => (typeof v === \"number\" ? v : undefined);\nconst words = (k: string) => k.toLowerCase().replace(/[._]+/g, \" \");\nconst trim = (n: number) => String(+n.toFixed(1));\n\nexport function clock(seconds: number): string {\n const s = Math.round(seconds);\n const h = Math.floor(s / 3600);\n const m = Math.floor((s % 3600) / 60);\n const r = String(s % 60).padStart(2, \"0\");\n return h > 0 ? `${h}:${String(m).padStart(2, \"0\")}:${r}` : `${m}:${r}`;\n}\n\nconst metres = (m: number) => (m >= 1000 ? `${+(m / 1000).toFixed(2)} km` : `${trim(m)} m`);\n/** Seconds per `unitMetres` at a speed in m/s, as m:ss. */\nconst pace = (metresPerSecond: number, unitMetres: number) => clock(unitMetres / metresPerSecond);\nconst MILE_METRES = 1609.344;\n\nconst STEP_LABEL: Record<string, string> = {\n warmup: \"Warm-up\",\n cooldown: \"Cool-down\",\n interval: \"Interval\",\n recovery: \"Recovery\",\n rest: \"Rest\",\n main: \"Main\",\n other: \"Other\",\n};\n\nfunction end(step: Doc): string {\n const kind = key(step[\"endCondition\"], \"conditionTypeKey\");\n const v = num(step[\"endConditionValue\"]) ?? 0;\n switch (kind) {\n case \"time\":\n return clock(v);\n case \"distance\":\n return metres(v);\n case \"lap.button\":\n return \"until lap button\";\n case \"reps\":\n return `${v} reps`;\n case \"fixed.rest\":\n return `${clock(v)} rest`;\n case \"calories\":\n return `${v} kcal`;\n case \"heart.rate\":\n return `until heart rate ${v} bpm`;\n case \"power\":\n return `until ${v} W`;\n case \"fixed.repetition\":\n return `${v} lengths`;\n default:\n return kind ?? \"no end condition\";\n }\n}\n\nfunction target(step: Doc, secondary: boolean): string | undefined {\n const f = (primary: string, second: string) => step[secondary ? second : primary];\n const type = key(f(\"targetType\", \"secondaryTargetType\"), \"workoutTargetTypeKey\");\n const one = num(f(\"targetValueOne\", \"secondaryTargetValueOne\"));\n const two = num(f(\"targetValueTwo\", \"secondaryTargetValueTwo\"));\n const zone = num(f(\"zoneNumber\", \"secondaryZoneNumber\"));\n const range = (unit: string) => (one !== undefined && two !== undefined ? `${trim(one)}–${trim(two)} ${unit}` : undefined);\n switch (type) {\n case undefined:\n case \"no.target\":\n return undefined;\n case \"pace.zone\":\n // Garmin keeps only the speeds, not the unit the user asked in, so show both.\n return one !== undefined && two !== undefined\n ? `${pace(one, 1000)}–${pace(two, 1000)} /km (${pace(one, MILE_METRES)}–${pace(two, MILE_METRES)} /mi)`\n : undefined;\n case \"speed.zone\":\n return range(\"m/s\");\n case \"heart.rate.zone\":\n return zone !== undefined ? `heart-rate zone ${zone}` : range(\"bpm\");\n case \"power.zone\":\n return zone !== undefined ? `power zone ${zone}` : range(\"W\");\n case \"cadence\":\n return range(\"rpm\");\n case \"grade\":\n return range(\"% grade\");\n case \"resistance\":\n return range(\"resistance\");\n case \"swim.css.offset\":\n return one !== undefined ? `CSS ${one >= 0 ? \"+\" : \"\"}${one} s` : undefined;\n default:\n return words(type);\n }\n}\n\nfunction stepLine(step: Doc): string {\n const parts = [`${STEP_LABEL[key(step[\"stepType\"], \"stepTypeKey\") ?? \"\"] ?? \"Step\"}: ${end(step)}`];\n const primary = target(step, false);\n const second = target(step, true);\n if (primary) parts.push(`@ ${primary}`);\n if (second) parts.push(`+ ${second}`);\n const exercise = key(step, \"exerciseName\") ?? key(step, \"category\");\n if (exercise) parts.push(words(exercise));\n const weight = num(step[\"weightValue\"]);\n if (weight !== undefined) parts.push(`${trim(weight)} kg`);\n for (const [field, k] of [[\"strokeType\", \"strokeTypeKey\"], [\"drillType\", \"drillTypeKey\"], [\"equipmentType\", \"equipmentTypeKey\"]] as const) {\n const v = key(step[field], k);\n if (v) parts.push(words(v));\n }\n const note = key(step, \"description\");\n if (note) parts.push(`\"${note}\"`);\n return parts.join(\" · \");\n}\n\nfunction lines(steps: Doc[], indent: string, out: string[]): void {\n steps.forEach((step, i) => {\n const n = `${indent}${i + 1}. `;\n if (step[\"type\"] === \"RepeatGroupDTO\") {\n const times = num(step[\"numberOfIterations\"]);\n out.push(`${n}${times !== undefined ? `Repeat ${times}×` : `Repeat for ${clock(num(step[\"endConditionValue\"]) ?? 0)}`}:`);\n lines(step[\"workoutSteps\"] as Doc[], `${indent} `, out);\n } else {\n out.push(`${n}${stepLine(step)}`);\n }\n });\n}\n\nexport function summarizeWorkout(workout: WorkoutInput): string {\n const doc = workout as unknown as Doc;\n const sport = key(doc[\"sportType\"], \"sportTypeKey\") ?? \"unknown sport\";\n const pool = num(doc[\"poolLength\"]);\n const poolUnit = key(doc[\"poolLengthUnit\"], \"unitKey\") === \"yard\" ? \"yd\" : \"m\";\n const out = [`${workout.workoutName} — ${words(sport)}${pool !== undefined ? `, ${pool} ${poolUnit} pool` : \"\"}`];\n const segments = doc[\"workoutSegments\"] as Doc[];\n if (segments.length === 1) {\n lines(segments[0]![\"workoutSteps\"] as Doc[], \"\", out);\n } else {\n segments.forEach((segment, i) => {\n out.push(`Leg ${i + 1}: ${words(key(segment[\"sportType\"], \"sportTypeKey\") ?? \"?\")}`);\n lines(segment[\"workoutSteps\"] as Doc[], \" \", out);\n });\n }\n return out.join(\"\\n\");\n}\n","import type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { WORKOUT_EXERCISE_CATEGORIES, WORKOUT_SPEC_JSON_SCHEMA, workoutFromSpec, type WorkoutInput } from \"garminconnect-js\";\nimport { EXERCISES } from \"garminconnect-js/exercises\";\nimport { textResult } from \"./results.js\";\nimport type { ToolFactory } from \"./server.js\";\nimport { summarizeWorkout } from \"./summary.js\";\n\n// The spec schema nests under `spec`; its $defs must sit at the TOOL root for \"#/$defs/…\" refs.\nconst { $schema: _schema, $defs, ...SPEC } = WORKOUT_SPEC_JSON_SCHEMA;\n\nfunction specInput(extra: Record<string, object> = {}): Tool[\"inputSchema\"] {\n return {\n type: \"object\",\n properties: { ...extra, spec: SPEC },\n required: [...Object.keys(extra), \"spec\"],\n additionalProperties: false,\n $defs,\n };\n}\n\nconst build = (input: Record<string, unknown>): WorkoutInput => workoutFromSpec(input[\"spec\"], EXERCISES);\nconst asJson = (w: WorkoutInput) => w as unknown as Record<string, unknown>;\n\nconst UNITS = \"Paces are minutes as decimals (4:30 = 4.5), distances metres, times seconds.\";\n\nconst CATEGORY_SET = new Set<string>(WORKOUT_EXERCISE_CATEGORIES);\n\n/**\n * Resolves a caller-supplied category against `WORKOUT_EXERCISE_CATEGORIES`. Categories are\n * SCREAMING_SNAKE_CASE (`\"SQUAT\"`), and a model or a human is more likely to type `\"squat\"`, so a\n * case miss is corrected rather than rejected outright. Returns `null` only when even the\n * upper-cased form isn't a real category.\n */\nexport function resolveExerciseCategory(category: string): string | null {\n if (CATEGORY_SET.has(category)) return category;\n const upper = category.toUpperCase();\n return CATEGORY_SET.has(upper) ? upper : null;\n}\n\nexport function searchExercises(query: string, category?: string, limit = 25): string[] {\n const words = query.toUpperCase().split(/[^A-Z0-9]+/).filter(Boolean);\n if (words.length === 0 && !category) return [];\n const joined = words.join(\"_\");\n const hits: { line: string; nameExact: number; catExact: number; score: number }[] = [];\n for (const [cat, names] of Object.entries(EXERCISES) as [string, readonly string[]][]) {\n if (category && cat !== category) continue;\n for (const name of names) {\n const parts = name.split(\"_\").filter(Boolean);\n const matched = words.filter((w) => parts.some((p) => p.startsWith(w))).length;\n if (words.length > 0 && matched === 0) continue;\n hits.push({\n line: `${cat} / ${name}`,\n nameExact: name === joined ? 1 : 0,\n catExact: cat === joined ? 1 : 0,\n score: matched * 100 - parts.length,\n });\n }\n }\n return hits\n .sort((a, b) => b.nameExact - a.nameExact || b.catExact - a.catExact || b.score - a.score || a.line.localeCompare(b.line))\n .slice(0, limit)\n .map((h) => h.line);\n}\n\nexport const workoutTools: ToolFactory = ({ session }) => [\n {\n tool: {\n name: \"preview_workout\",\n description:\n \"Check a workout and show it in readable form WITHOUT saving anything. Always call this first, show the user \" +\n `the result, and wait for them to confirm before create_workout. ${UNITS}`,\n inputSchema: specInput(),\n annotations: { title: \"Preview workout\", readOnlyHint: true, openWorldHint: false },\n },\n run: async (input) =>\n textResult(\n `${summarizeWorkout(build(input))}\\n\\nNothing has been saved. If the user confirms, call create_workout with the same spec.`,\n ),\n },\n {\n tool: {\n name: \"create_workout\",\n description:\n \"Save a workout to the user's Garmin Connect workout library. Only after the user has confirmed a \" +\n \"preview_workout of the same spec. Look exercise names up with search_exercises first; an unknown name is \" +\n \"rejected. Afterwards, schedule_workout (if available) puts it on the calendar and push_workout_to_device \" +\n `(if available) sends it to the watch. ${UNITS}`,\n inputSchema: specInput(),\n annotations: { title: \"Create workout\", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },\n },\n run: async (input) => {\n const workout = build(input);\n const created = await (await session.get()).uploadWorkout(asJson(workout));\n const id = (created as { workoutId?: unknown } | null)?.workoutId;\n const idLabel = typeof id === \"string\" || typeof id === \"number\" ? ` ${id}` : \"\";\n return textResult(`Created workout${idLabel}.\\n\\n${summarizeWorkout(workout)}`);\n },\n },\n {\n tool: {\n name: \"update_workout\",\n description:\n \"Replace an existing workout with a new spec. This OVERWRITES the whole workout; confirm with the user first, \" +\n `ideally after preview_workout. ${UNITS}`,\n inputSchema: specInput({ workoutId: { type: [\"integer\", \"string\"], description: \"From get_workouts or create_workout\" } }),\n annotations: { title: \"Update workout\", readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: true },\n },\n run: async (input) => {\n const workout = build(input);\n const id = input[\"workoutId\"] as number | string;\n await (await session.get()).updateWorkout(id, asJson(workout));\n return textResult(`Updated workout ${String(id)}.\\n\\n${summarizeWorkout(workout)}`);\n },\n },\n {\n tool: {\n name: \"search_exercises\",\n description:\n \"Find Garmin exercise names for strength, HIIT, cardio, yoga, pilates and mobility steps. Returns \" +\n \"CATEGORY / NAME lines; use them as exercise: { category, name }.\",\n inputSchema: {\n type: \"object\",\n properties: {\n query: { type: \"string\", description: 'Words to look for, e.g. \"back squat\" or \"push up\"' },\n category: { enum: [...WORKOUT_EXERCISE_CATEGORIES], description: \"Only search this category\" },\n },\n required: [\"query\"],\n additionalProperties: false,\n },\n annotations: { title: \"Search exercises\", readOnlyHint: true, openWorldHint: false },\n },\n run: async (input) => {\n const query = typeof input[\"query\"] === \"string\" ? input[\"query\"] : \"\";\n const rawCategory = input[\"category\"];\n let category: string | undefined;\n if (typeof rawCategory === \"string\") {\n const resolved = resolveExerciseCategory(rawCategory);\n if (resolved === null) {\n return textResult(\n `Unknown category \"${rawCategory}\". Valid categories: ${WORKOUT_EXERCISE_CATEGORIES.join(\", \")}`,\n );\n }\n category = resolved;\n }\n const hits = searchExercises(query, category);\n return textResult(\n hits.length > 0 ? hits.join(\"\\n\") : \"No matching exercises. Try fewer or different words, or a category alone (e.g. SQUAT).\",\n );\n },\n },\n];\n","import { methodTools } from \"./method-tools.js\";\nimport type { ToolFactory } from \"./server.js\";\nimport { workoutTools } from \"./workout-tools.js\";\n\n/** Every tool the server exposes, in listing order: the hand-written workout tools first. */\nexport const TOOL_FACTORIES: readonly ToolFactory[] = [workoutTools, methodTools];\n"],"mappings":"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AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ;AAAA,EACF;AAAA,EACA,cAAc;AAAA,IACZ;AAAA,EACF;AAAA,EACA,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,UAAU;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,YAAY;AAAA,IACV;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,WAAW;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,WAAW;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,gBAAgB;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,YAAY;AAAA,IACV;AAAA,EACF;AAAA,EACA,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,UAAU;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,WAAW;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,cAAc;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,KAAK;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,KAAK;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,YAAY;AAAA,IACV;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,gBAAgB;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,oBAAoB;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb;AAAA,IACA;AAAA,EACF;AAAA,EACA,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb;AAAA,EACF;AAAA,EACA,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ;AAAA,EACF;AAAA,EACA,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,mBAAmB;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AC96DA,IAAM,MAAM,CAACC,MAAc,UAAsC;AAC/D,QAAM,IAAKA,OAAiC,KAAK;AACjD,SAAO,OAAO,MAAM,WAAW,IAAI;AACrC;AACA,IAAM,MAAM,CAAC,MAAo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","names":["pair","path","key","target","key","lower","sleep","path","ticket","path","text","key","key","target","end","path","end","path","MAX_PAGINATED_REQUESTS","end","power","key","heartRate","list","end","end","MS_PER_DAY","toUtcMidnight","daysBetween","version","key","list","end","key","path","end","version","key","range","zone","build","path","key","words","pace","login","mkdir","readFile","writeFile","os","path","target","text","at","toolName","ref","target","zone","range","exercise","words","login"]}