@garmin/fitsdk 21.202.0 → 21.208.0

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
@@ -81,6 +81,7 @@ const { messages, errors } = decoder.read({
81
81
  decodeMemoGlobs: false,
82
82
  skipHeader: false,
83
83
  dataOnly: false,
84
+ legacyArrayMode: false, // Deprecated
84
85
  });
85
86
  ````
86
87
  #### mesgListener = (messageNumber, message) => {}
@@ -193,6 +194,16 @@ When true, the decoder will read past the 14-byte header and ignore its contents
193
194
  #### dataOnly: true | false
194
195
  When true, the decoder will read the file as if the 14-byte header was not written. The decoder then assumes the file begins with a message definition and assumes file data size from the size of the file's stream.
195
196
 
197
+ #### legacyArrayMode: true | false *(Deprecated)*
198
+ legacyArrayMode is deprecated and will be removed by EOY 2026.
199
+
200
+ When false *(default)*, the decoder will adhere to the profile for array fields.
201
+
202
+ Array fields will always be returned as arrays, even when there is only one element
203
+ Non-array fields will always return a single value, even when there are multiple values
204
+ Setting legacyArrayMode option to true will revert to pre-v21.205 behavior
205
+
206
+
196
207
  ## Creating Streams
197
208
  Stream objects contain the binary FIT data to be decoded. Stream objects can be created from byte-arrays, ArrayBuffers, and Node.js Buffers. Internally the Stream class uses an ArrayBuffer to manage the byte stream.
198
209
  #### From a Byte Array
package/package.json CHANGED
@@ -1,23 +1,25 @@
1
1
  {
2
- "name": "@garmin/fitsdk",
3
- "version": "21.202.0",
4
- "description": "FIT JavaScript SDK",
5
- "main": "src/index.js",
6
- "type": "module",
7
- "scripts": {
8
- "build": "node .",
9
- "test": "vitest run"
10
- },
11
- "author": "Garmin International, Inc.",
12
- "license": "SEE LICENSE IN LICENSE.txt",
13
- "repository": {
14
- "type": "git",
15
- "url": "https://github.com/garmin/fit-javascript-sdk"
16
- },
17
- "files": [
18
- "src/"
19
- ],
20
- "devDependencies": {
21
- "vitest": "^2.1.8"
22
- }
23
- }
2
+ "name": "@garmin/fitsdk",
3
+ "version": "21.208.0",
4
+ "description": "FIT JavaScript SDK",
5
+ "main": "src/index.js",
6
+ "types": "src/index.d.ts",
7
+ "type": "module",
8
+ "scripts": {
9
+ "test": "vitest run --silent=passed-only --typecheck"
10
+ },
11
+ "author": "Garmin International, Inc.",
12
+ "license": "SEE LICENSE IN LICENSE.txt",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/garmin/fit-javascript-sdk"
16
+ },
17
+ "files": [
18
+ "src/"
19
+ ],
20
+ "devDependencies": {
21
+ "@types/node": "^22.0.0",
22
+ "typescript": "^5.0.0",
23
+ "vitest": "^4.1.5"
24
+ }
25
+ }
@@ -5,8 +5,8 @@
5
5
  // Transfer (FIT) Protocol License.
6
6
  /////////////////////////////////////////////////////////////////////////////////////////////
7
7
  // ****WARNING**** This file is auto-generated! Do NOT edit this file.
8
- // Profile Version = 21.202.0Release
9
- // Tag = production/release/21.202.0-0-g9a57aebc
8
+ // Profile Version = 21.208.0Release
9
+ // Tag = production/release/21.208.0-0-g5209d509
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12
 
package/src/bit-stream.js CHANGED
@@ -5,25 +5,28 @@
5
5
  // Transfer (FIT) Protocol License.
6
6
  /////////////////////////////////////////////////////////////////////////////////////////////
7
7
  // ****WARNING**** This file is auto-generated! Do NOT edit this file.
8
- // Profile Version = 21.202.0Release
9
- // Tag = production/release/21.202.0-0-g9a57aebc
8
+ // Profile Version = 21.208.0Release
9
+ // Tag = production/release/21.208.0-0-g5209d509
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12
 
13
13
  import FIT from "./fit.js";
14
14
 
