@justanalyticsapp/node 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.
Files changed (52) hide show
  1. package/dist/client.d.ts +286 -0
  2. package/dist/client.js +681 -0
  3. package/dist/client.js.map +1 -0
  4. package/dist/context.d.ts +126 -0
  5. package/dist/context.js +170 -0
  6. package/dist/context.js.map +1 -0
  7. package/dist/errors.d.ts +135 -0
  8. package/dist/errors.js +180 -0
  9. package/dist/errors.js.map +1 -0
  10. package/dist/index.d.ts +301 -0
  11. package/dist/index.js +314 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/integrations/express.d.ts +77 -0
  14. package/dist/integrations/express.js +87 -0
  15. package/dist/integrations/express.js.map +1 -0
  16. package/dist/integrations/http.d.ts +129 -0
  17. package/dist/integrations/http.js +465 -0
  18. package/dist/integrations/http.js.map +1 -0
  19. package/dist/integrations/metrics.d.ts +110 -0
  20. package/dist/integrations/metrics.js +313 -0
  21. package/dist/integrations/metrics.js.map +1 -0
  22. package/dist/integrations/next.d.ts +252 -0
  23. package/dist/integrations/next.js +480 -0
  24. package/dist/integrations/next.js.map +1 -0
  25. package/dist/integrations/pg.d.ts +169 -0
  26. package/dist/integrations/pg.js +616 -0
  27. package/dist/integrations/pg.js.map +1 -0
  28. package/dist/integrations/pino.d.ts +52 -0
  29. package/dist/integrations/pino.js +153 -0
  30. package/dist/integrations/pino.js.map +1 -0
  31. package/dist/integrations/redis.d.ts +190 -0
  32. package/dist/integrations/redis.js +597 -0
  33. package/dist/integrations/redis.js.map +1 -0
  34. package/dist/integrations/winston.d.ts +48 -0
  35. package/dist/integrations/winston.js +99 -0
  36. package/dist/integrations/winston.js.map +1 -0
  37. package/dist/logger.d.ts +148 -0
  38. package/dist/logger.js +162 -0
  39. package/dist/logger.js.map +1 -0
  40. package/dist/span.d.ts +192 -0
  41. package/dist/span.js +197 -0
  42. package/dist/span.js.map +1 -0
  43. package/dist/transport.d.ts +246 -0
  44. package/dist/transport.js +654 -0
  45. package/dist/transport.js.map +1 -0
  46. package/dist/utils/headers.d.ts +60 -0
  47. package/dist/utils/headers.js +93 -0
  48. package/dist/utils/headers.js.map +1 -0
  49. package/dist/utils/id.d.ts +23 -0
  50. package/dist/utils/id.js +36 -0
  51. package/dist/utils/id.js.map +1 -0
  52. package/package.json +65 -0
