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
@@ -14,6 +14,10 @@ export type DataSourceType = "api" | "database" | "file" | "sftp" | "webhook" |
14
14
  export type DataSourceStatus = "active" | "paused" | "error" | "pending";
15
15
  /**
16
16
  * Data source configuration
17
+ *
18
+ * NOTE: The API reads `source_type`, `scraper_config`, `status` and `credentials`
19
+ * (nested under `data_source`). Earlier SDK versions used `type`/`config`/`enabled`,
20
+ * which the controller silently dropped.
17
21
  */
18
22
  export interface DataSource {
19
23
  /** Unique data source identifier */
@@ -21,63 +25,59 @@ export interface DataSource {
21
25
  /** User-friendly name */
22
26
  name: string;
23
27
  /** Data source type */
24
- type: DataSourceType;
25
- /** Connection configuration (encrypted) */
26
- config: Record<string, unknown>;
27
- /** Whether the data source is active */
28
- enabled: boolean;
28
+ source_type: DataSourceType;
29
+ /** Scraper / connection configuration */
30
+ scraper_config?: Record<string, unknown>;
29
31
  /** Current status */
30
32
  status: DataSourceStatus;
31
33
  /** Last successful sync timestamp */
32
34
  last_sync_at?: string;
33
35
  /** Next scheduled sync timestamp */
34
36
  next_sync_at?: string;
35
- /** Sync frequency in minutes */
36
- sync_frequency_minutes?: number;
37
37
  /** Number of successful syncs */
38
- successful_syncs: number;
38
+ successful_syncs?: number;
39
39
  /** Number of failed syncs */
40
- failed_syncs: number;
40
+ failed_syncs?: number;
41
41
  /** Last error message */
42
42
  last_error?: string;
43
- /** Optional metadata */
44
- metadata?: Record<string, unknown>;
45
43
  /** ISO timestamp when source was created */
46
44
  created_at: string;
47
45
  /** ISO timestamp when source was last updated */
48
46
  updated_at: string;
49
47
  }
50
48
  /**
51
- * Parameters for creating a data source
49
+ * Parameters for creating a data source.
50
+ *
51
+ * Maps to the controller's `data_source_params` strong params:
52
+ * `source_type`, `name`, `status`, `credentials`, `scraper_config`.
52
53
  */
53
54
  export interface CreateDataSourceParams {
54
55
  /** User-friendly name */
55
56
  name: string;
56
57
  /** Data source type */
57
- type: DataSourceType;
58
- /** Connection configuration */
59
- config: Record<string, unknown>;
60
- /** Whether to enable immediately (default: true) */
61
- enabled?: boolean;
62
- /** Sync frequency in minutes (default: 60) */
63
- sync_frequency_minutes?: number;
64
- /** Optional metadata */
65
- metadata?: Record<string, unknown>;
58
+ source_type: DataSourceType;
59
+ /** Scraper / connection configuration */
60
+ scraper_config?: Record<string, unknown>;
61
+ /** Credentials (encrypted server-side) */
62
+ credentials?: Record<string, unknown>;
63
+ /** Lifecycle status */
64
+ status?: DataSourceStatus;
66
65
  }
67
66
  /**
68
- * Parameters for updating a data source
67
+ * Parameters for updating a data source.
68
+ *
69
+ * Maps to `data_source_update_params`: `name`, `status`, `credentials`,
70
+ * `scraper_config` (source_type cannot be changed).
69
71
  */
70
72
  export interface UpdateDataSourceParams {
71
73
  /** User-friendly name */
72
74
  name?: string;
73
- /** Connection configuration */
74
- config?: Record<string, unknown>;
75
- /** Whether the data source is active */
76
- enabled?: boolean;
77
- /** Sync frequency in minutes */
78
- sync_frequency_minutes?: number;
79
- /** Metadata */
80
- metadata?: Record<string, unknown>;
75
+ /** Scraper / connection configuration */
76
+ scraper_config?: Record<string, unknown>;
77
+ /** Credentials (encrypted server-side) */
78
+ credentials?: Record<string, unknown>;
79
+ /** Lifecycle status */
80
+ status?: DataSourceStatus;
81
81
  }
82
82
  /**
83
83
  * Data source test response
@@ -361,5 +361,5 @@ export declare class DataSourcesResource {
361
361
  * console.log(`Credential rotation: ${result.success ? 'success' : 'failed'}`);
362
362
  * ```
363
363
  */
364
- rotateCredentials(id: string): Promise<CredentialRotationResponse>;
364
+ rotateCredentials(id: string, credentials: Record<string, unknown>): Promise<CredentialRotationResponse>;
365
365
  }
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * Manage custom data source integrations for Bring Your Own Source (BYOS) feature.
5
5
  */
