endurance-coach 0.1.0 → 1.0.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/README.md +3 -0
- package/dist/cli.js +318 -35
- package/dist/expander/expander.d.ts +20 -0
- package/dist/expander/expander.js +339 -0
- package/dist/expander/index.d.ts +8 -0
- package/dist/expander/index.js +9 -0
- package/dist/expander/types.d.ts +169 -0
- package/dist/expander/types.js +6 -0
- package/dist/expander/zones.d.ts +50 -0
- package/dist/expander/zones.js +159 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +9 -1
- package/dist/schema/compact-plan.d.ts +175 -0
- package/dist/schema/compact-plan.js +64 -0
- package/dist/schema/compact-plan.schema.d.ts +277 -0
- package/dist/schema/compact-plan.schema.js +205 -0
- package/dist/templates/index.d.ts +10 -0
- package/dist/templates/index.js +13 -0
- package/dist/templates/interpolate.d.ts +51 -0
- package/dist/templates/interpolate.js +204 -0
- package/dist/templates/loader.d.ts +19 -0
- package/dist/templates/loader.js +129 -0
- package/dist/templates/template.schema.d.ts +401 -0
- package/dist/templates/template.schema.js +101 -0
- package/dist/templates/template.types.d.ts +155 -0
- package/dist/templates/template.types.js +7 -0
- package/dist/templates/yaml-parser.d.ts +15 -0
- package/dist/templates/yaml-parser.js +18 -0
- package/package.json +2 -1
- package/templates/bike/CLAUDE.md +7 -0
- package/templates/bike/easy.yaml +38 -0
- package/templates/bike/endurance.yaml +42 -0
- package/templates/bike/hills.yaml +80 -0
- package/templates/bike/overunders.yaml +81 -0
- package/templates/bike/rest.yaml +16 -0
- package/templates/bike/sweetspot.yaml +80 -0
- package/templates/bike/tempo.yaml +79 -0
- package/templates/bike/threshold.yaml +83 -0
- package/templates/bike/vo2max.yaml +84 -0
- package/templates/brick/CLAUDE.md +7 -0
- package/templates/brick/halfironman.yaml +72 -0
- package/templates/brick/ironman.yaml +72 -0
- package/templates/brick/olympic.yaml +70 -0
- package/templates/brick/sprint.yaml +70 -0
- package/templates/plan-viewer.html +22 -22
- package/templates/run/CLAUDE.md +7 -0
- package/templates/run/easy.yaml +36 -0
- package/templates/run/fartlek.yaml +40 -0
- package/templates/run/hills.yaml +36 -0
- package/templates/run/intervals.1k.yaml +63 -0
- package/templates/run/intervals.400.yaml +63 -0
- package/templates/run/intervals.800.yaml +63 -0
- package/templates/run/intervals.mile.yaml +64 -0
- package/templates/run/long.yaml +41 -0
- package/templates/run/progression.yaml +49 -0
- package/templates/run/race.5k.yaml +36 -0
- package/templates/run/recovery.yaml +36 -0
- package/templates/run/rest.yaml +16 -0
- package/templates/run/strides.yaml +49 -0
- package/templates/run/tempo.yaml +56 -0
- package/templates/run/threshold.yaml +56 -0
- package/templates/strength/CLAUDE.md +7 -0
- package/templates/strength/core.yaml +56 -0
- package/templates/strength/foundation.yaml +65 -0
- package/templates/strength/full.yaml +73 -0
- package/templates/strength/maintenance.yaml +62 -0
- package/templates/swim/CLAUDE.md +7 -0
- package/templates/swim/aerobic.yaml +67 -0
- package/templates/swim/easy.yaml +51 -0
- package/templates/swim/openwater.yaml +60 -0
- package/templates/swim/rest.yaml +16 -0
- package/templates/swim/technique.yaml +67 -0
- package/templates/swim/threshold.yaml +75 -0
- package/templates/swim/vo2max.yaml +88 -0
- /package/bin/{claude-coach.js → endurance-coach.js} +0 -0
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workout Template Zod Schema
|
|
3
|
+
*
|
|
4
|
+
* Runtime validation for workout template definitions.
|
|
5
|
+
*/
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
export declare const SportSchema: z.ZodEnum<{
|
|
8
|
+
swim: "swim";
|
|
9
|
+
bike: "bike";
|
|
10
|
+
run: "run";
|
|
11
|
+
strength: "strength";
|
|
12
|
+
brick: "brick";
|
|
13
|
+
race: "race";
|
|
14
|
+
rest: "rest";
|
|
15
|
+
}>;
|
|
16
|
+
export declare const ParamTypeSchema: z.ZodEnum<{
|
|
17
|
+
string: "string";
|
|
18
|
+
number: "number";
|
|
19
|
+
duration: "duration";
|
|
20
|
+
int: "int";
|
|
21
|
+
distance: "distance";
|
|
22
|
+
}>;
|
|
23
|
+
export declare const StepTypeSchema: z.ZodEnum<{
|
|
24
|
+
rest: "rest";
|
|
25
|
+
warmup: "warmup";
|
|
26
|
+
work: "work";
|
|
27
|
+
recovery: "recovery";
|
|
28
|
+
cooldown: "cooldown";
|
|
29
|
+
}>;
|
|
30
|
+
export declare const WorkoutCategorySchema: z.ZodEnum<{
|
|
31
|
+
strength: "strength";
|
|
32
|
+
race: "race";
|
|
33
|
+
rest: "rest";
|
|
34
|
+
recovery: "recovery";
|
|
35
|
+
threshold: "threshold";
|
|
36
|
+
endurance: "endurance";
|
|
37
|
+
tempo: "tempo";
|
|
38
|
+
intervals: "intervals";
|
|
39
|
+
technique: "technique";
|
|
40
|
+
hills: "hills";
|
|
41
|
+
speed: "speed";
|
|
42
|
+
}>;
|
|
43
|
+
export declare const TemplateParamSchema: z.ZodObject<{
|
|
44
|
+
type: z.ZodEnum<{
|
|
45
|
+
string: "string";
|
|
46
|
+
number: "number";
|
|
47
|
+
duration: "duration";
|
|
48
|
+
int: "int";
|
|
49
|
+
distance: "distance";
|
|
50
|
+
}>;
|
|
51
|
+
required: z.ZodOptional<z.ZodBoolean>;
|
|
52
|
+
default: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>;
|
|
53
|
+
min: z.ZodOptional<z.ZodNumber>;
|
|
54
|
+
max: z.ZodOptional<z.ZodNumber>;
|
|
55
|
+
description: z.ZodOptional<z.ZodString>;
|
|
56
|
+
}, z.core.$strip>;
|
|
57
|
+
export declare const TemplateParamsSchema: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
58
|
+
type: z.ZodEnum<{
|
|
59
|
+
string: "string";
|
|
60
|
+
number: "number";
|
|
61
|
+
duration: "duration";
|
|
62
|
+
int: "int";
|
|
63
|
+
distance: "distance";
|
|
64
|
+
}>;
|
|
65
|
+
required: z.ZodOptional<z.ZodBoolean>;
|
|
66
|
+
default: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>;
|
|
67
|
+
min: z.ZodOptional<z.ZodNumber>;
|
|
68
|
+
max: z.ZodOptional<z.ZodNumber>;
|
|
69
|
+
description: z.ZodOptional<z.ZodString>;
|
|
70
|
+
}, z.core.$strip>>;
|
|
71
|
+
export declare const TemplateStepSchema: z.ZodObject<{
|
|
72
|
+
type: z.ZodEnum<{
|
|
73
|
+
rest: "rest";
|
|
74
|
+
warmup: "warmup";
|
|
75
|
+
work: "work";
|
|
76
|
+
recovery: "recovery";
|
|
77
|
+
cooldown: "cooldown";
|
|
78
|
+
}>;
|
|
79
|
+
name: z.ZodOptional<z.ZodString>;
|
|
80
|
+
duration: z.ZodOptional<z.ZodString>;
|
|
81
|
+
distance: z.ZodOptional<z.ZodString>;
|
|
82
|
+
pace: z.ZodOptional<z.ZodString>;
|
|
83
|
+
intensity: z.ZodOptional<z.ZodString>;
|
|
84
|
+
description: z.ZodOptional<z.ZodString>;
|
|
85
|
+
}, z.core.$strip>;
|
|
86
|
+
export declare const TemplateIntervalSetSchema: z.ZodObject<{
|
|
87
|
+
type: z.ZodLiteral<"intervals">;
|
|
88
|
+
repeats: z.ZodString;
|
|
89
|
+
work: z.ZodObject<{
|
|
90
|
+
type: z.ZodEnum<{
|
|
91
|
+
rest: "rest";
|
|
92
|
+
warmup: "warmup";
|
|
93
|
+
work: "work";
|
|
94
|
+
recovery: "recovery";
|
|
95
|
+
cooldown: "cooldown";
|
|
96
|
+
}>;
|
|
97
|
+
name: z.ZodOptional<z.ZodString>;
|
|
98
|
+
duration: z.ZodOptional<z.ZodString>;
|
|
99
|
+
distance: z.ZodOptional<z.ZodString>;
|
|
100
|
+
pace: z.ZodOptional<z.ZodString>;
|
|
101
|
+
intensity: z.ZodOptional<z.ZodString>;
|
|
102
|
+
description: z.ZodOptional<z.ZodString>;
|
|
103
|
+
}, z.core.$strip>;
|
|
104
|
+
recovery: z.ZodObject<{
|
|
105
|
+
type: z.ZodEnum<{
|
|
106
|
+
rest: "rest";
|
|
107
|
+
warmup: "warmup";
|
|
108
|
+
work: "work";
|
|
109
|
+
recovery: "recovery";
|
|
110
|
+
cooldown: "cooldown";
|
|
111
|
+
}>;
|
|
112
|
+
name: z.ZodOptional<z.ZodString>;
|
|
113
|
+
duration: z.ZodOptional<z.ZodString>;
|
|
114
|
+
distance: z.ZodOptional<z.ZodString>;
|
|
115
|
+
pace: z.ZodOptional<z.ZodString>;
|
|
116
|
+
intensity: z.ZodOptional<z.ZodString>;
|
|
117
|
+
description: z.ZodOptional<z.ZodString>;
|
|
118
|
+
}, z.core.$strip>;
|
|
119
|
+
}, z.core.$strip>;
|
|
120
|
+
export declare const MainSetElementSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
121
|
+
type: z.ZodEnum<{
|
|
122
|
+
rest: "rest";
|
|
123
|
+
warmup: "warmup";
|
|
124
|
+
work: "work";
|
|
125
|
+
recovery: "recovery";
|
|
126
|
+
cooldown: "cooldown";
|
|
127
|
+
}>;
|
|
128
|
+
name: z.ZodOptional<z.ZodString>;
|
|
129
|
+
duration: z.ZodOptional<z.ZodString>;
|
|
130
|
+
distance: z.ZodOptional<z.ZodString>;
|
|
131
|
+
pace: z.ZodOptional<z.ZodString>;
|
|
132
|
+
intensity: z.ZodOptional<z.ZodString>;
|
|
133
|
+
description: z.ZodOptional<z.ZodString>;
|
|
134
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
135
|
+
type: z.ZodLiteral<"intervals">;
|
|
136
|
+
repeats: z.ZodString;
|
|
137
|
+
work: z.ZodObject<{
|
|
138
|
+
type: z.ZodEnum<{
|
|
139
|
+
rest: "rest";
|
|
140
|
+
warmup: "warmup";
|
|
141
|
+
work: "work";
|
|
142
|
+
recovery: "recovery";
|
|
143
|
+
cooldown: "cooldown";
|
|
144
|
+
}>;
|
|
145
|
+
name: z.ZodOptional<z.ZodString>;
|
|
146
|
+
duration: z.ZodOptional<z.ZodString>;
|
|
147
|
+
distance: z.ZodOptional<z.ZodString>;
|
|
148
|
+
pace: z.ZodOptional<z.ZodString>;
|
|
149
|
+
intensity: z.ZodOptional<z.ZodString>;
|
|
150
|
+
description: z.ZodOptional<z.ZodString>;
|
|
151
|
+
}, z.core.$strip>;
|
|
152
|
+
recovery: z.ZodObject<{
|
|
153
|
+
type: z.ZodEnum<{
|
|
154
|
+
rest: "rest";
|
|
155
|
+
warmup: "warmup";
|
|
156
|
+
work: "work";
|
|
157
|
+
recovery: "recovery";
|
|
158
|
+
cooldown: "cooldown";
|
|
159
|
+
}>;
|
|
160
|
+
name: z.ZodOptional<z.ZodString>;
|
|
161
|
+
duration: z.ZodOptional<z.ZodString>;
|
|
162
|
+
distance: z.ZodOptional<z.ZodString>;
|
|
163
|
+
pace: z.ZodOptional<z.ZodString>;
|
|
164
|
+
intensity: z.ZodOptional<z.ZodString>;
|
|
165
|
+
description: z.ZodOptional<z.ZodString>;
|
|
166
|
+
}, z.core.$strip>;
|
|
167
|
+
}, z.core.$strip>]>;
|
|
168
|
+
export declare const TemplateStructureSchema: z.ZodObject<{
|
|
169
|
+
warmup: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
170
|
+
type: z.ZodEnum<{
|
|
171
|
+
rest: "rest";
|
|
172
|
+
warmup: "warmup";
|
|
173
|
+
work: "work";
|
|
174
|
+
recovery: "recovery";
|
|
175
|
+
cooldown: "cooldown";
|
|
176
|
+
}>;
|
|
177
|
+
name: z.ZodOptional<z.ZodString>;
|
|
178
|
+
duration: z.ZodOptional<z.ZodString>;
|
|
179
|
+
distance: z.ZodOptional<z.ZodString>;
|
|
180
|
+
pace: z.ZodOptional<z.ZodString>;
|
|
181
|
+
intensity: z.ZodOptional<z.ZodString>;
|
|
182
|
+
description: z.ZodOptional<z.ZodString>;
|
|
183
|
+
}, z.core.$strip>>>;
|
|
184
|
+
main: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
185
|
+
type: z.ZodEnum<{
|
|
186
|
+
rest: "rest";
|
|
187
|
+
warmup: "warmup";
|
|
188
|
+
work: "work";
|
|
189
|
+
recovery: "recovery";
|
|
190
|
+
cooldown: "cooldown";
|
|
191
|
+
}>;
|
|
192
|
+
name: z.ZodOptional<z.ZodString>;
|
|
193
|
+
duration: z.ZodOptional<z.ZodString>;
|
|
194
|
+
distance: z.ZodOptional<z.ZodString>;
|
|
195
|
+
pace: z.ZodOptional<z.ZodString>;
|
|
196
|
+
intensity: z.ZodOptional<z.ZodString>;
|
|
197
|
+
description: z.ZodOptional<z.ZodString>;
|
|
198
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
199
|
+
type: z.ZodLiteral<"intervals">;
|
|
200
|
+
repeats: z.ZodString;
|
|
201
|
+
work: z.ZodObject<{
|
|
202
|
+
type: z.ZodEnum<{
|
|
203
|
+
rest: "rest";
|
|
204
|
+
warmup: "warmup";
|
|
205
|
+
work: "work";
|
|
206
|
+
recovery: "recovery";
|
|
207
|
+
cooldown: "cooldown";
|
|
208
|
+
}>;
|
|
209
|
+
name: z.ZodOptional<z.ZodString>;
|
|
210
|
+
duration: z.ZodOptional<z.ZodString>;
|
|
211
|
+
distance: z.ZodOptional<z.ZodString>;
|
|
212
|
+
pace: z.ZodOptional<z.ZodString>;
|
|
213
|
+
intensity: z.ZodOptional<z.ZodString>;
|
|
214
|
+
description: z.ZodOptional<z.ZodString>;
|
|
215
|
+
}, z.core.$strip>;
|
|
216
|
+
recovery: z.ZodObject<{
|
|
217
|
+
type: z.ZodEnum<{
|
|
218
|
+
rest: "rest";
|
|
219
|
+
warmup: "warmup";
|
|
220
|
+
work: "work";
|
|
221
|
+
recovery: "recovery";
|
|
222
|
+
cooldown: "cooldown";
|
|
223
|
+
}>;
|
|
224
|
+
name: z.ZodOptional<z.ZodString>;
|
|
225
|
+
duration: z.ZodOptional<z.ZodString>;
|
|
226
|
+
distance: z.ZodOptional<z.ZodString>;
|
|
227
|
+
pace: z.ZodOptional<z.ZodString>;
|
|
228
|
+
intensity: z.ZodOptional<z.ZodString>;
|
|
229
|
+
description: z.ZodOptional<z.ZodString>;
|
|
230
|
+
}, z.core.$strip>;
|
|
231
|
+
}, z.core.$strip>]>>;
|
|
232
|
+
cooldown: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
233
|
+
type: z.ZodEnum<{
|
|
234
|
+
rest: "rest";
|
|
235
|
+
warmup: "warmup";
|
|
236
|
+
work: "work";
|
|
237
|
+
recovery: "recovery";
|
|
238
|
+
cooldown: "cooldown";
|
|
239
|
+
}>;
|
|
240
|
+
name: z.ZodOptional<z.ZodString>;
|
|
241
|
+
duration: z.ZodOptional<z.ZodString>;
|
|
242
|
+
distance: z.ZodOptional<z.ZodString>;
|
|
243
|
+
pace: z.ZodOptional<z.ZodString>;
|
|
244
|
+
intensity: z.ZodOptional<z.ZodString>;
|
|
245
|
+
description: z.ZodOptional<z.ZodString>;
|
|
246
|
+
}, z.core.$strip>>>;
|
|
247
|
+
}, z.core.$strip>;
|
|
248
|
+
export declare const WorkoutTemplateSchema: z.ZodObject<{
|
|
249
|
+
id: z.ZodString;
|
|
250
|
+
name: z.ZodString;
|
|
251
|
+
sport: z.ZodEnum<{
|
|
252
|
+
swim: "swim";
|
|
253
|
+
bike: "bike";
|
|
254
|
+
run: "run";
|
|
255
|
+
strength: "strength";
|
|
256
|
+
brick: "brick";
|
|
257
|
+
race: "race";
|
|
258
|
+
rest: "rest";
|
|
259
|
+
}>;
|
|
260
|
+
type: z.ZodString;
|
|
261
|
+
category: z.ZodEnum<{
|
|
262
|
+
strength: "strength";
|
|
263
|
+
race: "race";
|
|
264
|
+
rest: "rest";
|
|
265
|
+
recovery: "recovery";
|
|
266
|
+
threshold: "threshold";
|
|
267
|
+
endurance: "endurance";
|
|
268
|
+
tempo: "tempo";
|
|
269
|
+
intervals: "intervals";
|
|
270
|
+
technique: "technique";
|
|
271
|
+
hills: "hills";
|
|
272
|
+
speed: "speed";
|
|
273
|
+
}>;
|
|
274
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
275
|
+
type: z.ZodEnum<{
|
|
276
|
+
string: "string";
|
|
277
|
+
number: "number";
|
|
278
|
+
duration: "duration";
|
|
279
|
+
int: "int";
|
|
280
|
+
distance: "distance";
|
|
281
|
+
}>;
|
|
282
|
+
required: z.ZodOptional<z.ZodBoolean>;
|
|
283
|
+
default: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>;
|
|
284
|
+
min: z.ZodOptional<z.ZodNumber>;
|
|
285
|
+
max: z.ZodOptional<z.ZodNumber>;
|
|
286
|
+
description: z.ZodOptional<z.ZodString>;
|
|
287
|
+
}, z.core.$strip>>>;
|
|
288
|
+
structure: z.ZodOptional<z.ZodObject<{
|
|
289
|
+
warmup: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
290
|
+
type: z.ZodEnum<{
|
|
291
|
+
rest: "rest";
|
|
292
|
+
warmup: "warmup";
|
|
293
|
+
work: "work";
|
|
294
|
+
recovery: "recovery";
|
|
295
|
+
cooldown: "cooldown";
|
|
296
|
+
}>;
|
|
297
|
+
name: z.ZodOptional<z.ZodString>;
|
|
298
|
+
duration: z.ZodOptional<z.ZodString>;
|
|
299
|
+
distance: z.ZodOptional<z.ZodString>;
|
|
300
|
+
pace: z.ZodOptional<z.ZodString>;
|
|
301
|
+
intensity: z.ZodOptional<z.ZodString>;
|
|
302
|
+
description: z.ZodOptional<z.ZodString>;
|
|
303
|
+
}, z.core.$strip>>>;
|
|
304
|
+
main: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
305
|
+
type: z.ZodEnum<{
|
|
306
|
+
rest: "rest";
|
|
307
|
+
warmup: "warmup";
|
|
308
|
+
work: "work";
|
|
309
|
+
recovery: "recovery";
|
|
310
|
+
cooldown: "cooldown";
|
|
311
|
+
}>;
|
|
312
|
+
name: z.ZodOptional<z.ZodString>;
|
|
313
|
+
duration: z.ZodOptional<z.ZodString>;
|
|
314
|
+
distance: z.ZodOptional<z.ZodString>;
|
|
315
|
+
pace: z.ZodOptional<z.ZodString>;
|
|
316
|
+
intensity: z.ZodOptional<z.ZodString>;
|
|
317
|
+
description: z.ZodOptional<z.ZodString>;
|
|
318
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
319
|
+
type: z.ZodLiteral<"intervals">;
|
|
320
|
+
repeats: z.ZodString;
|
|
321
|
+
work: z.ZodObject<{
|
|
322
|
+
type: z.ZodEnum<{
|
|
323
|
+
rest: "rest";
|
|
324
|
+
warmup: "warmup";
|
|
325
|
+
work: "work";
|
|
326
|
+
recovery: "recovery";
|
|
327
|
+
cooldown: "cooldown";
|
|
328
|
+
}>;
|
|
329
|
+
name: z.ZodOptional<z.ZodString>;
|
|
330
|
+
duration: z.ZodOptional<z.ZodString>;
|
|
331
|
+
distance: z.ZodOptional<z.ZodString>;
|
|
332
|
+
pace: z.ZodOptional<z.ZodString>;
|
|
333
|
+
intensity: z.ZodOptional<z.ZodString>;
|
|
334
|
+
description: z.ZodOptional<z.ZodString>;
|
|
335
|
+
}, z.core.$strip>;
|
|
336
|
+
recovery: z.ZodObject<{
|
|
337
|
+
type: z.ZodEnum<{
|
|
338
|
+
rest: "rest";
|
|
339
|
+
warmup: "warmup";
|
|
340
|
+
work: "work";
|
|
341
|
+
recovery: "recovery";
|
|
342
|
+
cooldown: "cooldown";
|
|
343
|
+
}>;
|
|
344
|
+
name: z.ZodOptional<z.ZodString>;
|
|
345
|
+
duration: z.ZodOptional<z.ZodString>;
|
|
346
|
+
distance: z.ZodOptional<z.ZodString>;
|
|
347
|
+
pace: z.ZodOptional<z.ZodString>;
|
|
348
|
+
intensity: z.ZodOptional<z.ZodString>;
|
|
349
|
+
description: z.ZodOptional<z.ZodString>;
|
|
350
|
+
}, z.core.$strip>;
|
|
351
|
+
}, z.core.$strip>]>>;
|
|
352
|
+
cooldown: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
353
|
+
type: z.ZodEnum<{
|
|
354
|
+
rest: "rest";
|
|
355
|
+
warmup: "warmup";
|
|
356
|
+
work: "work";
|
|
357
|
+
recovery: "recovery";
|
|
358
|
+
cooldown: "cooldown";
|
|
359
|
+
}>;
|
|
360
|
+
name: z.ZodOptional<z.ZodString>;
|
|
361
|
+
duration: z.ZodOptional<z.ZodString>;
|
|
362
|
+
distance: z.ZodOptional<z.ZodString>;
|
|
363
|
+
pace: z.ZodOptional<z.ZodString>;
|
|
364
|
+
intensity: z.ZodOptional<z.ZodString>;
|
|
365
|
+
description: z.ZodOptional<z.ZodString>;
|
|
366
|
+
}, z.core.$strip>>>;
|
|
367
|
+
}, z.core.$strip>>;
|
|
368
|
+
humanReadable: z.ZodString;
|
|
369
|
+
estimatedDuration: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
|
|
370
|
+
targetZone: z.ZodOptional<z.ZodString>;
|
|
371
|
+
rpe: z.ZodOptional<z.ZodString>;
|
|
372
|
+
notes: z.ZodOptional<z.ZodString>;
|
|
373
|
+
}, z.core.$strip>;
|
|
374
|
+
export type TemplateValidationResult = {
|
|
375
|
+
success: true;
|
|
376
|
+
data: z.infer<typeof WorkoutTemplateSchema>;
|
|
377
|
+
} | {
|
|
378
|
+
success: false;
|
|
379
|
+
errors: TemplateValidationError[];
|
|
380
|
+
};
|
|
381
|
+
export interface TemplateValidationError {
|
|
382
|
+
path: string;
|
|
383
|
+
message: string;
|
|
384
|
+
code: string;
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Validate a workout template against the schema.
|
|
388
|
+
*/
|
|
389
|
+
export declare function validateTemplate(data: unknown): TemplateValidationResult;
|
|
390
|
+
/**
|
|
391
|
+
* Validate a template and throw an error if invalid.
|
|
392
|
+
*/
|
|
393
|
+
export declare function validateTemplateOrThrow(data: unknown): z.infer<typeof WorkoutTemplateSchema>;
|
|
394
|
+
export type WorkoutTemplate = z.infer<typeof WorkoutTemplateSchema>;
|
|
395
|
+
export type TemplateParam = z.infer<typeof TemplateParamSchema>;
|
|
396
|
+
export type TemplateParams = z.infer<typeof TemplateParamsSchema>;
|
|
397
|
+
export type TemplateStep = z.infer<typeof TemplateStepSchema>;
|
|
398
|
+
export type TemplateIntervalSet = z.infer<typeof TemplateIntervalSetSchema>;
|
|
399
|
+
export type TemplateStructure = z.infer<typeof TemplateStructureSchema>;
|
|
400
|
+
export type Sport = z.infer<typeof SportSchema>;
|
|
401
|
+
export type WorkoutCategory = z.infer<typeof WorkoutCategorySchema>;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workout Template Zod Schema
|
|
3
|
+
*
|
|
4
|
+
* Runtime validation for workout template definitions.
|
|
5
|
+
*/
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// Core Types
|
|
9
|
+
// ============================================================================
|
|
10
|
+
export const SportSchema = z.enum(["swim", "bike", "run", "strength", "brick", "race", "rest"]);
|
|
11
|
+
export const ParamTypeSchema = z.enum(["int", "number", "duration", "distance", "string"]);
|
|
12
|
+
export const StepTypeSchema = z.enum(["warmup", "work", "recovery", "rest", "cooldown"]);
|
|
13
|
+
export const WorkoutCategorySchema = z.enum([
|
|
14
|
+
"rest",
|
|
15
|
+
"recovery",
|
|
16
|
+
"endurance",
|
|
17
|
+
"tempo",
|
|
18
|
+
"threshold",
|
|
19
|
+
"intervals",
|
|
20
|
+
"speed",
|
|
21
|
+
"hills",
|
|
22
|
+
"race",
|
|
23
|
+
"strength",
|
|
24
|
+
"technique",
|
|
25
|
+
]);
|
|
26
|
+
// ============================================================================
|
|
27
|
+
// Template Parameters
|
|
28
|
+
// ============================================================================
|
|
29
|
+
export const TemplateParamSchema = z.object({
|
|
30
|
+
type: ParamTypeSchema,
|
|
31
|
+
required: z.boolean().optional(),
|
|
32
|
+
default: z.union([z.number(), z.string()]).optional(),
|
|
33
|
+
min: z.number().optional(),
|
|
34
|
+
max: z.number().optional(),
|
|
35
|
+
description: z.string().optional(),
|
|
36
|
+
});
|
|
37
|
+
export const TemplateParamsSchema = z.record(z.string(), TemplateParamSchema);
|
|
38
|
+
// ============================================================================
|
|
39
|
+
// Workout Structure
|
|
40
|
+
// ============================================================================
|
|
41
|
+
export const TemplateStepSchema = z.object({
|
|
42
|
+
type: StepTypeSchema,
|
|
43
|
+
name: z.string().optional(),
|
|
44
|
+
duration: z.string().optional(),
|
|
45
|
+
distance: z.string().optional(),
|
|
46
|
+
pace: z.string().optional(),
|
|
47
|
+
intensity: z.string().optional(),
|
|
48
|
+
description: z.string().optional(),
|
|
49
|
+
});
|
|
50
|
+
export const TemplateIntervalSetSchema = z.object({
|
|
51
|
+
type: z.literal("intervals"),
|
|
52
|
+
repeats: z.string(),
|
|
53
|
+
work: TemplateStepSchema,
|
|
54
|
+
recovery: TemplateStepSchema,
|
|
55
|
+
});
|
|
56
|
+
export const MainSetElementSchema = z.union([TemplateStepSchema, TemplateIntervalSetSchema]);
|
|
57
|
+
export const TemplateStructureSchema = z.object({
|
|
58
|
+
warmup: z.array(TemplateStepSchema).optional(),
|
|
59
|
+
main: z.array(MainSetElementSchema),
|
|
60
|
+
cooldown: z.array(TemplateStepSchema).optional(),
|
|
61
|
+
});
|
|
62
|
+
// ============================================================================
|
|
63
|
+
// Complete Template
|
|
64
|
+
// ============================================================================
|
|
65
|
+
export const WorkoutTemplateSchema = z.object({
|
|
66
|
+
id: z
|
|
67
|
+
.string()
|
|
68
|
+
.regex(/^[a-zA-Z0-9_.]+$/, "Template ID must contain only letters, numbers, dots, and underscores"),
|
|
69
|
+
name: z.string().min(1),
|
|
70
|
+
sport: SportSchema,
|
|
71
|
+
type: z.string().min(1),
|
|
72
|
+
category: WorkoutCategorySchema,
|
|
73
|
+
params: TemplateParamsSchema.optional(),
|
|
74
|
+
structure: TemplateStructureSchema.optional(),
|
|
75
|
+
humanReadable: z.string().min(1),
|
|
76
|
+
estimatedDuration: z.union([z.string(), z.number()]).optional(),
|
|
77
|
+
targetZone: z.string().optional(),
|
|
78
|
+
rpe: z.string().optional(),
|
|
79
|
+
notes: z.string().optional(),
|
|
80
|
+
});
|
|
81
|
+
/**
|
|
82
|
+
* Validate a workout template against the schema.
|
|
83
|
+
*/
|
|
84
|
+
export function validateTemplate(data) {
|
|
85
|
+
const result = WorkoutTemplateSchema.safeParse(data);
|
|
86
|
+
if (result.success) {
|
|
87
|
+
return { success: true, data: result.data };
|
|
88
|
+
}
|
|
89
|
+
const errors = result.error.issues.map((issue) => ({
|
|
90
|
+
path: issue.path.join("."),
|
|
91
|
+
message: issue.message,
|
|
92
|
+
code: issue.code,
|
|
93
|
+
}));
|
|
94
|
+
return { success: false, errors };
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Validate a template and throw an error if invalid.
|
|
98
|
+
*/
|
|
99
|
+
export function validateTemplateOrThrow(data) {
|
|
100
|
+
return WorkoutTemplateSchema.parse(data);
|
|
101
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workout Template Types
|
|
3
|
+
*
|
|
4
|
+
* Templates define reusable workout structures with parametrized values.
|
|
5
|
+
* They're referenced in compact plans and expanded with athlete-specific data.
|
|
6
|
+
*/
|
|
7
|
+
import type { Sport } from "../schema/compact-plan.js";
|
|
8
|
+
/**
|
|
9
|
+
* Parameter types for template variables.
|
|
10
|
+
*/
|
|
11
|
+
export type ParamType = "int" | "number" | "duration" | "distance" | "string";
|
|
12
|
+
/**
|
|
13
|
+
* A template parameter definition.
|
|
14
|
+
*/
|
|
15
|
+
export interface TemplateParam {
|
|
16
|
+
type: ParamType;
|
|
17
|
+
required?: boolean;
|
|
18
|
+
default?: number | string;
|
|
19
|
+
min?: number;
|
|
20
|
+
max?: number;
|
|
21
|
+
description?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Map of parameter names to their definitions.
|
|
25
|
+
*/
|
|
26
|
+
export interface TemplateParams {
|
|
27
|
+
[paramName: string]: TemplateParam;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Step types within a structured workout.
|
|
31
|
+
*/
|
|
32
|
+
export type StepType = "warmup" | "work" | "recovery" | "rest" | "cooldown";
|
|
33
|
+
/**
|
|
34
|
+
* A single step in a workout structure.
|
|
35
|
+
* Values can include ${variable} interpolation.
|
|
36
|
+
*/
|
|
37
|
+
export interface TemplateStep {
|
|
38
|
+
type: StepType;
|
|
39
|
+
name?: string;
|
|
40
|
+
duration?: string;
|
|
41
|
+
distance?: string;
|
|
42
|
+
pace?: string;
|
|
43
|
+
intensity?: string;
|
|
44
|
+
description?: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* An interval set with work/recovery pattern.
|
|
48
|
+
*/
|
|
49
|
+
export interface TemplateIntervalSet {
|
|
50
|
+
type: "intervals";
|
|
51
|
+
repeats: string;
|
|
52
|
+
work: TemplateStep;
|
|
53
|
+
recovery: TemplateStep;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The main section can be simple steps or interval sets.
|
|
57
|
+
*/
|
|
58
|
+
export type MainSetElement = TemplateStep | TemplateIntervalSet;
|
|
59
|
+
/**
|
|
60
|
+
* Structured workout with warmup, main, and cooldown sections.
|
|
61
|
+
*/
|
|
62
|
+
export interface TemplateStructure {
|
|
63
|
+
warmup?: TemplateStep[];
|
|
64
|
+
main: MainSetElement[];
|
|
65
|
+
cooldown?: TemplateStep[];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Workout category for organization.
|
|
69
|
+
*/
|
|
70
|
+
export type WorkoutCategory = "rest" | "recovery" | "endurance" | "tempo" | "threshold" | "intervals" | "speed" | "hills" | "race" | "strength" | "technique";
|
|
71
|
+
/**
|
|
72
|
+
* A complete workout template.
|
|
73
|
+
*/
|
|
74
|
+
export interface WorkoutTemplate {
|
|
75
|
+
/** Unique template identifier, e.g., "intervals.400", "easy", "tempo" */
|
|
76
|
+
id: string;
|
|
77
|
+
/** Human-readable name, e.g., "400m Repeats", "Easy Run" */
|
|
78
|
+
name: string;
|
|
79
|
+
/** Sport type */
|
|
80
|
+
sport: Sport;
|
|
81
|
+
/** Workout type for classification */
|
|
82
|
+
type: string;
|
|
83
|
+
/** Category for grouping */
|
|
84
|
+
category: WorkoutCategory;
|
|
85
|
+
/** Template parameters with defaults and validation */
|
|
86
|
+
params?: TemplateParams;
|
|
87
|
+
/** Structured workout (optional, for device export) */
|
|
88
|
+
structure?: TemplateStructure;
|
|
89
|
+
/**
|
|
90
|
+
* Human-readable workout description.
|
|
91
|
+
* Supports ${variable} interpolation.
|
|
92
|
+
* This becomes the workout's humanReadable field after expansion.
|
|
93
|
+
*/
|
|
94
|
+
humanReadable: string;
|
|
95
|
+
/**
|
|
96
|
+
* Estimated duration calculation.
|
|
97
|
+
* Can be a number (minutes) or expression string.
|
|
98
|
+
* E.g., "${10 + (reps * 3.5) + 10}" or "30"
|
|
99
|
+
*/
|
|
100
|
+
estimatedDuration?: string | number;
|
|
101
|
+
/** Target training zone, e.g., "Z2", "Z4-Z5" */
|
|
102
|
+
targetZone?: string;
|
|
103
|
+
/** RPE range, e.g., "6-7", "8-9" */
|
|
104
|
+
rpe?: string;
|
|
105
|
+
/** Additional notes about the workout */
|
|
106
|
+
notes?: string;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* A registry of all available workout templates.
|
|
110
|
+
*/
|
|
111
|
+
export interface TemplateRegistry {
|
|
112
|
+
/** All templates indexed by ID */
|
|
113
|
+
templates: Map<string, WorkoutTemplate>;
|
|
114
|
+
/** Get a template by ID */
|
|
115
|
+
get(id: string): WorkoutTemplate | undefined;
|
|
116
|
+
/** List all templates, optionally filtered by sport */
|
|
117
|
+
list(sport?: Sport): WorkoutTemplate[];
|
|
118
|
+
/** Check if a template exists */
|
|
119
|
+
has(id: string): boolean;
|
|
120
|
+
/** Get all template IDs */
|
|
121
|
+
ids(): string[];
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Context provided during template interpolation.
|
|
125
|
+
*/
|
|
126
|
+
export interface InterpolationContext {
|
|
127
|
+
/** Athlete's pace values */
|
|
128
|
+
paces: Record<string, string | undefined>;
|
|
129
|
+
/** Athlete's zone configuration */
|
|
130
|
+
zones?: {
|
|
131
|
+
hr?: {
|
|
132
|
+
lthr: number;
|
|
133
|
+
[zone: string]: number | undefined;
|
|
134
|
+
};
|
|
135
|
+
[key: string]: unknown;
|
|
136
|
+
};
|
|
137
|
+
/** Template parameters (reps, duration, etc.) */
|
|
138
|
+
[param: string]: unknown;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* A workout after template expansion.
|
|
142
|
+
* All ${variables} have been replaced with actual values.
|
|
143
|
+
*/
|
|
144
|
+
export interface ExpandedWorkout {
|
|
145
|
+
id: string;
|
|
146
|
+
sport: Sport;
|
|
147
|
+
type: string;
|
|
148
|
+
name: string;
|
|
149
|
+
description?: string;
|
|
150
|
+
durationMinutes?: number;
|
|
151
|
+
humanReadable: string;
|
|
152
|
+
targetZone?: string;
|
|
153
|
+
rpe?: string;
|
|
154
|
+
completed: boolean;
|
|
155
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* YAML Parser Wrapper
|
|
3
|
+
*
|
|
4
|
+
* Provides consistent YAML parsing for templates and compact plans.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Parse a YAML string into a JavaScript object.
|
|
8
|
+
*/
|
|
9
|
+
export declare function parse<T = unknown>(content: string): T;
|
|
10
|
+
/**
|
|
11
|
+
* Stringify a JavaScript object to YAML.
|
|
12
|
+
*/
|
|
13
|
+
export declare function stringify(data: unknown, options?: {
|
|
14
|
+
indent?: number;
|
|
15
|
+
}): string;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* YAML Parser Wrapper
|
|
3
|
+
*
|
|
4
|
+
* Provides consistent YAML parsing for templates and compact plans.
|
|
5
|
+
*/
|
|
6
|
+
import { parse as yamlParse, stringify as yamlStringify } from "yaml";
|
|
7
|
+
/**
|
|
8
|
+
* Parse a YAML string into a JavaScript object.
|
|
9
|
+
*/
|
|
10
|
+
export function parse(content) {
|
|
11
|
+
return yamlParse(content);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Stringify a JavaScript object to YAML.
|
|
15
|
+
*/
|
|
16
|
+
export function stringify(data, options) {
|
|
17
|
+
return yamlStringify(data, { indent: options?.indent ?? 2 });
|
|
18
|
+
}
|