@devtune/ai-traffic 0.1.2 → 0.2.1

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.
@@ -0,0 +1,505 @@
1
+ "use strict";
2
+ /**
3
+ * ABOUTME: Implements the DevTune AI Traffic edge-push client.
4
+ * Handles registry refresh, AI bot matching, batched ingest beacons, and route wrappers.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.DevTuneAiTrafficClient = exports.DEFAULT_REGISTRY_URL = exports.DEFAULT_INGEST_ENDPOINT = void 0;
8
+ exports.createDevTuneAiTraffic = createDevTuneAiTraffic;
9
+ exports.createDevTuneAiTrafficMiddleware = createDevTuneAiTrafficMiddleware;
10
+ exports.mightBeAiBotUserAgent = mightBeAiBotUserAgent;
11
+ exports.withDevTuneAiTrafficRoute = withDevTuneAiTrafficRoute;
12
+ const registry_js_1 = require("./registry.js");
13
+ exports.DEFAULT_INGEST_ENDPOINT = "https://devtune.ai/api/v1/llm-traffic/ingest";
14
+ exports.DEFAULT_REGISTRY_URL = "https://devtune.ai/api/v1/llm-traffic/registry";
15
+ const DEFAULT_REGISTRY_REVALIDATE_MS = 60 * 60 * 1000;
16
+ const DEFAULT_WAIT_UNTIL_REGISTRY_REFRESH = true;
17
+ const DEFAULT_BATCH_SIZE = 10;
18
+ const DEFAULT_FLUSH_INTERVAL_MS = 250;
19
+ const DEFAULT_STATUS = 200;
20
+ const MAX_INGEST_BATCH_SIZE = 100;
21
+ const MAX_EVENT_PATH_LENGTH = 2048;
22
+ const MAX_EVENT_UA_LENGTH = 2048;
23
+ const MAX_EVENT_URL_LENGTH = 4096;
24
+ const RATE_LIMITED_STATUS = 429;
25
+ const DEFAULT_MAX_RETRY_ATTEMPTS = 3;
26
+ const RETRY_ATTEMPTS_CEILING = 10;
27
+ const RETRY_BASE_DELAY_MS = 250;
28
+ const DEFAULT_MAX_RETRY_DELAY_MS = 5_000;
29
+ const RETRY_DELAY_CEILING_MS = 60_000;
30
+ const DEFAULT_MAX_QUEUED_EVENTS = 1_000;
31
+ const MAX_QUEUED_EVENTS_CEILING = 100_000;
32
+ const AI_BOT_USER_AGENT_HINTS = [
33
+ "-ai",
34
+ "ai-",
35
+ "agent",
36
+ "anthropic",
37
+ "bot",
38
+ "bytespider",
39
+ "claude",
40
+ "cohere",
41
+ "crawler",
42
+ "fetch",
43
+ "google-",
44
+ "gpt",
45
+ "meta-external",
46
+ "mistral",
47
+ "notebooklm",
48
+ "oai-",
49
+ "openai",
50
+ "perplexity",
51
+ "quora",
52
+ "spider",
53
+ "xai",
54
+ ];
55
+ class DevTuneAiTrafficClient {
56
+ options;
57
+ endpoint;
58
+ registryUrl;
59
+ registryRevalidateMs;
60
+ waitUntilRegistryRefresh;
61
+ batchSize;
62
+ flushIntervalMs;
63
+ defaultStatus;
64
+ fetchImpl;
65
+ logger;
66
+ now;
67
+ random;
68
+ errorSampleRate;
69
+ maxRetryAttempts;
70
+ maxRetryDelayMs;
71
+ maxQueuedEvents;
72
+ registry;
73
+ refreshPromise = null;
74
+ flushPromise = null;
75
+ delayedFlushPromise = null;
76
+ queue = [];
77
+ constructor(options) {
78
+ this.options = options;
79
+ if (!options.ingestKey) {
80
+ throw new Error("DevTune AI Traffic ingestKey is required");
81
+ }
82
+ this.endpoint = options.endpoint ?? exports.DEFAULT_INGEST_ENDPOINT;
83
+ this.registryUrl = options.registryUrl ?? exports.DEFAULT_REGISTRY_URL;
84
+ this.registryRevalidateMs = options.registryRevalidateMs ?? DEFAULT_REGISTRY_REVALIDATE_MS;
85
+ this.waitUntilRegistryRefresh =
86
+ options.waitUntilRegistryRefresh ?? DEFAULT_WAIT_UNTIL_REGISTRY_REFRESH;
87
+ this.batchSize = clampInteger(options.batchSize ?? DEFAULT_BATCH_SIZE, 1, MAX_INGEST_BATCH_SIZE);
88
+ this.flushIntervalMs = clampInteger(options.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS, 0, 60_000);
89
+ this.defaultStatus =
90
+ options.defaultStatus === null
91
+ ? null
92
+ : normalizeStatus(options.defaultStatus ?? DEFAULT_STATUS, DEFAULT_STATUS);
93
+ this.fetchImpl = options.fetch ?? fetch;
94
+ this.logger = options.logger ?? null;
95
+ this.now = options.now ?? (() => new Date());
96
+ this.random = options.random ?? Math.random;
97
+ this.errorSampleRate = clampNumber(options.errorSampleRate ?? 0.01, 0, 1);
98
+ this.maxRetryAttempts = clampInteger(options.maxRetryAttempts ?? DEFAULT_MAX_RETRY_ATTEMPTS, 0, RETRY_ATTEMPTS_CEILING);
99
+ this.maxRetryDelayMs = clampInteger(options.maxRetryDelayMs ?? DEFAULT_MAX_RETRY_DELAY_MS, 0, RETRY_DELAY_CEILING_MS);
100
+ this.maxQueuedEvents = clampInteger(options.maxQueuedEvents ?? DEFAULT_MAX_QUEUED_EVENTS, MAX_INGEST_BATCH_SIZE, MAX_QUEUED_EVENTS_CEILING);
101
+ const fallbackEntries = (0, registry_js_1.compileAiBotRegistryEntries)(registry_js_1.FALLBACK_AI_BOT_REGISTRY_ENTRIES);
102
+ const fallbackPrefilter = createRegistryPrefilter(fallbackEntries);
103
+ this.registry = {
104
+ entries: fallbackEntries,
105
+ etag: null,
106
+ fetchedAt: 0,
107
+ ...fallbackPrefilter,
108
+ version: "bundled",
109
+ };
110
+ }
111
+ mightTrackRequest(request) {
112
+ const userAgent = request.headers.get("user-agent");
113
+ if (!userAgent) {
114
+ return false;
115
+ }
116
+ if (mightBeAiBotUserAgent(userAgent) || this.registry.requiresFullPrefilterScan) {
117
+ return true;
118
+ }
119
+ const normalized = userAgent.toLowerCase();
120
+ return this.registry.userAgentHints.some((hint) => normalized.includes(hint));
121
+ }
122
+ trackRequest(request, waitUntilContext, responseStatus) {
123
+ if (!this.mightTrackRequest(request)) {
124
+ return null;
125
+ }
126
+ const userAgent = request.headers.get("user-agent");
127
+ if (!userAgent) {
128
+ return null;
129
+ }
130
+ const entry = (0, registry_js_1.matchAiBotRegistryEntry)(userAgent, this.registry.entries);
131
+ if (!entry) {
132
+ if (mightBeAiBotUserAgent(userAgent)) {
133
+ this.refreshRegistryIfStale(waitUntilContext);
134
+ }
135
+ return null;
136
+ }
137
+ this.refreshRegistryIfStale(waitUntilContext);
138
+ const event = this.createEvent(request, userAgent, responseStatus);
139
+ if (!event) {
140
+ return null;
141
+ }
142
+ this.enqueue(event, waitUntilContext);
143
+ return {
144
+ entry,
145
+ event,
146
+ };
147
+ }
148
+ async refreshRegistry() {
149
+ const headers = {
150
+ accept: "application/json",
151
+ };
152
+ if (this.registry.etag) {
153
+ headers["if-none-match"] = this.registry.etag;
154
+ }
155
+ const response = await this.fetchImpl(this.registryUrl, {
156
+ headers,
157
+ method: "GET",
158
+ });
159
+ if (response.status === 304) {
160
+ this.registry = {
161
+ ...this.registry,
162
+ fetchedAt: Date.now(),
163
+ };
164
+ return;
165
+ }
166
+ if (!response.ok) {
167
+ throw new Error(`Registry request failed with status ${response.status}`);
168
+ }
169
+ const payload = (0, registry_js_1.parseAiBotRegistryPayload)(await response.json());
170
+ if (!payload) {
171
+ throw new Error("Registry response was not a valid DevTune registry");
172
+ }
173
+ const entries = (0, registry_js_1.compileAiBotRegistryEntries)(payload.entries);
174
+ this.registry = {
175
+ entries,
176
+ etag: response.headers.get("etag") ?? `"${payload.version}"`,
177
+ fetchedAt: Date.now(),
178
+ ...createRegistryPrefilter(entries),
179
+ version: payload.version,
180
+ };
181
+ }
182
+ async flush() {
183
+ if (this.flushPromise) {
184
+ return this.flushPromise;
185
+ }
186
+ this.flushPromise = this.flushQueuedEvents().finally(() => {
187
+ this.flushPromise = null;
188
+ });
189
+ return this.flushPromise;
190
+ }
191
+ refreshRegistryIfStale(waitUntilContext) {
192
+ if (this.refreshPromise) {
193
+ return;
194
+ }
195
+ if (Date.now() - this.registry.fetchedAt < this.registryRevalidateMs) {
196
+ return;
197
+ }
198
+ this.refreshPromise = this.refreshRegistry()
199
+ .catch((error) => {
200
+ this.registry = {
201
+ ...this.registry,
202
+ fetchedAt: Date.now(),
203
+ };
204
+ this.sampleWarn("Failed to refresh DevTune AI bot registry", { error });
205
+ })
206
+ .finally(() => {
207
+ this.refreshPromise = null;
208
+ });
209
+ scheduleBackground(this.refreshPromise, this.waitUntilRegistryRefresh ? waitUntilContext : undefined);
210
+ }
211
+ createEvent(request, userAgent, responseStatus) {
212
+ const url = parseRequestUrl(request.url);
213
+ if (!url) {
214
+ return null;
215
+ }
216
+ const pathname = truncateString(url.pathname || "/", MAX_EVENT_PATH_LENGTH);
217
+ const status = this.resolveStatus(request, pathname, responseStatus);
218
+ return {
219
+ path: pathname,
220
+ url: truncateString(`${url.origin}${pathname}`, MAX_EVENT_URL_LENGTH),
221
+ ua: truncateString(userAgent, MAX_EVENT_UA_LENGTH),
222
+ ...(status === null ? {} : { status }),
223
+ ts: this.now().toISOString(),
224
+ };
225
+ }
226
+ resolveStatus(request, pathname, responseStatus) {
227
+ if (responseStatus === null) {
228
+ return null;
229
+ }
230
+ const explicitStatus = normalizeStatus(responseStatus, null);
231
+ if (explicitStatus !== null) {
232
+ return explicitStatus;
233
+ }
234
+ const resolverStatus = this.options.statusResolver?.(request);
235
+ if (resolverStatus === null) {
236
+ return null;
237
+ }
238
+ const resolvedStatus = normalizeStatus(resolverStatus, null);
239
+ if (resolvedStatus !== null) {
240
+ return resolvedStatus;
241
+ }
242
+ if (this.matchesNotFoundPath(pathname)) {
243
+ return 404;
244
+ }
245
+ return this.defaultStatus;
246
+ }
247
+ matchesNotFoundPath(pathname) {
248
+ for (const pattern of this.options.notFoundPathPatterns ?? []) {
249
+ if (typeof pattern === "string") {
250
+ if (pattern === pathname) {
251
+ return true;
252
+ }
253
+ continue;
254
+ }
255
+ pattern.lastIndex = 0;
256
+ if (pattern.test(pathname)) {
257
+ return true;
258
+ }
259
+ }
260
+ return false;
261
+ }
262
+ /**
263
+ * Adds an event to the queue and decides when to send.
264
+ *
265
+ * Backing off on a 429 means the queue can now drain slower than traffic
266
+ * arrives, which it never could when every batch cost exactly one request.
267
+ * The bound is what keeps that from growing without limit in a customer's
268
+ * process: past `maxQueuedEvents` the oldest events are shed, because the
269
+ * newest ones are the ones still worth measuring.
270
+ */
271
+ enqueue(event, waitUntilContext) {
272
+ this.queue.push(event);
273
+ if (this.queue.length > this.maxQueuedEvents) {
274
+ const shed = this.queue.splice(0, this.queue.length - this.maxQueuedEvents);
275
+ this.sampleWarn("DevTune AI Traffic ingest queue overflowed", {
276
+ droppedEvents: shed.length,
277
+ maxQueuedEvents: this.maxQueuedEvents,
278
+ });
279
+ }
280
+ if (this.queue.length >= this.batchSize) {
281
+ scheduleBackground(this.flush(), waitUntilContext);
282
+ return;
283
+ }
284
+ if (this.delayedFlushPromise) {
285
+ scheduleBackground(this.delayedFlushPromise, waitUntilContext);
286
+ return;
287
+ }
288
+ this.delayedFlushPromise = delay(this.flushIntervalMs)
289
+ .then(() => this.flush())
290
+ .finally(() => {
291
+ this.delayedFlushPromise = null;
292
+ });
293
+ scheduleBackground(this.delayedFlushPromise, waitUntilContext);
294
+ }
295
+ /**
296
+ * Drains the queue one wire batch at a time.
297
+ *
298
+ * A 429 is the one failure the ingest endpoint tells us is temporary, so the
299
+ * batch is held out of the queue and redelivered after the server's
300
+ * `Retry-After`, or a capped exponential backoff when the header is absent or
301
+ * unparseable. Holding it locally rather than putting it back at the head of
302
+ * the queue keeps the wire batch intact: events that arrive during a backoff
303
+ * are not folded into the batch being retried, so they cannot be dropped on a
304
+ * bound they never had a chance to spend.
305
+ *
306
+ * The retry budget belongs to the whole drain, not to each batch. A per-batch
307
+ * bound says nothing about how long a drain can run, because a throttled
308
+ * endpoint rejects every batch in turn and traffic keeps arriving behind it.
309
+ * One budget per pass caps the added latency of a flush at
310
+ * `maxRetryAttempts * maxRetryDelayMs` no matter how deep the queue is. When
311
+ * it is spent the current batch is dropped with the usual sampled warning and
312
+ * the drain stops, leaving the rest queued for the next flush, which gets a
313
+ * fresh budget.
314
+ *
315
+ * Every other failure keeps its previous behavior: one attempt, dropped, and
316
+ * a sampled warning.
317
+ */
318
+ async flushQueuedEvents() {
319
+ let retryBudget = this.maxRetryAttempts;
320
+ while (this.queue.length > 0) {
321
+ const batch = this.queue.splice(0, MAX_INGEST_BATCH_SIZE);
322
+ let attempts = 0;
323
+ for (;;) {
324
+ let response;
325
+ try {
326
+ response = await this.fetchImpl(this.endpoint, {
327
+ body: JSON.stringify({ events: batch }),
328
+ headers: {
329
+ authorization: `Bearer ${this.options.ingestKey}`,
330
+ "content-type": "application/json",
331
+ },
332
+ keepalive: true,
333
+ method: "POST",
334
+ });
335
+ }
336
+ catch (error) {
337
+ this.sampleWarn("DevTune AI Traffic ingest request failed", { error });
338
+ break;
339
+ }
340
+ attempts += 1;
341
+ if (response.status !== RATE_LIMITED_STATUS) {
342
+ if (!response.ok) {
343
+ this.sampleWarn("DevTune AI Traffic ingest request failed", {
344
+ status: response.status,
345
+ });
346
+ }
347
+ break;
348
+ }
349
+ if (retryBudget === 0) {
350
+ this.sampleWarn("DevTune AI Traffic ingest request failed", {
351
+ attempts,
352
+ droppedEvents: batch.length,
353
+ status: response.status,
354
+ });
355
+ return;
356
+ }
357
+ const retryDelayMs = this.resolveRetryDelayMs(response.headers.get("retry-after"), this.maxRetryAttempts - retryBudget);
358
+ retryBudget -= 1;
359
+ await delay(retryDelayMs);
360
+ }
361
+ }
362
+ }
363
+ resolveRetryDelayMs(retryAfterHeader, retryAttempts) {
364
+ const retryAfterMs = parseRetryAfterMs(retryAfterHeader, this.now());
365
+ const backoffMs = RETRY_BASE_DELAY_MS * 2 ** retryAttempts;
366
+ return Math.min(retryAfterMs ?? backoffMs, this.maxRetryDelayMs);
367
+ }
368
+ sampleWarn(message, context) {
369
+ if (this.errorSampleRate === 0 || this.random() > this.errorSampleRate) {
370
+ return;
371
+ }
372
+ this.logger?.warn(message, context);
373
+ }
374
+ }
375
+ exports.DevTuneAiTrafficClient = DevTuneAiTrafficClient;
376
+ function createDevTuneAiTraffic(options) {
377
+ return new DevTuneAiTrafficClient(options);
378
+ }
379
+ function createDevTuneAiTrafficMiddleware(options) {
380
+ const client = createDevTuneAiTraffic({
381
+ ...options,
382
+ defaultStatus: options.defaultStatus ?? null,
383
+ waitUntilRegistryRefresh: options.waitUntilRegistryRefresh ?? false,
384
+ });
385
+ return function devTuneAiTrafficMiddleware(request, event) {
386
+ client.trackRequest(request, event);
387
+ };
388
+ }
389
+ function mightBeAiBotUserAgent(userAgent) {
390
+ if (!userAgent) {
391
+ return false;
392
+ }
393
+ const normalized = userAgent.toLowerCase();
394
+ return AI_BOT_USER_AGENT_HINTS.some((hint) => normalized.includes(hint));
395
+ }
396
+ function withDevTuneAiTrafficRoute(handler, options) {
397
+ const client = createDevTuneAiTraffic(options);
398
+ return async function devTuneAiTrafficRoute(request, context) {
399
+ const response = await handler(request, context);
400
+ const waitUntilContext = getWaitUntilContext(context);
401
+ client.trackRequest(request, waitUntilContext, response.status);
402
+ return response;
403
+ };
404
+ }
405
+ function scheduleBackground(promise, waitUntilContext) {
406
+ const guardedPromise = promise.catch(() => undefined);
407
+ if (waitUntilContext) {
408
+ waitUntilContext.waitUntil(guardedPromise);
409
+ return;
410
+ }
411
+ void guardedPromise;
412
+ }
413
+ function getWaitUntilContext(value) {
414
+ if (!isRecord(value)) {
415
+ return undefined;
416
+ }
417
+ const waitUntil = value.waitUntil;
418
+ if (typeof waitUntil !== "function") {
419
+ return undefined;
420
+ }
421
+ return {
422
+ waitUntil: (promise) => {
423
+ waitUntil.call(value, promise);
424
+ },
425
+ };
426
+ }
427
+ function parseRequestUrl(url) {
428
+ try {
429
+ return new URL(url);
430
+ }
431
+ catch {
432
+ return null;
433
+ }
434
+ }
435
+ function delay(ms) {
436
+ if (ms <= 0) {
437
+ return Promise.resolve();
438
+ }
439
+ return new Promise((resolve) => {
440
+ setTimeout(resolve, ms);
441
+ });
442
+ }
443
+ /**
444
+ * Reads an RFC 9110 `Retry-After` value in either accepted form: delay seconds,
445
+ * or an HTTP date. Returns null when the header is missing or unusable so the
446
+ * caller can fall back to its own backoff.
447
+ */
448
+ function parseRetryAfterMs(value, now) {
449
+ const trimmed = value?.trim();
450
+ if (!trimmed) {
451
+ return null;
452
+ }
453
+ if (/^\d+$/u.test(trimmed)) {
454
+ return Number(trimmed) * 1000;
455
+ }
456
+ const retryAt = Date.parse(trimmed);
457
+ if (Number.isNaN(retryAt)) {
458
+ return null;
459
+ }
460
+ return Math.max(retryAt - now.getTime(), 0);
461
+ }
462
+ function createRegistryPrefilter(entries) {
463
+ const userAgentHints = new Set();
464
+ let requiresFullPrefilterScan = false;
465
+ for (const { entry } of entries) {
466
+ const hint = entry.uaPattern.toLowerCase();
467
+ if (hint.length < 3 || /[.^$|]/u.test(hint)) {
468
+ requiresFullPrefilterScan = true;
469
+ continue;
470
+ }
471
+ userAgentHints.add(hint);
472
+ }
473
+ return {
474
+ requiresFullPrefilterScan,
475
+ userAgentHints: [...userAgentHints],
476
+ };
477
+ }
478
+ function normalizeStatus(value, fallback) {
479
+ if (typeof value === "number" && Number.isInteger(value) && value >= 100 && value <= 599) {
480
+ return value;
481
+ }
482
+ return fallback;
483
+ }
484
+ function clampInteger(value, min, max) {
485
+ if (!Number.isFinite(value)) {
486
+ return min;
487
+ }
488
+ return Math.min(Math.max(Math.trunc(value), min), max);
489
+ }
490
+ function clampNumber(value, min, max) {
491
+ if (!Number.isFinite(value)) {
492
+ return min;
493
+ }
494
+ return Math.min(Math.max(value, min), max);
495
+ }
496
+ function truncateString(value, maxLength) {
497
+ if (value.length <= maxLength) {
498
+ return value;
499
+ }
500
+ return value.slice(0, maxLength);
501
+ }
502
+ function isRecord(value) {
503
+ return typeof value === "object" && value !== null;
504
+ }
505
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ /**
3
+ * ABOUTME: Standalone AI crawler and referrer classifiers for package consumers.
4
+ * Uses injectable registry entries with bundled snapshots as the offline default.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.FALLBACK_AI_REFERRER_REGISTRY_ENTRIES = void 0;
8
+ exports.detectAiCrawler = detectAiCrawler;
9
+ exports.detectAiReferrer = detectAiReferrer;
10
+ const registry_js_1 = require("./registry.js");
11
+ exports.FALLBACK_AI_REFERRER_REGISTRY_ENTRIES = [
12
+ { hostname: "chat.openai.com", llmPlatform: "openai", label: "ChatGPT" },
13
+ { hostname: "chatgpt.com", llmPlatform: "openai", label: "ChatGPT" },
14
+ { hostname: "claude.ai", llmPlatform: "anthropic", label: "Claude" },
15
+ { hostname: "perplexity.ai", llmPlatform: "perplexity", label: "Perplexity" },
16
+ { hostname: "gemini.google.com", llmPlatform: "google", label: "Gemini" },
17
+ { hostname: "copilot.microsoft.com", llmPlatform: "microsoft", label: "Copilot" },
18
+ { hostname: "meta.ai", llmPlatform: "meta", label: "Meta AI" },
19
+ ];
20
+ function detectAiCrawler(input, options = {}) {
21
+ const userAgent = typeof input === "string" ? input : input.headers.get("user-agent");
22
+ const entries = (0, registry_js_1.compileAiBotRegistryEntries)(options.registryEntries ?? registry_js_1.FALLBACK_AI_BOT_REGISTRY_ENTRIES);
23
+ return (0, registry_js_1.matchAiBotRegistryEntry)(userAgent, entries);
24
+ }
25
+ function detectAiReferrer(input, options = {}) {
26
+ const referrer = typeof input === "string"
27
+ ? input
28
+ : (input.headers.get("referer") ?? input.headers.get("referrer"));
29
+ if (!referrer) {
30
+ return null;
31
+ }
32
+ let hostname;
33
+ try {
34
+ hostname = new URL(referrer).hostname.toLowerCase().replace(/\.$/u, "");
35
+ }
36
+ catch {
37
+ return null;
38
+ }
39
+ for (const entry of options.registryEntries ?? exports.FALLBACK_AI_REFERRER_REGISTRY_ENTRIES) {
40
+ const knownHostname = entry.hostname.toLowerCase().replace(/\.$/u, "");
41
+ if (hostname === knownHostname || hostname.endsWith(`.${knownHostname}`)) {
42
+ return entry;
43
+ }
44
+ }
45
+ return null;
46
+ }
47
+ //# sourceMappingURL=detection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detection.js","sourceRoot":"","sources":["../../src/detection.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AA4CH,0CAUC;AAED,4CA8BC;AApFD,+CAMuB;AA0BV,QAAA,qCAAqC,GAAG;IACnD,EAAE,QAAQ,EAAE,iBAAiB,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE;IACxE,EAAE,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE;IACpE,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE;IACpE,EAAE,QAAQ,EAAE,eAAe,EAAE,WAAW,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE;IAC7E,EAAE,QAAQ,EAAE,mBAAmB,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE;IACzE,EAAE,QAAQ,EAAE,uBAAuB,EAAE,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE;IACjF,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE;CAClB,CAAC;AAE/C,SAAgB,eAAe,CAC7B,KAAoC,EACpC,UAAkC,EAAE;IAEpC,MAAM,SAAS,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACtF,MAAM,OAAO,GAAG,IAAA,yCAA2B,EACzC,OAAO,CAAC,eAAe,IAAI,8CAAgC,CAC5D,CAAC;IAEF,OAAO,IAAA,qCAAuB,EAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AACrD,CAAC;AAED,SAAgB,gBAAgB,CAC9B,KAAoC,EACpC,UAAmC,EAAE;IAErC,MAAM,QAAQ,GACZ,OAAO,KAAK,KAAK,QAAQ;QACvB,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;IAEtE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,QAAgB,CAAC;IAErB,IAAI,CAAC;QACH,QAAQ,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC1E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,eAAe,IAAI,6CAAqC,EAAE,CAAC;QACrF,MAAM,aAAa,GAAG,KAAK,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAEvE,IAAI,QAAQ,KAAK,aAAa,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,aAAa,EAAE,CAAC,EAAE,CAAC;YACzE,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ /**
3
+ * ABOUTME: Express middleware adapter for the DevTune AI Traffic client.
4
+ * Maps Express requests after response completion while sharing core matching and ingest logic.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.createDevTuneAiTrafficExpressMiddleware = createDevTuneAiTrafficExpressMiddleware;
8
+ const ai_traffic_1 = require("@devtune/ai-traffic");
9
+ function createDevTuneAiTrafficExpressMiddleware(options) {
10
+ const { origin, ...clientOptions } = options;
11
+ const client = (0, ai_traffic_1.createDevTuneAiTraffic)(clientOptions);
12
+ return function devTuneAiTrafficExpressMiddleware(request, response, next) {
13
+ const requestLike = {
14
+ headers: createHeadersLike(request),
15
+ url: createRequestUrl(request, origin),
16
+ };
17
+ if (!client.mightTrackRequest(requestLike)) {
18
+ next();
19
+ return;
20
+ }
21
+ response.once("finish", () => {
22
+ client.trackRequest(requestLike, undefined, response.statusCode);
23
+ });
24
+ next();
25
+ };
26
+ }
27
+ function createHeadersLike(request) {
28
+ return {
29
+ get(name) {
30
+ return getHeader(request, name);
31
+ },
32
+ };
33
+ }
34
+ function createRequestUrl(request, configuredOrigin) {
35
+ const requestPath = request.originalUrl ?? request.url;
36
+ try {
37
+ return new URL(requestPath, configuredOrigin ?? getRequestOrigin(request)).toString();
38
+ }
39
+ catch {
40
+ return requestPath;
41
+ }
42
+ }
43
+ function getRequestOrigin(request) {
44
+ const protocol = getForwardedHeader(request, "x-forwarded-proto") ?? request.protocol ?? "http";
45
+ const host = getForwardedHeader(request, "x-forwarded-host") ?? getHeader(request, "host") ?? "localhost";
46
+ return `${protocol}://${host}`;
47
+ }
48
+ function getHeader(request, name) {
49
+ return request.get?.(name) ?? headerValue(request.headers[name.toLowerCase()]);
50
+ }
51
+ function getForwardedHeader(request, name) {
52
+ const value = getHeader(request, name);
53
+ return value?.split(",", 1)[0]?.trim() || null;
54
+ }
55
+ function headerValue(value) {
56
+ if (typeof value === "string") {
57
+ return value;
58
+ }
59
+ return value?.[0] ?? null;
60
+ }
61
+ //# sourceMappingURL=express.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"express.js","sourceRoot":"","sources":["../../../express/src/express.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AA6BH,0FA0BC;AArDD,oDAI6B;AAuB7B,SAAgB,uCAAuC,CAAC,OAAuC;IAC7F,MAAM,EAAE,MAAM,EAAE,GAAG,aAAa,EAAE,GAAG,OAAO,CAAC;IAC7C,MAAM,MAAM,GAAG,IAAA,mCAAsB,EAAC,aAAa,CAAC,CAAC;IAErD,OAAO,SAAS,iCAAiC,CAC/C,OAAuC,EACvC,QAAyC,EACzC,IAAiC;QAEjC,MAAM,WAAW,GAAG;YAClB,OAAO,EAAE,iBAAiB,CAAC,OAAO,CAAC;YACnC,GAAG,EAAE,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC;SACvC,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,WAAW,CAAC,EAAE,CAAC;YAC3C,IAAI,EAAE,CAAC;YAEP,OAAO;QACT,CAAC;QAED,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE;YAC3B,MAAM,CAAC,YAAY,CAAC,WAAW,EAAE,SAAS,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;QACnE,CAAC,CAAC,CAAC;QAEH,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,OAAuC;IAChE,OAAO;QACL,GAAG,CAAC,IAAI;YACN,OAAO,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAClC,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,OAAuC,EAAE,gBAAyB;IAC1F,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC;IAEvD,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,WAAW,EAAE,gBAAgB,IAAI,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACxF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,WAAW,CAAC;IACrB,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,OAAuC;IAC/D,MAAM,QAAQ,GAAG,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,CAAC,IAAI,OAAO,CAAC,QAAQ,IAAI,MAAM,CAAC;IAChG,MAAM,IAAI,GACR,kBAAkB,CAAC,OAAO,EAAE,kBAAkB,CAAC,IAAI,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,WAAW,CAAC;IAE/F,OAAO,GAAG,QAAQ,MAAM,IAAI,EAAE,CAAC;AACjC,CAAC;AAED,SAAS,SAAS,CAAC,OAAuC,EAAE,IAAY;IACtE,OAAO,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;AACjF,CAAC;AAED,SAAS,kBAAkB,CAAC,OAAuC,EAAE,IAAY;IAC/E,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAEvC,OAAO,KAAK,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC;AACjD,CAAC;AAED,SAAS,WAAW,CAAC,KAAkB;IACrC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AAC5B,CAAC"}