@zonuexe/techbook-mcp 0.1.0 → 0.2.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.
Files changed (122) hide show
  1. package/.claude/settings.local.json +13 -1
  2. package/.codex/skills/techbook-mcp-release-prep/SKILL.md +105 -0
  3. package/.github/workflows/test.yml +36 -0
  4. package/.oxlintrc.json +12 -0
  5. package/AGENTS.md +29 -1
  6. package/CHANGELOG.md +27 -0
  7. package/deno.json +3 -0
  8. package/dist/adapters/html/cheerio-parser.d.ts.map +1 -1
  9. package/dist/adapters/html/cheerio-parser.js.map +1 -1
  10. package/dist/adapters/publishers/base.d.ts +22 -1
  11. package/dist/adapters/publishers/base.d.ts.map +1 -1
  12. package/dist/adapters/publishers/base.js +142 -2
  13. package/dist/adapters/publishers/base.js.map +1 -1
  14. package/dist/adapters/publishers/book-tech.d.ts +3 -0
  15. package/dist/adapters/publishers/book-tech.d.ts.map +1 -0
  16. package/dist/adapters/publishers/book-tech.js +95 -0
  17. package/dist/adapters/publishers/book-tech.js.map +1 -0
  18. package/dist/adapters/publishers/born-digital.d.ts +3 -0
  19. package/dist/adapters/publishers/born-digital.d.ts.map +1 -0
  20. package/dist/adapters/publishers/born-digital.js +122 -0
  21. package/dist/adapters/publishers/born-digital.js.map +1 -0
  22. package/dist/adapters/publishers/coronasha.d.ts +3 -0
  23. package/dist/adapters/publishers/coronasha.d.ts.map +1 -0
  24. package/dist/adapters/publishers/coronasha.js +119 -0
  25. package/dist/adapters/publishers/coronasha.js.map +1 -0
  26. package/dist/adapters/publishers/impress.d.ts +3 -0
  27. package/dist/adapters/publishers/impress.d.ts.map +1 -0
  28. package/dist/adapters/publishers/impress.js +92 -0
  29. package/dist/adapters/publishers/impress.js.map +1 -0
  30. package/dist/adapters/publishers/manatee.d.ts +3 -0
  31. package/dist/adapters/publishers/manatee.d.ts.map +1 -0
  32. package/dist/adapters/publishers/manatee.js +93 -0
  33. package/dist/adapters/publishers/manatee.js.map +1 -0
  34. package/dist/adapters/publishers/maruzen-publishing.d.ts +3 -0
  35. package/dist/adapters/publishers/maruzen-publishing.d.ts.map +1 -0
  36. package/dist/adapters/publishers/maruzen-publishing.js +108 -0
  37. package/dist/adapters/publishers/maruzen-publishing.js.map +1 -0
  38. package/dist/adapters/publishers/optronics.d.ts +3 -0
  39. package/dist/adapters/publishers/optronics.d.ts.map +1 -0
  40. package/dist/adapters/publishers/optronics.js +92 -0
  41. package/dist/adapters/publishers/optronics.js.map +1 -0
  42. package/dist/adapters/publishers/oreilly-japan.d.ts +3 -0
  43. package/dist/adapters/publishers/oreilly-japan.d.ts.map +1 -0
  44. package/dist/adapters/publishers/oreilly-japan.js +112 -0
  45. package/dist/adapters/publishers/oreilly-japan.js.map +1 -0
  46. package/dist/adapters/publishers/peaks.d.ts +3 -0
  47. package/dist/adapters/publishers/peaks.d.ts.map +1 -0
  48. package/dist/adapters/publishers/peaks.js +80 -0
  49. package/dist/adapters/publishers/peaks.js.map +1 -0
  50. package/dist/adapters/publishers/personal-media.d.ts +3 -0
  51. package/dist/adapters/publishers/personal-media.d.ts.map +1 -0
  52. package/dist/adapters/publishers/personal-media.js +144 -0
  53. package/dist/adapters/publishers/personal-media.js.map +1 -0
  54. package/dist/adapters/publishers/registry.d.ts.map +1 -1
  55. package/dist/adapters/publishers/registry.js +26 -0
  56. package/dist/adapters/publishers/registry.js.map +1 -1
  57. package/dist/adapters/publishers/rutles.d.ts +3 -0
  58. package/dist/adapters/publishers/rutles.d.ts.map +1 -0
  59. package/dist/adapters/publishers/rutles.js +128 -0
  60. package/dist/adapters/publishers/rutles.js.map +1 -0
  61. package/dist/adapters/publishers/saiensu.d.ts +3 -0
  62. package/dist/adapters/publishers/saiensu.d.ts.map +1 -0
  63. package/dist/adapters/publishers/saiensu.js +109 -0
  64. package/dist/adapters/publishers/saiensu.js.map +1 -0
  65. package/dist/adapters/publishers/seshop.d.ts +3 -0
  66. package/dist/adapters/publishers/seshop.d.ts.map +1 -0
  67. package/dist/adapters/publishers/seshop.js +98 -0
  68. package/dist/adapters/publishers/seshop.js.map +1 -0
  69. package/dist/application/get-book-detail.d.ts.map +1 -1
  70. package/dist/application/get-book-detail.js +5 -0
  71. package/dist/application/get-book-detail.js.map +1 -1
  72. package/dist/application/search-books.d.ts.map +1 -1
  73. package/dist/application/search-books.js +7 -1
  74. package/dist/application/search-books.js.map +1 -1
  75. package/dist/domain/book.d.ts +5 -4
  76. package/dist/domain/book.d.ts.map +1 -1
  77. package/dist/main.d.ts +1 -0
  78. package/dist/main.js +1 -0
  79. package/dist/main.js.map +1 -1
  80. package/dist/mcp/server.d.ts.map +1 -1
  81. package/dist/mcp/server.js +1 -0
  82. package/dist/mcp/server.js.map +1 -1
  83. package/flake.nix +1 -1
  84. package/package.json +7 -5
  85. package/src/adapters/html/cheerio-parser.ts +4 -3
  86. package/src/adapters/publishers/base.ts +150 -0
  87. package/src/adapters/publishers/born-digital.ts +2 -17
  88. package/src/adapters/publishers/impress.ts +103 -0
  89. package/src/adapters/publishers/manatee.ts +2 -1
  90. package/src/adapters/publishers/maruzen-publishing.ts +4 -16
  91. package/src/adapters/publishers/oreilly-japan.ts +5 -10
  92. package/src/adapters/publishers/registry.ts +2 -0
  93. package/src/adapters/publishers/rutles.ts +1 -13
  94. package/src/adapters/publishers/saiensu.ts +5 -18
  95. package/src/adapters/publishers/seshop.ts +1 -1
  96. package/src/application/get-book-detail.ts +7 -0
  97. package/src/application/search-books.ts +6 -1
  98. package/src/main.ts +1 -0
  99. package/tests/fixtures/impress-detail-epub.html +746 -0
  100. package/tests/fixtures/impress-detail-social.html +689 -0
  101. package/tests/unit/adapters/base.test.ts +441 -0
  102. package/tests/unit/adapters/publishers/book-tech.test.ts +18 -15
  103. package/tests/unit/adapters/publishers/born-digital.test.ts +18 -15
  104. package/tests/unit/adapters/publishers/coronasha.test.ts +26 -20
  105. package/tests/unit/adapters/publishers/gihyo.test.ts +21 -19
  106. package/tests/unit/adapters/publishers/impress.test.ts +129 -0
  107. package/tests/unit/adapters/publishers/lambdanote.test.ts +12 -11
  108. package/tests/unit/adapters/publishers/manatee.test.ts +14 -12
  109. package/tests/unit/adapters/publishers/maruzen-publishing.test.ts +19 -17
  110. package/tests/unit/adapters/publishers/optronics.test.ts +19 -16
  111. package/tests/unit/adapters/publishers/oreilly-japan.test.ts +19 -16
  112. package/tests/unit/adapters/publishers/peaks.test.ts +17 -14
  113. package/tests/unit/adapters/publishers/personal-media.test.ts +18 -15
  114. package/tests/unit/adapters/publishers/rutles.test.ts +15 -12
  115. package/tests/unit/adapters/publishers/saiensu.test.ts +14 -12
  116. package/tests/unit/adapters/publishers/seshop.test.ts +16 -13
  117. package/tests/unit/adapters/publishers/tatsu-zine.test.ts +13 -12
  118. package/tests/unit/adapters/publishers/techbookfest.test.ts +12 -11
  119. package/tests/unit/adapters/registry.test.ts +37 -0
  120. package/tests/unit/application/get-book-detail.test.ts +102 -0
  121. package/tests/unit/application/search-books.test.ts +137 -0
  122. package/vitest.config.ts +0 -8
