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
@@ -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
@@ -4,6 +4,7 @@
4
4
  * Access crude oil storage data including total US inventory, Cushing hub levels,
5
5
  * Strategic Petroleum Reserve (SPR), and regional breakdowns.
6
6
  */
7
+ import { ValidationError } from "../errors.js";
7
8
  /**
8
9
  * Storage Resource
9
10
  *
@@ -148,14 +149,14 @@ export class StorageResource {
148
149
  */
149
150
  async history(code, options) {
150
151
  if (!code || typeof code !== "string") {
151
- throw new Error("Storage location code must be a non-empty string");
152
+ throw new ValidationError("Storage location code must be a non-empty string");
152
153
  }
153
154
  const params = {};
154
- if (options?.startDate)
155
- params.start_date = options.startDate;
156
- if (options?.endDate)
157
- params.end_date = options.endDate;
158
- 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);
159
160
  return Array.isArray(response) ? response : response.data;
160
161
  }
161
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
+ }