oilpriceapi 0.8.2 → 0.9.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.
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 +192 -1
  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 +178 -1
  36. package/dist/resources/futures.js +190 -0
  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
  /**
@@ -40,13 +40,34 @@ export interface HistoricalFuturesPrice {
40
40
  open_interest?: number;
41
41
  }
42
42
  /**
43
- * Options for historical futures query
43
+ * Options for historical futures query.
44
+ *
45
+ * The controller reads `from` / `to` (dates) plus optional `interval` and
46
+ * `contracts` — NOT `start_date` / `end_date`.
44
47
  */
45
48
  export interface HistoricalFuturesOptions {
46
49
  /** Start date in ISO 8601 format (YYYY-MM-DD) */
47
50
  startDate?: string;
48
51
  /** End date in ISO 8601 format (YYYY-MM-DD) */
49
52
  endDate?: string;
53
+ /** Aggregation interval (e.g. '1d') */
54
+ interval?: string;
55
+ /** Specific contracts to include */
56
+ contracts?: string;
57
+ }
58
+ /**
59
+ * Options for futures OHLC query.
60
+ *
61
+ * The controller reads `days`, `contract` and `interval` — there is no `date`
62
+ * parameter for OHLC.
63
+ */
64
+ export interface FuturesOHLCOptions {
65
+ /** Number of days of OHLC bars (default 30, clamped 1-365) */
66
+ days?: number;
67
+ /** Specific contract */
68
+ contract?: string;
69
+ /** Aggregation interval */
70
+ interval?: string;
50
71
  }
51
72
  /**
52
73
  * OHLC (Open, High, Low, Close) data for a futures contract
@@ -152,6 +173,128 @@ export interface ContinuousFuturesData {
152
173
  /** Array of continuous prices */
153
174
  prices: ContinuousContractPrice[];
154
175
  }
