@flow-js/garmin-connect

中文文档
1.6.25发布于 2026/11/03MITTypeScriptCommonJS构建来源已验证近 30 天下载 4163

Makes it simple to interface with Garmin Connect to get or set any data point

原始使用文档
文档目录28 节
  1. Table of Contents
  2. Authentication
  3. Constructor
  4. Login
  5. Multi-Factor Authentication (MFA)
  6. Session Management
  7. User Data
  8. User Profile
  9. User Settings
  10. Activities
  11. Getting Activities
  12. Individual Activity Operations
  13. Activity Files
  14. Workouts
  15. Managing Workouts
  16. Workout Scheduling
  17. Export to intervals.icu
  18. Health Data
  19. Steps
  20. Sleep
  21. Weight
  22. Hydration
  23. Heart Rate
  24. Golf
  25. Gear
  26. GPX and Courses
  27. Calendar
  28. Custom Requests

Garmin Connect

This is a fork of https://github.com/Pythe1337N/garmin-connect which was inspired by https://github.com/matin/garth. Many thanks to contributors.


A JavaScript library for accessing and managing your Garmin Connect data. It comes with methods to get and set information in your Garmin account, and also supports custom requests using GET, POST, and PUT so you can cover additional needs.

This document provides detailed information about the public API methods available in the @flow-js/garmin-connect library.

Table of Contents

Authentication

Constructor

Create a new instance of the Garmin Connect client.

const { GarminConnect } = require('@flow-js/garmin-connect');

// Create a new Garmin Connect Client with credentials
const GCClient = new GarminConnect({
    username: '[email protected]',
    password: 'MySecretPassword'
});

// Alternatively, create a client using credentials from garmin.config.json
const GCClient = new GarminConnect();

You can also provide a configuration file named garmin.config.json at your project root:

{
    "username": "[email protected]",
    "password": "MySecretPassword"
}

Login

/**
 * Login to Garmin Connect with provided credentials or those set during construction
 * @param username - Optional username to override the one in credentials
 * @param password - Optional password to override the one in credentials
 * @param options - Optional login options (see MFA below)
 * @returns The GarminConnect instance for chaining
 */
async
login(
    username ? : string,
    password ? : string,
    options ? : LoginOptions
)
:
Promise < GarminConnect >

Example:

await GCClient.login();
// Or with specific credentials
await GCClient.login('[email protected]', 'MySecretPassword');

Full example: examples/example.js

Multi-Factor Authentication (MFA)

If your Garmin account has 2FA / MFA enabled, login will fail unless you supply an mfaHandler callback. When Garmin responds with MFA_REQUIRED, the library calls your handler, waits for the verification code (email or authenticator app), and completes the login.

/**
 * @property mfaHandler - Async function that resolves to the MFA verification code.
 *   Required for accounts with 2FA enabled. If MFA is required and this is omitted,
 *   login throws: "MFA required but no mfaHandler provided".
 */
interface LoginOptions {
    mfaHandler?: () => Promise<string>;
}

Example (prompt for the code in a Node.js CLI):

const readline = require('readline');
const { GarminConnect } = require('@flow-js/garmin-connect');

const promptMfaCode = () =>
    new Promise((resolve) => {
        const rl = readline.createInterface({
            input: process.stdin,
            output: process.stdout
        });
        rl.question('Enter MFA code: ', (code) => {
            rl.close();
            resolve(code);
        });
    });

const GCClient = new GarminConnect({
    username: '[email protected]',
    password: 'MySecretPassword'
});

await GCClient.login(undefined, undefined, {
    mfaHandler: promptMfaCode
});

You can also pass credentials and the MFA handler together:

await GCClient.login('[email protected]', 'MySecretPassword', {
    mfaHandler: async () => {
        // Fetch or prompt for the code (email / authenticator app)
        return '123456';
    }
});

After a successful MFA login, export the OAuth tokens (see Session Management) and reuse them with loadToken / loadTokenByFile on later runs so you do not need to enter an MFA code every time. Tokens obtained via MFA may include mfa_token and mfa_expiration_timestamp on the OAuth1 token; these are preserved across exportToken() / loadToken() round-trips.

Session Management

Export Tokens

/**
 * Exports OAuth tokens to files in the specified directory
 * @param dirPath - Directory path where token files will be saved
 */
exportTokenToFile(dirPath: string): void

Example:

