Skip to content

@kaiord/core


@kaiord/core / extractWorkout

Function: extractWorkout()

extractWorkout(krd): object

Defined in: packages/core/src/domain/validation/extract-workout.ts:17

Extracts and validates the structured workout from a KRD object.

Checks that the KRD type is "structured_workout" and validates the workout in extensions.structured_workout against workoutSchema.

Parameters

krd

KRD object to extract workout from

events?

object[] = ...

extensions?

{[key: string]: unknown; course?: unknown; course_points?: unknown; fit?: unknown; health?: {[key: string]: unknown; bodyComposition?: { bmi?: number; bodyFatPercent?: number; bodyWaterPercent?: number; boneMassKilograms?: number; externalId?: string; kaiordRecordId?: string; kind: "bodyComposition"; leanMassKilograms?: number; measuredAt: string; sourceBridgeId?: string; version: string; }; daily?: { activeCalories: number; date: string; externalId?: string; floorsClimbed?: number; intensityMinutes: { moderate: number; vigorous: number; }; kaiordRecordId?: string; kind: "daily"; restingCalories: number; sourceBridgeId?: string; steps: number; version: string; }; hrv?: { externalId?: string; kaiordRecordId?: string; kind: "hrv"; measuredAt: string; measurementWindow: "overnight" | "spot"; rMSSD: number; score?: number; sourceBridgeId?: string; version: string; }; sleep?: { endTime: string; externalId?: string; kaiordRecordId?: string; kind: "sleep"; restingHeartRate?: number; score?: number; sourceBridgeId?: string; stages: object[]; startTime: string; totalDurationSeconds: number; version: string; }; stress?: { averageLevel: number; endTime: string; externalId?: string; kaiordRecordId?: string; kind: "stress"; peakLevel: number; sourceBridgeId?: string; startTime: string; version: string; }; weight?: { externalId?: string; kaiordRecordId?: string; kind: "weight"; measuredAt: string; sourceBridgeId?: string; version: string; weightKilograms: number; }; }; structured_workout?: unknown; } = ...

extensions.course?

unknown = ...

extensions.course_points?

unknown = ...

extensions.fit?

unknown = ...

extensions.health?

{[key: string]: unknown; bodyComposition?: { bmi?: number; bodyFatPercent?: number; bodyWaterPercent?: number; boneMassKilograms?: number; externalId?: string; kaiordRecordId?: string; kind: "bodyComposition"; leanMassKilograms?: number; measuredAt: string; sourceBridgeId?: string; version: string; }; daily?: { activeCalories: number; date: string; externalId?: string; floorsClimbed?: number; intensityMinutes: { moderate: number; vigorous: number; }; kaiordRecordId?: string; kind: "daily"; restingCalories: number; sourceBridgeId?: string; steps: number; version: string; }; hrv?: { externalId?: string; kaiordRecordId?: string; kind: "hrv"; measuredAt: string; measurementWindow: "overnight" | "spot"; rMSSD: number; score?: number; sourceBridgeId?: string; version: string; }; sleep?: { endTime: string; externalId?: string; kaiordRecordId?: string; kind: "sleep"; restingHeartRate?: number; score?: number; sourceBridgeId?: string; stages: object[]; startTime: string; totalDurationSeconds: number; version: string; }; stress?: { averageLevel: number; endTime: string; externalId?: string; kaiordRecordId?: string; kind: "stress"; peakLevel: number; sourceBridgeId?: string; startTime: string; version: string; }; weight?: { externalId?: string; kaiordRecordId?: string; kind: "weight"; measuredAt: string; sourceBridgeId?: string; version: string; weightKilograms: number; }; } = ...

extensions.health.bodyComposition?

{ bmi?: number; bodyFatPercent?: number; bodyWaterPercent?: number; boneMassKilograms?: number; externalId?: string; kaiordRecordId?: string; kind: "bodyComposition"; leanMassKilograms?: number; measuredAt: string; sourceBridgeId?: string; version: string; } = ...

extensions.health.bodyComposition.bmi?

number = ...

extensions.health.bodyComposition.bodyFatPercent?

number = ...

extensions.health.bodyComposition.bodyWaterPercent?

number = ...

extensions.health.bodyComposition.boneMassKilograms?

number = ...

extensions.health.bodyComposition.externalId?

string = ...

extensions.health.bodyComposition.kaiordRecordId?

string = ...

extensions.health.bodyComposition.kind

"bodyComposition" = ...

extensions.health.bodyComposition.leanMassKilograms?

number = ...

extensions.health.bodyComposition.measuredAt

string = ...

extensions.health.bodyComposition.sourceBridgeId?

string = ...

extensions.health.bodyComposition.version

string = healthVersionSchema

extensions.health.daily?

{ activeCalories: number; date: string; externalId?: string; floorsClimbed?: number; intensityMinutes: { moderate: number; vigorous: number; }; kaiordRecordId?: string; kind: "daily"; restingCalories: number; sourceBridgeId?: string; steps: number; version: string; } = ...

extensions.health.daily.activeCalories

number = ...

extensions.health.daily.date