@@ -17,7 +17,19 @@
17
17
  "Read(//tmp/**)",
18
18
  "Bash(npm test:*)",
19
19
  "Bash(python3:*)",
20
- "WebFetch(domain:www.personal-media.co.jp)"
20
+ "WebFetch(domain:www.personal-media.co.jp)",
21
+ "Bash(grep -rn \"export.*Element\" node_modules/cheerio/dist/esm/*.d.ts)",
22
+ "Bash(npx tsc:*)",
23
+ "Bash(npx oxlint:*)",
24
+ "Bash(npm run:*)",
25
+ "Bash(curl -s \"https://book.impress.co.jp/books/1124101031\")",
26
+ "Bash(curl -s \"https://book.impress.co.jp/books/1125101113\")",
27
+ "Bash(cp /tmp/impress-detail-social.html tests/fixtures/impress-detail-social.html)",
28
+ "Bash(cp /tmp/impress-detail-nodrm.html tests/fixtures/impress-detail-epub.html)",
29
+ "Bash(wc -c tests/fixtures/impress-detail-*.html)",
30
+ "Bash(git -C /Users/megurine/repo/js/techbook-mcp status)",
31
+ "Bash(git -C /Users/megurine/repo/js/techbook-mcp diff)",
32
+ "Bash(git:*)"
21
33
  ]
22
34
  }
23
35
  }