GCClient.exportTokenToFile('/path/to/save/tokens');
// Creates oauth1_token.json and oauth2_token.json in the specified directory

Load Tokens from Files

/**
 * Loads OAuth tokens from files in the specified directory
 * @param dirPath - Directory path where token files are stored
 * @throws Error if directory not found
 */
loadTokenByFile(dirPath: string): void

Example:

GCClient.loadTokenByFile('/path/to/save/tokens');

Export Tokens as Object

/**
 * Exports OAuth tokens as an object
 * @returns Object containing OAuth1 and OAuth2 tokens
 * @throws Error if tokens are not found
 */
exportToken(): IGarminTokens

Load Tokens from Objects

/**
 * Loads OAuth tokens from provided token objects (e.g., from DB or localStorage)
 * @param oauth1 - OAuth1 token object
 * @param oauth2 - OAuth2 token object
 */
loadToken(oauth1: IOauth1Token, oauth2: IOauth2Token): void

Example:

const oauth1 = GCClient.client.oauth1Token;
const oauth2 = GCClient.client.oauth2Token;
// Later, use these to restore the session
GCClient.loadToken(oauth1, oauth2);

User Data

User Profile

/**
 * Retrieves the user's social profile from Garmin Connect
 * @returns User's social profile data
 */
async getUserProfile(): Promise<ISocialProfile>

Example:

const userProfile = await GCClient.getUserProfile();
console.log(userProfile.userName); // Verify login was successful

User Settings

/**
 * Retrieves the user's settings from Garmin Connect
 * @returns User settings data
 */
async getUserSettings(): Promise<IUserSettings>

Full example: examples/example.js

Activities

Getting Activities

/**
 * Retrieves a list of activities matching the specified criteria
 * @param start - Optional starting index for pagination
 * @param limit - Optional limit for pagination
 * @param activityType - Optional activity type filter
 * @param subActivityType - Optional activity subtype filter
 * @returns Array of activities matching the criteria
 */
async getActivities(
    start?: number,
    limit?: number,
    activityType?: ActivityType,
    subActivityType?: ActivitySubType
): Promise<IActivity[]>

Example:

const activities = await GCClient.getActivities(
    0,
    10,
    ActivityType.Running,
    ActivitySubType.Outdoor
);
/**
 * Counts lifetime activities
 * @returns Activity statistics including counts by type
 */
async countActivities(): Promise<ICountActivities>

Individual Activity Operations

/**
 * Retrieves a specific activity by its ID
 * @param activity - Object containing activityId
 * @returns Details of the specified activity
 * @throws Error if activityId is missing
 */
async getActivity(activity: {
    activityId: GCActivityId;
}): Promise<IActivity>

Example:

const activityDetails = await GCClient.getActivity({
    activityId: 'exampleActivityId'
});
/**
 * Deletes an activity by activityId
 * @param activity - with activityId
 * @returns void
 *
 */
async deleteActivity(activity: {
    activityId: GCActivityId;
}): Promise<void>
/**
 * Renames an activity with the given activityId to the newName.
 * @param activityId
 * @param newName
 */
async renameActivity(
    activityId: GCActivityId,
    newName: string
): Promise<void>

Activity Files

/**
 * Download activity original data file
 *
 * Use the activityId to download the original activity data. Usually this is supplied as a .zip file.
 *
 * @example
 * ```js
 * const [activity] = await GCClient.getActivities(0, 1);
 * // Directory path is optional and defaults to the current working directory.
 * // Downloads filename will be supplied by Garmin.
 * GCClient.downloadOriginalActivityData(activity, './some/path/that/exists');
 * ```
 *
 * @param activity - with activityId
 * @param dir - directory to save the file
 * @param type - 'zip' | 'gpx' | 'tcx' | 'kml' (default: 'zip')
 */
async downloadOriginalActivityData(
    activity: { activityId: GCActivityId },
    dir: string,
    type: ExportFileTypeValue = 'zip'
): Promise<void>
/**
 * Uploads an activity file
 *
 * Uploads an activity file as a new Activity. The file can be a 'gpx', 'tcx', or 'fit' file.
 * If the activity already exists, the result will have a status code of 409.
 * Note: Garmin changed the upload API in v1.4.4, the response `detailedImportResult` no longer contains the new activityId.
 *
 * @param file - Path to the activity file
 * @param format - 'fit' | 'gpx' | 'tcx'
 * @returns Response from the upload operation
 */
