{"_id":"@bluessu/meal-scraper","_rev":"3-50568d2901f4266ed308565903b54248","name":"@bluessu/meal-scraper","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.0":{"name":"@bluessu/meal-scraper","version":"0.1.0","keywords":["ssu","soongsil","meal","scraper","dormitory","typescript","node"],"author":{"name":"bluessu"},"license":"GPL-3.0-only","_id":"@bluessu/meal-scraper@0.1.0","maintainers":[{"name":"phw3071","email":"phw3071@gmail.com"}],"homepage":"https://github.com/blue-ssu/meal-scraper#readme","bugs":{"url":"https://github.com/blue-ssu/meal-scraper/issues"},"dist":{"shasum":"f719d48fb7818a81b98e3d45b0159f1fab345677","tarball":"https://registry.npmjs.org/@bluessu/meal-scraper/-/meal-scraper-0.1.0.tgz","fileCount":7,"integrity":"sha512-N1NdU0XfH6fFPSbFA0ZIPCBACHtBBVts4tn2MCwWXfHECPw8K9NFrzuIwlB98N8hUJF4YX5UVGDHWGwj6Hkzag==","signatures":[{"sig":"MEUCIQCF8j/J7qKsC5fucoLYvq6OZDwPPVzwcpmM5BRi4UQBzgIgaLg724NUWMuWESy2qCbrO2mY8oKOOHWlzn8T6BjQNF0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":77114},"main":"dist/index.cjs","type":"commonjs","_from":"file:bluessu-meal-scraper-0.1.0.tgz","types":"dist/index.d.ts","module":"dist/index.mjs","engines":{"node":">=18"},"exports":{".":{"import":"./dist/index.mjs","require":"./dist/index.cjs"}},"funding":"https://github.com/blue-ssu/meal-scraper","private":false,"scripts":{"build":"tsup","clean":"rimraf dist","quality":"pnpm run clean && pnpm run typecheck && pnpm run build","typecheck":"tsc --noEmit -p tsconfig.json","release:major":"pnpm version major && pnpm publish --access public","release:minor":"pnpm version minor && pnpm publish --access public","release:patch":"pnpm version patch && pnpm publish --access public"},"_npmUser":{"name":"phw3071","email":"phw3071@gmail.com"},"_resolved":"/private/var/folders/sw/gdbk9lxj5mlfck658p6kyjx00000gn/T/99f744072756c2b6027c1ae5f5c6abce/bluessu-meal-scraper-0.1.0.tgz","_integrity":"sha512-N1NdU0XfH6fFPSbFA0ZIPCBACHtBBVts4tn2MCwWXfHECPw8K9NFrzuIwlB98N8hUJF4YX5UVGDHWGwj6Hkzag==","repository":{"url":"git+https://github.com/blue-ssu/meal-scraper.git","type":"git"},"_npmVersion":"11.8.0","description":"A meal menu scraper for dormitory meal info.","directories":{},"_nodeVersion":"24.13.1","dependencies":{"axios":"^1.13.6","cheerio":"^1.2.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","rimraf":"^5.0.9","typescript":"^5.5.4","@types/node":"^22.7.1"},"optionalDependencies":{"openai":"^4.57.0"},"_npmOperationalInternal":{"tmp":"tmp/meal-scraper_0.1.0_1772263453797_0.7781277873170427","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@bluessu/meal-scraper","version":"0.1.1","keywords":["ssu","soongsil","meal","scraper","dormitory","typescript","node"],"author":{"name":"bluessu"},"license":"GPL-3.0-only","_id":"@bluessu/meal-scraper@0.1.1","maintainers":[{"name":"phw3071","email":"phw3071@gmail.com"}],"homepage":"https://github.com/blue-ssu/meal-scraper#readme","bugs":{"url":"https://github.com/blue-ssu/meal-scraper/issues"},"dist":{"shasum":"610b5489287422b6a3e055c8c7b0ad619d17f193","tarball":"https://registry.npmjs.org/@bluessu/meal-scraper/-/meal-scraper-0.1.1.tgz","fileCount":7,"integrity":"sha512-EGvgbw7FPv3bY/bIBdSoZewp0SEI/ja17sEAh0QPprC1PiuLMeDqHp1ndWeVO2cXSUOpMhQB9xCSOFrKRLo46A==","signatures":[{"sig":"MEUCIQCHEVi0wFNxkHxe2o+N+fqVj+XUaVNedckx7B7iUsegLwIgfrBAdxphgX/ShlBET+8vpT7rzK/W4FTWeFdSaFBVnJ8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":84029},"main":"dist/index.cjs","type":"commonjs","types":"dist/index.d.ts","module":"dist/index.mjs","engines":{"node":">=18"},"exports":{".":{"import":"./dist/index.mjs","require":"./dist/index.cjs"}},"funding":"https://github.com/blue-ssu/meal-scraper","gitHead":"2f5b5d21ebe837de8e14124ed6a695eaa4132e33","private":false,"scripts":{"build":"tsup","clean":"rimraf dist","prepack":"pnpm run quality","prepare":"pnpm run build","quality":"pnpm run clean && pnpm run typecheck && pnpm run build","typecheck":"tsc --noEmit -p tsconfig.json","release:major":"pnpm version major && pnpm publish --access public","release:minor":"pnpm version minor && pnpm publish --access public","release:patch":"pnpm version patch && pnpm publish --access public","prepublishOnly":"pnpm run quality"},"_npmUser":{"name":"phw3071","email":"phw3071@gmail.com"},"repository":{"url":"git+https://github.com/blue-ssu/meal-scraper.git","type":"git"},"_npmVersion":"11.8.0","description":"A meal menu scraper for dormitory meal info.","directories":{},"_nodeVersion":"24.13.1","dependencies":{"axios":"^1.13.6","cheerio":"^1.2.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","rimraf":"^5.0.9","typescript":"^5.5.4","@types/node":"^22.7.1"},"optionalDependencies":{"openai":"^4.57.0"},"_npmOperationalInternal":{"tmp":"tmp/meal-scraper_0.1.1_1772281315275_0.05237854435720335","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@bluessu/meal-scraper","private":false,"version":"0.1.2","description":"A meal menu scraper for dormitory meal info.","type":"commonjs","author":{"name":"bluessu"},"license":"GPL-3.0-only","homepage":"https://github.com/blue-ssu/meal-scraper#readme","keywords":["ssu","soongsil","meal","scraper","dormitory","typescript","node"],"repository":{"type":"git","url":"git+https://github.com/blue-ssu/meal-scraper.git"},"bugs":{"url":"https://github.com/blue-ssu/meal-scraper/issues"},"publishConfig":{"access":"public"},"main":"dist/index.cjs","module":"dist/index.mjs","types":"dist/index.d.ts","exports":{".":{"require":"./dist/index.cjs","import":"./dist/index.mjs"}},"funding":"https://github.com/blue-ssu/meal-scraper","scripts":{"typecheck":"tsc --noEmit -p tsconfig.json","build":"tsup","clean":"rimraf dist","prepare":"pnpm run build","quality":"pnpm run clean && pnpm run typecheck && pnpm run build","prepublishOnly":"pnpm run quality","prepack":"pnpm run quality","release:patch":"pnpm version patch && pnpm publish --access public","release:minor":"pnpm version minor && pnpm publish --access public","release:major":"pnpm version major && pnpm publish --access public"},"engines":{"node":">=18"},"dependencies":{"axios":"^1.13.6","cheerio":"^1.2.0"},"optionalDependencies":{"openai":"^4.57.0"},"devDependencies":{"tsup":"^8.5.0","rimraf":"^5.0.9","typescript":"^5.5.4","@types/node":"^22.7.1"},"gitHead":"4578225f3bb821fccfab206f69d68731cc3d052c","_id":"@bluessu/meal-scraper@0.1.2","_nodeVersion":"24.13.1","_npmVersion":"11.8.0","dist":{"integrity":"sha512-v6yBHZL1v4GhzRpS6YkfRspboHUpPW6Pb6crlEaxJD5KlzBslvK0jNSKWjah4mZp2IQNEXBoinTyGlcFGz7B5A==","shasum":"32ca4575ca7215f68ad33fc4a3df4971262d1566","tarball":"https://registry.npmjs.org/@bluessu/meal-scraper/-/meal-scraper-0.1.2.tgz","fileCount":7,"unpackedSize":77225,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIDAeqRtWHKxrMMmwrfYXSKkEXrc/SgWiSnDClr4Gl8xIAiEAjQtgDcrsRwIj2AieJ2zS0P8E1n6KPKSdGMwroxuXRt8="}]},"_npmUser":{"name":"phw3071","email":"phw3071@gmail.com"},"directories":{},"maintainers":[{"name":"phw3071","email":"phw3071@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/meal-scraper_0.1.2_1772282367660_0.2677689961707066"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-28T07:24:13.687Z","modified":"2026-02-28T12:39:27.977Z","0.1.0":"2026-02-28T07:24:13.945Z","0.1.1":"2026-02-28T12:21:55.442Z","0.1.2":"2026-02-28T12:39:27.827Z"},"bugs":{"url":"https://github.com/blue-ssu/meal-scraper/issues"},"author":{"name":"bluessu"},"license":"GPL-3.0-only","homepage":"https://github.com/blue-ssu/meal-scraper#readme","keywords":["ssu","soongsil","meal","scraper","dormitory","typescript","node"],"repository":{"type":"git","url":"git+https://github.com/blue-ssu/meal-scraper.git"},"description":"A meal menu scraper for dormitory meal info.","maintainers":[{"name":"phw3071","email":"phw3071@gmail.com"}],"readme":"# @bluessu/meal-scraper\n\n[![npm version](https://img.shields.io/npm/v/@bluessu/meal-scraper.svg)](https://www.npmjs.com/package/@bluessu/meal-scraper)\n[![npm downloads](https://img.shields.io/npm/dm/@bluessu/meal-scraper.svg)](https://www.npmjs.com/package/@bluessu/meal-scraper)\n[![license](https://img.shields.io/npm/l/@bluessu/meal-scraper.svg)](./LICENSE)\n[![TypeScript](https://img.shields.io/badge/language-TypeScript-3178C6.svg?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)\n\n## WIP (Working In Progress)\n\n현재 이 라이브러리는 개발 중인 상태입니다.\n\n## 프로젝트 출처\n\n이 프로젝트의 초기 구현은 [EAT-SSU/Food-Crawling](https://github.com/EAT-SSU/Food-Crawling) 내부 구현을 바탕으로 작성되었습니다.\n\n## 지원 환경\n\n- Node.js: `>= 18`\n- 공개 라이선스: GPL-3.0\n- OpenAI 파서를 사용하려면 프로젝트에 `openai`가 별도 설치되어 있어야 합니다. (`openai`는 선택 의존성입니다)\n\n## 배포/릴리스\n\n패키지 배포는 다음 스크립트를 사용합니다.\n\n```bash\npnpm run release:patch\npnpm run release:minor\npnpm run release:major\n```\n\n## 설치\n\nUsing npm:\n\n```bash\nnpm i @bluessu/meal-scraper\n```\n\nGPT 파서를 사용하려면 먼저 OpenAI 클라이언트를 설치하세요.\n\n```bash\npnpm add openai\n```\n\nUsing yarn\n\n```bash\nyarn add @bluessu/meal-scraper\n```\n\nUsing pnpm:\n\n```bash\npnpm add @bluessu/meal-scraper\n```\n\n## 특징\n\n- `createMealClient()` 또는 `new MealClient()`로 클라이언트 생성\n- 단건 조회/배치 조회/범위 조회 지원\n- 날짜 입력을 `string` 또는 `Date`로 유연하게 지원\n- 내부 구현 분리로 공개 API가 간결하고 유지보수하기 쉬운 구조\n\n## 공개 API\n\n`src/index.ts`에서 노출되는 주요 API는 다음과 같습니다.\n\n- `MealClient`\n- `createMealClient`\n- `normalizeMenuDate`\n- `buildDateRange`\n- 타입\n  - `MenuDateInput`\n  - `MenuDate`\n  - `ParserMode`\n  - `MealClientOptions`\n  - `RangeOptions`\n- 도메인/설정\n  - `CafeteriaType`\n  - `RawMenuData`\n  - `DailyMenu`\n  - `FoodCrawlerSettings`\n  - `defaultSettings`\n- 예외\n  - `BaseCafeteriaException`\n  - `HolidayException`\n  - `MenuFetchException`\n  - `MenuParseException`\n\n## 기본 사용법\n\n```ts\nimport {\n  MealClient,\n  createMealClient,\n  CafeteriaType,\n  normalizeMenuDate,\n  buildDateRange,\n} from \"@bluessu/meal-scraper\";\n\nconst client = createMealClient();\nawait client.getRawMenu(CafeteriaType.DODAM, new Date());\nawait client.getDailyMenu(CafeteriaType.HAKSIK, \"2026-02-28\");\nawait client.getDailyMenusByRange(CafeteriaType.FACULTY, \"2026-02-28\", \"2026-03-02\", {\n  concurrency: 3,\n});\n```\n\n## Client 옵션\n\n```ts\nexport type ParserMode = \"noop\" | \"gpt\" | \"custom\";\n```\n\n- `noop`(기본): 기본 파서(`NoopMenuParser`) 사용\n- `gpt`: OpenAI 파서 사용 (`gptApiKey` 필수)\n- `custom`: 직접 구현한 파서를 `parserImpl`로 주입\n\n```ts\nimport { createMealClient } from \"@bluessu/meal-scraper\";\n\n// GPT 모드 예시 (키가 없으면 생성 단계에서 에러)\nconst gptClient = createMealClient({\n  parser: \"gpt\",\n  gptApiKey: process.env.OPENAI_API_KEY,\n});\n\n// 커스텀 파서 주입 예시\nconst customClient = createMealClient({\n  parser: \"custom\",\n  parserImpl: {\n    parseMenu: async (raw) => {\n      // 사용자 구현\n      return {\n        date: raw.date,\n        cafeteria: raw.cafeteria,\n        status: \"open\",\n        breakfast: {},\n        lunch: {},\n        dinner: {},\n      };\n    },\n  },\n});\n```\n\n## 날짜 정규화 유틸\n\n```ts\nimport { normalizeMenuDate, buildDateRange } from \"@bluessu/meal-scraper\";\n\nnormalizeMenuDate(\"2026-02-28\"); // \"2026-02-28\"\nnormalizeMenuDate(new Date(2026, 1, 28)); // \"2026-02-28\"\n\nbuildDateRange(\"2026-02-28\", \"2026-03-02\"); // [\"2026-02-28\",\"2026-03-01\",\"2026-03-02\"]\n```\n\n지원 날짜 포맷은 내부적으로 모두 `YYYY-MM-DD`로 정규화됩니다.\n\n## API 목록\n\n### `MealClient`\n\n- `getRawMenu(cafeteria, date): Promise<RawMenuData>`\n- `getDailyMenu(cafeteria, date): Promise<DailyMenu>`\n- `getRawMenus(cafeteria, dates, options?): Promise<RawMenuData[]>`\n- `getDailyMenus(cafeteria, dates, options?): Promise<DailyMenu[]>`\n- `getRawMenusByRange(cafeteria, start, end, options?): Promise<RawMenuData[]>`\n- `getDailyMenusByRange(cafeteria, start, end, options?): Promise<DailyMenu[]>`\n\n### 옵션\n\n- `RangeOptions`\n  - `startInclusive?: boolean` (기본값: `true`)\n  - `concurrency?: number` (기본값: `3`)\n\n## 에러 처리\n\n```ts\nimport { HolidayException, MenuFetchException } from \"@bluessu/meal-scraper\";\n\ntry {\n  const menu = await client.getDailyMenu(CafeteriaType.DORMITORY, \"2026-02-28\");\n} catch (error) {\n  if (error instanceof HolidayException) {\n    console.log(\"휴일입니다\");\n  } else if (error instanceof MenuFetchException) {\n    console.log(\"수집 실패\");\n  } else {\n    console.error(error);\n  }\n}\n```\n\n## 프로젝트 구조\n\n현재 공개 엔트리는 `src/index.ts`에 집중하고, 실제 구현은 내부 레이어로 분리되어 있습니다.\n\n- `src/index.ts`: 라이브러리 바렐(export hub)\n- `src/client/*`: 클라이언트 API 및 유틸\n- `src/services/*`: 수집/파싱 오케스트레이션\n- `src/repositories/*`: 사이트별 스크래퍼\n- `src/parsers/*`: 파싱 전략\n- `src/domain.ts`, `src/config.ts`, `src/errors.ts`: 도메인/설정/예외\n\n## 라이선스\n\nGNU General Public License Version 3 (GPL-3.0) 입니다.  \n라이선스 파일은 `LICENSE`를 확인하세요.\n","readmeFilename":"README.md"}