@zonuexe/techbook-mcp 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/.claude/settings.local.json +4 -1
  2. package/CHANGELOG.md +21 -1
  3. package/dist/adapters/calil.d.ts +10 -0
  4. package/dist/adapters/calil.d.ts.map +1 -0
  5. package/dist/adapters/calil.js +45 -0
  6. package/dist/adapters/calil.js.map +1 -0
  7. package/dist/adapters/openbd.d.ts +57 -0
  8. package/dist/adapters/openbd.d.ts.map +1 -0
  9. package/dist/adapters/openbd.js +87 -0
  10. package/dist/adapters/openbd.js.map +1 -0
  11. package/dist/adapters/publishers/tatsu-zine.d.ts.map +1 -1
  12. package/dist/adapters/publishers/tatsu-zine.js +64 -53
  13. package/dist/adapters/publishers/tatsu-zine.js.map +1 -1
  14. package/dist/application/get-book-by-isbn.d.ts +12 -0
  15. package/dist/application/get-book-by-isbn.d.ts.map +1 -0
  16. package/dist/application/get-book-by-isbn.js +42 -0
  17. package/dist/application/get-book-by-isbn.js.map +1 -0
  18. package/dist/application/get-book-detail.d.ts.map +1 -1
  19. package/dist/application/get-book-detail.js +16 -1
  20. package/dist/application/get-book-detail.js.map +1 -1
  21. package/dist/application/search-books.d.ts.map +1 -1
  22. package/dist/application/search-books.js +20 -0
  23. package/dist/application/search-books.js.map +1 -1
  24. package/dist/mcp/server.d.ts.map +1 -1
  25. package/dist/mcp/server.js +10 -0
  26. package/dist/mcp/server.js.map +1 -1
  27. package/dist/mcp/tools.d.ts +13 -0
  28. package/dist/mcp/tools.d.ts.map +1 -1
  29. package/dist/mcp/tools.js +16 -0
  30. package/dist/mcp/tools.js.map +1 -1
  31. package/package.json +3 -2
  32. package/src/adapters/calil.ts +57 -0
  33. package/src/adapters/openbd.ts +142 -0
  34. package/src/adapters/publishers/tatsu-zine.ts +7 -19
  35. package/src/application/get-book-by-isbn.ts +50 -0
  36. package/src/application/get-book-detail.ts +17 -1
  37. package/src/application/search-books.ts +20 -0
  38. package/src/mcp/server.ts +10 -0
  39. package/src/mcp/tools.ts +17 -0
  40. package/tests/fixtures/calil-book.html +987 -0
  41. package/tests/fixtures/openbd-response.json +110 -0
  42. package/tests/fixtures/tatsu-zine-detail-free.html +14 -12
  43. package/tests/unit/adapters/calil.test.ts +69 -0
  44. package/tests/unit/adapters/openbd.test.ts +185 -0
  45. package/tests/unit/application/get-book-by-isbn.test.ts +176 -0
@@ -29,7 +29,10 @@
29
29
  "Bash(wc -c tests/fixtures/impress-detail-*.html)",
30
30
  "Bash(git -C /Users/megurine/repo/js/techbook-mcp status)",
31
31
  "Bash(git -C /Users/megurine/repo/js/techbook-mcp diff)",
32
- "Bash(git:*)"
32
+ "Bash(git:*)",
33
+ "Bash(npm pkg:*)",
34
+ "WebFetch(domain:api.openbd.jp)",
35
+ "WebFetch(domain:calil.jp)"
33
36
  ]
34
37
  }
35
38
  }
package/CHANGELOG.md CHANGED
@@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.3] - 2026-04-13
11
+
12
+ ### Added
13
+
14
+ - `get_book_by_isbn` ツールを追加(ISBNから書誌情報を取得)
15
+ - openBD にない書籍のフォールバックとしてカーリル API を追加
16
+
17
+ ### Fixed
18
+
19
+ - `getDetail()` の著者取得を自己紹介文ではなく `itemprop="author"` から取得するよう修正
20
+ - `bin` エントリの `./` プレフィックスを修正
21
+
22
+ ## [0.2.2] - 2026-04-12
23
+
24
+ ### Fixed
25
+
26
+ - `npm publish` 前に `dist/` が自動ビルドされるよう `prepublishOnly` スクリプトを追加
27
+
10
28
  ## [0.2.1] - 2026-04-12
11
29
 
12
30
  ### Fixed
@@ -29,6 +47,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
29
47
 
30
48
  - テストを vitest から `node:test` + `node:assert` に移行(Node.js・Bun・Deno で共通実行可能に)
