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
@@ -120,22 +120,18 @@ export class DataSourcesResource {
120
120
  if (!params.name || typeof params.name !== "string") {
121
121
  throw new ValidationError("Data source name is required");
122
122
  }
123
- if (!params.type) {
124
- throw new ValidationError("Data source type is required");
125
- }
126
- if (!params.config || typeof params.config !== "object") {
127
- throw new ValidationError("Data source config is required");
123
+ if (!params.source_type) {
124
+ throw new ValidationError("Data source source_type is required");
128
125
  }
129
126
  const response = await this.client["request"]("/v1/data-sources", {}, {
130
127
  method: "POST",
131
128
  body: {
132
129
  data_source: {
133
130
  name: params.name,
134
- type: params.type,
135
- config: params.config,
136
- enabled: params.enabled ?? true,
137
- sync_frequency_minutes: params.sync_frequency_minutes ?? 60,
138
- metadata: params.metadata,
131
+ source_type: params.source_type,
132
+ status: params.status,
133
+ credentials: params.credentials,
134
+ scraper_config: params.scraper_config,
139
135
  },
140
136
  },
141
137
  });
@@ -284,10 +280,15 @@ export class DataSourcesResource {
284
280
  * console.log(`Credential rotation: ${result.success ? 'success' : 'failed'}`);
285
281
  * ```
286
282
  */
287
- async rotateCredentials(id) {
283
+ async rotateCredentials(id, credentials) {
288
284
  if (!id || typeof id !== "string") {
289
285
  throw new ValidationError("Data source ID must be a non-empty string");
290
286
  }
291
- return this.client["request"](`/v1/data-sources/${id}/rotate-credentials`, {}, { method: "POST" });
287
+ if (!credentials || typeof credentials !== "object") {
288
+ throw new ValidationError("New credentials object is required");
289
+ }
290
+ // Route is POST /v1/data-sources/:id/rotate_credentials (underscore) and
291
+ // the controller does params.require(:credentials).
292
+ return this.client["request"](`/v1/data-sources/${id}/rotate_credentials`, {}, { method: "POST", body: { credentials } });
292
293
  }
293
294
  }
@@ -100,18 +100,32 @@ export interface WellChemical {
100
100
  mass_lbs?: number;
101
101
  }
102
102
  /**
103
- * FracFocus search query
103
+ * FracFocus search query.
104
+ *
105
+ * Maps to the parameters the `search` action actually reads. Note: `operator`
106
+ * and `chemical` are NOT search params (use the dedicated by-operator /
107
+ * by-chemical endpoints); state filtering uses `states` (comma-separated, plural).
104
108
  */
105
109
  export interface FracFocusSearchQuery {
106
- /** State filter */
107
- state?: string;
108
- /** Operator filter */
109
- operator?: string;
110
- /** Chemical filter */
111
- chemical?: string;
112
- /** Start date */
110
+ /** Comma-separated state codes (e.g. 'TX,NM') */
111
+ states?: string;
112
+ /** County name (partial match) */
113
+ county?: string;
114
+ /** Well name (partial match) */
115
+ well_name?: string;
116
+ /** API well number (partial match) */
117
+ api_number?: string;
118
+ /** Minimum total base water volume (gallons) */
119
+ min_water_gallons?: number;
120
+ /** Latitude for radius search */
121
+ latitude?: number;
122
+ /** Longitude for radius search */
123
+ longitude?: number;
124
+ /** Radius in miles (1-100, default 10) for lat/lng search */
125
+ radius_miles?: number;
126
+ /** Start date (job_start_date >=) */
113
127
  start_date?: string;
114
- /** End date */
128
+ /** End date (job_start_date <=) */
115
129
  end_date?: string;
116
130
  }
117
131
  /**
@@ -109,12 +109,22 @@ export class EIFracFocusResource {
109
109
  */
110
110
  async search(query) {
111
111
  const params = {};
112
- if (query.state)
113
- params.state = query.state;
114
- if (query.operator)
115
- params.operator = query.operator;
116
- if (query.chemical)
117
- params.chemical = query.chemical;
112
+ if (query.states)
113
+ params.states = query.states;
114
+ if (query.county)
115
+ params.county = query.county;
116
+ if (query.well_name)
117
+ params.well_name = query.well_name;
118
+ if (query.api_number)
119
+ params.api_number = query.api_number;
120
+ if (query.min_water_gallons !== undefined)
121
+ params.min_water_gallons = query.min_water_gallons.toString();
122
+ if (query.latitude !== undefined)
123
+ params.latitude = query.latitude.toString();
124
+ if (query.longitude !== undefined)
125
+ params.longitude = query.longitude.toString();
126
+ if (query.radius_miles !== undefined)
127
+ params.radius_miles = query.radius_miles.toString();
118
128
  if (query.start_date)
119
129
  params.start_date = query.start_date;
120
130
  if (query.end_date)
@@ -84,18 +84,34 @@ export interface PermitsByFormation {
84
84
  date: string;
85
85
  }
86
86
  /**
87
- * Well permit search query
87
+ * Well permit search query.
88
+ *
89
+ * Maps to the parameters the `search` action actually reads. Note: `operator`
90
+ * and `formation` are NOT search params (use the dedicated by-operator /
91
+ * by-formation endpoints); state filtering uses `states` (comma-separated, plural).
88
92
  */
89
93
  export interface WellPermitSearchQuery {
90
- /** State filter */
91
- state?: string;
92
- /** Operator filter */
93
- operator?: string;
94
- /** Formation filter */
95
- formation?: string;
96
- /** Start date */
94
+ /** Comma-separated state codes (e.g. 'TX,NM') */
95
+ states?: string;
96
+ /** County name (partial match) */
97
+ county?: string;
98
+ /** Well name (partial match) */
99
+ well_name?: string;
100
+ /** Permit type */
101
+ permit_type?: string;
102
+ /** Well type */
103
+ well_type?: string;
104
+ /** Free-form address (geocoded to lat/lng) */
105
+ address?: string;
106
+ /** Latitude for radius search */
107
+ latitude?: number;
108
+ /** Longitude for radius search */
109
+ longitude?: number;
110
+ /** Radius in miles (1-100, default 10) for lat/lng search */
111
+ radius_miles?: number;
112
+ /** Start date (permit_date >=) */
97
113
  start_date?: string;
98
- /** End date */
114
+ /** End date (permit_date <=) */
99
115
  end_date?: string;
100
116
  }
101
117
  /**
@@ -104,12 +104,24 @@ export class EIWellPermitsResource {
104
104
  */
105
105
  async search(query) {
106
106
  const params = {};
107
- if (query.state)
108
- params.state = query.state;
109
- if (query.operator)
110
- params.operator = query.operator;
111
- if (query.formation)
112
- params.formation = query.formation;
107
+ if (query.states)
108
+ params.states = query.states;
109
+ if (query.county)
110
+ params.county = query.county;
111
+ if (query.well_name)
112
+ params.well_name = query.well_name;
113
+ if (query.permit_type)
114
+ params.permit_type = query.permit_type;
115
+ if (query.well_type)
116
+ params.well_type = query.well_type;
117
+ if (query.address)
118
+ params.address = query.address;
119
+ if (query.latitude !== undefined)
120
+ params.latitude = query.latitude.toString();
121
+ if (query.longitude !== undefined)
122
+ params.longitude = query.longitude.toString();
123
+ if (query.radius_miles !== undefined)
124
+ params.radius_miles = query.radius_miles.toString();
113
125
  if (query.start_date)
114
126
  params.start_date = query.start_date;
115
127
  if (query.end_date)
@@ -172,7 +172,10 @@ export declare class ForecastsResource {
172
172
  * });
173
173
  * ```
174
174
  */
175
- archive(year?: number): Promise<ArchivedForecast[]>;
175
+ archive(options?: {
176
+ page?: number;
177
+ perPage?: number;
178
+ }): Promise<ArchivedForecast[]>;
176
179
  /**
177
180
  * Get forecast for a specific period
178
181
  *
@@ -85,7 +85,8 @@ export class ForecastsResource {
85
85
  * ```
86
86
  */
87
87
  async accuracy() {
88
- return this.client["request"]("/v1/forecasts/accuracy", {});
88
+ // Route is /v1/forecasts/monthly/accuracy (the bare /accuracy 404s).
89
+ return this.client["request"]("/v1/forecasts/monthly/accuracy", {});
89
90
  }
90
91
  /**
91
92
  * Get archived forecasts
@@ -116,11 +117,16 @@ export class ForecastsResource {
116
117
  * });
117
118
  * ```
118
119
  */
119
- async archive(year) {
120
+ async archive(options) {
121
+ // Route is /v1/forecasts/monthly/archive (the bare /archive 404s). The
122
+ // controller reads only `page` / `per_page` — it does NOT filter by year,
123
+ // so the previous `year` argument was silently ignored.
120
124
  const params = {};
121
- if (year)
122
- params.year = year.toString();
123
- const response = await this.client["request"]("/v1/forecasts/archive", params);
125
+ if (options?.page !== undefined)
126
+ params.page = options.page.toString();
127
+ if (options?.perPage !== undefined)
128
+ params.per_page = options.perPage.toString();
129
+ const response = await this.client["request"]("/v1/forecasts/monthly/archive", params);
124
130
  return Array.isArray(response) ? response : response.forecasts;
125
131
  }
126
132
  /**
@@ -6,23 +6,71 @@
6
6
  */
7
7
  import type { OilPriceAPI } from "../client.js";
8
8
  /**
9
- * Futures contract price data
9
+ * A single futures contract month within a {@link FuturesPrice} response.
10
+ *
11
+ * Returned at the top level under `front_month` and for every entry in
12
+ * `contracts[]`. The latest traded price is `last_price`.
13
+ */
14
+ export interface FuturesContractMonth {
15
+ /** Contract code (e.g. "BRENT_FUTURES_2026_08"). */
16
+ code?: string;
17
+ /** Contract month in YYYY-MM form (e.g. "2026-08"). */
18
+ contract_month?: string;
19
+ /** Latest traded/settlement price for this contract month. */
20
+ last_price?: number;
21
+ /** Currency code (e.g. "USD"). */
22
+ currency?: string;
23
+ /** Opening price (may be returned as a string by the API). */
24
+ open?: number | string;
25
+ /** Closing price (may be returned as a string by the API). */
26
+ close?: number | string;
27
+ /** Session high. */
28
+ high?: number | string;
29
+ /** Session low. */
30
+ low?: number | string;
31
+ /** Any additional fields the API returns for a contract month. */
32
+ [key: string]: unknown;
33
+ }
34
+ /**
35
+ * Futures contract price data.
36
+ *
37
+ * `GET /v1/futures/{slug}` returns a TOP-LEVEL object (there is NO
38
+ * `{ status, data }` envelope). The latest price lives at
39
+ * `front_month.last_price`, with the full term structure in `contracts[]`.
40
+ *
41
+ * Legacy flat fields (`contract`, `price`, `currency`, `timestamp`) are kept
42
+ * optional for backward compatibility, but real responses populate
43
+ * `front_month` / `contracts` instead.
10
44
  */
11
45
  export interface FuturesPrice {
12
- /** Contract symbol */
13
- contract: string;
14
- /** Current price */
15
- price: number;
16
- /** Formatted price string */
46
+ /** Commodity identifier (e.g. "BRENT_FUTURES"). */
47
+ commodity?: string;
48
+ /** Data source (e.g. "ICE"). */
49
+ source?: string;
50
+ /** ISO timestamp the data was last updated. */
51
+ updated_at?: string;
52
+ /** Settlement date for the prices. */
53
+ settlement_date?: string;
54
+ /** Front-month contract — the latest price is `front_month.last_price`. */
55
+ front_month?: FuturesContractMonth;
56
+ /** Full forward term structure, one entry per contract month. */
57
+ contracts?: FuturesContractMonth[];
58
+ /** Optional warning when the returned data is stale. */
59
+ data_age_warning?: unknown;
60
+ /** Additional metadata returned by the API. */
61
+ metadata?: Record<string, unknown>;
62
+ /** @deprecated Legacy flat contract symbol — use `front_month.code`. */
63
+ contract?: string;
64
+ /** @deprecated Legacy flat price — use `front_month.last_price`. */
65
+ price?: number;
66
+ /** @deprecated Legacy formatted price string. */
17
67
  formatted?: string;
18
- /** Currency code */
19
- currency: string;
20
- /** Contract expiration date */
68
+ /** @deprecated Legacy currency — use `front_month.currency`. */
69
+ currency?: string;
70
+ /** @deprecated Legacy contract expiration date. */
21
71
  expiration?: string;
22
- /** ISO timestamp when price was recorded */
23
- timestamp: string;
24
- /** Additional metadata */
25
- metadata?: Record<string, unknown>;
72
+ /** @deprecated Legacy ISO timestamp use `updated_at`. */
73
+ timestamp?: string;
26
74
  }
27
75
  /**
28
76
  * Historical futures price data
@@ -40,13 +88,34 @@ export interface HistoricalFuturesPrice {
40
88
  open_interest?: number;
41
89
  }
42
90
  /**
43
- * Options for historical futures query
91
+ * Options for historical futures query.
92
+ *
93
+ * The controller reads `from` / `to` (dates) plus optional `interval` and
94
+ * `contracts` — NOT `start_date` / `end_date`.
44
95
  */
45
96
  export interface HistoricalFuturesOptions {
46
97
  /** Start date in ISO 8601 format (YYYY-MM-DD) */
47
98
  startDate?: string;
48
99
  /** End date in ISO 8601 format (YYYY-MM-DD) */
49
100
  endDate?: string;
101
+ /** Aggregation interval (e.g. '1d') */
102
+ interval?: string;
103
+ /** Specific contracts to include */
104
+ contracts?: string;
105
+ }
106
+ /**
107
+ * Options for futures OHLC query.
108
+ *
109
+ * The controller reads `days`, `contract` and `interval` — there is no `date`
110
+ * parameter for OHLC.
111
+ */
112
+ export interface FuturesOHLCOptions {
113
+ /** Number of days of OHLC bars (default 30, clamped 1-365) */
114
+ days?: number;
115
+ /** Specific contract */
116
+ contract?: string;
117
+ /** Aggregation interval */
118
+ interval?: string;
50
119
  }
51
120
  /**
52
121
  * OHLC (Open, High, Low, Close) data for a futures contract
@@ -120,15 +189,25 @@ export interface FuturesCurvePoint {
120
189
  contract?: string;
121
190
  }
122
191
  /**
123
- * Futures curve data
192
+ * Futures curve data.
193
+ *
194
+ * `GET /v1/futures/{slug}/curve` can legitimately return a no-data response of
195
+ * the form `{ error: "No futures data available for curve analysis", date }`
196
+ * when a curve cannot be built. That is a valid state (not an HTTP error), so
197
+ * `curve` is optional and `error` / `date` are surfaced for callers to detect
198
+ * the no-data case.
124
199
  */
125
200
  export interface FuturesCurveData {
126
201
  /** Base contract */
127
- contract: string;
202
+ contract?: string;
128
203
  /** ISO timestamp when curve was generated */
129
- timestamp: string;
130
- /** Array of curve points */
131
- curve: FuturesCurvePoint[];
204
+ timestamp?: string;
205
+ /** Array of curve points (absent in the no-data response) */
206
+ curve?: FuturesCurvePoint[];
207
+ /** Present in the no-data response: "No futures data available for curve analysis". */
208
+ error?: string;
209
+ /** Date associated with the no-data response. */
210
+ date?: string;
132
211
  }
133
212
  /**
134
213
  * Continuous contract data point
@@ -152,6 +231,140 @@ export interface ContinuousFuturesData {
152
231
  /** Array of continuous prices */
153
232
  prices: ContinuousContractPrice[];
154
233
  }
234
+ /**
235
+ * Spread-history data point for a contract family.
236
+ */
237
+ export interface FuturesSpreadHistoryPoint {
238
+ /** ISO date */
239
+ date: string;
240
+ /** Spread value */
241
+ spread: number;
242
+ /** Optional percentage spread */
243
+ spread_percent?: number;
244
+ }
245
+ /**
246
+ * Spread-history data for a contract family.
247
+ */
248
+ export interface FuturesSpreadHistory {
249
+ /** Contract family slug (e.g., "ice-brent") */
250
+ family: string;
251
+ /** Array of historical spread points */
252
+ history: FuturesSpreadHistoryPoint[];
253
+ }
254
+ /**
255
+ * Slugs for the supported ICE / gas / carbon futures contract families.
256
+ *
257
+ * These map to the `GET /v1/futures/{slug}` (latest) endpoint plus the
258
+ * `GET /v1/futures/{slug}/...` sub-resources. Latest is the bare slug path
259
+ * (there is NO `/latest` suffix). Each family also supports `/historical`,
260
+ * `/ohlc`, `/intraday`, `/spreads`, `/curve`, and `/spread-history`.
261
+ */
262
+ export type FuturesContractFamilySlug = "ice-brent" | "ice-gasoil" | "ice-wti" | "natural-gas" | "ttf-gas" | "lng-jkm" | "eua-carbon" | "uk-carbon";
263
+ /**
264
+ * Ergonomic contract codes for the most-requested futures families (issue #1).
265
+ *
266
+ * Use with the generic {@link FuturesResource} methods, or use the typed
267
+ * {@link FuturesResource.family} helper for direct access to a family's
268
+ * endpoints.
269
+ *
270
+ * @example
271
+ * ```typescript
272
+ * import { FUTURES_CONTRACTS } from 'oilpriceapi';
273
+ *
274
+ * const brent = await client.futures.latest(FUTURES_CONTRACTS.BRENT); // "BZ"
275
+ * const gasoil = await client.futures.family('ice-gasoil').latest();
276
+ * ```
277
+ */
278
+ export declare const FUTURES_CONTRACTS: {
279
+ /** ICE Brent crude */
280
+ readonly BRENT: "BZ";
281
+ /** NYMEX WTI crude */
282
+ readonly WTI: "CL";
283
+ /** ICE Gasoil */
284
+ readonly GASOIL: "G";
285
+ /** Henry Hub natural gas */
286
+ readonly NATURAL_GAS: "NG";
287
+ /** TTF natural gas (Europe) */
288
+ readonly TTF_GAS: "TTF";
289
+ /** LNG JKM (Asia) */
290
+ readonly LNG_JKM: "JKM";
291
+ /** EU carbon allowance */
292
+ readonly EUA_CARBON: "EUA";
293
+ /** UK carbon allowance */
294
+ readonly UK_CARBON: "UKA";
295
+ };
296
+ /**
297
+ * Mapping of ergonomic contract codes to their API contract-family slugs.
298
+ *
299
+ * Lets you resolve a contract code (e.g., `"BZ"`) to the `/v1/futures/{slug}`
300
+ * path segment used by the typed family helpers.
301
+ */
302
+ export declare const FUTURES_FAMILY_SLUGS: Record<string, FuturesContractFamilySlug>;
303
+ /**
304
+ * Resolve a futures contract code (e.g. `"BZ"`, `"QS"`) or an already-valid
305
+ * family slug (e.g. `"ice-brent"`) to its `/v1/futures/{slug}` path segment.
306
+ *
307
+ * Matching is case-insensitive for codes. Returns `null` if the input maps to
308
+ * neither a known code nor a known family slug.
309
+ */
310
+ export declare function resolveFuturesFamilySlug(codeOrSlug: string): FuturesContractFamilySlug | null;
311
+ /**
312
+ * Typed helper for a single futures contract family (e.g., ICE Brent, Gasoil).
313
+ *
314
+ * Provides ergonomic access to the family's endpoints without having to
315
+ * remember the URL slug. Obtain an instance via {@link FuturesResource.family},
316
+ * {@link FuturesResource.brent}, {@link FuturesResource.gasoil}, etc.
317
+ *
318
+ * @example
319
+ * ```typescript
320
+ * const gasoil = client.futures.gasoil();
321
+ * const latest = await gasoil.latest();
322
+ * const curve = await gasoil.curve();
323
+ * ```
324
+ */
325
+ export declare class FuturesContractFamily {
326
+ private client;
327
+ /** The contract-family slug used in the API path. */
328
+ readonly slug: FuturesContractFamilySlug;
329
+ constructor(client: OilPriceAPI,
330
+ /** The contract-family slug used in the API path. */
331
+ slug: FuturesContractFamilySlug);
332
+ /**
333
+ * Get the latest price for this contract family.
334
+ *
335
+ * Latest is served from the bare slug path `GET /v1/futures/{slug}` —
336
+ * there is NO `/latest` suffix (that path 404s).
337
+ */
338
+ latest(): Promise<FuturesPrice>;
339
+ /**
340
+ * Get historical prices for this contract family.
341
+ *
342
+ * @param options - Optional date range filters.
343
+ */
344
+ historical(options?: HistoricalFuturesOptions): Promise<HistoricalFuturesPrice[]>;
345
+ /**
346
+ * Get OHLC data for this contract family.
347
+ *
348
+ * @param options - `{ days, contract, interval }` (the API has no `date` param here).
349
+ */
350
+ ohlc(options?: FuturesOHLCOptions): Promise<FuturesOHLC>;
351
+ /**
352
+ * Get intraday price data for this contract family.
353
+ */
354
+ intraday(): Promise<IntradayFuturesData>;
355
+ /**
356
+ * Get the spreads for this contract family.
357
+ */
358
+ spreads(): Promise<FuturesSpread[]>;
359
+ /**
360
+ * Get the forward curve for this contract family.
361
+ */
362
+ curve(): Promise<FuturesCurveData>;
363
+ /**
364
+ * Get historical spread data for this contract family.
365
+ */
366
+ spreadHistory(): Promise<FuturesSpreadHistory>;
367
+ }
155
368
  /**
156
369
  * Futures Resource
157
370
  *
@@ -164,16 +377,13 @@ export interface ContinuousFuturesData {
164
377
  *
165
378
  * const client = new OilPriceAPI({ apiKey: 'your_key' });
166
379
  *
167
- * // Get latest price
168
- * const latest = await client.futures.latest('CL.1');
380
+ * // Get the latest curve by contract code (resolves to GET /v1/futures/ice-wti)
381
+ * const latest = await client.futures.latest('CL');
169
382
  * console.log(`${latest.contract}: $${latest.price}`);
170
383
  *
171
- * // Get OHLC data
172
- * const ohlc = await client.futures.ohlc('CL.1', '2024-01-15');
173
- * console.log(`High: $${ohlc.high}, Low: $${ohlc.low}`);
174
- *
175
- * // Get futures curve
176
- * const curve = await client.futures.curve('CL');
384
+ * // Typed family helpers are the most ergonomic option:
385
+ * const brent = await client.futures.brent().latest();
386
+ * const curve = await client.futures.brent().curve();
177
387
  * curve.curve.forEach(point => {
178
388
  * console.log(`${point.months_out}mo: $${point.price}`);
179
389
  * });
@@ -183,18 +393,28 @@ export declare class FuturesResource {
183
393
  private client;
184
394
  constructor(client: OilPriceAPI);
185
395
  /**
186
- * Get latest price for a futures contract
396
+ * Get the latest curve/quote for a futures contract family.
187
397
  *
188
- * @param contract - Contract symbol (e.g., "CL.1", "BZ.2")
189
- * @returns Latest futures price data
398
+ * Accepts an ergonomic contract code (e.g. `"BZ"`, `"CL"`, `"QS"`) or a
399
+ * family slug (e.g. `"ice-brent"`). The code is resolved to its family slug
400
+ * and the request is sent to `GET /v1/futures/{slug}` — the bare slug path,
401
+ * with NO `/latest` suffix (the suffixed path 404s).
190
402
  *
191
- * @throws {NotFoundError} If contract not found
403
+ * Supported codes: BZ (Brent), CL (WTI), G/QS (Gasoil), NG (Natural Gas),
404
+ * TTF, JKM, EUA, UKA. Slugs: ice-brent, ice-wti, ice-gasoil, natural-gas,
405
+ * ttf-gas, lng-jkm, eua-carbon, uk-carbon.
406
+ *
407
+ * @param contract - Contract code (e.g. "BZ") or family slug (e.g. "ice-brent").
408
+ * @returns Latest futures price/curve data
409
+ *
410
+ * @throws {ValidationError} If the code/slug is empty or unrecognized.
192
411
  * @throws {OilPriceAPIError} If API request fails
193
412
  *
194
413
  * @example
195
414
  * ```typescript
196
- * const price = await client.futures.latest('CL.1');
197
- * console.log(`WTI Front Month: $${price.price}`);
415
+ * import { FUTURES_CONTRACTS } from 'oilpriceapi';
416
+ * const price = await client.futures.latest(FUTURES_CONTRACTS.BRENT); // "BZ"
417
+ * const wti = await client.futures.latest('ice-wti');
198
418
  * ```
199
419
  */
200
420
  latest(contract: string): Promise<FuturesPrice>;
@@ -319,4 +539,38 @@ export declare class FuturesResource {
319
539
  * ```
320
540
  */
321
541
  continuous(contract: string, months?: number): Promise<ContinuousFuturesData>;
542
+ /**
543
+ * Get a typed helper for a specific contract family (issue #1).
544
+ *
545
+ * Provides ergonomic access to the ICE Brent / WTI / Gasoil and gas/carbon
546
+ * family endpoints (`/latest`, `/historical`, `/ohlc`, `/intraday`,
547
+ * `/spreads`, `/curve`, `/spread-history`) without remembering the URL slug.
548
+ *
549
+ * @param slug - Contract family slug (e.g., `"ice-brent"`, `"ice-gasoil"`).
550
+ * @returns A {@link FuturesContractFamily} bound to the slug.
551
+ *
552
+ * @example
553
+ * ```typescript
554
+ * const brent = client.futures.family('ice-brent');
555
+ * const latest = await brent.latest();
556
+ * const curve = await brent.curve();
557
+ * ```
558
+ */
559
+ family(slug: FuturesContractFamilySlug): FuturesContractFamily;
560
+ /** ICE Brent crude futures family helper (issue #1). */
561
+ brent(): FuturesContractFamily;
562
+ /** ICE WTI crude futures family helper. */
563
+ wti(): FuturesContractFamily;
564
+ /** ICE Gasoil futures family helper (issue #1). */
565
+ gasoil(): FuturesContractFamily;
566
+ /** Henry Hub natural gas futures family helper. */
567
+ naturalGas(): FuturesContractFamily;
568
+ /** TTF natural gas (Europe) futures family helper. */
569
+ ttfGas(): FuturesContractFamily;
570
+ /** LNG JKM (Asia) futures family helper. */
571
+ lngJkm(): FuturesContractFamily;
572
+ /** EU carbon allowance (EUA) futures family helper. */
573
+ euaCarbon(): FuturesContractFamily;
574
+ /** UK carbon allowance (UKA) futures family helper. */
575
+ ukCarbon(): FuturesContractFamily;
322
576
  }