string = ...

extensions.health.daily.externalId?

string = ...

extensions.health.daily.floorsClimbed?

number = ...

extensions.health.daily.intensityMinutes

{ moderate: number; vigorous: number; } = ...

extensions.health.daily.intensityMinutes.moderate

number = ...

extensions.health.daily.intensityMinutes.vigorous

number = ...

extensions.health.daily.kaiordRecordId?

string = ...

extensions.health.daily.kind

"daily" = ...

extensions.health.daily.restingCalories

number = ...

extensions.health.daily.sourceBridgeId?

string = ...

extensions.health.daily.steps

number = ...

extensions.health.daily.version

string = healthVersionSchema

extensions.health.hrv?

{ externalId?: string; kaiordRecordId?: string; kind: "hrv"; measuredAt: string; measurementWindow: "overnight" | "spot"; rMSSD: number; score?: number; sourceBridgeId?: string; version: string; } = ...

extensions.health.hrv.externalId?

string = ...

extensions.health.hrv.kaiordRecordId?

string = ...

extensions.health.hrv.kind

"hrv" = ...

extensions.health.hrv.measuredAt

string = ...

extensions.health.hrv.measurementWindow

"overnight" | "spot" = ...

extensions.health.hrv.rMSSD

number = ...

extensions.health.hrv.score?

number = ...

extensions.health.hrv.sourceBridgeId?

string = ...

extensions.health.hrv.version

string = healthVersionSchema

extensions.health.sleep?

{ endTime: string; externalId?: string; kaiordRecordId?: string; kind: "sleep"; restingHeartRate?: number; score?: number; sourceBridgeId?: string; stages: object[]; startTime: string; totalDurationSeconds: number; version: string; } = ...

extensions.health.sleep.endTime

string = ...

extensions.health.sleep.externalId?

string = ...

extensions.health.sleep.kaiordRecordId?

string = ...

extensions.health.sleep.kind

"sleep" = ...

extensions.health.sleep.restingHeartRate?

number = ...

extensions.health.sleep.score?

number = ...

extensions.health.sleep.sourceBridgeId?

string = ...

extensions.health.sleep.stages

object[] = ...

extensions.health.sleep.startTime

string = ...

extensions.health.sleep.totalDurationSeconds

number = ...

extensions.health.sleep.version

string = healthVersionSchema

extensions.health.stress?

{ averageLevel: number; endTime: string; externalId?: string; kaiordRecordId?: string; kind: "stress"; peakLevel: number; sourceBridgeId?: string; startTime: string; version: string; } = ...

extensions.health.stress.averageLevel

number = ...

extensions.health.stress.endTime

string = ...

extensions.health.stress.externalId?

string = ...

extensions.health.stress.kaiordRecordId?

string = ...

extensions.health.stress.kind

"stress" = ...

extensions.health.stress.peakLevel

number = ...

extensions.health.stress.sourceBridgeId?

string = ...

extensions.health.stress.startTime

string = ...

extensions.health.stress.version

string = healthVersionSchema

extensions.health.weight?

{ externalId?: string; kaiordRecordId?: string; kind: "weight"; measuredAt: string; sourceBridgeId?: string; version: string; weightKilograms: number; } = ...

extensions.health.weight.externalId?

string = ...

extensions.health.weight.kaiordRecordId?

string = ...

extensions.health.weight.kind

"weight" = ...

extensions.health.weight.measuredAt

string = ...

extensions.health.weight.sourceBridgeId?

string = ...

extensions.health.weight.version

string = healthVersionSchema

extensions.health.weight.weightKilograms

number = ...

extensions.structured_workout?

unknown = ...

laps?

object[] = ...

metadata

{ created: string; manufacturer?: string; product?: string; serialNumber?: string; sport?: string; subSport?: string; } = krdMetadataSchema

metadata.created

string = ...

metadata.manufacturer?

string = ...

metadata.product?

string = ...

metadata.serialNumber?

string = ...

metadata.sport?

string = ...

See

sportSchema for known sport values. Accepts custom strings for forward compatibility.

Optional at the metadata level because health-metric KRD types (sleep, weight, HRV, daily wellness, body composition, stress) have no associated sport. A conditional refinement on krdSchema still requires sport for the three legacy workout/activity/course types so v1.x consumers see no change for those.

metadata.subSport?

string = ...

records?

object[] = ...

sessions?

object[] = ...

type

"structured_workout" | "recorded_activity" | "course" | "sleep_record" | "weight_measurement" | "hrv_summary" | "daily_wellness" | "body_composition" | "stress_episode" = fileTypeSchema

version

string = ...

Returns

Validated Workout object

extensions?

optional extensions?: Record<string, unknown>

name?

optional name?: string

poolLength?

optional poolLength?: number

meters — always normalized to meters on ingest

poolLengthUnit?

optional poolLengthUnit?: "meters"

sport

