amenbo 0.1.5 → 0.3.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 (56) hide show
  1. package/README.en.md +11 -1
  2. package/README.md +11 -1
  3. package/dist/cache.d.ts +48 -2
  4. package/dist/cache.js +164 -53
  5. package/dist/cache.js.map +1 -1
  6. package/dist/cli.d.ts +3 -1
  7. package/dist/cli.js +59 -4
  8. package/dist/cli.js.map +1 -1
  9. package/dist/core.d.ts +6 -0
  10. package/dist/core.js +134 -44
  11. package/dist/core.js.map +1 -1
  12. package/dist/diff.d.ts +1 -1
  13. package/dist/diff.js +29 -9
  14. package/dist/diff.js.map +1 -1
  15. package/dist/errors.d.ts +11 -0
  16. package/dist/errors.js +13 -0
  17. package/dist/errors.js.map +1 -1
  18. package/dist/extract/dataSources.js +17 -4
  19. package/dist/extract/dataSources.js.map +1 -1
  20. package/dist/extract/markdown.d.ts +44 -0
  21. package/dist/extract/markdown.js +181 -2
  22. package/dist/extract/markdown.js.map +1 -1
  23. package/dist/extract/outline.d.ts +18 -0
  24. package/dist/extract/outline.js +37 -4
  25. package/dist/extract/outline.js.map +1 -1
  26. package/dist/extract/pdf.js +2 -2
  27. package/dist/extract/pruning.d.ts +4 -2
  28. package/dist/extract/pruning.js +36 -7
  29. package/dist/extract/pruning.js.map +1 -1
  30. package/dist/extract/qualityScore.d.ts +3 -2
  31. package/dist/extract/qualityScore.js +8 -3
  32. package/dist/extract/qualityScore.js.map +1 -1
  33. package/dist/fetcher/browser.js +15 -1
  34. package/dist/fetcher/browser.js.map +1 -1
  35. package/dist/fetcher/http.d.ts +11 -1
  36. package/dist/fetcher/http.js +6 -1
  37. package/dist/fetcher/http.js.map +1 -1
  38. package/dist/fetcher/index.d.ts +6 -0
  39. package/dist/fetcher/index.js +18 -13
  40. package/dist/fetcher/index.js.map +1 -1
  41. package/dist/installBrowser.d.ts +11 -0
  42. package/dist/installBrowser.js +30 -0
  43. package/dist/installBrowser.js.map +1 -0
  44. package/dist/links.d.ts +12 -0
  45. package/dist/links.js +32 -17
  46. package/dist/links.js.map +1 -1
  47. package/dist/politeness.d.ts +23 -3
  48. package/dist/politeness.js +27 -6
  49. package/dist/politeness.js.map +1 -1
  50. package/dist/screenshot.d.ts +2 -0
  51. package/dist/screenshot.js +14 -4
  52. package/dist/screenshot.js.map +1 -1
  53. package/dist/server.d.ts +2 -0
  54. package/dist/server.js +55 -26
  55. package/dist/server.js.map +1 -1
  56. package/package.json +3 -6
