@chirpier/chirpier-js 0.2.0 → 0.3.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 CHANGED
@@ -35,8 +35,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
35
35
  });
36
36
  };
37
37
  var __generator = (this && this.__generator) || function (thisArg, body) {
38
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
39
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
38
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
39
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
40
40
  function verb(n) { return function (v) { return step([n, v]); }; }
41
41
  function step(op) {
42
42
  if (f) throw new TypeError("Generator is already executing.");
@@ -74,12 +74,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
74
74
  return (mod && mod.__esModule) ? mod : { "default": mod };
75
75
  };
76
76
  Object.defineProperty(exports, "__esModule", { value: true });
77
- exports.flush = exports.stop = exports.logEvent = exports.initialize = exports.createClient = exports.Client = exports.ChirpierError = void 0;
77
+ exports.Client = exports.ChirpierError = void 0;
78
+ exports.createClient = createClient;
79
+ exports.initialize = initialize;
80
+ exports.logEvent = logEvent;
81
+ exports.stop = stop;
82
+ exports.flush = flush;
78
83
  var axios_1 = __importDefault(require("axios"));
79
84
  var axios_retry_1 = __importDefault(require("axios-retry"));
80
85
  var dotenv_1 = __importDefault(require("dotenv"));
81
86
  var constants_1 = require("./constants");
82
87
  var async_lock_1 = __importDefault(require("async-lock"));
88
+ var uuid_1 = require("uuid");
83
89
  // Custom error class for Chirpier-specific errors
84
90
  var ChirpierError = /** @class */ (function (_super) {
85
91
  __extends(ChirpierError, _super);
@@ -98,7 +104,7 @@ var Client = /** @class */ (function () {
98
104
  if (options === void 0) { options = {}; }
99
105
  this.logQueue = [];
100
106
  this.flushTimeoutId = null;
101
- var providedKey = options.key, _a = options.apiEndpoint, apiEndpoint = _a === void 0 ? constants_1.DEFAULT_API_ENDPOINT : _a, _b = options.servicerEndpoint, servicerEndpoint = _b === void 0 ? constants_1.DEFAULT_SERVICER_ENDPOINT : _b, _c = options.logLevel, logLevel = _c === void 0 ? 0 /* LogLevel.None */ : _c, _d = options.retries, retries = _d === void 0 ? constants_1.DEFAULT_RETRIES : _d, _e = options.timeout, timeout = _e === void 0 ? constants_1.DEFAULT_TIMEOUT : _e, _f = options.batchSize, batchSize = _f === void 0 ? constants_1.DEFAULT_BATCH_SIZE : _f, _g = options.flushDelay, flushDelay = _g === void 0 ? constants_1.DEFAULT_FLUSH_DELAY : _g, _h = options.maxQueueSize, maxQueueSize = _h === void 0 ? constants_1.MAX_QUEUE_SIZE : _h;
107
+ var providedKey = options.key, _a = options.apiEndpoint, apiEndpoint = _a === void 0 ? constants_1.DEFAULT_API_ENDPOINT : _a, _b = options.servicerEndpoint, servicerEndpoint = _b === void 0 ? constants_1.DEFAULT_SERVICER_ENDPOINT : _b, _c = options.logLevel, logLevel = _c === void 0 ? 0 /* LogLevel.None */ : _c, _d = options.retries, retries = _d === void 0 ? constants_1.DEFAULT_RETRIES : _d, _e = options.timeout, timeout = _e === void 0 ? constants_1.DEFAULT_TIMEOUT : _e, _f = options.batchSize, batchSize = _f === void 0 ? constants_1.DEFAULT_BATCH_SIZE : _f, _g = options.flushDelay, flushDelay = _g === void 0 ? constants_1.DEFAULT_FLUSH_DELAY : _g, maxQueueSize = options.maxQueueSize;
102
108
  var key = resolveAPIKey(providedKey);
103
109
  if (!key) {
104
110
  throw new ChirpierError("API key is required", "INVALID_KEY");
@@ -114,7 +120,7 @@ var Client = /** @class */ (function () {
114
120
  try {
115
121
  parsedURL = new URL(apiEndpoint);
116
122
  }
117
- catch (_j) {
123
+ catch (_h) {
118
124
  throw new ChirpierError("apiEndpoint must be a valid absolute URL", "INVALID_API_ENDPOINT");
119
125
  }
120
126
  if (parsedURL.protocol !== "https:" && parsedURL.protocol !== "http:") {
@@ -134,9 +140,6 @@ var Client = /** @class */ (function () {
134
140
  if (flushDelay < 0) {
135
141
  throw new ChirpierError("Flush delay must be non-negative", "INVALID_FLUSH_DELAY");
136
142
  }
137
- if (maxQueueSize <= 0 || !Number.isInteger(maxQueueSize)) {
138
- throw new ChirpierError("Max queue size must be a positive integer", "INVALID_QUEUE_SIZE");
139
- }
140
143
  this.apiEndpoint = apiEndpoint !== null && apiEndpoint !== void 0 ? apiEndpoint : constants_1.DEFAULT_API_ENDPOINT;
141
144
  this.servicerEndpoint = servicerEndpoint !== null && servicerEndpoint !== void 0 ? servicerEndpoint : constants_1.DEFAULT_SERVICER_ENDPOINT;
142
145
  this.apiKey = key;
@@ -144,10 +147,10 @@ var Client = /** @class */ (function () {
144
147
  this.timeout = timeout;
145
148
  this.batchSize = batchSize;
146
149
  this.flushDelay = flushDelay;
147
- this.maxQueueSize = maxQueueSize;
148
150
  this.logLevel = logLevel;
149
- this.queueLock = new async_lock_1.default({ maxPending: this.maxQueueSize });
150
- this.flushLock = new async_lock_1.default({ maxPending: this.maxQueueSize });
151
+ void maxQueueSize;
152
+ this.queueLock = new async_lock_1.default();
153
+ this.flushLock = new async_lock_1.default();
151
154
  this.axiosInstance = axios_1.default.create({
152
155
  headers: { Authorization: "Bearer ".concat(this.apiKey) },
153
156
  timeout: this.timeout,
@@ -175,10 +178,19 @@ var Client = /** @class */ (function () {
175
178
  if (typeof log.event !== "string" || log.event.trim().length === 0) {
176
179
  return false;
177
180
  }
181
+ if (log.log_id !== undefined) {
182
+ if (typeof log.log_id !== "string") {
183
+ return false;
184
+ }
185
+ var trimmedLogID = log.log_id.trim();
186
+ if (trimmedLogID.length > 0 && !isUUID(trimmedLogID)) {
187
+ return false;
188
+ }
189
+ }
178
190
  if (typeof log.value !== "number" || !Number.isFinite(log.value)) {
179
191
  return false;
180
192
  }
181
- if (log.agent_id !== undefined && typeof log.agent_id !== "string") {
193
+ if (log.agent !== undefined && typeof log.agent !== "string") {
182
194
  return false;
183
195
  }
184
196
  if (log.meta !== undefined) {
@@ -207,13 +219,14 @@ var Client = /** @class */ (function () {
207
219
  };
208
220
  Client.prototype.normalizeLog = function (log) {
209
221
  var normalizedLog = {
222
+ log_id: resolveLogID(log.log_id),
210
223
  event: log.event.trim(),
211
224
  value: log.value,
212
225
  };
213
- if (typeof log.agent_id === "string") {
214
- var trimmedAgentID = log.agent_id.trim();
215
- if (trimmedAgentID.length > 0) {
216
- normalizedLog.agent_id = trimmedAgentID;
226
+ if (typeof log.agent === "string") {
227
+ var trimmedAgent = log.agent.trim();
228
+ if (trimmedAgent.length > 0) {
229
+ normalizedLog.agent = trimmedAgent;
217
230
  }
218
231
  }
219
232
  if (log.meta !== undefined) {
@@ -227,31 +240,23 @@ var Client = /** @class */ (function () {
227
240
  };
228
241
  Client.prototype.log = function (log) {
229
242
  return __awaiter(this, void 0, void 0, function () {
230
- var normalizedLog, queueFull;
243
+ var normalizedLog;
231
244
  var _this = this;
232
245
  return __generator(this, function (_a) {
233
246
  switch (_a.label) {
234
247
  case 0:
235
248
  if (!this.isValidLog(log)) {
236
- throw new ChirpierError("Invalid log format: event must not be empty, value must be a finite number, agent_id must be a string when provided, meta must be JSON-encodable, and occurred_at must be within the last 30 days and no more than 1 day in the future", "INVALID_LOG");
249
+ throw new ChirpierError("Invalid log format: log_id must be a UUID when provided, event must not be empty, value must be a finite number, agent must be a string when provided, meta must be JSON-encodable, and occurred_at must be within the last 30 days and no more than 1 day in the future", "INVALID_LOG");
237
250
  }
238
251
  normalizedLog = this.normalizeLog(log);
239
- queueFull = false;
240
252
  return [4 /*yield*/, this.queueLock.acquire("queue", function () { return __awaiter(_this, void 0, void 0, function () {
241
253
  return __generator(this, function (_a) {
242
- if (this.logQueue.length >= this.maxQueueSize) {
243
- queueFull = true;
244
- return [2 /*return*/];
245
- }
246
- this.logQueue.push({ log: normalizedLog, timestamp: Date.now(), retryCount: 0 });
254
+ this.logQueue.push({ log: normalizedLog, timestamp: Date.now() });
247
255
  return [2 /*return*/];
248
256
  });
249
257
  }); })];
250
258
  case 1:
251
259
  _a.sent();
252
- if (queueFull) {
253
- throw new ChirpierError("Log queue is full (max size: ".concat(this.maxQueueSize, ")"), "QUEUE_FULL");
254
- }
255
260
  if (!(this.logQueue.length >= this.batchSize)) return [3 /*break*/, 3];
256
261
  return [4 /*yield*/, this.flushQueue()];
257
262
  case 2:
@@ -273,7 +278,7 @@ var Client = /** @class */ (function () {
273
278
  return __generator(this, function (_a) {
274
279
  switch (_a.label) {
275
280
  case 0: return [4 /*yield*/, this.flushLock.acquire("flush", function () { return __awaiter(_this, void 0, void 0, function () {
276
- var logsToSend, error_1, retryableLogs_1, _i, logsToSend_1, queuedLog;
281
+ var logsToSend, error_1;
277
282
  var _this = this;
278
283
  return __generator(this, function (_a) {
279
284
  switch (_a.label) {
@@ -312,21 +317,9 @@ var Client = /** @class */ (function () {
312
317
  if (this.logLevel >= 1 /* LogLevel.Error */) {
313
318
  console.error("Failed to send logs:", error_1);
314
319
  }
315
- retryableLogs_1 = [];
316
- for (_i = 0, logsToSend_1 = logsToSend; _i < logsToSend_1.length; _i++) {
317
- queuedLog = logsToSend_1[_i];
318
- if (queuedLog.retryCount >= this.retries) {
319
- if (this.logLevel >= 1 /* LogLevel.Error */) {
320
- console.error("Dropping log after ".concat(this.retries, " retries:"), queuedLog.log);
321
- }
322
- continue;
323
- }
324
- queuedLog.retryCount++;
325
- retryableLogs_1.push(queuedLog);
326
- }
327
320
  return [4 /*yield*/, this.queueLock.acquire("logQueue", function () { return __awaiter(_this, void 0, void 0, function () {
328
321
  return __generator(this, function (_a) {
329
- this.logQueue = __spreadArray(__spreadArray([], retryableLogs_1, true), this.logQueue, true);
322
+ this.logQueue = __spreadArray(__spreadArray([], logsToSend, true), this.logQueue, true);
330
323
  return [2 /*return*/];
331
324
  });
332
325
  }); })];
@@ -410,6 +403,19 @@ var Client = /** @class */ (function () {
410
403
  });
411
404
  });
412
405
  };
406
+ Client.prototype.createEvent = function (payload) {
407
+ return __awaiter(this, void 0, void 0, function () {
408
+ var response;
409
+ return __generator(this, function (_a) {
410
+ switch (_a.label) {
411
+ case 0: return [4 /*yield*/, this.axiosInstance.post("".concat(this.servicerEndpoint, "/events"), payload)];
412
+ case 1:
413
+ response = _a.sent();
414
+ return [2 /*return*/, response.data];
415
+ }
416
+ });
417
+ });
418
+ };
413
419
  Client.prototype.getEvent = function (eventID) {
414
420
  return __awaiter(this, void 0, void 0, function () {
415
421
  var response;
@@ -449,6 +455,19 @@ var Client = /** @class */ (function () {
449
455
  });
450
456
  });
451
457
  };
458
+ Client.prototype.getPolicy = function (policyID) {
459
+ return __awaiter(this, void 0, void 0, function () {
460
+ var response;
461
+ return __generator(this, function (_a) {
462
+ switch (_a.label) {
463
+ case 0: return [4 /*yield*/, this.axiosInstance.get("".concat(this.servicerEndpoint, "/policies/").concat(policyID))];
464
+ case 1:
465
+ response = _a.sent();
466
+ return [2 /*return*/, response.data];
467
+ }
468
+ });
469
+ });
470
+ };
452
471
  Client.prototype.createPolicy = function (payload) {
453
472
  return __awaiter(this, void 0, void 0, function () {
454
473
  var response;
@@ -462,6 +481,19 @@ var Client = /** @class */ (function () {
462
481
  });
463
482
  });
464
483
  };
484
+ Client.prototype.updatePolicy = function (policyID, payload) {
485
+ return __awaiter(this, void 0, void 0, function () {
486
+ var response;
487
+ return __generator(this, function (_a) {
488
+ switch (_a.label) {
489
+ case 0: return [4 /*yield*/, this.axiosInstance.put("".concat(this.servicerEndpoint, "/policies/").concat(policyID), payload)];
490
+ case 1:
491
+ response = _a.sent();
492
+ return [2 /*return*/, response.data];
493
+ }
494
+ });
495
+ });
496
+ };
465
497
  Client.prototype.listAlerts = function (status) {
466
498
  return __awaiter(this, void 0, void 0, function () {
467
499
  var endpoint, response;
@@ -479,10 +511,23 @@ var Client = /** @class */ (function () {
479
511
  });
480
512
  });
481
513
  };
482
- Client.prototype.getAlertDeliveries = function (alertID, options) {
483
- if (options === void 0) { options = {}; }
514
+ Client.prototype.getAlert = function (alertID) {
484
515
  return __awaiter(this, void 0, void 0, function () {
516
+ var response;
517
+ return __generator(this, function (_a) {
518
+ switch (_a.label) {
519
+ case 0: return [4 /*yield*/, this.axiosInstance.get("".concat(this.servicerEndpoint, "/alerts/").concat(alertID))];
520
+ case 1:
521
+ response = _a.sent();
522
+ return [2 /*return*/, response.data];
523
+ }
524
+ });
525
+ });
526
+ };
527
+ Client.prototype.getAlertDeliveries = function (alertID_1) {
528
+ return __awaiter(this, arguments, void 0, function (alertID, options) {
485
529
  var params, suffix, response;
530
+ if (options === void 0) { options = {}; }
486
531
  return __generator(this, function (_a) {
487
532
  switch (_a.label) {
488
533
  case 0:
@@ -531,22 +576,75 @@ var Client = /** @class */ (function () {
531
576
  });
532
577
  });
533
578
  };
534
- Client.prototype.testWebhook = function (webhookID) {
579
+ Client.prototype.listDestinations = function () {
535
580
  return __awaiter(this, void 0, void 0, function () {
581
+ var response;
536
582
  return __generator(this, function (_a) {
537
583
  switch (_a.label) {
538
- case 0: return [4 /*yield*/, this.axiosInstance.post("".concat(this.servicerEndpoint, "/webhooks/").concat(webhookID, "/test"))];
584
+ case 0: return [4 /*yield*/, this.axiosInstance.get("".concat(this.servicerEndpoint, "/destinations"))];
539
585
  case 1:
540
- _a.sent();
541
- return [2 /*return*/];
586
+ response = _a.sent();
587
+ return [2 /*return*/, response.data];
542
588
  }
543
589
  });
544
590
  });
545
591
  };
546
- Client.prototype.getEventLogs = function (eventID, options) {
547
- if (options === void 0) { options = {}; }
592
+ Client.prototype.createDestination = function (payload) {
548
593
  return __awaiter(this, void 0, void 0, function () {
594
+ var response;
595
+ return __generator(this, function (_a) {
596
+ switch (_a.label) {
597
+ case 0: return [4 /*yield*/, this.axiosInstance.post("".concat(this.servicerEndpoint, "/destinations"), payload)];
598
+ case 1:
599
+ response = _a.sent();
600
+ return [2 /*return*/, response.data];
601
+ }
602
+ });
603
+ });
604
+ };
605
+ Client.prototype.getDestination = function (destinationID) {
606
+ return __awaiter(this, void 0, void 0, function () {
607
+ var response;
608
+ return __generator(this, function (_a) {
609
+ switch (_a.label) {
610
+ case 0: return [4 /*yield*/, this.axiosInstance.get("".concat(this.servicerEndpoint, "/destinations/").concat(destinationID))];
611
+ case 1:
612
+ response = _a.sent();
613
+ return [2 /*return*/, response.data];
614
+ }
615
+ });
616
+ });
617
+ };
618
+ Client.prototype.updateDestination = function (destinationID, payload) {
619
+ return __awaiter(this, void 0, void 0, function () {
620
+ var response;
621
+ return __generator(this, function (_a) {
622
+ switch (_a.label) {
623
+ case 0: return [4 /*yield*/, this.axiosInstance.put("".concat(this.servicerEndpoint, "/destinations/").concat(destinationID), payload)];
624
+ case 1:
625
+ response = _a.sent();
626
+ return [2 /*return*/, response.data];
627
+ }
628
+ });
629
+ });
630
+ };
631
+ Client.prototype.testDestination = function (destinationID) {
632
+ return __awaiter(this, void 0, void 0, function () {
633
+ var response;
634
+ return __generator(this, function (_a) {
635
+ switch (_a.label) {
636
+ case 0: return [4 /*yield*/, this.axiosInstance.post("".concat(this.servicerEndpoint, "/destinations/").concat(destinationID, "/test"))];
637
+ case 1:
638
+ response = _a.sent();
639
+ return [2 /*return*/, response.data];
640
+ }
641
+ });
642
+ });
643
+ };
644
+ Client.prototype.getEventLogs = function (eventID_1) {
645
+ return __awaiter(this, arguments, void 0, function (eventID, options) {
549
646
  var params, suffix, response;
647
+ if (options === void 0) { options = {}; }
550
648
  return __generator(this, function (_a) {
551
649
  switch (_a.label) {
552
650
  case 0:
@@ -569,6 +667,24 @@ var Client = /** @class */ (function () {
569
667
  });
570
668
  });
571
669
  };
670
+ Client.prototype.getEventAnalytics = function (eventID, query) {
671
+ return __awaiter(this, void 0, void 0, function () {
672
+ var params, response;
673
+ return __generator(this, function (_a) {
674
+ switch (_a.label) {
675
+ case 0:
676
+ params = new URLSearchParams();
677
+ params.set("view", query.view);
678
+ params.set("period", query.period);
679
+ params.set("previous", query.previous);
680
+ return [4 /*yield*/, this.axiosInstance.get("".concat(this.servicerEndpoint, "/events/").concat(eventID, "/analytics?").concat(params.toString()))];
681
+ case 1:
682
+ response = _a.sent();
683
+ return [2 /*return*/, response.data];
684
+ }
685
+ });
686
+ });
687
+ };
572
688
  Client.prototype.resolveAlert = function (alertID) {
573
689
  return __awaiter(this, void 0, void 0, function () {
574
690
  var response;
@@ -590,13 +706,24 @@ function createClient(config) {
590
706
  if (config === void 0) { config = {}; }
591
707
  return new Client(config);
592
708
  }
593
- exports.createClient = createClient;
594
709
  function isNodeEnvironment() {
595
710
  return typeof process !== "undefined" && !!(process.versions && process.versions.node);
596
711
  }
597
712
  function isValidAPIKey(token) {
598
713
  return token.startsWith("chp_") && token.length > "chp_".length;
599
714
  }
715
+ function isUUID(value) {
716
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
717
+ }
718
+ function resolveLogID(logID) {
719
+ if (typeof logID === "string") {
720
+ var trimmedLogID = logID.trim();
721
+ if (trimmedLogID.length > 0) {
722
+ return trimmedLogID;
723
+ }
724
+ }
725
+ return (0, uuid_1.v7)();
726
+ }
600
727
  function loadDotEnvKey() {
601
728
  if (!isNodeEnvironment()) {
602
729
  return undefined;
@@ -655,7 +782,6 @@ function initialize(options) {
655
782
  throw error;
656
783
  }
657
784
  }
658
- exports.initialize = initialize;
659
785
  function logEvent(log) {
660
786
  return __awaiter(this, void 0, void 0, function () {
661
787
  return __generator(this, function (_a) {
@@ -672,7 +798,6 @@ function logEvent(log) {
672
798
  });
673
799
  });
674
800
  }
675
- exports.logEvent = logEvent;
676
801
  function stop() {
677
802
  return __awaiter(this, void 0, void 0, function () {
678
803
  return __generator(this, function (_a) {
@@ -690,7 +815,6 @@ function stop() {
690
815
  });
691
816
  });
692
817
  }
693
- exports.stop = stop;
694
818
  function flush() {
695
819
  return __awaiter(this, void 0, void 0, function () {
696
820
  return __generator(this, function (_a) {
@@ -707,4 +831,3 @@ function flush() {
707
831
  });
708
832
  });
709
833
  }
710
- exports.flush = flush;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chirpier/chirpier-js",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Chirpier SDK for JavaScript",
5
5
  "keywords": [
6
6
  "chirpier",
@@ -32,7 +32,8 @@
32
32
  "axios-retry": "^4.5.0",
33
33
  "dotenv": "^16.4.7",
34
34
  "ts-node": "^10.9.2",
35
- "tslib": "^2.3.0"
35
+ "tslib": "^2.3.0",
36
+ "uuid": "^11.1.0"
36
37
  },
37
38
  "devDependencies": {
38
39
  "@eslint/js": "^9.15.0",
@@ -41,13 +42,12 @@
41
42
  "@types/jest": "^29.5.13",
42
43
  "@types/mocha": "^10.0.8",
43
44
  "@types/node": "^22.7.5",
44
- "@types/uuid": "^10.0.0",
45
45
  "axios-mock-adapter": "^2.0.0",
46
46
  "eslint": "^9.15.0",
47
47
  "globals": "^15.12.0",
48
48
  "jest": "^29.7.0",
49
49
  "ts-jest": "^29.2.4",
50
- "typescript": "^4.4.3",
50
+ "typescript": "^5.6.3",
51
51
  "typescript-eslint": "^8.15.0",
52
52
  "webpack": "^5.52.0",
53
53
  "webpack-cli": "^4.8.0"
@@ -134,7 +134,7 @@ describe("Chirpier SDK", () => {
134
134
  });
135
135
 
136
136
  const log: Log = {
137
- agent_id: "api.worker",
137
+ agent: "api.worker",
138
138
  event: "request.finished",
139
139
  value: 1,
140
140
  };
@@ -146,14 +146,38 @@ describe("Chirpier SDK", () => {
146
146
  expect(mock.history.post[0].url).toBe(DEFAULT_API_ENDPOINT);
147
147
  expect(JSON.parse(mock.history.post[0].data)).toEqual([
148
148
  {
149
- agent_id: "api.worker",
149
+ log_id: expect.any(String),
150
+ agent: "api.worker",
150
151
  event: "request.finished",
151
152
  value: 1,
152
153
  },
153
154
  ]);
155
+ expect(JSON.parse(mock.history.post[0].data)[0].log_id).toMatch(
156
+ /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
157
+ );
154
158
  });
155
159
 
156
- test("agent_id whitespace should be omitted", async () => {
160
+ test("should preserve provided log_id", async () => {
161
+ const mock = new MockAdapter(axios);
162
+ mock.onPost(DEFAULT_API_ENDPOINT).reply(200, { success: true });
163
+
164
+ initialize({
165
+ key: "chp_log_id_key",
166
+ logLevel: LogLevel.None,
167
+ });
168
+
169
+ await logEvent({
170
+ log_id: "9f97d65f-fb30-4062-b4d0-8617c03fe4f6",
171
+ event: "request.finished",
172
+ value: 1,
173
+ });
174
+
175
+ await new Promise((resolve) => setTimeout(resolve, 2000));
176
+ const payload = JSON.parse(mock.history.post[0].data);
177
+ expect(payload[0].log_id).toBe("9f97d65f-fb30-4062-b4d0-8617c03fe4f6");
178
+ });
179
+
180
+ test("agent whitespace should be omitted", async () => {
157
181
  const mock = new MockAdapter(axios);
158
182
  mock.onPost(DEFAULT_API_ENDPOINT).reply(200, { success: true });
159
183
 
@@ -163,14 +187,14 @@ describe("Chirpier SDK", () => {
163
187
  });
164
188
 
165
189
  await logEvent({
166
- agent_id: " ",
190
+ agent: " ",
167
191
  event: "metric.tick",
168
192
  value: 42,
169
193
  });
170
194
 
171
195
  await new Promise((resolve) => setTimeout(resolve, 2000));
172
196
  const payload = JSON.parse(mock.history.post[0].data);
173
- expect(payload[0].agent_id).toBeUndefined();
197
+ expect(payload[0].agent).toBeUndefined();
174
198
  });
175
199
 
176
200
  test("should support meta payload", async () => {
@@ -183,7 +207,7 @@ describe("Chirpier SDK", () => {
183
207
  });
184
208
 
185
209
  await logEvent({
186
- agent_id: "api.worker",
210
+ agent: "api.worker",
187
211
  event: "request.finished",
188
212
  value: 200,
189
213
  meta: {
@@ -251,6 +275,14 @@ describe("Chirpier SDK", () => {
251
275
  })
252
276
  ).rejects.toThrow(ChirpierError);
253
277
 
278
+ await expect(
279
+ logEvent({
280
+ log_id: "not-a-uuid",
281
+ event: "bad-log-id",
282
+ value: 1,
283
+ })
284
+ ).rejects.toThrow(ChirpierError);
285
+
254
286
  expect(mock.history.post.length).toBe(0);
255
287
  });
256
288
 
@@ -322,6 +354,39 @@ describe("Chirpier SDK", () => {
322
354
  }
323
355
  });
324
356
 
357
+ test("event, policy, alert, and destination helpers use servicer endpoints", async () => {
358
+ const mock = new MockAdapter(axios);
359
+ mock.onPost("https://api.chirpier.co/v1.0/events").reply(200, { event_id: "evt_123", event: "tool.errors.count", public: false, timezone: "UTC" });
360
+ mock.onGet("https://api.chirpier.co/v1.0/events/evt_123").reply(200, { event_id: "evt_123", event: "tool.errors.count", public: false, timezone: "UTC" });
361
+ mock.onGet("https://api.chirpier.co/v1.0/policies/pol_123").reply(200, { policy_id: "pol_123", event_id: "evt_123", title: "Policy", channel: "ops", period: "hour", aggregate: "sum", condition: "gt", threshold: 1, severity: "warning", enabled: true });
362
+ mock.onPut("https://api.chirpier.co/v1.0/policies/pol_123").reply(200, { policy_id: "pol_123", event_id: "evt_123", title: "Updated", channel: "ops", period: "hour", aggregate: "sum", condition: "gt", threshold: 1, severity: "warning", enabled: true });
363
+ mock.onGet("https://api.chirpier.co/v1.0/alerts/alrt_123").reply(200, { alert_id: "alrt_123", policy_id: "pol_123", event_id: "evt_123", event: "tool.errors.count", title: "Alert", channel: "ops", period: "hour", aggregate: "sum", condition: "gt", threshold: 1, severity: "warning", status: "triggered", value: 2, count: 2, min: 1, max: 1 });
364
+ mock.onGet("https://api.chirpier.co/v1.0/destinations").reply(200, []);
365
+ mock.onPost("https://api.chirpier.co/v1.0/destinations").reply(200, { destination_id: "dst_123", channel: "slack", scope: "all", enabled: true });
366
+ mock.onGet("https://api.chirpier.co/v1.0/destinations/dst_123").reply(200, { destination_id: "dst_123", channel: "slack", scope: "all", enabled: true });
367
+ mock.onPut("https://api.chirpier.co/v1.0/destinations/dst_123").reply(200, { destination_id: "dst_123", channel: "slack", scope: "all", enabled: false });
368
+
369
+ const client: Client = createClient({ key: "chp_client_route_key" });
370
+ try {
371
+ const createdEvent = await client.createEvent({ event: "tool.errors.count" });
372
+ expect(createdEvent.event_id).toBe("evt_123");
373
+ await client.getEvent("evt_123");
374
+ const policy = await client.getPolicy("pol_123");
375
+ expect(policy.policy_id).toBe("pol_123");
376
+ await client.updatePolicy("pol_123", { title: "Updated" });
377
+ const alert = await client.getAlert("alrt_123");
378
+ expect(alert.alert_id).toBe("alrt_123");
379
+ await client.listDestinations();
380
+ const destination = await client.createDestination({ channel: "slack", scope: "all", enabled: true });
381
+ expect(destination.destination_id).toBe("dst_123");
382
+ await client.getDestination("dst_123");
383
+ const updatedDestination = await client.updateDestination("dst_123", { enabled: false });
384
+ expect(updatedDestination.enabled).toBe(false);
385
+ } finally {
386
+ await client.shutdown();
387
+ }
388
+ });
389
+
325
390
  test("getAlertDeliveries uses pagination params", async () => {
326
391
  const mock = new MockAdapter(axios);
327
392
  mock.onGet("https://api.chirpier.co/v1.0/alerts/alrt_123/deliveries?kind=test&limit=20&offset=5").reply(200, []);
@@ -348,17 +413,46 @@ describe("Chirpier SDK", () => {
348
413
  }
349
414
  });
350
415
 
351
- test("testWebhook posts to servicer endpoint", async () => {
416
+ test("testDestination posts to servicer endpoint", async () => {
352
417
  const mock = new MockAdapter(axios);
353
- mock.onPost("https://api.chirpier.co/v1.0/webhooks/whk_123/test").reply(200);
418
+ mock.onPost("https://api.chirpier.co/v1.0/destinations/whk_123/test").reply(200, {
419
+ alert_id: "alrt_123",
420
+ destination_id: "whk_123",
421
+ status: "sent",
422
+ });
354
423
 
355
- const client: Client = createClient({ key: "chp_client_webhook_key" });
424
+ const client: Client = createClient({ key: "chp_client_destination_key" });
356
425
  try {
357
- await client.testWebhook("whk_123");
358
- expect(mock.history.post[0].url).toBe("https://api.chirpier.co/v1.0/webhooks/whk_123/test");
426
+ const result = await client.testDestination("whk_123");
427
+ expect(result.alert_id).toBe("alrt_123");
428
+ expect(mock.history.post[0].url).toBe("https://api.chirpier.co/v1.0/destinations/whk_123/test");
359
429
  } finally {
360
430
  await client.shutdown();
361
431
  }
362
432
  });
433
+
434
+ test("getEventAnalytics uses analytics endpoint", async () => {
435
+ const mock = new MockAdapter(axios);
436
+ mock.onGet("https://api.chirpier.co/v1.0/events/evt_123/analytics?view=window&period=1h&previous=previous_window").reply(200, {
437
+ event_id: "evt_123",
438
+ view: "window",
439
+ period: "1h",
440
+ previous: "previous_window",
441
+ data: null,
442
+ });
443
+
444
+ const client: Client = createClient({ key: "chp_client_analytics_key" });
445
+ try {
446
+ const analytics = await client.getEventAnalytics("evt_123", {
447
+ view: "window",
448
+ period: "1h",
449
+ previous: "previous_window",
450
+ });
451
+ expect(analytics.event_id).toBe("evt_123");
452
+ expect(mock.history.get[0].url).toBe("https://api.chirpier.co/v1.0/events/evt_123/analytics?view=window&period=1h&previous=previous_window");
453
+ } finally {
454
+ await client.shutdown();
455
+ }
456
+ });
363
457
  });
364
458
  });