oilpriceapi 0.7.0 → 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 (81) hide show
  1. package/README.md +244 -30
  2. package/dist/cjs/client.js +610 -0
  3. package/dist/cjs/errors.js +80 -0
  4. package/dist/cjs/index.js +96 -0
  5. package/dist/cjs/package.json +1 -0
  6. package/dist/cjs/resources/alerts.js +387 -0
  7. package/dist/cjs/resources/analytics.js +188 -0
  8. package/dist/cjs/resources/bunker-fuels.js +210 -0
  9. package/dist/cjs/resources/commodities.js +115 -0
  10. package/dist/cjs/resources/data-quality.js +144 -0
  11. package/dist/cjs/resources/data-sources.js +298 -0
  12. package/dist/cjs/resources/diesel.js +119 -0
  13. package/dist/cjs/resources/drilling.js +269 -0
  14. package/dist/cjs/resources/ei/drilling-productivity.js +108 -0
  15. package/dist/cjs/resources/ei/forecasts.js +106 -0
  16. package/dist/cjs/resources/ei/frac-focus.js +165 -0
  17. package/dist/cjs/resources/ei/index.js +98 -0
  18. package/dist/cjs/resources/ei/oil-inventories.js +97 -0
  19. package/dist/cjs/resources/ei/opec-production.js +97 -0
  20. package/dist/cjs/resources/ei/rig-counts.js +93 -0
  21. package/dist/cjs/resources/ei/well-permits.js +136 -0
  22. package/dist/cjs/resources/forecasts.js +168 -0
  23. package/dist/cjs/resources/futures.js +424 -0
  24. package/dist/cjs/resources/indicators.js +79 -0
  25. package/dist/cjs/resources/raw.js +128 -0
  26. package/dist/cjs/resources/rig-counts.js +164 -0
  27. package/dist/cjs/resources/spreads.js +105 -0
  28. package/dist/cjs/resources/storage.js +166 -0
  29. package/dist/cjs/resources/streaming.js +350 -0
  30. package/dist/cjs/resources/webhooks.js +283 -0
  31. package/dist/cjs/types.js +2 -0
  32. package/dist/cjs/version.js +24 -0
  33. package/dist/client.d.ts +130 -3
  34. package/dist/client.js +206 -30
  35. package/dist/errors.d.ts +6 -0
  36. package/dist/errors.js +25 -16
  37. package/dist/index.d.ts +28 -5
  38. package/dist/index.js +29 -1
  39. package/dist/resources/alerts.js +31 -77
  40. package/dist/resources/analytics.d.ts +147 -214
  41. package/dist/resources/analytics.js +104 -141
  42. package/dist/resources/bunker-fuels.d.ts +35 -12
  43. package/dist/resources/bunker-fuels.js +41 -26
  44. package/dist/resources/commodities.js +2 -1
  45. package/dist/resources/data-quality.js +2 -1
  46. package/dist/resources/data-sources.d.ts +31 -31
  47. package/dist/resources/data-sources.js +30 -85
  48. package/dist/resources/diesel.d.ts +1 -1
  49. package/dist/resources/diesel.js +9 -38
  50. package/dist/resources/drilling.js +2 -1
  51. package/dist/resources/ei/drilling-productivity.js +2 -1
  52. package/dist/resources/ei/forecasts.js +2 -1
  53. package/dist/resources/ei/frac-focus.d.ts +23 -9
  54. package/dist/resources/ei/frac-focus.js +20 -9
  55. package/dist/resources/ei/index.js +2 -1
  56. package/dist/resources/ei/oil-inventories.js +2 -1
  57. package/dist/resources/ei/opec-production.js +2 -1
  58. package/dist/resources/ei/rig-counts.js +2 -1
  59. package/dist/resources/ei/well-permits.d.ts +25 -9
  60. package/dist/resources/ei/well-permits.js +20 -7
  61. package/dist/resources/forecasts.d.ts +4 -1
  62. package/dist/resources/forecasts.js +13 -6
  63. package/dist/resources/futures.d.ts +178 -1
  64. package/dist/resources/futures.js +199 -8
  65. package/dist/resources/indicators.d.ts +170 -0
  66. package/dist/resources/indicators.js +75 -0
  67. package/dist/resources/raw.d.ts +94 -0
  68. package/dist/resources/raw.js +124 -0
  69. package/dist/resources/rig-counts.js +5 -2
  70. package/dist/resources/spreads.d.ts +121 -0
  71. package/dist/resources/spreads.js +101 -0
  72. package/dist/resources/storage.d.ts +5 -4
  73. package/dist/resources/storage.js +7 -6
  74. package/dist/resources/streaming.d.ts +272 -0
  75. package/dist/resources/streaming.js +342 -0
  76. package/dist/resources/webhooks.d.ts +73 -23
  77. package/dist/resources/webhooks.js +59 -77
  78. package/dist/types.d.ts +43 -1
  79. package/dist/version.d.ts +1 -1
  80. package/dist/version.js +2 -2
  81. package/package.json +21 -6
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * Access oil and gas well permit data by state, operator, and formation.
5
5
  */
6
+ import { ValidationError } from "../../errors.js";
6
7
  /**
7
8
  * EI Well Permits Resource
8
9
  *
@@ -48,7 +49,7 @@ export class EIWellPermitsResource {
48
49
  */