package/README.en.md CHANGED
@@ -37,7 +37,12 @@ For a measured comparison against similar tools (official fetch MCP / Jina Reade
37
37
 
38
38
  ```bash
39
39
  npm install -g amenbo
40
- # postinstall downloads Chromium (for SPA rendering & screenshots)
40
+ ```
41
+
42
+ That's enough for plain Markdown fetching (`fetch` / `links`). If you also want browser-based fetching — SPA escalation or screenshots — run this once (a ~170MB download the first time):
43
+
44
+ ```bash
45
+ npx -y amenbo install-browser
41
46
  ```
42
47
 
43
48
  Or for development:
@@ -165,6 +170,11 @@ Discovery order: sitemap → RSS/Atom → in-page links.
165
170
  - **SSRF protection**: rejects non-http/https schemes (`file:`, `ftp:`, etc.). Rejects DNS-resolved destinations that are private / loopback / link-local / reserved addresses. As a DNS rebinding (TOCTOU) countermeasure, actual connections are pinned to the validated IP
166
171
  - **Body size cap**: prevents OOM from oversized responses
167
172
 
173
+ ## Known limitations
174
+
175
+ - **No HTTP proxy support**: `HTTP_PROXY` / `HTTPS_PROXY` environment variables are not honored. As an SSRF countermeasure, connections are pinned to a validated IP (DNS rebinding protection), which is incompatible with delegating name resolution to an upstream proxy. Networks that require an upstream proxy are currently unsupported
176
+ - **No anti-bot circumvention**: fetch failures due to robots.txt denial or bot countermeasures are by design and reported as-is (see [Low impact on target sites](#low-impact-on-target-sites))
177
+
168
178
  ## Development
169
179
 
170
180
  ```bash
package/README.md CHANGED
@@ -37,7 +37,12 @@ amenbo(アメンボ / water strider)は、Claude Code や Codex のようなコ
37
37
 
38
38
  ```bash
39
39
  npm install -g amenbo
40
- # postinstall で Chromium が入ります(SPA描画・スクリーンショット用)
40
+ ```
41
+
42
+ Markdown 取得(通常の `fetch` / `links`)はこれだけで動きます。JS 描画が必要な SPA への昇格やスクリーンショットなど、ブラウザ(Chromium)経由の取得を使う場合のみ、初回に一度だけ実行してください(約 170MB のダウンロード):
43
+
44
+ ```bash
45
+ npx -y amenbo install-browser
41
46
  ```
42
47
 
43
48
  または開発用途:
@@ -160,6 +165,11 @@ sitemap → RSS/Atom → ページ内リンクの順で探索します。
160
165
  - **SSRF 対策**:http/https 以外のスキーム(`file:`, `ftp:` 等)を拒否。DNS 解決した接続先が private / loopback / link-local / 予約アドレスなら拒否。DNS rebinding(TOCTOU)対策として実接続を検証済み IP に固定します
161
166
  - **ボディサイズ上限**:巨大レスポンスによる OOM を防止
162
167
 
168
+ ## 既知の制限
169
+
170
+ - **HTTP プロキシ非対応**:`HTTP_PROXY` / `HTTPS_PROXY` 等の環境変数は尊重しません。SSRF 対策として接続先を検証済み IP に固定する設計(DNS rebinding 対策)と、プロキシへ名前解決を委ねる方式が両立しないためです。上流プロキシ必須のネットワークでは現状ご利用いただけません
171
+ - **anti-bot 回避は実装しません**:robots.txt 拒否やボット対策による取得失敗は仕様です。失敗はそのまま報告します([収集先への低負荷](#収集先への低負荷)参照)
172
+
163
173
  ## 開発
164
174
 
165
175
  ```bash
package/dist/cache.d.ts CHANGED
@@ -17,6 +17,7 @@ export interface CacheWriteInput {
17
17
  markdown: string;
18
18
  metadata: Record<string, unknown>;
19
19
  }
20
+ export declare function resolveCacheDir(): string;
20
21
  export declare function hashContent(content: string): string;
21
22
  /** スクリーンショットのキャッシュキー(url+撮影パラメータの組)を計算する。 */
22
23
  export declare function computeScreenshotCacheKey(url: string, width: number, scale: number, fullPage: boolean): string;
@@ -38,14 +39,31 @@ export declare class PageCache {
38
39
  private readonly cacheDir;
39
40
  private readonly ttlMs;
40
41
  private readonly now;
42
+ private readonly statements;
43
+ private closed;
41
44
  constructor(options?: {
42
45
  dbPath?: string;
43
46
  cacheDir?: string;
44
47
  ttlMs?: number;
45
48
  now?: () => number;
46
49
  });
50
+ /** 全SQL文を一度だけprepareする(DDL適用後・prune前に呼ぶ)。 */
51
+ private prepareStatements;
47
52
  /**
48
- * M3: TTL超過エントリを削除する(ディスク無制限増加の防止)。起動時に自動実行される。
53
+ * 前回pruneからTTL未満なら掃除を間引く。
54
+ *
55
+ * 起動のたびにpruneExpired(複数テーブルのDELETE+screenshots走査)を実行すると、CLIの
56
+ * 1コマンド=1プロセスでのバルク収集ループで毎回のプロセス起動に掃除コストが乗る。
57
+ * prune直後のTTL窓ではほとんど新規失効が無いため、前回pruneからの経過がTTL未満なら
58
+ * skipする(掃除間隔がTTL単位まで粗くなるだけで、ディスク無制限増加の防止という
59
+ * M3の目的は維持される。失効エントリの残留は最大でも約2×TTLに収まる)。
60
+ * meta未記録(新規DB/初回起動)では必ず実行するため、起動時掃除のテストは従来通り成立する。
61
+ */
62
+ private maybePruneExpired;
63
+ /** meta テーブルの単一整数値を返す(未記録ならnull)。 */
64
+ private getMetaValue;
65
+ /**
66
+ * M3: TTL超過エントリを削除する(ディスク無制限増加の防止)。maybePruneExpired経由で呼ばれる。
49
67
  * screenshotsはSQLite行に加え、対応するPNGファイル(タイル)もあわせて削除する。
50
68
  */
51
69
  private pruneExpired;
@@ -57,7 +75,16 @@ export declare class PageCache {
57
75
  }): boolean;
58
76
  /** 保存済みスクリーンショットエントリを取得する(TTL判定は isFresh を使う)。 */
59
77
  getScreenshot(cacheKey: string): ScreenshotCacheEntry | undefined;
60
- /** スクリーンショットのタイル群をファイル保存し、パスをSQLiteへ記録する。 */
78
+ /**
79
+ * スクリーンショットのタイル群をファイル保存し、パスをSQLiteへ記録する。
80
+ *
81
+ * レビュー指摘対応(Medium): 同一cacheKeyへの再撮影でタイル数が減った場合(旧5枚→新3枚)、
82
+ * 新しいtile_pathsで上書きされるDB行からは旧tile-3.png/tile-4.pngを参照できなくなり、
83
+ * pruneExpiredもそれらを認識できず孤立ファイルとしてディスクに残り続けていた。
84
+ * tileDirはcacheKey単位のディレクトリ(他のcacheKeyのタイルと混在しない)のため、
85
+ * 書き込み前にディレクトリごと削除してから作り直すことで、枚数が変化しても
86
+ * 旧タイルを確実に一掃する(初回撮影時はディレクトリが存在しないためforce:trueで無視する)。
87
+ */
61
88
  setScreenshot(input: ScreenshotWriteInput): ScreenshotCacheEntry;
62
89
  /** 新規取得結果を保存(既存があれば上書き)する。 */
63
90
  set(input: CacheWriteInput): CacheEntry;
@@ -86,5 +113,24 @@ export declare class PageCache {
86
113
  * store JSDoc参照)。せめて時刻が巻き戻らないよう、SQL側でMAXを取って単調増加を保証する。
87
114
  */
88
115
  setHostLastRequestAt(host: string, at: number): void;
116
+ /**
117
+ * レビュー指摘対応: オリジン(例 "https://example.com")のrobots.txtキャッシュを返す
118
+ * (未記録ならnull)。PolitenessManagerのrobotsStoreオプションとして注入し、プロセス間で
119
+ * robots.txt取得結果を共有するために使う。TTL判定(robotsTtlMs)は呼び出し元(PolitenessManager)
120
+ * がfetchedAtを見て行う(page cacheのttlMsとは別の時間軸のため、ここでは判定しない)。
121
+ * 空bodyのrobots.txt(=制限なし)も正しい取得結果として保存されるため、
122
+ * 「未記録(null)」と「空bodyの記録あり」は区別される。
123
+ */
124
+ getRobotsCache(origin: string): {
125
+ body: string;
126
+ fetchedAt: number;
127
+ } | null;
128
+ /** オリジンのrobots.txt取得結果(本文+取得時刻)を記録する。既存があれば上書きする。 */
129
+ setRobotsCache(origin: string, body: string, fetchedAt: number): void;
130
+ /**
131
+ * 冪等なclose。better-sqlite3のclose()は閉鎖済みでも安全だったが、node:sqliteは
132
+ * "database is not open" を投げるため、CLIのfinallyとprocess 'exit'ハンドラの両方から
133
+ * 呼ばれる二重close経路(core.ts参照)を自前のフラグで吸収する。
134
+ */
89
135
  close(): void;
90
136
  }
package/dist/cache.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * cache.ts — better-sqlite3によるURL単位のローカルキャッシュ。
2
+ * cache.ts — node:sqlite(DatabaseSync)によるURL単位のローカルキャッシュ。
3
3
  *
4
4
  * 保存場所: $AMENBO_CACHE_DIR または ~/.cache/amenbo/cache.sqlite
5
5
  * URL毎にETag/Last-Modified/本文ハッシュ/変換済みMarkdown/取得時刻を保存する。
@@ -21,17 +21,32 @@
21
21
  * 短時間に連続実行すると同一ドメインへの最小間隔が守られない。host_requests テーブルへ
22
22
  * 最終リクエスト時刻を永続化し、PolitenessManagerのstoreオプションとして注入することで
23
23
  * MCPサーバー/CLIの複数プロセス間で共有する(再起動直後の連続アクセスも守れる副次効果あり)。
24
- * journal_mode=WAL は複数プロセスからの同時アクセスを想定して設定している。
24
+ * 同じ理由でrobots.txtの取得結果もrobots_cache テーブルへ永続化し、PolitenessManagerの
25
+ * robotsStoreオプションとして注入する(CLIでの複数ページ一括収集時にコマンド毎の
26
+ * robots.txt再取得を防ぐ)。journal_mode=WAL は複数プロセスからの同時アクセスを想定して設定している。
27
+ *
28
+ * 性能: SQL文は全てコンストラクタで一度だけprepareし(this.statements)、以降は再利用する。
29
+ * node:sqliteのprepare()は呼び出しの度にSQLを再コンパイルするため、MCPサーバー常駐時の
30
+ * 反復実行やCLIバルク収集ループでの再コンパイルコストを避ける。
31
+ *
32
+ * node:sqliteの制約: better-sqlite3はNumber.MAX_SAFE_INTEGERを超えるINTEGER列を読むと
33
+ * 例外を投げたが、node:sqliteは黙ってbigintを返す(上流の挙動差)。本ファイルの整数列
34
+ * (fetched_at/last_request_at)は全てDate.now()由来でMAX_SAFE_INTEGERを超えないため、
35
+ * number型へのキャストのみで安全に扱える。
25
36
  */
26
37
  import { createHash } from "node:crypto";
27
38
  import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
28
39
  import { homedir } from "node:os";
29
40
  import { join } from "node:path";
30
- import Database from "better-sqlite3";
41
+ import { DatabaseSync } from "node:sqlite";
31
42
  const DEFAULT_TTL_MS = 15 * 60 * 1000; // 15分
32
43
  /** Phase 4テンプレート学習: 定型ブロック判定に使う「直近ページ数」の既定値。 */
33
44
  const DEFAULT_TEMPLATE_RECENT_PAGES = 3;
34
- function resolveCacheDir() {
45
+ /** meta テーブルに前回prune時刻を記録するキー。 */
46
+ const META_LAST_PRUNED_AT = "last_pruned_at";
47
+ // レビュー指摘対応: cli.ts(fetch画像の保存先)がキャッシュディレクトリ解決ロジックを
48
+ // 再利用できるようexportする(AMENBO_CACHE_DIR未指定時の既定値~/.cache/amenboとのずれを防ぐ)。
49
+ export function resolveCacheDir() {
35
50
  const dir = process.env.AMENBO_CACHE_DIR ?? join(homedir(), ".cache", "amenbo");
36
51
  if (!existsSync(dir)) {
37
52
  mkdirSync(dir, { recursive: true });
@@ -50,15 +65,17 @@ export class PageCache {
50
65
  cacheDir;
51
66
  ttlMs;
52
67
  now;
68
+ statements;
69
+ closed = false;
53
70
  constructor(options = {}) {
54
71
  this.cacheDir = options.cacheDir ?? resolveCacheDir();
55
72
  if (!existsSync(this.cacheDir)) {
56
73
  mkdirSync(this.cacheDir, { recursive: true });
57
74
  }
58
- this.db = new Database(options.dbPath ?? join(this.cacheDir, "cache.sqlite"));
75
+ this.db = new DatabaseSync(options.dbPath ?? join(this.cacheDir, "cache.sqlite"));
59
76
  this.ttlMs = options.ttlMs ?? DEFAULT_TTL_MS;
60
77
  this.now = options.now ?? Date.now;
61
- this.db.pragma("journal_mode = WAL");
78
+ this.db.exec("PRAGMA journal_mode = WAL");
62
79
  this.db.exec(`
63
80
  CREATE TABLE IF NOT EXISTS pages (
64
81
  url TEXT PRIMARY KEY,
@@ -95,22 +112,112 @@ export class PageCache {
95
112
  last_request_at INTEGER NOT NULL
96
113
  )
97
114
  `);
115
+ // レビュー指摘対応: robots.txtの取得結果をhost_requestsと同じ考え方でプロセス間共有する。
116
+ // CLIバルク収集(1コマンド=1プロセス)で、コマンド毎にrobots.txtを再取得してしまう
117
+ // 低負荷原則違反への対応(PolitenessManagerのrobotsStoreオプションとして注入する)。
118
+ this.db.exec(`
119
+ CREATE TABLE IF NOT EXISTS robots_cache (
120
+ origin TEXT PRIMARY KEY,
121
+ body TEXT NOT NULL,
122
+ fetched_at INTEGER NOT NULL
123
+ )
124
+ `);
125
+ // 前回prune時刻等の単一値メタデータ。maybePruneExpired の間引き判定に使う。
126
+ this.db.exec(`
127
+ CREATE TABLE IF NOT EXISTS meta (
128
+ key TEXT PRIMARY KEY,
129
+ value INTEGER NOT NULL
130
+ )
131
+ `);
132
+ this.statements = this.prepareStatements();
98
133
  // M3: TTL超過削除・サイズ上限が無くディスクが無制限に増加する問題への対応。
99
- // 起動(コンストラクタ)のたびにTTL超過エントリを掃除する。
134
+ // 起動のたびに掃除するとCLIバルク収集(1コマンド=1プロセス)で毎回DELETEが走るため、
135
+ // 前回pruneからTTL未満なら間引く(maybePruneExpired参照)。
136
+ this.maybePruneExpired();
137
+ }
138
+ /** 全SQL文を一度だけprepareする(DDL適用後・prune前に呼ぶ)。 */
139
+ prepareStatements() {
140
+ return {
141
+ deletePagesExpired: this.db.prepare("DELETE FROM pages WHERE fetched_at < ?"),
142
+ deleteDomainPagesExpired: this.db.prepare("DELETE FROM domain_pages WHERE fetched_at < ?"),
143
+ deleteHostRequestsExpired: this.db.prepare("DELETE FROM host_requests WHERE last_request_at < ?"),
144
+ selectScreenshotsExpired: this.db.prepare("SELECT * FROM screenshots WHERE fetched_at < ?"),
145
+ deleteScreenshotsExpired: this.db.prepare("DELETE FROM screenshots WHERE fetched_at < ?"),
146
+ getPage: this.db.prepare("SELECT * FROM pages WHERE url = ?"),
147
+ setPage: this.db.prepare(`INSERT INTO pages (url, etag, last_modified, content_hash, markdown, metadata, fetched_at)
148
+ VALUES (@url, @etag, @lastModified, @contentHash, @markdown, @metadata, @fetchedAt)
149
+ ON CONFLICT(url) DO UPDATE SET
150
+ etag = excluded.etag,
151
+ last_modified = excluded.last_modified,
152
+ content_hash = excluded.content_hash,
153
+ markdown = excluded.markdown,
154
+ metadata = excluded.metadata,
155
+ fetched_at = excluded.fetched_at`),
156
+ touchPage: this.db.prepare("UPDATE pages SET fetched_at = ? WHERE url = ?"),
157
+ getScreenshot: this.db.prepare("SELECT * FROM screenshots WHERE cache_key = ?"),
158
+ setScreenshot: this.db.prepare(`INSERT INTO screenshots (cache_key, url, tile_paths, metadata, fetched_at)
159
+ VALUES (@cacheKey, @url, @tilePaths, @metadata, @fetchedAt)
160
+ ON CONFLICT(cache_key) DO UPDATE SET
161
+ url = excluded.url,
162
+ tile_paths = excluded.tile_paths,
163
+ metadata = excluded.metadata,
164
+ fetched_at = excluded.fetched_at`),
165
+ recordDomainPage: this.db.prepare(`INSERT INTO domain_pages (domain, url, fetched_at, block_hashes)
166
+ VALUES (@domain, @url, @fetchedAt, @blockHashes)
167
+ ON CONFLICT(domain, url) DO UPDATE SET
168
+ fetched_at = excluded.fetched_at,
169
+ block_hashes = excluded.block_hashes`),
170
+ getDomainPages: this.db.prepare("SELECT * FROM domain_pages WHERE domain = ? ORDER BY fetched_at DESC LIMIT ?"),
171
+ getHostRequest: this.db.prepare("SELECT * FROM host_requests WHERE host = ?"),
172
+ setHostRequest: this.db.prepare(`INSERT INTO host_requests (host, last_request_at)
173
+ VALUES (@host, @lastRequestAt)
174
+ ON CONFLICT(host) DO UPDATE SET last_request_at = MAX(last_request_at, excluded.last_request_at)`),
175
+ getRobots: this.db.prepare("SELECT * FROM robots_cache WHERE origin = ?"),
176
+ setRobots: this.db.prepare(`INSERT INTO robots_cache (origin, body, fetched_at)
177
+ VALUES (@origin, @body, @fetchedAt)
178
+ ON CONFLICT(origin) DO UPDATE SET
179
+ body = excluded.body,
180
+ fetched_at = excluded.fetched_at`),
181
+ getMeta: this.db.prepare("SELECT value FROM meta WHERE key = ?"),
182
+ setMeta: this.db.prepare(`INSERT INTO meta (key, value) VALUES (@key, @value)
183
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value`),
184
+ };
185
+ }
186
+ /**
187
+ * 前回pruneからTTL未満なら掃除を間引く。
188
+ *
189
+ * 起動のたびにpruneExpired(複数テーブルのDELETE+screenshots走査)を実行すると、CLIの
190
+ * 1コマンド=1プロセスでのバルク収集ループで毎回のプロセス起動に掃除コストが乗る。
191
+ * prune直後のTTL窓ではほとんど新規失効が無いため、前回pruneからの経過がTTL未満なら
192
+ * skipする(掃除間隔がTTL単位まで粗くなるだけで、ディスク無制限増加の防止という
193
+ * M3の目的は維持される。失効エントリの残留は最大でも約2×TTLに収まる)。
194
+ * meta未記録(新規DB/初回起動)では必ず実行するため、起動時掃除のテストは従来通り成立する。
195
+ */
196
+ maybePruneExpired() {
197
+ const lastPrunedAt = this.getMetaValue(META_LAST_PRUNED_AT);
198
+ const at = this.now();
199
+ if (lastPrunedAt !== null && at - lastPrunedAt < this.ttlMs)
200
+ return;
100
201
  this.pruneExpired();
202
+ this.statements.setMeta.run({ key: META_LAST_PRUNED_AT, value: at });
203
+ }
204
+ /** meta テーブルの単一整数値を返す(未記録ならnull)。 */
205
+ getMetaValue(key) {
206
+ const row = this.statements.getMeta.get(key);
207
+ return row ? Number(row.value) : null;
101
208
  }
102
209
  /**
103
- * M3: TTL超過エントリを削除する(ディスク無制限増加の防止)。起動時に自動実行される。
210
+ * M3: TTL超過エントリを削除する(ディスク無制限増加の防止)。maybePruneExpired経由で呼ばれる。
104
211
  * screenshotsはSQLite行に加え、対応するPNGファイル(タイル)もあわせて削除する。
105
212
  */
106
213
  pruneExpired() {
107
214
  const cutoff = this.now() - this.ttlMs;
108
- this.db.prepare("DELETE FROM pages WHERE fetched_at < ?").run(cutoff);
109
- this.db.prepare("DELETE FROM domain_pages WHERE fetched_at < ?").run(cutoff);
215
+ this.statements.deletePagesExpired.run(cutoff);
216
+ this.statements.deleteDomainPagesExpired.run(cutoff);
110
217
  // code-reviewer指摘: host_requestsもM3の対象から漏れていた(訪問ホスト毎に1行増える
111
218
  // 無制限増加テーブルという点でdomain_pages等と同じ性質を持つため、他テーブルと一貫させる)。
112
- this.db.prepare("DELETE FROM host_requests WHERE last_request_at < ?").run(cutoff);
113
- const expiredScreenshots = this.db.prepare("SELECT * FROM screenshots WHERE fetched_at < ?").all(cutoff);
219
+ this.statements.deleteHostRequestsExpired.run(cutoff);
220
+ const expiredScreenshots = this.statements.selectScreenshotsExpired.all(cutoff);
114
221
  for (const row of expiredScreenshots) {
115
222
  const tilePaths = JSON.parse(row.tile_paths);
116
223
  for (const filePath of tilePaths) {
@@ -122,11 +229,11 @@ export class PageCache {
122
229
  }
123
230
  }
124
231
  }
125
- this.db.prepare("DELETE FROM screenshots WHERE fetched_at < ?").run(cutoff);
232
+ this.statements.deleteScreenshotsExpired.run(cutoff);
126
233
  }
127
234
  /** 保存済みエントリを取得する(TTL判定は行わない。判定は isFresh を使う)。 */
128
235
  get(url) {
129
- const row = this.db.prepare("SELECT * FROM pages WHERE url = ?").get(url);
236
+ const row = this.statements.getPage.get(url);
130
237
  if (!row)
131
238
  return undefined;
132
239
  return {
@@ -145,7 +252,7 @@ export class PageCache {
145
252
  }
146
253
  /** 保存済みスクリーンショットエントリを取得する(TTL判定は isFresh を使う)。 */
147
254
  getScreenshot(cacheKey) {
148
- const row = this.db.prepare("SELECT * FROM screenshots WHERE cache_key = ?").get(cacheKey);
255
+ const row = this.statements.getScreenshot.get(cacheKey);
149
256
  if (!row)
150
257
  return undefined;
151
258
  return {
@@ -156,9 +263,19 @@ export class PageCache {
156
263
  fetchedAt: row.fetched_at,
157
264
  };
158
265
  }
159
- /** スクリーンショットのタイル群をファイル保存し、パスをSQLiteへ記録する。 */
266
+ /**
267
+ * スクリーンショットのタイル群をファイル保存し、パスをSQLiteへ記録する。
268
+ *
269
+ * レビュー指摘対応(Medium): 同一cacheKeyへの再撮影でタイル数が減った場合(旧5枚→新3枚)、
270
+ * 新しいtile_pathsで上書きされるDB行からは旧tile-3.png/tile-4.pngを参照できなくなり、
271
+ * pruneExpiredもそれらを認識できず孤立ファイルとしてディスクに残り続けていた。
272
+ * tileDirはcacheKey単位のディレクトリ(他のcacheKeyのタイルと混在しない)のため、
273
+ * 書き込み前にディレクトリごと削除してから作り直すことで、枚数が変化しても
274
+ * 旧タイルを確実に一掃する(初回撮影時はディレクトリが存在しないためforce:trueで無視する)。
275
+ */
160
276
  setScreenshot(input) {
161
277
  const tileDir = join(this.cacheDir, "screenshots", input.cacheKey);
278
+ rmSync(tileDir, { recursive: true, force: true });
162
279
  mkdirSync(tileDir, { recursive: true });
163
280
  const tilePaths = input.tiles.map((buffer, index) => {
164
281
  const filePath = join(tileDir, `tile-${index}.png`);
@@ -166,15 +283,7 @@ export class PageCache {
166
283
  return filePath;
167
284
  });
168
285
  const fetchedAt = this.now();
169
- this.db
170
- .prepare(`INSERT INTO screenshots (cache_key, url, tile_paths, metadata, fetched_at)
171
- VALUES (@cacheKey, @url, @tilePaths, @metadata, @fetchedAt)
172
- ON CONFLICT(cache_key) DO UPDATE SET
173
- url = excluded.url,
174
- tile_paths = excluded.tile_paths,
175
- metadata = excluded.metadata,
176
- fetched_at = excluded.fetched_at`)
177
- .run({
286
+ this.statements.setScreenshot.run({
178
287
  cacheKey: input.cacheKey,
179
288
  url: input.url,
180
289
  tilePaths: JSON.stringify(tilePaths),
@@ -187,17 +296,7 @@ export class PageCache {
187
296
  set(input) {
188
297
  const contentHash = hashContent(input.markdown);
189
298
  const fetchedAt = this.now();
190
- this.db
191
- .prepare(`INSERT INTO pages (url, etag, last_modified, content_hash, markdown, metadata, fetched_at)
192
- VALUES (@url, @etag, @lastModified, @contentHash, @markdown, @metadata, @fetchedAt)
193
- ON CONFLICT(url) DO UPDATE SET
194
- etag = excluded.etag,
195
- last_modified = excluded.last_modified,
196
- content_hash = excluded.content_hash,
197
- markdown = excluded.markdown,
198
- metadata = excluded.metadata,
199
- fetched_at = excluded.fetched_at`)
200
- .run({
299
+ this.statements.setPage.run({
201
300
  url: input.url,
202
301
  etag: input.etag,
203
302
  lastModified: input.lastModified,
@@ -218,17 +317,11 @@ export class PageCache {
218
317
  }
219
318
  /** 304再検証成功時: 本文は変えず取得時刻のみ更新する(再変換しない)。 */
220
319
  touch(url) {
221
- this.db.prepare("UPDATE pages SET fetched_at = ? WHERE url = ?").run(this.now(), url);
320
+ this.statements.touchPage.run(this.now(), url);
222
321
  }
223
322
  /** Phase 4テンプレート学習: このページの(除去前・全)ブロックハッシュ集合をドメイン別に記録する。 */
224
323
  recordDomainPageBlocks(domain, url, blockHashes) {
225
- this.db
226
- .prepare(`INSERT INTO domain_pages (domain, url, fetched_at, block_hashes)
227
- VALUES (@domain, @url, @fetchedAt, @blockHashes)
228
- ON CONFLICT(domain, url) DO UPDATE SET
229
- fetched_at = excluded.fetched_at,
230
- block_hashes = excluded.block_hashes`)
231
- .run({ domain, url, fetchedAt: this.now(), blockHashes: JSON.stringify(blockHashes) });
324
+ this.statements.recordDomainPage.run({ domain, url, fetchedAt: this.now(), blockHashes: JSON.stringify(blockHashes) });
232
325
  }
233
326
  /**
234
327
  * 直近recentPages件のページ全てに共通して出現したブロックハッシュを定型ブロック
@@ -236,9 +329,7 @@ export class PageCache {
236
329
  * 無い場合(コールドスタート)は誤除去を避けるため空集合を返す。
237
330
  */
238
331
  getTemplateBlockHashes(domain, recentPages = DEFAULT_TEMPLATE_RECENT_PAGES) {
239
- const rows = this.db
240
- .prepare("SELECT * FROM domain_pages WHERE domain = ? ORDER BY fetched_at DESC LIMIT ?")
241
- .all(domain, recentPages);
332
+ const rows = this.statements.getDomainPages.all(domain, recentPages);
242
333
  if (rows.length < recentPages)
243
334
  return new Set();
244
335
  const occurrenceCount = new Map();
@@ -260,7 +351,7 @@ export class PageCache {
260
351
  * PolitenessManagerのstoreオプションとして注入し、プロセス間でレート制御状態を共有するために使う。
261
352
  */
262
353
  getHostLastRequestAt(host) {
263
- const row = this.db.prepare("SELECT * FROM host_requests WHERE host = ?").get(host);
354
+ const row = this.statements.getHostRequest.get(host);
264
355
  return row ? row.last_request_at : null;
265
356
  }
266
357
  /**
@@ -273,13 +364,33 @@ export class PageCache {
273
364
  * store JSDoc参照)。せめて時刻が巻き戻らないよう、SQL側でMAXを取って単調増加を保証する。
274
365
  */
275
366
  setHostLastRequestAt(host, at) {
276
- this.db
277
- .prepare(`INSERT INTO host_requests (host, last_request_at)
278
- VALUES (@host, @lastRequestAt)
279
- ON CONFLICT(host) DO UPDATE SET last_request_at = MAX(last_request_at, excluded.last_request_at)`)
280
- .run({ host, lastRequestAt: at });
367
+ this.statements.setHostRequest.run({ host, lastRequestAt: at });
368
+ }
369
+ /**
370
+ * レビュー指摘対応: オリジン(例 "https://example.com")のrobots.txtキャッシュを返す
371
+ * (未記録ならnull)。PolitenessManagerのrobotsStoreオプションとして注入し、プロセス間で
372
+ * robots.txt取得結果を共有するために使う。TTL判定(robotsTtlMs)は呼び出し元(PolitenessManager)
373
+ * がfetchedAtを見て行う(page cacheのttlMsとは別の時間軸のため、ここでは判定しない)。
374
+ * 空bodyのrobots.txt(=制限なし)も正しい取得結果として保存されるため、
375
+ * 「未記録(null)」と「空bodyの記録あり」は区別される。
376
+ */
377
+ getRobotsCache(origin) {
378
+ const row = this.statements.getRobots.get(origin);
379
+ return row ? { body: row.body, fetchedAt: row.fetched_at } : null;
281
380
  }
381
+ /** オリジンのrobots.txt取得結果(本文+取得時刻)を記録する。既存があれば上書きする。 */
382
+ setRobotsCache(origin, body, fetchedAt) {
383
+ this.statements.setRobots.run({ origin, body, fetchedAt });
384
+ }
385
+ /**
386
+ * 冪等なclose。better-sqlite3のclose()は閉鎖済みでも安全だったが、node:sqliteは
387
+ * "database is not open" を投げるため、CLIのfinallyとprocess 'exit'ハンドラの両方から
388
+ * 呼ばれる二重close経路(core.ts参照)を自前のフラグで吸収する。
389
+ */
282
390
  close() {
391
+ if (this.closed)
392
+ return;
393
+ this.closed = true;
283
394
  this.db.close();
284
395
  }
285
396
  }
package/dist/cache.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAsB,MAAM,aAAa,CAAC;AAwB/D,MAAM,cAAc,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,MAAM;AAC7C,gDAAgD;AAChD,MAAM,6BAA6B,GAAG,CAAC,CAAC;AACxC,kCAAkC;AAClC,MAAM,mBAAmB,GAAG,gBAAgB,CAAC;AAE7C,mDAAmD;AACnD,oEAAoE;AACpE,MAAM,UAAU,eAAe;IAC7B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAChF,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AA4DD,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC5D,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,yBAAyB,CAAC,GAAW,EAAE,KAAa,EAAE,KAAa,EAAE,QAAiB;IACpG,OAAO,WAAW,CAAC,GAAG,GAAG,MAAM,KAAK,MAAM,KAAK,SAAS,QAAQ,EAAE,CAAC,CAAC;AACtE,CAAC;AAiBD,MAAM,OAAO,SAAS;IACH,EAAE,CAAe;IACjB,QAAQ,CAAS;IACjB,KAAK,CAAS;IACd,GAAG,CAAe;IAClB,UAAU,CAAqB;IACxC,MAAM,GAAG,KAAK,CAAC;IAEvB,YAAY,OAAO,GAA+E,EAAE;QAClG,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,eAAe,EAAE,CAAC;QACtD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/B,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,CAAC;QACD,IAAI,CAAC,EAAE,GAAG,IAAI,YAAY,CAAC,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC;QAClF,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,cAAc,CAAC;QAC7C,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;QACnC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;QAC1C,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;KAUZ,CAAC,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;;;KAQZ,CAAC,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;;;KAQZ,CAAC,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,yGAAyG,CAAC,CAAC;QACxH,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;KAKZ,CAAC,CAAC;QACH,2DAA2D;QAC3D,mDAAmD;QACnD,0DAA0D;QAC1D,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;KAMZ,CAAC,CAAC;QACH,mDAAmD;QACnD,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;KAKZ,CAAC,CAAC;QAEH,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAE3C,2CAA2C;QAC3C,kDAAkD;QAClD,4CAA4C;QAC5C,IAAI,CAAC,iBAAiB,EAAE,CAAC;IAC3B,CAAC;IAED,6CAA6C;IACrC,iBAAiB;QACvB,OAAO;YACL,kBAAkB,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,wCAAwC,CAAC;YAC7E,wBAAwB,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,+CAA+C,CAAC;YAC1F,yBAAyB,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,qDAAqD,CAAC;YACjG,wBAAwB,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,gDAAgD,CAAC;YAC3F,wBAAwB,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,8CAA8C,CAAC;YACzF,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,mCAAmC,CAAC;YAC7D,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CACtB;;;;;;;;4CAQoC,CACrC;YACD,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,+CAA+C,CAAC;YAC3E,aAAa,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,+CAA+C,CAAC;YAC/E,aAAa,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAC5B;;;;;;4CAMoC,CACrC;YACD,gBAAgB,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAC/B;;;;gDAIwC,CACzC;YACD,cAAc,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,8EAA8E,CAAC;YAC/G,cAAc,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,4CAA4C,CAAC;YAC7E,cAAc,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAC7B;;0GAEkG,CACnG;YACD,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,6CAA6C,CAAC;YACzE,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CACxB;;;;4CAIoC,CACrC;YACD,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,sCAAsC,CAAC;YAChE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CACtB;+DACuD,CACxD;SACF,CAAC;IACJ,CAAC;IAED;;;;;;;;;OASG;IACK,iBAAiB;QACvB,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,mBAAmB,CAAC,CAAC;QAC5D,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACtB,IAAI,YAAY,KAAK,IAAI,IAAI,EAAE,GAAG,YAAY,GAAG,IAAI,CAAC,KAAK;YAAE,OAAO;QACpE,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,mBAAmB,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;IACvE,CAAC;IAED,qCAAqC;IAC7B,YAAY,CAAC,GAAW;QAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAkC,CAAC;QAC9E,OAAO,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACxC,CAAC;IAED;;;OAGG;IACK,YAAY;QAClB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;QAEvC,IAAI,CAAC,UAAU,CAAC,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC/C,IAAI,CAAC,UAAU,CAAC,wBAAwB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACrD,2DAA2D;QAC3D,sDAAsD;QACtD,IAAI,CAAC,UAAU,CAAC,yBAAyB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAEtD,MAAM,kBAAkB,GAAG,IAAI,CAAC,UAAU,CAAC,wBAAwB,CAAC,GAAG,CAAC,MAAM,CAA+B,CAAC;QAC9G,KAAK,MAAM,GAAG,IAAI,kBAAkB,EAAE,CAAC;YACrC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAa,CAAC;YACzD,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;gBACjC,IAAI,CAAC;oBACH,MAAM,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBACpC,CAAC;gBAAC,MAAM,CAAC;oBACP,oCAAoC;gBACtC,CAAC;YACH,CAAC;QACH,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,wBAAwB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACvD,CAAC;IAED,iDAAiD;IACjD,GAAG,CAAC,GAAW;QACb,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAwB,CAAC;QACpE,IAAI,CAAC,GAAG;YAAE,OAAO,SAAS,CAAC;QAC3B,OAAO;YACL,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,YAAY,EAAE,GAAG,CAAC,aAAa;YAC/B,WAAW,EAAE,GAAG,CAAC,YAAY;YAC7B,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAA4B;YAC7D,SAAS,EAAE,GAAG,CAAC,UAAU;SAC1B,CAAC;IACJ,CAAC;IAED,qDAAqD;IACrD,OAAO,CAAC,KAA4B;QAClC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC;IACnD,CAAC;IAED,kDAAkD;IAClD,aAAa,CAAC,QAAgB;QAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,CAA8B,CAAC;QACrF,IAAI,CAAC,GAAG;YAAE,OAAO,SAAS,CAAC;QAC3B,OAAO;YACL,QAAQ,EAAE,GAAG,CAAC,SAAS;YACvB,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAa;YACjD,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAA4B;YAC7D,SAAS,EAAE,GAAG,CAAC,UAAU;SAC1B,CAAC;IACJ,CAAC;IAED;;;;;;;;;OASG;IACH,aAAa,CAAC,KAA2B;QACvC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;QACnE,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACxC,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;YAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,KAAK,MAAM,CAAC,CAAC;YACpD,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YAChC,OAAO,QAAQ,CAAC;QAClB,CAAC,CAAC,CAAC;QAEH,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,GAAG,CAAC;YAChC,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC;YACpC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC;YACxC,SAAS;SACV,CAAC,CAAC;QAEH,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtG,CAAC;IAED,8BAA8B;IAC9B,GAAG,CAAC,KAAsB;QACxB,MAAM,WAAW,GAAG,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC;YAC1B,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,WAAW;YACX,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC;YACxC,SAAS;SACV,CAAC,CAAC;QACH,OAAO;YACL,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,WAAW;YACX,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,SAAS;SACV,CAAC;IACJ,CAAC;IAED,2CAA2C;IAC3C,KAAK,CAAC,GAAW;QACf,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,CAAC;IACjD,CAAC;IAED,2DAA2D;IAC3D,sBAAsB,CAAC,MAAc,EAAE,GAAW,EAAE,WAAqB;QACvE,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IACzH,CAAC;IAED;;;;OAIG;IACH,sBAAsB,CAAC,MAAc,EAAE,WAAW,GAAW,6BAA6B;QACxF,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,EAAE,WAAW,CAA+B,CAAC;QAEnG,IAAI,IAAI,CAAC,MAAM,GAAG,WAAW;YAAE,OAAO,IAAI,GAAG,EAAE,CAAC;QAEhD,MAAM,eAAe,GAAG,IAAI,GAAG,EAAkB,CAAC;QAClD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAa,CAAC;YACxD,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;gBAC1B,eAAe,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAClE,CAAC;QACH,CAAC;QAED,MAAM,cAAc,GAAG,IAAI,GAAG,EAAU,CAAC;QACzC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,eAAe,EAAE,CAAC;YAC5C,IAAI,KAAK,IAAI,WAAW;gBAAE,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACrD,CAAC;QACD,OAAO,cAAc,CAAC;IACxB,CAAC;IAED;;;OAGG;IACH,oBAAoB,CAAC,IAAY;QAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAA+B,CAAC;QACnF,OAAO,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1C,CAAC;IAED;;;;;;;;OAQG;IACH,oBAAoB,CAAC,IAAY,EAAE,EAAU;QAC3C,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC,CAAC;IAClE,CAAC;IAED;;;;;;;OAOG;IACH,cAAc,CAAC,MAAc;QAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAA+B,CAAC;QAChF,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACpE,CAAC;IAED,qDAAqD;IACrD,cAAc,CAAC,MAAc,EAAE,IAAY,EAAE,SAAiB;QAC5D,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED;;;;OAIG;IACH,KAAK;QACH,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO;QACxB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC;CACF"}
package/dist/cli.d.ts CHANGED
@@ -11,7 +11,9 @@ export type ParsedCommand = {
11
11
  kind: "version";
12
12
  } | {
13
13
  kind: "help";
14
- topic?: "fetch" | "links" | "screenshot";
14
+ topic?: "fetch" | "links" | "screenshot" | "install-browser";
15
+ } | {
16
+ kind: "install-browser";
15
17
  } | ParsedFetchCommand | ParsedLinksCommand | ParsedScreenshotCommand;
16
18
  export interface ParsedFetchCommand {
17
19
  kind: "fetch";