6
+ import { ValidationError } from "../errors.js";
6
7
  /**
7
8
  * Data Sources Resource
8
9
  *
@@ -86,7 +87,7 @@ export class DataSourcesResource {
86
87
  */
87
88
  async get(id) {
88
89
  if (!id || typeof id !== "string") {
89
- throw new Error("Data source ID must be a non-empty string");
90
+ throw new ValidationError("Data source ID must be a non-empty string");
90
91
  }
91
92
  const response = await this.client["request"](`/v1/data-sources/${id}`, {});
92
93
  return "data_source" in response ? response.data_source : response;
@@ -117,38 +118,24 @@ export class DataSourcesResource {
117
118
  */
118
119
  async create(params) {
119
120
  if (!params.name || typeof params.name !== "string") {
120
- throw new Error("Data source name is required");
121
+ throw new ValidationError("Data source name is required");
121
122
  }
122
- if (!params.type) {
123
- throw new Error("Data source type is required");
123
+ if (!params.source_type) {
124
+ throw new ValidationError("Data source source_type is required");
124
125
  }
125
- if (!params.config || typeof params.config !== "object") {
126
- throw new Error("Data source config is required");
127
- }
128
- const url = `${this.client["baseUrl"]}/v1/data-sources`;
129
- const response = await fetch(url, {
126
+ const response = await this.client["request"]("/v1/data-sources", {}, {
130
127
  method: "POST",
131
- headers: {
132
- Authorization: `Bearer ${this.client["apiKey"]}`,
133
- "Content-Type": "application/json",
134
- },
135
- body: JSON.stringify({
128
+ body: {
136
129
  data_source: {
137
130
  name: params.name,
138
- type: params.type,
139
- config: params.config,
140
- enabled: params.enabled ?? true,
141
- sync_frequency_minutes: params.sync_frequency_minutes ?? 60,
142
- metadata: params.metadata,
131
+ source_type: params.source_type,
132
+ status: params.status,
133
+ credentials: params.credentials,
134
+ scraper_config: params.scraper_config,
143
135
  },
144
- }),
136
+ },
145
137
  });
146
- if (!response.ok) {
147
- const errorText = await response.text();
148
- throw new Error(`Failed to create data source: ${response.status} ${errorText}`);
149
- }
150
- const data = (await response.json());
151
- return "data_source" in data ? data.data_source : data;
138
+ return "data_source" in response ? response.data_source : response;
152
139
  }
153
140
  /**
154
141
  * Update a data source
@@ -173,25 +160,13 @@ export class DataSourcesResource {
173
160
  */
174
161
  async update(id, params) {
175
162
  if (!id || typeof id !== "string") {
176
- throw new Error("Data source ID must be a non-empty string");
163
+ throw new ValidationError("Data source ID must be a non-empty string");
177
164
  }
178
- const url = `${this.client["baseUrl"]}/v1/data-sources/${id}`;
179
- const response = await fetch(url, {
165
+ const response = await this.client["request"](`/v1/data-sources/${id}`, {}, {
180
166
  method: "PATCH",
181
- headers: {
182
- Authorization: `Bearer ${this.client["apiKey"]}`,
183
- "Content-Type": "application/json",
184
- },
185
- body: JSON.stringify({
186
- data_source: params,
187
- }),
167
+ body: { data_source: params },
188
168
  });
189
- if (!response.ok) {
190
- const errorText = await response.text();
191
- throw new Error(`Failed to update data source: ${response.status} ${errorText}`);
192
- }
193
- const data = (await response.json());
194
- return "data_source" in data ? data.data_source : data;
169
+ return "data_source" in response ? response.data_source : response;
195
170
  }
196
171
  /**
197
172
  * Delete a data source
@@ -209,20 +184,9 @@ export class DataSourcesResource {
209
184
  */
210
185
  async delete(id) {
211
186
  if (!id || typeof id !== "string") {
212
- throw new Error("Data source ID must be a non-empty string");
213
- }
214
- const url = `${this.client["baseUrl"]}/v1/data-sources/${id}`;
215
- const response = await fetch(url, {
216
- method: "DELETE",
217
- headers: {
218
- Authorization: `Bearer ${this.client["apiKey"]}`,
219
- "Content-Type": "application/json",
220
- },
221
- });
222
- if (!response.ok) {
223
- const errorText = await response.text();
224
- throw new Error(`Failed to delete data source: ${response.status} ${errorText}`);
187
+ throw new ValidationError("Data source ID must be a non-empty string");
225
188
  }
189
+ await this.client["request"](`/v1/data-sources/${id}`, {}, { method: "DELETE" });
226
190
  }
227
191
  /**
228
192
  * Test a data source connection
@@ -245,21 +209,9 @@ export class DataSourcesResource {
245
209
  */
246
210
  async test(id) {
247
211
  if (!id || typeof id !== "string") {
248
- throw new Error("Data source ID must be a non-empty string");
212
+ throw new ValidationError("Data source ID must be a non-empty string");
249
213
  }
250
- const url = `${this.client["baseUrl"]}/v1/data-sources/${id}/test`;
251
- const response = await fetch(url, {
252
- method: "POST",
253
- headers: {
254
- Authorization: `Bearer ${this.client["apiKey"]}`,
255
- "Content-Type": "application/json",
256
- },
257
- });
258
- if (!response.ok) {
259
- const errorText = await response.text();
260
- throw new Error(`Failed to test data source: ${response.status} ${errorText}`);
261
- }
262
- return response.json();
214
+ return this.client["request"](`/v1/data-sources/${id}/test`, {}, { method: "POST" });
263
215
  }
264
216
  /**
265
217
  * Get data source sync logs
@@ -283,7 +235,7 @@ export class DataSourcesResource {
283
235
  */
284
236
  async logs(id) {
285
237
  if (!id || typeof id !== "string") {
286
- throw new Error("Data source ID must be a non-empty string");
238
+ throw new ValidationError("Data source ID must be a non-empty string");
287
239
  }
288
240
  const response = await this.client["request"](`/v1/data-sources/${id}/logs`, {});
289
241
  return Array.isArray(response) ? response : response.logs;
@@ -307,7 +259,7 @@ export class DataSourcesResource {
307
259
  */
308
260
  async health(id) {
309
261
  if (!id || typeof id !== "string") {
310
- throw new Error("Data source ID must be a non-empty string");
262
+ throw new ValidationError("Data source ID must be a non-empty string");
311
263
  }
312
264
  return this.client["request"](`/v1/data-sources/${id}/health`, {});
313
265
  }
@@ -328,22 +280,15 @@ export class DataSourcesResource {
328
280
  * console.log(`Credential rotation: ${result.success ? 'success' : 'failed'}`);
329
281
  * ```
330
282
  */
331
- async rotateCredentials(id) {
283
+ async rotateCredentials(id, credentials) {
332
284
  if (!id || typeof id !== "string") {
333
- throw new Error("Data source ID must be a non-empty string");
285
+ throw new ValidationError("Data source ID must be a non-empty string");
334
286
  }
335
- const url = `${this.client["baseUrl"]}/v1/data-sources/${id}/rotate-credentials`;
336
- const response = await fetch(url, {
337
- method: "POST",
338
- headers: {
339
- Authorization: `Bearer ${this.client["apiKey"]}`,
340
- "Content-Type": "application/json",
341
- },
342
- });
343
- if (!response.ok) {
344
- const errorText = await response.text();
345
- throw new Error(`Failed to rotate credentials: ${response.status} ${errorText}`);
287
+ if (!credentials || typeof credentials !== "object") {
288
+ throw new ValidationError("New credentials object is required");
346
289
  }
347
- return response.json();
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 } });
348
293
  }
349
294
  }
@@ -1,4 +1,4 @@
1
- import type { OilPriceAPI } from '../client.js';
1
+ import type { OilPriceAPI } from "../client.js";
2
2
  /**
3
3
  * Diesel price data for a specific state or region
4
4
  */
@@ -1,3 +1,4 @@
1
+ import { ValidationError } from "../errors.js";
1
2
  /**
2
3
  * Diesel Prices resource
3
4
  *
@@ -50,9 +51,9 @@ export class DieselResource {
50
51
  */
51
52
  async getPrice(state) {
52
53
  if (!state || state.length !== 2) {
53
- throw new Error('State must be a 2-letter US state code (e.g., "CA", "TX")');
54
+ throw new ValidationError('State must be a 2-letter US state code (e.g., "CA", "TX")');
54
55
  }
55
- const response = await this.client['request']('/v1/diesel-prices', { state: state.toUpperCase() });
56
+ const response = await this.client["request"]("/v1/diesel-prices", { state: state.toUpperCase() });
56
57
  return response.regional_average;
57
58
  }
58
59
  /**
@@ -98,47 +99,17 @@ export class DieselResource {
98
99
  const { lat, lng, radius = 8047 } = options;
99
100
  // Validate coordinates
100
101
  if (lat < -90 || lat > 90) {
101
- throw new Error('Latitude must be between -90 and 90');
102
+ throw new ValidationError("Latitude must be between -90 and 90");
102
103
  }
103
104
  if (lng < -180 || lng > 180) {
104
- throw new Error('Longitude must be between -180 and 180');
105
+ throw new ValidationError("Longitude must be between -180 and 180");
105
106
  }
106
107
  if (radius < 0 || radius > 50000) {
107
- throw new Error('Radius must be between 0 and 50000 meters');
108
+ throw new ValidationError("Radius must be between 0 and 50000 meters");
108
109
  }
109
- // Use POST request for stations endpoint
110
- const response = await fetch(`${this.client['baseUrl']}/v1/diesel-prices/stations`, {
111
- method: 'POST',
112
- headers: {
113
- 'Authorization': `Bearer ${this.client['apiKey']}`,
114
- 'Content-Type': 'application/json',
115
- 'User-Agent': 'oilpriceapi-node/0.4.0',
116
- 'X-SDK-Language': 'javascript',
117
- 'X-SDK-Version': '0.4.0',
118
- 'X-Client-Type': 'sdk',
119
- },
120
- body: JSON.stringify({ lat, lng, radius }),
110
+ return this.client["request"]("/v1/diesel-prices/stations", {}, {
111
+ method: "POST",
112
+ body: { lat, lng, radius },
121
113
  });
122
- if (!response.ok) {
123
- const errorBody = await response.text();
124
- let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
125
- try {
126
- const errorJson = JSON.parse(errorBody);
127
- errorMessage = errorJson.message || errorJson.error || errorMessage;
128
- }
129
- catch {
130
- // Use default error message
131
- }
132
- // Handle specific status codes
133
- if (response.status === 403) {
134
- throw new Error(`Diesel station queries not available on your plan. ${errorMessage}`);
135
- }
136
- if (response.status === 429) {
137
- throw new Error(`Diesel station query limit exceeded. ${errorMessage}`);
138
- }
139
- throw new Error(errorMessage);
140
- }
141
- const data = await response.json();
142
- return data;
143
114
  }
144
115
  }
@@ -4,6 +4,7 @@
4
4
  * Access US onshore drilling activity data including rig counts, well permits,
5
5
  * frac spreads, DUC wells, completions, and production trends by basin.
6
6
  */
7
+ import { ValidationError } from "../errors.js";
7
8
  /**
8
9
  * Drilling Intelligence Resource
9
10
  *
@@ -257,7 +258,7 @@ export class DrillingIntelligenceResource {
257
258
  */
258
259
  async basin(name) {
259
260
  if (!name || typeof name !== "string") {
260
- throw new Error("Basin name must be a non-empty string");
261
+ throw new ValidationError("Basin name must be a non-empty string");
261
262
  }
262
263
  return this.client["request"](`/v1/drilling-intelligence/basin/${name}`, {});
263
264
  }
@@ -4,6 +4,7 @@
4
4
  * Access EIA Drilling Productivity Report data including new well production,
5
5
  * legacy decline rates, and DUC well inventories by basin.
6
6
  */
7
+ import { ValidationError } from "../../errors.js";
7
8
  /**
8
9
  * EI Drilling Productivity Resource
9
10
  *
@@ -44,7 +45,7 @@ export class EIDrillingProductivityResource {
44
45
  */
45
46
  async get(id) {
46
47
  if (!id || typeof id !== "string") {
47
- throw new Error("Record ID must be a non-empty string");
48
+ throw new ValidationError("Record ID must be a non-empty string");
48
49
  }
49
50
  return this.client["request"](`/v1/ei/drilling_productivities/${id}`, {});
50
51
  }
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * Access EIA and IEA price and production forecasts with historical accuracy metrics.
5
5
  */
6
+ import { ValidationError } from "../../errors.js";
6
7
  /**
7
8
  * EI Forecasts Resource
8
9
  *
@@ -42,7 +43,7 @@ export class EIForecastsResource {
42
43
  */
43
44
  async get(id) {
44
45
  if (!id || typeof id !== "string") {
45
- throw new Error("Record ID must be a non-empty string");
46
+ throw new ValidationError("Record ID must be a non-empty string");
46
47
  }
47
48
  return this.client["request"](`/v1/ei/forecasts/${id}`, {});
48
49
  }
@@ -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
  /**
@@ -4,6 +4,7 @@
4
4
  * Access hydraulic fracturing disclosure data including chemicals, operators,
5
5
  * and well-level information from the FracFocus registry.
6
6
  */
7
+ import { ValidationError } from "../../errors.js";
7
8
  /**
8
9
  * EI FracFocus Resource
9
10
  *
@@ -53,7 +54,7 @@ export class EIFracFocusResource {
53
54
  */
54
55
  async get(id) {
55
56
  if (!id || typeof id !== "string") {
56
- throw new Error("Record ID must be a non-empty string");
57
+ throw new ValidationError("Record ID must be a non-empty string");
57
58
  }
58
59
  return this.client["request"](`/v1/ei/frac-focus/${id}`, {});
59
60
  }
@@ -108,12 +109,22 @@ export class EIFracFocusResource {
108
109
  */
109
110
  async search(query) {
110
111
  const params = {};
111
- if (query.state)
112
- params.state = query.state;
113
- if (query.operator)
114
- params.operator = query.operator;
115
- if (query.chemical)
116
- 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();
117
128
  if (query.start_date)
118
129
  params.start_date = query.start_date;
119
130
  if (query.end_date)
@@ -129,7 +140,7 @@ export class EIFracFocusResource {
129
140
  */
130
141
  async chemicals(id) {
131
142
  if (!id || typeof id !== "string") {
132
- throw new Error("Disclosure ID must be a non-empty string");
143
+ throw new ValidationError("Disclosure ID must be a non-empty string");
133
144
  }
134
145
  const response = await this.client["request"](`/v1/ei/frac-focus/${id}/chemicals`, {});
135
146
  return Array.isArray(response) ? response : response.chemicals;
@@ -142,7 +153,7 @@ export class EIFracFocusResource {
142
153
  */
143
154
  async forWell(apiNumber) {
144
155
  if (!apiNumber || typeof apiNumber !== "string") {
145
- throw new Error("API number must be a non-empty string");
156
+ throw new ValidationError("API number must be a non-empty string");
146
157
  }
147
158
  const response = await this.client["request"](`/v1/ei/frac-focus/for-well/${apiNumber}`, {});
148
159
  return Array.isArray(response) ? response : response.data;
@@ -11,6 +11,7 @@ import { EIDrillingProductivityResource } from "./drilling-productivity.js";
11
11
  import { EIForecastsResource } from "./forecasts.js";
12
12
  import { EIWellPermitsResource } from "./well-permits.js";
13
13
  import { EIFracFocusResource } from "./frac-focus.js";
14
+ import { ValidationError } from "../../errors.js";
14
15
  /**
15
16
  * Energy Intelligence Resource
16
17
  *
@@ -79,7 +80,7 @@ export class EnergyIntelligenceResource {
79
80
  */
80
81
  async wellTimeline(apiNumber) {
81
82
  if (!apiNumber || typeof apiNumber !== "string") {
82
- throw new Error("API number must be a non-empty string");
83
+ throw new ValidationError("API number must be a non-empty string");
83
84
  }
84
85
  return this.client["request"](`/v1/ei/wells/${apiNumber}/timeline`, {});
85
86
  }
@@ -4,6 +4,7 @@
4
4
  * Access EIA crude oil inventory data including total US stocks, Cushing levels,
5
5
  * and regional breakdowns.
6
6
  */
7
+ import { ValidationError } from "../../errors.js";
7
8
  /**
8
9
  * EI Oil Inventories Resource
9
10
  *
@@ -43,7 +44,7 @@ export class EIOilInventoriesResource {
43
44
  */
44
45
  async get(id) {
45
46
  if (!id || typeof id !== "string") {
46
- throw new Error("Record ID must be a non-empty string");
47
+ throw new ValidationError("Record ID must be a non-empty string");
47
48
  }
48
49
  return this.client["request"](`/v1/ei/oil_inventories/${id}`, {});
49
50
  }
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * Access OPEC crude oil production data by country with historical trends.
5
5
  */
6
+ import { ValidationError } from "../../errors.js";
6
7
  /**
7
8
  * EI OPEC Production Resource
8
9
  *
@@ -42,7 +43,7 @@ export class EIOPECProductionResource {
42
43
  */
43
44
  async get(id) {
44
45
  if (!id || typeof id !== "string") {
45
- throw new Error("Record ID must be a non-empty string");
46
+ throw new ValidationError("Record ID must be a non-empty string");
46
47
  }
47
48
  return this.client["request"](`/v1/ei/opec_productions/${id}`, {});
48
49
  }
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * Access Baker Hughes rig count data with basin, state, and historical breakdowns.
5
5
  */
6
+ import { ValidationError } from "../../errors.js";
6
7
  /**
7
8
  * EI Rig Counts Resource
8
9
  *
@@ -46,7 +47,7 @@ export class EIRigCountsResource {
46
47
  */
47
48
  async get(id) {
48
49
  if (!id || typeof id !== "string") {
49
- throw new Error("Record ID must be a non-empty string");
50
+ throw new ValidationError("Record ID must be a non-empty string");
50
51
  }
51
52
  return this.client["request"](`/v1/ei/rig_counts/${id}`, {});
52
53
  }
@@ -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
  /**