49
50
  async get(id) {
50
51
  if (!id || typeof id !== "string") {
51
- throw new Error("Record ID must be a non-empty string");
52
+ throw new ValidationError("Record ID must be a non-empty string");
52
53
  }
53
54
  return this.client["request"](`/v1/ei/well-permits/${id}`, {});
54
55
  }
@@ -103,12 +104,24 @@ export class EIWellPermitsResource {
103
104
  */
104
105
  async search(query) {
105
106
  const params = {};
106
- if (query.state)
107
- params.state = query.state;
108
- if (query.operator)
109
- params.operator = query.operator;
110
- if (query.formation)
111
- 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();
112
125
  if (query.start_date)
113
126
  params.start_date = query.start_date;
114
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
  *
@@ -4,6 +4,7 @@
4
4
  * Access official price forecasts from EIA, IEA, and other agencies including
5
5
  * monthly outlooks, accuracy metrics, and historical archives.
6
6
  */
7
+ import { ValidationError } from "../errors.js";
7
8
  /**
8
9
  * Forecasts Resource
9
10
  *
@@ -84,7 +85,8 @@ export class ForecastsResource {
84
85
  * ```
85
86
  */
86
87
  async accuracy() {
87
- 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", {});
88
90
  }
89
91
  /**
90
92
  * Get archived forecasts
@@ -115,11 +117,16 @@ export class ForecastsResource {
115
117
  * });
116
118
  * ```
117
119
  */
118
- 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.
119
124
  const params = {};
120
- if (year)
121
- params.year = year.toString();
122
- 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);
123
130
  return Array.isArray(response) ? response : response.forecasts;
124
131
  }
125
132
  /**
@@ -147,7 +154,7 @@ export class ForecastsResource {
147
154
  */
148
155
  async get(period, commodity) {
149
156
  if (!period || typeof period !== "string") {
150
- throw new Error("Period must be a non-empty string");
157
+ throw new ValidationError("Period must be a non-empty string");
151
158
  }
152
159
  const params = {};
153
160
  if (commodity)
@@ -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
  }
@@ -4,6 +4,142 @@
4
4
  * Access futures contract data including latest prices, historical data,
5
5
  * OHLC, intraday, spreads, curves, and continuous contracts.
6
6
  */
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
+ }
7
143
  /**
8
144
  * Futures Resource
9
145
  *
@@ -52,7 +188,7 @@ export class FuturesResource {
52
188
  */
53
189
  async latest(contract) {
54
190
  if (!contract || typeof contract !== "string") {
55
- throw new Error("Contract symbol must be a non-empty string");
191
+ throw new ValidationError("Contract symbol must be a non-empty string");
56
192
  }
57
193
  return this.client["request"](`/v1/futures/${contract}`, {});
58
194
  }
@@ -77,7 +213,7 @@ export class FuturesResource {
77
213
  */
78
214
  async historical(contract, options) {
79
215
  if (!contract || typeof contract !== "string") {
80
- throw new Error("Contract symbol must be a non-empty string");
216
+ throw new ValidationError("Contract symbol must be a non-empty string");
81
217
  }
82
218
  const params = {};
83
219
  if (options?.startDate)
@@ -108,7 +244,7 @@ export class FuturesResource {
108
244
  */
109
245
  async ohlc(contract, date) {
110
246
  if (!contract || typeof contract !== "string") {
111
- throw new Error("Contract symbol must be a non-empty string");
247
+ throw new ValidationError("Contract symbol must be a non-empty string");
112
248
  }
113
249
  const params = {};
114
250
  if (date)
@@ -136,7 +272,7 @@ export class FuturesResource {
136
272
  */
137
273
  async intraday(contract) {
138
274
  if (!contract || typeof contract !== "string") {
139
- throw new Error("Contract symbol must be a non-empty string");
275
+ throw new ValidationError("Contract symbol must be a non-empty string");
140
276
  }
141
277
  return this.client["request"](`/v1/futures/${contract}/intraday`, {});
142
278
  }
@@ -161,10 +297,10 @@ export class FuturesResource {
161
297
  */
162
298
  async spreads(contract1, contract2) {
163
299
  if (!contract1 || typeof contract1 !== "string") {
164
- throw new Error("First contract symbol must be a non-empty string");
300
+ throw new ValidationError("First contract symbol must be a non-empty string");
165
301
  }
166
302
  if (!contract2 || typeof contract2 !== "string") {
167
- throw new Error("Second contract symbol must be a non-empty string");
303
+ throw new ValidationError("Second contract symbol must be a non-empty string");
168
304
  }
169
305
  return this.client["request"]("/v1/futures/spreads", {
170
306
  contract1,
@@ -193,7 +329,7 @@ export class FuturesResource {
193
329
  */
194
330
  async curve(contract) {
195
331
  if (!contract || typeof contract !== "string") {
196
- throw new Error("Contract symbol must be a non-empty string");
332
+ throw new ValidationError("Contract symbol must be a non-empty string");
197
333
  }
198
334
  return this.client["request"](`/v1/futures/${contract}/curve`, {});
199
335
  }
@@ -218,11 +354,66 @@ export class FuturesResource {
218
354
  */
219
355
  async continuous(contract, months) {
220
356
  if (!contract || typeof contract !== "string") {
221
- throw new Error("Contract symbol must be a non-empty string");
357
+ throw new ValidationError("Contract symbol must be a non-empty string");
222
358
  }
223
359
  const params = {};
224
360
  if (months !== undefined)
225
361
  params.months = months.toString();
226
362
  return this.client["request"](`/v1/futures/${contract}/continuous`, params);
227
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
+ }
228
419
  }