31
49
 
32
- [Unreleased]: https://github.com/zonuexe/techbook-mcp/compare/v0.2.1...HEAD
50
+ [Unreleased]: https://github.com/zonuexe/techbook-mcp/compare/v0.2.3...HEAD
51
+ [0.2.3]: https://github.com/zonuexe/techbook-mcp/compare/v0.2.2...v0.2.3
52
+ [0.2.2]: https://github.com/zonuexe/techbook-mcp/compare/v0.2.1...v0.2.2
33
53
  [0.2.1]: https://github.com/zonuexe/techbook-mcp/compare/v0.2.0...v0.2.1
34
54
  [0.2.0]: https://github.com/zonuexe/techbook-mcp/releases/tag/v0.2.0
@@ -0,0 +1,10 @@
1
+ import type { PublisherDeps } from "../domain/publisher.js";
2
+ import type { BookRecord } from "../domain/book.js";
3
+ export declare const CALIL_BASE_URL = "https://calil.jp";
4
+ /**
5
+ * カーリルの書籍詳細ページ (/book/{isbn}) から書誌情報を取得する。
6
+ * openBD に存在しない書籍(廃業出版社など)のフォールバックとして使用する。
7
+ * @returns 書誌情報が見つかれば BookRecord、ページが存在しなければ null。
8
+ */
9
+ export declare function fetchCalilBook(isbn: string, deps: PublisherDeps): Promise<BookRecord | null>;
10
+ //# sourceMappingURL=calil.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calil.d.ts","sourceRoot":"","sources":["../../src/adapters/calil.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGpD,eAAO,MAAM,cAAc,qBAAqB,CAAC;AAEjD;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CA0C5B"}
@@ -0,0 +1,45 @@
1
+ import { fetchText } from "./publishers/base.js";
2
+ export const CALIL_BASE_URL = "https://calil.jp";
3
+ /**
4
+ * カーリルの書籍詳細ページ (/book/{isbn}) から書誌情報を取得する。
5
+ * openBD に存在しない書籍(廃業出版社など)のフォールバックとして使用する。
6
+ * @returns 書誌情報が見つかれば BookRecord、ページが存在しなければ null。
7
+ */
8
+ export async function fetchCalilBook(isbn, deps) {
9
+ const url = `${CALIL_BASE_URL}/book/${isbn}`;
10
+ let html;
11
+ try {
12
+ html = await fetchText(url, deps);
13
+ }
14
+ catch {
15
+ return null;
16
+ }
17
+ const doc = deps.parser.parse(html);
18
+ const title = doc.selectOne("h1.title[itemprop='name']")?.text().trim();
19
+ if (!title)
20
+ return null;
21
+ // 著者: div.author 内の <a> テキストを収集する
22
+ // <div class="author" itemprop="author">
23
+ // <a href="/search?q=author:...">WebビジネスPHP研究部会</a><span>(著)</span>
24
+ // </div>
25
+ const authorLinks = doc.select("div[itemprop='author'] a");
26
+ const authors = authorLinks.map(el => el.text().trim()).filter(Boolean);
27
+ const publisher = doc.selectOne("span[itemprop='publisher']")?.text().trim() || undefined;
28
+ // "(2002-02-01)" → "2002-02-01"
29
+ const rawDate = doc.selectOne("span[itemprop='datePublished']")?.text().trim();
30
+ const publishedAt = rawDate ? rawDate.replace(/^\(|\)$/g, "").trim() || undefined : undefined;
31
+ // ISBN-13: <span itemprop="isbn">ISBN-13:</span> 9784901676038 の形式
32
+ const isbn13Match = html.match(/ISBN-13:[^<]*<\/span>[^<\d]*(97[89]\d{10})/);
33
+ const isbn13 = isbn13Match?.[1] ?? isbn;
34
+ const coverImageUrl = doc.selectOne("img[itemprop='image']")?.attr("src") || undefined;
35
+ return {
36
+ title,
37
+ authors,
38
+ publisher: publisher ?? "",
39
+ isbn: isbn13,
40
+ publishedAt,
41
+ url,
42
+ coverImageUrl,
43
+ };
44
+ }
45
+ //# sourceMappingURL=calil.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calil.js","sourceRoot":"","sources":["../../src/adapters/calil.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,MAAM,CAAC,MAAM,cAAc,GAAG,kBAAkB,CAAC;AAEjD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAAY,EACZ,IAAmB;IAEnB,MAAM,GAAG,GAAG,GAAG,cAAc,SAAS,IAAI,EAAE,CAAC;IAC7C,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEpC,MAAM,KAAK,GAAG,GAAG,CAAC,SAAS,CAAC,2BAA2B,CAAC,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;IACxE,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,kCAAkC;IAClC,yCAAyC;IACzC,sEAAsE;IACtE,SAAS;IACT,MAAM,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAAC;IAC3D,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAExE,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,CAAC,4BAA4B,CAAC,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,SAAS,CAAC;IAE1F,gCAAgC;IAChC,MAAM,OAAO,GAAG,GAAG,CAAC,SAAS,CAAC,gCAAgC,CAAC,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;IAC/E,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAE9F,mEAAmE;IACnE,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAC7E,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IAExC,MAAM,aAAa,GAAG,GAAG,CAAC,SAAS,CAAC,uBAAuB,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,SAAS,CAAC;IAEvF,OAAO;QACL,KAAK;QACL,OAAO;QACP,SAAS,EAAE,SAAS,IAAI,EAAE;QAC1B,IAAI,EAAE,MAAM;QACZ,WAAW;QACX,GAAG;QACH,aAAa;KACd,CAAC;AACJ,CAAC"}
@@ -0,0 +1,57 @@
1
+ import type { PublisherDeps } from "../domain/publisher.js";
2
+ import type { BookRecord } from "../domain/book.js";
3
+ interface OpenBDSummary {
4
+ isbn: string;
5
+ title: string;
6
+ publisher: string;
7
+ pubdate: string;
8
+ cover: string;
9
+ author: string;
10
+ }
11
+ interface OpenBDTextContent {
12
+ TextType: string;
13
+ ContentAudience: string;
14
+ Text: string;
15
+ }
16
+ interface OpenBDPrice {
17
+ PriceType: string;
18
+ PriceAmount: string;
19
+ CurrencyCode: string;
20
+ }
21
+ interface OpenBDHanmoto {
22
+ isbn: string;
23
+ storelink?: string;
24
+ [key: string]: unknown;
25
+ }
26
+ export interface OpenBDEntry {
27
+ summary: OpenBDSummary;
28
+ hanmoto?: OpenBDHanmoto;
29
+ onix: {
30
+ CollateralDetail?: {
31
+ TextContent?: OpenBDTextContent[];
32
+ };
33
+ ProductSupply?: {
34
+ SupplyDetail?: {
35
+ Price?: OpenBDPrice[];
36
+ };
37
+ };
38
+ };
39
+ }
40
+ /**
41
+ * openBD API から複数ISBNの書誌情報を一括取得する。
42
+ * @returns ISBNをキーとするMapを返す。該当なし・取得失敗のISBNは含まれない。
43
+ */
44
+ export declare function fetchOpenBDBooks(isbns: string[], deps: PublisherDeps): Promise<Map<string, OpenBDEntry>>;
45
+ /**
46
+ * openBD エントリを BookRecord に変換する。
47
+ * 出版社サイトから取得できない場合のフォールバック用。
48
+ * url には hanmoto.storelink を使用し、なければ openBD API URL を使用する。
49
+ */
50
+ export declare function openBDEntryToBookRecord(entry: OpenBDEntry): BookRecord;
51
+ /**
52
+ * openBD の書誌情報で BookRecord の欠損フィールドを補完する。
53
+ * 既存のフィールドは上書きしない。
54
+ */
55
+ export declare function enrichWithOpenBD(book: BookRecord, entry: OpenBDEntry): BookRecord;
56
+ export {};
57
+ //# sourceMappingURL=openbd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openbd.d.ts","sourceRoot":"","sources":["../../src/adapters/openbd.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAOpD,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,iBAAiB;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,WAAW;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,IAAI,EAAE;QACJ,gBAAgB,CAAC,EAAE;YACjB,WAAW,CAAC,EAAE,iBAAiB,EAAE,CAAC;SACnC,CAAC;QACF,aAAa,CAAC,EAAE;YACd,YAAY,CAAC,EAAE;gBACb,KAAK,CAAC,EAAE,WAAW,EAAE,CAAC;aACvB,CAAC;SACH,CAAC;KACH,CAAC;CACH;AA+BD;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAenC;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,CAmBtE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,GAAG,UAAU,CAQjF"}
@@ -0,0 +1,87 @@
1
+ import { fetchText } from "./publishers/base.js";
2
+ const OPENBD_API_URL = "https://api.openbd.jp/v1/get";
3
+ // --- ユーティリティ ---
4
+ function parsePubDate(pubdate) {
5
+ if (!pubdate || pubdate.length < 8)
6
+ return undefined;
7
+ return `${pubdate.slice(0, 4)}-${pubdate.slice(4, 6)}-${pubdate.slice(6, 8)}`;
8
+ }
9
+ function findTextByType(entry, ...types) {
10
+ const texts = entry.onix.CollateralDetail?.TextContent;
11
+ if (!texts)
12
+ return undefined;
13
+ for (const type of types) {
14
+ const found = texts.find(t => t.TextType === type);
15
+ if (found?.Text)
16
+ return found.Text;
17
+ }
18
+ return undefined;
19
+ }
20
+ function getTaxIncludedPrice(entry) {
21
+ const prices = entry.onix.ProductSupply?.SupplyDetail?.Price;
22
+ if (!prices)
23
+ return undefined;
24
+ // PriceType "03" = 税込定価
25
+ const price = prices.find(p => p.PriceType === "03");
26
+ if (!price)
27
+ return undefined;
28
+ const amount = parseInt(price.PriceAmount, 10);
29
+ return isNaN(amount) ? undefined : amount;
30
+ }
31
+ // --- 公開API ---
32
+ /**
33
+ * openBD API から複数ISBNの書誌情報を一括取得する。
34
+ * @returns ISBNをキーとするMapを返す。該当なし・取得失敗のISBNは含まれない。
35
+ */
36
+ export async function fetchOpenBDBooks(isbns, deps) {
37
+ if (isbns.length === 0)
38
+ return new Map();
39
+ const url = `${OPENBD_API_URL}?isbn=${isbns.join(",")}`;
40
+ const text = await fetchText(url, deps);
41
+ const data = JSON.parse(text);
42
+ const result = new Map();
43
+ for (let i = 0; i < isbns.length; i++) {
44
+ const entry = data[i];
45
+ if (entry !== null && entry !== undefined) {
46
+ result.set(isbns[i], entry);
47
+ }
48
+ }
49
+ return result;
50
+ }
51
+ /**
52
+ * openBD エントリを BookRecord に変換する。
53
+ * 出版社サイトから取得できない場合のフォールバック用。
54
+ * url には hanmoto.storelink を使用し、なければ openBD API URL を使用する。
55
+ */
56
+ export function openBDEntryToBookRecord(entry) {
57
+ const { summary } = entry;
58
+ const storelink = entry.hanmoto?.storelink;
59
+ const authors = summary.author
60
+ ? summary.author.split(/[\//、,,]/).map(a => a.trim()).filter(Boolean)
61
+ : [];
62
+ return {
63
+ title: summary.title,
64
+ authors,
65
+ publisher: summary.publisher,
66
+ isbn: summary.isbn,
67
+ publishedAt: parsePubDate(summary.pubdate),
68
+ url: storelink ?? `https://api.openbd.jp/v1/get?isbn=${summary.isbn}`,
69
+ price: getTaxIncludedPrice(entry),
70
+ coverImageUrl: summary.cover || undefined,
71
+ description: findTextByType(entry, "03", "02"),
72
+ };
73
+ }
74
+ /**
75
+ * openBD の書誌情報で BookRecord の欠損フィールドを補完する。
76
+ * 既存のフィールドは上書きしない。
77
+ */
78
+ export function enrichWithOpenBD(book, entry) {
79
+ return {
80
+ ...book,
81
+ publishedAt: book.publishedAt ?? parsePubDate(entry.summary.pubdate),
82
+ price: book.price ?? getTaxIncludedPrice(entry),
83
+ coverImageUrl: book.coverImageUrl ?? (entry.summary.cover || undefined),
84
+ description: book.description ?? findTextByType(entry, "03", "02"),
85
+ };
86
+ }
87
+ //# sourceMappingURL=openbd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openbd.js","sourceRoot":"","sources":["../../src/adapters/openbd.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"tatsu-zine.d.ts","sourceRoot":"","sources":["../../../src/adapters/publishers/tatsu-zine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAiB,MAAM,2BAA2B,CAAC;AA4BjF,eAAO,MAAM,gBAAgB,EAAE,gBAoG9B,CAAC"}
1
+ {"version":3,"file":"tatsu-zine.d.ts","sourceRoot":"","sources":["../../../src/adapters/publishers/tatsu-zine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAiB,MAAM,2BAA2B,CAAC;AA2CjF,eAAO,MAAM,gBAAgB,EAAE,gBAkG9B,CAAC"}
@@ -10,6 +10,20 @@ function parseAuthors(text) {
10
10
  .map(part => part.replace(/\s*[((][^))]*[))]\s*$/, "").trim())
11
11
  .filter(Boolean);
12
12
  }
13
+ /**
14
+ * ページネーションリンクから最終ページ番号を取得する。
15
+ * <a class="btn-pagination" href="/books?page=11">最後へ</a>
16
+ */
17
+ function detectLastPage(doc) {
18
+ let max = 1;
19
+ for (const a of doc.select("a.btn-pagination")) {
20
+ const href = a.attr("href") ?? "";
21
+ const m = href.match(/[?&]page=(\d+)/);
22
+ if (m)
23
+ max = Math.max(max, parseInt(m[1], 10));
24
+ }
25
+ return max;
26
+ }
13
27
  /**
14
28
  * "3,300円 (3,000円+税)" → 3300
15
29
  * 最初の数値が税込価格。
@@ -25,44 +39,53 @@ export const tatsuZineAdapter = {
25
39
  name: "達人出版会",
26
40
  baseUrl: BASE_URL,
27
41
  async search(query, deps) {
28
- const word = [query.title, query.author].filter(Boolean).join(" ");
29
- if (!word)
42
+ // 検索APIがないため書籍一覧からローカルフィルタリングする
43
+ // 著者のみの検索は非対応
44
+ if (!query.title)
30
45
  return [];
31
- // 検索フォーム: <form method="get" action="/books/"><input name="search">
32
- const url = `${BASE_URL}/books/?search=${encodeURIComponent(word)}`;
33
- const html = await fetchText(url, deps);
34
- const doc = deps.parser.parse(html);
35
- // 書籍アイテムのHTML構造:
36
- // <a href="/books/{slug}"><img src="/images/books/{id}/cover_s.jpg" alt="Title"></a>
37
- // <h3><a href="/books/{slug}">Title</a></h3>
38
- // <p>Author(著), ...</p>
39
- //
40
- // タイトルリンクと著者段落を位置で対応付ける
41
- const titleLinks = doc.select("h3 a[href]").filter(a => {
42
- const href = a.attr("href") ?? "";
43
- return href.startsWith("/books/") && !href.startsWith("/books/pub/");
44
- });
45
- const authorParagraphs = doc.select("h3 + p");
46
+ const titleKeyword = query.title.toLowerCase();
47
+ const authorKeyword = query.author?.toLowerCase();
48
+ const limit = query.limit ?? 10;
49
+ // 書籍一覧ページ: <article class="book"> が各書籍アイテム、ページネーションあり
50
+ const firstHtml = await fetchText(`${BASE_URL}/books/`, deps);
51
+ const firstDoc = deps.parser.parse(firstHtml);
52
+ const lastPage = detectLastPage(firstDoc);
46
53
  const results = [];
47
- for (let i = 0; i < titleLinks.length; i++) {
48
- const titleLink = titleLinks[i];
49
- const title = titleLink.text().trim();
50
- const href = titleLink.attr("href");
51
- if (!title || !href)
52
- continue;
53
- const bookUrl = resolveUrl(BASE_URL, href);
54
- const authorText = authorParagraphs[i]?.text().trim() ?? "";
55
- const authors = authorText ? parseAuthors(authorText) : [];
56
- results.push({
57
- title,
58
- authors,
59
- publisher: "達人出版会",
60
- url: bookUrl,
61
- // 達人出版会は全書籍で購入者情報を各ページに印字 (ソーシャルDRM)
62
- ebookStores: [{ name: "達人出版会", url: bookUrl, drm: "social" }],
63
- });
54
+ const docs = [[firstHtml, firstDoc]];
55
+ // ページ2以降を先行して取得しておく(キャッシュ経由)
56
+ for (let page = 2; page <= lastPage; page++) {
57
+ const html = await fetchText(`${BASE_URL}/books?page=${page}`, deps);
58
+ docs.push([html, deps.parser.parse(html)]);
64
59
  }
65
- return results.slice(0, query.limit ?? 10);
60
+ outer: for (const [, doc] of docs) {
61
+ for (const article of doc.select("article.book")) {
62
+ const titleEl = article.find("h3[itemprop='name'] a")[0];
63
+ if (!titleEl)
64
+ continue;
65
+ const title = titleEl.text().trim();
66
+ if (!title.toLowerCase().includes(titleKeyword))
67
+ continue;
68
+ const authorText = article.find("p[itemprop='author']")[0]?.text().trim() ?? "";
69
+ if (authorKeyword && !authorText.toLowerCase().includes(authorKeyword))
70
+ continue;
71
+ const href = titleEl.attr("href");
72
+ if (!href)
73
+ continue;
74
+ const bookUrl = resolveUrl(BASE_URL, href);
75
+ const authors = authorText ? parseAuthors(authorText) : [];
76
+ results.push({
77
+ title,
78
+ authors,
79
+ publisher: "達人出版会",
80
+ url: bookUrl,
81
+ // 達人出版会は全書籍で購入者情報を各ページに印字 (ソーシャルDRM)
82
+ ebookStores: [{ name: "達人出版会", url: bookUrl, drm: "social" }],
83
+ });
84
+ if (results.length >= limit)
85
+ break outer;
86
+ }
87
+ }
88
+ return results;
66
89
  },
67
90
  async getDetail(url, deps) {
68
91
  const html = await fetchText(url, deps);
@@ -76,24 +99,12 @@ export const tatsuZineAdapter = {
76
99
  const imgEl = doc.selectOne("img[src*='/images/books/']");
77
100
  const imgSrc = imgEl?.attr("src");
78
101
  const coverImageUrl = imgSrc ? resolveUrl(BASE_URL, imgSrc) : undefined;
79
- // 著者・価格: dl > dd 構造を優先し、なければ p 要素を走査
80
- let authors = [];
81
- let price;
82
- const candidates = [
83
- ...doc.select("dd"),
84
- ...doc.select("p"),
85
- ];
86
- for (const el of candidates) {
87
- const text = el.text().trim();
88
- if (!authors.length && /[((][著訳監編]/.test(text)) {
89
- authors = parseAuthors(text);
90
- }
91
- if (price === undefined && /^\d/.test(text) && /円/.test(text)) {
92
- price = parsePrice(text);
93
- }
94
- if (authors.length && price !== undefined)
95
- break;
96
- }
102
+ // 著者: <p itemprop="author"> を優先使用
103
+ const authorText = doc.selectOne("p[itemprop='author']")?.text().trim() ?? "";
104
+ const authors = authorText ? parseAuthors(authorText) : [];
105
+ // 価格: <span itemprop="price"> を優先使用
106
+ const priceText = doc.selectOne("span[itemprop='price']")?.text().trim() ?? "";
107
+ const price = priceText ? parsePrice(priceText) : undefined;
97
108
  // 達人出版会は全書籍で購入者情報を各ページに印字 (ソーシャルDRM)
98
109
  const ebookStores = [{ name: "達人出版会", url, drm: "social" }];
99
110
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"tatsu-zine.js","sourceRoot":"","sources":["../../../src/adapters/publishers/tatsu-zine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tatsu-zine.js","sourceRoot":"","sources":["../../../src/adapters/publishers/tatsu-zine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { BookRecord } from "../domain/book.js";
2
+ import type { PublisherAdapter, PublisherDeps } from "../domain/publisher.js";
3
+ /**
4
+ * ISBNから書籍情報を取得する。
5
+ *
6
+ * 1. openBD で書誌情報と出版社ストアリンクを取得する
7
+ * 2. ストアリンクが既知アダプターと一致する場合は出版社サイトから詳細取得を試みる
8
+ * 3. 取得できない場合は openBD データをそのまま返す
9
+ * 4. openBD にも存在しない場合はカーリルから書誌情報を取得する(廃業出版社など)
10
+ */
11
+ export declare function getBookByIsbn(isbn: string, publishers: readonly PublisherAdapter[], deps: PublisherDeps): Promise<BookRecord>;
12
+ //# sourceMappingURL=get-book-by-isbn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-book-by-isbn.d.ts","sourceRoot":"","sources":["../../src/application/get-book-by-isbn.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAK9E;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,SAAS,gBAAgB,EAAE,EACvC,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,UAAU,CAAC,CA+BrB"}
@@ -0,0 +1,42 @@
1
+ import { checkRobotsTxt } from "../adapters/publishers/base.js";
2
+ import { fetchOpenBDBooks, openBDEntryToBookRecord } from "../adapters/openbd.js";
3
+ import { fetchCalilBook } from "../adapters/calil.js";
4
+ /**
5
+ * ISBNから書籍情報を取得する。
6
+ *
7
+ * 1. openBD で書誌情報と出版社ストアリンクを取得する
8
+ * 2. ストアリンクが既知アダプターと一致する場合は出版社サイトから詳細取得を試みる
9
+ * 3. 取得できない場合は openBD データをそのまま返す
10
+ * 4. openBD にも存在しない場合はカーリルから書誌情報を取得する(廃業出版社など)
11
+ */
12
+ export async function getBookByIsbn(isbn, publishers, deps) {
13
+ const normalizedIsbn = isbn.replace(/-/g, "");
14
+ const openBDMap = await fetchOpenBDBooks([normalizedIsbn], deps);
15
+ const entry = openBDMap.get(normalizedIsbn);
16
+ if (!entry) {
17
+ // openBD にない場合はカーリルをフォールバックとして試みる(廃業出版社など)
18
+ const calilBook = await fetchCalilBook(normalizedIsbn, deps);
19
+ if (calilBook)
20
+ return calilBook;
21
+ throw new Error(`書誌情報が見つかりません: ${isbn}`);
22
+ }
23
+ // hanmoto.storelink が既知アダプターの baseUrl と前方一致する場合は
24
+ // 出版社サイトから詳細取得を試みる
25
+ const storelink = entry.hanmoto?.storelink;
26
+ if (storelink) {
27
+ const publisher = publishers.find(p => storelink.startsWith(p.baseUrl));
28
+ if (publisher) {
29
+ const allowed = await checkRobotsTxt(storelink, deps);
30
+ if (allowed) {
31
+ try {
32
+ return await publisher.getDetail(storelink, deps);
33
+ }
34
+ catch {
35
+ // 出版社サイトからの取得失敗は無視して openBD データで返す
36
+ }
37
+ }
38
+ }
39
+ }
40
+ return openBDEntryToBookRecord(entry);
41
+ }
42
+ //# sourceMappingURL=get-book-by-isbn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-book-by-isbn.js","sourceRoot":"","sources":["../../src/application/get-book-by-isbn.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAClF,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,IAAY,EACZ,UAAuC,EACvC,IAAmB;IAEnB,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAE9C,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,CAAC,cAAc,CAAC,EAAE,IAAI,CAAC,CAAC;IACjE,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAE5C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,2CAA2C;QAC3C,MAAM,SAAS,GAAG,MAAM,cAAc,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;QAC7D,IAAI,SAAS;YAAE,OAAO,SAAS,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,iDAAiD;IACjD,mBAAmB;IACnB,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,EAAE,SAAS,CAAC;IAC3C,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QACxE,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;YACtD,IAAI,OAAO,EAAE,CAAC;gBACZ,IAAI,CAAC;oBACH,OAAO,MAAM,SAAS,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;gBACpD,CAAC;gBAAC,MAAM,CAAC;oBACP,mCAAmC;gBACrC,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,uBAAuB,CAAC,KAAK,CAAC,CAAC;AACxC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"get-book-detail.d.ts","sourceRoot":"","sources":["../../src/application/get-book-detail.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAG9E,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,SAAS,gBAAgB,EAAE,EACvC,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,UAAU,CAAC,CAerB"}
1
+ {"version":3,"file":"get-book-detail.d.ts","sourceRoot":"","sources":["../../src/application/get-book-detail.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAI9E,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,SAAS,gBAAgB,EAAE,EACvC,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,UAAU,CAAC,CA8BrB"}
@@ -1,4 +1,5 @@
1
1
  import { checkRobotsTxt } from "../adapters/publishers/base.js";
2
+ import { fetchOpenBDBooks, enrichWithOpenBD } from "../adapters/openbd.js";
2
3
  export async function getBookDetail(url, publishers, deps) {
3
4
  const publisher = publishers.find(p => url.startsWith(p.baseUrl));
4
5
  if (!publisher) {
@@ -9,6 +10,20 @@ export async function getBookDetail(url, publishers, deps) {
9
10
  if (!allowed) {
10
11
  throw new Error(`robots.txt によりアクセスが禁止されています: ${url}`);
11
12
  }
12
- return publisher.getDetail(url, deps);
13
+ const book = await publisher.getDetail(url, deps);
14
+ // ISBNが特定できる場合はopenBDで欠損フィールドを補完
15
+ if (book.isbn !== undefined) {
16
+ try {
17
+ const openBDMap = await fetchOpenBDBooks([book.isbn], deps);
18
+ const entry = openBDMap.get(book.isbn);
19
+ if (entry !== undefined) {
20
+ return enrichWithOpenBD(book, entry);
21
+ }
22
+ }
23
+ catch {
24
+ // openBD の取得失敗は無視して出版社から取得できた情報を返す
25
+ }
26
+ }
27
+ return book;
13
28
  }
14
29
  //# sourceMappingURL=get-book-detail.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"get-book-detail.js","sourceRoot":"","sources":["../../src/application/get-book-detail.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAEhE,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,GAAW,EACX,UAAuC,EACvC,IAAmB;IAEnB,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAClE,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,6BAA6B,GAAG,IAAI;YACpC,UAAU,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACtD,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAChD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,gCAAgC,GAAG,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,OAAO,SAAS,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AACxC,CAAC"}
1
+ {"version":3,"file":"get-book-detail.js","sourceRoot":"","sources":["../../src/application/get-book-detail.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE3E,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,GAAW,EACX,UAAuC,EACvC,IAAmB;IAEnB,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAClE,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,6BAA6B,GAAG,IAAI;YACpC,UAAU,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACtD,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAChD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,gCAAgC,GAAG,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAElD,iCAAiC;IACjC,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;YAC5D,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACvC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,OAAO,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YACvC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,mCAAmC;QACrC,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"search-books.d.ts","sourceRoot":"","sources":["../../src/application/search-books.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAG9E,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,MAAM,EAAE,KAAK,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACzD;AAED,wBAAsB,WAAW,CAC/B,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,SAAS,gBAAgB,EAAE,EACvC,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,iBAAiB,CAAC,CA8B5B"}
1
+ {"version":3,"file":"search-books.d.ts","sourceRoot":"","sources":["../../src/application/search-books.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAI9E,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,MAAM,EAAE,KAAK,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACzD;AAED,wBAAsB,WAAW,CAC/B,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,SAAS,gBAAgB,EAAE,EACvC,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,iBAAiB,CAAC,CAiD5B"}
@@ -1,4 +1,5 @@
1
1
  import { checkRobotsTxt } from "../adapters/publishers/base.js";
2
+ import { fetchOpenBDBooks, enrichWithOpenBD } from "../adapters/openbd.js";
2
3
  export async function searchBooks(query, publishers, deps) {
3
4
  const targets = query.publisherId
4
5
  ? publishers.filter(p => p.id === query.publisherId)
@@ -24,6 +25,25 @@ export async function searchBooks(query, publishers, deps) {
24
25
  errors.push({ publisherId: publisher.id, message });
25
26
  }
26
27
  }
28
+ // ISBNが特定できる書籍をopenBDで一括補完
29
+ const isbns = books.map(b => b.isbn).filter((isbn) => isbn !== undefined);
30
+ if (isbns.length > 0) {
31
+ try {
32
+ const openBDMap = await fetchOpenBDBooks(isbns, deps);
33
+ for (let i = 0; i < books.length; i++) {
34
+ const isbn = books[i].isbn;
35
+ if (isbn !== undefined) {
36
+ const entry = openBDMap.get(isbn);
37
+ if (entry !== undefined) {
38
+ books[i] = enrichWithOpenBD(books[i], entry);
39
+ }
40
+ }
41
+ }
42
+ }
43
+ catch {
44
+ // openBD の取得失敗は無視して出版社から取得できた情報を返す
45
+ }
46
+ }
27
47
  return { books, errors };
28
48
  }
29
49
  //# sourceMappingURL=search-books.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"search-books.js","sourceRoot":"","sources":["../../src/application/search-books.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAOhE,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAkB,EAClB,UAAuC,EACvC,IAAmB;IAEnB,MAAM,OAAO,GAAG,KAAK,CAAC,WAAW;QAC/B,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,WAAW,CAAC;QACpD,CAAC,CAAC,UAAU,CAAC;IAEf,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CACtC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QACtB,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACtD,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QAC3E,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC/B,CAAC,CAAC,CACH,CAAC;IAEF,MAAM,KAAK,GAAiB,EAAE,CAAC;IAC/B,MAAM,MAAM,GAAoD,EAAE,CAAC;IAEnE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QAC1B,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QAC7B,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YAClC,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,YAAY,KAAK;gBAC5C,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO;gBACvB,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC1B,MAAM,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,SAAS,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAC3B,CAAC"}
1
+ {"version":3,"file":"search-books.js","sourceRoot":"","sources":["../../src/application/search-books.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAMnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAwB9E,wBAAgB,YAAY,CAC1B,UAAU,EAAE,SAAS,gBAAgB,EAAE,EACvC,IAAI,EAAE,aAAa,GAClB,MAAM,CA4DR;AAED,wBAAsB,WAAW,CAC/B,UAAU,EAAE,SAAS,gBAAgB,EAAE,EACvC,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,IAAI,CAAC,CAIf"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAMnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAyB9E,wBAAgB,YAAY,CAC1B,UAAU,EAAE,SAAS,gBAAgB,EAAE,EACvC,IAAI,EAAE,aAAa,GAClB,MAAM,CAqER;AAED,wBAAsB,WAAW,CAC/B,UAAU,EAAE,SAAS,gBAAgB,EAAE,EACvC,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,IAAI,CAAC,CAIf"}