healthy-meals-core 0.0.2

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.
Files changed (83) hide show
  1. package/dist/bmr.d.ts +3 -0
  2. package/dist/bmr.js +14 -0
  3. package/dist/dailyMealPlanGenerator.d.ts +3 -0
  4. package/dist/dailyMealPlanGenerator.js +211 -0
  5. package/dist/data/detailed-recipes-bs.json +417 -0
  6. package/dist/data/detailed-recipes.json +744 -0
  7. package/dist/foodConversion.d.ts +55 -0
  8. package/dist/foodConversion.js +200 -0
  9. package/dist/index.d.ts +12 -0
  10. package/dist/index.js +27 -0
  11. package/dist/planner.d.ts +2 -0
  12. package/dist/planner.js +24 -0
  13. package/dist/recipeBasedMealPlanGenerator.d.ts +17 -0
  14. package/dist/recipeBasedMealPlanGenerator.js +255 -0
  15. package/dist/recipeService.d.ts +28 -0
  16. package/dist/recipeService.js +136 -0
  17. package/dist/rules/cholesterol.d.ts +2 -0
  18. package/dist/rules/cholesterol.js +7 -0
  19. package/dist/rules/diabetes.d.ts +2 -0
  20. package/dist/rules/diabetes.js +7 -0
  21. package/dist/rules/fattyLiver.d.ts +2 -0
  22. package/dist/rules/fattyLiver.js +7 -0
  23. package/dist/rules/index.d.ts +7 -0
  24. package/dist/rules/index.js +47 -0
  25. package/dist/rules/lowCarb.d.ts +2 -0
  26. package/dist/rules/lowCarb.js +7 -0
  27. package/dist/rules/triglycerides.d.ts +2 -0
  28. package/dist/rules/triglycerides.js +7 -0
  29. package/dist/src/bmr.d.ts +3 -0
  30. package/dist/src/bmr.js +13 -0
  31. package/dist/src/dailyMealPlanGenerator.d.ts +3 -0
  32. package/dist/src/dailyMealPlanGenerator.js +210 -0
  33. package/dist/src/foodConversion.d.ts +55 -0
  34. package/dist/src/foodConversion.js +199 -0
  35. package/dist/src/index.d.ts +12 -0
  36. package/dist/src/index.js +27 -0
  37. package/dist/src/planner.d.ts +2 -0
  38. package/dist/src/planner.js +23 -0
  39. package/dist/src/recipeBasedMealPlanGenerator.d.ts +17 -0
  40. package/dist/src/recipeBasedMealPlanGenerator.js +254 -0
  41. package/dist/src/recipeService.d.ts +28 -0
  42. package/dist/src/recipeService.js +136 -0
  43. package/dist/src/rules/cholesterol.d.ts +2 -0
  44. package/dist/src/rules/cholesterol.js +6 -0
  45. package/dist/src/rules/diabetes.d.ts +2 -0
  46. package/dist/src/rules/diabetes.js +6 -0
  47. package/dist/src/rules/fattyLiver.d.ts +2 -0
  48. package/dist/src/rules/fattyLiver.js +6 -0
  49. package/dist/src/rules/index.d.ts +7 -0
  50. package/dist/src/rules/index.js +46 -0
  51. package/dist/src/rules/lowCarb.d.ts +2 -0
  52. package/dist/src/rules/lowCarb.js +6 -0
  53. package/dist/src/rules/triglycerides.d.ts +2 -0
  54. package/dist/src/rules/triglycerides.js +6 -0
  55. package/dist/src/types/firestore.d.ts +100 -0
  56. package/dist/src/types/firestore.js +2 -0
  57. package/dist/src/types/openfoodfacts.d.ts +113 -0
  58. package/dist/src/types/openfoodfacts.js +3 -0
  59. package/dist/src/types/recipe.d.ts +36 -0
  60. package/dist/src/types/recipe.js +2 -0
  61. package/dist/src/types.d.ts +24 -0
  62. package/dist/src/types.js +2 -0
  63. package/dist/src/variety.d.ts +17 -0
  64. package/dist/src/variety.js +129 -0
  65. package/dist/src/weeklyMealPlanGenerator.d.ts +3 -0
  66. package/dist/src/weeklyMealPlanGenerator.js +468 -0
  67. package/dist/src/weeklyPlanner.d.ts +12 -0
  68. package/dist/src/weeklyPlanner.js +31 -0
  69. package/dist/types/firestore.d.ts +100 -0
  70. package/dist/types/firestore.js +2 -0
  71. package/dist/types/openfoodfacts.d.ts +113 -0
  72. package/dist/types/openfoodfacts.js +3 -0
  73. package/dist/types/recipe.d.ts +36 -0
  74. package/dist/types/recipe.js +2 -0
  75. package/dist/types.d.ts +24 -0
  76. package/dist/types.js +2 -0
  77. package/dist/variety.d.ts +17 -0
  78. package/dist/variety.js +130 -0
  79. package/dist/weeklyMealPlanGenerator.d.ts +3 -0
  80. package/dist/weeklyMealPlanGenerator.js +469 -0
  81. package/dist/weeklyPlanner.d.ts +12 -0
  82. package/dist/weeklyPlanner.js +32 -0
  83. package/package.json +66 -0