async uploadActivity(
    file: string,
    format: UploadFileTypeTypeValue = 'fit'
)

Example:

const upload = await GCClient.uploadActivity('./some/path/to/file.fit');
// Note: Garmin changed the upload API in v1.4.4
// const activityId = upload.detailedImportResult.successes[0].internalId; // Not working
// const uploadId = upload.detailedImportResult.uploadId;
/**
 * Uploads a photo to an activity
 * @param activityId - The ID of the activity to attach the photo to
 * @param filePath - Path to the image file to upload
 * @returns Response from the photo upload operation
 */
async uploadActivityPhoto(
    activityId: GCActivityId,
    filePath: string
): Promise<unknown>

Example:

await GCClient.uploadActivityPhoto(12345678, './my-run-photo.jpg');

Full example: examples/example-image.js

Workouts

Managing Workouts

/**
 * Gets the list of workouts
 * @param start
 * @param limit
 */
async getWorkouts(start: number, limit: number): Promise<IWorkout[]>

Full example: examples/example-intervals-icu.js

/**
 * Gets the workout detail by workoutId
 * @param workout
 * @returns workout detail - IWorkoutDetail
 */
async getWorkoutDetail(workout: {
    workoutId: string;
}): Promise<IWorkoutDetail>

Full example: examples/example-intervals-icu.js

/**
 * Creates a new workout
 *
 * Use workoutBuilder to create the workout object. See the example in [examples/example-workout.js](examples/example-workout.js) for more complex workouts.
 *
 * @param workout - workout detail
 * @returns Response from the workout creation operation
 *
 * @example
 * ```js
 * const wb = new WorkoutBuilder(
 *     WorkoutType.Running,
 *     'Workout running ' + new Date().toISOString()
 * );
 *
 * wb.addStep(
 *     new Step(
 *         StepType.Run,
 *         TimeDuration.fromSeconds(45),
 *         new NoTarget(),
 *         'Comment for the step: Run for 45 seconds'
 *     )
 * );
 *
 * GCClient.createWorkout(wb.build());
 * ```
 */
async createWorkout(workout: IWorkoutDetail)

Full example: examples/example-workout.js, examples/example-strength-workout.js

/**
 * Deletes a workout by workoutId
 * @param workout - with workoutId
 *
 * @example
 * ```js
 * const workouts = await GCClient.getWorkouts();
 * const id = workouts[0].workoutId;
 * GCClient.deleteWorkout({ workoutId: id });
 * ```
 */
async deleteWorkout(workout: { workoutId: string })
/**
 * Retrieves all workouts
 * @returns List of workouts
 */
async workouts(): Promise<Workout[]>

Workout Scheduling

/**
 * Schedule a workout by workoutId to a specific date
 *
 * To add a workout to your calendar, provide the workout id and the date to schedule it on.
 *
 * @param workout - with workoutId
 * @param scheduleDate - 'YYYY-MM-DD' format date string
 *
 * @example
 * ```js
 * const workouts = await GCClient.getWorkouts();
 * const id = workouts[0].workoutId;
 * GCClient.scheduleWorkout({ workoutId: id }, new Date('2025-12-01'));
 * ```
 */
async scheduleWorkout(
    workout: { workoutId: string },
    scheduleDate: string
)

Export to intervals.icu

Convert a Garmin workout detail into a plain-text description compatible with the intervals.icu workout builder. The workout name is omitted so you can set it separately on the intervals.icu event.

/**
 * Convert a Garmin workout detail into an intervals.icu workout description string.
 * @param workout - workout detail from getWorkoutDetail() or WorkoutBuilder.build()
 * @returns intervals.icu description (sections, steps, targets, repeats)
 */
toIntervalsIcuDescription(workout
:
IWorkoutDetail
):
string

Example:

const {
    GarminConnect,
    toIntervalsIcuDescription
} = require('@flow-js/garmin-connect');

const detail = await GCClient.getWorkoutDetail({ workoutId });
const description = toIntervalsIcuDescription(detail);
console.log(description);
// Warmup
// - Easy 10m Z2 HR
//
// Main Set 4x
// - 800mtr 5:00/km Pace
// - 400mtr Z1 HR
//
// Cooldown
// - 10m Z1 HR

See examples/example-intervals-icu.js for a full fetch-and-convert example.

