@chirpier/chirpier-js 0.1.5 → 0.2.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
@@ -14,6 +14,17 @@ var __extends = (this && this.__extends) || (function () {
14
14
  d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
15
  };
16
16
  })();
17
+ var __assign = (this && this.__assign) || function () {
18
+ __assign = Object.assign || function(t) {
19
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
20
+ s = arguments[i];
21
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
22
+ t[p] = s[p];
23
+ }
24
+ return t;
25
+ };
26
+ return __assign.apply(this, arguments);
27
+ };
17
28
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
18
29
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
19
30
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -63,26 +74,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
63
74
  return (mod && mod.__esModule) ? mod : { "default": mod };
64
75
  };
65
76
  Object.defineProperty(exports, "__esModule", { value: true });
66
- exports.monitor = exports.initialize = exports.Chirpier = exports.ChirpierError = exports.LogLevel = void 0;
67
- // Import necessary dependencies
77
+ exports.flush = exports.stop = exports.logEvent = exports.initialize = exports.createClient = exports.Client = exports.ChirpierError = void 0;
68
78
  var axios_1 = __importDefault(require("axios"));
69
79
  var axios_retry_1 = __importDefault(require("axios-retry"));
70
- var js_base64_1 = require("js-base64");
80
+ var dotenv_1 = __importDefault(require("dotenv"));
71
81
  var constants_1 = require("./constants");
72
82
  var async_lock_1 = __importDefault(require("async-lock"));
73
- // Define logging levels
74
- var LogLevel;
75
- (function (LogLevel) {
76
- LogLevel[LogLevel["None"] = 0] = "None";
77
- LogLevel[LogLevel["Error"] = 1] = "Error";
78
- LogLevel[LogLevel["Info"] = 2] = "Info";
79
- LogLevel[LogLevel["Debug"] = 3] = "Debug";
80
- })(LogLevel = exports.LogLevel || (exports.LogLevel = {}));
81
83
  // Custom error class for Chirpier-specific errors
