@osqd/bothandlerjs 0.4.0 → 0.5.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.
@@ -1,5 +1,38 @@
1
- import type { Detector } from "./types.js";
1
+ import type { Detector, DetectionContext } from "./types.js";
2
+ import type { BotSignature } from "./known-bots.js";
3
+ /**
4
+ * What an operator's own check concluded about a claimed identity.
5
+ *
6
+ * Three answers, and the third is not a formality. "I could not tell" has to be
7
+ * expressible and has to mean *silence* — a verifier that returned false for both "this
8
+ * is a forgery" and "my key server timed out" would turn an outage into an accusation.
9
+ */
10
+ export type VerificationOutcome = "verified" | "refuted" | "unknown";
11
+ /**
12
+ * Your own answer to "is this really who it says it is".
13
+ *
14
+ * Called with the same context the built-in checks get, for one claimed signature. It
15
+ * may be async: the natural implementations are a lookup or a signature check.
16
+ */
17
+ export type CrawlerVerifier = (ctx: DetectionContext, signature: BotSignature) => VerificationOutcome | Promise<VerificationOutcome>;
2
18
  export interface CrawlerVerificationOptions {
19
+ /**
20
+ * Verifiers of your own, by signature id — `{ googlebot: ..., gptbot: ... }`.
21
+ *
22
+ * Most of this database cannot be checked from inside a request: the operator
23
+ * publishes no DNS proof and no range list, and the claim is simply unfalsifiable.
24
+ * That is most bots, and until now it meant the library had nothing to offer an
25
+ * operator who *could* check — because their CDN had already verified the crawler and
26
+ * said so in a header, because the bot signs its requests, or because they hold the
27
+ * ASN data. Writing a whole detector to say so meant reimplementing the confirm and
28
+ * refute semantics in this file, including the part where an inconclusive answer must
29
+ * stay silent.
30
+ *
31
+ * A verifier here runs before the built-in check for that signature and a definite
32
+ * answer settles it, which also means no DNS lookup. `unknown` falls through to
33
+ * whatever this library can do on its own.
34
+ */
35
+ verifiers?: Readonly<Record<string, CrawlerVerifier>>;
3
36
  /**
4
37
  * Treat an address with no PTR record as a forged claim. Default true.
5
38
  *
@@ -1,3 +1,4 @@
1
+ import type { CrawlerVerificationOptions } from "./crawler-verification.js";
1
2
  import type { Detector } from "./types.js";
2
3
  export type { DetectionContext, Detector, DetectorResult } from "./types.js";
3
4
  export { evidence, absenceIsMeaningful } from "./types.js";
@@ -53,4 +54,6 @@ export type { BotSignature, BotCategory, Verification } from "./known-bots.js";
53
54
  * `clearanceDetector` is not here either, because it needs the challenge service —
54
55
  * the engine adds it automatically once `challenge.secrets` is configured.
55
56
  */
56
- export declare function defaultDetectors(): Detector[];
57
+ export declare function defaultDetectors(options?: {
58
+ crawlerVerification?: CrawlerVerificationOptions;
59
+ }): Detector[];
@@ -16,7 +16,35 @@ import { MultiPatternMatcher } from "../internal/matcher.js";
16
16
  */
17
17
  export type BotCategory = "search" | "ai" | "seo" | "social" | "monitoring" | "archive" | "feed" | "security" | "advertising" | "library" | "headless"
18
18
  /** A real browser engine embedded in a desktop application, with a person driving it. */
19
- | "embedded" | "other";
19
+ | "embedded"
20
+ /**
21
+ * Price, stock and catalogue collection: comparison shopping, marketplace feeds,
22
+ * repricing tools.
23
+ *
24
+ * Its own category because it is the one kind of crawling a shop has a commercial
25
+ * opinion about rather than a technical one. It is not `seo` — nothing here is
26
+ * auditing your site for you — and it is not `scraper`, which is a *behavioural*
27
+ * verdict this library reaches on its own. This is a client that says what it is.
28
+ */
29
+ | "commerce"
30
+ /**
31
+ * Accessibility auditing: contrast, landmarks, ARIA, WCAG conformance.
32
+ *
33
+ * Separated from `monitoring` because the answer is almost always different. A site
34
+ * owner who blocks uptime probes still wants the tool their accessibility team runs
35
+ * to reach the page, and frequently does not know it is arriving as a bot at all.
36
+ */
37
+ | "accessibility"
38
+ /**
39
+ * Research and measurement: universities, internet-measurement projects, plagiarism
40
+ * and citation indexes.
41
+ *
42
+ * Distinct from `ai` on purpose. Both read the whole page and neither sends a person,
43
+ * but the decision differs: an operator refusing to feed a commercial model may be
44
+ * perfectly happy to appear in a citation index, and folding the two together forces
45
+ * one answer onto two questions.
46
+ */
47
+ | "academic" | "other";
20
48
  /** Every category, for anything that has to enumerate them — a rule editor, a report. */
21
49
  export declare const BOT_CATEGORIES: readonly BotCategory[];
22
50
  /**
@@ -40,6 +68,26 @@ export type Verification = {
40
68
  } | {
41
69
  kind: "ip-ranges";
42
70
  publishedAt?: string;
71
+ }
72
+ /**
73
+ * The operator publishes a proof this library cannot check by itself, and you can.
74
+ *
75
+ * A signed request under [Web Bot Auth](https://www.rfc-editor.org/rfc/rfc9421), a
76
+ * CDN that has already verified the crawler and says so in a header it adds, an ASN
77
+ * lookup against data you hold — all of them are conclusive, and none of them are
78
+ * something a detection library should be doing on its own: two need a network
79
+ * dependency and the third needs a key it has no business fetching.
80
+ *
81
+ * So the claim is marked verifiable-by-you, and stays *unverified* until you supply a
82
+ * verifier for it in `crawlerVerification.verifiers`. Marked and unsupplied behaves
83
+ * exactly like `none`: neither confirmed nor accused.
84
+ *
85
+ * `via` names the mechanism, for the operator reading this table to know what they
86
+ * would have to write.
87
+ */
88
+ | {
89
+ kind: "proof";
90
+ via: string;
43
91
  } | {
44
92
  kind: "none";
45
93
  };