@swimedge/metrics 1.0.4 → 1.0.6
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/dist/index.d.ts +36 -18
- package/dist/index.js +116 -159
- package/dist/index.spec.js +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -6,19 +6,17 @@ export declare enum SwimType {
|
|
|
6
6
|
INDOOR = "indoorPool",
|
|
7
7
|
OPEN_WATER = "openWater"
|
|
8
8
|
}
|
|
9
|
-
export interface
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
lapStrokeRates?: number[];
|
|
19
|
-
lapDistancesPerStroke?: number[];
|
|
9
|
+
export interface SwimLap {
|
|
10
|
+
strokeCount?: number;
|
|
11
|
+
pace?: number;
|
|
12
|
+
strokeRate?: number;
|
|
13
|
+
distancePerStroke?: number;
|
|
14
|
+
strokeStyle?: string;
|
|
15
|
+
splitTime?: number;
|
|
16
|
+
swolfScore?: number;
|
|
17
|
+
calories?: number;
|
|
20
18
|
}
|
|
21
|
-
export interface SwimSession
|
|
19
|
+
export interface SwimSession {
|
|
22
20
|
id: string;
|
|
23
21
|
watchSessionId?: string;
|
|
24
22
|
date: string;
|
|
@@ -54,10 +52,10 @@ export interface SwimSession extends SwimSessionLaps {
|
|
|
54
52
|
equipment?: string[];
|
|
55
53
|
avgDistancePerStroke?: number;
|
|
56
54
|
routeCoordinates?: number[][];
|
|
57
|
-
routeMapImage?: string;
|
|
58
55
|
deviceType?: string;
|
|
59
56
|
osVersion?: string;
|
|
60
57
|
healthKitWorkoutId?: string;
|
|
58
|
+
lapData?: SwimLap[];
|
|
61
59
|
}
|
|
62
60
|
export interface AggregatedSwimMetrics {
|
|
63
61
|
totalDistance: number;
|
|
@@ -106,7 +104,6 @@ export interface MetricDefinition {
|
|
|
106
104
|
description: string;
|
|
107
105
|
icon?: string;
|
|
108
106
|
isPerSession?: boolean;
|
|
109
|
-
isPerLap?: boolean;
|
|
110
107
|
formula?: string;
|
|
111
108
|
source?: string;
|
|
112
109
|
healthKitSource?: string;
|
|
@@ -119,18 +116,39 @@ export interface MetricDefinition {
|
|
|
119
116
|
swimTypes: SwimType[];
|
|
120
117
|
hasChart?: boolean;
|
|
121
118
|
formatter?: (session: SwimSession) => string | number | null;
|
|
122
|
-
lapFormatter?: (value: any) => string;
|
|
123
119
|
condition?: (session: SwimSession) => boolean;
|
|
124
120
|
}
|
|
125
|
-
export
|
|
121
|
+
export interface LapMetricDefinition {
|
|
122
|
+
key: keyof SwimLap;
|
|
123
|
+
label: string;
|
|
124
|
+
unit?: string;
|
|
125
|
+
category: MetricCategory;
|
|
126
|
+
description: string;
|
|
127
|
+
icon?: string;
|
|
128
|
+
formula?: string;
|
|
129
|
+
source?: string;
|
|
130
|
+
healthKitSource?: string;
|
|
131
|
+
isHealthKit?: boolean;
|
|
132
|
+
decimals?: number;
|
|
133
|
+
availableFrom: {
|
|
134
|
+
watch: boolean;
|
|
135
|
+
manual: boolean;
|
|
136
|
+
};
|
|
137
|
+
swimTypes: SwimType[];
|
|
138
|
+
lapFormatter?: (value: any) => string;
|
|
139
|
+
}
|
|
140
|
+
export declare const LAP_METRICS_REGISTRY: Record<keyof SwimLap, LapMetricDefinition>;
|
|
141
|
+
export declare const METRICS_REGISTRY: Partial<Record<keyof SwimSession, MetricDefinition>>;
|
|
126
142
|
export declare const MetricsHelper: {
|
|
127
|
-
getMetric: (key: keyof SwimSession) => MetricDefinition;
|
|
143
|
+
getMetric: (key: keyof SwimSession) => MetricDefinition | undefined;
|
|
128
144
|
getSessionMetrics: () => MetricDefinition[];
|
|
129
145
|
getChartMetrics: () => MetricDefinition[];
|
|
130
|
-
getLapMetrics: () =>
|
|
146
|
+
getLapMetrics: () => LapMetricDefinition[];
|
|
147
|
+
getLapMetric: (key: keyof SwimLap) => LapMetricDefinition;
|
|
131
148
|
getMetricsByCategory: (category: MetricCategory) => MetricDefinition[];
|
|
132
149
|
getMetricsBySwimType: (swimType: SwimType) => MetricDefinition[];
|
|
133
150
|
getIndoorMetrics: () => MetricDefinition[];
|
|
134
151
|
getOpenWaterMetrics: () => MetricDefinition[];
|
|
135
152
|
getAllMetricKeys: () => string[];
|
|
153
|
+
getAllLapMetricKeys: () => string[];
|
|
136
154
|
};
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Shared metrics registry for frontend, backend, and watch app
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.MetricsHelper = exports.METRICS_REGISTRY = exports.formatSwimType = exports.formatDistance = exports.formatHeartRate = exports.formatTime = exports.formatPace = exports.formatNumber = exports.MetricCategory = exports.SwimType = void 0;
|
|
7
|
+
exports.MetricsHelper = exports.METRICS_REGISTRY = exports.LAP_METRICS_REGISTRY = exports.formatSwimType = exports.formatDistance = exports.formatHeartRate = exports.formatTime = exports.formatPace = exports.formatNumber = exports.MetricCategory = exports.SwimType = void 0;
|
|
8
8
|
var SwimType;
|
|
9
9
|
(function (SwimType) {
|
|
10
10
|
SwimType["INDOOR"] = "indoorPool";
|
|
@@ -31,12 +31,13 @@ const formatPace = (pace) => {
|
|
|
31
31
|
};
|
|
32
32
|
exports.formatPace = formatPace;
|
|
33
33
|
const formatTime = (seconds) => {
|
|
34
|
-
const
|
|
35
|
-
const
|
|
34
|
+
const totalSeconds = Math.floor(seconds);
|
|
35
|
+
const mins = Math.floor(totalSeconds / 60);
|
|
36
|
+
const secs = totalSeconds % 60;
|
|
36
37
|
if (mins >= 60) {
|
|
37
38
|
const hours = Math.floor(mins / 60);
|
|
38
39
|
const remainingMins = mins % 60;
|
|
39
|
-
return `${hours}:${remainingMins.toString().padStart(2, '0')}`;
|
|
40
|
+
return `${hours}:${remainingMins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
|
|
40
41
|
}
|
|
41
42
|
return `${mins}:${secs.toString().padStart(2, '0')}`;
|
|
42
43
|
};
|
|
@@ -60,6 +61,97 @@ const formatSwimType = (swimType) => {
|
|
|
60
61
|
}[swimType] || swimType);
|
|
61
62
|
};
|
|
62
63
|
exports.formatSwimType = formatSwimType;
|
|
64
|
+
exports.LAP_METRICS_REGISTRY = {
|
|
65
|
+
strokeCount: {
|
|
66
|
+
key: 'strokeCount',
|
|
67
|
+
label: 'Strokes',
|
|
68
|
+
unit: '',
|
|
69
|
+
category: MetricCategory.TECHNIQUE,
|
|
70
|
+
description: 'Number of strokes in this lap',
|
|
71
|
+
icon: 'hand-left-outline',
|
|
72
|
+
decimals: 0,
|
|
73
|
+
source: 'HealthKit: HKQuantityTypeIdentifierSwimmingStrokeCount per lap',
|
|
74
|
+
healthKitSource: 'HKQuantityTypeIdentifierSwimmingStrokeCount',
|
|
75
|
+
isHealthKit: true,
|
|
76
|
+
availableFrom: { watch: true, manual: false },
|
|
77
|
+
swimTypes: [SwimType.INDOOR],
|
|
78
|
+
},
|
|
79
|
+
pace: {
|
|
80
|
+
key: 'pace',
|
|
81
|
+
label: 'Pace',
|
|
82
|
+
unit: '/100m',
|
|
83
|
+
category: MetricCategory.PERFORMANCE,
|
|
84
|
+
description: 'Time per 100m for this lap',
|
|
85
|
+
decimals: 1,
|
|
86
|
+
availableFrom: { watch: true, manual: false },
|
|
87
|
+
swimTypes: [SwimType.INDOOR],
|
|
88
|
+
lapFormatter: (v) => (0, exports.formatPace)(v),
|
|
89
|
+
},
|
|
90
|
+
strokeRate: {
|
|
91
|
+
key: 'strokeRate',
|
|
92
|
+
label: 'SR',
|
|
93
|
+
unit: 'SPM',
|
|
94
|
+
category: MetricCategory.TECHNIQUE,
|
|
95
|
+
description: 'Strokes per minute for this lap',
|
|
96
|
+
icon: 'repeat-outline',
|
|
97
|
+
decimals: 1,
|
|
98
|
+
formula: 'Lap Strokes ÷ (Lap Time in Minutes)',
|
|
99
|
+
availableFrom: { watch: true, manual: false },
|
|
100
|
+
swimTypes: [SwimType.INDOOR],
|
|
101
|
+
},
|
|
102
|
+
distancePerStroke: {
|
|
103
|
+
key: 'distancePerStroke',
|
|
104
|
+
label: 'DPS',
|
|
105
|
+
unit: 'm',
|
|
106
|
+
category: MetricCategory.TECHNIQUE,
|
|
107
|
+
description: 'Distance per stroke for this lap',
|
|
108
|
+
icon: 'arrow-forward-outline',
|
|
109
|
+
decimals: 2,
|
|
110
|
+
formula: 'Lap Distance ÷ Lap Strokes',
|
|
111
|
+
availableFrom: { watch: true, manual: false },
|
|
112
|
+
swimTypes: [SwimType.INDOOR],
|
|
113
|
+
},
|
|
114
|
+
strokeStyle: {
|
|
115
|
+
key: 'strokeStyle',
|
|
116
|
+
label: 'Stroke',
|
|
117
|
+
category: MetricCategory.TECHNIQUE,
|
|
118
|
+
description: 'Swimming stroke used in this lap',
|
|
119
|
+
icon: 'list-outline',
|
|
120
|
+
availableFrom: { watch: true, manual: false },
|
|
121
|
+
swimTypes: [SwimType.INDOOR],
|
|
122
|
+
},
|
|
123
|
+
splitTime: {
|
|
124
|
+
key: 'splitTime',
|
|
125
|
+
label: 'Time',
|
|
126
|
+
unit: 's',
|
|
127
|
+
category: MetricCategory.PERFORMANCE,
|
|
128
|
+
description: 'Time taken for this lap',
|
|
129
|
+
icon: 'stopwatch-outline',
|
|
130
|
+
source: 'Tracked per lap completion',
|
|
131
|
+
availableFrom: { watch: true, manual: false },
|
|
132
|
+
swimTypes: [SwimType.INDOOR],
|
|
133
|
+
lapFormatter: (v) => (0, exports.formatTime)(v),
|
|
134
|
+
},
|
|
135
|
+
swolfScore: {
|
|
136
|
+
key: 'swolfScore',
|
|
137
|
+
label: 'SWOLF',
|
|
138
|
+
category: MetricCategory.TECHNIQUE,
|
|
139
|
+
description: 'SWOLF score for this lap',
|
|
140
|
+
decimals: 0,
|
|
141
|
+
availableFrom: { watch: true, manual: false },
|
|
142
|
+
swimTypes: [SwimType.INDOOR],
|
|
143
|
+
},
|
|
144
|
+
calories: {
|
|
145
|
+
key: 'calories',
|
|
146
|
+
label: 'Cal',
|
|
147
|
+
unit: 'kcal',
|
|
148
|
+
category: MetricCategory.ENERGY,
|
|
149
|
+
description: 'Calories burned in this lap',
|
|
150
|
+
decimals: 0,
|
|
151
|
+
availableFrom: { watch: true, manual: false },
|
|
152
|
+
swimTypes: [SwimType.INDOOR],
|
|
153
|
+
},
|
|
154
|
+
};
|
|
63
155
|
exports.METRICS_REGISTRY = {
|
|
64
156
|
distance: {
|
|
65
157
|
key: 'distance',
|
|
@@ -135,7 +227,6 @@ exports.METRICS_REGISTRY = {
|
|
|
135
227
|
availableFrom: { watch: true, manual: true },
|
|
136
228
|
swimTypes: [SwimType.INDOOR],
|
|
137
229
|
hasChart: true,
|
|
138
|
-
formatter: (s) => String(s.laps),
|
|
139
230
|
condition: (s) => !!s.laps,
|
|
140
231
|
},
|
|
141
232
|
avgPace: {
|
|
@@ -193,6 +284,7 @@ exports.METRICS_REGISTRY = {
|
|
|
193
284
|
isHealthKit: true,
|
|
194
285
|
availableFrom: { watch: true, manual: false },
|
|
195
286
|
swimTypes: [SwimType.INDOOR, SwimType.OPEN_WATER],
|
|
287
|
+
hasChart: true,
|
|
196
288
|
formatter: (s) => `${(0, exports.formatNumber)(s.waterTemp, 1)}°C`,
|
|
197
289
|
condition: (s) => !!s.waterTemp,
|
|
198
290
|
},
|
|
@@ -209,6 +301,7 @@ exports.METRICS_REGISTRY = {
|
|
|
209
301
|
isHealthKit: true,
|
|
210
302
|
availableFrom: { watch: true, manual: false },
|
|
211
303
|
swimTypes: [SwimType.INDOOR, SwimType.OPEN_WATER],
|
|
304
|
+
hasChart: true,
|
|
212
305
|
formatter: (s) => (0, exports.formatHeartRate)(s.avgHeartRate),
|
|
213
306
|
condition: (s) => !!s.avgHeartRate,
|
|
214
307
|
},
|
|
@@ -225,6 +318,7 @@ exports.METRICS_REGISTRY = {
|
|
|
225
318
|
isHealthKit: true,
|
|
226
319
|
availableFrom: { watch: true, manual: false },
|
|
227
320
|
swimTypes: [SwimType.INDOOR, SwimType.OPEN_WATER],
|
|
321
|
+
hasChart: true,
|
|
228
322
|
formatter: (s) => (0, exports.formatHeartRate)(s.maxHeartRate),
|
|
229
323
|
condition: (s) => !!s.maxHeartRate,
|
|
230
324
|
},
|
|
@@ -241,6 +335,7 @@ exports.METRICS_REGISTRY = {
|
|
|
241
335
|
isHealthKit: true,
|
|
242
336
|
availableFrom: { watch: true, manual: false },
|
|
243
337
|
swimTypes: [SwimType.INDOOR, SwimType.OPEN_WATER],
|
|
338
|
+
hasChart: true,
|
|
244
339
|
formatter: (s) => (0, exports.formatHeartRate)(s.minHeartRate),
|
|
245
340
|
condition: (s) => !!s.minHeartRate,
|
|
246
341
|
},
|
|
@@ -339,51 +434,6 @@ exports.METRICS_REGISTRY = {
|
|
|
339
434
|
formatter: (s) => s.primaryStrokeType,
|
|
340
435
|
condition: (s) => !!s.primaryStrokeType,
|
|
341
436
|
},
|
|
342
|
-
lapSplitTimes: {
|
|
343
|
-
key: 'lapSplitTimes',
|
|
344
|
-
label: 'Time',
|
|
345
|
-
unit: 's',
|
|
346
|
-
category: MetricCategory.PERFORMANCE,
|
|
347
|
-
description: 'Individual lap times recorded during the session.',
|
|
348
|
-
icon: 'stopwatch-outline',
|
|
349
|
-
isPerLap: true,
|
|
350
|
-
source: 'Tracked per lap completion',
|
|
351
|
-
availableFrom: { watch: true, manual: false },
|
|
352
|
-
swimTypes: [SwimType.INDOOR],
|
|
353
|
-
formatter: (s) => `${s.lapSplitTimes.length} splits`,
|
|
354
|
-
lapFormatter: (v) => (0, exports.formatTime)(v),
|
|
355
|
-
condition: (s) => !!s.lapSplitTimes?.length,
|
|
356
|
-
},
|
|
357
|
-
lapHeartRates: {
|
|
358
|
-
key: 'lapHeartRates',
|
|
359
|
-
label: 'HR',
|
|
360
|
-
unit: 'bpm',
|
|
361
|
-
category: MetricCategory.HEALTH,
|
|
362
|
-
description: 'HR per lap',
|
|
363
|
-
icon: 'heart-outline',
|
|
364
|
-
isPerLap: true,
|
|
365
|
-
decimals: 0,
|
|
366
|
-
source: 'HealthKit: HKQuantityTypeIdentifierHeartRate sampled at lap completion',
|
|
367
|
-
healthKitSource: 'HKQuantityTypeIdentifierHeartRate',
|
|
368
|
-
isHealthKit: true,
|
|
369
|
-
availableFrom: { watch: true, manual: false },
|
|
370
|
-
swimTypes: [SwimType.INDOOR],
|
|
371
|
-
},
|
|
372
|
-
lapStrokeCounts: {
|
|
373
|
-
key: 'lapStrokeCounts',
|
|
374
|
-
label: 'Strokes',
|
|
375
|
-
unit: '',
|
|
376
|
-
category: MetricCategory.TECHNIQUE,
|
|
377
|
-
description: 'Strokes per lap',
|
|
378
|
-
icon: 'hand-left-outline',
|
|
379
|
-
isPerLap: true,
|
|
380
|
-
decimals: 0,
|
|
381
|
-
source: 'HealthKit: HKQuantityTypeIdentifierSwimmingStrokeCount per lap',
|
|
382
|
-
healthKitSource: 'HKQuantityTypeIdentifierSwimmingStrokeCount',
|
|
383
|
-
isHealthKit: true,
|
|
384
|
-
availableFrom: { watch: true, manual: false },
|
|
385
|
-
swimTypes: [SwimType.INDOOR],
|
|
386
|
-
},
|
|
387
437
|
id: {
|
|
388
438
|
key: 'id',
|
|
389
439
|
label: 'ID',
|
|
@@ -420,101 +470,6 @@ exports.METRICS_REGISTRY = {
|
|
|
420
470
|
availableFrom: { watch: false, manual: false },
|
|
421
471
|
swimTypes: [SwimType.INDOOR, SwimType.OPEN_WATER],
|
|
422
472
|
},
|
|
423
|
-
// HealthKit doesn't track turn times
|
|
424
|
-
/*lapTurnTimes: {
|
|
425
|
-
key: 'lapTurnTimes',
|
|
426
|
-
label: 'Turn',
|
|
427
|
-
unit: 's',
|
|
428
|
-
category: MetricCategory.TECHNIQUE,
|
|
429
|
-
description: 'Time spent turning at pool wall per lap',
|
|
430
|
-
icon: 'refresh-circle-outline',
|
|
431
|
-
isPerLap: true,
|
|
432
|
-
decimals: 2,
|
|
433
|
-
availableFrom: { watch: true, manual: false },
|
|
434
|
-
swimTypes: [SwimType.INDOOR],
|
|
435
|
-
formatter: formatAverageTurnTime,
|
|
436
|
-
condition: (s) => !!s.lapTurnTimes?.length,
|
|
437
|
-
},*/
|
|
438
|
-
lapStrokeTypes: {
|
|
439
|
-
key: 'lapStrokeTypes',
|
|
440
|
-
label: 'Stroke',
|
|
441
|
-
category: MetricCategory.TECHNIQUE,
|
|
442
|
-
description: 'Swimming stroke used per lap',
|
|
443
|
-
icon: 'list-outline',
|
|
444
|
-
isPerLap: true,
|
|
445
|
-
availableFrom: { watch: true, manual: false },
|
|
446
|
-
swimTypes: [SwimType.INDOOR],
|
|
447
|
-
formatter: (s) => `${s.lapStrokeTypes.length} types`,
|
|
448
|
-
condition: (s) => !!s.lapStrokeTypes?.length,
|
|
449
|
-
},
|
|
450
|
-
lapPaces: {
|
|
451
|
-
key: 'lapPaces',
|
|
452
|
-
label: 'Pace',
|
|
453
|
-
unit: '/100m',
|
|
454
|
-
category: MetricCategory.PERFORMANCE,
|
|
455
|
-
description: 'Pace per lap',
|
|
456
|
-
isPerLap: true,
|
|
457
|
-
decimals: 1,
|
|
458
|
-
availableFrom: { watch: true, manual: false },
|
|
459
|
-
swimTypes: [SwimType.INDOOR],
|
|
460
|
-
},
|
|
461
|
-
lapCalories: {
|
|
462
|
-
key: 'lapCalories',
|
|
463
|
-
label: 'Cal',
|
|
464
|
-
unit: 'kcal',
|
|
465
|
-
category: MetricCategory.ENERGY,
|
|
466
|
-
description: 'Calories per lap',
|
|
467
|
-
isPerLap: true,
|
|
468
|
-
decimals: 0,
|
|
469
|
-
availableFrom: { watch: true, manual: false },
|
|
470
|
-
swimTypes: [SwimType.INDOOR],
|
|
471
|
-
},
|
|
472
|
-
lapDistances: {
|
|
473
|
-
key: 'lapDistances',
|
|
474
|
-
label: 'Lap Distances',
|
|
475
|
-
unit: 'm',
|
|
476
|
-
category: MetricCategory.PERFORMANCE,
|
|
477
|
-
description: 'Distance per lap',
|
|
478
|
-
isPerLap: true,
|
|
479
|
-
availableFrom: { watch: true, manual: false },
|
|
480
|
-
swimTypes: [SwimType.INDOOR],
|
|
481
|
-
},
|
|
482
|
-
lapSwolfScores: {
|
|
483
|
-
key: 'lapSwolfScores',
|
|
484
|
-
label: 'SWOLF',
|
|
485
|
-
category: MetricCategory.TECHNIQUE,
|
|
486
|
-
description: 'SWOLF per lap',
|
|
487
|
-
isPerLap: true,
|
|
488
|
-
decimals: 0,
|
|
489
|
-
availableFrom: { watch: true, manual: false },
|
|
490
|
-
swimTypes: [SwimType.INDOOR],
|
|
491
|
-
},
|
|
492
|
-
lapStrokeRates: {
|
|
493
|
-
key: 'lapStrokeRates',
|
|
494
|
-
label: 'SR',
|
|
495
|
-
unit: 'SPM',
|
|
496
|
-
category: MetricCategory.TECHNIQUE,
|
|
497
|
-
description: 'Strokes per minute per lap',
|
|
498
|
-
icon: 'repeat-outline',
|
|
499
|
-
isPerLap: true,
|
|
500
|
-
decimals: 1,
|
|
501
|
-
formula: 'Lap Strokes ÷ (Lap Time in Minutes)',
|
|
502
|
-
availableFrom: { watch: true, manual: false },
|
|
503
|
-
swimTypes: [SwimType.INDOOR],
|
|
504
|
-
},
|
|
505
|
-
lapDistancesPerStroke: {
|
|
506
|
-
key: 'lapDistancesPerStroke',
|
|
507
|
-
label: 'DPS',
|
|
508
|
-
unit: 'm',
|
|
509
|
-
category: MetricCategory.TECHNIQUE,
|
|
510
|
-
description: 'Distance covered per stroke per lap',
|
|
511
|
-
icon: 'arrow-forward-outline',
|
|
512
|
-
isPerLap: true,
|
|
513
|
-
decimals: 2,
|
|
514
|
-
formula: 'Lap Distance ÷ Lap Strokes',
|
|
515
|
-
availableFrom: { watch: true, manual: false },
|
|
516
|
-
swimTypes: [SwimType.INDOOR],
|
|
517
|
-
},
|
|
518
473
|
poolLocation: {
|
|
519
474
|
key: 'poolLocation',
|
|
520
475
|
label: 'Pool Location',
|
|
@@ -608,25 +563,27 @@ exports.METRICS_REGISTRY = {
|
|
|
608
563
|
availableFrom: { watch: true, manual: false },
|
|
609
564
|
swimTypes: [SwimType.INDOOR, SwimType.OPEN_WATER],
|
|
610
565
|
},
|
|
611
|
-
|
|
612
|
-
key: '
|
|
613
|
-
label: '
|
|
566
|
+
lapData: {
|
|
567
|
+
key: 'lapData',
|
|
568
|
+
label: 'Lap Data',
|
|
614
569
|
category: MetricCategory.PERFORMANCE,
|
|
615
|
-
description: '
|
|
570
|
+
description: 'Detailed data for each lap',
|
|
616
571
|
isPerSession: true,
|
|
617
|
-
availableFrom: { watch:
|
|
618
|
-
swimTypes: [SwimType.
|
|
619
|
-
condition: (s) => !!s.
|
|
572
|
+
availableFrom: { watch: true, manual: false },
|
|
573
|
+
swimTypes: [SwimType.INDOOR],
|
|
574
|
+
condition: (s) => !!s.lapData?.length,
|
|
620
575
|
},
|
|
621
576
|
};
|
|
622
577
|
exports.MetricsHelper = {
|
|
623
578
|
getMetric: (key) => exports.METRICS_REGISTRY[key],
|
|
624
|
-
getSessionMetrics: () => Object.values(exports.METRICS_REGISTRY).filter((m) => m
|
|
625
|
-
getChartMetrics: () => Object.values(exports.METRICS_REGISTRY).filter((m) => m
|
|
626
|
-
getLapMetrics: () => Object.values(exports.
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
579
|
+
getSessionMetrics: () => Object.values(exports.METRICS_REGISTRY).filter((m) => m?.isPerSession),
|
|
580
|
+
getChartMetrics: () => Object.values(exports.METRICS_REGISTRY).filter((m) => m?.isPerSession && m?.hasChart),
|
|
581
|
+
getLapMetrics: () => Object.values(exports.LAP_METRICS_REGISTRY),
|
|
582
|
+
getLapMetric: (key) => exports.LAP_METRICS_REGISTRY[key],
|
|
583
|
+
getMetricsByCategory: (category) => Object.values(exports.METRICS_REGISTRY).filter((m) => m?.category === category),
|
|
584
|
+
getMetricsBySwimType: (swimType) => Object.values(exports.METRICS_REGISTRY).filter((m) => m?.swimTypes?.includes(swimType)),
|
|
585
|
+
getIndoorMetrics: () => Object.values(exports.METRICS_REGISTRY).filter((m) => m?.swimTypes?.includes(SwimType.INDOOR)),
|
|
586
|
+
getOpenWaterMetrics: () => Object.values(exports.METRICS_REGISTRY).filter((m) => m?.swimTypes?.includes(SwimType.OPEN_WATER)),
|
|
631
587
|
getAllMetricKeys: () => Object.keys(exports.METRICS_REGISTRY),
|
|
588
|
+
getAllLapMetricKeys: () => Object.keys(exports.LAP_METRICS_REGISTRY),
|
|
632
589
|
};
|
package/dist/index.spec.js
CHANGED
|
@@ -35,7 +35,7 @@ describe('Metrics Formatting Functions', () => {
|
|
|
35
35
|
it('should format time in seconds to mm:ss', () => {
|
|
36
36
|
expect((0, index_1.formatTime)(125)).toBe('2:05');
|
|
37
37
|
expect((0, index_1.formatTime)(90)).toBe('1:30');
|
|
38
|
-
expect((0, index_1.formatTime)(3665)).toBe('
|
|
38
|
+
expect((0, index_1.formatTime)(3665)).toBe('1:01:05');
|
|
39
39
|
});
|
|
40
40
|
it('should handle zero', () => {
|
|
41
41
|
expect((0, index_1.formatTime)(0)).toBe('0:00');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swimedge/metrics",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "Shared metrics registry for SwimEdge (frontend, backend, watch)",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -52,4 +52,4 @@
|
|
|
52
52
|
"ts-jest": "^29.1.0",
|
|
53
53
|
"typescript": "^5.0.0"
|
|
54
54
|
}
|
|
55
|
-
}
|
|
55
|
+
}
|