oilpriceapi 0.6.0 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +418 -123
  2. package/dist/cjs/client.js +490 -0
  3. package/dist/cjs/errors.js +80 -0
  4. package/dist/cjs/index.js +82 -0
  5. package/dist/cjs/package.json +1 -0
  6. package/dist/cjs/resources/alerts.js +387 -0
  7. package/dist/cjs/resources/analytics.js +226 -0
  8. package/dist/cjs/resources/bunker-fuels.js +196 -0
  9. package/dist/cjs/resources/commodities.js +115 -0
  10. package/dist/cjs/resources/data-quality.js +144 -0
  11. package/dist/cjs/resources/data-sources.js +297 -0
  12. package/dist/cjs/resources/diesel.js +119 -0
  13. package/dist/cjs/resources/drilling.js +269 -0
  14. package/dist/cjs/resources/ei/drilling-productivity.js +108 -0
  15. package/dist/cjs/resources/ei/forecasts.js +106 -0
  16. package/dist/cjs/resources/ei/frac-focus.js +155 -0
  17. package/dist/cjs/resources/ei/index.js +98 -0
  18. package/dist/cjs/resources/ei/oil-inventories.js +97 -0
  19. package/dist/cjs/resources/ei/opec-production.js +97 -0
  20. package/dist/cjs/resources/ei/rig-counts.js +93 -0
  21. package/dist/cjs/resources/ei/well-permits.js +124 -0
  22. package/dist/cjs/resources/forecasts.js +162 -0
  23. package/dist/cjs/resources/futures.js +233 -0
  24. package/dist/cjs/resources/rig-counts.js +161 -0
  25. package/dist/cjs/resources/storage.js +166 -0
  26. package/dist/cjs/resources/webhooks.js +294 -0
  27. package/dist/cjs/types.js +2 -0
  28. package/dist/cjs/version.js +24 -0
  29. package/dist/client.d.ts +116 -5
  30. package/dist/client.js +169 -47
  31. package/dist/errors.d.ts +6 -0
  32. package/dist/errors.js +25 -16
  33. package/dist/index.d.ts +45 -6
  34. package/dist/index.js +40 -3
  35. package/dist/resources/alerts.d.ts +52 -15
  36. package/dist/resources/alerts.js +121 -109
  37. package/dist/resources/analytics.d.ts +325 -0
  38. package/dist/resources/analytics.js +222 -0
  39. package/dist/resources/bunker-fuels.d.ts +270 -0
  40. package/dist/resources/bunker-fuels.js +192 -0
  41. package/dist/resources/commodities.d.ts +148 -0
  42. package/dist/resources/commodities.js +111 -0
  43. package/dist/resources/data-quality.d.ts +229 -0
  44. package/dist/resources/data-quality.js +140 -0
  45. package/dist/resources/data-sources.d.ts +365 -0
  46. package/dist/resources/data-sources.js +293 -0
  47. package/dist/resources/diesel.d.ts +1 -1
  48. package/dist/resources/diesel.js +9 -38
  49. package/dist/resources/drilling.d.ts +403 -0
  50. package/dist/resources/drilling.js +265 -0
  51. package/dist/resources/ei/drilling-productivity.d.ts +173 -0
  52. package/dist/resources/ei/drilling-productivity.js +104 -0
  53. package/dist/resources/ei/forecasts.d.ts +177 -0
  54. package/dist/resources/ei/forecasts.js +102 -0
  55. package/dist/resources/ei/frac-focus.d.ts +212 -0
  56. package/dist/resources/ei/frac-focus.js +151 -0
  57. package/dist/resources/ei/index.d.ts +140 -0
  58. package/dist/resources/ei/index.js +88 -0
  59. package/dist/resources/ei/oil-inventories.d.ts +155 -0
  60. package/dist/resources/ei/oil-inventories.js +93 -0
  61. package/dist/resources/ei/opec-production.d.ts +146 -0
  62. package/dist/resources/ei/opec-production.js +93 -0
  63. package/dist/resources/ei/rig-counts.d.ts +131 -0
  64. package/dist/resources/ei/rig-counts.js +89 -0
  65. package/dist/resources/ei/well-permits.d.ts +178 -0
  66. package/dist/resources/ei/well-permits.js +120 -0
  67. package/dist/resources/forecasts.d.ts +200 -0
  68. package/dist/resources/forecasts.js +158 -0
  69. package/dist/resources/futures.d.ts +322 -0
  70. package/dist/resources/futures.js +229 -0
  71. package/dist/resources/rig-counts.d.ts +221 -0
  72. package/dist/resources/rig-counts.js +157 -0
  73. package/dist/resources/storage.d.ts +182 -0
  74. package/dist/resources/storage.js +162 -0
  75. package/dist/resources/webhooks.d.ts +326 -0
  76. package/dist/resources/webhooks.js +290 -0
  77. package/dist/types.d.ts +79 -8
  78. package/dist/version.d.ts +1 -1
  79. package/dist/version.js +2 -2
  80. package/package.json +17 -8