@@ -0,0 +1,100 @@
1
+ export interface UserProfile {
2
+ uid: string;
3
+ email: string;
4
+ displayName?: string;
5
+ age: number;
6
+ gender: 'male' | 'female' | 'other';
7
+ height: number;
8
+ weight: number;
9
+ activityLevel: 'sedentary' | 'lightly_active' | 'moderately_active' | 'very_active' | 'extremely_active';
10
+ dietaryRestrictions: string[];
11
+ healthGoals: string[];
12
+ allergies: string[];
13
+ preferences: {
14
+ cuisineTypes: string[];
15
+ mealComplexity: 'simple' | 'moderate' | 'complex';
16
+ cookingTime: number;
17
+ };
18
+ createdAt: Date;
19
+ updatedAt: Date;
20
+ }
21
+ export interface Ingredient {
22
+ id: string;
23
+ name: string;
24
+ quantity: number;
25
+ unit: string;
26
+ calories: number;
27
+ protein: number;
28
+ carbs: number;
29
+ fat: number;
30
+ fiber: number;
31
+ sugar: number;
32
+ sodium: number;
33
+ }
34
+ export interface Meal {
35
+ id: string;
36
+ name: string;
37
+ type: 'breakfast' | 'lunch' | 'dinner' | 'snack';
38
+ ingredients: Ingredient[];
39
+ instructions: string[];
40
+ prepTime: number;
41
+ cookTime: number;
42
+ servings: number;
43
+ nutrition: {
44
+ calories: number;
45
+ protein: number;
46
+ carbs: number;
47
+ fat: number;
48
+ fiber: number;
49
+ sugar: number;
50
+ sodium: number;
51
+ };
52
+ tags: string[];
53
+ difficulty: 'easy' | 'medium' | 'hard';
54
+ createdAt: Date;
55
+ updatedAt: Date;
56
+ }
57
+ export interface DailyMealPlan {
58
+ id: string;
59
+ date: string;
60
+ meals: {
61
+ breakfast?: Meal;
62
+ lunch?: Meal;
63
+ dinner?: Meal;
64
+ snacks?: Meal[];
65
+ };
66
+ totalNutrition: {
67
+ calories: number;
68
+ protein: number;
69
+ carbs: number;
70
+ fat: number;
71
+ fiber: number;
72
+ sugar: number;
73
+ sodium: number;
74
+ };
75
+ createdAt: Date;
76
+ updatedAt: Date;
77
+ }
78
+ export interface MealPlan {
79
+ id: string;
80
+ userId: string;
81
+ name: string;
82
+ description?: string;
83
+ startDate: string;
84
+ endDate: string;
85
+ dailyPlans: DailyMealPlan[];
86
+ meals?: Meal[];
87
+ totalCalories?: number;
88
+ totalProtein?: number;
89
+ totalCarbs?: number;
90
+ totalFat?: number;
91
+ uid?: string;
92
+ goals: {
93
+ dailyCalories: number;
94
+ proteinPercentage: number;
95
+ carbsPercentage: number;
96
+ fatPercentage: number;
97
+ };
98
+ createdAt: Date;
99
+ updatedAt: Date;
100
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,113 @@
1
+ export interface OpenFoodFactsProduct {
2
+ _id: string;
3
+ code: string;
4
+ product_name?: string;
5
+ product_name_en?: string;
6
+ brands?: string;
7
+ categories?: string;
8
+ labels?: string;
9
+ image_url?: string;
10
+ image_front_url?: string;
11
+ image_front_small_url?: string;
12
+ image_nutrition_url?: string;
13
+ image_nutrition_small_url?: string;
14
+ nutriments: Nutriments;
15
+ nutrition_grades?: string;
16
+ ecoscore_grade?: string;
17
+ nova_group?: number;
18
+ serving_size?: string;
19
+ serving_quantity?: number;
20
+ allergens?: string;
21
+ traces?: string;
22
+ ingredients_text?: string;
23
+ ingredients_text_en?: string;
24
+ countries?: string;
25
+ manufacturing_places?: string;
26
+ stores?: string;
27
+ packaging?: string;
28
+ quantity?: string;
29
+ completeness?: number;
30
+ }
31
+ export interface Nutriments {
32
+ energy?: number;
33
+ 'energy-kcal'?: number;
34
+ 'energy-kj'?: number;
35
+ 'energy_100g'?: number;
36
+ 'energy-kcal_100g'?: number;
37
+ 'energy-kj_100g'?: number;
38
+ fat?: number;
39
+ fat_100g?: number;
40
+ 'saturated-fat'?: number;
41
+ 'saturated-fat_100g'?: number;
42
+ carbohydrates?: number;
43
+ carbohydrates_100g?: number;
44
+ sugars?: number;
45
+ sugars_100g?: number;
46
+ fiber?: number;
47
+ fiber_100g?: number;
48
+ proteins?: number;
49
+ proteins_100g?: number;
50
+ salt?: number;
51
+ salt_100g?: number;
52
+ sodium?: number;
53
+ sodium_100g?: number;
54
+ 'nutrition-score-fr'?: number;
55
+ 'nutrition-score-uk'?: number;
56
+ }
57
+ export interface OpenFoodFactsSearchResponse {
58
+ count: number;
59
+ page: number;
60
+ page_count: number;
61
+ page_size: number;
62
+ products: OpenFoodFactsProduct[];
63
+ skip: number;
64
+ }
65
+ export interface OpenFoodFactsProductResponse {
66
+ code: string;
67
+ product: OpenFoodFactsProduct;
68
+ status: number;
69
+ status_verbose: string;
70
+ }
71
+ export interface FoodSearchParams {
72
+ search_terms?: string;
73
+ categories?: string;
74
+ brands?: string;
75
+ countries?: string;
76
+ page?: number;
77
+ page_size?: number;
78
+ sort_by?: 'popularity' | 'product_name' | 'created_t' | 'last_modified_t';
79
+ fields?: string;
80
+ }
81
+ export interface NormalizedFoodItem {
82
+ id: string;
83
+ barcode: string;
84
+ name: string;
85
+ brand?: string;
86
+ imageUrl?: string;
87
+ nutritionPer100g: {
88
+ calories: number;
89
+ protein: number;
90
+ carbs: number;
91
+ fat: number;
92
+ fiber?: number;
93
+ sugar?: number;
94
+ sodium?: number;
95
+ };
96
+ nutritionGrade?: string;
97
+ ecoScore?: string;
98
+ novaGroup?: number;
99
+ servingSize?: string;
100
+ ingredients?: string;
101
+ allergens?: string[];
102
+ categories?: string[];
103
+ }
104
+ export interface FoodSearchFilters {
105
+ category?: string;
106
+ brand?: string;
107
+ nutritionGrade?: string;
108
+ ecoScore?: string;
109
+ novaGroup?: number;
110
+ minProtein?: number;
111
+ maxCalories?: number;
112
+ allergenFree?: string[];
113
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ // Open Food Facts API types and interfaces
3
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,36 @@
1
+ export interface RecipeIngredient {
2
+ name: string;
3
+ quantity: number;
4
+ unit: string;
5
+ }
6
+ export interface RecipeNutrition {
7
+ calories: number;
8
+ protein: number;
9
+ carbs: number;
10
+ fat: number;
11
+ fiber: number;
12
+ sugar: number;
13
+ sodium: number;
14
+ }
15
+ export interface Recipe {
16
+ id: string;
17
+ name: string;
18
+ category: 'breakfast' | 'lunch' | 'dinner' | 'snack';
19
+ prepTime: number;
20
+ cookTime: number;
21
+ servings: number;
22
+ difficulty: 'easy' | 'medium' | 'hard';
23
+ ingredients: RecipeIngredient[];
24
+ instructions: string[];
25
+ nutrition: RecipeNutrition;
26
+ tags: string[];
27
+ }
28
+ export interface RecipeFilter {
29
+ category?: 'breakfast' | 'lunch' | 'dinner' | 'snack';
30
+ tags?: string[];
31
+ maxPrepTime?: number;
32
+ maxCookTime?: number;
33
+ difficulty?: 'easy' | 'medium' | 'hard';
34
+ maxCalories?: number;
35
+ minProtein?: number;
36
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,24 @@
1
+ export type Gender = 'male' | 'female';
2
+ export interface UserProfile {
3
+ heightCm: number;
4
+ weightKg: number;
5
+ age: number;
6
+ gender: Gender;
7
+ activityLevel: 1.2 | 1.375 | 1.55 | 1.725;
8
+ goals: 'maintain' | 'lose' | 'gain';
9
+ conditions: HealthCondition[];
10
+ }
11
+ export type HealthCondition = 'cholesterol' | 'triglycerides' | 'fatty_liver' | 'diabetes' | 'low_carb';
12
+ export interface Recipe {
13
+ id: string;
14
+ name: string;
15
+ calories: number;
16
+ protein: number;
17
+ fat: number;
18
+ carbs: number;
19
+ tags: HealthCondition[];
20
+ }
21
+ export interface MealPlan {
22
+ dailyCalories: number;
23
+ meals: Recipe[];
24
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,17 @@
1
+ import { Recipe } from './types';
2
+ export declare function shuffleArray<T>(array: T[]): T[];
3
+ export declare function preventConsecutiveRepeats(meals: Recipe[]): Recipe[];
4
+ export declare function ensureMealVariety(meals: Recipe[], minVariety?: number): Recipe[];
5
+ export declare function calculateMealDiversity(meals: Recipe[]): number;
6
+ export declare function getMealCategory(recipe: Recipe): string;
7
+ export declare function calculateCategoryDiversity(meals: Recipe[]): number;
8
+ export declare function hasConsecutiveRepeats(meals: Recipe[]): boolean;
9
+ export declare function scoreMealPlan(meals: Recipe[]): {
10
+ diversity: number;
11
+ categoryDiversity: number;
12
+ proteinBalance: number;
13
+ calorieDistribution: number;
14
+ noConsecutiveRepeats: number;
15
+ overallScore: number;
16
+ };
17
+ export declare function selectDiverseMeals(availableRecipes: Recipe[], targetCalories: number, previousMeals?: Recipe[]): Recipe[];
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.selectDiverseMeals = exports.scoreMealPlan = exports.hasConsecutiveRepeats = exports.calculateCategoryDiversity = exports.getMealCategory = exports.calculateMealDiversity = exports.ensureMealVariety = exports.preventConsecutiveRepeats = exports.shuffleArray = void 0;
4
+ function shuffleArray(array) {
5
+ const shuffled = [...array];
6
+ for (let i = shuffled.length - 1; i > 0; i--) {
7
+ const j = Math.floor(Math.random() * (i + 1));
8
+ [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
9
+ }
10
+ return shuffled;
11
+ }
12
+ exports.shuffleArray = shuffleArray;
13
+ function preventConsecutiveRepeats(meals) {
14
+ const result = [];
15
+ const used = new Set();
16
+ for (const meal of meals) {
17
+ if (result.length > 0 && result[result.length - 1].id === meal.id) {
18
+ continue;
19
+ }
20
+ result.push(meal);
21
+ used.add(meal.id);
22
+ }
23
+ return result;
24
+ }
25
+ exports.preventConsecutiveRepeats = preventConsecutiveRepeats;
26
+ function ensureMealVariety(meals, minVariety = 3) {
27
+ const mealCounts = new Map();
28
+ meals.forEach(meal => {
29
+ mealCounts.set(meal.id, (mealCounts.get(meal.id) || 0) + 1);
30
+ });
31
+ const overusedMeals = Array.from(mealCounts.entries())
32
+ .filter(([_, count]) => count > minVariety)
33
+ .map(([id]) => id);
34
+ if (overusedMeals.length === 0) {
35
+ return meals;
36
+ }
37
+ return meals.filter((meal, index) => {
38
+ if (!overusedMeals.includes(meal.id)) {
39
+ return true;
40
+ }
41
+ const previousOccurrences = meals
42
+ .slice(0, index)
43
+ .filter(m => m.id === meal.id).length;
44
+ return previousOccurrences < minVariety;
45
+ });
46
+ }
47
+ exports.ensureMealVariety = ensureMealVariety;
48
+ function calculateMealDiversity(meals) {
49
+ const uniqueMeals = new Set(meals.map(m => m.id));
50
+ return uniqueMeals.size / meals.length;
51
+ }
52
+ exports.calculateMealDiversity = calculateMealDiversity;
53
+ function getMealCategory(recipe) {
54
+ if (recipe.protein > 30)
55
+ return 'high-protein';
56
+ if (recipe.carbs > 50)
57
+ return 'high-carb';
58
+ if (recipe.fat > 20)
59
+ return 'high-fat';
60
+ return 'balanced';
61
+ }
62
+ exports.getMealCategory = getMealCategory;
63
+ function calculateCategoryDiversity(meals) {
64
+ const categories = meals.map(m => getMealCategory(m));
65
+ const uniqueCategories = new Set(categories);
66
+ return uniqueCategories.size / 4;
67
+ }
68
+ exports.calculateCategoryDiversity = calculateCategoryDiversity;
69
+ function hasConsecutiveRepeats(meals) {
70
+ for (let i = 1; i < meals.length; i++) {
71
+ if (meals[i].id === meals[i - 1].id) {
72
+ return true;
73
+ }
74
+ }
75
+ return false;
76
+ }
77
+ exports.hasConsecutiveRepeats = hasConsecutiveRepeats;
78
+ function scoreMealPlan(meals) {
79
+ const diversity = calculateMealDiversity(meals);
80
+ const categoryDiversity = calculateCategoryDiversity(meals);
81
+ const avgProtein = meals.reduce((sum, m) => sum + m.protein, 0) / meals.length;
82
+ const proteinVariance = meals.reduce((sum, m) => sum + Math.pow(m.protein - avgProtein, 2), 0) / meals.length;
83
+ const proteinBalance = 1 / (1 + proteinVariance / 100);
84
+ const avgCalories = meals.reduce((sum, m) => sum + m.calories, 0) / meals.length;
85
+ const calorieVariance = meals.reduce((sum, m) => sum + Math.pow(m.calories - avgCalories, 2), 0) / meals.length;
86
+ const calorieDistribution = 1 / (1 + calorieVariance / 10000);
87
+ const noConsecutiveRepeats = hasConsecutiveRepeats(meals) ? 0 : 1;
88
+ const overallScore = (diversity * 0.3) +
89
+ (categoryDiversity * 0.2) +
90
+ (proteinBalance * 0.2) +
91
+ (calorieDistribution * 0.15) +
92
+ (noConsecutiveRepeats * 0.15);
93
+ return {
94
+ diversity,
95
+ categoryDiversity,
96
+ proteinBalance,
97
+ calorieDistribution,
98
+ noConsecutiveRepeats,
99
+ overallScore
100
+ };
101
+ }
102
+ exports.scoreMealPlan = scoreMealPlan;
103
+ function selectDiverseMeals(availableRecipes, targetCalories, previousMeals = []) {
104
+ const shuffled = shuffleArray([...availableRecipes]);
105
+ const recentMealIds = new Set(previousMeals.slice(-3).map(m => m.id));
106
+ const prioritized = shuffled.sort((a, b) => {
107
+ const aRecent = recentMealIds.has(a.id) ? 1 : 0;
108
+ const bRecent = recentMealIds.has(b.id) ? 1 : 0;
109
+ return aRecent - bRecent;
110
+ });
111
+ let total = 0;
112
+ const selected = [];
113
+ const usedIds = new Set();
114
+ for (const recipe of prioritized) {
115
+ if (total >= targetCalories * 0.95)
116
+ break;
117
+ if (usedIds.has(recipe.id))
118
+ continue;
119
+ if (selected.length > 0 && selected[selected.length - 1].id === recipe.id) {
120
+ continue;
121
+ }
122
+ if (total + recipe.calories <= targetCalories * 1.05) {
123
+ selected.push(recipe);
124
+ usedIds.add(recipe.id);
125
+ total += recipe.calories;
126
+ }
127
+ }
128
+ return selected;
129
+ }
130
+ exports.selectDiverseMeals = selectDiverseMeals;
@@ -0,0 +1,3 @@
1
+ import { UserProfile } from './types/firestore';
2
+ import { MealPlan } from './types/firestore';
3
+ export declare function generateWeeklyMealPlan(profile: UserProfile, userId: string): MealPlan;