lubba-encoder 1.1.16 → 1.1.18

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.
@@ -125,7 +125,9 @@ const valueGoalTypeMap = {
125
125
  tidalVolume: 68,
126
126
  minuteVentilation: 69,
127
127
  minuteVentilationAverage60s: 70,
128
- inhaleExhaleRatio: 71
128
+ inhaleExhaleRatio: 71,
129
+ workoutNotes: 72,
130
+ ve: 73 // used for target type
129
131
  };
130
132
 
131
133
  const partTitleMapReverse = reverseObject(partTitleMap);
@@ -286,6 +288,10 @@ function encodeJsonObjectToLubbaData (object, encodingVersion) {
286
288
  encodePart(part, encoder);
287
289
  }
288
290
 
291
+ // Optional v1 trailer: old decoders stop after parts and safely ignore it.
292
+ // Omit absent notes so existing workout hashes remain byte-for-byte stable.
293
+ if (object.notes != null) encoding__namespace.writeVarString(encoder, object.notes);
294
+
289
295
  return encoding__namespace.toUint8Array(encoder)
290
296
  }
291
297
 
@@ -310,6 +316,10 @@ function decodeLubbaData (data) {
310
316
  decoded.parts.push(decodePart(decoder));
311
317
  }
312
318
 
319
+ if (decoding__namespace.hasContent(decoder)) {
320
+ decoded.notes = decoding__namespace.readVarString(decoder);
321
+ }
322
+
313
323
  return decoded
314
324
  }
315
325
 
@@ -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 breathingRate: 67,\n tidalVolume: 68,\n minuteVentilation: 69,\n minuteVentilationAverage60s: 70,\n inhaleExhaleRatio: 71\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 ve: 73 // used for target type\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.16",
3
+ "version": "1.1.18",
4
4
  "main": "./dist/lubba-encoder.cjs",
5
5
  "license": "MIT",
6
6
  "exports": {
package/src/index.js CHANGED
@@ -99,7 +99,9 @@ const valueGoalTypeMap = {
99
99
  tidalVolume: 68,
100
100
  minuteVentilation: 69,
101
101
  minuteVentilationAverage60s: 70,
102
- inhaleExhaleRatio: 71
102
+ inhaleExhaleRatio: 71,
103
+ workoutNotes: 72,
104
+ ve: 73 // used for target type
103
105
  }
104
106
 
105
107
  const partTitleMapReverse = reverseObject(partTitleMap)
@@ -260,6 +262,10 @@ export function encodeJsonObjectToLubbaData (object, encodingVersion) {
260
262
  encodePart(part, encoder)
261
263
  }
262
264
 
265
+ // Optional v1 trailer: old decoders stop after parts and safely ignore it.
266
+ // Omit absent notes so existing workout hashes remain byte-for-byte stable.
267
+ if (object.notes != null) encoding.writeVarString(encoder, object.notes)
268
+
263
269
  return encoding.toUint8Array(encoder)
264
270
  }
265
271
 
@@ -284,6 +290,10 @@ export function decodeLubbaData (data) {
284
290
  decoded.parts.push(decodePart(decoder))
285
291
  }
286
292
 
293
+ if (decoding.hasContent(decoder)) {
294
+ decoded.notes = decoding.readVarString(decoder)
295
+ }
296
+
287
297
  return decoded
288
298
  }
289
299
 
package/src/index.test.js CHANGED
@@ -367,6 +367,33 @@ test('supports Tymewear breathing layout values', () => {
367
367
  })
368
368
  })
369
369
 