package/dist/index.js CHANGED
@@ -5,6 +5,43 @@
5
5
  *
6
6
  * @packageDocumentation
7
7
  */
8
- export { OilPriceAPI } from './client.js';
9
- export { SDK_VERSION, SDK_NAME } from './version.js';
10
- export { OilPriceAPIError, AuthenticationError, RateLimitError, NotFoundError, ServerError, TimeoutError, } from './errors.js';
8
+ import { createHmac, timingSafeEqual } from "node:crypto";
9
+ export { OilPriceAPI } from "./client.js";
10
+ export { SDK_VERSION, SDK_NAME } from "./version.js";
11
+ export { OilPriceAPIError, AuthenticationError, RateLimitError, NotFoundError, ServerError, ValidationError, TimeoutError, } from "./errors.js";
12
+ export { DieselResource } from "./resources/diesel.js";
13
+ export { AlertsResource } from "./resources/alerts.js";
14
+ export { CommoditiesResource } from "./resources/commodities.js";
15
+ export { FuturesResource } from "./resources/futures.js";
16
+ export { StorageResource } from "./resources/storage.js";
17
+ export { RigCountsResource } from "./resources/rig-counts.js";
18
+ export { BunkerFuelsResource } from "./resources/bunker-fuels.js";
19
+ export { AnalyticsResource } from "./resources/analytics.js";
20
+ export { ForecastsResource } from "./resources/forecasts.js";
21
+ export { DataQualityResource } from "./resources/data-quality.js";
22
+ export { DrillingIntelligenceResource } from "./resources/drilling.js";
23
+ export { EnergyIntelligenceResource, EIRigCountsResource, EIOilInventoriesResource, EIOPECProductionResource, EIDrillingProductivityResource, EIForecastsResource, EIWellPermitsResource, EIFracFocusResource, } from "./resources/ei/index.js";
24
+ export { WebhooksResource } from "./resources/webhooks.js";
25
+ export { DataSourcesResource } from "./resources/data-sources.js";
26
+ /**
27
+ * Standalone webhook signature verification.
28
+ *
29
+ * Convenience function for verifying webhook signatures without
30
+ * instantiating a full client.
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * import { verifyWebhookSignature } from 'oilpriceapi';
35
+ *
36
+ * const isValid = verifyWebhookSignature(rawBody, signatureHeader, secret);
37
+ * ```
38
+ */
39
+ export function verifyWebhookSignature(payload, signature, secret) {
40
+ const expectedSignature = "sha256=" + createHmac("sha256", secret).update(payload).digest("hex");
41
+ try {
42
+ return timingSafeEqual(Buffer.from(expectedSignature), Buffer.from(signature));
43
+ }
44
+ catch {
45
+ return false;
46
+ }
47
+ }
@@ -3,11 +3,11 @@
3
3
  *
4
4
  * Manage price alert configurations for automated notifications.
5
5
  */
6
- import type { OilPriceAPI } from '../client.js';
6
+ import type { OilPriceAPI } from "../client.js";
7
7
  /**
8
8
  * Valid condition operators for price alerts
9
9
  */
10
- export type AlertOperator = 'greater_than' | 'less_than' | 'equals' | 'greater_than_or_equal' | 'less_than_or_equal';
10
+ export type AlertOperator = "greater_than" | "less_than" | "equals" | "greater_than_or_equal" | "less_than_or_equal";
11
11
  /**
12
12
  * Price alert configuration
13
13
  */
