oilpriceapi 0.8.2 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +201 -19
  2. package/dist/cjs/client.js +139 -19
  3. package/dist/cjs/index.js +17 -3
  4. package/dist/cjs/resources/analytics.js +99 -137
  5. package/dist/cjs/resources/bunker-fuels.js +37 -23
  6. package/dist/cjs/resources/data-sources.js +13 -12
  7. package/dist/cjs/resources/ei/frac-focus.js +16 -6
  8. package/dist/cjs/resources/ei/well-permits.js +18 -6
  9. package/dist/cjs/resources/forecasts.js +11 -5
  10. package/dist/cjs/resources/futures.js +244 -16
  11. package/dist/cjs/resources/indicators.js +79 -0
  12. package/dist/cjs/resources/raw.js +128 -0
  13. package/dist/cjs/resources/rig-counts.js +5 -2
  14. package/dist/cjs/resources/spreads.js +105 -0
  15. package/dist/cjs/resources/storage.js +5 -5
  16. package/dist/cjs/resources/streaming.js +350 -0
  17. package/dist/cjs/resources/webhooks.js +3 -14
  18. package/dist/cjs/version.js +1 -1
  19. package/dist/client.d.ts +97 -1
  20. package/dist/client.js +139 -19
  21. package/dist/index.d.ts +12 -3
  22. package/dist/index.js +5 -0
  23. package/dist/resources/analytics.d.ts +147 -214
  24. package/dist/resources/analytics.js +99 -137
  25. package/dist/resources/bunker-fuels.d.ts +35 -12
  26. package/dist/resources/bunker-fuels.js +37 -23
  27. package/dist/resources/data-sources.d.ts +31 -31
  28. package/dist/resources/data-sources.js +13 -12
  29. package/dist/resources/ei/frac-focus.d.ts +23 -9
  30. package/dist/resources/ei/frac-focus.js +16 -6
  31. package/dist/resources/ei/well-permits.d.ts +25 -9
  32. package/dist/resources/ei/well-permits.js +18 -6
  33. package/dist/resources/forecasts.d.ts +4 -1
  34. package/dist/resources/forecasts.js +11 -5
  35. package/dist/resources/futures.d.ts +287 -33
  36. package/dist/resources/futures.js +241 -15
  37. package/dist/resources/indicators.d.ts +170 -0
  38. package/dist/resources/indicators.js +75 -0
  39. package/dist/resources/raw.d.ts +94 -0
  40. package/dist/resources/raw.js +124 -0
  41. package/dist/resources/rig-counts.js +5 -2
  42. package/dist/resources/spreads.d.ts +121 -0
  43. package/dist/resources/spreads.js +101 -0
  44. package/dist/resources/storage.d.ts +5 -4
  45. package/dist/resources/storage.js +5 -5
  46. package/dist/resources/streaming.d.ts +272 -0
  47. package/dist/resources/streaming.js +342 -0
  48. package/dist/resources/webhooks.d.ts +37 -23
  49. package/dist/resources/webhooks.js +3 -14
  50. package/dist/types.d.ts +41 -0
  51. package/dist/version.d.ts +1 -1
  52. package/dist/version.js +1 -1
  53. package/package.json +7 -1
@@ -6,8 +6,167 @@
6
6
  * OHLC, intraday, spreads, curves, and continuous contracts.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.FuturesResource = void 0;
9
+ exports.FuturesResource = exports.FuturesContractFamily = exports.FUTURES_FAMILY_SLUGS = exports.FUTURES_CONTRACTS = void 0;
10
+ exports.resolveFuturesFamilySlug = resolveFuturesFamilySlug;
10
11
  const errors_js_1 = require("../errors.js");