@@ -0,0 +1,105 @@
1
+ ---
2
+ name: techbook-mcp-release-prep
3
+ description: Prepare a techbook-mcp release by bumping the version, updating the changelog, and running verification. Use when the user asks to prepare the next version, cut a release, or make sure versioned files are consistent before tagging.
4
+ ---
5
+
6
+ # techbook-mcp Release Prep
7
+
8
+ Follow this workflow when preparing a new `techbook-mcp` release.
9
+
10
+ ## Decide the Next Version
11
+
12
+ Choose the next semantic version before touching any files.
13
+
14
+ - `patch` (0.x.Y) — bug fixes, no new functionality
15
+ - `minor` (0.X.0) — new adapters, new features, backward-compatible changes
16
+ - `major` (X.0.0) — breaking changes to the MCP tool interface or `BookRecord` schema
17
+
18
+ If the user specifies a version, use it. Otherwise infer from the unreleased commits since the last tag.
19
+
20
+ ## Update Versioned Files
21
+
22
+ Update these files together in one pass:
23
+
24
+ - `CHANGELOG.md`
25
+ - `package.json` — `"version"` field
26
+ - `package-lock.json` — `"version"` field in the root object (same value as `package.json`)
27
+
28
+ ### CHANGELOG.md Rules
29
+
30
+ - If `CHANGELOG.md` does not exist yet, create it with the standard Keep a Changelog header.
31
+ - Add a new `## [x.y.z] - YYYY-MM-DD` section directly below `## [Unreleased]`.
32
+ - Use Keep a Changelog section headings as needed: `Added`, `Changed`, `Deprecated`, `Removed`, `Fixed`, `Security`.
33
+ - Group the same kinds of changes under the same heading.
34
+ - Write entries user-facing: what changed, not how. Skip internal refactors unless they affect users.
35
+ - List new publisher adapters under `Added`.
36
+ - Preserve the release date in every version heading.
37
+ - Keep the `[Unreleased]` section empty after moving its contents to the new release section.
38
+ - Update the `[Unreleased]` compare link and add the new release compare link at the bottom of the file.
39
+ - Keep version headings and bottom-of-file links consistent so releases and compare ranges remain linkable.
40
+
41
+ ### CHANGELOG.md Template (first release)
42
+
43
+ ```markdown
44
+ # Changelog
45
+
46
+ All notable changes to this project will be documented in this file.
47
+
48
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
49
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
50
+
51
+ ## [Unreleased]
52
+
53
+ ## [x.y.z] - YYYY-MM-DD
54
+
55
+ ### Added
56
+
57
+ - ...
58
+
59
+ [Unreleased]: https://github.com/zonuexe/techbook-mcp/compare/vx.y.z...HEAD
60
+ [x.y.z]: https://github.com/zonuexe/techbook-mcp/releases/tag/vx.y.z
61
+ ```
62
+
63
+ ## Verify Before Committing
64
+
65
+ Run all checks in order:
66
+
67
+ ```bash
68
+ npm test
69
+ ```
70
+
71
+ ```bash
72
+ npm run lint
73
+ ```
74
+
75
+ ```bash
76
+ npm run build
77
+ ```
78
+
79
+ All three must pass. Do not commit if any check fails.
80
+
81
+ ## Commit the Release
82
+
83
+ Prefer a single release-prep commit containing:
84
+
85
+ - version bump in `package.json` and `package-lock.json`
86
+ - `CHANGELOG.md` update
87
+
88
+ Use this commit message format:
89
+
90
+ ```text
91
+ Bump up version to x.y.z
92
+ ```
93
+
94
+ Do not include other unrelated changes in the release commit.
95
+
96
+ ## Quick Checklist
97
+
98
+ - Working tree starts clean or you understand every pending change.
99
+ - `CHANGELOG.md` has a new `## [x.y.z] - YYYY-MM-DD` section with user-facing entries.
100
+ - `package.json` and `package-lock.json` both show the new version.
101
+ - Bottom-of-file links in `CHANGELOG.md` are consistent.
102
+ - `npm test` passed.
103
+ - `npm run lint` passed.
104
+ - `npm run build` passed.
105
+ - Commit message follows `chore: release x.y.z`.
@@ -26,6 +26,9 @@ jobs:
26
26
  - name: Install dependencies
27
27
  run: npm ci
28
28
 
29
+ - name: Lint
30
+ run: npm run lint
31
+
29
32
  - name: Type check
30
33
  run: npx tsc --noEmit
31
34
 
@@ -34,3 +37,36 @@ jobs:
34
37
 
35
38
  - name: Build
36
39
  run: npm run build
40
+
41
+ bun:
42
+ runs-on: ubuntu-latest
43
+ steps:
44
+ - uses: actions/checkout@v4
45
+
46
+ - uses: oven-sh/setup-bun@v2
47
+
48
+ - name: Install dependencies
49
+ run: bun install
50
+
51
+ - name: Run tests
52
+ run: bun test
53
+
54
+ deno:
55
+ runs-on: ubuntu-latest
56
+ steps:
57
+ - uses: actions/checkout@v4
58
+
59
+ - uses: denoland/setup-deno@v2
60
+ with:
61
+ deno-version: v2.x
62
+
63
+ - name: Install Node deps (for node_modules)
64
+ uses: actions/setup-node@v4
65
+ with:
66
+ node-version: 22.x
67
+ cache: npm
68
+
69
+ - run: npm ci
70
+
71
+ - name: Run tests
72
+ run: deno test --allow-read --no-check --sloppy-imports tests/
package/.oxlintrc.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/oxc-project/oxc/main/npm/oxlint/configuration_schema.json",
3
+ "plugins": ["typescript", "unicorn"],
4
+ "rules": {
5
+ "no-unused-vars": "error",
6
+ "no-console": "warn",
7
+ "unicorn/no-array-for-each": "error",
8
+ "unicorn/prefer-string-slice": "error",
9
+ "typescript/consistent-type-imports": "error"
10
+ },
11
+ "ignorePatterns": ["dist/**", "node_modules/**"]
12
+ }
package/AGENTS.md CHANGED
@@ -3,11 +3,20 @@
3
3
  日本語技術書の書誌情報を出版社公式サイト・APIから取得するMCPサーバー。
