@sunsteel/contracts 0.62.0 → 0.64.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/dist/index.d.cts CHANGED
@@ -24,1285 +24,1538 @@ interface PaginatedResponse<T> {
24
24
  nextCursor?: string;
25
25
  }
26
26
 
27
- interface SetLog {
28
- id: string;
29
- sessionId: string;
30
- routineExerciseId: string;
31
- exerciseId: string;
32
- setNumber: number;
33
- reps: number;
34
- weight?: number | null;
35
- rpe?: number | null;
36
- isCompleted: boolean;
37
- completedAt?: IsoDateString | null;
38
- createdAt: IsoDateString;
39
- updatedAt: IsoDateString;
27
+ /**
28
+ * Per-routine visibility. The account-level `PROF-06` routines rule is the
29
+ * upper bound: a routine marked `PUBLIC` inside an account whose routines are
30
+ * `FOLLOWERS` is visible to followers only, the same way `SOC-04` bounds
31
+ * activity by the profile section it comes from.
32
+ */
33
+ declare const ROUTINE_VISIBILITY_VALUES: readonly ["PRIVATE", "FOLLOWERS", "PUBLIC"];
34
+ type RoutineVisibility = (typeof ROUTINE_VISIBILITY_VALUES)[number];
35
+ /** One routine keeps at most this many active links. */
36
+ declare const ROUTINE_SHARE_MAX_ACTIVE_LINKS = 10;
37
+ /** PUT /routines/:id/visibility */
38
+ interface UpdateRoutineVisibilityRequest {
39
+ visibility: RoutineVisibility;
40
40
  }
41
- interface WorkoutSession {
41
+ /** An active share link, visible only to the routine's owner. */
42
+ interface RoutineShare {
42
43
  id: string;
43
- userId: string;
44
44
  routineId: string;
45
- routineDayId: string;
46
- status: WorkoutSessionStatus;
47
- startedAt: IsoDateString;
48
- endedAt?: IsoDateString | null;
49
- durationSec?: number | null;
50
- notes?: string | null;
51
- lastActivityAt?: IsoDateString | null;
52
- setLogs?: SetLog[];
53
- /**
54
- * LIVE-11: slots performed with a different exercise in this session. The
55
- * routine day (snapshot) keeps the original prescription; set logs for a
56
- * substituted slot carry the substitute's `exerciseId`.
57
- */
58
- exerciseSubstitutions?: SessionExerciseSubstitution[];
59
- reused?: boolean;
60
- routine?: {
61
- id: string;
62
- name: string;
63
- description?: string | null;
64
- };
65
- routineDay?: {
66
- id: string;
67
- name?: string | null;
68
- order?: number;
69
- /** Null on a ROTATION routine day (ROUT-11). */
70
- dayOfWeek?: number | null;
71
- exercises: Array<{
72
- id: string;
73
- order: number;
74
- restSeconds?: number | null;
75
- note?: string | null;
76
- progressionScheme: ProgressionScheme;
77
- minWeightIncrement: number;
78
- exercise: {
79
- id: string;
80
- name: string;
81
- primaryMuscles: MuscleGroup[];
82
- secondaryMuscles?: MuscleGroup[];
83
- };
84
- sets: Array<{
85
- id: string;
86
- setNumber: number;
87
- repType: RepType;
88
- reps?: number | null;
89
- minReps?: number | null;
90
- maxReps?: number | null;
91
- weight?: number | null;
92
- rir?: number | null;
93
- }>;
94
- }>;
95
- };
96
- }
97
- /** Completed set from the latest earlier execution of the same routine day. */
98
- interface PreviousSetPerformance {
99
- routineExerciseId: string;
100
- exerciseId: string;
101
- setNumber: number;
102
- reps: number;
103
- weight?: number | null;
104
- rpe?: number | null;
45
+ /** Unguessable identifier used in the public `/shared/routines/:token` URL. */
46
+ token: string;
47
+ createdAt: IsoDateString;
105
48
  }
106
- /** Stable successful response of GET /workouts/sessions/:id/previous-performance. */
107
- interface PreviousPerformanceResponse {
108
- sessionId: string;
109
- endedAt: IsoDateString;
110
- sets: PreviousSetPerformance[];
49
+ /** Stable successful response of GET /routines/:id/shares. */
50
+ interface RoutineShareListResponse {
51
+ items: RoutineShare[];
111
52
  }
112
- interface StartWorkoutRequest {
113
- routineId: string;
114
- routineDayId: string;
115
- notes?: string;
53
+ interface SharedRoutineOwner {
54
+ username: string;
55
+ name: string;
56
+ lastName?: string | null;
57
+ avatarUrl?: string | null;
116
58
  }
117
- interface StartWorkoutResponse {
118
- id: string;
59
+ /**
60
+ * How a reader reached a routine. A link is the owner's explicit consent for
61
+ * that one routine and ignores visibility; a visibility read is governed by
62
+ * both the routine's own rule and the account's.
63
+ */
64
+ declare const SHARED_ROUTINE_SOURCES: readonly ["LINK", "VISIBILITY"];
65
+ type SharedRoutineSource = (typeof SHARED_ROUTINE_SOURCES)[number];
66
+ /**
67
+ * Stable successful response of the unauthenticated
68
+ * GET /shared/routines/:token, and of the authenticated member read.
69
+ */
70
+ interface SharedRoutine {
71
+ /** Kept so a future clone (`ROUT-05`) can record what it came from. */
119
72
  routineId: string;
120
- routineDayId: string;
121
- status: WorkoutSessionStatus;
122
- startedAt: IsoDateString;
123
- endedAt?: IsoDateString | null;
124
- reused: boolean;
125
- }
126
- type FinishStatus = Extract<WorkoutSessionStatus, 'COMPLETED' | 'ABORTED'>;
127
- interface FinishWorkoutRequest {
128
- status: FinishStatus;
129
- notes?: string;
130
- }
131
- type ProgressionRule = 'ALL_SETS_REACHED_TARGET' | 'SET_REACHED_TARGET';
132
- interface ProgressionSetChange {
133
- setNumber: number;
134
- targetReps: number;
135
- performedReps: number;
136
- previousWeightKg: number;
137
- newWeightKg: number;
73
+ setup: RoutineVersionSetup;
74
+ owner: SharedRoutineOwner;
75
+ source: SharedRoutineSource;
76
+ /** When the routine was last changed, not when it was shared. */
77
+ updatedAt: IsoDateString;
138
78
  }
139
- /** An automatic prescription update produced while completing a session. */
140
- interface ProgressionChange {
141
- routineExerciseId: string;
142
- exerciseId: string;
143
- exerciseName: string;
144
- progressionScheme: Extract<ProgressionScheme, 'DOUBLE_PROGRESSION' | 'DYNAMIC_DOUBLE_PROGRESSION'>;
145
- rule: ProgressionRule;
146
- minWeightIncrementKg: number;
147
- sets: ProgressionSetChange[];
79
+ /**
80
+ * ROUT-06. Where a cloned routine came from. It is recorded on the clone and
81
+ * never on the source, so a routine cannot learn who copied it. It is served
82
+ * only to a viewer who could read the source anyway: lineage must not become
83
+ * a way to discover that a private routine exists.
84
+ */
85
+ interface RoutineLineage {
86
+ /** The routine this one was cloned from, when the viewer may read it. */
87
+ sourceRoutineId: string | null;
88
+ /** The original author's public identity, when they still have one. */
89
+ author: SharedRoutineOwner | null;
90
+ /**
91
+ * True when the source exists but this viewer may not read it, or its author
92
+ * is gone. The clone still says it was cloned; it just cannot say from what.
93
+ */
94
+ isSourceHidden: boolean;
95
+ clonedAt: IsoDateString;
148
96
  }
149
- /** Stable successful response of PATCH /workouts/sessions/:id/finish. */
150
- interface FinishWorkoutResponse {
151
- session: WorkoutSession;
152
- progressionChanges: ProgressionChange[];
153
- recap: WorkoutSessionRecap | null;
97
+ /** A routine in a member's visible list, without loading its whole setup. */
98
+ interface SharedRoutineSummary {
99
+ routineId: string;
100
+ name: string;
101
+ description: string | null;
102
+ scheduleMode: RoutineScheduleMode;
103
+ dayCount: number;
104
+ exerciseCount: number;
105
+ updatedAt: IsoDateString;
154
106
  }
155
- interface UpsertSetLogRequest {
156
- routineExerciseId: string;
157
- exerciseId: string;
158
- setNumber: number;
159
- reps: number;
160
- weight?: number;
161
- rpe?: number;
162
- isCompleted?: boolean;
107
+ /** Stable successful response of GET /users/:identifier/routines. */
108
+ interface MemberRoutinesResponse {
109
+ routines: SharedRoutineSummary[];
163
110
  }
164
111
  /**
165
- * LIVE-11: an exercise performed in place of one routine slot for a single
166
- * session. The substitute's muscles are captured when the swap is made, so
167
- * later catalog changes cannot rewrite what the session trained.
112
+ * POST /routines/clones. Exactly one source, matching the two ways a routine
113
+ * can be read: `token` for a private link, `routineId` for one the viewer may
114
+ * already see. Sending both, or neither, is refused.
168
115
  */
169
- interface SessionExerciseSubstitution {
170
- /** The replaced slot, as in `routineDay.exercises[].id`. */
171
- routineExerciseId: string;
172
- exercise: {
173
- id: string;
174
- name: string;
175
- primaryMuscles: MuscleGroup[];
176
- secondaryMuscles: MuscleGroup[];
177
- };
178
- substitutedAt: IsoDateString;
179
- }
180
- /** Body of PUT /workouts/sessions/:id/exercises/:routineExerciseId/substitution. */
181
- interface SubstituteSessionExerciseRequest {
182
- exerciseId: string;
183
- /** Also use this exercise in the routine from the next session on. */
184
- applyToRoutine?: boolean;
116
+ interface CloneRoutineRequest {
117
+ /** The `/shared/routines/:token` link the reader followed. */
118
+ token?: string;
119
+ /** A routine the viewer may read under `ROUT-04` visibility. */
120
+ routineId?: string;
185
121
  }
122
+ /** The refusals a clone states by name rather than as a bare 4xx. */
123
+ declare const CLONE_ROUTINE_REFUSALS: {
124
+ /** Neither `token` nor `routineId`, or both at once. */
125
+ readonly SOURCE_REQUIRED: "SOURCE_REQUIRED";
126
+ /** An exercise the routine programs is no longer in the catalog. */
127
+ readonly UNKNOWN_EXERCISE: "UNKNOWN_EXERCISE";
128
+ };
129
+ type CloneRoutineRefusal = (typeof CLONE_ROUTINE_REFUSALS)[keyof typeof CLONE_ROUTINE_REFUSALS];
130
+
186
131
  /**
187
- * Stable successful response of the substitution PUT and DELETE. A swap is
188
- * refused once the slot has a completed set; incomplete drafts for the slot
189
- * are cleared because their values belonged to the other exercise.
132
+ * ROUT-11: a WEEKLY routine ties each day to a weekday; a ROTATION routine
133
+ * runs its days in `order`, each after the last completed one, whatever the
134
+ * weekday.
190
135
  */
191
- interface SubstituteSessionExerciseResponse {
192
- session: WorkoutSession;
193
- /** True only when `applyToRoutine` was asked for and the routine still has the slot. */
194
- routineUpdated: boolean;
195
- }
196
- type PersonalRecordKind = 'WEIGHT' | 'REPS' | 'VOLUME' | 'ESTIMATED_1RM';
197
- /** A record frontier crossed by the set mutation that produced this response. */
198
- interface EarnedPersonalRecord {
199
- kind: PersonalRecordKind;
200
- exerciseId: string;
201
- exerciseName: string;
202
- /** Canonical kg for every kind except REPS, where this is a repetition count. */
203
- value: number;
204
- /** Missing when this is the first completed result for that record kind. */
205
- previousBest?: number | null;
206
- }
207
- /** Stable successful response of PUT /workouts/sessions/:id/set-logs. */
208
- interface UpsertSetLogResponse {
209
- setLog: SetLog;
210
- earnedRecords: EarnedPersonalRecord[];
211
- }
212
- /** Final record frontier earned by one completed session. */
213
- interface SessionRecapRecord extends EarnedPersonalRecord {
136
+ declare const ROUTINE_SCHEDULE_MODES: readonly ["WEEKLY", "ROTATION"];
137
+ type RoutineScheduleMode = (typeof ROUTINE_SCHEDULE_MODES)[number];
138
+ /** At most seven days in either mode. */
139
+ declare const ROUTINE_DAYS_MAX = 7;
140
+ declare const ROUTINE_DAY_NAME_MAX = 40;
141
+ /**
142
+ * How a routine day is named everywhere, including history snapshots taken
143
+ * before ROUT-11: its own name, else its weekday, else its rotation letter
144
+ * ("Day A" for order 0).
145
+ */
146
+ declare function routineDayLabel(day: {
147
+ name?: string | null;
148
+ dayOfWeek?: number | null;
149
+ order?: number | null;
150
+ }): string;
151
+ interface RoutineSet {
214
152
  setNumber: number;
215
- achievedAt: IsoDateString;
153
+ repType: RepType;
154
+ reps?: number | null;
155
+ minReps?: number | null;
156
+ maxReps?: number | null;
157
+ weight?: number | null;
158
+ rir?: number | null;
216
159
  }
217
- /** Metrics from the latest earlier execution of the same routine day. */
218
- interface PreviousSessionRecap {
219
- sessionId: string;
220
- endedAt: IsoDateString;
221
- durationSec: number;
222
- totalVolumeKg: number;
223
- completedSets: number;
224
- durationDeltaSec: number;
225
- volumeDeltaKg: number;
226
- completedSetsDelta: number;
160
+ interface RoutineExercise {
161
+ id: string;
162
+ order: number;
163
+ restSeconds: number;
164
+ note?: string | null;
165
+ progressionScheme: ProgressionScheme;
166
+ minWeightIncrement: number;
167
+ exercise: {
168
+ id: string;
169
+ name: string;
170
+ primaryMuscles?: MuscleGroup[];
171
+ secondaryMuscles?: MuscleGroup[];
172
+ };
173
+ sets: RoutineSet[];
227
174
  }
228
- /** Stable successful response of GET /workouts/sessions/:id/recap. */
229
- interface WorkoutSessionRecap {
230
- sessionId: string;
231
- routineName: string;
232
- dayName?: string | null;
233
- startedAt: IsoDateString;
234
- endedAt: IsoDateString;
235
- durationSec: number;
236
- totalVolumeKg: number;
237
- completedSets: number;
238
- notes?: string | null;
239
- records: SessionRecapRecord[];
240
- progressionChanges: ProgressionChange[];
241
- previousSession: PreviousSessionRecap | null;
175
+ interface CreateRoutineExerciseInput {
176
+ exerciseId: string;
177
+ order?: number;
178
+ restSeconds: number;
179
+ note?: string;
180
+ progressionScheme: ProgressionScheme;
181
+ minWeightIncrement: number;
182
+ sets: RoutineSet[];
242
183
  }
243
- /** Parts of a completed session's recap the owner may choose to share. */
244
- declare const SESSION_SHARE_FIELDS: readonly ["duration", "volume", "completedSets", "records", "progression", "notes"];
245
- type SessionShareField = (typeof SESSION_SHARE_FIELDS)[number];
246
- /** Pre-selected when creating a link; notes and prescriptions are opt-in. */
247
- declare const SESSION_SHARE_DEFAULT_FIELDS: SessionShareField[];
248
- declare const SESSION_SHARE_MAX_ACTIVE_LINKS = 10;
249
- interface CreateSessionShareRequest {
250
- fields: SessionShareField[];
184
+ interface RoutineDay {
185
+ id: string;
186
+ /** 0=Sun..6=Sat on a WEEKLY routine; null on a ROTATION routine. */
187
+ dayOfWeek: number | null;
188
+ /** Optional label such as "Push" or "Upper A" (see `routineDayLabel`). */
189
+ name: string | null;
190
+ /** Rotation sequence, 0-based; also the display order. */
191
+ order: number;
192
+ exercises: RoutineExercise[];
251
193
  }
252
- /** An active share link, visible only to the session owner. */
253
- interface SessionShare {
194
+ interface CreateRoutineDayInput {
195
+ /** Required and unique on a WEEKLY routine; omitted or null on a ROTATION. */
196
+ dayOfWeek?: number | null;
197
+ name?: string | null;
198
+ order?: number;
199
+ exercises: CreateRoutineExerciseInput[];
200
+ }
201
+ interface Routine {
254
202
  id: string;
255
- sessionId: string;
256
- /** Unguessable identifier used in the public `/shared/sessions/:token` URL. */
257
- token: string;
258
- fields: SessionShareField[];
259
- createdAt: IsoDateString;
203
+ userId: string;
204
+ name: string;
205
+ description?: string | null;
206
+ isPeriodized: boolean;
207
+ isFavorite: boolean;
208
+ isCompleted: boolean;
209
+ scheduleMode: RoutineScheduleMode;
260
210
  /**
261
- * TRUST-04: a moderator has hidden the shared workout, so the link stops
262
- * resolving for everyone but its owner. The link is not revoked and the
263
- * session is untouched; the owner is told because a live-looking link that
264
- * opens for nobody is worse than one that says why.
211
+ * ROTATION only: the day after the one of the last completed session (an
212
+ * aborted session does not advance it), or the first day before any.
213
+ */
214
+ nextRotationDayId: string | null;
215
+ /**
216
+ * SCHED-07: weekdays (0=Sun..6=Sat) this weekly routine rests on by plan,
217
+ * never one of its training weekdays; always empty on a ROTATION routine.
218
+ */
219
+ restDays: number[];
220
+ /**
221
+ * SCHED-06: weekdays (0=Sun..6=Sat) a ROTATION routine trains on, sorted; the
222
+ * schedule places its days on them in order. Empty means any day, without
223
+ * dates; always empty on a WEEKLY routine.
224
+ */
225
+ rotationWeekdays: number[];
226
+ /**
227
+ * ROUT-04: who may read this routine, bounded by the account-level
228
+ * `PROF-06` routines rule. Owner-only field; it never appears in a shared
229
+ * read, where visibility is the reason the reader is there.
230
+ */
231
+ visibility: RoutineVisibility;
232
+ /**
233
+ * ROUT-06: present only on a routine that was cloned, and only with what
234
+ * this viewer is allowed to know about its source.
235
+ */
236
+ lineage?: RoutineLineage | null;
237
+ /**
238
+ * ROUT-07: owner-declared, both optional. They are claims about the
239
+ * programme that only its author can make, which is why they are stored
240
+ * here rather than derived from the author's `PROF-05` training identity.
241
+ */
242
+ goal?: TrainingGoal | null;
243
+ experienceLevel?: TrainingExperienceLevel | null;
244
+ /**
245
+ * TRUST-04: a moderator has hidden this routine from everyone but its
246
+ * owner. Owner-only field, and true on the owner's own read alone: a
247
+ * routine nobody else can open while its own visibility still reads
248
+ * "Public" would be a control with nothing behind it.
265
249
  */
266
250
  isHiddenByModeration?: boolean;
251
+ /** The baseline days. A block's days are in `trainingBlocks`, never here. */
252
+ days: RoutineDay[];
253
+ /**
254
+ * ROUT-15: every current block revision as a plan, past, active and future,
255
+ * ordered by start date. Owner-only; absent from any shared read. Resolve
256
+ * what a date trains with `resolveRoutinePlan`, never by reading this and
257
+ * `days` separately.
258
+ */
259
+ trainingBlocks?: RoutineTrainingBlockPlan[];
260
+ createdAt: IsoDateString;
261
+ updatedAt: IsoDateString;
267
262
  }
268
- /** Stable successful response of GET /workouts/sessions/:id/shares. */
269
- interface SessionShareListResponse {
270
- items: SessionShare[];
271
- }
272
- interface SharedSessionOwner {
273
- username: string;
263
+ interface CreateRoutineRequest {
274
264
  name: string;
275
- lastName?: string | null;
276
- avatarUrl?: string | null;
265
+ description?: string;
266
+ /** ROUT-07; omitted means undeclared, which is not the same as a default. */
267
+ goal?: TrainingGoal | null;
268
+ experienceLevel?: TrainingExperienceLevel | null;
269
+ isPeriodized: boolean;
270
+ /** Defaults to WEEKLY. Changing it on update requires `days`. */
271
+ scheduleMode?: RoutineScheduleMode;
272
+ /**
273
+ * Weekly routines only. Omitted on update keeps the stored rest days, minus
274
+ * any that became training weekdays.
275
+ */
276
+ restDays?: number[];
277
+ /**
278
+ * Rotation routines only. Omitted on update keeps the stored weekdays;
279
+ * switching to WEEKLY clears them.
280
+ */
281
+ rotationWeekdays?: number[];
282
+ days: CreateRoutineDayInput[];
277
283
  }
284
+ type UpdateRoutineRequest = Partial<CreateRoutineRequest>;
285
+ /** A routine keeps at most this many versions; saving past it is refused. */
286
+ declare const ROUTINE_VERSIONS_MAX = 20;
287
+ declare const ROUTINE_VERSION_NAME_MAX = 60;
278
288
  /**
279
- * Stable successful response of the unauthenticated
280
- * GET /shared/sessions/:token. Only the fields named in `fields` are present;
281
- * everything else is omitted rather than nulled. Weights are canonical kg and
282
- * `weightUnit` is the owner's display preference.
289
+ * SAVED is an intentional save; BEFORE_RESTORE is the setup a restore
290
+ * replaced, saved automatically so the restore can be undone.
283
291
  */
284
- interface SharedSessionRecap {
285
- fields: SessionShareField[];
286
- owner: SharedSessionOwner;
287
- weightUnit: WeightUnit;
288
- routineName: string;
289
- dayName?: string | null;
290
- endedAt: IsoDateString;
291
- durationSec?: number;
292
- totalVolumeKg?: number;
293
- completedSets?: number;
294
- records?: SessionRecapRecord[];
295
- progressionChanges?: ProgressionChange[];
296
- notes?: string | null;
297
- }
298
- interface WorkoutSessionSummary {
299
- id: string;
300
- status: WorkoutSessionStatus;
301
- startedAt: IsoDateString;
302
- endedAt?: IsoDateString | null;
303
- durationSec?: number | null;
304
- totalVolume?: number | null;
305
- totalSets?: number | null;
306
- totalExercises?: number | null;
307
- notes?: string | null;
308
- routine: {
292
+ declare const ROUTINE_VERSION_KINDS: readonly ["SAVED", "BEFORE_RESTORE"];
293
+ type RoutineVersionKind = (typeof ROUTINE_VERSION_KINDS)[number];
294
+ interface RoutineVersionExercise {
295
+ /** The catalog exercise and its name when the version was saved. */
296
+ exercise: {
309
297
  id: string;
310
298
  name: string;
311
- dayName?: string | null;
312
299
  };
300
+ order: number;
301
+ restSeconds: number;
302
+ note: string | null;
303
+ progressionScheme: ProgressionScheme;
304
+ minWeightIncrement: number;
305
+ sets: RoutineSet[];
313
306
  }
314
- interface ListSessionsParams {
315
- status?: WorkoutSessionStatus;
316
- routineId?: string;
317
- from?: IsoDateString;
318
- to?: IsoDateString;
319
- q?: string;
320
- cursor?: string;
321
- limit?: number;
322
- sort?: 'finishedAt:desc' | 'finishedAt:asc' | 'startedAt:desc' | 'startedAt:asc';
307
+ interface RoutineVersionDay {
308
+ dayOfWeek: number | null;
309
+ name: string | null;
310
+ order: number;
311
+ exercises: RoutineVersionExercise[];
323
312
  }
324
- type WorkoutSessionListResponse = PaginatedResponse<WorkoutSessionSummary>;
325
- interface WorkoutStatsQuery {
326
- weekStart: IsoDateString;
327
- weekEnd: IsoDateString;
328
- timeZone: string;
313
+ /** Everything a routine edit can change, as it was when the version was saved. */
314
+ interface RoutineVersionSetup {
315
+ name: string;
316
+ description: string | null;
317
+ scheduleMode: RoutineScheduleMode;
318
+ restDays: number[];
319
+ /** SCHED-06; absent in versions saved before it, which means none. */
320
+ rotationWeekdays?: number[];
321
+ days: RoutineVersionDay[];
329
322
  }
330
- interface WorkoutStatsResponse {
331
- totalCompleted: number;
332
- completionRate: number;
333
- weeklyWorkoutsCount: number;
334
- activeDaysThisWeek: number;
323
+ interface RoutineVersion {
324
+ id: string;
325
+ routineId: string;
326
+ /** 1, 2, 3… per routine, never reused after a deletion. */
327
+ number: number;
328
+ name: string | null;
329
+ kind: RoutineVersionKind;
330
+ /** BEFORE_RESTORE only: the number of the version that was restored. */
331
+ restoredVersionNumber: number | null;
332
+ createdAt: IsoDateString;
333
+ setup: RoutineVersionSetup;
334
+ }
335
+ /** `GET /routines/:id/versions`, newest first. */
336
+ interface RoutineVersionsResponse {
337
+ versions: RoutineVersion[];
338
+ max: number;
339
+ }
340
+ /** `POST /routines/:id/versions` */
341
+ interface CreateRoutineVersionRequest {
342
+ name?: string | null;
343
+ }
344
+ /** `POST /routines/:id/versions/:versionId/restore` */
345
+ interface RestoreRoutineVersionResponse {
346
+ routine: Routine;
347
+ /** The replaced setup, saved as a BEFORE_RESTORE version. */
348
+ savedVersion: RoutineVersion;
335
349
  }
336
350
 
337
- declare const TRAINING_EVENT_TYPES: readonly ["SESSION_COMPLETED", "PERSONAL_RECORD", "PROGRESSION_CHANGED", "STREAK_MILESTONE", "ACHIEVEMENT_UNLOCKED"];
338
- type TrainingEventType = (typeof TRAINING_EVENT_TYPES)[number];
339
- /** Stable successful response of GET /workouts/progress. */
340
- interface WorkoutProgressQuery {
341
- timeZone: string;
351
+ /** A local calendar date, YYYY-MM-DD. */
352
+ type CalendarDate = string;
353
+ /**
354
+ * The schedule-instance model: per-date overrides of a routine's plan. MOVE
355
+ * puts one weekly occurrence on another date (SCHED-04); SKIP marks it
356
+ * skipped on purpose (SCHED-05). Overrides are kept by calendar date, not by
357
+ * routine day, because routine edits replace the days.
358
+ */
359
+ declare const SCHEDULE_OVERRIDE_KINDS: readonly ["MOVE", "SKIP"];
360
+ type ScheduleOverrideKind = (typeof SCHEDULE_OVERRIDE_KINDS)[number];
361
+ /** A move goes at most this many days before or after the planned date. */
362
+ declare const SCHEDULE_MOVE_MAX_DAYS = 6;
363
+ /**
364
+ * SCHED-05: a skip can explain a planned day up to this many days back;
365
+ * ahead, any planned day can be skipped.
366
+ */
367
+ declare const SCHEDULE_SKIP_PAST_DAYS = 6;
368
+ /** Overrides are read for at most this many days at once. */
369
+ declare const SCHEDULE_OVERRIDES_MAX_RANGE_DAYS = 62;
370
+ interface ScheduleOverride {
371
+ id: string;
372
+ routineId: string;
373
+ /** The planned date this override changes. */
374
+ date: CalendarDate;
375
+ kind: ScheduleOverrideKind;
376
+ /** MOVE: the date the occurrence now falls on; null for SKIP. */
377
+ toDate: CalendarDate | null;
378
+ createdAt: IsoDateString;
342
379
  }
343
- interface PersonalRecordEntry {
344
- exerciseId: string;
345
- exerciseName: string;
346
- weight: number;
347
- reps: number;
348
- estimated1rm: number;
349
- achievedAt: string;
380
+ /**
381
+ * `GET /schedule/overrides?from&to`: the owner's overrides whose date or
382
+ * target falls in the range, both ends included.
383
+ */
384
+ interface ScheduleOverridesQuery {
385
+ from: CalendarDate;
386
+ to: CalendarDate;
350
387
  }
351
- interface RecentActivityEntry {
352
- sessionId: string;
388
+ interface ScheduleOverridesResponse {
389
+ overrides: ScheduleOverride[];
390
+ }
391
+ /** `PUT /schedule/overrides/move`: moves one occurrence, or moves it again. */
392
+ interface MoveOccurrenceRequest {
353
393
  routineId: string;
354
- routineName: string;
355
- dayName: string;
356
- startedAt: string;
357
- endedAt: string | null;
358
- durationSec: number | null;
359
- totalVolumeKg: number;
360
- completedSets: number;
394
+ date: CalendarDate;
395
+ toDate: CalendarDate;
361
396
  }
362
- interface WorkoutProgressResponse {
363
- totalVolumeKg: number;
364
- currentStreakDays: number;
365
- bestStreakDays: number;
366
- personalRecords: PersonalRecordEntry[];
367
- recentActivity: RecentActivityEntry[];
397
+ /**
398
+ * `PUT /schedule/overrides/skip`: marks one occurrence skipped. A moved
399
+ * occurrence is skipped as a whole; undoing is `DELETE` like a move.
400
+ */
401
+ interface SkipOccurrenceRequest {
402
+ routineId: string;
403
+ date: CalendarDate;
368
404
  }
369
- interface ExerciseStrengthTrendQuery {
370
- exerciseId?: string;
371
- from?: string;
372
- to?: string;
405
+
406
+ /** One routine may have this many current, non-overlapping planned blocks. */
407
+ declare const ROUTINE_TRAINING_BLOCKS_MAX = 24;
408
+ /** A started block keeps at most this many immutable revisions. */
409
+ declare const ROUTINE_TRAINING_BLOCK_REVISIONS_MAX = 20;
410
+ declare const ROUTINE_TRAINING_BLOCK_NAME_MAX = 60;
411
+ declare const ROUTINE_TRAINING_BLOCK_STATES: readonly ["FUTURE", "ACTIVE", "COMPLETE"];
412
+ type RoutineTrainingBlockState = (typeof ROUTINE_TRAINING_BLOCK_STATES)[number];
413
+ declare const ROUTINE_TRAINING_BLOCK_SOURCE_KINDS: readonly ["CURRENT_ROUTINE", "SAVED_VERSION"];
414
+ type RoutineTrainingBlockSourceKind = (typeof ROUTINE_TRAINING_BLOCK_SOURCE_KINDS)[number];
415
+ /**
416
+ * The origin is snapshotted so a later routine edit or ROUT-08 version
417
+ * deletion cannot change what this block says it was authored from.
418
+ */
419
+ interface RoutineTrainingBlockSource {
420
+ kind: RoutineTrainingBlockSourceKind;
421
+ versionId: string | null;
422
+ versionNumber: number | null;
423
+ versionName: string | null;
373
424
  }
374
- interface ExerciseStrengthSummary {
375
- exerciseId: string;
376
- exerciseName: string;
377
- weightKg: number;
378
- reps: number;
379
- estimated1rmKg: number;
380
- achievedAt: string;
425
+ /** One immutable revision of a named, dated setup. */
426
+ interface RoutineTrainingBlockRevision {
427
+ id: string;
428
+ routineId: string;
429
+ /** Stable across every replacement of the same logical block. */
430
+ seriesId: string;
431
+ /** 1, 2, 3… inside the series. */
432
+ revision: number;
433
+ name: string;
434
+ startDate: CalendarDate;
435
+ endDate: CalendarDate;
436
+ setup: RoutineVersionSetup;
437
+ source: RoutineTrainingBlockSource;
438
+ createdAt: IsoDateString;
439
+ /** Null only on the current revision. */
440
+ supersededAt: IsoDateString | null;
381
441
  }
382
- interface ExerciseStrengthTrendPoint {
383
- sessionId: string;
384
- achievedAt: string;
385
- weightKg: number;
386
- reps: number;
387
- estimated1rmKg: number;
442
+ /** A current block in the routine timeline. State is relative to `today`. */
443
+ interface RoutineTrainingBlock extends Omit<RoutineTrainingBlockRevision, 'supersededAt'> {
444
+ state: RoutineTrainingBlockState;
445
+ revisionCount: number;
388
446
  }
389
- /** Stable successful response of GET /workouts/progress/strength. */
390
- interface ExerciseStrengthTrendResponse {
391
- exercises: ExerciseStrengthSummary[];
392
- selectedExercise: ExerciseStrengthSummary | null;
393
- range: {
394
- from: string | null;
395
- to: string;
396
- };
397
- baseline: ExerciseStrengthTrendPoint | null;
398
- points: ExerciseStrengthTrendPoint[];
399
- truncated: boolean;
447
+ /** `GET /routines/:id/training-blocks`, ordered by start date. */
448
+ interface RoutineTrainingBlocksResponse {
449
+ blocks: RoutineTrainingBlock[];
450
+ max: number;
451
+ revisionMax: number;
452
+ /** The owner's local date used to derive every state in this response. */
453
+ today: CalendarDate;
400
454
  }
401
- interface ExercisePerformanceHistoryQuery {
402
- exerciseId?: string;
403
- from?: string;
404
- to?: string;
405
- cursor?: string;
406
- limit?: number;
455
+ /** `GET /routines/:id/training-blocks/:blockId/revisions`, newest first. */
456
+ interface RoutineTrainingBlockRevisionsResponse {
457
+ seriesId: string;
458
+ revisions: RoutineTrainingBlockRevision[];
459
+ max: number;
407
460
  }
408
- interface ExercisePerformanceSummary {
409
- exerciseId: string;
410
- exerciseName: string;
411
- lastPerformedAt: string;
412
- hasStrengthTrend: boolean;
461
+ /**
462
+ * `POST /routines/:id/training-blocks` and
463
+ * `PUT /routines/:id/training-blocks/:blockId`.
464
+ * Null or omission captures the routine as it exists at request time.
465
+ */
466
+ interface UpsertRoutineTrainingBlockRequest {
467
+ name: string;
468
+ startDate: CalendarDate;
469
+ endDate: CalendarDate;
470
+ sourceVersionId?: string | null;
413
471
  }
414
- interface ExercisePerformanceSet {
472
+ /**
473
+ * A current block as a plan the schedule, the dashboard and a session start
474
+ * use. Its days are the block's own working copy, with ids, kept apart from
475
+ * the routine's baseline `days`: a session of a block day logs against them
476
+ * and progression advances them, never the baseline, which resumes unchanged
477
+ * once the block ends. A new revision starts again from its authored setup.
478
+ */
479
+ interface RoutineTrainingBlockPlan {
480
+ /** The current revision's id. */
481
+ id: string;
482
+ seriesId: string;
483
+ revision: number;
484
+ name: string;
485
+ startDate: CalendarDate;
486
+ endDate: CalendarDate;
487
+ scheduleMode: RoutineScheduleMode;
488
+ restDays: number[];
489
+ rotationWeekdays: number[];
490
+ /**
491
+ * ROTATION only: the day after the last completed session of this block
492
+ * (any revision), or its first day before any. Never a baseline day.
493
+ */
494
+ nextRotationDayId: string | null;
495
+ days: RoutineDay[];
496
+ }
497
+ /** ROUT-15: the block a session trained, copied onto the session itself. */
498
+ interface SessionTrainingBlock {
499
+ /** The revision trained. */
500
+ id: string;
501
+ seriesId: string;
502
+ revision: number;
503
+ name: string;
504
+ }
505
+ type DatedBlock = {
506
+ startDate: CalendarDate;
507
+ endDate: CalendarDate;
508
+ };
509
+ /** Both ends are inclusive; dates compare as `YYYY-MM-DD` strings. */
510
+ declare function trainingBlockCovers(block: DatedBlock, date: CalendarDate): boolean;
511
+ /**
512
+ * The one active block for a date, or null. Blocks of one routine never
513
+ * overlap (ROUT-09), so the first cover is the only one.
514
+ */
515
+ declare function resolveActiveTrainingBlock<T extends DatedBlock>(blocks: readonly T[] | null | undefined, date: CalendarDate): T | null;
516
+ /** What a routine plans for one date: its active block, else its baseline. */
517
+ interface ResolvedRoutinePlan<D> {
518
+ block: SessionTrainingBlock & DatedBlock | null;
519
+ scheduleMode: RoutineScheduleMode;
520
+ restDays: number[];
521
+ rotationWeekdays: number[];
522
+ nextRotationDayId: string | null;
523
+ days: D[];
524
+ }
525
+ interface RoutinePlanSource<D> {
526
+ scheduleMode: RoutineScheduleMode;
527
+ restDays: number[];
528
+ rotationWeekdays?: number[] | null;
529
+ nextRotationDayId?: string | null;
530
+ days: D[];
531
+ trainingBlocks?: ReadonlyArray<DatedBlock & SessionTrainingBlock & {
532
+ scheduleMode: RoutineScheduleMode;
533
+ restDays: number[];
534
+ rotationWeekdays: number[];
535
+ nextRotationDayId: string | null;
536
+ days: D[];
537
+ }> | null;
538
+ }
539
+ /**
540
+ * ROUT-15's single resolver. Every reader that decides what a routine trains
541
+ * on a date - the schedule, the dashboard, a session start, reminders and the
542
+ * partner schedule, on the frontend and the backend alike - asks this, so
543
+ * weekly and rotation routines, and the baseline and a block, never disagree.
544
+ */
545
+ declare function resolveRoutinePlan<D>(routine: RoutinePlanSource<D>, date: CalendarDate): ResolvedRoutinePlan<D>;
546
+
547
+ interface SetLog {
548
+ id: string;
549
+ sessionId: string;
415
550
  routineExerciseId: string;
551
+ exerciseId: string;
416
552
  setNumber: number;
417
553
  reps: number;
418
- weightKg?: number | null;
554
+ weight?: number | null;
419
555
  rpe?: number | null;
556
+ isCompleted: boolean;
557
+ completedAt?: IsoDateString | null;
558
+ createdAt: IsoDateString;
559
+ updatedAt: IsoDateString;
420
560
  }
421
- interface ExercisePerformancePrescriptionSet {
422
- setNumber: number;
423
- repType: RepType;
424
- reps?: number | null;
425
- minReps?: number | null;
426
- maxReps?: number | null;
427
- weightKg?: number | null;
428
- rir?: number | null;
561
+ interface WorkoutSession {
562
+ id: string;
563
+ userId: string;
564
+ routineId: string;
565
+ routineDayId: string;
566
+ status: WorkoutSessionStatus;
567
+ startedAt: IsoDateString;
568
+ endedAt?: IsoDateString | null;
569
+ durationSec?: number | null;
570
+ notes?: string | null;
571
+ lastActivityAt?: IsoDateString | null;
572
+ setLogs?: SetLog[];
573
+ /**
574
+ * LIVE-11: slots performed with a different exercise in this session. The
575
+ * routine day (snapshot) keeps the original prescription; set logs for a
576
+ * substituted slot carry the substitute's `exerciseId`.
577
+ */
578
+ exerciseSubstitutions?: SessionExerciseSubstitution[];
579
+ /**
580
+ * LIVE-16: what the owner noted about one exercise in this workout. The
581
+ * routine's own note (`routineDay.exercises[].note`) is the standing
582
+ * instruction and is never written from a session.
583
+ */
584
+ exerciseNotes?: SessionExerciseNote[];
585
+ reused?: boolean;
586
+ /**
587
+ * ROUT-15: the training block this session trained, or null when it
588
+ * trained the routine's baseline. Copied at start, so a later revision or
589
+ * the block's end never rewrites what the session was.
590
+ */
591
+ trainingBlock?: SessionTrainingBlock | null;
592
+ routine?: {
593
+ id: string;
594
+ name: string;
595
+ description?: string | null;
596
+ };
597
+ routineDay?: {
598
+ id: string;
599
+ name?: string | null;
600
+ order?: number;
601
+ /** Null on a ROTATION routine day (ROUT-11). */
602
+ dayOfWeek?: number | null;
603
+ exercises: Array<{
604
+ id: string;
605
+ order: number;
606
+ restSeconds?: number | null;
607
+ note?: string | null;
608
+ progressionScheme: ProgressionScheme;
609
+ minWeightIncrement: number;
610
+ exercise: {
611
+ id: string;
612
+ name: string;
613
+ primaryMuscles: MuscleGroup[];
614
+ secondaryMuscles?: MuscleGroup[];
615
+ };
616
+ sets: Array<{
617
+ id: string;
618
+ setNumber: number;
619
+ repType: RepType;
620
+ reps?: number | null;
621
+ minReps?: number | null;
622
+ maxReps?: number | null;
623
+ weight?: number | null;
624
+ rir?: number | null;
625
+ }>;
626
+ }>;
627
+ };
429
628
  }
430
- interface ExercisePerformancePrescription {
629
+ /** Completed set from the latest earlier execution of the same routine day. */
630
+ interface PreviousSetPerformance {
431
631
  routineExerciseId: string;
432
- restSeconds?: number | null;
433
- note?: string | null;
434
- progressionScheme: ProgressionScheme;
435
- minWeightIncrementKg: number;
436
- sets: ExercisePerformancePrescriptionSet[];
632
+ exerciseId: string;
633
+ setNumber: number;
634
+ reps: number;
635
+ weight?: number | null;
636
+ rpe?: number | null;
437
637
  }
438
- interface ExercisePerformanceSession {
638
+ /** Stable successful response of GET /workouts/sessions/:id/previous-performance. */
639
+ interface PreviousPerformanceResponse {
439
640
  sessionId: string;
440
- status: Extract<WorkoutSessionStatus, 'COMPLETED' | 'ABORTED'>;
441
- routineName: string;
442
- dayName?: string | null;
443
- startedAt: string;
444
- endedAt: string;
445
- durationSec?: number | null;
446
- sessionNotes?: string | null;
447
- sets: ExercisePerformanceSet[];
448
- prescriptions: ExercisePerformancePrescription[];
449
- progressionChanges: ProgressionChange[];
450
- }
451
- /** Stable successful response of GET /workouts/progress/performance. */
452
- interface ExercisePerformanceHistoryResponse {
453
- exercises: ExercisePerformanceSummary[];
454
- selectedExercise: ExercisePerformanceSummary | null;
455
- items: ExercisePerformanceSession[];
456
- nextCursor?: string;
457
- }
458
- interface MuscleGroupHeatmapQuery {
459
- timeZone: string;
460
- /** Number of Monday-based calendar weeks to return, including this week. */
461
- weeks?: number;
462
- }
463
- interface MuscleGroupHeatmapValue {
464
- muscle: MuscleGroup;
465
- /** Completed-set equivalents: primary muscles count 1, secondary count 0.5. */
466
- weightedSets: number;
467
- }
468
- interface MuscleGroupHeatmapWeek {
469
- weekStart: string;
470
- isCurrentWeek: boolean;
471
- totalWeightedSets: number;
472
- muscles: MuscleGroupHeatmapValue[];
473
- }
474
- /** Stable successful response of GET /workouts/progress/muscles. */
475
- interface MuscleGroupHeatmapResponse {
476
- timeZone: string;
477
- weeks: MuscleGroupHeatmapWeek[];
478
- peakWeightedSets: number;
479
- }
480
- interface VolumeTrendQuery {
481
- timeZone: string;
482
- /** Number of Monday-based calendar weeks to return, including this week. */
483
- weeks?: number;
641
+ endedAt: IsoDateString;
642
+ sets: PreviousSetPerformance[];
484
643
  }
485
- interface VolumeTrendPoint {
486
- weekStart: string;
487
- isCurrentWeek: boolean;
488
- /** External-load volume in canonical kilograms: weight × repetitions. */
489
- volumeKg: number;
490
- completedSets: number;
644
+ interface StartWorkoutRequest {
645
+ routineId: string;
646
+ routineDayId: string;
647
+ notes?: string;
491
648
  }
492
- interface VolumeTrendSeries {
649
+ interface StartWorkoutResponse {
493
650
  id: string;
494
- name: string;
495
- totalVolumeKg: number;
496
- totalCompletedSets: number;
497
- points: VolumeTrendPoint[];
651
+ routineId: string;
652
+ routineDayId: string;
653
+ status: WorkoutSessionStatus;
654
+ startedAt: IsoDateString;
655
+ endedAt?: IsoDateString | null;
656
+ reused: boolean;
498
657
  }
499
- interface MuscleVolumeTrendSeries extends VolumeTrendSeries {
500
- id: MuscleGroup;
658
+ type FinishStatus = Extract<WorkoutSessionStatus, 'COMPLETED' | 'ABORTED'>;
659
+ interface FinishWorkoutRequest {
660
+ status: FinishStatus;
661
+ notes?: string;
501
662
  }
502
- /** Stable successful response of GET /workouts/progress/volume. */
503
- interface VolumeTrendResponse {
504
- timeZone: string;
505
- weeks: number;
506
- overall: VolumeTrendPoint[];
507
- muscles: MuscleVolumeTrendSeries[];
508
- routines: VolumeTrendSeries[];
509
- exercises: VolumeTrendSeries[];
663
+ type ProgressionRule = 'ALL_SETS_REACHED_TARGET' | 'SET_REACHED_TARGET';
664
+ interface ProgressionSetChange {
665
+ setNumber: number;
666
+ targetReps: number;
667
+ performedReps: number;
668
+ previousWeightKg: number;
669
+ newWeightKg: number;
510
670
  }
511
- interface SessionComparisonQuery {
512
- routineDayId?: string;
671
+ /** An automatic prescription update produced while completing a session. */
672
+ interface ProgressionChange {
673
+ routineExerciseId: string;
674
+ exerciseId: string;
675
+ exerciseName: string;
676
+ progressionScheme: Extract<ProgressionScheme, 'DOUBLE_PROGRESSION' | 'DYNAMIC_DOUBLE_PROGRESSION'>;
677
+ rule: ProgressionRule;
678
+ minWeightIncrementKg: number;
679
+ sets: ProgressionSetChange[];
513
680
  }
514
- interface SessionComparisonRoutineDay {
515
- routineDayId: string;
516
- routineId: string;
517
- routineName: string;
518
- dayName?: string | null;
519
- lastCompletedAt: IsoDateString;
520
- completedSessionCount: number;
681
+ /** Stable successful response of PATCH /workouts/sessions/:id/finish. */
682
+ interface FinishWorkoutResponse {
683
+ session: WorkoutSession;
684
+ progressionChanges: ProgressionChange[];
685
+ recap: WorkoutSessionRecap | null;
521
686
  }
522
- interface SessionComparisonSet {
687
+ interface UpsertSetLogRequest {
523
688
  routineExerciseId: string;
689
+ exerciseId: string;
524
690
  setNumber: number;
525
691
  reps: number;
526
- weightKg?: number | null;
527
- rpe?: number | null;
692
+ weight?: number;
693
+ rpe?: number;
694
+ isCompleted?: boolean;
528
695
  }
529
- interface SessionComparisonExercise {
696
+ /**
697
+ * LIVE-11: an exercise performed in place of one routine slot for a single
698
+ * session. The substitute's muscles are captured when the swap is made, so
699
+ * later catalog changes cannot rewrite what the session trained.
700
+ */
701
+ interface SessionExerciseSubstitution {
702
+ /** The replaced slot, as in `routineDay.exercises[].id`. */
530
703
  routineExerciseId: string;
531
- exerciseId: string;
532
- exerciseName: string;
533
- order: number;
534
- sets: SessionComparisonSet[];
704
+ exercise: {
705
+ id: string;
706
+ name: string;
707
+ primaryMuscles: MuscleGroup[];
708
+ secondaryMuscles: MuscleGroup[];
709
+ };
710
+ substitutedAt: IsoDateString;
535
711
  }
536
- interface SessionComparisonSession {
537
- sessionId: string;
538
- routineDayId: string;
539
- routineName: string;
540
- dayName?: string | null;
541
- startedAt: IsoDateString;
542
- endedAt: IsoDateString;
543
- durationSec: number;
544
- totalVolumeKg: number;
545
- completedSets: number;
712
+ declare const SESSION_NOTE_MAX_LENGTH = 2000;
713
+ declare const SESSION_EXERCISE_NOTE_MAX_LENGTH = 500;
714
+ /** One exercise's note for one workout, keyed by its routine slot. */
715
+ interface SessionExerciseNote {
716
+ /** The slot, as in `routineDay.exercises[].id`. */
717
+ routineExerciseId: string;
718
+ note: string;
719
+ }
720
+ /**
721
+ * Body of PUT /workouts/sessions/:id/notes. Partial: an omitted field keeps
722
+ * what is stored, `null` or an empty string clears it. Exercise notes merge
723
+ * by slot, so two notes saved moments apart cannot overwrite each other.
724
+ */
725
+ interface UpdateSessionNotesRequest {
546
726
  notes?: string | null;
547
- exercises: SessionComparisonExercise[];
727
+ exerciseNotes?: Array<{
728
+ routineExerciseId: string;
729
+ note: string | null;
730
+ }>;
548
731
  }
549
- /** Stable successful response of GET /workouts/progress/session-comparison. */
550
- interface SessionComparisonResponse {
551
- routineDays: SessionComparisonRoutineDay[];
552
- selectedRoutineDay: SessionComparisonRoutineDay | null;
553
- latestSession: SessionComparisonSession | null;
554
- previousSession: SessionComparisonSession | null;
732
+ interface UpdateSessionNotesResponse {
733
+ notes: string | null;
734
+ exerciseNotes: SessionExerciseNote[];
555
735
  }
556
- declare const PROGRESS_TIMELINE_EVENT_TYPES: readonly ["PERSONAL_RECORD", "PROGRESSION_CHANGED"];
557
- type ProgressTimelineEventType = (typeof PROGRESS_TIMELINE_EVENT_TYPES)[number];
558
- interface ProgressTimelineQuery {
559
- type?: ProgressTimelineEventType;
560
- /** Only events for one catalog exercise (EXER-01). */
561
- exerciseId?: string;
562
- cursor?: string;
563
- limit?: number;
564
- }
565
- interface ProgressTimelineSessionContext {
566
- sessionId: string;
567
- routineName: string;
568
- dayName?: string | null;
736
+ /** Body of PUT /workouts/sessions/:id/exercises/:routineExerciseId/substitution. */
737
+ interface SubstituteSessionExerciseRequest {
738
+ exerciseId: string;
739
+ /** Also use this exercise in the routine from the next session on. */
740
+ applyToRoutine?: boolean;
569
741
  }
570
- interface ProgressTimelineRecordPerformance {
571
- weightKg: number;
572
- reps: number;
573
- estimated1rmKg: number;
742
+ /**
743
+ * Stable successful response of the substitution PUT and DELETE. A swap is
744
+ * refused once the slot has a completed set; incomplete drafts for the slot
745
+ * are cleared because their values belonged to the other exercise.
746
+ */
747
+ interface SubstituteSessionExerciseResponse {
748
+ session: WorkoutSession;
749
+ /** True only when `applyToRoutine` was asked for and the routine still has the slot. */
750
+ routineUpdated: boolean;
574
751
  }
575
- type ProgressTimelineRecordReason = 'FIRST_RECORDED_BEST' | 'HEAVIER_LOAD' | 'MORE_REPS_AT_SAME_LOAD';
576
- interface ProgressTimelinePersonalRecordItem {
577
- eventId: string;
578
- type: 'PERSONAL_RECORD';
579
- occurredAt: IsoDateString;
580
- session: ProgressTimelineSessionContext;
752
+ type PersonalRecordKind = 'WEIGHT' | 'REPS' | 'VOLUME' | 'ESTIMATED_1RM';
753
+ /** A record frontier crossed by the set mutation that produced this response. */
754
+ interface EarnedPersonalRecord {
755
+ kind: PersonalRecordKind;
581
756
  exerciseId: string;
582
757
  exerciseName: string;
583
- current: ProgressTimelineRecordPerformance;
584
- previous: ProgressTimelineRecordPerformance | null;
585
- reason: ProgressTimelineRecordReason;
758
+ /** Canonical kg for every kind except REPS, where this is a repetition count. */
759
+ value: number;
760
+ /** Missing when this is the first completed result for that record kind. */
761
+ previousBest?: number | null;
586
762
  }
587
- interface ProgressTimelineProgressionItem {
588
- eventId: string;
589
- type: 'PROGRESSION_CHANGED';
590
- occurredAt: IsoDateString;
591
- session: ProgressTimelineSessionContext;
592
- exerciseId: string;
593
- exerciseName: string;
594
- change: ProgressionChange;
763
+ /** Stable successful response of PUT /workouts/sessions/:id/set-logs. */
764
+ interface UpsertSetLogResponse {
765
+ setLog: SetLog;
766
+ earnedRecords: EarnedPersonalRecord[];
595
767
  }
596
- type ProgressTimelineItem = ProgressTimelinePersonalRecordItem | ProgressTimelineProgressionItem;
597
- /** Stable successful response of GET /workouts/progress/timeline. */
598
- interface ProgressTimelineResponse {
599
- items: ProgressTimelineItem[];
600
- nextCursor?: string;
768
+ /** Final record frontier earned by one completed session. */
769
+ interface SessionRecapRecord extends EarnedPersonalRecord {
770
+ setNumber: number;
771
+ achievedAt: IsoDateString;
601
772
  }
602
- /** Immutable prescription captured before any sets or progression. */
603
- interface WorkoutSessionSnapshotV1 {
604
- schemaVersion: 1;
773
+ /** Metrics from the latest earlier execution of the same routine day. */
774
+ interface PreviousSessionRecap {
605
775
  sessionId: string;
606
- sourceRoutineId: string;
607
- sourceRoutineDayId: string;
608
- capturedAt: string;
609
- provenance: 'CAPTURED' | 'APPROXIMATED';
610
- notes: string | null;
611
- routine: NonNullable<WorkoutSession['routine']>;
612
- routineDay: NonNullable<WorkoutSession['routineDay']>;
613
- }
614
- interface SetAccountTimeZoneRequest {
615
- timeZone: string;
616
- /** Bootstrap must not replace a zone registered by another device. */
617
- onlyIfUnset?: boolean;
618
- }
619
- interface WorkoutAnalyticsStatus {
620
- timeZone: string | null;
621
- requestedTimeZone: string | null;
622
- state: 'UNINITIALIZED' | 'BUILDING' | 'READY' | 'FAILED';
623
- generationId: string | null;
624
- }
625
- /**
626
- * Thresholds behind every plateau. A lift is flagged only when all hold: at
627
- * least the account's minimum sessions (`PLATEAU_MIN_SESSIONS` by default)
628
- * of terminal sessions with completed loaded sets of it since its current
629
- * best (the session that set the best excluded, and counting only inside the
630
- * look-back window), the best is at least
631
- * `PLATEAU_MIN_DAYS_SINCE_BEST` days old, and the lift was trained within the
632
- * last `PLATEAU_RECENT_DAYS` days. They describe numbers, never a cause.
633
- */
634
- declare const PLATEAU_WINDOW_DAYS = 56;
635
- declare const PLATEAU_MIN_SESSIONS = 4;
636
- declare const PLATEAU_MIN_DAYS_SINCE_BEST = 21;
637
- declare const PLATEAU_RECENT_DAYS = 21;
638
- /**
639
- * PREF-05: each account chooses its minimum sessions within these bounds;
640
- * `PLATEAU_MIN_SESSIONS` is the default. The other thresholds stay fixed.
641
- */
642
- declare const PLATEAU_MIN_SESSIONS_MIN = 3;
643
- declare const PLATEAU_MIN_SESSIONS_MAX = 8;
644
- /** Body and response of PUT /users/preferences/plateaus. */
645
- interface PlateauPreferences {
646
- minSessions: number;
776
+ endedAt: IsoDateString;
777
+ durationSec: number;
778
+ totalVolumeKg: number;
779
+ completedSets: number;
780
+ durationDeltaSec: number;
781
+ volumeDeltaKg: number;
782
+ completedSetsDelta: number;
647
783
  }
648
- interface PlateauSet {
649
- weightKg: number;
650
- reps: number;
651
- estimated1rmKg: number;
784
+ /** Stable successful response of GET /workouts/sessions/:id/recap. */
785
+ interface WorkoutSessionRecap {
786
+ sessionId: string;
787
+ routineName: string;
788
+ dayName?: string | null;
789
+ startedAt: IsoDateString;
790
+ endedAt: IsoDateString;
791
+ durationSec: number;
792
+ totalVolumeKg: number;
793
+ completedSets: number;
794
+ notes?: string | null;
795
+ /** LIVE-16: exercise notes of this workout, named, in the day's order. */
796
+ exerciseNotes?: SessionRecapExerciseNote[];
797
+ records: SessionRecapRecord[];
798
+ progressionChanges: ProgressionChange[];
799
+ previousSession: PreviousSessionRecap | null;
652
800
  }
653
- interface ExercisePlateau {
654
- exerciseId: string;
801
+ interface SessionRecapExerciseNote {
802
+ routineExerciseId: string;
655
803
  exerciseName: string;
656
- /** The persisted best-set frontier. */
657
- best: PlateauSet & {
658
- achievedAt: IsoDateString;
659
- };
660
- /** Sessions were counted from the later of the best and the window start. */
661
- countedSince: IsoDateString;
662
- sessionsWithoutNewBest: number;
663
- /** The set since then with the highest estimated 1RM (latest on ties). */
664
- closest: PlateauSet & {
665
- performedAt: IsoDateString;
666
- };
667
- /** closest.estimated1rmKg / best.estimated1rmKg. */
668
- closestRatio: number;
669
- lastPerformedAt: IsoDateString;
804
+ note: string;
670
805
  }
671
- /** Stable successful response of GET /workouts/progress/plateaus. */
672
- interface PlateausResponse {
673
- asOf: IsoDateString;
674
- thresholds: {
675
- windowDays: number;
676
- /** The account's PREF-05 choice, within the bounds above. */
677
- minSessions: number;
678
- minDaysSinceBest: number;
679
- recentDays: number;
680
- };
681
- /** Lifts with a best set that were trained within the recent days. */
682
- checkedExercises: number;
683
- /** Longest-running first: most sessions without a new best. */
684
- plateaus: ExercisePlateau[];
806
+ /** Parts of a completed session's recap the owner may choose to share. */
807
+ declare const SESSION_SHARE_FIELDS: readonly ["duration", "volume", "completedSets", "records", "progression", "notes"];
808
+ type SessionShareField = (typeof SESSION_SHARE_FIELDS)[number];
809
+ /** Pre-selected when creating a link; notes and prescriptions are opt-in. */
810
+ declare const SESSION_SHARE_DEFAULT_FIELDS: SessionShareField[];
811
+ declare const SESSION_SHARE_MAX_ACTIVE_LINKS = 10;
812
+ interface CreateSessionShareRequest {
813
+ fields: SessionShareField[];
685
814
  }
686
-
687
- declare const ACHIEVEMENT_CATEGORIES: readonly ["SESSIONS", "SETS", "VOLUME_KG", "RECORDS", "STREAK_DAYS"];
688
- type AchievementCategory = (typeof ACHIEVEMENT_CATEGORIES)[number];
689
- interface AchievementDefinition {
815
+ /** An active share link, visible only to the session owner. */
816
+ interface SessionShare {
690
817
  id: string;
691
- category: AchievementCategory;
692
- threshold: number;
693
- title: string;
694
- description: string;
695
- }
696
- /** Stable milestone catalog shared by the writer and every presentation. */
697
- declare const ACHIEVEMENT_DEFINITIONS: readonly AchievementDefinition[];
698
- interface AchievementUnlockedEventPayload extends AchievementDefinition {
699
- schemaVersion: 1;
700
- backfilled: boolean;
701
- }
702
- interface StreakMilestoneEventPayload {
703
- schemaVersion: 1;
704
- achievementId: string;
705
- streakDays: number;
706
- backfilled: boolean;
818
+ sessionId: string;
819
+ /** Unguessable identifier used in the public `/shared/sessions/:token` URL. */
820
+ token: string;
821
+ fields: SessionShareField[];
822
+ createdAt: IsoDateString;
823
+ /**
824
+ * TRUST-04: a moderator has hidden the shared workout, so the link stops
825
+ * resolving for everyone but its owner. The link is not revoked and the
826
+ * session is untouched; the owner is told because a live-looking link that
827
+ * opens for nobody is worse than one that says why.
828
+ */
829
+ isHiddenByModeration?: boolean;
707
830
  }
708
- interface EarnedAchievement extends AchievementDefinition {
709
- eventId: string;
710
- unlockedAt: IsoDateString;
711
- sourceSessionId: string | null;
712
- /** True when existing verified history was recognized after ACH-01 shipped. */
713
- backfilled: boolean;
831
+ /** Stable successful response of GET /workouts/sessions/:id/shares. */
832
+ interface SessionShareListResponse {
833
+ items: SessionShare[];
714
834
  }
715
- interface RenaissanceRankDefinition {
716
- id: 'INITIATE' | 'APPRENTICE' | 'ARTISAN' | 'MAESTRO' | 'VIRTUOSO' | 'LAUREATE';
717
- title: string;
718
- description: string;
719
- minimumSessions: number;
720
- minimumActiveWeeks: number;
835
+ interface SharedSessionOwner {
836
+ username: string;
837
+ name: string;
838
+ lastName?: string | null;
839
+ avatarUrl?: string | null;
721
840
  }
722
841
  /**
723
- * Stable rank ladder. Both requirements are intentionally based on attendance:
724
- * completed sessions reward participation, while distinct active weeks reward
725
- * consistency without encouraging consecutive-day training.
842
+ * Stable successful response of the unauthenticated
843
+ * GET /shared/sessions/:token. Only the fields named in `fields` are present;
844
+ * everything else is omitted rather than nulled. Weights are canonical kg and
845
+ * `weightUnit` is the owner's display preference.
726
846
  */
727
- declare const RENAISSANCE_RANK_DEFINITIONS: readonly [{
728
- readonly id: "INITIATE";
729
- readonly title: "Initiate";
730
- readonly description: "Your place in the training ledger begins here.";
731
- readonly minimumSessions: 0;
732
- readonly minimumActiveWeeks: 0;
733
- }, {
734
- readonly id: "APPRENTICE";
735
- readonly title: "Apprentice";
736
- readonly description: "Learning the craft through regular practice.";
737
- readonly minimumSessions: 5;
738
- readonly minimumActiveWeeks: 3;
739
- }, {
740
- readonly id: "ARTISAN";
741
- readonly title: "Artisan";
742
- readonly description: "Building a dependable training practice.";
743
- readonly minimumSessions: 15;
744
- readonly minimumActiveWeeks: 8;
745
- }, {
746
- readonly id: "MAESTRO";
747
- readonly title: "Maestro";
748
- readonly description: "Sustaining purposeful work across many weeks.";
749
- readonly minimumSessions: 30;
750
- readonly minimumActiveWeeks: 16;
751
- }, {
752
- readonly id: "VIRTUOSO";
753
- readonly title: "Virtuoso";
754
- readonly description: "Showing enduring discipline through repeated seasons.";
755
- readonly minimumSessions: 60;
756
- readonly minimumActiveWeeks: 32;
757
- }, {
758
- readonly id: "LAUREATE";
759
- readonly title: "Laureate";
760
- readonly description: "A lasting training practice recorded in the ledger.";
761
- readonly minimumSessions: 100;
762
- readonly minimumActiveWeeks: 52;
763
- }];
764
- interface RenaissanceRankProgress {
765
- currentRank: RenaissanceRankDefinition;
766
- nextRank: RenaissanceRankDefinition | null;
767
- completedSessions: number;
768
- activeWeeks: number;
769
- sessionsRemaining: number;
770
- activeWeeksRemaining: number;
771
- }
772
- /**
773
- * Current verified total and the next fixed catalog milestone for one category.
774
- * A null next milestone means the category's finite catalog is complete.
775
- */
776
- interface AchievementCategoryProgress {
777
- category: AchievementCategory;
778
- currentValue: number;
779
- nextMilestone: AchievementDefinition | null;
780
- remaining: number;
847
+ interface SharedSessionRecap {
848
+ fields: SessionShareField[];
849
+ owner: SharedSessionOwner;
850
+ weightUnit: WeightUnit;
851
+ routineName: string;
852
+ dayName?: string | null;
853
+ endedAt: IsoDateString;
854
+ durationSec?: number;
855
+ totalVolumeKg?: number;
856
+ completedSets?: number;
857
+ records?: SessionRecapRecord[];
858
+ progressionChanges?: ProgressionChange[];
859
+ notes?: string | null;
860
+ /** LIVE-16: shared with the `notes` field. */
861
+ exerciseNotes?: SessionRecapExerciseNote[];
781
862
  }
782
- /**
783
- * ACH-05 recognises a return only after the athlete has rebuilt a small,
784
- * recovery-compatible pattern. The break is counted as full local calendar
785
- * days without a completed session; repeated sessions on one date count once.
786
- */
787
- declare const COMEBACK_MIN_INACTIVE_DAYS = 14;
788
- declare const COMEBACK_REQUIRED_ACTIVE_DAYS = 3;
789
- declare const COMEBACK_WINDOW_DAYS = 14;
790
- declare const COMEBACK_SESSION_LOOKBACK = 500;
791
- declare const COMEBACK_RECOGNITION_LIMIT = 20;
792
- interface ComebackRecognition {
863
+ interface WorkoutSessionSummary {
793
864
  id: string;
794
- inactiveDays: number;
795
- returnedAt: IsoDateString;
796
- recognizedAt: IsoDateString;
797
- sourceSessionId: string;
798
- activeDays: number;
799
- /** Inclusive local-calendar span from the return through recognition. */
800
- windowDays: number;
865
+ status: WorkoutSessionStatus;
866
+ startedAt: IsoDateString;
867
+ endedAt?: IsoDateString | null;
868
+ durationSec?: number | null;
869
+ totalVolume?: number | null;
870
+ totalSets?: number | null;
871
+ totalExercises?: number | null;
872
+ notes?: string | null;
873
+ routine: {
874
+ id: string;
875
+ name: string;
876
+ dayName?: string | null;
877
+ /** ROUT-15: the block trained, when it was one. */
878
+ trainingBlockName?: string | null;
879
+ };
801
880
  }
802
- interface ComebackRecognitionSummary {
803
- minimumInactiveDays: number;
804
- requiredActiveDays: number;
805
- windowDays: number;
806
- /** Most recent first, capped by COMEBACK_RECOGNITION_LIMIT. */
807
- recognitions: ComebackRecognition[];
808
- /** True when older completed-session events fell outside the bounded scan. */
809
- historyTruncated: boolean;
881
+ interface ListSessionsParams {
882
+ status?: WorkoutSessionStatus;
883
+ routineId?: string;
884
+ from?: IsoDateString;
885
+ to?: IsoDateString;
886
+ q?: string;
887
+ cursor?: string;
888
+ limit?: number;
889
+ sort?: 'finishedAt:desc' | 'finishedAt:asc' | 'startedAt:desc' | 'startedAt:asc';
810
890
  }
811
- /** Stable successful response of GET /achievements. */
812
- interface AchievementsResponse {
813
- analyticsReady: boolean;
814
- earnedCount: number;
815
- availableCount: number;
816
- achievements: EarnedAchievement[];
817
- rank: RenaissanceRankProgress | null;
818
- milestoneProgress: AchievementCategoryProgress[];
819
- comeback: ComebackRecognitionSummary | null;
891
+ type WorkoutSessionListResponse = PaginatedResponse<WorkoutSessionSummary>;
892
+ interface WorkoutStatsQuery {
893
+ weekStart: IsoDateString;
894
+ weekEnd: IsoDateString;
895
+ timeZone: string;
896
+ }
897
+ interface WorkoutStatsResponse {
898
+ totalCompleted: number;
899
+ completionRate: number;
900
+ weeklyWorkoutsCount: number;
901
+ activeDaysThisWeek: number;
820
902
  }
821
903
 
822
- /**
823
- * A block is **symmetric**. It removes any follow in both directions and
824
- * prevents a new one either way; neither account appears in the other's
825
- * search, suggestions, relationship lists or profile reads. Hiding only the
826
- * blocked account from the blocker would leave the blocker visible to them,
827
- * which is the half nobody asks for.
828
- *
829
- * It is **not retroactive over what was already handed out**: a `SOC-07`
830
- * session link and a `ROUT-04` routine link carry no viewer identity, so a
831
- * block cannot withdraw one. Revoking the link is that control.
832
- */
833
- interface BlockedMember {
834
- /** The blocked account's identity, as a search result carries it. */
835
- member: UserSearchResponse;
836
- blockedAt: IsoDateString;
904
+ declare const TRAINING_EVENT_TYPES: readonly ["SESSION_COMPLETED", "PERSONAL_RECORD", "PROGRESSION_CHANGED", "STREAK_MILESTONE", "ACHIEVEMENT_UNLOCKED"];
905
+ type TrainingEventType = (typeof TRAINING_EVENT_TYPES)[number];
906
+ /** Stable successful response of GET /workouts/progress. */
907
+ interface WorkoutProgressQuery {
908
+ timeZone: string;
837
909
  }
838
- /** Stable successful response of GET /users/me/blocks. */
839
- interface BlockedMembersResponse {
840
- blocks: BlockedMember[];
910
+ interface PersonalRecordEntry {
911
+ exerciseId: string;
912
+ exerciseName: string;
913
+ weight: number;
914
+ reps: number;
915
+ estimated1rm: number;
916
+ achievedAt: string;
841
917
  }
842
- /** One account blocks at most this many others. */
843
- declare const BLOCKED_MEMBERS_MAX = 500;
844
- /** What a viewer may do about one profile, so the UI never offers a no-op. */
845
- interface MemberModerationState {
846
- /** The viewer has blocked this member. */
847
- isBlocked: boolean;
918
+ interface RecentActivityEntry {
919
+ sessionId: string;
920
+ routineId: string;
921
+ routineName: string;
922
+ dayName: string;
923
+ startedAt: string;
924
+ endedAt: string | null;
925
+ durationSec: number | null;
926
+ totalVolumeKg: number;
927
+ completedSets: number;
848
928
  }
849
- declare const REPORT_SUBJECT_KINDS: readonly ["MEMBER", "ROUTINE", "SESSION", "COMMENT"];
850
- type ReportSubjectKind = (typeof REPORT_SUBJECT_KINDS)[number];
851
- /**
852
- * Why something was reported. The list is short and fixed on purpose: a free
853
- * text field would collect personal data `TRUST-04` has nowhere to put yet.
854
- */
855
- declare const REPORT_REASONS: readonly ["SPAM", "HARASSMENT", "IMPERSONATION", "UNSAFE_ADVICE", "SEXUAL_CONTENT", "OTHER"];
856
- type ReportReason = (typeof REPORT_REASONS)[number];
857
- declare const REPORT_DETAILS_MAX_LENGTH = 500;
858
- /** One account files at most this many reports a day. */
859
- declare const REPORTS_PER_DAY_MAX = 20;
860
- /** POST /reports */
861
- interface CreateReportRequest {
862
- subjectKind: ReportSubjectKind;
863
- /** A member id or username, a routine id, or a session share token. */
864
- subjectId: string;
865
- reason: ReportReason;
866
- /** Optional context from the reporter, never required. */
867
- details?: string | null;
929
+ interface WorkoutProgressResponse {
930
+ totalVolumeKg: number;
931
+ currentStreakDays: number;
932
+ bestStreakDays: number;
933
+ personalRecords: PersonalRecordEntry[];
934
+ recentActivity: RecentActivityEntry[];
868
935
  }
869
- /**
870
- * Stable successful response of POST /reports. It confirms the report was
871
- * recorded and says nothing about review, because nothing reviews it yet.
872
- */
873
- interface CreateReportResponse {
874
- id: string;
875
- createdAt: IsoDateString;
936
+ interface ExerciseStrengthTrendQuery {
937
+ exerciseId?: string;
938
+ from?: string;
939
+ to?: string;
876
940
  }
877
- /** Whether the signed-in account may open the queue at all. */
878
- interface ModeratorState {
879
- isModerator: boolean;
941
+ interface ExerciseStrengthSummary {
942
+ exerciseId: string;
943
+ exerciseName: string;
944
+ weightKg: number;
945
+ reps: number;
946
+ estimated1rmKg: number;
947
+ achievedAt: string;
880
948
  }
881
- declare const REPORT_STATUSES: readonly ["OPEN", "DISMISSED", "ACTIONED"];
882
- type ReportStatus = (typeof REPORT_STATUSES)[number];
883
- /**
884
- * Every moderator power, each one a record. `VIEW_SUBJECT` is here for the
885
- * same reason the others are: it is a thing a moderator did to somebody's
886
- * content, and it is the only one that leaves no other trace.
887
- */
888
- declare const MODERATION_ACTION_KINDS: readonly ["VIEW_SUBJECT", "DISMISS_REPORT", "HIDE_SUBJECT", "RESTORE_SUBJECT"];
889
- type ModerationActionKind = (typeof MODERATION_ACTION_KINDS)[number];
890
- declare const MODERATION_NOTE_MAX_LENGTH = 500;
891
- declare const MODERATION_QUEUE_PAGE_SIZE = 20;
892
- declare const MODERATION_HISTORY_PAGE_SIZE = 20;
893
- /**
894
- * What the reviewer may actually learn about a reported subject, resolved
895
- * server-side through the rules that already govern the subject. A reviewer
896
- * who may not read it is told so; the queue never fills the gap in.
897
- */
898
- interface ReportSubjectPreview {
899
- kind: ReportSubjectKind;
900
- /** As the reporter named it: a member id or username, a routine id, a token. */
901
- id: string;
902
- /**
903
- * The member id, routine id or session-share token this resolves to, which
904
- * is what a review action is recorded against. Null when the subject is
905
- * gone.
906
- */
907
- resolvedId: string | null;
908
- /** Present only when the reviewer may read the subject. */
909
- title: string | null;
910
- /** The subject's owner, when the reviewer may read the subject. */
911
- owner: UserSearchResponse | null;
912
- /** The subject no longer exists; only dismissing is left. */
913
- isMissing: boolean;
914
- /**
915
- * The shipped `PROF-06`/`PROF-10` rules deny this reviewer this subject.
916
- * It can still be hidden or dismissed on the strength of the report; it
917
- * cannot be read, and no moderator flag changes that.
918
- */
919
- isWithheld: boolean;
920
- /** A `HIDE_SUBJECT` is currently in force. */
921
- isHidden: boolean;
949
+ interface ExerciseStrengthTrendPoint {
950
+ sessionId: string;
951
+ achievedAt: string;
952
+ weightKg: number;
953
+ reps: number;
954
+ estimated1rmKg: number;
922
955
  }
923
- /** One row of the queue. */
924
- interface ModerationReport {
925
- id: string;
926
- status: ReportStatus;
927
- reason: ReportReason;
928
- details: string | null;
929
- createdAt: IsoDateString;
930
- reporter: UserSearchResponse;
931
- subject: ReportSubjectPreview;
932
- /** Other reports still open about the same subject, this one excluded. */
933
- otherOpenReports: number;
934
- resolvedAt: IsoDateString | null;
956
+ /** Stable successful response of GET /workouts/progress/strength. */
957
+ interface ExerciseStrengthTrendResponse {
958
+ exercises: ExerciseStrengthSummary[];
959
+ selectedExercise: ExerciseStrengthSummary | null;
960
+ range: {
961
+ from: string | null;
962
+ to: string;
963
+ };
964
+ baseline: ExerciseStrengthTrendPoint | null;
965
+ points: ExerciseStrengthTrendPoint[];
966
+ truncated: boolean;
935
967
  }
936
- interface ModerationQueueQuery {
937
- /** Omitted means `OPEN`, which is the queue's reason to exist. */
938
- status?: ReportStatus;
968
+ interface ExercisePerformanceHistoryQuery {
969
+ exerciseId?: string;
970
+ from?: string;
971
+ to?: string;
939
972
  cursor?: string;
940
973
  limit?: number;
941
974
  }
942
- /** Stable successful response of GET /moderation/queue. */
943
- interface ModerationQueueResponse {
944
- reports: ModerationReport[];
945
- nextCursor: string | null;
946
- /** Open reports in total, independent of the page or the filter. */
947
- openCount: number;
975
+ interface ExercisePerformanceSummary {
976
+ exerciseId: string;
977
+ exerciseName: string;
978
+ lastPerformedAt: string;
979
+ hasStrengthTrend: boolean;
948
980
  }
949
- /**
950
- * One enforcement record. It is written once and never updated or deleted —
951
- * including when a hide is undone, which appends a `RESTORE_SUBJECT` record
952
- * rather than editing the `HIDE_SUBJECT` one.
953
- */
954
- interface ModerationActionRecord {
981
+ interface ExercisePerformanceSet {
982
+ routineExerciseId: string;
983
+ setNumber: number;
984
+ reps: number;
985
+ weightKg?: number | null;
986
+ rpe?: number | null;
987
+ }
988
+ interface ExercisePerformancePrescriptionSet {
989
+ setNumber: number;
990
+ repType: RepType;
991
+ reps?: number | null;
992
+ minReps?: number | null;
993
+ maxReps?: number | null;
994
+ weightKg?: number | null;
995
+ rir?: number | null;
996
+ }
997
+ interface ExercisePerformancePrescription {
998
+ routineExerciseId: string;
999
+ restSeconds?: number | null;
1000
+ note?: string | null;
1001
+ progressionScheme: ProgressionScheme;
1002
+ minWeightIncrementKg: number;
1003
+ sets: ExercisePerformancePrescriptionSet[];
1004
+ }
1005
+ interface ExercisePerformanceSession {
1006
+ sessionId: string;
1007
+ status: Extract<WorkoutSessionStatus, 'COMPLETED' | 'ABORTED'>;
1008
+ routineName: string;
1009
+ dayName?: string | null;
1010
+ startedAt: string;
1011
+ endedAt: string;
1012
+ durationSec?: number | null;
1013
+ sessionNotes?: string | null;
1014
+ sets: ExercisePerformanceSet[];
1015
+ prescriptions: ExercisePerformancePrescription[];
1016
+ progressionChanges: ProgressionChange[];
1017
+ }
1018
+ /** Stable successful response of GET /workouts/progress/performance. */
1019
+ interface ExercisePerformanceHistoryResponse {
1020
+ exercises: ExercisePerformanceSummary[];
1021
+ selectedExercise: ExercisePerformanceSummary | null;
1022
+ items: ExercisePerformanceSession[];
1023
+ nextCursor?: string;
1024
+ }
1025
+ interface MuscleGroupHeatmapQuery {
1026
+ timeZone: string;
1027
+ /** Number of Monday-based calendar weeks to return, including this week. */
1028
+ weeks?: number;
1029
+ }
1030
+ interface MuscleGroupHeatmapValue {
1031
+ muscle: MuscleGroup;
1032
+ /** Completed-set equivalents: primary muscles count 1, secondary count 0.5. */
1033
+ weightedSets: number;
1034
+ }
1035
+ interface MuscleGroupHeatmapWeek {
1036
+ weekStart: string;
1037
+ isCurrentWeek: boolean;
1038
+ totalWeightedSets: number;
1039
+ muscles: MuscleGroupHeatmapValue[];
1040
+ }
1041
+ /** Stable successful response of GET /workouts/progress/muscles. */
1042
+ interface MuscleGroupHeatmapResponse {
1043
+ timeZone: string;
1044
+ weeks: MuscleGroupHeatmapWeek[];
1045
+ peakWeightedSets: number;
1046
+ }
1047
+ interface VolumeTrendQuery {
1048
+ timeZone: string;
1049
+ /** Number of Monday-based calendar weeks to return, including this week. */
1050
+ weeks?: number;
1051
+ }
1052
+ interface VolumeTrendPoint {
1053
+ weekStart: string;
1054
+ isCurrentWeek: boolean;
1055
+ /** External-load volume in canonical kilograms: weight × repetitions. */
1056
+ volumeKg: number;
1057
+ completedSets: number;
1058
+ }
1059
+ interface VolumeTrendSeries {
955
1060
  id: string;
956
- kind: ModerationActionKind;
957
- moderator: UserSearchResponse;
958
- /** The report the action was taken from, when it was taken from one. */
959
- reportId: string | null;
960
- subjectKind: ReportSubjectKind;
961
- subjectId: string;
962
- note: string | null;
963
- createdAt: IsoDateString;
1061
+ name: string;
1062
+ totalVolumeKg: number;
1063
+ totalCompletedSets: number;
1064
+ points: VolumeTrendPoint[];
964
1065
  }
965
- interface ModerationHistoryQuery {
1066
+ interface MuscleVolumeTrendSeries extends VolumeTrendSeries {
1067
+ id: MuscleGroup;
1068
+ }
1069
+ /** Stable successful response of GET /workouts/progress/volume. */
1070
+ interface VolumeTrendResponse {
1071
+ timeZone: string;
1072
+ weeks: number;
1073
+ overall: VolumeTrendPoint[];
1074
+ muscles: MuscleVolumeTrendSeries[];
1075
+ routines: VolumeTrendSeries[];
1076
+ exercises: VolumeTrendSeries[];
1077
+ }
1078
+ interface SessionComparisonQuery {
1079
+ routineDayId?: string;
1080
+ }
1081
+ interface SessionComparisonRoutineDay {
1082
+ routineDayId: string;
1083
+ routineId: string;
1084
+ routineName: string;
1085
+ dayName?: string | null;
1086
+ lastCompletedAt: IsoDateString;
1087
+ completedSessionCount: number;
1088
+ }
1089
+ interface SessionComparisonSet {
1090
+ routineExerciseId: string;
1091
+ setNumber: number;
1092
+ reps: number;
1093
+ weightKg?: number | null;
1094
+ rpe?: number | null;
1095
+ }
1096
+ interface SessionComparisonExercise {
1097
+ routineExerciseId: string;
1098
+ exerciseId: string;
1099
+ exerciseName: string;
1100
+ order: number;
1101
+ sets: SessionComparisonSet[];
1102
+ }
1103
+ interface SessionComparisonSession {
1104
+ sessionId: string;
1105
+ routineDayId: string;
1106
+ routineName: string;
1107
+ dayName?: string | null;
1108
+ startedAt: IsoDateString;
1109
+ endedAt: IsoDateString;
1110
+ durationSec: number;
1111
+ totalVolumeKg: number;
1112
+ completedSets: number;
1113
+ notes?: string | null;
1114
+ exercises: SessionComparisonExercise[];
1115
+ }
1116
+ /** Stable successful response of GET /workouts/progress/session-comparison. */
1117
+ interface SessionComparisonResponse {
1118
+ routineDays: SessionComparisonRoutineDay[];
1119
+ selectedRoutineDay: SessionComparisonRoutineDay | null;
1120
+ latestSession: SessionComparisonSession | null;
1121
+ previousSession: SessionComparisonSession | null;
1122
+ }
1123
+ declare const PROGRESS_TIMELINE_EVENT_TYPES: readonly ["PERSONAL_RECORD", "PROGRESSION_CHANGED"];
1124
+ type ProgressTimelineEventType = (typeof PROGRESS_TIMELINE_EVENT_TYPES)[number];
1125
+ interface ProgressTimelineQuery {
1126
+ type?: ProgressTimelineEventType;
1127
+ /** Only events for one catalog exercise (EXER-01). */
1128
+ exerciseId?: string;
966
1129
  cursor?: string;
967
1130
  limit?: number;
968
- /** Narrow to one subject's records, newest first. */
969
- subjectKind?: ReportSubjectKind;
970
- subjectId?: string;
971
1131
  }
972
- /** Stable successful response of GET /moderation/actions. */
973
- interface ModerationHistoryResponse {
974
- actions: ModerationActionRecord[];
975
- nextCursor: string | null;
1132
+ interface ProgressTimelineSessionContext {
1133
+ sessionId: string;
1134
+ routineName: string;
1135
+ dayName?: string | null;
1136
+ }
1137
+ interface ProgressTimelineRecordPerformance {
1138
+ weightKg: number;
1139
+ reps: number;
1140
+ estimated1rmKg: number;
1141
+ }
1142
+ type ProgressTimelineRecordReason = 'FIRST_RECORDED_BEST' | 'HEAVIER_LOAD' | 'MORE_REPS_AT_SAME_LOAD';
1143
+ interface ProgressTimelinePersonalRecordItem {
1144
+ eventId: string;
1145
+ type: 'PERSONAL_RECORD';
1146
+ occurredAt: IsoDateString;
1147
+ session: ProgressTimelineSessionContext;
1148
+ exerciseId: string;
1149
+ exerciseName: string;
1150
+ current: ProgressTimelineRecordPerformance;
1151
+ previous: ProgressTimelineRecordPerformance | null;
1152
+ reason: ProgressTimelineRecordReason;
1153
+ }
1154
+ interface ProgressTimelineProgressionItem {
1155
+ eventId: string;
1156
+ type: 'PROGRESSION_CHANGED';
1157
+ occurredAt: IsoDateString;
1158
+ session: ProgressTimelineSessionContext;
1159
+ exerciseId: string;
1160
+ exerciseName: string;
1161
+ change: ProgressionChange;
1162
+ }
1163
+ type ProgressTimelineItem = ProgressTimelinePersonalRecordItem | ProgressTimelineProgressionItem;
1164
+ /** Stable successful response of GET /workouts/progress/timeline. */
1165
+ interface ProgressTimelineResponse {
1166
+ items: ProgressTimelineItem[];
1167
+ nextCursor?: string;
976
1168
  }
977
- /**
978
- * POST /moderation/reports/:id/dismiss, /hide and /restore. The note is the
979
- * reviewer's own record of why; it is never shown to the reporter or to the
980
- * subject's owner, because neither is promised an explanation.
981
- */
982
- interface ReviewReportRequest {
983
- note?: string | null;
1169
+ /** Immutable prescription captured before any sets or progression. */
1170
+ interface WorkoutSessionSnapshotV1 {
1171
+ schemaVersion: 1;
1172
+ sessionId: string;
1173
+ sourceRoutineId: string;
1174
+ sourceRoutineDayId: string;
1175
+ capturedAt: string;
1176
+ provenance: 'CAPTURED' | 'APPROXIMATED';
1177
+ notes: string | null;
1178
+ routine: NonNullable<WorkoutSession['routine']>;
1179
+ routineDay: NonNullable<WorkoutSession['routineDay']>;
1180
+ /** ROUT-15; absent on snapshots captured before blocks executed. */
1181
+ trainingBlock?: WorkoutSession['trainingBlock'];
984
1182
  }
985
- /** Stable successful response of every review action, including a view. */
986
- interface ReviewReportResponse {
987
- report: ModerationReport;
988
- action: ModerationActionRecord;
1183
+ interface SetAccountTimeZoneRequest {
1184
+ timeZone: string;
1185
+ /** Bootstrap must not replace a zone registered by another device. */
1186
+ onlyIfUnset?: boolean;
1187
+ }
1188
+ interface WorkoutAnalyticsStatus {
1189
+ timeZone: string | null;
1190
+ requestedTimeZone: string | null;
1191
+ state: 'UNINITIALIZED' | 'BUILDING' | 'READY' | 'FAILED';
1192
+ generationId: string | null;
989
1193
  }
990
-
991
1194
  /**
992
- * ROUT-11: a WEEKLY routine ties each day to a weekday; a ROTATION routine
993
- * runs its days in `order`, each after the last completed one, whatever the
994
- * weekday.
1195
+ * Thresholds behind every plateau. A lift is flagged only when all hold: at
1196
+ * least the account's minimum sessions (`PLATEAU_MIN_SESSIONS` by default)
1197
+ * of terminal sessions with completed loaded sets of it since its current
1198
+ * best (the session that set the best excluded, and counting only inside the
1199
+ * look-back window), the best is at least
1200
+ * `PLATEAU_MIN_DAYS_SINCE_BEST` days old, and the lift was trained within the
1201
+ * last `PLATEAU_RECENT_DAYS` days. They describe numbers, never a cause.
995
1202
  */
996
- declare const ROUTINE_SCHEDULE_MODES: readonly ["WEEKLY", "ROTATION"];
997
- type RoutineScheduleMode = (typeof ROUTINE_SCHEDULE_MODES)[number];
998
- /** At most seven days in either mode. */
999
- declare const ROUTINE_DAYS_MAX = 7;
1000
- declare const ROUTINE_DAY_NAME_MAX = 40;
1203
+ declare const PLATEAU_WINDOW_DAYS = 56;
1204
+ declare const PLATEAU_MIN_SESSIONS = 4;
1205
+ declare const PLATEAU_MIN_DAYS_SINCE_BEST = 21;
1206
+ declare const PLATEAU_RECENT_DAYS = 21;
1001
1207
  /**
1002
- * How a routine day is named everywhere, including history snapshots taken
1003
- * before ROUT-11: its own name, else its weekday, else its rotation letter
1004
- * ("Day A" for order 0).
1208
+ * PREF-05: each account chooses its minimum sessions within these bounds;
1209
+ * `PLATEAU_MIN_SESSIONS` is the default. The other thresholds stay fixed.
1005
1210
  */
1006
- declare function routineDayLabel(day: {
1007
- name?: string | null;
1008
- dayOfWeek?: number | null;
1009
- order?: number | null;
1010
- }): string;
1011
- interface RoutineSet {
1012
- setNumber: number;
1013
- repType: RepType;
1014
- reps?: number | null;
1015
- minReps?: number | null;
1016
- maxReps?: number | null;
1017
- weight?: number | null;
1018
- rir?: number | null;
1211
+ declare const PLATEAU_MIN_SESSIONS_MIN = 3;
1212
+ declare const PLATEAU_MIN_SESSIONS_MAX = 8;
1213
+ /** Body and response of PUT /users/preferences/plateaus. */
1214
+ interface PlateauPreferences {
1215
+ minSessions: number;
1019
1216
  }
1020
- interface RoutineExercise {
1021
- id: string;
1022
- order: number;
1023
- restSeconds: number;
1024
- note?: string | null;
1025
- progressionScheme: ProgressionScheme;
1026
- minWeightIncrement: number;
1027
- exercise: {
1028
- id: string;
1029
- name: string;
1030
- primaryMuscles?: MuscleGroup[];
1031
- secondaryMuscles?: MuscleGroup[];
1032
- };
1033
- sets: RoutineSet[];
1217
+ interface PlateauSet {
1218
+ weightKg: number;
1219
+ reps: number;
1220
+ estimated1rmKg: number;
1034
1221
  }
1035
- interface CreateRoutineExerciseInput {
1222
+ interface ExercisePlateau {
1036
1223
  exerciseId: string;
1037
- order?: number;
1038
- restSeconds: number;
1039
- note?: string;
1040
- progressionScheme: ProgressionScheme;
1041
- minWeightIncrement: number;
1042
- sets: RoutineSet[];
1224
+ exerciseName: string;
1225
+ /** The persisted best-set frontier. */
1226
+ best: PlateauSet & {
1227
+ achievedAt: IsoDateString;
1228
+ };
1229
+ /** Sessions were counted from the later of the best and the window start. */
1230
+ countedSince: IsoDateString;
1231
+ sessionsWithoutNewBest: number;
1232
+ /** The set since then with the highest estimated 1RM (latest on ties). */
1233
+ closest: PlateauSet & {
1234
+ performedAt: IsoDateString;
1235
+ };
1236
+ /** closest.estimated1rmKg / best.estimated1rmKg. */
1237
+ closestRatio: number;
1238
+ lastPerformedAt: IsoDateString;
1043
1239
  }
1044
- interface RoutineDay {
1240
+ /** Stable successful response of GET /workouts/progress/plateaus. */
1241
+ interface PlateausResponse {
1242
+ asOf: IsoDateString;
1243
+ thresholds: {
1244
+ windowDays: number;
1245
+ /** The account's PREF-05 choice, within the bounds above. */
1246
+ minSessions: number;
1247
+ minDaysSinceBest: number;
1248
+ recentDays: number;
1249
+ };
1250
+ /** Lifts with a best set that were trained within the recent days. */
1251
+ checkedExercises: number;
1252
+ /** Longest-running first: most sessions without a new best. */
1253
+ plateaus: ExercisePlateau[];
1254
+ }
1255
+
1256
+ declare const ACHIEVEMENT_CATEGORIES: readonly ["SESSIONS", "SETS", "VOLUME_KG", "RECORDS", "STREAK_DAYS"];
1257
+ type AchievementCategory = (typeof ACHIEVEMENT_CATEGORIES)[number];
1258
+ interface AchievementDefinition {
1045
1259
  id: string;
1046
- /** 0=Sun..6=Sat on a WEEKLY routine; null on a ROTATION routine. */
1047
- dayOfWeek: number | null;
1048
- /** Optional label such as "Push" or "Upper A" (see `routineDayLabel`). */
1049
- name: string | null;
1050
- /** Rotation sequence, 0-based; also the display order. */
1051
- order: number;
1052
- exercises: RoutineExercise[];
1260
+ category: AchievementCategory;
1261
+ threshold: number;
1262
+ title: string;
1263
+ description: string;
1053
1264
  }
1054
- interface CreateRoutineDayInput {
1055
- /** Required and unique on a WEEKLY routine; omitted or null on a ROTATION. */
1056
- dayOfWeek?: number | null;
1057
- name?: string | null;
1058
- order?: number;
1059
- exercises: CreateRoutineExerciseInput[];
1265
+ /** Stable milestone catalog shared by the writer and every presentation. */
1266
+ declare const ACHIEVEMENT_DEFINITIONS: readonly AchievementDefinition[];
1267
+ interface AchievementUnlockedEventPayload extends AchievementDefinition {
1268
+ schemaVersion: 1;
1269
+ backfilled: boolean;
1060
1270
  }
1061
- interface Routine {
1271
+ interface StreakMilestoneEventPayload {
1272
+ schemaVersion: 1;
1273
+ achievementId: string;
1274
+ streakDays: number;
1275
+ backfilled: boolean;
1276
+ }
1277
+ interface EarnedAchievement extends AchievementDefinition {
1278
+ eventId: string;
1279
+ unlockedAt: IsoDateString;
1280
+ sourceSessionId: string | null;
1281
+ /** True when existing verified history was recognized after ACH-01 shipped. */
1282
+ backfilled: boolean;
1283
+ }
1284
+ interface RenaissanceRankDefinition {
1285
+ id: 'INITIATE' | 'APPRENTICE' | 'ARTISAN' | 'MAESTRO' | 'VIRTUOSO' | 'LAUREATE';
1286
+ title: string;
1287
+ description: string;
1288
+ minimumSessions: number;
1289
+ minimumActiveWeeks: number;
1290
+ }
1291
+ /**
1292
+ * Stable rank ladder. Both requirements are intentionally based on attendance:
1293
+ * completed sessions reward participation, while distinct active weeks reward
1294
+ * consistency without encouraging consecutive-day training.
1295
+ */
1296
+ declare const RENAISSANCE_RANK_DEFINITIONS: readonly [{
1297
+ readonly id: "INITIATE";
1298
+ readonly title: "Initiate";
1299
+ readonly description: "Your place in the training ledger begins here.";
1300
+ readonly minimumSessions: 0;
1301
+ readonly minimumActiveWeeks: 0;
1302
+ }, {
1303
+ readonly id: "APPRENTICE";
1304
+ readonly title: "Apprentice";
1305
+ readonly description: "Learning the craft through regular practice.";
1306
+ readonly minimumSessions: 5;
1307
+ readonly minimumActiveWeeks: 3;
1308
+ }, {
1309
+ readonly id: "ARTISAN";
1310
+ readonly title: "Artisan";
1311
+ readonly description: "Building a dependable training practice.";
1312
+ readonly minimumSessions: 15;
1313
+ readonly minimumActiveWeeks: 8;
1314
+ }, {
1315
+ readonly id: "MAESTRO";
1316
+ readonly title: "Maestro";
1317
+ readonly description: "Sustaining purposeful work across many weeks.";
1318
+ readonly minimumSessions: 30;
1319
+ readonly minimumActiveWeeks: 16;
1320
+ }, {
1321
+ readonly id: "VIRTUOSO";
1322
+ readonly title: "Virtuoso";
1323
+ readonly description: "Showing enduring discipline through repeated seasons.";
1324
+ readonly minimumSessions: 60;
1325
+ readonly minimumActiveWeeks: 32;
1326
+ }, {
1327
+ readonly id: "LAUREATE";
1328
+ readonly title: "Laureate";
1329
+ readonly description: "A lasting training practice recorded in the ledger.";
1330
+ readonly minimumSessions: 100;
1331
+ readonly minimumActiveWeeks: 52;
1332
+ }];
1333
+ interface RenaissanceRankProgress {
1334
+ currentRank: RenaissanceRankDefinition;
1335
+ nextRank: RenaissanceRankDefinition | null;
1336
+ completedSessions: number;
1337
+ activeWeeks: number;
1338
+ sessionsRemaining: number;
1339
+ activeWeeksRemaining: number;
1340
+ }
1341
+ /**
1342
+ * Current verified total and the next fixed catalog milestone for one category.
1343
+ * A null next milestone means the category's finite catalog is complete.
1344
+ */
1345
+ interface AchievementCategoryProgress {
1346
+ category: AchievementCategory;
1347
+ currentValue: number;
1348
+ nextMilestone: AchievementDefinition | null;
1349
+ remaining: number;
1350
+ }
1351
+ /**
1352
+ * ACH-05 recognises a return only after the athlete has rebuilt a small,
1353
+ * recovery-compatible pattern. The break is counted as full local calendar
1354
+ * days without a completed session; repeated sessions on one date count once.
1355
+ */
1356
+ declare const COMEBACK_MIN_INACTIVE_DAYS = 14;
1357
+ declare const COMEBACK_REQUIRED_ACTIVE_DAYS = 3;
1358
+ declare const COMEBACK_WINDOW_DAYS = 14;
1359
+ declare const COMEBACK_SESSION_LOOKBACK = 500;
1360
+ declare const COMEBACK_RECOGNITION_LIMIT = 20;
1361
+ interface ComebackRecognition {
1062
1362
  id: string;
1063
- userId: string;
1064
- name: string;
1065
- description?: string | null;
1066
- isPeriodized: boolean;
1067
- isFavorite: boolean;
1068
- isCompleted: boolean;
1069
- scheduleMode: RoutineScheduleMode;
1070
- /**
1071
- * ROTATION only: the day after the one of the last completed session (an
1072
- * aborted session does not advance it), or the first day before any.
1073
- */
1074
- nextRotationDayId: string | null;
1075
- /**
1076
- * SCHED-07: weekdays (0=Sun..6=Sat) this weekly routine rests on by plan,
1077
- * never one of its training weekdays; always empty on a ROTATION routine.
1078
- */
1079
- restDays: number[];
1080
- /**
1081
- * SCHED-06: weekdays (0=Sun..6=Sat) a ROTATION routine trains on, sorted; the
1082
- * schedule places its days on them in order. Empty means any day, without
1083
- * dates; always empty on a WEEKLY routine.
1084
- */
1085
- rotationWeekdays: number[];
1086
- /**
1087
- * ROUT-04: who may read this routine, bounded by the account-level
1088
- * `PROF-06` routines rule. Owner-only field; it never appears in a shared
1089
- * read, where visibility is the reason the reader is there.
1090
- */
1091
- visibility: RoutineVisibility;
1092
- /**
1093
- * ROUT-06: present only on a routine that was cloned, and only with what
1094
- * this viewer is allowed to know about its source.
1095
- */
1096
- lineage?: RoutineLineage | null;
1097
- /**
1098
- * ROUT-07: owner-declared, both optional. They are claims about the
1099
- * programme that only its author can make, which is why they are stored
1100
- * here rather than derived from the author's `PROF-05` training identity.
1101
- */
1102
- goal?: TrainingGoal | null;
1103
- experienceLevel?: TrainingExperienceLevel | null;
1104
- /**
1105
- * TRUST-04: a moderator has hidden this routine from everyone but its
1106
- * owner. Owner-only field, and true on the owner's own read alone: a
1107
- * routine nobody else can open while its own visibility still reads
1108
- * "Public" would be a control with nothing behind it.
1109
- */
1110
- isHiddenByModeration?: boolean;
1111
- days: RoutineDay[];
1112
- createdAt: IsoDateString;
1113
- updatedAt: IsoDateString;
1363
+ inactiveDays: number;
1364
+ returnedAt: IsoDateString;
1365
+ recognizedAt: IsoDateString;
1366
+ sourceSessionId: string;
1367
+ activeDays: number;
1368
+ /** Inclusive local-calendar span from the return through recognition. */
1369
+ windowDays: number;
1114
1370
  }
1115
- interface CreateRoutineRequest {
1116
- name: string;
1117
- description?: string;
1118
- /** ROUT-07; omitted means undeclared, which is not the same as a default. */
1119
- goal?: TrainingGoal | null;
1120
- experienceLevel?: TrainingExperienceLevel | null;
1121
- isPeriodized: boolean;
1122
- /** Defaults to WEEKLY. Changing it on update requires `days`. */
1123
- scheduleMode?: RoutineScheduleMode;
1124
- /**
1125
- * Weekly routines only. Omitted on update keeps the stored rest days, minus
1126
- * any that became training weekdays.
1127
- */
1128
- restDays?: number[];
1129
- /**
1130
- * Rotation routines only. Omitted on update keeps the stored weekdays;
1131
- * switching to WEEKLY clears them.
1132
- */
1133
- rotationWeekdays?: number[];
1134
- days: CreateRoutineDayInput[];
1371
+ interface ComebackRecognitionSummary {
1372
+ minimumInactiveDays: number;
1373
+ requiredActiveDays: number;
1374
+ windowDays: number;
1375
+ /** Most recent first, capped by COMEBACK_RECOGNITION_LIMIT. */
1376
+ recognitions: ComebackRecognition[];
1377
+ /** True when older completed-session events fell outside the bounded scan. */
1378
+ historyTruncated: boolean;
1135
1379
  }
1136
- type UpdateRoutineRequest = Partial<CreateRoutineRequest>;
1137
- /** A routine keeps at most this many versions; saving past it is refused. */
1138
- declare const ROUTINE_VERSIONS_MAX = 20;
1139
- declare const ROUTINE_VERSION_NAME_MAX = 60;
1380
+ /** Stable successful response of GET /achievements. */
1381
+ interface AchievementsResponse {
1382
+ analyticsReady: boolean;
1383
+ earnedCount: number;
1384
+ availableCount: number;
1385
+ achievements: EarnedAchievement[];
1386
+ rank: RenaissanceRankProgress | null;
1387
+ milestoneProgress: AchievementCategoryProgress[];
1388
+ comeback: ComebackRecognitionSummary | null;
1389
+ }
1390
+
1140
1391
  /**
1141
- * SAVED is an intentional save; BEFORE_RESTORE is the setup a restore
1142
- * replaced, saved automatically so the restore can be undone.
1392
+ * A block is **symmetric**. It removes any follow in both directions and
1393
+ * prevents a new one either way; neither account appears in the other's
1394
+ * search, suggestions, relationship lists or profile reads. Hiding only the
1395
+ * blocked account from the blocker would leave the blocker visible to them,
1396
+ * which is the half nobody asks for.
1397
+ *
1398
+ * It is **not retroactive over what was already handed out**: a `SOC-07`
1399
+ * session link and a `ROUT-04` routine link carry no viewer identity, so a
1400
+ * block cannot withdraw one. Revoking the link is that control.
1143
1401
  */
1144
- declare const ROUTINE_VERSION_KINDS: readonly ["SAVED", "BEFORE_RESTORE"];
1145
- type RoutineVersionKind = (typeof ROUTINE_VERSION_KINDS)[number];
1146
- interface RoutineVersionExercise {
1147
- /** The catalog exercise and its name when the version was saved. */
1148
- exercise: {
1149
- id: string;
1150
- name: string;
1151
- };
1152
- order: number;
1153
- restSeconds: number;
1154
- note: string | null;
1155
- progressionScheme: ProgressionScheme;
1156
- minWeightIncrement: number;
1157
- sets: RoutineSet[];
1402
+ interface BlockedMember {
1403
+ /** The blocked account's identity, as a search result carries it. */
1404
+ member: UserSearchResponse;
1405
+ blockedAt: IsoDateString;
1158
1406
  }
1159
- interface RoutineVersionDay {
1160
- dayOfWeek: number | null;
1161
- name: string | null;
1162
- order: number;
1163
- exercises: RoutineVersionExercise[];
1407
+ /** Stable successful response of GET /users/me/blocks. */
1408
+ interface BlockedMembersResponse {
1409
+ blocks: BlockedMember[];
1164
1410
  }
1165
- /** Everything a routine edit can change, as it was when the version was saved. */
1166
- interface RoutineVersionSetup {
1167
- name: string;
1168
- description: string | null;
1169
- scheduleMode: RoutineScheduleMode;
1170
- restDays: number[];
1171
- /** SCHED-06; absent in versions saved before it, which means none. */
1172
- rotationWeekdays?: number[];
1173
- days: RoutineVersionDay[];
1411
+ /** One account blocks at most this many others. */
1412
+ declare const BLOCKED_MEMBERS_MAX = 500;
1413
+ /** What a viewer may do about one profile, so the UI never offers a no-op. */
1414
+ interface MemberModerationState {
1415
+ /** The viewer has blocked this member. */
1416
+ isBlocked: boolean;
1174
1417
  }
1175
- interface RoutineVersion {
1418
+ declare const REPORT_SUBJECT_KINDS: readonly ["MEMBER", "ROUTINE", "SESSION", "COMMENT"];
1419
+ type ReportSubjectKind = (typeof REPORT_SUBJECT_KINDS)[number];
1420
+ /**
1421
+ * Why something was reported. The list is short and fixed on purpose: a free
1422
+ * text field would collect personal data `TRUST-04` has nowhere to put yet.
1423
+ */
1424
+ declare const REPORT_REASONS: readonly ["SPAM", "HARASSMENT", "IMPERSONATION", "UNSAFE_ADVICE", "SEXUAL_CONTENT", "OTHER"];
1425
+ type ReportReason = (typeof REPORT_REASONS)[number];
1426
+ declare const REPORT_DETAILS_MAX_LENGTH = 500;
1427
+ /** One account files at most this many reports a day. */
1428
+ declare const REPORTS_PER_DAY_MAX = 20;
1429
+ /** POST /reports */
1430
+ interface CreateReportRequest {
1431
+ subjectKind: ReportSubjectKind;
1432
+ /** A member id or username, a routine id, or a session share token. */
1433
+ subjectId: string;
1434
+ reason: ReportReason;
1435
+ /** Optional context from the reporter, never required. */
1436
+ details?: string | null;
1437
+ }
1438
+ /**
1439
+ * Stable successful response of POST /reports. It confirms the report was
1440
+ * recorded and says nothing about review, because nothing reviews it yet.
1441
+ */
1442
+ interface CreateReportResponse {
1176
1443
  id: string;
1177
- routineId: string;
1178
- /** 1, 2, 3… per routine, never reused after a deletion. */
1179
- number: number;
1180
- name: string | null;
1181
- kind: RoutineVersionKind;
1182
- /** BEFORE_RESTORE only: the number of the version that was restored. */
1183
- restoredVersionNumber: number | null;
1184
1444
  createdAt: IsoDateString;
1185
- setup: RoutineVersionSetup;
1186
1445
  }
1187
- /** `GET /routines/:id/versions`, newest first. */
1188
- interface RoutineVersionsResponse {
1189
- versions: RoutineVersion[];
1190
- max: number;
1191
- }
1192
- /** `POST /routines/:id/versions` */
1193
- interface CreateRoutineVersionRequest {
1194
- name?: string | null;
1195
- }
1196
- /** `POST /routines/:id/versions/:versionId/restore` */
1197
- interface RestoreRoutineVersionResponse {
1198
- routine: Routine;
1199
- /** The replaced setup, saved as a BEFORE_RESTORE version. */
1200
- savedVersion: RoutineVersion;
1446
+ /** Whether the signed-in account may open the queue at all. */
1447
+ interface ModeratorState {
1448
+ isModerator: boolean;
1201
1449
  }
1202
-
1450
+ declare const REPORT_STATUSES: readonly ["OPEN", "DISMISSED", "ACTIONED"];
1451
+ type ReportStatus = (typeof REPORT_STATUSES)[number];
1203
1452
  /**
1204
- * Per-routine visibility. The account-level `PROF-06` routines rule is the
1205
- * upper bound: a routine marked `PUBLIC` inside an account whose routines are
1206
- * `FOLLOWERS` is visible to followers only, the same way `SOC-04` bounds
1207
- * activity by the profile section it comes from.
1453
+ * Every moderator power, each one a record. `VIEW_SUBJECT` is here for the
1454
+ * same reason the others are: it is a thing a moderator did to somebody's
1455
+ * content, and it is the only one that leaves no other trace.
1208
1456
  */
1209
- declare const ROUTINE_VISIBILITY_VALUES: readonly ["PRIVATE", "FOLLOWERS", "PUBLIC"];
1210
- type RoutineVisibility = (typeof ROUTINE_VISIBILITY_VALUES)[number];
1211
- /** One routine keeps at most this many active links. */
1212
- declare const ROUTINE_SHARE_MAX_ACTIVE_LINKS = 10;
1213
- /** PUT /routines/:id/visibility */
1214
- interface UpdateRoutineVisibilityRequest {
1215
- visibility: RoutineVisibility;
1457
+ declare const MODERATION_ACTION_KINDS: readonly ["VIEW_SUBJECT", "DISMISS_REPORT", "HIDE_SUBJECT", "RESTORE_SUBJECT"];
1458
+ type ModerationActionKind = (typeof MODERATION_ACTION_KINDS)[number];
1459
+ declare const MODERATION_NOTE_MAX_LENGTH = 500;
1460
+ declare const MODERATION_QUEUE_PAGE_SIZE = 20;
1461
+ declare const MODERATION_HISTORY_PAGE_SIZE = 20;
1462
+ /**
1463
+ * What the reviewer may actually learn about a reported subject, resolved
1464
+ * server-side through the rules that already govern the subject. A reviewer
1465
+ * who may not read it is told so; the queue never fills the gap in.
1466
+ */
1467
+ interface ReportSubjectPreview {
1468
+ kind: ReportSubjectKind;
1469
+ /** As the reporter named it: a member id or username, a routine id, a token. */
1470
+ id: string;
1471
+ /**
1472
+ * The member id, routine id or session-share token this resolves to, which
1473
+ * is what a review action is recorded against. Null when the subject is
1474
+ * gone.
1475
+ */
1476
+ resolvedId: string | null;
1477
+ /** Present only when the reviewer may read the subject. */
1478
+ title: string | null;
1479
+ /** The subject's owner, when the reviewer may read the subject. */
1480
+ owner: UserSearchResponse | null;
1481
+ /** The subject no longer exists; only dismissing is left. */
1482
+ isMissing: boolean;
1483
+ /**
1484
+ * The shipped `PROF-06`/`PROF-10` rules deny this reviewer this subject.
1485
+ * It can still be hidden or dismissed on the strength of the report; it
1486
+ * cannot be read, and no moderator flag changes that.
1487
+ */
1488
+ isWithheld: boolean;
1489
+ /** A `HIDE_SUBJECT` is currently in force. */
1490
+ isHidden: boolean;
1216
1491
  }
1217
- /** An active share link, visible only to the routine's owner. */
1218
- interface RoutineShare {
1492
+ /** One row of the queue. */
1493
+ interface ModerationReport {
1219
1494
  id: string;
1220
- routineId: string;
1221
- /** Unguessable identifier used in the public `/shared/routines/:token` URL. */
1222
- token: string;
1495
+ status: ReportStatus;
1496
+ reason: ReportReason;
1497
+ details: string | null;
1223
1498
  createdAt: IsoDateString;
1499
+ reporter: UserSearchResponse;
1500
+ subject: ReportSubjectPreview;
1501
+ /** Other reports still open about the same subject, this one excluded. */
1502
+ otherOpenReports: number;
1503
+ resolvedAt: IsoDateString | null;
1224
1504
  }
1225
- /** Stable successful response of GET /routines/:id/shares. */
1226
- interface RoutineShareListResponse {
1227
- items: RoutineShare[];
1228
- }
1229
- interface SharedRoutineOwner {
1230
- username: string;
1231
- name: string;
1232
- lastName?: string | null;
1233
- avatarUrl?: string | null;
1505
+ interface ModerationQueueQuery {
1506
+ /** Omitted means `OPEN`, which is the queue's reason to exist. */
1507
+ status?: ReportStatus;
1508
+ cursor?: string;
1509
+ limit?: number;
1234
1510
  }
1235
- /**
1236
- * How a reader reached a routine. A link is the owner's explicit consent for
1237
- * that one routine and ignores visibility; a visibility read is governed by
1238
- * both the routine's own rule and the account's.
1239
- */
1240
- declare const SHARED_ROUTINE_SOURCES: readonly ["LINK", "VISIBILITY"];
1241
- type SharedRoutineSource = (typeof SHARED_ROUTINE_SOURCES)[number];
1242
- /**
1243
- * Stable successful response of the unauthenticated
1244
- * GET /shared/routines/:token, and of the authenticated member read.
1245
- */
1246
- interface SharedRoutine {
1247
- /** Kept so a future clone (`ROUT-05`) can record what it came from. */
1248
- routineId: string;
1249
- setup: RoutineVersionSetup;
1250
- owner: SharedRoutineOwner;
1251
- source: SharedRoutineSource;
1252
- /** When the routine was last changed, not when it was shared. */
1253
- updatedAt: IsoDateString;
1511
+ /** Stable successful response of GET /moderation/queue. */
1512
+ interface ModerationQueueResponse {
1513
+ reports: ModerationReport[];
1514
+ nextCursor: string | null;
1515
+ /** Open reports in total, independent of the page or the filter. */
1516
+ openCount: number;
1254
1517
  }
1255
1518
  /**
1256
- * ROUT-06. Where a cloned routine came from. It is recorded on the clone and
1257
- * never on the source, so a routine cannot learn who copied it. It is served
1258
- * only to a viewer who could read the source anyway: lineage must not become
1259
- * a way to discover that a private routine exists.
1519
+ * One enforcement record. It is written once and never updated or deleted —
1520
+ * including when a hide is undone, which appends a `RESTORE_SUBJECT` record
1521
+ * rather than editing the `HIDE_SUBJECT` one.
1260
1522
  */
1261
- interface RoutineLineage {
1262
- /** The routine this one was cloned from, when the viewer may read it. */
1263
- sourceRoutineId: string | null;
1264
- /** The original author's public identity, when they still have one. */
1265
- author: SharedRoutineOwner | null;
1266
- /**
1267
- * True when the source exists but this viewer may not read it, or its author
1268
- * is gone. The clone still says it was cloned; it just cannot say from what.
1269
- */
1270
- isSourceHidden: boolean;
1271
- clonedAt: IsoDateString;
1523
+ interface ModerationActionRecord {
1524
+ id: string;
1525
+ kind: ModerationActionKind;
1526
+ moderator: UserSearchResponse;
1527
+ /** The report the action was taken from, when it was taken from one. */
1528
+ reportId: string | null;
1529
+ subjectKind: ReportSubjectKind;
1530
+ subjectId: string;
1531
+ note: string | null;
1532
+ createdAt: IsoDateString;
1272
1533
  }
1273
- /** A routine in a member's visible list, without loading its whole setup. */
1274
- interface SharedRoutineSummary {
1275
- routineId: string;
1276
- name: string;
1277
- description: string | null;
1278
- scheduleMode: RoutineScheduleMode;
1279
- dayCount: number;
1280
- exerciseCount: number;
1281
- updatedAt: IsoDateString;
1534
+ interface ModerationHistoryQuery {
1535
+ cursor?: string;
1536
+ limit?: number;
1537
+ /** Narrow to one subject's records, newest first. */
1538
+ subjectKind?: ReportSubjectKind;
1539
+ subjectId?: string;
1282
1540
  }
1283
- /** Stable successful response of GET /users/:identifier/routines. */
1284
- interface MemberRoutinesResponse {
1285
- routines: SharedRoutineSummary[];
1541
+ /** Stable successful response of GET /moderation/actions. */
1542
+ interface ModerationHistoryResponse {
1543
+ actions: ModerationActionRecord[];
1544
+ nextCursor: string | null;
1286
1545
  }
1287
1546
  /**
1288
- * POST /routines/clones. Exactly one source, matching the two ways a routine
1289
- * can be read: `token` for a private link, `routineId` for one the viewer may
1290
- * already see. Sending both, or neither, is refused.
1547
+ * POST /moderation/reports/:id/dismiss, /hide and /restore. The note is the
1548
+ * reviewer's own record of why; it is never shown to the reporter or to the
1549
+ * subject's owner, because neither is promised an explanation.
1291
1550
  */
1292
- interface CloneRoutineRequest {
1293
- /** The `/shared/routines/:token` link the reader followed. */
1294
- token?: string;
1295
- /** A routine the viewer may read under `ROUT-04` visibility. */
1296
- routineId?: string;
1551
+ interface ReviewReportRequest {
1552
+ note?: string | null;
1553
+ }
1554
+ /** Stable successful response of every review action, including a view. */
1555
+ interface ReviewReportResponse {
1556
+ report: ModerationReport;
1557
+ action: ModerationActionRecord;
1297
1558
  }
1298
- /** The refusals a clone states by name rather than as a bare 4xx. */
1299
- declare const CLONE_ROUTINE_REFUSALS: {
1300
- /** Neither `token` nor `routineId`, or both at once. */
1301
- readonly SOURCE_REQUIRED: "SOURCE_REQUIRED";
1302
- /** An exercise the routine programs is no longer in the catalog. */
1303
- readonly UNKNOWN_EXERCISE: "UNKNOWN_EXERCISE";
1304
- };
1305
- type CloneRoutineRefusal = (typeof CLONE_ROUTINE_REFUSALS)[keyof typeof CLONE_ROUTINE_REFUSALS];
1306
1559
 
1307
1560
  declare const USERNAME_MIN_LENGTH = 3;
1308
1561
  declare const USERNAME_MAX_LENGTH = 30;
@@ -1698,128 +1951,6 @@ interface PersonalGoalsResponse {
1698
1951
  goals: PersonalGoalProgress[];
1699
1952
  }
1700
1953
 
1701
- /** A local calendar date, YYYY-MM-DD. */
1702
- type CalendarDate = string;
1703
- /**
1704
- * The schedule-instance model: per-date overrides of a routine's plan. MOVE
1705
- * puts one weekly occurrence on another date (SCHED-04); SKIP marks it
1706
- * skipped on purpose (SCHED-05). Overrides are kept by calendar date, not by
1707
- * routine day, because routine edits replace the days.
1708
- */
1709
- declare const SCHEDULE_OVERRIDE_KINDS: readonly ["MOVE", "SKIP"];
1710
- type ScheduleOverrideKind = (typeof SCHEDULE_OVERRIDE_KINDS)[number];
1711
- /** A move goes at most this many days before or after the planned date. */
1712
- declare const SCHEDULE_MOVE_MAX_DAYS = 6;
1713
- /**
1714
- * SCHED-05: a skip can explain a planned day up to this many days back;
1715
- * ahead, any planned day can be skipped.
1716
- */
1717
- declare const SCHEDULE_SKIP_PAST_DAYS = 6;
1718
- /** Overrides are read for at most this many days at once. */
1719
- declare const SCHEDULE_OVERRIDES_MAX_RANGE_DAYS = 62;
1720
- interface ScheduleOverride {
1721
- id: string;
1722
- routineId: string;
1723
- /** The planned date this override changes. */
1724
- date: CalendarDate;
1725
- kind: ScheduleOverrideKind;
1726
- /** MOVE: the date the occurrence now falls on; null for SKIP. */
1727
- toDate: CalendarDate | null;
1728
- createdAt: IsoDateString;
1729
- }
1730
- /**
1731
- * `GET /schedule/overrides?from&to`: the owner's overrides whose date or
1732
- * target falls in the range, both ends included.
1733
- */
1734
- interface ScheduleOverridesQuery {
1735
- from: CalendarDate;
1736
- to: CalendarDate;
1737
- }
1738
- interface ScheduleOverridesResponse {
1739
- overrides: ScheduleOverride[];
1740
- }
1741
- /** `PUT /schedule/overrides/move`: moves one occurrence, or moves it again. */
1742
- interface MoveOccurrenceRequest {
1743
- routineId: string;
1744
- date: CalendarDate;
1745
- toDate: CalendarDate;
1746
- }
1747
- /**
1748
- * `PUT /schedule/overrides/skip`: marks one occurrence skipped. A moved
1749
- * occurrence is skipped as a whole; undoing is `DELETE` like a move.
1750
- */
1751
- interface SkipOccurrenceRequest {
1752
- routineId: string;
1753
- date: CalendarDate;
1754
- }
1755
-
1756
- /** One routine may have this many current, non-overlapping planned blocks. */
1757
- declare const ROUTINE_TRAINING_BLOCKS_MAX = 24;
1758
- /** A started block keeps at most this many immutable revisions. */
1759
- declare const ROUTINE_TRAINING_BLOCK_REVISIONS_MAX = 20;
1760
- declare const ROUTINE_TRAINING_BLOCK_NAME_MAX = 60;
1761
- declare const ROUTINE_TRAINING_BLOCK_STATES: readonly ["FUTURE", "ACTIVE", "COMPLETE"];
1762
- type RoutineTrainingBlockState = (typeof ROUTINE_TRAINING_BLOCK_STATES)[number];
1763
- declare const ROUTINE_TRAINING_BLOCK_SOURCE_KINDS: readonly ["CURRENT_ROUTINE", "SAVED_VERSION"];
1764
- type RoutineTrainingBlockSourceKind = (typeof ROUTINE_TRAINING_BLOCK_SOURCE_KINDS)[number];
1765
- /**
1766
- * The origin is snapshotted so a later routine edit or ROUT-08 version
1767
- * deletion cannot change what this block says it was authored from.
1768
- */
1769
- interface RoutineTrainingBlockSource {
1770
- kind: RoutineTrainingBlockSourceKind;
1771
- versionId: string | null;
1772
- versionNumber: number | null;
1773
- versionName: string | null;
1774
- }
1775
- /** One immutable revision of a named, dated setup. */
1776
- interface RoutineTrainingBlockRevision {
1777
- id: string;
1778
- routineId: string;
1779
- /** Stable across every replacement of the same logical block. */
1780
- seriesId: string;
1781
- /** 1, 2, 3… inside the series. */
1782
- revision: number;
1783
- name: string;
1784
- startDate: CalendarDate;
1785
- endDate: CalendarDate;
1786
- setup: RoutineVersionSetup;
1787
- source: RoutineTrainingBlockSource;
1788
- createdAt: IsoDateString;
1789
- /** Null only on the current revision. */
1790
- supersededAt: IsoDateString | null;
1791
- }
1792
- /** A current block in the routine timeline. State is relative to `today`. */
1793
- interface RoutineTrainingBlock extends Omit<RoutineTrainingBlockRevision, 'supersededAt'> {
1794
- state: RoutineTrainingBlockState;
1795
- revisionCount: number;
1796
- }
1797
- /** `GET /routines/:id/training-blocks`, ordered by start date. */
1798
- interface RoutineTrainingBlocksResponse {
1799
- blocks: RoutineTrainingBlock[];
1800
- max: number;
1801
- revisionMax: number;
1802
- /** The owner's local date used to derive every state in this response. */
1803
- today: CalendarDate;
1804
- }
1805
- /** `GET /routines/:id/training-blocks/:blockId/revisions`, newest first. */
1806
- interface RoutineTrainingBlockRevisionsResponse {
1807
- seriesId: string;
1808
- revisions: RoutineTrainingBlockRevision[];
1809
- max: number;
1810
- }
1811
- /**
1812
- * `POST /routines/:id/training-blocks` and
1813
- * `PUT /routines/:id/training-blocks/:blockId`.
1814
- * Null or omission captures the routine as it exists at request time.
1815
- */
1816
- interface UpsertRoutineTrainingBlockRequest {
1817
- name: string;
1818
- startDate: CalendarDate;
1819
- endDate: CalendarDate;
1820
- sourceVersionId?: string | null;
1821
- }
1822
-
1823
1954
  /** Owner-declared, both optional. Undeclared is not a default, it is unknown. */
1824
1955
  interface RoutineClassification {
1825
1956
  goal?: TrainingGoal | null;
@@ -2871,4 +3002,4 @@ interface AccountExportV1 {
2871
3002
  /** The file name a download of the export is saved under. */
2872
3003
  declare function accountExportFileName(username: string, exportedAt: string): string;
2873
3004
 
2874
- export { ACCOUNT_EXPORT_FORMAT, ACCOUNT_EXPORT_VERSION, ACHIEVEMENT_CATEGORIES, ACHIEVEMENT_DEFINITIONS, ACTIVITY_CAPS, ACTIVITY_COMMENTS_PAGE_SIZE, ACTIVITY_COMMENTS_PER_DAY_MAX, ACTIVITY_COMMENT_MAX_LENGTH, ACTIVITY_DEFAULT_AUDIENCE, ACTIVITY_ENTRY_ID_MAX_LENGTH, ACTIVITY_FEED_FOLLOWED_MAX, ACTIVITY_PAGE_DEFAULT_LIMIT, ACTIVITY_PAGE_MAX_LIMIT, ACTIVITY_PREVIEW_AUDIENCES, ACTIVITY_REACTIONS, ACTIVITY_TYPES, ACTIVITY_TYPE_SECTIONS, type AccountExportGoal, type AccountExportMember, type AccountExportPersonalRecord, type AccountExportRoutine, type AccountExportScheduleOverride, type AccountExportTrainingEvent, type AccountExportTrainingLocation, type AccountExportV1, type AchievementActivity, type AchievementCategory, type AchievementCategoryProgress, type AchievementDefinition, type AchievementNotification, type AchievementUnlockedEventPayload, type AchievementsResponse, type ActivityAudience, type ActivityCap, type ActivityComment, type ActivityCommentNotification, type ActivityCommentSummary, type ActivityCommentsQuery, type ActivityCommentsResponse, type ActivityEntry, type ActivityEntrySharing, type ActivityFeedResponse, type ActivityLink, type ActivityPage, type ActivityPageQuery, type ActivityPreviewAudience, type ActivityPreviewQuery, type ActivityReaction, type ActivityReactionSummary, type ActivitySection, type ActivitySharingSettings, type ActivityType, type AppNotification, BLOCKED_MEMBERS_MAX, type BlockedMember, type BlockedMembersResponse, type Brand, CLONE_ROUTINE_REFUSALS, COMEBACK_MIN_INACTIVE_DAYS, COMEBACK_RECOGNITION_LIMIT, COMEBACK_REQUIRED_ACTIVE_DAYS, COMEBACK_SESSION_LOOKBACK, COMEBACK_WINDOW_DAYS, type CalendarDate, type CloneRoutineRefusal, type CloneRoutineRequest, type ComebackActivity, type ComebackRecognition, type ComebackRecognitionSummary, type CorrectSessionRequest, type CorrectSessionResponse, type CorrectSessionSetRequest, type CreateActivityCommentRequest, type CreateActivityCommentResponse, type CreateReportRequest, type CreateReportResponse, type CreateRoutineDayInput, type CreateRoutineExerciseInput, type CreateRoutineRequest, type CreateRoutineVersionRequest, type CreateSessionShareRequest, type DeleteAccountRequest, type DeleteAccountResponse, type DeleteActivityCommentResponse, type DeletePushSubscriptionRequest, type DiscoverableRoutine, EXERCISE_EQUIPMENT, EXERCISE_MECHANICS, type EarnedAchievement, type EarnedPersonalRecord, type Exercise, type ExerciseEquipment, type ExerciseId, type ExerciseMechanic, type ExercisePerformanceHistoryQuery, type ExercisePerformanceHistoryResponse, type ExercisePerformancePrescription, type ExercisePerformancePrescriptionSet, type ExercisePerformanceSession, type ExercisePerformanceSet, type ExercisePerformanceSummary, type ExercisePlateau, type ExerciseStrengthSummary, type ExerciseStrengthTrendPoint, type ExerciseStrengthTrendQuery, type ExerciseStrengthTrendResponse, FEATURED_PROFILE_ITEMS_MAX, FEATURED_PROFILE_ITEM_KINDS, FEATURED_PROFILE_REFERENCE_MAX_LENGTH, FOLLOW_SUGGESTIONS_DEFAULT_LIMIT, FOLLOW_SUGGESTIONS_MAX_LIMIT, FOLLOW_SUGGESTION_REASONS, type FeaturedProfileAchievementItem, type FeaturedProfileItem, type FeaturedProfileItemKind, type FeaturedProfileRankItem, type FeaturedProfileRecordItem, type FeaturedProfileRoutineItem, type FeaturedProfileSelection, type FeaturedProfileSelectionInput, type FeaturedProfileSelectionsResponse, type FinishStatus, type FinishWorkoutRequest, type FinishWorkoutResponse, type FollowSuggestion, type FollowSuggestionReason, type FollowSuggestionsResponse, type IsoDateString, type ListSessionsParams, MEASURABLE_GOALS_MAX, MEASURABLE_GOAL_DIRECTIONS, MEASURABLE_GOAL_TYPES, MINUTES_IN_DAY, MODERATION_ACTION_KINDS, MODERATION_HISTORY_PAGE_SIZE, MODERATION_NOTE_MAX_LENGTH, MODERATION_QUEUE_PAGE_SIZE, MOVEMENT_PATTERNS, MUSCLE_GROUPS, type MarkNotificationsReadRequest, type MarkNotificationsReadResponse, type MeasurableGoal, type MeasurableGoalDirection, type MeasurableGoalExercise, type MeasurableGoalInput, type MeasurableGoalType, type MemberActivityResponse, type MemberModerationState, type MemberRoutinesResponse, type ModerationActionKind, type ModerationActionRecord, type ModerationHistoryQuery, type ModerationHistoryResponse, type ModerationQueueQuery, type ModerationQueueResponse, type ModerationReport, type ModeratorState, type MoveOccurrenceRequest, type MovementPattern, type MuscleGroup, type MuscleGroupHeatmapQuery, type MuscleGroupHeatmapResponse, type MuscleGroupHeatmapValue, type MuscleGroupHeatmapWeek, type MuscleVolumeTrendSeries, NOTIFICATIONS_LIST_LIMIT, NOTIFICATIONS_LOOKBACK_DAYS, NOTIFICATIONS_RETENTION_DAYS, NOTIFICATION_CATEGORIES, NOTIFICATION_KINDS, type NewFollowerNotification, type NotificationCategory, type NotificationKind, type NotificationPreferences, type NotificationPreferencesResponse, type NotificationsResponse, type OwnActivityEntry, type OwnActivityResponse, PLATEAU_MIN_DAYS_SINCE_BEST, PLATEAU_MIN_SESSIONS, PLATEAU_MIN_SESSIONS_MAX, PLATEAU_MIN_SESSIONS_MIN, PLATEAU_RECENT_DAYS, PLATEAU_WINDOW_DAYS, PREFERRED_TRAINING_STYLE_VALUES, PROFILE_BIO_MAX_LENGTH, PROFILE_FAVORITE_EXERCISES_MAX, PROFILE_LOCATION_MAX_LENGTH, PROFILE_TRAINING_DISCIPLINES_MAX, PROFILE_TRAINING_GOALS_MAX, PROFILE_VISIBILITY_VALUES, PROGRESSION_SCHEMES, PROGRESS_TIMELINE_EVENT_TYPES, PUSH_PAYLOAD_KINDS, PUSH_SUBSCRIPTIONS_MAX, type PaginatedResponse, type PersonalGoalProgress, type PersonalGoalsResponse, type PersonalRecordActivity, type PersonalRecordEntry, type PersonalRecordKind, type PlannedReminder, type PlatePairInventory, type PlateauPreferences, type PlateauSet, type PlateausResponse, type PreferredTrainingStyle, type PreviousPerformanceResponse, type PreviousSessionRecap, type PreviousSetPerformance, type ProfileDiscoverySettings, type ProfileFavoriteExercise, type ProfilePrivacySettings, type ProfileViewerAccess, type ProfileVisibility, type ProgressTimelineEventType, type ProgressTimelineItem, type ProgressTimelinePersonalRecordItem, type ProgressTimelineProgressionItem, type ProgressTimelineQuery, type ProgressTimelineRecordPerformance, type ProgressTimelineRecordReason, type ProgressTimelineResponse, type ProgressTimelineSessionContext, type ProgressionActivity, type ProgressionChange, type ProgressionRule, type ProgressionScheme, type ProgressionSetChange, type PublicBodyMetrics, type PublicProfileAchievements, type PublicTrainingSummary, type PublicUserProfile, type PushPayload, type PushPayloadKind, type PushSubscriptionKeys, type PushSubscriptionSummary, type PushSubscriptionsResponse, type QuietHours, RELATIONSHIP_LIST_DEFAULT_LIMIT, RELATIONSHIP_LIST_KINDS, RELATIONSHIP_LIST_MAX_LIMIT, RENAISSANCE_RANK_DEFINITIONS, REPORTS_PER_DAY_MAX, REPORT_DETAILS_MAX_LENGTH, REPORT_REASONS, REPORT_STATUSES, REPORT_SUBJECT_KINDS, REP_TYPES, RESERVED_USERNAMES, REST_ALERT_MAX_LEAD_SECONDS, REST_ALERT_MIN_LEAD_SECONDS, REST_ALERT_REFUSALS, ROUTINE_DAYS_MAX, ROUTINE_DAY_NAME_MAX, ROUTINE_DISCOVERY_DEFAULT_LIMIT, ROUTINE_DISCOVERY_MAX_LIMIT, ROUTINE_DISCOVERY_SCAN_LIMIT, ROUTINE_DURATION_BANDS, ROUTINE_DURATION_BAND_MAX_MINUTES, ROUTINE_SCHEDULE_MODES, ROUTINE_SHARE_MAX_ACTIVE_LINKS, ROUTINE_TRAINING_BLOCKS_MAX, ROUTINE_TRAINING_BLOCK_NAME_MAX, ROUTINE_TRAINING_BLOCK_REVISIONS_MAX, ROUTINE_TRAINING_BLOCK_SOURCE_KINDS, ROUTINE_TRAINING_BLOCK_STATES, ROUTINE_VERSIONS_MAX, ROUTINE_VERSION_KINDS, ROUTINE_VERSION_NAME_MAX, ROUTINE_VISIBILITY_VALUES, type RecentActivityEntry, type RegisterPushSubscriptionRequest, type RelationshipListKind, type RelationshipListQuery, type RelationshipListResponse, type RelationshipMember, type RenaissanceRankDefinition, type RenaissanceRankProgress, type RepType, type ReplaceFeaturedProfileItemsRequest, type ReplaceMeasurableGoalsRequest, type ReplaceTrainingLocationsRequest, type ReportReason, type ReportStatus, type ReportSubjectKind, type ReportSubjectPreview, type RestAlertPushPayload, type RestAlertRefusal, type RestoreRoutineVersionResponse, type ReviewReportRequest, type ReviewReportResponse, type Routine, type RoutineClassification, type RoutineDay, type RoutineDayId, type RoutineDiscoveryQuery, type RoutineDiscoveryResponse, type RoutineDurationBand, type RoutineExercise, type RoutineFacets, type RoutineId, type RoutineLineage, type RoutineScheduleMode, type RoutineSet, type RoutineShare, type RoutineShareListResponse, type RoutineSharedActivity, type RoutineTrainingBlock, type RoutineTrainingBlockRevision, type RoutineTrainingBlockRevisionsResponse, type RoutineTrainingBlockSource, type RoutineTrainingBlockSourceKind, type RoutineTrainingBlockState, type RoutineTrainingBlocksResponse, type RoutineVersion, type RoutineVersionDay, type RoutineVersionExercise, type RoutineVersionKind, type RoutineVersionSetup, type RoutineVersionsResponse, type RoutineVisibility, SCHEDULE_MOVE_MAX_DAYS, SCHEDULE_OVERRIDES_MAX_RANGE_DAYS, SCHEDULE_OVERRIDE_KINDS, SCHEDULE_SKIP_PAST_DAYS, SESSION_CORRECTIONS_MAX, SESSION_CORRECTION_LIMITS, SESSION_CORRECTION_WINDOW_HOURS, SESSION_SHARE_DEFAULT_FIELDS, SESSION_SHARE_FIELDS, SESSION_SHARE_MAX_ACTIVE_LINKS, SEXES, SHARED_ROUTINE_SOURCES, STARRED_EXERCISES_MAX, STREAK_MAX_GAP_DAYS, type ScheduleOverride, type ScheduleOverrideKind, type ScheduleOverridesQuery, type ScheduleOverridesResponse, type ScheduleRestAlertRequest, type ScheduleRestAlertResponse, type SendTrainingPartnerEncouragementRequest, type SendTrainingPartnerEncouragementResponse, type SessionComparisonExercise, type SessionComparisonQuery, type SessionComparisonResponse, type SessionComparisonRoutineDay, type SessionComparisonSession, type SessionComparisonSet, type SessionCompletedActivity, type SessionCorrection, type SessionCorrectionClosedReason, type SessionCorrectionWindow, type SessionCorrectionsResponse, type SessionExerciseSubstitution, type SessionProgressNotification, type SessionRecapRecord, type SessionSetCorrection, type SessionShare, type SessionShareField, type SessionShareListResponse, type SetAccountTimeZoneRequest, type SetActivityEntryAudienceRequest, type SetActivityEntryAudienceResponse, type SetActivityReactionRequest, type SetActivityReactionResponse, type SetLog, type SetLogValues, type Sex, type SharedRoutine, type SharedRoutineOwner, type SharedRoutineSource, type SharedRoutineSummary, type SharedSessionOwner, type SharedSessionRecap, type SkipOccurrenceRequest, type StarredExercise, type StarredExercisesResponse, type StartWorkoutRequest, type StartWorkoutResponse, type StreakAtRiskPushPayload, type StreakMilestoneActivity, type StreakMilestoneEventPayload, type SubstituteSessionExerciseRequest, type SubstituteSessionExerciseResponse, type SupabaseAuthResponse, type SupabaseAuthUser, type SupabaseMigrationResponse, TRAINING_DISCIPLINE_VALUES, TRAINING_EVENT_TYPES, TRAINING_EXPERIENCE_LEVEL_VALUES, TRAINING_GOAL_VALUES, TRAINING_PARTNERSHIP_STATUSES, TRAINING_PARTNERS_MAX, TRAINING_PARTNER_ENCOURAGEMENTS_PER_24_HOURS_MAX, TRAINING_PARTNER_ENCOURAGEMENT_KINDS, TRAINING_PARTNER_PERMISSION_KEYS, TRAINING_PARTNER_REQUESTS_PER_DAY_MAX, type TrainingDiscipline, type TrainingEventType, type TrainingExperienceLevel, type TrainingGoal, type TrainingIdentity, type TrainingLocationPreference, type TrainingLocationPreferenceInput, type TrainingPartnerEncouragementKind, type TrainingPartnerEncouragementNotification, type TrainingPartnerPermissions, type TrainingPartnerScheduleDay, type TrainingPartnerScheduleResponse, type TrainingPartnership, type TrainingPartnershipStatus, type TrainingPartnershipsResponse, type TrainingReminderPreference, type TrainingReminderPushPayload, USERNAME_MAX_LENGTH, USERNAME_MIN_LENGTH, USERNAME_PATTERN_SOURCE, type UpdateActivitySharingRequest, type UpdateNotificationPreferencesRequest, type UpdateProfileDiscoveryRequest, type UpdateProfilePrivacyRequest, type UpdateProfileRequest, type UpdateRoutineRequest, type UpdateRoutineVisibilityRequest, type UpdateTrainingPartnerPermissionsRequest, type UpsertRoutineTrainingBlockRequest, type UpsertSetLogRequest, type UpsertSetLogResponse, type UserId, type UserProfile, type UserSearchResponse, type VolumeTrendPoint, type VolumeTrendQuery, type VolumeTrendResponse, type VolumeTrendSeries, WEIGHT_UNITS, WORKOUT_SESSION_STATUSES, type WeightUnit, type WorkoutAnalyticsStatus, type WorkoutProgressQuery, type WorkoutProgressResponse, type WorkoutSession, type WorkoutSessionId, type WorkoutSessionListResponse, type WorkoutSessionRecap, type WorkoutSessionSnapshotV1, type WorkoutSessionStatus, type WorkoutSessionSummary, type WorkoutStatsQuery, type WorkoutStatsResponse, accountExportFileName, isWithinQuietHours, matchesDeletionConfirmation, routineDayLabel, sessionCorrectionWindow, setLogValuesDiffer };
3005
+ export { ACCOUNT_EXPORT_FORMAT, ACCOUNT_EXPORT_VERSION, ACHIEVEMENT_CATEGORIES, ACHIEVEMENT_DEFINITIONS, ACTIVITY_CAPS, ACTIVITY_COMMENTS_PAGE_SIZE, ACTIVITY_COMMENTS_PER_DAY_MAX, ACTIVITY_COMMENT_MAX_LENGTH, ACTIVITY_DEFAULT_AUDIENCE, ACTIVITY_ENTRY_ID_MAX_LENGTH, ACTIVITY_FEED_FOLLOWED_MAX, ACTIVITY_PAGE_DEFAULT_LIMIT, ACTIVITY_PAGE_MAX_LIMIT, ACTIVITY_PREVIEW_AUDIENCES, ACTIVITY_REACTIONS, ACTIVITY_TYPES, ACTIVITY_TYPE_SECTIONS, type AccountExportGoal, type AccountExportMember, type AccountExportPersonalRecord, type AccountExportRoutine, type AccountExportScheduleOverride, type AccountExportTrainingEvent, type AccountExportTrainingLocation, type AccountExportV1, type AchievementActivity, type AchievementCategory, type AchievementCategoryProgress, type AchievementDefinition, type AchievementNotification, type AchievementUnlockedEventPayload, type AchievementsResponse, type ActivityAudience, type ActivityCap, type ActivityComment, type ActivityCommentNotification, type ActivityCommentSummary, type ActivityCommentsQuery, type ActivityCommentsResponse, type ActivityEntry, type ActivityEntrySharing, type ActivityFeedResponse, type ActivityLink, type ActivityPage, type ActivityPageQuery, type ActivityPreviewAudience, type ActivityPreviewQuery, type ActivityReaction, type ActivityReactionSummary, type ActivitySection, type ActivitySharingSettings, type ActivityType, type AppNotification, BLOCKED_MEMBERS_MAX, type BlockedMember, type BlockedMembersResponse, type Brand, CLONE_ROUTINE_REFUSALS, COMEBACK_MIN_INACTIVE_DAYS, COMEBACK_RECOGNITION_LIMIT, COMEBACK_REQUIRED_ACTIVE_DAYS, COMEBACK_SESSION_LOOKBACK, COMEBACK_WINDOW_DAYS, type CalendarDate, type CloneRoutineRefusal, type CloneRoutineRequest, type ComebackActivity, type ComebackRecognition, type ComebackRecognitionSummary, type CorrectSessionRequest, type CorrectSessionResponse, type CorrectSessionSetRequest, type CreateActivityCommentRequest, type CreateActivityCommentResponse, type CreateReportRequest, type CreateReportResponse, type CreateRoutineDayInput, type CreateRoutineExerciseInput, type CreateRoutineRequest, type CreateRoutineVersionRequest, type CreateSessionShareRequest, type DeleteAccountRequest, type DeleteAccountResponse, type DeleteActivityCommentResponse, type DeletePushSubscriptionRequest, type DiscoverableRoutine, EXERCISE_EQUIPMENT, EXERCISE_MECHANICS, type EarnedAchievement, type EarnedPersonalRecord, type Exercise, type ExerciseEquipment, type ExerciseId, type ExerciseMechanic, type ExercisePerformanceHistoryQuery, type ExercisePerformanceHistoryResponse, type ExercisePerformancePrescription, type ExercisePerformancePrescriptionSet, type ExercisePerformanceSession, type ExercisePerformanceSet, type ExercisePerformanceSummary, type ExercisePlateau, type ExerciseStrengthSummary, type ExerciseStrengthTrendPoint, type ExerciseStrengthTrendQuery, type ExerciseStrengthTrendResponse, FEATURED_PROFILE_ITEMS_MAX, FEATURED_PROFILE_ITEM_KINDS, FEATURED_PROFILE_REFERENCE_MAX_LENGTH, FOLLOW_SUGGESTIONS_DEFAULT_LIMIT, FOLLOW_SUGGESTIONS_MAX_LIMIT, FOLLOW_SUGGESTION_REASONS, type FeaturedProfileAchievementItem, type FeaturedProfileItem, type FeaturedProfileItemKind, type FeaturedProfileRankItem, type FeaturedProfileRecordItem, type FeaturedProfileRoutineItem, type FeaturedProfileSelection, type FeaturedProfileSelectionInput, type FeaturedProfileSelectionsResponse, type FinishStatus, type FinishWorkoutRequest, type FinishWorkoutResponse, type FollowSuggestion, type FollowSuggestionReason, type FollowSuggestionsResponse, type IsoDateString, type ListSessionsParams, MEASURABLE_GOALS_MAX, MEASURABLE_GOAL_DIRECTIONS, MEASURABLE_GOAL_TYPES, MINUTES_IN_DAY, MODERATION_ACTION_KINDS, MODERATION_HISTORY_PAGE_SIZE, MODERATION_NOTE_MAX_LENGTH, MODERATION_QUEUE_PAGE_SIZE, MOVEMENT_PATTERNS, MUSCLE_GROUPS, type MarkNotificationsReadRequest, type MarkNotificationsReadResponse, type MeasurableGoal, type MeasurableGoalDirection, type MeasurableGoalExercise, type MeasurableGoalInput, type MeasurableGoalType, type MemberActivityResponse, type MemberModerationState, type MemberRoutinesResponse, type ModerationActionKind, type ModerationActionRecord, type ModerationHistoryQuery, type ModerationHistoryResponse, type ModerationQueueQuery, type ModerationQueueResponse, type ModerationReport, type ModeratorState, type MoveOccurrenceRequest, type MovementPattern, type MuscleGroup, type MuscleGroupHeatmapQuery, type MuscleGroupHeatmapResponse, type MuscleGroupHeatmapValue, type MuscleGroupHeatmapWeek, type MuscleVolumeTrendSeries, NOTIFICATIONS_LIST_LIMIT, NOTIFICATIONS_LOOKBACK_DAYS, NOTIFICATIONS_RETENTION_DAYS, NOTIFICATION_CATEGORIES, NOTIFICATION_KINDS, type NewFollowerNotification, type NotificationCategory, type NotificationKind, type NotificationPreferences, type NotificationPreferencesResponse, type NotificationsResponse, type OwnActivityEntry, type OwnActivityResponse, PLATEAU_MIN_DAYS_SINCE_BEST, PLATEAU_MIN_SESSIONS, PLATEAU_MIN_SESSIONS_MAX, PLATEAU_MIN_SESSIONS_MIN, PLATEAU_RECENT_DAYS, PLATEAU_WINDOW_DAYS, PREFERRED_TRAINING_STYLE_VALUES, PROFILE_BIO_MAX_LENGTH, PROFILE_FAVORITE_EXERCISES_MAX, PROFILE_LOCATION_MAX_LENGTH, PROFILE_TRAINING_DISCIPLINES_MAX, PROFILE_TRAINING_GOALS_MAX, PROFILE_VISIBILITY_VALUES, PROGRESSION_SCHEMES, PROGRESS_TIMELINE_EVENT_TYPES, PUSH_PAYLOAD_KINDS, PUSH_SUBSCRIPTIONS_MAX, type PaginatedResponse, type PersonalGoalProgress, type PersonalGoalsResponse, type PersonalRecordActivity, type PersonalRecordEntry, type PersonalRecordKind, type PlannedReminder, type PlatePairInventory, type PlateauPreferences, type PlateauSet, type PlateausResponse, type PreferredTrainingStyle, type PreviousPerformanceResponse, type PreviousSessionRecap, type PreviousSetPerformance, type ProfileDiscoverySettings, type ProfileFavoriteExercise, type ProfilePrivacySettings, type ProfileViewerAccess, type ProfileVisibility, type ProgressTimelineEventType, type ProgressTimelineItem, type ProgressTimelinePersonalRecordItem, type ProgressTimelineProgressionItem, type ProgressTimelineQuery, type ProgressTimelineRecordPerformance, type ProgressTimelineRecordReason, type ProgressTimelineResponse, type ProgressTimelineSessionContext, type ProgressionActivity, type ProgressionChange, type ProgressionRule, type ProgressionScheme, type ProgressionSetChange, type PublicBodyMetrics, type PublicProfileAchievements, type PublicTrainingSummary, type PublicUserProfile, type PushPayload, type PushPayloadKind, type PushSubscriptionKeys, type PushSubscriptionSummary, type PushSubscriptionsResponse, type QuietHours, RELATIONSHIP_LIST_DEFAULT_LIMIT, RELATIONSHIP_LIST_KINDS, RELATIONSHIP_LIST_MAX_LIMIT, RENAISSANCE_RANK_DEFINITIONS, REPORTS_PER_DAY_MAX, REPORT_DETAILS_MAX_LENGTH, REPORT_REASONS, REPORT_STATUSES, REPORT_SUBJECT_KINDS, REP_TYPES, RESERVED_USERNAMES, REST_ALERT_MAX_LEAD_SECONDS, REST_ALERT_MIN_LEAD_SECONDS, REST_ALERT_REFUSALS, ROUTINE_DAYS_MAX, ROUTINE_DAY_NAME_MAX, ROUTINE_DISCOVERY_DEFAULT_LIMIT, ROUTINE_DISCOVERY_MAX_LIMIT, ROUTINE_DISCOVERY_SCAN_LIMIT, ROUTINE_DURATION_BANDS, ROUTINE_DURATION_BAND_MAX_MINUTES, ROUTINE_SCHEDULE_MODES, ROUTINE_SHARE_MAX_ACTIVE_LINKS, ROUTINE_TRAINING_BLOCKS_MAX, ROUTINE_TRAINING_BLOCK_NAME_MAX, ROUTINE_TRAINING_BLOCK_REVISIONS_MAX, ROUTINE_TRAINING_BLOCK_SOURCE_KINDS, ROUTINE_TRAINING_BLOCK_STATES, ROUTINE_VERSIONS_MAX, ROUTINE_VERSION_KINDS, ROUTINE_VERSION_NAME_MAX, ROUTINE_VISIBILITY_VALUES, type RecentActivityEntry, type RegisterPushSubscriptionRequest, type RelationshipListKind, type RelationshipListQuery, type RelationshipListResponse, type RelationshipMember, type RenaissanceRankDefinition, type RenaissanceRankProgress, type RepType, type ReplaceFeaturedProfileItemsRequest, type ReplaceMeasurableGoalsRequest, type ReplaceTrainingLocationsRequest, type ReportReason, type ReportStatus, type ReportSubjectKind, type ReportSubjectPreview, type ResolvedRoutinePlan, type RestAlertPushPayload, type RestAlertRefusal, type RestoreRoutineVersionResponse, type ReviewReportRequest, type ReviewReportResponse, type Routine, type RoutineClassification, type RoutineDay, type RoutineDayId, type RoutineDiscoveryQuery, type RoutineDiscoveryResponse, type RoutineDurationBand, type RoutineExercise, type RoutineFacets, type RoutineId, type RoutineLineage, type RoutinePlanSource, type RoutineScheduleMode, type RoutineSet, type RoutineShare, type RoutineShareListResponse, type RoutineSharedActivity, type RoutineTrainingBlock, type RoutineTrainingBlockPlan, type RoutineTrainingBlockRevision, type RoutineTrainingBlockRevisionsResponse, type RoutineTrainingBlockSource, type RoutineTrainingBlockSourceKind, type RoutineTrainingBlockState, type RoutineTrainingBlocksResponse, type RoutineVersion, type RoutineVersionDay, type RoutineVersionExercise, type RoutineVersionKind, type RoutineVersionSetup, type RoutineVersionsResponse, type RoutineVisibility, SCHEDULE_MOVE_MAX_DAYS, SCHEDULE_OVERRIDES_MAX_RANGE_DAYS, SCHEDULE_OVERRIDE_KINDS, SCHEDULE_SKIP_PAST_DAYS, SESSION_CORRECTIONS_MAX, SESSION_CORRECTION_LIMITS, SESSION_CORRECTION_WINDOW_HOURS, SESSION_EXERCISE_NOTE_MAX_LENGTH, SESSION_NOTE_MAX_LENGTH, SESSION_SHARE_DEFAULT_FIELDS, SESSION_SHARE_FIELDS, SESSION_SHARE_MAX_ACTIVE_LINKS, SEXES, SHARED_ROUTINE_SOURCES, STARRED_EXERCISES_MAX, STREAK_MAX_GAP_DAYS, type ScheduleOverride, type ScheduleOverrideKind, type ScheduleOverridesQuery, type ScheduleOverridesResponse, type ScheduleRestAlertRequest, type ScheduleRestAlertResponse, type SendTrainingPartnerEncouragementRequest, type SendTrainingPartnerEncouragementResponse, type SessionComparisonExercise, type SessionComparisonQuery, type SessionComparisonResponse, type SessionComparisonRoutineDay, type SessionComparisonSession, type SessionComparisonSet, type SessionCompletedActivity, type SessionCorrection, type SessionCorrectionClosedReason, type SessionCorrectionWindow, type SessionCorrectionsResponse, type SessionExerciseNote, type SessionExerciseSubstitution, type SessionProgressNotification, type SessionRecapExerciseNote, type SessionRecapRecord, type SessionSetCorrection, type SessionShare, type SessionShareField, type SessionShareListResponse, type SessionTrainingBlock, type SetAccountTimeZoneRequest, type SetActivityEntryAudienceRequest, type SetActivityEntryAudienceResponse, type SetActivityReactionRequest, type SetActivityReactionResponse, type SetLog, type SetLogValues, type Sex, type SharedRoutine, type SharedRoutineOwner, type SharedRoutineSource, type SharedRoutineSummary, type SharedSessionOwner, type SharedSessionRecap, type SkipOccurrenceRequest, type StarredExercise, type StarredExercisesResponse, type StartWorkoutRequest, type StartWorkoutResponse, type StreakAtRiskPushPayload, type StreakMilestoneActivity, type StreakMilestoneEventPayload, type SubstituteSessionExerciseRequest, type SubstituteSessionExerciseResponse, type SupabaseAuthResponse, type SupabaseAuthUser, type SupabaseMigrationResponse, TRAINING_DISCIPLINE_VALUES, TRAINING_EVENT_TYPES, TRAINING_EXPERIENCE_LEVEL_VALUES, TRAINING_GOAL_VALUES, TRAINING_PARTNERSHIP_STATUSES, TRAINING_PARTNERS_MAX, TRAINING_PARTNER_ENCOURAGEMENTS_PER_24_HOURS_MAX, TRAINING_PARTNER_ENCOURAGEMENT_KINDS, TRAINING_PARTNER_PERMISSION_KEYS, TRAINING_PARTNER_REQUESTS_PER_DAY_MAX, type TrainingDiscipline, type TrainingEventType, type TrainingExperienceLevel, type TrainingGoal, type TrainingIdentity, type TrainingLocationPreference, type TrainingLocationPreferenceInput, type TrainingPartnerEncouragementKind, type TrainingPartnerEncouragementNotification, type TrainingPartnerPermissions, type TrainingPartnerScheduleDay, type TrainingPartnerScheduleResponse, type TrainingPartnership, type TrainingPartnershipStatus, type TrainingPartnershipsResponse, type TrainingReminderPreference, type TrainingReminderPushPayload, USERNAME_MAX_LENGTH, USERNAME_MIN_LENGTH, USERNAME_PATTERN_SOURCE, type UpdateActivitySharingRequest, type UpdateNotificationPreferencesRequest, type UpdateProfileDiscoveryRequest, type UpdateProfilePrivacyRequest, type UpdateProfileRequest, type UpdateRoutineRequest, type UpdateRoutineVisibilityRequest, type UpdateSessionNotesRequest, type UpdateSessionNotesResponse, type UpdateTrainingPartnerPermissionsRequest, type UpsertRoutineTrainingBlockRequest, type UpsertSetLogRequest, type UpsertSetLogResponse, type UserId, type UserProfile, type UserSearchResponse, type VolumeTrendPoint, type VolumeTrendQuery, type VolumeTrendResponse, type VolumeTrendSeries, WEIGHT_UNITS, WORKOUT_SESSION_STATUSES, type WeightUnit, type WorkoutAnalyticsStatus, type WorkoutProgressQuery, type WorkoutProgressResponse, type WorkoutSession, type WorkoutSessionId, type WorkoutSessionListResponse, type WorkoutSessionRecap, type WorkoutSessionSnapshotV1, type WorkoutSessionStatus, type WorkoutSessionSummary, type WorkoutStatsQuery, type WorkoutStatsResponse, accountExportFileName, isWithinQuietHours, matchesDeletionConfirmation, resolveActiveTrainingBlock, resolveRoutinePlan, routineDayLabel, sessionCorrectionWindow, setLogValuesDiffer, trainingBlockCovers };