sport: "generic" | "running" | "cycling" | "transition" | "fitness_equipment" | "swimming" | "basketball" | "soccer" | "tennis" | "american_football" | "training" | "walking" | "cross_country_skiing" | "alpine_skiing" | "snowboarding" | "rowing" | "mountaineering" | "hiking" | "multisport" | "paddling" | "flying" | "e_biking" | "motorcycling" | "boating" | "driving" | "golf" | "hang_gliding" | "horseback_riding" | "hunting" | "fishing" | "inline_skating" | "rock_climbing" | "sailing" | "ice_skating" | "sky_diving" | "snowshoeing" | "snowmobiling" | "stand_up_paddleboarding" | "surfing" | "wakeboarding" | "water_skiing" | "kayaking" | "rafting" | "windsurfing" | "kitesurfing" | "tactical" | "jumpmaster" | "boxing" | "floor_climbing" | "baseball" | "diving" | "shooting" | "winter_sport" | "grinding" | "hiit" | "video_gaming" | "racket" | "wheelchair_push_walk" | "wheelchair_push_run" | "meditation" | "para_sport" | "disc_golf" | "team_sport" | "cricket" | "rugby" | "hockey" | "lacrosse" | "volleyball" | "water_tubing" | "wakesurfing" | "water_sport" | "archery" | "mixed_martial_arts" | "motor_sports" | "snorkeling" | "dance" | "jump_rope" | "pool_apnea" | "mobility" | "geocaching" | "canoeing" = sportSchema

steps

steps: ({ duration: { seconds: number; type: "time"; } | { meters: number; type: "distance"; } | { bpm: number; type: "heart_rate_less_than"; } | { bpm: number; repeatFrom: number; type: "repeat_until_heart_rate_greater_than"; } | { calories: number; type: "calories"; } | { type: "power_less_than"; watts: number; } | { type: "power_greater_than"; watts: number; } | { repeatFrom: number; seconds: number; type: "repeat_until_time"; } | { meters: number; repeatFrom: number; type: "repeat_until_distance"; } | { calories: number; repeatFrom: number; type: "repeat_until_calories"; } | { bpm: number; repeatFrom: number; type: "repeat_until_heart_rate_less_than"; } | { repeatFrom: number; type: "repeat_until_power_less_than"; watts: number; } | { repeatFrom: number; type: "repeat_until_power_greater_than"; watts: number; } | { type: "open"; }; durationType: "time" | "distance" | "heart_rate_less_than" | "repeat_until_heart_rate_greater_than" | "calories" | "power_less_than" | "power_greater_than" | "repeat_until_time" | "repeat_until_distance" | "repeat_until_calories" | "repeat_until_heart_rate_less_than" | "repeat_until_power_less_than" | "repeat_until_power_greater_than" | "open"; equipment?: "none" | "swim_fins" | "swim_kickboard" | "swim_paddles" | "swim_pull_buoy" | "swim_snorkel"; extensions?: Record<string, unknown>; intensity?: "warmup" | "active" | "cooldown" | "rest" | "recovery" | "interval" | "other"; name?: string; notes?: string; stepIndex: number; target: { type: "power"; value: { max: number; min: number; unit: "range"; } | { unit: "watts"; value: number; } | { unit: "percent_ftp"; value: number; } | { unit: "zone"; value: number; }; } | { type: "heart_rate"; value: { max: number; min: number; unit: "range"; } | { unit: "bpm"; value: number; } | { unit: "zone"; value: number; } | { unit: "percent_max"; value: number; }; } | { type: "cadence"; value: { max: number; min: number; unit: "range"; } | { unit: "rpm"; value: number; }; } | { type: "pace"; value: { max: number; min: number; unit: "range"; } | { unit: "mps"; value: number; } | { unit: "zone"; value: number; }; } | { type: "stroke_type"; value: { unit: "swim_stroke"; value: number; }; } | { type: "open"; }; targetType: "cadence" | "power" | "open" | "heart_rate" | "pace" | "stroke_type"; } | { id?: string; repeatCount: number; steps: object[]; })[]

subSport?

optional subSport?: "match" | "map" | "generic" | "treadmill" | "street" | "trail" | "track" | "spin" | "indoor_cycling" | "road" | "mountain" | "downhill" | "recumbent" | "cyclocross" | "hand_cycling" | "track_cycling" | "indoor_rowing" | "elliptical" | "stair_climbing" | "lap_swimming" | "open_water" | "flexibility_training" | "strength_training" | "warm_up" | "exercise" | "challenge" | "indoor_skiing" | "cardio_training" | "indoor_walking" | "e_bike_fitness" | "bmx" | "casual_walking" | "speed_walking" | "bike_to_run_transition" | "run_to_bike_transition" | "swim_to_bike_transition" | "atv" | "motocross" | "backcountry" | "resort" | "rc_drone" | "wingsuit" | "whitewater" | "skate_skiing" | "yoga" | "pilates" | "indoor_running" | "gravel_cycling" | "e_bike_mountain" | "commuting" | "mixed_surface" | "navigate" | "track_me" | "single_gas_diving" | "multi_gas_diving" | "gauge_diving" | "apnea_diving" | "apnea_hunting" | "virtual_activity" | "obstacle" | "all"

Throws

If KRD is not a structured workout or workout is invalid