keepa-api 0.2.0 → 0.2.3

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 (35) hide show
  1. package/README.md +10 -10
  2. package/dist/client.d.ts +2 -2
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +3 -3
  5. package/dist/client.js.map +1 -1
  6. package/dist/core/resource.d.ts +3 -3
  7. package/dist/core/resource.d.ts.map +1 -1
  8. package/dist/core/resource.js.map +1 -1
  9. package/dist/index.d.ts +1 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +1 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/lib/marketplace.d.ts +2 -2
  14. package/dist/lib/marketplace.d.ts.map +1 -1
  15. package/dist/lib/marketplace.js +6 -5
  16. package/dist/lib/marketplace.js.map +1 -1
  17. package/dist/resources/products/error.d.ts +10 -0
  18. package/dist/resources/products/error.d.ts.map +1 -0
  19. package/dist/resources/products/error.js +14 -0
  20. package/dist/resources/products/error.js.map +1 -0
  21. package/dist/resources/products/index.d.ts +4 -2
  22. package/dist/resources/products/index.d.ts.map +1 -1
  23. package/dist/resources/products/index.js +3 -1
  24. package/dist/resources/products/index.js.map +1 -1
  25. package/dist/resources/products/product.type.d.ts +7 -0
  26. package/dist/resources/products/product.type.d.ts.map +1 -1
  27. package/dist/resources/products/product.util.d.ts +15 -0
  28. package/dist/resources/products/product.util.d.ts.map +1 -0
  29. package/dist/resources/products/product.util.js +56 -0
  30. package/dist/resources/products/product.util.js.map +1 -0
  31. package/dist/resources/products/products.d.ts +4 -16
  32. package/dist/resources/products/products.d.ts.map +1 -1
  33. package/dist/resources/products/products.js +12 -59
  34. package/dist/resources/products/products.js.map +1 -1
  35. package/package.json +9 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # keepa-api
2
2
 
