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
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Raw Response Resource
3
+ *
4
+ * Provides opt-in access to the underlying HTTP status code and response
5
+ * headers alongside the parsed data. Mirrors the most commonly used top-level
6
+ * client methods. This is the #1 requested enhancement (issue #7).
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { OilPriceAPI } from 'oilpriceapi';
11
+ *
12
+ * const client = new OilPriceAPI({ apiKey: 'your_key' });
13
+ *
14
+ * const { data, status, headers } = await client.raw.getLatestPrices();
15
+ * console.log(`HTTP ${status}`);
16
+ * console.log(`Rate limit remaining: ${headers.get('x-ratelimit-remaining')}`);
17
+ * console.log(data[0].price);
18
+ * ```
19
+ */
20
+ /**
21
+ * Raw Response Resource
22
+ *
23
+ * Each method returns an {@link APIResponse} with `{ data, status, headers }`
24
+ * instead of just the parsed data, so callers can inspect HTTP metadata such
25
+ * as rate-limit headers, caching headers, and the exact status code.
26
+ */
27
+ export class RawResource {
28
+ constructor(client) {
29
+ this.client = client;
30
+ }
31
+ /**
32
+ * Make an arbitrary GET request and return data plus HTTP status and headers.
33
+ *
34
+ * Use this for endpoints without a dedicated raw helper.
35
+ *
36
+ * @typeParam T - Expected parsed response type.
37
+ * @param endpoint - API path beginning with `/` (e.g. `/v1/prices/latest`).
38
+ * @param params - Optional query parameters.
39
+ * @returns The parsed data along with the HTTP status code and headers.
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * const { data, status, headers } = await client.raw.get('/v1/futures/CL.1');
44
+ * ```
45
+ */
46
+ async get(endpoint, params) {
47
+ return this.client["requestRaw"](endpoint, params);
48
+ }
49
+ /**
50
+ * Latest prices with raw HTTP status and headers.
51
+ *
52
+ * @param options - Optional commodity filter.
53
+ * @returns Prices array with HTTP status and headers.
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * const { data, status, headers } = await client.raw.getLatestPrices({ commodity: 'WTI_USD' });
58
+ * ```
59
+ */
60
+ async getLatestPrices(options) {
61
+ const params = {};
62
+ if (options?.commodity) {
63
+ params.by_code = options.commodity;
64
+ }
65
+ return this.client["requestRaw"]("/v1/prices/latest", params);
66
+ }
67
+ /**
68
+ * Historical prices with raw HTTP status and headers.
69
+ *
70
+ * @param options - Time period and filter options.
71
+ * @returns Prices array with HTTP status and headers.
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * const { data, status, headers } = await client.raw.getHistoricalPrices({
76
+ * period: 'past_week',
77
+ * commodity: 'BRENT_CRUDE_USD',
78
+ * });
79
+ * ```
80
+ */
81
+ async getHistoricalPrices(options) {
82
+ const params = {};
83
+ if (options?.period)
84
+ params.period = options.period;
85
+ if (options?.commodity)
86
+ params.by_code = options.commodity;
87
+ if (options?.startDate)
88
+ params.start_date = options.startDate;
89
+ if (options?.endDate)
90
+ params.end_date = options.endDate;
91
+ if (options?.interval)
92
+ params.interval = options.interval;
93
+ if (options?.perPage !== undefined)
94
+ params.per_page = options.perPage.toString();
95
+ if (options?.page !== undefined)
96
+ params.page = options.page.toString();
97
+ return this.client["requestRaw"]("/v1/prices/past_year", params);
98
+ }
99
+ /**
100
+ * Commodities metadata with raw HTTP status and headers.
101
+ *
102
+ * @returns Commodities response with HTTP status and headers.
103
+ */
104
+ async getCommodities() {
105
+ return this.client["requestRaw"]("/v1/commodities", {});
106
+ }
107
+ /**
108
+ * Commodity categories with raw HTTP status and headers.
109
+ *
110
+ * @returns Categories response with HTTP status and headers.
111
+ */
112
+ async getCommodityCategories() {
113
+ return this.client["requestRaw"]("/v1/commodities/categories", {});
114
+ }
115
+ /**
116
+ * A single commodity's metadata with raw HTTP status and headers.
117
+ *
118
+ * @param code - Commodity code (e.g., "WTI_USD").
119
+ * @returns Commodity with HTTP status and headers.
120
+ */
121
+ async getCommodity(code) {
122
+ return this.client["requestRaw"](`/v1/commodities/${code}`, {});
123
+ }
124
+ }
@@ -96,11 +96,14 @@ export class RigCountsResource {
96
96
  * ```
97
97
  */
98
98
  async historical(options) {
99
+ // The controller filters via `has_scope :by_period, using: %i[from to], type: :hash`,
100
+ // i.e. it reads nested `by_period[from]` / `by_period[to]` query params — NOT
101
+ // flat `start_date` / `end_date` (which were silently ignored by earlier SDKs).
99
102
  const params = {};
100
103
  if (options?.startDate)
101
- params.start_date = options.startDate;
104
+ params["by_period[from]"] = options.startDate;
102
105
  if (options?.endDate)
103
- params.end_date = options.endDate;
106
+ params["by_period[to]"] = options.endDate;
104
107
  const response = await this.client["request"]("/v1/rig-counts/historical", params);
105
108
  return Array.isArray(response) ? response : response.data;
106
109
  }
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Spreads Resource
3
+ *
4
+ * Access oil & product spread analytics: crack spreads, basis spreads,
5
+ * curve-structure (contango/backwardation), refining margins, and physical
6
+ * premiums. Each spread type supports the latest value, full history, and an
7
+ * `all` listing.
8
+ */
9
+ import type { OilPriceAPI } from "../client.js";
10
+ /**
11
+ * Supported spread types.
12
+ *
13
+ * - `crack` — refining crack spread (e.g., 3:2:1)
14
+ * - `basis` — regional basis differential vs benchmark
15
+ * - `curve-structure` — contango / backwardation structure
16
+ * - `margin` — refining margin
17
+ * - `physical-premium` — physical-vs-paper premium
18
+ */
19
+ export type SpreadType = "crack" | "basis" | "curve-structure" | "margin" | "physical-premium";
20
+ /**
21
+ * A single spread data point.
22
+ */
23
+ export interface SpreadValue {
24
+ /** Spread type slug */
25
+ type: string;
26
+ /** Spread name / label */
27
+ name?: string;
28
+ /** Spread value */
29
+ value: number;
30
+ /** Unit (e.g., "USD/bbl") */
31
+ unit?: string;
32
+ /** Region or market */
33
+ region?: string;
34
+ /** Benchmark or components */
35
+ components?: string[];
36
+ /** ISO timestamp */
37
+ timestamp: string;
38
+ /** Additional metadata */
39
+ metadata?: Record<string, unknown>;
40
+ }
41
+ /**
42
+ * Historical spread data point.
43
+ */
44
+ export interface HistoricalSpreadValue {
45
+ /** ISO date */
46
+ date: string;
47
+ /** Spread value */
48
+ value: number;
49
+ /** Unit */
50
+ unit?: string;
51
+ }
52
+ /**
53
+ * Options for a historical spread query.
54
+ */
55
+ export interface HistoricalSpreadOptions {
56
+ /** Start date (YYYY-MM-DD) */
57
+ startDate?: string;
58
+ /** End date (YYYY-MM-DD) */
59
+ endDate?: string;
60
+ }
61
+ /**
62
+ * Spreads Resource
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * import { OilPriceAPI } from 'oilpriceapi';
67
+ *
68
+ * const client = new OilPriceAPI({ apiKey: 'your_key' });
69
+ *
70
+ * // Latest crack spread
71
+ * const crack = await client.spreads.crack();
72
+ * console.log(`Crack spread: ${crack.value} ${crack.unit}`);
73
+ *
74
+ * // Historical basis spreads
75
+ * const history = await client.spreads.historical('basis', {
76
+ * startDate: '2024-01-01',
77
+ * endDate: '2024-12-31',
78
+ * });
79
+ *
80
+ * // All margin spreads
81
+ * const all = await client.spreads.all('margin');
82
+ * ```
83
+ */
84
+ export declare class SpreadsResource {
85
+ private client;
86
+ constructor(client: OilPriceAPI);
87
+ /**
88
+ * Get the latest value for a spread type.
89
+ *
90
+ * @param type - Spread type slug.
91
+ * @returns Latest spread value.
92
+ * @throws {ValidationError} If the type is invalid.
93
+ */
94
+ get(type: SpreadType): Promise<SpreadValue>;
95
+ /**
96
+ * Get historical data for a spread type.
97
+ *
98
+ * @param type - Spread type slug.
99
+ * @param options - Optional date range filters.
100
+ * @returns Array of historical spread values.
101
+ */
102
+ historical(type: SpreadType, options?: HistoricalSpreadOptions): Promise<HistoricalSpreadValue[]>;
103
+ /**
104
+ * Get all spread values for a spread type.
105
+ *
106
+ * @param type - Spread type slug.
107
+ * @returns Array of spread values.
108
+ */
109
+ all(type: SpreadType): Promise<SpreadValue[]>;
110
+ /** Latest crack spread. */
111
+ crack(): Promise<SpreadValue>;
112
+ /** Latest basis spread. */
113
+ basis(): Promise<SpreadValue>;
114
+ /** Latest curve-structure (contango / backwardation). */
115
+ curveStructure(): Promise<SpreadValue>;
116
+ /** Latest refining margin. */
117
+ margin(): Promise<SpreadValue>;
118
+ /** Latest physical premium. */
119
+ physicalPremium(): Promise<SpreadValue>;
120
+ private validateType;
121
+ }
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Spreads Resource
3
+ *
4
+ * Access oil & product spread analytics: crack spreads, basis spreads,
5
+ * curve-structure (contango/backwardation), refining margins, and physical
6
+ * premiums. Each spread type supports the latest value, full history, and an
7
+ * `all` listing.
8
+ */
9
+ import { ValidationError } from "../errors.js";
10
+ /**
11
+ * Spreads Resource
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * import { OilPriceAPI } from 'oilpriceapi';
16
+ *
17
+ * const client = new OilPriceAPI({ apiKey: 'your_key' });
18
+ *
19
+ * // Latest crack spread
20
+ * const crack = await client.spreads.crack();
21
+ * console.log(`Crack spread: ${crack.value} ${crack.unit}`);
22
+ *
23
+ * // Historical basis spreads
24
+ * const history = await client.spreads.historical('basis', {
25
+ * startDate: '2024-01-01',
26
+ * endDate: '2024-12-31',
27
+ * });
28
+ *
29
+ * // All margin spreads
30
+ * const all = await client.spreads.all('margin');
31
+ * ```
32
+ */
33
+ export class SpreadsResource {
34
+ constructor(client) {
35
+ this.client = client;
36
+ }
37
+ /**
38
+ * Get the latest value for a spread type.
39
+ *
40
+ * @param type - Spread type slug.
41
+ * @returns Latest spread value.
42
+ * @throws {ValidationError} If the type is invalid.
43
+ */
44
+ async get(type) {
45
+ this.validateType(type);
46
+ return this.client["request"](`/v1/spreads/${type}`, {});
47
+ }
48
+ /**
49
+ * Get historical data for a spread type.
50
+ *
51
+ * @param type - Spread type slug.
52
+ * @param options - Optional date range filters.
53
+ * @returns Array of historical spread values.
54
+ */
55
+ async historical(type, options) {
56
+ this.validateType(type);
57
+ const params = {};
58
+ if (options?.startDate)
59
+ params.start_date = options.startDate;
60
+ if (options?.endDate)
61
+ params.end_date = options.endDate;
62
+ const response = await this.client["request"](`/v1/spreads/${type}/historical`, params);
63
+ return Array.isArray(response) ? response : response.data;
64
+ }
65
+ /**
66
+ * Get all spread values for a spread type.
67
+ *
68
+ * @param type - Spread type slug.
69
+ * @returns Array of spread values.
70
+ */
71
+ async all(type) {
72
+ this.validateType(type);
73
+ const response = await this.client["request"](`/v1/spreads/${type}/all`, {});
74
+ return Array.isArray(response) ? response : response.data;
75
+ }
76
+ /** Latest crack spread. */
77
+ async crack() {
78
+ return this.get("crack");
79
+ }
80
+ /** Latest basis spread. */
81
+ async basis() {
82
+ return this.get("basis");
83
+ }
84
+ /** Latest curve-structure (contango / backwardation). */
85
+ async curveStructure() {
86
+ return this.get("curve-structure");
87
+ }
88
+ /** Latest refining margin. */
89
+ async margin() {
90
+ return this.get("margin");
91
+ }
92
+ /** Latest physical premium. */
93
+ async physicalPremium() {
94
+ return this.get("physical-premium");
95
+ }
96
+ validateType(type) {
97
+ if (!type || typeof type !== "string") {
98
+ throw new ValidationError("Spread type must be a non-empty string");
99
+ }
100
+ }
101
+ }
@@ -43,10 +43,11 @@ export interface HistoricalStorageData {
43
43
  * Options for historical storage query
44
44
  */
45
45
  export interface HistoricalStorageOptions {
46
- /** Start date in ISO 8601 format (YYYY-MM-DD) */
47
- startDate?: string;
48
- /** End date in ISO 8601 format (YYYY-MM-DD) */
49
- endDate?: string;
46
+ /**
47
+ * Lookback period. The API reads a `period` token, one of
48
+ * '7d' | '30d' | '90d' (default) | '1y' | 'all' — not arbitrary date ranges.
49
+ */
50
+ period?: "7d" | "30d" | "90d" | "1y" | "all";
50
51
  }
51
52
  /**
52
53
  * Storage Resource
@@ -152,11 +152,11 @@ export class StorageResource {
152
152
  throw new ValidationError("Storage location code must be a non-empty string");
153
153
  }
154
154
  const params = {};
155
- if (options?.startDate)
156
- params.start_date = options.startDate;
157
- if (options?.endDate)
158
- params.end_date = options.endDate;
159
- const response = await this.client["request"](`/v1/storage/${code}/history`, params);
155
+ if (options?.period)
156
+ params.period = options.period;
157
+ // Route is GET /v1/storage/history/:code (the :code segment comes AFTER
158
+ // `history`), and the controller reads a `period` token.
159
+ const response = await this.client["request"](`/v1/storage/history/${code}`, params);
160
160
  return Array.isArray(response) ? response : response.data;
161
161
  }
162
162
  }
@@ -0,0 +1,272 @@
1
+ /**
2
+ * WebSocket Streaming Resource
3
+ *
4
+ * Real-time price streaming via the OilPriceAPI ActionCable endpoint
5
+ * (`wss://api.oilpriceapi.com/cable`).
6
+ *
7
+ * Streaming is a **Reservoir Mastery (Professional+)** feature. Connections
8
+ * authenticate with your API key and subscribe to the `EnergyPricesChannel`,
9
+ * which pushes an initial `welcome` snapshot followed by live `price_update`
10
+ * and (for drilling-tier accounts) `rig_count_update` messages.
11
+ *
12
+ * The implementation speaks the raw ActionCable JSON subprotocol over the
13
+ * `ws` package: it performs the `welcome` -> `subscribe` ->
14
+ * `confirm_subscription` handshake, answers server `ping` frames, and
15
+ * surfaces decoded channel messages as typed events. Auto-reconnect with
16
+ * exponential backoff keeps the stream alive across transient network drops.
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * const sub = client.stream.prices({}, (update) => {
21
+ * console.log(update.prices.oil.wti?.original_price);
22
+ * });
23
+ *
24
+ * sub.on("rig_count_update", (m) => console.log(m.rig_count.region, m.rig_count.count));
25
+ * sub.on("error", (err) => console.error(err));
26
+ *
27
+ * // later
28
+ * sub.close();
29
+ * ```
30
+ */
31
+ import { EventEmitter } from "node:events";
32
+ import WebSocket from "ws";
33
+ import type { OilPriceAPI } from "../client.js";
34
+ /**
35
+ * The ActionCable channel exposed by the OilPriceAPI server.
36
+ *
37
+ * Confirmed from `app/channels/energy_prices_channel.rb`
38
+ * (`class EnergyPricesChannel`).
39
+ */
40
+ export declare const ENERGY_PRICES_CHANNEL = "EnergyPricesChannel";
41
+ /**
42
+ * A single normalized price point as broadcast by the server.
43
+ *
44
+ * Mirrors the shape produced by `BroadcastEnergyPricesJob#normalized_price_for_cached`
45
+ * and `EnergyPricesChannel#normalize_price`.
46
+ */
47
+ export interface StreamedPrice {
48
+ /** Price converted to the common base unit (USD / MMBtu). */
49
+ normalized_price: number | null;
50
+ /** Original price in its native unit/currency. */
51
+ original_price: number | null;
52
+ /** Native unit (e.g. `"barrel_oil"`, `"mmbtu"`). */
53
+ original_unit: string;
54
+ /** Native currency (e.g. `"USD"`, `"GBP"`, `"EUR"`). */
55
+ original_currency: string;
56
+ /** ISO-8601 timestamp of the underlying price record. */
57
+ timestamp: string;
58
+ /** 24h absolute change (present on the initial `welcome` snapshot). */
59
+ change_24h?: number;
60
+ /** 24h percent change (present on the initial `welcome` snapshot). */
61
+ change_24h_percent?: number;
62
+ }
63
+ /**
64
+ * The `prices` map carried by `welcome` and `price_update` messages.
65
+ */
66
+ export interface StreamedPriceMap {
67
+ oil: {
68
+ brent: StreamedPrice | null;
69
+ wti: StreamedPrice | null;
70
+ };
71
+ natural_gas: {
72
+ uk: StreamedPrice | null;
73
+ us: StreamedPrice | null;
74
+ eu: StreamedPrice | null;
75
+ };
76
+ }
77
+ /**
78
+ * Live `price_update` broadcast (the most common streamed message).
79
+ */
80
+ export interface PriceUpdateMessage {
81
+ type: "price_update";
82
+ timestamp: string;
83
+ base_currency: string;
84
+ base_unit: string;
85
+ prices: StreamedPriceMap;
86
+ }
87
+ /**
88
+ * Initial snapshot transmitted immediately on subscription confirmation.
89
+ *
90
+ * Note: the server uses `type: "welcome"` for this *channel* message. It is
91
+ * distinct from the ActionCable transport-level `welcome` frame, which the
92
+ * client consumes internally and never surfaces.
93
+ */
94
+ export interface WelcomeMessage {
95
+ type: "welcome";
96
+ data: {
97
+ timestamp?: string;
98
+ base_currency?: string;
99
+ base_unit?: string;
100
+ prices?: StreamedPriceMap;
101
+ /** Present only for drilling-tier accounts. */
102
+ drilling_intelligence?: Record<string, unknown>;
103
+ /** Present when the initial snapshot could not be built. */
104
+ error?: string;
105
+ };
106
+ }
107
+ /**
108
+ * Rig-count update broadcast (drilling / Reservoir Mastery accounts).
109
+ */
110
+ export interface RigCountUpdateMessage {
111
+ type: "rig_count_update";
112
+ timestamp: string;
113
+ rig_count: {
114
+ code: string;
115
+ region: string;
116
+ count: number;
117
+ source: string;
118
+ updated_at: string;
119
+ };
120
+ }
121
+ /**
122
+ * Any decoded channel message. Unknown `type` values are passed through so
123
+ * forward-compatible servers don't break older SDKs.
124
+ */
125
+ export type StreamMessage = WelcomeMessage | PriceUpdateMessage | RigCountUpdateMessage | {
126
+ type: string;
127
+ [key: string]: unknown;
128
+ };
129
+ /**
130
+ * Options for {@link StreamingResource.prices}.
131
+ */
132
+ export interface StreamPricesOptions {
133
+ /**
134
+ * Optional client-side filter. When provided, only `price_update` messages
135
+ * whose normalized map contains at least one of these commodity slugs are
136
+ * delivered to `onUpdate` / the `price_update` event.
137
+ *
138
+ * Accepts the streamed slugs (`"brent"`, `"wti"`, `"uk"`, `"us"`, `"eu"`)
139
+ * or the upstream codes (`"BRENT_CRUDE_USD"`, `"WTI_USD"`,
140
+ * `"NATURAL_GAS_GBP"`, `"NATURAL_GAS_USD"`, `"DUTCH_TTF_EUR"`).
141
+ *
142
+ * The server broadcasts the full map regardless; filtering is applied
143
+ * locally so callers can scope updates without extra config.
144
+ */
145
+ commodities?: string[];
146
+ /** Disable automatic reconnection (default: reconnect enabled). */
147
+ autoReconnect?: boolean;
148
+ /** Base reconnect delay in ms (default: 1000). */
149
+ reconnectDelay?: number;
150
+ /** Maximum reconnect delay in ms for the exponential backoff (default: 30000). */
151
+ maxReconnectDelay?: number;
152
+ /**
153
+ * Maximum number of consecutive reconnect attempts before giving up and
154
+ * emitting a terminal `error`. `Infinity` to retry forever (default: 10).
155
+ */
156
+ maxReconnectAttempts?: number;
157
+ }
158
+ /** Callback invoked for each delivered `price_update` message. */
159
+ export type PriceUpdateHandler = (update: PriceUpdateMessage) => void;
160
+ /**
161
+ * Handle for an active price stream.
162
+ *
163
+ * Extends `EventEmitter`. Emitted events:
164
+ * - `"connected"` — transport connected and subscription confirmed
165
+ * - `"welcome"` — initial snapshot ({@link WelcomeMessage})
166
+ * - `"price_update"` — live price broadcast ({@link PriceUpdateMessage})
167
+ * - `"rig_count_update"` — drilling broadcast ({@link RigCountUpdateMessage})
168
+ * - `"message"` — every decoded channel message ({@link StreamMessage})
169
+ * - `"reconnecting"` — a reconnect attempt is scheduled (`{ attempt, delay }`)
170
+ * - `"disconnected"` — transport closed (`{ code, reason }`)
171
+ * - `"error"` — an `Error` (transport error, unauthorized, or retries exhausted)
172
+ * - `"close"` — the subscription was closed via {@link PriceStreamSubscription.close}
173
+ */
174
+ export declare class PriceStreamSubscription extends EventEmitter {
175
+ private readonly wsImpl;
176
+ private ws;
177
+ private readonly url;
178
+ private readonly apiKey;
179
+ private readonly identifier;
180
+ private readonly options;
181
+ private readonly commodityFilter;
182
+ private closed;
183
+ private subscribed;
184
+ private reconnectAttempts;
185
+ private reconnectTimer;
186
+ /**
187
+ * @param url - The `wss://.../cable` endpoint.
188
+ * @param apiKey - API key sent as the ActionCable `Authorization: Token <key>` header.
189
+ * @param options - Reconnect + filter options.
190
+ * @param wsImpl - Injectable WebSocket constructor (used by tests to mock).
191
+ * @internal Construct via {@link StreamingResource.prices}.
192
+ */
193
+ constructor(url: string, apiKey: string, options: StreamPricesOptions, wsImpl?: typeof WebSocket);
194
+ /**
195
+ * Open the transport and begin the ActionCable handshake.
196
+ * @internal Called once by {@link StreamingResource.prices}.
197
+ */
198
+ connect(): void;
199
+ private handleRaw;
200
+ private dispatch;
201
+ private matchesFilter;
202
+ private scheduleReconnect;
203
+ private send;
204
+ /** Whether the channel subscription has been confirmed by the server. */
205
+ get isSubscribed(): boolean;
206
+ /**
207
+ * Cleanly tear down the stream: cancels any pending reconnect, unsubscribes
208
+ * from the channel, and closes the socket. Safe to call multiple times.
209
+ * Emits `"close"` once.
210
+ */
211
+ close(): void;
212
+ }
213
+ /**
214
+ * Streaming resource — entry point for real-time price subscriptions.
215
+ *
216
+ * Accessed via `client.stream`.
217
+ */
218
+ export declare class StreamingResource {
219
+ private client;
220
+ /**
221
+ * Injectable WebSocket implementation. Defaults to the `ws` package;
222
+ * tests pass a mock constructor.
223
+ * @internal
224
+ */
225
+ private wsImpl;
226
+ constructor(client: OilPriceAPI,
227
+ /**
228
+ * Injectable WebSocket implementation. Defaults to the `ws` package;
229
+ * tests pass a mock constructor.
230
+ * @internal
231
+ */
232
+ wsImpl?: typeof WebSocket);
233
+ /**
234
+ * Derive the `wss://.../cable` endpoint from the client's REST base URL.
235
+ *
236
+ * `https://api.oilpriceapi.com` -> `wss://api.oilpriceapi.com/cable`
237
+ * `http://localhost:5000` -> `ws://localhost:5000/cable`
238
+ */
239
+ private cableUrl;
240
+ /**
241
+ * Open a real-time price stream over the `EnergyPricesChannel`.
242
+ *
243
+ * Returns a {@link PriceStreamSubscription} handle (an `EventEmitter`) you
244
+ * can attach further listeners to and `.close()` when done. The optional
245
+ * `onUpdate` callback is a convenience wired to the `price_update` event.
246
+ *
247
+ * @param options - Filtering and reconnect options.
248
+ * @param onUpdate - Optional callback for each `price_update` message.
249
+ * @returns The subscription handle.
250
+ *
251
+ * @throws {OilPriceAPIError} If no API key is configured on the client.
252
+ *
253
+ * @example
254
+ * ```typescript
255
+ * const client = new OilPriceAPI({ apiKey: process.env.OILPRICEAPI_KEY });
256
+ *
257
+ * const sub = client.stream.prices(
258
+ * { commodities: ["WTI_USD", "BRENT_CRUDE_USD"] },
259
+ * (update) => {
260
+ * const wti = update.prices.oil.wti;
261
+ * if (wti) console.log(`WTI ${wti.original_price} @ ${update.timestamp}`);
262
+ * },
263
+ * );
264
+ *
265
+ * sub.on("connected", () => console.log("streaming live"));
266
+ * sub.on("error", (err) => console.error("stream error:", err));
267
+ *
268
+ * process.on("SIGINT", () => sub.close());
269
+ * ```
270
+ */
271
+ prices(options?: StreamPricesOptions, onUpdate?: PriceUpdateHandler): PriceStreamSubscription;
272
+ }