@osqd/bothandlerjs 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 (186) hide show
  1. package/CHANGELOG.md +516 -0
  2. package/LICENSE +102 -0
  3. package/README.md +308 -0
  4. package/bin/bothandlerjs.mjs +14 -0
  5. package/dist/actions/index.d.ts +22 -0
  6. package/dist/actions/types.d.ts +59 -0
  7. package/dist/adapters/fastify.d.ts +43 -0
  8. package/dist/adapters/fetch.d.ts +51 -0
  9. package/dist/adapters/index.cjs +723 -0
  10. package/dist/adapters/index.cjs.map +1 -0
  11. package/dist/adapters/index.d.ts +8 -0
  12. package/dist/adapters/index.js +692 -0
  13. package/dist/adapters/index.js.map +1 -0
  14. package/dist/adapters/koa.d.ts +27 -0
  15. package/dist/adapters/node.d.ts +29 -0
  16. package/dist/adapters/shared.d.ts +39 -0
  17. package/dist/audit.d.ts +172 -0
  18. package/dist/challenge/index.d.ts +176 -0
  19. package/dist/challenge/language.d.ts +57 -0
  20. package/dist/challenge/page.d.ts +42 -0
  21. package/dist/challenge/pow.d.ts +33 -0
  22. package/dist/challenge/token.d.ts +72 -0
  23. package/dist/cli.cjs +13388 -0
  24. package/dist/cli.cjs.map +1 -0
  25. package/dist/cli.d.ts +5 -0
  26. package/dist/cli.js +13358 -0
  27. package/dist/cli.js.map +1 -0
  28. package/dist/client/index.cjs +139 -0
  29. package/dist/client/index.cjs.map +1 -0
  30. package/dist/client/index.d.ts +63 -0
  31. package/dist/client/index.js +112 -0
  32. package/dist/client/index.js.map +1 -0
  33. package/dist/config.d.ts +316 -0
  34. package/dist/core.d.ts +443 -0
  35. package/dist/corpus/adversarial.d.ts +2 -0
  36. package/dist/corpus/advertising-email.d.ts +2 -0
  37. package/dist/corpus/ai-crawlers.d.ts +2 -0
  38. package/dist/corpus/benign-bots.d.ts +2 -0
  39. package/dist/corpus/cdn-gateways.d.ts +2 -0
  40. package/dist/corpus/cookies.d.ts +49 -0
  41. package/dist/corpus/crawlers-regional.d.ts +2 -0
  42. package/dist/corpus/crawlers-vertical.d.ts +2 -0
  43. package/dist/corpus/headers.d.ts +403 -0
  44. package/dist/corpus/humans-apps.d.ts +2 -0
  45. package/dist/corpus/humans-browsers.d.ts +2 -0
  46. package/dist/corpus/humans.d.ts +2 -0
  47. package/dist/corpus/index.cjs +4196 -0
  48. package/dist/corpus/index.cjs.map +1 -0
  49. package/dist/corpus/index.d.ts +37 -0
  50. package/dist/corpus/index.js +4132 -0
  51. package/dist/corpus/index.js.map +1 -0
  52. package/dist/corpus/infrastructure.d.ts +17 -0
  53. package/dist/corpus/libraries-extended.d.ts +2 -0
  54. package/dist/corpus/ranges.d.ts +31 -0
  55. package/dist/corpus/reputation.d.ts +21 -0
  56. package/dist/corpus/runner.d.ts +130 -0
  57. package/dist/corpus/schema.d.ts +185 -0
  58. package/dist/corpus/tooling.d.ts +2 -0
  59. package/dist/corpus/unwanted.d.ts +2 -0
  60. package/dist/crawler-ranges.d.ts +113 -0
  61. package/dist/dashboard/client.generated.d.ts +7 -0
  62. package/dist/dashboard/feed.d.ts +186 -0
  63. package/dist/dashboard/index.d.ts +5 -0
  64. package/dist/dashboard/page.d.ts +51 -0
  65. package/dist/dashboard/parse-request.d.ts +28 -0
  66. package/dist/dashboard/preview.d.ts +45 -0
  67. package/dist/dashboard/server.d.ts +70 -0
  68. package/dist/dashboard/types.d.ts +714 -0
  69. package/dist/detectors/accept-signature.d.ts +6 -0
  70. package/dist/detectors/browsing-coherence.d.ts +44 -0
  71. package/dist/detectors/cadence.d.ts +28 -0
  72. package/dist/detectors/clearance.d.ts +25 -0
  73. package/dist/detectors/client-hints.d.ts +19 -0
  74. package/dist/detectors/client-signals.d.ts +27 -0
  75. package/dist/detectors/crawl-breadth.d.ts +28 -0
  76. package/dist/detectors/crawler-verification.d.ts +39 -0
  77. package/dist/detectors/fetch-metadata.d.ts +20 -0
  78. package/dist/detectors/header-integrity.d.ts +26 -0
  79. package/dist/detectors/header-order.d.ts +27 -0
  80. package/dist/detectors/identity-rotation.d.ts +34 -0
  81. package/dist/detectors/index.d.ts +56 -0
  82. package/dist/detectors/ip-intelligence.d.ts +30 -0
  83. package/dist/detectors/known-bots.d.ts +94 -0
  84. package/dist/detectors/probe-signature.d.ts +50 -0
  85. package/dist/detectors/rate-anomaly.d.ts +36 -0
  86. package/dist/detectors/self-identified.d.ts +33 -0
  87. package/dist/detectors/session-integrity.d.ts +24 -0
  88. package/dist/detectors/tls-fingerprint.d.ts +34 -0
  89. package/dist/detectors/trap.d.ts +98 -0
  90. package/dist/detectors/types.d.ts +70 -0
  91. package/dist/detectors/ua-coherence.d.ts +32 -0
  92. package/dist/evidence.d.ts +45 -0
  93. package/dist/facts.d.ts +46 -0
  94. package/dist/index.cjs +9600 -0
  95. package/dist/index.cjs.map +1 -0
  96. package/dist/index.d.ts +63 -0
  97. package/dist/index.js +9444 -0
  98. package/dist/index.js.map +1 -0
  99. package/dist/internal/async.d.ts +16 -0
  100. package/dist/internal/clock.d.ts +17 -0
  101. package/dist/internal/crypto.d.ts +26 -0
  102. package/dist/internal/dns.d.ts +100 -0
  103. package/dist/internal/emitter.d.ts +18 -0
  104. package/dist/internal/http.d.ts +22 -0
  105. package/dist/internal/ip.d.ts +73 -0
  106. package/dist/internal/lru.d.ts +34 -0
  107. package/dist/internal/matcher.d.ts +41 -0
  108. package/dist/internal/pattern.d.ts +14 -0
  109. package/dist/internal/ua.d.ts +92 -0
  110. package/dist/metrics.d.ts +120 -0
  111. package/dist/notify/hub.d.ts +70 -0
  112. package/dist/notify/index.d.ts +7 -0
  113. package/dist/notify/redact.d.ts +48 -0
  114. package/dist/notify/sinks.d.ts +62 -0
  115. package/dist/notify/types.d.ts +56 -0
  116. package/dist/policy/index.d.ts +7 -0
  117. package/dist/policy/match.d.ts +20 -0
  118. package/dist/policy/policy.d.ts +123 -0
  119. package/dist/policy/presets.d.ts +161 -0
  120. package/dist/policy/types.d.ts +155 -0
  121. package/dist/robots.d.ts +83 -0
  122. package/dist/state.d.ts +161 -0
  123. package/dist/stores/index.d.ts +5 -0
  124. package/dist/stores/memory.d.ts +33 -0
  125. package/dist/stores/redis.d.ts +59 -0
  126. package/dist/stores/types.d.ts +37 -0
  127. package/dist/types.d.ts +250 -0
  128. package/docs/challenge/index.md +152 -0
  129. package/docs/challenge/localisation.md +105 -0
  130. package/docs/concepts/actors.md +113 -0
  131. package/docs/concepts/evidence.md +133 -0
  132. package/docs/concepts/the-guard.md +121 -0
  133. package/docs/concepts/threat-model.md +120 -0
  134. package/docs/concepts/verdicts.md +108 -0
  135. package/docs/course/01-first-assessment.md +178 -0
  136. package/docs/course/02-proof-and-suspicion.md +164 -0
  137. package/docs/course/03-verdicts-and-scores.md +160 -0
  138. package/docs/course/04-the-guard.md +200 -0
  139. package/docs/course/05-detectors.md +178 -0
  140. package/docs/course/06-identity.md +161 -0
  141. package/docs/course/07-actors.md +178 -0
  142. package/docs/course/08-traps.md +183 -0
  143. package/docs/course/09-rules.md +224 -0
  144. package/docs/course/10-actions-and-presets.md +216 -0
  145. package/docs/course/11-the-challenge.md +227 -0
  146. package/docs/course/12-going-live.md +211 -0
  147. package/docs/course/13-operating-it.md +238 -0
  148. package/docs/course/14-scaling.md +195 -0
  149. package/docs/course/15-extending.md +259 -0
  150. package/docs/course/16-proving-it.md +266 -0
  151. package/docs/course/index.md +112 -0
  152. package/docs/design/decisions.md +216 -0
  153. package/docs/detection/client-signals.md +96 -0
  154. package/docs/detection/detectors.md +376 -0
  155. package/docs/detection/index.md +134 -0
  156. package/docs/detection/signatures.md +111 -0
  157. package/docs/detection/verification.md +123 -0
  158. package/docs/detection/writing-a-detector.md +145 -0
  159. package/docs/index.md +100 -0
  160. package/docs/integration/adapters.md +138 -0
  161. package/docs/integration/client-ip.md +114 -0
  162. package/docs/integration/index.md +55 -0
  163. package/docs/integration/stores.md +76 -0
  164. package/docs/operations/audit.md +116 -0
  165. package/docs/operations/dashboard.md +725 -0
  166. package/docs/operations/index.md +101 -0
  167. package/docs/operations/metrics.md +74 -0
  168. package/docs/operations/notifications.md +72 -0
  169. package/docs/operations/runtime-changes.md +118 -0
  170. package/docs/policy/actions.md +196 -0
  171. package/docs/policy/index.md +84 -0
  172. package/docs/policy/presets.md +191 -0
  173. package/docs/policy/robots.md +128 -0
  174. package/docs/policy/rules.md +134 -0
  175. package/docs/reference/api.md +126 -0
  176. package/docs/reference/configuration.md +175 -0
  177. package/docs/start/choosing-a-policy.md +127 -0
  178. package/docs/start/first-integration.md +127 -0
  179. package/docs/start/installation.md +63 -0
  180. package/docs/start/upgrading.md +72 -0
  181. package/docs/testing/cli.md +119 -0
  182. package/docs/testing/corpus.md +129 -0
  183. package/docs/testing/index.md +61 -0
  184. package/docs/testing/replay.md +102 -0
  185. package/docs/testing/try-it.md +189 -0
  186. package/package.json +145 -0