15
15
  class BitStream {
16
+ #data = null;
16
17
  #array = null;
17
18
  #currentArrayPosition = 0;
18
19
  #bitPerPosition = 0;
20
+ #isBigInt = false;
19
21
  #currentByte = 0;
20
22
  #currentBit = 0;
21
23
  #bitsAvailable = 0;
22
24
 
23
25
  constructor(data, baseType = FIT.BaseType.UINT8) {
24
- this.#array = Array.isArray(data) ? data : [data];
26
+ this.#data = Array.isArray(data) ? data : [data];
25
27
  const baseTypeSize = FIT.BaseTypeDefinitions[baseType].size;
26
28
  this.#bitPerPosition = baseTypeSize * 8;
29
+ this.#isBigInt = this.#bitPerPosition > 32;
27
30
  this.reset();
28
31
  }
29
32
 
@@ -36,9 +39,11 @@ class BitStream {
36
39
  }
37
40
 
38
41
  reset() {
42
+ this.#array = null;
39
43
  this.#currentArrayPosition = 0;
40
- this.#bitsAvailable = this.#bitPerPosition * this.#array.length;
41
- this.#nextByte();
44
+ this.#bitsAvailable = this.#bitPerPosition * this.#data.length;
45
+ this.#currentByte = 0;
46
+ this.#currentBit = 0;
42
47
  }
43
48
 
44
49
  readBit() {
@@ -46,12 +51,24 @@ class BitStream {
46
51
  this.#throwError();
47
52
  }
48
53
 
54
+ if (this.#array === null) {
55
+ this.#array = this.#data;
56
+ this.#currentArrayPosition = this.#data.length - (this.#bitsAvailable / this.#bitPerPosition);
57
+ this.#nextByte();
58
+ }
59
+
49
60
  if (this.#currentBit >= this.#bitPerPosition) {
50
61
  this.#nextByte();
51
62
  }
52
63
 
53
- const bit = this.#currentByte & 0x01;
54
- this.#currentByte = this.#currentByte >> 1;
64
+ let bit;
65
+ if (this.#isBigInt) {
66
+ bit = Number(this.#currentByte & 1n);
67
+ this.#currentByte >>= 1n;
68
+ } else {
69
+ bit = this.#currentByte & 0x01;
70
+ this.#currentByte >>= 1;
71
+ }
55
72
  this.#currentBit++;
56
73
  this.#bitsAvailable--;
57
74
 
@@ -59,10 +76,36 @@ class BitStream {
59
76
  }
60
77
 
61
78
  readBits(nBitsToRead) {
79
+ // Fast path: reading exactly one value's worth of bits and #array not yet initialized
80
+ if (nBitsToRead === this.#bitPerPosition && this.#array === null) {
81
+ if (!this.hasBitsAvailable) {
82
+ this.#throwError();
83
+ }
84
+ const index = this.#data.length - (this.#bitsAvailable / this.#bitPerPosition);
85
+ const value = this.#data[index];
86
+ this.#bitsAvailable -= nBitsToRead;
87
+
88
+ if (this.#isBigInt) {
89
+ return Number(BigInt.asUintN(nBitsToRead, value));
90
+ }
91
+ if (nBitsToRead < 32) {
92
+ return (value & ((1 << nBitsToRead) - 1)) >>> 0;
93
+ }
94
+ return value >>> 0;
95
+ }
96
+
97
+ if (nBitsToRead <= 32) {
98
+ let value = 0;
99
+ for (let i = 0; i < nBitsToRead; i++) {
100
+ value |= this.readBit() << i;
101
+ }
102
+ return value >>> 0;
103
+ }
104
+
62
105
  let value = 0n;
63
106
 
64
- for (let i = 0n; i < nBitsToRead; i++) {
65
- value |= BigInt(this.readBit()) << i;
107
+ for (let i = 0, shift = 0n; i < nBitsToRead; i++, shift++) {
108
+ value |= BigInt(this.readBit()) << shift;
66
109
  }
67
110
 
68
111
  return Number(value);
@@ -77,6 +120,10 @@ class BitStream {
77
120
  this.#currentBit = 0;
78
121
  }
79
122
 
123
+ get array() {
124
+ return this.#array;
125
+ }
126
+
80
127
  #throwError(error = "") {
81
128
  throw Error("FIT Runtime Error no bits available.");
82
129
  }
@@ -5,8 +5,8 @@
5
5
  // Transfer (FIT) Protocol License.
6
6
  /////////////////////////////////////////////////////////////////////////////////////////////
7
7
  // ****WARNING**** This file is auto-generated! Do NOT edit this file.
8
- // Profile Version = 21.202.0Release
9
- // Tag = production/release/21.202.0-0-g9a57aebc
8
+ // Profile Version = 21.208.0Release
9
+ // Tag = production/release/21.208.0-0-g5209d509
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12
 
package/src/decoder.js CHANGED
@@ -5,8 +5,8 @@
5
5
  // Transfer (FIT) Protocol License.
6
6
  /////////////////////////////////////////////////////////////////////////////////////////////
7
7
  // ****WARNING**** This file is auto-generated! Do NOT edit this file.
8
- // Profile Version = 21.202.0Release
9
- // Tag = production/release/21.202.0-0-g9a57aebc
8
+ // Profile Version = 21.208.0Release
9
+ // Tag = production/release/21.208.0-0-g5209d509
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12
 
@@ -61,12 +61,8 @@ class Decoder {
61
61
  #optIncludeUnknownData = false;
62
62
  #optMergeHeartRates = true;
63
63
  #optDecodeMemoGlobs = false;
64
+ #optLegacyArrayMode = false;
64
65
 
65
- /**
66
- * Creates a FIT File Decoder
67
- * @constructor
68
- * @param {Stream} stream - representing the FIT file to decode
69
- */
70
66
  constructor(stream) {
71
67
  if (stream == null) {
72
68
  throw Error("FIT Runtime Error stream parameter is null or undefined");
@@ -75,12 +71,6 @@ class Decoder {
75
71
  this.#stream = stream;
76
72
  }
77
73
 
78
- /**
79
- * Inspects the file header to determine if the input stream is a FIT file
80
- * @param {Stream} stream
81
- * @returns {Boolean} True if the stream is a FIT file
82
- * @static
83
- */
84
74
  static isFIT(stream) {
85
75
  try {
86
76
  const fileHeaderSize = stream.peekByte();
@@ -104,18 +94,10 @@ class Decoder {
104
94
  return true;
105
95
  }
106
96
 
107
- /**
108
- * Inspects the file header to determine if the input stream is a FIT file
109
- * @returns {Boolean} True if the stream is a FIT file
110
- */
111
97
  isFIT() {
112
98
  return Decoder.isFIT(this.#stream);
113
99
  }
114
100
 
115
- /**
116
- * Checks that the input stream is a FIT file and verifies both the header and file CRC values
117
- * @returns {Boolean} True if the stream passes the isFit() and CRC checks
118
- */
119
101
  checkIntegrity() {
120
102
  try {
121
103
  if (!this.isFIT()) {
@@ -128,7 +110,7 @@ class Decoder {
128
110
  return false;
129
111
  }
130
112
 
131
- const buf = new Uint8Array(this.#stream.slice(0, this.#stream.length))
113
+ const buf = this.#stream.asUint8Array();
132
114
 
133
115
  if (fileHeader.headerSize === HEADER_WITH_CRC_SIZE && fileHeader.headerCRC !== 0x0000
134
116
  && fileHeader.headerCRC != CrcCalculator.calculateCRC(buf, 0, 12)) {
@@ -147,48 +129,6 @@ class Decoder {
147
129
  return true;
148
130
  }
149
131
 
150
- /**
151
- * Message Listener Callback
152
- *
153
- * @callback Decoder~mesgListener
154
- * @param {Number} mesgNum - Profile.MesgNum
155
- * @param {Object} message - The message
156
- */
157
-
158
- /**
159
- * Message Definition Listener Callback
160
- *
161
- * @callback Decoder~mesgDefinitionListener
162
- * @param {Object} messageDefinition - The message Definition
163
- */
164
-
165
- /**
166
- * Developer Field Description Listener Callback
167
- *
168
- * @callback Decoder~fieldDescriptionListener
169
- * @param {Number} key - The key associated with this pairing of of Developer Data Id and Field Description Mesgs
170
- * @param {Object} developerDataIdMesg - The Developer Data Id Mesg associated with this pairing
171
- * @param {Object} fieldDescriptionMesg - The Field Description Mesg associated with this pairing
172
- */
173
-
174
- /**
175
- * Read the messages from the stream.
176
- * @param {Object=} [options] - Read options (optional)
177
- * @param {Decoder~mesgListener} [options.mesgListener=null] - (optional, default null) mesgListener(mesgNum, message)
178
- * @param {Decoder~mesgDefinitionListener} [options.mesgDefinitionListener=null] - (optional, default null) mesgDefinitionListener(mesgDefinition)
179
- * @param {Decoder~fieldDescriptionListener} [options.fieldDescriptionListener=null] - (optional, default null) fieldDescriptionListener(key, developerDataIdMesg, fieldDescriptionMesg)
180
- * @param {Boolean} [options.expandSubFields=true] - (optional, default true)
181
- * @param {Boolean} [options.expandComponents=true] - (optional, default true)
182
- * @param {Boolean} [options.applyScaleAndOffset=true] - (optional, default true)
183
- * @param {Boolean} [options.convertTypesToStrings=true] - (optional, default true)
184
- * @param {boolean} [options.convertDateTimesToDates=true] - (optional, default true)
185
- * @param {Boolean} [options.includeUnknownData=false] - (optional, default false)
186
- * @param {boolean} [options.mergeHeartRates=true] - (optional, default true)
187
- * @param {boolean} [options.decodeMemoGlobs=true] - (optional, default false)
188
- * @param {boolean} [options.skipHeader=false] - (optional, default false)
189
- * @param {boolean} [options.dataOnly=false] - (optional, default false)
190
- * @return {Object} result - {messages:Array, errors:Array}
191
- */
192
132
  read({
193
133
  mesgListener = null,
194
134
  mesgDefinitionListener = null,
@@ -202,7 +142,8 @@ class Decoder {
202
142
  mergeHeartRates = true,
203
143
  decodeMemoGlobs = false,
204
144
  skipHeader = false,
205
- dataOnly = false, } = {}) {
145
+ dataOnly = false,
146
+ legacyArrayMode = false, } = {}) {
206
147
 
207
148
  this.#mesgListener = mesgListener;
208
149
  this.#mesgDefinitionListener = mesgDefinitionListener;
@@ -215,6 +156,7 @@ class Decoder {
215
156
  this.#optIncludeUnknownData = includeUnknownData;
216
157
  this.#optMergeHeartRates = mergeHeartRates;
217
158
  this.#optDecodeMemoGlobs = decodeMemoGlobs;
159
+ this.#optLegacyArrayMode = legacyArrayMode;
218
160
 
219
161
  this.#localMessageDefinitions = [];
220
162
  this.#developerDataDefinitions = {};
@@ -224,6 +166,10 @@ class Decoder {
224
166
  const errors = [];
225
167
 
226
168
  try {
169
+ if (this.#optLegacyArrayMode) {
170
+ console.log("Decoder Warning: legacyArrayMode is deprecated and will be removed in the future. Afterwards, the default behavior will be equivalent to legacyArrayMode=false.");
171
+ }
172
+
227
173
  if (this.#optMergeHeartRates && (!this.#optApplyScaleAndOffset || !this.#optExpandComponents)) {
228
174
  this.#throwError("mergeHeartRates requires applyScaleAndOffset and expandComponents to be enabled");
229
175
  }
@@ -233,6 +179,7 @@ class Decoder {
233
179
  }
234
180
 
235
181
  this.#decodeMode = skipHeader ? DecodeMode.SKIP_HEADER : dataOnly ? DecodeMode.DATA_ONLY : DecodeMode.NORMAL;
182
+ this.#stream.legacyArrayMode = this.#optLegacyArrayMode;
236
183
 
237
184
  while (this.#stream.position < this.#stream.length) {
238
185
  this.#decodeNextFile();
@@ -304,9 +251,9 @@ class Decoder {
304
251
  messageDefinition["reserved"] = this.#stream.readByte();
305
252
 
306
253
  messageDefinition["architecture"] = this.#stream.readByte();
307
- messageDefinition["endianness"] = messageDefinition.architecture === 0 ? Stream.LITTLE_ENDIAN : Stream.BIG_ENDIAN;
254
+ messageDefinition["endianness"] = messageDefinition.architecture === 0;
308
255
 
309
- messageDefinition["globalMessageNumber"] = this.#stream.readUInt16({ endianness: messageDefinition["endianness"] });
256
+ messageDefinition["globalMessageNumber"] = this.#stream.readUInt16({ littleEndian: messageDefinition["endianness"] });
310
257
  messageDefinition["numFields"] = this.#stream.readByte();
311
258
  messageDefinition["fieldDefinitions"] = [];
312
259
  messageDefinition["developerFieldDefinitions"] = [];
@@ -346,7 +293,7 @@ class Decoder {
346
293
  }
347
294
  }
348
295
 
349
- this.#mesgDefinitionListener?.({...messageDefinition});
296
+ this.#mesgDefinitionListener?.({ ...messageDefinition });
350
297
 
351
298
  let messageProfile = Profile.messages[messageDefinition.globalMessageNumber];
352
299
 
@@ -417,7 +364,7 @@ class Decoder {
417
364
  developerFieldDefinition["invalidValue"] = FIT.BaseTypeDefinitions[developerFieldDefinition.baseType].invalid;
418
365
  developerFieldDefinition["baseTypeSize"] = FIT.BaseTypeDefinitions[developerFieldDefinition.baseType].size;
419
366
 
420
- const { rawFieldValue: fieldValue } = this.#readFieldValue(messageDefinition, developerFieldDefinition, field);
367
+ const fieldValue = this.#readDeveloperFieldValue(messageDefinition, developerFieldDefinition, field);
421
368
 
422
369
  if (fieldValue != null) {
423
370
  developerFields[field.key] = fieldValue;
@@ -458,7 +405,7 @@ class Decoder {
458
405
  return developerDataIdMesg.developerDataIndex === message.developerDataIndex;
459
406
  }) ?? {};
460
407
 
461
- this.#fieldDescriptionListener(message.key, {...developerDataIdMesg}, {...message});
408
+ this.#fieldDescriptionListener(message.key, { ...developerDataIdMesg }, { ...message });
462
409
  }
463
410
  }
464
411
  }
@@ -485,10 +432,21 @@ class Decoder {
485
432
  fieldDefinition.baseType,
486
433
  fieldDefinition.size,
487
434
  {
488
- endianness: messageDefinition["endianness"],
489
- convertInvalidToNull: !field?.hasComponents ?? false
490
- }
435
+ littleEndian: messageDefinition["endianness"],
436
+ isArray: field?.array ?? fieldDefinition.size > fieldDefinition.baseTypeSize,
437
+ },
491
438
  );
439
+
440
+ return rawFieldValue;
441
+ }
442
+
443
+ #readDeveloperFieldValue(messageDefinition, developerFieldDefinition, field) {
444
+
445
+ // Preserve arrays for developer fields
446
+ this.#stream.legacyArrayMode = true;
447
+ const rawFieldValue = this.#readRawFieldValue(messageDefinition, developerFieldDefinition, field);
448
+ this.#stream.legacyArrayMode = this.#optLegacyArrayMode;
449
+
492
450
  return rawFieldValue;
493
451
  }
494
452
 
@@ -570,8 +528,9 @@ class Decoder {
570
528
  continue;
571
529
  }
572
530
  if (referenceField.rawFieldValue === map.value) {
573
- message[subField.name] = JSON.parse(JSON.stringify(message[field.name]));
574
- message[subField.name].isSubField = true;
531
+ const src = message[field.name];
532
+ const rawFieldValue = Array.isArray(src.rawFieldValue) ? [...src.rawFieldValue] : src.rawFieldValue;
533
+ message[subField.name] = { ...src, rawFieldValue, isSubField: true };
575
534
 
576
535
  if (subField.hasComponents) {
577
536
  this.#fieldsToExpand.push(subField.name);
@@ -625,6 +584,7 @@ class Decoder {
625
584
  rawFieldValue: [],
626
585
  fieldDefinitionNumber: targetField.num,
627
586
  isExpandedField: true,
587
+ isArray: targetField?.array ?? false,
628
588
  invalidValue,
629
589
  };
630
590
  }
@@ -663,8 +623,9 @@ class Decoder {
663
623
  }
664
624
 
665
625
  Object.keys(mesg).forEach((key) => {
666
- mesg[key].fieldValue = UtilsInternal.sanitizeValues(mesg[key].fieldValue);
667
- mesg[key].rawFieldValue = UtilsInternal.sanitizeValues(mesg[key].rawFieldValue);
626
+ const field = mesg[key];
627
+ mesg[key].fieldValue = UtilsInternal.sanitizeValues(field.fieldValue, { legacyArrayMode: this.#optLegacyArrayMode, isArray: field.isArray });
628
+ mesg[key].rawFieldValue = UtilsInternal.sanitizeValues(field.rawFieldValue, { legacyArrayMode: this.#optLegacyArrayMode, isArray: field.isArray });
668
629
 
669
630
  message[key] = mesg[key];
670
631
  });
@@ -693,7 +654,7 @@ class Decoder {
693
654
  if (field == null) {
694
655
  fieldValue = rawFieldValue;
695
656
  }
696
- else if (FIT.NumericFieldTypes.includes(field?.type ?? -1)) {
657
+ else if (FIT.NumericFieldTypesSet.has(field?.type ?? -1)) {
697
658
  fieldValue = this.#applyScaleAndOffset(messageDefinition, field, rawFieldValue);
698
659
  }
699
660
  else if (field.type === "string") {
@@ -717,7 +678,7 @@ class Decoder {
717
678
  return rawFieldValue;
718
679
  }
719
680
 
720
- if (FIT.NumericFieldTypes.includes(field?.type ?? -1) === false) {
681
+ if (FIT.NumericFieldTypesSet.has(field?.type ?? -1) === false) {
721
682
  return rawFieldValue;
722
683
  }
723
684
 
@@ -760,7 +721,7 @@ class Decoder {
760
721
  components.forEach((componentFieldNum, i) => {
761
722
  const targetField = messageDefinition.fields[componentFieldNum];
762
723
 
763
- if(targetField?.num == field.num && targetField?.isAccumulated) {
724
+ if (targetField?.num == field.num && targetField?.isAccumulated) {
764
725
  value = (((value / field.scale) - field.offset) + containingField.offset[i]) * containingField.scale[i];
765
726
  }
766
727
  });
@@ -775,7 +736,7 @@ class Decoder {
775
736
  return rawFieldValue;
776
737
  }
777
738
 
778
- if (FIT.NumericFieldTypes.includes(field?.type ?? -1)) {
739
+ if (FIT.NumericFieldTypesSet.has(field?.type ?? -1)) {
779
740
  return rawFieldValue;
780
741
  }
781
742
 
package/src/encoder.js CHANGED
@@ -5,8 +5,8 @@
5
5
  // Transfer (FIT) Protocol License.
6
6
  /////////////////////////////////////////////////////////////////////////////////////////////
7
7
  // ****WARNING**** This file is auto-generated! Do NOT edit this file.
8
- // Profile Version = 21.202.0Release
9
- // Tag = production/release/21.202.0-0-g9a57aebc
8
+ // Profile Version = 21.208.0Release
9
+ // Tag = production/release/21.208.0-0-g5209d509
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12
 
@@ -20,17 +20,7 @@ import Utils from "./utils.js";
20
20
  const HEADER_WITH_CRC_SIZE = 14;
21
21
  const HEADER_WITHOUT_CRC_SIZE = 12;
22
22
 
23
- /**
24
- * A class for encoding FIT files.
25
- * @class
26
- */
27
23
  class Encoder {
28
- /**
29
- Creates a FIT File Encoder
30
- * @param {Object} [options] - Encoder options (optional)
31
- * @param {Object.<number,{object, object }} [options.fieldDescriptions=null] - (optional, default null) fieldDescriptions
32
- * @constructor
33
- */
34
24
  constructor({ fieldDescriptions = null, } = {}) {
35
25
  this.#fieldDescriptions = {};
36
26
 
@@ -41,10 +31,6 @@ class Encoder {
41
31
  this.#writeEmptyFileHeader();
42
32
  }
43
33
 
44
- /**
45
- * Closes the encoder and returns the file data
46
- * @returns {Uint8Array} A Uint8Array containing the file data
47
- */
48
34
  close() {
49
35
  this.#updateFileHeader();
50
36
  this.#writeFileCrc();
@@ -52,23 +38,10 @@ class Encoder {
52
38
  return this.#outputStream.uint8Array;
53
39
  }
54
40
 
55
- /**
56
- * Encodes a mesg into the file.
57
- * @param {Object} mesg - The message data
58
- * @param {Number} mesg.mesgNum - The mesg number for this message
59
- * @return {this}
60
- */
61
41
  writeMesg(mesg) {
62
42
  return this.onMesg(mesg.mesgNum, mesg);
63
43
  }
64
44
 
65
- /**
66
- * Encodes a mesg into the file.
67
- * This method can be used as a Decoder~mesgListener callback.
68
- * @param {Number} mesgNum - The message number for this message
69
- * @param {Object} mesg - The message data
70
- * @return {this}
71
- */
72
45
  onMesg(mesgNum, mesg) {
73
46
  try {
74
47
  const mesgDefinition = this.#createMesgDefinition(mesgNum, mesg);
@@ -113,16 +86,6 @@ class Encoder {
113
86
  return this;
114
87
  };
115
88
 
116
- /**
117
- * Adds a Developer Data Field Description and associated Developer Data Id Message to the Endoder
118
- * This provides the Encoder with the context required to write Developer Fields to the output-stream.
119
- * *** This method does not write the messages to the output-stream ***
120
- * This method can be used as a Decoder~fieldDescriptionListener callback.
121
- * @param {Number} key - The message number for this message
122
- * @param {Object} developerDataIdMesg - The Developer Data Id mesg
123
- * @param {Object} fieldDescriptionMesg - The Field Description mesg
124
- * @return {this}
125
- */
126
89
  addDeveloperField(key, developerDataIdMesg, fieldDescriptionMesg) {
127
90
  if(developerDataIdMesg.developerDataIndex == null || fieldDescriptionMesg.developerDataIndex == null) {
128
91
  throw new Error("addDeveloperField() - one or more developerDataIndex values are null.", {
package/src/fit.js CHANGED
@@ -5,8 +5,8 @@
5
5
  // Transfer (FIT) Protocol License.
6
6
  /////////////////////////////////////////////////////////////////////////////////////////////
7
7
  // ****WARNING**** This file is auto-generated! Do NOT edit this file.
8
- // Profile Version = 21.202.0Release
9
- // Tag = production/release/21.202.0-0-g9a57aebc
8
+ // Profile Version = 21.208.0Release
9
+ // Tag = production/release/21.208.0-0-g5209d509
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12
 
@@ -73,6 +73,8 @@ const NumericFieldTypes = [
73
73
  "uint64z"
74
74
  ];
75
75
 
76
+ const NumericFieldTypesSet = new Set(NumericFieldTypes);
77
+
76
78
  const FieldTypeToJsType = {
77
79
  "enum": "number",
78
80
  "sint8": "number",
@@ -202,6 +204,7 @@ export default {
202
204
  BaseTypeMask,
203
205
  BaseTypeDefinitions,
204
206
  NumericFieldTypes,
207
+ NumericFieldTypesSet,
205
208
  BigIntFieldTypes,
206
209
  FloatingPointFieldTypes,
207
210
  FieldTypeToBaseType,
package/src/index.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ /////////////////////////////////////////////////////////////////////////////////////////////
2
+ // Copyright 2026 Garmin International, Inc.
3
+ // Licensed under the Flexible and Interoperable Data Transfer (FIT) Protocol License; you
4
+ // may not use this file except in compliance with the Flexible and Interoperable Data
5
+ // Transfer (FIT) Protocol License.
6
+ /////////////////////////////////////////////////////////////////////////////////////////////
7
+ // ****WARNING**** This file is auto-generated! Do NOT edit this file.
8
+ // Profile Version = 21.208.0Release
9
+ // Tag = production/release/21.208.0-0-g5209d509
10
+ /////////////////////////////////////////////////////////////////////////////////////////////
11
+
12
+
13
+ export * from './types/crc-calculator';
14
+ export * from './types/decoder';
15
+ export * from './types/encoder';
16
+ export * from './types/mesg';
17
+ export * from './types/mesgs';
18
+ export * from './types/profile';
19
+ export * from './types/stream';
20
+ export * from './types/types';
21
+ export { default as Types } from './types/types';
22
+ export * from './types/utils';
package/src/index.js CHANGED
@@ -5,8 +5,8 @@
5
5
  // Transfer (FIT) Protocol License.
6
6
  /////////////////////////////////////////////////////////////////////////////////////////////
7
7
  // ****WARNING**** This file is auto-generated! Do NOT edit this file.
8
- // Profile Version = 21.202.0Release
9
- // Tag = production/release/21.202.0-0-g9a57aebc
8
+ // Profile Version = 21.208.0Release
9
+ // Tag = production/release/21.208.0-0-g5209d509
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12
 
@@ -5,8 +5,8 @@
5
5
  // Transfer (FIT) Protocol License.
6
6
  /////////////////////////////////////////////////////////////////////////////////////////////
7
7
  // ****WARNING**** This file is auto-generated! Do NOT edit this file.
8
- // Profile Version = 21.202.0Release
9
- // Tag = production/release/21.202.0-0-g9a57aebc
8
+ // Profile Version = 21.208.0Release
9
+ // Tag = production/release/21.208.0-0-g5209d509
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12