3
- Lightweight TypeScript SDK for the [Keepa](https://keepa.com) REST API. Mirrors the organizational style of [openai-node](https://github.com/openai/openai-node) — a single `Keepa` client class exposes resources (`products`, etc.) that wrap each endpoint with typed inputs and responses.
3
+ Lightweight TypeScript SDK for the [Keepa](https://keepa.com) REST API. Mirrors the organizational style of [openai-node](https://github.com/openai/openai-node) — a single `KeepaClient` class exposes resources (`products`, etc.) that wrap each endpoint with typed inputs and responses.
4
4
 
5
5
  Phase 1 ships the **Products** resource only. Categories, Search, and Bestsellers are planned but not yet implemented.
6
6
 
@@ -49,9 +49,9 @@ npm install /absolute/path/to/keepa-api-0.1.0.tgz
49
49
  ## Quickstart
50
50
 
51
51
  ```ts
52
- import Keepa from 'keepa-api';
52
+ import KeepaClient from 'keepa-api';
53
53
 
54
- const keepa = new Keepa({ apiKey: process.env.KEEPA_API_KEY });
54
+ const keepa = new KeepaClient({ apiKey: process.env.KEEPA_API_KEY });
55
55
 
56
56
  const products = await keepa.products.list({
57
57
  asins: ['B00MNV8E0C'],
@@ -65,7 +65,7 @@ The client reads `process.env.KEEPA_API_KEY` if you don't pass `apiKey` explicit
65
65
 
66
66
  ## API
67
67
 
68
- ### `new Keepa(options?)`
68
+ ### `new KeepaClient(options?)`
69
69
 
70
70
  | Option | Type | Default | Notes |
71
71
  |--------|------|---------|-------|
@@ -78,7 +78,7 @@ The client reads `process.env.KEEPA_API_KEY` if you don't pass `apiKey` explicit
78
78
  | Param | Type | Default | Notes |
79
79
  |-------|------|---------|-------|
80
80
  | `asins` | `string[]` | (required) | Validated + uppercased. Throws on malformed input. |
81
- | `marketplace` | `'US' \| 'UK' \| 'DE' \| 'FR' \| 'JP' \| 'CA' \| 'IT' \| 'ES' \| 'IN' \| 'MX' \| 'AU'` | `'US'` | Case-insensitive. Throws on unknown. |
81
+ | `marketplace` | `'US' \| 'GB' \| 'DE' \| 'FR' \| 'JP' \| 'CA' \| 'IT' \| 'ES' \| 'IN' \| 'MX' \| 'BR'` | `'US'` | Case-insensitive. Throws on unknown. |
82
82
  | `days` | `number` | `1` | Days of price history. Must be a positive integer (validated pre-flight). |
83
83
 
84
84
  The SDK maps Keepa's raw wire shape into a friendlier `KeepaProduct`:
@@ -88,7 +88,7 @@ The SDK maps Keepa's raw wire shape into a friendlier `KeepaProduct`:
88
88
 
89
89
  The raw `salesRanks` record is preserved for consumers that need to walk the full rank history. Other Keepa fields (`title`, `parentAsin`, `categoryTree`, `variations`, `features`, …) pass through unchanged.
90
90
 
91
- **Stub records:** Keepa returns one record per requested ASIN even when it has no data — these stubs have `title === undefined`. Filter with `isFoundProduct` (below).
91
+ **Stub records:** Keepa returns one record per requested ASIN even when it has no data — these stubs have `title === null`. Filter with `isFoundProduct` (below).
92
92
 
93
93
  ### Helpers
94
94
 
@@ -105,7 +105,7 @@ for (const product of real) {
105
105
 
106
106
  | Helper | Signature | Returns |
107
107
  |--------|-----------|---------|
108
- | `isFoundProduct(product)` | `(product: KeepaProduct) => boolean` | `true` only if Keepa returned real data (`title` is non-empty). |
108
+ | `isFoundProduct(product)` | `(product: KeepaProduct) => boolean` | `true` only if Keepa returned real data (stubs have `title === null`). |
109
109
  | `parseImagesCsv(csv)` | `(csv: string \| undefined) => string[]` | Build the full image-URL list from a raw Keepa imagesCSV. Used internally to fill `images`; exported for advanced use. |
110
110
  | `extractBsr(salesRanks, rootCategory)` | `(salesRanks: Record<string, number[]> \| undefined, rootCategory: number \| undefined) => number \| null` | Most recent real BSR from Keepa's raw `[ts, rank, ...]` history. Used internally to fill `bsr`; exported for advanced use. |
111
111
  | `extractImageUrl(imagesCSV)` | `(imagesCSV: string \| undefined) => string \| null` | Single URL — equivalent to `parseImagesCsv(imagesCSV)[0] ?? null`. Exported for advanced use. |
@@ -133,17 +133,17 @@ normalizeAsins(['B07XYZ']); // throws: Invalid ASIN(s): B07XYZ. ...
133
133
  import { MARKETPLACE_DOMAINS, resolveDomainId } from 'keepa-api';
134
134
 
135
135
  MARKETPLACE_DOMAINS.US; // 1
136
- resolveDomainId('uk'); // 2 (case-insensitive)
136
+ resolveDomainId('gb'); // 2 (case-insensitive)
137
137
  resolveDomainId(undefined); // 1 (defaults to US)
138
138
  ```
139
139
 
140
140
  | Code | Domain ID | Code | Domain ID |
141
141
  |------|-----------|------|-----------|
142
142
  | US | 1 | IT | 8 |
143
- | UK | 2 | ES | 9 |
143
+ | GB | 2 | ES | 9 |
144
144
  | DE | 3 | IN | 10 |
145
145
  | FR | 4 | MX | 11 |
146
- | JP | 5 | AU | 13 |
146
+ | JP | 5 | BR | 12 |
147
147
  | CA | 6 | | |
148
148
 
149
149
  ### Errors
package/dist/client.d.ts CHANGED
@@ -8,7 +8,7 @@ export interface ClientOptions {
8
8
  /** Custom fetch implementation. Defaults to `globalThis.fetch`. */
9
9
  fetch?: typeof globalThis.fetch;
10
10
  }
11
- export declare class Keepa {
11
+ export declare class KeepaClient {
12
12
  readonly apiKey: string;
13
13
  readonly baseURL: string;
14
14
  readonly fetch: typeof globalThis.fetch;
@@ -17,5 +17,5 @@ export declare class Keepa {
17
17
  /** Internal: used by APIResource subclasses to perform a request. */
18
18
  _request<T>(args: RequestArgs): Promise<T>;
19
19
  }
20
- export default Keepa;
20
+ export default KeepaClient;
21
21
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAiB,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAE5D,MAAM,WAAW,aAAa;IAC5B,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAID,qBAAa,KAAK;IAChB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAExC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;gBAEhB,OAAO,GAAE,aAAkB;IAuBvC,qEAAqE;IACrE,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC;CAQ3C;AAED,eAAe,KAAK,CAAC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAiB,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAE5D,MAAM,WAAW,aAAa;IAC5B,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAID,qBAAa,WAAW;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAExC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;gBAEhB,OAAO,GAAE,aAAkB;IAuBvC,qEAAqE;IACrE,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC;CAQ3C;AAED,eAAe,WAAW,CAAC"}
package/dist/client.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { request } from './core/request.js';
2
2
  import { Products } from './resources/products/products.js';
3
3
  const DEFAULT_BASE_URL = 'https://api.keepa.com';
4
- export class Keepa {
4
+ export class KeepaClient {
5
5
  apiKey;
6
6
  baseURL;
7
7
  fetch;
@@ -13,7 +13,7 @@ export class Keepa {
13
13
  const envApiKey = typeof process !== 'undefined' ? process.env?.KEEPA_API_KEY : undefined;
14
14
  const apiKey = options.apiKey || envApiKey;
15
15
  if (!apiKey) {
16
- throw new Error('Missing Keepa API key. Pass it as `new Keepa({ apiKey })` or set KEEPA_API_KEY in your environment.');
16
+ throw new Error('Missing Keepa API key. Pass it as `new KeepaClient({ apiKey })` or set KEEPA_API_KEY in your environment.');
17
17
  }
18
18
  this.apiKey = apiKey;
19
19
  // Strip a trailing slash so `${baseURL}${path}` never produces `//product`.
@@ -34,5 +34,5 @@ export class Keepa {
34
34
  return request(config, args);
35
35
  }
36
36
  }
37
- export default Keepa;
37
+ export default KeepaClient;
38
38
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAW5D,MAAM,gBAAgB,GAAG,uBAAuB,CAAC;AAEjD,MAAM,OAAO,KAAK;IACP,MAAM,CAAS;IACf,OAAO,CAAS;IAChB,KAAK,CAA0B;IAE/B,QAAQ,CAAW;IAE5B,YAAY,UAAyB,EAAE;QACrC,qFAAqF;QACrF,sFAAsF;QACtF,uCAAuC;QACvC,MAAM,SAAS,GACb,OAAO,OAAO,KAAK,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC;QAC1E,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,SAAS,CAAC;QAC3C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CACb,qGAAqG,CACtG,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,4EAA4E;QAC5E,IAAI,CAAC,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,gBAAgB,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACzE,sEAAsE;QACtE,0EAA0E;QAC1E,sEAAsE;QACtE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAEhE,IAAI,CAAC,QAAQ,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IAED,qEAAqE;IACrE,QAAQ,CAAI,IAAiB;QAC3B,MAAM,MAAM,GAAkB;YAC5B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,KAAK,EAAE,IAAI,CAAC,KAAK;SAClB,CAAC;QACF,OAAO,OAAO,CAAI,MAAM,EAAE,IAAI,CAAC,CAAC;IAClC,CAAC;CACF;AAED,eAAe,KAAK,CAAC"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAW5D,MAAM,gBAAgB,GAAG,uBAAuB,CAAC;AAEjD,MAAM,OAAO,WAAW;IACb,MAAM,CAAS;IACf,OAAO,CAAS;IAChB,KAAK,CAA0B;IAE/B,QAAQ,CAAW;IAE5B,YAAY,UAAyB,EAAE;QACrC,qFAAqF;QACrF,sFAAsF;QACtF,uCAAuC;QACvC,MAAM,SAAS,GACb,OAAO,OAAO,KAAK,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC;QAC1E,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,SAAS,CAAC;QAC3C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CACb,2GAA2G,CAC5G,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,4EAA4E;QAC5E,IAAI,CAAC,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,gBAAgB,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACzE,sEAAsE;QACtE,0EAA0E;QAC1E,sEAAsE;QACtE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAEhE,IAAI,CAAC,QAAQ,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IAED,qEAAqE;IACrE,QAAQ,CAAI,IAAiB;QAC3B,MAAM,MAAM,GAAkB;YAC5B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,KAAK,EAAE,IAAI,CAAC,KAAK;SAClB,CAAC;QACF,OAAO,OAAO,CAAI,MAAM,EAAE,IAAI,CAAC,CAAC;IAClC,CAAC;CACF;AAED,eAAe,WAAW,CAAC"}
@@ -1,6 +1,6 @@
1
- import type { Keepa } from '../client.js';
1
+ import type { KeepaClient } from '../client.js';
2
2
  export declare abstract class APIResource {
3
- protected _client: Keepa;
4
- constructor(client: Keepa);
3
+ protected _client: KeepaClient;
4
+ constructor(client: KeepaClient);
5
5
  }
6
6
  //# sourceMappingURL=resource.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../../src/core/resource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE1C,8BAAsB,WAAW;IAC/B,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC;gBAEb,MAAM,EAAE,KAAK;CAG1B"}
1
+ {"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../../src/core/resource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,8BAAsB,WAAW;IAC/B,SAAS,CAAC,OAAO,EAAE,WAAW,CAAC;gBAEnB,MAAM,EAAE,WAAW;CAGhC"}
@@ -1 +1 @@
1
- {"version":3,"file":"resource.js","sourceRoot":"","sources":["../../src/core/resource.ts"],"names":[],"mappings":"AAEA,MAAM,OAAgB,WAAW;IACrB,OAAO,CAAQ;IAEzB,YAAY,MAAa;QACvB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IACxB,CAAC;CACF"}
1
+ {"version":3,"file":"resource.js","sourceRoot":"","sources":["../../src/core/resource.ts"],"names":[],"mappings":"AAEA,MAAM,OAAgB,WAAW;IACrB,OAAO,CAAc;IAE/B,YAAY,MAAmB;QAC7B,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IACxB,CAAC;CACF"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { Keepa as default, Keepa, type ClientOptions } from './client.js';
1
+ export { KeepaClient as default, KeepaClient, type ClientOptions } from './client.js';
2
2
  export { KeepaError, APIError, RateLimitError, AuthenticationError, NetworkError, } from './core/error.js';
3
3
  export { APIResource } from './core/resource.js';
4
4
  export { MARKETPLACE_DOMAINS, resolveDomainId, type Marketplace, type DomainId, } from './lib/marketplace.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,OAAO,EAAE,KAAK,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAE1E,OAAO,EACL,UAAU,EACV,QAAQ,EACR,cAAc,EACd,mBAAmB,EACnB,YAAY,GACb,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,KAAK,WAAW,EAChB,KAAK,QAAQ,GACd,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,WAAW,EACX,UAAU,EACV,WAAW,EACX,cAAc,GACf,MAAM,eAAe,CAAC;AAEvB,cAAc,sBAAsB,CAAC;AAErC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,IAAI,OAAO,EAAE,WAAW,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAEtF,OAAO,EACL,UAAU,EACV,QAAQ,EACR,cAAc,EACd,mBAAmB,EACnB,YAAY,GACb,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,KAAK,WAAW,EAChB,KAAK,QAAQ,GACd,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,WAAW,EACX,UAAU,EACV,WAAW,EACX,cAAc,GACf,MAAM,eAAe,CAAC;AAEvB,cAAc,sBAAsB,CAAC;AAErC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { Keepa as default, Keepa } from './client.js';
1
+ export { KeepaClient as default, KeepaClient } from './client.js';
2
2
  export { KeepaError, APIError, RateLimitError, AuthenticationError, NetworkError, } from './core/error.js';
3
3
  export { APIResource } from './core/resource.js';
4
4
  export { MARKETPLACE_DOMAINS, resolveDomainId, } from './lib/marketplace.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,OAAO,EAAE,KAAK,EAAsB,MAAM,aAAa,CAAC;AAE1E,OAAO,EACL,UAAU,EACV,QAAQ,EACR,cAAc,EACd,mBAAmB,EACnB,YAAY,GACb,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,OAAO,EACL,mBAAmB,EACnB,eAAe,GAGhB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,WAAW,EACX,UAAU,EACV,WAAW,EACX,cAAc,GACf,MAAM,eAAe,CAAC;AAEvB,cAAc,sBAAsB,CAAC;AAErC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,IAAI,OAAO,EAAE,WAAW,EAAsB,MAAM,aAAa,CAAC;AAEtF,OAAO,EACL,UAAU,EACV,QAAQ,EACR,cAAc,EACd,mBAAmB,EACnB,YAAY,GACb,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,OAAO,EACL,mBAAmB,EACnB,eAAe,GAGhB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,WAAW,EACX,UAAU,EACV,WAAW,EACX,cAAc,GACf,MAAM,eAAe,CAAC;AAEvB,cAAc,sBAAsB,CAAC;AAErC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
@@ -1,6 +1,6 @@
1
1
  export declare const MARKETPLACE_DOMAINS: {
2
2
  readonly US: 1;
3
- readonly UK: 2;
3
+ readonly GB: 2;
4
4
  readonly DE: 3;
5
5
  readonly FR: 4;
6
6
  readonly JP: 5;
@@ -9,7 +9,7 @@ export declare const MARKETPLACE_DOMAINS: {
9
9
  readonly ES: 9;
10
10
  readonly IN: 10;
11
11
  readonly MX: 11;
12
- readonly AU: 13;
12
+ readonly BR: 12;
13
13
  };
14
14
  export type Marketplace = keyof typeof MARKETPLACE_DOMAINS;
15
15
  export type DomainId = (typeof MARKETPLACE_DOMAINS)[Marketplace];
@@ -1 +1 @@
1
- {"version":3,"file":"marketplace.d.ts","sourceRoot":"","sources":["../../src/lib/marketplace.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,mBAAmB;;;;;;;;;;;;CAYtB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,mBAAmB,CAAC;AAC3D,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,WAAW,CAAC,CAAC;AAIjE,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,CASzE"}
1
+ {"version":3,"file":"marketplace.d.ts","sourceRoot":"","sources":["../../src/lib/marketplace.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,mBAAmB;;;;;;;;;;;;CAYtB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,mBAAmB,CAAC;AAC3D,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,WAAW,CAAC,CAAC;AAIjE,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,CASzE"}
@@ -1,9 +1,10 @@
1
- // The 11 marketplaces consumed by the existing internal projects. Keepa supports more
2
- // (AE, NL, PL, SE, BR, TR, …); extend this map and the README marketplace table when
3
- // a new region is needed. The numeric id is Keepa's `domain` query parameter value.
1
+ // The full set of marketplaces Keepa currently supports. Codes are ISO 3166-1
2
+ // alpha-2; the numeric id is Keepa's `domain` query parameter value. Domain 7
3
+ // is reserved (formerly Amazon China, retired). Update the README marketplace
4
+ // table alongside any change here.
4
5
  export const MARKETPLACE_DOMAINS = {
5
6
  US: 1,
6
- UK: 2,
7
+ GB: 2,
7
8
  DE: 3,
8
9
  FR: 4,
9
10
  JP: 5,
@@ -12,7 +13,7 @@ export const MARKETPLACE_DOMAINS = {
12
13
  ES: 9,
13
14
  IN: 10,
14
15
  MX: 11,
15
- AU: 13,
16
+ BR: 12,
16
17
  };
17
18
  const SUPPORTED_LIST = Object.keys(MARKETPLACE_DOMAINS).join(', ');
18
19
  export function resolveDomainId(marketplace) {
@@ -1 +1 @@
1
- {"version":3,"file":"marketplace.js","sourceRoot":"","sources":["../../src/lib/marketplace.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,qFAAqF;AACrF,oFAAoF;AACpF,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,EAAE,EAAE,CAAC;IACL,EAAE,EAAE,CAAC;IACL,EAAE,EAAE,CAAC;IACL,EAAE,EAAE,CAAC;IACL,EAAE,EAAE,CAAC;IACL,EAAE,EAAE,CAAC;IACL,EAAE,EAAE,CAAC;IACL,EAAE,EAAE,CAAC;IACL,EAAE,EAAE,EAAE;IACN,EAAE,EAAE,EAAE;IACN,EAAE,EAAE,EAAE;CACE,CAAC;AAKX,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEnE,MAAM,UAAU,eAAe,CAAC,WAA+B;IAC7D,MAAM,GAAG,GAAG,CAAC,WAAW,IAAI,IAAI,CAAC,CAAC,WAAW,EAAiB,CAAC;IAC/D,MAAM,QAAQ,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAC;IAC1C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CACb,wBAAwB,WAAW,iBAAiB,cAAc,EAAE,CACrE,CAAC;IACJ,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"marketplace.js","sourceRoot":"","sources":["../../src/lib/marketplace.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,8EAA8E;AAC9E,8EAA8E;AAC9E,mCAAmC;AACnC,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,EAAE,EAAE,CAAC;IACL,EAAE,EAAE,CAAC;IACL,EAAE,EAAE,CAAC;IACL,EAAE,EAAE,CAAC;IACL,EAAE,EAAE,CAAC;IACL,EAAE,EAAE,CAAC;IACL,EAAE,EAAE,CAAC;IACL,EAAE,EAAE,CAAC;IACL,EAAE,EAAE,EAAE;IACN,EAAE,EAAE,EAAE;IACN,EAAE,EAAE,EAAE;CACE,CAAC;AAKX,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEnE,MAAM,UAAU,eAAe,CAAC,WAA+B;IAC7D,MAAM,GAAG,GAAG,CAAC,WAAW,IAAI,IAAI,CAAC,CAAC,WAAW,EAAiB,CAAC;IAC/D,MAAM,QAAQ,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAC;IAC1C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CACb,wBAAwB,WAAW,iBAAiB,cAAc,EAAE,CACrE,CAAC;IACJ,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { KeepaError } from '../../core/error.js';
2
+ /** Thrown by `Products.retrieve` when Keepa has no record for the requested ASIN
3
+ * (either no product object returned, or a stub with no title). The `asin`
4
+ * property carries the value the caller passed in, unchanged, so it can be
5
+ * surfaced in user-facing messages without re-deriving it. */
6
+ export declare class ProductNotFoundError extends KeepaError {
7
+ readonly asin: string;
8
+ constructor(asin: string);
9
+ }
10
+ //# sourceMappingURL=error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../../src/resources/products/error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD;;;+DAG+D;AAC/D,qBAAa,oBAAqB,SAAQ,UAAU;IAClD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,MAAM;CAKzB"}
@@ -0,0 +1,14 @@
1
+ import { KeepaError } from '../../core/error.js';
2
+ /** Thrown by `Products.retrieve` when Keepa has no record for the requested ASIN
3
+ * (either no product object returned, or a stub with no title). The `asin`
4
+ * property carries the value the caller passed in, unchanged, so it can be
5
+ * surfaced in user-facing messages without re-deriving it. */
6
+ export class ProductNotFoundError extends KeepaError {
7
+ asin;
8
+ constructor(asin) {
9
+ super(`Keepa: no product found for ASIN ${asin}`);
10
+ this.name = 'ProductNotFoundError';
11
+ this.asin = asin;
12
+ }
13
+ }
14
+ //# sourceMappingURL=error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error.js","sourceRoot":"","sources":["../../../src/resources/products/error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD;;;+DAG+D;AAC/D,MAAM,OAAO,oBAAqB,SAAQ,UAAU;IACzC,IAAI,CAAS;IAEtB,YAAY,IAAY;QACtB,KAAK,CAAC,oCAAoC,IAAI,EAAE,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;QACnC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF"}
@@ -1,4 +1,6 @@
1
- export { Products, extractBsr, isFoundProduct } from './products.js';
2
- export type { ProductListParams, KeepaProduct, KeepaVariation, KeepaVariationAttribute, KeepaCategoryNode, } from './product.type.js';
1
+ export { Products } from './products.js';
2
+ export { extractBsr, isFoundProduct } from './product.util.js';
3
+ export { ProductNotFoundError } from './error.js';
4
+ export type { ProductListParams, ProductRetrieveParams, KeepaProduct, KeepaVariation, KeepaVariationAttribute, KeepaCategoryNode, } from './product.type.js';
3
5
  export { PRODUCT_PATH, PRODUCT_LIST_CONTEXT, DEFAULT_DAYS, AMAZON_IMAGE_BASE, KEEPA_NO_DATA_SENTINEL, } from './constant.js';
4
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/resources/products/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAErE,YAAY,EACV,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACd,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAM3B,OAAO,EACL,YAAY,EACZ,oBAAoB,EACpB,YAAY,EACZ,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/resources/products/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAElD,YAAY,EACV,iBAAiB,EACjB,qBAAqB,EACrB,YAAY,EACZ,cAAc,EACd,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAM3B,OAAO,EACL,YAAY,EACZ,oBAAoB,EACpB,YAAY,EACZ,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,eAAe,CAAC"}
@@ -1,4 +1,6 @@
1
- export { Products, extractBsr, isFoundProduct } from './products.js';
1
+ export { Products } from './products.js';
2
+ export { extractBsr, isFoundProduct } from './product.util.js';
3
+ export { ProductNotFoundError } from './error.js';
2
4
  // NOTE: raw Keepa wire types (KeepaProductRaw, KeepaProductResponseRaw) are
3
5
  // intentionally NOT re-exported. They are an implementation detail — Products.list
4
6
  // maps them to the consumer-friendly KeepaProduct shape before returning.
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/resources/products/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAUrE,4EAA4E;AAC5E,mFAAmF;AACnF,0EAA0E;AAE1E,OAAO,EACL,YAAY,EACZ,oBAAoB,EACpB,YAAY,EACZ,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/resources/products/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAWlD,4EAA4E;AAC5E,mFAAmF;AACnF,0EAA0E;AAE1E,OAAO,EACL,YAAY,EACZ,oBAAoB,EACpB,YAAY,EACZ,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,eAAe,CAAC"}
@@ -6,6 +6,13 @@ export interface ProductListParams {
6
6
  /** Days of price history to include. Defaults to 1. */
7
7
  days?: number;
8
8
  }
9
+ export interface ProductRetrieveParams {
10
+ asin: string;
11
+ /** Marketplace code (case-insensitive at runtime). Defaults to 'US'. */
12
+ marketplace?: Marketplace;
13
+ /** Days of price history to include. Defaults to 1. */
14
+ days?: number;
15
+ }
9
16
  export interface KeepaCategoryNode {
10
17
  catId: number;
11
18
  name: string;
@@ -1 +1 @@
1
- {"version":3,"file":"product.type.d.ts","sourceRoot":"","sources":["../../../src/resources/products/product.type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,wEAAwE;IACxE,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,uBAAuB,EAAE,CAAC;CACxC;AAED;;;+DAG+D;AAC/D,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACtC,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IAEpB,gFAAgF;IAChF,MAAM,EAAE,MAAM,EAAE,CAAC;IAEjB;oDACgD;IAChD,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB"}
1
+ {"version":3,"file":"product.type.d.ts","sourceRoot":"","sources":["../../../src/resources/products/product.type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,wEAAwE;IACxE,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,uBAAuB,EAAE,CAAC;CACxC;AAED;;;+DAG+D;AAC/D,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACtC,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IAEpB,gFAAgF;IAChF,MAAM,EAAE,MAAM,EAAE,CAAC;IAEjB;oDACgD;IAChD,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB"}
@@ -0,0 +1,15 @@
1
+ import type { KeepaProduct } from './product.type.js';
2
+ import type { KeepaProductRaw } from './product.raw.type.js';
3
+ /** Map Keepa's raw wire shape into the consumer-friendly KeepaProduct. */
4
+ export declare function toKeepaProduct(raw: KeepaProductRaw): KeepaProduct;
5
+ /** Returns true when Keepa returned an actual product record (not just a stub
6
+ * for an unknown ASIN). Stubs come back with `title: null`; real listings
7
+ * always have a string. Use as a `.filter()` predicate to drop empty matches. */
8
+ export declare function isFoundProduct(product: KeepaProduct): boolean;
9
+ /** Extract the most recent real BSR from Keepa's `[ts, rank, ts, rank, ...]` salesRanks array.
10
+ * Walks backward through rank entries (odd indices) and skips Keepa's `-1` sentinel which
11
+ * marks "no data captured at that timestamp". Returns `null` if every entry is sentinel.
12
+ * Most consumers won't need this — `Products.list` already fills `bsr` on every returned
13
+ * product. Useful when working with a raw Keepa response. */
14
+ export declare function extractBsr(salesRanks: Record<string, number[]> | undefined, rootCategory: number | undefined): number | null;
15
+ //# sourceMappingURL=product.util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"product.util.d.ts","sourceRoot":"","sources":["../../../src/resources/products/product.util.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAiB,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE5E,0EAA0E;AAC1E,wBAAgB,cAAc,CAAC,GAAG,EAAE,eAAe,GAAG,YAAY,CAcjE;AAYD;;kFAEkF;AAClF,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAE7D;AAED;;;;8DAI8D;AAC9D,wBAAgB,UAAU,CACxB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,SAAS,EAChD,YAAY,EAAE,MAAM,GAAG,SAAS,GAC/B,MAAM,GAAG,IAAI,CAaf"}
@@ -0,0 +1,56 @@
1
+ import { AMAZON_IMAGE_BASE, KEEPA_NO_DATA_SENTINEL, VALID_IMAGE_FILENAME, } from './constant.js';
2
+ /** Map Keepa's raw wire shape into the consumer-friendly KeepaProduct. */
3
+ export function toKeepaProduct(raw) {
4
+ return {
5
+ asin: raw.asin,
6
+ title: raw.title,
7
+ description: raw.description,
8
+ parentAsin: raw.parentAsin,
9
+ categoryTree: raw.categoryTree,
10
+ rootCategory: raw.rootCategory,
11
+ salesRanks: raw.salesRanks,
12
+ variations: raw.variations,
13
+ features: raw.features,
14
+ images: rawImagesToUrls(raw.images),
15
+ bsr: extractBsr(raw.salesRanks, raw.rootCategory),
16
+ };
17
+ }
18
+ /** Convert Keepa's raw images array into full Amazon image URLs (the large
19
+ * variant). Filters entries whose filename doesn't match the expected
20
+ * alphanumeric image-name pattern as defense-in-depth. */
21
+ function rawImagesToUrls(images) {
22
+ if (!images || images.length === 0)
23
+ return [];
24
+ return images
25
+ .filter((img) => typeof img.l === 'string' && VALID_IMAGE_FILENAME.test(img.l))
26
+ .map((img) => `${AMAZON_IMAGE_BASE}/${img.l}`);
27
+ }
28
+ /** Returns true when Keepa returned an actual product record (not just a stub
29
+ * for an unknown ASIN). Stubs come back with `title: null`; real listings
30
+ * always have a string. Use as a `.filter()` predicate to drop empty matches. */
31
+ export function isFoundProduct(product) {
32
+ return product.title != null;
33
+ }
34
+ /** Extract the most recent real BSR from Keepa's `[ts, rank, ts, rank, ...]` salesRanks array.
35
+ * Walks backward through rank entries (odd indices) and skips Keepa's `-1` sentinel which
36
+ * marks "no data captured at that timestamp". Returns `null` if every entry is sentinel.
37
+ * Most consumers won't need this — `Products.list` already fills `bsr` on every returned
38
+ * product. Useful when working with a raw Keepa response. */
39
+ export function extractBsr(salesRanks, rootCategory) {
40
+ if (!salesRanks || rootCategory === undefined)
41
+ return null;
42
+ const ranks = salesRanks[String(rootCategory)];
43
+ if (!ranks || ranks.length < 2)
44
+ return null;
45
+ // Keepa pairs are [ts, rank, ts, rank, ...]. If length is even, the last index
46
+ // is a rank; if odd (truncated/schema drift), it's a dangling timestamp — skip
47
+ // back one slot so we always start on a rank.
48
+ const start = ranks.length % 2 === 0 ? ranks.length - 1 : ranks.length - 2;
49
+ for (let i = start; i >= 1; i -= 2) {
50
+ const rank = ranks[i];
51
+ if (rank !== undefined && rank !== KEEPA_NO_DATA_SENTINEL)
52
+ return rank;
53
+ }
54
+ return null;
55
+ }
56
+ //# sourceMappingURL=product.util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"product.util.js","sourceRoot":"","sources":["../../../src/resources/products/product.util.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,eAAe,CAAC;AAIvB,0EAA0E;AAC1E,MAAM,UAAU,cAAc,CAAC,GAAoB;IACjD,OAAO;QACL,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,YAAY,EAAE,GAAG,CAAC,YAAY;QAC9B,YAAY,EAAE,GAAG,CAAC,YAAY;QAC9B,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,MAAM,EAAE,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC;QACnC,GAAG,EAAE,UAAU,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,YAAY,CAAC;KAClD,CAAC;AACJ,CAAC;AAED;;2DAE2D;AAC3D,SAAS,eAAe,CAAC,MAAmC;IAC1D,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAC9C,OAAO,MAAM;SACV,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,GAAG,CAAC,CAAC,KAAK,QAAQ,IAAI,oBAAoB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;SAC9E,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,iBAAiB,IAAI,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;AACnD,CAAC;AAED;;kFAEkF;AAClF,MAAM,UAAU,cAAc,CAAC,OAAqB;IAClD,OAAO,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC;AAC/B,CAAC;AAED;;;;8DAI8D;AAC9D,MAAM,UAAU,UAAU,CACxB,UAAgD,EAChD,YAAgC;IAEhC,IAAI,CAAC,UAAU,IAAI,YAAY,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAC3D,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;IAC/C,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5C,+EAA+E;IAC/E,+EAA+E;IAC/E,8CAA8C;IAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IAC3E,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,sBAAsB;YAAE,OAAO,IAAI,CAAC;IACzE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -1,21 +1,9 @@
1
1
  import { APIResource } from '../../core/resource.js';
2
- import type { KeepaProduct, ProductListParams } from './product.type.js';
2
+ import type { KeepaProduct, ProductListParams, ProductRetrieveParams } from './product.type.js';
3
3
  export declare class Products extends APIResource {
4
4
  list(params: ProductListParams): Promise<KeepaProduct[]>;
5
+ /** Fetch a single product by ASIN. Throws `ProductNotFoundError` when Keepa
6
+ * has no record for the ASIN (no product returned, or a stub with no title). */
7
+ retrieve(params: ProductRetrieveParams): Promise<KeepaProduct>;
5
8
  }
6
- /** Returns true when Keepa returned an actual product record (not just a stub
7
- * for an unknown ASIN). Use as a `.filter()` predicate to drop empty matches.
8
- *
9
- * We use `title.length > 0` because it's the strongest single correlate of
10
- * "Keepa has data" — stubs for unknown ASINs come back without a title, and
11
- * every real listing has one. If Keepa's stub format changes (e.g. they start
12
- * returning a placeholder title), tighten this predicate to also require
13
- * `categoryTree` or another non-string field. */
14
- export declare function isFoundProduct(product: KeepaProduct): boolean;
15
- /** Extract the most recent real BSR from Keepa's `[ts, rank, ts, rank, ...]` salesRanks array.
16
- * Walks backward through rank entries (odd indices) and skips Keepa's `-1` sentinel which
17
- * marks "no data captured at that timestamp". Returns `null` if every entry is sentinel.
18
- * Most consumers won't need this — `Products.list` already fills `bsr` on every returned
19
- * product. Useful when working with a raw Keepa response. */
20
- export declare function extractBsr(salesRanks: Record<string, number[]> | undefined, rootCategory: number | undefined): number | null;
21
9
  //# sourceMappingURL=products.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"products.d.ts","sourceRoot":"","sources":["../../../src/resources/products/products.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAWrD,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAOzE,qBAAa,QAAS,SAAQ,WAAW;IACjC,IAAI,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;CAuB/D;AA6BD;;;;;;;kDAOkD;AAClD,wBAAgB,cAAc,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAE7D;AAED;;;;8DAI8D;AAC9D,wBAAgB,UAAU,CACxB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,SAAS,EAChD,YAAY,EAAE,MAAM,GAAG,SAAS,GAC/B,MAAM,GAAG,IAAI,CAaf"}
1
+ {"version":3,"file":"products.d.ts","sourceRoot":"","sources":["../../../src/resources/products/products.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAQrD,OAAO,KAAK,EACV,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,EACtB,MAAM,mBAAmB,CAAC;AAK3B,qBAAa,QAAS,SAAQ,WAAW;IACjC,IAAI,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAwB9D;qFACiF;IAC3E,QAAQ,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,YAAY,CAAC;CAQrE"}
@@ -1,7 +1,9 @@
1
1
  import { APIResource } from '../../core/resource.js';
2
2
  import { resolveDomainId } from '../../lib/marketplace.js';
3
3
  import { normalizeAsins } from '../../lib/asin.js';
4
- import { PRODUCT_PATH, PRODUCT_LIST_CONTEXT, DEFAULT_DAYS, AMAZON_IMAGE_BASE, KEEPA_NO_DATA_SENTINEL, VALID_IMAGE_FILENAME, } from './constant.js';
4
+ import { PRODUCT_PATH, PRODUCT_LIST_CONTEXT, DEFAULT_DAYS, } from './constant.js';
5
+ import { ProductNotFoundError } from './error.js';
6
+ import { toKeepaProduct, isFoundProduct } from './product.util.js';
5
7
  export class Products extends APIResource {
6
8
  async list(params) {
7
9
  if (params.asins.length === 0) {
@@ -24,64 +26,15 @@ export class Products extends APIResource {
24
26
  });
25
27
  return (data.products ?? []).map(toKeepaProduct);
26
28
  }
27
- }
28
- /** Map Keepa's raw wire shape into the consumer-friendly KeepaProduct. */
29
- function toKeepaProduct(raw) {
30
- return {
31
- asin: raw.asin,
32
- title: raw.title,
33
- description: raw.description,
34
- parentAsin: raw.parentAsin,
35
- categoryTree: raw.categoryTree,
36
- rootCategory: raw.rootCategory,
37
- salesRanks: raw.salesRanks,
38
- variations: raw.variations,
39
- features: raw.features,
40
- images: rawImagesToUrls(raw.images),
41
- bsr: extractBsr(raw.salesRanks, raw.rootCategory),
42
- };
43
- }
44
- /** Convert Keepa's raw images array into full Amazon image URLs (the large
45
- * variant). Filters entries whose filename doesn't match the expected
46
- * alphanumeric image-name pattern as defense-in-depth. */
47
- function rawImagesToUrls(images) {
48
- if (!images || images.length === 0)
49
- return [];
50
- return images
51
- .filter((img) => typeof img.l === 'string' && VALID_IMAGE_FILENAME.test(img.l))
52
- .map((img) => `${AMAZON_IMAGE_BASE}/${img.l}`);
53
- }
54
- /** Returns true when Keepa returned an actual product record (not just a stub
55
- * for an unknown ASIN). Use as a `.filter()` predicate to drop empty matches.
56
- *
57
- * We use `title.length > 0` because it's the strongest single correlate of
58
- * "Keepa has data" — stubs for unknown ASINs come back without a title, and
59
- * every real listing has one. If Keepa's stub format changes (e.g. they start
60
- * returning a placeholder title), tighten this predicate to also require
61
- * `categoryTree` or another non-string field. */
62
- export function isFoundProduct(product) {
63
- return typeof product.title === 'string' && product.title.length > 0;
64
- }
65
- /** Extract the most recent real BSR from Keepa's `[ts, rank, ts, rank, ...]` salesRanks array.
66
- * Walks backward through rank entries (odd indices) and skips Keepa's `-1` sentinel which
67
- * marks "no data captured at that timestamp". Returns `null` if every entry is sentinel.
68
- * Most consumers won't need this — `Products.list` already fills `bsr` on every returned
69
- * product. Useful when working with a raw Keepa response. */
70
- export function extractBsr(salesRanks, rootCategory) {
71
- if (!salesRanks || rootCategory === undefined)
72
- return null;
73
- const ranks = salesRanks[String(rootCategory)];
74
- if (!ranks || ranks.length < 2)
75
- return null;
76
- // Keepa pairs are [ts, rank, ts, rank, ...]. If length is even, the last index
77
- // is a rank; if odd (truncated/schema drift), it's a dangling timestamp — skip
78
- // back one slot so we always start on a rank.
79
- const start = ranks.length % 2 === 0 ? ranks.length - 1 : ranks.length - 2;
80
- for (let i = start; i >= 1; i -= 2) {
81
- const rank = ranks[i];
82
- if (rank !== undefined && rank !== KEEPA_NO_DATA_SENTINEL)
83
- return rank;
29
+ /** Fetch a single product by ASIN. Throws `ProductNotFoundError` when Keepa
30
+ * has no record for the ASIN (no product returned, or a stub with no title). */
31
+ async retrieve(params) {
32
+ const { asin, ...rest } = params;
33
+ const [product] = await this.list({ ...rest, asins: [asin] });
34
+ if (!product || !isFoundProduct(product)) {
35
+ throw new ProductNotFoundError(asin);
36
+ }
37
+ return product;
84
38
  }
85
- return null;
86
39
  }
87
40
  //# sourceMappingURL=products.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"products.js","sourceRoot":"","sources":["../../../src/resources/products/products.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"products.js","sourceRoot":"","sources":["../../../src/resources/products/products.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EACL,YAAY,EACZ,oBAAoB,EACpB,YAAY,GACb,MAAM,eAAe,CAAC;AAOvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnE,MAAM,OAAO,QAAS,SAAQ,WAAW;IACvC,KAAK,CAAC,IAAI,CAAC,MAAyB;QAClC,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;QACnD,CAAC;QACD,IACE,MAAM,CAAC,IAAI,KAAK,SAAS;YACzB,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,EACnD,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,iBAAiB,MAAM,CAAC,IAAI,+BAA+B,CAAC,CAAC;QAC/E,CAAC;QACD,MAAM,KAAK,GAAG,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC3C,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACnD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAA0B;YAChE,IAAI,EAAE,YAAY;YAClB,KAAK,EAAE;gBACL,MAAM;gBACN,IAAI,EAAE,KAAK;gBACX,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,YAAY;aAClC;YACD,OAAO,EAAE,oBAAoB;SAC9B,CAAC,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACnD,CAAC;IAED;qFACiF;IACjF,KAAK,CAAC,QAAQ,CAAC,MAA6B;QAC1C,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,MAAM,CAAC;QACjC,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9D,IAAI,CAAC,OAAO,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;YACzC,MAAM,IAAI,oBAAoB,CAAC,IAAI,CAAC,CAAC;QACvC,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;CACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keepa-api",
3
- "version": "0.2.0",
3
+ "version": "0.2.3",
4
4
  "description": "TypeScript SDK for the Keepa API.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -35,6 +35,14 @@
35
35
  "asin"
36
36
  ],
37
37
  "license": "MIT",
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "git+https://github.com/bilalyasin1616/keepa-api.git"
41
+ },
42
+ "bugs": {
43
+ "url": "https://github.com/bilalyasin1616/keepa-api/issues"
44
+ },
45
+ "homepage": "https://github.com/bilalyasin1616/keepa-api#readme",
38
46
  "devDependencies": {
39
47
  "@types/node": "^22.10.0",
40
48
  "dotenv": "^16.4.0",