Supported mappings include time and distance durations, lap press, pace / HR / power / cadence targets, section headers (Warmup, Main Set, Cooldown), and repeat groups (Main Set Nx). Strength steps and unsupported end conditions (calories, HR threshold, reps) are emitted as descriptive cue text.

Health Data

Steps

/**
 * Retrieves step count for a specific date
 * @param date - The date to get step count for, defaults to current date
 * @returns Total step count for the specified date
 * @throws Error if steps data not found for the date
 */
async getSteps(date = new Date()): Promise<number>

Example:

const totalSteps = await GCClient.getSteps(new Date('2020-03-24'));

Sleep

/**
 * Retrieves sleep data for a specific date
 * @param date - The date to get sleep data for, defaults to current date
 * @returns Sleep data for the specified date
 * @throws Error if sleep data is invalid or empty
 */
async getSleepData(date = new Date()): Promise<SleepData>
/**
 * Calculates sleep duration for a specific date
 *
 * Retrieves hours and minutes slept for a given date.
 *
 * @param date - The date to get sleep duration for, defaults to current date
 * @returns Object with hours and minutes of sleep
 * @throws Error if sleep data is missing or invalid
 *
 * @example
 * ```js
 * const detailedSleep = await GCClient.getSleepDuration(new Date('2020-03-24'));
 * console.log(`Hours: ${detailedSleep.hours}, Minutes: ${detailedSleep.minutes}`);
 * ```
 */
async getSleepDuration(
    date = new Date()
): Promise<{ hours: number; minutes: number }>

Weight

/**
 * Retrieves weight data for a specific date
 * @param date - The date to get weight data for, defaults to current date
 * @returns Weight data for the specified date
 * @throws Error if weight data is invalid or empty
 */
async getDailyWeightData(date = new Date()): Promise<WeightData>
/**
 * Retrieves weight data in pounds for a specific date
 * @param date - The date to get weight data for, defaults to current date
 * @returns Weight in pounds for the specified date
 * @throws Error if valid weight data not found for the date
 */
async getDailyWeightInPounds(date = new Date()): Promise<number>
/**
 * Updates weight data for a specific date
 *
 * Updates weight information for the specified date.
 *
 * @param date - The date for the weight data, defaults to current date
 * @param lbs - Weight value in pounds
 * @param timezone - Timezone string for correct timestamp conversion
 * @returns Response from the weight update operation
 * @throws Error if update fails
 *
 * @example
 * ```js
 * await GCClient.updateWeight(undefined, 202.9, 'America/Los_Angeles');
 * ```
 */
async updateWeight(
    date = new Date(),
    lbs: number,
    timezone: string
): Promise<UpdateWeight>

Hydration

/**
 * Retrieves hydration data in fluid ounces for a specific date
 * @param date - The date to get hydration data for, defaults to current date
 * @returns Hydration value in fluid ounces for the specified date
 * @throws Error if hydration data is invalid or empty
 */
async getDailyHydration(date = new Date()): Promise<number>
/**
 * Updates hydration log with fluid ounces for a specific date
 *
 * Adds a hydration log entry in ounces for a given date.
 *
 * @param date - The date for the hydration data, defaults to current date
 * @param valueInOz - Hydration value in fluid ounces. Accepts negative number.
 * @returns Response from the hydration update operation
 * @throws Error if update fails
 *
 * @example
 * ```js
 * const hydrationLogEntry = await GCClient.updateHydrationLogOunces(
 *     new Date('2020-03-24'),
 *     16
 * );
 * ```
 */
async updateHydrationLogOunces(
    date = new Date(),
    valueInOz: number
): Promise<WaterIntake>

Heart Rate

/**
 * Retrieves heart rate data for a specific date
 *
 * Retrieves daily heart rate data for a given date.
 *
 * @param date - The date to get heart rate data for, defaults to current date
 * @returns Heart rate data for the specified date
 * @throws Error if the operation fails
 *
 * @example
 * ```js
 * const heartRateData = await GCClient.getHeartRate(new Date('2020-03-24'));
 * ```
 */
async getHeartRate(date = new Date()): Promise<HeartRate>

Golf

/**
 * Retrieves golf summary data
 * @returns Summary of golf activities
 * @throws Error if golf summary data is invalid or empty
 */
