@apideck/agent-analytics 0.11.0 → 0.12.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.
package/dist/index.js CHANGED
@@ -1,876 +1,3 @@
1
- // src/bots.ts
2
- var AI_BOT_PATTERN = /ClaudeBot|Claude-User|Claude-SearchBot|Claude-Web|Anthropic|GPTBot|ChatGPT-User|OAI-SearchBot|PerplexityBot|Perplexity-User|Google-Extended|Google-CloudVertexBot|Google-Agent|GoogleAgent-Mariner|Gemini-Deep-Research|Applebot|cohere|Bytespider|CCBot|Amazonbot|Amzn-SearchBot|NovaAct|AzureAI-SearchBot|Meta-ExternalAgent|meta-externalfetcher|meta-webindexer|FacebookBot|DuckAssistBot|MistralAI-User|YouBot|AI2Bot|Diffbot|DeepSeek|PanguBot|Webzio-Extended|omgili|Timpibot|Grok|Manus-User|quillbot|MyCentralAIScraperBot|Cursor|Windsurf/i;
3
- var HTTP_CLIENT_PATTERN = /axios\/|curl\/|(?:^|[\s(])got(?:\/|[\s(])|\bcolly\b|Electron\/|node-fetch\/|python-requests\/|Go-http-client\/|okhttp\/|aiohttp\/|Deno\//i;
4
- function isAiBot(userAgent) {
5
- if (!userAgent) return false;
6
- return AI_BOT_PATTERN.test(userAgent);
7
- }
8
- function isHttpClient(userAgent) {
9
- if (!userAgent) return false;
10
- return HTTP_CLIENT_PATTERN.test(userAgent);
11
- }
12
- function parseBotName(userAgent) {
13
- if (!userAgent || typeof userAgent !== "string") return "Other";
14
- const s = userAgent.toLowerCase();
15
- if (s.includes("chatgpt-user") || s.includes("gptbot") || s.includes("oai-searchbot") || s.includes("openai"))
16
- return "ChatGPT";
17
- if (s.includes("claudebot") || s.includes("claude-user") || s.includes("claude-searchbot") || s.includes("claude-web") || s.includes("anthropic"))
18
- return "Claude";
19
- if (s.includes("perplexitybot") || s.includes("perplexity-user")) return "Perplexity";
20
- if (s.includes("ccbot")) return "Common Crawl";
21
- if (s.includes("google-extended") || s.includes("googlebot") || s.includes("google-cloudvertexbot") || s.includes("google-agent") || s.includes("googleagent-mariner") || s.includes("gemini-deep-research"))
22
- return "Google";
23
- if (s.includes("applebot")) return "Apple";
24
- if (s.includes("bingbot")) return "Bing";
25
- if (s.includes("bytespider")) return "Bytespider";
26
- if (s.includes("amazonbot") || s.includes("amzn-searchbot") || s.includes("novaact")) return "Amazon";
27
- if (s.includes("meta-externalagent") || s.includes("meta-externalfetcher") || s.includes("meta-webindexer") || s.includes("facebookbot"))
28
- return "Meta";
29
- if (s.includes("mistralai-user")) return "Mistral";
30
- if (s.includes("duckassistbot")) return "DuckDuckGo";
31
- if (s.includes("youbot")) return "You.com";
32
- if (s.includes("diffbot")) return "Diffbot";
33
- if (s.includes("ai2bot")) return "AI2";
34
- if (s.includes("cohere")) return "Cohere";
35
- if (s.includes("cursor")) return "Cursor";
36
- if (s.includes("windsurf")) return "Windsurf";
37
- if (s.includes("deepseek")) return "DeepSeek";
38
- if (s.includes("pangubot")) return "Huawei";
39
- if (s.includes("webzio") || s.includes("omgili")) return "Webz.io";
40
- if (s.includes("timpibot")) return "Timpi";
41
- if (s.includes("grok") || s.includes("xai-")) return "xAI";
42
- if (s.includes("manus-user")) return "Manus";
43
- if (s.includes("quillbot")) return "QuillBot";
44
- if (s.includes("azureai-searchbot")) return "Microsoft";
45
- if (s.includes("mycentralaiscraperbot")) return "MyCentralAI";
46
- if (s.includes("petalbot")) return "PetalBot";
47
- if (s.includes("ahrefsbot")) return "Ahrefs";
48
- if (s.includes("semrushbot")) return "Semrush";
49
- if (s.includes("mj12bot")) return "Majestic";
50
- if (s.includes("dotbot")) return "Moz";
51
- if (s.includes("rogerbot")) return "Moz";
52
- if (s.includes("screaming frog")) return "Screaming Frog";
53
- if (s.includes("sitebulb")) return "Sitebulb";
54
- if (s.includes("linkfluence")) return "Linkfluence";
55
- if (s.includes("dataforseo")) return "DataForSEO";
56
- if (s.includes("serpstatbot")) return "Serpstat";
57
- if (s.includes("uptimerobot")) return "UptimeRobot";
58
- if (s.includes("pingdom")) return "Pingdom";
59
- if (s.includes("statuscake")) return "StatusCake";
60
- if (s.includes("newrelicpinger")) return "New Relic";
61
- if (s.includes("datadogagent") || s.includes("datadog")) return "Datadog";
62
- if (s.includes("slackbot")) return "Slack";
63
- if (s.includes("twitterbot")) return "Twitter";
64
- if (s.includes("linkedinbot")) return "LinkedIn";
65
- if (s.includes("discordbot")) return "Discord";
66
- if (s.includes("telegrambot")) return "Telegram";
67
- if (s.includes("whatsapp")) return "WhatsApp";
68
- if (s.includes("linkupbot")) return "Linkup";
69
- if (s.includes("sogou")) return "Sogou";
70
- if (s.includes("yandexbot")) return "Yandex";
71
- if (s.includes("baiduspider")) return "Baidu";
72
- if (s.includes("facebookexternalhit")) return "Facebook";
73
- if (s.includes("com.apple.webkit")) return "Apple URL Preview";
74
- if (s.includes("ohdear")) return "Oh Dear";
75
- if (s.includes("scrapy")) return "Scrapy";
76
- if (s.includes("headlesschrome")) return "Headless Chrome";
77
- if (s.includes("phantomjs")) return "PhantomJS";
78
- if (s.includes("wget")) return "wget";
79
- if (s.includes("httpie")) return "HTTPie";
80
- if (s.includes("guzzlehttp")) return "Guzzle";
81
- if (s.includes("electron/")) return "Electron";
82
- if (/curl\//.test(s)) return "curl";
83
- if (/axios\//.test(s)) return "axios";
84
- if (/(?:^|[\s(])got(?:\/|[\s(])/.test(s)) return "got";
85
- if (/\bcolly\b/.test(s)) return "colly";
86
- if (/node-fetch\//.test(s)) return "node-fetch";
87
- if (/python-requests\//.test(s)) return "python-requests";
88
- if (/go-http-client\//.test(s)) return "Go http client";
89
- if (/okhttp\//.test(s)) return "OkHttp";
90
- if (/aiohttp\//.test(s)) return "aiohttp";
91
- if (/deno\//.test(s)) return "Deno";
92
- if (s.includes("mozilla") || s.includes("chrome") || s.includes("safari") || s.includes("firefox"))
93
- return "Browser";
94
- return "Other";
95
- }
96
- function firstUserAgentProduct(userAgent) {
97
- if (!userAgent || typeof userAgent !== "string") return "Other";
98
- const compatibleMatch = userAgent.match(/compatible;\s*([^/;\s]+)(?:\/[^\s;]*)?/i);
99
- if (compatibleMatch && compatibleMatch[1]) return compatibleMatch[1].trim();
100
- const first = userAgent.trim().split("/")[0]?.trim().split(/\s+/)[0]?.trim();
101
- return first || "Other";
102
- }
103
- function detectHeadless(req) {
104
- const signals = [];
105
- const ua = (req.headers.get("user-agent") || "").toLowerCase();
106
- const isBrowserUA = ua.includes("mozilla") || ua.includes("chrome") || ua.includes("safari") || ua.includes("firefox");
107
- if (!isBrowserUA) return { score: 0, signals: [], likely: false };
108
- if (!req.headers.get("accept-language")) {
109
- signals.push("missing-accept-language");
110
- }
111
- if (!req.headers.get("sec-fetch-mode")) {
112
- signals.push("missing-sec-fetch-mode");
113
- }
114
- const secChUa = req.headers.get("sec-ch-ua");
115
- if (!secChUa) {
116
- signals.push("missing-sec-ch-ua");
117
- } else if (secChUa.toLowerCase().includes("headlesschrome")) {
118
- signals.push("headless-chrome-hint");
119
- }
120
- const accept = req.headers.get("accept") || "";
121
- if (!accept || accept === "*/*") {
122
- signals.push("missing-or-bare-accept");
123
- }
124
- if ((req.headers.get("connection") || "").toLowerCase() === "close") {
125
- signals.push("connection-close");
126
- }
127
- const score = signals.length;
128
- return { score, signals, likely: score >= 2 };
129
- }
130
- function classifyAgent(userAgent) {
131
- const label = parseBotName(userAgent);
132
- const aiBot = isAiBot(userAgent);
133
- const httpClient = isHttpClient(userAgent);
134
- let kind;
135
- if (aiBot) kind = "declared-crawler";
136
- else if (httpClient) kind = "coding-agent-hint";
137
- else if (label === "Browser") kind = "browser";
138
- else kind = "other";
139
- return { kind, label, isAiBot: aiBot, codingAgentHint: httpClient };
140
- }
141
- function classifyRequest(req) {
142
- const userAgent = req.headers.get("user-agent") || "";
143
- const base = classifyAgent(userAgent);
144
- const headless = detectHeadless(req);
145
- let kind = base.kind;
146
- if (kind === "browser" && headless.likely) {
147
- kind = "headless-likely";
148
- }
149
- return { ...base, kind, headless };
150
- }
151
-
152
- // src/bot-ranges.ts
153
- var BOT_RANGES_CAPTURED_AT = "2026-08-02T00:00:00Z";
154
- var BOT_IP_RANGES = {
155
- ChatGPT: [
156
- "104.208.184.192/28",
157
- "104.208.184.208/28",
158
- "104.210.139.192/28",
159
- "104.210.139.224/28",
160
- "104.210.140.128/28",
161
- "128.85.198.32/28",
162
- "13.65.138.112/28",
163
- "13.65.138.96/28",
164
- "13.67.72.16/28",
165
- "13.70.107.160/28",
166
- "13.71.2.208/28",
167
- "13.76.115.224/28",
168
- "13.76.115.240/28",
169
- "13.76.116.80/28",
170
- "13.76.32.208/28",
171
- "13.83.167.128/28",
172
- "13.83.237.176/28",
173
- "132.196.82.48/28",
174
- "132.196.86.0/24",
175
- "134.149.233.80/28",
176
- "135.116.136.160/28",
177
- "135.13.64.240/28",
178
- "135.220.73.208/28",
179
- "135.220.73.240/28",
180
- "135.234.64.0/24",
181
- "135.237.131.208/28",
182
- "135.237.133.48/28",
183
- "137.135.191.176/28",
184
- "138.91.30.48/28",
185
- "138.91.46.96/28",
186
- "145.132.1.32/28",
187
- "145.132.136.96/28",
188
- "145.133.0.176/28",
189
- "158.158.5.32/28",
190
- "168.63.252.240/28",
191
- "172.162.248.64/28",
192
- "172.170.1.80/28",
193
- "172.170.225.0/28",
194
- "172.170.241.80/28",
195
- "172.170.8.208/28",
196
- "172.171.4.176/28",
197
- "172.175.152.224/28",
198
- "172.178.140.144/28",
199
- "172.178.141.112/28",
200
- "172.178.141.128/28",
201
- "172.182.193.224/28",
202
- "172.182.193.80/28",
203
- "172.182.194.144/28",
204
- "172.182.194.32/28",
205
- "172.182.195.48/28",
206
- "172.182.202.0/25",
207
- "172.182.204.0/24",
208
- "172.182.207.0/25",
209
- "172.182.209.208/28",
210
- "172.182.211.192/28",
211
- "172.182.213.192/28",
212
- "172.182.214.0/24",
213
- "172.182.215.0/24",
214
- "172.182.224.0/28",
215
- "172.183.143.224/28",
216
- "172.183.222.128/28",
217
- "172.192.112.208/28",
218
- "172.192.88.192/28",
219
- "172.192.97.32/28",
220
- "172.197.160.192/28",
221
- "172.197.161.208/28",
222
- "172.197.170.80/28",
223
- "172.197.203.16/28",
224
- "172.199.137.80/28",
225
- "172.202.102.112/28",
226
- "172.203.190.128/28",
227
- "172.204.27.16/28",
228
- "172.204.28.224/28",
229
- "172.204.96.32/28",
230
- "172.204.96.48/28",
231
- "172.204.96.80/28",
232
- "172.205.189.192/28",
233
- "172.207.1.32/28",
234
- "172.208.128.32/28",
235
- "172.208.128.48/28",
236
- "172.212.159.64/28",
237
- "172.212.172.160/28",
238
- "172.213.21.16/28",
239
- "172.215.215.32/28",
240
- "172.215.218.96/28",
241
- "191.233.1.112/28",
242
- "191.233.1.128/28",
243
- "191.233.194.32/28",
244
- "191.233.196.112/28",
245
- "191.233.199.160/28",
246
- "191.233.2.0/28",
247
- "191.235.66.16/28",
248
- "191.235.99.80/28",
249
- "191.237.249.64/28",
250
- "191.239.245.16/28",
251
- "20.102.212.144/28",
252
- "20.113.211.112/28",
253
- "20.113.225.112/28",
254
- "20.125.112.224/28",
255
- "20.125.144.144/28",
256
- "20.125.66.80/28",
257
- "20.14.99.96/28",
258
- "20.161.75.208/28",
259
- "20.168.18.32/28",
260
- "20.168.7.192/28",
261
- "20.168.7.240/28",
262
- "20.169.6.224/28",
263
- "20.169.7.48/28",
264
- "20.169.72.112/28",
265
- "20.169.73.176/28",
266
- "20.169.73.32/28",
267
- "20.169.73.64/28",
268
- "20.169.77.0/25",
269
- "20.169.78.112/28",
270
- "20.169.78.128/28",
271
- "20.169.78.144/28",
272
- "20.169.78.160/28",
273
- "20.169.78.176/28",
274
- "20.169.78.192/28",
275
- "20.169.78.208/28",
276
- "20.169.78.48/28",
277
- "20.169.78.64/28",
278
- "20.169.78.80/28",
279
- "20.169.78.96/28",
280
- "20.169.86.224/28",
281
- "20.169.86.240/28",
282
- "20.169.87.112/28",
283
- "20.17.108.96/28",
284
- "20.170.184.16/28",
285
- "20.170.184.32/28",
286
- "20.170.184.48/28",
287
- "20.170.184.64/28",
288
- "20.170.184.80/28",
289
- "20.171.123.64/28",
290
- "20.171.206.0/24",
291
- "20.171.207.0/24",
292
- "20.171.53.224/28",
293
- "20.172.29.32/28",
294
- "20.193.233.240/28",
295
- "20.193.50.32/28",
296
- "20.194.0.208/28",
297
- "20.194.1.0/28",
298
- "20.198.67.96/28",
299
- "20.199.211.160/28",
300
- "20.199.242.0/28",
301
- "20.200.212.240/28",
302
- "20.204.24.240/28",
303
- "20.210.154.128/28",
304
- "20.210.174.208/28",
305
- "20.210.211.192/28",
306
- "20.215.187.208/28",
307
- "20.215.188.192/28",
308
- "20.215.214.16/28",
309
- "20.215.219.128/28",
310
- "20.215.219.160/28",
311
- "20.215.219.208/28",
312
- "20.215.220.112/28",
313
- "20.215.220.128/28",
314
- "20.215.220.144/28",
315
- "20.215.220.160/28",
316
- "20.215.220.176/28",
317
- "20.215.220.192/28",
318
- "20.215.220.208/28",
319
- "20.215.220.64/28",
320
- "20.215.220.80/28",
321
- "20.215.220.96/28",
322
- "20.218.30.240/28",
323
- "20.219.71.192/28",
324
- "20.222.36.192/28",
325
- "20.226.32.80/28",
326
- "20.227.140.32/28",
327
- "20.228.106.176/28",
328
- "20.235.75.208/28",
329
- "20.235.87.224/28",
330
- "20.249.63.208/28",
331
- "20.25.151.224/28",
332
- "20.250.136.64/28",
333
- "20.250.136.80/28",
334
- "20.250.6.128/28",
335
- "20.27.94.128/28",
336
- "20.42.10.176/28",
337
- "20.45.178.144/28",
338
- "20.48.120.208/28",
339
- "20.52.125.160/28",
340
- "20.55.129.0/28",
341
- "20.55.229.144/28",
342
- "20.57.199.192/28",
343
- "20.63.180.96/28",
344
- "20.63.221.64/28",
345
- "20.79.59.112/28",
346
- "20.81.183.64/28",
347
- "20.83.243.176/28",
348
- "20.97.189.96/28",
349
- "23.102.140.144/28",
350
- "23.102.141.32/28",
351
- "23.98.142.176/28",
352
- "23.98.179.16/28",
353
- "23.98.186.176/28",
354
- "23.98.186.192/28",
355
- "23.98.186.64/28",
356
- "23.98.186.96/28",
357
- "4.151.119.48/28",
358
- "4.151.241.240/28",
359
- "4.151.71.176/28",
360
- "4.189.118.208/28",
361
- "4.189.119.48/28",
362
- "4.196.118.112/28",
363
- "4.197.115.112/28",
364
- "4.197.19.176/28",
365
- "4.197.22.112/28",
366
- "4.197.64.0/28",
367
- "4.197.64.16/28",
368
- "4.197.64.48/28",
369
- "4.197.64.64/28",
370
- "4.198.72.16/28",
371
- "4.198.96.112/28",
372
- "4.201.232.64/28",
373
- "4.201.232.80/28",
374
- "4.203.96.80/28",
375
- "4.205.128.176/28",
376
- "4.218.24.64/28",
377
- "4.226.200.16/28",
378
- "4.226.226.32/28",
379
- "4.227.36.0/25",
380
- "40.116.73.208/28",
381
- "40.122.235.112/28",
382
- "40.67.175.0/25",
383
- "40.67.183.160/28",
384
- "40.67.183.176/28",
385
- "40.78.161.48/28",
386
- "40.81.134.128/28",
387
- "40.81.134.144/28",
388
- "40.81.234.144/28",
389
- "40.81.67.96/28",
390
- "40.84.181.32/28",
391
- "40.84.221.208/28",
392
- "40.84.221.224/28",
393
- "40.90.214.16/28",
394
- "48.193.44.32/28",
395
- "48.221.184.112/28",
396
- "48.221.184.80/28",
397
- "48.221.184.96/28",
398
- "48.221.40.176/28",
399
- "51.107.70.192/28",
400
- "51.116.2.80/28",
401
- "51.116.221.96/28",
402
- "51.56.40.80/28",
403
- "51.57.0.96/28",
404
- "51.59.24.64/28",
405
- "51.59.24.80/28",
406
- "51.59.40.80/28",
407
- "51.59.40.96/28",
408
- "51.59.48.80/28",
409
- "51.59.48.96/28",
410
- "51.8.102.0/24",
411
- "51.8.155.112/28",
412
- "51.8.155.48/28",
413
- "51.8.155.64/28",
414
- "51.8.187.224/28",
415
- "52.148.129.32/28",
416
- "52.153.130.64/28",
417
- "52.154.22.48/28",
418
- "52.156.77.144/28",
419
- "52.159.227.32/28",
420
- "52.159.249.96/28",
421
- "52.161.49.224/28",
422
- "52.161.49.96/28",
423
- "52.165.212.16/28",
424
- "52.165.212.32/28",
425
- "52.165.212.48/28",
426
- "52.172.129.160/28",
427
- "52.172.251.112/28",
428
- "52.173.219.112/28",
429
- "52.173.219.96/28",
430
- "52.173.221.16/28",
431
- "52.173.221.176/28",
432
- "52.173.221.208/28",
433
- "52.173.234.16/28",
434
- "52.173.234.80/28",
435
- "52.173.235.80/28",
436
- "52.183.217.240/28",
437
- "52.187.246.128/28",
438
- "52.190.137.144/28",
439
- "52.190.137.16/28",
440
- "52.190.139.48/28",
441
- "52.190.142.64/28",
442
- "52.190.190.16/28",
443
- "52.225.75.208/28",
444
- "52.230.152.0/24",
445
- "52.230.163.32/28",
446
- "52.230.164.176/28",
447
- "52.231.30.48/28",
448
- "52.231.34.176/28",
449
- "52.231.39.144/28",
450
- "52.231.39.192/28",
451
- "52.231.49.48/28",
452
- "52.231.50.64/28",
453
- "52.236.94.144/28",
454
- "52.241.146.208/28",
455
- "52.242.132.224/28",
456
- "52.242.132.240/28",
457
- "52.242.245.208/28",
458
- "52.252.113.240/28",
459
- "52.255.109.112/28",
460
- "52.255.109.128/28",
461
- "52.255.109.144/28",
462
- "52.255.109.80/28",
463
- "52.255.109.96/28",
464
- "52.255.111.0/28",
465
- "52.255.111.112/28",
466
- "52.255.111.32/28",
467
- "52.255.111.48/28",
468
- "52.255.111.80/28",
469
- "57.154.174.112/28",
470
- "57.154.175.0/28",
471
- "57.154.187.32/28",
472
- "68.154.28.96/28",
473
- "68.218.30.112/28",
474
- "68.220.57.64/28",
475
- "68.221.67.192/28",
476
- "68.221.67.224/28",
477
- "68.221.67.240/28",
478
- "70.153.139.208/28",
479
- "70.153.189.192/28",
480
- "70.153.190.16/28",
481
- "70.153.76.16/28",
482
- "70.153.87.224/28",
483
- "70.156.144.64/28",
484
- "70.156.152.80/28",
485
- "70.156.152.96/28",
486
- "74.161.200.96/28",
487
- "74.224.217.64/28",
488
- "74.226.253.160/28",
489
- "74.249.86.176/28",
490
- "74.7.175.128/25",
491
- "74.7.227.0/25",
492
- "74.7.227.128/25",
493
- "74.7.228.0/25",
494
- "74.7.228.128/25",
495
- "74.7.229.0/25",
496
- "74.7.229.128/25",
497
- "74.7.230.0/25",
498
- "74.7.241.0/25",
499
- "74.7.241.128/25",
500
- "74.7.242.0/25",
501
- "74.7.242.128/25",
502
- "74.7.243.0/25",
503
- "74.7.243.128/25",
504
- "74.7.244.0/25",
505
- "74.7.35.112/28",
506
- "74.7.35.48/28",
507
- "74.7.36.64/28",
508
- "74.7.36.80/28",
509
- "74.7.36.96/28",
510
- "85.211.241.128/28",
511
- "9.129.0.0/17",
512
- "9.160.128.16/28",
513
- "9.160.128.32/28",
514
- "9.160.128.64/28",
515
- "9.160.163.128/28",
516
- "9.160.164.128/28",
517
- "9.160.34.144/28",
518
- "9.160.36.16/28",
519
- "9.160.96.16/28",
520
- "9.163.101.48/28",
521
- "9.205.25.128/28",
522
- "9.205.8.48/28",
523
- "9.223.181.208/28",
524
- "9.234.96.192/28",
525
- "9.234.97.128/28",
526
- "9.234.97.96/28",
527
- "9.235.40.32/28"
528
- ],
529
- Claude: [
530
- "136.107.176.208/32",
531
- "216.73.216.0/22",
532
- "34.11.34.31/32",
533
- "34.150.241.79/32",
534
- "34.162.191.81/32",
535
- "34.162.230.222/32",
536
- "34.162.244.71/32",
537
- "34.182.140.95/32",
538
- "34.182.161.143/32",
539
- "34.182.218.27/32",
540
- "34.182.220.85/32",
541
- "34.182.222.37/32",
542
- "34.182.225.167/32",
543
- "34.182.226.151/32",
544
- "34.182.226.221/32",
545
- "34.186.108.163/32",
546
- "34.85.172.162/32",
547
- "35.221.29.174/32",
548
- "35.245.175.129/32",
549
- "35.245.89.239/32"
550
- ],
551
- Perplexity: [
552
- "107.20.236.150/32",
553
- "18.210.92.235/32",
554
- "18.97.1.228/30",
555
- "18.97.9.96/29",
556
- "3.211.124.183/32",
557
- "3.222.232.239/32",
558
- "3.224.62.45/32",
559
- "3.231.139.107/32"
560
- ],
561
- Apple: [
562
- "17.22.237.0/24",
563
- "17.22.245.0/24",
564
- "17.22.253.0/24",
565
- "17.241.193.160/27",
566
- "17.241.200.160/27",
567
- "17.241.208.160/27",
568
- "17.241.219.0/24",
569
- "17.241.227.0/24",
570
- "17.241.75.0/24",
571
- "17.246.15.0/24",
572
- "17.246.19.0/24",
573
- "17.246.23.0/24"
574
- ]
575
- };
576
- var VERIFIABLE_VENDORS = Object.keys(BOT_IP_RANGES);
577
-
578
- // src/cidr.ts
579
- function ipv4ToInt(ip) {
580
- const parts = ip.split(".");
581
- if (parts.length !== 4) return null;
582
- let out = 0;
583
- for (const part of parts) {
584
- if (!/^\d{1,3}$/.test(part)) return null;
585
- if (part.length > 1 && part[0] === "0") return null;
586
- const n = Number(part);
587
- if (n > 255) return null;
588
- out = out << 8 | n;
589
- }
590
- return out >>> 0;
591
- }
592
- function ipv6ToBigInt(ip) {
593
- let text = ip;
594
- const zone = text.indexOf("%");
595
- if (zone !== -1) text = text.slice(0, zone);
596
- if (!text || text.indexOf(":") === -1) return null;
597
- let tail = null;
598
- const lastColon = text.lastIndexOf(":");
599
- const maybeV4 = text.slice(lastColon + 1);
600
- if (maybeV4.indexOf(".") !== -1) {
601
- tail = ipv4ToInt(maybeV4);
602
- if (tail === null) return null;
603
- text = text.slice(0, lastColon + 1) + "0:0";
604
- }
605
- const halves = text.split("::");
606
- if (halves.length > 2) return null;
607
- const head = halves[0] ? halves[0].split(":") : [];
608
- const rest = halves.length === 2 ? halves[1] ? halves[1].split(":") : [] : null;
609
- let groups;
610
- if (rest === null) {
611
- groups = head;
612
- if (groups.length !== 8) return null;
613
- } else {
614
- const fill = 8 - head.length - rest.length;
615
- if (fill < 0) return null;
616
- groups = [...head, ...Array(fill).fill("0"), ...rest];
617
- }
618
- let out = 0n;
619
- for (const g of groups) {
620
- if (!/^[0-9a-fA-F]{1,4}$/.test(g)) return null;
621
- out = out << 16n | BigInt(parseInt(g, 16));
622
- }
623
- if (tail !== null) out = out >> 32n << 32n | BigInt(tail >>> 0);
624
- return out;
625
- }
626
- function compileRanges(cidrs) {
627
- const v4 = [];
628
- const v6 = [];
629
- for (const cidr of cidrs) {
630
- const slash = cidr.lastIndexOf("/");
631
- if (slash === -1) continue;
632
- const addr = cidr.slice(0, slash);
633
- const bits = Number(cidr.slice(slash + 1));
634
- if (!Number.isInteger(bits) || bits < 0) continue;
635
- if (addr.indexOf(":") !== -1) {
636
- if (bits > 128) continue;
637
- const net = ipv6ToBigInt(addr);
638
- if (net === null) continue;
639
- v6.push({ net: bits === 0 ? 0n : net >> BigInt(128 - bits) << BigInt(128 - bits), bits });
640
- } else {
641
- if (bits > 32) continue;
642
- const net = ipv4ToInt(addr);
643
- if (net === null) continue;
644
- const mask = bits === 0 ? 0 : 4294967295 << 32 - bits >>> 0;
645
- v4.push({ net: (net & mask) >>> 0, mask });
646
- }
647
- }
648
- return { v4, v6 };
649
- }
650
- function ipInRanges(ip, ranges) {
651
- if (!ip) return false;
652
- const trimmed = ip.trim();
653
- if (!trimmed) return false;
654
- if (trimmed.indexOf(":") !== -1) {
655
- const value2 = ipv6ToBigInt(trimmed);
656
- if (value2 === null) return false;
657
- const V4_MAPPED_PREFIX = 0xffffn << 32n;
658
- if (value2 >> 32n === V4_MAPPED_PREFIX >> 32n) {
659
- const low = Number(value2 & 0xffffffffn) >>> 0;
660
- if (matchV4(low, ranges.v4)) return true;
661
- }
662
- for (const r of ranges.v6) {
663
- if (r.bits === 0) return true;
664
- if (value2 >> BigInt(128 - r.bits) << BigInt(128 - r.bits) === r.net) return true;
665
- }
666
- return false;
667
- }
668
- const value = ipv4ToInt(trimmed);
669
- if (value === null) return false;
670
- return matchV4(value, ranges.v4);
671
- }
672
- function matchV4(value, list) {
673
- for (const r of list) {
674
- if ((value & r.mask) >>> 0 === r.net) return true;
675
- }
676
- return false;
677
- }
678
- function ipInCidr(ip, cidr) {
679
- return ipInRanges(ip, compileRanges([cidr]));
680
- }
681
-
682
- // src/verify.ts
683
- var CLIENT_SIDE_AGENT_PATTERN = /claude-code|perplexity-user|cursor|windsurf|cline|aider/i;
684
- var SERVER_SIDE_CRAWLER_PATTERN = /ClaudeBot|Claude-SearchBot|GPTBot|OAI-SearchBot|ChatGPT-User|PerplexityBot|Applebot/i;
685
- var COMPILED = {};
686
- for (const vendor of VERIFIABLE_VENDORS) {
687
- COMPILED[vendor] = compileRanges(BOT_IP_RANGES[vendor] ?? []);
688
- }
689
- function verifiableVendors() {
690
- return VERIFIABLE_VENDORS;
691
- }
692
- function verifyBotIdentity(userAgent, ip) {
693
- const ua = userAgent ?? "";
694
- const claimed = parseBotName(userAgent);
695
- const ranges = COMPILED[claimed];
696
- if (!ranges) {
697
- const isKnownCrawler = claimed !== "Other" && claimed !== "Browser";
698
- return {
699
- verdict: isKnownCrawler ? "unverifiable" : "not-claimed",
700
- ...isKnownCrawler ? { reason: "no-published-ranges" } : {},
701
- claimed: isKnownCrawler ? claimed : null,
702
- verified: null
703
- };
704
- }
705
- if (CLIENT_SIDE_AGENT_PATTERN.test(ua) || !SERVER_SIDE_CRAWLER_PATTERN.test(ua)) {
706
- return {
707
- verdict: "unverifiable",
708
- reason: "client-side-agent",
709
- claimed,
710
- verified: null
711
- };
712
- }
713
- const trimmed = (ip ?? "").trim();
714
- if (!trimmed) {
715
- return { verdict: "unverifiable", reason: "no-client-ip", claimed, verified: null };
716
- }
717
- const inRange = ipInRanges(trimmed, ranges);
718
- return {
719
- verdict: inRange ? "verified" : "spoofed",
720
- claimed,
721
- verified: inRange
722
- };
723
- }
724
- function clientIpFromRequest(req) {
725
- const forwarded = req.headers.get("x-forwarded-for") || "";
726
- const first = forwarded.split(",")[0]?.trim();
727
- if (first) return first;
728
- return (req.headers.get("cf-connecting-ip") || req.headers.get("x-real-ip") || "").trim();
729
- }
730
- function verifyRequest(req) {
731
- return verifyBotIdentity(req.headers.get("user-agent"), clientIpFromRequest(req));
732
- }
733
-
734
- // src/hash.ts
735
- function hashId(input) {
736
- let h = 5381;
737
- for (let i = 0; i < input.length; i++) {
738
- h = (h << 5) + h + input.charCodeAt(i) & 4294967295;
739
- }
740
- return "anon_" + (h >>> 0).toString(16);
741
- }
742
-
743
- // src/track.ts
744
- async function trackVisit(req, opts) {
745
- const userAgent = req.headers.get("user-agent") || "";
746
- const onlyBots = opts.onlyBots ?? false;
747
- const skipBrowsers = opts.skipBrowsers ?? false;
748
- if (onlyBots && !isAiBot(userAgent)) return;
749
- if (skipBrowsers && !isAiBot(userAgent) && !isHttpClient(userAgent)) {
750
- if (!detectHeadless(req).likely) return;
751
- }
752
- let pathname = "/";
753
- let originFromUrl = "";
754
- try {
755
- const url = new URL(req.url);
756
- pathname = url.pathname;
757
- originFromUrl = url.origin;
758
- } catch {
759
- pathname = req.url || "/";
760
- }
761
- const origin = opts.origin ?? originFromUrl;
762
- const forwardedFor = req.headers.get("x-forwarded-for") || "";
763
- const ip = forwardedFor.split(",")[0]?.trim() ?? "";
764
- const referer = req.headers.get("referer");
765
- const country = opts.captureCountry ? req.headers.get("x-vercel-ip-country") || req.headers.get("cf-ipcountry") || req.headers.get("x-country-code") || null : null;
766
- const geo = opts.captureGeo ? extractGeo(req) : null;
767
- const classification = classifyRequest(req);
768
- const verification = opts.verifyIdentity ? verifyBotIdentity(userAgent, ip) : null;
769
- const event = {
770
- event: opts.eventName ?? "agent_visit",
771
- distinctId: hashId(`${ip}:${userAgent}`),
772
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
773
- properties: {
774
- $process_person_profile: false,
775
- $current_url: origin ? `${origin}${pathname}` : pathname,
776
- path: pathname,
777
- method: req.method,
778
- ...opts.captureCountry ? { country_code: country } : {},
779
- ...geo ?? {},
780
- ...opts.captureIp ? { client_ip: ip || null } : {},
781
- user_agent: userAgent,
782
- is_ai_bot: classification.isAiBot,
783
- bot_name: classification.label,
784
- ua_category: classification.kind,
785
- coding_agent_hint: classification.codingAgentHint,
786
- headless_score: classification.headless?.score ?? 0,
787
- headless_likely: classification.headless?.likely ?? false,
788
- ...verification ? {
789
- bot_verified: verification.verified,
790
- bot_verification: verification.verdict,
791
- ...verification.reason ? { bot_verification_reason: verification.reason } : {}
792
- } : {},
793
- referer,
794
- source: opts.source ?? null,
795
- ...opts.properties
796
- }
797
- };
798
- try {
799
- await opts.analytics.capture(event);
800
- } catch {
801
- }
802
- }
803
- function extractGeo(req) {
804
- const decode = (v) => {
805
- if (!v) return "";
806
- try {
807
- return decodeURIComponent(v);
808
- } catch {
809
- return v;
810
- }
811
- };
812
- const fields = [
813
- ["region", decode(req.headers.get("x-vercel-ip-country-region"))],
814
- ["city", decode(req.headers.get("x-vercel-ip-city"))],
815
- ["latitude", req.headers.get("x-vercel-ip-latitude") ?? ""],
816
- ["longitude", req.headers.get("x-vercel-ip-longitude") ?? ""],
817
- ["timezone", req.headers.get("x-vercel-ip-timezone") ?? ""]
818
- ];
819
- const out = {};
820
- for (const [k, v] of fields) if (v) out[k] = v;
821
- return out;
822
- }
823
-
824
- // src/adapters/posthog.ts
825
- function posthogAnalytics(config) {
826
- const hostRaw = config.host ?? "https://us.i.posthog.com";
827
- const base = (/^https?:\/\//.test(hostRaw) ? hostRaw : `https://${hostRaw}`).replace(/\/$/, "");
828
- const path = (config.path ?? "/i/v0/e/").replace(/^(?!\/)/, "/");
829
- const endpoint = `${base}${path}`;
830
- const fetchImpl = config.fetchImpl ?? fetch;
831
- return {
832
- async capture(event) {
833
- const payload = {
834
- api_key: config.apiKey,
835
- event: event.event,
836
- distinct_id: event.distinctId,
837
- timestamp: event.timestamp,
838
- properties: event.properties
839
- };
840
- await fetchImpl(endpoint, {
841
- method: "POST",
842
- headers: { "Content-Type": "application/json" },
843
- body: JSON.stringify(payload),
844
- keepalive: true
845
- });
846
- }
847
- };
848
- }
849
-
850
- // src/adapters/webhook.ts
851
- function webhookAnalytics(config) {
852
- const fetchImpl = config.fetchImpl ?? fetch;
853
- const transform = config.transform ?? ((e) => e);
854
- return {
855
- async capture(event) {
856
- await fetchImpl(config.url, {
857
- method: "POST",
858
- headers: {
859
- "Content-Type": "application/json",
860
- ...config.headers ?? {}
861
- },
862
- body: JSON.stringify(transform(event)),
863
- keepalive: true
864
- });
865
- }
866
- };
867
- }
868
-
869
- // src/adapters/custom.ts
870
- function customAnalytics(capture) {
871
- return { capture };
872
- }
873
-
874
- export { AI_BOT_PATTERN, BOT_IP_RANGES, BOT_RANGES_CAPTURED_AT, HTTP_CLIENT_PATTERN, VERIFIABLE_VENDORS, classifyAgent, classifyRequest, clientIpFromRequest, compileRanges, customAnalytics, detectHeadless, firstUserAgentProduct, hashId, ipInCidr, ipInRanges, isAiBot, isHttpClient, parseBotName, posthogAnalytics, trackVisit, verifiableVendors, verifyBotIdentity, verifyRequest, webhookAnalytics };
875
- //# sourceMappingURL=index.js.map
1
+ var C=/ClaudeBot|Claude-User|Claude-SearchBot|Claude-Web|Anthropic|GPTBot|ChatGPT-User|OAI-SearchBot|PerplexityBot|Perplexity-User|Google-Extended|Google-CloudVertexBot|Google-Agent|GoogleAgent-Mariner|Gemini-Deep-Research|Applebot|cohere|Bytespider|CCBot|Amazonbot|Amzn-SearchBot|NovaAct|AzureAI-SearchBot|Meta-ExternalAgent|meta-externalfetcher|meta-webindexer|FacebookBot|DuckAssistBot|MistralAI-User|YouBot|AI2Bot|Diffbot|DeepSeek|PanguBot|Webzio-Extended|omgili|Timpibot|Grok|Manus-User|quillbot|MyCentralAIScraperBot|Cursor|Windsurf/i,T=/axios\/|curl\/|(?:^|[\s(])got(?:\/|[\s(])|\bcolly\b|Electron\/|node-fetch\/|python-requests\/|Go-http-client\/|okhttp\/|aiohttp\/|Deno\//i;function d(t){return t?C.test(t):false}function g(t){return t?T.test(t):false}function S(t){if(!t||typeof t!="string")return "Other";let e=t.toLowerCase();return e.includes("chatgpt-user")||e.includes("gptbot")||e.includes("oai-searchbot")||e.includes("openai")?"ChatGPT":e.includes("claudebot")||e.includes("claude-user")||e.includes("claude-searchbot")||e.includes("claude-web")||e.includes("anthropic")?"Claude":e.includes("perplexitybot")||e.includes("perplexity-user")?"Perplexity":e.includes("ccbot")?"Common Crawl":e.includes("google-extended")||e.includes("googlebot")||e.includes("google-cloudvertexbot")||e.includes("google-agent")||e.includes("googleagent-mariner")||e.includes("gemini-deep-research")?"Google":e.includes("applebot")?"Apple":e.includes("bingbot")?"Bing":e.includes("bytespider")?"Bytespider":e.includes("amazonbot")||e.includes("amzn-searchbot")||e.includes("novaact")?"Amazon":e.includes("meta-externalagent")||e.includes("meta-externalfetcher")||e.includes("meta-webindexer")||e.includes("facebookbot")?"Meta":e.includes("mistralai-user")?"Mistral":e.includes("duckassistbot")?"DuckDuckGo":e.includes("youbot")?"You.com":e.includes("diffbot")?"Diffbot":e.includes("ai2bot")?"AI2":e.includes("cohere")?"Cohere":e.includes("cursor")?"Cursor":e.includes("windsurf")?"Windsurf":e.includes("deepseek")?"DeepSeek":e.includes("pangubot")?"Huawei":e.includes("webzio")||e.includes("omgili")?"Webz.io":e.includes("timpibot")?"Timpi":e.includes("grok")||e.includes("xai-")?"xAI":e.includes("manus-user")?"Manus":e.includes("quillbot")?"QuillBot":e.includes("azureai-searchbot")?"Microsoft":e.includes("mycentralaiscraperbot")?"MyCentralAI":e.includes("petalbot")?"PetalBot":e.includes("ahrefsbot")?"Ahrefs":e.includes("semrushbot")?"Semrush":e.includes("mj12bot")?"Majestic":e.includes("dotbot")||e.includes("rogerbot")?"Moz":e.includes("screaming frog")?"Screaming Frog":e.includes("sitebulb")?"Sitebulb":e.includes("linkfluence")?"Linkfluence":e.includes("dataforseo")?"DataForSEO":e.includes("serpstatbot")?"Serpstat":e.includes("uptimerobot")?"UptimeRobot":e.includes("pingdom")?"Pingdom":e.includes("statuscake")?"StatusCake":e.includes("newrelicpinger")?"New Relic":e.includes("datadogagent")||e.includes("datadog")?"Datadog":e.includes("slackbot")?"Slack":e.includes("twitterbot")?"Twitter":e.includes("linkedinbot")?"LinkedIn":e.includes("discordbot")?"Discord":e.includes("telegrambot")?"Telegram":e.includes("whatsapp")?"WhatsApp":e.includes("linkupbot")?"Linkup":e.includes("sogou")?"Sogou":e.includes("yandexbot")?"Yandex":e.includes("baiduspider")?"Baidu":e.includes("facebookexternalhit")?"Facebook":e.includes("com.apple.webkit")?"Apple URL Preview":e.includes("ohdear")?"Oh Dear":e.includes("scrapy")?"Scrapy":e.includes("headlesschrome")?"Headless Chrome":e.includes("phantomjs")?"PhantomJS":e.includes("wget")?"wget":e.includes("httpie")?"HTTPie":e.includes("guzzlehttp")?"Guzzle":e.includes("electron/")?"Electron":/curl\//.test(e)?"curl":/axios\//.test(e)?"axios":/(?:^|[\s(])got(?:\/|[\s(])/.test(e)?"got":/\bcolly\b/.test(e)?"colly":/node-fetch\//.test(e)?"node-fetch":/python-requests\//.test(e)?"python-requests":/go-http-client\//.test(e)?"Go http client":/okhttp\//.test(e)?"OkHttp":/aiohttp\//.test(e)?"aiohttp":/deno\//.test(e)?"Deno":e.includes("mozilla")||e.includes("chrome")||e.includes("safari")||e.includes("firefox")?"Browser":"Other"}function M(t){if(!t||typeof t!="string")return "Other";let e=t.match(/compatible;\s*([^/;\s]+)(?:\/[^\s;]*)?/i);return e&&e[1]?e[1].trim():t.trim().split("/")[0]?.trim().split(/\s+/)[0]?.trim()||"Other"}function h(t){let e=[],n=(t.headers.get("user-agent")||"").toLowerCase();if(!(n.includes("mozilla")||n.includes("chrome")||n.includes("safari")||n.includes("firefox")))return {score:0,signals:[],likely:false};t.headers.get("accept-language")||e.push("missing-accept-language"),t.headers.get("sec-fetch-mode")||e.push("missing-sec-fetch-mode");let r=t.headers.get("sec-ch-ua");r?r.toLowerCase().includes("headlesschrome")&&e.push("headless-chrome-hint"):e.push("missing-sec-ch-ua");let i=t.headers.get("accept")||"";(!i||i==="*/*")&&e.push("missing-or-bare-accept"),(t.headers.get("connection")||"").toLowerCase()==="close"&&e.push("connection-close");let o=e.length;return {score:o,signals:e,likely:o>=2}}function v(t){let e=S(t),n=d(t),s=g(t),r;return n?r="declared-crawler":s?r="coding-agent-hint":e==="Browser"?r="browser":r="other",{kind:r,label:e,isAiBot:n,codingAgentHint:s}}function m(t){let e=t.headers.get("user-agent")||"",n=v(e),s=h(t),r=n.kind,i=n.label;return r==="browser"&&s.likely&&(r="headless-likely",i="Headless"),{...n,kind:r,label:i,headless:s}}var f=class extends Error{constructor(e){super(e),this.name="HashSecretError";}};function y(){let t=globalThis.crypto;if(!t?.subtle)throw new f("Web Crypto is unavailable. agent-analytics requires Node >= 20, or any runtime exposing globalThis.crypto.subtle (Vercel Edge, Cloudflare Workers, Deno, browsers).");return t.subtle}var B=new Map;function z(t){let e=B.get(t);return e||(e=y().importKey("raw",new TextEncoder().encode(t),{name:"HMAC",hash:"SHA-256"},false,["sign"]),B.set(t,e)),e}async function b(t,e){if(typeof e!="string"||e.length===0)throw new f("hashId requires a non-empty secret");let n=await y().sign("HMAC",await z(e),new TextEncoder().encode(t)),s=new Uint8Array(n,0,8),r="";for(let i of s)r+=i.toString(16).padStart(2,"0");return "anon_"+r}function A(){let t=new Uint8Array(32);y(),globalThis.crypto.getRandomValues(t);let e="";for(let n of t)e+=n.toString(16).padStart(2,"0");return e}var x,E=false;function N(t){if(t)return t;let e=typeof process<"u"?process.env?.AGENT_ANALYTICS_ID_SECRET:void 0;return e||(x||(x=A(),E||(E=true,console.warn("[agent-analytics] No idSecret or AGENT_ANALYTICS_ID_SECRET set. Using a per-instance random secret: distinctIds will not correlate across instances or deploys."))),x)}async function G(t,e){let n=t.headers.get("user-agent")||"",s=e.onlyBots??false,r=e.skipBrowsers??false;if(!(s&&!d(n))&&!(r&&!d(n)&&!g(n)&&!h(t).likely))try{let i="/",o="";try{let w=new URL(t.url);i=w.pathname,o=w.origin;}catch{i=t.url||"/";}let p=e.origin??o,k=(t.headers.get("x-forwarded-for")||"").split(",")[0]?.trim()??"",_=t.headers.get("referer"),I=e.captureCountry&&(t.headers.get("x-vercel-ip-country")||t.headers.get("cf-ipcountry")||t.headers.get("x-country-code"))||null,P=e.captureGeo?O(t):null,a=m(t),l=e.verify?e.verify(t):null,H=a.kind==="headless-likely"||a.kind==="browser",R=await b(`${k}:${n}`,N(e.idSecret)),D={event:e.eventName??"agent_visit",distinctId:R,timestamp:new Date().toISOString(),properties:{...e.properties,$process_person_profile:!1,$current_url:p?`${p}${i}`:i,path:i,method:t.method,...e.captureCountry?{country_code:I}:{},...P??{},...e.captureIp?{client_ip:k||null}:{},user_agent:n,is_ai_bot:a.isAiBot,bot_name:a.label,ua_category:a.kind,coding_agent_hint:a.codingAgentHint,...H?{headless_score:a.headless?.score??0,headless_likely:a.headless?.likely??!1}:{},...l?{bot_verified:l.verified,bot_verification:l.verdict,...l.reason?{bot_verification_reason:l.reason}:{}}:{},referer:_,source:e.source??null}};await e.analytics.capture(D);}catch(i){e.onError?.(i instanceof Error?i:new Error(String(i)));}}function O(t){let e=r=>{if(!r)return "";try{return decodeURIComponent(r)}catch{return r}},n=[["region",e(t.headers.get("x-vercel-ip-country-region"))],["city",e(t.headers.get("x-vercel-ip-city"))],["latitude",t.headers.get("x-vercel-ip-latitude")??""],["longitude",t.headers.get("x-vercel-ip-longitude")??""],["timezone",t.headers.get("x-vercel-ip-timezone")??""]],s={};for(let[r,i]of n)i&&(s[r]=i);return s}var c=class extends Error{status;body;constructor(e,n,s){super(e),this.name="CaptureTransportError",this.status=n,this.body=s;}};function U(t){let e=t.host??"https://us.i.posthog.com",n=(/^https?:\/\//.test(e)?e:`https://${e}`).replace(/\/$/,""),s=(t.path??"/i/v0/e/").replace(/^(?!\/)/,"/"),r=`${n}${s}`,i=t.fetchImpl??fetch;return {async capture(o){let p={api_key:t.apiKey,event:o.event,distinct_id:o.distinctId,timestamp:o.timestamp,properties:o.properties},u=await i(r,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(p),keepalive:true,signal:AbortSignal.timeout(t.timeoutMs??3e3)});if(!u.ok)throw new c(`PostHog capture failed: ${u.status} ${u.statusText}`,u.status,await u.text().catch(()=>{}))}}}function L(t){let e=t.fetchImpl??fetch,n=t.transform??(s=>s);return {async capture(s){let r=await e(t.url,{method:"POST",headers:{"Content-Type":"application/json",...t.headers??{}},body:JSON.stringify(n(s)),keepalive:true,signal:AbortSignal.timeout(t.timeoutMs??3e3)});if(!r.ok)throw new c(`Webhook capture failed: ${r.status} ${r.statusText}`,r.status,await r.text().catch(()=>{}))}}}function $(t){return {capture:t}}
2
+ export{C as AI_BOT_PATTERN,c as CaptureTransportError,T as HTTP_CLIENT_PATTERN,f as HashSecretError,v as classifyAgent,m as classifyRequest,$ as customAnalytics,h as detectHeadless,M as firstUserAgentProduct,b as hashId,d as isAiBot,g as isHttpClient,S as parseBotName,U as posthogAnalytics,A as randomSecret,G as trackVisit,L as webhookAnalytics};//# sourceMappingURL=index.js.map
876
3
  //# sourceMappingURL=index.js.map