encarapi 1.1.1 → 1.2.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
@@ -82,7 +82,9 @@ saveCursor(client.china.lastCursor);
82
82
  |---|---|---|
83
83
  | `catalog(params)` | `GET /api/catalog` | Search & list. `source`: `encar` (default), `kbc`, `kcar`, `all` |
84
84
  | `iterateCatalog(params)` | `GET /api/catalog` | Async iterator over all pages |
85
+ | `iterateCatalogById(params)` | `GET /api/catalog?sort=id` | Complete, stable traversal (keyset cursor, nothing repeated or skipped) |
85
86
  | `leasing(params)` | `GET /api/catalog/leasing` | Lease takeovers and rentals |
87
+ | `iterateLeasingById(params)` | `GET /api/catalog/leasing?sort=id` | Complete, stable traversal of lease/rental listings |
86
88
  | `nav(params)` | `GET /api/nav` | Filter facets with counts |
87
89
  | `enums(params)` | `GET /api/enums` | Valid values for the flat filters |
88
90
  | `modelSearch(search, params)` | `GET /api/model-search` | Model autocomplete |
@@ -94,7 +96,7 @@ saveCursor(client.china.lastCursor);
94
96
  | `bulkVehicles(ids)` / `bulkInspections(ids)` / `bulkRecords(ids)` | `POST /api/.../bulk` | Up to 500 ids (Business/Scale) |
95
97
  | `inspectionVersions(id)` / `recordVersions(id)` | `GET /api/.../versions` | Report history (Business/Scale) |
96
98
  | `changes(params)` / `iterateChanges(params)` | `GET /api/catalog/changes` | Incremental sync (Business/Scale) |
97
- | `exportCsv()` | `GET /api/catalog/export` | Full catalog CSV (Business/Scale) |
99
+ | `exportCsv(params)` | `GET /api/catalog/export` | Full catalog CSV (Business/Scale); `{ sell_type: "lease,rental" }` for lease/rental |
98
100
  | `makesCsv()` / `modelsCsv()` / `badgesCsv()` | `GET /api/taxonomy/*.csv` | Reference data |
99
101
 
100
102
  ## China API (`client.china`)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "encarapi",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "Official Node.js client for EnCarAPI: Korean used car data (Encar, KB Chachacha, K Car) and Chinese used car data (Dongchedi, Che168) in one REST API.",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
