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 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
- > Parse your .FIT files easily, directly from JS.
4
- > Written in Typescript
3
+ [![CI](https://github.com/jimmykane/fit-parser/actions/workflows/ci.yml/badge.svg)](https://github.com/jimmykane/fit-parser/actions/workflows/ci.yml)
4
+ [![npm](https://img.shields.io/npm/v/fit-file-parser.svg)](https://www.npmjs.com/package/fit-file-parser)
5
+ [![license](https://img.shields.io/npm/l/fit-file-parser.svg)](./LICENSE)
5
6
 
6
- ## Install
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
- ## How to use
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
- See in [examples](./examples) folder:
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
- ### using callbacks
103
+ ### Callback API
17
104
 
18
105
  ```javascript
19
- import fs from 'node:fs/promises'
106
+ import { readFile } from 'node:fs'
20
107
  import FitParser from 'fit-file-parser'
21
108
 
22
- fs.readFile('./example.fit', (err, content) => {
23
- // Create a FitParser instance (options argument is optional)
24
- if (err) {
25
- console.error(err)
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
- // Parse your file
38
- fitParser.parse(content, (error, data) => {
39
- // Handle result of parse method
40
- if (error) {
41
- console.error(error)
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
- ### using async/await
127
+ Parser errors are strings. `parseAsync()` rejects with the same value that the
128
+ callback API receives as its first argument.
51
129
 
52
- ```javascript
53
- import fs from 'node:fs/promises'
54
- import FitParser from 'fit-file-parser'
130
+ ## Parser options
55
131
 
56
- const buffer = await fs.readFile('./example.fit')
57
- const fitObject = await fitParser.parseAsync(buffer)
58
- ```
132
+ All options are optional.
59
133
 
60
- ## Encoding
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
- `FitEncoder` writes FIT headers, message definitions, data messages, and CRCs.
63
- It is profile-agnostic: callers provide profile field identifiers and values in
64
- their raw FIT representation (including any scale or offset). Scalar 64-bit
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
- ```javascript
69
- import { FitBaseType, FitEncoder } from 'fit-file-parser'
148
+ ## Output modes
70
149
 
71
- const encoder = new FitEncoder()
72
- encoder.writeMessage(0, [
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
- const fitBytes = encoder.close()
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
- Use a distinct local message number (the optional third `writeMessage`
81
- argument) for each recurring message shape to avoid redundant definitions.
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
- ## Development
175
+ ## Profile-backed output
86
176
 
87
- To build the project, run:
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
- npm run build
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
- To run tests, run:
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
- To rebuild the typescript types (as they are autogenerated from the `FIT` object) run:
199
+ Both parser methods accept:
100
200
 
101
- ```npm run codegen
201
+ - Node.js `Buffer`
202
+ - `ArrayBuffer`
102
203
 
204
+ ```javascript
205
+ const parsed = await new FitParser().parseAsync(arrayBuffer)
103
206
  ```
104
207
 
105
- > this will update the file `src/fit_types.ts` as it is only running with node (with type stripping), regenerating them requires node>=245
208
+ ## Developer fields
106
209
 
107
- To run the codegen in watch mode during local development, run:
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
- ```npm run dev
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
- To build the local examples, run:
222
+ ```javascript
223
+ import { FitBaseType, FitEncoder } from 'fit-file-parser'
114
224
 
115
- ```
116
- npm run examples
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
- To lint and format the code, run:
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
- To run the typechecker, run:
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
- npm run type-check
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
- ## API Documentation
259
+ ## TypeScript and module formats
132
260
 
133
- ### new FitParser(Object _options_)
261
+ The package includes TypeScript declarations and exports
262
+ `FitParserOptions`, `FitEncoderField`, and `FitEncoderOptions`.
134
263
 
135
- Needed to create a new instance. _options_ is optional, and is used to customize the returned object.
264
+ ESM:
136
265
 
137
- Allowed properties :
266
+ ```javascript
267
+ import FitParser, { FitBaseType, FitEncoder } from 'fit-file-parser'
268
+ ```
138
269
 
139
- - `mode`: String
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
- ### fitParser.parse(Buffer _file_, Function _callback_)
272
+ ```javascript
273
+ const {
274
+ default: FitParser,
275
+ FitBaseType,
276
+ FitEncoder,
277
+ } = require('fit-file-parser')
278
+ ```
163
279
 
164
- _callback_ receives two arguments, the first as a error String, and the second as Object, result of parsing.
280
+ ## Development
165
281
 
166
- ### fitParser.parseAsync(Buffer _file_)
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
- returns a Promise that resolves to the result of parsing.
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
- ## Contributors
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
- All started thanks to [Pierre Jacquier](https://github.com/pierremtb)
325
+ ## Contributors
173
326
 
174
- Big thanks to [Mikael Lofjärd](https://github.com/mlofjard) for [his early prototype](https://github.com/mlofjard/jsonfit).
175
- See [CONTRIBUTORS](./CONTRIBUTORS.md).
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 license; see [LICENSE](./LICENSE).
335
+ MIT; see [`LICENSE`](./LICENSE).
180
336
 
181
- (c) 2019 Dimitrios Kanellopoulos
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: MesgNum | '';
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
  };