4
4
  詳細な設計は [docs/design-doc.md](docs/design-doc.md) を参照。
5
5
 
6
+ ## コミットメッセージ規約
7
+
8
+ Conventional Commits は使わない。コミットメッセージは端的な日本語または英語の命令形で書く。
9
+
10
+ ```
11
+ robots.txt チェックを追加し結果を6時間キャッシュする
12
+ Add robots.txt check with 6-hour cache
13
+ ```
14
+
6
15
  ## 開発コマンド
7
16
 
8
17
  ```bash
9
18
  npm install
10
- npm test # ユニットテスト実行 (Vitest)
19
+ npm test # ユニットテスト実行 (node:test)
11
20
  npm run build # TypeScript コンパイル → dist/
12
21
  ```
13
22
 
@@ -47,7 +56,12 @@ npm run build # TypeScript コンパイル → dist/
47
56
 
48
57
  ## テスト方針
49
58
 
59
+ テストフレームワークは `node:test` + `node:assert/strict` を使う(vitest は使わない)。
60
+
50
61
  ```typescript
62
+ import { describe, it } from "node:test";
63
+ import assert from "node:assert/strict";
64
+
51
65
  // 標準的なテストセットアップ
52
66
  function makeDeps(http: MockHttpClient) {
53
67
  return { http, parser: new CheerioHtmlParser(), cache: new NullCacheStore() };
@@ -60,6 +74,20 @@ const http = new MockHttpClient()
60
74
  // POST のモック (GraphQL等)
61
75
  const http = new MockHttpClient()
62
76
  .addPostResponse("https://api.example.com/graphql", { status: 200, body: json });
77
+
78
+ // vitest → node:assert の主な対応
79
+ // expect(x).toBe(y) → assert.strictEqual(x, y)
80
+ // expect(x).toEqual(y) → assert.deepStrictEqual(x, y)
81
+ // expect(x).toMatchObject(y) → assert.partialDeepStrictEqual(x, y)
82
+ // expect(x).toHaveLength(n) → assert.strictEqual(x.length, n)
83
+ // expect(x).toContain(s) → assert.ok(x.includes(s))
84
+ // expect(x).toMatch(/r/) → assert.match(x, /r/)
85
+ // await expect(p).rejects.toThrow("msg") → await assert.rejects(p, /msg/)
86
+
87
+ // モック関数: node:test の mock.fn() は Bun 非対応のため、テストファイル内に
88
+ // ローカルで mockFn() ヘルパーを定義して使う(Node.js・Bun・Deno 共通で動作)
89
+ // vi.fn().mockResolvedValue(v) → mockFn(async () => v)
90
+ // fn.toHaveBeenCalledOnce() → assert.strictEqual(fn.mock.callCount(), 1)
63
91
  ```
64
92
 
65
93
  ## よくある落とし穴