@@ -275,24 +275,61 @@ export declare class AlertsResource {
275
275
  */
276
276
  delete(id: string): Promise<void>;
277
277
  /**
278
- * Test a webhook endpoint
278
+ * Test an alert
279
279
  *
280
- * **NOTE:** This feature is not yet available in the API. The `/v1/alerts/test_webhook`
281
- * endpoint has not been implemented yet. This method will throw an error until the
282
- * backend endpoint is added.
280
+ * Triggers a test run of the alert to verify it's working correctly.
281
+ * Does not affect the alert's cooldown or trigger count.
283
282
  *
284
- * To test if an alert would trigger, use the backend's `/v1/alerts/test` endpoint instead:
285
- * ```bash
286
- * curl -X POST "https://api.oilpriceapi.com/v1/alerts/:id/test" \
287
- * -H "Authorization: Bearer YOUR_API_KEY"
283
+ * @param alertId - The alert ID to test
284
+ * @returns Test results
285
+ *
286
+ * @throws {NotFoundError} If alert not found
287
+ * @throws {OilPriceAPIError} If API request fails
288
+ *
289
+ * @example
290
+ * ```typescript
291
+ * const result = await client.alerts.test(alertId);
292
+ * console.log(`Test ${result.success ? 'passed' : 'failed'}`);
293
+ * if (result.response_time_ms) {
294
+ * console.log(`Webhook response time: ${result.response_time_ms}ms`);
295
+ * }
288
296
  * ```
297
+ */
298
+ test(alertId: string): Promise<WebhookTestResponse>;
299
+ /**
300
+ * Get available alert triggers
301
+ *
302
+ * Returns list of supported trigger conditions and event types.
289
303
  *
290
- * @param webhookUrl - The HTTPS webhook URL to test
291
- * @returns Test results including response time and status
304
+ * @returns Array of available triggers
292
305
  *
293
- * @throws {Error} Feature not yet available
306
+ * @throws {OilPriceAPIError} If API request fails
294
307
  *
295
- * @deprecated This feature is not yet available in the API
308
+ * @example
309
+ * ```typescript
310
+ * const triggers = await client.alerts.triggers();
311
+ * triggers.forEach(trigger => {
312
+ * console.log(`${trigger.name}: ${trigger.description}`);
313
+ * });
314
+ * ```
315
+ */
316
+ triggers(): Promise<any[]>;
317
+ /**
318
+ * Get alert analytics history
319
+ *
320
+ * Returns historical analytics data for alerts including trigger frequency,
321
+ * success rates, and response times.
322
+ *
323
+ * @returns Analytics history data
324
+ *
325
+ * @throws {OilPriceAPIError} If API request fails
326
+ *
327
+ * @example
328
+ * ```typescript
329
+ * const analytics = await client.alerts.analyticsHistory();
330
+ * console.log(`Total triggers: ${analytics.total_triggers}`);
331
+ * console.log(`Success rate: ${analytics.success_rate}%`);
332
+ * ```
296
333
  */
297
- testWebhook(webhookUrl: string): Promise<WebhookTestResponse>;
334
+ analyticsHistory(): Promise<any>;
298
335
  }
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * Manage price alert configurations for automated notifications.
5
5
  */
6
+ import { ValidationError } from "../errors.js";
6
7
  /**
7
8
  * Price Alerts Resource
8
9
  *
@@ -76,9 +77,9 @@ export class AlertsResource {
76
77
  * ```
77
78
  */
78
79
  async list() {
79
- const response = await this.client['request']('/v1/alerts', {});
80
+ const response = await this.client["request"]("/v1/alerts", {});
80
81
  // API returns array directly, but handle both formats for compatibility
81
- return Array.isArray(response) ? response : (response.alerts || []);
82
+ return Array.isArray(response) ? response : response.alerts || [];
82
83
  }
83
84
  /**
84
85
  * Get a specific price alert by ID
@@ -99,12 +100,12 @@ export class AlertsResource {
99
100
  * ```
100
101
  */
