lubba-encoder 1.1.15 → 1.1.17

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
@@ -3,3 +3,16 @@
3
3
  Encodes Lubba workouts from/to yaml, uint8 array and base64 hash.
4
4
 
5
5
  Can be used to create workouts that the Lubba app can import.
6
+
7
+ ## Workout notes
8
+
9
+ Workouts can include an optional `notes` string. JSON, YAML, and share hashes
10
+ preserve its Unicode text, newlines, and empty strings. Null or missing notes
11
+ are omitted.
12
+
13
+ Encoding version 1 stores notes as an optional trailing variable-length string
14
+ after the workout parts. Workouts without notes keep exactly the same bytes and
15
+ hashes. Updated decoders read old links; older decoders still read the workout
16
+ but ignore the notes trailer. Older decoders do not recognize the new
17
+ `workoutNotes` layout value (ID 72), so update consumers before sharing layouts
18
+ that use it.
@@ -120,7 +120,13 @@ const valueGoalTypeMap = {
120
120
  powerAverageIntervalPercentageCP: 63,
121
121
  powerToHeartRateRatio: 64,
122
122
  powerToHeartRateRatioAverageDuration: 65,
123
- powerToHeartRateRatioAverageInterval: 66
123
+ powerToHeartRateRatioAverageInterval: 66,
124
+ breathingRate: 67,
125
+ tidalVolume: 68,
126
+ minuteVentilation: 69,
127
+ minuteVentilationAverage60s: 70,
128
+ inhaleExhaleRatio: 71,
129
+ workoutNotes: 72
124
130
  };
125
131
 
126
132
  const partTitleMapReverse = reverseObject(partTitleMap);
@@ -281,6 +287,10 @@ function encodeJsonObjectToLubbaData (object, encodingVersion) {
281
287
  encodePart(part, encoder);
282
288
  }
283
289
 
290
+ // Optional v1 trailer: old decoders stop after parts and safely ignore it.
291
+ // Omit absent notes so existing workout hashes remain byte-for-byte stable.
292
+ if (object.notes != null) encoding__namespace.writeVarString(encoder, object.notes);
293
+
284
294
  return encoding__namespace.toUint8Array(encoder)
285
295
  }
286
296
 
@@ -305,6 +315,10 @@ function decodeLubbaData (data) {
305
315
  decoded.parts.push(decodePart(decoder));
306
316
  }
307
317
 
318
+ if (decoding__namespace.hasContent(decoder)) {
319
+ decoded.notes = decoding__namespace.readVarString(decoder);
320
+ }
321
+
308
322
  return decoded
309
323
  }
310
324
 