@@ -0,0 +1,654 @@
1
+ "use strict";
2
+ /**
3
+ * @file packages/node-sdk/src/transport.ts
4
+ * @description Batched HTTP transport for sending span and error data to the JustAnalytics server.
5
+ *
6
+ * Implements Story 035 - Node.js SDK Core
7
+ * Updated for Story 041 - Server-Side Error Tracking via SDK
8
+ * Updated for Story 046 - SDK Log Integration
9
+ * Updated for Story 048 - Infrastructure Metrics Collection
10
+ *
11
+ * The BatchTransport collects ended spans, error events, log entries, and
12
+ * infrastructure metrics in separate in-memory buffers and periodically
13
+ * flushes them to their respective endpoints:
14
+ * - Spans: `POST /api/ingest/spans` (batched, 1-100 per request)
15
+ * - Errors: `POST /api/ingest/errors` (individual, one per request)
16
+ * - Logs: `POST /api/ingest/logs` (batched, 1-100 per request)
17
+ * - Metrics: `POST /api/ingest/metrics` (batched, 1-500 per request)
18
+ *
19
+ * It uses Node.js built-in `http`/`https` modules (not fetch, not axios)
20
+ * for maximum compatibility with Node.js 18+.
21
+ *
22
+ * Flush behavior:
23
+ * - Timer-based: flushes every `flushIntervalMs` milliseconds (default: 2000)
24
+ * - Size-based: flushes immediately when buffer reaches `maxBatchSize` (default: 100)
25
+ * - Manual: `flush()` can be called explicitly
26
+ *
27
+ * Error handling:
28
+ * - HTTP 429 (rate limited): doubles flush interval for 60 seconds, then resets
29
+ * - Network errors / non-2xx: logs warning (in debug mode), drops the batch
30
+ * - Never throws unhandled exceptions that could crash the host process
31
+ *
32
+ * References:
33
+ * - src/app/api/ingest/spans/route.ts (target endpoint and expected payload format)
34
+ * - src/app/api/ingest/errors/route.ts (error ingestion endpoint)
35
+ */
36
+ var __importDefault = (this && this.__importDefault) || function (mod) {
37
+ return (mod && mod.__esModule) ? mod : { "default": mod };
38
+ };
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.BatchTransport = void 0;
41
+ const http_1 = __importDefault(require("http"));
42
+ const https_1 = __importDefault(require("https"));
43
+ const url_1 = require("url");
44
+ /**
45
+ * BatchTransport collects spans and errors in memory and sends them
46
+ * in batches to the JustAnalytics ingestion endpoints.
47
+ *
48
+ * Uses Node.js built-in `http`/`https` modules for HTTP communication.
49
+ * Implements timer-based and size-based flushing with 429 backoff.
50
+ */
51
+ class BatchTransport {
52
+ constructor(options) {
53
+ this.buffer = [];
54
+ this.errorBuffer = [];
55
+ this.logBuffer = [];
56
+ this.metricBuffer = [];
57
+ this.timer = null;
58
+ /** Independent flushing guards for spans, errors, logs, and metrics */
59
+ this.isFlushingSpans = false;
60
+ this.isFlushingErrors = false;
61
+ this.isFlushingLogs = false;
62
+ this.isFlushingMetrics = false;
63
+ /** Timer for resetting flush interval after 429 backoff */
64
+ this.backoffResetTimer = null;
65
+ this.serverUrl = options.serverUrl;
66
+ this.apiKey = options.apiKey;
67
+ this.flushIntervalMs = options.flushIntervalMs;
68
+ this.maxBatchSize = options.maxBatchSize;
69
+ this.debug = options.debug;
70
+ this.originalFlushIntervalMs = options.flushIntervalMs;
71
+ this.currentFlushIntervalMs = options.flushIntervalMs;
72
+ }
73
+ /**
74
+ * Enqueue a span payload for batched sending.
75
+ *
76
+ * If the buffer reaches `maxBatchSize`, triggers an immediate flush.
77
+ *
78
+ * @param span - Serialized span payload to enqueue
79
+ */
80
+ enqueue(span) {
81
+ this.buffer.push(span);
82
+ if (this.buffer.length >= this.maxBatchSize) {
83
+ // Trigger immediate flush (fire-and-forget)
84
+ this.flushSpans().catch(() => {
85
+ // Errors handled inside flushSpans()
86
+ });
87
+ }
88
+ }
89
+ /**
90
+ * Enqueue an error event payload for batched sending.
91
+ * Errors are flushed alongside spans on the periodic timer.
92
+ *
93
+ * @param payload - Error event payload to enqueue
94
+ */
95
+ enqueueError(payload) {
96
+ this.errorBuffer.push(payload);
97
+ if (this.errorBuffer.length >= this.maxBatchSize) {
98
+ this.flushErrors().catch(() => {
99
+ // Errors handled inside flushErrors()
100
+ });
101
+ }
102
+ }
103
+ /**
104
+ * Enqueue a log entry payload for batched sending.
105
+ * Logs are flushed alongside spans and errors on the periodic timer.
106
+ *
107
+ * If the buffer reaches `maxBatchSize`, triggers an immediate flush.
108
+ *
109
+ * @param entry - Log entry payload to enqueue
110
+ */
111
+ enqueueLog(entry) {
112
+ this.logBuffer.push(entry);
113
+ if (this.logBuffer.length >= this.maxBatchSize) {
114
+ this.flushLogs().catch(() => {
115
+ // Errors handled inside flushLogs()
116
+ });
117
+ }
118
+ }
119
+ /**
120
+ * Enqueue an infrastructure metric payload for batched sending.
121
+ * Metrics are flushed alongside spans, errors, and logs on the periodic timer.
122
+ *
123
+ * If the buffer reaches `maxBatchSize`, triggers an immediate flush.
124
+ *
125
+ * @param metric - Metric data point payload to enqueue
126
+ */
127
+ enqueueMetric(metric) {
128
+ this.metricBuffer.push(metric);
129
+ if (this.metricBuffer.length >= this.maxBatchSize) {
130
+ this.flushMetrics().catch(() => {
131
+ // Errors handled inside flushMetrics()
132
+ });
133
+ }
134
+ }
135
+ /**
136
+ * Send a single error immediately (non-batched).
137
+ * Used for uncaughtException where the process is about to exit.
138
+ *
139
+ * Fire-and-forget: the promise result is intentionally not awaited
140
+ * by the caller because the process is exiting.
141
+ *
142
+ * @param payload - Error event payload to send immediately
143
+ */
144
+ sendErrorImmediate(payload) {
145
+ try {
146
+ this.sendSingleError(payload).catch(() => {
147
+ // Never throw from immediate send
148
+ });
149
+ }
150
+ catch {
151
+ // Never throw
152
+ }
153
+ }
154
+ /**
155
+ * Flush all pending spans and errors to the server.
156
+ *
157
+ * Delegates to `flushSpans()` and `flushErrors()` in parallel.
158
+ * Each sub-method has its own isFlushing guard.
159
+ *
160
+ * @returns Promise that resolves when both flushes complete
161
+ */
162
+ async flush() {
163
+ await Promise.all([
164
+ this.flushSpans(),
165
+ this.flushErrors(),
166
+ this.flushLogs(),
167
+ this.flushMetrics(),
168
+ ]);
169
+ }
170
+ /**
171
+ * Flush all pending span payloads to `POST /api/ingest/spans`.
172
+ *
173
+ * Sends all buffered spans in a single HTTP request.
174
+ * The buffer is cleared before sending, so new spans that arrive
175
+ * during the flush are queued for the next flush.
176
+ *
177
+ * @returns Promise that resolves when the flush completes (or fails)
178
+ */
179
+ async flushSpans() {
180
+ if (this.buffer.length === 0)
181
+ return;
182
+ if (this.isFlushingSpans)
183
+ return;
184
+ this.isFlushingSpans = true;
185
+ // Take the current buffer and clear it
186
+ const batch = this.buffer.splice(0, this.buffer.length);
187
+ try {
188
+ await this.sendBatch(batch);
189
+ }
190
+ catch (error) {
191
+ if (this.debug) {
192
+ console.debug(`[JustAnalytics] Span flush failed, dropped ${batch.length} span(s):`, error instanceof Error ? error.message : String(error));
193
+ }
194
+ // Drop the batch -- do not re-enqueue to prevent memory leaks
195
+ }
196
+ finally {
197
+ this.isFlushingSpans = false;
198
+ }
199
+ }
200
+ /**
201
+ * Flush all pending error event payloads to `POST /api/ingest/errors`.
202
+ *
203
+ * Each error is sent as an individual POST request because the server-side
204
+ * fingerprinting and upsert logic operates on individual events.
205
+ *
206
+ * @returns Promise that resolves when all errors are sent (or dropped)
207
+ */
208
+ async flushErrors() {
209
+ if (this.errorBuffer.length === 0)
210
+ return;
211
+ if (this.isFlushingErrors)
212
+ return;
213
+ this.isFlushingErrors = true;
214
+ const batch = this.errorBuffer.splice(0, this.errorBuffer.length);
215
+ try {
216
+ await this.sendErrorBatch(batch);
217
+ }
218
+ catch (error) {
219
+ if (this.debug) {
220
+ console.debug(`[JustAnalytics] Error flush failed, dropped ${batch.length} error(s):`, error instanceof Error ? error.message : String(error));
221
+ }
222
+ }
223
+ finally {
224
+ this.isFlushingErrors = false;
225
+ }
226
+ }
227
+ /**
228
+ * Start the periodic flush timer.
229
+ *
230
+ * Uses `setInterval` with the current effective flush interval.
231
+ * The timer is `unref()`'d so it does not keep the process alive.
232
+ */
233
+ start() {
234
+ this.stop(); // Clear any existing timer
235
+ this.timer = setInterval(() => {
236
+ this.flush().catch(() => {
237
+ // Errors handled inside flush()
238
+ });
239
+ }, this.currentFlushIntervalMs);
240
+ // unref() so the timer doesn't keep the Node.js process alive
241
+ if (this.timer && typeof this.timer.unref === 'function') {
242
+ this.timer.unref();
243
+ }
244
+ }
245
+ /**
246
+ * Stop the periodic flush timer.
247
+ */
248
+ stop() {
249
+ if (this.timer !== null) {
250
+ clearInterval(this.timer);
251
+ this.timer = null;
252
+ }
253
+ if (this.backoffResetTimer !== null) {
254
+ clearTimeout(this.backoffResetTimer);
255
+ this.backoffResetTimer = null;
256
+ }
257
+ }
258
+ /**
259
+ * Number of spans currently in the buffer awaiting flush.
260
+ */
261
+ get pendingCount() {
262
+ return this.buffer.length;
263
+ }
264
+ /**
265
+ * Number of errors currently in the error buffer awaiting flush.
266
+ */
267
+ get pendingErrorCount() {
268
+ return this.errorBuffer.length;
269
+ }
270
+ /**
271
+ * Number of log entries currently in the buffer awaiting flush.
272
+ */
273
+ get pendingLogCount() {
274
+ return this.logBuffer.length;
275
+ }
276
+ /**
277
+ * Number of metrics currently in the buffer awaiting flush.
278
+ */
279
+ get pendingMetricCount() {
280
+ return this.metricBuffer.length;
281
+ }
282
+ /**
283
+ * Send a batch of spans via HTTP POST to /api/ingest/spans.
284
+ *
285
+ * Uses Node.js built-in `http` or `https` module based on the server URL
286
+ * protocol. Handles HTTP 429 with backoff.
287
+ *
288
+ * @param batch - Array of span payloads to send
289
+ */
290
+ sendBatch(batch) {
291
+ return new Promise((resolve) => {
292
+ const body = JSON.stringify({ spans: batch });
293
+ const url = new url_1.URL('/api/ingest/spans', this.serverUrl);
294
+ const isHttps = url.protocol === 'https:';
295
+ const transport = isHttps ? https_1.default : http_1.default;
296
+ const requestOptions = {
297
+ hostname: url.hostname,
298
+ port: url.port || (isHttps ? 443 : 80),
299
+ path: url.pathname,
300
+ method: 'POST',
301
+ headers: {
302
+ 'Content-Type': 'application/json',
303
+ 'Content-Length': Buffer.byteLength(body),
304
+ 'Authorization': `Bearer ${this.apiKey}`,
305
+ },
306
+ timeout: 10000, // 10 second timeout
307
+ };
308
+ const req = transport.request(requestOptions, (res) => {
309
+ // Consume response body
310
+ const chunks = [];
311
+ res.on('data', (chunk) => chunks.push(chunk));
312
+ res.on('end', () => {
313
+ const statusCode = res.statusCode || 0;
314
+ if (statusCode >= 200 && statusCode < 300) {
315
+ if (this.debug) {
316
+ console.debug(`[JustAnalytics] Flushed ${batch.length} span(s) successfully`);
317
+ }
318
+ resolve();
319
+ }
320
+ else if (statusCode === 429) {
321
+ this.handleBackoff();
322
+ if (this.debug) {
323
+ console.debug(`[JustAnalytics] Rate limited (429). Backing off flush interval. Dropped ${batch.length} span(s).`);
324
+ }
325
+ resolve(); // Don't reject -- we handled it
326
+ }
327
+ else {
328
+ if (this.debug) {
329
+ const responseBody = Buffer.concat(chunks).toString('utf-8');
330
+ console.debug(`[JustAnalytics] Flush failed with HTTP ${statusCode}. Dropped ${batch.length} span(s). Response: ${responseBody}`);
331
+ }
332
+ resolve(); // Don't reject for HTTP errors -- just drop the batch
333
+ }
334
+ });
335
+ });
336
+ req.on('error', (error) => {
337
+ if (this.debug) {
338
+ console.debug(`[JustAnalytics] Network error during flush: ${error.message}. Dropped ${batch.length} span(s).`);
339
+ }
340
+ // Resolve instead of reject so the caller doesn't need to handle it
341
+ resolve();
342
+ });
343
+ req.on('timeout', () => {
344
+ req.destroy();
345
+ if (this.debug) {
346
+ console.debug(`[JustAnalytics] Flush request timed out. Dropped ${batch.length} span(s).`);
347
+ }
348
+ resolve();
349
+ });
350
+ req.write(body);
351
+ req.end();
352
+ });
353
+ }
354
+ /**
355
+ * Send a batch of error events via HTTP POST.
356
+ * Each error is sent as an individual POST to /api/ingest/errors
357
+ * because the server-side fingerprinting and upsert logic operates
358
+ * on individual events.
359
+ *
360
+ * @param batch - Array of error payloads to send
361
+ */
362
+ async sendErrorBatch(batch) {
363
+ for (const payload of batch) {
364
+ await this.sendSingleError(payload);
365
+ }
366
+ }
367
+ /**
368
+ * Send a single error event via HTTP POST to /api/ingest/errors.
369
+ *
370
+ * @param payload - Error event payload to send
371
+ */
372
+ sendSingleError(payload) {
373
+ return new Promise((resolve) => {
374
+ try {
375
+ const body = JSON.stringify(payload);
376
+ const url = new url_1.URL('/api/ingest/errors', this.serverUrl);
377
+ const isHttps = url.protocol === 'https:';
378
+ const transport = isHttps ? https_1.default : http_1.default;
379
+ const requestOptions = {
380
+ hostname: url.hostname,
381
+ port: url.port || (isHttps ? 443 : 80),
382
+ path: url.pathname,
383
+ method: 'POST',
384
+ headers: {
385
+ 'Content-Type': 'application/json',
386
+ 'Content-Length': Buffer.byteLength(body),
387
+ 'Authorization': `Bearer ${this.apiKey}`,
388
+ },
389
+ timeout: 10000,
390
+ };
391
+ const req = transport.request(requestOptions, (res) => {
392
+ // Consume response body
393
+ const chunks = [];
394
+ res.on('data', (chunk) => chunks.push(chunk));
395
+ res.on('end', () => {
396
+ const statusCode = res.statusCode || 0;
397
+ if (statusCode >= 200 && statusCode < 300) {
398
+ if (this.debug) {
399
+ console.debug(`[JustAnalytics] Error event sent successfully (eventId: ${payload.eventId})`);
400
+ }
401
+ }
402
+ else {
403
+ if (this.debug) {
404
+ const responseBody = Buffer.concat(chunks).toString('utf-8');
405
+ console.debug(`[JustAnalytics] Error send failed with HTTP ${statusCode}. Response: ${responseBody}`);
406
+ }
407
+ }
408
+ resolve();
409
+ });
410
+ });
411
+ req.on('error', (error) => {
412
+ if (this.debug) {
413
+ console.debug(`[JustAnalytics] Network error sending error event: ${error.message}`);
414
+ }
415
+ resolve();
416
+ });
417
+ req.on('timeout', () => {
418
+ req.destroy();
419
+ if (this.debug) {
420
+ console.debug(`[JustAnalytics] Error send request timed out.`);
421
+ }
422
+ resolve();
423
+ });
424
+ req.write(body);
425
+ req.end();
426
+ }
427
+ catch {
428
+ // Never throw from error send
429
+ resolve();
430
+ }
431
+ });
432
+ }
433
+ /**
434
+ * Flush all pending log entry payloads to POST /api/ingest/logs.
435
+ *
436
+ * Sends all buffered logs in a single HTTP POST request.
437
+ * The buffer is cleared before sending, so new logs that arrive
438
+ * during the flush are queued for the next flush.
439
+ *
440
+ * @returns Promise that resolves when the flush completes (or fails)
441
+ */
442
+ async flushLogs() {
443
+ if (this.logBuffer.length === 0)
444
+ return;
445
+ if (this.isFlushingLogs)
446
+ return;
447
+ this.isFlushingLogs = true;
448
+ const batch = this.logBuffer.splice(0, this.logBuffer.length);
449
+ try {
450
+ await this.sendLogBatch(batch);
451
+ }
452
+ catch (error) {
453
+ if (this.debug) {
454
+ console.debug(`[JustAnalytics] Log flush failed, dropped ${batch.length} log(s):`, error instanceof Error ? error.message : String(error));
455
+ }
456
+ // Drop the batch -- do not re-enqueue to prevent memory leaks
457
+ }
458
+ finally {
459
+ this.isFlushingLogs = false;
460
+ }
461
+ }
462
+ /**
463
+ * Send a batch of log entries via HTTP POST to /api/ingest/logs.
464
+ *
465
+ * Uses Node.js built-in `http`/`https` module based on the server URL
466
+ * protocol. Handles HTTP 429 with backoff.
467
+ *
468
+ * @param batch - Array of log entry payloads to send
469
+ */
470
+ sendLogBatch(batch) {
471
+ return new Promise((resolve) => {
472
+ const body = JSON.stringify({ logs: batch });
473
+ const url = new url_1.URL('/api/ingest/logs', this.serverUrl);
474
+ const isHttps = url.protocol === 'https:';
475
+ const transport = isHttps ? https_1.default : http_1.default;
476
+ const requestOptions = {
477
+ hostname: url.hostname,
478
+ port: url.port || (isHttps ? 443 : 80),
479
+ path: url.pathname,
480
+ method: 'POST',
481
+ headers: {
482
+ 'Content-Type': 'application/json',
483
+ 'Content-Length': Buffer.byteLength(body),
484
+ 'Authorization': `Bearer ${this.apiKey}`,
485
+ },
486
+ timeout: 10000,
487
+ };
488
+ const req = transport.request(requestOptions, (res) => {
489
+ const chunks = [];
490
+ res.on('data', (chunk) => chunks.push(chunk));
491
+ res.on('end', () => {
492
+ const statusCode = res.statusCode || 0;
493
+ if (statusCode >= 200 && statusCode < 300) {
494
+ if (this.debug) {
495
+ console.debug(`[JustAnalytics] Flushed ${batch.length} log(s) successfully`);
496
+ }
497
+ resolve();
498
+ }
499
+ else if (statusCode === 429) {
500
+ this.handleBackoff();
501
+ if (this.debug) {
502
+ console.debug(`[JustAnalytics] Rate limited (429). Backing off. Dropped ${batch.length} log(s).`);
503
+ }
504
+ resolve();
505
+ }
506
+ else {
507
+ if (this.debug) {
508
+ const responseBody = Buffer.concat(chunks).toString('utf-8');
509
+ console.debug(`[JustAnalytics] Log flush failed with HTTP ${statusCode}. Dropped ${batch.length} log(s). Response: ${responseBody}`);
510
+ }
511
+ resolve();
512
+ }
513
+ });
514
+ });
515
+ req.on('error', (error) => {
516
+ if (this.debug) {
517
+ console.debug(`[JustAnalytics] Network error during log flush: ${error.message}. Dropped ${batch.length} log(s).`);
518
+ }
519
+ resolve();
520
+ });
521
+ req.on('timeout', () => {
522
+ req.destroy();
523
+ if (this.debug) {
524
+ console.debug(`[JustAnalytics] Log flush request timed out. Dropped ${batch.length} log(s).`);
525
+ }
526
+ resolve();
527
+ });
528
+ req.write(body);
529
+ req.end();
530
+ });
531
+ }
532
+ /**
533
+ * Flush all pending metric payloads to POST /api/ingest/metrics.
534
+ *
535
+ * Sends all buffered metrics in a single HTTP POST request.
536
+ * The buffer is cleared before sending, so new metrics that arrive
537
+ * during the flush are queued for the next flush.
538
+ *
539
+ * @returns Promise that resolves when the flush completes (or fails)
540
+ */
541
+ async flushMetrics() {
542
+ if (this.metricBuffer.length === 0)
543
+ return;
544
+ if (this.isFlushingMetrics)
545
+ return;
546
+ this.isFlushingMetrics = true;
547
+ const batch = this.metricBuffer.splice(0, this.metricBuffer.length);
548
+ try {
549
+ await this.sendMetricBatch(batch);
550
+ }
551
+ catch (error) {
552
+ if (this.debug) {
553
+ console.debug(`[JustAnalytics] Metric flush failed, dropped ${batch.length} metric(s):`, error instanceof Error ? error.message : String(error));
554
+ }
555
+ // Drop the batch -- do not re-enqueue to prevent memory leaks
556
+ }
557
+ finally {
558
+ this.isFlushingMetrics = false;
559
+ }
560
+ }
561
+ /**
562
+ * Send a batch of metrics via HTTP POST to /api/ingest/metrics.
563
+ *
564
+ * Uses Node.js built-in `http`/`https` module based on the server URL
565
+ * protocol. Handles HTTP 429 with backoff.
566
+ *
567
+ * @param batch - Array of metric payloads to send
568
+ */
569
+ sendMetricBatch(batch) {
570
+ return new Promise((resolve) => {
571
+ const body = JSON.stringify({ metrics: batch });
572
+ const url = new url_1.URL('/api/ingest/metrics', this.serverUrl);
573
+ const isHttps = url.protocol === 'https:';
574
+ const transport = isHttps ? https_1.default : http_1.default;
575
+ const requestOptions = {
576
+ hostname: url.hostname,
577
+ port: url.port || (isHttps ? 443 : 80),
578
+ path: url.pathname,
579
+ method: 'POST',
580
+ headers: {
581
+ 'Content-Type': 'application/json',
582
+ 'Content-Length': Buffer.byteLength(body),
583
+ 'Authorization': `Bearer ${this.apiKey}`,
584
+ },
585
+ timeout: 10000,
586
+ };
587
+ const req = transport.request(requestOptions, (res) => {
588
+ const chunks = [];
589
+ res.on('data', (chunk) => chunks.push(chunk));
590
+ res.on('end', () => {
591
+ const statusCode = res.statusCode || 0;
592
+ if (statusCode >= 200 && statusCode < 300) {
593
+ if (this.debug) {
594
+ console.debug(`[JustAnalytics] Flushed ${batch.length} metric(s) successfully`);
595
+ }
596
+ resolve();
597
+ }
598
+ else if (statusCode === 429) {
599
+ this.handleBackoff();
600
+ if (this.debug) {
601
+ console.debug(`[JustAnalytics] Rate limited (429). Backing off. Dropped ${batch.length} metric(s).`);
602
+ }
603
+ resolve();
604
+ }
605
+ else {
606
+ if (this.debug) {
607
+ const responseBody = Buffer.concat(chunks).toString('utf-8');
608
+ console.debug(`[JustAnalytics] Metric flush failed with HTTP ${statusCode}. Dropped ${batch.length} metric(s). Response: ${responseBody}`);
609
+ }
610
+ resolve();
611
+ }
612
+ });
613
+ });
614
+ req.on('error', (error) => {
615
+ if (this.debug) {
616
+ console.debug(`[JustAnalytics] Network error during metric flush: ${error.message}. Dropped ${batch.length} metric(s).`);
617
+ }
618
+ resolve();
619
+ });
620
+ req.on('timeout', () => {
621
+ req.destroy();
622
+ if (this.debug) {
623
+ console.debug(`[JustAnalytics] Metric flush request timed out. Dropped ${batch.length} metric(s).`);
624
+ }
625
+ resolve();
626
+ });
627
+ req.write(body);
628
+ req.end();
629
+ });
630
+ }
631
+ /**
632
+ * Handle HTTP 429 backoff: double the flush interval for 60 seconds, then reset.
633
+ */
634
+ handleBackoff() {
635
+ // Double the effective flush interval
636
+ this.currentFlushIntervalMs = this.originalFlushIntervalMs * 2;
637
+ // Restart the timer with the new interval
638
+ this.start();
639
+ // Reset after 60 seconds
640
+ if (this.backoffResetTimer !== null) {
641
+ clearTimeout(this.backoffResetTimer);
642
+ }
643
+ this.backoffResetTimer = setTimeout(() => {
644
+ this.currentFlushIntervalMs = this.originalFlushIntervalMs;
645
+ this.start(); // Restart with original interval
646
+ this.backoffResetTimer = null;
647
+ }, 60000);
648
+ if (this.backoffResetTimer && typeof this.backoffResetTimer.unref === 'function') {
649
+ this.backoffResetTimer.unref();
650
+ }
651
+ }
652
+ }
653
+ exports.BatchTransport = BatchTransport;
654
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}