@meterapp/vehicle-db 2.5.0 → 2.7.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 +131 -4
- package/dist/data.d.ts +14 -0
- package/dist/data.js +1 -1
- package/dist/index.d.ts +75 -2
- package/dist/index.js +138 -3
- package/dist/search.d.ts +47 -0
- package/dist/search.js +482 -0
- package/package.json +26 -2
package/README.md
CHANGED
|
@@ -2,8 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
An offline, international vehicle make/model catalog for Node.js and TypeScript. The package combines U.S. model-year data, the UK registered fleet, Asian-origin vehicles registered in New Zealand, Malaysian registration transactions, and an Indian manufacturer catalog into one small, zero-dependency API. It never makes runtime network requests.
|
|
4
4
|
|
|
5
|
+
The current snapshot spans **1990–2026** and includes **1,145 makes**, **14,841 model names**, and **132,491 deduplicated model-year entries** from **5 data sources**.
|
|
6
|
+
|
|
5
7
|
The catalog covers seven vehicle types: **Motorcycle**, **Passenger Car**, **Truck**, **Bus**, **Multipurpose Passenger Vehicle (MPV)**, **Auto Rickshaw**, and **Other Vehicle**. The Asia-Pacific sources add Japanese domestic and kei models, Chinese EVs, Indian and Korean vehicles, Southeast Asian makes such as Perodua and Proton, and additional motorcycles and commercial vehicles.
|
|
6
8
|
|
|
9
|
+
## Demo and playground
|
|
10
|
+
|
|
11
|
+
This catalog is the backbone of the [Car Image API](https://car-imgs.vercel.app) — an AI-native API that renders studio-quality, transparent-background images of every vehicle listed here (six camera angles, 15 colors, PNG/WebP/JPG, $1 per 1,000 images). Explore the data in the [interactive playground](https://car-imgs.vercel.app/playground) or browse vehicles at [car-imgs.vercel.app/cars](https://car-imgs.vercel.app/cars).
|
|
12
|
+
|
|
13
|
+
**Missing a vehicle?** Add it here and it becomes renderable in the API on the next release — see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
14
|
+
|
|
7
15
|
## Install
|
|
8
16
|
|
|
9
17
|
```bash
|
|
@@ -21,6 +29,10 @@ import {
|
|
|
21
29
|
getMakes,
|
|
22
30
|
getModels,
|
|
23
31
|
getAvailableYears,
|
|
32
|
+
getAvailableYearRanges,
|
|
33
|
+
getModelAppearanceRanges,
|
|
34
|
+
getModelRenderGroups,
|
|
35
|
+
getRepresentativeYear,
|
|
24
36
|
} from "@meterapp/vehicle-db";
|
|
25
37
|
|
|
26
38
|
// Inspect provenance and coverage before querying.
|
|
@@ -75,9 +87,100 @@ const malaysiaMakes = getMakes({
|
|
|
75
87
|
// Existing queries remain valid.
|
|
76
88
|
const toyota = getMakes({ year: 2024 }).find((make) => make.makeName === "TOYOTA");
|
|
77
89
|
const toyotaModels = getModels({ makeId: toyota!.makeId, year: 2024 });
|
|
78
|
-
const years = getAvailableYears(
|
|
90
|
+
const years = getAvailableYears({
|
|
91
|
+
makeId: toyota!.makeId,
|
|
92
|
+
vehicleTypeId: 2,
|
|
93
|
+
sourceId: "nhtsa-vpic",
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Availability and exterior equivalence are intentionally separate.
|
|
97
|
+
const availability = getAvailableYearRanges({ makeId: toyota!.makeId });
|
|
98
|
+
const arteonAppearances = getModelAppearanceRanges({
|
|
99
|
+
makeId: getMakes().find((make) => make.makeName === "VOLKSWAGEN")!.makeId,
|
|
100
|
+
modelName: "Arteon",
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Safe cache identity: verified ranges share a representative year; unknown
|
|
104
|
+
// and overlapping transition years return the requested year unchanged.
|
|
105
|
+
const renderYear = getRepresentativeYear({
|
|
106
|
+
makeId: arteonAppearances[0].makeId,
|
|
107
|
+
modelName: "Arteon",
|
|
108
|
+
year: 2018,
|
|
109
|
+
}); // 2019
|
|
79
110
|
```
|
|
80
111
|
|
|
112
|
+
## Appearance ranges and image reuse
|
|
113
|
+
|
|
114
|
+
A model being available in consecutive years does **not** prove that its exterior stayed the
|
|
115
|
+
same. `getAvailableYearRanges()` only compresses catalog availability for display. Sourced
|
|
116
|
+
generation/facelift facts live in `data/appearance-ranges.json` and are returned by
|
|
117
|
+
`getModelAppearanceRanges()` with their body style, market, and evidence URL.
|
|
118
|
+
|
|
119
|
+
`getModelRenderGroups()` turns those facts into a complete cache plan. It groups a year only when
|
|
120
|
+
exactly one verified appearance range covers it. Years with no evidence, and transition years
|
|
121
|
+
covered by two overlapping ranges, remain singleton exact-year groups. `getRepresentativeYear()`
|
|
122
|
+
is the convenience lookup for storage/cache keys and has the same fail-closed behavior.
|
|
123
|
+
|
|
124
|
+
This split is deliberate. NHTSA vPIC provides model-year and body-class data but no global
|
|
125
|
+
generation identifier; Wikidata is CC0 but generation and facelift coverage is sparse. Broad
|
|
126
|
+
third-party generation dumps commonly carry restrictive or share-alike terms and overlapping
|
|
127
|
+
records, so they are useful for research but are not imported automatically. Verified ranges are
|
|
128
|
+
small, reviewable facts linked to first-party or equivalently authoritative public evidence.
|
|
129
|
+
|
|
130
|
+
NHTSA wheelbase, dimensions, doors, series, and truck cab/bed fields can rank possible body-family
|
|
131
|
+
matches. They are candidate evidence only: related platforms and trims can still have visibly
|
|
132
|
+
different bodywork. `appearanceId` is intentionally stricter than a derived `body_family_id` and
|
|
133
|
+
is the only grouping allowed to drive render reuse. See CONTRIBUTING for the review criteria.
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
const volkswagen = getMakes().find((make) => make.makeName === "VOLKSWAGEN")!;
|
|
137
|
+
|
|
138
|
+
getModelAppearanceRanges({ makeId: volkswagen.makeId, modelName: "Arteon" });
|
|
139
|
+
// Original Arteon: 2017–2020, Fastback, with Volkswagen evidence
|
|
140
|
+
// Updated Arteon: 2020–2026, Fastback, with Volkswagen evidence
|
|
141
|
+
|
|
142
|
+
getModelRenderGroups({ makeId: volkswagen.makeId, modelName: "Arteon" });
|
|
143
|
+
// 2017–2019 share one render; overlapping 2020 stays exact; 2021–2026 share one render.
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Driver search and autocomplete
|
|
147
|
+
|
|
148
|
+
The optional, zero-dependency search entry point turns free-form driver input into canonical catalog candidates. Its index is built lazily on the first search, and matching runs entirely in memory without network requests.
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
import { searchVehicles } from "@meterapp/vehicle-db/search";
|
|
152
|
+
|
|
153
|
+
const suggestions = searchVehicles("2020 toy cam", {
|
|
154
|
+
sourceId: "nhtsa-vpic",
|
|
155
|
+
vehicleTypeId: 2,
|
|
156
|
+
limit: 10,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const camry = suggestions.find(
|
|
160
|
+
(result) => result.kind === "model" && result.modelName === "Camry",
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
if (camry?.kind === "model") {
|
|
164
|
+
// A query containing a year has one directly selectable variant.
|
|
165
|
+
const selection = camry.variants[0];
|
|
166
|
+
// Persist year, makeId, modelId, and vehicleTypeId — not display text alone.
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Search accepts year, make, and model tokens in any order. It recognizes common punctuation variants such as `F-150`/`f150` and `CR-V`/`crv`, a small set of make aliases such as `VW` and `Chevy`, and conservative misspellings. Results are ranked deterministically by exact, prefix, token, substring, then fuzzy match. Fuzzy matching is only used when no lexical result exists.
|
|
171
|
+
|
|
172
|
+
Queries without a year group a canonical make/model/type across all available years rather than returning duplicate suggestions for every year. Each model result contains `variants`, which provides the preferred catalog `modelId` for every selectable year.
|
|
173
|
+
|
|
174
|
+
For the simplest driver experience:
|
|
175
|
+
|
|
176
|
+
1. Infer the relevant market and pass its `sourceId`; year semantics differ by source.
|
|
177
|
+
2. Offer one field labelled “Search year, make, or model” and begin suggesting after two characters.
|
|
178
|
+
3. If the driver enters only a year, use `getMakes({ year, ... })` for the next step; a year-only search intentionally returns no arbitrary alphabetical suggestions.
|
|
179
|
+
4. On empty input, show application-owned recent vehicles. The catalog intentionally does not pretend that record frequency is vehicle popularity.
|
|
180
|
+
5. Use the manual fallback Year → Make → Model. `getAvailableYears(options)` supports every step.
|
|
181
|
+
|
|
182
|
+
Applications with regional telemetry can request more candidates and rerank **within the same `matchKind`**. Text quality and market compatibility should remain ahead of behavioral popularity so an exact result never loses to an unrelated popular vehicle.
|
|
183
|
+
|
|
81
184
|
## API
|
|
82
185
|
|
|
83
186
|
### `getDataSources(): DataSource[]`
|
|
@@ -133,10 +236,11 @@ interface Make {
|
|
|
133
236
|
|
|
134
237
|
### `getModels(options?): Model[]`
|
|
135
238
|
|
|
136
|
-
Returns models, optionally filtered by `year`, `vehicleTypeId`, `makeId`, and/or `sourceId`. `sourceIds` preserves provenance when equivalent records appear in more than one source.
|
|
239
|
+
Returns models, optionally filtered by `year`, `vehicleTypeId`, `makeId`, `modelId`, and/or `sourceId`. `sourceIds` preserves provenance when equivalent records appear in more than one source.
|
|
137
240
|
|
|
138
241
|
```typescript
|
|
139
242
|
getModels({ makeId: 474, year: 2024 });
|
|
243
|
+
getModels({ modelId: 2469, year: 2024 });
|
|
140
244
|
getModels({ year: 2024, vehicleTypeId: 1 });
|
|
141
245
|
getModels({ year: 2024, vehicleTypeId: 5, sourceId: "uk-dft-vehicle-licensing" });
|
|
142
246
|
```
|
|
@@ -153,9 +257,32 @@ interface Model {
|
|
|
153
257
|
}
|
|
154
258
|
```
|
|
155
259
|
|
|
156
|
-
### `getAvailableYears(): number[]`
|
|
260
|
+
### `getAvailableYears(options?): number[]`
|
|
261
|
+
|
|
262
|
+
Returns years present in the combined catalog, optionally filtered by `makeId`, `modelId`, `vehicleTypeId`, and/or `sourceId`. Results are sorted ascending.
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
getAvailableYears();
|
|
266
|
+
getAvailableYears({ makeId: 448, vehicleTypeId: 2, sourceId: "nhtsa-vpic" });
|
|
267
|
+
getAvailableYears({ modelId: 2469, sourceId: "nhtsa-vpic" });
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Appearance and year-range APIs
|
|
271
|
+
|
|
272
|
+
- `getAvailableYearRanges(options?): VehicleYearRange[]` compresses consecutive availability
|
|
273
|
+
years; it makes no exterior-equivalence claim.
|
|
274
|
+
- `getModelAppearanceRanges({ makeId, modelName, year? }): VehicleAppearanceRange[]` returns
|
|
275
|
+
verified generation/facelift periods and evidence. Overlap is preserved.
|
|
276
|
+
- `getModelRenderGroups({ makeId, modelName, vehicleTypeId?, sourceId? }): VehicleRenderGroup[]`
|
|
277
|
+
returns safe, non-overlapping cache groups for every available year.
|
|
278
|
+
- `getRepresentativeYear({ makeId, modelName, year, ... }): number` returns the canonical cache
|
|
279
|
+
year for an unambiguous verified group, otherwise the requested year.
|
|
280
|
+
|
|
281
|
+
### `searchVehicles(query, options?): VehicleSearchResult[]`
|
|
282
|
+
|
|
283
|
+
Import from `@meterapp/vehicle-db/search`. Returns deterministic make and grouped model candidates for free-form input. Options include `year`, `vehicleTypeId`, `sourceId`, `limit` (default 10, maximum 100), and `fuzzy` (default `true`).
|
|
157
284
|
|
|
158
|
-
|
|
285
|
+
Model results contain `years` and a year-specific `variants` array. Make results intentionally omit models, allowing applications to transition into the existing `getModels` flow after the driver chooses a make.
|
|
159
286
|
|
|
160
287
|
## Data sources
|
|
161
288
|
|
package/dist/data.d.ts
CHANGED
|
@@ -24,6 +24,20 @@ interface CompactData {
|
|
|
24
24
|
}[];
|
|
25
25
|
modelNames: string[];
|
|
26
26
|
models: [number, number, number, number, number, number][];
|
|
27
|
+
appearanceRanges: {
|
|
28
|
+
id: string;
|
|
29
|
+
make_id: number;
|
|
30
|
+
make_name: string;
|
|
31
|
+
model_name: string;
|
|
32
|
+
label: string;
|
|
33
|
+
body_style: string;
|
|
34
|
+
year_from: number;
|
|
35
|
+
year_to: number;
|
|
36
|
+
representative_year: number;
|
|
37
|
+
regions: string[];
|
|
38
|
+
source_name: string;
|
|
39
|
+
source_url: string;
|
|
40
|
+
}[];
|
|
27
41
|
}
|
|
28
42
|
declare const data: CompactData;
|
|
29
43
|
export default data;
|