trackswap 0.0.15 → 0.0.17

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.
package/README.md CHANGED
@@ -13,7 +13,8 @@
13
13
  - 🔄 **多格式支持**: GPX 1.1、FIT、TCX 格式
14
14
  - 🎯 **统一转换**: 任意格式之间相互转换
15
15
  - 🤖 **自动检测**: 智能识别文件格式
16
- - 🔧 **插件架构**: 基于插件的可扩展设计
16
+ - 🧩 **扩展系统**: 灵活的扩展架构,支持自定义数据处理
17
+ - 📊 **智能聚合**: 默认启用运动数据聚合(心率、功率、速度等)
17
18
  - 🛡️ **类型安全**: 完整的 TypeScript 支持
18
19
  - ⚡ **高性能**: 优化的解析和编码算法
19
20
 
@@ -72,8 +73,32 @@ const parsedData = await trackSwap.parseFile(buffer);
72
73
  const sportData = await trackSwap.parseToActivity(buffer);
73
74
  ```
74
75
 
76
+ ### 扩展系统
77
+
78
+ ```typescript
79
+ import { TrackSwap } from 'trackswap';
80
+ import { SlopeExtension } from 'trackswap/extensions';
81
+
82
+ // 🧩 使用扩展增强功能
83
+ const trackSwap = new TrackSwap()
84
+ .extend(new SlopeExtension()); // 添加坡度计算
85
+
86
+ // 📊 默认已启用基础指标聚合(心率、功率、速度、踏频等)
87
+ const result = await trackSwap.parseGPX(gpxBuffer);
88
+ // result 包含完整的聚合数据和坡度信息
89
+
90
+ // 🔗 链式添加多个扩展
91
+ const enhancedTrackSwap = new TrackSwap()
92
+ .extend(new SlopeExtension())
93
+ .extend(new CustomExtension());
94
+ ```
95
+
75
96
  ## 📖 详细使用指南
76
97
 
98
+ ### 扩展系统
99
+
100
+ 详细的扩展开发和使用指南请参考:[扩展系统文档](EXTENSIONS.md)
101
+
77
102
  ### 1. 文件解析
78
103
 
79
104
  #### GPX 文件处理
@@ -387,23 +412,23 @@ TrackSwap 采用模块化架构,核心组件包括:
387
412
  ```
388
413
  src/
389
414
  ├── TrackSwap.ts # 主入口类
390
- ├── GPX/ # GPX 模块
391
- │ ├── decoder.ts
392
- │ ├── encoder.ts
393
- │ └── types.ts
394
- ├── FIT/ # FIT 模块
395
- │ ├── decoder.ts
396
- │ ├── encoder.ts
397
- │ └── types.ts
398
- ├── TCX/ # TCX 模块
399
- │ ├── decoder.ts
400
- │ ├── encoder.ts
401
- │ └── types.ts
402
- ├── sport/ # 统一转换模块
403
- │ ├── processor.ts
404
- │ ├── converters.ts
405
- │ ├── encoders.ts
406
- │ └── base.ts
415
+ ├── activity/ # 活动处理模块
416
+ │ ├── extensions.ts # 扩展系统核心
417
+ │ ├── slope-extension.ts # 坡度计算扩展
418
+ │ ├── processor.ts # 活动处理器
419
+ │ └── pipeline.ts # 数据处理管道
420
+ ├── decoders/ # 解码器模块
421
+ │ ├── GPXDecoder.ts
422
+ │ ├── FITDecoder.ts
423
+ │ └── TCXDecoder.ts
424
+ ├── encoders/ # 编码器模块
425
+ │ ├── GPXEncoder.ts
426
+ │ ├── FITEncoder.ts
427
+ │ └── TCXEncoder.ts
428
+ ├── converters/ # 格式转换器
429
+ │ ├── GPXConverter.ts
430
+ │ ├── FITConverter.ts
431
+ │ └── TCXConverter.ts
407
432
  └── types.ts # 公共类型定义