12
+ /**
13
+ * Ergonomic contract codes for the most-requested futures families (issue #1).
14
+ *
15
+ * Use with the generic {@link FuturesResource} methods, or use the typed
16
+ * {@link FuturesResource.family} helper for direct access to a family's
17
+ * endpoints.
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * import { FUTURES_CONTRACTS } from 'oilpriceapi';
22
+ *
23
+ * const brent = await client.futures.latest(FUTURES_CONTRACTS.BRENT); // "BZ"
24
+ * const gasoil = await client.futures.family('ice-gasoil').latest();
25
+ * ```
26
+ */
27
+ exports.FUTURES_CONTRACTS = {
28
+ /** ICE Brent crude */
29
+ BRENT: "BZ",
30
+ /** NYMEX WTI crude */
31
+ WTI: "CL",
32
+ /** ICE Gasoil */
33
+ GASOIL: "G",
34
+ /** Henry Hub natural gas */
35
+ NATURAL_GAS: "NG",
36
+ /** TTF natural gas (Europe) */
37
+ TTF_GAS: "TTF",
38
+ /** LNG JKM (Asia) */
39
+ LNG_JKM: "JKM",
40
+ /** EU carbon allowance */
41
+ EUA_CARBON: "EUA",
42
+ /** UK carbon allowance */
43
+ UK_CARBON: "UKA",
44
+ };
45
+ /**
46
+ * Mapping of ergonomic contract codes to their API contract-family slugs.
47
+ *
48
+ * Lets you resolve a contract code (e.g., `"BZ"`) to the `/v1/futures/{slug}`
49
+ * path segment used by the typed family helpers.
50
+ */
51
+ exports.FUTURES_FAMILY_SLUGS = {
52
+ [exports.FUTURES_CONTRACTS.BRENT]: "ice-brent", // BZ
53
+ [exports.FUTURES_CONTRACTS.WTI]: "ice-wti", // CL
54
+ [exports.FUTURES_CONTRACTS.GASOIL]: "ice-gasoil", // G
55
+ QS: "ice-gasoil", // ICE Gasoil also trades under the QS ticker prefix
56
+ [exports.FUTURES_CONTRACTS.NATURAL_GAS]: "natural-gas", // NG
57
+ [exports.FUTURES_CONTRACTS.TTF_GAS]: "ttf-gas", // TTF
58
+ [exports.FUTURES_CONTRACTS.LNG_JKM]: "lng-jkm", // JKM
59
+ [exports.FUTURES_CONTRACTS.EUA_CARBON]: "eua-carbon", // EUA
60
+ [exports.FUTURES_CONTRACTS.UK_CARBON]: "uk-carbon", // UKA
61
+ };
62
+ /**
63
+ * Resolve a futures contract code (e.g. `"BZ"`, `"QS"`) or an already-valid
64
+ * family slug (e.g. `"ice-brent"`) to its `/v1/futures/{slug}` path segment.
65
+ *
66
+ * Matching is case-insensitive for codes. Returns `null` if the input maps to
67
+ * neither a known code nor a known family slug.
68
+ */
69
+ function resolveFuturesFamilySlug(codeOrSlug) {
70
+ const trimmed = codeOrSlug.trim();
71
+ // Direct code match (case-insensitive — codes are upper-case).
72
+ const byCode = exports.FUTURES_FAMILY_SLUGS[trimmed.toUpperCase()];
73
+ if (byCode)
74
+ return byCode;
75
+ // Already a valid family slug?
76
+ const lower = trimmed.toLowerCase();
77
+ const isSlug = Object.values(exports.FUTURES_FAMILY_SLUGS).includes(lower);
78
+ return isSlug ? lower : null;
79
+ }
80
+ /**
81
+ * Typed helper for a single futures contract family (e.g., ICE Brent, Gasoil).
82
+ *
83
+ * Provides ergonomic access to the family's endpoints without having to
84
+ * remember the URL slug. Obtain an instance via {@link FuturesResource.family},
85
+ * {@link FuturesResource.brent}, {@link FuturesResource.gasoil}, etc.
86
+ *
87
+ * @example
88
+ * ```typescript
89
+ * const gasoil = client.futures.gasoil();
90
+ * const latest = await gasoil.latest();
91
+ * const curve = await gasoil.curve();
92
+ * ```
93
+ */
94
+ class FuturesContractFamily {
95
+ constructor(client,
96
+ /** The contract-family slug used in the API path. */
97
+ slug) {
98
+ this.client = client;
99
+ this.slug = slug;
100
+ }
101
+ /**
102
+ * Get the latest price for this contract family.
103
+ *
104
+ * Latest is served from the bare slug path `GET /v1/futures/{slug}` —
105
+ * there is NO `/latest` suffix (that path 404s).
106
+ */
107
+ async latest() {
108
+ return this.client["request"](`/v1/futures/${this.slug}`, {});
109
+ }
110
+ /**
111
+ * Get historical prices for this contract family.
112
+ *
113
+ * @param options - Optional date range filters.
114
+ */
115
+ async historical(options) {
116
+ const params = {};
117
+ if (options?.startDate)
118
+ params.from = options.startDate;
119
+ if (options?.endDate)
120
+ params.to = options.endDate;
121
+ if (options?.interval)
122
+ params.interval = options.interval;
123
+ if (options?.contracts)
124
+ params.contracts = options.contracts;
125
+ const response = await this.client["request"](`/v1/futures/${this.slug}/historical`, params);
126
+ return Array.isArray(response) ? response : response.prices;
127
+ }
128
+ /**
129
+ * Get OHLC data for this contract family.
130
+ *
131
+ * @param options - `{ days, contract, interval }` (the API has no `date` param here).
132
+ */
133
+ async ohlc(options) {
134
+ const params = {};
135
+ if (options?.days !== undefined)
136
+ params.days = options.days.toString();
137
+ if (options?.contract)
138
+ params.contract = options.contract;
139
+ if (options?.interval)
140
+ params.interval = options.interval;
141
+ return this.client["request"](`/v1/futures/${this.slug}/ohlc`, params);
142
+ }
143
+ /**
144
+ * Get intraday price data for this contract family.
145
+ */
146
+ async intraday() {
147
+ return this.client["request"](`/v1/futures/${this.slug}/intraday`, {});
148
+ }
149
+ /**
150
+ * Get the spreads for this contract family.
151
+ */
152
+ async spreads() {
153
+ const response = await this.client["request"](`/v1/futures/${this.slug}/spreads`, {});
154
+ return Array.isArray(response) ? response : response.data;
155
+ }
156
+ /**
157
+ * Get the forward curve for this contract family.
158
+ */
159
+ async curve() {
160
+ return this.client["request"](`/v1/futures/${this.slug}/curve`, {});
161
+ }
162
+ /**
163
+ * Get historical spread data for this contract family.
164
+ */
165
+ async spreadHistory() {
166
+ return this.client["request"](`/v1/futures/${this.slug}/spread-history`, {});
167
+ }
168
+ }
169
+ exports.FuturesContractFamily = FuturesContractFamily;
11
170
  /**
12
171
  * Futures Resource
13
172
  *
@@ -20,16 +179,13 @@ const errors_js_1 = require("../errors.js");
20
179
  *
21
180
  * const client = new OilPriceAPI({ apiKey: 'your_key' });
22
181
  *
23
- * // Get latest price
24
- * const latest = await client.futures.latest('CL.1');
182
+ * // Get the latest curve by contract code (resolves to GET /v1/futures/ice-wti)
183
+ * const latest = await client.futures.latest('CL');
25
184
  * console.log(`${latest.contract}: $${latest.price}`);
26
185
  *
27
- * // Get OHLC data
28
- * const ohlc = await client.futures.ohlc('CL.1', '2024-01-15');
29
- * console.log(`High: $${ohlc.high}, Low: $${ohlc.low}`);
30
- *
31
- * // Get futures curve
32
- * const curve = await client.futures.curve('CL');
186
+ * // Typed family helpers are the most ergonomic option:
187
+ * const brent = await client.futures.brent().latest();
188
+ * const curve = await client.futures.brent().curve();
33
189
  * curve.curve.forEach(point => {
34
190
  * console.log(`${point.months_out}mo: $${point.price}`);
35
191
  * });
@@ -40,25 +196,42 @@ class FuturesResource {
40
196
  this.client = client;
41
197
  }
42
198
  /**
43
- * Get latest price for a futures contract
199
+ * Get the latest curve/quote for a futures contract family.
44
200
  *
45
- * @param contract - Contract symbol (e.g., "CL.1", "BZ.2")
46
- * @returns Latest futures price data
201
+ * Accepts an ergonomic contract code (e.g. `"BZ"`, `"CL"`, `"QS"`) or a
202
+ * family slug (e.g. `"ice-brent"`). The code is resolved to its family slug
203
+ * and the request is sent to `GET /v1/futures/{slug}` — the bare slug path,
204
+ * with NO `/latest` suffix (the suffixed path 404s).
47
205
  *
48
- * @throws {NotFoundError} If contract not found
206
+ * Supported codes: BZ (Brent), CL (WTI), G/QS (Gasoil), NG (Natural Gas),
207
+ * TTF, JKM, EUA, UKA. Slugs: ice-brent, ice-wti, ice-gasoil, natural-gas,
208
+ * ttf-gas, lng-jkm, eua-carbon, uk-carbon.
209
+ *
210
+ * @param contract - Contract code (e.g. "BZ") or family slug (e.g. "ice-brent").
211
+ * @returns Latest futures price/curve data
212
+ *
213
+ * @throws {ValidationError} If the code/slug is empty or unrecognized.
49
214
  * @throws {OilPriceAPIError} If API request fails
50
215
  *
51
216
  * @example
52
217
  * ```typescript
53
- * const price = await client.futures.latest('CL.1');
54
- * console.log(`WTI Front Month: $${price.price}`);
218
+ * import { FUTURES_CONTRACTS } from 'oilpriceapi';
219
+ * const price = await client.futures.latest(FUTURES_CONTRACTS.BRENT); // "BZ"
220
+ * const wti = await client.futures.latest('ice-wti');
55
221
  * ```
56
222
  */
