{"_id":"@crazystudent13/health-archive-parser","_rev":"3-0fc3304f6d15b34d6e1007c6e6a8b15d","name":"@crazystudent13/health-archive-parser","dist-tags":{"latest":"0.2.3"},"versions":{"0.1.0":{"name":"@crazystudent13/health-archive-parser","version":"0.1.0","license":"PolyForm-Noncommercial-1.0.0","_id":"@crazystudent13/health-archive-parser@0.1.0","maintainers":[{"name":"crazystudent13","email":"1076535690@qq.com"}],"dist":{"shasum":"451b348c8d24deb322210281550165c765464b00","tarball":"https://registry.npmjs.org/@crazystudent13/health-archive-parser/-/health-archive-parser-0.1.0.tgz","fileCount":10,"integrity":"sha512-uCr4ofbNz7EZhvaeSi04p2dW/tcZw0qr1pkCGjzgVg66J8AcoF0M0GAEKS5twC3kH3s5L2NUG3Tb3U78QWWYhw==","signatures":[{"sig":"MEUCIBshQNF8y8Ff1x6+qnSTWMsm+HYulzTIYUeWwVjxX69MAiEAy1rvqsWNk1OjNukqQeenVz/BrzlEGyf/LkYwuIaTdDQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":80907},"main":"./lib/health-archive-parser.mjs","type":"module","types":"./lib/health-archive-parser.d.mts","engines":{"node":">=22.13.0"},"exports":{".":{"types":"./lib/health-archive-parser.d.mts","default":"./lib/health-archive-parser.mjs"},"./huawei":{"default":"./lib/huawei-archive-parser.mjs"},"./xiaomi":{"types":"./lib/xiaomi-archive-parser.d.mts","default":"./lib/xiaomi-archive-parser.mjs"}},"gitHead":"bb555df1498988d0359456b4216811515e1ec9a0","scripts":{"test":"node test/test-xiaomi-archive-parser.mjs"},"_npmUser":{"name":"crazystudent13","email":"1076535690@qq.com"},"_npmVersion":"10.9.7","description":"Parse Xiaomi Mi Fitness and Huawei Health ZIP exports into a normalized health archive JSON document.","directories":{},"_nodeVersion":"22.22.2","dependencies":{"yauzl":"^3.4.0","csv-parser":"^3.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@9.15.0","_npmOperationalInternal":{"tmp":"tmp/health-archive-parser_0.1.0_1788015772038_0.34227372228245145","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@crazystudent13/health-archive-parser","version":"0.2.1","license":"PolyForm-Noncommercial-1.0.0","_id":"@crazystudent13/health-archive-parser@0.2.1","maintainers":[{"name":"crazystudent13","email":"1076535690@qq.com"}],"dist":{"shasum":"be266d66bc631fbe0208b72f91230066dc7fcbd5","tarball":"https://registry.npmjs.org/@crazystudent13/health-archive-parser/-/health-archive-parser-0.2.1.tgz","fileCount":15,"integrity":"sha512-qXE8YpHjbdaH2F59oRXhMPEH8ID4aUO9jJTfKpFn2yWkYmAyvHRAkZEMVTdCGStUKUo6kfwe0UGFR/jP72y/Xw==","signatures":[{"sig":"MEUCIQCzZWmBuroz19mgVgjj17xryNlwc8HJqMeAb7/8a58JfAIgBjuZaXZDE1lK4Slove0s8iLlajFET6vlj3xOwltg7nw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCICE9ngd5Q6+a39N02ZuqpbRG2m3r35Iz2bdLUB9SKgp1AiANo0nTQifvEjE1aAo2AOJiUS+4QPIbqwJwkTONt1nuOw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":106256},"main":"./lib/health-archive-parser.mjs","type":"module","types":"./lib/health-archive-parser.d.mts","engines":{"node":">=22.13.0"},"exports":{".":{"types":"./lib/health-archive-parser.d.mts","default":"./lib/health-archive-parser.mjs"},"./huawei":{"types":"./lib/huawei-archive-parser.d.mts","default":"./lib/huawei-archive-parser.mjs"},"./xiaomi":{"types":"./lib/xiaomi-archive-parser.d.mts","default":"./lib/xiaomi-archive-parser.mjs"}},"gitHead":"2f5d4629d013d6f704ebba87e811bff5c449b61d","scripts":{"test":"node --test test/test-xiaomi-archive-parser.mjs"},"_npmUser":{"name":"crazystudent13","email":"1076535690@qq.com"},"_npmVersion":"10.9.7","description":"Parse Xiaomi Mi Fitness and Huawei Health ZIP exports into a normalized health archive JSON document.","directories":{},"_nodeVersion":"22.22.2","dependencies":{"yauzl":"^3.4.0","csv-parser":"^3.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@9.15.0","_npmOperationalInternal":{"tmp":"tmp/health-archive-parser_0.2.1_1788069359032_0.4831732281568617","host":"s3://npm-registry-packages-npm-production"}},"0.2.3":{"_id":"@crazystudent13/health-archive-parser@0.2.3","dist":{"shasum":"f951756486efaf97e9ec470f0599ca9d32f54103","tarball":"https://registry.npmjs.org/@crazystudent13/health-archive-parser/-/health-archive-parser-0.2.3.tgz","fileCount":15,"integrity":"sha512-HSQdEqqiHMS/WnBfCfk4Jt/wVJmVAUZ3qGE7IO9ZH0xqMiNCi0CiJdA6T5844kQt3qfEMVLZ4d1ysZ2BTOJ6iA==","signatures":[{"sig":"MEQCIFwwlHQzC2CBG8awsfFnHsVi/w8AGvrlmlRvC8YmwrFIAiATvkRCWM3+Hq/tn/MtT3/m9VQjRzIbWPkJtfDrDsACNw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQC5KdqFDhG3aAsmcQFX/s6EEW9vlMsZzzXVd0H+S8anWAIhAIu2DhtVLlxd/DOH2vnooDd/gDpxz4cXzu/4qn0m0/S6"}],"unpackedSize":113912},"main":"./lib/health-archive-parser.mjs","name":"@crazystudent13/health-archive-parser","type":"module","types":"./lib/health-archive-parser.d.mts","engines":{"node":">=22.13.0"},"exports":{".":{"types":"./lib/health-archive-parser.d.mts","default":"./lib/health-archive-parser.mjs"},"./huawei":{"types":"./lib/huawei-archive-parser.d.mts","default":"./lib/huawei-archive-parser.mjs"},"./xiaomi":{"types":"./lib/xiaomi-archive-parser.d.mts","default":"./lib/xiaomi-archive-parser.mjs"}},"gitHead":"8022fd928389290e6cc9e8c868f56d2deabf994f","license":"PolyForm-Noncommercial-1.0.0","scripts":{"test":"node --test test/test-xiaomi-archive-parser.mjs"},"version":"0.2.3","_npmUser":{"name":"crazystudent13","email":"1076535690@qq.com"},"_npmVersion":"10.9.7","description":"Parse Xiaomi Mi Fitness and Huawei Health ZIP exports into a normalized health archive JSON document.","directories":{},"maintainers":[{"name":"crazystudent13","email":"1076535690@qq.com"}],"_nodeVersion":"22.22.2","dependencies":{"yauzl":"^3.4.0","csv-parser":"^3.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@9.15.0","_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/health-archive-parser_0.2.3_1788454731488_0.3495885850239375"}}},"time":{"created":"2026-08-29T15:02:51.868Z","modified":"2026-09-03T16:58:51.769Z","0.1.0":"2026-08-29T15:02:52.185Z","0.2.1":"2026-08-30T05:55:59.120Z","0.2.3":"2026-09-03T16:58:51.571Z"},"license":"PolyForm-Noncommercial-1.0.0","description":"Parse Xiaomi Mi Fitness and Huawei Health ZIP exports into a normalized health archive JSON document.","maintainers":[{"name":"crazystudent13","email":"1076535690@qq.com"}],"readme":"# @crazystudent13/health-archive-parser\r\n\r\n把小米 Mi Fitness 和华为运动健康的 ZIP 导出，解析为统一的健康档案 JSON 文档。\r\n\r\n> English docs: [README.md](./README.md)\r\n\r\n## 安装\r\n\r\n```bash\r\npnpm add @crazystudent13/health-archive-parser\r\n```\r\n\r\n## 用法\r\n\r\n```js\r\nimport { parseHealthArchive } from '@crazystudent13/health-archive-parser';\r\n\r\nconst normalized = await parseHealthArchive('/path/to/export.zip', {\r\n  platform: 'huawei', // 'xiaomi' | 'huawei'\r\n});\r\n```\r\n\r\n或按平台直接调用：\r\n\r\n```js\r\nimport { parseXiaomiArchive } from '@crazystudent13/health-archive-parser';\r\nimport { parseHuaweiArchive } from '@crazystudent13/health-archive-parser/huawei';\r\n```\r\n\r\n## 选项\r\n\r\n| 选项 | 类型 | 默认值 | 说明 |\r\n|---|---|---|---|\r\n| `platform` | `'xiaomi' \\| 'huawei'` | `'xiaomi'` | 平台（仅 `parseHealthArchive`） |\r\n| `minDate` | `string` | `'2010-01-01'` | 只保留该日期之后的数据，`YYYY-MM-DD` |\r\n| `maxIssues` | `number` | `100` | 最多记录的解析异常条数 |\r\n| `limits` | `object` | 内置限制 | 压缩包安全限制（条目数 / 大小 / 压缩比） |\r\n| `timezone` | `string` | `'Asia/Shanghai'` | 本地日期时区（IANA 时区名，如 `'America/New_York'`） |\r\n\r\n## 输出结构\r\n\r\n所有解析函数返回同一形状的标准化文档：\r\n\r\n```js\r\n{\r\n  schemaVersion: 'huawei-health/v1',   // 或 'xiaomi-mi-fitness/v1'\r\n  source: {\r\n    provider: 'huawei-health',\r\n    timezone: 'Asia/Shanghai',\r\n    sourceRows: { health: 42094, sampleSequence: 1034, /* ... */ },\r\n    archive: {\r\n      fileName: 'HUAWEI_HEALTH_20260803154004.zip',\r\n      sizeBytes: 2568297,\r\n      sha256: 'd053d1...',\r\n      entryCount: 143,\r\n      uncompressedSizeBytes: 26866114,\r\n      selectedFiles: { /* 平台相关 */ }\r\n    }\r\n  },\r\n  profile: {\r\n    providerAccountKey: null,\r\n    displayName: null,\r\n    sex: 'male',\r\n    birthDate: null,\r\n    heightCm: 180,\r\n    initialWeightKg: 110.6,\r\n    targetWeightKg: null,\r\n    dailyCalorieGoal: 700,\r\n    vo2Max: null\r\n  },\r\n  metricSeries: [\r\n    {\r\n      date: '2026-07-24',\r\n      timezone: 'Asia/Shanghai',\r\n      metricType: 'heart_rate',\r\n      unit: 'bpm',\r\n      samples: [{ timestamp: 1784824800, value: 72 }],\r\n      summary: {\r\n        sampleCount: 1,\r\n        firstTimestamp: 1784824800,\r\n        lastTimestamp: 1784824800,\r\n        min: 72, max: 72, avg: 72, sum: 72\r\n      }\r\n    }\r\n  ],\r\n  bloodPressureRecords: [\r\n    {\r\n      externalId: 'szVrjwAAAAAFAAAAs00CxZ8BAAA=',\r\n      date: '2026-08-03',\r\n      timezone: 'Asia/Shanghai',\r\n      measuredAt: 1785716690,             // epoch 秒\r\n      systolic: 127,\r\n      diastolic: 82,\r\n      heartRate: 78,\r\n      sourceProvider: 'huawei-health',\r\n      details: { source: '...' }\r\n    }\r\n  ],\r\n  sleepSessions: [\r\n    {\r\n      date: '2026-07-24',\r\n      timezone: 'Asia/Shanghai',\r\n      sessionType: 'night',             // 'night' | 'nap'\r\n      bedtime: 1784824800,              // epoch 秒\r\n      wakeUp: 1784851440,\r\n      durationMinutes: 444,\r\n      deepSleepMinutes: 150,\r\n      lightSleepMinutes: 200,\r\n      remSleepMinutes: 75,\r\n      awakeMinutes: 19,\r\n      avgHeartRate: 73,\r\n      stages: [{ startAt: 1784824800, endAt: 1784828400, state: 'light' }],\r\n      source: { fileName: '...' }\r\n    }\r\n  ],\r\n  sportRecords: [\r\n    {\r\n      externalId: 'huawei-motion:cycling:...',\r\n      date: '2026-07-24',\r\n      timezone: 'Asia/Shanghai',\r\n      sportType: 'cycling',\r\n      category: 'cycling',\r\n      startedAt: 1784854171,\r\n      endedAt: 1784854659,\r\n      durationSeconds: 488,\r\n      distanceMeters: 3210.5,\r\n      calories: 234,\r\n      steps: null,\r\n      avgHeartRate: 139,\r\n      maxHeartRate: 155,\r\n      details: { /* 平台原始数据 */ },\r\n      source: { fileName: '...' }\r\n    }\r\n  ],\r\n  summary: {\r\n    dateRange: { start: '2026-07-23', end: '2026-08-03' },\r\n    counts: {\r\n      sourceRows: 44906,\r\n      metricSeries: 89,\r\n      bloodPressureRecords: 1,\r\n      metricSamples: 15381,\r\n      sleepSessions: 16,\r\n      sportRecords: 25,\r\n      issues: 0\r\n    },\r\n    metrics: { heart_rate: { series: 12, samples: 7613 }, /* ... */ }\r\n  },\r\n  issues: [\r\n    { source: '...', rowNumber: 42, entityType: 'metric', code: 'INVALID_JSON', message: '...', rawRecord: { /* ... */ } }\r\n  ]\r\n}\r\n```\r\n\r\n指标类型：`steps`（步数）、`calories`（卡路里）、`distance`（距离）、`heart_rate`（心率）、`stress`（压力）、`weight`（体重）、`spo2`（血氧）、`intensity`（强度）。\r\n\r\n## TypeScript\r\n\r\n完整类型从根入口导出：\r\n\r\n```ts\r\nimport {\r\n  parseHealthArchive,\r\n  type NormalizedHealthArchive,\r\n  type HealthArchiveMetricSeries,\r\n  type HealthArchiveSleepSession,\r\n  type HealthArchiveSportRecord,\r\n} from '@crazystudent13/health-archive-parser';\r\n\r\nconst normalized: NormalizedHealthArchive = await parseHealthArchive(file, {\r\n  platform: 'xiaomi',\r\n});\r\n```\r\n\r\n## 环境要求\r\n\r\n- Node.js `>= 22.13.0`\r\n- 纯 ESM（`.mjs`）。CommonJS 消费方需 Node `>= 22.12`（原生 `require(esm)`）。\r\n- 运行时依赖仅 `csv-parser` 和 `yauzl`。\r\n\r\n## 支持平台\r\n\r\n| 平台 | 来源 | schemaVersion |\r\n|---|---|---|\r\n| 小米 | Mi Fitness ZIP（未加密 CSV） | `xiaomi-mi-fitness/v1` |\r\n| 华为 | 华为运动健康 ZIP（未加密 JSON） | `huawei-health/v1` |\r\n\r\n## 公开 API\r\n\r\n- `parseHealthArchive(archivePath, options)` — 按平台自动分发\r\n- `parseXiaomiArchive(archivePath, options)` / `parseHuaweiArchive(archivePath, options)`\r\n- `createXiaomiNormalizer(options)` / `createHuaweiNormalizer(options)` — 流式逐行消费\r\n- `normalizeImportPlatform` / `getImportPlatformConfig` / `IMPORT_PLATFORMS`\r\n- 错误类：`HealthArchiveParseError` / `XiaomiArchiveParseError`\r\n\r\n## License\r\n\r\nPolyForm Noncommercial License 1.0.0 — 仅限非商业使用。\r\n","readmeFilename":"README.zh-CN.md"}