oilpriceapi 0.3.2 → 0.5.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 +325 -3
- package/dist/client.d.ts +10 -0
- package/dist/client.js +7 -2
- package/dist/index.d.ts +2 -0
- package/dist/resources/alerts.d.ts +298 -0
- package/dist/resources/alerts.js +371 -0
- package/dist/resources/diesel.d.ts +190 -0
- package/dist/resources/diesel.js +144 -0
- package/package.json +5 -2
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Price Alerts Resource
|
|
3
|
+
*
|
|
4
|
+
* Manage price alert configurations for automated notifications.
|
|
5
|
+
*/
|
|
6
|
+
import type { OilPriceAPI } from '../client.js';
|
|
7
|
+
/**
|
|
8
|
+
* Valid condition operators for price alerts
|
|
9
|
+
*/
|
|
10
|
+
export type AlertOperator = 'greater_than' | 'less_than' | 'equals' | 'greater_than_or_equal' | 'less_than_or_equal';
|
|
11
|
+
/**
|
|
12
|
+
* Price alert configuration
|
|
13
|
+
*/
|
|
14
|
+
export interface PriceAlert {
|
|
15
|
+
/** Unique alert identifier */
|
|
16
|
+
id: string;
|
|
17
|
+
/** User-friendly alert name */
|
|
18
|
+
name: string;
|
|
19
|
+
/** Commodity code to monitor (e.g., "BRENT_CRUDE_USD") */
|
|
20
|
+
commodity_code: string;
|
|
21
|
+
/** Comparison operator for alert condition */
|
|
22
|
+
condition_operator: AlertOperator;
|
|
23
|
+
/** Price threshold value in USD */
|
|
24
|
+
condition_value: number;
|
|
25
|
+
/** Optional webhook URL for notifications */
|
|
26
|
+
webhook_url?: string | null;
|
|
27
|
+
/** Whether the alert is active */
|
|
28
|
+
enabled: boolean;
|
|
29
|
+
/** Minimum minutes between alert triggers (0-1440) */
|
|
30
|
+
cooldown_minutes: number;
|
|
31
|
+
/** Optional metadata for custom use */
|
|
32
|
+
metadata?: Record<string, unknown> | null;
|
|
33
|
+
/** Number of times this alert has triggered */
|
|
34
|
+
trigger_count: number;
|
|
35
|
+
/** ISO timestamp of last trigger, or null if never triggered */
|
|
36
|
+
last_triggered_at: string | null;
|
|
37
|
+
/** ISO timestamp when alert was created */
|
|
38
|
+
created_at: string;
|
|
39
|
+
/** ISO timestamp when alert was last updated */
|
|
40
|
+
updated_at: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Parameters for creating a new price alert
|
|
44
|
+
*/
|
|
45
|
+
export interface CreateAlertParams {
|
|
46
|
+
/** User-friendly alert name */
|
|
47
|
+
name: string;
|
|
48
|
+
/** Commodity code to monitor (e.g., "BRENT_CRUDE_USD") */
|
|
49
|
+
commodity_code: string;
|
|
50
|
+
/** Comparison operator for alert condition */
|
|
51
|
+
condition_operator: AlertOperator;
|
|
52
|
+
/** Price threshold value in USD (must be > 0 and <= 1,000,000) */
|
|
53
|
+
condition_value: number;
|
|
54
|
+
/** Optional webhook URL for POST notifications */
|
|
55
|
+
webhook_url?: string;
|
|
56
|
+
/** Whether to enable the alert immediately (default: true) */
|
|
57
|
+
enabled?: boolean;
|
|
58
|
+
/** Minimum minutes between triggers (0-1440, default: 60) */
|
|
59
|
+
cooldown_minutes?: number;
|
|
60
|
+
/** Optional metadata for custom use */
|
|
61
|
+
metadata?: Record<string, unknown>;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Parameters for updating an existing price alert
|
|
65
|
+
*/
|
|
66
|
+
export interface UpdateAlertParams {
|
|
67
|
+
/** User-friendly alert name */
|
|
68
|
+
name?: string;
|
|
69
|
+
/** Commodity code to monitor */
|
|
70
|
+
commodity_code?: string;
|
|
71
|
+
/** Comparison operator for alert condition */
|
|
72
|
+
condition_operator?: AlertOperator;
|
|
73
|
+
/** Price threshold value in USD */
|
|
74
|
+
condition_value?: number;
|
|
75
|
+
/** Webhook URL for notifications */
|
|
76
|
+
webhook_url?: string | null;
|
|
77
|
+
/** Whether the alert is active */
|
|
78
|
+
enabled?: boolean;
|
|
79
|
+
/** Minimum minutes between triggers (0-1440) */
|
|
80
|
+
cooldown_minutes?: number;
|
|
81
|
+
/** Metadata for custom use */
|
|
82
|
+
metadata?: Record<string, unknown> | null;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Response from webhook test endpoint
|
|
86
|
+
*/
|
|
87
|
+
export interface WebhookTestResponse {
|
|
88
|
+
/** Test result status */
|
|
89
|
+
success: boolean;
|
|
90
|
+
/** HTTP status code from webhook endpoint */
|
|
91
|
+
status_code: number;
|
|
92
|
+
/** Response time in milliseconds */
|
|
93
|
+
response_time_ms: number;
|
|
94
|
+
/** Response body from webhook endpoint */
|
|
95
|
+
response_body?: string;
|
|
96
|
+
/** Error message if test failed */
|
|
97
|
+
error?: string;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Price Alerts Resource
|
|
101
|
+
*
|
|
102
|
+
* Manage automated price alert configurations with webhook notifications.
|
|
103
|
+
*
|
|
104
|
+
* **Features:**
|
|
105
|
+
* - Create alerts with customizable conditions
|
|
106
|
+
* - Monitor commodity prices automatically
|
|
107
|
+
* - Webhook notifications when conditions are met
|
|
108
|
+
* - Cooldown periods to prevent spam
|
|
109
|
+
* - 100 alerts per user soft limit
|
|
110
|
+
*
|
|
111
|
+
* **Example:**
|
|
112
|
+
* ```typescript
|
|
113
|
+
* import { OilPriceAPI } from 'oilpriceapi';
|
|
114
|
+
*
|
|
115
|
+
* const client = new OilPriceAPI({ apiKey: 'your_key' });
|
|
116
|
+
*
|
|
117
|
+
* // Create a price alert
|
|
118
|
+
* const alert = await client.alerts.create({
|
|
119
|
+
* name: 'Brent High Price Alert',
|
|
120
|
+
* commodity_code: 'BRENT_CRUDE_USD',
|
|
121
|
+
* condition_operator: 'greater_than',
|
|
122
|
+
* condition_value: 85.00,
|
|
123
|
+
* webhook_url: 'https://your-app.com/webhooks/price-alert',
|
|
124
|
+
* enabled: true,
|
|
125
|
+
* cooldown_minutes: 60
|
|
126
|
+
* });
|
|
127
|
+
*
|
|
128
|
+
* console.log(`Alert created: ${alert.name} (ID: ${alert.id})`);
|
|
129
|
+
*
|
|
130
|
+
* // List all alerts
|
|
131
|
+
* const alerts = await client.alerts.list();
|
|
132
|
+
* console.log(`You have ${alerts.length} active alerts`);
|
|
133
|
+
*
|
|
134
|
+
* // Update an alert
|
|
135
|
+
* const updated = await client.alerts.update(alert.id, {
|
|
136
|
+
* condition_value: 90.00,
|
|
137
|
+
* enabled: false
|
|
138
|
+
* });
|
|
139
|
+
*
|
|
140
|
+
* // Delete an alert
|
|
141
|
+
* await client.alerts.delete(alert.id);
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
export declare class AlertsResource {
|
|
145
|
+
private client;
|
|
146
|
+
constructor(client: OilPriceAPI);
|
|
147
|
+
/**
|
|
148
|
+
* List all price alerts for the authenticated user
|
|
149
|
+
*
|
|
150
|
+
* Returns all configured price alerts, including disabled ones.
|
|
151
|
+
* Alerts are sorted by creation date (newest first).
|
|
152
|
+
*
|
|
153
|
+
* @returns Array of all price alerts
|
|
154
|
+
*
|
|
155
|
+
* @throws {OilPriceAPIError} If API request fails
|
|
156
|
+
* @throws {AuthenticationError} If API key is invalid
|
|
157
|
+
* @throws {RateLimitError} If rate limit exceeded
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```typescript
|
|
161
|
+
* const alerts = await client.alerts.list();
|
|
162
|
+
*
|
|
163
|
+
* alerts.forEach(alert => {
|
|
164
|
+
* console.log(`${alert.name}: ${alert.commodity_code} ${alert.condition_operator} ${alert.condition_value}`);
|
|
165
|
+
* console.log(` Status: ${alert.enabled ? 'Active' : 'Disabled'}`);
|
|
166
|
+
* console.log(` Triggers: ${alert.trigger_count}`);
|
|
167
|
+
* });
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
list(): Promise<PriceAlert[]>;
|
|
171
|
+
/**
|
|
172
|
+
* Get a specific price alert by ID
|
|
173
|
+
*
|
|
174
|
+
* @param id - The alert ID to retrieve
|
|
175
|
+
* @returns The price alert details
|
|
176
|
+
*
|
|
177
|
+
* @throws {OilPriceAPIError} If API request fails
|
|
178
|
+
* @throws {DataNotFoundError} If alert ID not found
|
|
179
|
+
* @throws {AuthenticationError} If API key is invalid
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```typescript
|
|
183
|
+
* const alert = await client.alerts.get('550e8400-e29b-41d4-a716-446655440000');
|
|
184
|
+
* console.log(`Alert: ${alert.name}`);
|
|
185
|
+
* console.log(`Condition: ${alert.commodity_code} ${alert.condition_operator} ${alert.condition_value}`);
|
|
186
|
+
* console.log(`Last triggered: ${alert.last_triggered_at || 'Never'}`);
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
get(id: string): Promise<PriceAlert>;
|
|
190
|
+
/**
|
|
191
|
+
* Create a new price alert
|
|
192
|
+
*
|
|
193
|
+
* Creates a price alert that monitors a commodity and triggers when
|
|
194
|
+
* the price meets the specified condition. Optionally sends webhook
|
|
195
|
+
* notifications when triggered.
|
|
196
|
+
*
|
|
197
|
+
* **Validation:**
|
|
198
|
+
* - name: 1-100 characters
|
|
199
|
+
* - commodity_code: Must be a valid commodity code
|
|
200
|
+
* - condition_value: Must be > 0 and <= 1,000,000
|
|
201
|
+
* - cooldown_minutes: Must be 0-1440 (24 hours)
|
|
202
|
+
* - webhook_url: Must be valid HTTPS URL if provided
|
|
203
|
+
*
|
|
204
|
+
* **Soft Limit:** 100 alerts per user
|
|
205
|
+
*
|
|
206
|
+
* @param params - Alert configuration parameters
|
|
207
|
+
* @returns The created price alert
|
|
208
|
+
*
|
|
209
|
+
* @throws {ValidationError} If parameters are invalid
|
|
210
|
+
* @throws {OilPriceAPIError} If API request fails
|
|
211
|
+
* @throws {AuthenticationError} If API key is invalid
|
|
212
|
+
*
|
|
213
|
+
* @example
|
|
214
|
+
* ```typescript
|
|
215
|
+
* // Alert when Brent crude exceeds $85
|
|
216
|
+
* const alert = await client.alerts.create({
|
|
217
|
+
* name: 'Brent $85 Alert',
|
|
218
|
+
* commodity_code: 'BRENT_CRUDE_USD',
|
|
219
|
+
* condition_operator: 'greater_than',
|
|
220
|
+
* condition_value: 85.00,
|
|
221
|
+
* webhook_url: 'https://myapp.com/webhook',
|
|
222
|
+
* enabled: true,
|
|
223
|
+
* cooldown_minutes: 120 // 2 hours between triggers
|
|
224
|
+
* });
|
|
225
|
+
* ```
|
|
226
|
+
*/
|
|
227
|
+
create(params: CreateAlertParams): Promise<PriceAlert>;
|
|
228
|
+
/**
|
|
229
|
+
* Update an existing price alert
|
|
230
|
+
*
|
|
231
|
+
* Updates one or more fields of an existing alert. Only provided
|
|
232
|
+
* fields will be updated; others remain unchanged.
|
|
233
|
+
*
|
|
234
|
+
* @param id - The alert ID to update
|
|
235
|
+
* @param params - Fields to update (partial update supported)
|
|
236
|
+
* @returns The updated price alert
|
|
237
|
+
*
|
|
238
|
+
* @throws {ValidationError} If parameters are invalid
|
|
239
|
+
* @throws {DataNotFoundError} If alert ID not found
|
|
240
|
+
* @throws {OilPriceAPIError} If API request fails
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* ```typescript
|
|
244
|
+
* // Disable an alert
|
|
245
|
+
* await client.alerts.update(alertId, { enabled: false });
|
|
246
|
+
*
|
|
247
|
+
* // Change threshold and cooldown
|
|
248
|
+
* await client.alerts.update(alertId, {
|
|
249
|
+
* condition_value: 90.00,
|
|
250
|
+
* cooldown_minutes: 180
|
|
251
|
+
* });
|
|
252
|
+
*
|
|
253
|
+
* // Update webhook URL
|
|
254
|
+
* await client.alerts.update(alertId, {
|
|
255
|
+
* webhook_url: 'https://newapp.com/webhook'
|
|
256
|
+
* });
|
|
257
|
+
* ```
|
|
258
|
+
*/
|
|
259
|
+
update(id: string, params: UpdateAlertParams): Promise<PriceAlert>;
|
|
260
|
+
/**
|
|
261
|
+
* Delete a price alert
|
|
262
|
+
*
|
|
263
|
+
* Permanently deletes a price alert. This action cannot be undone.
|
|
264
|
+
*
|
|
265
|
+
* @param id - The alert ID to delete
|
|
266
|
+
*
|
|
267
|
+
* @throws {DataNotFoundError} If alert ID not found
|
|
268
|
+
* @throws {OilPriceAPIError} If API request fails
|
|
269
|
+
*
|
|
270
|
+
* @example
|
|
271
|
+
* ```typescript
|
|
272
|
+
* await client.alerts.delete(alertId);
|
|
273
|
+
* console.log('Alert deleted successfully');
|
|
274
|
+
* ```
|
|
275
|
+
*/
|
|
276
|
+
delete(id: string): Promise<void>;
|
|
277
|
+
/**
|
|
278
|
+
* Test a webhook endpoint
|
|
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.
|
|
283
|
+
*
|
|
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"
|
|
288
|
+
* ```
|
|
289
|
+
*
|
|
290
|
+
* @param webhookUrl - The HTTPS webhook URL to test
|
|
291
|
+
* @returns Test results including response time and status
|
|
292
|
+
*
|
|
293
|
+
* @throws {Error} Feature not yet available
|
|
294
|
+
*
|
|
295
|
+
* @deprecated This feature is not yet available in the API
|
|
296
|
+
*/
|
|
297
|
+
testWebhook(webhookUrl: string): Promise<WebhookTestResponse>;
|
|
298
|
+
}
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Price Alerts Resource
|
|
3
|
+
*
|
|
4
|
+
* Manage price alert configurations for automated notifications.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Price Alerts Resource
|
|
8
|
+
*
|
|
9
|
+
* Manage automated price alert configurations with webhook notifications.
|
|
10
|
+
*
|
|
11
|
+
* **Features:**
|
|
12
|
+
* - Create alerts with customizable conditions
|
|
13
|
+
* - Monitor commodity prices automatically
|
|
14
|
+
* - Webhook notifications when conditions are met
|
|
15
|
+
* - Cooldown periods to prevent spam
|
|
16
|
+
* - 100 alerts per user soft limit
|
|
17
|
+
*
|
|
18
|
+
* **Example:**
|
|
19
|
+
* ```typescript
|
|
20
|
+
* import { OilPriceAPI } from 'oilpriceapi';
|
|
21
|
+
*
|
|
22
|
+
* const client = new OilPriceAPI({ apiKey: 'your_key' });
|
|
23
|
+
*
|
|
24
|
+
* // Create a price alert
|
|
25
|
+
* const alert = await client.alerts.create({
|
|
26
|
+
* name: 'Brent High Price Alert',
|
|
27
|
+
* commodity_code: 'BRENT_CRUDE_USD',
|
|
28
|
+
* condition_operator: 'greater_than',
|
|
29
|
+
* condition_value: 85.00,
|
|
30
|
+
* webhook_url: 'https://your-app.com/webhooks/price-alert',
|
|
31
|
+
* enabled: true,
|
|
32
|
+
* cooldown_minutes: 60
|
|
33
|
+
* });
|
|
34
|
+
*
|
|
35
|
+
* console.log(`Alert created: ${alert.name} (ID: ${alert.id})`);
|
|
36
|
+
*
|
|
37
|
+
* // List all alerts
|
|
38
|
+
* const alerts = await client.alerts.list();
|
|
39
|
+
* console.log(`You have ${alerts.length} active alerts`);
|
|
40
|
+
*
|
|
41
|
+
* // Update an alert
|
|
42
|
+
* const updated = await client.alerts.update(alert.id, {
|
|
43
|
+
* condition_value: 90.00,
|
|
44
|
+
* enabled: false
|
|
45
|
+
* });
|
|
46
|
+
*
|
|
47
|
+
* // Delete an alert
|
|
48
|
+
* await client.alerts.delete(alert.id);
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export class AlertsResource {
|
|
52
|
+
constructor(client) {
|
|
53
|
+
this.client = client;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* List all price alerts for the authenticated user
|
|
57
|
+
*
|
|
58
|
+
* Returns all configured price alerts, including disabled ones.
|
|
59
|
+
* Alerts are sorted by creation date (newest first).
|
|
60
|
+
*
|
|
61
|
+
* @returns Array of all price alerts
|
|
62
|
+
*
|
|
63
|
+
* @throws {OilPriceAPIError} If API request fails
|
|
64
|
+
* @throws {AuthenticationError} If API key is invalid
|
|
65
|
+
* @throws {RateLimitError} If rate limit exceeded
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* const alerts = await client.alerts.list();
|
|
70
|
+
*
|
|
71
|
+
* alerts.forEach(alert => {
|
|
72
|
+
* console.log(`${alert.name}: ${alert.commodity_code} ${alert.condition_operator} ${alert.condition_value}`);
|
|
73
|
+
* console.log(` Status: ${alert.enabled ? 'Active' : 'Disabled'}`);
|
|
74
|
+
* console.log(` Triggers: ${alert.trigger_count}`);
|
|
75
|
+
* });
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
async list() {
|
|
79
|
+
const response = await this.client['request']('/v1/alerts', {});
|
|
80
|
+
// API returns array directly, but handle both formats for compatibility
|
|
81
|
+
return Array.isArray(response) ? response : (response.alerts || []);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Get a specific price alert by ID
|
|
85
|
+
*
|
|
86
|
+
* @param id - The alert ID to retrieve
|
|
87
|
+
* @returns The price alert details
|
|
88
|
+
*
|
|
89
|
+
* @throws {OilPriceAPIError} If API request fails
|
|
90
|
+
* @throws {DataNotFoundError} If alert ID not found
|
|
91
|
+
* @throws {AuthenticationError} If API key is invalid
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```typescript
|
|
95
|
+
* const alert = await client.alerts.get('550e8400-e29b-41d4-a716-446655440000');
|
|
96
|
+
* console.log(`Alert: ${alert.name}`);
|
|
97
|
+
* console.log(`Condition: ${alert.commodity_code} ${alert.condition_operator} ${alert.condition_value}`);
|
|
98
|
+
* console.log(`Last triggered: ${alert.last_triggered_at || 'Never'}`);
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
async get(id) {
|
|
102
|
+
if (!id || typeof id !== 'string') {
|
|
103
|
+
throw new Error('Alert ID must be a non-empty string');
|
|
104
|
+
}
|
|
105
|
+
const response = await this.client['request'](`/v1/alerts/${id}`, {});
|
|
106
|
+
// API returns object directly, but handle both formats for compatibility
|
|
107
|
+
return 'alert' in response ? response.alert : response;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Create a new price alert
|
|
111
|
+
*
|
|
112
|
+
* Creates a price alert that monitors a commodity and triggers when
|
|
113
|
+
* the price meets the specified condition. Optionally sends webhook
|
|
114
|
+
* notifications when triggered.
|
|
115
|
+
*
|
|
116
|
+
* **Validation:**
|
|
117
|
+
* - name: 1-100 characters
|
|
118
|
+
* - commodity_code: Must be a valid commodity code
|
|
119
|
+
* - condition_value: Must be > 0 and <= 1,000,000
|
|
120
|
+
* - cooldown_minutes: Must be 0-1440 (24 hours)
|
|
121
|
+
* - webhook_url: Must be valid HTTPS URL if provided
|
|
122
|
+
*
|
|
123
|
+
* **Soft Limit:** 100 alerts per user
|
|
124
|
+
*
|
|
125
|
+
* @param params - Alert configuration parameters
|
|
126
|
+
* @returns The created price alert
|
|
127
|
+
*
|
|
128
|
+
* @throws {ValidationError} If parameters are invalid
|
|
129
|
+
* @throws {OilPriceAPIError} If API request fails
|
|
130
|
+
* @throws {AuthenticationError} If API key is invalid
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```typescript
|
|
134
|
+
* // Alert when Brent crude exceeds $85
|
|
135
|
+
* const alert = await client.alerts.create({
|
|
136
|
+
* name: 'Brent $85 Alert',
|
|
137
|
+
* commodity_code: 'BRENT_CRUDE_USD',
|
|
138
|
+
* condition_operator: 'greater_than',
|
|
139
|
+
* condition_value: 85.00,
|
|
140
|
+
* webhook_url: 'https://myapp.com/webhook',
|
|
141
|
+
* enabled: true,
|
|
142
|
+
* cooldown_minutes: 120 // 2 hours between triggers
|
|
143
|
+
* });
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
async create(params) {
|
|
147
|
+
// Validate required fields
|
|
148
|
+
if (!params.name || typeof params.name !== 'string') {
|
|
149
|
+
throw new Error('Alert name is required and must be a string');
|
|
150
|
+
}
|
|
151
|
+
if (params.name.length < 1 || params.name.length > 100) {
|
|
152
|
+
throw new Error('Alert name must be 1-100 characters');
|
|
153
|
+
}
|
|
154
|
+
if (!params.commodity_code || typeof params.commodity_code !== 'string') {
|
|
155
|
+
throw new Error('Commodity code is required and must be a string');
|
|
156
|
+
}
|
|
157
|
+
if (!params.condition_operator) {
|
|
158
|
+
throw new Error('Condition operator is required');
|
|
159
|
+
}
|
|
160
|
+
const validOperators = [
|
|
161
|
+
'greater_than',
|
|
162
|
+
'less_than',
|
|
163
|
+
'equals',
|
|
164
|
+
'greater_than_or_equal',
|
|
165
|
+
'less_than_or_equal'
|
|
166
|
+
];
|
|
167
|
+
if (!validOperators.includes(params.condition_operator)) {
|
|
168
|
+
throw new Error(`Invalid operator. Must be one of: ${validOperators.join(', ')}`);
|
|
169
|
+
}
|
|
170
|
+
if (typeof params.condition_value !== 'number') {
|
|
171
|
+
throw new Error('Condition value must be a number');
|
|
172
|
+
}
|
|
173
|
+
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
|
+
}
|
|
176
|
+
// Validate optional fields
|
|
177
|
+
if (params.webhook_url !== undefined) {
|
|
178
|
+
if (typeof params.webhook_url !== 'string') {
|
|
179
|
+
throw new Error('Webhook URL must be a string');
|
|
180
|
+
}
|
|
181
|
+
if (params.webhook_url && !params.webhook_url.startsWith('https://')) {
|
|
182
|
+
throw new Error('Webhook URL must use HTTPS protocol');
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (params.cooldown_minutes !== undefined) {
|
|
186
|
+
if (typeof params.cooldown_minutes !== 'number') {
|
|
187
|
+
throw new Error('Cooldown minutes must be a number');
|
|
188
|
+
}
|
|
189
|
+
if (params.cooldown_minutes < 0 || params.cooldown_minutes > 1440) {
|
|
190
|
+
throw new Error('Cooldown minutes must be between 0 and 1440 (24 hours)');
|
|
191
|
+
}
|
|
192
|
+
}
|
|
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({
|
|
201
|
+
price_alert: {
|
|
202
|
+
name: params.name,
|
|
203
|
+
commodity_code: params.commodity_code,
|
|
204
|
+
condition_operator: params.condition_operator,
|
|
205
|
+
condition_value: params.condition_value,
|
|
206
|
+
webhook_url: params.webhook_url,
|
|
207
|
+
enabled: params.enabled ?? true,
|
|
208
|
+
cooldown_minutes: params.cooldown_minutes ?? 60,
|
|
209
|
+
metadata: params.metadata
|
|
210
|
+
}
|
|
211
|
+
})
|
|
212
|
+
});
|
|
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;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Update an existing price alert
|
|
223
|
+
*
|
|
224
|
+
* Updates one or more fields of an existing alert. Only provided
|
|
225
|
+
* fields will be updated; others remain unchanged.
|
|
226
|
+
*
|
|
227
|
+
* @param id - The alert ID to update
|
|
228
|
+
* @param params - Fields to update (partial update supported)
|
|
229
|
+
* @returns The updated price alert
|
|
230
|
+
*
|
|
231
|
+
* @throws {ValidationError} If parameters are invalid
|
|
232
|
+
* @throws {DataNotFoundError} If alert ID not found
|
|
233
|
+
* @throws {OilPriceAPIError} If API request fails
|
|
234
|
+
*
|
|
235
|
+
* @example
|
|
236
|
+
* ```typescript
|
|
237
|
+
* // Disable an alert
|
|
238
|
+
* await client.alerts.update(alertId, { enabled: false });
|
|
239
|
+
*
|
|
240
|
+
* // Change threshold and cooldown
|
|
241
|
+
* await client.alerts.update(alertId, {
|
|
242
|
+
* condition_value: 90.00,
|
|
243
|
+
* cooldown_minutes: 180
|
|
244
|
+
* });
|
|
245
|
+
*
|
|
246
|
+
* // Update webhook URL
|
|
247
|
+
* await client.alerts.update(alertId, {
|
|
248
|
+
* webhook_url: 'https://newapp.com/webhook'
|
|
249
|
+
* });
|
|
250
|
+
* ```
|
|
251
|
+
*/
|
|
252
|
+
async update(id, params) {
|
|
253
|
+
if (!id || typeof id !== 'string') {
|
|
254
|
+
throw new Error('Alert ID must be a non-empty string');
|
|
255
|
+
}
|
|
256
|
+
// Validate fields if provided
|
|
257
|
+
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');
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (params.condition_operator !== undefined) {
|
|
263
|
+
const validOperators = [
|
|
264
|
+
'greater_than',
|
|
265
|
+
'less_than',
|
|
266
|
+
'equals',
|
|
267
|
+
'greater_than_or_equal',
|
|
268
|
+
'less_than_or_equal'
|
|
269
|
+
];
|
|
270
|
+
if (!validOperators.includes(params.condition_operator)) {
|
|
271
|
+
throw new Error(`Invalid operator. Must be one of: ${validOperators.join(', ')}`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (params.condition_value !== undefined) {
|
|
275
|
+
if (typeof params.condition_value !== 'number') {
|
|
276
|
+
throw new Error('Condition value must be a number');
|
|
277
|
+
}
|
|
278
|
+
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');
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
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');
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
if (params.cooldown_minutes !== undefined) {
|
|
288
|
+
if (typeof params.cooldown_minutes !== 'number' ||
|
|
289
|
+
params.cooldown_minutes < 0 ||
|
|
290
|
+
params.cooldown_minutes > 1440) {
|
|
291
|
+
throw new Error('Cooldown minutes must be between 0 and 1440 (24 hours)');
|
|
292
|
+
}
|
|
293
|
+
}
|
|
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
|
+
})
|
|
304
|
+
});
|
|
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;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Delete a price alert
|
|
315
|
+
*
|
|
316
|
+
* Permanently deletes a price alert. This action cannot be undone.
|
|
317
|
+
*
|
|
318
|
+
* @param id - The alert ID to delete
|
|
319
|
+
*
|
|
320
|
+
* @throws {DataNotFoundError} If alert ID not found
|
|
321
|
+
* @throws {OilPriceAPIError} If API request fails
|
|
322
|
+
*
|
|
323
|
+
* @example
|
|
324
|
+
* ```typescript
|
|
325
|
+
* await client.alerts.delete(alertId);
|
|
326
|
+
* console.log('Alert deleted successfully');
|
|
327
|
+
* ```
|
|
328
|
+
*/
|
|
329
|
+
async delete(id) {
|
|
330
|
+
if (!id || typeof id !== 'string') {
|
|
331
|
+
throw new Error('Alert ID must be a non-empty string');
|
|
332
|
+
}
|
|
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}`);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Test a webhook endpoint
|
|
348
|
+
*
|
|
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.
|
|
352
|
+
*
|
|
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"
|
|
357
|
+
* ```
|
|
358
|
+
*
|
|
359
|
+
* @param webhookUrl - The HTTPS webhook URL to test
|
|
360
|
+
* @returns Test results including response time and status
|
|
361
|
+
*
|
|
362
|
+
* @throws {Error} Feature not yet available
|
|
363
|
+
*
|
|
364
|
+
* @deprecated This feature is not yet available in the API
|
|
365
|
+
*/
|
|
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.');
|
|
370
|
+
}
|
|
371
|
+
}
|