async getGolfSummary(): Promise<GolfSummary>
/**
 * Retrieves golf scorecard for a specific round
 * @param scorecardId - ID of the scorecard to retrieve
 * @returns Golf scorecard data
 * @throws Error if golf scorecard data is invalid or empty
 */
async getGolfScorecard(scorecardId: number): Promise<GolfScorecard>

Gear

/**
 * Returns the gear data for the user.
 * @param availableGearDate - Optional date to filter the gear available at the date (format: 'YYYY-MM-DD').
 */
async getGear(availableGearDate?: string): Promise<GearData[]>
/**
 * Returns the gear data assigned with a specific activity.
 * @param activityId
 */
async getGearsForActivity(activityId: GCActivityId): Promise<GearData[]>
/**
 * Links a gear item to an activity.
 * @param activityId
 * @param gearId - uuid field from GearData
 * @return GearData - the linked gear item data
 */
async linkGearToActivity(
    activityId: GCActivityId,
    gearId: GCGearId
): Promise<GearData>
/**
 * Unlinks a gear item from an activity.
 * @param activityId
 * @param gearId - uuid field from GearData
 * @return GearData - the unlinked gear item data
 */
async unlinkGearFromActivity(
    activityId: GCActivityId,
    gearId: GCGearId
): Promise<GearData>

GPX and Courses

/**
 * Imports GPX file content
 *
 * @example ./examples/example-gpx-file.js
 * @param fileName - Name of the GPX file
 * @param fileContent - Content of the GPX file as string
 * @returns Response from the GPX import operation containing courseName, geoPoints, and coursePoints
 *
 * @example
 * ```js
 * const fileContent = await fs.readFile('paris-marathon.gpx', 'utf8');
 * const response = await GCClient.importGpx('paris-marathon.gpx', fileContent);
 * // The response contains courseName, geoPoints, and coursePoints that can be used with createCourse
 * ```
 */
async importGpx(
    fileName: string,
    fileContent: string
): Promise<ImportedGpxResponse>

Full example: examples/example-gpx-file.js

/**
 * Creates a course from GPX data
 * You can get geoPoints and coursePoints from the imported GPX file response.
 *
 * @example ./examples/example-gpx-file.js
 * @param activityType - Type of activity for the course
 * @param courseName - Name of the course
 * @param geoPoints - Array of geographical points making up the course
 * @param coursePoints - Optional array of course points (waypoints)
 * @returns Response from the course creation operation containing the courseId
 *
 * @example
 * ```js
 * // First import GPX to get geoPoints and coursePoints
 * const response = await GCClient.importGpx('course.gpx', gpxFileContent);
 *
 * // Then create the course
 * const createCourseResponse = await GCClient.createCourse(
 *     1,  // activityType (1 = running)
 *     response.courseName,
 *     response.geoPoints,
 *     response.coursePoints
 * );
 *
 * console.log('Course created with id:', createCourseResponse.courseId);
 * ```
 */
async createCourse(
    activityType: GpxActivityType,
    courseName: string,
    geoPoints: GeoPoint[],
    coursePoints: CoursePoint[] = []
)

Full example: examples/example-gpx-file.js

/**
 * Lists all courses
 * @returns List of courses in ListCoursesResponse format
 *
 * @example
 * ```js
 * const listCourses = await GCClient.listCourses();
 * console.log(
 *     'Last course:',
 *     listCourses.coursesForUser[0].courseId,
 *     listCourses.coursesForUser[0].courseName
 * );
 * ```
 */
async listCourses(): Promise<ListCoursesResponse>

Full example: examples/example-gpx-file.js

/**
 * Get the details of a course
 * @param courseId - Course id
 * @returns Course details
 *
 * @example
 * ```js
 * const course = await GCClient.getCourseDetails(123456789);
 * console.log('Course name', course.courseName);
 * ```
 */
async getCourseDetails(
    courseId: string | number
): Promise<CourseDetailsResponse>

Full example: examples/example-gpx-file.js

/**
 * Edit course privacy
 * @param courseId - Course Id
 * @param privacy - Privacy setting for the course, use CoursePrivacyRule.PUBLIC (1) for public courses
 *                  or CoursePrivacyRule.PRIVATE (2) for private courses. Defaults to PRIVATE.
 * @returns Course details
 *
 * @example
 * ```js
 * // Make a course public
 * await GCClient.updateCoursePrivacy(courseId, 1);
 * ```
 */
