diff options
| author | Igor Soarez <igor@soarez.org> | 2026-08-03 21:18:02 +0100 |
|---|---|---|
| committer | Igor Soarez <igor@soarez.org> | 2026-08-03 21:18:02 +0100 |
| commit | 495de0d5283dd3e4a6ef715b596c4a2892e95915 (patch) | |
| tree | aae2ec78d59cb96d8e90c56ab7626a6886d30be2 /src/target-store.ts | |
Web search for pi through an existing Chrome over CDP
Attaches to a browser that is already running — never launches one —
using the same endpoint configuration as pi-browser-harness, so a single
/browser-target choice governs both packages.
One tool, castle_cdp_search, deliberately not named web_search so it
coexists with pi-web-access rather than shadowing it.
Notes from validating against castle's Chrome:
- tbs=qdr:*, the parameter Google's own Tools menu writes, renders an
empty page on this profile; the older as_qdr=* works. Any date filter
combined with udm=14 is also empty, so recency drops udm.
- Target.createTarget must not be raced against the abort signal:
raceAbort abandons the promise but cannot cancel the command, and the
command's side effect is a tab nothing is left holding.
- A search cancelled while queued has to be removed from the semaphore
queue, or the slot handed to it later is never counted back.
- A decaying rate-limit block stops serving /sorry/ and returns an empty
results page instead, indistinguishable from a genuine zero-hit search.
Diffstat (limited to 'src/target-store.ts')
| -rw-r--r-- | src/target-store.ts | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/src/target-store.ts b/src/target-store.ts new file mode 100644 index 0000000..6ff0db4 --- /dev/null +++ b/src/target-store.ts @@ -0,0 +1,42 @@ +/** + * Read-only view of the target pi-browser-harness persists for `/browser-target`. + * + * The stored value is the raw string a user would have put in BU_CDP_HTTP + * ("local", "10.88.0.25:9223", …) — kept in that vocabulary deliberately, so + * there is one resolution path in endpoint.ts and a stored value can never mean + * something the variable could not. + * + * Every read failure degrades to "nothing stored" rather than throwing: a + * corrupt or absent file must fall back to the built-in default, not break search. + */ + +import { readFile } from "node:fs/promises"; +import { targetFilePath } from "./paths.ts"; + +const CURRENT_VERSION = 1; + +/** + * The persisted target, or null when nothing is stored, the file is missing, or + * it cannot be parsed. A file written by a newer version is treated as "nothing + * stored" rather than guessed at. + */ +export const readStoredTarget = async (): Promise<string | null> => { + let raw: string; + try { + raw = await readFile(targetFilePath(), "utf8"); + } catch { + return null; + } + try { + const parsed: unknown = JSON.parse(raw); + if (typeof parsed !== "object" || parsed === null) return null; + const file = parsed as Record<string, unknown>; + if (file["version"] !== CURRENT_VERSION) return null; + const target = file["target"]; + if (typeof target !== "string") return null; + const trimmed = target.trim(); + return trimmed.length > 0 ? trimmed : null; + } catch { + return null; + } +}; |
