npm.io
0.2.0 • Published yesterday

trackswap

Licence
MIT
Version
0.2.0
Deps
4
Size
845 kB
Vulns
0
Weekly
0
Stars
1

TrackSwap

TrackSwap 是一个面向 Node.js 和 TypeScript 的运动、轨迹与健康数据工具包。它使用统一文档模型读取 FIT、GPX 和 TCX,并通过格式适配器隔离各协议的解析与编码实现。

安装

npm install trackswap

需要 Node.js 18 或更高版本。

核心模型

import TrackSwap from "trackswap";

const trackSwap = new TrackSwap();

try {
  const document = await trackSwap.decode(buffer);

  console.log(document.format);
  console.log(document.kinds);
  console.log(document.facets.activity);
  console.log(document.facets.health);
  console.log(document.metadata);
} finally {
  await trackSwap.dispose();
}

decode() 默认不会返回格式原生对象。只有调试或协议级处理确实需要时才启用:

const document = await trackSwap.decode(buffer, {
  format: "fit",
  includeNative: true,
  fit: {
    includeUnknownMessages: true,
  },
});

活动读取、编码与转换

const activity = await trackSwap.decodeActivity(input);

const gpx = await trackSwap.encodeActivity(activity, { format: "gpx" });
const fit = await trackSwap.encodeActivity(activity, { format: "fit" });
const tcx = await trackSwap.encodeActivity(activity, { format: "tcx" });

const converted = await trackSwap.transcode(input, {
  sourceFormat: "gpx",
  format: "tcx",
});

const course = await trackSwap.encodeCourse(input);

FIT 健康数据

FIT 文件只解码一次,活动与健康数据作为同一 TrackDocument 的 facet 返回。健康结构不直接绑定 Garmin Connect JSON,使用稳定的中间表示:

  • points:心率、压力、呼吸率、血氧、Body Battery、HRV、温度等时间点;
  • intervals:步数、距离、热量和活动累计量;
  • sessions:睡眠、小睡和 Health Snapshot;
  • summaries:日汇总、睡眠汇总及设备汇总;
  • diagnostics:FIT SDK profile、无效值、未知消息和解析警告。
const document = await trackSwap.decode(fitBuffer, {
  fit: {
    includeDeveloperFields: true,
    health: {
      reconstructIntervals: true,
      retainCumulativeValues: false,
    },
  },
});

错误处理

所有公共操作使用 TrackSwapError,可通过稳定错误码分类:

import { TrackSwapError } from "trackswap";

try {
  await trackSwap.decode(input);
} catch (error) {
  if (error instanceof TrackSwapError) {
    console.error(error.code, error.format, error.cause);
  }
}

错误码包括 FORMAT_UNKNOWNFORMAT_UNSUPPORTEDDECODE_FAILEDACTIVITY_NOT_FOUNDENCODE_FAILEDADAPTER_CONFLICTDISPOSED

自定义格式适配器

格式扩展发生在一个明确边界上,不需要访问 TrackSwap 内部解码器:

import TrackSwap, { type TrackFormatAdapter } from "trackswap";

const adapter: TrackFormatAdapter = {
  format: "geojson",
  matches: (input) => input.includes(Buffer.from('"FeatureCollection"')),
  decode: async (input, options) => ({
    kinds: ["route"],
    facets: { activity: myDecode(input, options) },
    native: {},
  }),
  encodeActivity: async (activity) => myEncode(activity),
};

const trackSwap = new TrackSwap({ adapters: [adapter] });

自定义适配器默认追加到 FIT、GPX、TCX 之后。每种格式只能注册一个适配器;重复注册会立即抛出 ADAPTER_CONFLICT。测试或完全定制运行时可设置 includeBuiltInAdapters: false

公共 API

方法 作用
detect(input) 检测 FIT、GPX 或 TCX
decode(input, options?) 返回统一 TrackDocument
decodeActivity(input, options?) 读取并要求存在活动 facet
encodeActivity(activity, options) 将统一活动编码为目标格式
transcode(input, options) 通过统一活动模型转换格式
encodeCourse(inputOrActivity, options?) 生成 FIT Course
dispose() 释放当前实例已创建的解码器

设计原则

  • façade 只负责编排,不包含协议逻辑;
  • 格式适配器负责检测、原生解码与编码;
  • 统一活动和健康模型是格式之间唯一的数据交换边界;
  • 默认惰性创建解码器,未使用的格式没有初始化成本;
  • 核心解析阶段 fail-fast,不返回部分损坏的文档;
  • 原生协议对象默认不进入公共结果,避免业务层依赖实现细节。

License

MIT

Keywords