101
102
  async get(id) {
102
- if (!id || typeof id !== 'string') {
103
- throw new Error('Alert ID must be a non-empty string');
103
+ if (!id || typeof id !== "string") {
104
+ throw new ValidationError("Alert ID must be a non-empty string");
104
105
  }
105
- const response = await this.client['request'](`/v1/alerts/${id}`, {});
106
+ const response = await this.client["request"](`/v1/alerts/${id}`, {});
106
107
  // API returns object directly, but handle both formats for compatibility
107
- return 'alert' in response ? response.alert : response;
108
+ return "alert" in response ? response.alert : response;
108
109
  }
109
110
  /**
110
111
  * Create a new price alert
@@ -145,59 +146,54 @@ export class AlertsResource {
145
146
  */
146
147
  async create(params) {
147
148
  // Validate required fields
148
- if (!params.name || typeof params.name !== 'string') {
149
- throw new Error('Alert name is required and must be a string');
149
+ if (!params.name || typeof params.name !== "string") {
150
+ throw new ValidationError("Alert name is required and must be a string");
150
151
  }
151
152
  if (params.name.length < 1 || params.name.length > 100) {
152
- throw new Error('Alert name must be 1-100 characters');
153
+ throw new ValidationError("Alert name must be 1-100 characters");
153
154
  }
154
- if (!params.commodity_code || typeof params.commodity_code !== 'string') {
155
- throw new Error('Commodity code is required and must be a string');
155
+ if (!params.commodity_code || typeof params.commodity_code !== "string") {
156
+ throw new ValidationError("Commodity code is required and must be a string");
156
157
  }
157
158
  if (!params.condition_operator) {
158
- throw new Error('Condition operator is required');
159
+ throw new ValidationError("Condition operator is required");
159
160
  }
160
161
  const validOperators = [
161
- 'greater_than',
162
- 'less_than',
163
- 'equals',
164
- 'greater_than_or_equal',
165
- 'less_than_or_equal'
162
+ "greater_than",
163
+ "less_than",
164
+ "equals",
165
+ "greater_than_or_equal",
166
+ "less_than_or_equal",
166
167
  ];
167
168
  if (!validOperators.includes(params.condition_operator)) {
168
- throw new Error(`Invalid operator. Must be one of: ${validOperators.join(', ')}`);
169
+ throw new ValidationError(`Invalid operator. Must be one of: ${validOperators.join(", ")}`);
169
170
  }
170
- if (typeof params.condition_value !== 'number') {
171
- throw new Error('Condition value must be a number');
171
+ if (typeof params.condition_value !== "number") {
172
+ throw new ValidationError("Condition value must be a number");
172
173
  }
173
174
  if (params.condition_value <= 0 || params.condition_value > 1000000) {
174
- throw new Error('Condition value must be greater than 0 and less than or equal to 1,000,000');
175
+ throw new ValidationError("Condition value must be greater than 0 and less than or equal to 1,000,000");
175
176
  }
176
177
  // Validate optional fields
177
178
  if (params.webhook_url !== undefined) {
178
- if (typeof params.webhook_url !== 'string') {
179
- throw new Error('Webhook URL must be a string');
179
+ if (typeof params.webhook_url !== "string") {
180
+ throw new ValidationError("Webhook URL must be a string");
180
181
  }
181
- if (params.webhook_url && !params.webhook_url.startsWith('https://')) {
182
- throw new Error('Webhook URL must use HTTPS protocol');
182
+ if (params.webhook_url && !params.webhook_url.startsWith("https://")) {
183
+ throw new ValidationError("Webhook URL must use HTTPS protocol");
183
184
  }
184
185
  }
185
186
  if (params.cooldown_minutes !== undefined) {
186
- if (typeof params.cooldown_minutes !== 'number') {
187
- throw new Error('Cooldown minutes must be a number');
187
+ if (typeof params.cooldown_minutes !== "number") {
188
+ throw new ValidationError("Cooldown minutes must be a number");
188
189
  }
189
190
  if (params.cooldown_minutes < 0 || params.cooldown_minutes > 1440) {
190
- throw new Error('Cooldown minutes must be between 0 and 1440 (24 hours)');
191
+ throw new ValidationError("Cooldown minutes must be between 0 and 1440 (24 hours)");
191
192
  }
192
193
  }
193
- const url = `${this.client['baseUrl']}/v1/alerts`;
194
- const response = await fetch(url, {
195
- method: 'POST',
196
- headers: {
197
- 'Authorization': `Bearer ${this.client['apiKey']}`,
198
- 'Content-Type': 'application/json',
199
- },
200
- body: JSON.stringify({
194
+ const response = await this.client["request"]("/v1/alerts", {}, {
195
+ method: "POST",
196
+ body: {
201
197
  price_alert: {
202
198
  name: params.name,
203
199
  commodity_code: params.commodity_code,
@@ -206,17 +202,11 @@ export class AlertsResource {
206
202
  webhook_url: params.webhook_url,
207
203
  enabled: params.enabled ?? true,
208
204
  cooldown_minutes: params.cooldown_minutes ?? 60,
209
- metadata: params.metadata
210
- }
211
- })
205
+ metadata: params.metadata,
206
+ },
207
+ },
212
208
  });
213
- if (!response.ok) {
214
- const errorText = await response.text();
215
- throw new Error(`Failed to create alert: ${response.status} ${errorText}`);
216
- }
217
- const data = await response.json();
218
- // API returns object directly, but handle both formats for compatibility
219
- return 'alert' in data ? data.alert : data;
209
+ return "alert" in response ? response.alert : response;
220
210
  }
221
211
  /**
222
212
  * Update an existing price alert
@@ -250,65 +240,55 @@ export class AlertsResource {
250
240
  * ```
251
241
  */
252
242
  async update(id, params) {
253
- if (!id || typeof id !== 'string') {
254
- throw new Error('Alert ID must be a non-empty string');
243
+ if (!id || typeof id !== "string") {
244
+ throw new ValidationError("Alert ID must be a non-empty string");
255
245
  }
256
246
  // Validate fields if provided
257
247
  if (params.name !== undefined) {
258
- if (typeof params.name !== 'string' || params.name.length < 1 || params.name.length > 100) {
259
- throw new Error('Alert name must be 1-100 characters');
248
+ if (typeof params.name !== "string" ||
249
+ params.name.length < 1 ||
250
+ params.name.length > 100) {
251
+ throw new ValidationError("Alert name must be 1-100 characters");
260
252
  }
261
253
  }
262
254
  if (params.condition_operator !== undefined) {
263
255
  const validOperators = [
264
- 'greater_than',
265
- 'less_than',
266
- 'equals',
267
- 'greater_than_or_equal',
268
- 'less_than_or_equal'
256
+ "greater_than",
257
+ "less_than",
258
+ "equals",
259
+ "greater_than_or_equal",
260
+ "less_than_or_equal",
269
261
  ];
270
262
  if (!validOperators.includes(params.condition_operator)) {
271
- throw new Error(`Invalid operator. Must be one of: ${validOperators.join(', ')}`);
263
+ throw new ValidationError(`Invalid operator. Must be one of: ${validOperators.join(", ")}`);
272
264
  }
273
265
  }
274
266
  if (params.condition_value !== undefined) {
275
- if (typeof params.condition_value !== 'number') {
276
- throw new Error('Condition value must be a number');
267
+ if (typeof params.condition_value !== "number") {
268
+ throw new ValidationError("Condition value must be a number");
277
269
  }
278
270
  if (params.condition_value <= 0 || params.condition_value > 1000000) {
279
- throw new Error('Condition value must be greater than 0 and less than or equal to 1,000,000');
271
+ throw new ValidationError("Condition value must be greater than 0 and less than or equal to 1,000,000");
280
272
  }
281
273
  }
282
274
  if (params.webhook_url !== undefined && params.webhook_url !== null) {
283
- if (typeof params.webhook_url !== 'string' || !params.webhook_url.startsWith('https://')) {
284
- throw new Error('Webhook URL must be a valid HTTPS URL');
275
+ if (typeof params.webhook_url !== "string" ||
276
+ !params.webhook_url.startsWith("https://")) {
277
+ throw new ValidationError("Webhook URL must be a valid HTTPS URL");
285
278
  }
286
279
  }
287
280
  if (params.cooldown_minutes !== undefined) {
288
- if (typeof params.cooldown_minutes !== 'number' ||
281
+ if (typeof params.cooldown_minutes !== "number" ||
289
282
  params.cooldown_minutes < 0 ||
290
283
  params.cooldown_minutes > 1440) {
291
- throw new Error('Cooldown minutes must be between 0 and 1440 (24 hours)');
284
+ throw new ValidationError("Cooldown minutes must be between 0 and 1440 (24 hours)");
292
285
  }
293
286
  }
294
- const url = `${this.client['baseUrl']}/v1/alerts/${id}`;
295
- const response = await fetch(url, {
296
- method: 'PATCH',
297
- headers: {
298
- 'Authorization': `Bearer ${this.client['apiKey']}`,
299
- 'Content-Type': 'application/json',
300
- },
301
- body: JSON.stringify({
302
- price_alert: params
303
- })
287
+ const response = await this.client["request"](`/v1/alerts/${id}`, {}, {
288
+ method: "PATCH",
289
+ body: { price_alert: params },
304
290
  });
305
- if (!response.ok) {
306
- const errorText = await response.text();
307
- throw new Error(`Failed to update alert: ${response.status} ${errorText}`);
308
- }
309
- const data = await response.json();
310
- // API returns object directly, but handle both formats for compatibility
311
- return 'alert' in data ? data.alert : data;
291
+ return "alert" in response ? response.alert : response;
312
292
  }
313
293
  /**
314
294
  * Delete a price alert
@@ -327,45 +307,77 @@ export class AlertsResource {
327
307
  * ```
328
308
  */
329
309
  async delete(id) {
330
- if (!id || typeof id !== 'string') {
331
- throw new Error('Alert ID must be a non-empty string');
310
+ if (!id || typeof id !== "string") {
311
+ throw new ValidationError("Alert ID must be a non-empty string");
332
312
  }
333
- const url = `${this.client['baseUrl']}/v1/alerts/${id}`;
334
- const response = await fetch(url, {
335
- method: 'DELETE',
336
- headers: {
337
- 'Authorization': `Bearer ${this.client['apiKey']}`,
338
- 'Content-Type': 'application/json',
339
- }
340
- });
341
- if (!response.ok) {
342
- const errorText = await response.text();
343
- throw new Error(`Failed to delete alert: ${response.status} ${errorText}`);
313
+ await this.client["request"](`/v1/alerts/${id}`, {}, { method: "DELETE" });
314
+ }
315
+ /**
316
+ * Test an alert
317
+ *
318
+ * Triggers a test run of the alert to verify it's working correctly.
319
+ * Does not affect the alert's cooldown or trigger count.
320
+ *
321
+ * @param alertId - The alert ID to test
322
+ * @returns Test results
323
+ *
324
+ * @throws {NotFoundError} If alert not found
325
+ * @throws {OilPriceAPIError} If API request fails
326
+ *
327
+ * @example
328
+ * ```typescript
329
+ * const result = await client.alerts.test(alertId);
330
+ * console.log(`Test ${result.success ? 'passed' : 'failed'}`);
331
+ * if (result.response_time_ms) {
332
+ * console.log(`Webhook response time: ${result.response_time_ms}ms`);
333
+ * }
334
+ * ```
335
+ */
336
+ async test(alertId) {
337
+ if (!alertId || typeof alertId !== "string") {
338
+ throw new ValidationError("Alert ID must be a non-empty string");
344
339
  }
340
+ return this.client["request"](`/v1/alerts/${alertId}/test`, {}, { method: "POST" });
345
341
  }
346
342
  /**
347
- * Test a webhook endpoint
343
+ * Get available alert triggers
348
344
  *
349
- * **NOTE:** This feature is not yet available in the API. The `/v1/alerts/test_webhook`
350
- * endpoint has not been implemented yet. This method will throw an error until the
351
- * backend endpoint is added.
345
+ * Returns list of supported trigger conditions and event types.
352
346
  *
353
- * To test if an alert would trigger, use the backend's `/v1/alerts/test` endpoint instead:
354
- * ```bash
355
- * curl -X POST "https://api.oilpriceapi.com/v1/alerts/:id/test" \
356
- * -H "Authorization: Bearer YOUR_API_KEY"
347
+ * @returns Array of available triggers
348
+ *
349
+ * @throws {OilPriceAPIError} If API request fails
350
+ *
351
+ * @example
352
+ * ```typescript
353
+ * const triggers = await client.alerts.triggers();
354
+ * triggers.forEach(trigger => {
355
+ * console.log(`${trigger.name}: ${trigger.description}`);
356
+ * });
357
357
  * ```
358
+ */
359
+ async triggers() {
360
+ const response = await this.client["request"]("/v1/alerts/triggers", {});
361
+ return Array.isArray(response) ? response : response.triggers;
362
+ }
363
+ /**
364
+ * Get alert analytics history
365
+ *
366
+ * Returns historical analytics data for alerts including trigger frequency,
367
+ * success rates, and response times.
358
368
  *
359
- * @param webhookUrl - The HTTPS webhook URL to test
360
- * @returns Test results including response time and status
369
+ * @returns Analytics history data
361
370
  *
362
- * @throws {Error} Feature not yet available
371
+ * @throws {OilPriceAPIError} If API request fails
363
372
  *
364
- * @deprecated This feature is not yet available in the API
373
+ * @example
374
+ * ```typescript
375
+ * const analytics = await client.alerts.analyticsHistory();
376
+ * console.log(`Total triggers: ${analytics.total_triggers}`);
377
+ * console.log(`Success rate: ${analytics.success_rate}%`);
378
+ * ```
365
379
  */
366
- async testWebhook(webhookUrl) {
367
- throw new Error('Webhook testing is not yet available. The /v1/alerts/test_webhook endpoint ' +
368
- 'has not been implemented in the API. To test if an alert would trigger, ' +
369
- 'use the /v1/alerts/:id/test endpoint instead.');
380
+ async analyticsHistory() {
381
+ return this.client["request"]("/v1/alerts/analytics_history", {});
370
382
  }
371
383
  }