From 46c0af699a7b7ec3688fc58435e26d4eda0d6d6b Mon Sep 17 00:00:00 2001 From: Joshua Su Date: Thu, 27 Aug 2026 00:08:57 +0800 Subject: [PATCH 1/2] fix(client): use China region locale defaults --- README.md | 4 ++-- src/client/fitdays-client.ts | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 067a32a..8b4985f 100644 --- a/README.md +++ b/README.md @@ -80,8 +80,8 @@ new FitDaysClient(opts?: ClientOptions) | ------------- | -------------------------------- | ---------------------------------------------------------- | | `region` | `'us'` | `'us'` \| `'eu'` \| `'cn'` — picks the API host | | `baseUrl` | derived from `region` | overrides the host (useful for tests or new hosts) | -| `country` | `'US'` | sent as the `country` query param | -| `language` | `'en'` | sent as the `language` query param | +| `country` | `'CN'` for `cn`, otherwise `'US'` | sent as the `country` query param | +| `language` | `'zh'` for `cn`, otherwise `'en'` | sent as the `language` query param | | `deviceModel` | `'AndroidSDKbuiltforarm64-6.0'` | sent as the `device_model` query param | | `clientId` | generated (uppercase MD5 of UUID) | identifies the client "device" | | `fetchImpl` | `globalThis.fetch` | inject for tests or to use `undici` / `node-fetch` | diff --git a/src/client/fitdays-client.ts b/src/client/fitdays-client.ts index dcd6b3e..5ebdba7 100644 --- a/src/client/fitdays-client.ts +++ b/src/client/fitdays-client.ts @@ -26,9 +26,10 @@ export class FitDaysClient { private readonly fetchImpl: typeof fetch constructor(opts: ClientOptions = {}) { - this.baseUrl = (opts.baseUrl ?? REGION_HOSTS[opts.region ?? 'us']).replace(/\/$/, '') - this.country = opts.country ?? 'US' - this.language = opts.language ?? 'en' + const region = opts.region ?? 'us' + this.baseUrl = (opts.baseUrl ?? REGION_HOSTS[region]).replace(/\/$/, '') + this.country = opts.country ?? (region === 'cn' ? 'CN' : 'US') + this.language = opts.language ?? (region === 'cn' ? 'zh' : 'en') this.deviceModel = opts.deviceModel ?? DEFAULT_DEVICE_MODEL this.clientId = opts.clientId ?? newClientId() this.fetchImpl = opts.fetchImpl ?? fetch From 415e735137d00d4031e518965cb8ccce90884862 Mon Sep 17 00:00:00 2001 From: Rodrigo Roque Date: Mon, 7 Sep 2026 17:40:42 -0300 Subject: [PATCH 2/2] refactor(client): table the per-region locale defaults Keep the country and language defaults next to REGION_HOSTS in a REGION_LOCALES constant instead of inline region checks in the constructor, export the RegionLocale type, and cover the cn and eu defaults with tests. --- src/client/fitdays-client.ts | 6 ++++-- src/constants/api.ts | 8 +++++++- src/fitdays-api.ts | 2 +- src/tests/fitdays-client.test.ts | 13 +++++++++++++ src/types/client.ts | 5 +++++ 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/client/fitdays-client.ts b/src/client/fitdays-client.ts index 5ebdba7..6c492a5 100644 --- a/src/client/fitdays-client.ts +++ b/src/client/fitdays-client.ts @@ -8,6 +8,7 @@ import { DEFAULT_DEVICE_MODEL, FULL_SYNC_WINDOW_SECONDS, REGION_HOSTS, + REGION_LOCALES, USER_AGENT, } from '../constants/api.js' import { FitDaysApiError } from '../errors/api-error.js' @@ -27,9 +28,10 @@ export class FitDaysClient { constructor(opts: ClientOptions = {}) { const region = opts.region ?? 'us' + const locale = REGION_LOCALES[region] this.baseUrl = (opts.baseUrl ?? REGION_HOSTS[region]).replace(/\/$/, '') - this.country = opts.country ?? (region === 'cn' ? 'CN' : 'US') - this.language = opts.language ?? (region === 'cn' ? 'zh' : 'en') + this.country = opts.country ?? locale.country + this.language = opts.language ?? locale.language this.deviceModel = opts.deviceModel ?? DEFAULT_DEVICE_MODEL this.clientId = opts.clientId ?? newClientId() this.fetchImpl = opts.fetchImpl ?? fetch diff --git a/src/constants/api.ts b/src/constants/api.ts index 75957ed..9bb3aec 100644 --- a/src/constants/api.ts +++ b/src/constants/api.ts @@ -1,4 +1,4 @@ -import type { Region } from '../types/client.js' +import type { Region, RegionLocale } from '../types/client.js' export const APP_VER = '1.21.0' export const DEFAULT_DEVICE_MODEL = 'AndroidSDKbuiltforarm64-6.0' @@ -10,5 +10,11 @@ export const REGION_HOSTS: Record = { us: 'https://online-us.fitdays.cn', } +export const REGION_LOCALES: Record = { + cn: { country: 'CN', language: 'zh' }, + eu: { country: 'US', language: 'en' }, + us: { country: 'US', language: 'en' }, +} + /** Default sync window (~6 years / 2160 days) used by `syncAll()`. */ export const FULL_SYNC_WINDOW_SECONDS = 186624000 diff --git a/src/fitdays-api.ts b/src/fitdays-api.ts index baf22a4..fbb5165 100644 --- a/src/fitdays-api.ts +++ b/src/fitdays-api.ts @@ -9,7 +9,7 @@ export { export { PASSWORD_SALT, SIGN_SECRET } from './constants/sign.js' export { FitDaysApiError } from './errors/api-error.js' export type { ApiResponse, LoginData } from './types/api.js' -export type { ClientOptions, Region, Session } from './types/client.js' +export type { ClientOptions, Region, RegionLocale, Session } from './types/client.js' export type { SignParams } from './types/sign.js' export type { AccountInfo, diff --git a/src/tests/fitdays-client.test.ts b/src/tests/fitdays-client.test.ts index a0804b6..bbd028c 100644 --- a/src/tests/fitdays-client.test.ts +++ b/src/tests/fitdays-client.test.ts @@ -80,6 +80,19 @@ describe('FitDaysClient — constructor', () => { assert.equal(c.session, null) }) + it('defaults country and language to the China locale for the cn region', () => { + const c = new FitDaysClient({ region: 'cn' }) + assert.equal(c.country, 'CN') + assert.equal(c.language, 'zh') + assert.equal(c.baseUrl, 'https://online.fitdays.cn') + }) + + it('keeps the US locale for the eu region', () => { + const c = new FitDaysClient({ region: 'eu' }) + assert.equal(c.country, 'US') + assert.equal(c.language, 'en') + }) + it('honours overrides', () => { const c = new FitDaysClient({ clientId: 'AAAA', diff --git a/src/types/client.ts b/src/types/client.ts index 9f63abe..080a295 100644 --- a/src/types/client.ts +++ b/src/types/client.ts @@ -10,6 +10,11 @@ export type ClientOptions = { export type Region = 'cn' | 'eu' | 'us' +export type RegionLocale = { + country: string + language: string +} + export type Session = { refreshToken?: string token: string