176
+ /**
177
+ * Spread-history data point for a contract family.
178
+ */
179
+ export interface FuturesSpreadHistoryPoint {
180
+ /** ISO date */
181
+ date: string;
182
+ /** Spread value */
183
+ spread: number;
184
+ /** Optional percentage spread */
185
+ spread_percent?: number;
186
+ }
187
+ /**
188
+ * Spread-history data for a contract family.
189
+ */
190
+ export interface FuturesSpreadHistory {
191
+ /** Contract family slug (e.g., "ice-brent") */
192
+ family: string;
193
+ /** Array of historical spread points */
194
+ history: FuturesSpreadHistoryPoint[];
195
+ }
196
+ /**
197
+ * Slugs for the supported ICE / gas / carbon futures contract families.
198
+ *
199
+ * These map to the `GET /v1/futures/{slug}/...` endpoints. Each family
200
+ * supports `/latest`, `/historical`, `/ohlc`, `/intraday`, `/spreads`,
201
+ * `/curve`, and `/spread-history`.
202
+ */
203
+ export type FuturesContractFamilySlug = "ice-brent" | "ice-gasoil" | "ice-wti" | "natural-gas" | "ttf-gas" | "lng-jkm" | "eua-carbon" | "uk-carbon";
204
+ /**
205
+ * Ergonomic contract codes for the most-requested futures families (issue #1).
206
+ *
207
+ * Use with the generic {@link FuturesResource} methods, or use the typed
208
+ * {@link FuturesResource.family} helper for direct access to a family's
209
+ * endpoints.
210
+ *
211
+ * @example
212
+ * ```typescript
213
+ * import { FUTURES_CONTRACTS } from 'oilpriceapi';
214
+ *
215
+ * const brent = await client.futures.latest(FUTURES_CONTRACTS.BRENT); // "BZ"
216
+ * const gasoil = await client.futures.family('ice-gasoil').latest();
217
+ * ```
218
+ */
219
+ export declare const FUTURES_CONTRACTS: {
220
+ /** ICE Brent crude */
221
+ readonly BRENT: "BZ";
222
+ /** NYMEX WTI crude */
223
+ readonly WTI: "CL";
224
+ /** ICE Gasoil */
225
+ readonly GASOIL: "G";
226
+ /** Henry Hub natural gas */
227
+ readonly NATURAL_GAS: "NG";
228
+ /** TTF natural gas (Europe) */
229
+ readonly TTF_GAS: "TTF";
230
+ /** LNG JKM (Asia) */
231
+ readonly LNG_JKM: "JKM";
232
+ /** EU carbon allowance */
233
+ readonly EUA_CARBON: "EUA";
234
+ /** UK carbon allowance */
235
+ readonly UK_CARBON: "UKA";
236
+ };
237
+ /**
238
+ * Mapping of ergonomic contract codes to their API contract-family slugs.
239
+ *
240
+ * Lets you resolve a contract code (e.g., `"BZ"`) to the `/v1/futures/{slug}`
241
+ * path segment used by the typed family helpers.
242
+ */
243
+ export declare const FUTURES_FAMILY_SLUGS: Record<string, FuturesContractFamilySlug>;
244
+ /**
245
+ * Typed helper for a single futures contract family (e.g., ICE Brent, Gasoil).
246
+ *
247
+ * Provides ergonomic access to the family's endpoints without having to
248
+ * remember the URL slug. Obtain an instance via {@link FuturesResource.family},
249
+ * {@link FuturesResource.brent}, {@link FuturesResource.gasoil}, etc.
250
+ *
251
+ * @example
252
+ * ```typescript
253
+ * const gasoil = client.futures.gasoil();
254
+ * const latest = await gasoil.latest();
255
+ * const curve = await gasoil.curve();
256
+ * ```
257
+ */
258
+ export declare class FuturesContractFamily {
259
+ private client;
260
+ /** The contract-family slug used in the API path. */
261
+ readonly slug: FuturesContractFamilySlug;
262
+ constructor(client: OilPriceAPI,
263
+ /** The contract-family slug used in the API path. */
264
+ slug: FuturesContractFamilySlug);
265
+ /**
266
+ * Get the latest price for this contract family.
267
+ */
268
+ latest(): Promise<FuturesPrice>;
269
+ /**
270
+ * Get historical prices for this contract family.
271
+ *
272
+ * @param options - Optional date range filters.
273
+ */
274
+ historical(options?: HistoricalFuturesOptions): Promise<HistoricalFuturesPrice[]>;
275
+ /**
276
+ * Get OHLC data for this contract family.
277
+ *
278
+ * @param options - `{ days, contract, interval }` (the API has no `date` param here).
279
+ */
280
+ ohlc(options?: FuturesOHLCOptions): Promise<FuturesOHLC>;
281
+ /**
282
+ * Get intraday price data for this contract family.
283
+ */
284
+ intraday(): Promise<IntradayFuturesData>;
285
+ /**
286
+ * Get the spreads for this contract family.
287
+ */
288
+ spreads(): Promise<FuturesSpread[]>;
289
+ /**
290
+ * Get the forward curve for this contract family.
291
+ */
292
+ curve(): Promise<FuturesCurveData>;
293
+ /**
294
+ * Get historical spread data for this contract family.
295
+ */
296
+ spreadHistory(): Promise<FuturesSpreadHistory>;
297
+ }
155
298
  /**
156
299
  * Futures Resource
157
300
  *
@@ -319,4 +462,38 @@ export declare class FuturesResource {
319
462
  * ```
320
463
  */
321
464
  continuous(contract: string, months?: number): Promise<ContinuousFuturesData>;
465
+ /**
466
+ * Get a typed helper for a specific contract family (issue #1).
467
+ *
468
+ * Provides ergonomic access to the ICE Brent / WTI / Gasoil and gas/carbon
469
+ * family endpoints (`/latest`, `/historical`, `/ohlc`, `/intraday`,
470
+ * `/spreads`, `/curve`, `/spread-history`) without remembering the URL slug.
471
+ *
472
+ * @param slug - Contract family slug (e.g., `"ice-brent"`, `"ice-gasoil"`).
473
+ * @returns A {@link FuturesContractFamily} bound to the slug.
474
+ *
475
+ * @example
476
+ * ```typescript
477
+ * const brent = client.futures.family('ice-brent');
478
+ * const latest = await brent.latest();
479
+ * const curve = await brent.curve();
480
+ * ```
481
+ */
482
+ family(slug: FuturesContractFamilySlug): FuturesContractFamily;
483
+ /** ICE Brent crude futures family helper (issue #1). */
484
+ brent(): FuturesContractFamily;
485
+ /** ICE WTI crude futures family helper. */
486
+ wti(): FuturesContractFamily;
487
+ /** ICE Gasoil futures family helper (issue #1). */
488
+ gasoil(): FuturesContractFamily;
489
+ /** Henry Hub natural gas futures family helper. */
490
+ naturalGas(): FuturesContractFamily;
491
+ /** TTF natural gas (Europe) futures family helper. */
492
+ ttfGas(): FuturesContractFamily;
493
+ /** LNG JKM (Asia) futures family helper. */
494
+ lngJkm(): FuturesContractFamily;
495
+ /** EU carbon allowance (EUA) futures family helper. */
496
+ euaCarbon(): FuturesContractFamily;
497
+ /** UK carbon allowance (UKA) futures family helper. */
498
+ ukCarbon(): FuturesContractFamily;
322
499
  }