@@ -1 +1 @@
1
- {"version":3,"file":"lubba-encoder.cjs","sources":["../src/index.js"],"sourcesContent":["/* global btoa atob */\nimport * as encoding from 'lib0/dist/encoding.cjs'\nimport * as decoding from 'lib0/dist/decoding.cjs'\nimport { parse as parseYaml } from 'yaml'\n\nconst reverseObject = (object) => (\n Object.keys(object).reduce((res, key) => { res[object[key]] = key; return res }, {})\n)\n\nconst partTitleMap = {\n Warmup: 1,\n Activity: 2,\n Fast: 3,\n Recover: 4,\n Rest: 5,\n Cooldown: 6,\n Ski: 7,\n Run: 8,\n Skate: 9,\n Walk: 10\n}\nconst layoutMap = {\n 1: 1,\n '2+1': 2,\n '2+2': 3,\n '2+3': 4,\n '3+3': 5,\n '1+1': 6,\n '1+2': 7\n}\nconst valueGoalTypeMap = {\n duration: 1,\n distance: 2,\n distanceTest: 3,\n paceCurrent: 4,\n paceTest: 5,\n paceTest2: 6,\n paceAverageDuration: 7,\n bpm: 8,\n bpmAverageDuration: 9,\n intervalLeft: 10,\n durationInterval: 11,\n distanceInterval: 12,\n desiredAccuracy: 13,\n pace: 14, // used for target type\n paceSplits: 15,\n smartDistance: 16,\n smartDuration: 17,\n speedCurrent: 18,\n speedAverageDuration: 19,\n totalActiveEnergyBurned: 20,\n activeEnergyBurnedInterval: 21,\n totalEnergyBurned: 22,\n energyBurnedInterval: 23,\n runningPower: 24,\n runningVerticalOscillation: 25,\n runningGroundContactTime: 26,\n rpe: 27,\n speed: 28,\n cyclingPower: 29,\n pacePer100Current: 30,\n pacePer100AverageDuration: 31,\n laps: 32,\n lapsInterval: 33,\n smartLaps: 34,\n paceInterval: 35,\n pacePer100Interval: 36,\n speedInterval: 37,\n pacePerKmMiSegment: 38,\n speedPerKmMiSegment: 39,\n bpmAverageInterval: 40,\n bpmAverageKmMiSegment: 41,\n bpmZone: 42,\n cyclingCadence: 43,\n runningCadence: 44,\n powerTotalRSS: 45,\n powerAverageDuration: 46,\n powerAverage3s: 47,\n powerAverage10s: 48,\n powerAverageInterval: 49,\n powerMaxDuration: 50,\n power: 51,\n runningStrideLength: 52,\n runningStrideLengthAverageDuration: 53,\n runningStrideLengthAverageInterval: 54,\n dfaAlpha1: 55,\n coreBodyTemperature: 56,\n skinTemperature: 57,\n heatStrainIndex: 58,\n powerPercentageCP: 59,\n powerAverageDurationPercentageCP: 60,\n powerAverage3sPercentageCP: 61,\n powerAverage10sPercentageCP: 62,\n powerAverageIntervalPercentageCP: 63,\n powerToHeartRateRatio: 64,\n powerToHeartRateRatioAverageDuration: 65,\n powerToHeartRateRatioAverageInterval: 66\n}\n\nconst partTitleMapReverse = reverseObject(partTitleMap)\nconst layoutMapReverse = reverseObject(layoutMap)\nconst valueGoalTypeMapReverse = reverseObject(valueGoalTypeMap)\n\nfunction getBit (number, bitPosition) {\n return (number & (1 << bitPosition)) === 0 ? 0 : 1\n}\n\nfunction updateBit (number, bitPosition, bitValue) {\n const bitValueNormalized = bitValue ? 1 : 0\n const clearMask = ~(1 << bitPosition)\n return (number & clearMask) | (bitValueNormalized << bitPosition)\n}\n\nfunction encodePart (part, encoder) {\n // Set flags for nil values\n let flagsA = 0\n let flagsB = 0\n\n flagsA = updateBit(flagsA, 0, part.title != null)\n flagsA = updateBit(flagsA, 1, part.layout != null)\n flagsA = updateBit(flagsA, 2, part.layoutValues != null && part.layoutValues.length > 0)\n flagsA = updateBit(flagsA, 3, part.goalType != null)\n flagsA = updateBit(flagsA, 4, part.goalValue != null)\n flagsA = updateBit(flagsA, 5, part.goalIsVariable === true)\n flagsA = updateBit(flagsA, 6, part.targetType != null)\n flagsA = updateBit(flagsA, 7, part.targetMin != null)\n\n flagsB = updateBit(flagsB, 0, part.targetMax != null)\n flagsB = updateBit(flagsB, 1, part.repeats != null && part.repeats > 0)\n flagsB = updateBit(flagsB, 2, part.repeatParts != null && part.repeatParts.length > 0)\n flagsB = updateBit(flagsB, 3, part.goalTypeVariation != null)\n\n encoding.writeUint8(encoder, flagsA)\n encoding.writeUint8(encoder, flagsB)\n\n // Use part title map, or custom title\n if (part.title != null) {\n const titleIndex = partTitleMap[part.title]\n if (titleIndex) {\n encoding.writeUint8(encoder, titleIndex)\n } else {\n encoding.writeUint8(encoder, 0) // 0 indicates custom string\n encoding.writeVarString(encoder, part.title)\n }\n }\n\n if (part.layout != null) encoding.writeUint8(encoder, layoutMap[part.layout])\n if (part.layoutValues != null && part.layoutValues.length > 0) {\n encoding.writeUint8(encoder, part.layoutValues.length)\n\n for (const value of part.layoutValues) {\n encoding.writeUint8(encoder, valueGoalTypeMap[value])\n }\n }\n\n if (part.goalType != null) encoding.writeUint8(encoder, valueGoalTypeMap[part.goalType])\n if (part.goalValue != null) encoding.writeFloat64(encoder, part.goalValue)\n if (part.goalTypeVariation != null) encoding.writeUint8(encoder, part.goalTypeVariation)\n\n if (part.targetType != null) encoding.writeUint8(encoder, valueGoalTypeMap[part.targetType])\n if (part.targetMin != null) encoding.writeFloat64(encoder, part.targetMin)\n if (part.targetMax != null) encoding.writeFloat64(encoder, part.targetMax)\n\n if (part.repeats != null && part.repeats > 0) encoding.writeUint8(encoder, part.repeats)\n\n if (part.repeatParts != null && part.repeatParts.length > 0) {\n encoding.writeUint8(encoder, part.repeatParts.length)\n\n for (const subPart of part.repeatParts) {\n encodePart(subPart, encoder)\n }\n }\n}\n\nfunction decodePart (decoder) {\n const part = {}\n\n // Some flags to indicate what values is non-nil\n const flagsA = decoding.readUint8(decoder)\n const flagsB = decoding.readUint8(decoder)\n\n const hasTitle = getBit(flagsA, 0)\n const hasLayout = getBit(flagsA, 1)\n const hasLayoutValues = getBit(flagsA, 2)\n const hasGoalType = getBit(flagsA, 3)\n const hasGoalValue = getBit(flagsA, 4)\n const hasGoalIsVariable = getBit(flagsA, 5)\n const hasTargetType = getBit(flagsA, 6)\n const hasTargetMin = getBit(flagsA, 7)\n\n const hasTargetMax = getBit(flagsB, 0)\n const hasRepeats = getBit(flagsB, 1)\n const hasRepeatParts = getBit(flagsB, 2)\n const hasGoalTypeVariation = getBit(flagsB, 3)\n\n // Use part title map, or custom title\n if (hasTitle) {\n const titleIndex = decoding.readUint8(decoder)\n const titleIsCustomString = titleIndex === 0\n part.title = titleIsCustomString ? decoding.readVarString(decoder) : partTitleMapReverse[titleIndex]\n }\n\n if (hasLayout) part.layout = layoutMapReverse[decoding.readUint8(decoder)]\n if (hasLayoutValues) {\n const amountValues = decoding.readUint8(decoder)\n part.layoutValues = []\n\n for (let j = 0; j < amountValues; j++) {\n part.layoutValues.push(valueGoalTypeMapReverse[decoding.readUint8(decoder)])\n }\n }\n\n if (hasGoalType) part.goalType = valueGoalTypeMapReverse[decoding.readUint8(decoder)]\n if (hasGoalValue) part.goalValue = decoding.readFloat64(decoder)\n if (hasGoalTypeVariation) part.goalTypeVariation = decoding.readUint8(decoder)\n if (hasGoalIsVariable) part.goalIsVariable = true\n\n if (hasTargetType) part.targetType = valueGoalTypeMapReverse[decoding.readUint8(decoder)]\n if (hasTargetMin) part.targetMin = decoding.readFloat64(decoder)\n if (hasTargetMax) part.targetMax = decoding.readFloat64(decoder)\n\n if (hasRepeats) part.repeats = decoding.readUint8(decoder)\n if (hasRepeatParts) {\n const amountParts = decoding.readUint8(decoder)\n part.repeatParts = []\n\n for (let j = 0; j < amountParts; j++) {\n part.repeatParts.push(decodePart(decoder))\n }\n }\n\n return part\n}\n\nexport function encodeYamlToLubbaData (yaml, encodingVersion) {\n const object = parseYaml(yaml)\n\n return encodeJsonObjectToLubbaData(object, encodingVersion)\n}\n\nexport function encodeJsonObjectToLubbaData (object, encodingVersion) {\n const encoder = encoding.createEncoder()\n\n encoding.writeUint8(encoder, encodingVersion)\n encoding.writeUint8(encoder, object.isMetric ? 1 : 0)\n encoding.writeVarString(encoder, object.title)\n encoding.writeUint32(encoder, object.activityType)\n encoding.writeUint8(encoder, object.locationType)\n\n // Parts\n const amountParts = (object.parts && object.parts.length) || 0\n encoding.writeUint8(encoder, amountParts)\n\n for (const part of object.parts) {\n encodePart(part, encoder)\n }\n\n return encoding.toUint8Array(encoder)\n}\n\nexport function decodeLubbaData (data) {\n const decoder = decoding.createDecoder(data)\n const encodingVersion = decoding.readUint8(decoder)\n\n if (encodingVersion === 1) {\n const decoded = {\n isCustom: true // Assume all are custom\n }\n\n decoded.isMetric = decoding.readUint8(decoder) === 1\n decoded.title = decoding.readVarString(decoder)\n decoded.activityType = decoding.readUint32(decoder)\n decoded.locationType = decoding.readUint8(decoder)\n\n // Parts\n const amountParts = decoding.readUint8(decoder)\n decoded.parts = []\n for (let i = 0; i < amountParts; i++) {\n decoded.parts.push(decodePart(decoder))\n }\n\n return decoded\n }\n\n return null\n}\n\n// Some short encoding (base64)\nexport function encodeLubbaDataToHash (data, urlEncode) {\n let s = ''\n for (const byte of data) {\n s += String.fromCharCode(byte)\n }\n\n if (urlEncode) {\n return btoa(s).replace(/\\//g, '%2F')\n } else {\n return btoa(s)\n }\n}\n\nexport function decodeLubbaDataFromHash (hash) {\n const a = atob(hash)\n const bytes = new Uint8Array(a.length)\n for (let i = 0; i < a.length; i++) {\n bytes[i] = a.charCodeAt(i)\n }\n return bytes\n}\n"],"names":["encoding","decoding","yaml","parseYaml"],"mappings":"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"}
1
+ {"version":3,"file":"lubba-encoder.cjs","sources":["../src/index.js"],"sourcesContent":["/* global btoa atob */\nimport * as encoding from 'lib0/dist/encoding.cjs'\nimport * as decoding from 'lib0/dist/decoding.cjs'\nimport { parse as parseYaml } from 'yaml'\n\nconst reverseObject = (object) => (\n Object.keys(object).reduce((res, key) => { res[object[key]] = key; return res }, {})\n)\n\nconst partTitleMap = {\n Warmup: 1,\n Activity: 2,\n Fast: 3,\n Recover: 4,\n Rest: 5,\n Cooldown: 6,\n Ski: 7,\n Run: 8,\n Skate: 9,\n Walk: 10\n}\nconst layoutMap = {\n 1: 1,\n '2+1': 2,\n '2+2': 3,\n '2+3': 4,\n '3+3': 5,\n '1+1': 6,\n '1+2': 7\n}\nconst valueGoalTypeMap = {\n duration: 1,\n distance: 2,\n distanceTest: 3,\n paceCurrent: 4,\n paceTest: 5,\n paceTest2: 6,\n paceAverageDuration: 7,\n bpm: 8,\n bpmAverageDuration: 9,\n intervalLeft: 10,\n durationInterval: 11,\n distanceInterval: 12,\n desiredAccuracy: 13,\n pace: 14, // used for target type\n paceSplits: 15,\n smartDistance: 16,\n smartDuration: 17,\n speedCurrent: 18,\n speedAverageDuration: 19,\n totalActiveEnergyBurned: 20,\n activeEnergyBurnedInterval: 21,\n totalEnergyBurned: 22,\n energyBurnedInterval: 23,\n runningPower: 24,\n runningVerticalOscillation: 25,\n runningGroundContactTime: 26,\n rpe: 27,\n speed: 28,\n cyclingPower: 29,\n pacePer100Current: 30,\n pacePer100AverageDuration: 31,\n laps: 32,\n lapsInterval: 33,\n smartLaps: 34,\n paceInterval: 35,\n pacePer100Interval: 36,\n speedInterval: 37,\n pacePerKmMiSegment: 38,\n speedPerKmMiSegment: 39,\n bpmAverageInterval: 40,\n bpmAverageKmMiSegment: 41,\n bpmZone: 42,\n cyclingCadence: 43,\n runningCadence: 44,\n powerTotalRSS: 45,\n powerAverageDuration: 46,\n powerAverage3s: 47,\n powerAverage10s: 48,\n powerAverageInterval: 49,\n powerMaxDuration: 50,\n power: 51,\n runningStrideLength: 52,\n runningStrideLengthAverageDuration: 53,\n runningStrideLengthAverageInterval: 54,\n dfaAlpha1: 55,\n coreBodyTemperature: 56,\n skinTemperature: 57,\n heatStrainIndex: 58,\n powerPercentageCP: 59,\n powerAverageDurationPercentageCP: 60,\n powerAverage3sPercentageCP: 61,\n powerAverage10sPercentageCP: 62,\n powerAverageIntervalPercentageCP: 63,\n powerToHeartRateRatio: 64,\n powerToHeartRateRatioAverageDuration: 65,\n powerToHeartRateRatioAverageInterval: 66,\n breathingRate: 67,\n tidalVolume: 68,\n minuteVentilation: 69,\n minuteVentilationAverage60s: 70,\n inhaleExhaleRatio: 71,\n workoutNotes: 72\n}\n\nconst partTitleMapReverse = reverseObject(partTitleMap)\nconst layoutMapReverse = reverseObject(layoutMap)\nconst valueGoalTypeMapReverse = reverseObject(valueGoalTypeMap)\n\nfunction getBit (number, bitPosition) {\n return (number & (1 << bitPosition)) === 0 ? 0 : 1\n}\n\nfunction updateBit (number, bitPosition, bitValue) {\n const bitValueNormalized = bitValue ? 1 : 0\n const clearMask = ~(1 << bitPosition)\n return (number & clearMask) | (bitValueNormalized << bitPosition)\n}\n\nfunction encodePart (part, encoder) {\n // Set flags for nil values\n let flagsA = 0\n let flagsB = 0\n\n flagsA = updateBit(flagsA, 0, part.title != null)\n flagsA = updateBit(flagsA, 1, part.layout != null)\n flagsA = updateBit(flagsA, 2, part.layoutValues != null && part.layoutValues.length > 0)\n flagsA = updateBit(flagsA, 3, part.goalType != null)\n flagsA = updateBit(flagsA, 4, part.goalValue != null)\n flagsA = updateBit(flagsA, 5, part.goalIsVariable === true)\n flagsA = updateBit(flagsA, 6, part.targetType != null)\n flagsA = updateBit(flagsA, 7, part.targetMin != null)\n\n flagsB = updateBit(flagsB, 0, part.targetMax != null)\n flagsB = updateBit(flagsB, 1, part.repeats != null && part.repeats > 0)\n flagsB = updateBit(flagsB, 2, part.repeatParts != null && part.repeatParts.length > 0)\n flagsB = updateBit(flagsB, 3, part.goalTypeVariation != null)\n\n encoding.writeUint8(encoder, flagsA)\n encoding.writeUint8(encoder, flagsB)\n\n // Use part title map, or custom title\n if (part.title != null) {\n const titleIndex = partTitleMap[part.title]\n if (titleIndex) {\n encoding.writeUint8(encoder, titleIndex)\n } else {\n encoding.writeUint8(encoder, 0) // 0 indicates custom string\n encoding.writeVarString(encoder, part.title)\n }\n }\n\n if (part.layout != null) encoding.writeUint8(encoder, layoutMap[part.layout])\n if (part.layoutValues != null && part.layoutValues.length > 0) {\n encoding.writeUint8(encoder, part.layoutValues.length)\n\n for (const value of part.layoutValues) {\n encoding.writeUint8(encoder, valueGoalTypeMap[value])\n }\n }\n\n if (part.goalType != null) encoding.writeUint8(encoder, valueGoalTypeMap[part.goalType])\n if (part.goalValue != null) encoding.writeFloat64(encoder, part.goalValue)\n if (part.goalTypeVariation != null) encoding.writeUint8(encoder, part.goalTypeVariation)\n\n if (part.targetType != null) encoding.writeUint8(encoder, valueGoalTypeMap[part.targetType])\n if (part.targetMin != null) encoding.writeFloat64(encoder, part.targetMin)\n if (part.targetMax != null) encoding.writeFloat64(encoder, part.targetMax)\n\n if (part.repeats != null && part.repeats > 0) encoding.writeUint8(encoder, part.repeats)\n\n if (part.repeatParts != null && part.repeatParts.length > 0) {\n encoding.writeUint8(encoder, part.repeatParts.length)\n\n for (const subPart of part.repeatParts) {\n encodePart(subPart, encoder)\n }\n }\n}\n\nfunction decodePart (decoder) {\n const part = {}\n\n // Some flags to indicate what values is non-nil\n const flagsA = decoding.readUint8(decoder)\n const flagsB = decoding.readUint8(decoder)\n\n const hasTitle = getBit(flagsA, 0)\n const hasLayout = getBit(flagsA, 1)\n const hasLayoutValues = getBit(flagsA, 2)\n const hasGoalType = getBit(flagsA, 3)\n const hasGoalValue = getBit(flagsA, 4)\n const hasGoalIsVariable = getBit(flagsA, 5)\n const hasTargetType = getBit(flagsA, 6)\n const hasTargetMin = getBit(flagsA, 7)\n\n const hasTargetMax = getBit(flagsB, 0)\n const hasRepeats = getBit(flagsB, 1)\n const hasRepeatParts = getBit(flagsB, 2)\n const hasGoalTypeVariation = getBit(flagsB, 3)\n\n // Use part title map, or custom title\n if (hasTitle) {\n const titleIndex = decoding.readUint8(decoder)\n const titleIsCustomString = titleIndex === 0\n part.title = titleIsCustomString ? decoding.readVarString(decoder) : partTitleMapReverse[titleIndex]\n }\n\n if (hasLayout) part.layout = layoutMapReverse[decoding.readUint8(decoder)]\n if (hasLayoutValues) {\n const amountValues = decoding.readUint8(decoder)\n part.layoutValues = []\n\n for (let j = 0; j < amountValues; j++) {\n part.layoutValues.push(valueGoalTypeMapReverse[decoding.readUint8(decoder)])\n }\n }\n\n if (hasGoalType) part.goalType = valueGoalTypeMapReverse[decoding.readUint8(decoder)]\n if (hasGoalValue) part.goalValue = decoding.readFloat64(decoder)\n if (hasGoalTypeVariation) part.goalTypeVariation = decoding.readUint8(decoder)\n if (hasGoalIsVariable) part.goalIsVariable = true\n\n if (hasTargetType) part.targetType = valueGoalTypeMapReverse[decoding.readUint8(decoder)]\n if (hasTargetMin) part.targetMin = decoding.readFloat64(decoder)\n if (hasTargetMax) part.targetMax = decoding.readFloat64(decoder)\n\n if (hasRepeats) part.repeats = decoding.readUint8(decoder)\n if (hasRepeatParts) {\n const amountParts = decoding.readUint8(decoder)\n part.repeatParts = []\n\n for (let j = 0; j < amountParts; j++) {\n part.repeatParts.push(decodePart(decoder))\n }\n }\n\n return part\n}\n\nexport function encodeYamlToLubbaData (yaml, encodingVersion) {\n const object = parseYaml(yaml)\n\n return encodeJsonObjectToLubbaData(object, encodingVersion)\n}\n\nexport function encodeJsonObjectToLubbaData (object, encodingVersion) {\n const encoder = encoding.createEncoder()\n\n encoding.writeUint8(encoder, encodingVersion)\n encoding.writeUint8(encoder, object.isMetric ? 1 : 0)\n encoding.writeVarString(encoder, object.title)\n encoding.writeUint32(encoder, object.activityType)\n encoding.writeUint8(encoder, object.locationType)\n\n // Parts\n const amountParts = (object.parts && object.parts.length) || 0\n encoding.writeUint8(encoder, amountParts)\n\n for (const part of object.parts) {\n encodePart(part, encoder)\n }\n\n // Optional v1 trailer: old decoders stop after parts and safely ignore it.\n // Omit absent notes so existing workout hashes remain byte-for-byte stable.\n if (object.notes != null) encoding.writeVarString(encoder, object.notes)\n\n return encoding.toUint8Array(encoder)\n}\n\nexport function decodeLubbaData (data) {\n const decoder = decoding.createDecoder(data)\n const encodingVersion = decoding.readUint8(decoder)\n\n if (encodingVersion === 1) {\n const decoded = {\n isCustom: true // Assume all are custom\n }\n\n decoded.isMetric = decoding.readUint8(decoder) === 1\n decoded.title = decoding.readVarString(decoder)\n decoded.activityType = decoding.readUint32(decoder)\n decoded.locationType = decoding.readUint8(decoder)\n\n // Parts\n const amountParts = decoding.readUint8(decoder)\n decoded.parts = []\n for (let i = 0; i < amountParts; i++) {\n decoded.parts.push(decodePart(decoder))\n }\n\n if (decoding.hasContent(decoder)) {\n decoded.notes = decoding.readVarString(decoder)\n }\n\n return decoded\n }\n\n return null\n}\n\n// Some short encoding (base64)\nexport function encodeLubbaDataToHash (data, urlEncode) {\n let s = ''\n for (const byte of data) {\n s += String.fromCharCode(byte)\n }\n\n if (urlEncode) {\n return btoa(s).replace(/\\//g, '%2F')\n } else {\n return btoa(s)\n }\n}\n\nexport function decodeLubbaDataFromHash (hash) {\n const a = atob(hash)\n const bytes = new Uint8Array(a.length)\n for (let i = 0; i < a.length; i++) {\n bytes[i] = a.charCodeAt(i)\n }\n return bytes\n}\n"],"names":["encoding","decoding","yaml","parseYaml"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lubba-encoder",
3
- "version": "1.1.15",
3
+ "version": "1.1.17",
4
4
  "main": "./dist/lubba-encoder.cjs",
5
5
  "license": "MIT",
6
6
  "exports": {
package/src/index.js CHANGED
@@ -94,7 +94,13 @@ const valueGoalTypeMap = {
94
94
  powerAverageIntervalPercentageCP: 63,
95
95
  powerToHeartRateRatio: 64,
96
96
  powerToHeartRateRatioAverageDuration: 65,
97
- powerToHeartRateRatioAverageInterval: 66
97
+ powerToHeartRateRatioAverageInterval: 66,
98
+ breathingRate: 67,
99
+ tidalVolume: 68,
100
+ minuteVentilation: 69,
101
+ minuteVentilationAverage60s: 70,
102
+ inhaleExhaleRatio: 71,
103
+ workoutNotes: 72
98
104
  }
99
105
 
100
106
  const partTitleMapReverse = reverseObject(partTitleMap)
@@ -255,6 +261,10 @@ export function encodeJsonObjectToLubbaData (object, encodingVersion) {
255
261
  encodePart(part, encoder)
256
262
  }
257
263
 
264
+ // Optional v1 trailer: old decoders stop after parts and safely ignore it.
265
+ // Omit absent notes so existing workout hashes remain byte-for-byte stable.
266
+ if (object.notes != null) encoding.writeVarString(encoder, object.notes)
267
+
258
268
  return encoding.toUint8Array(encoder)
259
269
  }
260
270
 
@@ -279,6 +289,10 @@ export function decodeLubbaData (data) {
279
289
  decoded.parts.push(decodePart(decoder))
280
290
  }
281
291
 
292
+ if (decoding.hasContent(decoder)) {
293
+ decoded.notes = decoding.readVarString(decoder)
294
+ }
295
+
282
296
  return decoded
283
297
  }
284
298
 
package/src/index.test.js CHANGED
@@ -322,6 +322,51 @@ test('supports CORE2 temperature layout values', () => {
322
322
  })
323
323
  })
