types.ts•11.9 kB
import { z } from 'zod';
// Base schemas
export const DateSchema = z.string().regex(/^\d{4}-\d{2}-\d{2}$/);
export const DateTimeSchema = z.string(); // Oura uses various datetime formats, be flexible
// Personal Info schemas
export const PersonalInfoSchema = z.object({
id: z.string(),
email: z.string().email(),
age: z.number().optional(),
weight: z.number().optional(),
height: z.number().optional(),
biological_sex: z.enum(['male', 'female']).optional(),
timezone: z.string().optional(),
});
export const PersonalInfoResponseSchema = z.union([
z.object({
data: PersonalInfoSchema,
}),
PersonalInfoSchema, // Sometimes the API returns the data directly without wrapper
]);
// Sleep schemas
export const SleepSchema = z.object({
id: z.string(),
contributors: z.object({
deep_sleep: z.number().optional(),
efficiency: z.number().optional(),
latency: z.number().optional(),
rem_sleep: z.number().optional(),
restfulness: z.number().optional(),
timing: z.number().optional(),
total_sleep: z.number().optional(),
}).optional(),
day: DateSchema,
score: z.number().optional(),
timestamp: DateTimeSchema.optional(),
}).passthrough(); // Allow additional fields from API
export const MultipleDocumentResponseSchema = <T extends z.ZodTypeAny>(schema: T) =>
z.object({
data: z.array(schema),
next_token: z.string().nullable().optional(),
});
export const SleepResponseSchema = MultipleDocumentResponseSchema(SleepSchema);
// Activity schemas
export const ActivitySchema = z.object({
id: z.string(),
class_5_min: z.string().optional(),
score: z.number().optional(),
active_calories: z.number().optional(),
average_met_minutes: z.number().optional(),
contributors: z.object({
meet_daily_targets: z.number().optional(),
move_every_hour: z.number().optional(),
recovery_time: z.number().optional(),
stay_active: z.number().optional(),
training_frequency: z.number().optional(),
training_volume: z.number().optional(),
}).optional(),
equivalent_walking_distance: z.number().optional(),
high_activity_met_minutes: z.number().optional(),
high_activity_time: z.number().optional(),
inactivity_alerts: z.number().optional(),
low_activity_met_minutes: z.number().optional(),
low_activity_time: z.number().optional(),
medium_activity_met_minutes: z.number().optional(),
medium_activity_time: z.number().optional(),
met: z.object({
interval: z.number().optional(),
items: z.array(z.number()).optional(),
timestamp: DateTimeSchema.optional(),
}).optional(),
meters_to_target: z.number().optional(),
non_wear_time: z.number().optional(),
resting_time: z.number().optional(),
sedentary_met_minutes: z.number().optional(),
sedentary_time: z.number().optional(),
steps: z.number().optional(),
target_calories: z.number().optional(),
target_meters: z.number().optional(),
total_calories: z.number().optional(),
day: DateSchema,
timestamp: DateTimeSchema.optional(),
}).passthrough(); // Allow additional fields from API
export const ActivityResponseSchema = MultipleDocumentResponseSchema(ActivitySchema);
// Readiness schemas
export const ReadinessSchema = z.object({
id: z.string(),
contributors: z.object({
activity_balance: z.number().optional(),
body_temperature: z.number().optional(),
hrv_balance: z.number().optional(),
previous_day_activity: z.number().optional(),
previous_night: z.number().optional(),
recovery_index: z.number().optional(),
resting_heart_rate: z.number().optional(),
sleep_balance: z.number().optional(),
}).optional(),
day: DateSchema,
score: z.number().optional(),
temperature_deviation: z.number().optional(),
temperature_trend_deviation: z.number().optional(),
timestamp: DateTimeSchema.optional(),
}).passthrough(); // Allow additional fields from API
export const ReadinessResponseSchema = MultipleDocumentResponseSchema(ReadinessSchema);
// Heart Rate schemas
export const HeartRateSchema = z.object({
bpm: z.number(),
source: z.enum(['awake', 'rest', 'sleep', 'session']),
timestamp: DateTimeSchema,
});
export const HeartRateResponseSchema = MultipleDocumentResponseSchema(HeartRateSchema);
// Workout schemas
export const WorkoutSchema = z.object({
id: z.string(),
activity: z.string(),
calories: z.number().optional(),
day: DateSchema,
distance: z.number().optional(),
end_datetime: DateTimeSchema,
intensity: z.enum(['easy', 'moderate', 'vigorous']),
label: z.string().optional(),
source: z.enum(['manual', 'autodetected', 'confirmed', 'workout_heart_rate']),
start_datetime: DateTimeSchema,
});
export const WorkoutResponseSchema = MultipleDocumentResponseSchema(WorkoutSchema);
// Session schemas
export const SessionSchema = z.object({
id: z.string(),
day: DateSchema,
start_datetime: DateTimeSchema,
end_datetime: DateTimeSchema,
type: z.enum(['breathing', 'meditation', 'nap', 'relaxation', 'rest', 'body_status']),
heart_rate: z.object({
interval: z.number(),
items: z.array(z.number()),
timestamp: DateTimeSchema,
}).optional(),
heart_rate_variability: z.object({
interval: z.number(),
items: z.array(z.number()),
timestamp: DateTimeSchema,
}).optional(),
mood: z.enum(['bad', 'worse', 'same', 'good', 'great']).optional(),
motion_count: z.object({
interval: z.number(),
items: z.array(z.number()),
timestamp: DateTimeSchema,
}).optional(),
});
export const SessionResponseSchema = MultipleDocumentResponseSchema(SessionSchema);
// Tag schemas
export const TagSchema = z.object({
id: z.string(),
day: DateSchema,
text: z.string(),
timestamp: DateTimeSchema,
tags: z.array(z.string()),
});
export const TagResponseSchema = MultipleDocumentResponseSchema(TagSchema);
// Daily schemas
export const DailyActivitySchema = z.object({
id: z.string(),
class_5_min: z.string().optional(),
score: z.number().optional(),
active_calories: z.number().optional(),
average_met_minutes: z.number().optional(),
contributors: z.object({
meet_daily_targets: z.number().optional(),
move_every_hour: z.number().optional(),
recovery_time: z.number().optional(),
stay_active: z.number().optional(),
training_frequency: z.number().optional(),
training_volume: z.number().optional(),
}).optional(),
equivalent_walking_distance: z.number().optional(),
high_activity_met_minutes: z.number().optional(),
high_activity_time: z.number().optional(),
inactivity_alerts: z.number().optional(),
low_activity_met_minutes: z.number().optional(),
low_activity_time: z.number().optional(),
medium_activity_met_minutes: z.number().optional(),
medium_activity_time: z.number().optional(),
meters_to_target: z.number().optional(),
non_wear_time: z.number().optional(),
resting_time: z.number().optional(),
sedentary_met_minutes: z.number().optional(),
sedentary_time: z.number().optional(),
steps: z.number().optional(),
target_calories: z.number().optional(),
target_meters: z.number().optional(),
total_calories: z.number().optional(),
day: DateSchema,
timestamp: DateTimeSchema.optional(),
}).passthrough(); // Allow additional fields from API
export const DailyActivityResponseSchema = MultipleDocumentResponseSchema(DailyActivitySchema);
// Daily Sleep schema
export const DailySleepSchema = z.object({
id: z.string(),
contributors: z.object({
deep_sleep: z.number().optional(),
efficiency: z.number().optional(),
latency: z.number().optional(),
rem_sleep: z.number().optional(),
restfulness: z.number().optional(),
timing: z.number().optional(),
total_sleep: z.number().optional(),
}).optional(),
day: DateSchema,
score: z.number().optional(),
timestamp: DateTimeSchema.optional(),
}).passthrough(); // Allow additional fields from API
export const DailySleepResponseSchema = MultipleDocumentResponseSchema(DailySleepSchema);
// Daily Readiness schema
export const DailyReadinessSchema = z.object({
id: z.string(),
contributors: z.object({
activity_balance: z.number().optional(),
body_temperature: z.number().optional(),
hrv_balance: z.number().optional(),
previous_day_activity: z.number().optional(),
previous_night: z.number().optional(),
recovery_index: z.number().optional(),
resting_heart_rate: z.number().optional(),
sleep_balance: z.number().optional(),
}).optional(),
day: DateSchema,
score: z.number().optional(),
temperature_deviation: z.number().optional(),
temperature_trend_deviation: z.number().optional(),
timestamp: DateTimeSchema.optional(),
}).passthrough(); // Allow additional fields from API
export const DailyReadinessResponseSchema = MultipleDocumentResponseSchema(DailyReadinessSchema);
// Daily Stress schema
export const DailyStressSchema = z.object({
id: z.string(),
day: DateSchema,
stress_high: z.number().optional(),
recovery_high: z.number().optional(),
day_summary: z.enum(['restore', 'normal', 'stressful']).optional(),
});
export const DailyStressResponseSchema = MultipleDocumentResponseSchema(DailyStressSchema);
// Webhook subscription schemas
export const WebhookSubscriptionSchema = z.object({
id: z.string(),
callback_url: z.string().url(),
event_type: z.enum(['create', 'update', 'delete']),
data_type: z.enum([
'tag',
'enhanced_tag',
'workout',
'session',
'sleep',
'daily_sleep',
'daily_readiness',
'daily_activity',
'daily_stress',
]),
verification_token: z.string(),
created_at: DateTimeSchema,
updated_at: DateTimeSchema,
});
export const WebhookSubscriptionResponseSchema = MultipleDocumentResponseSchema(WebhookSubscriptionSchema);
// Type exports
export type PersonalInfo = z.infer<typeof PersonalInfoSchema>;
export type PersonalInfoResponse = z.infer<typeof PersonalInfoResponseSchema>;
export type Sleep = z.infer<typeof SleepSchema>;
export type SleepResponse = z.infer<typeof SleepResponseSchema>;
export type Activity = z.infer<typeof ActivitySchema>;
export type ActivityResponse = z.infer<typeof ActivityResponseSchema>;
export type Readiness = z.infer<typeof ReadinessSchema>;
export type ReadinessResponse = z.infer<typeof ReadinessResponseSchema>;
export type HeartRate = z.infer<typeof HeartRateSchema>;
export type HeartRateResponse = z.infer<typeof HeartRateResponseSchema>;
export type Workout = z.infer<typeof WorkoutSchema>;
export type WorkoutResponse = z.infer<typeof WorkoutResponseSchema>;
export type Session = z.infer<typeof SessionSchema>;
export type SessionResponse = z.infer<typeof SessionResponseSchema>;
export type Tag = z.infer<typeof TagSchema>;
export type TagResponse = z.infer<typeof TagResponseSchema>;
export type DailyActivity = z.infer<typeof DailyActivitySchema>;
export type DailyActivityResponse = z.infer<typeof DailyActivityResponseSchema>;
export type DailySleep = z.infer<typeof DailySleepSchema>;
export type DailySleepResponse = z.infer<typeof DailySleepResponseSchema>;
export type DailyReadiness = z.infer<typeof DailyReadinessSchema>;
export type DailyReadinessResponse = z.infer<typeof DailyReadinessResponseSchema>;
export type DailyStress = z.infer<typeof DailyStressSchema>;
export type DailyStressResponse = z.infer<typeof DailyStressResponseSchema>;
export type WebhookSubscription = z.infer<typeof WebhookSubscriptionSchema>;
export type WebhookSubscriptionResponse = z.infer<typeof WebhookSubscriptionResponseSchema>;
// API Request parameters
export interface DateRangeParams {
start_date?: string;
end_date?: string;
next_token?: string;
}
export interface WebhookSubscriptionCreateParams {
callback_url: string;
verification_token: string;
event_type: 'create' | 'update' | 'delete';
data_type: 'tag' | 'enhanced_tag' | 'workout' | 'session' | 'sleep' | 'daily_sleep' | 'daily_readiness' | 'daily_activity' | 'daily_stress';
}