@apideck/agent-analytics 0.11.0 → 0.13.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 +102 -92
- package/dist/index.d.ts +102 -92
- 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,11 @@
|
|
|
1
|
-
import { T as TrackVisitOptions, C as CaptureEvent, A as AnalyticsAdapter } from './types-
|
|
1
|
+
import { T as TrackVisitOptions, B as BotVerificationLike, C as CaptureEvent, A as AnalyticsAdapter } from './types-sQoQK-ox.js';
|
|
2
2
|
export { posthogAnalytics } from './adapters/posthog.js';
|
|
3
3
|
export { webhookAnalytics } from './adapters/webhook.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Capture an event describing the incoming request. Fire-and-forget: awaits
|
|
7
|
-
*
|
|
8
|
-
* the response path. Callers typically don't await
|
|
6
|
+
* Capture an event describing the incoming request. Fire-and-forget: awaits the
|
|
7
|
+
* adapter but routes errors to {@link TrackVisitOptions.onError} rather than
|
|
8
|
+
* letting them reach the response path. Callers typically don't await it.
|
|
9
9
|
*
|
|
10
10
|
* By default, captures every request so coding-agent traffic (axios, curl,
|
|
11
11
|
* Electron, …) shows up alongside branded crawlers. Set `onlyBots: true` to
|
|
@@ -131,110 +131,120 @@ declare function classifyAgent(userAgent: string | null | undefined): AgentClass
|
|
|
131
131
|
declare function classifyRequest(req: Request): AgentClassification;
|
|
132
132
|
|
|
133
133
|
/**
|
|
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.
|
|
134
|
+
* Keyed, non-reversible anonymous identifiers.
|
|
144
135
|
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
* finding.
|
|
136
|
+
* The previous implementation was an unsalted 32-bit djb2 over `ip:userAgent`.
|
|
137
|
+
* Because the user agent is emitted in plaintext on the same event, an attacker
|
|
138
|
+
* held half the preimage and only had to search the IPv4 space — recovering a
|
|
139
|
+
* residential IP took 75 seconds single-threaded. That is pseudonymisation, not
|
|
140
|
+
* anonymisation, and it does not survive GDPR Recital 26.
|
|
141
|
+
*
|
|
142
|
+
* This uses HMAC-SHA-256 with a caller-supplied secret, truncated to 64 bits.
|
|
143
|
+
* Web Crypto is available on Vercel Edge, Cloudflare Workers, Deno and Node 18+.
|
|
154
144
|
*/
|
|
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;
|
|
145
|
+
/** Thrown when a secret is missing or unusable. */
|
|
146
|
+
declare class HashSecretError extends Error {
|
|
147
|
+
constructor(message: string);
|
|
170
148
|
}
|
|
171
|
-
/** Vendor labels this build can produce a verified/spoofed verdict for. */
|
|
172
|
-
declare function verifiableVendors(): readonly string[];
|
|
173
149
|
/**
|
|
174
|
-
*
|
|
150
|
+
* Hash `input` under `secret`, returning `anon_` followed by 16 hex characters
|
|
151
|
+
* (64 bits — collision-free well past any realistic distinct-visitor count).
|
|
175
152
|
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
153
|
+
* The secret must be stable across instances for identifiers to be comparable
|
|
154
|
+
* over time, and secret from anyone who can read your events: publishing it
|
|
155
|
+
* makes the identifier exactly as reversible as the old implementation was.
|
|
156
|
+
* Rotating it deliberately breaks continuity, which is correct behaviour for a
|
|
157
|
+
* privacy-preserving id.
|
|
180
158
|
*/
|
|
181
|
-
declare function
|
|
159
|
+
declare function hashId(input: string, secret: string): Promise<string>;
|
|
182
160
|
/**
|
|
183
|
-
*
|
|
184
|
-
*
|
|
161
|
+
* Generate a random secret. Used as the default when none is configured, so the
|
|
162
|
+
* privacy-preserving path is the one you get by doing nothing. Identifiers are
|
|
163
|
+
* then only stable within a single instance's lifetime — set a real secret when
|
|
164
|
+
* you need them comparable across instances and over time.
|
|
185
165
|
*/
|
|
186
|
-
declare function
|
|
187
|
-
|
|
188
|
-
|
|
166
|
+
declare function randomSecret(): string;
|
|
167
|
+
|
|
168
|
+
/** Thrown when the analytics backend rejects, errors, or times out a capture. */
|
|
169
|
+
declare class CaptureTransportError extends Error {
|
|
170
|
+
readonly status: number | undefined;
|
|
171
|
+
readonly body: string | undefined;
|
|
172
|
+
constructor(message: string, status?: number, body?: string);
|
|
173
|
+
}
|
|
189
174
|
|
|
190
175
|
/**
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
* GENERATED FILE — do not edit by hand. Regenerate with:
|
|
176
|
+
* What to do with an agent request.
|
|
194
177
|
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
178
|
+
* - `'allow'` — serve it, free. Humans, search crawlers, and the retrieval
|
|
179
|
+
* agents you *want* reading your site.
|
|
180
|
+
* - `'meter'` — serve it, but count it as billable. Bulk corpus collection.
|
|
181
|
+
* - `'charge'` — don't serve it until it pays (HTTP 402).
|
|
182
|
+
* - `'block'` — refuse. Failed identity verification, mostly.
|
|
183
|
+
*/
|
|
184
|
+
type AgentAction = 'allow' | 'meter' | 'charge' | 'block';
|
|
185
|
+
/**
|
|
186
|
+
* Why an agent fetched the page. This is the distinction the whole module
|
|
187
|
+
* exists for, and no other signal on the request carries it.
|
|
203
188
|
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
189
|
+
* - `'retrieval'` — a person asked a question and the assistant went to read
|
|
190
|
+
* the page for them. This is *demand*: the agent is a distribution channel,
|
|
191
|
+
* and charging for it is charging for your own marketing.
|
|
192
|
+
* - `'training'` — bulk corpus collection for model training. You get nothing
|
|
193
|
+
* back per fetch, which is where a price makes sense.
|
|
194
|
+
* - `'search'` — classic index crawlers. Blocking these costs you SEO.
|
|
195
|
+
* - `'tooling'` — coding agents and HTTP clients. Usually developers using
|
|
196
|
+
* your docs; treat like retrieval unless you see abuse.
|
|
197
|
+
* - `'unknown'` — everything else, including real browsers.
|
|
209
198
|
*/
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
interface V6Range {
|
|
221
|
-
net: bigint;
|
|
222
|
-
bits: number;
|
|
199
|
+
type AgentIntent = 'retrieval' | 'training' | 'search' | 'tooling' | 'unknown';
|
|
200
|
+
interface AgentDecision {
|
|
201
|
+
action: AgentAction;
|
|
202
|
+
intent: AgentIntent;
|
|
203
|
+
/** Vendor label, same string `parseBotName` returns. */
|
|
204
|
+
label: string;
|
|
205
|
+
/** Identity verdict, when a verifier was supplied. */
|
|
206
|
+
verification?: string;
|
|
207
|
+
/** Short human-readable justification — log it, don't parse it. */
|
|
208
|
+
reason: string;
|
|
223
209
|
}
|
|
224
|
-
interface
|
|
225
|
-
|
|
226
|
-
|
|
210
|
+
interface AgentPolicyOptions {
|
|
211
|
+
/**
|
|
212
|
+
* Identity verifier. Import `verifyRequest` from
|
|
213
|
+
* `@apideck/agent-analytics/verify` and pass it here to have a `spoofed`
|
|
214
|
+
* verdict produce `'block'`.
|
|
215
|
+
*
|
|
216
|
+
* Injected rather than imported so the published IP range tables only reach
|
|
217
|
+
* bundles that use them. Only meaningful when your edge controls
|
|
218
|
+
* `x-forwarded-for`: behind a proxy that forwards a client-supplied header,
|
|
219
|
+
* an attacker picks their own verdict.
|
|
220
|
+
*/
|
|
221
|
+
verify?: (req: Request) => BotVerificationLike;
|
|
222
|
+
/** What to do with bulk training crawlers. Defaults to `'meter'`. */
|
|
223
|
+
onTraining?: AgentAction;
|
|
224
|
+
/** What to do with retrieval agents. Defaults to `'allow'` — see AgentIntent. */
|
|
225
|
+
onRetrieval?: AgentAction;
|
|
226
|
+
/** What to do with search indexers. Defaults to `'allow'`. */
|
|
227
|
+
onSearch?: AgentAction;
|
|
228
|
+
/** What to do with coding agents and HTTP clients. Defaults to `'allow'`. */
|
|
229
|
+
onTooling?: AgentAction;
|
|
230
|
+
/** Vendor labels or UA substrings always allowed, whatever the intent. */
|
|
231
|
+
allowList?: readonly string[];
|
|
227
232
|
}
|
|
233
|
+
/** Classify why an agent is here, from its user agent alone. */
|
|
234
|
+
declare function agentIntent(userAgent: string | null | undefined): AgentIntent;
|
|
228
235
|
/**
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
236
|
+
* Decide what to do with a request. Pure classification plus policy — no
|
|
237
|
+
* payment rails, no network calls, nothing to configure beyond the four
|
|
238
|
+
* intent knobs.
|
|
239
|
+
*
|
|
240
|
+
* @example
|
|
241
|
+
* ```ts
|
|
242
|
+
* const decision = agentPolicy(req, { verify: true, onTraining: 'charge' })
|
|
243
|
+
* if (decision.action === 'block') return new Response(null, { status: 403 })
|
|
244
|
+
* if (decision.action === 'charge') return paymentRequired(decision)
|
|
245
|
+
* ```
|
|
232
246
|
*/
|
|
233
|
-
declare function
|
|
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;
|
|
247
|
+
declare function agentPolicy(req: Request, opts?: AgentPolicyOptions): AgentDecision;
|
|
238
248
|
|
|
239
249
|
/**
|
|
240
250
|
* Escape hatch for wiring a callback directly as an analytics adapter.
|
|
@@ -248,4 +258,4 @@ declare function ipInCidr(ip: string, cidr: string): boolean;
|
|
|
248
258
|
*/
|
|
249
259
|
declare function customAnalytics(capture: (event: CaptureEvent) => Promise<void> | void): AnalyticsAdapter;
|
|
250
260
|
|
|
251
|
-
export { AI_BOT_PATTERN, type
|
|
261
|
+
export { AI_BOT_PATTERN, type AgentAction, type AgentClassification, type AgentDecision, type AgentIntent, type AgentKind, type AgentPolicyOptions, AnalyticsAdapter, BotVerificationLike, CaptureEvent, CaptureTransportError, HTTP_CLIENT_PATTERN, HashSecretError, type HeadlessDetection, TrackVisitOptions, agentIntent, agentPolicy, classifyAgent, classifyRequest, customAnalytics, detectHeadless, firstUserAgentProduct, hashId, isAiBot, isHttpClient, parseBotName, randomSecret, trackVisit };
|