oilpriceapi 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Oil Price API
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,375 @@
1
+ # Oil Price API - Node.js SDK
2
+
3
+ [![npm version](https://badge.fury.io/js/oilpriceapi.svg)](https://www.npmjs.com/package/oilpriceapi)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ Official Node.js SDK for [Oil Price API](https://www.oilpriceapi.com) - Get real-time and historical oil & commodity prices.
7
+
8
+ ## Features
9
+
10
+ - ✅ **Simple** - Get started in 5 lines of code
11
+ - 🔒 **Type-Safe** - Full TypeScript support with detailed type definitions
12
+ - ⚡ **Fast** - Zero dependencies, uses native fetch (Node 18+)
13
+ - 🎯 **Comprehensive** - Covers all API endpoints
14
+ - 🚀 **Modern** - ES Modules, async/await, Promise-based
15
+ - 🛡️ **Robust** - Custom error classes for better error handling
16
+ - 🔄 **Resilient** - Automatic retries with exponential backoff
17
+ - ⏱️ **Reliable** - Request timeouts and smart error handling
18
+ - 🐛 **Debuggable** - Built-in debug logging mode
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ npm install oilpriceapi
24
+ ```
25
+
26
+ ## Quick Start
27
+
28
+ ```typescript
29
+ import { OilPriceAPI } from 'oilpriceapi';
30
+
31
+ // Initialize the client
32
+ const client = new OilPriceAPI({
33
+ apiKey: 'your_api_key_here', // Get your free key at https://www.oilpriceapi.com
34
+ retries: 3, // Automatic retries (default: 3)
35
+ timeout: 30000 // Request timeout in ms (default: 30000)
36
+ });
37
+
38
+ // Get latest prices
39
+ const prices = await client.getLatestPrices();
40
+ console.log(prices);
41
+ ```
42
+
43
+ ## Usage Examples
44
+
45
+ ### Get Latest Prices (All Commodities)
46
+
47
+ ```typescript
48
+ const prices = await client.getLatestPrices();
49
+
50
+ // Example output:
51
+ // [
52
+ // {
53
+ // code: 'WTI_USD',
54
+ // name: 'WTI Crude Oil',
55
+ // value: 74.25,
56
+ // currency: 'USD',
57
+ // unit: 'barrel',
58
+ // timestamp: '2024-11-24T12:00:00Z',
59
+ // created_at: '2024-11-24T12:01:00Z',
60
+ // updated_at: '2024-11-24T12:01:00Z'
61
+ // },
62
+ // // ... more prices
63
+ // ]
64
+ ```
65
+
66
+ ### Get Latest Price for Specific Commodity
67
+
68
+ ```typescript
69
+ // Get only WTI crude oil price
70
+ const wti = await client.getLatestPrices({ commodity: 'WTI_USD' });
71
+ console.log(`WTI: $${wti[0].value} per barrel`);
72
+
73
+ // Get only Brent crude price
74
+ const brent = await client.getLatestPrices({ commodity: 'BRENT_CRUDE_USD' });
75
+ console.log(`Brent: $${brent[0].value} per barrel`);
76
+ ```
77
+
78
+ ### Get Historical Prices (Past Week)
79
+
80
+ ```typescript
81
+ const weekPrices = await client.getHistoricalPrices({
82
+ period: 'past_week',
83
+ commodity: 'WTI_USD'
84
+ });
85
+
86
+ console.log(`Got ${weekPrices.length} data points from the past week`);
87
+ ```
88
+
89
+ ### Get Historical Prices (Custom Date Range)
90
+
91
+ ```typescript
92
+ const prices = await client.getHistoricalPrices({
93
+ startDate: '2024-01-01',
94
+ endDate: '2024-12-31',
95
+ commodity: 'BRENT_CRUDE_USD'
96
+ });
97
+
98
+ console.log(`Got ${prices.length} data points for 2024`);
99
+ ```
100
+
101
+ ### Advanced Configuration
102
+
103
+ ```typescript
104
+ import { OilPriceAPI } from 'oilpriceapi';
105
+
106
+ const client = new OilPriceAPI({
107
+ apiKey: 'your_key',
108
+
109
+ // Retry configuration
110
+ retries: 3, // Max retry attempts (default: 3)
111
+ retryDelay: 1000, // Initial delay in ms (default: 1000)
112
+ retryStrategy: 'exponential', // 'exponential', 'linear', or 'fixed'
113
+
114
+ // Timeout configuration
115
+ timeout: 30000, // Request timeout in ms (default: 30000)
116
+
117
+ // Debug mode
118
+ debug: true // Enable debug logging (default: false)
119
+ });
120
+ ```
121
+
122
+ ### Error Handling
123
+
124
+ ```typescript
125
+ import {
126
+ OilPriceAPI,
127
+ AuthenticationError,
128
+ RateLimitError,
129
+ NotFoundError,
130
+ TimeoutError,
131
+ ServerError
132
+ } from 'oilpriceapi';
133
+
134
+ const client = new OilPriceAPI({ apiKey: 'your_key' });
135
+
136
+ try {
137
+ const prices = await client.getLatestPrices();
138
+ } catch (error) {
139
+ if (error instanceof AuthenticationError) {
140
+ console.error('Invalid API key:', error.message);
141
+ } else if (error instanceof RateLimitError) {
142
+ console.error('Rate limit exceeded. Retry after:', error.retryAfter, 'seconds');
143
+ } else if (error instanceof TimeoutError) {
144
+ console.error('Request timed out:', error.message);
145
+ } else if (error instanceof ServerError) {
146
+ console.error('Server error:', error.statusCode, error.message);
147
+ } else if (error instanceof NotFoundError) {
148
+ console.error('Commodity not found:', error.message);
149
+ } else {
150
+ console.error('Unknown error:', error);
151
+ }
152
+ }
153
+ ```
154
+
155
+ ### Debug Mode
156
+
157
+ Enable debug logging to see detailed request/response information:
158
+
159
+ ```typescript
160
+ const client = new OilPriceAPI({
161
+ apiKey: 'your_key',
162
+ debug: true
163
+ });
164
+
165
+ // This will log all requests, responses, retries, and errors
166
+ const prices = await client.getLatestPrices();
167
+
168
+ // Example output:
169
+ // [OilPriceAPI 2024-11-24T20:28:23.145Z] Request: https://api.oilpriceapi.com/v1/prices/latest
170
+ // [OilPriceAPI 2024-11-24T20:28:23.393Z] Response: 200 OK
171
+ // [OilPriceAPI 2024-11-24T20:28:23.394Z] Response data received { status: 'success', hasData: true }
172
+ ```
173
+
174
+ ## Integration Examples
175
+
176
+ ### Express.js
177
+
178
+ ```typescript
179
+ import express from 'express';
180
+ import { OilPriceAPI } from 'oilpriceapi';
181
+
182
+ const app = express();
183
+ const oilPrices = new OilPriceAPI({
184
+ apiKey: process.env.OIL_PRICE_API_KEY
185
+ });
186
+
187
+ app.get('/api/prices', async (req, res) => {
188
+ try {
189
+ const prices = await oilPrices.getLatestPrices();
190
+ res.json({ success: true, data: prices });
191
+ } catch (error) {
192
+ res.status(500).json({
193
+ success: false,
194
+ error: error.message
195
+ });
196
+ }
197
+ });
198
+
199
+ app.listen(3000, () => {
200
+ console.log('Server running on port 3000');
201
+ });
202
+ ```
203
+
204
+ ### Next.js API Route
205
+
206
+ ```typescript
207
+ // app/api/prices/route.ts
208
+ import { OilPriceAPI } from 'oilpriceapi';
209
+
210
+ const client = new OilPriceAPI({
211
+ apiKey: process.env.OIL_PRICE_API_KEY
212
+ });
213
+
214
+ export async function GET() {
215
+ try {
216
+ const prices = await client.getLatestPrices();
217
+ return Response.json(prices);
218
+ } catch (error) {
219
+ return Response.json(
220
+ { error: error.message },
221
+ { status: 500 }
222
+ );
223
+ }
224
+ }
225
+ ```
226
+
227
+ ### Price Monitoring Script
228
+
229
+ ```typescript
230
+ import { OilPriceAPI } from 'oilpriceapi';
231
+
232
+ const client = new OilPriceAPI({ apiKey: process.env.OIL_PRICE_API_KEY });
233
+
234
+ async function checkPrice() {
235
+ const wti = await client.getLatestPrices({ commodity: 'WTI_USD' });
236
+ const price = wti[0].value;
237
+
238
+ console.log(`Current WTI price: $${price}`);
239
+
240
+ if (price < 70) {
241
+ console.log('🚨 ALERT: WTI below $70!');
242
+ // Send notification, email, etc.
243
+ }
244
+ }
245
+
246
+ // Check every 5 minutes
247
+ setInterval(checkPrice, 5 * 60 * 1000);
248
+ checkPrice(); // Run immediately
249
+ ```
250
+
251
+ ## API Reference
252
+
253
+ ### `OilPriceAPI`
254
+
255
+ Main client class for interacting with the Oil Price API.
256
+
257
+ #### Constructor
258
+
259
+ ```typescript
260
+ new OilPriceAPI(config: OilPriceAPIConfig)
261
+ ```
262
+
263
+ **Parameters:**
264
+ - `config.apiKey` (string, required) - Your API key from https://www.oilpriceapi.com
265
+ - `config.baseUrl` (string, optional) - Custom API base URL (for testing)
266
+
267
+ #### Methods
268
+
269
+ ##### `getLatestPrices(options?)`
270
+
271
+ Get the latest prices for all commodities or a specific commodity.
272
+
273
+ **Parameters:**
274
+ - `options.commodity` (string, optional) - Filter by commodity code (e.g., "WTI_USD")
275
+
276
+ **Returns:** `Promise<Price[]>`
277
+
278
+ ##### `getHistoricalPrices(options?)`
279
+
280
+ Get historical prices for a time period.
281
+
282
+ **Parameters:**
283
+ - `options.period` (string, optional) - One of: "past_week", "past_month", "past_year"
284
+ - `options.commodity` (string, optional) - Filter by commodity code
285
+ - `options.startDate` (string, optional) - Start date in ISO 8601 format (YYYY-MM-DD)
286
+ - `options.endDate` (string, optional) - End date in ISO 8601 format (YYYY-MM-DD)
287
+
288
+ **Returns:** `Promise<Price[]>`
289
+
290
+ ### Types
291
+
292
+ #### `Price`
293
+
294
+ ```typescript
295
+ interface Price {
296
+ code: string; // Commodity code (e.g., "WTI_USD")
297
+ name: string; // Human-readable name
298
+ value: number; // Price value
299
+ currency: string; // Currency code (e.g., "USD")
300
+ unit: string; // Unit of measurement (e.g., "barrel")
301
+ timestamp: string; // ISO 8601 timestamp
302
+ created_at: string; // ISO 8601 timestamp
303
+ updated_at: string; // ISO 8601 timestamp
304
+ }
305
+ ```
306
+
307
+ ### Error Classes
308
+
309
+ All errors extend `OilPriceAPIError`:
310
+
311
+ - `AuthenticationError` (401) - Invalid API key
312
+ - `RateLimitError` (429) - Rate limit exceeded
313
+ - `NotFoundError` (404) - Resource not found
314
+ - `ServerError` (5xx) - Server-side error
315
+
316
+ ## Available Commodities
317
+
318
+ The API provides prices for the following commodities:
319
+
320
+ - **Crude Oil**: WTI, Brent Crude
321
+ - **Refined Products**: Gasoline, Diesel, Heating Oil, Jet Fuel
322
+ - **Natural Gas**: US Natural Gas, EU Natural Gas, UK Natural Gas
323
+ - **And more...**
324
+
325
+ See the [full list of commodities](https://www.oilpriceapi.com/commodities) in the documentation.
326
+
327
+ ## Pricing & Rate Limits
328
+
329
+ - **Free Tier**: 1,000 requests/month
330
+ - **Starter**: 50,000 requests/month - $49/mo
331
+ - **Professional**: 100,000 requests/month - $99/mo
332
+ - **Business**: 200,000 requests/month - $199/mo
333
+ - **Enterprise**: Custom limits - Contact us
334
+
335
+ Get started with a free API key at [oilpriceapi.com](https://www.oilpriceapi.com).
336
+
337
+ ## Requirements
338
+
339
+ - Node.js 18.0.0 or higher (for native fetch support)
340
+ - TypeScript 5.0+ (if using TypeScript)
341
+
342
+ ## TypeScript Support
343
+
344
+ This package is written in TypeScript and includes full type definitions. You get:
345
+
346
+ - ✅ Full autocomplete in your IDE
347
+ - ✅ Type checking for method parameters
348
+ - ✅ Detailed JSDoc comments
349
+ - ✅ Type-safe error handling
350
+
351
+ ## Contributing
352
+
353
+ We welcome contributions! Please see our [Contributing Guide](https://github.com/OilpriceAPI/oilpriceapi-node/blob/main/CONTRIBUTING.md) for details.
354
+
355
+ ## Support
356
+
357
+ - 📧 Email: support@oilpriceapi.com
358
+ - 🐛 Issues: [GitHub Issues](https://github.com/OilpriceAPI/oilpriceapi-node/issues)
359
+ - 📚 Documentation: [oilpriceapi.com/docs](https://www.oilpriceapi.com/docs)
360
+ - 💬 Discord: [Join our community](https://discord.gg/oilpriceapi)
361
+
362
+ ## License
363
+
364
+ MIT License - see [LICENSE](LICENSE) file for details.
365
+
366
+ ## Links
367
+
368
+ - [Website](https://www.oilpriceapi.com)
369
+ - [API Documentation](https://www.oilpriceapi.com/docs)
370
+ - [GitHub Repository](https://github.com/OilpriceAPI/oilpriceapi-node)
371
+ - [npm Package](https://www.npmjs.com/package/oilpriceapi)
372
+
373
+ ---
374
+
375
+ Made with ❤️ by the Oil Price API team
@@ -0,0 +1,96 @@
1
+ import type { OilPriceAPIConfig, Price, LatestPricesOptions, HistoricalPricesOptions } from './types.js';
2
+ /**
3
+ * Official Node.js client for Oil Price API
4
+ *
5
+ * @example
6
+ * ```typescript
7
+ * import { OilPriceAPI } from 'oilpriceapi';
8
+ *
9
+ * const client = new OilPriceAPI({
10
+ * apiKey: 'your_api_key_here',
11
+ * retries: 3,
12
+ * timeout: 30000
13
+ * });
14
+ *
15
+ * // Get latest prices
16
+ * const prices = await client.getLatestPrices();
17
+ *
18
+ * // Get WTI price only
19
+ * const wti = await client.getLatestPrices({ commodity: 'WTI_USD' });
20
+ *
21
+ * // Get historical data
22
+ * const historical = await client.getHistoricalPrices({
23
+ * period: 'past_week',
24
+ * commodity: 'BRENT_CRUDE_USD'
25
+ * });
26
+ * ```
27
+ */
28
+ export declare class OilPriceAPI {
29
+ private apiKey;
30
+ private baseUrl;
31
+ private retries;
32
+ private retryDelay;
33
+ private retryStrategy;
34
+ private timeout;
35
+ private debug;
36
+ constructor(config: OilPriceAPIConfig);
37
+ /**
38
+ * Log debug messages if debug mode is enabled
39
+ */
40
+ private log;
41
+ /**
42
+ * Calculate delay for retry based on strategy
43
+ */
44
+ private calculateRetryDelay;
45
+ /**
46
+ * Sleep for specified milliseconds
47
+ */
48
+ private sleep;
49
+ /**
50
+ * Determine if error is retryable
51
+ */
52
+ private isRetryable;
53
+ /**
54
+ * Internal method to make HTTP requests with retry and timeout
55
+ */
56
+ private request;
57
+ /**
58
+ * Get the latest prices for all commodities or a specific commodity
59
+ *
60
+ * @param options - Optional filters
61
+ * @returns Array of price objects
62
+ *
63
+ * @example
64
+ * ```typescript
65
+ * // Get all latest prices
66
+ * const allPrices = await client.getLatestPrices();
67
+ *
68
+ * // Get WTI price only
69
+ * const wti = await client.getLatestPrices({ commodity: 'WTI_USD' });
70
+ * ```
71
+ */
72
+ getLatestPrices(options?: LatestPricesOptions): Promise<Price[]>;
73
+ /**
74
+ * Get historical prices for a time period
75
+ *
76
+ * @param options - Time period and filter options
77
+ * @returns Array of historical price objects
78
+ *
79
+ * @example
80
+ * ```typescript
81
+ * // Get past week of WTI prices
82
+ * const weekPrices = await client.getHistoricalPrices({
83
+ * period: 'past_week',
84
+ * commodity: 'WTI_USD'
85
+ * });
86
+ *
87
+ * // Get custom date range
88
+ * const customPrices = await client.getHistoricalPrices({
89
+ * startDate: '2024-01-01',
90
+ * endDate: '2024-12-31',
91
+ * commodity: 'BRENT_CRUDE_USD'
92
+ * });
93
+ * ```
94
+ */
95
+ getHistoricalPrices(options?: HistoricalPricesOptions): Promise<Price[]>;
96
+ }
package/dist/client.js ADDED
@@ -0,0 +1,291 @@
1
+ import { OilPriceAPIError, AuthenticationError, RateLimitError, NotFoundError, ServerError, TimeoutError, } from './errors.js';
2
+ /**
3
+ * Official Node.js client for Oil Price API
4
+ *
5
+ * @example
6
+ * ```typescript
7
+ * import { OilPriceAPI } from 'oilpriceapi';
8
+ *
9
+ * const client = new OilPriceAPI({
10
+ * apiKey: 'your_api_key_here',
11
+ * retries: 3,
12
+ * timeout: 30000
13
+ * });
14
+ *
15
+ * // Get latest prices
16
+ * const prices = await client.getLatestPrices();
17
+ *
18
+ * // Get WTI price only
19
+ * const wti = await client.getLatestPrices({ commodity: 'WTI_USD' });
20
+ *
21
+ * // Get historical data
22
+ * const historical = await client.getHistoricalPrices({
23
+ * period: 'past_week',
24
+ * commodity: 'BRENT_CRUDE_USD'
25
+ * });
26
+ * ```
27
+ */
28
+ export class OilPriceAPI {
29
+ constructor(config) {
30
+ if (!config.apiKey) {
31
+ throw new OilPriceAPIError('API key is required');
32
+ }
33
+ this.apiKey = config.apiKey;
34
+ this.baseUrl = config.baseUrl || 'https://api.oilpriceapi.com';
35
+ this.retries = config.retries !== undefined ? config.retries : 3;
36
+ this.retryDelay = config.retryDelay || 1000;
37
+ this.retryStrategy = config.retryStrategy || 'exponential';
38
+ this.timeout = config.timeout || 30000;
39
+ this.debug = config.debug || false;
40
+ }
41
+ /**
42
+ * Log debug messages if debug mode is enabled
43
+ */
44
+ log(message, data) {
45
+ if (this.debug) {
46
+ const timestamp = new Date().toISOString();
47
+ console.log(`[OilPriceAPI ${timestamp}] ${message}`, data || '');
48
+ }
49
+ }
50
+ /**
51
+ * Calculate delay for retry based on strategy
52
+ */
53
+ calculateRetryDelay(attempt) {
54
+ switch (this.retryStrategy) {
55
+ case 'exponential':
56
+ return this.retryDelay * Math.pow(2, attempt);
57
+ case 'linear':
58
+ return this.retryDelay * (attempt + 1);
59
+ case 'fixed':
60
+ default:
61
+ return this.retryDelay;
62
+ }
63
+ }
64
+ /**
65
+ * Sleep for specified milliseconds
66
+ */
67
+ sleep(ms) {
68
+ return new Promise(resolve => setTimeout(resolve, ms));
69
+ }
70
+ /**
71
+ * Determine if error is retryable
72
+ */
73
+ isRetryable(error) {
74
+ // Retry on network errors
75
+ if (error instanceof TypeError && error.message.includes('fetch')) {
76
+ return true;
77
+ }
78
+ // Retry on timeout errors
79
+ if (error instanceof TimeoutError) {
80
+ return true;
81
+ }
82
+ // Retry on 5xx server errors
83
+ if (error instanceof ServerError) {
84
+ return true;
85
+ }
86
+ // Retry on rate limit errors (with delay)
87
+ if (error instanceof RateLimitError) {
88
+ return true;
89
+ }
90
+ // Don't retry on client errors (4xx except 429)
91
+ return false;
92
+ }
93
+ /**
94
+ * Internal method to make HTTP requests with retry and timeout
95
+ */
96
+ async request(endpoint, params) {
97
+ // Build URL with query parameters
98
+ const url = new URL(`${this.baseUrl}${endpoint}`);
99
+ if (params) {
100
+ Object.entries(params).forEach(([key, value]) => {
101
+ if (value !== undefined && value !== null) {
102
+ url.searchParams.append(key, value);
103
+ }
104
+ });
105
+ }
106
+ this.log(`Request: ${url.toString()}`);
107
+ let lastError = null;
108
+ // Retry loop
109
+ for (let attempt = 0; attempt <= this.retries; attempt++) {
110
+ try {
111
+ // Add retry info to logs
112
+ if (attempt > 0) {
113
+ this.log(`Retry attempt ${attempt}/${this.retries}`);
114
+ }
115
+ // Create abort controller for timeout
116
+ const controller = new AbortController();
117
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
118
+ try {
119
+ const response = await fetch(url.toString(), {
120
+ method: 'GET',
121
+ headers: {
122
+ 'Authorization': `Bearer ${this.apiKey}`,
123
+ 'Content-Type': 'application/json',
124
+ 'User-Agent': 'oilpriceapi-node/0.2.0',
125
+ },
126
+ signal: controller.signal,
127
+ });
128
+ clearTimeout(timeoutId);
129
+ this.log(`Response: ${response.status} ${response.statusText}`);
130
+ // Handle error responses
131
+ if (!response.ok) {
132
+ const errorBody = await response.text();
133
+ let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
134
+ // Try to parse JSON error response
135
+ try {
136
+ const errorJson = JSON.parse(errorBody);
137
+ errorMessage = errorJson.message || errorJson.error || errorMessage;
138
+ }
139
+ catch {
140
+ // Use default error message if response isn't JSON
141
+ }
142
+ this.log(`Error response: ${errorMessage}`);
143
+ // Throw specific error types based on status code
144
+ switch (response.status) {
145
+ case 401:
146
+ throw new AuthenticationError(errorMessage);
147
+ case 404:
148
+ throw new NotFoundError(errorMessage);
149
+ case 429:
150
+ const retryAfter = response.headers.get('Retry-After');
151
+ const rateLimitError = new RateLimitError(errorMessage, retryAfter ? parseInt(retryAfter, 10) : undefined);
152
+ // If rate limited and we have retries left, wait and retry
153
+ if (attempt < this.retries && rateLimitError.retryAfter) {
154
+ this.log(`Rate limited. Waiting ${rateLimitError.retryAfter}s`);
155
+ await this.sleep(rateLimitError.retryAfter * 1000);
156
+ continue;
157
+ }
158
+ throw rateLimitError;
159
+ case 500:
160
+ case 502:
161
+ case 503:
162
+ case 504:
163
+ throw new ServerError(errorMessage, response.status);
164
+ default:
165
+ throw new OilPriceAPIError(errorMessage, response.status, 'HTTP_ERROR');
166
+ }
167
+ }
168
+ // Parse successful response
169
+ const responseData = await response.json();
170
+ this.log('Response data received', {
171
+ status: responseData.status,
172
+ hasData: !!responseData.data
173
+ });
174
+ // Handle different response structures
175
+ // Latest endpoint: { status, data: { price, ... } }
176
+ // Historical endpoint: { status, data: { prices: [...] } }
177
+ if (responseData.status === 'success' && responseData.data) {
178
+ if (responseData.data.prices) {
179
+ // Historical endpoint - return prices array
180
+ this.log(`Returning ${responseData.data.prices.length} prices`);
181
+ return responseData.data.prices;
182
+ }
183
+ else if (responseData.data.price !== undefined) {
184
+ // Latest endpoint - wrap single price in array
185
+ this.log('Returning single price (wrapped in array)');
186
+ return [responseData.data];
187
+ }
188
+ }
189
+ // Fallback - return data as-is
190
+ this.log('Returning data as-is');
191
+ return responseData.data;
192
+ }
193
+ catch (error) {
194
+ // Handle abort (timeout)
195
+ if (error instanceof Error && error.name === 'AbortError') {
196
+ throw new TimeoutError('Request timeout', this.timeout);
197
+ }
198
+ throw error;
199
+ }
200
+ }
201
+ catch (error) {
202
+ lastError = error;
203
+ this.log(`Request failed: ${lastError.message}`, {
204
+ attempt,
205
+ retryable: this.isRetryable(lastError)
206
+ });
207
+ // Re-throw our custom errors if not retryable
208
+ if (error instanceof OilPriceAPIError && !this.isRetryable(error)) {
209
+ throw error;
210
+ }
211
+ // If this was our last attempt, throw the error
212
+ if (attempt === this.retries) {
213
+ if (error instanceof OilPriceAPIError) {
214
+ throw error;
215
+ }
216
+ // Wrap fetch errors (network issues, etc.)
217
+ if (error instanceof Error) {
218
+ throw new OilPriceAPIError(`Request failed after ${this.retries + 1} attempts: ${error.message}`, undefined, 'NETWORK_ERROR');
219
+ }
220
+ throw error;
221
+ }
222
+ // Calculate delay and retry
223
+ const delay = this.calculateRetryDelay(attempt);
224
+ this.log(`Waiting ${delay}ms before retry...`);
225
+ await this.sleep(delay);
226
+ }
227
+ }
228
+ // This should never be reached, but TypeScript wants it
229
+ throw lastError || new OilPriceAPIError('Unknown error occurred');
230
+ }
231
+ /**
232
+ * Get the latest prices for all commodities or a specific commodity
233
+ *
234
+ * @param options - Optional filters
235
+ * @returns Array of price objects
236
+ *
237
+ * @example
238
+ * ```typescript
239
+ * // Get all latest prices
240
+ * const allPrices = await client.getLatestPrices();
241
+ *
242
+ * // Get WTI price only
243
+ * const wti = await client.getLatestPrices({ commodity: 'WTI_USD' });
244
+ * ```
245
+ */
246
+ async getLatestPrices(options) {
247
+ const params = {};
248
+ if (options?.commodity) {
249
+ params.by_code = options.commodity;
250
+ }
251
+ return this.request('/v1/prices/latest', params);
252
+ }
253
+ /**
254
+ * Get historical prices for a time period
255
+ *
256
+ * @param options - Time period and filter options
257
+ * @returns Array of historical price objects
258
+ *
259
+ * @example
260
+ * ```typescript
261
+ * // Get past week of WTI prices
262
+ * const weekPrices = await client.getHistoricalPrices({
263
+ * period: 'past_week',
264
+ * commodity: 'WTI_USD'
265
+ * });
266
+ *
267
+ * // Get custom date range
268
+ * const customPrices = await client.getHistoricalPrices({
269
+ * startDate: '2024-01-01',
270
+ * endDate: '2024-12-31',
271
+ * commodity: 'BRENT_CRUDE_USD'
272
+ * });
273
+ * ```
274
+ */
275
+ async getHistoricalPrices(options) {
276
+ const params = {};
277
+ if (options?.period) {
278
+ params.period = options.period;
279
+ }
280
+ if (options?.commodity) {
281
+ params.by_code = options.commodity;
282
+ }
283
+ if (options?.startDate) {
284
+ params.start_date = options.startDate;
285
+ }
286
+ if (options?.endDate) {
287
+ params.end_date = options.endDate;
288
+ }
289
+ return this.request('/v1/prices', params);
290
+ }
291
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Base error class for all Oil Price API errors
3
+ */
4
+ export declare class OilPriceAPIError extends Error {
5
+ /**
6
+ * HTTP status code (if applicable)
7
+ */
8
+ statusCode?: number;
9
+ /**
10
+ * Error code from the API
11
+ */
12
+ code?: string;
13
+ constructor(message: string, statusCode?: number, code?: string);
14
+ }
15
+ /**
16
+ * Thrown when API authentication fails (401)
17
+ */
18
+ export declare class AuthenticationError extends OilPriceAPIError {
19
+ constructor(message?: string);
20
+ }
21
+ /**
22
+ * Thrown when rate limit is exceeded (429)
23
+ */
24
+ export declare class RateLimitError extends OilPriceAPIError {
25
+ /**
26
+ * Number of seconds until rate limit resets
27
+ */
28
+ retryAfter?: number;
29
+ constructor(message?: string, retryAfter?: number);
30
+ }
31
+ /**
32
+ * Thrown when requested resource is not found (404)
33
+ */
34
+ export declare class NotFoundError extends OilPriceAPIError {
35
+ constructor(message?: string);
36
+ }
37
+ /**
38
+ * Thrown when server returns 5xx error
39
+ */
40
+ export declare class ServerError extends OilPriceAPIError {
41
+ constructor(message?: string, statusCode?: number);
42
+ }
43
+ /**
44
+ * Thrown when request exceeds timeout
45
+ */
46
+ export declare class TimeoutError extends OilPriceAPIError {
47
+ constructor(message: string | undefined, timeout: number);
48
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Base error class for all Oil Price API errors
3
+ */
4
+ export class OilPriceAPIError extends Error {
5
+ constructor(message, statusCode, code) {
6
+ super(message);
7
+ this.name = 'OilPriceAPIError';
8
+ this.statusCode = statusCode;
9
+ this.code = code;
10
+ // Maintains proper stack trace for where our error was thrown (only available on V8)
11
+ if (Error.captureStackTrace) {
12
+ Error.captureStackTrace(this, this.constructor);
13
+ }
14
+ }
15
+ }
16
+ /**
17
+ * Thrown when API authentication fails (401)
18
+ */
19
+ export class AuthenticationError extends OilPriceAPIError {
20
+ constructor(message = 'Invalid API key') {
21
+ super(message, 401, 'AUTHENTICATION_ERROR');
22
+ this.name = 'AuthenticationError';
23
+ }
24
+ }
25
+ /**
26
+ * Thrown when rate limit is exceeded (429)
27
+ */
28
+ export class RateLimitError extends OilPriceAPIError {
29
+ constructor(message = 'Rate limit exceeded', retryAfter) {
30
+ super(message, 429, 'RATE_LIMIT_ERROR');
31
+ this.name = 'RateLimitError';
32
+ this.retryAfter = retryAfter;
33
+ }
34
+ }
35
+ /**
36
+ * Thrown when requested resource is not found (404)
37
+ */
38
+ export class NotFoundError extends OilPriceAPIError {
39
+ constructor(message = 'Resource not found') {
40
+ super(message, 404, 'NOT_FOUND_ERROR');
41
+ this.name = 'NotFoundError';
42
+ }
43
+ }
44
+ /**
45
+ * Thrown when server returns 5xx error
46
+ */
47
+ export class ServerError extends OilPriceAPIError {
48
+ constructor(message = 'Internal server error', statusCode = 500) {
49
+ super(message, statusCode, 'SERVER_ERROR');
50
+ this.name = 'ServerError';
51
+ }
52
+ }
53
+ /**
54
+ * Thrown when request exceeds timeout
55
+ */
56
+ export class TimeoutError extends OilPriceAPIError {
57
+ constructor(message = 'Request timeout', timeout) {
58
+ super(`${message} (${timeout}ms)`, undefined, 'TIMEOUT_ERROR');
59
+ this.name = 'TimeoutError';
60
+ }
61
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Official Node.js SDK for Oil Price API
3
+ *
4
+ * Get real-time and historical oil & commodity prices in your Node.js applications.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ export { OilPriceAPI } from './client.js';
9
+ export type { OilPriceAPIConfig, RetryStrategy, Price, LatestPricesOptions, HistoricalPricesOptions, HistoricalPeriod, } from './types.js';
10
+ export { OilPriceAPIError, AuthenticationError, RateLimitError, NotFoundError, ServerError, TimeoutError, } from './errors.js';
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Official Node.js SDK for Oil Price API
3
+ *
4
+ * Get real-time and historical oil & commodity prices in your Node.js applications.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ export { OilPriceAPI } from './client.js';
9
+ export { OilPriceAPIError, AuthenticationError, RateLimitError, NotFoundError, ServerError, TimeoutError, } from './errors.js';
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Retry backoff strategy
3
+ */
4
+ export type RetryStrategy = 'exponential' | 'linear' | 'fixed';
5
+ /**
6
+ * Configuration options for OilPriceAPI client
7
+ */
8
+ export interface OilPriceAPIConfig {
9
+ /**
10
+ * Your API key from https://www.oilpriceapi.com
11
+ */
12
+ apiKey: string;
13
+ /**
14
+ * Base URL for the API (optional, for testing)
15
+ * @default "https://api.oilpriceapi.com"
16
+ */
17
+ baseUrl?: string;
18
+ /**
19
+ * Maximum number of retry attempts for failed requests
20
+ * @default 3
21
+ */
22
+ retries?: number;
23
+ /**
24
+ * Initial delay between retries in milliseconds
25
+ * @default 1000
26
+ */
27
+ retryDelay?: number;
28
+ /**
29
+ * Retry backoff strategy
30
+ * @default "exponential"
31
+ */
32
+ retryStrategy?: RetryStrategy;
33
+ /**
34
+ * Request timeout in milliseconds
35
+ * @default 30000 (30 seconds)
36
+ */
37
+ timeout?: number;
38
+ /**
39
+ * Enable debug logging to console
40
+ * @default false
41
+ */
42
+ debug?: boolean;
43
+ }
44
+ /**
45
+ * Represents a single price data point
46
+ */
47
+ export interface Price {
48
+ /**
49
+ * Commodity code (e.g., "WTI_USD", "BRENT_CRUDE_USD")
50
+ */
51
+ code: string;
52
+ /**
53
+ * Current price value
54
+ */
55
+ price: number;
56
+ /**
57
+ * Formatted price string (e.g., "$74.25")
58
+ */
59
+ formatted: string;
60
+ /**
61
+ * Currency code (e.g., "USD")
62
+ */
63
+ currency: string;
64
+ /**
65
+ * ISO 8601 timestamp of when this price was recorded
66
+ */
67
+ created_at: string;
68
+ /**
69
+ * Type of price (e.g., "spot_price")
70
+ */
71
+ type: string;
72
+ /**
73
+ * Data source (e.g., "oilprice.ft", "internal")
74
+ */
75
+ source: string;
76
+ /**
77
+ * Price changes over different time periods (24h, 7d, 30d, 90d)
78
+ */
79
+ changes?: {
80
+ '24h'?: {
81
+ amount: number;
82
+ percent: number;
83
+ previous_price: number;
84
+ };
85
+ '7d'?: {
86
+ amount: number;
87
+ percent: number;
88
+ previous_price: number;
89
+ };
90
+ '30d'?: {
91
+ amount: number;
92
+ percent: number;
93
+ previous_price: number;
94
+ };
95
+ '90d'?: {
96
+ amount: number;
97
+ percent: number;
98
+ previous_price: number;
99
+ };
100
+ };
101
+ /**
102
+ * Additional metadata about the source
103
+ */
104
+ metadata?: {
105
+ source: string;
106
+ source_description?: string;
107
+ };
108
+ }
109
+ /**
110
+ * Options for fetching latest prices
111
+ */
112
+ export interface LatestPricesOptions {
113
+ /**
114
+ * Filter by specific commodity code (optional)
115
+ * Example: "WTI_USD", "BRENT_CRUDE_USD"
116
+ */
117
+ commodity?: string;
118
+ }
119
+ /**
120
+ * Time period options for historical data
121
+ */
122
+ export type HistoricalPeriod = 'past_week' | 'past_month' | 'past_year';
123
+ /**
124
+ * Options for fetching historical prices
125
+ */
126
+ export interface HistoricalPricesOptions {
127
+ /**
128
+ * Predefined time period (alternative to startDate/endDate)
129
+ */
130
+ period?: HistoricalPeriod;
131
+ /**
132
+ * Filter by specific commodity code (optional)
133
+ */
134
+ commodity?: string;
135
+ /**
136
+ * Start date in ISO 8601 format (YYYY-MM-DD)
137
+ * Example: "2024-01-01"
138
+ */
139
+ startDate?: string;
140
+ /**
141
+ * End date in ISO 8601 format (YYYY-MM-DD)
142
+ * Example: "2024-12-31"
143
+ */
144
+ endDate?: string;
145
+ }
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "oilpriceapi",
3
+ "version": "0.2.0",
4
+ "description": "Official Node.js SDK for Oil Price API - Real-time and historical oil & commodity prices",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/index.js",
10
+ "require": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md",
17
+ "LICENSE"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsc",
21
+ "test": "vitest run",
22
+ "test:watch": "vitest",
23
+ "prepublishOnly": "npm run build"
24
+ },
25
+ "keywords": [
26
+ "oil",
27
+ "price",
28
+ "commodity",
29
+ "api",
30
+ "brent",
31
+ "wti",
32
+ "crude",
33
+ "gasoline",
34
+ "diesel",
35
+ "natural-gas",
36
+ "energy",
37
+ "trading"
38
+ ],
39
+ "author": "Oil Price API <karl@oilpriceapi.com>",
40
+ "license": "MIT",
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "https://github.com/OilpriceAPI/oilpriceapi-node.git"
44
+ },
45
+ "bugs": {
46
+ "url": "https://github.com/OilpriceAPI/oilpriceapi-node/issues"
47
+ },
48
+ "homepage": "https://www.oilpriceapi.com",
49
+ "engines": {
50
+ "node": ">=18.0.0"
51
+ },
52
+ "devDependencies": {
53
+ "@types/node": "^20.10.0",
54
+ "typescript": "^5.3.0",
55
+ "vitest": "^1.0.0"
56
+ }
57
+ }