408
433
  ```
409
434
 
@@ -427,4 +452,4 @@ MIT License
427
452
  <div align="center">
428
453
  <strong>TrackSwap - 让轨迹数据处理变得简单</strong><br>
429
454
  🚀 高效 • 🔄 统一 • 🛡️ 安全 • 📈 可扩展
430
- </div>
455
+ </div>
@@ -27,7 +27,7 @@ export declare class FITDecoder {
27
27
  skipValidation?: boolean;
28
28
  enableStats?: boolean;
29
29
  userData?: Record<string, any>;
30
- }): Promise<FITFileType>;
30
+ }): Promise<FITFileType | undefined>;
31
31
  }
32
32
  declare const _default: {
33
33
  FITDecoder: typeof FITDecoder;
@@ -34,7 +34,7 @@ export interface FileCreatorMesgType {
34
34
  softwareVersion?: number;
35
35
  }
36
36
  export interface EventMesgType {
37
- timestamp?: string;
37
+ timestamp?: Date;
38
38
  data?: number;
39
39
  event?: string;
40
40
  eventType?: string;
@@ -79,65 +79,260 @@ export interface UserProfileMesgType {
79
79
  temperatureSetting?: string;
80
80
  }
81
81
  export interface SessionMesgType {
82
- timestamp?: string;
83
- startTime?: string;
82
+ messageIndex?: number;
83
+ timestamp: Date;
84
+ event: string;
85
+ eventType: string;
86
+ startTime: Date;
84
87
  startPositionLat?: number;
85
88
  startPositionLong?: number;
89
+ sport?: string;
90
+ subSport?: string;
86
91
  totalElapsedTime?: number;
87
92
  totalTimerTime?: number;
88
93
  totalDistance?: number;
89
94
  totalCycles?: number;
90
- necLat?: number;
91
- necLong?: number;
92
- swcLat?: number;
93
- swcLong?: number;
94
- totalWork?: number;
95
- messageIndex?: number;
95
+ totalStrides?: number;
96
+ totalStrokes?: number;
96
97
  totalCalories?: number;
97
98
  totalFatCalories?: number;
98
99
  avgSpeed?: number;
100
+ enhancedAvgSpeed?: number;
99
101
  maxSpeed?: number;
102
+ enhancedMaxSpeed?: number;
103
+ avgHeartRate?: number;
104
+ maxHeartRate?: number;
105
+ avgCadence?: number;
106
+ avgRunningCadence?: number;
107
+ maxCadence?: number;
108
+ maxRunningCadence?: number;
100
109
  avgPower?: number;
101
110
  maxPower?: number;
102
111
  totalAscent?: number;
103
112
  totalDescent?: number;
113
+ totalTrainingEffect?: number;
104
114
  firstLapIndex?: number;
105
115
  numLaps?: number;
116
+ eventGroup?: number;
117
+ trigger?: string;
118
+ necLat?: number;
119
+ necLong?: number;
120
+ swcLat?: number;
121
+ swcLong?: number;
122
+ numLengths?: number;
106
123
  normalizedPower?: number;
107
124
  trainingStressScore?: number;
108
125
  intensityFactor?: number;
126
+ leftRightBalance?: number;
127
+ endPositionLat?: number;
128
+ endPositionLong?: number;
129
+ avgStrokeCount?: number;
130
+ avgStrokeDistance?: number;
131
+ swimStroke?: string;
132
+ poolLength?: number;
109
133
  thresholdPower?: number;
110
- event?: string;
111
- eventType?: string;
112
- sport?: string;
113
- subActivity?: string;
114
- avgCadence?: number;
115
- maxCadence?: number;
116
- trigger?: number;
117
- totalStrokes?: number;
118
- enhancedAvgSpeed?: number;
119
- enhancedMaxSpeed?: number;
134
+ poolLengthUnit?: string;
135
+ numActiveLengths?: number;
136
+ totalWork?: number;
137
+ avgAltitude?: number;
138
+ enhancedAvgAltitude?: number;
139
+ maxAltitude?: number;
140
+ enhancedMaxAltitude?: number;
141
+ gpsAccuracy?: number;
142
+ avgGrade?: number;
143
+ avgPosGrade?: number;
144
+ avgNegGrade?: number;
145
+ maxPosGrade?: number;
146
+ maxNegGrade?: number;
147
+ avgTemperature?: number;
148
+ maxTemperature?: number;
149
+ minTemperature?: number;
150
+ totalMovingTime?: number;
151
+ avgPosVerticalSpeed?: number;
152
+ avgNegVerticalSpeed?: number;
153
+ maxPosVerticalSpeed?: number;
154
+ maxNegVerticalSpeed?: number;
155
+ minHeartRate?: number;
156
+ timeInHrZone?: number[];
157
+ timeInSpeedZone?: number[];
158
+ timeInCadenceZone?: number[];
159
+ timeInPowerZone?: number[];
160
+ avgLapTime?: number;
161
+ bestLapIndex?: number;
162
+ minAltitude?: number;
163
+ enhancedMinAltitude?: number;
164
+ playerScore?: number;
165
+ opponentScore?: number;
166
+ opponentName?: string;
167
+ strokeCount?: number[];
168
+ zoneCount?: number[];
169
+ maxBallSpeed?: number;
170
+ avgBallSpeed?: number;
171
+ avgVerticalOscillation?: number;
172
+ avgStanceTimePercent?: number;
173
+ avgStanceTime?: number;
174
+ avgFractionalCadence?: number;
175
+ maxFractionalCadence?: number;
176
+ totalFractionalCycles?: number;
177
+ avgTotalHemoglobinConc?: number;
178
+ minTotalHemoglobinConc?: number;
179
+ maxTotalHemoglobinConc?: number;
180
+ avgSaturatedHemoglobinPercent?: number;
181
+ minSaturatedHemoglobinPercent?: number;
182
+ maxSaturatedHemoglobinPercent?: number;
183
+ avgLeftTorqueEffectiveness?: number;
184
+ avgRightTorqueEffectiveness?: number;
185
+ avgLeftPedalSmoothness?: number;
186
+ avgRightPedalSmoothness?: number;
187
+ avgCombinedPedalSmoothness?: number;
188
+ sportProfileName?: string;
189
+ sportIndex?: number;
190
+ timeStanding?: number;
191
+ standCount?: number;
192
+ avgLeftPco?: number;
193
+ avgRightPco?: number;
194
+ avgLeftPowerPhase?: number[];
195
+ avgLeftPowerPhasePeak?: number[];
196
+ avgRightPowerPhase?: number[];
197
+ avgRightPowerPhasePeak?: number[];
198
+ avgPowerPosition?: number[];
199
+ maxPowerPosition?: number[];
200
+ avgCadencePosition?: number[];
201
+ maxCadencePosition?: number[];
202
+ avgLevMotorPower?: number;
203
+ maxLevMotorPower?: number;
204
+ levBatteryConsumption?: number;
205
+ avgVerticalRatio?: number;
206
+ avgStanceTimeBalance?: number;
207
+ avgStepLength?: number;
208
+ totalAnaerobicTrainingEffect?: number;
209
+ avgVam?: number;
210
+ avgDepth?: number;
211
+ maxDepth?: number;
212
+ surfaceInterval?: number;
213
+ startCns?: number;
214
+ endCns?: number;
215
+ startN2?: number;
216
+ endN2?: number;
217
+ avgRespirationRate?: number;
218
+ maxRespirationRate?: number;
219
+ minRespirationRate?: number;
220
+ enhancedAvgRespirationRate?: number;
221
+ enhancedMaxRespirationRate?: number;
222
+ enhancedMinRespirationRate?: number;
223
+ o2Toxicity?: number;
224
+ diveNumber?: number;
225
+ trainingLoadPeak?: number;
226
+ totalGrit?: number;
227
+ totalFlow?: number;
228
+ jumpCount?: number;
229
+ avgGrit?: number;
230
+ avgFlow?: number;
231
+ workoutFeel?: number;
232
+ workoutRpe?: number;
233
+ avgSpo2?: number;
234
+ avgStress?: number;
235
+ sdrrHrv?: number;
236
+ rmssdHrv?: number;
237
+ totalFractionalAscent?: number;
238
+ totalFractionalDescent?: number;
239
+ avgCoreTemperature?: number;
240
+ minCoreTemperature?: number;
241
+ maxCoreTemperature?: number;
120
242
  lapMesgs?: LapMesgType[];
121
243
  }
122
244
  export interface RecordMesgType {
123
- timestamp?: string;
245
+ timestamp: Date;
124
246
  positionLat?: number;
125
247
  positionLong?: number;
126
248
  altitude?: number;
249
+ enhancedAltitude?: number;
250
+ heartRate?: number;
251
+ cadence?: number;
127
252
  distance?: number;
128
- accumulatedPower?: number;
129
253
  speed?: number;
254
+ enhancedSpeed?: number;
130
255
  power?: number;
131
- cadence?: number;
132
- heartRate?: number;
256
+ compressedSpeedDistance?: Uint8Array;
257
+ grade?: number;
258
+ resistance?: number;
259
+ timeFromCourse?: number;
260
+ cycleLength?: number;
133
261
  temperature?: number;
134
- enhancedAltitude?: number;
135
- enhancedSpeed?: number;
136
- [key: string]: number | string | undefined | any;
262
+ speed1s?: number;
263
+ cycles?: number;
264
+ totalCycles?: number;
265
+ compressedAccumulatedPower?: number;
266
+ accumulatedPower?: number;
267
+ leftRightBalance?: number;
268
+ gpsAccuracy?: number;
269
+ verticalSpeed?: number;
270
+ calories?: number;
271
+ verticalOscillation?: number;
272
+ stanceTimePercent?: number;
273
+ stanceTime?: number;
274
+ activityType?: string;
275
+ leftTorqueEffectiveness?: number;
276
+ rightTorqueEffectiveness?: number;
277
+ leftPedalSmoothness?: number;
278
+ rightPedalSmoothness?: number;
279
+ combinedPedalSmoothness?: number;
280
+ time128?: number;
281
+ strokeType?: string;
282
+ zone?: number;
283
+ ballSpeed?: number;
284
+ cadence256?: number;
285
+ fractionalCadence?: number;
286
+ totalHemoglobinConc?: number;
287
+ totalHemoglobinConcMin?: number;
288
+ totalHemoglobinConcMax?: number;
289
+ saturatedHemoglobinPercent?: number;
290
+ saturatedHemoglobinPercentMin?: number;
291
+ saturatedHemoglobinPercentMax?: number;
292
+ deviceIndex?: number;
293
+ leftPco?: number;
294
+ rightPco?: number;
295
+ leftPowerPhase?: number;
296
+ leftPowerPhasePeak?: number;
297
+ rightPowerPhase?: number;
298
+ rightPowerPhasePeak?: number;
299
+ batterySoc?: number;
300
+ motorPower?: number;
301
+ verticalRatio?: number;
302
+ stanceTimeBalance?: number;
303
+ stepLength?: number;
304
+ cycleLength16?: number;
305
+ absolutePressure?: number;
306
+ depth?: number;
307
+ nextStopDepth?: number;
308
+ nextStopTime?: number;
309
+ timeToSurface?: number;
310
+ ndlTime?: number;
311
+ cnsLoad?: number;
312
+ n2Load?: number;
313
+ respirationRate?: number;
314
+ enhancedRespirationRate?: number;
315
+ grit?: number;
316
+ flow?: number;
317
+ currentStress?: number;
318
+ ebikeTravelRange?: number;
319
+ ebikeBatteryLevel?: number;
320
+ ebikeAssistMode?: number;
321
+ ebikeAssistLevelPercent?: number;
322
+ airTimeRemaining?: number;
323
+ pressureSac?: number;
324
+ volumeSac?: number;
325
+ rmv?: number;
326
+ ascentRate?: number;
327
+ po2?: number;
328
+ coreTemperature?: number;
137
329
  }
138
330
  export interface LapMesgType {
139
- timestamp?: string;
140
- startTime?: string;
331
+ messageIndex: number;
332
+ timestamp?: Date;
333
+ event?: string;
334
+ eventType?: string;
335
+ startTime?: Date;
141
336
  startPositionLat?: number;
142
337
  startPositionLong?: number;
143
338
  endPositionLat?: number;
@@ -146,30 +341,124 @@ export interface LapMesgType {
146
341
  totalTimerTime?: number;
147
342
  totalDistance?: number;
148
343
  totalCycles?: number;
149
- totalWork?: number;
150
- messageIndex?: number;
344
+ totalStrides?: number;
345
+ totalStrokes?: number;
151
346
  totalCalories?: number;
152
347
  totalFatCalories?: number;
153
348
  avgSpeed?: number;
349
+ enhancedAvgSpeed?: number;
154
350
  maxSpeed?: number;
351
+ enhancedMaxSpeed?: number;
352
+ avgHeartRate?: number;
353
+ maxHeartRate?: number;
354
+ avgCadence?: number;
355
+ avgRunningCadence?: number;
356
+ maxCadence?: number;
357
+ maxRunningCadence?: number;
155
358
  avgPower?: number;
156
359
  maxPower?: number;
157
360
  totalAscent?: number;
158
361
  totalDescent?: number;
159
- normalizedPower?: number;
160
- event?: string;
161
- eventType?: string;
162
- avgCadence?: number;
163
- maxCadence?: number;
362
+ intensity?: string;
164
363
  lapTrigger?: string;
165
364
  sport?: string;
166
- totalStrokes?: number;
167
- enhancedAvgSpeed?: number;
168
- enhancedMaxSpeed?: number;
365
+ eventGroup?: number;
366
+ numLengths?: number;
367
+ normalizedPower?: number;
368
+ leftRightBalance?: number;
369
+ firstLengthIndex?: number;
370
+ avgStrokeDistance?: number;
371
+ swimStroke?: string;
372
+ subSport?: string;
373
+ numActiveLengths?: number;
374
+ totalWork?: number;
375
+ avgAltitude?: number;
376
+ enhancedAvgAltitude?: number;
377
+ maxAltitude?: number;
378
+ enhancedMaxAltitude?: number;
379
+ gpsAccuracy?: number;
380
+ avgGrade?: number;
381
+ avgPosGrade?: number;
382
+ avgNegGrade?: number;
383
+ maxPosGrade?: number;
384
+ maxNegGrade?: number;
385
+ avgTemperature?: number;
386
+ maxTemperature?: number;
387
+ totalMovingTime?: number;
388
+ avgPosVerticalSpeed?: number;
389
+ avgNegVerticalSpeed?: number;
390
+ maxPosVerticalSpeed?: number;
391
+ maxNegVerticalSpeed?: number;
392
+ minHeartRate?: number;
393
+ timeInHrZone?: number[];
394
+ timeInSpeedZone?: number[];
395
+ timeInCadenceZone?: number[];
396
+ timeInPowerZone?: number[];
397
+ repetitionNum?: number;
398
+ minAltitude?: number;
399
+ enhancedMinAltitude?: number;
400
+ wktStepIndex?: number;
401
+ opponentScore?: number;
402
+ strokeCount?: number[];
403
+ zoneCount?: number[];
404
+ avgVerticalOscillation?: number;
405
+ avgStanceTimePercent?: number;
406
+ avgStanceTime?: number;
407
+ avgFractionalCadence?: number;
408
+ maxFractionalCadence?: number;
409
+ totalFractionalCycles?: number;
410
+ playerScore?: number;
411
+ avgTotalHemoglobinConc?: number;
412
+ minTotalHemoglobinConc?: number;
413
+ maxTotalHemoglobinConc?: number;
414
+ avgSaturatedHemoglobinPercent?: number;
415
+ minSaturatedHemoglobinPercent?: number;
416
+ maxSaturatedHemoglobinPercent?: number;
417
+ avgLeftTorqueEffectiveness?: number;
418
+ avgRightTorqueEffectiveness?: number;
419
+ avgLeftPedalSmoothness?: number;
420
+ avgRightPedalSmoothness?: number;
421
+ avgCombinedPedalSmoothness?: number;
422
+ timeStanding?: number;
423
+ standCount?: number;
424
+ avgLeftPco?: number;
425
+ avgRightPco?: number;
426
+ avgLeftPowerPhase?: number[];
427
+ avgLeftPowerPhasePeak?: number[];
428
+ avgRightPowerPhase?: number[];
429
+ avgRightPowerPhasePeak?: number[];
430
+ avgPowerPosition?: number[];
431
+ maxPowerPosition?: number[];
432
+ avgCadencePosition?: number[];
433
+ maxCadencePosition?: number[];
434
+ avgLevMotorPower?: number;
435
+ maxLevMotorPower?: number;
436
+ levBatteryConsumption?: number;
437
+ avgVerticalRatio?: number;
438
+ avgStanceTimeBalance?: number;
439
+ avgStepLength?: number;
440
+ avgVam?: number;
441
+ avgDepth?: number;
442
+ maxDepth?: number;
443
+ minTemperature?: number;
444
+ enhancedAvgRespirationRate?: number;
445
+ enhancedMaxRespirationRate?: number;
446
+ avgRespirationRate?: number;
447
+ maxRespirationRate?: number;
448
+ totalGrit?: number;
449
+ totalFlow?: number;
450
+ jumpCount?: number;
451
+ avgGrit?: number;
452
+ avgFlow?: number;
453
+ totalFractionalAscent?: number;
454
+ totalFractionalDescent?: number;
455
+ avgCoreTemperature?: number;
456
+ minCoreTemperature?: number;
457
+ maxCoreTemperature?: number;
169
458
  recordMesgs?: RecordMesgType[];
170
459
  }
171
460
  export interface ActivityMesgType {
172
- timestamp?: string;
461
+ timestamp?: Date;
173
462
  totalTimerTime?: number;
174
463
  numSessions?: number;
175
464
  type?: string;
@@ -19,7 +19,7 @@ export declare class TrackSwap {
19
19
  parseGPXString(xmlString: string): Promise<GPX11Type | undefined>;
20
20
  encodeGPX(gpxData: GPX11Type): Promise<Buffer>;
21
21
  encodeGPXString(gpxData: GPX11Type): string;
22
- parseFIT(buffer: Buffer): Promise<FITFileType>;
22
+ parseFIT(buffer: Buffer): Promise<FITFileType | undefined>;
23
23
  encodeFIT(fitData: FITFileType): Promise<Buffer>;
24
24
  encodeFITCourse(fitData: FITFileType): Promise<Buffer>;
25
25
  parseTCXString(xmlString: string): Promise<TCXFileType>;
@@ -34,8 +34,8 @@ export declare class TrackSwap {
34
34
  convertActivityToTCX(file: FileType): Promise<TCXFileType>;
35
35
  convertFile(sourceFile: Buffer, targetType: "gpx" | "fit" | "tcx", sourceType?: "gpx" | "fit" | "tcx"): Promise<Buffer>;
36
36
  detectFormat(buffer: Buffer): "gpx" | "fit" | "tcx" | "unknown";
37
- parseFile(buffer: Buffer, sourceType?: "gpx" | "fit" | "tcx"): Promise<GPX11Type | FITFileType | TCXFileType>;
38
- parseToActivity(buffer: Buffer, sourceType?: "gpx" | "fit" | "tcx"): Promise<FileType>;
37
+ parseFile(buffer: Buffer, sourceType?: "gpx" | "fit" | "tcx"): Promise<GPX11Type | FITFileType | TCXFileType | undefined>;
38
+ parseToActivity(buffer: Buffer, sourceType?: "gpx" | "fit" | "tcx"): Promise<FileType | undefined>;
39
39
  getActivityProcessor(): ActivityProcessor;
40
40
  getGPXDecoder(): GPXDecoder;
41
41
  getGPXEncoder(): GPXEncoder;