@@ -0,0 +1,403 @@
1
+ import type { CaseRequest } from "./schema.js";
2
+ /**
3
+ * Header profiles for real clients.
4
+ *
5
+ * Three things here are load-bearing and easy to get wrong when writing fixtures by
6
+ * hand.
7
+ *
8
+ * **Order.** Each engine emits headers in a fixed sequence that differs between
9
+ * Chromium, Gecko and WebKit and barely changes across releases. It is one of the few
10
+ * properties a scraper cannot fix by copying a User-Agent, so a corpus that gets the
11
+ * order wrong is testing a client that does not exist.
12
+ *
13
+ * **Completeness.** A real browser sends a whole cluster together — the negotiation
14
+ * headers, the `Sec-Fetch-*` set, the Client Hints on Chromium, a dozen cookies it
15
+ * never asked for. Omitting one because it seemed unimportant turns a human fixture
16
+ * into a bot fixture and quietly inverts what the case proves.
17
+ *
18
+ * **The optional apparatus.** Modern browsers carry a long tail of conditional
19
+ * headers: high-entropy Client Hints once a server has asked for them, `Sec-GPC` from
20
+ * privacy-preserving builds, `Save-Data` on metered connections, `Sec-Purpose` on
21
+ * speculative loads, `Early-Data` on a TLS 1.3 resumption, cache validators on a
22
+ * revisit. Each is modelled here because each is something a hand-rolled client
23
+ * forgets, and because a corpus of only the happy path tests only the happy path.
24
+ *
25
+ * Sources: 2026 User-Agent lists; W3C `TR/fetch-metadata` for the `Sec-Fetch-*`
26
+ * combinations; the UA Client Hints specification for the `Sec-CH-*` set; observed
27
+ * request captures.
28
+ */
29
+ export type Header = readonly [name: string, value: string];
30
+ /** What kind of request this is. Decides the `Sec-Fetch-*` set and the `Accept` value. */
31
+ export type RequestKind =
32
+ /** Typing a URL or following a bookmark: no referrer, user-initiated. */
33
+ "navigate"
34
+ /** Following a link within the site. */
35
+ | "same-origin-navigate"
36
+ /** Arriving from another site. */
37
+ | "cross-site-navigate"
38
+ /** A form POST back to the same origin. */
39
+ | "form-post"
40
+ /** `fetch()` for JSON from page script. */
41
+ | "xhr"
42
+ /** A cross-origin `fetch()` that will be preflighted. */
43
+ | "cors"
44
+ /** An image, font or stylesheet. */
45
+ | "subresource"
46
+ /** A stylesheet specifically. */
47
+ | "stylesheet"
48
+ /** A script tag. */
49
+ | "script"
50
+ /** A media byte-range request from a `<video>`. */
51
+ | "media"
52
+ /** An `EventSource` stream. */
53
+ | "eventsource"
54
+ /** A `<iframe>` load. */
55
+ | "iframe";
56
+ export interface ProfileOptions {
57
+ kind?: RequestKind;
58
+ host?: string;
59
+ /** Cookie header value. See `cookies.ts` for realistic jars. */
60
+ cookie?: string;
61
+ referer?: string;
62
+ origin?: string;
63
+ /** Overrides the profile's default language list — a real setting people change. */
64
+ acceptLanguage?: string;
65
+ /** High-entropy Client Hints, sent only after a server advertises `Accept-CH`. */
66
+ highEntropyHints?: boolean;
67
+ /** `DNT: 1`. Still sent by a meaningful minority despite being deprecated. */
68
+ dnt?: boolean;
69
+ /** `Sec-GPC: 1` — Global Privacy Control, sent by Brave, DuckDuckGo and others. */
70
+ gpc?: boolean;
71
+ /** `Save-Data: on` — a metered or data-saver connection. */
72
+ saveData?: boolean;
73
+ /** Network Information hints (`RTT`, `Downlink`, `ECT`), also gated behind `Accept-CH`. */
74
+ networkHints?: {
75
+ rtt: number;
76
+ downlink: number;
77
+ ect: "slow-2g" | "2g" | "3g" | "4g";
78
+ };
79
+ /** Layout hints (`Viewport-Width`, `DPR`, `Width`), gated behind `Accept-CH`. */
80
+ layoutHints?: {
81
+ viewportWidth: number;
82
+ dpr: number;
83
+ };
84
+ /** Conditional request headers from a revisit. */
85
+ revalidate?: {
86
+ etag?: string;
87
+ modifiedSince?: string;
88
+ };
89
+ /** `Cache-Control: max-age=0`, which a browser sends on an explicit reload. */
90
+ reload?: boolean;
91
+ /** `Sec-Purpose: prefetch` plus the legacy `Purpose` header. */
92
+ prefetch?: boolean;
93
+ /** `Sec-Fetch-Storage-Access`, sent by recent Chromium in third-party contexts. */
94
+ storageAccess?: "none" | "active" | "inactive";
95
+ /** User preference hints, sent when the server asks for them. */
96
+ prefers?: {
97
+ colorScheme?: "light" | "dark";
98
+ reducedMotion?: "no-preference" | "reduce";
99
+ };
100
+ /** `Early-Data: 1` — a TLS 1.3 0-RTT resumption replayed by an intermediary. */
101
+ earlyData?: boolean;
102
+ /** Byte range for a media request. */
103
+ range?: string;
104
+ /** Body content type for a POST. */
105
+ contentType?: string;
106
+ contentLength?: number;
107
+ }
108
+ interface EngineProfile {
109
+ userAgent: string;
110
+ acceptDocument: string;
111
+ acceptEncoding: string;
112
+ acceptLanguage: string;
113
+ build: (options: ResolvedOptions, self: EngineProfile) => Header[];
114
+ }
115
+ type ResolvedOptions = ProfileOptions & Required<Pick<ProfileOptions, "host" | "kind" | "acceptLanguage">>;
116
+ /** Firefox leads with identity and content negotiation, and closes with Fetch Metadata. */
117
+ declare function geckoBuild(options: ResolvedOptions, self: EngineProfile): Header[];
118
+ /** Safari interleaves Fetch Metadata with content negotiation rather than grouping it. */
119
+ declare function webkitBuild(options: ResolvedOptions, self: EngineProfile): Header[];
120
+ /** Older WebKit and embedded builds: no Fetch Metadata at all. */
121
+ declare function legacyWebkitBuild(options: ResolvedOptions, self: EngineProfile): Header[];
122
+ export declare const PROFILES: {
123
+ readonly chromeWindows: {
124
+ readonly userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36";
125
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7";
126
+ readonly acceptEncoding: "gzip, deflate, br, zstd";
127
+ readonly acceptLanguage: "en-US,en;q=0.9";
128
+ readonly build: (options: ResolvedOptions, self: EngineProfile) => Header[];
129
+ };
130
+ readonly chromeMac: {
131
+ readonly userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36";
132
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7";
133
+ readonly acceptEncoding: "gzip, deflate, br, zstd";
134
+ readonly acceptLanguage: "en-GB,en-US;q=0.9,en;q=0.8";
135
+ readonly build: (options: ResolvedOptions, self: EngineProfile) => Header[];
136
+ };
137
+ readonly chromeLinux: {
138
+ readonly userAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36";
139
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7";
140
+ readonly acceptEncoding: "gzip, deflate, br, zstd";
141
+ readonly acceptLanguage: "en-US,en;q=0.9";
142
+ readonly build: (options: ResolvedOptions, self: EngineProfile) => Header[];
143
+ };
144
+ readonly chromeChromeOs: {
145
+ readonly userAgent: "Mozilla/5.0 (X11; CrOS x86_64 15886.69.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36";
146
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7";
147
+ readonly acceptEncoding: "gzip, deflate, br, zstd";
148
+ readonly acceptLanguage: "en-US,en;q=0.9";
149
+ readonly build: (options: ResolvedOptions, self: EngineProfile) => Header[];
150
+ };
151
+ readonly edgeWindows: {
152
+ readonly userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 Edg/150.0.0.0";
153
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7";
154
+ readonly acceptEncoding: "gzip, deflate, br, zstd";
155
+ readonly acceptLanguage: "en-US,en;q=0.9";
156
+ readonly build: (options: ResolvedOptions, self: EngineProfile) => Header[];
157
+ };
158
+ readonly edgeMac: {
159
+ readonly userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 Edg/150.0.0.0";
160
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7";
161
+ readonly acceptEncoding: "gzip, deflate, br, zstd";
162
+ readonly acceptLanguage: "en-US,en;q=0.9";
163
+ readonly build: (options: ResolvedOptions, self: EngineProfile) => Header[];
164
+ };
165
+ readonly operaWindows: {
166
+ readonly userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 OPR/135.0.0.0";
167
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7";
168
+ readonly acceptEncoding: "gzip, deflate, br, zstd";
169
+ readonly acceptLanguage: "en-US,en;q=0.9";
170
+ readonly build: (options: ResolvedOptions, self: EngineProfile) => Header[];
171
+ };
172
+ readonly vivaldiWindows: {
173
+ readonly userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Vivaldi/7.6.3797.48";
174
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7";
175
+ readonly acceptEncoding: "gzip, deflate, br, zstd";
176
+ readonly acceptLanguage: "en-US,en;q=0.9";
177
+ readonly build: (options: ResolvedOptions, self: EngineProfile) => Header[];
178
+ };
179
+ /** Brave presents an unmodified Chrome identity by design, and adds Sec-GPC. */
180
+ readonly braveWindows: {
181
+ readonly userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36";
182
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7";
183
+ readonly acceptEncoding: "gzip, deflate, br, zstd";
184
+ readonly acceptLanguage: "en-US,en;q=0.9";
185
+ readonly build: (options: ResolvedOptions, self: EngineProfile) => Header[];
186
+ };
187
+ readonly yandexWindows: {
188
+ readonly userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 YaBrowser/25.8.0.0 Safari/537.36";
189
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7";
190
+ readonly acceptEncoding: "gzip, deflate, br, zstd";
191
+ readonly acceptLanguage: "ru,en;q=0.9";
192
+ readonly build: (options: ResolvedOptions, self: EngineProfile) => Header[];
193
+ };
194
+ readonly firefoxWindows: {
195
+ readonly userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:148.0) Gecko/20100101 Firefox/148.0";
196
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8";
197
+ readonly acceptEncoding: "gzip, deflate, br, zstd";
198
+ readonly acceptLanguage: "en-US,en;q=0.5";
199
+ readonly build: typeof geckoBuild;
200
+ };
201
+ readonly firefoxMac: {
202
+ readonly userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:148.0) Gecko/20100101 Firefox/148.0";
203
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8";
204
+ readonly acceptEncoding: "gzip, deflate, br, zstd";
205
+ readonly acceptLanguage: "en-GB,en;q=0.5";
206
+ readonly build: typeof geckoBuild;
207
+ };
208
+ readonly firefoxLinux: {
209
+ readonly userAgent: "Mozilla/5.0 (X11; Linux x86_64; rv:148.0) Gecko/20100101 Firefox/148.0";
210
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8";
211
+ readonly acceptEncoding: "gzip, deflate, br, zstd";
212
+ readonly acceptLanguage: "de-DE,de;q=0.8,en-US;q=0.5,en;q=0.3";
213
+ readonly build: typeof geckoBuild;
214
+ };
215
+ readonly firefoxEsr: {
216
+ readonly userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0";
217
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8";
218
+ readonly acceptEncoding: "gzip, deflate, br, zstd";
219
+ readonly acceptLanguage: "en-US,en;q=0.5";
220
+ readonly build: typeof geckoBuild;
221
+ };
222
+ readonly firefoxAndroid: {
223
+ readonly userAgent: "Mozilla/5.0 (Android 15; Mobile; rv:148.0) Gecko/148.0 Firefox/148.0";
224
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8";
225
+ readonly acceptEncoding: "gzip, deflate, br, zstd";
226
+ readonly acceptLanguage: "en-GB,en;q=0.5";
227
+ readonly build: typeof geckoBuild;
228
+ };
229
+ readonly safariMac: {
230
+ readonly userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.7 Safari/605.1.15";
231
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
232
+ readonly acceptEncoding: "gzip, deflate, br";
233
+ readonly acceptLanguage: "en-GB,en;q=0.9";
234
+ readonly build: typeof webkitBuild;
235
+ };
236
+ readonly safariIos: {
237
+ readonly userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.7 Mobile/15E148 Safari/604.1";
238
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
239
+ readonly acceptEncoding: "gzip, deflate, br";
240
+ readonly acceptLanguage: "en-US,en;q=0.9";
241
+ readonly build: typeof webkitBuild;
242
+ };
243
+ readonly safariIpad: {
244
+ readonly userAgent: "Mozilla/5.0 (iPad; CPU OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.7 Mobile/15E148 Safari/604.1";
245
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
246
+ readonly acceptEncoding: "gzip, deflate, br";
247
+ readonly acceptLanguage: "en-GB,en;q=0.9";
248
+ readonly build: typeof webkitBuild;
249
+ };
250
+ /** Chrome on iOS is WebKit underneath — the engine, and so the header order, is Safari's. */
251
+ readonly chromeIos: {
252
+ readonly userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/152.0.7258.60 Mobile/15E148 Safari/604.1";
253
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
254
+ readonly acceptEncoding: "gzip, deflate, br";
255
+ readonly acceptLanguage: "en-US,en;q=0.9";
256
+ readonly build: typeof webkitBuild;
257
+ };
258
+ readonly firefoxIos: {
259
+ readonly userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/140.0 Mobile/15E148 Safari/605.1.15";
260
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
261
+ readonly acceptEncoding: "gzip, deflate, br";
262
+ readonly acceptLanguage: "en-US,en;q=0.9";
263
+ readonly build: typeof webkitBuild;
264
+ };
265
+ readonly edgeIos: {
266
+ readonly userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 EdgiOS/150.0.3296.60 Mobile/15E148 Safari/605.1.15";
267
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
268
+ readonly acceptEncoding: "gzip, deflate, br";
269
+ readonly acceptLanguage: "en-US,en;q=0.9";
270
+ readonly build: typeof webkitBuild;
271
+ };
272
+ readonly duckduckgoIos: {
273
+ readonly userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.7 Mobile/15E148 Safari/604.1 DuckDuckGo/7";
274
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
275
+ readonly acceptEncoding: "gzip, deflate, br";
276
+ readonly acceptLanguage: "en-US,en;q=0.9";
277
+ readonly build: typeof webkitBuild;
278
+ };
279
+ readonly chromeAndroid: {
280
+ readonly userAgent: "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Mobile Safari/537.36";
281
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7";
282
+ readonly acceptEncoding: "gzip, deflate, br, zstd";
283
+ readonly acceptLanguage: "en-GB,en;q=0.9";
284
+ readonly build: (options: ResolvedOptions, self: EngineProfile) => Header[];
285
+ };
286
+ readonly chromeAndroidTablet: {
287
+ readonly userAgent: "Mozilla/5.0 (Linux; Android 15; SM-X910) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36";
288
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7";
289
+ readonly acceptEncoding: "gzip, deflate, br, zstd";
290
+ readonly acceptLanguage: "en-US,en;q=0.9";
291
+ readonly build: (options: ResolvedOptions, self: EngineProfile) => Header[];
292
+ };
293
+ readonly samsungInternet: {
294
+ readonly userAgent: "Mozilla/5.0 (Linux; Android 15; SM-S938B) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/29.0 Chrome/147.0.0.0 Mobile Safari/537.36";
295
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7";
296
+ readonly acceptEncoding: "gzip, deflate, br";
297
+ readonly acceptLanguage: "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7";
298
+ readonly build: (options: ResolvedOptions, self: EngineProfile) => Header[];
299
+ };
300
+ readonly operaAndroid: {
301
+ readonly userAgent: "Mozilla/5.0 (Linux; Android 14; CPH2451) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Mobile Safari/537.36 OPR/91.0.0.0";
302
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7";
303
+ readonly acceptEncoding: "gzip, deflate, br";
304
+ readonly acceptLanguage: "id-ID,id;q=0.9,en-US;q=0.8";
305
+ readonly build: (options: ResolvedOptions, self: EngineProfile) => Header[];
306
+ };
307
+ readonly edgeAndroid: {
308
+ readonly userAgent: "Mozilla/5.0 (Linux; Android 15; Pixel 9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Mobile Safari/537.36 EdgA/150.0.3296.60";
309
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7";
310
+ readonly acceptEncoding: "gzip, deflate, br, zstd";
311
+ readonly acceptLanguage: "en-US,en;q=0.9";
312
+ readonly build: (options: ResolvedOptions, self: EngineProfile) => Header[];
313
+ };
314
+ /** UC Browser — very large user base across South and Southeast Asia. */
315
+ readonly ucBrowser: {
316
+ readonly userAgent: "Mozilla/5.0 (Linux; U; Android 13; en-IN; RMX3771 Build/TP1A.220905.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4896.58 UCBrowser/13.7.5.1329 Mobile Safari/537.36";
317
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
318
+ readonly acceptEncoding: "gzip, deflate";
319
+ readonly acceptLanguage: "en-IN,en-US;q=0.9,en;q=0.8,hi;q=0.7";
320
+ readonly build: typeof legacyWebkitBuild;
321
+ };
322
+ readonly miBrowser: {
323
+ readonly userAgent: "Mozilla/5.0 (Linux; U; Android 14; en-in; 23049PCD8I Build/UKQ1.230917.001) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Chrome/125.0.6422.165 Mobile Safari/533.1 XiaoMi/MiuiBrowser/19.4.220521";
324
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
325
+ readonly acceptEncoding: "gzip, deflate";
326
+ readonly acceptLanguage: "en-IN,en;q=0.9";
327
+ readonly build: typeof legacyWebkitBuild;
328
+ };
329
+ readonly huaweiBrowser: {
330
+ readonly userAgent: "Mozilla/5.0 (Linux; Android 12; ELS-NX9; HMSCore 6.14.0.302) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.186 HuaweiBrowser/15.0.5.310 Mobile Safari/537.36";
331
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7";
332
+ readonly acceptEncoding: "gzip, deflate, br";
333
+ readonly acceptLanguage: "zh-CN,zh;q=0.9,en;q=0.8";
334
+ readonly build: typeof legacyWebkitBuild;
335
+ };
336
+ readonly qqBrowser: {
337
+ readonly userAgent: "Mozilla/5.0 (Linux; U; Android 14; zh-cn; 2211133C Build/UKQ1.230804.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/122.0.6261.119 MQQBrowser/15.7 Mobile Safari/537.36";
338
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
339
+ readonly acceptEncoding: "gzip, deflate";
340
+ readonly acceptLanguage: "zh-CN,zh;q=0.9";
341
+ readonly build: typeof legacyWebkitBuild;
342
+ };
343
+ readonly silkKindle: {
344
+ readonly userAgent: "Mozilla/5.0 (Linux; Android 11; KFRAWI) AppleWebKit/537.36 (KHTML, like Gecko) Silk/128.1.2 like Chrome/128.0.6613.146 Safari/537.36";
345
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7";
346
+ readonly acceptEncoding: "gzip, deflate, br";
347
+ readonly acceptLanguage: "en-GB,en;q=0.9";
348
+ readonly build: typeof legacyWebkitBuild;
349
+ };
350
+ readonly tizenTv: {
351
+ readonly userAgent: "Mozilla/5.0 (SMART-TV; LINUX; Tizen 8.0) AppleWebKit/537.36 (KHTML, like Gecko) 108.0.5359.1/8.0 TV Safari/537.36";
352
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
353
+ readonly acceptEncoding: "gzip, deflate";
354
+ readonly acceptLanguage: "en-US";
355
+ readonly build: typeof legacyWebkitBuild;
356
+ };
357
+ readonly webOsTv: {
358
+ readonly userAgent: "Mozilla/5.0 (Web0S; Linux/SmartTV) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.215 Safari/537.36 WebAppManager";
359
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
360
+ readonly acceptEncoding: "gzip, deflate";
361
+ readonly acceptLanguage: "en-GB";
362
+ readonly build: typeof legacyWebkitBuild;
363
+ };
364
+ readonly playstation: {
365
+ readonly userAgent: "Mozilla/5.0 (PlayStation; PlayStation 5/9.60) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15";
366
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
367
+ readonly acceptEncoding: "gzip, deflate, br";
368
+ readonly acceptLanguage: "en-GB";
369
+ readonly build: typeof legacyWebkitBuild;
370
+ };
371
+ readonly nintendoSwitch: {
372
+ readonly userAgent: "Mozilla/5.0 (Nintendo Switch; WifiWebAuthApplet) AppleWebKit/609.4 (KHTML, like Gecko) NF/6.0.2.23.4 NintendoBrowser/5.1.0.23519";
373
+ readonly acceptDocument: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
374
+ readonly acceptEncoding: "gzip, deflate";
375
+ readonly acceptLanguage: "en-GB";
376
+ readonly build: typeof legacyWebkitBuild;
377
+ };
378
+ };
379
+ export type ProfileName = keyof typeof PROFILES;
380
+ export declare const PROFILE_NAMES: ProfileName[];
381
+ /** Builds a request from a named profile. The normal way to write a human case. */
382
+ export declare function browser(name: ProfileName, options?: ProfileOptions): CaseRequest;
383
+ /** The raw User-Agent of a profile, for cases that alter it deliberately. */
384
+ export declare function userAgentOf(name: ProfileName): string;
385
+ /**
386
+ * A minimal bot-shaped request: a User-Agent and whatever else you name.
387
+ *
388
+ * Most automation really does send this little. Where a specific client is known to
389
+ * send more, the case says so explicitly rather than using this helper.
390
+ */
391
+ export declare function plain(userAgent: string, extra?: readonly Header[], host?: string): CaseRequest;
392
+ /**
393
+ * A well-behaved crawler's request: identity, a contact address, and the negotiation
394
+ * headers a fetcher that intends to parse HTML actually sends.
395
+ */
396
+ export declare function crawler(userAgent: string, options?: {
397
+ from?: string;
398
+ accept?: string;
399
+ encoding?: string;
400
+ host?: string;
401
+ extra?: readonly Header[];
402
+ }): CaseRequest;
403
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { TrafficCase } from "./schema.js";
2
+ export declare const HUMAN_APP_CASES: TrafficCase[];
@@ -0,0 +1,2 @@
1
+ import type { TrafficCase } from "./schema.js";
2
+ export declare const HUMAN_BROWSER_CASES: TrafficCase[];
@@ -0,0 +1,2 @@
1
+ import type { TrafficCase } from "./schema.js";
2
+ export declare const HUMAN_CASES: TrafficCase[];