324
324
 
325
+ test('supports Tymewear breathing layout values', () => {
326
+ const encodingVersion = 1
327
+ const encoded = encodeJsonObjectToLubbaData({
328
+ isCustom: true,
329
+ isMetric: true,
330
+ title: 'Tymewear workout',
331
+ activityType: 37,
332
+ locationType: 1,
333
+ parts: [
334
+ {
335
+ title: 'Run',
336
+ layout: '2+3',
337
+ layoutValues: [
338
+ 'breathingRate',
339
+ 'tidalVolume',
340
+ 'minuteVentilation',
341
+ 'minuteVentilationAverage60s',
342
+ 'inhaleExhaleRatio'
343
+ ]
344
+ }
345
+ ]
346
+ }, encodingVersion)
347
+
348
+ expect(decodeLubbaData(encoded)).toEqual({
349
+ isCustom: true,
350
+ isMetric: true,
351
+ title: 'Tymewear workout',
352
+ activityType: 37,
353
+ locationType: 1,
354
+ parts: [
355
+ {
356
+ title: 'Run',
357
+ layout: '2+3',
358
+ layoutValues: [
359
+ 'breathingRate',
360
+ 'tidalVolume',
361
+ 'minuteVentilation',
362
+ 'minuteVentilationAverage60s',
363
+ 'inhaleExhaleRatio'
364
+ ]
365
+ }
366
+ ]
367
+ })
368
+ })
369
+
325
370
  test('supports power percentage of CP layout values', () => {
326
371
  const encodingVersion = 1
327
372
  const encoded = encodeJsonObjectToLubbaData({
@@ -431,3 +476,86 @@ test('supports power to heart rate ratio layout values', () => {
431
476
  ]
432
477
  })
433
478
  })
479
+
480
+ test('preserves workout notes layout values in single, grid, and nested layouts', () => {
481
+ const workout = {
482
+ isCustom: true,
483
+ isMetric: true,
484
+ title: 'Race plan',
485
+ activityType: 37,
486
+ locationType: 3,
487
+ parts: [
488
+ { layout: '1', layoutValues: ['workoutNotes'] },
489
+ {
490
+ layout: '2+2',
491
+ layoutValues: ['workoutNotes', 'duration', 'distance', 'bpm']
492
+ },
493
+ {
494
+ repeats: 2,
495
+ repeatParts: [{ layout: '1', layoutValues: ['workoutNotes'] }]
496
+ }
497
+ ]
498
+ }
499
+ const encoded = encodeJsonObjectToLubbaData(workout, 1)
500
+ const hash = encodeLubbaDataToHash(encoded)
501
+
502
+ expect(decodeLubbaData(decodeLubbaDataFromHash(hash))).toEqual(workout)
503
+ })
504
+
505
+ test('uses the next unused layout value ID without changing existing IDs', () => {
506
+ const encoded = encodeJsonObjectToLubbaData({
507
+ isMetric: true,
508
+ title: '',
509
+ activityType: 37,
510
+ locationType: 3,
511
+ parts: [{ layoutValues: ['inhaleExhaleRatio', 'workoutNotes', 'duration'] }]
512
+ }, 1)
513
+
514
+ expect(Array.from(encoded.slice(-3))).toEqual([71, 72, 1])
515
+ })
516
+
517
+ test.each([
518
+ '',
519
+ 'Fuel every 30 minutes.\n\nRelax shoulders.\nFinish strong.\n',
520
+ 'Ät en gel. 飲水 🏃\nKeep going!',
521
+ 'Long race plan: fuel, drink, relax.\n'.repeat(3000)
522
+ ])('preserves notes through JSON and URL hash encoding (%#)', (notes) => {
523
+ const workout = { ...jsonObject, notes }
524
+ const encoded = encodeJsonObjectToLubbaData(workout, 1)
525
+ const hash = encodeLubbaDataToHash(encoded, true)
526
+ const decoded = decodeLubbaData(decodeLubbaDataFromHash(decodeURIComponent(hash)))
527
+
528
+ expect(decoded).toEqual({ ...result, notes })
529
+ const legacyBytes = encodeJsonObjectToLubbaData(jsonObject, 1)
530
+ expect(encoded.slice(0, legacyBytes.length)).toEqual(legacyBytes)
531
+ })
532
+
533
+ test('preserves YAML multiline notes', () => {
534
+ const encoded = encodeYamlToLubbaData(yaml + `notes: |
535
+ Take a gel every 30 minutes.
536
+
537
+ Relax shoulders.
538
+ `, 1)
539
+ expect(decodeLubbaData(encoded)).toEqual({
540
+ ...result,
541
+ notes: 'Take a gel every 30 minutes.\n\nRelax shoulders.\n'
542
+ })
543
+ })
544
+
545
+ test('omits null notes and keeps legacy hashes unchanged', () => {
546
+ const legacyBytes = encodeJsonObjectToLubbaData(jsonObject, 1)
547
+ const withoutNotes = encodeJsonObjectToLubbaData({ ...jsonObject, notes: null }, 1)
548
+
549
+ expect(withoutNotes).toEqual(legacyBytes)
550
+ expect(decodeLubbaData(withoutNotes)).toEqual(result)
551
+ expect(decodeLubbaData(decodeLubbaDataFromHash(
552
+ 'AQERTXkgY3VzdG9tIHdvcmtvdXQlAAAAAwMBAAEZAAgCQI9AAAAAAAABAAY='
553
+ ))).toMatchObject({
554
+ title: 'My custom workout',
555
+ parts: [
556
+ { title: 'Warmup' },
557
+ { title: 'Run', goalType: 'distance', goalValue: 1000 },
558
+ { title: 'Cooldown' }
559
+ ]
560
+ })
561
+ })