async updateCoursePrivacy(
    courseId: string | number,
    privacy: CoursePrivacyRule = CoursePrivacyRule.PRIVATE
): Promise<CourseDetailsResponse>

Full example: examples/example-gpx-file.js

/**
 * Rename a course
 * @param courseId - Course Id
 * @param courseName - The new course name
 * @returns Course details
 *
 * @example
 * ```js
 * await GCClient.renameCourse(courseId, 'My new course name');
 * ```
 */
async renameCourse(
    courseId: string | number,
    courseName: string
): Promise<CourseDetailsResponse>
/**
 * Complete update of a course
 * @param courseRequest - the full data of the course. Use getCourseDetails to get the existing set
 * @returns Course details updated
 *
 * @example
 * ```js
 * const course = await GCClient.getCourseDetails(courseId);
 * await GCClient.updateCourse({ ...course, description: 'Updated description' });
 * ```
 */
async updateCourse(
    courseRequest: CourseDetailsRequest
): Promise<CourseDetailsResponse>
/**
 * Exports a course as GPX file content
 * @param courseId - ID of the course to export
 * @returns GPX file content as string
 *
 * @example
 * ```js
 * const downloadGpx = await GCClient.exportCourseAsGpx(courseId);
 * console.log('Downloaded GPX size:', downloadGpx.length);
 * ```
 */
async exportCourseAsGpx(courseId: number): Promise<string>

Full example: examples/example-gpx-file.js

Calendar

/**
 * Retrieves calendar events for a specific year.
 * @param year {number} - The year for which to retrieve calendar events.
 */
async getYearCalendarEvents(year: number): Promise<YearCalendar>
/**
 * Retrieves calendar events for a specific month and year.
 * @param year {number} - The year for which to retrieve calendar events.
 * @param month {number} - The month (0-11) for which to retrieve calendar events.
 */
async getMonthCalendarEvents(
    year: number,
    month: number
): Promise<MonthCalendar>
/**
 * Retrieves calendar events for a specific week containing the given date.
 * @param year {number} - The year of the date.
 * @param month {number} - The month (0-11) of the date.
 * @param day {number} - The day of the first day of the week.
 * @param firstDayOfWeek {number} - Optional first day of the week, default is 1
 */
async getWeekCalendarEvents(
    year: number,
    month: number,
    day: number,
    firstDayOfWeek?: number
): Promise<any>

Custom Requests

The library provides methods for making custom requests to the Garmin Connect API:

/**
 * Performs a GET request to the specified URL
 * @param url - URL to send the request to
 * @param data - Optional query parameters or request configuration
 * @returns Response data of type T
 */
async get<T>(url: string, data?: any)
/**
 * Performs a POST request to the specified URL
 * @param url - URL to send the request to
 * @param data - Data to send in the request body
 * @returns Response data of type T
 */
async post<T>(url: string, data: any)
/**
 * Performs a PUT request to the specified URL
 * @param url - URL to send the request to
 * @param data - Data to send in the request body
 * @returns Response data of type T
 */
async put<T>(url: string, data: any)

版本与发布记录

@flow-js/garmin-connect 共发布 20 个版本,首次发布于 2025/10/20;过去 12 个月发布了 15 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
1.6.25latest2026/11/0312 天前
1.6.242026/10/051 个月前
1.6.232026/10/051 个月前
1.6.222026/09/231 个月前
1.6.212026/09/231 个月前
1.6.202026/09/231 个月前

关于 @flow-js/garmin-connect 的常见问题

@flow-js/garmin-connect 是什么?

Makes it simple to interface with Garmin Connect to get or set any data point

如何安装 @flow-js/garmin-connect?

在项目目录运行 npm install @flow-js/garmin-connect,或使用 pnpm add / yarn add / bun add。

@flow-js/garmin-connect 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@flow-js/garmin-connect 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@flow-js/garmin-connect 可以商用吗?

@flow-js/garmin-connect 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@flow-js/garmin-connect 的下载量有多少?

根据 npm 官方下载统计,@flow-js/garmin-connect 在 2026/10/15 – 2026/11/13 这 30 天内被下载 4,163 次,日均约 139 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@flow-js/garmin-connect 还在维护吗?

最新版本 1.6.25 发布于 2026/11/03(12 天前);至今共发布 20 个版本,其中过去 12 个月发布了 15 个;首次发布于 2025/10/20。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。