gymmonk-schema 0.21.0 → 0.22.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.
@@ -68,6 +68,7 @@ export declare const exerciseSummarySchema: z.ZodObject<{
68
68
  }>;
69
69
  targetArea: z.ZodString;
70
70
  thumbnailUrl: z.ZodNullable<z.ZodString>;
71
+ centerId: z.ZodNullable<z.ZodString>;
71
72
  }, z.core.$strip>;
72
73
  export type ExerciseSummary = z.infer<typeof exerciseSummarySchema>;
73
74
  export declare const exerciseSchema: z.ZodObject<{
@@ -122,7 +123,7 @@ export declare const exerciseSchema: z.ZodObject<{
122
123
  }, z.core.$strip>;
123
124
  export type Exercise = z.infer<typeof exerciseSchema>;
124
125
  export declare const createExerciseBodySchema: z.ZodObject<{
125
- centerId: z.ZodString;
126
+ centerId: z.ZodNullable<z.ZodString>;
126
127
  name: z.ZodString;
127
128
  description: z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
128
129
  category: z.ZodEnum<{
@@ -1 +1 @@
1
- {"version":3,"file":"exercise.d.ts","sourceRoot":"","sources":["../src/exercise.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,gBAAgB;;;;EAAmD,CAAC;AACjF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,eAAO,MAAM,sBAAsB;;;;;;EAMjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,+EAA+E;AAC/E,eAAO,MAAM,aAAa,sLAiBhB,CAAC;AACX,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;EAAwB,CAAC;AACvD,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAI5D,eAAO,MAAM,iBAAiB;;;;;iBAK5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAI5D,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;iBAQhC,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAIpE,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAUzB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAItD,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAanC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAA8D,CAAC;AACpG,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAI1E,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;iBAKrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC"}
1
+ {"version":3,"file":"exercise.d.ts","sourceRoot":"","sources":["../src/exercise.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,gBAAgB;;;;EAAmD,CAAC;AACjF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,eAAO,MAAM,sBAAsB;;;;;;EAMjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,+EAA+E;AAC/E,eAAO,MAAM,aAAa,sLAiBhB,CAAC;AACX,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;EAAwB,CAAC;AACvD,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAI5D,eAAO,MAAM,iBAAiB;;;;;iBAK5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAI5D,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;iBAmBhC,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAIpE,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBASzB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAItD,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsBnC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAA8D,CAAC;AACpG,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAI1E,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;iBAKrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC"}
package/dist/exercise.js CHANGED
@@ -54,10 +54,20 @@ export const exerciseSummarySchema = z.object({
54
54
  category: exerciseCategorySchema,
55
55
  targetArea: z.string(),
56
56
  thumbnailUrl: z.string().nullable(),
57
+ /**
58
+ * Who authored this entry: `null` = the PLATFORM library, every gym sees it;
59
+ * a center id = that gym's own, and only its people see it.
60
+ *
61
+ * On the SUMMARY, not just the detail, because the grid is where the
62
+ * distinction has to be visible. An owner scrolling their library needs to
63
+ * know which cards are theirs to edit before tapping one, and a member is
64
+ * entitled to know that a routine came from their gym rather than from us.
65
+ * The detail shape inherits it from here, so there is one definition.
66
+ */
67
+ centerId: objectIdSchema.nullable(),
57
68
  });
58
69
  // ─── Detail (full entity) ────────────────────────────────────────────────────
59
70
  export const exerciseSchema = exerciseSummarySchema.extend({
60
- centerId: objectIdSchema.nullable(),
61
71
  description: z.string(),
62
72
  youtubeId: z.string().nullable(),
63
73
  posterUrl: z.string().nullable(),
@@ -69,7 +79,16 @@ export const exerciseSchema = exerciseSummarySchema.extend({
69
79
  });
70
80
  // ─── Create / update body ────────────────────────────────────────────────────
71
81
  export const createExerciseBodySchema = z.object({
72
- centerId: objectIdSchema,
82
+ /**
83
+ * Which library this entry joins. `null` is the PLATFORM library — content
84
+ * the product publishes to every gym — and only platform staff may send it.
85
+ *
86
+ * Nullable rather than optional on purpose: an omitted field would default to
87
+ * the global library, so a client that simply forgot to send a center would
88
+ * silently publish a gym's private exercise to the whole platform. Choosing
89
+ * global has to be something the caller SAYS.
90
+ */
91
+ centerId: objectIdSchema.nullable(),
73
92
  name: z.string().trim().min(1, 'Name is required').max(120),
74
93
  description: optionalTrimmedString(4000),
75
94
  category: exerciseCategorySchema,
@@ -1 +1 @@
1
- {"version":3,"file":"exercise.js","sourceRoot":"","sources":["../src/exercise.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * gymmonk-schema — Exercise library\n * ==================================\n * The catalog of exercises. Global entries (centerId null) plus gym-custom ones\n * an owner authors. Difficulty/category/muscle vocabularies are normalised to\n * lowercase; the frontend title-cases for display.\n *\n * @module gymmonk-schema/exercise\n */\n\nimport { z } from 'zod';\nimport { isoDateTimeSchema, objectIdSchema, optionalTrimmedString } from './common.js';\n\n// ─── Enums ───────────────────────────────────────────────────────────────────\n\nexport const difficultySchema = z.enum(['beginner', 'intermediate', 'advanced']);\nexport type Difficulty = z.infer<typeof difficultySchema>;\n\nexport const exerciseCategorySchema = z.enum([\n 'cardio',\n 'upper-body',\n 'lower-body',\n 'core',\n 'full-body',\n]);\nexport type ExerciseCategory = z.infer<typeof exerciseCategorySchema>;\n\n/** Normalised superset of the target-muscle vocabulary used across the app. */\nexport const MUSCLE_GROUPS = [\n 'chest',\n 'back',\n 'shoulders',\n 'biceps',\n 'triceps',\n 'forearms',\n 'quads',\n 'hamstrings',\n 'glutes',\n 'calves',\n 'legs',\n 'core',\n 'obliques',\n 'lower-back',\n 'full-body',\n 'cardio',\n] as const;\nexport const muscleGroupSchema = z.enum(MUSCLE_GROUPS);\nexport type MuscleGroup = z.infer<typeof muscleGroupSchema>;\n\n// ─── Prescribed sets (on the detail view) ────────────────────────────────────\n\nexport const exerciseSetSchema = z.object({\n order: z.number().int().min(1),\n reps: z.string().trim().min(1),\n weight: z.string().trim(),\n tempo: z.string().trim(),\n});\nexport type ExerciseSet = z.infer<typeof exerciseSetSchema>;\n\n// ─── Summary (library card) ──────────────────────────────────────────────────\n\nexport const exerciseSummarySchema = z.object({\n id: objectIdSchema,\n slug: z.string(),\n name: z.string(),\n difficulty: difficultySchema,\n category: exerciseCategorySchema,\n targetArea: z.string(),\n thumbnailUrl: z.string().nullable(),\n});\nexport type ExerciseSummary = z.infer<typeof exerciseSummarySchema>;\n\n// ─── Detail (full entity) ────────────────────────────────────────────────────\n\nexport const exerciseSchema = exerciseSummarySchema.extend({\n centerId: objectIdSchema.nullable(),\n description: z.string(),\n youtubeId: z.string().nullable(),\n posterUrl: z.string().nullable(),\n targetMuscles: z.array(muscleGroupSchema),\n sets: z.array(exerciseSetSchema),\n formTips: z.array(z.string()),\n createdAt: isoDateTimeSchema,\n updatedAt: isoDateTimeSchema,\n});\nexport type Exercise = z.infer<typeof exerciseSchema>;\n\n// ─── Create / update body ────────────────────────────────────────────────────\n\nexport const createExerciseBodySchema = z.object({\n centerId: objectIdSchema,\n name: z.string().trim().min(1, 'Name is required').max(120),\n description: optionalTrimmedString(4000),\n category: exerciseCategorySchema,\n difficulty: difficultySchema,\n targetArea: optionalTrimmedString(120),\n youtubeId: optionalTrimmedString(40),\n thumbnailUrl: optionalTrimmedString(2000),\n posterUrl: optionalTrimmedString(2000),\n targetMuscles: z.array(muscleGroupSchema).max(16).default([]),\n sets: z.array(exerciseSetSchema).max(20).default([]),\n formTips: z.array(z.string().trim().max(400)).max(20).default([]),\n});\nexport type CreateExerciseBody = z.infer<typeof createExerciseBodySchema>;\n\nexport const updateExerciseBodySchema = createExerciseBodySchema.omit({ centerId: true }).partial();\nexport type UpdateExerciseBody = z.infer<typeof updateExerciseBodySchema>;\n\n// ─── Library query ───────────────────────────────────────────────────────────\n\nexport const exerciseLibraryQuerySchema = z.object({\n centerId: objectIdSchema.optional(),\n category: exerciseCategorySchema.optional(),\n difficulty: difficultySchema.optional(),\n q: optionalTrimmedString(120),\n});\nexport type ExerciseLibraryQuery = z.infer<typeof exerciseLibraryQuerySchema>;\n"]}
1
+ {"version":3,"file":"exercise.js","sourceRoot":"","sources":["../src/exercise.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * gymmonk-schema — Exercise library\n * ==================================\n * The catalog of exercises. Global entries (centerId null) plus gym-custom ones\n * an owner authors. Difficulty/category/muscle vocabularies are normalised to\n * lowercase; the frontend title-cases for display.\n *\n * @module gymmonk-schema/exercise\n */\n\nimport { z } from 'zod';\nimport { isoDateTimeSchema, objectIdSchema, optionalTrimmedString } from './common.js';\n\n// ─── Enums ───────────────────────────────────────────────────────────────────\n\nexport const difficultySchema = z.enum(['beginner', 'intermediate', 'advanced']);\nexport type Difficulty = z.infer<typeof difficultySchema>;\n\nexport const exerciseCategorySchema = z.enum([\n 'cardio',\n 'upper-body',\n 'lower-body',\n 'core',\n 'full-body',\n]);\nexport type ExerciseCategory = z.infer<typeof exerciseCategorySchema>;\n\n/** Normalised superset of the target-muscle vocabulary used across the app. */\nexport const MUSCLE_GROUPS = [\n 'chest',\n 'back',\n 'shoulders',\n 'biceps',\n 'triceps',\n 'forearms',\n 'quads',\n 'hamstrings',\n 'glutes',\n 'calves',\n 'legs',\n 'core',\n 'obliques',\n 'lower-back',\n 'full-body',\n 'cardio',\n] as const;\nexport const muscleGroupSchema = z.enum(MUSCLE_GROUPS);\nexport type MuscleGroup = z.infer<typeof muscleGroupSchema>;\n\n// ─── Prescribed sets (on the detail view) ────────────────────────────────────\n\nexport const exerciseSetSchema = z.object({\n order: z.number().int().min(1),\n reps: z.string().trim().min(1),\n weight: z.string().trim(),\n tempo: z.string().trim(),\n});\nexport type ExerciseSet = z.infer<typeof exerciseSetSchema>;\n\n// ─── Summary (library card) ──────────────────────────────────────────────────\n\nexport const exerciseSummarySchema = z.object({\n id: objectIdSchema,\n slug: z.string(),\n name: z.string(),\n difficulty: difficultySchema,\n category: exerciseCategorySchema,\n targetArea: z.string(),\n thumbnailUrl: z.string().nullable(),\n /**\n * Who authored this entry: `null` = the PLATFORM library, every gym sees it;\n * a center id = that gym's own, and only its people see it.\n *\n * On the SUMMARY, not just the detail, because the grid is where the\n * distinction has to be visible. An owner scrolling their library needs to\n * know which cards are theirs to edit before tapping one, and a member is\n * entitled to know that a routine came from their gym rather than from us.\n * The detail shape inherits it from here, so there is one definition.\n */\n centerId: objectIdSchema.nullable(),\n});\nexport type ExerciseSummary = z.infer<typeof exerciseSummarySchema>;\n\n// ─── Detail (full entity) ────────────────────────────────────────────────────\n\nexport const exerciseSchema = exerciseSummarySchema.extend({\n description: z.string(),\n youtubeId: z.string().nullable(),\n posterUrl: z.string().nullable(),\n targetMuscles: z.array(muscleGroupSchema),\n sets: z.array(exerciseSetSchema),\n formTips: z.array(z.string()),\n createdAt: isoDateTimeSchema,\n updatedAt: isoDateTimeSchema,\n});\nexport type Exercise = z.infer<typeof exerciseSchema>;\n\n// ─── Create / update body ────────────────────────────────────────────────────\n\nexport const createExerciseBodySchema = z.object({\n /**\n * Which library this entry joins. `null` is the PLATFORM library — content\n * the product publishes to every gym — and only platform staff may send it.\n *\n * Nullable rather than optional on purpose: an omitted field would default to\n * the global library, so a client that simply forgot to send a center would\n * silently publish a gym's private exercise to the whole platform. Choosing\n * global has to be something the caller SAYS.\n */\n centerId: objectIdSchema.nullable(),\n name: z.string().trim().min(1, 'Name is required').max(120),\n description: optionalTrimmedString(4000),\n category: exerciseCategorySchema,\n difficulty: difficultySchema,\n targetArea: optionalTrimmedString(120),\n youtubeId: optionalTrimmedString(40),\n thumbnailUrl: optionalTrimmedString(2000),\n posterUrl: optionalTrimmedString(2000),\n targetMuscles: z.array(muscleGroupSchema).max(16).default([]),\n sets: z.array(exerciseSetSchema).max(20).default([]),\n formTips: z.array(z.string().trim().max(400)).max(20).default([]),\n});\nexport type CreateExerciseBody = z.infer<typeof createExerciseBodySchema>;\n\nexport const updateExerciseBodySchema = createExerciseBodySchema.omit({ centerId: true }).partial();\nexport type UpdateExerciseBody = z.infer<typeof updateExerciseBodySchema>;\n\n// ─── Library query ───────────────────────────────────────────────────────────\n\nexport const exerciseLibraryQuerySchema = z.object({\n centerId: objectIdSchema.optional(),\n category: exerciseCategorySchema.optional(),\n difficulty: difficultySchema.optional(),\n q: optionalTrimmedString(120),\n});\nexport type ExerciseLibraryQuery = z.infer<typeof exerciseLibraryQuerySchema>;\n"]}
@@ -97,7 +97,7 @@ export declare const planDaySchema: z.ZodObject<{
97
97
  export type PlanDay = z.infer<typeof planDaySchema>;
98
98
  export declare const workoutPlanSummarySchema: z.ZodObject<{
99
99
  id: z.ZodString;
100
- centerId: z.ZodString;
100
+ centerId: z.ZodNullable<z.ZodString>;
101
101
  name: z.ZodString;
102
102
  description: z.ZodNullable<z.ZodString>;
103
103
  goals: z.ZodNullable<z.ZodString>;
@@ -108,7 +108,7 @@ export declare const workoutPlanSummarySchema: z.ZodObject<{
108
108
  export type WorkoutPlanSummary = z.infer<typeof workoutPlanSummarySchema>;
109
109
  export declare const workoutPlanSchema: z.ZodObject<{
110
110
  id: z.ZodString;
111
- centerId: z.ZodString;
111
+ centerId: z.ZodNullable<z.ZodString>;
112
112
  name: z.ZodString;
113
113
  description: z.ZodNullable<z.ZodString>;
114
114
  goals: z.ZodNullable<z.ZodString>;
@@ -152,7 +152,7 @@ export declare const workoutPlanSchema: z.ZodObject<{
152
152
  }, z.core.$strip>;
153
153
  export type WorkoutPlan = z.infer<typeof workoutPlanSchema>;
154
154
  export declare const createWorkoutPlanBodySchema: z.ZodObject<{
155
- centerId: z.ZodString;
155
+ centerId: z.ZodNullable<z.ZodString>;
156
156
  name: z.ZodString;
157
157
  description: z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
158
158
  goals: z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
@@ -1 +1 @@
1
- {"version":3,"file":"workout-plan.d.ts","sourceRoot":"","sources":["../src/workout-plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,uEAAuE;AACvE,eAAO,MAAM,uBAAuB;;;;;iBAKlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;iBAGpC,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAI5E,6EAA6E;AAC7E,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;iBAY7B,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAGxB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAIpD,eAAO,MAAM,wBAAwB;;;;;;;;;iBAkBnC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAE5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAI5D,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;iBAOtC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEhF,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;iBAE5B,CAAC;AACb,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC"}
1
+ {"version":3,"file":"workout-plan.d.ts","sourceRoot":"","sources":["../src/workout-plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,uEAAuE;AACvE,eAAO,MAAM,uBAAuB;;;;;iBAKlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;iBAGpC,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAI5E,6EAA6E;AAC7E,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;iBAY7B,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAGxB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAIpD,eAAO,MAAM,wBAAwB;;;;;;;;;iBAyBnC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAE5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAI5D,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;iBAetC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEhF,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;iBAE5B,CAAC;AACb,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC"}
@@ -46,7 +46,14 @@ export const planDaySchema = z.object({
46
46
  // ─── Entity ──────────────────────────────────────────────────────────────────
47
47
  export const workoutPlanSummarySchema = z.object({
48
48
  id: objectIdSchema,
49
- centerId: objectIdSchema,
49
+ /**
50
+ * `null` = a PLATFORM template, offered to every gym; a center id = that
51
+ * gym's own routine, visible only to its people.
52
+ *
53
+ * See `createWorkoutPlanBodySchema.centerId` for why the global case is a
54
+ * null the caller must state rather than a field they may omit.
55
+ */
56
+ centerId: objectIdSchema.nullable(),
50
57
  name: z.string(),
51
58
  description: z.string().nullable(),
52
59
  /**
@@ -68,7 +75,15 @@ export const workoutPlanSchema = workoutPlanSummarySchema.extend({
68
75
  });
69
76
  // ─── Create / update body ────────────────────────────────────────────────────
70
77
  export const createWorkoutPlanBodySchema = z.object({
71
- centerId: objectIdSchema,
78
+ /**
79
+ * Which library this plan joins. `null` is the PLATFORM template shelf, which
80
+ * only platform staff may write to.
81
+ *
82
+ * Nullable rather than optional: omitting the field would quietly mean
83
+ * "global", so one forgetful client could publish a gym's programming to
84
+ * every competitor on the product. Going global has to be stated.
85
+ */
86
+ centerId: objectIdSchema.nullable(),
72
87
  name: z.string().trim().min(1, 'Plan name is required').max(120),
73
88
  description: optionalTrimmedString(2000),
74
89
  goals: optionalTrimmedString(400),
@@ -1 +1 @@
1
- {"version":3,"file":"workout-plan.js","sourceRoot":"","sources":["../src/workout-plan.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * gymmonk-schema — Workout plans (routines)\n * ==========================================\n * A weekly training routine an owner builds from library exercises and assigns\n * to members. Each day carries prescribed exercises (sets / reps / rest). The\n * prescription is stored by exercise ref; the API populates a summary for\n * rendering.\n *\n * @module gymmonk-schema/workout-plan\n */\n\nimport { z } from 'zod';\nimport { isoDateTimeSchema, objectIdSchema, optionalTrimmedString } from './common.js';\nimport { difficultySchema, exerciseCategorySchema } from './exercise.js';\nimport { weekdaySchema } from './shared.js';\n\n// ─── Prescription (stored input) ─────────────────────────────────────────────\n\n/** One exercise slot in a plan day, referencing a library exercise. */\nexport const planExerciseInputSchema = z.object({\n exerciseId: objectIdSchema,\n sets: z.number().int().min(1).max(20),\n reps: z.string().trim().min(1).max(40),\n restSec: z.number().int().min(0).max(3600),\n});\nexport type PlanExerciseInput = z.infer<typeof planExerciseInputSchema>;\n\nexport const workoutPlanDayInputSchema = z.object({\n weekday: weekdaySchema,\n exercises: z.array(planExerciseInputSchema).max(30).default([]),\n});\nexport type WorkoutPlanDayInput = z.infer<typeof workoutPlanDayInputSchema>;\n\n// ─── Populated response shapes ───────────────────────────────────────────────\n\n/** A plan-day exercise with its populated library summary + prescription. */\nexport const planExerciseSchema = z.object({\n exerciseId: objectIdSchema,\n slug: z.string(),\n name: z.string(),\n description: z.string(),\n thumbnailUrl: z.string().nullable(),\n difficulty: difficultySchema,\n category: exerciseCategorySchema,\n targetArea: z.string(),\n sets: z.number().int(),\n reps: z.string(),\n restSec: z.number().int(),\n});\nexport type PlanExercise = z.infer<typeof planExerciseSchema>;\n\nexport const planDaySchema = z.object({\n weekday: weekdaySchema,\n exercises: z.array(planExerciseSchema),\n});\nexport type PlanDay = z.infer<typeof planDaySchema>;\n\n// ─── Entity ──────────────────────────────────────────────────────────────────\n\nexport const workoutPlanSummarySchema = z.object({\n id: objectIdSchema,\n centerId: objectIdSchema,\n name: z.string(),\n description: z.string().nullable(),\n /**\n * What the plan is FOR (\"Strength, Endurance\"), as distinct from\n * `description`, the prose blurb on the plan card.\n *\n * `createWorkoutPlanBodySchema` has accepted `goals` from the start but no\n * read shape carried it, so the owner's Goals / Focus field was write-only —\n * and, until the Mongoose model gained the path, not even written. Reading it\n * back is what lets the plan be edited without silently clearing the field.\n */\n goals: z.string().nullable(),\n focusTags: z.array(z.string()),\n createdAt: isoDateTimeSchema,\n updatedAt: isoDateTimeSchema,\n});\nexport type WorkoutPlanSummary = z.infer<typeof workoutPlanSummarySchema>;\n\nexport const workoutPlanSchema = workoutPlanSummarySchema.extend({\n days: z.array(planDaySchema),\n});\nexport type WorkoutPlan = z.infer<typeof workoutPlanSchema>;\n\n// ─── Create / update body ────────────────────────────────────────────────────\n\nexport const createWorkoutPlanBodySchema = z.object({\n centerId: objectIdSchema,\n name: z.string().trim().min(1, 'Plan name is required').max(120),\n description: optionalTrimmedString(2000),\n goals: optionalTrimmedString(400),\n focusTags: z.array(z.string().trim().max(40)).max(20).default([]),\n days: z.array(workoutPlanDayInputSchema).max(7).default([]),\n});\nexport type CreateWorkoutPlanBody = z.infer<typeof createWorkoutPlanBodySchema>;\n\nexport const updateWorkoutPlanBodySchema = createWorkoutPlanBodySchema\n .omit({ centerId: true })\n .partial();\nexport type UpdateWorkoutPlanBody = z.infer<typeof updateWorkoutPlanBodySchema>;\n"]}
1
+ {"version":3,"file":"workout-plan.js","sourceRoot":"","sources":["../src/workout-plan.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * gymmonk-schema — Workout plans (routines)\n * ==========================================\n * A weekly training routine an owner builds from library exercises and assigns\n * to members. Each day carries prescribed exercises (sets / reps / rest). The\n * prescription is stored by exercise ref; the API populates a summary for\n * rendering.\n *\n * @module gymmonk-schema/workout-plan\n */\n\nimport { z } from 'zod';\nimport { isoDateTimeSchema, objectIdSchema, optionalTrimmedString } from './common.js';\nimport { difficultySchema, exerciseCategorySchema } from './exercise.js';\nimport { weekdaySchema } from './shared.js';\n\n// ─── Prescription (stored input) ─────────────────────────────────────────────\n\n/** One exercise slot in a plan day, referencing a library exercise. */\nexport const planExerciseInputSchema = z.object({\n exerciseId: objectIdSchema,\n sets: z.number().int().min(1).max(20),\n reps: z.string().trim().min(1).max(40),\n restSec: z.number().int().min(0).max(3600),\n});\nexport type PlanExerciseInput = z.infer<typeof planExerciseInputSchema>;\n\nexport const workoutPlanDayInputSchema = z.object({\n weekday: weekdaySchema,\n exercises: z.array(planExerciseInputSchema).max(30).default([]),\n});\nexport type WorkoutPlanDayInput = z.infer<typeof workoutPlanDayInputSchema>;\n\n// ─── Populated response shapes ───────────────────────────────────────────────\n\n/** A plan-day exercise with its populated library summary + prescription. */\nexport const planExerciseSchema = z.object({\n exerciseId: objectIdSchema,\n slug: z.string(),\n name: z.string(),\n description: z.string(),\n thumbnailUrl: z.string().nullable(),\n difficulty: difficultySchema,\n category: exerciseCategorySchema,\n targetArea: z.string(),\n sets: z.number().int(),\n reps: z.string(),\n restSec: z.number().int(),\n});\nexport type PlanExercise = z.infer<typeof planExerciseSchema>;\n\nexport const planDaySchema = z.object({\n weekday: weekdaySchema,\n exercises: z.array(planExerciseSchema),\n});\nexport type PlanDay = z.infer<typeof planDaySchema>;\n\n// ─── Entity ──────────────────────────────────────────────────────────────────\n\nexport const workoutPlanSummarySchema = z.object({\n id: objectIdSchema,\n /**\n * `null` = a PLATFORM template, offered to every gym; a center id = that\n * gym's own routine, visible only to its people.\n *\n * See `createWorkoutPlanBodySchema.centerId` for why the global case is a\n * null the caller must state rather than a field they may omit.\n */\n centerId: objectIdSchema.nullable(),\n name: z.string(),\n description: z.string().nullable(),\n /**\n * What the plan is FOR (\"Strength, Endurance\"), as distinct from\n * `description`, the prose blurb on the plan card.\n *\n * `createWorkoutPlanBodySchema` has accepted `goals` from the start but no\n * read shape carried it, so the owner's Goals / Focus field was write-only —\n * and, until the Mongoose model gained the path, not even written. Reading it\n * back is what lets the plan be edited without silently clearing the field.\n */\n goals: z.string().nullable(),\n focusTags: z.array(z.string()),\n createdAt: isoDateTimeSchema,\n updatedAt: isoDateTimeSchema,\n});\nexport type WorkoutPlanSummary = z.infer<typeof workoutPlanSummarySchema>;\n\nexport const workoutPlanSchema = workoutPlanSummarySchema.extend({\n days: z.array(planDaySchema),\n});\nexport type WorkoutPlan = z.infer<typeof workoutPlanSchema>;\n\n// ─── Create / update body ────────────────────────────────────────────────────\n\nexport const createWorkoutPlanBodySchema = z.object({\n /**\n * Which library this plan joins. `null` is the PLATFORM template shelf, which\n * only platform staff may write to.\n *\n * Nullable rather than optional: omitting the field would quietly mean\n * \"global\", so one forgetful client could publish a gym's programming to\n * every competitor on the product. Going global has to be stated.\n */\n centerId: objectIdSchema.nullable(),\n name: z.string().trim().min(1, 'Plan name is required').max(120),\n description: optionalTrimmedString(2000),\n goals: optionalTrimmedString(400),\n focusTags: z.array(z.string().trim().max(40)).max(20).default([]),\n days: z.array(workoutPlanDayInputSchema).max(7).default([]),\n});\nexport type CreateWorkoutPlanBody = z.infer<typeof createWorkoutPlanBodySchema>;\n\nexport const updateWorkoutPlanBodySchema = createWorkoutPlanBodySchema\n .omit({ centerId: true })\n .partial();\nexport type UpdateWorkoutPlanBody = z.infer<typeof updateWorkoutPlanBodySchema>;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gymmonk-schema",
3
- "version": "0.21.0",
3
+ "version": "0.22.0",
4
4
  "description": "Shared Zod schemas, enums and domain types for GymMonk (fitness SaaS) — single source of truth (SSOT) consumed by gymmonk-backend and gymmonk-web-client.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",