{"_id":"@brandcast_app/mealviewer-api-client","_rev":"4-73eae3d1b83f6d50291b952faca79fde","name":"@brandcast_app/mealviewer-api-client","dist-tags":{"latest":"0.2.2"},"versions":{"0.1.0":{"name":"@brandcast_app/mealviewer-api-client","version":"0.1.0","keywords":["mealviewer","school-lunch","menu","api-client","typescript","javascript","familycast","brandcast"],"author":{"name":"BrandCast Team"},"license":"MIT","_id":"@brandcast_app/mealviewer-api-client@0.1.0","maintainers":[{"name":"jamieeduncan","email":"jamie@brandcast.app"}],"homepage":"https://github.com/BrandCast-Signage/mealviewer-api-client#readme","bugs":{"url":"https://github.com/BrandCast-Signage/mealviewer-api-client/issues"},"dist":{"shasum":"508655a1ddfb4f9fb6b03b30877f7f6af67a425d","tarball":"https://registry.npmjs.org/@brandcast_app/mealviewer-api-client/-/mealviewer-api-client-0.1.0.tgz","fileCount":9,"integrity":"sha512-7a0X+DcwJGZHcWI0/yDs3fSgwLmWeq92DxG4ntipHMPgIM++vm3M+X6bVdvNlvt73rz5lNStl8bfyHM1KQ4h2Q==","signatures":[{"sig":"MEUCIBnebkYm9VgNBsdrC3QXqY+MbiurWW7GxdzP9e9IhFwmAiEAh5jXOkXLFTFy/nBPKw45jroHxlG8MKEydCjT6dpKQMc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":21084},"jest":{"preset":"ts-jest","testMatch":["**/src/__tests__/**/*.test.ts"],"testEnvironment":"node","collectCoverageFrom":["src/**/*.ts","!src/**/*.d.ts"]},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=16.0.0"},"gitHead":"db71d75ab22e2ba845f63ed74460a6783bcebaff","scripts":{"test":"jest","build":"tsc","test:coverage":"jest --coverage","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"jamieeduncan","email":"jamie@brandcast.app"},"repository":{"url":"git+https://github.com/BrandCast-Signage/mealviewer-api-client.git","type":"git"},"_npmVersion":"10.9.3","description":"TypeScript/JavaScript client for MealViewer School Lunch Menu API","directories":{},"_nodeVersion":"22.18.0","dependencies":{"axios":"^1.7.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.5.0","ts-jest":"^29.1.0","typescript":"^5.0.0","@types/jest":"^29.5.0","@types/node":"^20.0.0"},"_npmOperationalInternal":{"tmp":"tmp/mealviewer-api-client_0.1.0_1762893001182_0.9180157594743021","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@brandcast_app/mealviewer-api-client","version":"0.2.0","keywords":["mealviewer","school-lunch","menu","api-client","typescript","javascript","familycast","brandcast"],"author":{"name":"BrandCast Team"},"license":"MIT","_id":"@brandcast_app/mealviewer-api-client@0.2.0","maintainers":[{"name":"jamieeduncan","email":"jamie@brandcast.app"}],"homepage":"https://github.com/BrandCast-Signage/mealviewer-api-client#readme","bugs":{"url":"https://github.com/BrandCast-Signage/mealviewer-api-client/issues"},"dist":{"shasum":"f869ffbb75cf6a7ed659fddafe9ea4953d5f5dc8","tarball":"https://registry.npmjs.org/@brandcast_app/mealviewer-api-client/-/mealviewer-api-client-0.2.0.tgz","fileCount":10,"integrity":"sha512-nqrqglRDrJjPTDw5zcrfCYprIvspkY/k2oPNDWoUSNVklhv+jvJnah1XhFmLY8nesE5NIphDCg+4dFSUOlpt/g==","signatures":[{"sig":"MEQCIHIzb/rhcmN72giS7LkG7/HzXZanACW6spjG6KIA6G1lAiB1cX8wGwFaN717U5v9jhbTor//FcXDL9lTOWY4UUzz/Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":35112},"jest":{"preset":"ts-jest","testMatch":["**/src/__tests__/**/*.test.ts"],"testEnvironment":"node","collectCoverageFrom":["src/**/*.ts","!src/**/*.d.ts"]},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=16.0.0"},"gitHead":"92b5facede585ac09b0e81053e7b9475ce75ec51","scripts":{"test":"jest","build":"tsc","type-check":"tsc --noEmit","test:coverage":"jest --coverage","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"jamieeduncan","email":"jamie@brandcast.app"},"repository":{"url":"git+https://github.com/BrandCast-Signage/mealviewer-api-client.git","type":"git"},"_npmVersion":"10.9.3","description":"TypeScript/JavaScript client for MealViewer School Lunch Menu API","directories":{},"_nodeVersion":"22.18.0","dependencies":{"axios":"^1.7.0","@google-cloud/storage":"^7.0.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.5.0","ts-jest":"^29.1.0","typescript":"^5.0.0","@types/jest":"^29.5.0","@types/node":"^20.0.0"},"_npmOperationalInternal":{"tmp":"tmp/mealviewer-api-client_0.2.0_1762902151971_0.6553587405070205","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@brandcast_app/mealviewer-api-client","version":"0.2.1","keywords":["mealviewer","school-lunch","menu","api-client","typescript","javascript","familycast","brandcast"],"author":{"name":"BrandCast Team"},"license":"MIT","_id":"@brandcast_app/mealviewer-api-client@0.2.1","maintainers":[{"name":"jamieeduncan","email":"jamie@brandcast.app"}],"homepage":"https://github.com/BrandCast-Signage/mealviewer-api-client#readme","bugs":{"url":"https://github.com/BrandCast-Signage/mealviewer-api-client/issues"},"dist":{"shasum":"eba0e8a85b2aa5339a24beedd1f0b1fb241def84","tarball":"https://registry.npmjs.org/@brandcast_app/mealviewer-api-client/-/mealviewer-api-client-0.2.1.tgz","fileCount":10,"integrity":"sha512-mnEr10/eSlLsTygI9uCBYJk5JXNhkB4x+tl5GpZXjVqiKLJEnZ6vRuIPndaOe6OckG1PYARLwmhwFCjYgqJknA==","signatures":[{"sig":"MEUCIQD/IethyakV8oF/cMoXTzDHP6jF0HeB/3tlFrAIoE7PTgIgR1vBVAN4XNWrxYbgeKdSoDfAyL0ID37mZ5P+rlkqIKQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":32348},"jest":{"preset":"ts-jest","testMatch":["**/src/__tests__/**/*.test.ts"],"testEnvironment":"node","collectCoverageFrom":["src/**/*.ts","!src/**/*.d.ts"]},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=16.0.0"},"gitHead":"92b5facede585ac09b0e81053e7b9475ce75ec51","scripts":{"test":"jest","build":"tsc","type-check":"tsc --noEmit","test:coverage":"jest --coverage","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"jamieeduncan","email":"jamie@brandcast.app"},"repository":{"url":"git+https://github.com/BrandCast-Signage/mealviewer-api-client.git","type":"git"},"_npmVersion":"10.9.3","description":"TypeScript/JavaScript client for MealViewer School Lunch Menu API","directories":{},"_nodeVersion":"22.18.0","dependencies":{"axios":"^1.7.0"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.5.0","ts-jest":"^29.1.0","typescript":"^5.0.0","@types/jest":"^29.5.0","@types/node":"^20.0.0"},"_npmOperationalInternal":{"tmp":"tmp/mealviewer-api-client_0.2.1_1762904499270_0.9488274445860398","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"@brandcast_app/mealviewer-api-client","version":"0.2.2","description":"TypeScript/JavaScript client for MealViewer School Lunch Menu API","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc","type-check":"tsc --noEmit","test":"jest","test:coverage":"jest --coverage","prepublishOnly":"npm run build && npm test"},"keywords":["mealviewer","school-lunch","menu","api-client","typescript","javascript","familycast","brandcast"],"author":{"name":"BrandCast Team"},"license":"MIT","engines":{"node":">=16.0.0"},"repository":{"type":"git","url":"git+https://github.com/BrandCast-Signage/mealviewer-api-client.git"},"bugs":{"url":"https://github.com/BrandCast-Signage/mealviewer-api-client/issues"},"homepage":"https://github.com/BrandCast-Signage/mealviewer-api-client#readme","dependencies":{"axios":"^1.7.0"},"devDependencies":{"@types/jest":"^29.5.0","@types/node":"^20.0.0","jest":"^29.5.0","ts-jest":"^29.1.0","typescript":"^5.0.0"},"jest":{"preset":"ts-jest","testEnvironment":"node","testMatch":["**/src/__tests__/**/*.test.ts"],"collectCoverageFrom":["src/**/*.ts","!src/**/*.d.ts"]},"_id":"@brandcast_app/mealviewer-api-client@0.2.2","gitHead":"5098782194ed6fdf27dbe42978ecadd86dc56aa1","_nodeVersion":"22.18.0","_npmVersion":"10.9.3","dist":{"integrity":"sha512-UouwLkjx59xPbjRmiyw5XLnygQUHUUFccBGcS8MYSmr+AvAMQc4l7b3npdpoRLCHxRjcElFmnM0RLv6t7xYvEw==","shasum":"8e5f5fdee663fd464e1bd19fb28c6735c0573b90","tarball":"https://registry.npmjs.org/@brandcast_app/mealviewer-api-client/-/mealviewer-api-client-0.2.2.tgz","fileCount":10,"unpackedSize":34225,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDb1c0LS3ynawygbYG6hJ74ZLPXTEYuumN9fAbun2ovtwIgOlpkGPNS4KsSVknhjqnA8PSEZM5Cq4l4tx5A9PxWBP4="}]},"_npmUser":{"name":"jamieeduncan","email":"jamie@brandcast.app"},"directories":{},"maintainers":[{"name":"jamieeduncan","email":"jamie@brandcast.app"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/mealviewer-api-client_0.2.2_1762959684487_0.07103092552156198"},"_hasShrinkwrap":false}},"time":{"created":"2025-11-11T20:30:01.085Z","modified":"2025-11-12T15:01:24.875Z","0.1.0":"2025-11-11T20:30:01.374Z","0.2.0":"2025-11-11T23:02:32.171Z","0.2.1":"2025-11-11T23:41:39.457Z","0.2.2":"2025-11-12T15:01:24.667Z"},"bugs":{"url":"https://github.com/BrandCast-Signage/mealviewer-api-client/issues"},"author":{"name":"BrandCast Team"},"license":"MIT","homepage":"https://github.com/BrandCast-Signage/mealviewer-api-client#readme","keywords":["mealviewer","school-lunch","menu","api-client","typescript","javascript","familycast","brandcast"],"repository":{"type":"git","url":"git+https://github.com/BrandCast-Signage/mealviewer-api-client.git"},"description":"TypeScript/JavaScript client for MealViewer School Lunch Menu API","maintainers":[{"name":"jamieeduncan","email":"jamie@brandcast.app"}],"readme":"# MealViewer API Client\n\n[![npm version](https://badge.fury.io/js/%40brandcast_app%2Fmealviewer-api-client.svg)](https://badge.fury.io/js/%40brandcast_app%2Fmealviewer-api-client)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nTypeScript/JavaScript client for the MealViewer School Lunch Menu API.\n\n## Features\n\n- 🔍 Search for schools by name, district, city, or state\n- 📅 Fetch school lunch menus by date\n- 🍎 Access nutrition information and allergens\n- 📦 TypeScript support with full type definitions\n- 🛡️ Error handling and type safety\n- 🐛 Optional debug logging\n- ✅ Public API (no authentication required)\n\n## Installation\n\n```bash\nnpm install @brandcast_app/mealviewer-api-client\n```\n\nor\n\n```bash\nyarn add @brandcast_app/mealviewer-api-client\n```\n\n## Quick Start\n\n```typescript\nimport { MealViewerClient } from '@brandcast_app/mealviewer-api-client';\n\n// Create a client instance\nconst client = new MealViewerClient({\n  debug: true, // Optional: enable debug logging\n  timeout: 30000, // Optional: request timeout in ms (default: 30000)\n});\n\n// Get today's menu for a school\nconst today = new Date().toISOString().split('T')[0]; // YYYY-MM-DD\n\nconst result = await client.getMenu({\n  schoolName: 'ElmwoodElementary',\n  startDate: today,\n});\n\n// Display menus\nfor (const menu of result.menus) {\n  console.log(`\\nMenu for ${menu.date.toDateString()}`);\n  console.log(`School: ${menu.school.name}`);\n\n  for (const meal of menu.meals) {\n    console.log(`\\n${meal.mealPeriod}:`);\n\n    for (const line of meal.cafeteriaLines) {\n      console.log(`  ${line.name}:`);\n\n      for (const item of line.items) {\n        console.log(`    - ${item.name} (${item.servingSize})`);\n      }\n    }\n  }\n}\n```\n\n## API Reference\n\n### Constructor\n\n#### `new MealViewerClient(config?)`\n\nCreate a new MealViewer API client.\n\n**Parameters:**\n- `config` (optional): Configuration object\n  - `baseURL` (string): API base URL (default: `https://api.mealviewer.com/api/v4`)\n  - `timeout` (number): Request timeout in ms (default: `30000`)\n  - `userAgent` (string): Custom user agent\n  - `debug` (boolean): Enable debug logging (default: `false`)\n\n**Example:**\n```typescript\nconst client = new MealViewerClient({ debug: true });\n```\n\n---\n\n### Methods\n\n#### `searchSchools(query: string): Promise<SchoolSearchResult[]>`\n\nSearch for schools by name, district, city, or state.\n\n**Parameters:**\n- `query` (string): Search query (minimum 2 characters)\n\n**Returns:** Promise with array of matching schools (empty array if no matches)\n\n**Example:**\n```typescript\n// Search for schools\nconst results = await client.searchSchools('elmwood');\n\nconsole.log(`Found ${results.length} schools`);\nfor (const school of results) {\n  console.log(`${school.name} - ${school.district}`);\n  console.log(`  ${school.city}, ${school.state}`);\n  console.log(`  Identifier: ${school.identifier}`);\n}\n```\n\n**Search Tips:**\n- Searches across school name, district, city, state, and identifier\n- Case-insensitive matching\n- Partial matches supported (e.g., \"spring\" matches \"Springfield\")\n- Results are cached for 1 hour for better performance\n\n---\n\n#### `getMenu(request: GetMenuRequest): Promise<GetMenuResponse>`\n\nGet menu for a school and date range.\n\n**Parameters:**\n- `request.schoolName` (string): School identifier (e.g., `\"ElmwoodElementary\"`)\n- `request.startDate` (Date | string): Start date (YYYY-MM-DD or Date object)\n- `request.endDate` (Date | string, optional): End date (defaults to startDate)\n\n**Returns:** Promise with menus and school information\n\n**Example:**\n```typescript\n// Get menu for single day\nconst result = await client.getMenu({\n  schoolName: 'ElmwoodElementary',\n  startDate: '2025-01-15',\n});\n\n// Get menu for date range (week)\nconst weekResult = await client.getMenu({\n  schoolName: 'ElmwoodElementary',\n  startDate: '2025-01-13', // Monday\n  endDate: '2025-01-17',   // Friday\n});\n\nconsole.log(`Found ${weekResult.menus.length} days of menus`);\n```\n\n---\n\n## Type Definitions\n\n### SchoolSearchResult\n\n```typescript\ninterface SchoolSearchResult {\n  identifier: string;     // School identifier for getMenu() calls\n  name: string;           // School name\n  district: string;       // School district name\n  city?: string;          // City\n  state?: string;         // State (e.g., \"MO\", \"KS\")\n  address?: string;       // Street address\n  zip?: string;           // ZIP code\n}\n```\n\n### GetMenuResponse\n\n```typescript\ninterface GetMenuResponse {\n  menus: DailyMenu[];\n  school: MealViewerSchool;\n}\n```\n\n### DailyMenu\n\n```typescript\ninterface DailyMenu {\n  date: Date;\n  school: MealViewerSchool;\n  meals: MenuBlock[];\n}\n```\n\n### MenuBlock\n\n```typescript\ninterface MenuBlock {\n  mealPeriod: 'Breakfast' | 'Lunch' | 'Dinner' | 'Snack';\n  cafeteriaLines: CafeteriaLine[];\n}\n```\n\n### CafeteriaLine\n\n```typescript\ninterface CafeteriaLine {\n  name: string;\n  items: MenuItem[];\n}\n```\n\n### MenuItem\n\n```typescript\ninterface MenuItem {\n  name: string;\n  altName?: string;\n  description?: string;\n  type: 'Entree' | 'Side' | 'Vegetable' | 'Fruit' | 'Milk' | 'Condiment' | string;\n  servingSize: string;\n  nutrition?: NutritionFacts;\n  allergens?: string[];\n}\n```\n\n### MealViewerSchool\n\n```typescript\ninterface MealViewerSchool {\n  name: string;\n  address: string;\n  city: string;\n  state?: string;\n  latitude?: number;\n  longitude?: number;\n}\n```\n\n---\n\n## Error Handling\n\nThe client throws `MealViewerError` with a specific error code:\n\n```typescript\nclass MealViewerError extends Error {\n  code: 'SCHOOL_NOT_FOUND' | 'API_ERROR' | 'INVALID_DATE' | 'NETWORK_ERROR';\n}\n```\n\n**Example:**\n```typescript\ntry {\n  const result = await client.getMenu({\n    schoolName: 'InvalidSchool',\n    startDate: '2025-01-15',\n  });\n} catch (error) {\n  if (error instanceof MealViewerError) {\n    console.error('Error code:', error.code);\n    console.error('Error message:', error.message);\n\n    if (error.code === 'SCHOOL_NOT_FOUND') {\n      console.log('Please check the school name and try again.');\n    }\n  }\n}\n```\n\n---\n\n## Finding School Names\n\nUse the `searchSchools()` method to find schools:\n\n```typescript\n// Search for schools in Springfield\nconst schools = await client.searchSchools('springfield');\n\n// Search by district\nconst districtSchools = await client.searchSchools('blue valley');\n\n// Search by state\nconst moSchools = await client.searchSchools('MO');\n```\n\nOnce you find your school, use the `identifier` field to fetch menus:\n\n```typescript\nconst results = await client.searchSchools('elmwood');\nif (results.length > 0) {\n  const school = results[0];\n\n  const menu = await client.getMenu({\n    schoolName: school.identifier, // Use the identifier\n    startDate: '2025-01-15',\n  });\n}\n```\n\n---\n\n## Complete Example\n\n```typescript\nimport { MealViewerClient, MealViewerError } from '@brandcast_app/mealviewer-api-client';\n\nasync function main() {\n  const client = new MealViewerClient({ debug: true });\n\n  try {\n    // Step 1: Search for a school\n    console.log('Searching for schools...');\n    const schools = await client.searchSchools('elmwood');\n\n    if (schools.length === 0) {\n      console.log('No schools found');\n      return;\n    }\n\n    console.log(`Found ${schools.length} school(s):`);\n    for (const school of schools) {\n      console.log(`  - ${school.name} (${school.district})`);\n      console.log(`    ${school.city}, ${school.state}`);\n    }\n\n    // Step 2: Get this week's menus for the first school\n    const selectedSchool = schools[0];\n    console.log(`\\nFetching menus for: ${selectedSchool.name}`);\n\n    const monday = new Date('2025-01-13');\n    const friday = new Date('2025-01-17');\n\n    const result = await client.getMenu({\n      schoolName: selectedSchool.identifier,\n      startDate: monday,\n      endDate: friday,\n    });\n\n    console.log(`\\n${result.school.name}`);\n    console.log(`${result.school.address}, ${result.school.city}`);\n    console.log(`\\nMenus for ${result.menus.length} days:\\n`);\n\n    for (const menu of result.menus) {\n      console.log(`\\n=== ${menu.date.toDateString()} ===`);\n\n      const lunch = menu.meals.find(m => m.mealPeriod === 'Lunch');\n\n      if (lunch) {\n        for (const line of lunch.cafeteriaLines) {\n          console.log(`\\n${line.name}:`);\n          for (const item of line.items) {\n            console.log(`  • ${item.name} - ${item.servingSize}`);\n            if (item.description) {\n              console.log(`    ${item.description}`);\n            }\n          }\n        }\n      }\n    }\n\n  } catch (error) {\n    if (error instanceof MealViewerError) {\n      console.error(`\\n❌ ${error.code}: ${error.message}`);\n    } else {\n      console.error('Unexpected error:', error);\n    }\n  }\n}\n\nmain();\n```\n\n---\n\n## Development\n\n### Building\n\n```bash\nnpm install\nnpm run build\n```\n\n### Testing\n\n```bash\nnpm test\nnpm run test:coverage\n```\n\n---\n\n## Use Cases\n\nThis client is useful for:\n- 📱 Family information displays (FamilyCast)\n- 🏫 School district apps\n- 📧 Parent notification systems\n- 🤖 Chat bot integrations (e.g., Claude Desktop via MCP)\n- 📊 Menu analytics and tracking\n\n---\n\n## Related Projects\n\n- [mealviewer-mcp-server](https://github.com/BrandCast-Signage/mealviewer-mcp-server) - MCP server for Claude Desktop\n- [FamilyCast](https://familycast.app) - Family information displays\n\n---\n\n## Legal\n\nThis is an unofficial library and is not affiliated with, endorsed by, or connected to MealViewer. The MealViewer API is public and does not require authentication.\n\n---\n\n## License\n\nMIT License - see [LICENSE](LICENSE) file for details.\n\n---\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n---\n\n## Support\n\n- 🐛 [Report Issues](https://github.com/BrandCast-Signage/mealviewer-api-client/issues)\n- 💬 [Discussions](https://github.com/BrandCast-Signage/mealviewer-api-client/discussions)\n\n---\n\n## Changelog\n\n### 0.2.0\n\n- 🔍 Added `searchSchools()` method for finding schools\n- 📚 School database with 20+ Missouri/Kansas area schools\n- 💾 Automatic caching of school database (1 hour TTL)\n- 📖 Updated documentation with search examples\n- 🎯 Enhanced type exports with `SchoolSearchResult`\n\n### 0.1.0 (Initial Release)\n\n- ✨ Initial implementation\n- 📅 Fetch menus by date range\n- 🍎 Access menu items, nutrition, allergens\n- 📦 Full TypeScript support\n- 🐛 Debug logging option\n","readmeFilename":"README.md"}