package/src/index.d.ts CHANGED
@@ -65,10 +65,17 @@ export interface KoreaCatalogParams {
65
65
  exclude_prices?: string;
66
66
  exclude_duplicates?: Bool;
67
67
  min_first_seen?: string;
68
+ /** Region codes, comma = OR (seoul, gyeonggi, busan, ...). Encar listings only for now. */
69
+ region?: string;
70
+ /** Cities, comma = OR: value from korea.enums().city (e.g. "suwon"), English or Korean name. Encar only. */
71
+ city?: string;
72
+ /** Keyset cursor for sort "id": nextAfter of the previous response. */
73
+ after?: string;
68
74
  /** Raw Encar q-grammar (alternative to the flat filters). */
69
75
  q?: string;
70
76
  lang?: "en";
71
- sort?: "newest" | "price_asc" | "price_desc" | "mileage_asc" | "mileage_desc" | "year_desc" | "year_asc";
77
+ /** "id" = stable listing-id order; page with `after` (see iterateCatalogById). */
78
+ sort?: "newest" | "price_asc" | "price_desc" | "mileage_asc" | "mileage_desc" | "year_desc" | "year_asc" | "id";
72
79
  page?: number;
73
80
  limit?: number;
74
81
  count?: Bool;
@@ -77,6 +84,10 @@ export interface KoreaCatalogParams {
77
84
  export interface KoreaCatalogResponse {
78
85
  Count?: number;
79
86
  SearchResults: Json[];
87
+ /** Only with sort "id": pass as `after` for the next page; null on the last page. */
88
+ nextAfter?: string | null;
89
+ /** Only with sort "id": true while more pages follow. */
90
+ hasMore?: boolean;
80
91
  [key: string]: any;
81
92
  }
82
93
 
@@ -115,6 +126,10 @@ export class KoreaClient {
115
126
  enums(params?: { source?: KoreaSource }): Promise<Json>;
116
127
  modelSearch(search: string, params?: { limit?: number; source?: KoreaSource; exclude_duplicates?: Bool; has_photos?: Bool; exclude_prices?: string; min_price?: number }): Promise<Json>;
117
128
  iterateCatalog(params?: KoreaCatalogParams): AsyncGenerator<Json, void, unknown>;
129
+ /** Complete, stable traversal (sort=id + after): nothing repeated or skipped while the catalog changes. */
130
+ iterateCatalogById(params?: KoreaCatalogParams): AsyncGenerator<Json, void, unknown>;
131
+ /** iterateCatalogById() for lease-takeover and rental listings. */
132
+ iterateLeasingById(params?: KoreaCatalogParams): AsyncGenerator<Json, void, unknown>;
118
133
  /** Ids: Encar id, "kbc:<id>" or "kcar:<id>". */
119
134
  vehicle(id: string, params?: { lang?: "en" }): Promise<Json>;
120
135
  inspection(id: string): Promise<Json>;
@@ -130,7 +145,8 @@ export class KoreaClient {
130
145
  changes(params: KoreaChangesParams): Promise<KoreaChangesResponse>;
131
146
  iterateChanges(params: KoreaChangesParams): AsyncGenerator<KoreaChange, void, unknown>;
132
147
  /** CSV text. */
133
- exportCsv(params?: { source?: KoreaSource }): Promise<string>;
148
+ /** sell_type: "sale" (default), "lease", "rental", a comma list or "all". */
149
+ exportCsv(params?: { source?: KoreaSource; sell_type?: string }): Promise<string>;
134
150
  makesCsv(params?: { source?: KoreaSource }): Promise<string>;
135
151
  modelsCsv(params?: { source?: KoreaSource }): Promise<string>;
136
152
  badgesCsv(params?: { source?: KoreaSource }): Promise<string>;
package/src/korea.js CHANGED
@@ -49,6 +49,32 @@ class KoreaClient {
49
49
  }
50
50
  }
51
51
 
52
+ /**
53
+ * Complete, stable traversal via sort=id + after (keyset cursor): rows never
54
+ * shift between pages while the catalog changes, so nothing is repeated or
55
+ * skipped. Yields every matching listing once, in listing-id order.
56
+ * for await (const car of korea.iterateCatalogById({ manufacturer: "BMW" })) {}
57
+ */
58
+ async *iterateCatalogById(params = {}) {
59
+ yield* this._iterateById("/api/catalog", params);
60
+ }
61
+
62
+ /** Same as iterateCatalogById() for lease-takeover and rental listings. */
63
+ async *iterateLeasingById(params = {}) {
64
+ yield* this._iterateById("/api/catalog/leasing", params);
65
+ }
66
+
67
+ async *_iterateById(path, params) {
68
+ const { page, ...rest } = params;
69
+ let query = { ...rest, sort: "id", limit: params.limit || 1000 };
70
+ for (;;) {
71
+ const res = await this.http.request("GET", path, { params: query });
72
+ for (const item of res.SearchResults || []) yield item;
73
+ if (!res.hasMore || !res.nextAfter) return;
74
+ query = { ...query, after: res.nextAfter };
75
+ }
76
+ }
77
+
52
78
  // -- one vehicle -------------------------------------------------------------
53
79
 
54
80
  /** Full vehicle detail. Ids: Encar id, "kbc:<id>" or "kcar:<id>". */
@@ -105,7 +131,10 @@ class KoreaClient {
105
131
  }
106
132
  }
107
133
 
108
- /** Full catalog as CSV text. */
134
+ /**
135
+ * Full catalog as CSV text. { sell_type: "lease,rental" } for the lease/rental
136
+ * inventory, { source: "kbc" } etc. for other marketplaces.
137
+ */
109
138
  exportCsv(params) { return this.http.request("GET", "/api/catalog/export", { params, text: true }); }
110
139
 
111
140
  // -- reference data -------------------------------------------------------------