@crvouga/mockingbird-service-edamam 3.7.0 → 3.8.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/CHANGELOG.md CHANGED
@@ -1,6 +1,13 @@
1
1
  # Changelog — @crvouga/mockingbird-service-edamam
2
2
 
3
- ## 3.7.0 (2026-10-19)
3
+ ## 3.8.0 (2026-10-21)
4
+
5
+ ### Features
6
+
7
+ - raise the serve and fleet body limit to the S3 maximum ([86b9e2b](https://github.com/crvouga/mockingbird/commit/86b9e2b80bcaaaef57f52edbac50b27da0b42f33))
8
+ - validate block limits, filter nutrients, list block children ([2acb823](https://github.com/crvouga/mockingbird/commit/2acb823ba66b30f3d03221996e015c127b0f72c6))
9
+
10
+ ## 3.7.0 (2026-10-18)
4
11
 
5
12
  ### Features
6
13
 
package/README.md CHANGED
@@ -64,7 +64,7 @@ also accept `Authorization: Basic app_id:app_key`, which our adapter sends).
64
64
 
65
65
  | Route | Behaviour |
66
66
  | --- | --- |
67
- | `GET /api/food-database/v2/parser` | `ingr` is parsed into a leading quantity ("2", "1/2", "a", "two"), a measure the food has ("cup", "large", "slice", "g", "oz") and the best-matching food → `parsed[]`; every food sharing a word → `hints[]` with `measures`. Filters: `categoryLabel` (`food` drops meals), `category`, `health` (repeatable), `calories` (per 100 g). `upc` looks up a packaged food (unknown UPC 404). |
67
+ | `GET /api/food-database/v2/parser` | `ingr` is parsed into a leading quantity ("2", "1/2", "a", "two"), a measure the food has ("cup", "large", "slice", "g", "oz") and the best-matching food → `parsed[]`; every food sharing a word → `hints[]` with `measures`. Filters: `categoryLabel` (`food` drops meals), `category`, `health` (repeatable), `calories` (per 100 g), `nutrients[CODE]` (per 100 g, see below). `upc` looks up a packaged food (unknown UPC 404). |
68
68
  | `POST /api/food-database/v2/nutrients` | `{ingredients: [{quantity, measureURI, foodId}]}` → `calories`, `totalWeight`, `totalNutrients`, `totalDaily`, `dietLabels`, `healthLabels`, `ingredients[].parsed[]`; an unknown food or measure is 422. |
69
69
  | `POST /api/food-database/nutrients-from-image?beta=true` | `{image: data URL or http URL}` → `{parsed: {food, quantity, measure}, recipe: {label, calories, totalNutrients}}`, deterministic per image (or pinned with `PUT /__admin/vision`). |
70
70
  | `GET /api/nutrition-data?ingr=` | One ingredient line; unparsable is 422. |
@@ -108,6 +108,18 @@ and the Python client, which concatenate paths; the meal adapter resolves paths
108
108
 
109
109
  - Edamam's NLP and databases: the parser understands leading quantities, known measures and
110
110
  corpus food names only; real food and recipe content needs a recorded corpus.
111
+ - Parser `nutrients[CODE]` is a **best guess, not oracle-verified** (vendor docs only say the
112
+ Food Database can "search for food by given nutrient quantity"; the query syntax, the error for a
113
+ malformed range and any plan restriction were never observed live). The emulator reads
114
+ `nutrients[PROCNT]=20+`, `=5` (at most) and `=5-15` (inclusive) like `calories`, against the
115
+ food's per-100 g `nutrients`, and a raw `+` that decoded to a space still means "or more".
116
+ Several codes, a repeated code and `health` / `calories` / `category` / `categoryLabel` all must
117
+ hold; nothing matching is `200` with `hints: []` and `parsed: []`. A food with no value for the
118
+ code never matches. Any code shaped like a nutrient code is accepted, but the built-in corpus
119
+ carries only `ENERC_KCAL`, `PROCNT`, `FAT`, `CHOCDF`, `FIBTG` and `SUGAR`, so codes such as `NA` or
120
+ `FE` match only foods seeded with `POST /__admin/foods` that carry them (an emulator limitation,
121
+ not a vendor answer). A malformed range or code is `400 bad_request`. The `upc` lookup ignores the
122
+ filters, as it does for `calories`.
111
123
  - Food Database autocomplete, brand search and `nutrients` qualifiers; Recipe Search user
112
124
  recipes (`type=user`), `field=` projection and images other than the URL.
113
125
  - Meal Planner plan-level `fit` beyond a day-calorie check, `mark` weighting, nested
@@ -4017,7 +4017,7 @@ var stateAdminRoutes = (routes) => {
4017
4017
  };
4018
4018
 
4019
4019
  // ../core/dist/version.js
4020
- var PACKAGE_VERSION = true ? "3.7.0" : UNRELEASED_VERSION;
4020
+ var PACKAGE_VERSION = true ? "3.8.0" : UNRELEASED_VERSION;
4021
4021
 
4022
4022
  // ../core/dist/signing.js
4023
4023
  var encoder = new TextEncoder();
@@ -5643,7 +5643,7 @@ var DEFAULT_RECIPES = [
5643
5643
  ];
5644
5644
 
5645
5645
  // src/generated/openapi.ts
5646
- var document = JSON.parse(`{"openapi":"3.1.0","info":{"title":"Edamam APIs (Mockingbird subset)","description":"Stateful emulator subset of Edamam's Food Database v2 (parser, nutrients, image), Nutrition Analysis (nutrition-data, nutrition-details), Recipe Search v2 (search, by-uri, by id), Meal Planner v1 (select) and Shopping List v2, over a built-in corpus. Hand-authored from Edamam's docs and the consumers (edamam-nutrition.adapter.ts, edamam-meal-planning.adapter.ts, the Python chat client's tools/nutrition/client.py).\\n","version":"2","x-mockingbird-upstream":{"note":"Edamam publishes per-API docs, no single OpenAPI; shapes trimmed to the fields our consumers read (zod schemas in edamam-nutrition.adapter.ts and edamam-meal-planning.schemas.ts)."}},"servers":[{"url":"https://api.edamam.com"}],"paths":{"/api/food-database/v2/parser":{"get":{"operationId":"FoodParser","description":"Parse a food description (\`ingr\`) or look up a barcode (\`upc\`): \`parsed\` (the best match with quantity and measure) and \`hints\` (every related food with its measures).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/AppId"},{"$ref":"#/components/parameters/AppKey"},{"name":"ingr","in":"query","required":false,"schema":{"type":"string","enum":["2 large eggs","1 cup cooked rice","banana","chicken breast","greek yogurt","3 slices bread","salmon fillet","chicken salad","xyzzy"]},"description":"Parity vocabulary; the emulator parses any text."},{"name":"upc","in":"query","required":false,"schema":{"type":"string","enum":["850000000012","850000000029","850000000036","000000000000"]}},{"name":"nutrition-type","in":"query","required":false,"schema":{"type":"string","enum":["cooking","logging"]}},{"name":"categoryLabel","in":"query","required":false,"schema":{"type":"string","enum":["food","meal"]}},{"name":"category","in":"query","required":false,"schema":{"type":"string","enum":["generic-foods","packaged-foods","generic-meals"]}},{"name":"health","in":"query","required":false,"schema":{"type":"string","enum":["vegan","vegetarian","gluten-free","dairy-free"]}},{"name":"calories","in":"query","required":false,"schema":{"type":"string","enum":["50-200","300+","100"]}}],"responses":{"200":{"description":"Parser result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParserResponse"}}}},"400":{"description":"Neither ingr nor upc","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}},"401":{"description":"Unknown app_id / app_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}},"404":{"description":"Unknown UPC","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}},"429":{"description":"Usage limits are exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}}}}},"/api/food-database/v2/nutrients":{"post":{"operationId":"FoodNutrients","description":"Full nutrition for foods at given measures.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/AppId"},{"$ref":"#/components/parameters/AppKey"}],"responses":{"200":{"description":"Nutrition","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NutritionAnalysis"}}}},"401":{"description":"Unknown app_id / app_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}},"422":{"description":"Unknown food or measure","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}},"429":{"description":"Usage limits are exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NutrientsRequest"}}}}}},"/api/food-database/nutrients-from-image":{"post":{"operationId":"FoodFromImage","description":"Recognise a plated meal from an image (beta).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/AppId"},{"$ref":"#/components/parameters/AppKey"},{"name":"beta","in":"query","required":false,"schema":{"type":"string","enum":["true"]}}],"responses":{"200":{"description":"Recognition","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisionResponse"}}}},"400":{"description":"Not an image","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}},"401":{"description":"Unknown app_id / app_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}},"429":{"description":"Usage limits are exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageRequest"}}}}}},"/api/nutrition-data":{"get":{"operationId":"NutritionData","description":"Nutrition analysis of one ingredient line.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/AppId"},{"$ref":"#/components/parameters/AppKey"},{"name":"ingr","in":"query","required":true,"schema":{"type":"string","enum":["1 cup cooked rice","2 large eggs","1 banana","xyzzy"]},"description":"Parity vocabulary; the emulator parses any text."},{"name":"nutrition-type","in":"query","required":false,"schema":{"type":"string","enum":["cooking","logging"]}}],"responses":{"200":{"description":"Nutrition","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NutritionAnalysis"}}}},"401":{"description":"Unknown app_id / app_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}},"422":{"description":"Could not parse the ingredient","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}},"429":{"description":"Usage limits are exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}}}}},"/api/nutrition-details":{"post":{"operationId":"NutritionDetails","description":"Nutrition analysis of a recipe (ingredient lines).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/AppId"},{"$ref":"#/components/parameters/AppKey"}],"responses":{"200":{"description":"Nutrition","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NutritionAnalysis"}}}},"401":{"description":"Unknown app_id / app_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}},"422":{"description":"No ingredients","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}},"429":{"description":"Usage limits are exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}},"555":{"description":"Insufficient quality","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeAnalysisRequest"}}}}}},"/api/recipes/v2":{"get":{"operationId":"RecipeSearch","description":"Recipe search v2 (20 per page, \`_links.next\` carries \`_cont\`).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/AppId"},{"$ref":"#/components/parameters/AppKey"},{"name":"Edamam-Account-User","in":"header","required":false,"schema":{"type":"string","pattern":"^[a-f0-9]{1,30}$","description":"The first 30 hex chars of sha256(user id), as our meal adapter sends it."}},{"name":"type","in":"query","required":true,"schema":{"type":"string","enum":["public","user","any"]}},{"name":"q","in":"query","required":false,"schema":{"type":"string","enum":["chicken","salmon","oats","yogurt","toast","xyzzy"]},"description":"Parity vocabulary; the emulator parses any text."},{"name":"health","in":"query","required":false,"schema":{"type":"string","enum":["vegan","vegetarian","gluten-free","dairy-free","pescatarian"]}},{"name":"diet","in":"query","required":false,"schema":{"type":"string","enum":["high-protein","low-carb","high-fiber","balanced"]}},{"name":"mealType","in":"query","required":false,"schema":{"type":"string","enum":["Breakfast","Lunch","Dinner","Snack"]}},{"name":"dishType","in":"query","required":false,"schema":{"type":"string","enum":["Main course","Salad","Cereals","Egg"]}},{"name":"cuisineType","in":"query","required":false,"schema":{"type":"string","enum":["American","Asian","Mediterranean","French"]}},{"name":"calories","in":"query","required":false,"schema":{"type":"string","enum":["100-400","500+","300"]}},{"name":"time","in":"query","required":false,"schema":{"type":"string","enum":["1-10","30","20+"]}},{"name":"excluded","in":"query","required":false,"schema":{"type":"string","enum":["spinach","almonds"]}},{"name":"imageSize","in":"query","required":false,"schema":{"type":"string","enum":["REGULAR","SMALL","THUMBNAIL","LARGE"]}},{"name":"random","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"Hits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeSearchResponse"}}}},"400":{"description":"Illegal parameter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}},"401":{"description":"Unknown app_id / app_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}},"429":{"description":"Usage limits are exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}}}}},"/api/recipes/v2/by-uri":{"get":{"operationId":"RecipesByUri","description":"Recipes by URI (up to 20 \`uri\` parameters).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/AppId"},{"$ref":"#/components/parameters/AppKey"},{"name":"Edamam-Account-User","in":"header","required":false,"schema":{"type":"string","pattern":"^[a-f0-9]{1,30}$","description":"The first 30 hex chars of sha256(user id), as our meal adapter sends it."}},{"name":"type","in":"query","required":true,"schema":{"type":"string","enum":["public"]}},{"name":"uri","in":"query","required":true,"schema":{"type":"string","enum":["http://www.edamam.com/ontologies/edamam.owl#recipe_overnight_oats","http://www.edamam.com/ontologies/edamam.owl#recipe_baked_salmon","http://www.edamam.com/ontologies/edamam.owl#recipe_missing"]}}],"responses":{"200":{"description":"Hits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeSearchResponse"}}}},"400":{"description":"Illegal parameter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}},"401":{"description":"Unknown app_id / app_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}},"429":{"description":"Usage limits are exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}}}}},"/api/recipes/v2/{id}":{"get":{"operationId":"RecipeById","description":"One recipe (the \`_links.self\` target).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/AppId"},{"$ref":"#/components/parameters/AppKey"},{"name":"Edamam-Account-User","in":"header","required":false,"schema":{"type":"string","pattern":"^[a-f0-9]{1,30}$","description":"The first 30 hex chars of sha256(user id), as our meal adapter sends it."}},{"name":"id","in":"path","required":true,"schema":{"type":"string","enum":["overnight_oats","veggie_omelette","chicken_rice_bowl","missing"]}},{"name":"type","in":"query","required":true,"schema":{"type":"string","enum":["public"]}}],"responses":{"200":{"description":"The recipe","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeHit"}}}},"401":{"description":"Unknown app_id / app_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}},"404":{"description":"Unknown recipe","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}},"429":{"description":"Usage limits are exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}}}}},"/api/meal-planner/v1/{app_id}/select":{"post":{"operationId":"MealPlanSelect","description":"Select recipes for \`size\` days of a plan (Basic auth plus app_id/app_key).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/AppId"},{"$ref":"#/components/parameters/AppKey"},{"name":"Edamam-Account-User","in":"header","required":false,"schema":{"type":"string","pattern":"^[a-f0-9]{1,30}$","description":"The first 30 hex chars of sha256(user id), as our meal adapter sends it."}},{"name":"app_id","in":"path","required":true,"schema":{"type":"string","enum":["parity"]}},{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["public"]}}],"responses":{"200":{"description":"Selection","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MealPlanResponse"}}}},"400":{"description":"Illegal plan","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}},"401":{"description":"Unknown app_id / app_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}},"429":{"description":"Usage limits are exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MealPlanRequest"}}}}}},"/api/shopping-list/v2":{"post":{"operationId":"ShoppingList","description":"Aggregate the ingredients of recipes into a shopping list (optionally a cart link).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/AppId"},{"$ref":"#/components/parameters/AppKey"},{"name":"Edamam-Account-User","in":"header","required":false,"schema":{"type":"string","pattern":"^[a-f0-9]{1,30}$","description":"The first 30 hex chars of sha256(user id), as our meal adapter sends it."}},{"name":"shopping-cart","in":"query","required":false,"schema":{"type":"string","enum":["true"]}},{"name":"beta","in":"query","required":false,"schema":{"type":"string","enum":["true"]}}],"responses":{"200":{"description":"Shopping list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShoppingListResponse"}}}},"400":{"description":"Unknown recipe","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}},"401":{"description":"Unknown app_id / app_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}},"429":{"description":"Usage limits are exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShoppingListRequest"}}}}}}},"components":{"parameters":{"AppId":{"name":"app_id","in":"query","required":true,"description":"Edamam application id (any value unless \`apps\` is set). The parity vocabulary is fixed.","schema":{"type":"string","enum":["parity"]}},"AppKey":{"name":"app_key","in":"query","required":true,"schema":{"type":"string","enum":["parity-key"]}}},"schemas":{"Measure":{"type":"object","required":["uri","label","weight"],"properties":{"uri":{"type":"string"},"label":{"type":"string"},"weight":{"type":"number"}}},"Food":{"type":"object","required":["foodId","label","category","categoryLabel"],"properties":{"foodId":{"type":"string"},"label":{"type":"string"},"knownAs":{"type":"string"},"nutrients":{"type":"object","additionalProperties":{"type":"number"}},"brand":{"type":"string"},"category":{"type":"string"},"categoryLabel":{"type":"string"},"foodContentsLabel":{"type":"string"},"image":{"type":"string"},"servingSizes":{"type":"array","items":{"type":"object"}},"servingsPerContainer":{"type":"number"}}},"Recipe":{"type":"object","required":["uri","label","url","yield","ingredientLines","ingredients","totalNutrients","cautions","dietLabels","healthLabels"],"properties":{"uri":{"type":"string"},"label":{"type":"string"},"image":{"type":"string"},"source":{"type":"string"},"url":{"type":"string"},"shareAs":{"type":"string"},"yield":{"type":"number"},"dietLabels":{"type":"array","items":{"type":"string"}},"healthLabels":{"type":"array","items":{"type":"string"}},"cautions":{"type":"array","items":{"type":"string"}},"ingredientLines":{"type":"array","items":{"type":"string"}},"ingredients":{"type":"array","items":{"type":"object","required":["food","quantity"],"properties":{"text":{"type":"string"},"quantity":{"type":"number"},"measure":{"type":["string","null"]},"food":{"type":"string"},"weight":{"type":"number"},"foodCategory":{"type":["string","null"]},"foodId":{"type":"string"},"image":{"type":["string","null"]}}}},"calories":{"type":"number"},"totalWeight":{"type":"number"},"totalTime":{"type":"number"},"cuisineType":{"type":"array","items":{"type":"string"}},"mealType":{"type":"array","items":{"type":"string"}},"dishType":{"type":"array","items":{"type":"string"}},"totalNutrients":{"type":"object","additionalProperties":{"type":"object","required":["label","quantity","unit"],"properties":{"label":{"type":"string"},"quantity":{"type":"number"},"unit":{"type":"string"}}}},"totalDaily":{"type":"object","additionalProperties":{"type":"object","required":["label","quantity","unit"],"properties":{"label":{"type":"string"},"quantity":{"type":"number"},"unit":{"type":"string"}}}}}},"Link":{"type":"object","required":["href"],"properties":{"href":{"type":"string","x-mockingbird-volatile":{"kind":"url"}},"title":{"type":"string"}}},"ParserResponse":{"type":"object","required":["text","parsed","hints"],"properties":{"text":{"type":"string"},"parsed":{"type":"array","items":{"type":"object","required":["food"],"properties":{"food":{"$ref":"#/components/schemas/Food"},"quantity":{"type":"number"},"measure":{"$ref":"#/components/schemas/Measure"}}}},"hints":{"type":"array","items":{"type":"object","required":["food","measures"],"properties":{"food":{"$ref":"#/components/schemas/Food"},"measures":{"type":"array","items":{"$ref":"#/components/schemas/Measure"}}}}},"_links":{"type":"object"}}},"NutrientsRequest":{"type":"object","required":["ingredients"],"properties":{"ingredients":{"type":"array","minItems":1,"maxItems":3,"items":{"type":"object","required":["quantity","measureURI","foodId"],"properties":{"quantity":{"type":"number","exclusiveMinimum":0,"maximum":20},"measureURI":{"type":"string","examples":["http://www.edamam.com/ontologies/edamam.owl#Measure_unit","http://www.edamam.com/ontologies/edamam.owl#Measure_cup","http://www.edamam.com/ontologies/edamam.owl#Measure_gram"]},"foodId":{"type":"string","examples":["food_egg","food_banana","food_rice_cooked"]},"qualifiers":{"type":"array","items":{"type":"string"}}}}}}},"NutritionAnalysis":{"type":"object","required":["calories","totalWeight","dietLabels","healthLabels","cautions","totalNutrients","totalDaily"],"properties":{"uri":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"calories":{"type":"number"},"totalWeight":{"type":"number"},"dietLabels":{"type":"array","items":{"type":"string"}},"healthLabels":{"type":"array","items":{"type":"string"}},"cautions":{"type":"array","items":{"type":"string"}},"totalNutrients":{"type":"object","additionalProperties":{"type":"object","required":["label","quantity","unit"],"properties":{"label":{"type":"string"},"quantity":{"type":"number"},"unit":{"type":"string"}}}},"totalDaily":{"type":"object","additionalProperties":{"type":"object","required":["label","quantity","unit"],"properties":{"label":{"type":"string"},"quantity":{"type":"number"},"unit":{"type":"string"}}}},"ingredients":{"type":"array","items":{"type":"object"}},"yield":{"type":"number"}}},"ImageRequest":{"type":"object","required":["image"],"properties":{"image":{"type":"string","minLength":1,"maxLength":200,"examples":["data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ==","data:image/png;base64,iVBORw0KGgo="]}}},"VisionResponse":{"type":"object","properties":{"parsed":{"type":"object","properties":{"food":{"$ref":"#/components/schemas/Food"},"quantity":{"type":"number"},"measure":{"$ref":"#/components/schemas/Measure"}}},"recipe":{"type":"object","properties":{"label":{"type":"string"},"calories":{"type":"number"},"totalNutrients":{"type":"object","additionalProperties":{"type":"object","required":["label","quantity","unit"],"properties":{"label":{"type":"string"},"quantity":{"type":"number"},"unit":{"type":"string"}}}}}}}},"RecipeAnalysisRequest":{"type":"object","required":["ingr"],"properties":{"title":{"type":"string","maxLength":80},"yield":{"type":"integer","minimum":1,"maximum":8},"ingr":{"type":"array","maxItems":4,"items":{"type":"string","minLength":1,"maxLength":60,"examples":["2 large eggs","1 cup cooked rice","1 banana","1 slice bread","xyzzy"]}}}},"RecipeHit":{"type":"object","required":["recipe"],"properties":{"recipe":{"$ref":"#/components/schemas/Recipe"},"_links":{"type":"object","properties":{"self":{"$ref":"#/components/schemas/Link"}}}}},"RecipeSearchResponse":{"type":"object","required":["from","to","count","hits"],"properties":{"from":{"type":"integer"},"to":{"type":"integer"},"count":{"type":"integer"},"_links":{"type":"object","properties":{"next":{"$ref":"#/components/schemas/Link"}}},"hits":{"type":"array","items":{"$ref":"#/components/schemas/RecipeHit"}}}},"MealPlanRequest":{"type":"object","required":["size","plan"],"properties":{"size":{"type":"integer","minimum":1,"maximum":7},"plan":{"$ref":"#/components/schemas/PlanSection"}}},"PlanSection":{"type":"object","properties":{"accept":{"type":"object","required":["all"],"properties":{"all":{"type":"array","maxItems":2,"items":{"type":"object","properties":{"health":{"type":"array","maxItems":2,"items":{"type":"string","enum":["VEGAN","VEGETARIAN","GLUTEN_FREE","DAIRY_FREE","PESCATARIAN"]}},"meal":{"type":"array","maxItems":2,"items":{"type":"string","enum":["breakfast","lunch/dinner","snack"]}},"dish":{"type":"array","maxItems":2,"items":{"type":"string","enum":["main course","salad","cereals","egg"]}}}}}}},"fit":{"type":"object","properties":{"ENERC_KCAL":{"type":"object","properties":{"min":{"type":"number","minimum":0},"max":{"type":"number","minimum":0},"mark":{"type":"number","minimum":0}}},"PROCNT":{"type":"object","properties":{"min":{"type":"number","minimum":0},"max":{"type":"number","minimum":0},"mark":{"type":"number","minimum":0}}},"CHOCDF":{"type":"object","properties":{"min":{"type":"number","minimum":0},"max":{"type":"number","minimum":0},"mark":{"type":"number","minimum":0}}},"FAT":{"type":"object","properties":{"min":{"type":"number","minimum":0},"max":{"type":"number","minimum":0},"mark":{"type":"number","minimum":0}}},"FIBTG":{"type":"object","properties":{"min":{"type":"number","minimum":0},"max":{"type":"number","minimum":0},"mark":{"type":"number","minimum":0}}}}},"exclude":{"type":"array","maxItems":2,"items":{"type":"string","enum":["http://www.edamam.com/ontologies/edamam.owl#recipe_overnight_oats","http://www.edamam.com/ontologies/edamam.owl#recipe_baked_salmon"]}},"sections":{"type":"object","maxProperties":4,"additionalProperties":{"$ref":"#/components/schemas/PlanSection"},"examples":[{"Breakfast":{},"Lunch":{},"Dinner":{}}]}}},"MealPlanResponse":{"type":"object","properties":{"status":{"type":"string","enum":["OK","INCOMPLETE","TIME_OUT"]},"selection":{"type":"array","items":{"type":"object","required":["sections"],"properties":{"sections":{"type":"object","additionalProperties":{"type":"object","properties":{"assigned":{"type":"string"},"_links":{"type":"object","properties":{"self":{"$ref":"#/components/schemas/Link"}}},"sections":{"type":"object"}}}}}}}}},"ShoppingListRequest":{"type":"object","required":["entries"],"properties":{"entries":{"type":"array","minItems":1,"maxItems":3,"items":{"type":"object","required":["quantity","item"],"properties":{"quantity":{"type":"number","exclusiveMinimum":0,"maximum":10},"measure":{"type":"string","enum":["http://www.edamam.com/ontologies/edamam.owl#Measure_serving"]},"item":{"type":"string","examples":["http://www.edamam.com/ontologies/edamam.owl#recipe_overnight_oats","http://www.edamam.com/ontologies/edamam.owl#recipe_chicken_rice_bowl","http://www.edamam.com/ontologies/edamam.owl#recipe_missing"]}}}}}},"ShoppingListResponse":{"type":"object","required":["entries"],"properties":{"entries":{"type":"array","items":{"type":"object","required":["foodId","food","quantities"],"properties":{"foodId":{"type":"string"},"food":{"type":"string"},"quantities":{"type":"array","items":{"type":"object","required":["quantity","measure"],"properties":{"quantity":{"type":"number"},"measure":{"type":"string"},"qualifiers":{"type":"array","items":{"type":"string"}}}}}}}},"_links":{"type":"object","properties":{"shopping-cart":{"$ref":"#/components/schemas/Link"}}}}},"FoodError":{"type":"object","required":["status","message"],"properties":{"status":{"type":"string","enum":["error"]},"message":{"type":"string"},"error":{"type":"string"}}},"RecipeErrors":{"type":"array","items":{"type":"object","required":["errorCode","message"],"properties":{"errorCode":{"type":"string"},"message":{"type":"string"},"params":{"type":"array","items":{"type":"string"}}}}}}}}`);
5646
+ var document = JSON.parse(`{"openapi":"3.1.0","info":{"title":"Edamam APIs (Mockingbird subset)","description":"Stateful emulator subset of Edamam's Food Database v2 (parser, nutrients, image), Nutrition Analysis (nutrition-data, nutrition-details), Recipe Search v2 (search, by-uri, by id), Meal Planner v1 (select) and Shopping List v2, over a built-in corpus. Hand-authored from Edamam's docs and the consumers (edamam-nutrition.adapter.ts, edamam-meal-planning.adapter.ts, the Python chat client's tools/nutrition/client.py).\\n","version":"2","x-mockingbird-upstream":{"note":"Edamam publishes per-API docs, no single OpenAPI; shapes trimmed to the fields our consumers read (zod schemas in edamam-nutrition.adapter.ts and edamam-meal-planning.schemas.ts)."}},"servers":[{"url":"https://api.edamam.com"}],"paths":{"/api/food-database/v2/parser":{"get":{"operationId":"FoodParser","description":"Parse a food description (\`ingr\`) or look up a barcode (\`upc\`): \`parsed\` (the best match with quantity and measure) and \`hints\` (every related food with its measures).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/AppId"},{"$ref":"#/components/parameters/AppKey"},{"name":"ingr","in":"query","required":false,"schema":{"type":"string","enum":["2 large eggs","1 cup cooked rice","banana","chicken breast","greek yogurt","3 slices bread","salmon fillet","chicken salad","xyzzy"]},"description":"Parity vocabulary; the emulator parses any text."},{"name":"upc","in":"query","required":false,"schema":{"type":"string","enum":["850000000012","850000000029","850000000036","000000000000"]}},{"name":"nutrition-type","in":"query","required":false,"schema":{"type":"string","enum":["cooking","logging"]}},{"name":"categoryLabel","in":"query","required":false,"schema":{"type":"string","enum":["food","meal"]}},{"name":"category","in":"query","required":false,"schema":{"type":"string","enum":["generic-foods","packaged-foods","generic-meals"]}},{"name":"health","in":"query","required":false,"schema":{"type":"string","enum":["vegan","vegetarian","gluten-free","dairy-free"]}},{"name":"calories","in":"query","required":false,"schema":{"type":"string","enum":["50-200","300+","100"]}},{"name":"nutrients[PROCNT]","in":"query","required":false,"schema":{"type":"string","enum":["20+","5-15","5"]},"description":"Per 100 g range (\`MIN-MAX\`, \`MIN+\` or \`MAX\`) on a nutrient code. Any nutrient code is accepted as \`nutrients[CODE]\` and repeats combine (best guess, not oracle-verified; see README)."}],"responses":{"200":{"description":"Parser result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParserResponse"}}}},"400":{"description":"Neither ingr nor upc","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}},"401":{"description":"Unknown app_id / app_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}},"404":{"description":"Unknown UPC","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}},"429":{"description":"Usage limits are exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}}}}},"/api/food-database/v2/nutrients":{"post":{"operationId":"FoodNutrients","description":"Full nutrition for foods at given measures.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/AppId"},{"$ref":"#/components/parameters/AppKey"}],"responses":{"200":{"description":"Nutrition","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NutritionAnalysis"}}}},"401":{"description":"Unknown app_id / app_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}},"422":{"description":"Unknown food or measure","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}},"429":{"description":"Usage limits are exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NutrientsRequest"}}}}}},"/api/food-database/nutrients-from-image":{"post":{"operationId":"FoodFromImage","description":"Recognise a plated meal from an image (beta).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/AppId"},{"$ref":"#/components/parameters/AppKey"},{"name":"beta","in":"query","required":false,"schema":{"type":"string","enum":["true"]}}],"responses":{"200":{"description":"Recognition","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisionResponse"}}}},"400":{"description":"Not an image","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}},"401":{"description":"Unknown app_id / app_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}},"429":{"description":"Usage limits are exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageRequest"}}}}}},"/api/nutrition-data":{"get":{"operationId":"NutritionData","description":"Nutrition analysis of one ingredient line.","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/AppId"},{"$ref":"#/components/parameters/AppKey"},{"name":"ingr","in":"query","required":true,"schema":{"type":"string","enum":["1 cup cooked rice","2 large eggs","1 banana","xyzzy"]},"description":"Parity vocabulary; the emulator parses any text."},{"name":"nutrition-type","in":"query","required":false,"schema":{"type":"string","enum":["cooking","logging"]}}],"responses":{"200":{"description":"Nutrition","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NutritionAnalysis"}}}},"401":{"description":"Unknown app_id / app_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}},"422":{"description":"Could not parse the ingredient","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}},"429":{"description":"Usage limits are exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}}}}},"/api/nutrition-details":{"post":{"operationId":"NutritionDetails","description":"Nutrition analysis of a recipe (ingredient lines).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/AppId"},{"$ref":"#/components/parameters/AppKey"}],"responses":{"200":{"description":"Nutrition","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NutritionAnalysis"}}}},"401":{"description":"Unknown app_id / app_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}},"422":{"description":"No ingredients","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}},"429":{"description":"Usage limits are exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}},"555":{"description":"Insufficient quality","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeAnalysisRequest"}}}}}},"/api/recipes/v2":{"get":{"operationId":"RecipeSearch","description":"Recipe search v2 (20 per page, \`_links.next\` carries \`_cont\`).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/AppId"},{"$ref":"#/components/parameters/AppKey"},{"name":"Edamam-Account-User","in":"header","required":false,"schema":{"type":"string","pattern":"^[a-f0-9]{1,30}$","description":"The first 30 hex chars of sha256(user id), as our meal adapter sends it."}},{"name":"type","in":"query","required":true,"schema":{"type":"string","enum":["public","user","any"]}},{"name":"q","in":"query","required":false,"schema":{"type":"string","enum":["chicken","salmon","oats","yogurt","toast","xyzzy"]},"description":"Parity vocabulary; the emulator parses any text."},{"name":"health","in":"query","required":false,"schema":{"type":"string","enum":["vegan","vegetarian","gluten-free","dairy-free","pescatarian"]}},{"name":"diet","in":"query","required":false,"schema":{"type":"string","enum":["high-protein","low-carb","high-fiber","balanced"]}},{"name":"mealType","in":"query","required":false,"schema":{"type":"string","enum":["Breakfast","Lunch","Dinner","Snack"]}},{"name":"dishType","in":"query","required":false,"schema":{"type":"string","enum":["Main course","Salad","Cereals","Egg"]}},{"name":"cuisineType","in":"query","required":false,"schema":{"type":"string","enum":["American","Asian","Mediterranean","French"]}},{"name":"calories","in":"query","required":false,"schema":{"type":"string","enum":["100-400","500+","300"]}},{"name":"time","in":"query","required":false,"schema":{"type":"string","enum":["1-10","30","20+"]}},{"name":"excluded","in":"query","required":false,"schema":{"type":"string","enum":["spinach","almonds"]}},{"name":"imageSize","in":"query","required":false,"schema":{"type":"string","enum":["REGULAR","SMALL","THUMBNAIL","LARGE"]}},{"name":"random","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"Hits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeSearchResponse"}}}},"400":{"description":"Illegal parameter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}},"401":{"description":"Unknown app_id / app_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}},"429":{"description":"Usage limits are exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}}}}},"/api/recipes/v2/by-uri":{"get":{"operationId":"RecipesByUri","description":"Recipes by URI (up to 20 \`uri\` parameters).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/AppId"},{"$ref":"#/components/parameters/AppKey"},{"name":"Edamam-Account-User","in":"header","required":false,"schema":{"type":"string","pattern":"^[a-f0-9]{1,30}$","description":"The first 30 hex chars of sha256(user id), as our meal adapter sends it."}},{"name":"type","in":"query","required":true,"schema":{"type":"string","enum":["public"]}},{"name":"uri","in":"query","required":true,"schema":{"type":"string","enum":["http://www.edamam.com/ontologies/edamam.owl#recipe_overnight_oats","http://www.edamam.com/ontologies/edamam.owl#recipe_baked_salmon","http://www.edamam.com/ontologies/edamam.owl#recipe_missing"]}}],"responses":{"200":{"description":"Hits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeSearchResponse"}}}},"400":{"description":"Illegal parameter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}},"401":{"description":"Unknown app_id / app_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}},"429":{"description":"Usage limits are exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}}}}},"/api/recipes/v2/{id}":{"get":{"operationId":"RecipeById","description":"One recipe (the \`_links.self\` target).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/AppId"},{"$ref":"#/components/parameters/AppKey"},{"name":"Edamam-Account-User","in":"header","required":false,"schema":{"type":"string","pattern":"^[a-f0-9]{1,30}$","description":"The first 30 hex chars of sha256(user id), as our meal adapter sends it."}},{"name":"id","in":"path","required":true,"schema":{"type":"string","enum":["overnight_oats","veggie_omelette","chicken_rice_bowl","missing"]}},{"name":"type","in":"query","required":true,"schema":{"type":"string","enum":["public"]}}],"responses":{"200":{"description":"The recipe","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeHit"}}}},"401":{"description":"Unknown app_id / app_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}},"404":{"description":"Unknown recipe","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}},"429":{"description":"Usage limits are exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}}}}},"/api/meal-planner/v1/{app_id}/select":{"post":{"operationId":"MealPlanSelect","description":"Select recipes for \`size\` days of a plan (Basic auth plus app_id/app_key).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/AppId"},{"$ref":"#/components/parameters/AppKey"},{"name":"Edamam-Account-User","in":"header","required":false,"schema":{"type":"string","pattern":"^[a-f0-9]{1,30}$","description":"The first 30 hex chars of sha256(user id), as our meal adapter sends it."}},{"name":"app_id","in":"path","required":true,"schema":{"type":"string","enum":["parity"]}},{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["public"]}}],"responses":{"200":{"description":"Selection","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MealPlanResponse"}}}},"400":{"description":"Illegal plan","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}},"401":{"description":"Unknown app_id / app_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}},"429":{"description":"Usage limits are exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MealPlanRequest"}}}}}},"/api/shopping-list/v2":{"post":{"operationId":"ShoppingList","description":"Aggregate the ingredients of recipes into a shopping list (optionally a cart link).","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"$ref":"#/components/parameters/AppId"},{"$ref":"#/components/parameters/AppKey"},{"name":"Edamam-Account-User","in":"header","required":false,"schema":{"type":"string","pattern":"^[a-f0-9]{1,30}$","description":"The first 30 hex chars of sha256(user id), as our meal adapter sends it."}},{"name":"shopping-cart","in":"query","required":false,"schema":{"type":"string","enum":["true"]}},{"name":"beta","in":"query","required":false,"schema":{"type":"string","enum":["true"]}}],"responses":{"200":{"description":"Shopping list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShoppingListResponse"}}}},"400":{"description":"Unknown recipe","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}},"401":{"description":"Unknown app_id / app_key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}},"429":{"description":"Usage limits are exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeErrors"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShoppingListRequest"}}}}}}},"components":{"parameters":{"AppId":{"name":"app_id","in":"query","required":true,"description":"Edamam application id (any value unless \`apps\` is set). The parity vocabulary is fixed.","schema":{"type":"string","enum":["parity"]}},"AppKey":{"name":"app_key","in":"query","required":true,"schema":{"type":"string","enum":["parity-key"]}}},"schemas":{"Measure":{"type":"object","required":["uri","label","weight"],"properties":{"uri":{"type":"string"},"label":{"type":"string"},"weight":{"type":"number"}}},"Food":{"type":"object","required":["foodId","label","category","categoryLabel"],"properties":{"foodId":{"type":"string"},"label":{"type":"string"},"knownAs":{"type":"string"},"nutrients":{"type":"object","additionalProperties":{"type":"number"}},"brand":{"type":"string"},"category":{"type":"string"},"categoryLabel":{"type":"string"},"foodContentsLabel":{"type":"string"},"image":{"type":"string"},"servingSizes":{"type":"array","items":{"type":"object"}},"servingsPerContainer":{"type":"number"}}},"Recipe":{"type":"object","required":["uri","label","url","yield","ingredientLines","ingredients","totalNutrients","cautions","dietLabels","healthLabels"],"properties":{"uri":{"type":"string"},"label":{"type":"string"},"image":{"type":"string"},"source":{"type":"string"},"url":{"type":"string"},"shareAs":{"type":"string"},"yield":{"type":"number"},"dietLabels":{"type":"array","items":{"type":"string"}},"healthLabels":{"type":"array","items":{"type":"string"}},"cautions":{"type":"array","items":{"type":"string"}},"ingredientLines":{"type":"array","items":{"type":"string"}},"ingredients":{"type":"array","items":{"type":"object","required":["food","quantity"],"properties":{"text":{"type":"string"},"quantity":{"type":"number"},"measure":{"type":["string","null"]},"food":{"type":"string"},"weight":{"type":"number"},"foodCategory":{"type":["string","null"]},"foodId":{"type":"string"},"image":{"type":["string","null"]}}}},"calories":{"type":"number"},"totalWeight":{"type":"number"},"totalTime":{"type":"number"},"cuisineType":{"type":"array","items":{"type":"string"}},"mealType":{"type":"array","items":{"type":"string"}},"dishType":{"type":"array","items":{"type":"string"}},"totalNutrients":{"type":"object","additionalProperties":{"type":"object","required":["label","quantity","unit"],"properties":{"label":{"type":"string"},"quantity":{"type":"number"},"unit":{"type":"string"}}}},"totalDaily":{"type":"object","additionalProperties":{"type":"object","required":["label","quantity","unit"],"properties":{"label":{"type":"string"},"quantity":{"type":"number"},"unit":{"type":"string"}}}}}},"Link":{"type":"object","required":["href"],"properties":{"href":{"type":"string","x-mockingbird-volatile":{"kind":"url"}},"title":{"type":"string"}}},"ParserResponse":{"type":"object","required":["text","parsed","hints"],"properties":{"text":{"type":"string"},"parsed":{"type":"array","items":{"type":"object","required":["food"],"properties":{"food":{"$ref":"#/components/schemas/Food"},"quantity":{"type":"number"},"measure":{"$ref":"#/components/schemas/Measure"}}}},"hints":{"type":"array","items":{"type":"object","required":["food","measures"],"properties":{"food":{"$ref":"#/components/schemas/Food"},"measures":{"type":"array","items":{"$ref":"#/components/schemas/Measure"}}}}},"_links":{"type":"object"}}},"NutrientsRequest":{"type":"object","required":["ingredients"],"properties":{"ingredients":{"type":"array","minItems":1,"maxItems":3,"items":{"type":"object","required":["quantity","measureURI","foodId"],"properties":{"quantity":{"type":"number","exclusiveMinimum":0,"maximum":20},"measureURI":{"type":"string","examples":["http://www.edamam.com/ontologies/edamam.owl#Measure_unit","http://www.edamam.com/ontologies/edamam.owl#Measure_cup","http://www.edamam.com/ontologies/edamam.owl#Measure_gram"]},"foodId":{"type":"string","examples":["food_egg","food_banana","food_rice_cooked"]},"qualifiers":{"type":"array","items":{"type":"string"}}}}}}},"NutritionAnalysis":{"type":"object","required":["calories","totalWeight","dietLabels","healthLabels","cautions","totalNutrients","totalDaily"],"properties":{"uri":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"calories":{"type":"number"},"totalWeight":{"type":"number"},"dietLabels":{"type":"array","items":{"type":"string"}},"healthLabels":{"type":"array","items":{"type":"string"}},"cautions":{"type":"array","items":{"type":"string"}},"totalNutrients":{"type":"object","additionalProperties":{"type":"object","required":["label","quantity","unit"],"properties":{"label":{"type":"string"},"quantity":{"type":"number"},"unit":{"type":"string"}}}},"totalDaily":{"type":"object","additionalProperties":{"type":"object","required":["label","quantity","unit"],"properties":{"label":{"type":"string"},"quantity":{"type":"number"},"unit":{"type":"string"}}}},"ingredients":{"type":"array","items":{"type":"object"}},"yield":{"type":"number"}}},"ImageRequest":{"type":"object","required":["image"],"properties":{"image":{"type":"string","minLength":1,"maxLength":200,"examples":["data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ==","data:image/png;base64,iVBORw0KGgo="]}}},"VisionResponse":{"type":"object","properties":{"parsed":{"type":"object","properties":{"food":{"$ref":"#/components/schemas/Food"},"quantity":{"type":"number"},"measure":{"$ref":"#/components/schemas/Measure"}}},"recipe":{"type":"object","properties":{"label":{"type":"string"},"calories":{"type":"number"},"totalNutrients":{"type":"object","additionalProperties":{"type":"object","required":["label","quantity","unit"],"properties":{"label":{"type":"string"},"quantity":{"type":"number"},"unit":{"type":"string"}}}}}}}},"RecipeAnalysisRequest":{"type":"object","required":["ingr"],"properties":{"title":{"type":"string","maxLength":80},"yield":{"type":"integer","minimum":1,"maximum":8},"ingr":{"type":"array","maxItems":4,"items":{"type":"string","minLength":1,"maxLength":60,"examples":["2 large eggs","1 cup cooked rice","1 banana","1 slice bread","xyzzy"]}}}},"RecipeHit":{"type":"object","required":["recipe"],"properties":{"recipe":{"$ref":"#/components/schemas/Recipe"},"_links":{"type":"object","properties":{"self":{"$ref":"#/components/schemas/Link"}}}}},"RecipeSearchResponse":{"type":"object","required":["from","to","count","hits"],"properties":{"from":{"type":"integer"},"to":{"type":"integer"},"count":{"type":"integer"},"_links":{"type":"object","properties":{"next":{"$ref":"#/components/schemas/Link"}}},"hits":{"type":"array","items":{"$ref":"#/components/schemas/RecipeHit"}}}},"MealPlanRequest":{"type":"object","required":["size","plan"],"properties":{"size":{"type":"integer","minimum":1,"maximum":7},"plan":{"$ref":"#/components/schemas/PlanSection"}}},"PlanSection":{"type":"object","properties":{"accept":{"type":"object","required":["all"],"properties":{"all":{"type":"array","maxItems":2,"items":{"type":"object","properties":{"health":{"type":"array","maxItems":2,"items":{"type":"string","enum":["VEGAN","VEGETARIAN","GLUTEN_FREE","DAIRY_FREE","PESCATARIAN"]}},"meal":{"type":"array","maxItems":2,"items":{"type":"string","enum":["breakfast","lunch/dinner","snack"]}},"dish":{"type":"array","maxItems":2,"items":{"type":"string","enum":["main course","salad","cereals","egg"]}}}}}}},"fit":{"type":"object","properties":{"ENERC_KCAL":{"type":"object","properties":{"min":{"type":"number","minimum":0},"max":{"type":"number","minimum":0},"mark":{"type":"number","minimum":0}}},"PROCNT":{"type":"object","properties":{"min":{"type":"number","minimum":0},"max":{"type":"number","minimum":0},"mark":{"type":"number","minimum":0}}},"CHOCDF":{"type":"object","properties":{"min":{"type":"number","minimum":0},"max":{"type":"number","minimum":0},"mark":{"type":"number","minimum":0}}},"FAT":{"type":"object","properties":{"min":{"type":"number","minimum":0},"max":{"type":"number","minimum":0},"mark":{"type":"number","minimum":0}}},"FIBTG":{"type":"object","properties":{"min":{"type":"number","minimum":0},"max":{"type":"number","minimum":0},"mark":{"type":"number","minimum":0}}}}},"exclude":{"type":"array","maxItems":2,"items":{"type":"string","enum":["http://www.edamam.com/ontologies/edamam.owl#recipe_overnight_oats","http://www.edamam.com/ontologies/edamam.owl#recipe_baked_salmon"]}},"sections":{"type":"object","maxProperties":4,"additionalProperties":{"$ref":"#/components/schemas/PlanSection"},"examples":[{"Breakfast":{},"Lunch":{},"Dinner":{}}]}}},"MealPlanResponse":{"type":"object","properties":{"status":{"type":"string","enum":["OK","INCOMPLETE","TIME_OUT"]},"selection":{"type":"array","items":{"type":"object","required":["sections"],"properties":{"sections":{"type":"object","additionalProperties":{"type":"object","properties":{"assigned":{"type":"string"},"_links":{"type":"object","properties":{"self":{"$ref":"#/components/schemas/Link"}}},"sections":{"type":"object"}}}}}}}}},"ShoppingListRequest":{"type":"object","required":["entries"],"properties":{"entries":{"type":"array","minItems":1,"maxItems":3,"items":{"type":"object","required":["quantity","item"],"properties":{"quantity":{"type":"number","exclusiveMinimum":0,"maximum":10},"measure":{"type":"string","enum":["http://www.edamam.com/ontologies/edamam.owl#Measure_serving"]},"item":{"type":"string","examples":["http://www.edamam.com/ontologies/edamam.owl#recipe_overnight_oats","http://www.edamam.com/ontologies/edamam.owl#recipe_chicken_rice_bowl","http://www.edamam.com/ontologies/edamam.owl#recipe_missing"]}}}}}},"ShoppingListResponse":{"type":"object","required":["entries"],"properties":{"entries":{"type":"array","items":{"type":"object","required":["foodId","food","quantities"],"properties":{"foodId":{"type":"string"},"food":{"type":"string"},"quantities":{"type":"array","items":{"type":"object","required":["quantity","measure"],"properties":{"quantity":{"type":"number"},"measure":{"type":"string"},"qualifiers":{"type":"array","items":{"type":"string"}}}}}}}},"_links":{"type":"object","properties":{"shopping-cart":{"$ref":"#/components/schemas/Link"}}}}},"FoodError":{"type":"object","required":["status","message"],"properties":{"status":{"type":"string","enum":["error"]},"message":{"type":"string"},"error":{"type":"string"}}},"RecipeErrors":{"type":"array","items":{"type":"object","required":["errorCode","message"],"properties":{"errorCode":{"type":"string"},"message":{"type":"string"},"params":{"type":"array","items":{"type":"string"}}}}}}}}`);
5647
5647
  var operationIds = ["FoodParser", "FoodNutrients", "FoodFromImage", "NutritionData", "NutritionDetails", "RecipeSearch", "RecipesByUri", "RecipeById", "MealPlanSelect", "ShoppingList"];
5648
5648
  var supportedOperationIds = ["FoodParser", "FoodNutrients", "FoodFromImage", "NutritionData", "NutritionDetails", "RecipeSearch", "RecipesByUri", "RecipeById", "MealPlanSelect", "ShoppingList"];
5649
5649
 
@@ -5731,7 +5731,7 @@ var relatedFoods = (text, foods) => {
5731
5731
  var parseRange = (value) => {
5732
5732
  const both = /^(\d+(?:\.\d+)?)-(\d+(?:\.\d+)?)$/.exec(value);
5733
5733
  if (both) return { min: Number(both[1]), max: Number(both[2]) };
5734
- const plus = /^(\d+(?:\.\d+)?)\+$/.exec(value);
5734
+ const plus = /^(\d+(?:\.\d+)?)[+ ]$/.exec(value);
5735
5735
  if (plus) return { min: Number(plus[1]), max: Number.POSITIVE_INFINITY };
5736
5736
  if (/^\d+(\.\d+)?$/.test(value)) return { min: 0, max: Number(value) };
5737
5737
  return void 0;
@@ -6237,12 +6237,25 @@ var EdamamAPI = class {
6237
6237
  if (caloriesParam && !calories) {
6238
6238
  return foodError(400, "bad_request", `Illegal value for calories: ${caloriesParam}`);
6239
6239
  }
6240
+ const nutrientRanges = [];
6241
+ for (const [key, value] of url.searchParams) {
6242
+ const code = /^nutrients\[(.*)\]$/.exec(key)?.[1];
6243
+ if (code === void 0) continue;
6244
+ const range = parseRange(value);
6245
+ if (!/^[A-Za-z][A-Za-z0-9_.]*$/.test(code) || !range) {
6246
+ return foodError(400, "bad_request", `Illegal value for ${key}: ${value}`);
6247
+ }
6248
+ nutrientRanges.push({ code, ...range });
6249
+ }
6240
6250
  const categories = {
6241
6251
  "generic-foods": "Generic foods",
6242
6252
  "packaged-foods": "Packaged foods",
6243
6253
  "generic-meals": "Generic meals"
6244
6254
  };
6245
- return (food2) => (!categoryLabel || food2.categoryLabel === categoryLabel) && (!category || food2.category === categories[category]) && health.every((h) => food2.healthLabels.includes(h)) && (!calories || food2.nutrients.ENERC_KCAL !== void 0 && food2.nutrients.ENERC_KCAL >= calories.min && food2.nutrients.ENERC_KCAL <= calories.max);
6255
+ return (food2) => (!categoryLabel || food2.categoryLabel === categoryLabel) && (!category || food2.category === categories[category]) && health.every((h) => food2.healthLabels.includes(h)) && nutrientRanges.every(({ code, min, max }) => {
6256
+ const quantity = food2.nutrients[code];
6257
+ return quantity !== void 0 && quantity >= min && quantity <= max;
6258
+ }) && (!calories || food2.nutrients.ENERC_KCAL !== void 0 && food2.nutrients.ENERC_KCAL >= calories.min && food2.nutrients.ENERC_KCAL <= calories.max);
6246
6259
  }
6247
6260
  parser(context) {
6248
6261
  const url = context.url;
@@ -6631,4 +6644,4 @@ export {
6631
6644
  appIdCredential,
6632
6645
  EdamamAPI
6633
6646
  };
6634
- //# sourceMappingURL=chunk-ULEKWBW5.js.map
6647
+ //# sourceMappingURL=chunk-3UCNVLYD.js.map