@chirpier/chirpier-js 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -76,6 +76,11 @@ Default servicer endpoint is `https://api.chirpier.co/v1.0`.
76
76
  The same bearer token is used for both ingest and servicer APIs.
77
77
  Queued logs are not dropped locally because of queue capacity or retry exhaustion.
78
78
 
79
+ ### Retry behavior
80
+
81
+ The SDK retries network/transport failures, `429` responses, and retryable `5xx` responses such as `502` and `504`.
82
+ It does not retry `401`, `403`, `404`, `500`, or `503`, and `401`/`403` errors surface the Chirpier response message when available.
83
+
79
84
  ### `logEvent(log)`
80
85
 
81
86
  Queues a log for batched delivery.
@@ -50,7 +50,10 @@ describe("Chirpier SDK", function () {
50
50
  afterEach(function () { return __awaiter(void 0, void 0, void 0, function () {
51
51
  return __generator(this, function (_a) {
52
52
  switch (_a.label) {
53
- case 0: return [4 /*yield*/, (0, index_1.stop)()];
53
+ case 0:
54
+ jest.useRealTimers();
55
+ jest.restoreAllMocks();
56
+ return [4 /*yield*/, (0, index_1.stop)()];
54
57
  case 1:
55
58
  _a.sent();
56
59
  return [2 /*return*/];
@@ -450,6 +453,306 @@ describe("Chirpier SDK", function () {
450
453
  }
451
454
  });
452
455
  }); });
456
+ test("retries network errors", function () { return __awaiter(void 0, void 0, void 0, function () {
457
+ var client, axiosBackedClient, attempts, flushPromise;
458
+ return __generator(this, function (_a) {
459
+ switch (_a.label) {
460
+ case 0:
461
+ jest.useFakeTimers();
462
+ client = (0, index_1.createClient)({
463
+ key: "chp_network_retry_key",
464
+ retries: 2,
465
+ flushDelay: 10000,
466
+ });
467
+ axiosBackedClient = client;
468
+ attempts = 0;
469
+ axiosBackedClient.axiosInstance.defaults.adapter = function (config) { return __awaiter(void 0, void 0, void 0, function () {
470
+ return __generator(this, function (_a) {
471
+ attempts += 1;
472
+ if (attempts < 3) {
473
+ throw Object.assign(new Error("Network Error"), {
474
+ code: "ECONNRESET",
475
+ config: config,
476
+ });
477
+ }
478
+ return [2 /*return*/, {
479
+ data: { success: true },
480
+ status: 200,
481
+ statusText: "OK",
482
+ headers: {},
483
+ config: config,
484
+ }];
485
+ });
486
+ }); };
487
+ _a.label = 1;
488
+ case 1:
489
+ _a.trys.push([1, , 5, 7]);
490
+ return [4 /*yield*/, client.log({ event: "network.retry", value: 1 })];
491
+ case 2:
492
+ _a.sent();
493
+ flushPromise = client.flush();
494
+ return [4 /*yield*/, jest.runAllTimersAsync()];
495
+ case 3:
496
+ _a.sent();
497
+ return [4 /*yield*/, expect(flushPromise).resolves.toBeUndefined()];
498
+ case 4:
499
+ _a.sent();
500
+ expect(attempts).toBe(3);
501
+ return [3 /*break*/, 7];
502
+ case 5: return [4 /*yield*/, client.shutdown()];
503
+ case 6:
504
+ _a.sent();
505
+ return [7 /*endfinally*/];
506
+ case 7: return [2 /*return*/];
507
+ }
508
+ });
509
+ }); });
510
+ test("retries 429 responses", function () { return __awaiter(void 0, void 0, void 0, function () {
511
+ var mock, client, flushPromise;
512
+ return __generator(this, function (_a) {
513
+ switch (_a.label) {
514
+ case 0:
515
+ jest.useFakeTimers();
516
+ mock = new axios_mock_adapter_1.default(axios_1.default);
517
+ mock.onPost(constants_1.DEFAULT_API_ENDPOINT).replyOnce(429, { error: "rate limited" }, { "retry-after": "1" });
518
+ mock.onPost(constants_1.DEFAULT_API_ENDPOINT).replyOnce(429, { error: "rate limited" }, { "retry-after": "1" });
519
+ mock.onPost(constants_1.DEFAULT_API_ENDPOINT).replyOnce(200, { success: true });
520
+ client = (0, index_1.createClient)({
521
+ key: "chp_rate_limit_key",
522
+ retries: 2,
523
+ flushDelay: 10000,
524
+ });
525
+ _a.label = 1;
526
+ case 1:
527
+ _a.trys.push([1, , 5, 7]);
528
+ return [4 /*yield*/, client.log({ event: "rate.limit", value: 1 })];
529
+ case 2:
530
+ _a.sent();
531
+ flushPromise = client.flush();
532
+ return [4 /*yield*/, jest.runAllTimersAsync()];
533
+ case 3:
534
+ _a.sent();
535
+ return [4 /*yield*/, expect(flushPromise).resolves.toBeUndefined()];
536
+ case 4:
537
+ _a.sent();
538
+ expect(mock.history.post.length).toBe(3);
539
+ return [3 /*break*/, 7];
540
+ case 5: return [4 /*yield*/, client.shutdown()];
541
+ case 6:
542
+ _a.sent();
543
+ return [7 /*endfinally*/];
544
+ case 7: return [2 /*return*/];
545
+ }
546
+ });
547
+ }); });
548
+ test("does not retry 401 and logs the Chirpier response message", function () { return __awaiter(void 0, void 0, void 0, function () {
549
+ var mock, errorSpy, client;
550
+ return __generator(this, function (_a) {
551
+ switch (_a.label) {
552
+ case 0:
553
+ mock = new axios_mock_adapter_1.default(axios_1.default);
554
+ errorSpy = jest.spyOn(console, "error").mockImplementation(function () { return undefined; });
555
+ mock.onPost(constants_1.DEFAULT_API_ENDPOINT).replyOnce(401, { error: "invalid api key" });
556
+ client = (0, index_1.createClient)({
557
+ key: "chp_unauthorized_key",
558
+ retries: 3,
559
+ flushDelay: 10000,
560
+ logLevel: 1 /* LogLevel.Error */,
561
+ });
562
+ _a.label = 1;
563
+ case 1:
564
+ _a.trys.push([1, , 5, 7]);
565
+ return [4 /*yield*/, client.log({ event: "auth.failed", value: 1 })];
566
+ case 2:
567
+ _a.sent();
568
+ return [4 /*yield*/, client.flush()];
569
+ case 3:
570
+ _a.sent();
571
+ return [4 /*yield*/, client.flush()];
572
+ case 4:
573
+ _a.sent();
574
+ expect(mock.history.post.length).toBe(1);
575
+ expect(errorSpy).toHaveBeenCalledWith("Chirpier API returned 401: invalid api key");
576
+ return [3 /*break*/, 7];
577
+ case 5: return [4 /*yield*/, client.shutdown()];
578
+ case 6:
579
+ _a.sent();
580
+ return [7 /*endfinally*/];
581
+ case 7: return [2 /*return*/];
582
+ }
583
+ });
584
+ }); });
585
+ test("does not retry 403 and logs the Chirpier response message", function () { return __awaiter(void 0, void 0, void 0, function () {
586
+ var mock, errorSpy, client;
587
+ return __generator(this, function (_a) {
588
+ switch (_a.label) {
589
+ case 0:
590
+ mock = new axios_mock_adapter_1.default(axios_1.default);
591
+ errorSpy = jest.spyOn(console, "error").mockImplementation(function () { return undefined; });
592
+ mock.onPost(constants_1.DEFAULT_API_ENDPOINT).replyOnce(403, { message: "project is disabled" });
593
+ client = (0, index_1.createClient)({
594
+ key: "chp_forbidden_key",
595
+ retries: 3,
596
+ flushDelay: 10000,
597
+ logLevel: 1 /* LogLevel.Error */,
598
+ });
599
+ _a.label = 1;
600
+ case 1:
601
+ _a.trys.push([1, , 5, 7]);
602
+ return [4 /*yield*/, client.log({ event: "auth.forbidden", value: 1 })];
603
+ case 2:
604
+ _a.sent();
605
+ return [4 /*yield*/, client.flush()];
606
+ case 3:
607
+ _a.sent();
608
+ return [4 /*yield*/, client.flush()];
609
+ case 4:
610
+ _a.sent();
611
+ expect(mock.history.post.length).toBe(1);
612
+ expect(errorSpy).toHaveBeenCalledWith("Chirpier API returned 403: project is disabled");
613
+ return [3 /*break*/, 7];
614
+ case 5: return [4 /*yield*/, client.shutdown()];
615
+ case 6:
616
+ _a.sent();
617
+ return [7 /*endfinally*/];
618
+ case 7: return [2 /*return*/];
619
+ }
620
+ });
621
+ }); });
622
+ test.each([404, 500, 503])("does not retry non-retryable status %s", function (status) { return __awaiter(void 0, void 0, void 0, function () {
623
+ var mock, client;
624
+ return __generator(this, function (_a) {
625
+ switch (_a.label) {
626
+ case 0:
627
+ mock = new axios_mock_adapter_1.default(axios_1.default);
628
+ mock.onPost(constants_1.DEFAULT_API_ENDPOINT).replyOnce(status, { error: "http ".concat(status) });
629
+ client = (0, index_1.createClient)({
630
+ key: "chp_non_retryable_".concat(status),
631
+ retries: 3,
632
+ flushDelay: 10000,
633
+ });
634
+ _a.label = 1;
635
+ case 1:
636
+ _a.trys.push([1, , 5, 7]);
637
+ return [4 /*yield*/, client.log({ event: "non.retryable.".concat(status), value: 1 })];
638
+ case 2:
639
+ _a.sent();
640
+ return [4 /*yield*/, client.flush()];
641
+ case 3:
642
+ _a.sent();
643
+ return [4 /*yield*/, client.flush()];
644
+ case 4:
645
+ _a.sent();
646
+ expect(mock.history.post.length).toBe(1);
647
+ return [3 /*break*/, 7];
648
+ case 5: return [4 /*yield*/, client.shutdown()];
649
+ case 6:
650
+ _a.sent();
651
+ return [7 /*endfinally*/];
652
+ case 7: return [2 /*return*/];
653
+ }
654
+ });
655
+ }); });
656
+ test("retries 502 responses", function () { return __awaiter(void 0, void 0, void 0, function () {
657
+ var mock, client, flushPromise;
658
+ return __generator(this, function (_a) {
659
+ switch (_a.label) {
660
+ case 0:
661
+ jest.useFakeTimers();
662
+ mock = new axios_mock_adapter_1.default(axios_1.default);
663
+ mock.onPost(constants_1.DEFAULT_API_ENDPOINT).replyOnce(502, { error: "bad gateway" });
664
+ mock.onPost(constants_1.DEFAULT_API_ENDPOINT).replyOnce(502, { error: "bad gateway" });
665
+ mock.onPost(constants_1.DEFAULT_API_ENDPOINT).replyOnce(200, { success: true });
666
+ client = (0, index_1.createClient)({
667
+ key: "chp_bad_gateway_key",
668
+ retries: 2,
669
+ flushDelay: 10000,
670
+ });
671
+ _a.label = 1;
672
+ case 1:
673
+ _a.trys.push([1, , 5, 7]);
674
+ return [4 /*yield*/, client.log({ event: "bad.gateway", value: 1 })];
675
+ case 2:
676
+ _a.sent();
677
+ flushPromise = client.flush();
678
+ return [4 /*yield*/, jest.runAllTimersAsync()];
679
+ case 3:
680
+ _a.sent();
681
+ return [4 /*yield*/, expect(flushPromise).resolves.toBeUndefined()];
682
+ case 4:
683
+ _a.sent();
684
+ expect(mock.history.post.length).toBe(3);
685
+ return [3 /*break*/, 7];
686
+ case 5: return [4 /*yield*/, client.shutdown()];
687
+ case 6:
688
+ _a.sent();
689
+ return [7 /*endfinally*/];
690
+ case 7: return [2 /*return*/];
691
+ }
692
+ });
693
+ }); });
694
+ test("flush requeues only retryable failures", function () { return __awaiter(void 0, void 0, void 0, function () {
695
+ var retryableMock, retryableClient, nonRetryableMock, nonRetryableClient;
696
+ return __generator(this, function (_a) {
697
+ switch (_a.label) {
698
+ case 0:
699
+ retryableMock = new axios_mock_adapter_1.default(axios_1.default);
700
+ retryableMock.onPost(constants_1.DEFAULT_API_ENDPOINT).replyOnce(502, { error: "bad gateway" });
701
+ retryableMock.onPost(constants_1.DEFAULT_API_ENDPOINT).replyOnce(200, { success: true });
702
+ retryableClient = (0, index_1.createClient)({
703
+ key: "chp_retryable_requeue_key",
704
+ retries: 0,
705
+ flushDelay: 10000,
706
+ });
707
+ _a.label = 1;
708
+ case 1:
709
+ _a.trys.push([1, , 5, 7]);
710
+ return [4 /*yield*/, retryableClient.log({ event: "retryable.requeue", value: 1 })];
711
+ case 2:
712
+ _a.sent();
713
+ return [4 /*yield*/, retryableClient.flush()];
714
+ case 3:
715
+ _a.sent();
716
+ return [4 /*yield*/, retryableClient.flush()];
717
+ case 4:
718
+ _a.sent();
719
+ expect(retryableMock.history.post.length).toBe(2);
720
+ return [3 /*break*/, 7];
721
+ case 5: return [4 /*yield*/, retryableClient.shutdown()];
722
+ case 6:
723
+ _a.sent();
724
+ return [7 /*endfinally*/];
725
+ case 7:
726
+ nonRetryableMock = new axios_mock_adapter_1.default(axios_1.default);
727
+ nonRetryableMock.onPost(constants_1.DEFAULT_API_ENDPOINT).replyOnce(404, { error: "not found" });
728
+ nonRetryableClient = (0, index_1.createClient)({
729
+ key: "chp_non_retryable_requeue_key",
730
+ retries: 0,
731
+ flushDelay: 10000,
732
+ logLevel: 0 /* LogLevel.None */,
733
+ });
734
+ _a.label = 8;
735
+ case 8:
736
+ _a.trys.push([8, , 12, 14]);
737
+ return [4 /*yield*/, nonRetryableClient.log({ event: "non.retryable.drop", value: 1 })];
738
+ case 9:
739
+ _a.sent();
740
+ return [4 /*yield*/, nonRetryableClient.flush()];
741
+ case 10:
742
+ _a.sent();
743
+ return [4 /*yield*/, nonRetryableClient.flush()];
744
+ case 11:
745
+ _a.sent();
746
+ expect(nonRetryableMock.history.post.length).toBe(1);
747
+ return [3 /*break*/, 14];
748
+ case 12: return [4 /*yield*/, nonRetryableClient.shutdown()];
749
+ case 13:
750
+ _a.sent();
751
+ return [7 /*endfinally*/];
752
+ case 14: return [2 /*return*/];
753
+ }
754
+ });
755
+ }); });
453
756
  test("getEventLogs uses servicer endpoint with period, limit, and offset", function () { return __awaiter(void 0, void 0, void 0, function () {
454
757
  var mock, client;
455
758
  return __generator(this, function (_a) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -99,6 +99,83 @@ var ChirpierError = /** @class */ (function (_super) {
99
99
  return ChirpierError;
100
100
  }(Error));
101
101
  exports.ChirpierError = ChirpierError;
102
+ function classifyLogResponseStatus(status) {
103
+ if (status === undefined) {
104
+ return "success";
105
+ }
106
+ if (status === 429) {
107
+ return "retry_after";
108
+ }
109
+ if (status >= 500) {
110
+ if (status === 500 || status === 503) {
111
+ return "non_retryable";
112
+ }
113
+ return "retryable";
114
+ }
115
+ if (status >= 400) {
116
+ return "non_retryable";
117
+ }
118
+ return "success";
119
+ }
120
+ function getChirpierResponseMessage(data) {
121
+ if (typeof data === "string") {
122
+ var trimmed = data.trim();
123
+ return trimmed.length > 0 ? trimmed : undefined;
124
+ }
125
+ if (data && typeof data === "object") {
126
+ var record = data;
127
+ if (typeof record.message === "string" && record.message.trim().length > 0) {
128
+ return record.message.trim();
129
+ }
130
+ if (typeof record.error === "string" && record.error.trim().length > 0) {
131
+ return record.error.trim();
132
+ }
133
+ try {
134
+ return JSON.stringify(data);
135
+ }
136
+ catch (_a) {
137
+ return undefined;
138
+ }
139
+ }
140
+ return undefined;
141
+ }
142
+ function getRetryDelayMs(retryCount, error) {
143
+ var _a, _b;
144
+ if (axios_1.default.isAxiosError(error) && ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 429) {
145
+ var retryAfterHeader = (_b = error.response.headers) === null || _b === void 0 ? void 0 : _b["retry-after"];
146
+ var retryAfterSeconds = Number(retryAfterHeader);
147
+ if (Number.isFinite(retryAfterSeconds) && retryAfterSeconds >= 0) {
148
+ return retryAfterSeconds * 1000;
149
+ }
150
+ }
151
+ var baseDelay = Math.pow(2, retryCount) * 1000;
152
+ var jitter = Math.random() * 0.3 * baseDelay;
153
+ return baseDelay + jitter;
154
+ }
155
+ function normalizeSendLogsError(error, logLevel) {
156
+ var _a, _b;
157
+ if (!axios_1.default.isAxiosError(error)) {
158
+ return error;
159
+ }
160
+ var status = (_a = error.response) === null || _a === void 0 ? void 0 : _a.status;
161
+ if (classifyLogResponseStatus(status) !== "non_retryable") {
162
+ return error;
163
+ }
164
+ var responseMessage = getChirpierResponseMessage((_b = error.response) === null || _b === void 0 ? void 0 : _b.data);
165
+ if ((status === 401 || status === 403) && logLevel >= 1 /* LogLevel.Error */) {
166
+ if (responseMessage) {
167
+ console.error("Chirpier API returned ".concat(status, ": ").concat(responseMessage));
168
+ }
169
+ else {
170
+ console.error("Chirpier API returned ".concat(status));
171
+ }
172
+ }
173
+ var message = responseMessage ? "HTTP ".concat(status, ": ").concat(responseMessage) : "HTTP ".concat(status);
174
+ return new ChirpierError(message, "NON_RETRYABLE_RESPONSE");
175
+ }
176
+ function isNonRetryableLogError(error) {
177
+ return error instanceof ChirpierError && error.code === "NON_RETRYABLE_RESPONSE";
178
+ }
102
179
  var Client = /** @class */ (function () {
103
180
  function Client(options) {
104
181
  if (options === void 0) { options = {}; }
@@ -158,15 +235,15 @@ var Client = /** @class */ (function () {
158
235
  this.axiosInstance.interceptors.response.use(function (response) { return response; }, function (error) { return Promise.reject(error); });
159
236
  (0, axios_retry_1.default)(this.axiosInstance, {
160
237
  retries: this.retries,
161
- retryDelay: function (retryCount) {
162
- var baseDelay = Math.pow(2, retryCount) * 1000;
163
- var jitter = Math.random() * 0.3 * baseDelay;
164
- return baseDelay + jitter;
165
- },
238
+ retryDelay: function (retryCount, error) { return getRetryDelayMs(retryCount, error); },
166
239
  retryCondition: function (error) {
167
- return (axios_retry_1.default.isNetworkError(error) ||
168
- axios_retry_1.default.isRetryableError(error) ||
169
- (error.response && error.response.status) === 429);
240
+ var _a;
241
+ if (axios_retry_1.default.isNetworkError(error)) {
242
+ return true;
243
+ }
244
+ var status = (_a = error.response) === null || _a === void 0 ? void 0 : _a.status;
245
+ var retryPolicy = classifyLogResponseStatus(status);
246
+ return retryPolicy === "retryable" || retryPolicy === "retry_after";
170
247
  },
171
248
  shouldResetTimeout: true,
172
249
  });
@@ -317,6 +394,12 @@ var Client = /** @class */ (function () {
317
394
  if (this.logLevel >= 1 /* LogLevel.Error */) {
318
395
  console.error("Failed to send logs:", error_1);
319
396
  }
397
+ if (isNonRetryableLogError(error_1)) {
398
+ if (this.logLevel >= 1 /* LogLevel.Error */) {
399
+ console.error("Dropping logs after non-retryable response from API");
400
+ }
401
+ return [2 /*return*/];
402
+ }
320
403
  return [4 /*yield*/, this.queueLock.acquire("logQueue", function () { return __awaiter(_this, void 0, void 0, function () {
321
404
  return __generator(this, function (_a) {
322
405
  this.logQueue = __spreadArray(__spreadArray([], logsToSend, true), this.logQueue, true);
@@ -339,12 +422,19 @@ var Client = /** @class */ (function () {
339
422
  };
340
423
  Client.prototype.sendLogs = function (logs) {
341
424
  return __awaiter(this, void 0, void 0, function () {
425
+ var error_2;
342
426
  return __generator(this, function (_a) {
343
427
  switch (_a.label) {
344
- case 0: return [4 /*yield*/, this.axiosInstance.post(this.apiEndpoint, logs)];
428
+ case 0:
429
+ _a.trys.push([0, 2, , 3]);
430
+ return [4 /*yield*/, this.axiosInstance.post(this.apiEndpoint, logs)];
345
431
  case 1:
346
432
  _a.sent();
347
- return [2 /*return*/];
433
+ return [3 /*break*/, 3];
434
+ case 2:
435
+ error_2 = _a.sent();
436
+ throw normalizeSendLogsError(error_2, this.logLevel);
437
+ case 3: return [2 /*return*/];
348
438
  }
349
439
  });
350
440
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chirpier/chirpier-js",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Chirpier SDK for JavaScript",
5
5
  "keywords": [
6
6
  "chirpier",
@@ -1,7 +1,7 @@
1
1
  import fs from "fs";
2
2
  import os from "os";
3
3
  import path from "path";
4
- import axios from "axios";
4
+ import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
5
5
  import MockAdapter from "axios-mock-adapter";
6
6
  import {
7
7
  Client,
@@ -20,6 +20,8 @@ import {
20
20
 
21
21
  describe("Chirpier SDK", () => {
22
22
  afterEach(async () => {
23
+ jest.useRealTimers();
24
+ jest.restoreAllMocks();
23
25
  await stop();
24
26
  });
25
27
 
@@ -341,6 +343,203 @@ describe("Chirpier SDK", () => {
341
343
  expect(JSON.parse(mock.history.post[0].data)[0].event).toBe("queued.before.flush");
342
344
  });
343
345
 
346
+ test("retries network errors", async () => {
347
+ jest.useFakeTimers();
348
+ const client: Client = createClient({
349
+ key: "chp_network_retry_key",
350
+ retries: 2,
351
+ flushDelay: 10000,
352
+ });
353
+ const axiosBackedClient = client as unknown as { axiosInstance: AxiosInstance };
354
+ let attempts = 0;
355
+ axiosBackedClient.axiosInstance.defaults.adapter = async (
356
+ config: AxiosRequestConfig
357
+ ): Promise<AxiosResponse> => {
358
+ attempts += 1;
359
+ if (attempts < 3) {
360
+ throw Object.assign(new Error("Network Error"), {
361
+ code: "ECONNRESET",
362
+ config,
363
+ });
364
+ }
365
+
366
+ return {
367
+ data: { success: true },
368
+ status: 200,
369
+ statusText: "OK",
370
+ headers: {},
371
+ config,
372
+ };
373
+ };
374
+
375
+ try {
376
+ await client.log({ event: "network.retry", value: 1 });
377
+ const flushPromise = client.flush();
378
+ await jest.runAllTimersAsync();
379
+ await expect(flushPromise).resolves.toBeUndefined();
380
+ expect(attempts).toBe(3);
381
+ } finally {
382
+ await client.shutdown();
383
+ }
384
+ });
385
+
386
+ test("retries 429 responses", async () => {
387
+ jest.useFakeTimers();
388
+ const mock = new MockAdapter(axios);
389
+ mock.onPost(DEFAULT_API_ENDPOINT).replyOnce(429, { error: "rate limited" }, { "retry-after": "1" });
390
+ mock.onPost(DEFAULT_API_ENDPOINT).replyOnce(429, { error: "rate limited" }, { "retry-after": "1" });
391
+ mock.onPost(DEFAULT_API_ENDPOINT).replyOnce(200, { success: true });
392
+
393
+ const client: Client = createClient({
394
+ key: "chp_rate_limit_key",
395
+ retries: 2,
396
+ flushDelay: 10000,
397
+ });
398
+
399
+ try {
400
+ await client.log({ event: "rate.limit", value: 1 });
401
+ const flushPromise = client.flush();
402
+ await jest.runAllTimersAsync();
403
+ await expect(flushPromise).resolves.toBeUndefined();
404
+ expect(mock.history.post.length).toBe(3);
405
+ } finally {
406
+ await client.shutdown();
407
+ }
408
+ });
409
+
410
+ test("does not retry 401 and logs the Chirpier response message", async () => {
411
+ const mock = new MockAdapter(axios);
412
+ const errorSpy = jest.spyOn(console, "error").mockImplementation(() => undefined);
413
+ mock.onPost(DEFAULT_API_ENDPOINT).replyOnce(401, { error: "invalid api key" });
414
+
415
+ const client: Client = createClient({
416
+ key: "chp_unauthorized_key",
417
+ retries: 3,
418
+ flushDelay: 10000,
419
+ logLevel: LogLevel.Error,
420
+ });
421
+
422
+ try {
423
+ await client.log({ event: "auth.failed", value: 1 });
424
+ await client.flush();
425
+ await client.flush();
426
+
427
+ expect(mock.history.post.length).toBe(1);
428
+ expect(errorSpy).toHaveBeenCalledWith("Chirpier API returned 401: invalid api key");
429
+ } finally {
430
+ await client.shutdown();
431
+ }
432
+ });
433
+
434
+ test("does not retry 403 and logs the Chirpier response message", async () => {
435
+ const mock = new MockAdapter(axios);
436
+ const errorSpy = jest.spyOn(console, "error").mockImplementation(() => undefined);
437
+ mock.onPost(DEFAULT_API_ENDPOINT).replyOnce(403, { message: "project is disabled" });
438
+
439
+ const client: Client = createClient({
440
+ key: "chp_forbidden_key",
441
+ retries: 3,
442
+ flushDelay: 10000,
443
+ logLevel: LogLevel.Error,
444
+ });
445
+
446
+ try {
447
+ await client.log({ event: "auth.forbidden", value: 1 });
448
+ await client.flush();
449
+ await client.flush();
450
+
451
+ expect(mock.history.post.length).toBe(1);
452
+ expect(errorSpy).toHaveBeenCalledWith("Chirpier API returned 403: project is disabled");
453
+ } finally {
454
+ await client.shutdown();
455
+ }
456
+ });
457
+
458
+ test.each([404, 500, 503])( "does not retry non-retryable status %s", async (status) => {
459
+ const mock = new MockAdapter(axios);
460
+ mock.onPost(DEFAULT_API_ENDPOINT).replyOnce(status, { error: `http ${status}` });
461
+
462
+ const client: Client = createClient({
463
+ key: `chp_non_retryable_${status}`,
464
+ retries: 3,
465
+ flushDelay: 10000,
466
+ });
467
+
468
+ try {
469
+ await client.log({ event: `non.retryable.${status}`, value: 1 });
470
+ await client.flush();
471
+ await client.flush();
472
+
473
+ expect(mock.history.post.length).toBe(1);
474
+ } finally {
475
+ await client.shutdown();
476
+ }
477
+ });
478
+
479
+ test("retries 502 responses", async () => {
480
+ jest.useFakeTimers();
481
+ const mock = new MockAdapter(axios);
482
+ mock.onPost(DEFAULT_API_ENDPOINT).replyOnce(502, { error: "bad gateway" });
483
+ mock.onPost(DEFAULT_API_ENDPOINT).replyOnce(502, { error: "bad gateway" });
484
+ mock.onPost(DEFAULT_API_ENDPOINT).replyOnce(200, { success: true });
485
+
486
+ const client: Client = createClient({
487
+ key: "chp_bad_gateway_key",
488
+ retries: 2,
489
+ flushDelay: 10000,
490
+ });
491
+
492
+ try {
493
+ await client.log({ event: "bad.gateway", value: 1 });
494
+ const flushPromise = client.flush();
495
+ await jest.runAllTimersAsync();
496
+ await expect(flushPromise).resolves.toBeUndefined();
497
+ expect(mock.history.post.length).toBe(3);
498
+ } finally {
499
+ await client.shutdown();
500
+ }
501
+ });
502
+
503
+ test("flush requeues only retryable failures", async () => {
504
+ const retryableMock = new MockAdapter(axios);
505
+ retryableMock.onPost(DEFAULT_API_ENDPOINT).replyOnce(502, { error: "bad gateway" });
506
+ retryableMock.onPost(DEFAULT_API_ENDPOINT).replyOnce(200, { success: true });
507
+
508
+ const retryableClient: Client = createClient({
509
+ key: "chp_retryable_requeue_key",
510
+ retries: 0,
511
+ flushDelay: 10000,
512
+ });
513
+
514
+ try {
515
+ await retryableClient.log({ event: "retryable.requeue", value: 1 });
516
+ await retryableClient.flush();
517
+ await retryableClient.flush();
518
+ expect(retryableMock.history.post.length).toBe(2);
519
+ } finally {
520
+ await retryableClient.shutdown();
521
+ }
522
+
523
+ const nonRetryableMock = new MockAdapter(axios);
524
+ nonRetryableMock.onPost(DEFAULT_API_ENDPOINT).replyOnce(404, { error: "not found" });
525
+
526
+ const nonRetryableClient: Client = createClient({
527
+ key: "chp_non_retryable_requeue_key",
528
+ retries: 0,
529
+ flushDelay: 10000,
530
+ logLevel: LogLevel.None,
531
+ });
532
+
533
+ try {
534
+ await nonRetryableClient.log({ event: "non.retryable.drop", value: 1 });
535
+ await nonRetryableClient.flush();
536
+ await nonRetryableClient.flush();
537
+ expect(nonRetryableMock.history.post.length).toBe(1);
538
+ } finally {
539
+ await nonRetryableClient.shutdown();
540
+ }
541
+ });
542
+
344
543
  test("getEventLogs uses servicer endpoint with period, limit, and offset", async () => {
345
544
  const mock = new MockAdapter(axios);
346
545
  mock.onGet("https://api.chirpier.co/v1.0/events/evt_123/logs?period=hour&limit=25&offset=10").reply(200, []);
package/src/index.ts CHANGED
@@ -204,6 +204,99 @@ export class ChirpierError extends Error {
204
204
  }
205
205
  }
206
206
 
207
+ type LogRetryPolicy = "success" | "retryable" | "retry_after" | "non_retryable";
208
+
209
+ function classifyLogResponseStatus(status?: number): LogRetryPolicy {
210
+ if (status === undefined) {
211
+ return "success";
212
+ }
213
+
214
+ if (status === 429) {
215
+ return "retry_after";
216
+ }
217
+
218
+ if (status >= 500) {
219
+ if (status === 500 || status === 503) {
220
+ return "non_retryable";
221
+ }
222
+
223
+ return "retryable";
224
+ }
225
+
226
+ if (status >= 400) {
227
+ return "non_retryable";
228
+ }
229
+
230
+ return "success";
231
+ }
232
+
233
+ function getChirpierResponseMessage(data: unknown): string | undefined {
234
+ if (typeof data === "string") {
235
+ const trimmed = data.trim();
236
+ return trimmed.length > 0 ? trimmed : undefined;
237
+ }
238
+
239
+ if (data && typeof data === "object") {
240
+ const record = data as Record<string, unknown>;
241
+ if (typeof record.message === "string" && record.message.trim().length > 0) {
242
+ return record.message.trim();
243
+ }
244
+
245
+ if (typeof record.error === "string" && record.error.trim().length > 0) {
246
+ return record.error.trim();
247
+ }
248
+
249
+ try {
250
+ return JSON.stringify(data);
251
+ } catch {
252
+ return undefined;
253
+ }
254
+ }
255
+
256
+ return undefined;
257
+ }
258
+
259
+ function getRetryDelayMs(retryCount: number, error: unknown): number {
260
+ if (axios.isAxiosError(error) && error.response?.status === 429) {
261
+ const retryAfterHeader = error.response.headers?.["retry-after"];
262
+ const retryAfterSeconds = Number(retryAfterHeader);
263
+ if (Number.isFinite(retryAfterSeconds) && retryAfterSeconds >= 0) {
264
+ return retryAfterSeconds * 1000;
265
+ }
266
+ }
267
+
268
+ const baseDelay = Math.pow(2, retryCount) * 1000;
269
+ const jitter = Math.random() * 0.3 * baseDelay;
270
+ return baseDelay + jitter;
271
+ }
272
+
273
+ function normalizeSendLogsError(error: unknown, logLevel: LogLevel): unknown {
274
+ if (!axios.isAxiosError(error)) {
275
+ return error;
276
+ }
277
+
278
+ const status = error.response?.status;
279
+ if (classifyLogResponseStatus(status) !== "non_retryable") {
280
+ return error;
281
+ }
282
+
283
+ const responseMessage = getChirpierResponseMessage(error.response?.data);
284
+ if ((status === 401 || status === 403) && logLevel >= LogLevel.Error) {
285
+ if (responseMessage) {
286
+ console.error(`Chirpier API returned ${status}: ${responseMessage}`);
287
+ } else {
288
+ console.error(`Chirpier API returned ${status}`);
289
+ }
290
+ }
291
+
292
+ const message = responseMessage ? `HTTP ${status}: ${responseMessage}` : `HTTP ${status}`;
293
+ return new ChirpierError(message, "NON_RETRYABLE_RESPONSE");
294
+ }
295
+
296
+ function isNonRetryableLogError(error: unknown): error is ChirpierError {
297
+ return error instanceof ChirpierError && error.code === "NON_RETRYABLE_RESPONSE";
298
+ }
299
+
207
300
  interface QueuedLog {
208
301
  readonly log: Log;
209
302
  readonly timestamp: number;
@@ -311,17 +404,15 @@ export class Client {
311
404
 
312
405
  axiosRetry(this.axiosInstance, {
313
406
  retries: this.retries,
314
- retryDelay: (retryCount) => {
315
- const baseDelay = Math.pow(2, retryCount) * 1000;
316
- const jitter = Math.random() * 0.3 * baseDelay;
317
- return baseDelay + jitter;
318
- },
407
+ retryDelay: (retryCount, error) => getRetryDelayMs(retryCount, error),
319
408
  retryCondition: (error) => {
320
- return (
321
- axiosRetry.isNetworkError(error) ||
322
- axiosRetry.isRetryableError(error) ||
323
- (error.response && error.response.status) === 429
324
- );
409
+ if (axiosRetry.isNetworkError(error)) {
410
+ return true;
411
+ }
412
+
413
+ const status = error.response?.status;
414
+ const retryPolicy = classifyLogResponseStatus(status);
415
+ return retryPolicy === "retryable" || retryPolicy === "retry_after";
325
416
  },
326
417
  shouldResetTimeout: true,
327
418
  });
@@ -466,6 +557,13 @@ export class Client {
466
557
  console.error("Failed to send logs:", error);
467
558
  }
468
559
 
560
+ if (isNonRetryableLogError(error)) {
561
+ if (this.logLevel >= LogLevel.Error) {
562
+ console.error("Dropping logs after non-retryable response from API");
563
+ }
564
+ return;
565
+ }
566
+
469
567
  await this.queueLock.acquire("logQueue", async () => {
470
568
  this.logQueue = [...logsToSend, ...this.logQueue];
471
569
  });
@@ -474,7 +572,11 @@ export class Client {
474
572
  }
475
573
 
476
574
  private async sendLogs(logs: Log[]): Promise<void> {
477
- await this.axiosInstance.post(this.apiEndpoint, logs);
575
+ try {
576
+ await this.axiosInstance.post(this.apiEndpoint, logs);
577
+ } catch (error) {
578
+ throw normalizeSendLogsError(error, this.logLevel);
579
+ }
478
580
  }
479
581
 
480
582
  public async flush(): Promise<void> {