@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/README.md +56 -0
- package/dist/adapters/posthog.cjs +2 -30
- package/dist/adapters/posthog.cjs.map +1 -1
- package/dist/adapters/posthog.d.cts +7 -1
- package/dist/adapters/posthog.d.ts +7 -1
- package/dist/adapters/posthog.js +2 -28
- package/dist/adapters/posthog.js.map +1 -1
- package/dist/adapters/webhook.cjs +1 -23
- package/dist/adapters/webhook.cjs.map +1 -1
- package/dist/adapters/webhook.d.cts +3 -1
- package/dist/adapters/webhook.d.ts +3 -1
- package/dist/adapters/webhook.js +1 -21
- package/dist/adapters/webhook.js.map +1 -1
- package/dist/index.cjs +2 -900
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -100
- package/dist/index.d.ts +37 -100
- package/dist/index.js +2 -875
- package/dist/index.js.map +1 -1
- package/dist/markdown.cjs +2 -67
- package/dist/markdown.cjs.map +1 -1
- package/dist/markdown.js +2 -63
- package/dist/markdown.js.map +1 -1
- package/dist/{types-DKqlfVz6.d.cts → types-sQoQK-ox.d.cts} +31 -2
- package/dist/{types-DKqlfVz6.d.ts → types-sQoQK-ox.d.ts} +31 -2
- package/dist/verify.cjs +3 -0
- package/dist/verify.cjs.map +1 -0
- package/dist/verify.d.cts +50 -0
- package/dist/verify.d.ts +50 -0
- package/dist/verify.js +3 -0
- package/dist/verify.js.map +1 -0
- package/package.json +7 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { T as TrackVisitOptions, C as CaptureEvent, A as AnalyticsAdapter } from './types-
|
|
1
|
+
import { T as TrackVisitOptions, C as CaptureEvent, A as AnalyticsAdapter } from './types-sQoQK-ox.js';
|
|
2
|
+
export { B as BotVerificationLike } from './types-sQoQK-ox.js';
|
|
2
3
|
export { posthogAnalytics } from './adapters/posthog.js';
|
|
3
4
|
export { webhookAnalytics } from './adapters/webhook.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
|
-
* Capture an event describing the incoming request. Fire-and-forget: awaits
|
|
7
|
-
*
|
|
8
|
-
* the response path. Callers typically don't await
|
|
7
|
+
* Capture an event describing the incoming request. Fire-and-forget: awaits the
|
|
8
|
+
* adapter but routes errors to {@link TrackVisitOptions.onError} rather than
|
|
9
|
+
* letting them reach the response path. Callers typically don't await it.
|
|
9
10
|
*
|
|
10
11
|
* By default, captures every request so coding-agent traffic (axios, curl,
|
|
11
12
|
* Electron, …) shows up alongside branded crawlers. Set `onlyBots: true` to
|
|
@@ -131,110 +132,46 @@ declare function classifyAgent(userAgent: string | null | undefined): AgentClass
|
|
|
131
132
|
declare function classifyRequest(req: Request): AgentClassification;
|
|
132
133
|
|
|
133
134
|
/**
|
|
134
|
-
*
|
|
135
|
-
* build stable anonymous distinct-ids from `ip:ua:...` tuples without
|
|
136
|
-
* collecting identifying data. Not cryptographic — collisions are fine for
|
|
137
|
-
* analytics segmentation.
|
|
138
|
-
*/
|
|
139
|
-
declare function hashId(input: string): string;
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Verdict on whether a request's claimed crawler identity holds up against the
|
|
143
|
-
* vendor's published IP ranges.
|
|
135
|
+
* Keyed, non-reversible anonymous identifiers.
|
|
144
136
|
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
* finding.
|
|
137
|
+
* The previous implementation was an unsalted 32-bit djb2 over `ip:userAgent`.
|
|
138
|
+
* Because the user agent is emitted in plaintext on the same event, an attacker
|
|
139
|
+
* held half the preimage and only had to search the IPv4 space — recovering a
|
|
140
|
+
* residential IP took 75 seconds single-threaded. That is pseudonymisation, not
|
|
141
|
+
* anonymisation, and it does not survive GDPR Recital 26.
|
|
142
|
+
*
|
|
143
|
+
* This uses HMAC-SHA-256 with a caller-supplied secret, truncated to 64 bits.
|
|
144
|
+
* Web Crypto is available on Vercel Edge, Cloudflare Workers, Deno and Node 18+.
|
|
154
145
|
*/
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
interface BotVerification {
|
|
159
|
-
verdict: VerificationVerdict;
|
|
160
|
-
reason?: UnverifiableReason;
|
|
161
|
-
/** Vendor label the UA claims, when it claims one. */
|
|
162
|
-
claimed: string | null;
|
|
163
|
-
/**
|
|
164
|
-
* Convenience boolean for filtering: `true` only for `'verified'`, `false`
|
|
165
|
-
* only for `'spoofed'`, `null` when no judgement was possible. Deliberately
|
|
166
|
-
* tri-state — collapsing "unverifiable" into `false` would brand every
|
|
167
|
-
* Bytespider and Amazonbot hit an impostor.
|
|
168
|
-
*/
|
|
169
|
-
verified: boolean | null;
|
|
146
|
+
/** Thrown when a secret is missing or unusable. */
|
|
147
|
+
declare class HashSecretError extends Error {
|
|
148
|
+
constructor(message: string);
|
|
170
149
|
}
|
|
171
|
-
/** Vendor labels this build can produce a verified/spoofed verdict for. */
|
|
172
|
-
declare function verifiableVendors(): readonly string[];
|
|
173
150
|
/**
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
151
|
+
* Hash `input` under `secret`, returning `anon_` followed by 16 hex characters
|
|
152
|
+
* (64 bits — collision-free well past any realistic distinct-visitor count).
|
|
153
|
+
*
|
|
154
|
+
* The secret must be stable across instances for identifiers to be comparable
|
|
155
|
+
* over time, and secret from anyone who can read your events: publishing it
|
|
156
|
+
* makes the identifier exactly as reversible as the old implementation was.
|
|
157
|
+
* Rotating it deliberately breaks continuity, which is correct behaviour for a
|
|
158
|
+
* privacy-preserving id.
|
|
180
159
|
*/
|
|
181
|
-
declare function
|
|
160
|
+
declare function hashId(input: string, secret: string): Promise<string>;
|
|
182
161
|
/**
|
|
183
|
-
*
|
|
184
|
-
*
|
|
162
|
+
* Generate a random secret. Used as the default when none is configured, so the
|
|
163
|
+
* privacy-preserving path is the one you get by doing nothing. Identifiers are
|
|
164
|
+
* then only stable within a single instance's lifetime — set a real secret when
|
|
165
|
+
* you need them comparable across instances and over time.
|
|
185
166
|
*/
|
|
186
|
-
declare function
|
|
187
|
-
/** Verify straight from a request object. */
|
|
188
|
-
declare function verifyRequest(req: Request): BotVerification;
|
|
167
|
+
declare function randomSecret(): string;
|
|
189
168
|
|
|
190
|
-
/**
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
* node scripts/refresh-bot-ranges.mjs
|
|
196
|
-
*
|
|
197
|
-
* Keys match the labels {@link parseBotName} returns, so a claimed identity
|
|
198
|
-
* maps to its range list without a translation table.
|
|
199
|
-
*
|
|
200
|
-
* Only vendors that publish a machine-readable feed appear here. A vendor's
|
|
201
|
-
* absence means "cannot be verified", never "not a real bot" — see
|
|
202
|
-
* {@link verifyBotIdentity} for how that distinction is surfaced.
|
|
203
|
-
*
|
|
204
|
-
* Freshness is the whole ballgame: these lists rotate. Almost every OpenAI
|
|
205
|
-
* prefix is an Azure block and every Anthropic prefix is GCP or similar, so
|
|
206
|
-
* "came from a datacenter" proves nothing on its own — only membership in the
|
|
207
|
-
* current published list does. A stale snapshot produces false 'spoofed'
|
|
208
|
-
* verdicts on legitimate crawlers, which is the failure mode to fear.
|
|
209
|
-
*/
|
|
210
|
-
/** When these ranges were captured from the vendor feeds (UTC). */
|
|
211
|
-
declare const BOT_RANGES_CAPTURED_AT = "2026-08-02T00:00:00Z";
|
|
212
|
-
declare const BOT_IP_RANGES: Readonly<Record<string, readonly string[]>>;
|
|
213
|
-
/** Vendor labels this build can verify. Anything else yields a null verdict. */
|
|
214
|
-
declare const VERIFIABLE_VENDORS: readonly string[];
|
|
215
|
-
|
|
216
|
-
interface V4Range {
|
|
217
|
-
net: number;
|
|
218
|
-
mask: number;
|
|
169
|
+
/** Thrown when the analytics backend rejects, errors, or times out a capture. */
|
|
170
|
+
declare class CaptureTransportError extends Error {
|
|
171
|
+
readonly status: number | undefined;
|
|
172
|
+
readonly body: string | undefined;
|
|
173
|
+
constructor(message: string, status?: number, body?: string);
|
|
219
174
|
}
|
|
220
|
-
interface V6Range {
|
|
221
|
-
net: bigint;
|
|
222
|
-
bits: number;
|
|
223
|
-
}
|
|
224
|
-
interface CompiledRanges {
|
|
225
|
-
v4: V4Range[];
|
|
226
|
-
v6: V6Range[];
|
|
227
|
-
}
|
|
228
|
-
/**
|
|
229
|
-
* Pre-compile a list of CIDR strings into numeric form. Invalid entries are
|
|
230
|
-
* dropped rather than thrown — a malformed line in a vendor's published feed
|
|
231
|
-
* shouldn't take down the whole check.
|
|
232
|
-
*/
|
|
233
|
-
declare function compileRanges(cidrs: readonly string[]): CompiledRanges;
|
|
234
|
-
/** True when `ip` falls inside any range in the pre-compiled set. */
|
|
235
|
-
declare function ipInRanges(ip: string, ranges: CompiledRanges): boolean;
|
|
236
|
-
/** Convenience wrapper — compiles on every call, so prefer {@link ipInRanges}. */
|
|
237
|
-
declare function ipInCidr(ip: string, cidr: string): boolean;
|
|
238
175
|
|
|
239
176
|
/**
|
|
240
177
|
* Escape hatch for wiring a callback directly as an analytics adapter.
|
|
@@ -248,4 +185,4 @@ declare function ipInCidr(ip: string, cidr: string): boolean;
|
|
|
248
185
|
*/
|
|
249
186
|
declare function customAnalytics(capture: (event: CaptureEvent) => Promise<void> | void): AnalyticsAdapter;
|
|
250
187
|
|
|
251
|
-
export { AI_BOT_PATTERN, type AgentClassification, type AgentKind, AnalyticsAdapter,
|
|
188
|
+
export { AI_BOT_PATTERN, type AgentClassification, type AgentKind, AnalyticsAdapter, CaptureEvent, CaptureTransportError, HTTP_CLIENT_PATTERN, HashSecretError, type HeadlessDetection, TrackVisitOptions, classifyAgent, classifyRequest, customAnalytics, detectHeadless, firstUserAgentProduct, hashId, isAiBot, isHttpClient, parseBotName, randomSecret, trackVisit };
|