57
223
  async latest(contract) {
58
224
  if (!contract || typeof contract !== "string") {
59
225
  throw new errors_js_1.ValidationError("Contract symbol must be a non-empty string");
60
226
  }
61
- return this.client["request"](`/v1/futures/${contract}`, {});
227
+ const slug = resolveFuturesFamilySlug(contract);
228
+ if (!slug) {
229
+ throw new errors_js_1.ValidationError(`Unknown futures contract "${contract}". Use a contract code ` +
230
+ `(BZ, CL, G, QS, NG, TTF, JKM, EUA, UKA) or a family slug ` +
231
+ `(ice-brent, ice-wti, ice-gasoil, natural-gas, ttf-gas, lng-jkm, ` +
232
+ `eua-carbon, uk-carbon).`);
233
+ }
234
+ return this.client["request"](`/v1/futures/${slug}`, {});
62
235
  }
63
236
  /**
64
237
  * Get historical prices for a futures contract
@@ -229,5 +402,60 @@ class FuturesResource {
229
402
  params.months = months.toString();
230
403
  return this.client["request"](`/v1/futures/${contract}/continuous`, params);
231
404
  }
405
+ /**
406
+ * Get a typed helper for a specific contract family (issue #1).
407
+ *
408
+ * Provides ergonomic access to the ICE Brent / WTI / Gasoil and gas/carbon
409
+ * family endpoints (`/latest`, `/historical`, `/ohlc`, `/intraday`,
410
+ * `/spreads`, `/curve`, `/spread-history`) without remembering the URL slug.
411
+ *
412
+ * @param slug - Contract family slug (e.g., `"ice-brent"`, `"ice-gasoil"`).
413
+ * @returns A {@link FuturesContractFamily} bound to the slug.
414
+ *
415
+ * @example
416
+ * ```typescript
417
+ * const brent = client.futures.family('ice-brent');
418
+ * const latest = await brent.latest();
419
+ * const curve = await brent.curve();
420
+ * ```
421
+ */
422
+ family(slug) {
423
+ if (!slug || typeof slug !== "string") {
424
+ throw new errors_js_1.ValidationError("Contract family slug must be a non-empty string");
425
+ }
426
+ return new FuturesContractFamily(this.client, slug);
427
+ }
428
+ /** ICE Brent crude futures family helper (issue #1). */
429
+ brent() {
430
+ return this.family("ice-brent");
431
+ }
432
+ /** ICE WTI crude futures family helper. */
433
+ wti() {
434
+ return this.family("ice-wti");
435
+ }
436
+ /** ICE Gasoil futures family helper (issue #1). */
437
+ gasoil() {
438
+ return this.family("ice-gasoil");
439
+ }
440
+ /** Henry Hub natural gas futures family helper. */
441
+ naturalGas() {
442
+ return this.family("natural-gas");
443
+ }
444
+ /** TTF natural gas (Europe) futures family helper. */
445
+ ttfGas() {
446
+ return this.family("ttf-gas");
447
+ }
448
+ /** LNG JKM (Asia) futures family helper. */
449
+ lngJkm() {
450
+ return this.family("lng-jkm");
451
+ }
452
+ /** EU carbon allowance (EUA) futures family helper. */
453
+ euaCarbon() {
454
+ return this.family("eua-carbon");
455
+ }
456
+ /** UK carbon allowance (UKA) futures family helper. */
457
+ ukCarbon() {
458
+ return this.family("uk-carbon");
459
+ }
232
460
  }
