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.
- package/README.md +418 -123
- package/dist/cjs/client.js +490 -0
- package/dist/cjs/errors.js +80 -0
- package/dist/cjs/index.js +82 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/resources/alerts.js +387 -0
- package/dist/cjs/resources/analytics.js +226 -0
- package/dist/cjs/resources/bunker-fuels.js +196 -0
- package/dist/cjs/resources/commodities.js +115 -0
- package/dist/cjs/resources/data-quality.js +144 -0
- package/dist/cjs/resources/data-sources.js +297 -0
- package/dist/cjs/resources/diesel.js +119 -0
- package/dist/cjs/resources/drilling.js +269 -0
- package/dist/cjs/resources/ei/drilling-productivity.js +108 -0
- package/dist/cjs/resources/ei/forecasts.js +106 -0
- package/dist/cjs/resources/ei/frac-focus.js +155 -0
- package/dist/cjs/resources/ei/index.js +98 -0
- package/dist/cjs/resources/ei/oil-inventories.js +97 -0
- package/dist/cjs/resources/ei/opec-production.js +97 -0
- package/dist/cjs/resources/ei/rig-counts.js +93 -0
- package/dist/cjs/resources/ei/well-permits.js +124 -0
- package/dist/cjs/resources/forecasts.js +162 -0
- package/dist/cjs/resources/futures.js +233 -0
- package/dist/cjs/resources/rig-counts.js +161 -0
- package/dist/cjs/resources/storage.js +166 -0
- package/dist/cjs/resources/webhooks.js +294 -0
- package/dist/cjs/types.js +2 -0
- package/dist/cjs/version.js +24 -0
- package/dist/client.d.ts +116 -5
- package/dist/client.js +169 -47
- package/dist/errors.d.ts +6 -0
- package/dist/errors.js +25 -16
- package/dist/index.d.ts +45 -6
- package/dist/index.js +40 -3
- package/dist/resources/alerts.d.ts +52 -15
- package/dist/resources/alerts.js +121 -109
- package/dist/resources/analytics.d.ts +325 -0
- package/dist/resources/analytics.js +222 -0
- package/dist/resources/bunker-fuels.d.ts +270 -0
- package/dist/resources/bunker-fuels.js +192 -0
- package/dist/resources/commodities.d.ts +148 -0
- package/dist/resources/commodities.js +111 -0
- package/dist/resources/data-quality.d.ts +229 -0
- package/dist/resources/data-quality.js +140 -0
- package/dist/resources/data-sources.d.ts +365 -0
- package/dist/resources/data-sources.js +293 -0
- package/dist/resources/diesel.d.ts +1 -1
- package/dist/resources/diesel.js +9 -38
- package/dist/resources/drilling.d.ts +403 -0
- package/dist/resources/drilling.js +265 -0
- package/dist/resources/ei/drilling-productivity.d.ts +173 -0
- package/dist/resources/ei/drilling-productivity.js +104 -0
- package/dist/resources/ei/forecasts.d.ts +177 -0
- package/dist/resources/ei/forecasts.js +102 -0
- package/dist/resources/ei/frac-focus.d.ts +212 -0
- package/dist/resources/ei/frac-focus.js +151 -0
- package/dist/resources/ei/index.d.ts +140 -0
- package/dist/resources/ei/index.js +88 -0
- package/dist/resources/ei/oil-inventories.d.ts +155 -0
- package/dist/resources/ei/oil-inventories.js +93 -0
- package/dist/resources/ei/opec-production.d.ts +146 -0
- package/dist/resources/ei/opec-production.js +93 -0
- package/dist/resources/ei/rig-counts.d.ts +131 -0
- package/dist/resources/ei/rig-counts.js +89 -0
- package/dist/resources/ei/well-permits.d.ts +178 -0
- package/dist/resources/ei/well-permits.js +120 -0
- package/dist/resources/forecasts.d.ts +200 -0
- package/dist/resources/forecasts.js +158 -0
- package/dist/resources/futures.d.ts +322 -0
- package/dist/resources/futures.js +229 -0
- package/dist/resources/rig-counts.d.ts +221 -0
- package/dist/resources/rig-counts.js +157 -0
- package/dist/resources/storage.d.ts +182 -0
- package/dist/resources/storage.js +162 -0
- package/dist/resources/webhooks.d.ts +326 -0
- package/dist/resources/webhooks.js +290 -0
- package/dist/types.d.ts +79 -8
- package/dist/version.d.ts +1 -1
- package/dist/version.js +2 -2
- package/package.json +17 -8
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OilPriceAPI = void 0;
|
|
4
|
+
const errors_js_1 = require("./errors.js");
|
|
5
|
+
const diesel_js_1 = require("./resources/diesel.js");
|
|
6
|
+
const alerts_js_1 = require("./resources/alerts.js");
|
|
7
|
+
const commodities_js_1 = require("./resources/commodities.js");
|
|
8
|
+
const futures_js_1 = require("./resources/futures.js");
|
|
9
|
+
const storage_js_1 = require("./resources/storage.js");
|
|
10
|
+
const rig_counts_js_1 = require("./resources/rig-counts.js");
|
|
11
|
+
const bunker_fuels_js_1 = require("./resources/bunker-fuels.js");
|
|
12
|
+
const analytics_js_1 = require("./resources/analytics.js");
|
|
13
|
+
const forecasts_js_1 = require("./resources/forecasts.js");
|
|
14
|
+
const data_quality_js_1 = require("./resources/data-quality.js");
|
|
15
|
+
const drilling_js_1 = require("./resources/drilling.js");
|
|
16
|
+
const index_js_1 = require("./resources/ei/index.js");
|
|
17
|
+
const webhooks_js_1 = require("./resources/webhooks.js");
|
|
18
|
+
const data_sources_js_1 = require("./resources/data-sources.js");
|
|
19
|
+
const version_js_1 = require("./version.js");
|
|
20
|
+
/**
|
|
21
|
+
* Official Node.js client for Oil Price API
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* import { OilPriceAPI } from 'oilpriceapi';
|
|
26
|
+
*
|
|
27
|
+
* const client = new OilPriceAPI({
|
|
28
|
+
* apiKey: 'your_api_key_here',
|
|
29
|
+
* retries: 3,
|
|
30
|
+
* timeout: 30000
|
|
31
|
+
* });
|
|
32
|
+
*
|
|
33
|
+
* // Get latest prices
|
|
34
|
+
* const prices = await client.getLatestPrices();
|
|
35
|
+
*
|
|
36
|
+
* // Get WTI price only
|
|
37
|
+
* const wti = await client.getLatestPrices({ commodity: 'WTI_USD' });
|
|
38
|
+
*
|
|
39
|
+
* // Get historical data
|
|
40
|
+
* const historical = await client.getHistoricalPrices({
|
|
41
|
+
* period: 'past_week',
|
|
42
|
+
* commodity: 'BRENT_CRUDE_USD'
|
|
43
|
+
* });
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
class OilPriceAPI {
|
|
47
|
+
constructor(config = {}) {
|
|
48
|
+
this.apiKey = config.apiKey || process.env.OILPRICEAPI_KEY || "";
|
|
49
|
+
if (!this.apiKey) {
|
|
50
|
+
throw new errors_js_1.OilPriceAPIError("API key required. Set OILPRICEAPI_KEY env var or pass apiKey in config.");
|
|
51
|
+
}
|
|
52
|
+
this.baseUrl = config.baseUrl || "https://api.oilpriceapi.com";
|
|
53
|
+
this.retries = config.retries !== undefined ? config.retries : 3;
|
|
54
|
+
this.retryDelay = config.retryDelay || 1000;
|
|
55
|
+
this.retryStrategy = config.retryStrategy || "exponential";
|
|
56
|
+
this.timeout = config.timeout || 90000; // 90 seconds for slow historical queries
|
|
57
|
+
this.debug = config.debug || false;
|
|
58
|
+
this.appUrl = config.appUrl;
|
|
59
|
+
this.appName = config.appName;
|
|
60
|
+
// Initialize resources
|
|
61
|
+
this.diesel = new diesel_js_1.DieselResource(this);
|
|
62
|
+
this.alerts = new alerts_js_1.AlertsResource(this);
|
|
63
|
+
this.commodities = new commodities_js_1.CommoditiesResource(this);
|
|
64
|
+
this.futures = new futures_js_1.FuturesResource(this);
|
|
65
|
+
this.storage = new storage_js_1.StorageResource(this);
|
|
66
|
+
this.rigCounts = new rig_counts_js_1.RigCountsResource(this);
|
|
67
|
+
this.bunkerFuels = new bunker_fuels_js_1.BunkerFuelsResource(this);
|
|
68
|
+
this.analytics = new analytics_js_1.AnalyticsResource(this);
|
|
69
|
+
this.forecasts = new forecasts_js_1.ForecastsResource(this);
|
|
70
|
+
this.dataQuality = new data_quality_js_1.DataQualityResource(this);
|
|
71
|
+
this.drilling = new drilling_js_1.DrillingIntelligenceResource(this);
|
|
72
|
+
this.ei = new index_js_1.EnergyIntelligenceResource(this);
|
|
73
|
+
this.webhooks = new webhooks_js_1.WebhooksResource(this);
|
|
74
|
+
this.dataSources = new data_sources_js_1.DataSourcesResource(this);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Log debug messages if debug mode is enabled
|
|
78
|
+
*/
|
|
79
|
+
log(message, data) {
|
|
80
|
+
if (this.debug) {
|
|
81
|
+
const timestamp = new Date().toISOString();
|
|
82
|
+
console.log(`[OilPriceAPI ${timestamp}] ${message}`, data || "");
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Calculate delay for retry based on strategy
|
|
87
|
+
*/
|
|
88
|
+
calculateRetryDelay(attempt) {
|
|
89
|
+
switch (this.retryStrategy) {
|
|
90
|
+
case "exponential":
|
|
91
|
+
return this.retryDelay * Math.pow(2, attempt);
|
|
92
|
+
case "linear":
|
|
93
|
+
return this.retryDelay * (attempt + 1);
|
|
94
|
+
case "fixed":
|
|
95
|
+
default:
|
|
96
|
+
return this.retryDelay;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Sleep for specified milliseconds
|
|
101
|
+
*/
|
|
102
|
+
sleep(ms) {
|
|
103
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Determine if error is retryable
|
|
107
|
+
*/
|
|
108
|
+
isRetryable(error) {
|
|
109
|
+
// Retry on network errors
|
|
110
|
+
if (error instanceof TypeError && error.message.includes("fetch")) {
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
// Retry on timeout errors
|
|
114
|
+
if (error instanceof errors_js_1.TimeoutError) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
// Retry on 5xx server errors
|
|
118
|
+
if (error instanceof errors_js_1.ServerError) {
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
// Retry on rate limit errors (with delay)
|
|
122
|
+
if (error instanceof errors_js_1.RateLimitError) {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
// Don't retry on client errors (4xx except 429)
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Internal method to make HTTP requests with retry and timeout.
|
|
130
|
+
* Supports all HTTP methods (GET, POST, PATCH, DELETE) with consistent
|
|
131
|
+
* retry logic, timeout handling, and typed error responses.
|
|
132
|
+
*/
|
|
133
|
+
async request(endpoint, params, options) {
|
|
134
|
+
// Build URL with query parameters
|
|
135
|
+
const url = new URL(`${this.baseUrl}${endpoint}`);
|
|
136
|
+
if (params) {
|
|
137
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
138
|
+
if (value !== undefined && value !== null) {
|
|
139
|
+
url.searchParams.append(key, value);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
this.log(`Request: ${url.toString()}`);
|
|
144
|
+
let lastError = null;
|
|
145
|
+
// Retry loop
|
|
146
|
+
for (let attempt = 0; attempt <= this.retries; attempt++) {
|
|
147
|
+
try {
|
|
148
|
+
// Add retry info to logs
|
|
149
|
+
if (attempt > 0) {
|
|
150
|
+
this.log(`Retry attempt ${attempt}/${this.retries}`);
|
|
151
|
+
}
|
|
152
|
+
// Create abort controller for timeout
|
|
153
|
+
const controller = new AbortController();
|
|
154
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
155
|
+
try {
|
|
156
|
+
// Build headers with optional telemetry
|
|
157
|
+
const headers = {
|
|
158
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
159
|
+
"Content-Type": "application/json",
|
|
160
|
+
"User-Agent": (0, version_js_1.buildUserAgent)(),
|
|
161
|
+
"X-SDK-Name": version_js_1.SDK_NAME,
|
|
162
|
+
"X-SDK-Version": version_js_1.SDK_VERSION,
|
|
163
|
+
};
|
|
164
|
+
// Add optional telemetry headers (10% bonus for appUrl!)
|
|
165
|
+
if (this.appUrl) {
|
|
166
|
+
headers["X-App-URL"] = this.appUrl;
|
|
167
|
+
}
|
|
168
|
+
if (this.appName) {
|
|
169
|
+
headers["X-App-Name"] = this.appName;
|
|
170
|
+
}
|
|
171
|
+
const fetchOptions = {
|
|
172
|
+
method: options?.method || "GET",
|
|
173
|
+
headers,
|
|
174
|
+
signal: controller.signal,
|
|
175
|
+
};
|
|
176
|
+
if (options?.body !== undefined) {
|
|
177
|
+
fetchOptions.body = JSON.stringify(options.body);
|
|
178
|
+
}
|
|
179
|
+
const response = await fetch(url.toString(), fetchOptions);
|
|
180
|
+
clearTimeout(timeoutId);
|
|
181
|
+
this.log(`Response: ${response.status} ${response.statusText}`);
|
|
182
|
+
// Handle error responses
|
|
183
|
+
if (!response.ok) {
|
|
184
|
+
const errorBody = await response.text();
|
|
185
|
+
let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
|
|
186
|
+
// Try to parse JSON error response
|
|
187
|
+
try {
|
|
188
|
+
const errorJson = JSON.parse(errorBody);
|
|
189
|
+
errorMessage = errorJson.message || errorJson.error || errorMessage;
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
// Use default error message if response isn't JSON
|
|
193
|
+
}
|
|
194
|
+
this.log(`Error response: ${errorMessage}`);
|
|
195
|
+
// Throw specific error types based on status code
|
|
196
|
+
switch (response.status) {
|
|
197
|
+
case 401:
|
|
198
|
+
throw new errors_js_1.AuthenticationError(errorMessage);
|
|
199
|
+
case 404:
|
|
200
|
+
throw new errors_js_1.NotFoundError(errorMessage);
|
|
201
|
+
case 429:
|
|
202
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
203
|
+
const rateLimitError = new errors_js_1.RateLimitError(errorMessage, retryAfter ? parseInt(retryAfter, 10) : undefined);
|
|
204
|
+
// If rate limited and we have retries left, wait and retry
|
|
205
|
+
if (attempt < this.retries && rateLimitError.retryAfter) {
|
|
206
|
+
this.log(`Rate limited. Waiting ${rateLimitError.retryAfter}s`);
|
|
207
|
+
await this.sleep(rateLimitError.retryAfter * 1000);
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
throw rateLimitError;
|
|
211
|
+
case 500:
|
|
212
|
+
case 502:
|
|
213
|
+
case 503:
|
|
214
|
+
case 504:
|
|
215
|
+
throw new errors_js_1.ServerError(errorMessage, response.status);
|
|
216
|
+
default:
|
|
217
|
+
throw new errors_js_1.OilPriceAPIError(errorMessage, response.status, "HTTP_ERROR");
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// Handle empty responses (e.g., 204 No Content from DELETE)
|
|
221
|
+
const responseText = await response.text();
|
|
222
|
+
if (!responseText) {
|
|
223
|
+
this.log("Empty response body");
|
|
224
|
+
return {};
|
|
225
|
+
}
|
|
226
|
+
// Parse successful response
|
|
227
|
+
const responseData = JSON.parse(responseText);
|
|
228
|
+
this.log("Response data received", {
|
|
229
|
+
status: responseData.status,
|
|
230
|
+
hasData: !!responseData.data,
|
|
231
|
+
});
|
|
232
|
+
// Handle different response structures
|
|
233
|
+
// Latest endpoint: { status, data: { price, ... } }
|
|
234
|
+
// Historical endpoint: { status, data: { prices: [...] } }
|
|
235
|
+
if (responseData.status === "success" && responseData.data) {
|
|
236
|
+
if (responseData.data.prices) {
|
|
237
|
+
// Historical endpoint - return prices array
|
|
238
|
+
this.log(`Returning ${responseData.data.prices.length} prices`);
|
|
239
|
+
return responseData.data.prices;
|
|
240
|
+
}
|
|
241
|
+
else if (responseData.data.price !== undefined) {
|
|
242
|
+
// Latest endpoint - wrap single price in array
|
|
243
|
+
this.log("Returning single price (wrapped in array)");
|
|
244
|
+
return [responseData.data];
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
// Fallback - return data as-is (used by resource mutations, alerts, webhooks, etc.)
|
|
248
|
+
this.log("Returning data as-is");
|
|
249
|
+
return (responseData.data !== undefined ? responseData.data : responseData);
|
|
250
|
+
}
|
|
251
|
+
catch (error) {
|
|
252
|
+
// Handle abort (timeout)
|
|
253
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
254
|
+
throw new errors_js_1.TimeoutError("Request timeout", this.timeout);
|
|
255
|
+
}
|
|
256
|
+
throw error;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
catch (error) {
|
|
260
|
+
lastError = error;
|
|
261
|
+
this.log(`Request failed: ${lastError.message}`, {
|
|
262
|
+
attempt,
|
|
263
|
+
retryable: this.isRetryable(lastError),
|
|
264
|
+
});
|
|
265
|
+
// Re-throw our custom errors if not retryable
|
|
266
|
+
if (error instanceof errors_js_1.OilPriceAPIError && !this.isRetryable(error)) {
|
|
267
|
+
throw error;
|
|
268
|
+
}
|
|
269
|
+
// If this was our last attempt, throw the error
|
|
270
|
+
if (attempt === this.retries) {
|
|
271
|
+
if (error instanceof errors_js_1.OilPriceAPIError) {
|
|
272
|
+
throw error;
|
|
273
|
+
}
|
|
274
|
+
// Wrap fetch errors (network issues, etc.)
|
|
275
|
+
if (error instanceof Error) {
|
|
276
|
+
throw new errors_js_1.OilPriceAPIError(`Request failed after ${this.retries + 1} attempts: ${error.message}`, undefined, "NETWORK_ERROR");
|
|
277
|
+
}
|
|
278
|
+
throw error;
|
|
279
|
+
}
|
|
280
|
+
// Calculate delay and retry
|
|
281
|
+
const delay = this.calculateRetryDelay(attempt);
|
|
282
|
+
this.log(`Waiting ${delay}ms before retry...`);
|
|
283
|
+
await this.sleep(delay);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
// This should never be reached, but TypeScript wants it
|
|
287
|
+
throw lastError || new errors_js_1.OilPriceAPIError("Unknown error occurred");
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Get the latest prices for all commodities or a specific commodity
|
|
291
|
+
*
|
|
292
|
+
* @param options - Optional filters
|
|
293
|
+
* @returns Array of price objects
|
|
294
|
+
*
|
|
295
|
+
* @example
|
|
296
|
+
* ```typescript
|
|
297
|
+
* // Get all latest prices
|
|
298
|
+
* const allPrices = await client.getLatestPrices();
|
|
299
|
+
*
|
|
300
|
+
* // Get WTI price only
|
|
301
|
+
* const wti = await client.getLatestPrices({ commodity: 'WTI_USD' });
|
|
302
|
+
* ```
|
|
303
|
+
*/
|
|
304
|
+
async getLatestPrices(options) {
|
|
305
|
+
const params = {};
|
|
306
|
+
if (options?.commodity) {
|
|
307
|
+
params.by_code = options.commodity;
|
|
308
|
+
}
|
|
309
|
+
return this.request("/v1/prices/latest", params);
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Get historical prices for a time period
|
|
313
|
+
*
|
|
314
|
+
* @param options - Time period and filter options
|
|
315
|
+
* @returns Array of historical price objects
|
|
316
|
+
*
|
|
317
|
+
* @example
|
|
318
|
+
* ```typescript
|
|
319
|
+
* // Get past week of WTI prices
|
|
320
|
+
* const weekPrices = await client.getHistoricalPrices({
|
|
321
|
+
* period: 'past_week',
|
|
322
|
+
* commodity: 'WTI_USD'
|
|
323
|
+
* });
|
|
324
|
+
*
|
|
325
|
+
* // Get custom date range
|
|
326
|
+
* const customPrices = await client.getHistoricalPrices({
|
|
327
|
+
* startDate: '2024-01-01',
|
|
328
|
+
* endDate: '2024-12-31',
|
|
329
|
+
* commodity: 'BRENT_CRUDE_USD'
|
|
330
|
+
* });
|
|
331
|
+
* ```
|
|
332
|
+
*/
|
|
333
|
+
async getHistoricalPrices(options) {
|
|
334
|
+
const params = {};
|
|
335
|
+
if (options?.period) {
|
|
336
|
+
params.period = options.period;
|
|
337
|
+
}
|
|
338
|
+
if (options?.commodity) {
|
|
339
|
+
params.by_code = options.commodity;
|
|
340
|
+
}
|
|
341
|
+
if (options?.startDate) {
|
|
342
|
+
params.start_date = options.startDate;
|
|
343
|
+
}
|
|
344
|
+
if (options?.endDate) {
|
|
345
|
+
params.end_date = options.endDate;
|
|
346
|
+
}
|
|
347
|
+
// PERFORMANCE FIX (December 24, 2025):
|
|
348
|
+
// Pass interval parameter to enable aggregated queries
|
|
349
|
+
// This reduces response times from 74s to <1s for year-long queries
|
|
350
|
+
// by returning 365 daily points instead of 600k+ raw points
|
|
351
|
+
if (options?.interval) {
|
|
352
|
+
params.interval = options.interval;
|
|
353
|
+
}
|
|
354
|
+
// Pagination parameters
|
|
355
|
+
if (options?.perPage !== undefined) {
|
|
356
|
+
params.per_page = options.perPage.toString();
|
|
357
|
+
}
|
|
358
|
+
if (options?.page !== undefined) {
|
|
359
|
+
params.page = options.page.toString();
|
|
360
|
+
}
|
|
361
|
+
// CRITICAL FIX (December 17, 2025):
|
|
362
|
+
// Use /v1/prices/past_year endpoint instead of /v1/prices
|
|
363
|
+
// The /v1/prices endpoint does NOT correctly handle start_date/end_date parameters
|
|
364
|
+
// This was the same bug that affected the Python SDK (fixed in v1.4.4)
|
|
365
|
+
// Issue: SDK was returning wrong dates for historical queries
|
|
366
|
+
// Root Cause: Backend has_scope :by_period not working on /v1/prices
|
|
367
|
+
// Solution: Use /v1/prices/past_year which uses direct WHERE clauses
|
|
368
|
+
return this.request("/v1/prices/past_year", params);
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Paginate through historical prices automatically.
|
|
372
|
+
*
|
|
373
|
+
* Returns an async generator that yields pages of prices, fetching
|
|
374
|
+
* the next page only when needed. Avoids loading all data into memory.
|
|
375
|
+
*
|
|
376
|
+
* @param options - Same options as getHistoricalPrices, plus perPage (default: 100)
|
|
377
|
+
*
|
|
378
|
+
* @example
|
|
379
|
+
* ```typescript
|
|
380
|
+
* // Iterate through all pages
|
|
381
|
+
* for await (const page of client.paginateHistoricalPrices({
|
|
382
|
+
* commodity: 'BRENT_CRUDE_USD',
|
|
383
|
+
* startDate: '2024-01-01',
|
|
384
|
+
* endDate: '2024-12-31',
|
|
385
|
+
* perPage: 100,
|
|
386
|
+
* })) {
|
|
387
|
+
* console.log(`Got ${page.length} prices`);
|
|
388
|
+
* // Process each page...
|
|
389
|
+
* }
|
|
390
|
+
*
|
|
391
|
+
* // Or collect all prices
|
|
392
|
+
* const allPrices: Price[] = [];
|
|
393
|
+
* for await (const page of client.paginateHistoricalPrices({ commodity: 'WTI_USD' })) {
|
|
394
|
+
* allPrices.push(...page);
|
|
395
|
+
* }
|
|
396
|
+
* ```
|
|
397
|
+
*/
|
|
398
|
+
async *paginateHistoricalPrices(options) {
|
|
399
|
+
const perPage = options?.perPage || 100;
|
|
400
|
+
let page = 1;
|
|
401
|
+
while (true) {
|
|
402
|
+
const results = await this.getHistoricalPrices({
|
|
403
|
+
...options,
|
|
404
|
+
page,
|
|
405
|
+
perPage,
|
|
406
|
+
});
|
|
407
|
+
if (results.length === 0)
|
|
408
|
+
break;
|
|
409
|
+
yield results;
|
|
410
|
+
if (results.length < perPage)
|
|
411
|
+
break;
|
|
412
|
+
page++;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Get prices from your connected data sources (BYOS)
|
|
417
|
+
*
|
|
418
|
+
* Requires Data Connector feature enabled on your organization.
|
|
419
|
+
*
|
|
420
|
+
* @example
|
|
421
|
+
* ```typescript
|
|
422
|
+
* // Get all connected prices
|
|
423
|
+
* const prices = await client.getDataConnectorPrices();
|
|
424
|
+
*
|
|
425
|
+
* // Filter by fuel type
|
|
426
|
+
* const vlsfo = await client.getDataConnectorPrices({ fuelType: 'VLSFO' });
|
|
427
|
+
*
|
|
428
|
+
* // Filter by port
|
|
429
|
+
* const singapore = await client.getDataConnectorPrices({ port: 'SINGAPORE' });
|
|
430
|
+
* ```
|
|
431
|
+
*/
|
|
432
|
+
async getDataConnectorPrices(options = {}) {
|
|
433
|
+
const params = {};
|
|
434
|
+
if (options.fuelType)
|
|
435
|
+
params.fuel_type = options.fuelType;
|
|
436
|
+
if (options.port)
|
|
437
|
+
params.port = options.port;
|
|
438
|
+
if (options.region)
|
|
439
|
+
params.region = options.region;
|
|
440
|
+
if (options.since)
|
|
441
|
+
params.since = options.since;
|
|
442
|
+
const response = await this.request("/v1/prices/data-connector", params);
|
|
443
|
+
return response.prices;
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Get metadata for all supported commodities
|
|
447
|
+
*
|
|
448
|
+
* @returns Object containing array of commodities
|
|
449
|
+
*
|
|
450
|
+
* @example
|
|
451
|
+
* ```typescript
|
|
452
|
+
* const response = await client.getCommodities();
|
|
453
|
+
* console.log(response.commodities); // Array of commodity objects
|
|
454
|
+
* ```
|
|
455
|
+
*/
|
|
456
|
+
async getCommodities() {
|
|
457
|
+
return this.request("/v1/commodities", {});
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Get all commodity categories with their commodities
|
|
461
|
+
*
|
|
462
|
+
* @returns Object with category keys mapped to category objects
|
|
463
|
+
*
|
|
464
|
+
* @example
|
|
465
|
+
* ```typescript
|
|
466
|
+
* const categories = await client.getCommodityCategories();
|
|
467
|
+
* console.log(categories.oil.name); // "Oil"
|
|
468
|
+
* console.log(categories.oil.commodities.length); // 11
|
|
469
|
+
* ```
|
|
470
|
+
*/
|
|
471
|
+
async getCommodityCategories() {
|
|
472
|
+
return this.request("/v1/commodities/categories", {});
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Get metadata for a specific commodity by code
|
|
476
|
+
*
|
|
477
|
+
* @param code - Commodity code (e.g., "WTI_USD", "BRENT_CRUDE_USD")
|
|
478
|
+
* @returns Commodity metadata object
|
|
479
|
+
*
|
|
480
|
+
* @example
|
|
481
|
+
* ```typescript
|
|
482
|
+
* const commodity = await client.getCommodity('WTI_USD');
|
|
483
|
+
* console.log(commodity.name); // "WTI Crude Oil"
|
|
484
|
+
* ```
|
|
485
|
+
*/
|
|
486
|
+
async getCommodity(code) {
|
|
487
|
+
return this.request(`/v1/commodities/${code}`, {});
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
exports.OilPriceAPI = OilPriceAPI;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TimeoutError = exports.ValidationError = exports.ServerError = exports.NotFoundError = exports.RateLimitError = exports.AuthenticationError = exports.OilPriceAPIError = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Base error class for all Oil Price API errors
|
|
6
|
+
*/
|
|
7
|
+
class OilPriceAPIError extends Error {
|
|
8
|
+
constructor(message, statusCode, code) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "OilPriceAPIError";
|
|
11
|
+
this.statusCode = statusCode;
|
|
12
|
+
this.code = code;
|
|
13
|
+
// Maintains proper stack trace for where our error was thrown (only available on V8)
|
|
14
|
+
if (Error.captureStackTrace) {
|
|
15
|
+
Error.captureStackTrace(this, this.constructor);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.OilPriceAPIError = OilPriceAPIError;
|
|
20
|
+
/**
|
|
21
|
+
* Thrown when API authentication fails (401)
|
|
22
|
+
*/
|
|
23
|
+
class AuthenticationError extends OilPriceAPIError {
|
|
24
|
+
constructor(message = "Invalid API key") {
|
|
25
|
+
super(message, 401, "AUTHENTICATION_ERROR");
|
|
26
|
+
this.name = "AuthenticationError";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.AuthenticationError = AuthenticationError;
|
|
30
|
+
/**
|
|
31
|
+
* Thrown when rate limit is exceeded (429)
|
|
32
|
+
*/
|
|
33
|
+
class RateLimitError extends OilPriceAPIError {
|
|
34
|
+
constructor(message = "Rate limit exceeded", retryAfter) {
|
|
35
|
+
super(message, 429, "RATE_LIMIT_ERROR");
|
|
36
|
+
this.name = "RateLimitError";
|
|
37
|
+
this.retryAfter = retryAfter;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.RateLimitError = RateLimitError;
|
|
41
|
+
/**
|
|
42
|
+
* Thrown when requested resource is not found (404)
|
|
43
|
+
*/
|
|
44
|
+
class NotFoundError extends OilPriceAPIError {
|
|
45
|
+
constructor(message = "Resource not found") {
|
|
46
|
+
super(message, 404, "NOT_FOUND_ERROR");
|
|
47
|
+
this.name = "NotFoundError";
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
exports.NotFoundError = NotFoundError;
|
|
51
|
+
/**
|
|
52
|
+
* Thrown when server returns 5xx error
|
|
53
|
+
*/
|
|
54
|
+
class ServerError extends OilPriceAPIError {
|
|
55
|
+
constructor(message = "Internal server error", statusCode = 500) {
|
|
56
|
+
super(message, statusCode, "SERVER_ERROR");
|
|
57
|
+
this.name = "ServerError";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
exports.ServerError = ServerError;
|
|
61
|
+
/**
|
|
62
|
+
* Thrown when SDK-side input validation fails
|
|
63
|
+
*/
|
|
64
|
+
class ValidationError extends OilPriceAPIError {
|
|
65
|
+
constructor(message) {
|
|
66
|
+
super(message, undefined, "VALIDATION_ERROR");
|
|
67
|
+
this.name = "ValidationError";
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.ValidationError = ValidationError;
|
|
71
|
+
/**
|
|
72
|
+
* Thrown when request exceeds timeout
|
|
73
|
+
*/
|
|
74
|
+
class TimeoutError extends OilPriceAPIError {
|
|
75
|
+
constructor(message = "Request timeout", timeout) {
|
|
76
|
+
super(`${message} (${timeout}ms)`, undefined, "TIMEOUT_ERROR");
|
|
77
|
+
this.name = "TimeoutError";
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
exports.TimeoutError = TimeoutError;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Official Node.js SDK for Oil Price API
|
|
4
|
+
*
|
|
5
|
+
* Get real-time and historical oil & commodity prices in your Node.js applications.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.DataSourcesResource = exports.WebhooksResource = exports.EIFracFocusResource = exports.EIWellPermitsResource = exports.EIForecastsResource = exports.EIDrillingProductivityResource = exports.EIOPECProductionResource = exports.EIOilInventoriesResource = exports.EIRigCountsResource = exports.EnergyIntelligenceResource = exports.DrillingIntelligenceResource = exports.DataQualityResource = exports.ForecastsResource = exports.AnalyticsResource = exports.BunkerFuelsResource = exports.RigCountsResource = exports.StorageResource = exports.FuturesResource = exports.CommoditiesResource = exports.AlertsResource = exports.DieselResource = exports.TimeoutError = exports.ValidationError = exports.ServerError = exports.NotFoundError = exports.RateLimitError = exports.AuthenticationError = exports.OilPriceAPIError = exports.SDK_NAME = exports.SDK_VERSION = exports.OilPriceAPI = void 0;
|
|
11
|
+
exports.verifyWebhookSignature = verifyWebhookSignature;
|
|
12
|
+
const node_crypto_1 = require("node:crypto");
|
|
13
|
+
var client_js_1 = require("./client.js");
|
|
14
|
+
Object.defineProperty(exports, "OilPriceAPI", { enumerable: true, get: function () { return client_js_1.OilPriceAPI; } });
|
|
15
|
+
var version_js_1 = require("./version.js");
|
|
16
|
+
Object.defineProperty(exports, "SDK_VERSION", { enumerable: true, get: function () { return version_js_1.SDK_VERSION; } });
|
|
17
|
+
Object.defineProperty(exports, "SDK_NAME", { enumerable: true, get: function () { return version_js_1.SDK_NAME; } });
|
|
18
|
+
var errors_js_1 = require("./errors.js");
|
|
19
|
+
Object.defineProperty(exports, "OilPriceAPIError", { enumerable: true, get: function () { return errors_js_1.OilPriceAPIError; } });
|
|
20
|
+
Object.defineProperty(exports, "AuthenticationError", { enumerable: true, get: function () { return errors_js_1.AuthenticationError; } });
|
|
21
|
+
Object.defineProperty(exports, "RateLimitError", { enumerable: true, get: function () { return errors_js_1.RateLimitError; } });
|
|
22
|
+
Object.defineProperty(exports, "NotFoundError", { enumerable: true, get: function () { return errors_js_1.NotFoundError; } });
|
|
23
|
+
Object.defineProperty(exports, "ServerError", { enumerable: true, get: function () { return errors_js_1.ServerError; } });
|
|
24
|
+
Object.defineProperty(exports, "ValidationError", { enumerable: true, get: function () { return errors_js_1.ValidationError; } });
|
|
25
|
+
Object.defineProperty(exports, "TimeoutError", { enumerable: true, get: function () { return errors_js_1.TimeoutError; } });
|
|
26
|
+
var diesel_js_1 = require("./resources/diesel.js");
|
|
27
|
+
Object.defineProperty(exports, "DieselResource", { enumerable: true, get: function () { return diesel_js_1.DieselResource; } });
|
|
28
|
+
var alerts_js_1 = require("./resources/alerts.js");
|
|
29
|
+
Object.defineProperty(exports, "AlertsResource", { enumerable: true, get: function () { return alerts_js_1.AlertsResource; } });
|
|
30
|
+
var commodities_js_1 = require("./resources/commodities.js");
|
|
31
|
+
Object.defineProperty(exports, "CommoditiesResource", { enumerable: true, get: function () { return commodities_js_1.CommoditiesResource; } });
|
|
32
|
+
var futures_js_1 = require("./resources/futures.js");
|
|
33
|
+
Object.defineProperty(exports, "FuturesResource", { enumerable: true, get: function () { return futures_js_1.FuturesResource; } });
|
|
34
|
+
var storage_js_1 = require("./resources/storage.js");
|
|
35
|
+
Object.defineProperty(exports, "StorageResource", { enumerable: true, get: function () { return storage_js_1.StorageResource; } });
|
|
36
|
+
var rig_counts_js_1 = require("./resources/rig-counts.js");
|
|
37
|
+
Object.defineProperty(exports, "RigCountsResource", { enumerable: true, get: function () { return rig_counts_js_1.RigCountsResource; } });
|
|
38
|
+
var bunker_fuels_js_1 = require("./resources/bunker-fuels.js");
|
|
39
|
+
Object.defineProperty(exports, "BunkerFuelsResource", { enumerable: true, get: function () { return bunker_fuels_js_1.BunkerFuelsResource; } });
|
|
40
|
+
var analytics_js_1 = require("./resources/analytics.js");
|
|
41
|
+
Object.defineProperty(exports, "AnalyticsResource", { enumerable: true, get: function () { return analytics_js_1.AnalyticsResource; } });
|
|
42
|
+
var forecasts_js_1 = require("./resources/forecasts.js");
|
|
43
|
+
Object.defineProperty(exports, "ForecastsResource", { enumerable: true, get: function () { return forecasts_js_1.ForecastsResource; } });
|
|
44
|
+
var data_quality_js_1 = require("./resources/data-quality.js");
|
|
45
|
+
Object.defineProperty(exports, "DataQualityResource", { enumerable: true, get: function () { return data_quality_js_1.DataQualityResource; } });
|
|
46
|
+
var drilling_js_1 = require("./resources/drilling.js");
|
|
47
|
+
Object.defineProperty(exports, "DrillingIntelligenceResource", { enumerable: true, get: function () { return drilling_js_1.DrillingIntelligenceResource; } });
|
|
48
|
+
var index_js_1 = require("./resources/ei/index.js");
|
|
49
|
+
Object.defineProperty(exports, "EnergyIntelligenceResource", { enumerable: true, get: function () { return index_js_1.EnergyIntelligenceResource; } });
|
|
50
|
+
Object.defineProperty(exports, "EIRigCountsResource", { enumerable: true, get: function () { return index_js_1.EIRigCountsResource; } });
|
|
51
|
+
Object.defineProperty(exports, "EIOilInventoriesResource", { enumerable: true, get: function () { return index_js_1.EIOilInventoriesResource; } });
|
|
52
|
+
Object.defineProperty(exports, "EIOPECProductionResource", { enumerable: true, get: function () { return index_js_1.EIOPECProductionResource; } });
|
|
53
|
+
Object.defineProperty(exports, "EIDrillingProductivityResource", { enumerable: true, get: function () { return index_js_1.EIDrillingProductivityResource; } });
|
|
54
|
+
Object.defineProperty(exports, "EIForecastsResource", { enumerable: true, get: function () { return index_js_1.EIForecastsResource; } });
|
|
55
|
+
Object.defineProperty(exports, "EIWellPermitsResource", { enumerable: true, get: function () { return index_js_1.EIWellPermitsResource; } });
|
|
56
|
+
Object.defineProperty(exports, "EIFracFocusResource", { enumerable: true, get: function () { return index_js_1.EIFracFocusResource; } });
|
|
57
|
+
var webhooks_js_1 = require("./resources/webhooks.js");
|
|
58
|
+
Object.defineProperty(exports, "WebhooksResource", { enumerable: true, get: function () { return webhooks_js_1.WebhooksResource; } });
|
|
59
|
+
var data_sources_js_1 = require("./resources/data-sources.js");
|
|
60
|
+
Object.defineProperty(exports, "DataSourcesResource", { enumerable: true, get: function () { return data_sources_js_1.DataSourcesResource; } });
|
|
61
|
+
/**
|
|
62
|
+
* Standalone webhook signature verification.
|
|
63
|
+
*
|
|
64
|
+
* Convenience function for verifying webhook signatures without
|
|
65
|
+
* instantiating a full client.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* import { verifyWebhookSignature } from 'oilpriceapi';
|
|
70
|
+
*
|
|
71
|
+
* const isValid = verifyWebhookSignature(rawBody, signatureHeader, secret);
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
function verifyWebhookSignature(payload, signature, secret) {
|
|
75
|
+
const expectedSignature = "sha256=" + (0, node_crypto_1.createHmac)("sha256", secret).update(payload).digest("hex");
|
|
76
|
+
try {
|
|
77
|
+
return (0, node_crypto_1.timingSafeEqual)(Buffer.from(expectedSignature), Buffer.from(signature));
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"commonjs"}
|