devn-bot-detector-core 0.1.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 ADDED
@@ -0,0 +1,497 @@
1
+ // src/constants.ts
2
+ var DEFAULT_SESSION_DURATION_MS = 30 * 60 * 1e3;
3
+ var DEFAULT_TELEMETRY_INTERVAL_MS = 5e3;
4
+ var MAX_TELEMETRY_BYTES = 32 * 1024;
5
+ var DEFAULT_RISK_TOKEN_DURATION_MS = 5 * 60 * 1e3;
6
+ var TELEMETRY_VERSION = 1;
7
+ var SITE_KEY_HEADER = "X-Bot-Site-Key";
8
+ var API_PATHS = {
9
+ session: "/v1/session",
10
+ analyze: "/v1/analyze"
11
+ };
12
+ var DEFAULT_RISK_THRESHOLDS = {
13
+ allow: 70,
14
+ monitor: 50,
15
+ challenge: 30
16
+ };
17
+ var ERROR_CODES = [
18
+ "INVALID_SITE_KEY",
19
+ "INVALID_HOSTNAME",
20
+ "INVALID_SESSION",
21
+ "SESSION_EXPIRED",
22
+ "INVALID_NONCE",
23
+ "INVALID_SEQUENCE",
24
+ "RATE_LIMITED",
25
+ "INVALID_TELEMETRY",
26
+ "MALFORMED_REQUEST",
27
+ "INTERNAL_ERROR",
28
+ "IP_BLOCKED",
29
+ "TOKEN_ALREADY_USED",
30
+ "ACTION_MISMATCH"
31
+ ];
32
+
33
+ // src/errors.ts
34
+ var BotDetectorError = class extends Error {
35
+ constructor(code, message, requestId) {
36
+ super(message);
37
+ this.name = "BotDetectorError";
38
+ this.code = code;
39
+ this.requestId = requestId;
40
+ }
41
+ toJSON() {
42
+ return {
43
+ error: {
44
+ code: this.code,
45
+ message: this.message,
46
+ requestId: this.requestId
47
+ }
48
+ };
49
+ }
50
+ };
51
+ function isBotDetectorError(value) {
52
+ return value instanceof BotDetectorError;
53
+ }
54
+
55
+ // src/utils.ts
56
+ function clamp(value, min, max) {
57
+ return Math.min(max, Math.max(min, value));
58
+ }
59
+ function decisionFromScore(score, thresholds = DEFAULT_RISK_THRESHOLDS) {
60
+ if (score >= thresholds.allow) return "allow";
61
+ if (score >= thresholds.monitor) return "monitor";
62
+ if (score >= thresholds.challenge) return "challenge";
63
+ return "block";
64
+ }
65
+ function riskLevelFromScore(score) {
66
+ if (score >= 70) return "low";
67
+ if (score >= 40) return "medium";
68
+ return "high";
69
+ }
70
+ function mergeRiskThresholds(partial) {
71
+ return {
72
+ allow: partial?.allow ?? DEFAULT_RISK_THRESHOLDS.allow,
73
+ monitor: partial?.monitor ?? DEFAULT_RISK_THRESHOLDS.monitor,
74
+ challenge: partial?.challenge ?? DEFAULT_RISK_THRESHOLDS.challenge
75
+ };
76
+ }
77
+ function isPlainObject(value) {
78
+ return typeof value === "object" && value !== null && !Array.isArray(value);
79
+ }
80
+ function utf8ByteLength(value) {
81
+ if (typeof TextEncoder !== "undefined") {
82
+ return new TextEncoder().encode(value).length;
83
+ }
84
+ let bytes = 0;
85
+ for (let i = 0; i < value.length; i++) {
86
+ const code = value.charCodeAt(i);
87
+ if (code < 128) bytes += 1;
88
+ else if (code < 2048) bytes += 2;
89
+ else if (code >= 55296 && code <= 56319) {
90
+ bytes += 4;
91
+ i++;
92
+ } else bytes += 3;
93
+ }
94
+ return bytes;
95
+ }
96
+ function normalizeHostname(hostname) {
97
+ return hostname.trim().toLowerCase().replace(/\.$/, "");
98
+ }
99
+ function hostnameAllowed(hostname, allowedDomains) {
100
+ const host = normalizeHostname(hostname);
101
+ if (!host) return false;
102
+ for (const raw of allowedDomains) {
103
+ const allowed = normalizeHostname(raw);
104
+ if (!allowed) continue;
105
+ if (host === allowed) return true;
106
+ if (host.endsWith(`.${allowed}`)) return true;
107
+ }
108
+ return false;
109
+ }
110
+ function extractHostnameFromOrigin(origin) {
111
+ if (!origin) return null;
112
+ try {
113
+ const url = new URL(origin);
114
+ return normalizeHostname(url.hostname);
115
+ } catch {
116
+ return null;
117
+ }
118
+ }
119
+ function ipMatches(ip, patterns) {
120
+ if (!ip || !patterns || patterns.length === 0) return false;
121
+ const cleanIp = ip.trim().toLowerCase();
122
+ for (const raw of patterns) {
123
+ const pattern = raw.trim().toLowerCase();
124
+ if (!pattern) continue;
125
+ if (pattern === cleanIp || pattern === "*") return true;
126
+ if (pattern.includes("*")) {
127
+ const regex = new RegExp("^" + pattern.replace(/\./g, "\\.").replace(/\*/g, ".*") + "$");
128
+ if (regex.test(cleanIp)) return true;
129
+ continue;
130
+ }
131
+ if (pattern.includes("/")) {
132
+ const [range, prefixStr] = pattern.split("/");
133
+ const prefix = parseInt(prefixStr, 10);
134
+ if (isNaN(prefix) || prefix < 0 || prefix > 32) continue;
135
+ const ipParts = cleanIp.split(".").map(Number);
136
+ const rangeParts = range.split(".").map(Number);
137
+ if (ipParts.length === 4 && rangeParts.length === 4 && ipParts.every((n) => !isNaN(n) && n >= 0 && n <= 255) && rangeParts.every((n) => !isNaN(n) && n >= 0 && n <= 255)) {
138
+ const ipInt = (ipParts[0] << 24 | ipParts[1] << 16 | ipParts[2] << 8 | ipParts[3]) >>> 0;
139
+ const rangeInt = (rangeParts[0] << 24 | rangeParts[1] << 16 | rangeParts[2] << 8 | rangeParts[3]) >>> 0;
140
+ const mask = prefix === 0 ? 0 : -1 << 32 - prefix >>> 0;
141
+ if ((ipInt & mask) === (rangeInt & mask)) return true;
142
+ }
143
+ }
144
+ }
145
+ return false;
146
+ }
147
+
148
+ // src/validation.ts
149
+ function asFiniteNumber(value) {
150
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
151
+ }
152
+ function asOptionalFiniteNumber(value) {
153
+ if (value === void 0) return void 0;
154
+ if (value === null) return null;
155
+ return asFiniteNumber(value);
156
+ }
157
+ function asString(value) {
158
+ return typeof value === "string" ? value : null;
159
+ }
160
+ function asBoolean(value) {
161
+ return typeof value === "boolean" ? value : null;
162
+ }
163
+ function validateBrowser(raw) {
164
+ if (!isPlainObject(raw)) return { ok: false, message: "browser must be an object" };
165
+ const userAgent = asString(raw.userAgent);
166
+ const language = asString(raw.language);
167
+ const timezone = asString(raw.timezone);
168
+ const platform = asString(raw.platform);
169
+ const languagesLength = asFiniteNumber(raw.languagesLength);
170
+ const timezoneOffset = asFiniteNumber(raw.timezoneOffset);
171
+ const screenWidth = asFiniteNumber(raw.screenWidth);
172
+ const screenHeight = asFiniteNumber(raw.screenHeight);
173
+ const colorDepth = asFiniteNumber(raw.colorDepth);
174
+ const devicePixelRatio = asFiniteNumber(raw.devicePixelRatio);
175
+ const maxTouchPoints = asFiniteNumber(raw.maxTouchPoints);
176
+ const cookieEnabled = asBoolean(raw.cookieEnabled);
177
+ const webdriver = asBoolean(raw.webdriver);
178
+ const hardwareConcurrency = raw.hardwareConcurrency === null ? null : asFiniteNumber(raw.hardwareConcurrency);
179
+ const webglRenderer = raw.webglRenderer === null ? null : raw.webglRenderer !== void 0 ? asString(raw.webglRenderer) : void 0;
180
+ const webglVendor = raw.webglVendor === null ? null : raw.webglVendor !== void 0 ? asString(raw.webglVendor) : void 0;
181
+ const hasChrome = raw.hasChrome !== void 0 ? asBoolean(raw.hasChrome) ?? void 0 : void 0;
182
+ const pluginsCount = raw.pluginsCount !== void 0 ? asFiniteNumber(raw.pluginsCount) ?? void 0 : void 0;
183
+ const screenOrientation = raw.screenOrientation === null ? null : raw.screenOrientation !== void 0 ? asString(raw.screenOrientation) : void 0;
184
+ if (userAgent == null || language == null || timezone == null || platform == null || languagesLength == null || timezoneOffset == null || screenWidth == null || screenHeight == null || colorDepth == null || devicePixelRatio == null || maxTouchPoints == null || cookieEnabled == null || webdriver == null || hardwareConcurrency === void 0) {
185
+ return { ok: false, message: "browser signals incomplete" };
186
+ }
187
+ return {
188
+ ok: true,
189
+ value: {
190
+ userAgent: userAgent.slice(0, 512),
191
+ language: language.slice(0, 32),
192
+ languagesLength,
193
+ timezone: timezone.slice(0, 64),
194
+ timezoneOffset,
195
+ platform: platform.slice(0, 64),
196
+ screenWidth,
197
+ screenHeight,
198
+ colorDepth,
199
+ devicePixelRatio,
200
+ hardwareConcurrency,
201
+ maxTouchPoints,
202
+ cookieEnabled,
203
+ webdriver,
204
+ ...webglRenderer !== void 0 ? { webglRenderer: webglRenderer ? webglRenderer.slice(0, 128) : null } : {},
205
+ ...webglVendor !== void 0 ? { webglVendor: webglVendor ? webglVendor.slice(0, 128) : null } : {},
206
+ ...hasChrome !== void 0 ? { hasChrome } : {},
207
+ ...pluginsCount !== void 0 ? { pluginsCount } : {},
208
+ ...screenOrientation !== void 0 ? { screenOrientation: screenOrientation ? screenOrientation.slice(0, 32) : null } : {}
209
+ }
210
+ };
211
+ }
212
+ function validateIntervalStats(raw, label) {
213
+ const averageInterval = asOptionalFiniteNumber(raw.averageInterval);
214
+ const minInterval = asOptionalFiniteNumber(raw.minInterval);
215
+ const maxInterval = asOptionalFiniteNumber(raw.maxInterval);
216
+ if (averageInterval === void 0 || minInterval === void 0 || maxInterval === void 0) {
217
+ return { ok: false, message: `${label} intervals incomplete` };
218
+ }
219
+ return { ok: true, value: { averageInterval, minInterval, maxInterval } };
220
+ }
221
+ function validatePointer(raw) {
222
+ if (!isPlainObject(raw)) return { ok: false, message: "pointer must be an object" };
223
+ const eventCount = asFiniteNumber(raw.eventCount);
224
+ const movementDistance = asFiniteNumber(raw.movementDistance);
225
+ const directionChanges = asFiniteNumber(raw.directionChanges);
226
+ const idlePeriods = asFiniteNumber(raw.idlePeriods);
227
+ const activeDuration = asFiniteNumber(raw.activeDuration);
228
+ const clickCount = asFiniteNumber(raw.clickCount);
229
+ const intervals = validateIntervalStats(raw, "pointer");
230
+ if (!intervals.ok) return intervals;
231
+ if (eventCount == null || movementDistance == null || directionChanges == null || idlePeriods == null || activeDuration == null || clickCount == null) {
232
+ return { ok: false, message: "pointer signals incomplete" };
233
+ }
234
+ return {
235
+ ok: true,
236
+ value: {
237
+ eventCount,
238
+ movementDistance,
239
+ ...intervals.value,
240
+ directionChanges,
241
+ idlePeriods,
242
+ activeDuration,
243
+ clickCount
244
+ }
245
+ };
246
+ }
247
+ function validateKeyboard(raw) {
248
+ if (!isPlainObject(raw)) return { ok: false, message: "keyboard must be an object" };
249
+ const keydownCount = asFiniteNumber(raw.keydownCount);
250
+ const keyupCount = asFiniteNumber(raw.keyupCount);
251
+ const pasteCount = asFiniteNumber(raw.pasteCount);
252
+ const timingVariance = asOptionalFiniteNumber(raw.timingVariance);
253
+ const intervals = validateIntervalStats(raw, "keyboard");
254
+ if (!intervals.ok) return intervals;
255
+ if (keydownCount == null || keyupCount == null || pasteCount == null || timingVariance === void 0) {
256
+ return { ok: false, message: "keyboard signals incomplete" };
257
+ }
258
+ return {
259
+ ok: true,
260
+ value: {
261
+ keydownCount,
262
+ keyupCount,
263
+ ...intervals.value,
264
+ timingVariance,
265
+ pasteCount
266
+ }
267
+ };
268
+ }
269
+ function validateTouch(raw) {
270
+ if (!isPlainObject(raw)) return { ok: false, message: "touch must be an object" };
271
+ const touchCount = asFiniteNumber(raw.touchCount);
272
+ const averageInterval = asOptionalFiniteNumber(raw.averageInterval);
273
+ const activeDuration = asFiniteNumber(raw.activeDuration);
274
+ const multiTouchCount = asFiniteNumber(raw.multiTouchCount);
275
+ if (touchCount == null || averageInterval === void 0 || activeDuration == null || multiTouchCount == null) {
276
+ return { ok: false, message: "touch signals incomplete" };
277
+ }
278
+ return { ok: true, value: { touchCount, averageInterval, activeDuration, multiTouchCount } };
279
+ }
280
+ function validateScroll(raw) {
281
+ if (!isPlainObject(raw)) return { ok: false, message: "scroll must be an object" };
282
+ const scrollCount = asFiniteNumber(raw.scrollCount);
283
+ const averageInterval = asOptionalFiniteNumber(raw.averageInterval);
284
+ const totalDistance = asFiniteNumber(raw.totalDistance);
285
+ const directionChanges = asFiniteNumber(raw.directionChanges);
286
+ const activeDuration = asFiniteNumber(raw.activeDuration);
287
+ if (scrollCount == null || averageInterval === void 0 || totalDistance == null || directionChanges == null || activeDuration == null) {
288
+ return { ok: false, message: "scroll signals incomplete" };
289
+ }
290
+ return {
291
+ ok: true,
292
+ value: { scrollCount, averageInterval, totalDistance, directionChanges, activeDuration }
293
+ };
294
+ }
295
+ function validateFocus(raw) {
296
+ if (!isPlainObject(raw)) return { ok: false, message: "focus must be an object" };
297
+ const focusCount = asFiniteNumber(raw.focusCount);
298
+ const blurCount = asFiniteNumber(raw.blurCount);
299
+ if (focusCount == null || blurCount == null) {
300
+ return { ok: false, message: "focus signals incomplete" };
301
+ }
302
+ return { ok: true, value: { focusCount, blurCount } };
303
+ }
304
+ function validateVisibility(raw) {
305
+ if (!isPlainObject(raw)) return { ok: false, message: "visibility must be an object" };
306
+ const visibilityChanges = asFiniteNumber(raw.visibilityChanges);
307
+ const visibleDuration = asFiniteNumber(raw.visibleDuration);
308
+ const hiddenDuration = asFiniteNumber(raw.hiddenDuration);
309
+ if (visibilityChanges == null || visibleDuration == null || hiddenDuration == null) {
310
+ return { ok: false, message: "visibility signals incomplete" };
311
+ }
312
+ return { ok: true, value: { visibilityChanges, visibleDuration, hiddenDuration } };
313
+ }
314
+ function validateInteraction(raw) {
315
+ if (!isPlainObject(raw)) return { ok: false, message: "interaction must be an object" };
316
+ const pageLoadTime = asFiniteNumber(raw.pageLoadTime);
317
+ const firstInteractionTime = asOptionalFiniteNumber(raw.firstInteractionTime);
318
+ const timeToFirstInteraction = asOptionalFiniteNumber(raw.timeToFirstInteraction);
319
+ const clickCount = asFiniteNumber(raw.clickCount);
320
+ const interactionCount = asFiniteNumber(raw.interactionCount);
321
+ const formInteractionCount = asFiniteNumber(raw.formInteractionCount);
322
+ const scrollCount = asFiniteNumber(raw.scrollCount);
323
+ const focusCount = asFiniteNumber(raw.focusCount);
324
+ if (pageLoadTime == null || firstInteractionTime === void 0 || timeToFirstInteraction === void 0 || clickCount == null || interactionCount == null || formInteractionCount == null || scrollCount == null || focusCount == null) {
325
+ return { ok: false, message: "interaction signals incomplete" };
326
+ }
327
+ return {
328
+ ok: true,
329
+ value: {
330
+ pageLoadTime,
331
+ firstInteractionTime,
332
+ timeToFirstInteraction,
333
+ clickCount,
334
+ interactionCount,
335
+ formInteractionCount,
336
+ scrollCount,
337
+ focusCount
338
+ }
339
+ };
340
+ }
341
+ var FORBIDDEN_TELEMETRY_KEYS = /* @__PURE__ */ new Set([
342
+ "password",
343
+ "passwords",
344
+ "value",
345
+ "values",
346
+ "key",
347
+ "keys",
348
+ "code",
349
+ "codes",
350
+ "clipboard",
351
+ "cookie",
352
+ "cookies",
353
+ "localStorage",
354
+ "sessionStorage",
355
+ "token",
356
+ "tokens",
357
+ "authorization",
358
+ "text",
359
+ "innerText",
360
+ "innerHTML",
361
+ "coordinates",
362
+ "path",
363
+ "points"
364
+ ]);
365
+ function assertNoForbiddenKeys(value, path) {
366
+ if (Array.isArray(value)) {
367
+ for (let i = 0; i < value.length; i++) {
368
+ const err = assertNoForbiddenKeys(value[i], `${path}[${i}]`);
369
+ if (err) return err;
370
+ }
371
+ return null;
372
+ }
373
+ if (!isPlainObject(value)) return null;
374
+ for (const key of Object.keys(value)) {
375
+ if (FORBIDDEN_TELEMETRY_KEYS.has(key)) {
376
+ return `forbidden telemetry field: ${path}.${key}`;
377
+ }
378
+ const err = assertNoForbiddenKeys(value[key], `${path}.${key}`);
379
+ if (err) return err;
380
+ }
381
+ return null;
382
+ }
383
+ function validateTelemetry(raw, maxBytes = MAX_TELEMETRY_BYTES) {
384
+ if (!isPlainObject(raw)) return { ok: false, message: "telemetry must be an object" };
385
+ const forbidden = assertNoForbiddenKeys(raw, "telemetry");
386
+ if (forbidden) return { ok: false, message: forbidden };
387
+ const serialized = JSON.stringify(raw);
388
+ if (utf8ByteLength(serialized) > maxBytes) {
389
+ return { ok: false, message: `telemetry exceeds ${maxBytes} bytes` };
390
+ }
391
+ const version = asFiniteNumber(raw.version);
392
+ if (version !== TELEMETRY_VERSION) {
393
+ return { ok: false, message: "unsupported telemetry version" };
394
+ }
395
+ const telemetry = { version: 1 };
396
+ if (raw.browser !== void 0) {
397
+ const r = validateBrowser(raw.browser);
398
+ if (!r.ok) return r;
399
+ telemetry.browser = r.value;
400
+ }
401
+ if (raw.pointer !== void 0) {
402
+ const r = validatePointer(raw.pointer);
403
+ if (!r.ok) return r;
404
+ telemetry.pointer = r.value;
405
+ }
406
+ if (raw.keyboard !== void 0) {
407
+ const r = validateKeyboard(raw.keyboard);
408
+ if (!r.ok) return r;
409
+ telemetry.keyboard = r.value;
410
+ }
411
+ if (raw.touch !== void 0) {
412
+ const r = validateTouch(raw.touch);
413
+ if (!r.ok) return r;
414
+ telemetry.touch = r.value;
415
+ }
416
+ if (raw.scroll !== void 0) {
417
+ const r = validateScroll(raw.scroll);
418
+ if (!r.ok) return r;
419
+ telemetry.scroll = r.value;
420
+ }
421
+ if (raw.focus !== void 0) {
422
+ const r = validateFocus(raw.focus);
423
+ if (!r.ok) return r;
424
+ telemetry.focus = r.value;
425
+ }
426
+ if (raw.visibility !== void 0) {
427
+ const r = validateVisibility(raw.visibility);
428
+ if (!r.ok) return r;
429
+ telemetry.visibility = r.value;
430
+ }
431
+ if (raw.interaction !== void 0) {
432
+ const r = validateInteraction(raw.interaction);
433
+ if (!r.ok) return r;
434
+ telemetry.interaction = r.value;
435
+ }
436
+ return { ok: true, value: telemetry };
437
+ }
438
+ function validateCreateSessionRequest(raw) {
439
+ if (!isPlainObject(raw)) return { ok: false, message: "body must be an object" };
440
+ const hostname = asString(raw.hostname);
441
+ const timestamp = asFiniteNumber(raw.timestamp);
442
+ const userAgent = raw.userAgent === void 0 ? void 0 : asString(raw.userAgent) ?? void 0;
443
+ if (!hostname || timestamp == null) {
444
+ return { ok: false, message: "hostname and timestamp are required" };
445
+ }
446
+ return {
447
+ ok: true,
448
+ value: {
449
+ hostname: hostname.slice(0, 253),
450
+ timestamp,
451
+ ...userAgent !== void 0 ? { userAgent: userAgent.slice(0, 512) } : {}
452
+ }
453
+ };
454
+ }
455
+ function validateAnalyzeRequest(raw, maxBytes = MAX_TELEMETRY_BYTES) {
456
+ if (!isPlainObject(raw)) return { ok: false, message: "body must be an object" };
457
+ const sessionId = asString(raw.sessionId);
458
+ const sequence = asFiniteNumber(raw.sequence);
459
+ const timestamp = asFiniteNumber(raw.timestamp);
460
+ const hostname = asString(raw.hostname);
461
+ const nonce = raw.nonce === void 0 ? void 0 : asString(raw.nonce) ?? void 0;
462
+ const action = raw.action === void 0 ? void 0 : asString(raw.action) ?? void 0;
463
+ let metadata;
464
+ if (raw.metadata !== void 0) {
465
+ if (!isPlainObject(raw.metadata)) {
466
+ return { ok: false, message: "metadata must be an object" };
467
+ }
468
+ const forbidden = assertNoForbiddenKeys(raw.metadata, "metadata");
469
+ if (forbidden) return { ok: false, message: forbidden };
470
+ metadata = raw.metadata;
471
+ }
472
+ if (!sessionId || sequence == null || timestamp == null || !hostname) {
473
+ return { ok: false, message: "sessionId, sequence, timestamp, and hostname are required" };
474
+ }
475
+ if (!Number.isInteger(sequence) || sequence < 1) {
476
+ return { ok: false, message: "sequence must be a positive integer" };
477
+ }
478
+ const telemetry = validateTelemetry(raw.telemetry, maxBytes);
479
+ if (!telemetry.ok) return telemetry;
480
+ return {
481
+ ok: true,
482
+ value: {
483
+ sessionId,
484
+ sequence,
485
+ timestamp,
486
+ hostname: hostname.slice(0, 253),
487
+ telemetry: telemetry.value,
488
+ ...nonce !== void 0 ? { nonce } : {},
489
+ ...action !== void 0 ? { action: action.slice(0, 64) } : {},
490
+ ...metadata !== void 0 ? { metadata } : {}
491
+ }
492
+ };
493
+ }
494
+
495
+ export { API_PATHS, BotDetectorError, DEFAULT_RISK_THRESHOLDS, DEFAULT_RISK_TOKEN_DURATION_MS, DEFAULT_SESSION_DURATION_MS, DEFAULT_TELEMETRY_INTERVAL_MS, ERROR_CODES, MAX_TELEMETRY_BYTES, SITE_KEY_HEADER, TELEMETRY_VERSION, clamp, decisionFromScore, extractHostnameFromOrigin, hostnameAllowed, ipMatches, isBotDetectorError, isPlainObject, mergeRiskThresholds, normalizeHostname, riskLevelFromScore, utf8ByteLength, validateAnalyzeRequest, validateCreateSessionRequest, validateTelemetry };
496
+ //# sourceMappingURL=index.js.map
497
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/constants.ts","../src/errors.ts","../src/utils.ts","../src/validation.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/** Default session lifetime (30 minutes). */\nexport const DEFAULT_SESSION_DURATION_MS = 30 * 60 * 1000\n\n/** Default client telemetry flush interval. */\nexport const DEFAULT_TELEMETRY_INTERVAL_MS = 5000\n\n/** Soft max size for a telemetry JSON payload. */\nexport const MAX_TELEMETRY_BYTES = 32 * 1024\n\n/** Default risk token lifetime (5 minutes). */\nexport const DEFAULT_RISK_TOKEN_DURATION_MS = 5 * 60 * 1000\n\n/** Protocol version embedded in telemetry. */\nexport const TELEMETRY_VERSION = 1 as const\n\n/** HTTP header for the public site key. */\nexport const SITE_KEY_HEADER = 'X-Bot-Site-Key'\n\n/** API path suffixes (relative to endpoint base). */\nexport const API_PATHS = {\n session: '/v1/session',\n analyze: '/v1/analyze',\n} as const\n\n/**\n * Default human-score thresholds (higher = more human-like).\n * allow >= 70, monitor >= 50, challenge >= 30, block < 30\n */\nexport const DEFAULT_RISK_THRESHOLDS = {\n allow: 70,\n monitor: 50,\n challenge: 30,\n} as const\n\nexport const ERROR_CODES = [\n 'INVALID_SITE_KEY',\n 'INVALID_HOSTNAME',\n 'INVALID_SESSION',\n 'SESSION_EXPIRED',\n 'INVALID_NONCE',\n 'INVALID_SEQUENCE',\n 'RATE_LIMITED',\n 'INVALID_TELEMETRY',\n 'MALFORMED_REQUEST',\n 'INTERNAL_ERROR',\n 'IP_BLOCKED',\n 'TOKEN_ALREADY_USED',\n 'ACTION_MISMATCH',\n] as const\n\nexport type ErrorCode = (typeof ERROR_CODES)[number]\n","import type { ErrorCode } from './constants'\nimport type { ApiErrorBody } from './types'\n\nexport class BotDetectorError extends Error {\n readonly code: ErrorCode\n readonly requestId: string\n\n constructor(code: ErrorCode, message: string, requestId: string) {\n super(message)\n this.name = 'BotDetectorError'\n this.code = code\n this.requestId = requestId\n }\n\n toJSON(): ApiErrorBody {\n return {\n error: {\n code: this.code,\n message: this.message,\n requestId: this.requestId,\n },\n }\n }\n}\n\nexport function isBotDetectorError(value: unknown): value is BotDetectorError {\n return value instanceof BotDetectorError\n}\n","import type { RiskConfig, RiskDecision, RiskLevel } from './types'\nimport { DEFAULT_RISK_THRESHOLDS } from './constants'\n\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value))\n}\n\nexport function decisionFromScore(score: number, thresholds: RiskConfig = DEFAULT_RISK_THRESHOLDS): RiskDecision {\n if (score >= thresholds.allow) return 'allow'\n if (score >= thresholds.monitor) return 'monitor'\n if (score >= thresholds.challenge) return 'challenge'\n return 'block'\n}\n\nexport function riskLevelFromScore(score: number): RiskLevel {\n if (score >= 70) return 'low'\n if (score >= 40) return 'medium'\n return 'high'\n}\n\nexport function mergeRiskThresholds(partial?: Partial<RiskConfig>): RiskConfig {\n return {\n allow: partial?.allow ?? DEFAULT_RISK_THRESHOLDS.allow,\n monitor: partial?.monitor ?? DEFAULT_RISK_THRESHOLDS.monitor,\n challenge: partial?.challenge ?? DEFAULT_RISK_THRESHOLDS.challenge,\n }\n}\n\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nexport function utf8ByteLength(value: string): number {\n if (typeof TextEncoder !== 'undefined') {\n return new TextEncoder().encode(value).length\n }\n // Fallback for unusual environments\n let bytes = 0\n for (let i = 0; i < value.length; i++) {\n const code = value.charCodeAt(i)\n if (code < 0x80) bytes += 1\n else if (code < 0x800) bytes += 2\n else if (code >= 0xd800 && code <= 0xdbff) {\n bytes += 4\n i++\n } else bytes += 3\n }\n return bytes\n}\n\n/** Normalize hostname for allowlist comparison. */\nexport function normalizeHostname(hostname: string): string {\n return hostname.trim().toLowerCase().replace(/\\.$/, '')\n}\n\n/** Check whether hostname matches an allowed domain (exact or subdomain). */\nexport function hostnameAllowed(hostname: string, allowedDomains: readonly string[]): boolean {\n const host = normalizeHostname(hostname)\n if (!host) return false\n for (const raw of allowedDomains) {\n const allowed = normalizeHostname(raw)\n if (!allowed) continue\n if (host === allowed) return true\n if (host.endsWith(`.${allowed}`)) return true\n }\n return false\n}\n\nexport function extractHostnameFromOrigin(origin: string | undefined): string | null {\n if (!origin) return null\n try {\n const url = new URL(origin)\n return normalizeHostname(url.hostname)\n } catch {\n return null\n }\n}\n\n/** Check whether an IP matches any entry in a list of exact IPs, wildcards, or IPv4 CIDR blocks. */\nexport function ipMatches(ip: string | undefined, patterns: readonly string[]): boolean {\n if (!ip || !patterns || patterns.length === 0) return false\n const cleanIp = ip.trim().toLowerCase()\n\n for (const raw of patterns) {\n const pattern = raw.trim().toLowerCase()\n if (!pattern) continue\n if (pattern === cleanIp || pattern === '*') return true\n\n // Wildcard match (e.g. 192.168.*)\n if (pattern.includes('*')) {\n const regex = new RegExp('^' + pattern.replace(/\\./g, '\\\\.').replace(/\\*/g, '.*') + '$')\n if (regex.test(cleanIp)) return true\n continue\n }\n\n // CIDR match (IPv4)\n if (pattern.includes('/')) {\n const [range, prefixStr] = pattern.split('/')\n const prefix = parseInt(prefixStr, 10)\n if (isNaN(prefix) || prefix < 0 || prefix > 32) continue\n\n const ipParts = cleanIp.split('.').map(Number)\n const rangeParts = range.split('.').map(Number)\n\n if (\n ipParts.length === 4 &&\n rangeParts.length === 4 &&\n ipParts.every((n) => !isNaN(n) && n >= 0 && n <= 255) &&\n rangeParts.every((n) => !isNaN(n) && n >= 0 && n <= 255)\n ) {\n const ipInt =\n ((ipParts[0] << 24) | (ipParts[1] << 16) | (ipParts[2] << 8) | ipParts[3]) >>> 0\n const rangeInt =\n ((rangeParts[0] << 24) | (rangeParts[1] << 16) | (rangeParts[2] << 8) | rangeParts[3]) >>>\n 0\n const mask = prefix === 0 ? 0 : (~0 << (32 - prefix)) >>> 0\n if ((ipInt & mask) === (rangeInt & mask)) return true\n }\n }\n }\n return false\n}\n\n","import { MAX_TELEMETRY_BYTES, TELEMETRY_VERSION } from './constants'\nimport type {\n AnalyzeRequest,\n BrowserSignals,\n CreateSessionRequest,\n FocusSignals,\n InteractionSignals,\n KeyboardSignals,\n PointerSignals,\n ScrollSignals,\n Telemetry,\n TouchSignals,\n VisibilitySignals,\n} from './types'\nimport { isPlainObject, utf8ByteLength } from './utils'\n\nexport type ValidationResult<T> =\n | { readonly ok: true; readonly value: T }\n | { readonly ok: false; readonly message: string }\n\nfunction asFiniteNumber(value: unknown): number | null {\n return typeof value === 'number' && Number.isFinite(value) ? value : null\n}\n\nfunction asOptionalFiniteNumber(value: unknown): number | null | undefined {\n if (value === undefined) return undefined\n if (value === null) return null\n return asFiniteNumber(value)\n}\n\nfunction asString(value: unknown): string | null {\n return typeof value === 'string' ? value : null\n}\n\nfunction asBoolean(value: unknown): boolean | null {\n return typeof value === 'boolean' ? value : null\n}\n\nfunction validateBrowser(raw: unknown): ValidationResult<BrowserSignals> {\n if (!isPlainObject(raw)) return { ok: false, message: 'browser must be an object' }\n const userAgent = asString(raw.userAgent)\n const language = asString(raw.language)\n const timezone = asString(raw.timezone)\n const platform = asString(raw.platform)\n const languagesLength = asFiniteNumber(raw.languagesLength)\n const timezoneOffset = asFiniteNumber(raw.timezoneOffset)\n const screenWidth = asFiniteNumber(raw.screenWidth)\n const screenHeight = asFiniteNumber(raw.screenHeight)\n const colorDepth = asFiniteNumber(raw.colorDepth)\n const devicePixelRatio = asFiniteNumber(raw.devicePixelRatio)\n const maxTouchPoints = asFiniteNumber(raw.maxTouchPoints)\n const cookieEnabled = asBoolean(raw.cookieEnabled)\n const webdriver = asBoolean(raw.webdriver)\n const hardwareConcurrency =\n raw.hardwareConcurrency === null ? null : asFiniteNumber(raw.hardwareConcurrency)\n\n const webglRenderer =\n raw.webglRenderer === null\n ? null\n : raw.webglRenderer !== undefined\n ? asString(raw.webglRenderer)\n : undefined\n const webglVendor =\n raw.webglVendor === null\n ? null\n : raw.webglVendor !== undefined\n ? asString(raw.webglVendor)\n : undefined\n const hasChrome =\n raw.hasChrome !== undefined ? asBoolean(raw.hasChrome) ?? undefined : undefined\n const pluginsCount =\n raw.pluginsCount !== undefined ? asFiniteNumber(raw.pluginsCount) ?? undefined : undefined\n const screenOrientation =\n raw.screenOrientation === null\n ? null\n : raw.screenOrientation !== undefined\n ? asString(raw.screenOrientation)\n : undefined\n\n if (\n userAgent == null ||\n language == null ||\n timezone == null ||\n platform == null ||\n languagesLength == null ||\n timezoneOffset == null ||\n screenWidth == null ||\n screenHeight == null ||\n colorDepth == null ||\n devicePixelRatio == null ||\n maxTouchPoints == null ||\n cookieEnabled == null ||\n webdriver == null ||\n (hardwareConcurrency === undefined)\n ) {\n return { ok: false, message: 'browser signals incomplete' }\n }\n\n return {\n ok: true,\n value: {\n userAgent: userAgent.slice(0, 512),\n language: language.slice(0, 32),\n languagesLength,\n timezone: timezone.slice(0, 64),\n timezoneOffset,\n platform: platform.slice(0, 64),\n screenWidth,\n screenHeight,\n colorDepth,\n devicePixelRatio,\n hardwareConcurrency,\n maxTouchPoints,\n cookieEnabled,\n webdriver,\n ...(webglRenderer !== undefined\n ? { webglRenderer: webglRenderer ? webglRenderer.slice(0, 128) : null }\n : {}),\n ...(webglVendor !== undefined\n ? { webglVendor: webglVendor ? webglVendor.slice(0, 128) : null }\n : {}),\n ...(hasChrome !== undefined ? { hasChrome } : {}),\n ...(pluginsCount !== undefined ? { pluginsCount } : {}),\n ...(screenOrientation !== undefined\n ? { screenOrientation: screenOrientation ? screenOrientation.slice(0, 32) : null }\n : {}),\n },\n }\n}\n\nfunction validateIntervalStats(raw: Record<string, unknown>, label: string): ValidationResult<{\n averageInterval: number | null\n minInterval: number | null\n maxInterval: number | null\n}> {\n const averageInterval = asOptionalFiniteNumber(raw.averageInterval)\n const minInterval = asOptionalFiniteNumber(raw.minInterval)\n const maxInterval = asOptionalFiniteNumber(raw.maxInterval)\n if (averageInterval === undefined || minInterval === undefined || maxInterval === undefined) {\n return { ok: false, message: `${label} intervals incomplete` }\n }\n return { ok: true, value: { averageInterval, minInterval, maxInterval } }\n}\n\nfunction validatePointer(raw: unknown): ValidationResult<PointerSignals> {\n if (!isPlainObject(raw)) return { ok: false, message: 'pointer must be an object' }\n const eventCount = asFiniteNumber(raw.eventCount)\n const movementDistance = asFiniteNumber(raw.movementDistance)\n const directionChanges = asFiniteNumber(raw.directionChanges)\n const idlePeriods = asFiniteNumber(raw.idlePeriods)\n const activeDuration = asFiniteNumber(raw.activeDuration)\n const clickCount = asFiniteNumber(raw.clickCount)\n const intervals = validateIntervalStats(raw, 'pointer')\n if (!intervals.ok) return intervals\n if (\n eventCount == null ||\n movementDistance == null ||\n directionChanges == null ||\n idlePeriods == null ||\n activeDuration == null ||\n clickCount == null\n ) {\n return { ok: false, message: 'pointer signals incomplete' }\n }\n return {\n ok: true,\n value: {\n eventCount,\n movementDistance,\n ...intervals.value,\n directionChanges,\n idlePeriods,\n activeDuration,\n clickCount,\n },\n }\n}\n\nfunction validateKeyboard(raw: unknown): ValidationResult<KeyboardSignals> {\n if (!isPlainObject(raw)) return { ok: false, message: 'keyboard must be an object' }\n const keydownCount = asFiniteNumber(raw.keydownCount)\n const keyupCount = asFiniteNumber(raw.keyupCount)\n const pasteCount = asFiniteNumber(raw.pasteCount)\n const timingVariance = asOptionalFiniteNumber(raw.timingVariance)\n const intervals = validateIntervalStats(raw, 'keyboard')\n if (!intervals.ok) return intervals\n if (keydownCount == null || keyupCount == null || pasteCount == null || timingVariance === undefined) {\n return { ok: false, message: 'keyboard signals incomplete' }\n }\n return {\n ok: true,\n value: {\n keydownCount,\n keyupCount,\n ...intervals.value,\n timingVariance,\n pasteCount,\n },\n }\n}\n\nfunction validateTouch(raw: unknown): ValidationResult<TouchSignals> {\n if (!isPlainObject(raw)) return { ok: false, message: 'touch must be an object' }\n const touchCount = asFiniteNumber(raw.touchCount)\n const averageInterval = asOptionalFiniteNumber(raw.averageInterval)\n const activeDuration = asFiniteNumber(raw.activeDuration)\n const multiTouchCount = asFiniteNumber(raw.multiTouchCount)\n if (\n touchCount == null ||\n averageInterval === undefined ||\n activeDuration == null ||\n multiTouchCount == null\n ) {\n return { ok: false, message: 'touch signals incomplete' }\n }\n return { ok: true, value: { touchCount, averageInterval, activeDuration, multiTouchCount } }\n}\n\nfunction validateScroll(raw: unknown): ValidationResult<ScrollSignals> {\n if (!isPlainObject(raw)) return { ok: false, message: 'scroll must be an object' }\n const scrollCount = asFiniteNumber(raw.scrollCount)\n const averageInterval = asOptionalFiniteNumber(raw.averageInterval)\n const totalDistance = asFiniteNumber(raw.totalDistance)\n const directionChanges = asFiniteNumber(raw.directionChanges)\n const activeDuration = asFiniteNumber(raw.activeDuration)\n if (\n scrollCount == null ||\n averageInterval === undefined ||\n totalDistance == null ||\n directionChanges == null ||\n activeDuration == null\n ) {\n return { ok: false, message: 'scroll signals incomplete' }\n }\n return {\n ok: true,\n value: { scrollCount, averageInterval, totalDistance, directionChanges, activeDuration },\n }\n}\n\nfunction validateFocus(raw: unknown): ValidationResult<FocusSignals> {\n if (!isPlainObject(raw)) return { ok: false, message: 'focus must be an object' }\n const focusCount = asFiniteNumber(raw.focusCount)\n const blurCount = asFiniteNumber(raw.blurCount)\n if (focusCount == null || blurCount == null) {\n return { ok: false, message: 'focus signals incomplete' }\n }\n return { ok: true, value: { focusCount, blurCount } }\n}\n\nfunction validateVisibility(raw: unknown): ValidationResult<VisibilitySignals> {\n if (!isPlainObject(raw)) return { ok: false, message: 'visibility must be an object' }\n const visibilityChanges = asFiniteNumber(raw.visibilityChanges)\n const visibleDuration = asFiniteNumber(raw.visibleDuration)\n const hiddenDuration = asFiniteNumber(raw.hiddenDuration)\n if (visibilityChanges == null || visibleDuration == null || hiddenDuration == null) {\n return { ok: false, message: 'visibility signals incomplete' }\n }\n return { ok: true, value: { visibilityChanges, visibleDuration, hiddenDuration } }\n}\n\nfunction validateInteraction(raw: unknown): ValidationResult<InteractionSignals> {\n if (!isPlainObject(raw)) return { ok: false, message: 'interaction must be an object' }\n const pageLoadTime = asFiniteNumber(raw.pageLoadTime)\n const firstInteractionTime = asOptionalFiniteNumber(raw.firstInteractionTime)\n const timeToFirstInteraction = asOptionalFiniteNumber(raw.timeToFirstInteraction)\n const clickCount = asFiniteNumber(raw.clickCount)\n const interactionCount = asFiniteNumber(raw.interactionCount)\n const formInteractionCount = asFiniteNumber(raw.formInteractionCount)\n const scrollCount = asFiniteNumber(raw.scrollCount)\n const focusCount = asFiniteNumber(raw.focusCount)\n if (\n pageLoadTime == null ||\n firstInteractionTime === undefined ||\n timeToFirstInteraction === undefined ||\n clickCount == null ||\n interactionCount == null ||\n formInteractionCount == null ||\n scrollCount == null ||\n focusCount == null\n ) {\n return { ok: false, message: 'interaction signals incomplete' }\n }\n return {\n ok: true,\n value: {\n pageLoadTime,\n firstInteractionTime,\n timeToFirstInteraction,\n clickCount,\n interactionCount,\n formInteractionCount,\n scrollCount,\n focusCount,\n },\n }\n}\n\n/** Forbidden keys that must never appear in telemetry (defense in depth). */\nconst FORBIDDEN_TELEMETRY_KEYS = new Set([\n 'password',\n 'passwords',\n 'value',\n 'values',\n 'key',\n 'keys',\n 'code',\n 'codes',\n 'clipboard',\n 'cookie',\n 'cookies',\n 'localStorage',\n 'sessionStorage',\n 'token',\n 'tokens',\n 'authorization',\n 'text',\n 'innerText',\n 'innerHTML',\n 'coordinates',\n 'path',\n 'points',\n])\n\nfunction assertNoForbiddenKeys(value: unknown, path: string): string | null {\n if (Array.isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n const err = assertNoForbiddenKeys(value[i], `${path}[${i}]`)\n if (err) return err\n }\n return null\n }\n if (!isPlainObject(value)) return null\n for (const key of Object.keys(value)) {\n if (FORBIDDEN_TELEMETRY_KEYS.has(key)) {\n return `forbidden telemetry field: ${path}.${key}`\n }\n const err = assertNoForbiddenKeys(value[key], `${path}.${key}`)\n if (err) return err\n }\n return null\n}\n\nexport function validateTelemetry(\n raw: unknown,\n maxBytes: number = MAX_TELEMETRY_BYTES,\n): ValidationResult<Telemetry> {\n if (!isPlainObject(raw)) return { ok: false, message: 'telemetry must be an object' }\n\n const forbidden = assertNoForbiddenKeys(raw, 'telemetry')\n if (forbidden) return { ok: false, message: forbidden }\n\n const serialized = JSON.stringify(raw)\n if (utf8ByteLength(serialized) > maxBytes) {\n return { ok: false, message: `telemetry exceeds ${maxBytes} bytes` }\n }\n\n const version = asFiniteNumber(raw.version)\n if (version !== TELEMETRY_VERSION) {\n return { ok: false, message: 'unsupported telemetry version' }\n }\n\n const telemetry: {\n version: 1\n browser?: BrowserSignals\n pointer?: PointerSignals\n keyboard?: KeyboardSignals\n touch?: TouchSignals\n scroll?: ScrollSignals\n focus?: FocusSignals\n visibility?: VisibilitySignals\n interaction?: InteractionSignals\n } = { version: 1 }\n\n if (raw.browser !== undefined) {\n const r = validateBrowser(raw.browser)\n if (!r.ok) return r\n telemetry.browser = r.value\n }\n if (raw.pointer !== undefined) {\n const r = validatePointer(raw.pointer)\n if (!r.ok) return r\n telemetry.pointer = r.value\n }\n if (raw.keyboard !== undefined) {\n const r = validateKeyboard(raw.keyboard)\n if (!r.ok) return r\n telemetry.keyboard = r.value\n }\n if (raw.touch !== undefined) {\n const r = validateTouch(raw.touch)\n if (!r.ok) return r\n telemetry.touch = r.value\n }\n if (raw.scroll !== undefined) {\n const r = validateScroll(raw.scroll)\n if (!r.ok) return r\n telemetry.scroll = r.value\n }\n if (raw.focus !== undefined) {\n const r = validateFocus(raw.focus)\n if (!r.ok) return r\n telemetry.focus = r.value\n }\n if (raw.visibility !== undefined) {\n const r = validateVisibility(raw.visibility)\n if (!r.ok) return r\n telemetry.visibility = r.value\n }\n if (raw.interaction !== undefined) {\n const r = validateInteraction(raw.interaction)\n if (!r.ok) return r\n telemetry.interaction = r.value\n }\n\n return { ok: true, value: telemetry }\n}\n\nexport function validateCreateSessionRequest(raw: unknown): ValidationResult<CreateSessionRequest> {\n if (!isPlainObject(raw)) return { ok: false, message: 'body must be an object' }\n const hostname = asString(raw.hostname)\n const timestamp = asFiniteNumber(raw.timestamp)\n const userAgent = raw.userAgent === undefined ? undefined : asString(raw.userAgent) ?? undefined\n if (!hostname || timestamp == null) {\n return { ok: false, message: 'hostname and timestamp are required' }\n }\n return {\n ok: true,\n value: {\n hostname: hostname.slice(0, 253),\n timestamp,\n ...(userAgent !== undefined ? { userAgent: userAgent.slice(0, 512) } : {}),\n },\n }\n}\n\nexport function validateAnalyzeRequest(\n raw: unknown,\n maxBytes: number = MAX_TELEMETRY_BYTES,\n): ValidationResult<AnalyzeRequest> {\n if (!isPlainObject(raw)) return { ok: false, message: 'body must be an object' }\n const sessionId = asString(raw.sessionId)\n const sequence = asFiniteNumber(raw.sequence)\n const timestamp = asFiniteNumber(raw.timestamp)\n const hostname = asString(raw.hostname)\n const nonce = raw.nonce === undefined ? undefined : asString(raw.nonce) ?? undefined\n const action = raw.action === undefined ? undefined : asString(raw.action) ?? undefined\n let metadata: Record<string, unknown> | undefined\n if (raw.metadata !== undefined) {\n if (!isPlainObject(raw.metadata)) {\n return { ok: false, message: 'metadata must be an object' }\n }\n const forbidden = assertNoForbiddenKeys(raw.metadata, 'metadata')\n if (forbidden) return { ok: false, message: forbidden }\n metadata = raw.metadata\n }\n\n if (!sessionId || sequence == null || timestamp == null || !hostname) {\n return { ok: false, message: 'sessionId, sequence, timestamp, and hostname are required' }\n }\n if (!Number.isInteger(sequence) || sequence < 1) {\n return { ok: false, message: 'sequence must be a positive integer' }\n }\n\n const telemetry = validateTelemetry(raw.telemetry, maxBytes)\n if (!telemetry.ok) return telemetry\n\n return {\n ok: true,\n value: {\n sessionId,\n sequence,\n timestamp,\n hostname: hostname.slice(0, 253),\n telemetry: telemetry.value,\n ...(nonce !== undefined ? { nonce } : {}),\n ...(action !== undefined ? { action: action.slice(0, 64) } : {}),\n ...(metadata !== undefined ? { metadata } : {}),\n },\n }\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "devn-bot-detector-core",
3
+ "version": "0.1.0",
4
+ "description": "Shared types, constants, and validation for bot-detector SDK",
5
+ "license": "MIT",
6
+ "author": "devn",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/devn5900/devn-bot-detector.git",
10
+ "directory": "packages/core"
11
+ },
12
+ "homepage": "https://github.com/devn5900/devn-bot-detector/tree/main/packages/core#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/devn5900/devn-bot-detector/issues"
15
+ },
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "keywords": [
20
+ "bot-detector",
21
+ "bot-detection",
22
+ "anti-bot",
23
+ "fraud-prevention",
24
+ "behavioral-biometrics",
25
+ "types",
26
+ "security"
27
+ ],
28
+ "type": "module",
29
+ "main": "./dist/index.cjs",
30
+ "module": "./dist/index.js",
31
+ "types": "./dist/index.d.ts",
32
+ "exports": {
33
+ ".": {
34
+ "types": "./dist/index.d.ts",
35
+ "import": "./dist/index.js",
36
+ "require": "./dist/index.cjs"
37
+ }
38
+ },
39
+ "files": [
40
+ "dist",
41
+ "README.md",
42
+ "LICENSE"
43
+ ],
44
+ "sideEffects": false,
45
+ "devDependencies": {
46
+ "tsup": "^8.5.0",
47
+ "typescript": "^5.9.2",
48
+ "vitest": "^3.2.4"
49
+ },
50
+ "scripts": {
51
+ "build": "tsup",
52
+ "dev": "tsup --watch",
53
+ "typecheck": "tsc --noEmit",
54
+ "test": "vitest run",
55
+ "lint": "tsc --noEmit",
56
+ "clean": "rm -rf dist"
57
+ }
58
+ }