370
+ test('supports VE workout targets', () => {
371
+ const encodingVersion = 1
372
+ const workout = {
373
+ isCustom: true,
374
+ isMetric: true,
375
+ title: 'VE target workout',
376
+ activityType: 37,
377
+ locationType: 1,
378
+ parts: [
379
+ {
380
+ title: 'Run',
381
+ goalType: 'duration',
382
+ goalValue: 600,
383
+ targetType: 've',
384
+ targetMin: 40,
385
+ targetMax: 48,
386
+ layout: '1+1',
387
+ layoutValues: ['minuteVentilation', 'minuteVentilationAverage60s']
388
+ }
389
+ ]
390
+ }
391
+
392
+ const encoded = encodeJsonObjectToLubbaData(workout, encodingVersion)
393
+
394
+ expect(decodeLubbaData(encoded)).toEqual(workout)
395
+ })
396
+
370
397
  test('supports power percentage of CP layout values', () => {
371
398
  const encodingVersion = 1
372
399
  const encoded = encodeJsonObjectToLubbaData({
@@ -476,3 +503,86 @@ test('supports power to heart rate ratio layout values', () => {
476
503
  ]
477
504
  })
478
505
  })
506
+
507
+ test('preserves workout notes layout values in single, grid, and nested layouts', () => {
508
+ const workout = {
509
+ isCustom: true,
510
+ isMetric: true,
511
+ title: 'Race plan',
512
+ activityType: 37,
513
+ locationType: 3,
514
+ parts: [
515
+ { layout: '1', layoutValues: ['workoutNotes'] },
516
+ {
517
+ layout: '2+2',
518
+ layoutValues: ['workoutNotes', 'duration', 'distance', 'bpm']
519
+ },
520
+ {
521
+ repeats: 2,
522
+ repeatParts: [{ layout: '1', layoutValues: ['workoutNotes'] }]
523
+ }
524
+ ]
525
+ }
526
+ const encoded = encodeJsonObjectToLubbaData(workout, 1)
527
+ const hash = encodeLubbaDataToHash(encoded)
528
+
529
+ expect(decodeLubbaData(decodeLubbaDataFromHash(hash))).toEqual(workout)
530
+ })
531
+
532
+ test('uses the next unused layout value ID without changing existing IDs', () => {
533
+ const encoded = encodeJsonObjectToLubbaData({
534
+ isMetric: true,
535
+ title: '',
536
+ activityType: 37,
537
+ locationType: 3,
538
+ parts: [{ layoutValues: ['inhaleExhaleRatio', 'workoutNotes', 'duration'] }]
539
+ }, 1)
540
+
541
+ expect(Array.from(encoded.slice(-3))).toEqual([71, 72, 1])
542
+ })
543
+
544
+ test.each([
545
+ '',
546
+ 'Fuel every 30 minutes.\n\nRelax shoulders.\nFinish strong.\n',
547
+ 'Ät en gel. 飲水 🏃\nKeep going!',
548
+ 'Long race plan: fuel, drink, relax.\n'.repeat(3000)
549
+ ])('preserves notes through JSON and URL hash encoding (%#)', (notes) => {
550
+ const workout = { ...jsonObject, notes }
551
+ const encoded = encodeJsonObjectToLubbaData(workout, 1)
552
+ const hash = encodeLubbaDataToHash(encoded, true)
553
+ const decoded = decodeLubbaData(decodeLubbaDataFromHash(decodeURIComponent(hash)))
554
+
555
+ expect(decoded).toEqual({ ...result, notes })
556
+ const legacyBytes = encodeJsonObjectToLubbaData(jsonObject, 1)
557
+ expect(encoded.slice(0, legacyBytes.length)).toEqual(legacyBytes)
558
+ })
559
+
560
+ test('preserves YAML multiline notes', () => {
561
+ const encoded = encodeYamlToLubbaData(yaml + `notes: |
562
+ Take a gel every 30 minutes.
563
+
564
+ Relax shoulders.
565
+ `, 1)
566
+ expect(decodeLubbaData(encoded)).toEqual({
567
+ ...result,
568
+ notes: 'Take a gel every 30 minutes.\n\nRelax shoulders.\n'
569
+ })
570
+ })
571
+
572
+ test('omits null notes and keeps legacy hashes unchanged', () => {
573
+ const legacyBytes = encodeJsonObjectToLubbaData(jsonObject, 1)
574
+ const withoutNotes = encodeJsonObjectToLubbaData({ ...jsonObject, notes: null }, 1)
575
+
576
+ expect(withoutNotes).toEqual(legacyBytes)
577
+ expect(decodeLubbaData(withoutNotes)).toEqual(result)
578
+ expect(decodeLubbaData(decodeLubbaDataFromHash(
579
+ 'AQERTXkgY3VzdG9tIHdvcmtvdXQlAAAAAwMBAAEZAAgCQI9AAAAAAAABAAY='
580
+ ))).toMatchObject({
581
+ title: 'My custom workout',
582
+ parts: [
583
+ { title: 'Warmup' },
584
+ { title: 'Run', goalType: 'distance', goalValue: 1000 },
585
+ { title: 'Cooldown' }
586
+ ]
587
+ })
588
+ })