@whereq/cloud 0.4.0 → 0.5.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.
package/README.md CHANGED
@@ -21,6 +21,7 @@ import { Whereq } from "@whereq/cloud";
21
21
 
22
22
  const wq = new Whereq(); // public access
23
23
  // const wq = new Whereq({ apiKey: "wq_live_…" }); // metered tier
24
+ // const wq = new Whereq(); // uses $WHEREQ_API_KEY
24
25
 
25
26
  // Cost of living — compare US states, CA provinces, or metros (by rent-series id)
26
27
  await wq.costOfLiving("us:California,ca:Ontario,m:3958");
package/dist/index.cjs CHANGED
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  // src/index.ts
6
- var VERSION = "0.4.0";
6
+ var VERSION = "0.5.0";
7
7
  var DEFAULT_BASE_URL = "https://api.whereq.cloud";
8
8
  var FUEL_PRODUCTS = ["regular", "midgrade", "premium", "diesel"];
9
9
  var FUEL_COUNTRIES = ["MX", "US", "CA"];
@@ -22,6 +22,10 @@ var WhereqError = class extends Error {
22
22
  status;
23
23
  url;
24
24
  };
25
+ function envApiKey() {
26
+ const proc = globalThis.process;
27
+ return proc?.env?.WHEREQ_API_KEY ?? "";
28
+ }
25
29
  var Whereq = class {
26
30
  baseUrl;
27
31
  headers;
@@ -29,7 +33,8 @@ var Whereq = class {
29
33
  constructor(opts = {}) {
30
34
  this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
31
35
  this.headers = { Accept: "application/json" };
32
- if (opts.apiKey) this.headers["X-API-Key"] = opts.apiKey;
36
+ const key = opts.apiKey ?? envApiKey();
37
+ if (key) this.headers["X-API-Key"] = key;
33
38
  const f = opts.fetch ?? globalThis.fetch;
34
39
  if (!f) throw new Error("No global fetch available \u2014 pass `fetch` in options (Node <18).");
35
40
  this._fetch = f;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * whereq.cloud — official JavaScript/TypeScript SDK for the WhereQ data cloud.\n *\n * A thin, typed wrapper over the versioned `/v1` HTTP API at `api.whereq.cloud`.\n * Public endpoints work with no key; metered endpoints take an API key.\n *\n * ```ts\n * import { Whereq } from \"@whereq/cloud\";\n *\n * const wq = new Whereq(); // public access\n * // const wq = new Whereq({ apiKey: \"wq_live_…\" }); // metered tier\n *\n * await wq.costOfLiving(\"us:California,ca:Ontario\");\n * await wq.prices({ domain: \"rent\", region: \"us\", bedrooms: 2 });\n * await wq.get(\"/v1/trending\", { limit: 10 }); // escape hatch\n * ```\n */\nexport const VERSION = \"0.4.0\";\nconst DEFAULT_BASE_URL = \"https://api.whereq.cloud\";\n\n/** The products a station can quote. Mexico's CRE feed carries the first,\n * second and fourth; GasBuddy (US/Canada) adds midgrade. */\nexport const FUEL_PRODUCTS = [\"regular\", \"midgrade\", \"premium\", \"diesel\"] as const;\nexport type FuelProduct = (typeof FUEL_PRODUCTS)[number];\n\n/** Countries with station-level fuel data. */\nexport const FUEL_COUNTRIES = [\"MX\", \"US\", \"CA\"] as const;\nexport type FuelCountry = (typeof FUEL_COUNTRIES)[number];\n\n/** The unit each country quotes in — always local currency per litre. */\nexport const FUEL_CURRENCIES: Record<FuelCountry, string> = {\n MX: \"MXN/L\",\n US: \"USD/L\",\n CA: \"CAD/L\",\n};\n\n/** One product's latest price at a station. */\nexport interface FuelStationPrice {\n price: number;\n observed_at: string;\n}\n\n/** A geolocated retail fuel station and its latest prices.\n * `state` is the human label (\"Ontario\", \"Texas\"); `state_iso` is the\n * two-letter code (\"ON\", \"TX\"). */\nexport interface FuelStation {\n id: number;\n source: string;\n ext_id: string;\n country: string;\n name: string;\n brand?: string | null;\n state?: string | null;\n state_iso?: string | null;\n municipality?: string | null;\n lat?: number | null;\n lon?: number | null;\n prices: Record<string, FuelStationPrice>;\n}\n\n/** Filters for `fuelStations()`. */\nexport interface FuelStationsParams {\n /** \"MX\", \"US\" or \"CA\". */\n country?: FuelCountry | string;\n /** State/province name *or* ISO code — \"Ontario\"/\"ON\", \"Texas\"/\"TX\". */\n state?: string;\n /** City name, e.g. \"Mississauga\". */\n municipality?: string;\n product?: FuelProduct | string;\n /** \"minLon,minLat,maxLon,maxLat\" — a map viewport. */\n bbox?: string;\n /** Station-name search. */\n q?: string;\n /** 1–500 rows per page (default 100). */\n limit?: number;\n /** Row offset for paging. */\n offset?: number;\n}\n\n/** Filters for `fuelStation()`. */\nexport interface FuelStationParams {\n /** Restrict the timeline to one product. */\n product?: FuelProduct | string;\n /** How far back the timeline reaches (1–1825, default 90). */\n days?: number;\n}\n\n/** `GET /v1/fuel/stations`. Unentitled callers get a 100-row preview of the\n * oldest rows: `demo` is true, `total` is null and paging is ignored. */\nexport interface FuelStationsResponse {\n demo?: boolean;\n preview_rows?: number;\n note?: string;\n upgrade_url?: string;\n as_of: string;\n count: number;\n total?: number | null;\n stations: FuelStation[];\n}\n\n/** One observed price change — the intra-day timeline for a station. */\nexport interface FuelStationPricePoint {\n product: string;\n observed_at: string;\n price: number;\n}\n\n/** `GET /v1/fuel/stations/{id}`. `days` is null in the unentitled preview. */\nexport interface FuelStationDetail {\n demo?: boolean;\n preview_rows?: number;\n note?: string;\n upgrade_url?: string;\n station: FuelStation;\n days?: number | null;\n prices: FuelStationPricePoint[];\n}\n\n/** Filters for `fuelPrices()`. */\nexport interface FuelPricesParams {\n /** Region slug, or a comma-separated list of them (\"us,ca\"). */\n region?: string;\n /** Free-text place name (\"Calgary, Alberta\"). */\n geo?: string;\n q?: string;\n limit?: number;\n offset?: number;\n}\n\n/** One aggregated price series (state / national / metro). */\nexport interface PriceSeries {\n id: number;\n domain: string;\n source: string;\n region?: string | null;\n geo?: string | null;\n item: string;\n item_cn?: string | null;\n unit?: string | null;\n unit_cn?: string | null;\n frequency?: string | null;\n latest_period?: string | null;\n latest_value?: number | null;\n prev_value?: number | null;\n points?: number | null;\n spark?: number[];\n}\n\n/** `GET /v1/prices` — a page of series plus the page's own metadata. */\nexport interface PriceSeriesResponse {\n count: number;\n domain?: string | null;\n region?: string | null;\n limit: number;\n offset: number;\n data: PriceSeries[];\n}\n\nexport class WhereqError extends Error {\n constructor(\n public readonly status: number,\n message: string,\n public readonly url: string,\n ) {\n super(`whereq.cloud API error ${status} for ${url}: ${message}`);\n this.name = \"WhereqError\";\n }\n}\n\nexport interface ClientOptions {\n /** `wq_live_…` key for metered endpoints (sent as `X-API-Key`). */\n apiKey?: string;\n /** Override the API base (default `https://api.whereq.cloud`). */\n baseUrl?: string;\n /** Custom fetch (e.g. for Node <18 or testing). Defaults to global `fetch`. */\n fetch?: typeof fetch;\n}\n\ntype Params = Record<string, unknown>;\n\nexport class Whereq {\n private readonly baseUrl: string;\n private readonly headers: Record<string, string>;\n private readonly _fetch: typeof fetch;\n\n constructor(opts: ClientOptions = {}) {\n this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.headers = { Accept: \"application/json\" };\n if (opts.apiKey) this.headers[\"X-API-Key\"] = opts.apiKey;\n const f = opts.fetch ?? globalThis.fetch;\n if (!f) throw new Error(\"No global fetch available — pass `fetch` in options (Node <18).\");\n this._fetch = f;\n }\n\n private url(path: string, params: Params): string {\n const qs = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined && v !== null) qs.set(k, String(v));\n }\n const s = qs.toString();\n return `${this.baseUrl}${path}${s ? `?${s}` : \"\"}`;\n }\n\n /** GET any endpoint; `undefined`/`null` params are dropped. Returns parsed JSON. */\n async get<T = unknown>(path: string, params: Params = {}): Promise<T> {\n const url = this.url(path, params);\n const res = await this._fetch(url, { headers: this.headers });\n if (!res.ok) {\n let msg = res.statusText;\n try {\n const j = (await res.json()) as { detail?: string };\n msg = j?.detail || JSON.stringify(j) || msg;\n } catch {\n /* non-JSON error body */\n }\n throw new WhereqError(res.status, msg, url);\n }\n return (await res.json()) as T;\n }\n\n /** GET a non-JSON endpoint (e.g. CSV export) as text. */\n async getText(path: string, params: Params = {}): Promise<string> {\n const url = this.url(path, params);\n const res = await this._fetch(url, { headers: this.headers });\n if (!res.ok) throw new WhereqError(res.status, res.statusText, url);\n return res.text();\n }\n\n // -- prices / cost of living ------------------------------------------------\n /** Cost-of-living price series (fuel | food | energy | housing | rent).\n * `region` takes a region slug or a comma-separated list (\"us,ca\");\n * `geo` is a free-text place name (\"Calgary, Alberta\"). */\n prices(p: { domain?: string; region?: string; geo?: string; bedrooms?: number; q?: string; limit?: number; offset?: number } = {}): Promise<PriceSeriesResponse> {\n return this.get<PriceSeriesResponse>(\"/v1/prices\", p);\n }\n price(seriesId: number) {\n return this.get(`/v1/prices/${seriesId}`);\n }\n pricesCsv(p: { domain?: string; region?: string; geo?: string; bedrooms?: number; q?: string } = {}) {\n return this.getText(\"/v1/prices/export\", p);\n }\n /** Compare cost of living across US states / CA provinces / metros.\n * `places`: comma-separated `region:name` or `m:<rent-series-id>`. */\n costOfLiving(places: string) {\n return this.get(\"/v1/cost-of-living\", { places });\n }\n\n // -- discovery / facets -----------------------------------------------------\n catalog() { return this.get(\"/v1/catalog\"); }\n categories() { return this.get(\"/v1/categories\"); }\n regions() { return this.get(\"/v1/regions\"); }\n domains() { return this.get(\"/v1/domains\"); }\n trending(p: Params = {}) { return this.get(\"/v1/trending\", p); }\n\n // -- finance ----------------------------------------------------------------\n hotstocks(limit = 20) { return this.get(\"/v1/hotstocks\", { limit }); }\n quotes(p: Params = {}) { return this.get(\"/v1/quotes\", p); }\n news(p: Params = {}) { return this.get(\"/v1/news\", p); }\n screener(p: Params = {}) { return this.get(\"/v1/screener\", p); }\n search(q: string, p: Params = {}) { return this.get(\"/v1/search\", { q, ...p }); }\n\n // -- autos ------------------------------------------------------------------\n autosRecalls(p: Params = {}) { return this.get(\"/v1/autos/recalls\", p); }\n autosListings(p: Params = {}) { return this.get(\"/v1/autos/listings\", p); }\n autosFuelEconomy(p: Params = {}) { return this.get(\"/v1/autos/fuel-economy\", p); }\n autosModels(p: Params = {}) { return this.get(\"/v1/autos/models\", p); }\n\n // -- lottery -----------------------------------------------------------------\n /** Recent lottery draws, newest first.\n *\n * Unentitled callers get the oldest 100 draws instead of the recent\n * ones — check `response.demo`.\n */\n lotteryDraws(p: { game?: string; days?: number; limit?: number } & Params = {}): Promise<any> {\n return this.get(\"/v1/lottery/draws\", p);\n }\n /** The most recent draw for a game. On the unentitled preview this is the\n * *oldest* draw — the recent one is the gated, valuable row. */\n lotteryLatestDraw(game: string): Promise<any> {\n return this.get(`/v1/lottery/draws/${encodeURIComponent(game)}/latest`);\n }\n /** Per-number frequency for a game over a window (30–1825 days). */\n lotteryFrequency(game: string, days = 365): Promise<any> {\n return this.get(`/v1/lottery/draws/${encodeURIComponent(game)}/frequency`, { days });\n }\n /** The lottery game registry: names, play rules and draw days. */\n lotteryGames(p: { country?: string; region?: string } & Params = {}): Promise<any> {\n return this.get(\"/v1/lottery/games\", p);\n }\n /** One game's full play rules and metadata. */\n lotteryGame(slug: string): Promise<any> {\n return this.get(`/v1/lottery/games/${encodeURIComponent(slug)}`);\n }\n\n // -- fuel (gas & diesel) ----------------------------------------------------\n /** Geolocated retail fuel stations with their latest prices.\n *\n * Coverage: Mexico (`MX`, CRE open data), the United States (`US`) and\n * Canada (`CA`). Prices are in **local currency per litre** — `MXN/L`,\n * `USD/L` and `CAD/L` respectively.\n *\n * Unentitled callers get a 100-row preview of the oldest rows and the\n * pagination arguments are ignored — check `response.demo`.\n */\n fuelStations(p: FuelStationsParams & Params = {}): Promise<FuelStationsResponse> {\n return this.get<FuelStationsResponse>(\"/v1/fuel/stations\", p);\n }\n\n /** One station: location, latest prices and its price-change timeline. */\n fuelStation(\n id: number | string,\n p: FuelStationParams & Params = {},\n ): Promise<FuelStationDetail> {\n return this.get<FuelStationDetail>(\n `/v1/fuel/stations/${encodeURIComponent(String(id))}`,\n p,\n );\n }\n\n /** Yield every matching station, paging through the API for you.\n *\n * Only meaningful with an entitled key. The unentitled preview always\n * returns the *same* oldest 100 rows and ignores the paging arguments,\n * so there is nothing more to fetch: this yields that first page and\n * stops rather than looping on it.\n */\n async *fuelStationsAll(\n p: FuelStationsParams & Params = {},\n ): AsyncGenerator<FuelStation> {\n const pageSize = Math.min(Math.max(Number(p.limit ?? 500), 1), 500);\n let offset = Number(p.offset ?? 0);\n for (;;) {\n const page = await this.fuelStations({ ...p, limit: pageSize, offset });\n const stations = page.stations ?? [];\n if (stations.length === 0) return;\n for (const s of stations) yield s;\n if (page.demo) return; // preview: every page is the same slice\n offset += stations.length;\n if (page.total != null && offset >= page.total) return;\n }\n }\n\n /** Aggregated fuel price series (state / national / metro).\n *\n * These are the *series* behind the charts — EIA weekly for the US,\n * StatCan monthly for Canada, CRE for Mexico — not the station-level\n * prices that `fuelStations()` returns.\n */\n fuelPrices(p: FuelPricesParams & Params = {}): Promise<PriceSeriesResponse> {\n return this.get<PriceSeriesResponse>(\"/v1/prices\", { domain: \"fuel\", ...p });\n }\n}\n\nexport default Whereq;\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * whereq.cloud — official JavaScript/TypeScript SDK for the WhereQ data cloud.\n *\n * A thin, typed wrapper over the versioned `/v1` HTTP API at `api.whereq.cloud`.\n * Public endpoints work with no key; metered endpoints take an API key.\n *\n * ```ts\n * import { Whereq } from \"@whereq/cloud\";\n *\n * const wq = new Whereq(); // public access\n * // const wq = new Whereq({ apiKey: \"wq_live_…\" }); // metered tier\n *\n * await wq.costOfLiving(\"us:California,ca:Ontario\");\n * await wq.prices({ domain: \"rent\", region: \"us\", bedrooms: 2 });\n * await wq.get(\"/v1/trending\", { limit: 10 }); // escape hatch\n * ```\n */\nexport const VERSION = \"0.5.0\";\nconst DEFAULT_BASE_URL = \"https://api.whereq.cloud\";\n\n/** The products a station can quote. Mexico's CRE feed carries the first,\n * second and fourth; GasBuddy (US/Canada) adds midgrade. */\nexport const FUEL_PRODUCTS = [\"regular\", \"midgrade\", \"premium\", \"diesel\"] as const;\nexport type FuelProduct = (typeof FUEL_PRODUCTS)[number];\n\n/** Countries with station-level fuel data. */\nexport const FUEL_COUNTRIES = [\"MX\", \"US\", \"CA\"] as const;\nexport type FuelCountry = (typeof FUEL_COUNTRIES)[number];\n\n/** The unit each country quotes in — always local currency per litre. */\nexport const FUEL_CURRENCIES: Record<FuelCountry, string> = {\n MX: \"MXN/L\",\n US: \"USD/L\",\n CA: \"CAD/L\",\n};\n\n/** One product's latest price at a station. */\nexport interface FuelStationPrice {\n price: number;\n observed_at: string;\n}\n\n/** A geolocated retail fuel station and its latest prices.\n * `state` is the human label (\"Ontario\", \"Texas\"); `state_iso` is the\n * two-letter code (\"ON\", \"TX\"). */\nexport interface FuelStation {\n id: number;\n source: string;\n ext_id: string;\n country: string;\n name: string;\n brand?: string | null;\n state?: string | null;\n state_iso?: string | null;\n municipality?: string | null;\n lat?: number | null;\n lon?: number | null;\n prices: Record<string, FuelStationPrice>;\n}\n\n/** Filters for `fuelStations()`. */\nexport interface FuelStationsParams {\n /** \"MX\", \"US\" or \"CA\". */\n country?: FuelCountry | string;\n /** State/province name *or* ISO code — \"Ontario\"/\"ON\", \"Texas\"/\"TX\". */\n state?: string;\n /** City name, e.g. \"Mississauga\". */\n municipality?: string;\n product?: FuelProduct | string;\n /** \"minLon,minLat,maxLon,maxLat\" — a map viewport. */\n bbox?: string;\n /** Station-name search. */\n q?: string;\n /** 1–500 rows per page (default 100). */\n limit?: number;\n /** Row offset for paging. */\n offset?: number;\n}\n\n/** Filters for `fuelStation()`. */\nexport interface FuelStationParams {\n /** Restrict the timeline to one product. */\n product?: FuelProduct | string;\n /** How far back the timeline reaches (1–1825, default 90). */\n days?: number;\n}\n\n/** `GET /v1/fuel/stations`. Unentitled callers get a 100-row preview of the\n * oldest rows: `demo` is true, `total` is null and paging is ignored. */\nexport interface FuelStationsResponse {\n demo?: boolean;\n preview_rows?: number;\n note?: string;\n upgrade_url?: string;\n as_of: string;\n count: number;\n total?: number | null;\n stations: FuelStation[];\n}\n\n/** One observed price change — the intra-day timeline for a station. */\nexport interface FuelStationPricePoint {\n product: string;\n observed_at: string;\n price: number;\n}\n\n/** `GET /v1/fuel/stations/{id}`. `days` is null in the unentitled preview. */\nexport interface FuelStationDetail {\n demo?: boolean;\n preview_rows?: number;\n note?: string;\n upgrade_url?: string;\n station: FuelStation;\n days?: number | null;\n prices: FuelStationPricePoint[];\n}\n\n/** Filters for `fuelPrices()`. */\nexport interface FuelPricesParams {\n /** Region slug, or a comma-separated list of them (\"us,ca\"). */\n region?: string;\n /** Free-text place name (\"Calgary, Alberta\"). */\n geo?: string;\n q?: string;\n limit?: number;\n offset?: number;\n}\n\n/** One aggregated price series (state / national / metro). */\nexport interface PriceSeries {\n id: number;\n domain: string;\n source: string;\n region?: string | null;\n geo?: string | null;\n item: string;\n item_cn?: string | null;\n unit?: string | null;\n unit_cn?: string | null;\n frequency?: string | null;\n latest_period?: string | null;\n latest_value?: number | null;\n prev_value?: number | null;\n points?: number | null;\n spark?: number[];\n}\n\n/** `GET /v1/prices` — a page of series plus the page's own metadata. */\nexport interface PriceSeriesResponse {\n count: number;\n domain?: string | null;\n region?: string | null;\n limit: number;\n offset: number;\n data: PriceSeries[];\n}\n\nexport class WhereqError extends Error {\n constructor(\n public readonly status: number,\n message: string,\n public readonly url: string,\n ) {\n super(`whereq.cloud API error ${status} for ${url}: ${message}`);\n this.name = \"WhereqError\";\n }\n}\n\nexport interface ClientOptions {\n /** `wq_live_…` key for metered endpoints (sent as `X-API-Key`). */\n apiKey?: string;\n /** Override the API base (default `https://api.whereq.cloud`). */\n baseUrl?: string;\n /** Custom fetch (e.g. for Node <18 or testing). Defaults to global `fetch`. */\n fetch?: typeof fetch;\n}\n\ntype Params = Record<string, unknown>;\n\n/** The API key from the environment, when there is one. */\nfunction envApiKey(): string {\n const proc = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process;\n return proc?.env?.WHEREQ_API_KEY ?? \"\";\n}\n\nexport class Whereq {\n private readonly baseUrl: string;\n private readonly headers: Record<string, string>;\n private readonly _fetch: typeof fetch;\n\n constructor(opts: ClientOptions = {}) {\n this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.headers = { Accept: \"application/json\" };\n // The key may come from the options or the environment, in that order.\n const key = opts.apiKey ?? envApiKey();\n if (key) this.headers[\"X-API-Key\"] = key;\n const f = opts.fetch ?? globalThis.fetch;\n if (!f) throw new Error(\"No global fetch available — pass `fetch` in options (Node <18).\");\n this._fetch = f;\n }\n\n private url(path: string, params: Params): string {\n const qs = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined && v !== null) qs.set(k, String(v));\n }\n const s = qs.toString();\n return `${this.baseUrl}${path}${s ? `?${s}` : \"\"}`;\n }\n\n /** GET any endpoint; `undefined`/`null` params are dropped. Returns parsed JSON. */\n async get<T = unknown>(path: string, params: Params = {}): Promise<T> {\n const url = this.url(path, params);\n const res = await this._fetch(url, { headers: this.headers });\n if (!res.ok) {\n let msg = res.statusText;\n try {\n const j = (await res.json()) as { detail?: string };\n msg = j?.detail || JSON.stringify(j) || msg;\n } catch {\n /* non-JSON error body */\n }\n throw new WhereqError(res.status, msg, url);\n }\n return (await res.json()) as T;\n }\n\n /** GET a non-JSON endpoint (e.g. CSV export) as text. */\n async getText(path: string, params: Params = {}): Promise<string> {\n const url = this.url(path, params);\n const res = await this._fetch(url, { headers: this.headers });\n if (!res.ok) throw new WhereqError(res.status, res.statusText, url);\n return res.text();\n }\n\n // -- prices / cost of living ------------------------------------------------\n /** Cost-of-living price series (fuel | food | energy | housing | rent).\n * `region` takes a region slug or a comma-separated list (\"us,ca\");\n * `geo` is a free-text place name (\"Calgary, Alberta\"). */\n prices(p: { domain?: string; region?: string; geo?: string; bedrooms?: number; q?: string; limit?: number; offset?: number } = {}): Promise<PriceSeriesResponse> {\n return this.get<PriceSeriesResponse>(\"/v1/prices\", p);\n }\n price(seriesId: number) {\n return this.get(`/v1/prices/${seriesId}`);\n }\n pricesCsv(p: { domain?: string; region?: string; geo?: string; bedrooms?: number; q?: string } = {}) {\n return this.getText(\"/v1/prices/export\", p);\n }\n /** Compare cost of living across US states / CA provinces / metros.\n * `places`: comma-separated `region:name` or `m:<rent-series-id>`. */\n costOfLiving(places: string) {\n return this.get(\"/v1/cost-of-living\", { places });\n }\n\n // -- discovery / facets -----------------------------------------------------\n catalog() { return this.get(\"/v1/catalog\"); }\n categories() { return this.get(\"/v1/categories\"); }\n regions() { return this.get(\"/v1/regions\"); }\n domains() { return this.get(\"/v1/domains\"); }\n trending(p: Params = {}) { return this.get(\"/v1/trending\", p); }\n\n // -- finance ----------------------------------------------------------------\n hotstocks(limit = 20) { return this.get(\"/v1/hotstocks\", { limit }); }\n quotes(p: Params = {}) { return this.get(\"/v1/quotes\", p); }\n news(p: Params = {}) { return this.get(\"/v1/news\", p); }\n screener(p: Params = {}) { return this.get(\"/v1/screener\", p); }\n search(q: string, p: Params = {}) { return this.get(\"/v1/search\", { q, ...p }); }\n\n // -- autos ------------------------------------------------------------------\n autosRecalls(p: Params = {}) { return this.get(\"/v1/autos/recalls\", p); }\n autosListings(p: Params = {}) { return this.get(\"/v1/autos/listings\", p); }\n autosFuelEconomy(p: Params = {}) { return this.get(\"/v1/autos/fuel-economy\", p); }\n autosModels(p: Params = {}) { return this.get(\"/v1/autos/models\", p); }\n\n // -- lottery -----------------------------------------------------------------\n /** Recent lottery draws, newest first.\n *\n * Unentitled callers get the oldest 100 draws instead of the recent\n * ones — check `response.demo`.\n */\n lotteryDraws(p: { game?: string; days?: number; limit?: number } & Params = {}): Promise<any> {\n return this.get(\"/v1/lottery/draws\", p);\n }\n /** The most recent draw for a game. On the unentitled preview this is the\n * *oldest* draw — the recent one is the gated, valuable row. */\n lotteryLatestDraw(game: string): Promise<any> {\n return this.get(`/v1/lottery/draws/${encodeURIComponent(game)}/latest`);\n }\n /** Per-number frequency for a game over a window (30–1825 days). */\n lotteryFrequency(game: string, days = 365): Promise<any> {\n return this.get(`/v1/lottery/draws/${encodeURIComponent(game)}/frequency`, { days });\n }\n /** The lottery game registry: names, play rules and draw days. */\n lotteryGames(p: { country?: string; region?: string } & Params = {}): Promise<any> {\n return this.get(\"/v1/lottery/games\", p);\n }\n /** One game's full play rules and metadata. */\n lotteryGame(slug: string): Promise<any> {\n return this.get(`/v1/lottery/games/${encodeURIComponent(slug)}`);\n }\n\n // -- fuel (gas & diesel) ----------------------------------------------------\n /** Geolocated retail fuel stations with their latest prices.\n *\n * Coverage: Mexico (`MX`, CRE open data), the United States (`US`) and\n * Canada (`CA`). Prices are in **local currency per litre** — `MXN/L`,\n * `USD/L` and `CAD/L` respectively.\n *\n * Unentitled callers get a 100-row preview of the oldest rows and the\n * pagination arguments are ignored — check `response.demo`.\n */\n fuelStations(p: FuelStationsParams & Params = {}): Promise<FuelStationsResponse> {\n return this.get<FuelStationsResponse>(\"/v1/fuel/stations\", p);\n }\n\n /** One station: location, latest prices and its price-change timeline. */\n fuelStation(\n id: number | string,\n p: FuelStationParams & Params = {},\n ): Promise<FuelStationDetail> {\n return this.get<FuelStationDetail>(\n `/v1/fuel/stations/${encodeURIComponent(String(id))}`,\n p,\n );\n }\n\n /** Yield every matching station, paging through the API for you.\n *\n * Only meaningful with an entitled key. The unentitled preview always\n * returns the *same* oldest 100 rows and ignores the paging arguments,\n * so there is nothing more to fetch: this yields that first page and\n * stops rather than looping on it.\n */\n async *fuelStationsAll(\n p: FuelStationsParams & Params = {},\n ): AsyncGenerator<FuelStation> {\n const pageSize = Math.min(Math.max(Number(p.limit ?? 500), 1), 500);\n let offset = Number(p.offset ?? 0);\n for (;;) {\n const page = await this.fuelStations({ ...p, limit: pageSize, offset });\n const stations = page.stations ?? [];\n if (stations.length === 0) return;\n for (const s of stations) yield s;\n if (page.demo) return; // preview: every page is the same slice\n offset += stations.length;\n if (page.total != null && offset >= page.total) return;\n }\n }\n\n /** Aggregated fuel price series (state / national / metro).\n *\n * These are the *series* behind the charts — EIA weekly for the US,\n * StatCan monthly for Canada, CRE for Mexico — not the station-level\n * prices that `fuelStations()` returns.\n */\n fuelPrices(p: FuelPricesParams & Params = {}): Promise<PriceSeriesResponse> {\n return this.get<PriceSeriesResponse>(\"/v1/prices\", { domain: \"fuel\", ...p });\n }\n}\n\nexport default Whereq;\n"]}
package/dist/index.d.cts CHANGED
@@ -15,7 +15,7 @@
15
15
  * await wq.get("/v1/trending", { limit: 10 }); // escape hatch
16
16
  * ```
17
17
  */
18
- declare const VERSION = "0.4.0";
18
+ declare const VERSION = "0.5.0";
19
19
  /** The products a station can quote. Mexico's CRE feed carries the first,
20
20
  * second and fourth; GasBuddy (US/Canada) adds midgrade. */
21
21
  declare const FUEL_PRODUCTS: readonly ["regular", "midgrade", "premium", "diesel"];
package/dist/index.d.ts CHANGED
@@ -15,7 +15,7 @@
15
15
  * await wq.get("/v1/trending", { limit: 10 }); // escape hatch
16
16
  * ```
17
17
  */
18
- declare const VERSION = "0.4.0";
18
+ declare const VERSION = "0.5.0";
19
19
  /** The products a station can quote. Mexico's CRE feed carries the first,
20
20
  * second and fourth; GasBuddy (US/Canada) adds midgrade. */
21
21
  declare const FUEL_PRODUCTS: readonly ["regular", "midgrade", "premium", "diesel"];
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/index.ts
2
- var VERSION = "0.4.0";
2
+ var VERSION = "0.5.0";
3
3
  var DEFAULT_BASE_URL = "https://api.whereq.cloud";
4
4
  var FUEL_PRODUCTS = ["regular", "midgrade", "premium", "diesel"];
5
5
  var FUEL_COUNTRIES = ["MX", "US", "CA"];
@@ -18,6 +18,10 @@ var WhereqError = class extends Error {
18
18
  status;
19
19
  url;
20
20
  };
21
+ function envApiKey() {
22
+ const proc = globalThis.process;
23
+ return proc?.env?.WHEREQ_API_KEY ?? "";
24
+ }
21
25
  var Whereq = class {
22
26
  baseUrl;
23
27
  headers;
@@ -25,7 +29,8 @@ var Whereq = class {
25
29
  constructor(opts = {}) {
26
30
  this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
27
31
  this.headers = { Accept: "application/json" };
28
- if (opts.apiKey) this.headers["X-API-Key"] = opts.apiKey;
32
+ const key = opts.apiKey ?? envApiKey();
33
+ if (key) this.headers["X-API-Key"] = key;
29
34
  const f = opts.fetch ?? globalThis.fetch;
30
35
  if (!f) throw new Error("No global fetch available \u2014 pass `fetch` in options (Node <18).");
31
36
  this._fetch = f;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * whereq.cloud — official JavaScript/TypeScript SDK for the WhereQ data cloud.\n *\n * A thin, typed wrapper over the versioned `/v1` HTTP API at `api.whereq.cloud`.\n * Public endpoints work with no key; metered endpoints take an API key.\n *\n * ```ts\n * import { Whereq } from \"@whereq/cloud\";\n *\n * const wq = new Whereq(); // public access\n * // const wq = new Whereq({ apiKey: \"wq_live_…\" }); // metered tier\n *\n * await wq.costOfLiving(\"us:California,ca:Ontario\");\n * await wq.prices({ domain: \"rent\", region: \"us\", bedrooms: 2 });\n * await wq.get(\"/v1/trending\", { limit: 10 }); // escape hatch\n * ```\n */\nexport const VERSION = \"0.4.0\";\nconst DEFAULT_BASE_URL = \"https://api.whereq.cloud\";\n\n/** The products a station can quote. Mexico's CRE feed carries the first,\n * second and fourth; GasBuddy (US/Canada) adds midgrade. */\nexport const FUEL_PRODUCTS = [\"regular\", \"midgrade\", \"premium\", \"diesel\"] as const;\nexport type FuelProduct = (typeof FUEL_PRODUCTS)[number];\n\n/** Countries with station-level fuel data. */\nexport const FUEL_COUNTRIES = [\"MX\", \"US\", \"CA\"] as const;\nexport type FuelCountry = (typeof FUEL_COUNTRIES)[number];\n\n/** The unit each country quotes in — always local currency per litre. */\nexport const FUEL_CURRENCIES: Record<FuelCountry, string> = {\n MX: \"MXN/L\",\n US: \"USD/L\",\n CA: \"CAD/L\",\n};\n\n/** One product's latest price at a station. */\nexport interface FuelStationPrice {\n price: number;\n observed_at: string;\n}\n\n/** A geolocated retail fuel station and its latest prices.\n * `state` is the human label (\"Ontario\", \"Texas\"); `state_iso` is the\n * two-letter code (\"ON\", \"TX\"). */\nexport interface FuelStation {\n id: number;\n source: string;\n ext_id: string;\n country: string;\n name: string;\n brand?: string | null;\n state?: string | null;\n state_iso?: string | null;\n municipality?: string | null;\n lat?: number | null;\n lon?: number | null;\n prices: Record<string, FuelStationPrice>;\n}\n\n/** Filters for `fuelStations()`. */\nexport interface FuelStationsParams {\n /** \"MX\", \"US\" or \"CA\". */\n country?: FuelCountry | string;\n /** State/province name *or* ISO code — \"Ontario\"/\"ON\", \"Texas\"/\"TX\". */\n state?: string;\n /** City name, e.g. \"Mississauga\". */\n municipality?: string;\n product?: FuelProduct | string;\n /** \"minLon,minLat,maxLon,maxLat\" — a map viewport. */\n bbox?: string;\n /** Station-name search. */\n q?: string;\n /** 1–500 rows per page (default 100). */\n limit?: number;\n /** Row offset for paging. */\n offset?: number;\n}\n\n/** Filters for `fuelStation()`. */\nexport interface FuelStationParams {\n /** Restrict the timeline to one product. */\n product?: FuelProduct | string;\n /** How far back the timeline reaches (1–1825, default 90). */\n days?: number;\n}\n\n/** `GET /v1/fuel/stations`. Unentitled callers get a 100-row preview of the\n * oldest rows: `demo` is true, `total` is null and paging is ignored. */\nexport interface FuelStationsResponse {\n demo?: boolean;\n preview_rows?: number;\n note?: string;\n upgrade_url?: string;\n as_of: string;\n count: number;\n total?: number | null;\n stations: FuelStation[];\n}\n\n/** One observed price change — the intra-day timeline for a station. */\nexport interface FuelStationPricePoint {\n product: string;\n observed_at: string;\n price: number;\n}\n\n/** `GET /v1/fuel/stations/{id}`. `days` is null in the unentitled preview. */\nexport interface FuelStationDetail {\n demo?: boolean;\n preview_rows?: number;\n note?: string;\n upgrade_url?: string;\n station: FuelStation;\n days?: number | null;\n prices: FuelStationPricePoint[];\n}\n\n/** Filters for `fuelPrices()`. */\nexport interface FuelPricesParams {\n /** Region slug, or a comma-separated list of them (\"us,ca\"). */\n region?: string;\n /** Free-text place name (\"Calgary, Alberta\"). */\n geo?: string;\n q?: string;\n limit?: number;\n offset?: number;\n}\n\n/** One aggregated price series (state / national / metro). */\nexport interface PriceSeries {\n id: number;\n domain: string;\n source: string;\n region?: string | null;\n geo?: string | null;\n item: string;\n item_cn?: string | null;\n unit?: string | null;\n unit_cn?: string | null;\n frequency?: string | null;\n latest_period?: string | null;\n latest_value?: number | null;\n prev_value?: number | null;\n points?: number | null;\n spark?: number[];\n}\n\n/** `GET /v1/prices` — a page of series plus the page's own metadata. */\nexport interface PriceSeriesResponse {\n count: number;\n domain?: string | null;\n region?: string | null;\n limit: number;\n offset: number;\n data: PriceSeries[];\n}\n\nexport class WhereqError extends Error {\n constructor(\n public readonly status: number,\n message: string,\n public readonly url: string,\n ) {\n super(`whereq.cloud API error ${status} for ${url}: ${message}`);\n this.name = \"WhereqError\";\n }\n}\n\nexport interface ClientOptions {\n /** `wq_live_…` key for metered endpoints (sent as `X-API-Key`). */\n apiKey?: string;\n /** Override the API base (default `https://api.whereq.cloud`). */\n baseUrl?: string;\n /** Custom fetch (e.g. for Node <18 or testing). Defaults to global `fetch`. */\n fetch?: typeof fetch;\n}\n\ntype Params = Record<string, unknown>;\n\nexport class Whereq {\n private readonly baseUrl: string;\n private readonly headers: Record<string, string>;\n private readonly _fetch: typeof fetch;\n\n constructor(opts: ClientOptions = {}) {\n this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.headers = { Accept: \"application/json\" };\n if (opts.apiKey) this.headers[\"X-API-Key\"] = opts.apiKey;\n const f = opts.fetch ?? globalThis.fetch;\n if (!f) throw new Error(\"No global fetch available — pass `fetch` in options (Node <18).\");\n this._fetch = f;\n }\n\n private url(path: string, params: Params): string {\n const qs = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined && v !== null) qs.set(k, String(v));\n }\n const s = qs.toString();\n return `${this.baseUrl}${path}${s ? `?${s}` : \"\"}`;\n }\n\n /** GET any endpoint; `undefined`/`null` params are dropped. Returns parsed JSON. */\n async get<T = unknown>(path: string, params: Params = {}): Promise<T> {\n const url = this.url(path, params);\n const res = await this._fetch(url, { headers: this.headers });\n if (!res.ok) {\n let msg = res.statusText;\n try {\n const j = (await res.json()) as { detail?: string };\n msg = j?.detail || JSON.stringify(j) || msg;\n } catch {\n /* non-JSON error body */\n }\n throw new WhereqError(res.status, msg, url);\n }\n return (await res.json()) as T;\n }\n\n /** GET a non-JSON endpoint (e.g. CSV export) as text. */\n async getText(path: string, params: Params = {}): Promise<string> {\n const url = this.url(path, params);\n const res = await this._fetch(url, { headers: this.headers });\n if (!res.ok) throw new WhereqError(res.status, res.statusText, url);\n return res.text();\n }\n\n // -- prices / cost of living ------------------------------------------------\n /** Cost-of-living price series (fuel | food | energy | housing | rent).\n * `region` takes a region slug or a comma-separated list (\"us,ca\");\n * `geo` is a free-text place name (\"Calgary, Alberta\"). */\n prices(p: { domain?: string; region?: string; geo?: string; bedrooms?: number; q?: string; limit?: number; offset?: number } = {}): Promise<PriceSeriesResponse> {\n return this.get<PriceSeriesResponse>(\"/v1/prices\", p);\n }\n price(seriesId: number) {\n return this.get(`/v1/prices/${seriesId}`);\n }\n pricesCsv(p: { domain?: string; region?: string; geo?: string; bedrooms?: number; q?: string } = {}) {\n return this.getText(\"/v1/prices/export\", p);\n }\n /** Compare cost of living across US states / CA provinces / metros.\n * `places`: comma-separated `region:name` or `m:<rent-series-id>`. */\n costOfLiving(places: string) {\n return this.get(\"/v1/cost-of-living\", { places });\n }\n\n // -- discovery / facets -----------------------------------------------------\n catalog() { return this.get(\"/v1/catalog\"); }\n categories() { return this.get(\"/v1/categories\"); }\n regions() { return this.get(\"/v1/regions\"); }\n domains() { return this.get(\"/v1/domains\"); }\n trending(p: Params = {}) { return this.get(\"/v1/trending\", p); }\n\n // -- finance ----------------------------------------------------------------\n hotstocks(limit = 20) { return this.get(\"/v1/hotstocks\", { limit }); }\n quotes(p: Params = {}) { return this.get(\"/v1/quotes\", p); }\n news(p: Params = {}) { return this.get(\"/v1/news\", p); }\n screener(p: Params = {}) { return this.get(\"/v1/screener\", p); }\n search(q: string, p: Params = {}) { return this.get(\"/v1/search\", { q, ...p }); }\n\n // -- autos ------------------------------------------------------------------\n autosRecalls(p: Params = {}) { return this.get(\"/v1/autos/recalls\", p); }\n autosListings(p: Params = {}) { return this.get(\"/v1/autos/listings\", p); }\n autosFuelEconomy(p: Params = {}) { return this.get(\"/v1/autos/fuel-economy\", p); }\n autosModels(p: Params = {}) { return this.get(\"/v1/autos/models\", p); }\n\n // -- lottery -----------------------------------------------------------------\n /** Recent lottery draws, newest first.\n *\n * Unentitled callers get the oldest 100 draws instead of the recent\n * ones — check `response.demo`.\n */\n lotteryDraws(p: { game?: string; days?: number; limit?: number } & Params = {}): Promise<any> {\n return this.get(\"/v1/lottery/draws\", p);\n }\n /** The most recent draw for a game. On the unentitled preview this is the\n * *oldest* draw — the recent one is the gated, valuable row. */\n lotteryLatestDraw(game: string): Promise<any> {\n return this.get(`/v1/lottery/draws/${encodeURIComponent(game)}/latest`);\n }\n /** Per-number frequency for a game over a window (30–1825 days). */\n lotteryFrequency(game: string, days = 365): Promise<any> {\n return this.get(`/v1/lottery/draws/${encodeURIComponent(game)}/frequency`, { days });\n }\n /** The lottery game registry: names, play rules and draw days. */\n lotteryGames(p: { country?: string; region?: string } & Params = {}): Promise<any> {\n return this.get(\"/v1/lottery/games\", p);\n }\n /** One game's full play rules and metadata. */\n lotteryGame(slug: string): Promise<any> {\n return this.get(`/v1/lottery/games/${encodeURIComponent(slug)}`);\n }\n\n // -- fuel (gas & diesel) ----------------------------------------------------\n /** Geolocated retail fuel stations with their latest prices.\n *\n * Coverage: Mexico (`MX`, CRE open data), the United States (`US`) and\n * Canada (`CA`). Prices are in **local currency per litre** — `MXN/L`,\n * `USD/L` and `CAD/L` respectively.\n *\n * Unentitled callers get a 100-row preview of the oldest rows and the\n * pagination arguments are ignored — check `response.demo`.\n */\n fuelStations(p: FuelStationsParams & Params = {}): Promise<FuelStationsResponse> {\n return this.get<FuelStationsResponse>(\"/v1/fuel/stations\", p);\n }\n\n /** One station: location, latest prices and its price-change timeline. */\n fuelStation(\n id: number | string,\n p: FuelStationParams & Params = {},\n ): Promise<FuelStationDetail> {\n return this.get<FuelStationDetail>(\n `/v1/fuel/stations/${encodeURIComponent(String(id))}`,\n p,\n );\n }\n\n /** Yield every matching station, paging through the API for you.\n *\n * Only meaningful with an entitled key. The unentitled preview always\n * returns the *same* oldest 100 rows and ignores the paging arguments,\n * so there is nothing more to fetch: this yields that first page and\n * stops rather than looping on it.\n */\n async *fuelStationsAll(\n p: FuelStationsParams & Params = {},\n ): AsyncGenerator<FuelStation> {\n const pageSize = Math.min(Math.max(Number(p.limit ?? 500), 1), 500);\n let offset = Number(p.offset ?? 0);\n for (;;) {\n const page = await this.fuelStations({ ...p, limit: pageSize, offset });\n const stations = page.stations ?? [];\n if (stations.length === 0) return;\n for (const s of stations) yield s;\n if (page.demo) return; // preview: every page is the same slice\n offset += stations.length;\n if (page.total != null && offset >= page.total) return;\n }\n }\n\n /** Aggregated fuel price series (state / national / metro).\n *\n * These are the *series* behind the charts — EIA weekly for the US,\n * StatCan monthly for Canada, CRE for Mexico — not the station-level\n * prices that `fuelStations()` returns.\n */\n fuelPrices(p: FuelPricesParams & Params = {}): Promise<PriceSeriesResponse> {\n return this.get<PriceSeriesResponse>(\"/v1/prices\", { domain: \"fuel\", ...p });\n }\n}\n\nexport default Whereq;\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";AAiBO,IAAM,OAAA,GAAU;AACvB,IAAM,gBAAA,GAAmB,0BAAA;AAIlB,IAAM,aAAA,GAAgB,CAAC,SAAA,EAAW,UAAA,EAAY,WAAW,QAAQ;AAIjE,IAAM,cAAA,GAAiB,CAAC,IAAA,EAAM,IAAA,EAAM,IAAI;AAIxC,IAAM,eAAA,GAA+C;AAAA,EAC1D,EAAA,EAAI,OAAA;AAAA,EACJ,EAAA,EAAI,OAAA;AAAA,EACJ,EAAA,EAAI;AACN;AA4HO,IAAM,WAAA,GAAN,cAA0B,KAAA,CAAM;AAAA,EACrC,WAAA,CACkB,MAAA,EAChB,OAAA,EACgB,GAAA,EAChB;AACA,IAAA,KAAA,CAAM,0BAA0B,MAAM,CAAA,KAAA,EAAQ,GAAG,CAAA,EAAA,EAAK,OAAO,CAAA,CAAE,CAAA;AAJ/C,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAEA,IAAA,IAAA,CAAA,GAAA,GAAA,GAAA;AAGhB,IAAA,IAAA,CAAK,IAAA,GAAO,aAAA;AAAA,EACd;AAAA,EANkB,MAAA;AAAA,EAEA,GAAA;AAKpB;AAcA,SAAS,SAAA,GAAoB;AAC3B,EAAA,MAAM,OAAQ,UAAA,CAA0E,OAAA;AACxF,EAAA,OAAO,IAAA,EAAM,KAAK,cAAA,IAAkB,EAAA;AACtC;AAEO,IAAM,SAAN,MAAa;AAAA,EACD,OAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EAEjB,WAAA,CAAY,IAAA,GAAsB,EAAC,EAAG;AACpC,IAAA,IAAA,CAAK,WAAW,IAAA,CAAK,OAAA,IAAW,gBAAA,EAAkB,OAAA,CAAQ,QAAQ,EAAE,CAAA;AACpE,IAAA,IAAA,CAAK,OAAA,GAAU,EAAE,MAAA,EAAQ,kBAAA,EAAmB;AAE5C,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,MAAA,IAAU,SAAA,EAAU;AACrC,IAAA,IAAI,GAAA,EAAK,IAAA,CAAK,OAAA,CAAQ,WAAW,CAAA,GAAI,GAAA;AACrC,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,KAAA,IAAS,UAAA,CAAW,KAAA;AACnC,IAAA,IAAI,CAAC,CAAA,EAAG,MAAM,IAAI,MAAM,sEAAiE,CAAA;AACzF,IAAA,IAAA,CAAK,MAAA,GAAS,CAAA;AAAA,EAChB;AAAA,EAEQ,GAAA,CAAI,MAAc,MAAA,EAAwB;AAChD,IAAA,MAAM,EAAA,GAAK,IAAI,eAAA,EAAgB;AAC/B,IAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,KAAK,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAA,EAAG;AAC3C,MAAA,IAAI,CAAA,KAAM,UAAa,CAAA,KAAM,IAAA,KAAS,GAAA,CAAI,CAAA,EAAG,MAAA,CAAO,CAAC,CAAC,CAAA;AAAA,IACxD;AACA,IAAA,MAAM,CAAA,GAAI,GAAG,QAAA,EAAS;AACtB,IAAA,OAAO,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,EAAG,IAAI,GAAG,CAAA,GAAI,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA,GAAK,EAAE,CAAA,CAAA;AAAA,EAClD;AAAA;AAAA,EAGA,MAAM,GAAA,CAAiB,IAAA,EAAc,MAAA,GAAiB,EAAC,EAAe;AACpE,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,IAAA,EAAM,MAAM,CAAA;AACjC,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,KAAK,EAAE,OAAA,EAAS,IAAA,CAAK,OAAA,EAAS,CAAA;AAC5D,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,IAAI,MAAM,GAAA,CAAI,UAAA;AACd,MAAA,IAAI;AACF,QAAA,MAAM,CAAA,GAAK,MAAM,GAAA,CAAI,IAAA,EAAK;AAC1B,QAAA,GAAA,GAAM,CAAA,EAAG,MAAA,IAAU,IAAA,CAAK,SAAA,CAAU,CAAC,CAAA,IAAK,GAAA;AAAA,MAC1C,CAAA,CAAA,MAAQ;AAAA,MAER;AACA,MAAA,MAAM,IAAI,WAAA,CAAY,GAAA,CAAI,MAAA,EAAQ,KAAK,GAAG,CAAA;AAAA,IAC5C;AACA,IAAA,OAAQ,MAAM,IAAI,IAAA,EAAK;AAAA,EACzB;AAAA;AAAA,EAGA,MAAM,OAAA,CAAQ,IAAA,EAAc,MAAA,GAAiB,EAAC,EAAoB;AAChE,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,IAAA,EAAM,MAAM,CAAA;AACjC,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,KAAK,EAAE,OAAA,EAAS,IAAA,CAAK,OAAA,EAAS,CAAA;AAC5D,IAAA,IAAI,CAAC,GAAA,CAAI,EAAA,EAAI,MAAM,IAAI,YAAY,GAAA,CAAI,MAAA,EAAQ,GAAA,CAAI,UAAA,EAAY,GAAG,CAAA;AAClE,IAAA,OAAO,IAAI,IAAA,EAAK;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAA,CAAO,CAAA,GAAwH,EAAC,EAAiC;AAC/J,IAAA,OAAO,IAAA,CAAK,GAAA,CAAyB,YAAA,EAAc,CAAC,CAAA;AAAA,EACtD;AAAA,EACA,MAAM,QAAA,EAAkB;AACtB,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,CAAA,WAAA,EAAc,QAAQ,CAAA,CAAE,CAAA;AAAA,EAC1C;AAAA,EACA,SAAA,CAAU,CAAA,GAAuF,EAAC,EAAG;AACnG,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,mBAAA,EAAqB,CAAC,CAAA;AAAA,EAC5C;AAAA;AAAA;AAAA,EAGA,aAAa,MAAA,EAAgB;AAC3B,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,oBAAA,EAAsB,EAAE,QAAQ,CAAA;AAAA,EAClD;AAAA;AAAA,EAGA,OAAA,GAAU;AAAE,IAAA,OAAO,IAAA,CAAK,IAAI,aAAa,CAAA;AAAA,EAAG;AAAA,EAC5C,UAAA,GAAa;AAAE,IAAA,OAAO,IAAA,CAAK,IAAI,gBAAgB,CAAA;AAAA,EAAG;AAAA,EAClD,OAAA,GAAU;AAAE,IAAA,OAAO,IAAA,CAAK,IAAI,aAAa,CAAA;AAAA,EAAG;AAAA,EAC5C,OAAA,GAAU;AAAE,IAAA,OAAO,IAAA,CAAK,IAAI,aAAa,CAAA;AAAA,EAAG;AAAA,EAC5C,QAAA,CAAS,CAAA,GAAY,EAAC,EAAG;AAAE,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,cAAA,EAAgB,CAAC,CAAA;AAAA,EAAG;AAAA;AAAA,EAG/D,SAAA,CAAU,QAAQ,EAAA,EAAI;AAAE,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,eAAA,EAAiB,EAAE,OAAO,CAAA;AAAA,EAAG;AAAA,EACrE,MAAA,CAAO,CAAA,GAAY,EAAC,EAAG;AAAE,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,YAAA,EAAc,CAAC,CAAA;AAAA,EAAG;AAAA,EAC3D,IAAA,CAAK,CAAA,GAAY,EAAC,EAAG;AAAE,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,UAAA,EAAY,CAAC,CAAA;AAAA,EAAG;AAAA,EACvD,QAAA,CAAS,CAAA,GAAY,EAAC,EAAG;AAAE,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,cAAA,EAAgB,CAAC,CAAA;AAAA,EAAG;AAAA,EAC/D,MAAA,CAAO,CAAA,EAAW,CAAA,GAAY,EAAC,EAAG;AAAE,IAAA,OAAO,KAAK,GAAA,CAAI,YAAA,EAAc,EAAE,CAAA,EAAG,GAAG,GAAG,CAAA;AAAA,EAAG;AAAA;AAAA,EAGhF,YAAA,CAAa,CAAA,GAAY,EAAC,EAAG;AAAE,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,mBAAA,EAAqB,CAAC,CAAA;AAAA,EAAG;AAAA,EACxE,aAAA,CAAc,CAAA,GAAY,EAAC,EAAG;AAAE,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,oBAAA,EAAsB,CAAC,CAAA;AAAA,EAAG;AAAA,EAC1E,gBAAA,CAAiB,CAAA,GAAY,EAAC,EAAG;AAAE,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,wBAAA,EAA0B,CAAC,CAAA;AAAA,EAAG;AAAA,EACjF,WAAA,CAAY,CAAA,GAAY,EAAC,EAAG;AAAE,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,kBAAA,EAAoB,CAAC,CAAA;AAAA,EAAG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQtE,YAAA,CAAa,CAAA,GAA+D,EAAC,EAAiB;AAC5F,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,mBAAA,EAAqB,CAAC,CAAA;AAAA,EACxC;AAAA;AAAA;AAAA,EAGA,kBAAkB,IAAA,EAA4B;AAC5C,IAAA,OAAO,KAAK,GAAA,CAAI,CAAA,kBAAA,EAAqB,kBAAA,CAAmB,IAAI,CAAC,CAAA,OAAA,CAAS,CAAA;AAAA,EACxE;AAAA;AAAA,EAEA,gBAAA,CAAiB,IAAA,EAAc,IAAA,GAAO,GAAA,EAAmB;AACvD,IAAA,OAAO,IAAA,CAAK,IAAI,CAAA,kBAAA,EAAqB,kBAAA,CAAmB,IAAI,CAAC,CAAA,UAAA,CAAA,EAAc,EAAE,IAAA,EAAM,CAAA;AAAA,EACrF;AAAA;AAAA,EAEA,YAAA,CAAa,CAAA,GAAoD,EAAC,EAAiB;AACjF,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,mBAAA,EAAqB,CAAC,CAAA;AAAA,EACxC;AAAA;AAAA,EAEA,YAAY,IAAA,EAA4B;AACtC,IAAA,OAAO,KAAK,GAAA,CAAI,CAAA,kBAAA,EAAqB,kBAAA,CAAmB,IAAI,CAAC,CAAA,CAAE,CAAA;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,YAAA,CAAa,CAAA,GAAiC,EAAC,EAAkC;AAC/E,IAAA,OAAO,IAAA,CAAK,GAAA,CAA0B,mBAAA,EAAqB,CAAC,CAAA;AAAA,EAC9D;AAAA;AAAA,EAGA,WAAA,CACE,EAAA,EACA,CAAA,GAAgC,EAAC,EACL;AAC5B,IAAA,OAAO,IAAA,CAAK,GAAA;AAAA,MACV,CAAA,kBAAA,EAAqB,kBAAA,CAAmB,MAAA,CAAO,EAAE,CAAC,CAAC,CAAA,CAAA;AAAA,MACnD;AAAA,KACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,eAAA,CACL,CAAA,GAAiC,EAAC,EACL;AAC7B,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,CAAA,CAAE,KAAA,IAAS,GAAG,CAAA,EAAG,CAAC,CAAA,EAAG,GAAG,CAAA;AAClE,IAAA,IAAI,MAAA,GAAS,MAAA,CAAO,CAAA,CAAE,MAAA,IAAU,CAAC,CAAA;AACjC,IAAA,WAAS;AACP,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,YAAA,CAAa,EAAE,GAAG,CAAA,EAAG,KAAA,EAAO,QAAA,EAAU,MAAA,EAAQ,CAAA;AACtE,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,IAAY,EAAC;AACnC,MAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG;AAC3B,MAAA,KAAA,MAAW,CAAA,IAAK,UAAU,MAAM,CAAA;AAChC,MAAA,IAAI,KAAK,IAAA,EAAM;AACf,MAAA,MAAA,IAAU,QAAA,CAAS,MAAA;AACnB,MAAA,IAAI,IAAA,CAAK,KAAA,IAAS,IAAA,IAAQ,MAAA,IAAU,KAAK,KAAA,EAAO;AAAA,IAClD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,UAAA,CAAW,CAAA,GAA+B,EAAC,EAAiC;AAC1E,IAAA,OAAO,IAAA,CAAK,IAAyB,YAAA,EAAc,EAAE,QAAQ,MAAA,EAAQ,GAAG,GAAG,CAAA;AAAA,EAC7E;AACF;AAEA,IAAO,aAAA,GAAQ","file":"index.js","sourcesContent":["/**\n * whereq.cloud — official JavaScript/TypeScript SDK for the WhereQ data cloud.\n *\n * A thin, typed wrapper over the versioned `/v1` HTTP API at `api.whereq.cloud`.\n * Public endpoints work with no key; metered endpoints take an API key.\n *\n * ```ts\n * import { Whereq } from \"@whereq/cloud\";\n *\n * const wq = new Whereq(); // public access\n * // const wq = new Whereq({ apiKey: \"wq_live_…\" }); // metered tier\n *\n * await wq.costOfLiving(\"us:California,ca:Ontario\");\n * await wq.prices({ domain: \"rent\", region: \"us\", bedrooms: 2 });\n * await wq.get(\"/v1/trending\", { limit: 10 }); // escape hatch\n * ```\n */\nexport const VERSION = \"0.5.0\";\nconst DEFAULT_BASE_URL = \"https://api.whereq.cloud\";\n\n/** The products a station can quote. Mexico's CRE feed carries the first,\n * second and fourth; GasBuddy (US/Canada) adds midgrade. */\nexport const FUEL_PRODUCTS = [\"regular\", \"midgrade\", \"premium\", \"diesel\"] as const;\nexport type FuelProduct = (typeof FUEL_PRODUCTS)[number];\n\n/** Countries with station-level fuel data. */\nexport const FUEL_COUNTRIES = [\"MX\", \"US\", \"CA\"] as const;\nexport type FuelCountry = (typeof FUEL_COUNTRIES)[number];\n\n/** The unit each country quotes in — always local currency per litre. */\nexport const FUEL_CURRENCIES: Record<FuelCountry, string> = {\n MX: \"MXN/L\",\n US: \"USD/L\",\n CA: \"CAD/L\",\n};\n\n/** One product's latest price at a station. */\nexport interface FuelStationPrice {\n price: number;\n observed_at: string;\n}\n\n/** A geolocated retail fuel station and its latest prices.\n * `state` is the human label (\"Ontario\", \"Texas\"); `state_iso` is the\n * two-letter code (\"ON\", \"TX\"). */\nexport interface FuelStation {\n id: number;\n source: string;\n ext_id: string;\n country: string;\n name: string;\n brand?: string | null;\n state?: string | null;\n state_iso?: string | null;\n municipality?: string | null;\n lat?: number | null;\n lon?: number | null;\n prices: Record<string, FuelStationPrice>;\n}\n\n/** Filters for `fuelStations()`. */\nexport interface FuelStationsParams {\n /** \"MX\", \"US\" or \"CA\". */\n country?: FuelCountry | string;\n /** State/province name *or* ISO code — \"Ontario\"/\"ON\", \"Texas\"/\"TX\". */\n state?: string;\n /** City name, e.g. \"Mississauga\". */\n municipality?: string;\n product?: FuelProduct | string;\n /** \"minLon,minLat,maxLon,maxLat\" — a map viewport. */\n bbox?: string;\n /** Station-name search. */\n q?: string;\n /** 1–500 rows per page (default 100). */\n limit?: number;\n /** Row offset for paging. */\n offset?: number;\n}\n\n/** Filters for `fuelStation()`. */\nexport interface FuelStationParams {\n /** Restrict the timeline to one product. */\n product?: FuelProduct | string;\n /** How far back the timeline reaches (1–1825, default 90). */\n days?: number;\n}\n\n/** `GET /v1/fuel/stations`. Unentitled callers get a 100-row preview of the\n * oldest rows: `demo` is true, `total` is null and paging is ignored. */\nexport interface FuelStationsResponse {\n demo?: boolean;\n preview_rows?: number;\n note?: string;\n upgrade_url?: string;\n as_of: string;\n count: number;\n total?: number | null;\n stations: FuelStation[];\n}\n\n/** One observed price change — the intra-day timeline for a station. */\nexport interface FuelStationPricePoint {\n product: string;\n observed_at: string;\n price: number;\n}\n\n/** `GET /v1/fuel/stations/{id}`. `days` is null in the unentitled preview. */\nexport interface FuelStationDetail {\n demo?: boolean;\n preview_rows?: number;\n note?: string;\n upgrade_url?: string;\n station: FuelStation;\n days?: number | null;\n prices: FuelStationPricePoint[];\n}\n\n/** Filters for `fuelPrices()`. */\nexport interface FuelPricesParams {\n /** Region slug, or a comma-separated list of them (\"us,ca\"). */\n region?: string;\n /** Free-text place name (\"Calgary, Alberta\"). */\n geo?: string;\n q?: string;\n limit?: number;\n offset?: number;\n}\n\n/** One aggregated price series (state / national / metro). */\nexport interface PriceSeries {\n id: number;\n domain: string;\n source: string;\n region?: string | null;\n geo?: string | null;\n item: string;\n item_cn?: string | null;\n unit?: string | null;\n unit_cn?: string | null;\n frequency?: string | null;\n latest_period?: string | null;\n latest_value?: number | null;\n prev_value?: number | null;\n points?: number | null;\n spark?: number[];\n}\n\n/** `GET /v1/prices` — a page of series plus the page's own metadata. */\nexport interface PriceSeriesResponse {\n count: number;\n domain?: string | null;\n region?: string | null;\n limit: number;\n offset: number;\n data: PriceSeries[];\n}\n\nexport class WhereqError extends Error {\n constructor(\n public readonly status: number,\n message: string,\n public readonly url: string,\n ) {\n super(`whereq.cloud API error ${status} for ${url}: ${message}`);\n this.name = \"WhereqError\";\n }\n}\n\nexport interface ClientOptions {\n /** `wq_live_…` key for metered endpoints (sent as `X-API-Key`). */\n apiKey?: string;\n /** Override the API base (default `https://api.whereq.cloud`). */\n baseUrl?: string;\n /** Custom fetch (e.g. for Node <18 or testing). Defaults to global `fetch`. */\n fetch?: typeof fetch;\n}\n\ntype Params = Record<string, unknown>;\n\n/** The API key from the environment, when there is one. */\nfunction envApiKey(): string {\n const proc = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process;\n return proc?.env?.WHEREQ_API_KEY ?? \"\";\n}\n\nexport class Whereq {\n private readonly baseUrl: string;\n private readonly headers: Record<string, string>;\n private readonly _fetch: typeof fetch;\n\n constructor(opts: ClientOptions = {}) {\n this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.headers = { Accept: \"application/json\" };\n // The key may come from the options or the environment, in that order.\n const key = opts.apiKey ?? envApiKey();\n if (key) this.headers[\"X-API-Key\"] = key;\n const f = opts.fetch ?? globalThis.fetch;\n if (!f) throw new Error(\"No global fetch available — pass `fetch` in options (Node <18).\");\n this._fetch = f;\n }\n\n private url(path: string, params: Params): string {\n const qs = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined && v !== null) qs.set(k, String(v));\n }\n const s = qs.toString();\n return `${this.baseUrl}${path}${s ? `?${s}` : \"\"}`;\n }\n\n /** GET any endpoint; `undefined`/`null` params are dropped. Returns parsed JSON. */\n async get<T = unknown>(path: string, params: Params = {}): Promise<T> {\n const url = this.url(path, params);\n const res = await this._fetch(url, { headers: this.headers });\n if (!res.ok) {\n let msg = res.statusText;\n try {\n const j = (await res.json()) as { detail?: string };\n msg = j?.detail || JSON.stringify(j) || msg;\n } catch {\n /* non-JSON error body */\n }\n throw new WhereqError(res.status, msg, url);\n }\n return (await res.json()) as T;\n }\n\n /** GET a non-JSON endpoint (e.g. CSV export) as text. */\n async getText(path: string, params: Params = {}): Promise<string> {\n const url = this.url(path, params);\n const res = await this._fetch(url, { headers: this.headers });\n if (!res.ok) throw new WhereqError(res.status, res.statusText, url);\n return res.text();\n }\n\n // -- prices / cost of living ------------------------------------------------\n /** Cost-of-living price series (fuel | food | energy | housing | rent).\n * `region` takes a region slug or a comma-separated list (\"us,ca\");\n * `geo` is a free-text place name (\"Calgary, Alberta\"). */\n prices(p: { domain?: string; region?: string; geo?: string; bedrooms?: number; q?: string; limit?: number; offset?: number } = {}): Promise<PriceSeriesResponse> {\n return this.get<PriceSeriesResponse>(\"/v1/prices\", p);\n }\n price(seriesId: number) {\n return this.get(`/v1/prices/${seriesId}`);\n }\n pricesCsv(p: { domain?: string; region?: string; geo?: string; bedrooms?: number; q?: string } = {}) {\n return this.getText(\"/v1/prices/export\", p);\n }\n /** Compare cost of living across US states / CA provinces / metros.\n * `places`: comma-separated `region:name` or `m:<rent-series-id>`. */\n costOfLiving(places: string) {\n return this.get(\"/v1/cost-of-living\", { places });\n }\n\n // -- discovery / facets -----------------------------------------------------\n catalog() { return this.get(\"/v1/catalog\"); }\n categories() { return this.get(\"/v1/categories\"); }\n regions() { return this.get(\"/v1/regions\"); }\n domains() { return this.get(\"/v1/domains\"); }\n trending(p: Params = {}) { return this.get(\"/v1/trending\", p); }\n\n // -- finance ----------------------------------------------------------------\n hotstocks(limit = 20) { return this.get(\"/v1/hotstocks\", { limit }); }\n quotes(p: Params = {}) { return this.get(\"/v1/quotes\", p); }\n news(p: Params = {}) { return this.get(\"/v1/news\", p); }\n screener(p: Params = {}) { return this.get(\"/v1/screener\", p); }\n search(q: string, p: Params = {}) { return this.get(\"/v1/search\", { q, ...p }); }\n\n // -- autos ------------------------------------------------------------------\n autosRecalls(p: Params = {}) { return this.get(\"/v1/autos/recalls\", p); }\n autosListings(p: Params = {}) { return this.get(\"/v1/autos/listings\", p); }\n autosFuelEconomy(p: Params = {}) { return this.get(\"/v1/autos/fuel-economy\", p); }\n autosModels(p: Params = {}) { return this.get(\"/v1/autos/models\", p); }\n\n // -- lottery -----------------------------------------------------------------\n /** Recent lottery draws, newest first.\n *\n * Unentitled callers get the oldest 100 draws instead of the recent\n * ones — check `response.demo`.\n */\n lotteryDraws(p: { game?: string; days?: number; limit?: number } & Params = {}): Promise<any> {\n return this.get(\"/v1/lottery/draws\", p);\n }\n /** The most recent draw for a game. On the unentitled preview this is the\n * *oldest* draw — the recent one is the gated, valuable row. */\n lotteryLatestDraw(game: string): Promise<any> {\n return this.get(`/v1/lottery/draws/${encodeURIComponent(game)}/latest`);\n }\n /** Per-number frequency for a game over a window (30–1825 days). */\n lotteryFrequency(game: string, days = 365): Promise<any> {\n return this.get(`/v1/lottery/draws/${encodeURIComponent(game)}/frequency`, { days });\n }\n /** The lottery game registry: names, play rules and draw days. */\n lotteryGames(p: { country?: string; region?: string } & Params = {}): Promise<any> {\n return this.get(\"/v1/lottery/games\", p);\n }\n /** One game's full play rules and metadata. */\n lotteryGame(slug: string): Promise<any> {\n return this.get(`/v1/lottery/games/${encodeURIComponent(slug)}`);\n }\n\n // -- fuel (gas & diesel) ----------------------------------------------------\n /** Geolocated retail fuel stations with their latest prices.\n *\n * Coverage: Mexico (`MX`, CRE open data), the United States (`US`) and\n * Canada (`CA`). Prices are in **local currency per litre** — `MXN/L`,\n * `USD/L` and `CAD/L` respectively.\n *\n * Unentitled callers get a 100-row preview of the oldest rows and the\n * pagination arguments are ignored — check `response.demo`.\n */\n fuelStations(p: FuelStationsParams & Params = {}): Promise<FuelStationsResponse> {\n return this.get<FuelStationsResponse>(\"/v1/fuel/stations\", p);\n }\n\n /** One station: location, latest prices and its price-change timeline. */\n fuelStation(\n id: number | string,\n p: FuelStationParams & Params = {},\n ): Promise<FuelStationDetail> {\n return this.get<FuelStationDetail>(\n `/v1/fuel/stations/${encodeURIComponent(String(id))}`,\n p,\n );\n }\n\n /** Yield every matching station, paging through the API for you.\n *\n * Only meaningful with an entitled key. The unentitled preview always\n * returns the *same* oldest 100 rows and ignores the paging arguments,\n * so there is nothing more to fetch: this yields that first page and\n * stops rather than looping on it.\n */\n async *fuelStationsAll(\n p: FuelStationsParams & Params = {},\n ): AsyncGenerator<FuelStation> {\n const pageSize = Math.min(Math.max(Number(p.limit ?? 500), 1), 500);\n let offset = Number(p.offset ?? 0);\n for (;;) {\n const page = await this.fuelStations({ ...p, limit: pageSize, offset });\n const stations = page.stations ?? [];\n if (stations.length === 0) return;\n for (const s of stations) yield s;\n if (page.demo) return; // preview: every page is the same slice\n offset += stations.length;\n if (page.total != null && offset >= page.total) return;\n }\n }\n\n /** Aggregated fuel price series (state / national / metro).\n *\n * These are the *series* behind the charts — EIA weekly for the US,\n * StatCan monthly for Canada, CRE for Mexico — not the station-level\n * prices that `fuelStations()` returns.\n */\n fuelPrices(p: FuelPricesParams & Params = {}): Promise<PriceSeriesResponse> {\n return this.get<PriceSeriesResponse>(\"/v1/prices\", { domain: \"fuel\", ...p });\n }\n}\n\nexport default Whereq;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@whereq/cloud",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Official JavaScript/TypeScript SDK for the WhereQ data cloud (api.whereq.cloud) — North-America fuel & gas-station prices, cost-of-living prices, autos, lottery, trending, finance & more.",
5
5
  "license": "MIT",
6
6
  "author": "WhereQ <whereq@gmail.com>",