@@ -5,6 +5,141 @@
5
5
  * OHLC, intraday, spreads, curves, and continuous contracts.
6
6
  */
7
7
  import { ValidationError } from "../errors.js";
8
+ /**
9
+ * Ergonomic contract codes for the most-requested futures families (issue #1).
10
+ *
11
+ * Use with the generic {@link FuturesResource} methods, or use the typed
12
+ * {@link FuturesResource.family} helper for direct access to a family's
13
+ * endpoints.
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * import { FUTURES_CONTRACTS } from 'oilpriceapi';
18
+ *
19
+ * const brent = await client.futures.latest(FUTURES_CONTRACTS.BRENT); // "BZ"
20
+ * const gasoil = await client.futures.family('ice-gasoil').latest();
21
+ * ```
22
+ */
23
+ export const FUTURES_CONTRACTS = {
24
+ /** ICE Brent crude */
25
+ BRENT: "BZ",
26
+ /** NYMEX WTI crude */
27
+ WTI: "CL",
28
+ /** ICE Gasoil */
29
+ GASOIL: "G",
30
+ /** Henry Hub natural gas */
31
+ NATURAL_GAS: "NG",
32
+ /** TTF natural gas (Europe) */
33
+ TTF_GAS: "TTF",
34
+ /** LNG JKM (Asia) */
35
+ LNG_JKM: "JKM",
36
+ /** EU carbon allowance */
37
+ EUA_CARBON: "EUA",
38
+ /** UK carbon allowance */
39
+ UK_CARBON: "UKA",
40
+ };
41
+ /**
42
+ * Mapping of ergonomic contract codes to their API contract-family slugs.
43
+ *
44
+ * Lets you resolve a contract code (e.g., `"BZ"`) to the `/v1/futures/{slug}`
45
+ * path segment used by the typed family helpers.
46
+ */
47
+ export const FUTURES_FAMILY_SLUGS = {
48
+ [FUTURES_CONTRACTS.BRENT]: "ice-brent",
49
+ [FUTURES_CONTRACTS.WTI]: "ice-wti",
50
+ [FUTURES_CONTRACTS.GASOIL]: "ice-gasoil",
51
+ [FUTURES_CONTRACTS.NATURAL_GAS]: "natural-gas",
52
+ [FUTURES_CONTRACTS.TTF_GAS]: "ttf-gas",
53
+ [FUTURES_CONTRACTS.LNG_JKM]: "lng-jkm",
54
+ [FUTURES_CONTRACTS.EUA_CARBON]: "eua-carbon",
55
+ [FUTURES_CONTRACTS.UK_CARBON]: "uk-carbon",
56
+ };
57
+ /**
58
+ * Typed helper for a single futures contract family (e.g., ICE Brent, Gasoil).
59
+ *
60
+ * Provides ergonomic access to the family's endpoints without having to
61
+ * remember the URL slug. Obtain an instance via {@link FuturesResource.family},
62
+ * {@link FuturesResource.brent}, {@link FuturesResource.gasoil}, etc.
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * const gasoil = client.futures.gasoil();
67
+ * const latest = await gasoil.latest();
68
+ * const curve = await gasoil.curve();
69
+ * ```
70
+ */
71
+ export class FuturesContractFamily {
72
+ constructor(client,
73
+ /** The contract-family slug used in the API path. */
74
+ slug) {
75
+ this.client = client;
76
+ this.slug = slug;
77
+ }
78
+ /**
79
+ * Get the latest price for this contract family.
80
+ */
81
+ async latest() {
82
+ return this.client["request"](`/v1/futures/${this.slug}/latest`, {});
83
+ }
84
+ /**
85
+ * Get historical prices for this contract family.
86
+ *
87
+ * @param options - Optional date range filters.
88
+ */
89
+ async historical(options) {
90
+ const params = {};
91
+ if (options?.startDate)
92
+ params.from = options.startDate;
93
+ if (options?.endDate)
94
+ params.to = options.endDate;
95
+ if (options?.interval)
96
+ params.interval = options.interval;
97
+ if (options?.contracts)
98
+ params.contracts = options.contracts;
99
+ const response = await this.client["request"](`/v1/futures/${this.slug}/historical`, params);
100
+ return Array.isArray(response) ? response : response.prices;
101
+ }
102
+ /**
103
+ * Get OHLC data for this contract family.
104
+ *
105
+ * @param options - `{ days, contract, interval }` (the API has no `date` param here).
106
+ */
107
+ async ohlc(options) {
108
+ const params = {};
109
+ if (options?.days !== undefined)
110
+ params.days = options.days.toString();
111
+ if (options?.contract)
112
+ params.contract = options.contract;
113
+ if (options?.interval)
114
+ params.interval = options.interval;
115
+ return this.client["request"](`/v1/futures/${this.slug}/ohlc`, params);
116
+ }
117
+ /**
118
+ * Get intraday price data for this contract family.
119
+ */
120
+ async intraday() {
121
+ return this.client["request"](`/v1/futures/${this.slug}/intraday`, {});
122
+ }
123
+ /**
124
+ * Get the spreads for this contract family.
125
+ */
126
+ async spreads() {
127
+ const response = await this.client["request"](`/v1/futures/${this.slug}/spreads`, {});
128
+ return Array.isArray(response) ? response : response.data;
129
+ }
130
+ /**
131
+ * Get the forward curve for this contract family.
132
+ */
133
+ async curve() {
134
+ return this.client["request"](`/v1/futures/${this.slug}/curve`, {});
135
+ }
136
+ /**
137
+ * Get historical spread data for this contract family.
138
+ */
139
+ async spreadHistory() {
140
+ return this.client["request"](`/v1/futures/${this.slug}/spread-history`, {});
141
+ }
142
+ }
8
143
  /**
9
144
  * Futures Resource
10
145
  *
@@ -226,4 +361,59 @@ export class FuturesResource {
226
361
  params.months = months.toString();
227
362
  return this.client["request"](`/v1/futures/${contract}/continuous`, params);
228
363
  }
364
+ /**
365
+ * Get a typed helper for a specific contract family (issue #1).
366
+ *
367
+ * Provides ergonomic access to the ICE Brent / WTI / Gasoil and gas/carbon
368
+ * family endpoints (`/latest`, `/historical`, `/ohlc`, `/intraday`,
369
+ * `/spreads`, `/curve`, `/spread-history`) without remembering the URL slug.
370
+ *
371
+ * @param slug - Contract family slug (e.g., `"ice-brent"`, `"ice-gasoil"`).
372
+ * @returns A {@link FuturesContractFamily} bound to the slug.
373
+ *
374
+ * @example
375
+ * ```typescript
376
+ * const brent = client.futures.family('ice-brent');
377
+ * const latest = await brent.latest();
378
+ * const curve = await brent.curve();
379
+ * ```
380
+ */
381
+ family(slug) {
382
+ if (!slug || typeof slug !== "string") {
383
+ throw new ValidationError("Contract family slug must be a non-empty string");
384
+ }
385
+ return new FuturesContractFamily(this.client, slug);
386
+ }
387
+ /** ICE Brent crude futures family helper (issue #1). */
388
+ brent() {
389
+ return this.family("ice-brent");
390
+ }
391
+ /** ICE WTI crude futures family helper. */
392
+ wti() {
393
+ return this.family("ice-wti");
394
+ }
395
+ /** ICE Gasoil futures family helper (issue #1). */
396
+ gasoil() {
397
+ return this.family("ice-gasoil");
398
+ }
399
+ /** Henry Hub natural gas futures family helper. */
400
+ naturalGas() {
401
+ return this.family("natural-gas");
402
+ }
403
+ /** TTF natural gas (Europe) futures family helper. */
404
+ ttfGas() {
405
+ return this.family("ttf-gas");
406
+ }
407
+ /** LNG JKM (Asia) futures family helper. */
408
+ lngJkm() {
409
+ return this.family("lng-jkm");
410
+ }
411
+ /** EU carbon allowance (EUA) futures family helper. */
412
+ euaCarbon() {
413
+ return this.family("eua-carbon");
414
+ }
415
+ /** UK carbon allowance (UKA) futures family helper. */
416
+ ukCarbon() {
417
+ return this.family("uk-carbon");
418
+ }
229
419
  }