package/CHANGELOG.md ADDED
@@ -0,0 +1,27 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.2.0] - 2026-04-12
11
+
12
+ ### Added
13
+
14
+ - インプレスブックス (`impress-books`) アダプターを追加
15
+ - 各出版社サイトの `robots.txt` をチェックし、クロール可否を判定する機能を追加(結果は6時間キャッシュ)
16
+ - GitHub Actions に Bun・Deno のテストジョブを追加
17
+
18
+ ### Fixed
19
+
20
+ - `npx` でバイナリ起動する際に shebang がなくエラーになる問題を修正
21
+
22
+ ### Changed
23
+
24
+ - テストを vitest から `node:test` + `node:assert` に移行(Node.js・Bun・Deno で共通実行可能に)
25
+
26
+ [Unreleased]: https://github.com/zonuexe/techbook-mcp/compare/v0.2.0...HEAD
27
+ [0.2.0]: https://github.com/zonuexe/techbook-mcp/releases/tag/v0.2.0
package/deno.json ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "nodeModulesDir": "auto"
3
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"cheerio-parser.d.ts","sourceRoot":"","sources":["../../../src/adapters/html/cheerio-parser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAe,MAAM,4BAA4B,CAAC;AA0CxF,qBAAa,iBAAkB,YAAW,UAAU;IAClD,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY;CAIlC"}
1
+ {"version":3,"file":"cheerio-parser.d.ts","sourceRoot":"","sources":["../../../src/adapters/html/cheerio-parser.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAe,MAAM,4BAA4B,CAAC;AA0CxF,qBAAa,iBAAkB,YAAW,UAAU;IAClD,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY;CAIlC"}
@@ -1 +1 @@
1
- {"version":3,"file":"cheerio-parser.js","sourceRoot":"","sources":["../../../src/adapters/html/cheerio-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAGnC,MAAM,cAAc;IAEC;IACA;IAFnB,YACmB,CAAqB,EACrB,EAAmB;QADnB,MAAC,GAAD,CAAC,CAAoB;QACrB,OAAE,GAAF,EAAE,CAAiB;IACnC,CAAC;IAEJ,IAAI;QACF,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;IACvC,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAChC,CAAC;IAED,IAAI,CAAC,IAAY;QACf,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IAED,IAAI,CAAC,QAAgB;QACnB,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;aACnB,IAAI,CAAC,QAAQ,CAAC;aACd,OAAO,EAAE;aACT,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IAC/C,CAAC;CACF;AAED,MAAM,eAAe;IACU;IAA7B,YAA6B,CAAqB;QAArB,MAAC,GAAD,CAAC,CAAoB;IAAG,CAAC;IAEtD,MAAM,CAAC,QAAgB;QACrB,OAAO,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC;aACpB,OAAO,EAAE;aACT,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IAC/C,CAAC;IAED,SAAS,CAAC,QAAgB;QACxB,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IAC1C,CAAC;CACF;AAED,MAAM,OAAO,iBAAiB;IAC5B,KAAK,CAAC,IAAY;QAChB,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7B,OAAO,IAAI,eAAe,CAAC,CAAC,CAAC,CAAC;IAChC,CAAC;CACF"}
1
+ {"version":3,"file":"cheerio-parser.js","sourceRoot":"","sources":["../../../src/adapters/html/cheerio-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAInC,MAAM,cAAc;IAEC;IACA;IAFnB,YACmB,CAAqB,EACrB,EAAW;QADX,MAAC,GAAD,CAAC,CAAoB;QACrB,OAAE,GAAF,EAAE,CAAS;IAC3B,CAAC;IAEJ,IAAI;QACF,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;IACvC,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAChC,CAAC;IAED,IAAI,CAAC,IAAY;QACf,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IAED,IAAI,CAAC,QAAgB;QACnB,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;aACnB,IAAI,CAAC,QAAQ,CAAC;aACd,OAAO,EAAE;aACT,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,EAAE,EAAa,CAAC,CAAC,CAAC;IAC1D,CAAC;CACF;AAED,MAAM,eAAe;IACU;IAA7B,YAA6B,CAAqB;QAArB,MAAC,GAAD,CAAC,CAAoB;IAAG,CAAC;IAEtD,MAAM,CAAC,QAAgB;QACrB,OAAO,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC;aACpB,OAAO,EAAE;aACT,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,EAAE,EAAa,CAAC,CAAC,CAAC;IAC1D,CAAC;IAED,SAAS,CAAC,QAAgB;QACxB,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IAC1C,CAAC;CACF;AAED,MAAM,OAAO,iBAAiB;IAC5B,KAAK,CAAC,IAAY;QAChB,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7B,OAAO,IAAI,eAAe,CAAC,CAAC,CAAC,CAAC;IAChC,CAAC;CACF"}
@@ -2,9 +2,30 @@ import type { PublisherDeps } from "../../domain/publisher.js";
2
2
  import type { EbookStore } from "../../domain/book.js";
3
3
  import type { HtmlDocument } from "../../ports/html-parser.js";
4
4
  export declare const CACHE_TTL_SECONDS = 3600;
5
- export declare function fetchText(url: string, deps: PublisherDeps): Promise<string>;
5
+ export declare const ROBOTS_CACHE_TTL_SECONDS: number;
6
+ /**
7
+ * 指定URLのオリジンの robots.txt を取得してアクセス可否を返す。
8
+ * 取得結果は6時間キャッシュする。エラー時はアクセスを許可する(fail-open)。
9
+ */
10
+ export declare function checkRobotsTxt(url: string, deps: PublisherDeps): Promise<boolean>;
11
+ export declare function fetchText(url: string, deps: PublisherDeps, extraHeaders?: Record<string, string>): Promise<string>;
6
12
  /** HTMLタグを除去する(gihyo APIのauthorフィールドのruby markup除去に使用) */
7
13
  export declare function stripHtmlTags(html: string): string;
14
+ /**
15
+ * キーワードを EUC-JP でパーセントエンコードする。
16
+ * born-digital・rutles など EUC-JP エンコードのみ受け付けるサイト向け。
17
+ */
18
+ export declare function encodeEucJp(text: string): string;
19
+ /**
20
+ * "2026年3月25日" → "2026-03-25"
21
+ * 1桁の月・日も対応する。
22
+ */
23
+ export declare function parseJapaneseDateToISO(text: string): string | undefined;
24
+ /**
25
+ * 著者名末尾の役割語(著・訳・編・監修・監訳など)を除去して名前だけを返す。
26
+ * 例: "Dan Vanderkam 著" → "Dan Vanderkam"
27
+ */
28
+ export declare function stripAuthorRole(name: string): string;
8
29
  /** "¥3,960" や "3,300円(税込)" などから整数値を取り出す */
9
30
  export declare function parseJapanesePrice(text: string): number | undefined;
10
31
  /** 相対URLを絶対URLに解決する */
@@ -1 +1 @@
1
- {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/adapters/publishers/base.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAW,MAAM,sBAAsB,CAAC;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAQ/D,eAAO,MAAM,iBAAiB,OAAO,CAAC;AAEtC,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAYjF;AAED,0DAA0D;AAC1D,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,2CAA2C;AAC3C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAInE;AAED,uBAAuB;AACvB,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG5D;AA6BD,sCAAsC;AACtC,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAOjE;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,YAAY,GAAG,UAAU,EAAE,CAgBzE"}
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/adapters/publishers/base.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAW,MAAM,sBAAsB,CAAC;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAQ/D,eAAO,MAAM,iBAAiB,OAAO,CAAC;AACtC,eAAO,MAAM,wBAAwB,QAAW,CAAC;AAyFjD;;;GAGG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CA0BvF;AAED,wBAAsB,SAAS,CAC7B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,aAAa,EACnB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACpC,OAAO,CAAC,MAAM,CAAC,CAgBjB;AAED,0DAA0D;AAC1D,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKhD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAIvE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,2CAA2C;AAC3C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAInE;AAED,uBAAuB;AACvB,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG5D;AAwCD,sCAAsC;AACtC,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAOjE;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,YAAY,GAAG,UAAU,EAAE,CAgBzE"}
@@ -1,14 +1,116 @@
1
+ import iconv from "iconv-lite";
1
2
  const DEFAULT_HEADERS = {
2
3
  "User-Agent": "techbook-mcp/0.1.0 (+https://github.com/zonuexe/techbook-mcp; bibliographic search bot)",
3
4
  "Accept": "text/html,application/xhtml+xml,application/json",
4
5
  "Accept-Language": "ja,en;q=0.9",
5
6
  };
6
7
  export const CACHE_TTL_SECONDS = 3600; // 1時間
7
- export async function fetchText(url, deps) {
8
+ export const ROBOTS_CACHE_TTL_SECONDS = 6 * 3600; // 6時間
9
+ /** robots.txt をパースしてセクション一覧を返す */
10
+ function parseRobotsTxt(content) {
11
+ const sections = [];
12
+ let current = null;
13
+ let inAgentBlock = true;
14
+ for (const rawLine of content.split(/\r?\n/)) {
15
+ const trimmedRaw = rawLine.trim();
16
+ // 空行(コメント行ではない)のみセクションをリセット
17
+ if (!trimmedRaw || trimmedRaw.startsWith("#")) {
18
+ if (!trimmedRaw) {
19
+ current = null;
20
+ inAgentBlock = true;
21
+ }
22
+ continue;
23
+ }
24
+ const line = trimmedRaw.split("#")[0].trim();
25
+ if (!line)
26
+ continue;
27
+ const colonIdx = line.indexOf(":");
28
+ if (colonIdx === -1)
29
+ continue;
30
+ const key = line.slice(0, colonIdx).trim().toLowerCase();
31
+ const value = line.slice(colonIdx + 1).trim();
32
+ if (key === "user-agent") {
33
+ if (inAgentBlock && current !== null) {
34
+ // 同じセクションに複数のUser-agent行
35
+ current.agents.push(value.toLowerCase());
36
+ }
37
+ else {
38
+ // 新しいセクション開始
39
+ current = { agents: [value.toLowerCase()], rules: [] };
40
+ sections.push(current);
41
+ inAgentBlock = true;
42
+ }
43
+ }
44
+ else if (current !== null && (key === "allow" || key === "disallow")) {
45
+ inAgentBlock = false;
46
+ current.rules.push({ type: key, path: value });
47
+ }
48
+ }
49
+ return sections;
50
+ }
51
+ /** 指定ユーザーエージェントに適用されるルールを返す(固有エージェント優先、なければ * にフォールバック) */
52
+ function getRulesForAgent(sections, agentToken) {
53
+ const lower = agentToken.toLowerCase();
54
+ for (const section of sections) {
55
+ if (section.agents.includes(lower))
56
+ return section.rules;
57
+ }
58
+ for (const section of sections) {
59
+ if (section.agents.includes("*"))
60
+ return section.rules;
61
+ }
62
+ return [];
63
+ }
64
+ /** パスがルール一覧で許可されているか判定する(最長プレフィックス一致) */
65
+ function isPathAllowed(path, rules) {
66
+ let bestMatch = { length: -1, allowed: true };
67
+ for (const rule of rules) {
68
+ if (!rule.path)
69
+ continue; // 空の Disallow は「全許可」を意味するが不一致として扱う
70
+ if (path.startsWith(rule.path) && rule.path.length > bestMatch.length) {
71
+ bestMatch = { length: rule.path.length, allowed: rule.type === "allow" };
72
+ }
73
+ }
74
+ return bestMatch.allowed;
75
+ }
76
+ /**
77
+ * 指定URLのオリジンの robots.txt を取得してアクセス可否を返す。
78
+ * 取得結果は6時間キャッシュする。エラー時はアクセスを許可する(fail-open)。
79
+ */
80
+ export async function checkRobotsTxt(url, deps) {
81
+ const parsed = new URL(url);
82
+ const origin = `${parsed.protocol}//${parsed.host}`;
83
+ const cacheKey = `robots:${origin}`;
84
+ let content;
85
+ const cached = await deps.cache.get(cacheKey);
86
+ if (cached !== null) {
87
+ content = cached;
88
+ }
89
+ else {
90
+ try {
91
+ const response = await deps.http.get(`${origin}/robots.txt`, { headers: DEFAULT_HEADERS });
92
+ content = response.status === 200 ? await response.text() : "";
93
+ }
94
+ catch {
95
+ // robots.txt 取得失敗時はアクセスを許可する
96
+ content = "";
97
+ }
98
+ await deps.cache.set(cacheKey, content, ROBOTS_CACHE_TTL_SECONDS);
99
+ }
100
+ if (!content)
101
+ return true;
102
+ const sections = parseRobotsTxt(content);
103
+ const rules = getRulesForAgent(sections, "techbook-mcp");
104
+ return isPathAllowed(parsed.pathname + parsed.search, rules);
105
+ }
106
+ export async function fetchText(url, deps, extraHeaders) {
8
107
  const cached = await deps.cache.get(url);
9
108
  if (cached !== null)
10
109
  return cached;
11
- const response = await deps.http.get(url, { headers: DEFAULT_HEADERS });
110
+ const headers = extraHeaders
111
+ ? { ...DEFAULT_HEADERS, ...extraHeaders }
112
+ : DEFAULT_HEADERS;
113
+ const response = await deps.http.get(url, { headers });
12
114
  if (response.status !== 200) {
13
115
  throw new Error(`HTTP ${response.status}: ${url}`);
14
116
  }
@@ -20,6 +122,33 @@ export async function fetchText(url, deps) {
20
122
  export function stripHtmlTags(html) {
21
123
  return html.replace(/<[^>]+>/g, "");
22
124
  }
125
+ /**
126
+ * キーワードを EUC-JP でパーセントエンコードする。
127
+ * born-digital・rutles など EUC-JP エンコードのみ受け付けるサイト向け。
128
+ */
129
+ export function encodeEucJp(text) {
130
+ const bytes = iconv.encode(text, "euc-jp");
131
+ return Array.from(bytes)
132
+ .map(b => "%" + b.toString(16).toUpperCase().padStart(2, "0"))
133
+ .join("");
134
+ }
135
+ /**
136
+ * "2026年3月25日" → "2026-03-25"
137
+ * 1桁の月・日も対応する。
138
+ */
139
+ export function parseJapaneseDateToISO(text) {
140
+ const m = text.match(/(\d{4})年(\d{1,2})月(\d{1,2})日/);
141
+ if (!m)
142
+ return undefined;
143
+ return `${m[1]}-${m[2].padStart(2, "0")}-${m[3].padStart(2, "0")}`;
144
+ }
145
+ /**
146
+ * 著者名末尾の役割語(著・訳・編・監修・監訳など)を除去して名前だけを返す。
147
+ * 例: "Dan Vanderkam 著" → "Dan Vanderkam"
148
+ */
149
+ export function stripAuthorRole(name) {
150
+ return name.replace(/[\u3000\s]*(著|訳|編|監修|監訳|著訳|著・訳|他)[\u3000\s]*$/, "").trim();
151
+ }
23
152
  /** "¥3,960" や "3,300円(税込)" などから整数値を取り出す */
24
153
  export function parseJapanesePrice(text) {
25
154
  const match = text.match(/[\d,]+/);
@@ -42,14 +171,25 @@ export function extractAsin(html) {
42
171
  const EBOOK_STORE_PATTERNS = [
43
172
  // DRM-free
44
173
  { pattern: /techbookfest\.org\/product\//, name: "技術書典", drm: "free" },
174
+ { pattern: /oreilly\.co\.jp\/books\//, name: "オライリー・ジャパン", drm: "free" },
175
+ { pattern: /shop\.rutles\.net\//, name: "ラトルズ", drm: "free" },
176
+ { pattern: /peaks\.cc\/books\//, name: "PEAKS", drm: "free" },
177
+ { pattern: /optronics-ebook\.com\/products\//, name: "オプトロニクス社", drm: "free" },
45
178
  { pattern: /gihyo\.jp\/dp\/ebook\//, name: "Gihyo Digital Publishing", drm: "social" },
179
+ { pattern: /seshop\.com\/product\//, name: "SEshop", drm: "social" },
180
+ { pattern: /book-tech\.com\/books\//, name: "BOOK TECH", drm: "social" },
181
+ { pattern: /wgn-obs\.shop-pro\.jp\/\?pid=/, name: "ボーンデジタル", drm: "social" },
46
182
  // ソーシャルDRM (購入時生成IDまたは購入者情報を透かし刻印、技術的制限なし)
183
+ { pattern: /book\.mynavi\.jp\/manatee\//, name: "マナティ", drm: "social" },
47
184
  { pattern: /www\.lambdanote\.com\/products\//, name: "ラムダノート", drm: "social" },
48
185
  { pattern: /tatsu-zine\.com\/books\/(?!pub\/)/, name: "達人出版会", drm: "social" },
49
186
  // ソーシャルDRM (購入者情報透かし入りPDF、技術的制限なし)
50
187
  { pattern: /book\.impress\.co\.jp\/books\//, name: "インプレスブックス", drm: "social" },
51
188
  // DRM-attached
189
+ { pattern: /saiensu\.co\.jp/, name: "サイエンス社", drm: "password_pdf" },
52
190
  { pattern: /amazon\.co\.jp/, name: "Kindle", drm: "drm" },
191
+ { pattern: /kinokuniya\.co\.jp\/(?:kinoppystore|f\/dsg-08)/, name: "Kinoppy", drm: "drm" },
192
+ { pattern: /coop-ebook\.jp\/mem\//, name: "VarsityWave eBooks", drm: "drm" },
53
193
  { pattern: /books\.rakuten\.co\.jp|rakuten\.kobo\.com|kobo\.com/, name: "楽天Kobo", drm: "drm" },
54
194
  { pattern: /booklive\.jp/, name: "BookLive", drm: "drm" },
55
195
  { pattern: /honto\.jp/, name: "honto", drm: "drm" },
@@ -1 +1 @@
1
- {"version":3,"file":"base.js","sourceRoot":"","sources":["../../../src/adapters/publishers/base.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../../src/adapters/publishers/base.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { PublisherAdapter } from "../../domain/publisher.js";
2
+ export declare const bookTechAdapter: PublisherAdapter;
3
+ //# sourceMappingURL=book-tech.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"book-tech.d.ts","sourceRoot":"","sources":["../../../src/adapters/publishers/book-tech.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAiB,MAAM,2BAA2B,CAAC;AAqBjF,eAAO,MAAM,eAAe,EAAE,gBA+F7B,CAAC"}
@@ -0,0 +1,95 @@
1
+ import { fetchText, parseJapanesePrice, resolveUrl } from "./base.js";
2
+ const BASE_URL = "https://book-tech.com";
3
+ const SEARCH_URL = `${BASE_URL}/books`;
4
+ // クエリパラメータキー(URLエンコード済み)
5
+ const SEARCH_PARAM = "q%5Btitle_or_overview_or_identification_number_1_or_product_code_cont%5D";
6
+ /** "2026/2/20" → "2026-02-20" */
7
+ function parseDate(text) {
8
+ const m = text.match(/(\d{4})\/(\d{1,2})\/(\d{1,2})/);
9
+ if (!m)
10
+ return undefined;
11
+ return `${m[1]}-${m[2].padStart(2, "0")}-${m[3].padStart(2, "0")}`;
12
+ }
13
+ /** "(著)" などの役割語を末尾から除去する */
14
+ function stripRole(name) {
15
+ return name.replace(/\s*[((][^))]*[))]\s*$/, "").trim();
16
+ }
17
+ export const bookTechAdapter = {
18
+ id: "book-tech",
19
+ name: "BOOK TECH",
20
+ baseUrl: BASE_URL,
21
+ async search(query, deps) {
22
+ const word = [query.title, query.author].filter(Boolean).join(" ");
23
+ if (!word)
24
+ return [];
25
+ const url = `${SEARCH_URL}?${SEARCH_PARAM}=${encodeURIComponent(word)}`;
26
+ const html = await fetchText(url, deps);
27
+ const doc = deps.parser.parse(html);
28
+ const results = [];
29
+ const limit = query.limit ?? 10;
30
+ for (const item of doc.select("div.contents-index-item")) {
31
+ const linkEl = item.find("a.book-ribbon-link")[0];
32
+ const href = linkEl?.attr("href");
33
+ if (!href)
34
+ continue;
35
+ const bookUrl = resolveUrl(BASE_URL, href);
36
+ const title = item.find(".contents-index-item-detail-title")[0]?.text().trim();
37
+ if (!title)
38
+ continue;
39
+ const publisherEl = item.find("a[href*='publisher_relations']")[0];
40
+ const publisher = publisherEl?.text().trim() ?? "";
41
+ const authors = item.find("a[href*='author_relations']")
42
+ .map(el => stripRole(el.text().trim()))
43
+ .filter(Boolean);
44
+ const priceText = item.find(".contents-index-item-detail-price_include_tax")[0]?.text();
45
+ const price = priceText ? parseJapanesePrice(priceText) : undefined;
46
+ const dateText = item.find(".my-1")[0]?.text();
47
+ const publishedAt = dateText ? parseDate(dateText) : undefined;
48
+ const imgEl = item.find("img.thumb")[0];
49
+ const coverImageUrl = imgEl?.attr("src") ?? undefined;
50
+ results.push({
51
+ title,
52
+ authors,
53
+ publisher,
54
+ url: bookUrl,
55
+ price,
56
+ publishedAt,
57
+ coverImageUrl,
58
+ ebookStores: [{ name: "BOOK TECH", url: bookUrl, drm: "social" }],
59
+ });
60
+ if (results.length >= limit)
61
+ break;
62
+ }
63
+ return results;
64
+ },
65
+ async getDetail(url, deps) {
66
+ const html = await fetchText(url, deps);
67
+ const doc = deps.parser.parse(html);
68
+ const title = doc.selectOne(".contents-book-about-title h1")?.text().trim() ?? "";
69
+ const publisherEl = doc.selectOne("a[href*='publisher_relations']");
70
+ const publisher = publisherEl?.text().trim() ?? "";
71
+ const authors = doc.select("a[href*='author_relations']")
72
+ .map(el => stripRole(el.text().trim()))
73
+ .filter(Boolean);
74
+ const priceText = doc.selectOne(".contents-book-item-detail-price_include_tax")?.text();
75
+ const price = priceText ? parseJapanesePrice(priceText) : undefined;
76
+ const dateText = doc.selectOne(".contents-book-about-publicationdate")?.text();
77
+ const publishedAt = dateText ? parseDate(dateText) : undefined;
78
+ const isbnText = doc.selectOne(".contents-book-about-id")?.text();
79
+ const isbn = isbnText?.match(/\d{13}/)?.[0];
80
+ const imgEl = doc.selectOne("img.thumb");
81
+ const coverImageUrl = imgEl?.attr("src") ?? undefined;
82
+ return {
83
+ title,
84
+ authors,
85
+ publisher,
86
+ url,
87
+ isbn,
88
+ price,
89
+ publishedAt,
90
+ coverImageUrl,
91
+ ebookStores: [{ name: "BOOK TECH", url, drm: "social" }],
92
+ };
93
+ },
94
+ };
95
+ //# sourceMappingURL=book-tech.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"book-tech.js","sourceRoot":"","sources":["../../../src/adapters/publishers/book-tech.ts"],"names":[],"mappings":"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"}