233
461
  exports.FuturesResource = FuturesResource;
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ /**
3
+ * Indicators Resource
4
+ *
5
+ * Access derived market indicators and signals: fuel-switching economics,
6
+ * price context, storage analytics, market annotations, CFTC positioning, and
7
+ * congressional energy-sector trades.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.IndicatorsResource = void 0;
11
+ const errors_js_1 = require("../errors.js");
12
+ /**
13
+ * Indicators Resource
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * import { OilPriceAPI } from 'oilpriceapi';
18
+ *
19
+ * const client = new OilPriceAPI({ apiKey: 'your_key' });
20
+ *
21
+ * // Fuel-switching economics
22
+ * const fs = await client.indicators.fuelSwitching();
23
+ * console.log(`Switching economical: ${fs.economical}`);
24
+ *
25
+ * // CFTC positioning
26
+ * const cftc = await client.indicators.cftcPositioning();
27
+ * cftc.forEach(p => console.log(`${p.market}: net ${p.net_position}`));
28
+ *
29
+ * // Congressional trades
30
+ * const trades = await client.indicators.congressionalTrades();
31
+ * ```
32
+ */
33
+ class IndicatorsResource {
34
+ constructor(client) {
35
+ this.client = client;
36
+ }
37
+ /**
38
+ * Get an arbitrary indicator by type.
39
+ *
40
+ * @typeParam T - Expected response type.
41
+ * @param type - Indicator type slug.
42
+ * @returns The indicator data.
43
+ * @throws {ValidationError} If the type is invalid.
44
+ */
45
+ async get(type) {
46
+ if (!type || typeof type !== "string") {
47
+ throw new errors_js_1.ValidationError("Indicator type must be a non-empty string");
48
+ }
49
+ return this.client["request"](`/v1/indicators/${type}`, {});
50
+ }
51
+ /** Fuel-switching economics indicator. */
52
+ async fuelSwitching() {
53
+ return this.get("fuel-switching");
54
+ }
55
+ /** Price-context indicator. */
56
+ async priceContext() {
57
+ return this.get("price-context");
58
+ }
59
+ /** Storage-analytics indicator. */
60
+ async storageAnalytics() {
61
+ return this.get("storage-analytics");
62
+ }
63
+ /** Market annotations. */
64
+ async annotations() {
65
+ const response = await this.client["request"]("/v1/indicators/annotations", {});
66
+ return Array.isArray(response) ? response : response.data;
67
+ }
68
+ /** CFTC positioning (Commitment of Traders) indicators. */
69
+ async cftcPositioning() {
70
+ const response = await this.client["request"]("/v1/indicators/cftc-positioning", {});
71
+ return Array.isArray(response) ? response : response.data;
72
+ }
73
+ /** Congressional energy-sector trade indicators. */
74
+ async congressionalTrades() {
75
+ const response = await this.client["request"]("/v1/indicators/congressional-trades", {});
76
+ return Array.isArray(response) ? response : response.data;
77
+ }
78
+ }
79
+ exports.IndicatorsResource = IndicatorsResource;
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ /**
3
+ * Raw Response Resource
4
+ *
5
+ * Provides opt-in access to the underlying HTTP status code and response
6
+ * headers alongside the parsed data. Mirrors the most commonly used top-level
7
+ * client methods. This is the #1 requested enhancement (issue #7).
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { OilPriceAPI } from 'oilpriceapi';
12
+ *
13
+ * const client = new OilPriceAPI({ apiKey: 'your_key' });
14
+ *
15
+ * const { data, status, headers } = await client.raw.getLatestPrices();
16
+ * console.log(`HTTP ${status}`);
17
+ * console.log(`Rate limit remaining: ${headers.get('x-ratelimit-remaining')}`);
18
+ * console.log(data[0].price);
19
+ * ```
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.RawResource = void 0;
23
+ /**
24
+ * Raw Response Resource
25
+ *
26
+ * Each method returns an {@link APIResponse} with `{ data, status, headers }`
27
+ * instead of just the parsed data, so callers can inspect HTTP metadata such
28
+ * as rate-limit headers, caching headers, and the exact status code.
29
+ */
30
+ class RawResource {
31
+ constructor(client) {
32
+ this.client = client;
33
+ }
34
+ /**
35
+ * Make an arbitrary GET request and return data plus HTTP status and headers.
36
+ *
37
+ * Use this for endpoints without a dedicated raw helper.
38
+ *
39
+ * @typeParam T - Expected parsed response type.
40
+ * @param endpoint - API path beginning with `/` (e.g. `/v1/prices/latest`).
41
+ * @param params - Optional query parameters.
42
+ * @returns The parsed data along with the HTTP status code and headers.
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * const { data, status, headers } = await client.raw.get('/v1/futures/CL.1');
47
+ * ```
48
+ */
49
+ async get(endpoint, params) {
50
+ return this.client["requestRaw"](endpoint, params);
51
+ }
52
+ /**
53
+ * Latest prices with raw HTTP status and headers.
54
+ *
55
+ * @param options - Optional commodity filter.
56
+ * @returns Prices array with HTTP status and headers.
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * const { data, status, headers } = await client.raw.getLatestPrices({ commodity: 'WTI_USD' });
61
+ * ```
62
+ */
63
+ async getLatestPrices(options) {
64
+ const params = {};
65
+ if (options?.commodity) {
66
+ params.by_code = options.commodity;
67
+ }
68
+ return this.client["requestRaw"]("/v1/prices/latest", params);
69
+ }
70
+ /**
71
+ * Historical prices with raw HTTP status and headers.
72
+ *
73
+ * @param options - Time period and filter options.
74
+ * @returns Prices array with HTTP status and headers.
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * const { data, status, headers } = await client.raw.getHistoricalPrices({
79
+ * period: 'past_week',
80
+ * commodity: 'BRENT_CRUDE_USD',
81
+ * });
82
+ * ```
83
+ */
84
+ async getHistoricalPrices(options) {
85
+ const params = {};
86
+ if (options?.period)
87
+ params.period = options.period;
88
+ if (options?.commodity)
89
+ params.by_code = options.commodity;
90
+ if (options?.startDate)
91
+ params.start_date = options.startDate;
92
+ if (options?.endDate)
93
+ params.end_date = options.endDate;
94
+ if (options?.interval)
95
+ params.interval = options.interval;
96
+ if (options?.perPage !== undefined)
97
+ params.per_page = options.perPage.toString();
98
+ if (options?.page !== undefined)
99
+ params.page = options.page.toString();
100
+ return this.client["requestRaw"]("/v1/prices/past_year", params);
101
+ }
102
+ /**
103
+ * Commodities metadata with raw HTTP status and headers.
104
+ *
105
+ * @returns Commodities response with HTTP status and headers.
106
+ */
107
+ async getCommodities() {
108
+ return this.client["requestRaw"]("/v1/commodities", {});
109
+ }
110
+ /**
111
+ * Commodity categories with raw HTTP status and headers.
112
+ *
113
+ * @returns Categories response with HTTP status and headers.
114
+ */
115
+ async getCommodityCategories() {
116
+ return this.client["requestRaw"]("/v1/commodities/categories", {});
117
+ }
118
+ /**
119
+ * A single commodity's metadata with raw HTTP status and headers.
120
+ *
121
+ * @param code - Commodity code (e.g., "WTI_USD").
122
+ * @returns Commodity with HTTP status and headers.
123
+ */
124
+ async getCommodity(code) {
125
+ return this.client["requestRaw"](`/v1/commodities/${code}`, {});
126
+ }
127
+ }
128
+ exports.RawResource = RawResource;
@@ -99,11 +99,14 @@ class RigCountsResource {
99
99
  * ```
100
100
  */
101
101
  async historical(options) {
102
+ // The controller filters via `has_scope :by_period, using: %i[from to], type: :hash`,
103
+ // i.e. it reads nested `by_period[from]` / `by_period[to]` query params — NOT
104
+ // flat `start_date` / `end_date` (which were silently ignored by earlier SDKs).
102
105
  const params = {};
103
106
  if (options?.startDate)
104
- params.start_date = options.startDate;
107
+ params["by_period[from]"] = options.startDate;
105
108
  if (options?.endDate)
106
- params.end_date = options.endDate;
109
+ params["by_period[to]"] = options.endDate;
107
110
  const response = await this.client["request"]("/v1/rig-counts/historical", params);
108
111
  return Array.isArray(response) ? response : response.data;
109
112
  }
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ /**
3
+ * Spreads Resource
4
+ *
5
+ * Access oil & product spread analytics: crack spreads, basis spreads,
6
+ * curve-structure (contango/backwardation), refining margins, and physical
7
+ * premiums. Each spread type supports the latest value, full history, and an
8
+ * `all` listing.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.SpreadsResource = void 0;
12
+ const errors_js_1 = require("../errors.js");
13
+ /**
14
+ * Spreads Resource
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import { OilPriceAPI } from 'oilpriceapi';
19
+ *
20
+ * const client = new OilPriceAPI({ apiKey: 'your_key' });
21
+ *
22
+ * // Latest crack spread
23
+ * const crack = await client.spreads.crack();
24
+ * console.log(`Crack spread: ${crack.value} ${crack.unit}`);
25
+ *
26
+ * // Historical basis spreads
27
+ * const history = await client.spreads.historical('basis', {
28
+ * startDate: '2024-01-01',
29
+ * endDate: '2024-12-31',
30
+ * });
31
+ *
32
+ * // All margin spreads
33
+ * const all = await client.spreads.all('margin');
34
+ * ```
35
+ */
36
+ class SpreadsResource {
37
+ constructor(client) {
38
+ this.client = client;
39
+ }
40
+ /**
41
+ * Get the latest value for a spread type.
42
+ *
43
+ * @param type - Spread type slug.
44
+ * @returns Latest spread value.
45
+ * @throws {ValidationError} If the type is invalid.
46
+ */
47
+ async get(type) {
48
+ this.validateType(type);
49
+ return this.client["request"](`/v1/spreads/${type}`, {});
50
+ }
51
+ /**
52
+ * Get historical data for a spread type.
53
+ *
54
+ * @param type - Spread type slug.
55
+ * @param options - Optional date range filters.
56
+ * @returns Array of historical spread values.
57
+ */
58
+ async historical(type, options) {
59
+ this.validateType(type);
60
+ const params = {};
61
+ if (options?.startDate)
62
+ params.start_date = options.startDate;
63
+ if (options?.endDate)
64
+ params.end_date = options.endDate;
65
+ const response = await this.client["request"](`/v1/spreads/${type}/historical`, params);
66
+ return Array.isArray(response) ? response : response.data;
67
+ }
68
+ /**
69
+ * Get all spread values for a spread type.
70
+ *
71
+ * @param type - Spread type slug.
72
+ * @returns Array of spread values.
73
+ */
74
+ async all(type) {
75
+ this.validateType(type);
76
+ const response = await this.client["request"](`/v1/spreads/${type}/all`, {});
77
+ return Array.isArray(response) ? response : response.data;
78
+ }
79
+ /** Latest crack spread. */
80
+ async crack() {
81
+ return this.get("crack");
82
+ }
83
+ /** Latest basis spread. */
84
+ async basis() {
85
+ return this.get("basis");
86
+ }
87
+ /** Latest curve-structure (contango / backwardation). */
88
+ async curveStructure() {
89
+ return this.get("curve-structure");
90
+ }
91
+ /** Latest refining margin. */
92
+ async margin() {
93
+ return this.get("margin");
94
+ }
95
+ /** Latest physical premium. */
96
+ async physicalPremium() {
97
+ return this.get("physical-premium");
98
+ }
99
+ validateType(type) {
100
+ if (!type || typeof type !== "string") {
101
+ throw new errors_js_1.ValidationError("Spread type must be a non-empty string");
102
+ }
103
+ }
104
+ }
105
+ exports.SpreadsResource = SpreadsResource;
@@ -155,11 +155,11 @@ class StorageResource {
155
155
  throw new errors_js_1.ValidationError("Storage location code must be a non-empty string");
156
156
  }
157
157
  const params = {};
158
- if (options?.startDate)
159
- params.start_date = options.startDate;
160
- if (options?.endDate)
161
- params.end_date = options.endDate;
162
- const response = await this.client["request"](`/v1/storage/${code}/history`, params);
158
+ if (options?.period)
159
+ params.period = options.period;
160
+ // Route is GET /v1/storage/history/:code (the :code segment comes AFTER
161
+ // `history`), and the controller reads a `period` token.
162
+ const response = await this.client["request"](`/v1/storage/history/${code}`, params);
163
163
  return Array.isArray(response) ? response : response.data;
164
164
  }
165
165
  }