@garmin/fitsdk 21.188.0 → 21.195.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
@@ -1,288 +1,298 @@
1
- # Garmin - FIT JavaScript SDK
2
- ## FIT SDK Documentation
3
- The FIT SDK documentation is available at [https://developer.garmin.com/fit](https://developer.garmin.com/fit).
4
- ## FIT SDK Developer Forum
5
- Share your knowledge, ask questions, and get the latest FIT SDK news in the [FIT SDK Developer Forum](https://forums.garmin.com/developer/).
6
- ## FIT JavaScript SDK Requirements
7
- The FIT JavaScript SDK uses ECMAScript module syntax and requires Node.js v14.0 or higher, or a browser with a compatible JavaScript runtime engine.
8
- ## Install
9
- ```sh
10
- npm install @garmin/fitsdk
11
- ```
12
- ## Decoder
13
- ### Usage
14
- ````js
15
- import { Decoder, Stream, Profile, Utils } from '@garmin/fitsdk';
16
-
17
- const bytes = [0x0E, 0x10, 0xD9, 0x07, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x46, 0x49, 0x54, 0x91, 0x33, 0x00, 0x00];
18
-
19
- const stream = Stream.fromByteArray(bytes);
20
- console.log("isFIT (static method): " + Decoder.isFIT(stream));
21
-
22
- const decoder = new Decoder(stream);
23
- console.log("isFIT (instance method): " + decoder.isFIT());
24
- console.log("checkIntegrity: " + decoder.checkIntegrity());
25
-
26
- const { messages, errors } = decoder.read();
27
-
28
- console.log(errors);
29
- console.log(messages);
30
- ````
31
- ### Constructor
32
-
33
- Decoder objects are created from Streams representing the binary FIT file data to be decoded. See [Creating Streams](#creatingstreams) for more information on constructing Stream objects.
34
-
35
- Once a Decoder object is created it can be used to check that the Stream is a FIT file, that the FIT file is valid, and to read the contents of the FIT file.
36
-
37
- ### isFIT Method
38
-
39
- All valid FIT files should include a 12 or 14 byte file header. The 14 byte header is the preferred header size and the most common size used. Bytes 8–11 of the header contain the ASCII values ".FIT". This string can easily be spotted when opening a binary FIT file in a text or hex editor.
40
-
41
- ````bash
42
- Offset: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
43
- 00000000: 0E 10 43 08 78 06 09 00 2E 46 49 54 96 85 40 00 ..C.x....FIT..@.
44
- 00000010: 00 00 00 07 03 04 8C 04 04 86 07 04 86 01 02 84 ................
45
- 00000020: 02 02 84 05 02 84 00 01 00 00 19 28 7E C5 95 B0 ...........(~E.0
46
- ````
47
-
48
- The isFIT method reads the file header and returns true if bytes 8–11 are equal to the ACSII values ".FIT". isFIT provides a quick way to check that the file is a FIT file before attempting to decode the file.
49
-
50
- The Decoder class includes a static and instance version of the isFIT method.
51
-
52
- ### Check Integrity Method
53
-
54
- The checkIntegrity method performs three checks on a FIT file:
55
-
56
- 1. Checks that bytes 8–11 of the header contain the ASCII values ".FIT".
57
- 2. Checks that the total file size is equal to Header Size + Data Size + CRC Size.
58
- 3. Reads the contents of the file, computes the CRC, and then checks that the computed CRC matches the file CRC.
59
-
60
- A file must pass all three of these tests to be considered a valid FIT file. See the [IsFIT(), CheckIntegrity(), and Read() Methods recipe](/fit/cookbook/isfit-checkintegrity-read/) for use-cases where the checkIntegrity method should be used and cases when it might be better to avoid it.
61
-
62
- ### Read Method
63
- The Read method decodes all message from the input stream and returns an object containing an array of errors encountered during the decoding and a dictionary of decoded messages grouped by message type. Any exceptions encountered during decoding will be caught by the Read method and added to the array of errors.
64
-
65
- The Read method accepts an optional options object that can be used to customize how field data is represented in the decoded messages. All options are enabled by default. Disabling options may speed up file decoding. Options may also be enabled or disable based on how the decoded data will be used.
66
-
67
- ````js
68
- const { messages, errors } = decoder.read({
69
- mesgListener: (messageNumber, message) => {},
70
- mesgDefinitionListener: (mesgDefinition) => {},
71
- fieldDescriptionListener: (key, developerDataIdMesg, fieldDescriptionMesg) => {},
72
- applyScaleAndOffset: true,
73
- expandSubFields: true,
74
- expandComponents: true,
75
- convertTypesToStrings: true,
76
- convertDateTimesToDates: true,
77
- includeUnknownData: false,
78
- mergeHeartRates: true
79
- decodeMemoGlobs: false,
80
- });
81
- ````
82
- #### mesgListener = (messageNumber, message) => {}
83
- Optional callback function that can be used to inspect or manipulate messages after they are fully decoded and all the options have been applied. The message is mutable and we be returned from the Read method in the messages dictionary.
84
-
85
- Example mesgListener callback that tracks the field names across all Record messages.
86
- ````js
87
- const recordFields = new Set();
88
-
89
- const onMesg = (messageNumber, message) => {
90
- if (Profile.types.mesgNum[messageNumber] === "record") {
91
- Object.keys(message).forEach(field => recordFields.add(field));
92
- }
93
- }
94
-
95
- const { messages, errors } = decoder.read({
96
- mesgListener = onMesg
97
- });
98
-
99
- console.log(recordFields);
100
- ````
101
- #### mesgDefinitionListener: (mesgDefinition) => {}
102
- Optional callback function that can be used to inspect message defintions as they are decoded from the file.
103
- #### fieldDescriptionListener: (key, developerDataIdMesg, fieldDescriptionMesg) => {}
104
- Optional callback function that can be used to inspect developer field descriptions as they are decoded from the file.
105
- #### applyScaleAndOffset: true | false
106
- When true the scale and offset values as defined in the FIT Profile are applied to the raw field values.
107
- ````js
108
- {
109
- altitude: 1587 // with a scale of 5 and offset of 500 applied
110
- }
111
- ````
112
- When false the raw field value is used.
113
- ````js
114
- {
115
- altitude: 10435 // raw value store in file
116
- }
117
- ````
118
- #### expandSubFields: true | false
119
- When true subfields are created for fields as defined in the FIT Profile.
120
- ````js
121
- {
122
- event: 'rearGearChange',
123
- data: 16717829,
124
- gearChangeData:16717829 // Sub Field of data when event == 'rearGearChange'
125
- }
126
- ````
127
- When false subfields are omitted.
128
- ````js
129
- {
130
- event: 'rearGearChange',
131
- data: 16717829
132
- }
133
- ````
134
- #### expandComponents: true | false
135
- When true field components as defined in the FIT Profile are expanded into new fields. expandSubFields must be set to true in order for subfields to be expanded
136
-
137
- ````js
138
- {
139
- event: 'rearGearChange'
140
- data: 16717829,
141
- gearChangeData:16717829, // Sub Field of data when event == 'rearGearChange
142
- frontGear: 2, // Expanded field of gearChangeData, bits 0-7
143
- frontGearNum: 53, // Expanded field of gearChangeData, bits 8-15
144
- rearGear: 11, // Expanded field of gearChangeData, bits 16-23
145
- rearGearNum: 1, // Expanded field of gearChangeData, bits 24-31
146
- }
147
- ````
148
- When false field components are not expanded.
149
- ````js
150
- {
151
- event: 'rearGearChange',
152
- data: 16717829,
153
- gearChangeData: 16717829 // Sub Field of data when event == 'rearGearChange
154
- }
155
- ````
156
- #### convertTypesToStrings: true | false
157
- When true field values are converted from raw integer values to the corresponding string values as defined in the FIT Profile.
158
- ````js
159
- { type:'activity'}
160
- ````
161
- When false the raw integer value is used.
162
- ````js
163
- { type: 4 }
164
- ````
165
- #### convertDateTimesToDates: true | false
166
- When true FIT Epoch values are converted to JavaScript Date objects.
167
- ````js
168
- { timeCreated: {JavaScript Date object} }
169
- ````
170
- When false the FIT Epoch value is used.
171
- ````js
172
- { timeCreated: 995749880 }
173
- ````
174
- When false the Utils.convertDateTimeToDate method may be used to convert FIT Epoch values to JavaScript Date objects.
175
- #### includeUnknownData: true | false
176
- When true unknown field values are stored in the message using the field id as the key.
177
- ````js
178
- { 249: 1234} // Unknown field with an id of 249
179
- ````
180
- #### mergeHeartRates: true | false
181
- When true automatically merge heart rate values from HR messages into the Record messages. This option requires the applyScaleAndOffset and expandComponents options to be enabled. This option has no effect on the Record messages when no HR messages are present in the decoded messages.
182
-
183
- #### decodeMemoGlobs: true | false
184
- When true, the decoder will reconstruct strings from memoGlob messages. Each reconstructed string will overwrite the targeted message field.
185
-
186
- ## Creating Streams
187
- Stream objects contain the binary FIT data to be decoded. Streams objects can be created from byte-arrays, ArrayBuffers, and Node.js Buffers. Internally the Stream class uses an ArrayBuffer to manage the byte stream.
188
- #### From a Byte Array
189
- ````js
190
- const streamFromByteArray = Stream.fromByteArray([0x0E, 0x10, 0xD9, 0x07, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x46, 0x49, 0x54, 0x91, 0x33, 0x00, 0x00]);
191
- console.log("isFIT: " + Decoder.isFIT(streamFromByteArray));
192
- ````
193
- #### From an ArrayBuffer
194
- ````js
195
- const uint8Array = new Uint8Array([0x0E, 0x10, 0xD9, 0x07, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x46, 0x49, 0x54, 0x91, 0x33, 0x00, 0x00]);
196
- const streamFromArrayBuffer = Stream.fromArrayBuffer(uint8Array.buffer);
197
- console.log("isFIT: " + Decoder.isFIT(streamFromArrayBuffer));
198
- ````
199
- #### From a Node.js Buffer
200
- ````js
201
- const buffer = Buffer.from([0x0E, 0x10, 0xD9, 0x07, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x46, 0x49, 0x54, 0x91, 0x33, 0x00, 0x00]);
202
- const streamFromBuffer = Stream.fromBuffer(buffer);
203
- console.log("isFIT: " + Decoder.isFIT(streamFromBuffer));
204
- ````
205
- #### From a file using Node.js
206
- ````js
207
- const buf = fs.readFileSync('activity.fit');
208
- const streamfromFileSync = Stream.fromBuffer(buf);
209
- console.log("isFIT: " + Decoder.isFIT(streamfromFileSync));
210
- ````
211
- ## Utils
212
- The Utils object contains both constants and methods for working with decoded messages and fields.
213
- ### FIT_EPOCH_MS Constant
214
- The FIT_EPOCH_MS constant represents the number of milliseconds between the Unix Epoch and the FIT Epoch.
215
- ````js
216
- const FIT_EPOCH_MS = 631065600000;
217
- ````
218
- The FIT_EPOCH_MS value can be used to convert FIT Epoch values to JavaScript Date objects.
219
- ````js
220
- const jsDate = new Date(fitDateTime * 1000 + Utils.FIT_EPOCH_MS);
221
- ````
222
- ### convertDateTimeToDate Method
223
- A convince method for converting FIT Epoch values to JavaScript Date objects.
224
- ````js
225
- const jsDate = Utils.convertDateTimeToDate(fitDateTime);
226
- ````
227
- ## Encoder
228
- ### Usage
229
- ````js
230
- // Import the SDK
231
- import { Encoder, Profile} from "@garmin/fitsdk";
232
-
233
- // Create an Encoder
234
- const encoder = new Encoder();
235
-
236
- //
237
- // Write messages to the output-stream
238
- //
239
- // The message data should match the format returned by
240
- // the Decoder. Field names should be camelCase. The fields
241
- // definitions can be found in the Profile.
242
- //
243
-
244
- // Pass the MesgNum and message data as separate parameters to the onMesg() method
245
- encoder.onMesg(Profile.MesgNum.FILE_ID, {
246
- manufacturer: "development",
247
- product: 1,
248
- timeCreated: new Date(),
249
- type: "activity",
250
- });
251
-
252
- // The writeMesg() method expects the mesgNum to be included in the message data
253
- // Internally, writeMesg() calls onMesg()
254
- encoder.writeMesg({
255
- mesgNum: Profile.MesgNum.FILE_ID,
256
- manufacturer: "development",
257
- product: 1,
258
- timeCreated: new Date(),
259
- type: "activity",
260
- });
261
-
262
- // Unknown values in the message will be ignored by the Encoder
263
- encoder.onMesg(Profile.MesgNum.FILE_ID, {
264
- manufacturer: "development",
265
- product: 1,
266
- timeCreated: new Date(),
267
- type: "activity",
268
- customField: 12345, // This value will be ignored by the Encoder
269
- });
270
-
271
- // Subfield values in the message will be ignored by the Encoder
272
- encoder.onMesg(Profile.MesgNum.FILE_ID, {
273
- manufacturer: "development",
274
- product: 4440, // This is the main product field, which is a uint16
275
- garminProduct: "edge1050", // This value will be ignored by the Encoder, use the main field value instead
276
- timeCreated: new Date(),
277
- type: "activity",
278
- });
279
-
280
- // Closing the encoder returns the file as an UInt8 Array
281
- const uint8Array = encoder.close();
282
-
283
- // Write the file to disk,
284
- import * as fs from "fs";
285
- fs.writeFileSync("example.fit", uint8Array);
286
-
287
- ````
288
- See the [Encode Activity Recipe](https://github.com/garmin/fit-javascript-sdk/blob/main/test/encode-activity-recipe.test.js) for a complete example of encoding a FIT Activity file usine the FIT JavaScript SDK.
1
+ # Garmin - FIT JavaScript SDK
2
+ ## FIT SDK Documentation
3
+ The FIT SDK documentation is available at [https://developer.garmin.com/fit](https://developer.garmin.com/fit).
4
+ ## FIT SDK Developer Forum
5
+ Share your knowledge, ask questions, and get the latest FIT SDK news in the [FIT SDK Developer Forum](https://forums.garmin.com/developer/).
6
+ ## FIT JavaScript SDK Requirements
7
+ The FIT JavaScript SDK uses ECMAScript module syntax and requires Node.js v14.0 or higher, or a browser with a compatible JavaScript runtime engine.
8
+ ## Install
9
+ The FIT JavaScript SDK is published as a NodeJS Pacakge on npm as [@garmin/fitsdk](https://www.npmjs.com/package/@garmin/fitsdk) and can be installed with the npm cli.
10
+
11
+ ```sh
12
+ npm install @garmin/fitsdk
13
+ ```
14
+ ## Decoder
15
+ ### Usage
16
+ ````js
17
+ import { Decoder, Stream, Profile, Utils } from '@garmin/fitsdk';
18
+
19
+ const bytes = [0x0E, 0x10, 0xD9, 0x07, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x46, 0x49, 0x54, 0x91, 0x33, 0x00, 0x00];
20
+
21
+ const stream = Stream.fromByteArray(bytes);
22
+ console.log("isFIT (static method): " + Decoder.isFIT(stream));
23
+
24
+ const decoder = new Decoder(stream);
25
+ console.log("isFIT (instance method): " + decoder.isFIT());
26
+ console.log("checkIntegrity: " + decoder.checkIntegrity());
27
+
28
+ const { messages, errors } = decoder.read();
29
+
30
+ console.log(errors);
31
+ console.log(messages);
32
+ ````
33
+ ### Constructor
34
+
35
+ Decoder objects are created from Streams representing the binary FIT file data to be decoded. See [Creating Streams](#creatingstreams) for more information on constructing Stream objects.
36
+
37
+ Once a Decoder object is created it can be used to check that the Stream is a FIT file, that the FIT file is valid, and to read the contents of the FIT file.
38
+
39
+ ### isFIT Method
40
+
41
+ All valid FIT files should include a 12 or 14 byte file header. The 14 byte header is the preferred header size and the most common size used. Bytes 8–11 of the header contain the ASCII values ".FIT". This string can easily be spotted when opening a binary FIT file in a text or hex editor.
42
+
43
+ ````bash
44
+ Offset: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
45
+ 00000000: 0E 10 43 08 78 06 09 00 2E 46 49 54 96 85 40 00 ..C.x....FIT..@.
46
+ 00000010: 00 00 00 07 03 04 8C 04 04 86 07 04 86 01 02 84 ................
47
+ 00000020: 02 02 84 05 02 84 00 01 00 00 19 28 7E C5 95 B0 ...........(~E.0
48
+ ````
49
+
50
+ The isFIT method reads the file header and returns true if bytes 8–11 are equal to the ACSII values ".FIT". isFIT provides a quick way to check that the file is a FIT file before attempting to decode the file.
51
+
52
+ The Decoder class includes a static and instance version of the isFIT method.
53
+
54
+ ### Check Integrity Method
55
+
56
+ The checkIntegrity method performs three checks on a FIT file:
57
+
58
+ 1. Checks that bytes 8–11 of the header contain the ASCII values ".FIT".
59
+ 2. Checks that the total file size is equal to Header Size + Data Size + CRC Size.
60
+ 3. Reads the contents of the file, computes the CRC, and then checks that the computed CRC matches the file CRC.
61
+
62
+ A file must pass all three of these tests to be considered a valid FIT file. See the [IsFIT(), CheckIntegrity(), and Read() Methods recipe](/fit/cookbook/isfit-checkintegrity-read/) for use-cases where the checkIntegrity method should be used and cases when it might be better to avoid it.
63
+
64
+ ### Read Method
65
+ The Read method decodes all message from the input stream and returns an object containing an array of errors encountered during the decoding and a dictionary of decoded messages grouped by message type. Any exceptions encountered during decoding will be caught by the Read method and added to the array of errors.
66
+
67
+ The Read method accepts an optional options object that can be used to customize how field data is represented in the decoded messages. All options are enabled by default. Disabling options may speed up file decoding. Options may also be enabled or disable based on how the decoded data will be used.
68
+
69
+ ````js
70
+ const { messages, errors } = decoder.read({
71
+ mesgListener: (messageNumber, message) => {},
72
+ mesgDefinitionListener: (mesgDefinition) => {},
73
+ fieldDescriptionListener: (key, developerDataIdMesg, fieldDescriptionMesg) => {},
74
+ applyScaleAndOffset: true,
75
+ expandSubFields: true,
76
+ expandComponents: true,
77
+ convertTypesToStrings: true,
78
+ convertDateTimesToDates: true,
79
+ includeUnknownData: false,
80
+ mergeHeartRates: true
81
+ decodeMemoGlobs: false,
82
+ skipHeader: false,
83
+ dataOnly: false,
84
+ });
85
+ ````
86
+ #### mesgListener = (messageNumber, message) => {}
87
+ Optional callback function that can be used to inspect or manipulate messages after they are fully decoded and all the options have been applied. The message is mutable and we be returned from the Read method in the messages dictionary.
88
+
89
+ Example mesgListener callback that tracks the field names across all Record messages.
90
+ ````js
91
+ const recordFields = new Set();
92
+
93
+ const onMesg = (messageNumber, message) => {
94
+ if (Profile.types.mesgNum[messageNumber] === "record") {
95
+ Object.keys(message).forEach(field => recordFields.add(field));
96
+ }
97
+ }
98
+
99
+ const { messages, errors } = decoder.read({
100
+ mesgListener = onMesg
101
+ });
102
+
103
+ console.log(recordFields);
104
+ ````
105
+ #### mesgDefinitionListener: (mesgDefinition) => {}
106
+ Optional callback function that can be used to inspect message defintions as they are decoded from the file.
107
+ #### fieldDescriptionListener: (key, developerDataIdMesg, fieldDescriptionMesg) => {}
108
+ Optional callback function that can be used to inspect developer field descriptions as they are decoded from the file.
109
+ #### applyScaleAndOffset: true | false
110
+ When true the scale and offset values as defined in the FIT Profile are applied to the raw field values.
111
+ ````js
112
+ {
113
+ altitude: 1587 // with a scale of 5 and offset of 500 applied
114
+ }
115
+ ````
116
+ When false the raw field value is used.
117
+ ````js
118
+ {
119
+ altitude: 10435 // raw value store in file
120
+ }
121
+ ````
122
+ #### expandSubFields: true | false
123
+ When true subfields are created for fields as defined in the FIT Profile.
124
+ ````js
125
+ {
126
+ event: 'rearGearChange',
127
+ data: 16717829,
128
+ gearChangeData:16717829 // Sub Field of data when event == 'rearGearChange'
129
+ }
130
+ ````
131
+ When false subfields are omitted.
132
+ ````js
133
+ {
134
+ event: 'rearGearChange',
135
+ data: 16717829
136
+ }
137
+ ````
138
+ #### expandComponents: true | false
139
+ When true field components as defined in the FIT Profile are expanded into new fields. expandSubFields must be set to true in order for subfields to be expanded
140
+
141
+ ````js
142
+ {
143
+ event: 'rearGearChange'
144
+ data: 16717829,
145
+ gearChangeData:16717829, // Sub Field of data when event == 'rearGearChange
146
+ frontGear: 2, // Expanded field of gearChangeData, bits 0-7
147
+ frontGearNum: 53, // Expanded field of gearChangeData, bits 8-15
148
+ rearGear: 11, // Expanded field of gearChangeData, bits 16-23
149
+ rearGearNum: 1, // Expanded field of gearChangeData, bits 24-31
150
+ }
151
+ ````
152
+ When false field components are not expanded.
153
+ ````js
154
+ {
155
+ event: 'rearGearChange',
156
+ data: 16717829,
157
+ gearChangeData: 16717829 // Sub Field of data when event == 'rearGearChange
158
+ }
159
+ ````
160
+ #### convertTypesToStrings: true | false
161
+ When true field values are converted from raw integer values to the corresponding string values as defined in the FIT Profile.
162
+ ````js
163
+ { type:'activity'}
164
+ ````
165
+ When false the raw integer value is used.
166
+ ````js
167
+ { type: 4 }
168
+ ````
169
+ #### convertDateTimesToDates: true | false
170
+ When true FIT Epoch values are converted to JavaScript Date objects.
171
+ ````js
172
+ { timeCreated: {JavaScript Date object} }
173
+ ````
174
+ When false the FIT Epoch value is used.
175
+ ````js
176
+ { timeCreated: 995749880 }
177
+ ````
178
+ When false the Utils.convertDateTimeToDate method may be used to convert FIT Epoch values to JavaScript Date objects.
179
+ #### includeUnknownData: true | false
180
+ When true unknown field values are stored in the message using the field id as the key.
181
+ ````js
182
+ { 249: 1234} // Unknown field with an id of 249
183
+ ````
184
+ #### mergeHeartRates: true | false
185
+ When true automatically merge heart rate values from HR messages into the Record messages. This option requires the applyScaleAndOffset and expandComponents options to be enabled. This option has no effect on the Record messages when no HR messages are present in the decoded messages.
186
+
187
+ #### decodeMemoGlobs: true | false
188
+ When true, the decoder will reconstruct strings from memoGlob messages. Each reconstructed string will overwrite the targeted message field.
189
+
190
+ #### skipHeader: true | false
191
+ When true, the decoder will read past the 14-byte header and ignore its contents. The decoder then assumes file data size from the size of the file's stream.
192
+
193
+ #### dataOnly: true | false
194
+ 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
+ ## Creating Streams
197
+ Stream objects contain the binary FIT data to be decoded. Streams 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
+ #### From a Byte Array
199
+ ````js
200
+ const streamFromByteArray = Stream.fromByteArray([0x0E, 0x10, 0xD9, 0x07, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x46, 0x49, 0x54, 0x91, 0x33, 0x00, 0x00]);
201
+ console.log("isFIT: " + Decoder.isFIT(streamFromByteArray));
202
+ ````
203
+ #### From an ArrayBuffer
204
+ ````js
205
+ const uint8Array = new Uint8Array([0x0E, 0x10, 0xD9, 0x07, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x46, 0x49, 0x54, 0x91, 0x33, 0x00, 0x00]);
206
+ const streamFromArrayBuffer = Stream.fromArrayBuffer(uint8Array.buffer);
207
+ console.log("isFIT: " + Decoder.isFIT(streamFromArrayBuffer));
208
+ ````
209
+ #### From a Node.js Buffer
210
+ ````js
211
+ const buffer = Buffer.from([0x0E, 0x10, 0xD9, 0x07, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x46, 0x49, 0x54, 0x91, 0x33, 0x00, 0x00]);
212
+ const streamFromBuffer = Stream.fromBuffer(buffer);
213
+ console.log("isFIT: " + Decoder.isFIT(streamFromBuffer));
214
+ ````
215
+ #### From a file using Node.js
216
+ ````js
217
+ const buf = fs.readFileSync('activity.fit');
218
+ const streamfromFileSync = Stream.fromBuffer(buf);
219
+ console.log("isFIT: " + Decoder.isFIT(streamfromFileSync));
220
+ ````
221
+ ## Utils
222
+ The Utils object contains both constants and methods for working with decoded messages and fields.
223
+ ### FIT_EPOCH_MS Constant
224
+ The FIT_EPOCH_MS constant represents the number of milliseconds between the Unix Epoch and the FIT Epoch.
225
+ ````js
226
+ const FIT_EPOCH_MS = 631065600000;
227
+ ````
228
+ The FIT_EPOCH_MS value can be used to convert FIT Epoch values to JavaScript Date objects.
229
+ ````js
230
+ const jsDate = new Date(fitDateTime * 1000 + Utils.FIT_EPOCH_MS);
231
+ ````
232
+ ### convertDateTimeToDate Method
233
+ A convince method for converting FIT Epoch values to JavaScript Date objects.
234
+ ````js
235
+ const jsDate = Utils.convertDateTimeToDate(fitDateTime);
236
+ ````
237
+ ## Encoder
238
+ ### Usage
239
+ ````js
240
+ // Import the SDK
241
+ import { Encoder, Profile} from "@garmin/fitsdk";
242
+
243
+ // Create an Encoder
244
+ const encoder = new Encoder();
245
+
246
+ //
247
+ // Write messages to the output-stream
248
+ //
249
+ // The message data should match the format returned by
250
+ // the Decoder. Field names should be camelCase. The fields
251
+ // definitions can be found in the Profile.
252
+ //
253
+
254
+ // Pass the MesgNum and message data as separate parameters to the onMesg() method
255
+ encoder.onMesg(Profile.MesgNum.FILE_ID, {
256
+ manufacturer: "development",
257
+ product: 1,
258
+ timeCreated: new Date(),
259
+ type: "activity",
260
+ });
261
+
262
+ // The writeMesg() method expects the mesgNum to be included in the message data
263
+ // Internally, writeMesg() calls onMesg()
264
+ encoder.writeMesg({
265
+ mesgNum: Profile.MesgNum.FILE_ID,
266
+ manufacturer: "development",
267
+ product: 1,
268
+ timeCreated: new Date(),
269
+ type: "activity",
270
+ });
271
+
272
+ // Unknown values in the message will be ignored by the Encoder
273
+ encoder.onMesg(Profile.MesgNum.FILE_ID, {
274
+ manufacturer: "development",
275
+ product: 1,
276
+ timeCreated: new Date(),
277
+ type: "activity",
278
+ customField: 12345, // This value will be ignored by the Encoder
279
+ });
280
+
281
+ // Subfield values in the message will be ignored by the Encoder
282
+ encoder.onMesg(Profile.MesgNum.FILE_ID, {
283
+ manufacturer: "development",
284
+ product: 4440, // This is the main product field, which is a uint16
285
+ garminProduct: "edge1050", // This value will be ignored by the Encoder, use the main field value instead
286
+ timeCreated: new Date(),
287
+ type: "activity",
288
+ });
289
+
290
+ // Closing the encoder returns the file as an UInt8 Array
291
+ const uint8Array = encoder.close();
292
+
293
+ // Write the file to disk,
294
+ import * as fs from "fs";
295
+ fs.writeFileSync("example.fit", uint8Array);
296
+
297
+ ````
298
+ See the [Encode Activity Recipe](https://github.com/garmin/fit-javascript-sdk/blob/main/test/encode-activity-recipe.test.js) for a complete example of encoding a FIT Activity file usine the FIT JavaScript SDK.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@garmin/fitsdk",
3
- "version": "21.188.0",
3
+ "version": "21.195.0",
4
4
  "description": "FIT JavaScript SDK",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -1,12 +1,12 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////////////////
2
- // Copyright 2025 Garmin International, Inc.
2
+ // Copyright 2026 Garmin International, Inc.
3
3
  // Licensed under the Flexible and Interoperable Data Transfer (FIT) Protocol License; you
4
4
  // may not use this file except in compliance with the Flexible and Interoperable Data
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.188.0Release
9
- // Tag = production/release/21.188.0-0-g55050f8
8
+ // Profile Version = 21.195.0Release
9
+ // Tag = production/release/21.195.0-0-g569e7e5
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12
 
package/src/bit-stream.js CHANGED
@@ -1,12 +1,12 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////////////////
2
- // Copyright 2025 Garmin International, Inc.
2
+ // Copyright 2026 Garmin International, Inc.
3
3
  // Licensed under the Flexible and Interoperable Data Transfer (FIT) Protocol License; you
4
4
  // may not use this file except in compliance with the Flexible and Interoperable Data
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.188.0Release
9
- // Tag = production/release/21.188.0-0-g55050f8
8
+ // Profile Version = 21.195.0Release
9
+ // Tag = production/release/21.195.0-0-g569e7e5
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12
 
@@ -1,12 +1,12 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////////////////
2
- // Copyright 2025 Garmin International, Inc.
2
+ // Copyright 2026 Garmin International, Inc.
3
3
  // Licensed under the Flexible and Interoperable Data Transfer (FIT) Protocol License; you
4
4
  // may not use this file except in compliance with the Flexible and Interoperable Data
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.188.0Release
9
- // Tag = production/release/21.188.0-0-g55050f8
8
+ // Profile Version = 21.195.0Release
9
+ // Tag = production/release/21.195.0-0-g569e7e5
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12
 
package/src/decoder.js CHANGED
@@ -1,12 +1,12 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////////////////
2
- // Copyright 2025 Garmin International, Inc.
2
+ // Copyright 2026 Garmin International, Inc.
3
3
  // Licensed under the Flexible and Interoperable Data Transfer (FIT) Protocol License; you
4
4
  // may not use this file except in compliance with the Flexible and Interoperable Data
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.188.0Release
9
- // Tag = production/release/21.188.0-0-g55050f8
8
+ // Profile Version = 21.195.0Release
9
+ // Tag = production/release/21.195.0-0-g569e7e5
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12
 
package/src/encoder.js CHANGED
@@ -1,12 +1,12 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////////////////
2
- // Copyright 2025 Garmin International, Inc.
2
+ // Copyright 2026 Garmin International, Inc.
3
3
  // Licensed under the Flexible and Interoperable Data Transfer (FIT) Protocol License; you
4
4
  // may not use this file except in compliance with the Flexible and Interoperable Data
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.188.0Release
9
- // Tag = production/release/21.188.0-0-g55050f8
8
+ // Profile Version = 21.195.0Release
9
+ // Tag = production/release/21.195.0-0-g569e7e5
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12
 
@@ -212,12 +212,25 @@ class Encoder {
212
212
  throw new Error();
213
213
  }
214
214
 
215
+ // Convert valid numeric strings to the correct type
216
+ if (FIT.isString(value)) {
217
+ value = FIT.BigIntFieldTypes.includes(fieldDefinition.type)
218
+ ? BigInt(value)
219
+ : Number(value);
220
+ }
221
+
215
222
  const hasScaleOrOffset = (fieldDefinition.scale != FIT.FIELD_DEFAULT_SCALE || fieldDefinition.offset != FIT.FIELD_DEFAULT_OFFSET);
216
223
 
224
+ if (!hasScaleOrOffset && !this.#isValidType(value, fieldDefinition.type)) {
225
+ throw new Error();
226
+ }
227
+
217
228
  if (hasScaleOrOffset) {
218
- const scaledValue = (value + fieldDefinition.offset) * fieldDefinition.scale;
229
+ const scaledValue = this.#unapplyScaleAndOffset(value, fieldDefinition.scale, fieldDefinition.offset);
230
+
231
+ const roundedValue = FIT.FloatingPointFieldTypes.includes(fieldDefinition.type) || FIT.isBigInt(scaledValue) ? scaledValue : Math.round(scaledValue);
219
232
 
220
- return FIT.FloatingPointFieldTypes.includes(fieldDefinition.type) ? scaledValue : Math.round(scaledValue);
233
+ return FIT.BigIntFieldTypes.includes(fieldDefinition.type) ? BigInt(roundedValue) : Number(roundedValue);
221
234
  }
222
235
 
223
236
  return value;
@@ -265,6 +278,18 @@ class Encoder {
265
278
  }
266
279
  }
267
280
 
281
+ #isValidType = (value, type) => {
282
+ const jsType = FIT.FieldTypeToJsType[type];
283
+
284
+ return typeof value === jsType
285
+ }
286
+
287
+ #unapplyScaleAndOffset(value, scale, offset) {
288
+ return FIT.isBigInt(value)
289
+ ? (value + BigInt(offset)) * BigInt(scale)
290
+ : (value + offset) * scale;
291
+ }
292
+
268
293
  /**
269
294
  * Creates a MesgDefinition from the mesgNum and mesg.
270
295
  * @param {Number} mesgNum - The mesg number for this message
package/src/fit.js CHANGED
@@ -1,12 +1,12 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////////////////
2
- // Copyright 2025 Garmin International, Inc.
2
+ // Copyright 2026 Garmin International, Inc.
3
3
  // Licensed under the Flexible and Interoperable Data Transfer (FIT) Protocol License; you
4
4
  // may not use this file except in compliance with the Flexible and Interoperable Data
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.188.0Release
9
- // Tag = production/release/21.188.0-0-g55050f8
8
+ // Profile Version = 21.195.0Release
9
+ // Tag = production/release/21.195.0-0-g569e7e5
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12
 
@@ -73,6 +73,32 @@ const NumericFieldTypes = [
73
73
  "uint64z"
74
74
  ];
75
75
 
76
+ const FieldTypeToJsType = {
77
+ "enum": "number",
78
+ "sint8": "number",
79
+ "uint8": "number",
80
+ "sint16": "number",
81
+ "uint16": "number",
82
+ "sint32": "number",
83
+ "uint32": "number",
84
+ "string": "string",
85
+ "float32": "number",
86
+ "float64": "number",
87
+ "uint8z": "number",
88
+ "uint16z": "number",
89
+ "uint32z": "number",
90
+ "byte": "number",
91
+ "sint64": "bigint",
92
+ "uint64": "bigint",
93
+ "uint64z": "bigint"
94
+ }
95
+
96
+ const BigIntFieldTypes = [
97
+ "sint64",
98
+ "uint64",
99
+ "uint64z"
100
+ ];
101
+
76
102
  const FloatingPointFieldTypes = [
77
103
  "float32",
78
104
  "float64",
@@ -138,8 +164,21 @@ const isString = (obj) => {
138
164
  return typeof obj === "string";
139
165
  };
140
166
 
167
+ const isBigInt = (obj) => {
168
+ return typeof obj === "bigint";
169
+ };
170
+
141
171
  const isNumeric = (obj) => {
142
- return !isNaN(parseFloat(obj)) && isFinite(obj);
172
+ if (typeof obj === "number") {
173
+ return !isNaN(obj) && isFinite(obj);
174
+ }
175
+
176
+ if (typeof obj === "bigint") {
177
+ return true;
178
+ }
179
+
180
+ const num = parseFloat(obj);
181
+ return !isNaN(num) && isFinite(num);
143
182
  };
144
183
 
145
184
  const isNotNumberStringDateOrBoolean = (obj) => {
@@ -151,7 +190,7 @@ const isNumberStringDateOrBoolean = (obj) => {
151
190
  return false;
152
191
  }
153
192
 
154
- if (!isDate(obj) && !isString(obj) && !isNumeric(obj) && !isBoolean(obj)) {
193
+ if (!isNumeric(obj) && !isDate(obj) && !isString(obj) && !isBoolean(obj)) {
155
194
  return false;
156
195
  }
157
196
 
@@ -163,14 +202,17 @@ export default {
163
202
  BaseTypeMask,
164
203
  BaseTypeDefinitions,
165
204
  NumericFieldTypes,
205
+ BigIntFieldTypes,
166
206
  FloatingPointFieldTypes,
167
207
  FieldTypeToBaseType,
168
208
  BaseTypeToFieldType,
209
+ FieldTypeToJsType,
169
210
  isNullOrUndefined,
170
211
  isObject,
171
212
  isBoolean,
172
213
  isDate,
173
214
  isString,
215
+ isBigInt,
174
216
  isNumeric,
175
217
  isNumberStringDateOrBoolean,
176
218
  isNotNumberStringDateOrBoolean,
package/src/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////////////////
2
- // Copyright 2025 Garmin International, Inc.
2
+ // Copyright 2026 Garmin International, Inc.
3
3
  // Licensed under the Flexible and Interoperable Data Transfer (FIT) Protocol License; you
4
4
  // may not use this file except in compliance with the Flexible and Interoperable Data
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.188.0Release
9
- // Tag = production/release/21.188.0-0-g55050f8
8
+ // Profile Version = 21.195.0Release
9
+ // Tag = production/release/21.195.0-0-g569e7e5
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12
 
@@ -1,12 +1,12 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////////////////
2
- // Copyright 2025 Garmin International, Inc.
2
+ // Copyright 2026 Garmin International, Inc.
3
3
  // Licensed under the Flexible and Interoperable Data Transfer (FIT) Protocol License; you
4
4
  // may not use this file except in compliance with the Flexible and Interoperable Data
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.188.0Release
9
- // Tag = production/release/21.188.0-0-g55050f8
8
+ // Profile Version = 21.195.0Release
9
+ // Tag = production/release/21.195.0-0-g569e7e5
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12
 
@@ -86,6 +86,10 @@ class MesgDefinition {
86
86
  fieldDefinitionNumber: fieldDescriptionMesg.fieldDefinitionNumber,
87
87
  size: this.#fieldSize(mesg.developerFields[key], baseTypeDef),
88
88
  developerDataIndex: developerDataIdMesg.developerDataIndex,
89
+ type: FIT.BaseTypeToFieldType[baseTypeDef.type],
90
+ scale: 1,
91
+ offset: 0,
92
+ components: [],
89
93
  });
90
94
  });
91
95
 
@@ -1,20 +1,21 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////////////////
2
- // Copyright 2025 Garmin International, Inc.
2
+ // Copyright 2026 Garmin International, Inc.
3
3
  // Licensed under the Flexible and Interoperable Data Transfer (FIT) Protocol License; you
4
4
  // may not use this file except in compliance with the Flexible and Interoperable Data
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.188.0Release
9
- // Tag = production/release/21.188.0-0-g55050f8
8
+ // Profile Version = 21.195.0Release
9
+ // Tag = production/release/21.195.0-0-g569e7e5
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12
 
13
13
  import FIT from "./fit.js";
14
14
 
15
15
  const ONE_MEGABYTE = 1048576;
16
- const TEN_MEGABYTES = ONE_MEGABYTE * 10;
16
+ const FIVE_HUNDRED_MEGABYTES = ONE_MEGABYTE * 500;
17
17
  const HALF_MEGABYTE = ONE_MEGABYTE / 2;
18
+ const MAX_BYTE_LENGTH = FIVE_HUNDRED_MEGABYTES;
18
19
 
19
20
  class OutputStream {
20
21
  #arrayBuffer = null;
@@ -29,12 +30,12 @@ class OutputStream {
29
30
  * @constructor
30
31
  * @param {Object=} [options] - Read options (optional)
31
32
  * @param {Number} [options.initialByteLength=0.5MB] - (optional, default 0.5 MB)
32
- * @param {Number} [options.maxByteLength=2MB] - (optional, default 2 MB)
33
+ * @param {Number} [options.maxByteLength=500MB] - (optional, default 500 MB)
33
34
  * @param {Number} [options.resizeByBytes=0.5MB] - (optional, default 0.5 MB)
34
35
  */
35
36
  constructor({
36
37
  initialByteLength = HALF_MEGABYTE,
37
- maxByteLength = TEN_MEGABYTES,
38
+ maxByteLength = MAX_BYTE_LENGTH,
38
39
  resizeByBytes = HALF_MEGABYTE,
39
40
  } = {}) {
40
41
  this.#arrayBuffer = new ArrayBuffer(initialByteLength, { maxByteLength, });
@@ -209,11 +210,13 @@ class OutputStream {
209
210
  return;
210
211
  }
211
212
 
212
- if (!this.#arrayBuffer.resizable) {
213
+ const newByteLength = this.#arrayBuffer.byteLength + Math.max(this.#resizeByBytes, byteCount);
214
+
215
+ if (newByteLength > this.#arrayBuffer.maxByteLength) {
213
216
  throw new Error("Can not resize OutputStream. Set a larger initial size.");
214
217
  }
215
218
 
216
- this.#arrayBuffer.resize(this.#arrayBuffer.byteLength + Math.max(this.#resizeByBytes, byteCount));
219
+ this.#arrayBuffer.resize(newByteLength);
217
220
  }
218
221
  }
219
222
 
package/src/profile.js CHANGED
@@ -1,19 +1,19 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////////////////
2
- // Copyright 2025 Garmin International, Inc.
2
+ // Copyright 2026 Garmin International, Inc.
3
3
  // Licensed under the Flexible and Interoperable Data Transfer (FIT) Protocol License; you
4
4
  // may not use this file except in compliance with the Flexible and Interoperable Data
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.188.0Release
9
- // Tag = production/release/21.188.0-0-g55050f8
8
+ // Profile Version = 21.195.0Release
9
+ // Tag = production/release/21.195.0-0-g569e7e5
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12
 
13
13
  const Profile = {
14
14
  version: {
15
15
  major: 21,
16
- minor: 188,
16
+ minor: 195,
17
17
  patch: 0,
18
18
  type: "Release"
19
19
  },
@@ -7042,6 +7042,21 @@ const Profile = {
7042
7042
  hasComponents: false,
7043
7043
  subFields: []
7044
7044
  },
7045
+ 196: {
7046
+ num: 196,
7047
+ name: "metabolicCalories",
7048
+ type: "uint16",
7049
+ baseType: "uint16",
7050
+ array: false,
7051
+ scale: 1,
7052
+ offset: 0,
7053
+ units: "kcal",
7054
+ bits: [],
7055
+ components: [],
7056
+ isAccumulated: false,
7057
+ hasComponents: false,
7058
+ subFields: []
7059
+ },
7045
7060
  197: {
7046
7061
  num: 197, // Standard deviation of R-R interval (SDRR) - Heart rate variability measure most useful for wellness users.
7047
7062
  name: "sdrrHrv",
@@ -24363,6 +24378,11 @@ types: {
24363
24378
  334: "daradInnovationCorporation",
24364
24379
  335: "cycloptim",
24365
24380
  337: "runna",
24381
+ 339: "zepp",
24382
+ 340: "peloton",
24383
+ 341: "carv",
24384
+ 342: "tissot",
24385
+ 345: "realVelo",
24366
24386
  5759: "actigraphcorp",
24367
24387
  },
24368
24388
  garminProduct: {
@@ -24825,6 +24845,7 @@ types: {
24825
24845
  4759: "instinct3Solar50mm",
24826
24846
  4775: "tactix8Amoled",
24827
24847
  4776: "tactix8Solar",
24848
+ 4825: "approachJ1",
24828
24849
  4879: "d2Mach2",
24829
24850
  4678: "instinctCrossoverAmoled",
24830
24851
  4944: "d2AirX15",
package/src/stream.js CHANGED
@@ -1,12 +1,12 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////////////////
2
- // Copyright 2025 Garmin International, Inc.
2
+ // Copyright 2026 Garmin International, Inc.
3
3
  // Licensed under the Flexible and Interoperable Data Transfer (FIT) Protocol License; you
4
4
  // may not use this file except in compliance with the Flexible and Interoperable Data
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.188.0Release
9
- // Tag = production/release/21.188.0-0-g55050f8
8
+ // Profile Version = 21.195.0Release
9
+ // Tag = production/release/21.195.0-0-g569e7e5
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12
 
@@ -1,12 +1,12 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////////////////
2
- // Copyright 2025 Garmin International, Inc.
2
+ // Copyright 2026 Garmin International, Inc.
3
3
  // Licensed under the Flexible and Interoperable Data Transfer (FIT) Protocol License; you
4
4
  // may not use this file except in compliance with the Flexible and Interoperable Data
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.188.0Release
9
- // Tag = production/release/21.188.0-0-g55050f8
8
+ // Profile Version = 21.195.0Release
9
+ // Tag = production/release/21.195.0-0-g569e7e5
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12
 
@@ -1,12 +1,12 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////////////////
2
- // Copyright 2025 Garmin International, Inc.
2
+ // Copyright 2026 Garmin International, Inc.
3
3
  // Licensed under the Flexible and Interoperable Data Transfer (FIT) Protocol License; you
4
4
  // may not use this file except in compliance with the Flexible and Interoperable Data
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.188.0Release
9
- // Tag = production/release/21.188.0-0-g55050f8
8
+ // Profile Version = 21.195.0Release
9
+ // Tag = production/release/21.195.0-0-g569e7e5
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12
 
@@ -1,12 +1,12 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////////////////
2
- // Copyright 2025 Garmin International, Inc.
2
+ // Copyright 2026 Garmin International, Inc.
3
3
  // Licensed under the Flexible and Interoperable Data Transfer (FIT) Protocol License; you
4
4
  // may not use this file except in compliance with the Flexible and Interoperable Data
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.188.0Release
9
- // Tag = production/release/21.188.0-0-g55050f8
8
+ // Profile Version = 21.195.0Release
9
+ // Tag = production/release/21.195.0-0-g569e7e5
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12
  import Profile from "./profile.js";
package/src/utils.js CHANGED
@@ -1,12 +1,12 @@
1
1
  /////////////////////////////////////////////////////////////////////////////////////////////
2
- // Copyright 2025 Garmin International, Inc.
2
+ // Copyright 2026 Garmin International, Inc.
3
3
  // Licensed under the Flexible and Interoperable Data Transfer (FIT) Protocol License; you
4
4
  // may not use this file except in compliance with the Flexible and Interoperable Data
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.188.0Release
9
- // Tag = production/release/21.188.0-0-g55050f8
8
+ // Profile Version = 21.195.0Release
9
+ // Tag = production/release/21.195.0-0-g569e7e5
10
10
  /////////////////////////////////////////////////////////////////////////////////////////////
11
11
 
12
12