82
84
  var ChirpierError = /** @class */ (function (_super) {
83
85
  __extends(ChirpierError, _super);
84
- function ChirpierError(message) {
86
+ function ChirpierError(message, code) {
85
87
  var _this = _super.call(this, message) || this;
88
+ _this.code = code;
86
89
  _this.name = "ChirpierError";
87
90
  Object.setPrototypeOf(_this, ChirpierError.prototype);
88
91
  return _this;
@@ -90,113 +93,166 @@ var ChirpierError = /** @class */ (function (_super) {
90
93
  return ChirpierError;
91
94
  }(Error));
92
95
  exports.ChirpierError = ChirpierError;
93
- /**
94
- * Main Chirpier class for monitoring events.
95
- */
96
- var Chirpier = /** @class */ (function () {
97
- /**
98
- * Initializes a new instance of the Chirpier class.
99
- * @param options - Configuration options for the SDK.
100
- */
101
- function Chirpier(options) {
102
- this.eventQueue = [];
96
+ var Client = /** @class */ (function () {
97
+ function Client(options) {
98
+ if (options === void 0) { options = {}; }
99
+ this.logQueue = [];
103
100
  this.flushTimeoutId = null;
104
- this.queueLock = new async_lock_1.default();
105
- this.flushLock = new async_lock_1.default();
106
- var key = options.key, _a = options.region, region = _a === void 0 ? "events" : _a, _b = options.logLevel, logLevel = _b === void 0 ? LogLevel.None : _b;
107
- if (!key || typeof key !== "string") {
108
- throw new ChirpierError("API key is required and must be a string");
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;
102
+ var key = resolveAPIKey(providedKey);
103
+ if (!key) {
104
+ throw new ChirpierError("API key is required", "INVALID_KEY");
105
+ }
106
+ if (!isValidAPIKey(key)) {
107
+ throw new ChirpierError("Invalid API key: must start with 'chp_'", "INVALID_KEY");
108
+ }
109
+ if (apiEndpoint !== undefined) {
110
+ if (typeof apiEndpoint !== "string" || apiEndpoint.trim().length === 0) {
111
+ throw new ChirpierError("apiEndpoint must be a non-empty string", "INVALID_API_ENDPOINT");
112
+ }
113
+ var parsedURL = void 0;
114
+ try {
115
+ parsedURL = new URL(apiEndpoint);
116
+ }
117
+ catch (_j) {
118
+ throw new ChirpierError("apiEndpoint must be a valid absolute URL", "INVALID_API_ENDPOINT");
119
+ }
120
+ if (parsedURL.protocol !== "https:" && parsedURL.protocol !== "http:") {
121
+ throw new ChirpierError("apiEndpoint must use http or https", "INVALID_API_ENDPOINT");
122
+ }
123
+ }
124
+ // Validate numeric options
125
+ if (retries < 0 || !Number.isInteger(retries)) {
126
+ throw new ChirpierError("Retries must be a non-negative integer", "INVALID_RETRIES");
127
+ }
128
+ if (timeout <= 0) {
129
+ throw new ChirpierError("Timeout must be positive", "INVALID_TIMEOUT");
130
+ }
131
+ if (batchSize <= 0 || !Number.isInteger(batchSize)) {
132
+ throw new ChirpierError("Batch size must be a positive integer", "INVALID_BATCH_SIZE");
109
133
  }
110
- if (typeof region !== "string" && !["us-west", "eu-west", "asia-southeast", "events"].includes(region)) {
111
- throw new ChirpierError("Region must be one of: us-west, eu-west, asia-southeast, events");
134
+ if (flushDelay < 0) {
135
+ throw new ChirpierError("Flush delay must be non-negative", "INVALID_FLUSH_DELAY");
112
136
  }
113
- this.apiEndpoint = "https://".concat(region, ".chirpier.co/v1.0/events");
137
+ if (maxQueueSize <= 0 || !Number.isInteger(maxQueueSize)) {
138
+ throw new ChirpierError("Max queue size must be a positive integer", "INVALID_QUEUE_SIZE");
139
+ }
140
+ this.apiEndpoint = apiEndpoint !== null && apiEndpoint !== void 0 ? apiEndpoint : constants_1.DEFAULT_API_ENDPOINT;
141
+ this.servicerEndpoint = servicerEndpoint !== null && servicerEndpoint !== void 0 ? servicerEndpoint : constants_1.DEFAULT_SERVICER_ENDPOINT;
114
142
  this.apiKey = key;
115
- this.retries = constants_1.DEFAULT_RETRIES;
116
- this.timeout = constants_1.DEFAULT_TIMEOUT;
117
- this.batchSize = constants_1.DEFAULT_BATCH_SIZE;
118
- this.flushDelay = constants_1.DEFAULT_FLUSH_DELAY;
143
+ this.retries = retries;
144
+ this.timeout = timeout;
145
+ this.batchSize = batchSize;
146
+ this.flushDelay = flushDelay;
147
+ this.maxQueueSize = maxQueueSize;
119
148
  this.logLevel = logLevel;
120
- // Create axios instance with authorization header
149
+ this.queueLock = new async_lock_1.default({ maxPending: this.maxQueueSize });
150
+ this.flushLock = new async_lock_1.default({ maxPending: this.maxQueueSize });
121
151
  this.axiosInstance = axios_1.default.create({
122
152
  headers: { Authorization: "Bearer ".concat(this.apiKey) },
123
153
  timeout: this.timeout,
124
154
  });
125
- // Add the interceptor here
126
- this.axiosInstance.interceptors.response.use(function (response) { return response; }, function (error) {
127
- // Don't handle the error here; let axios-retry handle it
128
- return Promise.reject(error);
129
- });
130
- // Apply axios-retry to your Axios instance
155
+ this.axiosInstance.interceptors.response.use(function (response) { return response; }, function (error) { return Promise.reject(error); });
131
156
  (0, axios_retry_1.default)(this.axiosInstance, {
132
157
  retries: this.retries,
133
158
  retryDelay: function (retryCount) {
134
- return Math.pow(2, retryCount) * 1000; // Exponential backoff starting at 1 second
159
+ var baseDelay = Math.pow(2, retryCount) * 1000;
160
+ var jitter = Math.random() * 0.3 * baseDelay;
161
+ return baseDelay + jitter;
135
162
  },
136
163
  retryCondition: function (error) {
137
- // Retry on network errors, 5xx errors, and 429 (Too Many Requests)
138
164
  return (axios_retry_1.default.isNetworkError(error) ||
139
165
  axios_retry_1.default.isRetryableError(error) ||
140
- ((error.response && error.response.status) === 429));
166
+ (error.response && error.response.status) === 429);
141
167
  },
142
168
  shouldResetTimeout: true,
143
169
  });
144
170
  }
145
- /**
146
- * Gets the singleton instance of Chirpier, creating it if it doesn't exist.
147
- * @param options - Configuration options for the SDK.
148
- * @returns The Chirpier instance.
149
- */
150
- Chirpier.getInstance = function (options) {
151
- if (!Chirpier.instance && options.key) {
152
- Chirpier.instance = new Chirpier(options);
171
+ Client.prototype.isValidLog = function (log) {
172
+ var now = Date.now();
173
+ var oldestAllowed = now - 30 * 24 * 60 * 60 * 1000;
174
+ var newestAllowed = now + 24 * 60 * 60 * 1000;
175
+ if (typeof log.event !== "string" || log.event.trim().length === 0) {
176
+ return false;
177
+ }
178
+ if (typeof log.value !== "number" || !Number.isFinite(log.value)) {
179
+ return false;
180
+ }
181
+ if (log.agent_id !== undefined && typeof log.agent_id !== "string") {
182
+ return false;
183
+ }
184
+ if (log.meta !== undefined) {
185
+ try {
186
+ var serializedMeta = JSON.stringify(log.meta);
187
+ if (serializedMeta === undefined) {
188
+ return false;
189
+ }
190
+ }
191
+ catch (_a) {
192
+ return false;
193
+ }
194
+ }
195
+ if (log.occurred_at !== undefined) {
196
+ var occurredAtMillis = log.occurred_at instanceof Date
197
+ ? log.occurred_at.getTime()
198
+ : new Date(log.occurred_at).getTime();
199
+ if (!Number.isFinite(occurredAtMillis)) {
200
+ return false;
201
+ }
202
+ if (occurredAtMillis < oldestAllowed || occurredAtMillis > newestAllowed) {
203
+ return false;
204
+ }
153
205
  }
154
- return Chirpier.instance;
206
+ return true;
155
207
  };
156
- /**
157
- * Validates the event structure.
158
- * @param event - The event to validate.
159
- * @returns True if valid, false otherwise.
160
- */
161
- Chirpier.prototype.isValidEvent = function (event) {
162
- return (typeof event.group_id === "string" &&
163
- /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(event.group_id) &&
164
- event.group_id.trim().length > 0 &&
165
- typeof event.stream_name === "string" &&
166
- event.stream_name.trim().length > 0 &&
167
- typeof event.value === "number");
208
+ Client.prototype.normalizeLog = function (log) {
209
+ var normalizedLog = {
210
+ event: log.event.trim(),
211
+ value: log.value,
212
+ };
213
+ if (typeof log.agent_id === "string") {
214
+ var trimmedAgentID = log.agent_id.trim();
215
+ if (trimmedAgentID.length > 0) {
216
+ normalizedLog.agent_id = trimmedAgentID;
217
+ }
218
+ }
219
+ if (log.meta !== undefined) {
220
+ normalizedLog.meta = log.meta;
221
+ }
222
+ if (log.occurred_at !== undefined) {
223
+ var occurredAtDate = log.occurred_at instanceof Date ? log.occurred_at : new Date(log.occurred_at);
224
+ normalizedLog.occurred_at = occurredAtDate.toISOString();
225
+ }
226
+ return normalizedLog;
168
227
  };
169
- /**
170
- * Monitors an event by adding it to the queue and scheduling a flush if necessary.
171
- * @param event - The event to monitor.
172
- */
173
- Chirpier.prototype.monitor = function (event) {
228
+ Client.prototype.log = function (log) {
174
229
  return __awaiter(this, void 0, void 0, function () {
230
+ var normalizedLog, queueFull;
175
231
  var _this = this;
176
232
  return __generator(this, function (_a) {
177
233
  switch (_a.label) {
178
234
  case 0:
179
- if (!this.isValidEvent(event)) {
180
- if (this.logLevel >= LogLevel.Debug) {
181
- console.debug("Invalid event format, dropping event:", event);
182
- }
183
- return [2 /*return*/]; // Silently drop the event
235
+ 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");
184
237
  }
238
+ normalizedLog = this.normalizeLog(log);
239
+ queueFull = false;
185
240
  return [4 /*yield*/, this.queueLock.acquire("queue", function () { return __awaiter(_this, void 0, void 0, function () {
186
241
  return __generator(this, function (_a) {
187
- if (this.eventQueue.length >= constants_1.MAX_QUEUE_SIZE) {
188
- if (this.logLevel >= LogLevel.Debug) {
189
- console.debug("Event queue is full, dropping event:", event);
190
- }
191
- return [2 /*return*/]; // Silently drop the event
242
+ if (this.logQueue.length >= this.maxQueueSize) {
243
+ queueFull = true;
244
+ return [2 /*return*/];
192
245
  }
193
- this.eventQueue.push({ event: event, timestamp: Date.now(), retryCount: 0 });
246
+ this.logQueue.push({ log: normalizedLog, timestamp: Date.now(), retryCount: 0 });
194
247
  return [2 /*return*/];
195
248
  });
196
249
  }); })];
197
250
  case 1:
198
251
  _a.sent();
199
- if (!(this.eventQueue.length >= this.batchSize)) return [3 /*break*/, 3];
252
+ if (queueFull) {
253
+ throw new ChirpierError("Log queue is full (max size: ".concat(this.maxQueueSize, ")"), "QUEUE_FULL");
254
+ }
255
+ if (!(this.logQueue.length >= this.batchSize)) return [3 /*break*/, 3];
200
256
  return [4 /*yield*/, this.flushQueue()];
201
257
  case 2:
202
258
  _a.sent();
@@ -211,84 +267,70 @@ var Chirpier = /** @class */ (function () {
211
267
  });
212
268
  });
213
269
  };
214
- /**
215
- * Flushes the event queue by sending all events to the API.
216
- */
217
- Chirpier.prototype.flushQueue = function () {
270
+ Client.prototype.flushQueue = function () {
218
271
  return __awaiter(this, void 0, void 0, function () {
219
272
  var _this = this;
220
273
  return __generator(this, function (_a) {
221
274
  switch (_a.label) {
222
- case 0:
223
- // Acquire the flush lock
224
- return [4 /*yield*/, this.flushLock.acquire("flush", function () { return __awaiter(_this, void 0, void 0, function () {
225
- var eventsToSend, error_1, retryableEvents_1, _i, eventsToSend_1, queuedEvent;
275
+ 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;
226
277
  var _this = this;
227
278
  return __generator(this, function (_a) {
228
279
  switch (_a.label) {
229
280
  case 0:
230
- eventsToSend = [];
231
- // Extract events from the queue under the queue lock
232
- return [4 /*yield*/, this.queueLock.acquire("eventQueue", function () { return __awaiter(_this, void 0, void 0, function () {
281
+ logsToSend = [];
282
+ return [4 /*yield*/, this.queueLock.acquire("logQueue", function () { return __awaiter(_this, void 0, void 0, function () {
233
283
  return __generator(this, function (_a) {
234
- if (this.eventQueue.length > 0) {
235
- eventsToSend = __spreadArray([], this.eventQueue, true);
236
- this.eventQueue = [];
284
+ if (this.logQueue.length > 0) {
285
+ logsToSend = __spreadArray([], this.logQueue, true);
286
+ this.logQueue = [];
237
287
  }
238
288
  return [2 /*return*/];
239
289
  });
240
290
  }); })];
241
291
  case 1:
242
- // Extract events from the queue under the queue lock
243
292
  _a.sent();
244
- if (eventsToSend.length === 0) {
293
+ if (logsToSend.length === 0) {
245
294
  return [2 /*return*/];
246
295
  }
247
296
  _a.label = 2;
248
297
  case 2:
249
298
  _a.trys.push([2, 4, , 6]);
250
- // Clear any pending flush timeout
251
299
  if (this.flushTimeoutId) {
252
300
  clearTimeout(this.flushTimeoutId);
253
301
  this.flushTimeoutId = null;
254
302
  }
255
- // Attempt to send events
256
- return [4 /*yield*/, this.sendEvents(eventsToSend.map(function (qe) { return qe.event; }))];
303
+ return [4 /*yield*/, this.sendLogs(logsToSend.map(function (queuedLog) { return queuedLog.log; }))];
257
304
  case 3:
258
- // Attempt to send events
259
305
  _a.sent();
260
- if (this.logLevel >= LogLevel.Info) {
261
- console.info("Successfully sent ".concat(eventsToSend.length, " events"));
306
+ if (this.logLevel >= 2 /* LogLevel.Info */) {
307
+ console.info("Successfully sent ".concat(logsToSend.length, " logs"));
262
308
  }
263
309
  return [3 /*break*/, 6];
264
310
  case 4:
265
311
  error_1 = _a.sent();
266
- // Log failure
267
- if (this.logLevel >= LogLevel.Error) {
268
- console.error("Failed to send events:", error_1);
312
+ if (this.logLevel >= 1 /* LogLevel.Error */) {
313
+ console.error("Failed to send logs:", error_1);
269
314
  }
270
- retryableEvents_1 = [];
271
- for (_i = 0, eventsToSend_1 = eventsToSend; _i < eventsToSend_1.length; _i++) {
272
- queuedEvent = eventsToSend_1[_i];
273
- if (queuedEvent.retryCount >= this.retries) {
274
- if (this.logLevel >= LogLevel.Error) {
275
- console.error("Dropping event after ".concat(this.retries, " retries:"), queuedEvent.event);
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);
276
321
  }
277
- continue; // Skip adding this event back to the queue
322
+ continue;
278
323
  }
279
- // Increment retry count and add back to the queue
280
- queuedEvent.retryCount++;
281
- retryableEvents_1.push(queuedEvent);
324
+ queuedLog.retryCount++;
325
+ retryableLogs_1.push(queuedLog);
282
326
  }
283
- // Requeue remaining retryable events
284
- return [4 /*yield*/, this.queueLock.acquire("eventQueue", function () { return __awaiter(_this, void 0, void 0, function () {
327
+ return [4 /*yield*/, this.queueLock.acquire("logQueue", function () { return __awaiter(_this, void 0, void 0, function () {
285
328
  return __generator(this, function (_a) {
286
- this.eventQueue = __spreadArray(__spreadArray([], retryableEvents_1, true), this.eventQueue, true);
329
+ this.logQueue = __spreadArray(__spreadArray([], retryableLogs_1, true), this.logQueue, true);
287
330
  return [2 /*return*/];
288
331
  });
289
332
  }); })];
290
333
  case 5:
291
- // Requeue remaining retryable events
292
334
  _a.sent();
293
335
  return [3 /*break*/, 6];
294
336
  case 6: return [2 /*return*/];
@@ -296,22 +338,29 @@ var Chirpier = /** @class */ (function () {
296
338
  });
297
339
  }); })];
298
340
  case 1:
299
- // Acquire the flush lock
300
341
  _a.sent();
301
342
  return [2 /*return*/];
302
343
  }
303
344
  });
304
345
  });
305
346
  };
306
- /**
307
- * Sends multiple events to the API in a batch.
308
- * @param events - The array of events to send.
309
- */
310
- Chirpier.prototype.sendEvents = function (events) {
347
+ Client.prototype.sendLogs = function (logs) {
348
+ return __awaiter(this, void 0, void 0, function () {
349
+ return __generator(this, function (_a) {
350
+ switch (_a.label) {
351
+ case 0: return [4 /*yield*/, this.axiosInstance.post(this.apiEndpoint, logs)];
352
+ case 1:
353
+ _a.sent();
354
+ return [2 /*return*/];
355
+ }
356
+ });
357
+ });
358
+ };
359
+ Client.prototype.flush = function () {
311
360
  return __awaiter(this, void 0, void 0, function () {
312
361
  return __generator(this, function (_a) {
313
362
  switch (_a.label) {
314
- case 0: return [4 /*yield*/, this.axiosInstance.post(this.apiEndpoint, events)];
363
+ case 0: return [4 /*yield*/, this.flushQueue()];
315
364
  case 1:
316
365
  _a.sent();
317
366
  return [2 /*return*/];
@@ -319,89 +368,287 @@ var Chirpier = /** @class */ (function () {
319
368
  });
320
369
  });
321
370
  };
322
- // Stop the timeout and uninitialize the Chirpier instance
323
- Chirpier.stop = function () {
371
+ Client.prototype.shutdown = function () {
324
372
  return __awaiter(this, void 0, void 0, function () {
325
373
  return __generator(this, function (_a) {
326
374
  switch (_a.label) {
327
375
  case 0:
328
- if (!Chirpier.instance) {
329
- return [2 /*return*/];
376
+ if (this.flushTimeoutId) {
377
+ clearTimeout(this.flushTimeoutId);
378
+ this.flushTimeoutId = null;
330
379
  }
331
- if (Chirpier.instance.flushTimeoutId) {
332
- clearTimeout(Chirpier.instance.flushTimeoutId);
333
- Chirpier.instance.flushTimeoutId = null;
380
+ return [4 /*yield*/, this.flushQueue()];
381
+ case 1:
382
+ _a.sent();
383
+ return [2 /*return*/];
384
+ }
385
+ });
386
+ });
387
+ };
388
+ Client.prototype.close = function () {
389
+ return __awaiter(this, void 0, void 0, function () {
390
+ return __generator(this, function (_a) {
391
+ switch (_a.label) {
392
+ case 0: return [4 /*yield*/, this.shutdown()];
393
+ case 1:
394
+ _a.sent();
395
+ return [2 /*return*/];
396
+ }
397
+ });
398
+ });
399
+ };
400
+ Client.prototype.listEvents = function () {
401
+ return __awaiter(this, void 0, void 0, function () {
402
+ var response;
403
+ return __generator(this, function (_a) {
404
+ switch (_a.label) {
405
+ case 0: return [4 /*yield*/, this.axiosInstance.get("".concat(this.servicerEndpoint, "/events"))];
406
+ case 1:
407
+ response = _a.sent();
408
+ return [2 /*return*/, response.data];
409
+ }
410
+ });
411
+ });
412
+ };
413
+ Client.prototype.getEvent = function (eventID) {
414
+ return __awaiter(this, void 0, void 0, function () {
415
+ var response;
416
+ return __generator(this, function (_a) {
417
+ switch (_a.label) {
418
+ case 0: return [4 /*yield*/, this.axiosInstance.get("".concat(this.servicerEndpoint, "/events/").concat(eventID))];
419
+ case 1:
420
+ response = _a.sent();
421
+ return [2 /*return*/, response.data];
422
+ }
423
+ });
424
+ });
425
+ };
426
+ Client.prototype.updateEvent = function (eventID, payload) {
427
+ return __awaiter(this, void 0, void 0, function () {
428
+ var response;
429
+ return __generator(this, function (_a) {
430
+ switch (_a.label) {
431
+ case 0: return [4 /*yield*/, this.axiosInstance.put("".concat(this.servicerEndpoint, "/events/").concat(eventID), payload)];
432
+ case 1:
433
+ response = _a.sent();
434
+ return [2 /*return*/, response.data];
435
+ }
436
+ });
437
+ });
438
+ };
439
+ Client.prototype.listPolicies = function () {
440
+ return __awaiter(this, void 0, void 0, function () {
441
+ var response;
442
+ return __generator(this, function (_a) {
443
+ switch (_a.label) {
444
+ case 0: return [4 /*yield*/, this.axiosInstance.get("".concat(this.servicerEndpoint, "/policies"))];
445
+ case 1:
446
+ response = _a.sent();
447
+ return [2 /*return*/, response.data];
448
+ }
449
+ });
450
+ });
451
+ };
452
+ Client.prototype.createPolicy = function (payload) {
453
+ return __awaiter(this, void 0, void 0, function () {
454
+ var response;
455
+ return __generator(this, function (_a) {
456
+ switch (_a.label) {
457
+ case 0: return [4 /*yield*/, this.axiosInstance.post("".concat(this.servicerEndpoint, "/policies"), payload)];
458
+ case 1:
459
+ response = _a.sent();
460
+ return [2 /*return*/, response.data];
461
+ }
462
+ });
463
+ });
464
+ };
465
+ Client.prototype.listAlerts = function (status) {
466
+ return __awaiter(this, void 0, void 0, function () {
467
+ var endpoint, response;
468
+ return __generator(this, function (_a) {
469
+ switch (_a.label) {
470
+ case 0:
471
+ endpoint = status
472
+ ? "".concat(this.servicerEndpoint, "/alerts?status=").concat(encodeURIComponent(status))
473
+ : "".concat(this.servicerEndpoint, "/alerts");
474
+ return [4 /*yield*/, this.axiosInstance.get(endpoint)];
475
+ case 1:
476
+ response = _a.sent();
477
+ return [2 /*return*/, response.data];
478
+ }
479
+ });
480
+ });
481
+ };
482
+ Client.prototype.getAlertDeliveries = function (alertID, options) {
483
+ if (options === void 0) { options = {}; }
484
+ return __awaiter(this, void 0, void 0, function () {
485
+ var params, suffix, response;
486
+ return __generator(this, function (_a) {
487
+ switch (_a.label) {
488
+ case 0:
489
+ params = new URLSearchParams();
490
+ if (options.kind) {
491
+ params.set("kind", options.kind);
492
+ }
493
+ if (typeof options.limit === "number") {
494
+ params.set("limit", String(options.limit));
334
495
  }
335
- // Flush any remaining events in the queue
336
- return [4 /*yield*/, Chirpier.instance.flushQueue()];
496
+ if (typeof options.offset === "number") {
497
+ params.set("offset", String(options.offset));
498
+ }
499
+ suffix = params.toString() ? "?".concat(params.toString()) : "";
500
+ return [4 /*yield*/, this.axiosInstance.get("".concat(this.servicerEndpoint, "/alerts/").concat(alertID, "/deliveries").concat(suffix))];
501
+ case 1:
502
+ response = _a.sent();
503
+ return [2 /*return*/, response.data];
504
+ }
505
+ });
506
+ });
507
+ };
508
+ Client.prototype.acknowledgeAlert = function (alertID) {
509
+ return __awaiter(this, void 0, void 0, function () {
510
+ var response;
511
+ return __generator(this, function (_a) {
512
+ switch (_a.label) {
513
+ case 0: return [4 /*yield*/, this.axiosInstance.post("".concat(this.servicerEndpoint, "/alerts/").concat(alertID, "/acknowledge"))];
514
+ case 1:
515
+ response = _a.sent();
516
+ return [2 /*return*/, response.data];
517
+ }
518
+ });
519
+ });
520
+ };
521
+ Client.prototype.archiveAlert = function (alertID) {
522
+ return __awaiter(this, void 0, void 0, function () {
523
+ var response;
524
+ return __generator(this, function (_a) {
525
+ switch (_a.label) {
526
+ case 0: return [4 /*yield*/, this.axiosInstance.post("".concat(this.servicerEndpoint, "/alerts/").concat(alertID, "/archive"))];
527
+ case 1:
528
+ response = _a.sent();
529
+ return [2 /*return*/, response.data];
530
+ }
531
+ });
532
+ });
533
+ };
534
+ Client.prototype.testWebhook = function (webhookID) {
535
+ return __awaiter(this, void 0, void 0, function () {
536
+ return __generator(this, function (_a) {
537
+ switch (_a.label) {
538
+ case 0: return [4 /*yield*/, this.axiosInstance.post("".concat(this.servicerEndpoint, "/webhooks/").concat(webhookID, "/test"))];
337
539
  case 1:
338
- // Flush any remaining events in the queue
339
540
  _a.sent();
340
- // Uninitialize the Chirpier instance
341
- Chirpier.instance = null;
342
541
  return [2 /*return*/];
343
542
  }
344
543
  });
345
544
  });
346
545
  };
347
- Chirpier.instance = null;
348
- return Chirpier;
546
+ Client.prototype.getEventLogs = function (eventID, options) {
547
+ if (options === void 0) { options = {}; }
548
+ return __awaiter(this, void 0, void 0, function () {
549
+ var params, suffix, response;
550
+ return __generator(this, function (_a) {
551
+ switch (_a.label) {
552
+ case 0:
553
+ params = new URLSearchParams();
554
+ if (options.period) {
555
+ params.set("period", options.period);
556
+ }
557
+ if (typeof options.limit === "number") {
558
+ params.set("limit", String(options.limit));
559
+ }
560
+ if (typeof options.offset === "number") {
561
+ params.set("offset", String(options.offset));
562
+ }
563
+ suffix = params.toString() ? "?".concat(params.toString()) : "";
564
+ return [4 /*yield*/, this.axiosInstance.get("".concat(this.servicerEndpoint, "/events/").concat(eventID, "/logs").concat(suffix))];
565
+ case 1:
566
+ response = _a.sent();
567
+ return [2 /*return*/, response.data];
568
+ }
569
+ });
570
+ });
571
+ };
572
+ Client.prototype.resolveAlert = function (alertID) {
573
+ return __awaiter(this, void 0, void 0, function () {
574
+ var response;
575
+ return __generator(this, function (_a) {
576
+ switch (_a.label) {
577
+ case 0: return [4 /*yield*/, this.axiosInstance.post("".concat(this.servicerEndpoint, "/alerts/").concat(alertID, "/resolve"))];
578
+ case 1:
579
+ response = _a.sent();
580
+ return [2 /*return*/, response.data];
581
+ }
582
+ });
583
+ });
584
+ };
585
+ return Client;
349
586
  }());
350
- exports.Chirpier = Chirpier;
351
- /**
352
- * Decodes a base64url encoded string.
353
- * @param str - The base64url encoded string to decode.
354
- * @returns The decoded string.
355
- */
356
- function base64UrlDecode(str) {
357
- // Replace '-' with '+' and '_' with '/'
358
- var base64 = str.replace(/-/g, "+").replace(/_/g, "/");
359
- // Pad the base64 string
360
- var padding = base64.length % 4;
361
- if (padding !== 0) {
362
- base64 += "=".repeat(4 - padding);
363
- }
364
- return js_base64_1.Base64.decode(base64);
587
+ exports.Client = Client;
588
+ var instance = null;
589
+ function createClient(config) {
590
+ if (config === void 0) { config = {}; }
591
+ return new Client(config);
365
592
  }
366
- /**
367
- * Validates if the provided token is a valid JWT.
368
- * @param token - The token to validate.
369
- * @returns True if valid, false otherwise.
370
- */
371
- function isValidJWT(token) {
372
- var parts = token.split(".");
373
- if (parts.length !== 3) {
374
- return false;
593
+ exports.createClient = createClient;
594
+ function isNodeEnvironment() {
595
+ return typeof process !== "undefined" && !!(process.versions && process.versions.node);
596
+ }
597
+ function isValidAPIKey(token) {
598
+ return token.startsWith("chp_") && token.length > "chp_".length;
599
+ }
600
+ function loadDotEnvKey() {
601
+ if (!isNodeEnvironment()) {
602
+ return undefined;
375
603
  }
376
604
  try {
377
- var header = JSON.parse(base64UrlDecode(parts[0]));
378
- var payload = JSON.parse(base64UrlDecode(parts[1]));
379
- return typeof header === "object" && typeof payload === "object";
605
+ dotenv_1.default.config({ path: ".env", override: false });
380
606
  }
381
- catch (error) {
382
- console.error("Failed to validate JWT:", error);
383
- return false;
607
+ catch (_a) {
608
+ return undefined;
384
609
  }
610
+ var envKey = process.env.CHIRPIER_API_KEY;
611
+ if (typeof envKey !== "string") {
612
+ return undefined;
613
+ }
614
+ var trimmedKey = envKey.trim();
615
+ return trimmedKey.length > 0 ? trimmedKey : undefined;
616
+ }
617
+ function resolveAPIKey(providedKey) {
618
+ if (typeof providedKey === "string" && providedKey.trim().length > 0) {
619
+ return providedKey.trim();
620
+ }
621
+ if (typeof process !== "undefined" && process.env && typeof process.env.CHIRPIER_API_KEY === "string") {
622
+ var envKey = process.env.CHIRPIER_API_KEY.trim();
623
+ if (envKey.length > 0) {
624
+ return envKey;
625
+ }
626
+ }
627
+ return loadDotEnvKey();
385
628
  }
386
- /**
387
- * Initializes the Chirpier SDK.
388
- * @param options - Configuration options for the SDK.
389
- */
390
629
  function initialize(options) {
391
- if (!isValidJWT(options.key)) {
392
- throw new ChirpierError("Invalid API key: Not a valid JWT");
630
+ if (options === void 0) { options = {}; }
631
+ var resolvedKey = resolveAPIKey(options.key);
632
+ if (!resolvedKey) {
633
+ throw new ChirpierError("API key is required", "INVALID_KEY");
634
+ }
635
+ if (!isValidAPIKey(resolvedKey)) {
636
+ throw new ChirpierError("Invalid API key: must start with 'chp_'", "INVALID_KEY");
637
+ }
638
+ if (instance) {
639
+ return;
393
640
  }
394
641
  try {
395
- Chirpier.getInstance(options);
642
+ instance = new Client(__assign(__assign({}, options), { key: resolvedKey }));
396
643
  }
397
644
  catch (error) {
398
645
  if (error instanceof ChirpierError) {
399
- if (options.logLevel && options.logLevel >= LogLevel.Error) {
646
+ if (options.logLevel && options.logLevel >= 1 /* LogLevel.Error */) {
400
647
  console.error("Failed to initialize Chirpier SDK:", error.message);
401
648
  }
402
649
  }
403
650
  else {
404
- if (options.logLevel && options.logLevel >= LogLevel.Error) {
651
+ if (options.logLevel && options.logLevel >= 1 /* LogLevel.Error */) {
405
652
  console.error("An unexpected error occurred during Chirpier SDK initialization:", error);
406
653
  }
407
654
  }
@@ -409,17 +656,55 @@ function initialize(options) {
409
656
  }
410
657
  }
411
658
  exports.initialize = initialize;
412
- /**
413
- * Monitors an event using the Chirpier SDK.
414
- * @param event - The event to monitor.
415
- */
416
- function monitor(event) {
417
- var instance = Chirpier.getInstance({});
418
- if (!instance) {
419
- throw new ChirpierError("Chirpier SDK is not initialized. Please call initialize() first.");
420
- }
421
- instance.monitor(event).catch(function (error) {
422
- console.error("Error in monitor function:", error);
659
+ function logEvent(log) {
660
+ return __awaiter(this, void 0, void 0, function () {
661
+ return __generator(this, function (_a) {
662
+ switch (_a.label) {
663
+ case 0:
664
+ if (!instance) {
665
+ throw new ChirpierError("Chirpier SDK is not initialized. Please call initialize() first.", "NOT_INITIALIZED");
666
+ }
667
+ return [4 /*yield*/, instance.log(log)];
668
+ case 1:
669
+ _a.sent();
670
+ return [2 /*return*/];
671
+ }
672
+ });
673
+ });
674
+ }
675
+ exports.logEvent = logEvent;
676
+ function stop() {
677
+ return __awaiter(this, void 0, void 0, function () {
678
+ return __generator(this, function (_a) {
679
+ switch (_a.label) {
680
+ case 0:
681
+ if (!instance) {
682
+ return [2 /*return*/];
683
+ }
684
+ return [4 /*yield*/, instance.shutdown()];
685
+ case 1:
686
+ _a.sent();
687
+ instance = null;
688
+ return [2 /*return*/];
689
+ }
690
+ });
691
+ });
692
+ }
693
+ exports.stop = stop;
694
+ function flush() {
695
+ return __awaiter(this, void 0, void 0, function () {
696
+ return __generator(this, function (_a) {
697
+ switch (_a.label) {
698
+ case 0:
699
+ if (!instance) {
700
+ throw new ChirpierError("Chirpier SDK is not initialized. Please call initialize() first.", "NOT_INITIALIZED");
701
+ }
702
+ return [4 /*yield*/, instance.flush()];
703
+ case 1:
704
+ _a.sent();
705
+ return [2 /*return*/];
706
+ }
707
+ });
423
708
  });
424
709
  }
425
- exports.monitor = monitor;
710
+ exports.flush = flush;