fit-file-parser 4.0.2 → 5.0.1
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/CHANGELOG.md +91 -0
- package/README.md +273 -117
- package/dist/binary.d.ts +7 -4
- package/dist/binary.js +207 -163
- package/dist/cjs/binary.d.ts +7 -4
- package/dist/cjs/binary.js +207 -163
- package/dist/cjs/fit-parser.js +41 -21
- package/dist/cjs/fit.d.ts +15 -7
- package/dist/cjs/fit.js +137 -9078
- package/dist/cjs/fit_types.d.ts +1384 -298
- package/dist/cjs/garmin_profile.generated.d.ts +9 -0
- package/dist/cjs/garmin_profile.generated.js +17838 -0
- package/dist/cjs/helper.js +22 -12
- package/dist/cjs/messages.d.ts +2 -3
- package/dist/cjs/type_generator.d.ts +3 -0
- package/dist/cjs/type_generator.js +56 -27
- package/dist/fit-parser.js +41 -21
- package/dist/fit.d.ts +15 -7
- package/dist/fit.js +136 -9077
- package/dist/fit_types.d.ts +1384 -298
- package/dist/garmin_profile.generated.d.ts +9 -0
- package/dist/garmin_profile.generated.js +17835 -0
- package/dist/helper.js +22 -12
- package/dist/messages.d.ts +2 -3
- package/dist/type_generator.d.ts +3 -0
- package/dist/type_generator.js +55 -27
- package/package.json +9 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,96 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
## 5.0.1
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Run CI and version-driven npm publishing from the repository's `main`
|
|
10
|
+
branch, with a guarded manual recovery path for a missed release.
|
|
11
|
+
|
|
12
|
+
## 5.0.0
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- Generate the complete standard message, field, and type surface from the
|
|
17
|
+
pinned Garmin FIT SDK without handwritten standard-profile overrides.
|
|
18
|
+
- Preserve SDK alphanumeric tokens when generating public `snake_case` names,
|
|
19
|
+
including `n2`, `po2`, `time128`, and Garmin product identifiers.
|
|
20
|
+
- Restrict non-SDK support to a collision-checked allowlist of Garmin fields
|
|
21
|
+
and private messages observed in the external FIT corpus.
|
|
22
|
+
- Emit only parsed FIT values: Garmin product names are no longer inferred,
|
|
23
|
+
and record elapsed/timer values are generated only when
|
|
24
|
+
`elapsedRecordField: true` is requested.
|
|
25
|
+
|
|
26
|
+
### Breaking
|
|
27
|
+
|
|
28
|
+
- Remove compatibility aliases such as `resting_calories`,
|
|
29
|
+
`recovery_advisor`, `repeat_dive_time`, and deprecated time-in-zone names.
|
|
30
|
+
- Remove guessed stress fields, handwritten enum/type additions, placeholder
|
|
31
|
+
zero-mask names, and the misspelled `hip_swing_excercise_name` type.
|
|
32
|
+
- Use the pinned SDK's `cadence_zone_high_bondary` spelling and generated
|
|
33
|
+
alphanumeric field/type spellings instead of manual corrections.
|
|
34
|
+
- Correct generated declarations to expose runtime `Date` values, numeric FIT
|
|
35
|
+
`bool` fields and unknown enum IDs, decoded mask objects, nullable array
|
|
36
|
+
entries, and optional profile fields.
|
|
37
|
+
- Keep undated cascade rows in file order and avoid duplicating them when a lap
|
|
38
|
+
or session boundary timestamp is absent.
|
|
39
|
+
|
|
40
|
+
## 4.1.1
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
|
|
44
|
+
- Apply Garmin FIT profile scale and offset to primitive numeric fields, while
|
|
45
|
+
retaining semicircle conversion only for fields declared in semicircles.
|
|
46
|
+
- Apply FIT developer-field offsets with the parser's equivalent signed form,
|
|
47
|
+
including scaled signed developer values.
|
|
48
|
+
- Decode native diving ascent-rate fields as meters per second instead of
|
|
49
|
+
geographic coordinates.
|
|
50
|
+
- Decode native dive depth and bottom-time fields with their Garmin FIT SDK
|
|
51
|
+
scale instead of exposing their encoded integer representation.
|
|
52
|
+
- Keep the pinned Garmin SDK authoritative for standard field types, arrays,
|
|
53
|
+
scales, offsets, and units while retaining compatible public field names.
|
|
54
|
+
|
|
55
|
+
## 4.1.0
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
|
|
59
|
+
- Generate all 124 standard messages, 1,406 fields, and 200 profile types from
|
|
60
|
+
the exactly pinned Garmin FIT SDK 21.208.0 profile.
|
|
61
|
+
- Retain every recognized message in file order under the typed
|
|
62
|
+
`ParsedFit.messages` index without changing existing list, cascade, or
|
|
63
|
+
singleton outputs.
|
|
64
|
+
- Decode Garmin strength-training `set` messages in list and cascade modes.
|
|
65
|
+
- Add reproducible generated-profile and privacy-safe external corpus audits,
|
|
66
|
+
and enforce profile freshness and coverage in CI.
|
|
67
|
+
|
|
68
|
+
### Fixed
|
|
69
|
+
|
|
70
|
+
- Decode fields from their wire base types, including compatible developer
|
|
71
|
+
enum/uint8/byte definitions and correctly sized numeric arrays.
|
|
72
|
+
- Reconstruct compressed timestamps and keep timestamp state isolated between
|
|
73
|
+
parser instances.
|
|
74
|
+
- Accept omitted header CRCs, validate file CRCs across the complete FIT header
|
|
75
|
+
and data section, and report strict header and file CRC failures explicitly.
|
|
76
|
+
- Reject structurally unsafe FIT inputs consistently in callback and Promise
|
|
77
|
+
APIs while retaining force-mode recovery for CRC corruption.
|
|
78
|
+
- Correct Garmin profile mappings for OHR settings, monitoring HR, sleep,
|
|
79
|
+
time-in-zone, altitude offsets, and lap/segment flow and grit summaries.
|
|
80
|
+
- Correct Celsius-to-Kelvin conversion, add `celsius` as the canonical
|
|
81
|
+
temperature unit, and retain `°C` as a supported alias.
|
|
82
|
+
|
|
83
|
+
### Compatibility and documentation
|
|
84
|
+
|
|
85
|
+
- Preserve compatible legacy field names, scales, value shapes, parser
|
|
86
|
+
signatures, output modes, and date behavior while adding canonical profile
|
|
87
|
+
names.
|
|
88
|
+
- Add regression coverage for temperature, pressure, validation, compressed
|
|
89
|
+
timestamps, generated profile messages, repeated messages, and MTB
|
|
90
|
+
flow/grit data.
|
|
91
|
+
- Refresh the README with current runtime, API, units, output modes, developer
|
|
92
|
+
fields, encoder behavior, and repository commands.
|
|
93
|
+
|
|
3
94
|
## 4.0.2
|
|
4
95
|
|
|
5
96
|
- Preserve record alignment when developer-field descriptions are missing or
|
package/README.md
CHANGED
|
@@ -1,181 +1,337 @@
|
|
|
1
1
|
# fit-file-parser
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
[](https://github.com/jimmykane/fit-parser/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/fit-file-parser)
|
|
5
|
+
[](./LICENSE)
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
Parse and encode FIT files in JavaScript and TypeScript. The parser supports
|
|
8
|
+
files produced by Garmin, Polar, Suunto, and other FIT-compatible devices,
|
|
9
|
+
including developer-defined data.
|
|
7
10
|
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- Parse Node.js `Buffer` and standard `ArrayBuffer` inputs.
|
|
14
|
+
- Choose flat lists, nested activity data, or both output shapes.
|
|
15
|
+
- Convert speed, length, temperature, and pressure fields to preferred units.
|
|
16
|
+
- Decode developer fields while preserving record alignment when descriptions
|
|
17
|
+
arrive after their definitions.
|
|
18
|
+
- Encode profile-agnostic FIT messages with validated field definitions and
|
|
19
|
+
CRCs.
|
|
20
|
+
- Use ESM or CommonJS with bundled TypeScript declarations.
|
|
21
|
+
|
|
22
|
+
## Requirements
|
|
23
|
+
|
|
24
|
+
- Node.js 20 or newer
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
npm install fit-file-parser
|
|
8
30
|
```
|
|
9
|
-
$ npm install fit-file-parser --save
|
|
10
|
-
```
|
|
11
31
|
|
|
12
|
-
##
|
|
32
|
+
## Migrating from 4.x to 5.0
|
|
33
|
+
|
|
34
|
+
Version 5.0 is a breaking release because parsed output now follows the pinned
|
|
35
|
+
Garmin FIT SDK profile without compatibility aliases or guessed fields. Parser
|
|
36
|
+
construction, module imports, output modes, and parser options are unchanged.
|
|
37
|
+
|
|
38
|
+
Update field access, destructuring, persisted schemas, and snapshots to use the
|
|
39
|
+
SDK-backed names. Common migrations include:
|
|
40
|
+
|
|
41
|
+
| 4.x name | 5.0 name |
|
|
42
|
+
| ------------------------------ | ---------------------------- |
|
|
43
|
+
| `speed_1s` | `speed1s` |
|
|
44
|
+
| `start_n_2`, `end_n_2` | `start_n2`, `end_n2` |
|
|
45
|
+
| `o_2_toxicity` | `o2_toxicity` |
|
|
46
|
+
| `avg_spo_2`, `reading_spo_2` | `avg_spo2`, `reading_spo2` |
|
|
47
|
+
| `po_2` | `po2` |
|
|
48
|
+
| `cycle_length_16` | `cycle_length16` |
|
|
49
|
+
| `map_3_sample_mean` | `map3_sample_mean` |
|
|
50
|
+
| `time_256` | `time256` |
|
|
51
|
+
| `last_night_5_min_high` | `last_night5_min_high` |
|
|
52
|
+
| `average_7_day_deviation` | `average7_day_deviation` |
|
|
53
|
+
| `spo_2_data`, `hsa_spo_2_data` | `spo2_data`, `hsa_spo2_data` |
|
|
54
|
+
| `repeat_dive_time` | `repeat_dive_interval` |
|
|
55
|
+
| `cadence_zone_high_boundary` | `cadence_zone_high_bondary` |
|
|
56
|
+
| `HipSwingExcerciseName` | `HipSwingExerciseName` |
|
|
57
|
+
|
|
58
|
+
The same alphanumeric-token rule applies to enum strings, for example
|
|
59
|
+
`camera_orientation_90` becomes `camera_orientation90`, `po_2_warn` becomes
|
|
60
|
+
`po2_warn`, and `power_3s` becomes `power3s`. The generated TypeScript
|
|
61
|
+
declarations are the exhaustive name and value reference for the pinned SDK.
|
|
62
|
+
|
|
63
|
+
The handwritten `resting_calories` and guessed `recovery_advisor` fields have
|
|
64
|
+
no 5.0 replacement. Other behavior to account for during migration:
|
|
65
|
+
|
|
66
|
+
- `product_name` is emitted only when it exists in the FIT input. It is no
|
|
67
|
+
longer inferred from `manufacturer` and `product`.
|
|
68
|
+
- Record `elapsed_time` and `timer_time` require
|
|
69
|
+
`elapsedRecordField: true`.
|
|
70
|
+
- FIT timestamps are typed as `Date`, FIT `bool` values remain numeric, mask
|
|
71
|
+
fields are `{ value, ...flags }` objects, unknown enum values remain numbers,
|
|
72
|
+
and array entries may be `null` when the FIT invalid sentinel is retained.
|
|
73
|
+
- Every profile field is optional because individual FIT message definitions
|
|
74
|
+
determine which fields are present.
|
|
75
|
+
- When upgrading from 4.1.0 or earlier, remove application-side scale or offset
|
|
76
|
+
corrections for parsed numeric values, including dive depth, bottom time,
|
|
77
|
+
ascent rate, and developer fields. The parser now applies the SDK metadata.
|
|
78
|
+
|
|
79
|
+
## Quick start
|
|
80
|
+
|
|
81
|
+
The Promise API is the simplest way to parse a file:
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
import { readFile } from 'node:fs/promises'
|
|
85
|
+
import FitParser from 'fit-file-parser'
|
|
86
|
+
|
|
87
|
+
const content = await readFile('./activity.fit')
|
|
88
|
+
const parser = new FitParser({
|
|
89
|
+
mode: 'list',
|
|
90
|
+
speedUnit: 'km/h',
|
|
91
|
+
lengthUnit: 'km',
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
const data = await parser.parseAsync(content)
|
|
13
95
|
|
|
14
|
-
|
|
96
|
+
console.log({
|
|
97
|
+
sessions: data.sessions?.length ?? 0,
|
|
98
|
+
laps: data.laps?.length ?? 0,
|
|
99
|
+
records: data.records?.length ?? 0,
|
|
100
|
+
})
|
|
101
|
+
```
|
|
15
102
|
|
|
16
|
-
###
|
|
103
|
+
### Callback API
|
|
17
104
|
|
|
18
105
|
```javascript
|
|
19
|
-
import
|
|
106
|
+
import { readFile } from 'node:fs'
|
|
20
107
|
import FitParser from 'fit-file-parser'
|
|
21
108
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
109
|
+
readFile('./activity.fit', (readError, content) => {
|
|
110
|
+
if (readError) {
|
|
111
|
+
console.error(readError)
|
|
112
|
+
return
|
|
26
113
|
}
|
|
27
|
-
const fitParser = new FitParser({
|
|
28
|
-
force: true,
|
|
29
|
-
speedUnit: 'km/h',
|
|
30
|
-
lengthUnit: 'km',
|
|
31
|
-
temperatureUnit: 'kelvin',
|
|
32
|
-
pressureUnit: 'bar', // accept bar, cbar and psi (default is bar)
|
|
33
|
-
elapsedRecordField: true,
|
|
34
|
-
mode: 'cascade',
|
|
35
|
-
})
|
|
36
114
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
console.log(JSON.stringify(data))
|
|
115
|
+
const parser = new FitParser()
|
|
116
|
+
parser.parse(content, (parseError, data) => {
|
|
117
|
+
if (parseError) {
|
|
118
|
+
console.error(parseError)
|
|
119
|
+
return
|
|
45
120
|
}
|
|
121
|
+
|
|
122
|
+
console.log(data)
|
|
46
123
|
})
|
|
47
124
|
})
|
|
48
125
|
```
|
|
49
126
|
|
|
50
|
-
|
|
127
|
+
Parser errors are strings. `parseAsync()` rejects with the same value that the
|
|
128
|
+
callback API receives as its first argument.
|
|
51
129
|
|
|
52
|
-
|
|
53
|
-
import fs from 'node:fs/promises'
|
|
54
|
-
import FitParser from 'fit-file-parser'
|
|
130
|
+
## Parser options
|
|
55
131
|
|
|
56
|
-
|
|
57
|
-
const fitObject = await fitParser.parseAsync(buffer)
|
|
58
|
-
```
|
|
132
|
+
All options are optional.
|
|
59
133
|
|
|
60
|
-
|
|
134
|
+
| Option | Values | Default | Behavior |
|
|
135
|
+
| -------------------- | --------------------------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
136
|
+
| `mode` | `list`, `cascade`, `both` | `list` | Controls whether primary activity collections are returned as root lists, nested data, or both. |
|
|
137
|
+
| `force` | `true`, `false` | `true` | Skips header and file CRC validation and enables supported best-effort field recovery. Structural header and data bounds are always validated. |
|
|
138
|
+
| `speedUnit` | `m/s`, `km/h`, `mph` | `m/s` | Converts speed-related fields. |
|
|
139
|
+
| `lengthUnit` | `m`, `km`, `mi` | `m` | Converts distance, altitude, and other length-related fields. |
|
|
140
|
+
| `temperatureUnit` | `celsius`, `°C`, `kelvin`, `fahrenheit` | `celsius` | Converts temperature fields. `°C` remains available as a legacy alias. |
|
|
141
|
+
| `pressureUnit` | `bar`, `cbar`, `psi` | `bar` | Converts pressure and tank-pressure fields. |
|
|
142
|
+
| `elapsedRecordField` | `true`, `false` | `false` | Adds `elapsed_time` and `timer_time`, in seconds, to records. |
|
|
61
143
|
|
|
62
|
-
`
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
values use `bigint`; strings and numeric arrays use exact-size raw
|
|
66
|
-
`Uint8Array` values.
|
|
144
|
+
`force: true` does not make arbitrary bytes a valid FIT file. Inputs that are
|
|
145
|
+
too short, have an invalid header size or signature, or declare data beyond the
|
|
146
|
+
available bytes are rejected in both modes.
|
|
67
147
|
|
|
68
|
-
|
|
69
|
-
import { FitBaseType, FitEncoder } from 'fit-file-parser'
|
|
148
|
+
## Output modes
|
|
70
149
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
{ number: 0, size: 1, baseType: FitBaseType.Enum, value: 6 }, // FileId.type = course
|
|
74
|
-
{ number: 4, size: 4, baseType: FitBaseType.Uint32, value: FitEncoder.toFitTimestamp(new Date()) },
|
|
75
|
-
])
|
|
150
|
+
The mode controls where sessions, laps, records, and related activity
|
|
151
|
+
collections are exposed.
|
|
76
152
|
|
|
77
|
-
|
|
153
|
+
| Mode | Root lists | Nested under `activity` | Default |
|
|
154
|
+
| --------- | ---------- | ----------------------- | ------- |
|
|
155
|
+
| `list` | Yes | No | Yes |
|
|
156
|
+
| `cascade` | No | Yes | No |
|
|
157
|
+
| `both` | Yes | Yes | No |
|
|
158
|
+
|
|
159
|
+
In cascade output, sessions contain their laps and laps contain their records
|
|
160
|
+
and lengths. Other parsed FIT message collections remain available where the
|
|
161
|
+
parser exposes them.
|
|
162
|
+
|
|
163
|
+
Every recognized message is also retained in file order in `data.messages`.
|
|
164
|
+
This additive index is useful for message kinds that historically exposed
|
|
165
|
+
only the last value at the root:
|
|
166
|
+
|
|
167
|
+
```javascript
|
|
168
|
+
const workoutSteps = data.messages?.workout_step ?? []
|
|
169
|
+
const diveSummaries = data.messages?.dive_summary ?? []
|
|
78
170
|
```
|
|
79
171
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
The encoder validates field definitions and numeric ranges before writing, so
|
|
83
|
-
an exception never leaves a partial message in the output.
|
|
172
|
+
Existing root lists, cascade nesting, and last-message root properties remain
|
|
173
|
+
unchanged.
|
|
84
174
|
|
|
85
|
-
##
|
|
175
|
+
## Profile-backed output
|
|
86
176
|
|
|
87
|
-
|
|
177
|
+
Standard message names, field names, enum values, wire types, scales, offsets,
|
|
178
|
+
arrays, and units come from the exactly pinned Garmin FIT SDK profile. Public
|
|
179
|
+
names use the parser's generated `snake_case` form while preserving SDK
|
|
180
|
+
alphanumeric tokens such as `n2`, `po2`, and `time128`. The parser does not add
|
|
181
|
+
compatibility aliases for alternate field spellings.
|
|
88
182
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
183
|
+
The small vendor extension table contains only Garmin fields and private
|
|
184
|
+
messages observed in the external FIT corpus. Extensions cannot replace a
|
|
185
|
+
standard SDK field or type value; the profile audit rejects collisions and
|
|
186
|
+
unregistered additions.
|
|
92
187
|
|
|
93
|
-
|
|
188
|
+
Only values present in the FIT input are emitted. In particular,
|
|
189
|
+
`product_name` is not inferred from `manufacturer` and `product`, and record
|
|
190
|
+
`elapsed_time` and `timer_time` are added only when `elapsedRecordField: true`
|
|
191
|
+
is requested. Parsed FIT timestamps are `Date` objects, FIT `bool` fields keep
|
|
192
|
+
their numeric wire values, mask fields decode to `{ value, ...flags }` objects,
|
|
193
|
+
unknown enum IDs remain numbers, and invalid entries retained inside FIT arrays
|
|
194
|
+
are `null`. All profile fields are optional because each FIT message definition
|
|
195
|
+
chooses which fields are present.
|
|
94
196
|
|
|
95
|
-
|
|
96
|
-
npm test
|
|
97
|
-
```
|
|
197
|
+
## Inputs
|
|
98
198
|
|
|
99
|
-
|
|
199
|
+
Both parser methods accept:
|
|
100
200
|
|
|
101
|
-
|
|
201
|
+
- Node.js `Buffer`
|
|
202
|
+
- `ArrayBuffer`
|
|
102
203
|
|
|
204
|
+
```javascript
|
|
205
|
+
const parsed = await new FitParser().parseAsync(arrayBuffer)
|
|
103
206
|
```
|
|
104
207
|
|
|
105
|
-
|
|
208
|
+
## Developer fields
|
|
106
209
|
|
|
107
|
-
|
|
210
|
+
FIT producers may define custom fields outside the standard profile. The
|
|
211
|
+
parser consumes every developer field's declared byte size so later messages
|
|
212
|
+
stay aligned. If a field description is not available yet, that value is
|
|
213
|
+
omitted. Subsequent values are decoded by name once the description appears.
|
|
108
214
|
|
|
109
|
-
|
|
215
|
+
## Encoding
|
|
110
216
|
|
|
111
|
-
|
|
217
|
+
`FitEncoder` writes FIT headers, message definitions, data messages, and CRCs.
|
|
218
|
+
It is profile-agnostic: callers provide profile message and field numbers,
|
|
219
|
+
base types, sizes, and values in their raw FIT representation. Applying FIT
|
|
220
|
+
scales and offsets is the caller's responsibility.
|
|
112
221
|
|
|
113
|
-
|
|
222
|
+
```javascript
|
|
223
|
+
import { FitBaseType, FitEncoder } from 'fit-file-parser'
|
|
114
224
|
|
|
115
|
-
|
|
116
|
-
|
|
225
|
+
const encoder = new FitEncoder()
|
|
226
|
+
encoder.writeMessage(0, [
|
|
227
|
+
{
|
|
228
|
+
number: 0,
|
|
229
|
+
size: 1,
|
|
230
|
+
baseType: FitBaseType.Enum,
|
|
231
|
+
value: 6,
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
number: 4,
|
|
235
|
+
size: 4,
|
|
236
|
+
baseType: FitBaseType.Uint32,
|
|
237
|
+
value: FitEncoder.toFitTimestamp(new Date()),
|
|
238
|
+
},
|
|
239
|
+
])
|
|
240
|
+
|
|
241
|
+
const fitBytes = encoder.close()
|
|
117
242
|
```
|
|
118
243
|
|
|
119
|
-
|
|
244
|
+
`writeMessage(globalMessageNumber, fields, localMessageNumber?)` accepts local
|
|
245
|
+
message numbers from 0 through 15. Definitions are emitted automatically and
|
|
246
|
+
reused until the shape assigned to that local number changes. `close()` returns
|
|
247
|
+
a `Uint8Array`.
|
|
120
248
|
|
|
121
|
-
|
|
122
|
-
npm run lint
|
|
123
|
-
```
|
|
249
|
+
The encoder also provides:
|
|
124
250
|
|
|
125
|
-
|
|
251
|
+
- `FitEncoder.string(value)` for null-terminated UTF-8 field bytes.
|
|
252
|
+
- `FitEncoder.toFitTimestamp(value)` for FIT timestamps.
|
|
253
|
+
- `FitEncoder.calculateCRC(bytes)` for FIT-compatible CRC calculation.
|
|
126
254
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
255
|
+
Scalar 64-bit values use `bigint`. Strings, numeric arrays, and other
|
|
256
|
+
variable-length values use exact-size `Uint8Array` values. Invalid field
|
|
257
|
+
definitions or numeric ranges throw before a partial message is written.
|
|
130
258
|
|
|
131
|
-
##
|
|
259
|
+
## TypeScript and module formats
|
|
132
260
|
|
|
133
|
-
|
|
261
|
+
The package includes TypeScript declarations and exports
|
|
262
|
+
`FitParserOptions`, `FitEncoderField`, and `FitEncoderOptions`.
|
|
134
263
|
|
|
135
|
-
|
|
264
|
+
ESM:
|
|
136
265
|
|
|
137
|
-
|
|
266
|
+
```javascript
|
|
267
|
+
import FitParser, { FitBaseType, FitEncoder } from 'fit-file-parser'
|
|
268
|
+
```
|
|
138
269
|
|
|
139
|
-
|
|
140
|
-
- `cascade`: Returned object is organized as a tree, eg. each lap contains a `records` fields, that is an array of its records (**default**)
|
|
141
|
-
- `list`: Returned object is organized as lists of sessions, laps, records, etc..., without parent-child relation
|
|
142
|
-
- `both`: A mix of the two other modes, eg. `records` are available inside the root field as well as inside each laps
|
|
143
|
-
- `lengthUnit`: String
|
|
144
|
-
- `m`: Lengths are in meters (**default**)
|
|
145
|
-
- `km`: Lengths are in kilometers
|
|
146
|
-
- `mi`: Lengths are in miles
|
|
147
|
-
- `temperatureUnit`: String
|
|
148
|
-
- `celsius`:Temperatures are in °C (**default**)
|
|
149
|
-
- `kelvin`: Temperatures are in °K
|
|
150
|
-
- `fahrenheit`: Temperatures are in °F
|
|
151
|
-
- `speedUnit`: String
|
|
152
|
-
- `m/s`: Speeds are in meters per seconds (**default**)
|
|
153
|
-
- `km/h`: Speeds are in kilometers per hour
|
|
154
|
-
- `mph`: Speeds are in miles per hour
|
|
155
|
-
- `force`: Boolean
|
|
156
|
-
- `true`: Continues even if they are errors (**default for now**)
|
|
157
|
-
- `false`: Stops if an error occurs
|
|
158
|
-
- `elapsedRecordField`: Boolean
|
|
159
|
-
- `true`: Includes `elapsed_time`, containing the elapsed time in seconds since the first record, and `timer_time`, containing the time shown on the device, inside each `record` field
|
|
160
|
-
- `false` (**default**)
|
|
270
|
+
CommonJS:
|
|
161
271
|
|
|
162
|
-
|
|
272
|
+
```javascript
|
|
273
|
+
const {
|
|
274
|
+
default: FitParser,
|
|
275
|
+
FitBaseType,
|
|
276
|
+
FitEncoder,
|
|
277
|
+
} = require('fit-file-parser')
|
|
278
|
+
```
|
|
163
279
|
|
|
164
|
-
|
|
280
|
+
## Development
|
|
165
281
|
|
|
166
|
-
|
|
282
|
+
Run commands from the repository root.
|
|
283
|
+
|
|
284
|
+
| Command | Purpose |
|
|
285
|
+
| ---------------------------------- | -------------------------------------------------- |
|
|
286
|
+
| `npm ci` | Install locked dependencies. |
|
|
287
|
+
| `npm run build` | Build ESM and CommonJS output. |
|
|
288
|
+
| `npm test -- --run` | Run the complete test suite once. |
|
|
289
|
+
| `npm test -- --run test/<file>.ts` | Run a focused test file. |
|
|
290
|
+
| `npm run codegen` | Regenerate the Garmin profile and public types. |
|
|
291
|
+
| `npm run codegen:check` | Verify both generated files are current. |
|
|
292
|
+
| `npm run profile:audit` | Audit SDK profile coverage and private overlays. |
|
|
293
|
+
| `npm run corpus:check -- <path>` | Validate an external FIT corpus without file data. |
|
|
294
|
+
| `npm run lint` | Check lint and formatting rules. |
|
|
295
|
+
| `npm run fmt` | Apply the configured formatting rules. |
|
|
296
|
+
| `npm run type-check` | Run TypeScript without emitting files. |
|
|
297
|
+
| `npm run examples` | Build and regenerate checked-in example outputs. |
|
|
298
|
+
| `npm run check` | Run profile audit, lint, types, tests, and builds. |
|
|
299
|
+
|
|
300
|
+
### External FIT corpus (optional)
|
|
301
|
+
|
|
302
|
+
The external corpus is not part of this repository or the npm package. For the
|
|
303
|
+
standard contributor layout, clone it alongside this checkout, then run the
|
|
304
|
+
aggregate-only validation command:
|
|
305
|
+
|
|
306
|
+
```sh
|
|
307
|
+
git clone https://github.com/ThomasKuehne/FIT-test-files.git ../FIT-test-files
|
|
308
|
+
npm run corpus:check -- ../FIT-test-files --allow-force-recovery
|
|
309
|
+
```
|
|
167
310
|
|
|
168
|
-
|
|
311
|
+
The command accepts any corpus path; the sibling location is only a convenient
|
|
312
|
+
convention. The corpus contains a known header-CRC failure that is expected to
|
|
313
|
+
recover only in force mode. It reports aggregate counts and never prints file
|
|
314
|
+
names or parsed activity data.
|
|
169
315
|
|
|
170
|
-
|
|
316
|
+
Do not edit `src/garmin_profile.generated.ts` or `src/fit_types.ts` manually.
|
|
317
|
+
Update the pinned SDK, audited vendor extensions, or a generator, then run
|
|
318
|
+
`npm run codegen`.
|
|
319
|
+
|
|
320
|
+
Repository-specific automation guidance is tracked in
|
|
321
|
+
[`.agent/README.md`](./.agent/README.md). More examples are available in the
|
|
322
|
+
[`examples`](./examples) directory, and release notes are in the
|
|
323
|
+
[`CHANGELOG`](./CHANGELOG.md).
|
|
171
324
|
|
|
172
|
-
|
|
325
|
+
## Contributors
|
|
173
326
|
|
|
174
|
-
|
|
175
|
-
|
|
327
|
+
This project started from work by
|
|
328
|
+
[Pierre Jacquier](https://github.com/pierremtb). Thanks to
|
|
329
|
+
[Mikael Lofjärd](https://github.com/mlofjard) for
|
|
330
|
+
[his early prototype](https://github.com/mlofjard/jsonfit), and to everyone in
|
|
331
|
+
[`CONTRIBUTORS.md`](./CONTRIBUTORS.md).
|
|
176
332
|
|
|
177
333
|
## License
|
|
178
334
|
|
|
179
|
-
MIT
|
|
335
|
+
MIT; see [`LICENSE`](./LICENSE).
|
|
180
336
|
|
|
181
|
-
|
|
337
|
+
Copyright 2019-present Dimitrios Kanellopoulos.
|
package/dist/binary.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { FitParserOptions } from './fit-parser.js';
|
|
2
|
-
import type { FieldDefinition } from './fit.js';
|
|
3
|
-
import type { MesgNum } from './fit_types.js';
|
|
2
|
+
import type { FieldDefinition, MessageName } from './fit.js';
|
|
4
3
|
import { Buffer } from 'buffer';
|
|
5
4
|
export interface MessageTypeDefinition {
|
|
6
5
|
littleEndian: boolean;
|
|
@@ -17,9 +16,13 @@ export interface DeveloperFieldDefinition {
|
|
|
17
16
|
resolvedFieldDef?: FieldDefinition;
|
|
18
17
|
resolvedFrom?: unknown;
|
|
19
18
|
}
|
|
19
|
+
export interface DecoderState {
|
|
20
|
+
lastTimestamp?: number;
|
|
21
|
+
monitoringTimestamp?: number;
|
|
22
|
+
}
|
|
20
23
|
export declare function addEndian(littleEndian: boolean, bytes: number[]): number;
|
|
21
|
-
export declare function readRecord(blob: Uint8Array, messageTypes: MessageTypeDefinition[], developerFields: any[], startIndex: number, options: FitParserOptions, startDate: number | undefined, pausedTime: number, dataView?: DataView): {
|
|
22
|
-
messageType:
|
|
24
|
+
export declare function readRecord(blob: Uint8Array, messageTypes: MessageTypeDefinition[], developerFields: any[], startIndex: number, options: FitParserOptions, startDate: number | undefined, pausedTime: number, dataView?: DataView, decoderState?: DecoderState): {
|
|
25
|
+
messageType: MessageName | 'definition' | '';
|
|
23
26
|
nextIndex: number;
|
|
24
27
|
message?: any;
|
|
25
28
|
};
|